-- CoaExporter - Spellbook collector -- -- Walks the player's spell book (BOOKTYPE_SPELL) tab by tab and emits -- name + rank + spellID + icon for every learned spell. Pet book is -- skipped — it's not part of the build/guide use-case. -- -- 3.3.5 / Ascension API quirks handled defensively: -- - GetSpellBookItemInfo(slot, "spell") returns (name, subName) on -- vanilla 3.3.5 and (name, rank, [stuff]) on newer/private servers. -- We treat the second return as a rank string regardless. -- - GetSpellBookItemInfo doesn't return a spellID on 3.3.5. The reliable -- way to get the ID is to parse it out of GetSpellLink(slot, "spell") -- which yields "|cff71d5ff|Hspell:NNNN|h[Name]|h|r". -- - Some entries can be category headers / flyouts; if no link or -- spellID, we still record the name (it might be a known-spell that -- just doesn't link, e.g. some passives). CoaExporter = _G.CoaExporter or {} _G.CoaExporter = CoaExporter local AE = CoaExporter local BOOKTYPE = (BOOKTYPE_SPELL or "spell") local function safeCall(fn, ...) if type(fn) ~= "function" then return nil end local ok, a, b, c = pcall(fn, ...) if not ok then return nil end return a, b, c end local function spellIdFromLink(link) if not link or link == "" then return 0 end local id = string.match(link, "spell:(%d+)") return tonumber(id) or 0 end local function iconPath(icon) if not icon or icon == "" then return "" end local p = icon:match("Interface\\Icons\\(.+)") or icon return tostring(p):lower() end function AE.CollectSpellbook() local out = { tabs = {}, totalSpells = 0 } if type(GetNumSpellTabs) ~= "function" then out.error = "GetNumSpellTabs not available" return out end local numTabs = GetNumSpellTabs() or 0 for tabIndex = 1, numTabs do local tabName, tabTexture, offset, numSpells = safeCall(GetSpellTabInfo, tabIndex) offset = offset or 0 numSpells = numSpells or 0 local tab = { index = tabIndex, name = tabName or ("Tab " .. tabIndex), texture = iconPath(tabTexture), offset = offset, numSpells = numSpells, spells = {}, } for slot = offset + 1, offset + numSpells do local name, subOrRank = safeCall(GetSpellBookItemInfo, slot, BOOKTYPE) if (not name or name == "") and type(GetSpellName) == "function" then -- vanilla 3.3.5 fallback name, subOrRank = safeCall(GetSpellName, slot, BOOKTYPE) end local link = safeCall(GetSpellLink, slot, BOOKTYPE) local spellID = spellIdFromLink(link) local icon if spellID > 0 then local _, _, ic = GetSpellInfo(spellID) icon = ic end if (not icon) and type(GetSpellTexture) == "function" then icon = safeCall(GetSpellTexture, slot, BOOKTYPE) end if name and name ~= "" then table.insert(tab.spells, { slot = slot, name = name, rank = subOrRank or "", spellID = spellID, icon = iconPath(icon), }) out.totalSpells = out.totalSpells + 1 end end table.insert(out.tabs, tab) end return out end AE._loadedSpellbook = true