WoWInterface SVN LibSpellName2SID

Compare Revisions

  • This comparison shows the changes necessary to convert path
    /populator/tags/LibSpellName2SID-Populator-1.0.08b
    from Rev 74 to Rev 76
    Reverse comparison

Rev 74 → Rev 76

LibSpellName2SID-1.0-Populator.toc
1,9 → 1,10
## Interface: 70300
## Interface: 70305
## Title: LibSpellName2SID: Populator (DEV)
## Notes: Get available spells from a character;|nSave them to file: inside main-table, as|nClass-table->Spec-table.
## Notes: Get available spells from a character;|nSave them to file: inside main-table, as|nClass-table(->Class-specific-table(s)).
## Author: aallkkaa
## Version: 1.0.02a
## SavedVariables: SpellNamesAndIDs
## Version: 1.0.08-Easier_fetching_of_castable_talent_spells+Passive_spells_table
## SavedVariables: SpellNamesAndIDs, SpellNamesAndIDs_PASSIVES
## DefaultState: disabled
## X-Category: Development
 
LibspellName2SID-1.0-Populator.lua
LibSpellName2SID-1.0-Populator.lua
LibspellName2SID-1.0-Populator.lua
1,5 → 1,5
----------
-- (C) 2017 aallkkaa
-- (C) 2017-2018 by aallkkaa
-- http://www.wowinterface.com/forums/member.php?action=getinfo&userid=335646
--
-- Lib: SpellName2SID-1.0: Populator
8,367 → 8,576
----------
local AddonName, AddonEnv = ...;
 
local SN2SID_table; -- Local copy of the saved variables table: SpellNamesAndIDs
-- Local copies of the saved variables' tables: SpellNamesAndIDs and SpellNamesAndIDs_PASSIVES
-- local SN2SID_table, SN2SID_PASSIVES_table;
 
local curLocale, gameBuild, universalClassName, generalTabName, charLevel;
local updateClassDataSource = false;
local updateClassSpells = false;
local updateGeneralDataSource = false;
local updateGeneralSpells = false;
-- Stuff
local NumberOfTalentTiers = 7; -- Current number of talent tiers - WoW-7.x.x
 
 
-- Function to store information about the data source: how up to date it is --
local updateDataSource = function(generalTabName, universalClassName)
-- General tab dataSource
if updateGeneralDataSource then
if charLevel > SN2SID_table[generalTabName].dataSource.charLevel then
-- SN2SID_table[generalTabName].dataSource.clientLocale = curLocale; -- TEMP FIX
SN2SID_table[generalTabName].dataSource.charLevel = charLevel;
if charLevel > SN2SID_table[generalTabName].dataSource.charMaxLevel then
SN2SID_table[generalTabName].dataSource.charMaxLevel = charLevel;
end
updateGeneralSpells = true;
-- Functions to store information about the dataSource (how up to date it is) and other metadata --
----------------------------------------------------------------------------------------------------
 
-- Update the General tab dataSource + raceBuilds --
local updateGeneralTabMetadata_func = function(SN2SID_table, SN2SID_PASSIVES_table, curLocale, gameBuild, universalRaceName, generalTabName, charLevel)
if not updateGeneralTabMetadata then
return;
end
 
-- print(AddonName.. ": Will now check whether the GeneralTab Metadata needs updating.");
-- Actively-cast spells
if charLevel > SN2SID_table[generalTabName].METADATA.dataSource.charLevel then
SN2SID_table[generalTabName].METADATA.dataSource.charLevel = charLevel;
if charLevel > SN2SID_table[generalTabName].METADATA.dataSource.charMaxLevel then
SN2SID_table[generalTabName].METADATA.dataSource.charMaxLevel = charLevel;
end
if gameBuild > SN2SID_table[generalTabName].dataSource.gameBuild then
-- SN2SID_table[generalTabName].dataSource.clientLocale = curLocale; -- TEMP FIX
SN2SID_table[generalTabName].dataSource.gameBuild = gameBuild;
-- Highest charLevel stored upon the most recent gameBuild
SN2SID_table[generalTabName].dataSource.charLevel = charLevel;
-- Highest charLevel ever stored is kept in [...].charMaxLevel
updateGeneralSpells = true;
end
updateGeneralDataSource = false;
updateGeneralSpells = true;
end
-- Class dataSource
if updateClassDataSource then
if charLevel > SN2SID_table[universalClassName].dataSource.charLevel then
SN2SID_table[universalClassName].dataSource.charLevel = charLevel;
if charLevel > SN2SID_table[universalClassName].dataSource.charMaxLevel then
SN2SID_table[universalClassName].dataSource.charMaxLevel = charLevel;
end
updateClassSpells = true;
if gameBuild > SN2SID_table[generalTabName].METADATA.dataSource.gameBuild then
SN2SID_table[generalTabName].METADATA.dataSource.gameBuild = gameBuild;
-- Highest charLevel stored upon the most recent gameBuild
SN2SID_table[generalTabName].METADATA.dataSource.charLevel = charLevel;
-- Highest charLevel ever stored is kept in [...].charMaxLevel
updateGeneralSpells = true;
end
if (not SN2SID_table[generalTabName].METADATA.raceBuilds[universalRaceName]) or
(gameBuild > SN2SID_table[generalTabName].METADATA.raceBuilds[universalRaceName]) then
SN2SID_table[generalTabName].METADATA.raceBuilds[universalRaceName] = gameBuild;
updateGeneralSpells = true;
end
-- Passive spells
if charLevel > SN2SID_PASSIVES_table[generalTabName].METADATA.dataSource.charLevel then
SN2SID_PASSIVES_table[generalTabName].METADATA.dataSource.charLevel = charLevel;
if charLevel > SN2SID_PASSIVES_table[generalTabName].METADATA.dataSource.charMaxLevel then
SN2SID_PASSIVES_table[generalTabName].METADATA.dataSource.charMaxLevel = charLevel;
end
if gameBuild > SN2SID_table[universalClassName].dataSource.gameBuild then
SN2SID_table[universalClassName].dataSource.gameBuild = gameBuild;
SN2SID_table[universalClassName].dataSource.charLevel = charLevel;
updateClassSpells = true;
end
updateClassDataSource = false;
updateGeneralSpells = true;
end
if gameBuild > SN2SID_PASSIVES_table[generalTabName].METADATA.dataSource.gameBuild then
SN2SID_PASSIVES_table[generalTabName].METADATA.dataSource.gameBuild = gameBuild;
-- Highest charLevel stored upon the most recent gameBuild
SN2SID_PASSIVES_table[generalTabName].METADATA.dataSource.charLevel = charLevel;
-- Highest charLevel ever stored is kept in [...].charMaxLevel
updateGeneralSpells = true;
end
if (not SN2SID_PASSIVES_table[generalTabName].METADATA.raceBuilds[universalRaceName]) or
(gameBuild > SN2SID_PASSIVES_table[generalTabName].METADATA.raceBuilds[universalRaceName]) then
SN2SID_PASSIVES_table[generalTabName].METADATA.raceBuilds[universalRaceName] = gameBuild;
updateGeneralSpells = true;
end
updateGeneralTabMetadata = false;
end
 
 
-- Functions to store spellNames and IDs of General tab and of player Class --
 
