6badf0e7ea
New Collectors/Spellbook.lua walks GetNumSpellTabs() and emits one entry
per tab with name, texture, offset, numSpells, and a spells[] array of
{ slot, name, rank, spellID, icon }.
3.3.5/Ascension API differences are handled defensively: name comes
from GetSpellBookItemInfo or vanilla GetSpellName; spellID is parsed
out of GetSpellLink (3.3.5 doesn't return it from GetSpellBookItemInfo);
icon falls back to GetSpellTexture if GetSpellInfo doesn't have it yet.
Wiring:
- CoaExporter.toc: load Collectors/Spellbook.lua after Talents
- Core.lua: AssembleExport() includes spellbook for all + spellbook
- Core.lua: HandleExport() accepts /coae export spellbook
- Core.lua: debug output shows tab + spell counts
- UI/ExportFrame.lua: "Spellbook" button in the Character section
104 lines
3.4 KiB
Lua
104 lines
3.4 KiB
Lua
-- 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
|