---------- |
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); |