-- GeneralTab: Tables of exclusions: don't store spells that contain these words
local GeneralTabSpellSubNameExclusions = { "Passive", };
local GeneralTabSpellNameExclusions = { "Riding", "Skills", "Guild Mail",
"Hasty Hearth", "Mount Up", "Silver Dollar Club", "The Quick and the Dead",
"Trading Pact", "Upgrades", }; -- Several passives don't have a spellSubName.
-- General tab: Function to check whether a given spell is to be excluded
local excludeGeneralTabSpell = function(spellName, spellSubName)
if GeneralTabSpellSubNameExclusions and GeneralTabSpellSubNameExclusions ~= "" then
for k,v in ipairs(GeneralTabSpellSubNameExclusions) do
if spellSubName and strfind(spellSubName, v) then
return true;
end
end
-- Update the Class dataSource --
local updateClassMetadata_func = function(SN2SID_table, SN2SID_PASSIVES_table, curLocale, gameBuild, universalClassName, charLevel)
if not updateClassMetadata then
return;
end
if GeneralTabSpellNameExclusions and GeneralTabSpellNameExclusions ~= "" then
for k,v in ipairs(GeneralTabSpellNameExclusions) do
if strfind(spellName, v) then
return true;
end
-- print(AddonName.. ": Will now check whether the ".. universalClassName.. " Metadata needs updating.");
-- Actively-cast spells
if charLevel > SN2SID_table[universalClassName].METADATA.dataSource.charLevel then
SN2SID_table[universalClassName].METADATA.dataSource.charLevel = charLevel;
if charLevel > SN2SID_table[universalClassName].METADATA.dataSource.charMaxLevel then
SN2SID_table[universalClassName].METADATA.dataSource.charMaxLevel = charLevel;
end
updateClassSpells = true;
end
return false;
end
-- Class tabs: Tables of exclusions: don't store spells that contain these words
local ClassTabsSpellSubNameExclusions = { "Passive", }; -- Maybe allow inclusion
-- because, for example, 'Tidal
-- Waves' is a passive that procs a
-- buff of the same name...? Though
-- it would make for an incomplete
-- list of buffs anyway.
local ClassTabsSpellNameExclusions = { "Mastery:", };
-- Class tabs: Function to check whether a given spell is to be excluded
local excludeClassTabsSpell = function(spellName, spellSubName)
if ClassTabsSpellSubNameExclusions and ClassTabsSpellSubNameExclusions ~= "" then
for k,v in ipairs(ClassTabsSpellSubNameExclusions) do
if spellSubName and strfind(spellSubName, v) then
return true;
end
end
if gameBuild > SN2SID_table[universalClassName].METADATA.dataSource.gameBuild then
SN2SID_table[universalClassName].METADATA.dataSource.gameBuild = gameBuild;
SN2SID_table[universalClassName].METADATA.dataSource.charLevel = charLevel;
updateClassSpells = true;
end
if ClassTabsSpellNameExclusions and ClassTabsSpellNameExclusions ~= "" then
for k,v in ipairs(ClassTabsSpellNameExclusions) do
if strfind(spellName, v) then
return true;
end
-- Passive spells
if charLevel > SN2SID_PASSIVES_table[universalClassName].METADATA.dataSource.charLevel then
SN2SID_PASSIVES_table[universalClassName].METADATA.dataSource.charLevel = charLevel;
if charLevel > SN2SID_PASSIVES_table[universalClassName].METADATA.dataSource.charMaxLevel then
SN2SID_PASSIVES_table[universalClassName].METADATA.dataSource.charMaxLevel = charLevel;
end
updateClassSpells = true;
end
return false;
if gameBuild > SN2SID_PASSIVES_table[universalClassName].METADATA.dataSource.gameBuild then
SN2SID_PASSIVES_table[universalClassName].METADATA.dataSource.gameBuild = gameBuild;
SN2SID_PASSIVES_table[universalClassName].METADATA.dataSource.charLevel = charLevel;
updateClassSpells = true;
end
updateClassMetadata = false;
end
-- Pet spells: Tables of exclusions: don't store spells that contain these words
local PetSpellSubNameExclusions = { "Passive", };
local PetSpelsNameExclusions = { PET_ASSIST, PET_ACTION_ATTACK, PET_DEFENSIVE,
PET_ACTION_FOLLOW, PET_ACTION_MOVE_TO,
PET_PASSIVE, "Stay", }; -- The 7 default actions
-- for which GetSpellInfo() returns nil
-- NB: It might be desirable to store
-- these spell references, which would
-- be the tokens (string) above...?
-- Pet spells: Function to check whether a given spell is to be excluded
local excludePetSpell = function(spellName, spellSubName)
if PetSpellSubNameExclusions and PetSpellSubNameExclusions ~= "" then
for k,v in ipairs(PetSpellSubNameExclusions) do
if spellSubName and strfind(spellSubName, v) then
return true;
 
 
---- Functions to update the lists of Spell Names and their IDs ----
--------------------------------------------------------------------
 
-- Update the Talents' lists of spells
local updateTalentSpells_func = function(SN2SID_table, SN2SID_PASSIVES_table, universalClassName, ClassNumSpecs, ClassSpecNames2IDs)
if not updateClassSpells then -- Sanity check
return;
end
 
for i = 1, ClassNumSpecs do
-- Create "SpecName" subtables and "SpecName_Talents" subtables if they doesn't exist yet
local specID, locSpecName = GetSpecializationInfo(i);
if locSpecName then -- Sanity check
-- Actives
if not SN2SID_table[universalClassName][locSpecName.."_Talents"] then
SN2SID_table[universalClassName][locSpecName.."_Talents"] = {};
end
-- Passives
if not SN2SID_PASSIVES_table[universalClassName][locSpecName.."_Talents"] then
SN2SID_PASSIVES_table[universalClassName][locSpecName.."_Talents"] = {};
end
end
end
if PetSpelsNameExclusions and PetSpelsNameExclusions ~= "" then
for k,v in ipairs(PetSpelsNameExclusions) do
if strfind(spellName, v) then
return true;
for ii = 1, NumberOfTalentTiers do
for iii = 1, 3 do
local _, spellName, _, _, _, spellID, _, _, _, _, _ = GetTalentInfoBySpecialization(i, ii, iii);
if spellName then
if IsPassiveSpell(spellID) then
SN2SID_PASSIVES_table[universalClassName][locSpecName.."_Talents"][spellName] = spellID;
else
SN2SID_table[universalClassName][locSpecName.."_Talents"][spellName] = spellID;
end
end
end
end
end
return false;
end
 
-- -- Update the lists of spell names and their IDs -- --
local updateSpellNames = function(universalClassName)
-- Update the Spellbook's GeneralTab and ClassTabs lists of spells
local updateSpellbookSpells_func = function(SN2SID_table, SN2SID_PASSIVES_table, generalTabName, universalClassName, ClassNumSpecs, ClassSpecNames2IDs)
-- General tab spells
if updateGeneralSpells then -- In current addon version, always true
local generalTabName, _, offset, numEntries, _, _ = GetSpellTabInfo(1);
local generalTabName, _, offset, numEntries, _, _, _ = GetSpellTabInfo(1);
-- name, texture, offset, numEntries, isGuild, offspecID = GetSpellTabInfo(tabIndex)
for i = offset +1, offset +numEntries do
local spellName, spellSubName = GetSpellBookItemName(i, BOOKTYPE_SPELL);
-- Only store non-Passive skills
if spellName and not excludeGeneralTabSpell(spellName, spellSubName) then
local spellID = select(2, GetSpellBookItemInfo(i, BOOKTYPE_SPELL));
SN2SID_table[generalTabName].ID[spellName] = spellID;
if spellName then
local _, spellID = GetSpellBookItemInfo(i, BOOKTYPE_SPELL);
-- Store Passive and Active abilities into their own separate tables
if IsPassiveSpell(spellID) then
SN2SID_PASSIVES_table[generalTabName].Spells[spellName] = spellID;
else
SN2SID_table[generalTabName].Spells[spellName] = spellID;
end
end
end
end
 
-- Class spells
if updateClassSpells then
for i = 2, GetNumSpellTabs() do
local _, _, offset, numEntries, _, _ = GetSpellTabInfo(i);
for ii = offset +1, offset +numEntries do
local spellName, spellSubName = GetSpellBookItemName(ii, BOOKTYPE_SPELL);
-- Only store non-Passive skills
if spellName and not excludeClassTabsSpell(spellName, spellSubName) then
local spellID = select(2, GetSpellBookItemInfo(ii, BOOKTYPE_SPELL));
SN2SID_table[universalClassName].ID[spellName] = spellID;
-- NB Some spell names can have more than one spell ID.
-- E.g. Elemantal Shaman "Flame Shock" ID = 188389
-- Restoration Shaman "Flame Shock" ID = 188838
-- But their English names should translate equally to
-- other languages. And the addon using this library is
-- expected to get the spellID for the currently active
-- spec from its Englsih spellName.
-- Therefore we can store either spell ID and get the same
-- translation everytime. The addon will then get the right
-- spellID for the active spec, by its name.
updateTalentSpells_func(SN2SID_table, SN2SID_PASSIVES_table, universalClassName, ClassNumSpecs, ClassSpecNames2IDs);
for i = 2, (ClassNumSpecs +1) do
-- Get the current tab's first spell's index, total number of spells therein and specID
local _, _, offset, numEntries, _, _, _, specID = GetSpellTabInfo(i);
if specID then -- Sanity check
local _, locSpecName = GetSpecializationInfoByID(specID);
--- Create SpecName subtables and SpecName_Talents subtables if they doesn't exist yet
if locSpecName then -- Sanity check
if not SN2SID_table[universalClassName][locSpecName] then
SN2SID_table[universalClassName][locSpecName] = {};
end
if not SN2SID_PASSIVES_table[universalClassName][locSpecName] then
SN2SID_PASSIVES_table[universalClassName][locSpecName] = {};
end
end
-- Populate
for ii = offset +1, offset +numEntries do
local spellName, spellSubName = GetSpellBookItemName(ii, BOOKTYPE_SPELL);
if spellName then
local _, spellID = GetSpellBookItemInfo(ii, BOOKTYPE_SPELL);
-- Store Passive and Active abilities into their own separate tables
if IsPassiveSpell(spellID) and ((not SN2SID_PASSIVES_table[universalClassName][locSpecName.."_Talents"])
or (not SN2SID_PASSIVES_table[universalClassName][locSpecName.."_Talents"][spellName])) then
SN2SID_PASSIVES_table[universalClassName][locSpecName][spellName] = spellID;
elseif (not SN2SID_table[universalClassName][locSpecName.."_Talents"])
or (not SN2SID_table[universalClassName][locSpecName.."_Talents"][spellName]) then
SN2SID_table[universalClassName][locSpecName][spellName] = spellID;
end
end
end
end
end
updateClassSpells = false;
end
end
-- Update the Names and IDs for Pet Spells
local updatePetSpellNames = function(universalClassName)
local _ , _, offset, numEntries, _, _ = GetSpellTabInfo(1);
for i = offset +1, offset +numEntries do
local spellName, spellSubName = GetSpellBookItemName(i, BOOKTYPE_PET);
if spellName and (not excludePetSpell(spellName, spellSubName)) then
-- GetSpellBookItemInfo() is returning weird values for Pet Spells.
-- GetSpellInfo(), on the other hand, gets the correct ones.
-- The seven standard Pet abilities every controllable pet has -
-- - Assist, Attack, Defensive, Follow, Move To, Passive and Stay -
-- - when queried by GetSpellBookItemInfo(), return more of them weird
-- values. When queried by GetSpellInfo(), they don't return any value
-- at all. Our excludePetSpell(...) function above handles this.
local spellID = select(2, GetSpellBookItemInfo(i, BOOKTYPE_PET));
-- local spellIDaltGet = select(7, GetSpellInfo(spellName));
if spellIDaltGet and ( spellIDaltGet ~= spellID ) then
-- if spellIDaltGet then
-- print(spellName.. " (".. spellSubName.. ") ID:".. spellIDaltGet);
SN2SID_table[universalClassName].Pet[spellName] = spellIDaltGet;
elseif not SN2SID_table[universalClassName].Pet[spellName] then
-- This is so weird. A simple "else" should do, but no, we do need
-- to check whether the spellName has been stored already, so as to
-- not overwrite the correct GetSpellInfo() value with the wrong
-- one from GetSpellBookItemInfo().
-- print(spellName.. " (".. spellSubName.. ") ID:".. spellID);
SN2SID_table[universalClassName].Pet[spellName] = spellID;
 
-- Update the Pet-Spellbook and PetActionBar's spells --
-- Table of spellnames to exclude from storage
local PetSpellNameExclusions = { PET_ASSIST, PET_ACTION_ATTACK, PET_DEFENSIVE,PET_ACTION_FOLLOW,
PET_ACTION_MOVE_TO, PET_PASSIVE, "Stay" };
-- TABLE ABOVE: The 7 default actions for which GetSpellInfo() returns
-- nil. QUESTION: Would it be desirable to save these spell references,
-- which names would be the tokens (string) above?
-- Pet Spells update function
local updatePetSpellNames = function(SN2SID_table, SN2SID_PASSIVES_table, universalClassName)
-- print(AddonName.. ": Fetching Pet spells ...");
local petHasSpellsConfirmed = false;
-- NOTES:
-- GetSpellInfo(spellName) is the most reliable way to get the SpellID for a give SpellName, 7th
-- return value. BUT we need to get a list of spell names first, and that's where the other two
-- Blizzard functions, GetPetActionInfo(buttonNumber) and GetSpellBookItemName(SpellbookIndex,
-- BOOKTYPE_PET), come in.
--
-- GetPetActionInfo(buttonNumber) only retrieves information for spells on the PetActionBar;
-- given that there might be other Pet Spells - on the PetSpellbook - we will later need to get
-- them using other means. But first we will get these spells from the bar, for these reasons:
-- - One thing to note is the 'isToken' return value from GetPetActionInfo(). This value will be
-- true if the spell is one of the 7 standard spells that every controllable pet gets: Assist,
-- Attack, Defensive, Follow, Move To, Passive, Stay. This flag is NOT returned by any of the
-- the other functions we get info on PetSpells from. Again, unfortunately, GetPetActionInfo()
-- only returns info on spells in the PetActionBar and not all PetSpells are in there.
-- Another important thing to note is that Temporary Controllable-pets (e.g. the Elemental
-- Shaman pets, if the talent 'Primal Elementalist' is active) do not have any spells in a
-- spellbook; but all their spells should be on the PetActionBar. Thus GetPetActionInfo is the
-- only way - and the only way needed - to get info on these pets' spells.
--
-- GetSpellBookItemInfo() not only does not return anything for Temporary Controllable-pets, it
-- also seems BUGGED, as it returns weird values for Pet SpellIDs (9 or 10 digits long numbers,
-- sometimes negatives!).
-- GetSpellBookItemName() (other function) however returns correct SpellNames and is rather
-- exaustive as far as getting them for permanent pets.
--
-- GetPetActionInfo(buttonNumber) + GetSpellInfo(spellName) --
if PetHasActionBar() then -- As all controllable pets do. Note: HasPetUI() returns 'true' for
-- classes which have pets but are too low level to have control
-- over them; e.g. Warlocks under Level 10. PetHasActionBar() only
-- returns 'true' if a PetActionBar is actually available.
for i = 1, NUM_PET_ACTION_SLOTS do
local spellName, spellSubName, _, isToken, _, _, _ = GetPetActionInfo(i);
-- print(AddonName.. ": Bar: ".. tostring(spellName));
if spellName and (not isToken) then
local _, _, _, _, _, _, spellID = GetSpellInfo(spellName);
if IsPassiveSpell(spellID) then
SN2SID_PASSIVES_table[universalClassName].Pets[spellName] = spellID;
else
SN2SID_table[universalClassName].Pets[spellName] = spellID;
end
end
end
petHasSpellsConfirmed = true;
end
-- Temporary controllable pets (controlable "guardians"?)
-- Iterate through the PetActionBar buttons, for e.g. Elemental Shaman, with
-- Primal Elementalist talent, Fire Elemental's spels, which don't go into
-- the SpellBook.
for i = 1, NUM_PET_ACTION_SLOTS do
local spellName, spellSubName, _, isToken, _, _, _ = GetPetActionInfo(i);
-- print(AddonName.. ": PetActionBar buton".. i.. ": ".. tostring(spellName)..
-- " (".. tostring(spellSubName).. ") ".. " Token? ".. tostring(isToken));
if spellName and (not isToken) and
(not SN2SID_table[universalClassName].Pet[spellName]) and
(not excludePetSpell(spellName, spellSubName)) then
-- NB: If isToken, then spellNameOtherGet == PET_ASSIST, etc; will give
-- the same token-like result for the 3rd argument (spell texture).
local spellID = select(7, GetSpellInfo(spellName));
-- print(AddonName.. ": PetActionBar buton".. i.. ": ".. spellName..
-- " (".. tostring(spellSubName).. ") ".. "ID:".. spellID);
SN2SID_table[universalClassName].Pet[spellName] = spellID;
-- GetSpellBookItemName(SpellbookIndex, BOOKTYPE_PET) + GetSpellInfo(spellName) --
if HasPetSpells() then -- I.e. whether there is a Pet Spellbook. WARNING: Returns 'true' for
-- classes which have pets but are too low level to have control
-- over them; e.g. Warlocks under Level 10.
local _ , _, offset, numEntries, _, _ = GetSpellTabInfo(1);
-- print(AddonName.. ": offset, numEntries = ".. offset.. ", ".. numEntries);
for i = offset +1, offset +numEntries do
local spellName, spellSubName = GetSpellBookItemName(i, BOOKTYPE_PET);
-- print(AddonName.. ": Book: ".. tostring(spellName));
if spellName then
-- No isToken flag from GetPetActionInfo() here, so do the check ourselves
local isToken = false;
for ii in ipairs(PetSpellNameExclusions) do
-- print(AddonName.. ": ".. i.. ": Spell: ".. spellname);
-- print(AddonName.. ": ".. i.. ": Exclusion: ".. PetSpellNameExclusions[ii]);
if spellName == PetSpellNameExclusions[ii] then
isToken = true;
break;
end
end
if not isToken then
-- local _, spellID = GetSpellBookItemInfo(i, BOOKTYPE_PET);
local _, _, _, _, _, _, spellID = GetSpellInfo(spellName);
if IsPassiveSpell(spellID) and (not SN2SID_PASSIVES_table[universalClassName].Pets[spellName]) then
SN2SID_PASSIVES_table[universalClassName].Pets[spellName] = spellID;
elseif (not SN2SID_table[universalClassName].Pets[spellName]) then
SN2SID_table[universalClassName].Pets[spellName] = spellID;
end
end
end
end
petHasSpellsConfirmed = true;
end
-- print(AddonName.. ": Fetched? ".. tostring(petHasSpellsConfirmed));
end
 
 
-- When ADDON_LOADED fires, SpellBook isn't available yet; it is w/ PLAYER_LOGIN
-- PLAYER_LOGIN event handler; we set the other events up when this one fires --
-- -- -- RUNTIME -- -- --
-------------------------
 
-- Frame to listen to game events
local SN2SID_frame, SN2SID_events = CreateFrame("Frame", nil), {};
-- SN2SID_frame:RegisterEvent("ADDON_LOADED");
-- NB: When ADDON_LOADED fires, the SpellBook etc aren't available yet, only upon PLAYER_LOGIN.
SN2SID_frame:RegisterEvent("PLAYER_LOGIN");
 
SN2SID_frame:SetScript("OnEvent", function(self, event)
if event ~= "PLAYER_LOGIN" then -- Should not be needed, as we set this
-- script to nil, at the end of this func.
return;
end
print("Loading: ".. AddonName);
-- Copy the global saved-variables table to our local table
SN2SID_table = AddonEnv.SpellNamesAndIDs or SpellNamesAndIDs or {};
 
-- Function to call upon PLAYER_LOGIN (see bottom of file)
local lsn2sidpStartup = function()
-- Startup --
print(AddonName.. ": Startup!");
-- Copy the global saved-variables tables to our local tables
local SN2SID_table = AddonEnv.SpellNamesAndIDs or SpellNamesAndIDs or {};
local SN2SID_PASSIVES_table = AddonEnv.SpellNamesAndIDs_PASSIVES or SpellNamesAndIDs_PASSIVES or {};
-- print(AddonName.. ": AddonEnv.SpellNamesAndIDs = ".. tostring(AddonEnv.SpellNamesAndIDs)); -- nil
-- print(AddonName.. ": AddonEnv.SpellNamesAndIDs_PASSIVES = ".. tostring(AddonEnv.SpellNamesAndIDs_PASSIVES)); -- nil
-- print(AddonName.. ": SpellNamesAndIDs = ".. tostring(SpellNamesAndIDs)); -- TableA
-- print(AddonName.. ": SpellNamesAndIDs_PASSIVES = ".. tostring(SpellNamesAndIDs_PASSIVES)); -- TableB
-- print(AddonName.. ": SN2SID_table = ".. tostring(SN2SID_table));-- TableA
-- print(AddonName.. ": SN2SID_PASSIVES_table = ".. tostring(SN2SID_PASSIVES_table)); -- TableB
 
-- -- Metadata fields: Data source, Class', ... -- --
-- Data source --
-- We're only interested in storing the English names, at least for now
curLocale = GetLocale();
local curLocale = GetLocale();
if ( curLocale ~= "enUS") then
SN2SID_frame:UnregisterAllEvents();
error(AddonName.. " only retrieves data from English (enUS or enGB) clients.");
return;
end
gameBuild = select(2, GetBuildInfo());
-- Locale-independent name of the current player class
universalClassName = select(2, UnitClass("player"));
-- Character level
charLevel = UnitLevel("player");
-- Spells in the General tab: Racial abilities are here. It may be desirable
-- to handle other spells of this tab as well.
generalTabName = select(1, GetSpellTabInfo(1)); -- Tab#1 = General
-- Create the root table, if needed
local universalRaceName = select(2, UnitRace("player"));
-- Self-explanatory:
local gameBuild = select(2, GetBuildInfo());
local charLevel = UnitLevel("player");
-- Spells in the General tab: Racial abilities, etc
local generalTabName = (GetSpellTabInfo(1)); -- Tab#1 = General
-- Class stuff --
local universalClassName = select(2, UnitClass("player")); -- Locale-independent Class name
local ClassNumSpecs = GetNumSpecializations(false, false); -- Number of Specialisations
-- Ordered list of Class specs' IDs and Names -- Do we still use this?
local specID, specName = GetSpecializationInfo(1);
local ClassSpecNames2IDs = {};
for i = 1, ClassNumSpecs do
local specID, specName = GetSpecializationInfo(i);
ClassSpecNames2IDs[specName] = specID;
end
 
---- Check the tables' skeleton structure and build whatever may be missing ----
--
if not SN2SID_table then -- sanity check
-- SN2SID_table = {};
error(AddonName.. "Local copy of saved variables is missing.");
return;
end
-- Create and populate the subtables --
-- General tab dataSource
if not SN2SID_PASSIVES_table then -- sanity check
error(AddonName.. "Local copy of saved variables is missing.");
return;
end
--
-- If needed, create and populate the Metadata subtables; --
-- Flag spell-lists for update if applicable --
--
-- General tab skeleton + dataSource + raceBuilds
-- NB: We separate the two types of tables in two if-loops for the sake of sanity-keep (against
-- e.g. manual edits to the file).
if not SN2SID_table[generalTabName] then
print(AddonName.. ": Will now create the ".. generalTabName.. " dataSource for Active spells.");
SN2SID_table[generalTabName] = {};
SN2SID_table[generalTabName].ID = {};
SN2SID_table[generalTabName].dataSource = {
SN2SID_table[generalTabName].Spells = {};
SN2SID_table[generalTabName].METADATA = {};
SN2SID_table[generalTabName].METADATA.dataSource = {
clientLocale = curLocale, -- Currently always enUS
gameBuild = gameBuild,
charLevel = charLevel,
charMaxLevel = charLevel,
};
updateGeneralSpells = true;
SN2SID_table[generalTabName].METADATA.raceBuilds = { [universalRaceName] = gamebuild };
-- We've just created and populated the GeneralTabMetadata, hence no need to update
updateGeneralTabMetadata = false;
updateGeneralSpells = true; -- Do populate the actual list of spells
else
updateGeneralTabMetadata = true; -- Will check whether it's updated; if not, will update;
-- The function which checks above var will also flag for Spells-list update if needed.
end
updateGeneralDataSource = true;
-- Class spells dataSource
if not SN2SID_PASSIVES_table[generalTabName] then
print(AddonName.. ": Will now create the ".. generalTabName.. " dataSource for Passive spells.");
SN2SID_PASSIVES_table[generalTabName] = {};
SN2SID_PASSIVES_table[generalTabName].Spells = {};
SN2SID_PASSIVES_table[generalTabName].METADATA = {};
SN2SID_PASSIVES_table[generalTabName].METADATA.dataSource = {
clientLocale = curLocale, -- Currently always enUS
gameBuild = gameBuild,
charLevel = charLevel,
charMaxLevel = charLevel,
};
SN2SID_PASSIVES_table[generalTabName].METADATA.raceBuilds = { [universalRaceName] = gamebuild };
-- We've just created and populated the GeneralTabMetadata, hence no need to update ...
if not updateGeneralTabMetadata then -- ... unless it's needed for the Active spells
updateGeneralTabMetadata = false; -- And this seems redundant. Keep it 'cause I'll forget it otherwise...
end
updateGeneralSpells = true; -- Do populate the actual list of spells
else
updateGeneralTabMetadata = true; -- Will check whether it's updated, if not will update;
-- The function which checks above var will also flag for Spells-list update if needed.
end
-- Run the update function (does both Active and Passive trees), delayed
updateGeneralTabMetadata_func(SN2SID_table, SN2SID_PASSIVES_table, curLocale, gameBuild, universalRaceName, generalTabName, charLevel);
 
-- Class spells' Metadata (dataSource only; class Specs will be handled afterwards)
if not SN2SID_table[universalClassName] then
print(AddonName.. ": Will now create the ".. universalClassName.. "'s table and dataSource for Active spells.");
SN2SID_table[universalClassName] = {};
SN2SID_table[universalClassName].ID = {};
SN2SID_table[universalClassName].dataSource = {
SN2SID_table[universalClassName].METADATA = {};
SN2SID_table[universalClassName].METADATA.dataSource = {
clientLocale = curLocale, -- Currently always enUS
gameBuild = gameBuild,
charLevel = charLevel,
charMaxLevel = charLevel,
};
updateClassSpells = true;
-- We've just created and populated the Class' dataSource fields, hence no need to update;
-- Class Specs fields are updated in another if-clause, further ahead.
updateClassMetadata = false;
updateClassSpells = true; -- Do populate the actual list of spells.
else
updateClassMetadata = true; -- Will check whether it's updated and if not, will update;
-- The function which checks above var will also flag for Spells-list update if needed.
end
updateClassDataSource = true;
updateDataSource(generalTabName, universalClassName);
-- Update General (always ATM) and Class spellNames2IDs
updateSpellNames(universalClassName);
-- Pet spells will only be available when a pet is out, so wait for it, i.e.
-- wait for UNIT_PET to fire for "player".
if not SN2SID_PASSIVES_table[universalClassName] then
print(AddonName.. ": Will now create the ".. universalClassName.. "'s table and dataSource for Passive spells.");
SN2SID_PASSIVES_table[universalClassName] = {};
SN2SID_PASSIVES_table[universalClassName].METADATA = {};
SN2SID_PASSIVES_table[universalClassName].METADATA.dataSource = {
clientLocale = curLocale, -- Currently always enUS
gameBuild = gameBuild,
charLevel = charLevel,
charMaxLevel = charLevel,
};
if not updateClassMetadata then -- See above, in the Actives snippet
updateClassMetadata = false;
end
updateClassSpells = true; -- Do populate the actual list of spells.
else
updateClassMetadata = true;
end
-- Do the actual update of the Class Metadata (dataSource only now; Specs will be handled next)
updateClassMetadata_func(SN2SID_table, SN2SID_PASSIVES_table, curLocale, gameBuild, universalClassName, charLevel);
 
-- If needed, create and populate Class Specs' Active and Passive Spells --
-- Flag spell-lists for update if applicable --
if not SN2SID_table[universalClassName].METADATA.Specs then
print(AddonName.. ": Will now create the ".. universalClassName.. "'s \'Specs\' (Actives) tables.");
for i = 1, ClassNumSpecs do
local specID, specName = GetSpecializationInfo(i);
-- ClassSpecNames2IDs[i] = { specID, specName };
ClassSpecNames2IDs[specName] = specID;
-- print(AddonName.. ": ".. i.. " = ".. specID.. " = ".. specName); -- For reference
-- local specString = "Spec"..specID;
if not SN2SID_table[universalClassName].METADATA.Specs then
SN2SID_table[universalClassName].METADATA.Specs = {};
SN2SID_table[universalClassName].METADATA.Specs[specName] = specID; -- Reference
SN2SID_table[universalClassName][specName] = {}; -- For "[SpellName] = SpellID"
elseif not SN2SID_table[universalClassName].METADATA.Specs[i] then
SN2SID_table[universalClassName].METADATA.Specs[specName] = specID; -- Reference
SN2SID_table[universalClassName][specName] = {}; -- For "[SpellName] = SpellID"
end
end
updateClassSpells = true; -- Do populate the actual list of spells.
end
if not SN2SID_PASSIVES_table[universalClassName].METADATA.Specs then
print(AddonName.. ": Will now create the ".. universalClassName.. "'s \'Specs\' (Passives) tables.");
for i = 1, ClassNumSpecs do
local specID, specName = GetSpecializationInfo(i);
-- ClassSpecNames2IDs[i] = { specID, specName };
ClassSpecNames2IDs[specName] = specID;
-- print(AddonName.. ": ".. i.. " = ".. specID.. " = ".. specName); -- For reference
if not SN2SID_PASSIVES_table[universalClassName].METADATA.Specs then
SN2SID_PASSIVES_table[universalClassName].METADATA.Specs = {};
SN2SID_PASSIVES_table[universalClassName].METADATA.Specs[specName] = specID; -- Ref.
SN2SID_PASSIVES_table[universalClassName][specName] = {}; -- "[SpellName] = SpellID"
elseif not SN2SID_PASSIVES_table[universalClassName].METADATA.Specs[i] then
SN2SID_PASSIVES_table[universalClassName].METADATA.Specs[specName] = specID; -- Ref.
SN2SID_PASSIVES_table[universalClassName][specName] = {}; -- "[SpellName] = SpellID"
end
end
updateClassSpells = true; -- Do populate the actual list of spells.
end
 
-- Update General (always ATM) and Class SpellNames2SIDs (both Actives and Passives) --
updateSpellbookSpells_func(SN2SID_table, SN2SID_PASSIVES_table, generalTabName, universalClassName, ClassNumSpecs, ClassSpecNames2IDs);
-- Pet spells will only be available when a pet is out, so wait for it, i.e. wait for UNIT_PET
-- to fire for "player".
 
 
-- Other Events' Handlers --
-- Set up Other Event-Handlers --
---------------------------------
 
function SN2SID_events:PLAYER_TALENT_UPDATE(self)
updateGeneralSpells = true; -- unneeded, in place for future version
-- updateGeneralSpells = true; -- unneeded, placeholder for future version
updateClassSpells = true;
updateSpellNames(universalClassName);
updateSpellbookSpells_func(SN2SID_table, SN2SID_PASSIVES_table, generalTabName, universalClassName, ClassNumSpecs, ClassSpecNames2IDs);
end
 
-- function SN2SID_events:PLAYER_LEVEL_UP(self, ...)
-- UnitLevel("player") doesn't update its result soon enough to have it
-- indicate the *new* char level in response to this event. OTH, this
-- event does provide arguments but,whatever they are, they're NOT the
-- new char leve, for sure. Pro'ly best just flag for update on Logout.
-- updateGeneralDataSource = true;
-- updateClassDataSource = true;
-- updateDataSource(generalTabName, universalClassName);
-- end
function SN2SID_events:PLAYER_LEVEL_UP(self, ...)
-- UnitLevel("player") doesn't update its result soon enough to have it indicate the *new*
-- char level in response to this event. OTH, this event does provide arguments but,
-- whatever they are, they're NOT the new char leve, for sure. Might be best to just flag
-- for update on Logout. But we'll still do it here, for now.
updateGeneralTabMetadata = true; -- Maybe useful.
updateClassMetadata = true; -- Stuff like talents only become available at level 10.
updateClassMetadata_func(SN2SID_table, SN2SID_PASSIVES_table, curLocale, gameBuild, universalClassName, charLevel);
updateGeneralTabMetadata = true; -- Maybe useful.
updateClassMetadata = true; -- Stuff like talents only become available at level 10.
end
 
-- Update pets' existence and spells when one comes up for "player"
function SN2SID_events:UNIT_PET(...)
local petOwner = ...;
if petOwner == "player" and HasPetSpells() then
print(AddonName.. ": Player has Pet with spells.");
if not SN2SID_table[universalClassName].Pet then
SN2SID_table[universalClassName].Pet = {};
-- NB: Fires after PLAYER_LOGIN if the player already has a pet out.
function SN2SID_events:UNIT_PET(self, ...)
-- print(AddonName.. ": UNIT_PET fired for player");
if not SN2SID_table[universalClassName].Pets then
SN2SID_table[universalClassName].Pets = {};
end
updatePetSpellNames(universalClassName);
end
if not SN2SID_PASSIVES_table[universalClassName].Pets then
SN2SID_PASSIVES_table[universalClassName].Pets = {};
end
updatePetSpellNames(SN2SID_table, SN2SID_PASSIVES_table, universalClassName);
end
 
-- Switch player's pet -- this isn't right
-- function SN2SID_events:PET_UI_UPDATE(self, ...)
-- local petOwner = ...;
-- if petOwner == "player" and HasPetSpells() then
-- -- if petOwner == "player" and HasPetSpells() then
-- if petOwner == "player" then
-- print(AddonName.. ": Player switched Pet.");
-- if not SN2SID_table[universalClassName].Pet then
-- SN2SID_table[universalClassName].Pet = {};
-- if not SN2SID_table[universalClassName].Pets then
-- SN2SID_table[universalClassName].Pets = {};
-- end
-- updatePetSpellNames(universalClassName);
-- updatePetSpellNames(SN2SID_table, SN2SID_PASSIVES_table, universalClassName);
-- end
-- end
--
-- I can't seem to find an event for Pet Talents change. Do an update on PLAYER_LOGOUT, for the
-- sake of trying to get something. Works for getting the last active pet...
-- EDIT: Maybe PET_UI_UPDATE will work if registered the same way as we do for UNIT_PET ? I.e.
-- use SN2SID_frame:RegisterUnitEvent instead of SN2SID_frame:RegisterEvent ...? TODO: Try!
 
-- I can't seem to find an event for Pet Talents change. Do an update on
-- PLAYER_LOGOUT, for the sake of trying to get something.
 
function SN2SID_events:PLAYER_LOGOUT(self)
-- Bring everything up to date
charLevel = UnitLevel("player");
updateGeneralDataSource = true;
updateClassDataSource = true;
updateDataSource(generalTabName, universalClassName);
if SN2SID_table[universalClassName].Pet then
updatePetSpellNames(universalClassName);
updateGeneralTabMetadata = true;
updateClassMetadata = true;
updateGeneralTabMetadata_func(SN2SID_table, SN2SID_PASSIVES_table, curLocale, gameBuild, universalRaceName, generalTabName, charLevel);
updateClassMetadata_func(SN2SID_table, SN2SID_PASSIVES_table, curLocale, gameBuild, universalClassName, charLevel);
updateSpellbookSpells_func(SN2SID_table, SN2SID_PASSIVES_table, generalTabName, universalClassName, ClassNumSpecs, ClassSpecNames2IDs);
-- NB: UNIT_PET fires upon summoning new pets; but NOT upon switching Hunters' Pet-Specs.
if SN2SID_table[universalClassName].Pets or SN2SID_PASSIVES_table[universalClassName].Pets then
updatePetSpellNames(SN2SID_table, SN2SID_PASSIVES_table, universalClassName);
end
 
-- Copy our local table to the global saved-variables table
-- Copy our local tables to the global saved-variables tables --
if AddonEnv.SpellNamesAndIDs then
AddonEnv.SpellNamesAndIDs = SN2SID_table;
else
SpellNamesAndIDs = SN2SID_table;
end
if AddonEnv.SpellNamesAndIDs_PASSIVES then
AddonEnv.SpellNamesAndIDs_PASSIVES = SN2SID_PASSIVES_table;
else
SpellNamesAndIDs_PASSIVES = SN2SID_PASSIVES_table;
end
end
 
SN2SID_frame:SetScript("OnEvent", nil); -- Not good enough? => Add test at
-- start of handler. ^
 
-- Unregister the event (handler) in which we are now running
SN2SID_frame:UnregisterEvent("PLAYER_LOGIN");
-- Set the post-PLAYER_LOGIN event-handlers and Register the respective events
SN2SID_frame:SetScript("OnEvent", function(self, event, ...)
SN2SID_events[event](self, ...);
end);
 
for k, v in pairs(SN2SID_events) do
SN2SID_frame:RegisterEvent(k);
if k == "UNIT_PET" then
SN2SID_frame:RegisterUnitEvent("UNIT_PET", "player");
else
SN2SID_frame:RegisterEvent(k);
end
end
end);
end
 
-- PLAYER_LOGIN event handler; we set up the other events when this one fires --
SN2SID_frame:SetScript("OnEvent", function(self, event)
C_Timer.After(3, lsn2sidpStartup);
end);
\ No newline at end of file