WoWInterface SVN LibSpellName2SID

Compare Revisions

  • This comparison shows the changes necessary to convert path
    /
    from Rev 164 to Rev 165
    Reverse comparison

Rev 164 → Rev 165

populator/branches/LibSpellName2SID-Populator-1.1.06/LibSpellName2SID-1.1-Populator.toc New file
0,0 → 1,10
## Interface: 80200
## Title: LibSpellName2SID-1.1: Populator (DEV)
## Notes: Get all spells from a character and save them to file.
## Author: aallkkaa
## Version: 1.1.06
## SavedVariables: SpellNamesAndIDs, SpellNamesAndIDs_PASSIVES, DEBUG_messages, METAdata
## DefaultState: disabled
## X-Category: Development
 
LibSpellName2SID-1.1-Populator.lua
populator/branches/LibSpellName2SID-Populator-1.1.06/LibSpellName2SID-1.1-Populator.lua New file
0,0 → 1,2236
----------
-- (C) 2017-2019 by aallkkaa
-- http://www.wowinterface.com/forums/member.php?action=getinfo&userid=335646
--
-- LibSpellName2SID-1.1: Populator
-- Notes: Populates the library's database
-- http://svn.wowinterface.com/listing.php?repname=LibSpellName2ID&path=%2Fpopulator%2F#_populator_
----------
local AddonName, AddonEnv = ...;
 
-- Local copies of the saved variables' tables: SpellNamesAndIDs, SpellNamesAndIDs_PASSIVES, DEBUG_messages and METAdata
local SN2SID_table, SN2SID_PASSIVES_table, DEBUGmsgs, METADATA_table;
 
-- Variables for debugging
local DBG_CurrentEvent = "" -- Event last fired when a task is being done
 
-- WoW Expansion/Patch constants
local NumberOfTalentTiers = 7; -- Current number of talent tiers - WoW-7.x.y and 8.x.y
-- local NumberOfPVPTalentTiers = 6; -- Current number of PVP talent tiers - WoW-7.x.y
local NumberOfPVPTalentSlots = 4; -- Current number of PVP talent tiers - WoW-8.x.y
 
-- Metadata flags
local updateGeneralTabMetadata, updateClassMetadata = false, false;
 
-- (Usually) One-time fetched values
local generalTabName, universalRaceName, universalClassName;
local petFamily, petSpec;
 
-- Table for storing of dealyed-fetch spells' information (namely de subSpellName )
local delayedSpellsInfo_tbl = {
-- Id<number> = API_call,
};
 
-- "Manually" added/modified spells - normally AFTER regular update functions were called
local postUpdate_Spells2Add = {
["General"] = {
["AzeriteEssences"] = {
-- https://www.wowhead.com/guides/heart-of-azeroth-essence-overview#list-of-all-essences
["Heart Essence"] = 296208, -- Generic place-holder
-- Rank 1 --
-- Essences Used by All Roles
["Concentrated Flame"] = 295373,
["Worldvein Resonance"] = 295186,
["Reality Shift"] = 302916,
["Vision of Perfection"] = 296325,
["Memory of Lucid Dreams"] = 298357,
["Conflict"] = 303823,
-- Tank Essences
["Aegis of the Deep"] = 298168,
["Empowered Null Barrier"] = 295746,
["Suppressing Pulse"] = 293031,
["Azeroth's Undying Gift"] = 293019,
["Anima of Death"] = 294926,
-- Healer Essences
["Overcharge Mana"] = 296072,
["Refreshment"] = 296197,
["Standstill"] = 296094,
["Life-Binder's Invocation"] = 293032,
["Vitality Conduit"] = 296230,
},
["Racials"] = {
["VoidElf"] = {
-- ["Spatial Rift"] = 256948,
["Spatial Rift(Step 1)"] = 256948, -- Tear rift!
["Spatial Rift(Step 2)"] = 257040, -- Teleport!
},
},
["ZoneAbilities"] = {
-- TODO: Maybe a hooksecurefunc(ZoneAbilityFrame, "Show", function())?
-- Also check: /dump Enum.ZoneAbilityType
-- Dump: value=Enum.ZoneAbilityType
-- [1]={
-- Argus=2,
-- OrderHall=1,
-- Garrison=0
-- }
--
-- Draenor -- These are never added to the Spellbook
["Garrison Ability"] = 161691, -- Cast the Garrison/Outpost ability active on the zone
["Call to Arms"] = 161676, -- Shadowmoon Valley / Frostfire Ridge
["Champion's Honor"] = 164221, -- Gorgrond outpost
["Summon Mechashredder 5000"] = 164050, -- Gorgrond outpost
["Telaari Siege Engine"] = 160240, -- Nagrand
["Telaari Talbuk"] = 165803, -- Nagrand (Alliance)
["Frostwolf War Wolf"] = 164222, -- Nagrand (Horde)
["Home Away from Home"] = 168487, -- Spires of Arak
["Smuggling Run!"] = 170108, -- Spires of Arak
["Artillery Strike"] = 162075, -- Talador outpost
["Guardian Orb"] = 161767, -- Talador outpost
["Logging"] = 167895, -- Mark lumber for gathering in Draenor (requires logging camp)
-- Broken Isles
["Combat Ally"] = 211390,
-- Argus
["Vindicaar Matrix Crystal"] = 251463, -- Cast the one active of the other four
["Light's Judgment"] = 247427, -- Same name, different ID, than that of the Lightforged
-- Draenei Racial spell.
["Summon Lightforged Warframe"] = 250436,
["Fel Heart Bond"] = 248011, -- Passive workings? - tooltip says "Instant"
["Shroud of Arcane Echoes"] = 248779,
},
},
["DEATHKNIGHT"] = {
["Blood"] = {
["Corpse Exploder"] = 127344, -- Cosmetic ability learned from tome
},
["Frost"] = {
["Corpse Exploder"] = 127344, -- Cosmetic ability learned from tome
},
["Unholy"] = {
["Corpse Exploder"] = 127344, -- Cosmetic ability learned from tome
},
--[[
["Pets"] = {
["Ghoul"] = {
-- The spell "Dark Transformation" used to temporarily change the Ghoul's regular
-- abilities into different ones (different names and IDs). Dark Transformation is
-- still in the game and still modifies the Ghoul's abilities, but these changes are
-- now "rolled into" the Ghoul's standard abilities; the old different ones can still
-- be referenced by their old spell IDs, but no longer by their names (even though
-- GetSpellInfo()* does return the spell name if queried through its ID).
-- Bottomline: For the purpose of doing anything with using these spells' name as
-- arguments, they are no longer existent.
-- * C_Spell.DoesSpellExist(spellID) works for these spells, DoesSpellExist("spellName")
-- does not.
-- ["Sweeping Claws"] = 91778,
-- ["Monstrous Blow"] = 91797,
-- ["Shambling Rush"] = 91802,
-- ["Putrid Bulwark"] = 91837,
-- The regular spells:
["Claw"] = 47468,
["Gnaw"] = 47481,
["Leap"] = 47482,
["Huddle"] = 47484,
},
-- The Unholy spec talent "Sludge Belcher" which summoned an Abomination instead of a
-- Ghoul before 8.0.1 is no longer ingame. I.e. this type of DK pet is now gone.
-- ["Abomination"] = { -- If the talent 'Sludge Belcher' is taken, the Ghoul becomes an
-- -- 'Abomination' instead.
-- ["Cleaver"] = 212333,
-- ["Smash"] = 212336,
-- ["Hook"] = 212468,
-- ["Protective Bile"] = 212384,
-- -- 'Abomination' + 'Dark Transformation':
44 -- ["Vile Gas"] = 212338,
-- ["Gastric Bloat"] = 212383,
-- },
 
},
]]--
},
["DRUID"] = { -- The two different teleports + Abilities learned from Tomes
["Balance"] = {
-- The two different teleports
["Teleport: Moonglade"] = 18960, -- BEFORE the Legion Druid quest that gives:
["Dreamwalk"] = 193753, -- AFTER the Legion Druid quest: [98 - 110] To The Dreamgrove .
-- The Minimap ability "Track Humanoids" is NOT on the Spellbook. It does have a spell
-- ID that returns its name and all when passed as argument to GetSpellInfo(), but the
-- spell name itself is not recognized by GetSpellBookItemInfo(). Thus we will NOT add
-- it to our database.
-- ["Track Humanoids"] = 19883
-- Abilities learned from Tomes
["Charm Woodland Creature"] = 127757, -- Turn a critter into a minion for 1 hour
["Flap"] = 164862, -- Requires Moonkin Form; channeled, NO CD other than Global
["Stag Form"] = 210053, -- Proper shapeshift (unlike Treant?) == Ground Travel Form
-- ["Track Beasts"] = 210065, -- Cat Form only, can be simultaneous with "Track
-- Humanoids", but suffers from the same exact
-- not-in-Spellbook issue; hence excluded from the DB.
["Treant Form"] = 114282, -- Shapeshift form, appearance only (?); Reportedly randomly
-- switches position with Moonkin Form (WoW-7.0.2 in the
-- Stance Bar (relog and respec); unsure if fixed later on)
-- "Nature's Beacon" is a (Druid-only) TOY
},
["Feral"] = {
-- The two different teleports
["Teleport: Moonglade"] = 18960, -- BEFORE the Legion Druid quest that gives:
["Dreamwalk"] = 193753, -- AFTER the Legion Druid quest: [98 - 110] "To The Dreamgrove".
-- The Minimap ability "Track Humanoids" is NOT on the Spellbook. It does have a spell
-- ID that returns its name and all when passed as argument to GetSpellInfo(), but the
-- spell name itself is not recognized by GetSpellBookItemInfo(). Thus we will NOT add
-- it to our database.
-- ["Track Humanoids"] = 19883
-- Abilities learned from Tomes
["Charm Woodland Creature"] = 127757, -- Turn a critter into a minion for 1 hour
["Flap"] = 164862, -- Requires Moonkin Form; channeled, NO CD other than Global
["Stag Form"] = 210053, -- Proper shapeshift (unlike Treant?) == Ground Travel Form
-- ["Track Beasts"] = 210065, -- Cat Form only, can be simultaneous with "Track
-- Humanoids", but suffers from the same exact
-- not-in-Spellbook issue; hence excluded from the DB.
["Treant Form"] = 114282, -- Shapeshift form, appearance only (?); Reportedly randomly
-- switches position with Moonkin Form (WoW-7.0.2 in the
-- Stance Bar (relog and respec); unsure if fixed later on)
-- "Nature's Beacon" is a (Druid-only) TOY
},
["Guardian"] = {
-- The two different teleports
["Teleport: Moonglade"] = 18960, -- BEFORE the Legion Druid quest that gives:
["Dreamwalk"] = 193753, -- AFTER the Legion Druid quest: [98 - 110] "To The Dreamgrove".
-- The Minimap ability "Track Humanoids" is NOT on the Spellbook. It does have a spell
-- ID that returns its name and all when passed as argument to GetSpellInfo(), but the
-- spell name itself is not recognized by GetSpellBookItemInfo(). Thus we will NOT add
-- it to our database.
-- ["Track Humanoids"] = 19883
-- Abilities learned from Tomes
-- Abilities learned from Tomes
["Charm Woodland Creature"] = 127757, -- Turn a critter into a minion for 1 hour
["Flap"] = 164862, -- Requires Moonkin Form; channeled, NO CD other than Global
["Stag Form"] = 210053, -- Proper shapeshift (unlike Treant?) == Ground Travel Form
-- ["Track Beasts"] = 210065, -- Cat Form only, can be simultaneous with "Track
-- Humanoids", but suffers from the same exact
-- not-in-Spellbook issue; hence excluded from the DB.s
["Treant Form"] = 114282, -- Shapeshift form, appearance only (?); Reportedly randomly
-- switches position with Moonkin Form (WoW-7.0.2 in the
-- Stance Bar (relog and respec); unsure if fixed later on)
-- "Nature's Beacon" is a (Druid-only) TOY
},
["Restoration"] = {
-- The two different teleports
["Teleport: Moonglade"] = 18960, -- BEFORE the Legion Druid quest that gives:
["Dreamwalk"] = 193753, -- AFTER the Legion Druid quest: [98 - 110] "To The Dreamgrove".
-- The Minimap ability "Track Humanoids" is NOT on the Spellbook. It does have a spell
-- ID that returns its name and all when passed as argument to GetSpellInfo(), but the
-- spell name itself is not recognized by GetSpellBookItemInfo(). Thus we will NOT add
-- it to our database.
-- ["Track Humanoids"] = 19883
-- Abilities learned from Tomes
["Charm Woodland Creature"] = 127757, -- Turn a critter into a minion for 1 hour
["Flap"] = 164862, -- Requires Moonkin Form; channeled, NO CD other than Global
["Stag Form"] = 210053, -- Proper shapeshift (unlike Treant?) == Ground Travel Form
-- ["Track Beasts"] = 210065, -- Cat Form only, can be simultaneous with "Track
-- Humanoids", but suffers from the same exact
-- not-in-Spellbook issue; hence excluded from the DB.
["Treant Form"] = 114282, -- Shapeshift form, appearance only (?); Reportedly randomly
-- switches position with Moonkin Form (WoW-7.0.2 in the
-- Stance Bar (relog and respec); unsure if fixed later on)
-- "Nature's Beacon" is a (Druid-only) TOY
},
},
["HUNTER"] = {
["Beast Mastery"] = {
["Call Pet"] = 9,
["Pet Utility"] = 103,
},
["Marksmanship"] = {
["Call Pet"] = 9,
["Pet Utility"] = 103,
},
["Survival"] = {
["Call Pet"] = 9,
["Pet Utility"] = 103,
},
["FlyoutsTOGET"] = {
["Call Pet"] = 9,
["Pet Utility"] = 103,
},
["Pets"] = {
-- https://www.wowhead.com/battle-for-azeroth-hunter-pet-guide#hunter-pet-family-list-tenacity
["Ferocity"] = {
-- Some pets Bite, some pets Claw and some pets Smack
["Bite"] = 17253,
["Claw"] = 16827,
["Smack"] = 49966,
-- Specialization ability
["Primal Rage"] = 264667,
-- All Hunter pets (regardless of spec or family) have these two Basic abilities:
["Dash"] = 61684,
["Growl"] = 2649,
},
["Tenacity"] = {
-- - Some pets Bite, some pets Claw and some pets Smack
["Bite"] = 17253,
["Claw"] = 16827,
["Smack"] = 49966,
-- Specialization ability
["Survival of the Fittest"] = 272679,
-- All Hunter pets (regardless of spec or family) have these two Basic abilities:
["Dash"] = 61684,
["Growl"] = 2649,
},
["Cunning"] = {
-- - Some pets Bite, some pets Claw and some pets Smack
["Bite"] = 17253,
["Claw"] = 16827,
["Smack"] = 49966,
-- Specialization ability
["Master's Call"] = 53271,
-- All Hunter pets (regardless of spec or family) have these two Basic abilities:
["Dash"] = 61684,
["Growl"] = 2649,
},
-- We categorize Hunter Pet spells mainly by their specialiZations, but some pet
-- families also have Special abilites. And yes, same-name diff-ID spells do occur.
-- Spell types: Special, Bonus and Exotic
-- NB: The comment "8.x" bellow denotes I checked the pet on wowhead.com (or ingame)
-- during WoW 8.x, NOT that they were introduced only in WoW 8.x (though of course some
-- were).
["Basilisk"] = { -- 8.x
["Petrifying Gaze"] = 263841,
},
["Bat"] = { -- 8.x
["Sonic Blast"] = 264263,
},
["Bear"] = { -- 8.x
["Rest"] = 94019,
},
["Beetle"] = { -- 8.x
["Harden Carapace"] = 90339,
},
["Bird of Prey"] = { -- 8.x
["Talon Rend"] = 263852,
["Trick"] = 94022,
},
["Blood Beast"] = { -- 8.1
["Blood Bolt"] = 288962,
},
["Boar"] = { -- 8.x
["Bristle"] = 263869,
},
["Carrion Bird"] = { -- 8.x
["Bloody Screech"] = 24423,
},
["Cat"] = { -- 8.x
["Catlike Reflexes"] = 263892,
["Prowl"] = 24450,
},
["Chimaera"] = { -- 8.x
["Frost Breath"] = 54644,
["Froststorm Breath"] = 92380,
},
["Clefthoof"] = { -- 8.x
["Thick Hide"] = 160057,
["Blood of the Rhino"] = 280069,
},
["Core Hound"] = { -- 8.x
["Obsidian Skin"] = 263867,
["Molten Hide"] = 159788,
},
["Crab"] = { -- 8.x
["Pin"] = 50245,
},
["Crane"] = { -- 8.x
["Chi-Ji's Tranquility"] = 264028,
["Trick"] = 126259,
},
["Crocolisk"] = { -- 8.x
["Ankle Crack"] = 50433,
},
["Devilsaur"] = { -- 8.x
["Feast"] = 159953,
["Monstrous Bite"] = 54680,
},
["Direhorn"] = { -- 8.x
["Gore"] = 263861,
},
["Dog"] = { -- 8.x
["Lock Jaw"] = 263423,
},
["Dragonhawk"] ={ -- 8.x
["Dragon's Guile"] = 263887,
},
["Feathermane"] ={ -- 8.x
["Feather Flurry"] = 263916,
["Updraft"] = 160007,
},
["Fox"] = { -- 8.x
["Agile Reflexes"] = 160011,
["Play"] = 90347,
},
["Gorilla"] = { -- 8.x
["Silverback"] = 263939,
},
["Hydra"] = { -- 8.x
["Acid Bite"] = 263863,
},
["Hyena"] = { -- 8.x
["Infected Bite"] = 263853,
},
["Krolusk"] = { -- 8.x
["Bulwark"] = 279410,
},
["Lizard"] = { -- 8.x
["Grievous Bite"] = 279362,
},
["Mechanical"] = { -- 8.x
["Defense Matrix"] = 263868,
},
["Monkey"] = { -- 8.x
["Primal Agility"] = 160044,
},
["Moth"] = { -- 8.x
["Serenity Dust"] = 264055,
},
-- ["Nether Ray"] = { -- 8.x
["Ray"] = { -- "Nether Ray" got renamed to "Ray" in WoW 8.2.0
["Nether Shock"] = 264264,
},
["Oxen"] = { -- 8.x
["Niuzao's Fortitude"] = 264023,
},
["Pterrordax"] = { -- 8.x
["Ancient Hide"] = 279399,
["Updraft"] = 160007,
},
["Quilen"] = { -- 8.x
["Eternal Guardian"] = 267922,
["Stone Armor"] = 160049,
},
["Raptor"] = { -- 8.x
["Savage Rend"] = 263854,
},
["Ravager"] = { -- 8.x
["Ravage"] = 263857,
},
["Riverbeast"] = { -- 8.x
["Gruesome Bite"] = 160018,
},
["Rodent"] = { -- 8.x
["Gnaw"] = 263856,
["Rest"] = 126364,
},
-- ["Rylak"] = { -- Rylak have been merged into Chimaera in 8.x
-- ["Updraft"] = 160007,
-- },
["Scalehide"] = { -- 8.x
["Scale Shield"] = 263865,
},
["Scorpid"] = { -- 8.x
["Deadly Sting"] = 160060,
},
["Serpent"] = { -- 8.x
["Serpent's Swiftness"] = 263904,
},
["Shale Spider"] = { -- 8.x
["Solid Shell"] = 160063,
},
["Silithid"] = { -- 8.x
["Tendon Rip"] = 160065,
["Dune Strider"] = 280151,
},
["Spider"] = { -- 8.x
["Web Spray"] = 160067,
},
["Spirit Beast"] = { -- 8.x
["Spirit Shock"] = 264265,
["Spirit Mend"] = 90361,
["Spirit Walk"] = 90328,
},
["Sporebat"] = { -- 8.x
["Spore Cloud"] = 264056,
},
["Stag"] = { -- 8.x
["Nature's Grace"] = 264266,
},
["Tallstrider"] = { -- 8.x
["Dust Cloud"] = 50285,
},
["Toad"] = { -- 8.x
["Swarm of Flies"] = 279336,
},
["Turtle"] = { -- 8.x
["Shell Shield"] = 26064,
},
["Warp Stalker"] = { -- 8.x
["Warp Time"] = 35346,
},
["Wasp"] = { -- 8.x
["Toxic Sting"] = 263858,
},
["Water Strider"] = { -- 8.x
["Soothing Water"] = 264262,
["Surface Trot"] = 126311,
},
["Wind Serpent"] = { -- 8.x
["Winged Agility"] = 264360,
},
["Wolf"] = { -- 8.x
["Furious Bite"] = 263840,
},
["Worm"] = { -- 8.x
["Acid Spit"] = 263446,
["Burrow Attack"] = 93433,
},
},
},
["MAGE"] = {
["Arcane"] = {
["Polymorph Variants"] = 92,
},
["Fire"] = {
["Polymorph Variants"] = 92,
},
["Frost"] = {
["Polymorph Variants"] = 92,
},
["FlyoutsTOGET"] = {
["Polymorph Variants"] = 92,
},
["Flyouts"] = {
-- Polymorph Variants are now fetchable (all the ones currently ingame) from the game,
-- regardless of whether the Mage has them or not (all, some, one or even none).
-- BUT the Mage must have learned at least one Polymorph variant for us to fetch them
-- normally; otherwise the "Polymorph Variants" flyout-button does not appear in the
-- SpellBook.
-- However, you can pass the Flyout-button ("Polymorph Variants")'s Spell ID to
-- GetFlyoutSlotInfo(Flyout-SpellID, FlyoutSlot) and retrieve the variants even if the
-- character has learned none of them yet. The Spell Id for Polymorph Variants is: 92.
-- GetFlyoutSlotInfo() returns 5 values:
-- 1. SpellID
-- 2. SpellID again (same as in 1)
-- 3. Unknown boolean
-- 4. Spell name (e.g. "Polymorph")
-- 5. Unknown number (0 for the first two slots of GetFlyoutSlotInfo(92, FlyoutSlot)
-- Testing the above returned SpellID=61305 for GetFlyoutSlotInfo(92, 1).
-- GetSpellInfo(61305) on a Mage with NO Polymorph variants learned, returns the correct
-- information for Polymorph(Black Cat), as retrieved with this addon, on another
-- Mage with one Polymorph variant learned. GetFlyoutSlotInfo(92, 2) on the ignorant
-- Mage returns the spell ID for Polymorph(Monkey).
--[[
["Polymorph Variants"] = { -- Polymorph variants (including the default "Sheep") are
-- all called "Polymorph" but, like the Shaman Hex, these
-- spells do bear information about the variant's flavor
-- via GetSpellInfo(), on its 2nd return value (spell
-- "rank" / spell subname). This subname can be suffixed
-- onto the spell name to specify the variant, as in e.g.
-- "Polymorph(Sheep)". It can be passed as argument to
-- GetSpellInfo() as well as the console/macro "/cast"
-- command.
-- Since WoW 8.0.1, the 2nd return value is now no longer
-- guaranteed to be provided upon calling GetSpellInfo().
-- The value can however be retrieved via the new Spell
-- Mixin API (that was introduced with that patch), after a
-- delay. But the former use of"Polymorph(Sheep)" and etc
-- as argument to GetSpellInfo(), or the "/cast" command,
-- still works, with no need to explicitly use the new
-- Spell Mixin API, as it did before.
--
-- WoW build 29981 (8.1.5): The following were all fetched
-- fetched from the server:
["Polymorph(Black Cat)"] = 61305,
["Polymorph(Bumblebee)"] = 277792,
["Polymorph(Direhorn)"] = 277787,
["Polymorph(Monkey)"] = 161354,
["Polymorph(Peacock)"] = 161372,
["Polymorph(Penguin)"] = 161355,
["Polymorph(Pig)"] = 28272,
["Polymorph(Polar Bear Cub)"] = 161353,
["Polymorph(Porcupine)"] = 126819,
["Polymorph(Rabbit)"] = 61721,
["Polymorph(Serpent)"] = 61025,
["Polymorph(Turkey)"] = 61780,
["Polymorph(Turtle)"] = 28271,
},
]]--
-- The 'Portal: ' and 'Teleport: ' flyouts have (mostly) different destinations for
-- Alliance and for Horde Magi. Thus, we'll add them all here (incl. faction-shared):
["Portal"] = {
["Portal: Exodar"] = 32266, -- Alliance only
["Portal: Stonard"] = 49361, -- Horde only
["Portal: Undercity"] = 11418, -- Horde only
["Portal: Vale of Eternal Blossoms(Alliance)"] = 132620, -- Added: "(Alliance)"
["Portal: Vale of Eternal Blossoms(Horde)"] = 132626, -- Added: "(Horde)"
["Ancient Portal: Dalaran"] = 120146, -- Dalaran Crater (way ABOVE it! -> FALL!)
["Portal: Tol Barad(Alliance)"] = 88345, -- Added: "(Alliance)"
["Portal: Tol Barad(Horde)"] = 88346, -- Added: "(Horde)"
["Portal: Shattrath(Alliance)"] = 33691, -- Added: "(Alliance)"
["Portal: Shattrath(Horde)"] = 35717, -- Added: "(Horde)"
["Portal: Warspear"] = 176244, -- Horde only
["Portal: Theramore"] = 49360, -- Alliance only
["Portal: Thunder Bluff"] = 11420, -- Horde only
["Portal: Darnassus"] = 11419, -- Alliance only
["Portal: Silvermoon"] = 32267, -- Horde only
["Portal: Dalaran - Northrend"] = 53142,
["Portal: Stormwind"] = 10059, -- Alliance only
["Portal: Stormshield"] = 176246, -- Alliance only
["Portal: Dalaran - Broken Isles"] = 224871,
["Portal: Orgrimmar"] = 11417, -- Horde only
["Portal: Ironforge"] = 11416, -- Alliance only
["Portal: Dalaran - Broken Isles"] = 224871,
["Portal: Boralus"] = 281400, -- Alliance only
["Portal: Dazar'alor"] = 281402, -- Horde only
},
["Teleport"] = {
["Teleport: Vale of Eternal Blossoms(Alliance)"] = 132621, -- Added: "(Alliance)"
["Teleport: Vale of Eternal Blossoms(Horde)"] = 132627, -- Added: (Horde)
["Teleport: Dalaran - Northrend"] = 53140,
["Teleport: Shattrath(Alliance)"] = 33690, -- Added: "(Alliance)"
["Teleport: Shattrath(Horde)"] = 35715, -- Added: "(Horde)"
["Teleport: Stonard"] = 49358, -- Horde only
["Teleport: Stormshield"] = 176248, -- Alliance only
["Teleport: Darnassus"] = 3565, -- Alliance only
["Teleport: Dalaran - Broken Isles"] = 224869,
["Teleport: Stormwind"] = 3561, -- Alliance only
["Teleport: Hall of the Guardian"] = 193759, -- Mage Class Hall
["Teleport: Tol Barad(Alliance)"] = 88342, -- Added: "(Alliance)"
["Teleport: Tol Barad(Horde)"] = 88344, -- Added: "(Horde)"
["Teleport: Orgrimmar"] = 3567, -- Horde only
["Teleport: Ironforge"] = 3562, -- Alliance only
["Teleport: Warspear"] = 176242, -- Horde only
["Teleport: Theramore"] = 49359, -- Alliance only
["Teleport: Silvermoon"] = 32272, -- Horde only
["Teleport: Undercity"] = 3563, -- Horde only
["Ancient Teleport: Dalaran"] = 120145, -- Dalaran Crater (way ABOVE it! -> FALL!)
["Teleport: Exodar"] = 32271, -- Alliance only
["Teleport: Thunder Bluff"] = 3566, -- Horde only
["Teleport: Boralus"] = 281403, -- Alliance only
["Teleport: Dazar'alor"] = 281404, -- Horde only
},
},
-- Get the Pets spell from a high level Frost Mage instead
--[[
["Pets"] = {
["Water Elemental"] = { -- Frost specialization only
["Freeze"] = 33395,
["Waterbolt"] = 31707,
},
},
]]--
},
-- All Rogue Poisons are fetchable from the logged in character. The bellow is no longer needed.
["ROGUE"] = {
["Assassination"] = {
["Poisons"] = 66,
["Envenom"] = 32645, -- Replaces Eviscerate at level 36
["Eviscerate"] = 196819, -- Is replaced by Envenom at level 36
},
["Subtlety"] = {
["Poisons"] = 66,
},
["Outlaw"] = {
["Poisons"] = 66,
},
["FlyoutsTOGET"] = {
["Poisons"] = 66,
},
--[[
["Flyouts"] = {
["Poisons"] = { -- Since WoW 7.0, (I think) Assassintation specialization only. But, at
-- least on WoW 8.1.5, on the SpellBook of all three specializations.
["Agonizing Poison"] = 200802,
["Crippling Poison"] = 3408,
["Deadly Poison"] = 2823,
["Leeching Poison"] = 108211,
["Wound Poison"] = 8679,
},
},
]]--
},
["SHAMAN"] = {
["Elemental"] = {
["Bloodlust"] = 2825, -- Horde
["Heroism"] = 32182, -- Alliance
["Hex Variants"] = 106,
},
["Enhancement"] = {
["Bloodlust"] = 2825, -- Horde
["Heroism"] = 32182, -- Alliance
["Hex Variants"] = 106,
},
["Restoration"] = {
["Bloodlust"] = 2825, -- Horde
["Heroism"] = 32182, -- Alliance
["Hex Variants"] = 106,
},
-- Hex Variants are now fetchable (all the ones currently ingame) from the game,
-- regardless of whether the Shaman has them or not (all, some, one or even none).
-- BUT the Shaman must have learned at least one Hex variant for us to fetch them
-- normally; otherwise the "Hex Variants" flyout-button does not appear in the
-- SpellBook.
-- However, you can pass the Flyout-button ("Hex Variants")'s Spell ID to
-- GetFlyoutSlotInfo(Flyout-SpellID, FlyoutSlot) and retrieve the variants even if the
-- character has learned none of them yet. The Spell Id for Hex Variants is: 106.
-- GetFlyoutSlotInfo() returns 5 values:
-- 1. SpellID
-- 2. SpellID again (same as in 1)
-- 3. Unknown boolean
-- 4. Spell name (e.g. "Hex")
-- 5. Unknown number (0 for the first two slots of GetFlyoutSlotInfo(106, FlyoutSlot)
-- Testing the above returned SpellID=210873 for GetFlyoutSlotInfo(106, 1).
-- GetSpellInfo(210873) on a Shaman with NO Hex variants learned, returns the correct
-- information for Hex(Compy), as retrieved with this addon, on another Shaman with
-- some Hex variants learned. GetFlyoutSlotInfo(106, 2) on the ignorant Shaman returns
-- the spell ID for Hex(Cockroach).
["FlyoutsTOGET"] = {
["Hex Variants"] = 106,
},
--[[
["Flyouts"] = {
["Hex Variants"] = { -- Hex variants (including the default "Frog") are all
-- called "Hex" but, (since WoW 8.1.5 or earlier) like the
-- Mage Polymorph, these spells do bear information
-- about the variant's flavor via GetSpellInfo(), on its
-- 2nd return value (spell "rank" / spell subname). This
-- subname can be suffixed onto the spell name to specify
-- the variant, as in e.g. "Hex(Frog)". It can be passed as
-- argument to GetSpellInfo() as well as the console/macro
-- "/cast" command.
-- Since WoW 8.0.1, the 2nd return value is now no longer
-- guaranteed to be provided upon calling GetSpellInfo().
-- The value can however be retrieved via the new Spell
-- Mixin API (that was introduced with that patch), after a
-- delay. But the use of "Hex(Frog)" and etc as argument
-- to GetSpellInfo(), or the "/cast" command, still works,
-- with no need to explicitly use the new Spell Mixin API.
["Hex(Cockroach)"] = 211015,
["Hex(Compy)"] = 210873,
["Hex(Skeletal Hatchling)"] = 269352,
["Hex(Snake)"] = 211010,
["Hex(Spider)"] = 211004,
["Hex(Wicker Mongrel)"] = 277784, -- Alliance only
["Hex(Zandalari Tendonripper)"] = 277778, -- Horde only
},
},
]]--
["Pets"] = { -- In WoW 8.x.y, only the Elemental specialization has controllable pets,
-- and only if the talent "Primal Elementalist"(5,2) is active (they're guardians
-- (no spells castable by the player) otherwise). On top of that, although the
-- Earth Elemental is always available to all three Shaman specs, the Fire and
-- Storm elementals are mutually exclusive (Fire Elemental becomes Storm Elemental
-- if the talent "Storm Elemental" is chosen).
-- TL;DR: Better make sure the spells bellow are added, rather than going through
-- the gimmick of swithcing the talents every time we update the SHAMAN lists of
-- spells.
["Earth Elemental"] = {
["Angered Earth"] = 36213, -- Taunt
["Harden Skin"] = 118337, -- -40% damage taken by the Shaman
["Pulverize"] = 118345, -- Stun
},
["Fire Elemental"] = {
["Fire Blast"] = 57984,
["Immolate"] = 118297,
["Meteor"] = 117588,
},
["Storm Elemental"] = {
["Call Lightning"] = 157348,
["Eye of the Storm"] = 157375,
["Wind Gust"] = 157331,
},
},
},
["WARLOCK"] = {
["Affliction"] = {
["Summon Demon"] = 10,
},
["Demonology"] = {
["Summon Demon"] = 10,
},
["Destruction"] = {
["Summon Demon"] = 10,
},
["FlyoutsTOGET"] = {
["Summon Demon"] = 10,
},
["Pets"] = { -- Spells of the glyph-enhanced versions of the regular Warlock Demons.
-- NB: We're including spells that remain the same on both versions of the
-- demon.
["Fel Imp"] = {
["Felbolt"] = 115746, -- Fel Imp
["Sear Magic"] = 115276, -- Fel Imp
["Cauterize Master"] = 119905, -- Fel Imp & Imp
["Flee"] = 89792, -- Fel Imp & Imp
},
["Voidlord"] = {
["Void Shield"] = 115236, -- Voidlord
["Suffering"] = 119907, -- Voidlord & Voidwalker
["Consuming Shadows"] = 3716, -- Voidlord & Voidwalker
["Shadow Bulwark"] = 17767, -- Voidlord & Voidwalker
["Threatening Presence"] = 134477, -- Voidlord & Voidwalker
},
["Observer"] = {
["Optical Blast"] = 115781, -- Observer
["Tongue Lash"] = 115778, -- Observer
["Devour Magic"] = 19505, -- Observer & Felhunter
},
["Shivarra"] = {
["Bladedance"] = 115748, -- Shivarra
["Fellash"] = 115770, -- Shivarra
["Mesmerize"] = 115268, -- Shivarra
["Lesser Invisibility"] = 7870, -- Shivarra & Succubus
},
["Wrathguard"] = {
["Mortal Cleave"] = 115625, -- Wrathguard
["Wrathstorm"] = 115831, -- Wrathguard
["Axe Toss"] = 89766, -- Wrathguard & Felguard
["Pursuit"] = 30151, -- Wrathguard & Felguard
["Threatening Presence"] = 134477 -- Wrathguard & Felguard
},
},
},
["WARRIOR"] = {
["Protection"] = {
["Charge"] = 100, -- Replaced by Intercept at level 28
["Intercept"] = 198304, -- Replaces Charge at level 28
},
},
};
 
local postUpdate_Spells2Add_PASSIVES = {
["General"] = {
["AzeriteEssences"] = {
-- https://www.wowhead.com/guides/heart-of-azeroth-essence-overview#list-of-all-essences
-- Rank 1 --
-- Essences Used by All Roles
["Ancient Flame"] = 295365,
["Lifeblood"] = 295078,
["Ripple in Space"] = 302731,
["Strive for Perfection"] = 296320,
["Lucid Dreams"] = 298268,
["Strife"] = 304081,
-- Tank Essences
["Stand Your Ground"] = 298193,
["Null Barrier"] = 295750,
["Sphere of Suppression"] = 294910,
["Hardened Azerite"] = 294668,
["Anima of Life"] = 294964,
-- Healer Essences
["The Ever-Rising Tide"] = 296050,
["The Well of Existence"] = 296136,
["Artifice of Time"] = 296081,
["Seed of Eonar"] = 296207,
["Transference"] = 303448,
},
["Riding"] = {
["Draenor Pathfinder"] = 191645, -- One rank only -- Flying -- USABLE
["Apprentice Riding"] = 33388,
["Broken Isles Pathfinder(Rank 1)"] = 226342, -- +20% mounted speed -- USABLE
["Broken Isles Pathfinder(Rank 2)"] = 233368, -- Flying -- USABLE
["Broken Isles Pathfinder"] = 233368, -- Flying -- USABLE
["Expert Riding"] = 34090,
["Journeyman Riding"] = 33391,
["Artisan Riding"] = 34091,
["Master Riding"] = 90265,
["Battle for Azeroth Pathfinder"] = 281576, -- +20% mounted speed -- USABLE
["Battle for Azeroth Pathfinder(Rank 1)"] = 281576, -- +20% mounted speed -- USABLE
},
["ZoneAbilities"] = {
-- Draenor
["Dragoon"] = 169605,
["Swift Recovery"] = 169608,
["Trading Pact"] = 170200,
["Upgrades"] = 170733,
["Runes of Power"] = 178777,
},
},
--[[
-- NB: See reason to no longer be hardcoding this in the Active Spells section above.
["DEATHKNIGHT"] = {
["Pets"] = {
-- With talent 'Sludge Belcher':
["Ghoul"] = {
["Avoidance"] = 62137,
},
-- The Unholy spec talent "Sludge Belcher" which summoned an Abomination instead of a
-- Ghoul before 8.0.1 is no longer ingame.
-- ["Abomination"] = {
-- ["Avoidance"] = 62137,
-- },
},
},
]]--
["HUNTER"] = {
["Pets"] = {
-- NB: The comment "8.x" bellow denotes I checked the pet on wowhead.com (or ingame)
-- during WoW 8.x, NOT that they were introduced only in WoW 8.x (though of course some
-- were).
-- Specializations
["Ferocity"] = { -- 8.x
["Avoidance"] = 65220, -- Present on a lvl 14 Hunter
["Predator's Thirst"] = 264663, -- Present on a lvl 14 Hunter
},
["Tenacity"] = { -- 8.x
["Avoidance"] = 65220, -- Present on a lvl 14 Hunter
["Endurance Training"] = 264662, -- Present on a lvl 14 Hunter
},
["Cunning"] = { -- 8.x
["Avoidance"] = 65220, -- Present on a lvl 14 Hunter
["Pathfinding"] = 264656, -- Present on a lvl 14 Hunter
},
-- Families
["Bear"] = { -- 8.x
["Thick Fur"] = 263934,
},
["Gorilla"] = { -- 8.x
["Silverback"] = 263939,
},
["Krolusk"] = { -- 8.x
["Calcified Carapace"] = 279254,
},
["Shale Spider"] = { -- 8.x
["Shimmering Shale"] = 279259,
},
},
},
--[[
-- Easely fetchable from server, on a Frost Mage with the pet summoned
["MAGE"] = {
["Pets"] = {
["Water Elemental"] = { -- Frost specialization only
["Avoidance"] = 65220,
},
},
},
]]--
["WARLOCK"] = {
["Pets"] = { -- Spells of the glyph-enhanced versions of the regular Warlock Demons.
-- NB: We're including spells that remain the same on both versions.
["Fel Imp"] = {
["Avoidance"] = 32233, -- Fel Imp & Imp
},
["Voidlord"] = {
["Avoidance"] = 32233, -- Voidlord & Voidwalker
["Void Reflexes"] = 117225, -- Voidlord & Voidwalker
},
["Observer"] = {
["Avoidance"] = 32233, -- Observer & Felhunter
},
["Shivarra"] = {
["Avoidance"] = 32233, -- Shivarra & Succubus
},
["Wrathguard"] = {
["Avoidance"] = 32233, -- Wrathguard & Felguard
["Void Reflexes"] = 117225, -- Wrathguard & Felguard
},
},
},
};
 
 
-- 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(curLocale, gameBuild, charLevel)
tinsert(DEBUGmsgs[DBG_CurrentEvent], tostring(GetTime()).. ": updateGeneralTabMetadata_func: START");
tinsert(DEBUGmsgs[DBG_CurrentEvent], tostring(GetTime()).. ": Check whether GeneralTab\'s Metadata needs update");
-- print(AddonName.. ": Will now check whether the GeneralTab Metadata needs updating.");
if not updateGeneralTabMetadata then
-- print(AddonName.. ": GeneralTab\'s Metadata does NOT need update.");
tinsert(DEBUGmsgs[DBG_CurrentEvent], tostring(GetTime()).. ": GeneralTab\'s Metadata does NOT need update.");
tinsert(DEBUGmsgs[DBG_CurrentEvent], tostring(GetTime()).. ": updateGeneralTabMetadata_func: END");
return;
end
tinsert(DEBUGmsgs[DBG_CurrentEvent], "GeneralTab\'s Metadata DOES need update.");
-- Actively-cast spells
-- print(AddonName.. ": type(METADATA_table) = ".. tostring(type(METADATA_table)));
-- print(AddonName.. ": type(generalTabName) = ".. tostring(type(generalTabName)));
-- print(AddonName.. ": type(METADATA_table[generalTabName]) = ".. tostring(type(METADATA_table[generalTabName])));
if charLevel > METADATA_table[generalTabName].dataSource.charLevel then
METADATA_table[generalTabName].dataSource.charLevel = charLevel;
if charLevel > METADATA_table[generalTabName].dataSource.charMaxLevel then
METADATA_table[generalTabName].dataSource.charMaxLevel = charLevel;
end
updateGeneralSpells = true;
end
if gameBuild > METADATA_table[generalTabName].dataSource.gameBuild then
METADATA_table[generalTabName].dataSource.gameBuild = gameBuild;
-- Highest charLevel stored upon the most recent gameBuild
METADATA_table[generalTabName].dataSource.charLevel = charLevel;
-- Highest charLevel ever stored is kept in [...].charMaxLevel
updateGeneralSpells = true;
end
if not METADATA_table[generalTabName].raceBuilds then
METADATA_table[generalTabName].raceBuilds = { [universalRaceName] = gameBuild, };
elseif (not METADATA_table[generalTabName].raceBuilds[universalRaceName]) or
(gameBuild > METADATA_table[generalTabName].raceBuilds[universalRaceName]) then
METADATA_table[generalTabName].raceBuilds[universalRaceName] = gameBuild;
updateGeneralSpells = true;
end
updateGeneralTabMetadata = false;
tinsert(DEBUGmsgs[DBG_CurrentEvent], tostring(GetTime()).. ": updateGeneralTabMetadata_func: END");
end
 
-- Update the Class dataSource --
local updateClassMetadata_func = function(curLocale, gameBuild, charLevel)
tinsert(DEBUGmsgs[DBG_CurrentEvent], tostring(GetTime()).. ": updateClassMetadata_func: START");
tinsert(DEBUGmsgs[DBG_CurrentEvent], tostring(GetTime()).. ": Check whether ".. universalClassName.. "\'s Metadata needs update.");
-- print(AddonName.. ": Will now check whether the ".. universalClassName.. " Metadata needs updating.");
if not updateClassMetadata then
-- print(AddonName.. ": ".. universalClassName.. "\'s Metadata does NOT need update.");
tinsert(DEBUGmsgs[DBG_CurrentEvent], tostring(GetTime()).. ": ".. universalClassName.. "\'s Metadata does NOT need update.");
tinsert(DEBUGmsgs[DBG_CurrentEvent], tostring(GetTime()).. ": updateClassMetadata_func: END");
return;
end
-- print(AddonName.. ": ".. universalClassName.. "\'s Metadata DOES need update.");
tinsert(DEBUGmsgs[DBG_CurrentEvent], tostring(GetTime()).. ": ".. universalClassName.. "\'s Metadata DOES need update.");
if charLevel > METADATA_table[universalClassName].dataSource.charLevel then
METADATA_table[universalClassName].dataSource.charLevel = charLevel;
if charLevel > METADATA_table[universalClassName].dataSource.charMaxLevel then
METADATA_table[universalClassName].dataSource.charMaxLevel = charLevel;
end
updateClassSpells = true;
end
if gameBuild > METADATA_table[universalClassName].dataSource.gameBuild then
METADATA_table[universalClassName].dataSource.gameBuild = gameBuild;
METADATA_table[universalClassName].dataSource.charLevel = charLevel;
updateClassSpells = true;
end
updateClassMetadata = false;
tinsert(DEBUGmsgs[DBG_CurrentEvent], tostring(GetTime()).. ": updateClassMetadata_func: END");
end
 
 
---- Functions to update the lists of Spell Names and their IDs ----
--------------------------------------------------------------------
 
-- Update the PvE Talents' lists of spells
local updateTalentSpells_func = function(ClassNumSpecs)
tinsert(DEBUGmsgs[DBG_CurrentEvent], tostring(GetTime()).. ": updateTalentSpells_func: START");
if not updateClassSpells then -- Sanity check
-- print(AddonName.. ": Mo need to update the ".. universalClassName.. " PvE Talents.");
return;
end
 
for i = 1, ClassNumSpecs do
-- Create "SpecName_Talents" subtables if they doesn't exist yet
local specID, locSpecName = GetSpecializationInfo(i);
if locSpecName then -- Sanity check
-- print(AddonName.. ": PvE Talents: locSpecName = ".. locSpecName);
-- 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
else
-- print(AddonName.. ": PVE: NO specialization has been selected for this character!");
return;
end
-- Populate the "SpecName_Talents" subtables
for ii = 1, NumberOfTalentTiers do
for iii = 1, 3 do
local _, spellName, _, _, _, spellID, _, _, _, _, _ = GetTalentInfoBySpecialization(i, ii, iii);
if spellName then
if IsPassiveSpell(spellID) then
if SN2SID_PASSIVES_table[universalClassName][locSpecName.."_Talents"] then
SN2SID_PASSIVES_table[universalClassName][locSpecName.."_Talents"][spellName] = spellID;
else
SN2SID_PASSIVES_table[universalClassName][locSpecName.."_Talents"] = { [spellName] = spellID, };
end
else
if SN2SID_table[universalClassName][locSpecName.."_Talents"] then
SN2SID_table[universalClassName][locSpecName.."_Talents"][spellName] = spellID;
else
SN2SID_table[universalClassName][locSpecName.."_Talents"] = { [spellName] = spellID, };
end
end
end
end
end
-- NB: There is NO WAY to store a key-value pairs table of non-integer keys in ordered/
-- sorted mode in Lua.
-- At most, you could extract all keys and sort them in an array-like table (NO PAIRS!),
-- and then fetch the keys in order from that array-table and then the corresponding values
-- from another tab le (the original, unordered/unsorted key-value pairs table).
-- The function from https://wow.gamepedia.com/Orderedpairs gets you the ordered values
-- from the unordered table in running-time, but cannot be used to change the stored data,
-- just like the extract-keys-then-sort-them method above.
-- Thus, it's not possible to store the data in an easy to visually (or OS-based) diff two
-- versions of a database, as I wished.
end
tinsert(DEBUGmsgs[DBG_CurrentEvent], tostring(GetTime()).. ": updateTalentSpells_func: END");
end
 
-- Update the PvP Talents' lists of spells
local updatePVPTalentSpells_func = function(ClassNumSpecs)
tinsert(DEBUGmsgs[DBG_CurrentEvent], tostring(GetTime()).. ": updatePVPTalentSpells_func: START");
if not updateClassSpells then -- Sanity check
-- print(AddonName.. ": No need to update the ".. universalClassName.. " PvP Talents.");
return;
end
 
for i = 1, ClassNumSpecs do
-- Create "SpecName_PVPTalents" subtables if they don't exist yet
local specID, locSpecName = GetSpecializationInfo(i);
if locSpecName then -- Sanity check
-- print(AddonName.. ": PvP Talents: locSpecName = ".. locSpecName);
-- Actives
-- if not SN2SID_table[universalClassName][locSpecName.."_PVPTalents"] then
-- SN2SID_table[universalClassName][locSpecName.."_PVPTalents"] = {};
-- end
-- Passives
-- if not SN2SID_PASSIVES_table[universalClassName][locSpecName.."_PVPTalents"] then
-- SN2SID_PASSIVES_table[universalClassName][locSpecName.."_PVPTalents"] = {};
-- end
else
-- print(AddonName.. ": PVP: NO specialization has been selected for this character!");
return;
end
-- Populate the "SpecName_PVPTalents" subtables
-- TODO Review this "NumberOfPVPTalentSlots" thing
for ii = 1, NumberOfPVPTalentSlots do
local talentOptions = C_SpecializationInfo.GetPvpTalentSlotInfo(ii).availableTalentIDs;
for iii = 1, #talentOptions do
-- local _, spellName, _, _, _, spellID, _, _, _, _, _ = GetPvpTalentInfoBySpecialization(i, ii, iii);
local talentID = talentOptions[iii];
local _, spellName, _, _, _, spellID, _, _, _, _, _ = GetPvpTalentInfoByID(talentID);
-- print(AddonName.. ": PVPTalent spellName = ".. tostring(spellName));
if spellName then
if IsPassiveSpell(spellID) then
if SN2SID_PASSIVES_table[universalClassName][locSpecName.."_PVPTalents"] then
SN2SID_PASSIVES_table[universalClassName][locSpecName.."_PVPTalents"][spellName] = spellID;
else
SN2SID_PASSIVES_table[universalClassName][locSpecName.."_PVPTalents"] = { [spellName] = spellID, };
end
else
if SN2SID_table[universalClassName][locSpecName.."_PVPTalents"] then
SN2SID_table[universalClassName][locSpecName.."_PVPTalents"][spellName] = spellID;
else
SN2SID_table[universalClassName][locSpecName.."_PVPTalents"] = { [spellName] = spellID, };
end
end
end
end
end
end
tinsert(DEBUGmsgs[DBG_CurrentEvent], tostring(GetTime()).. ": updatePVPTalentSpells_func: END");
end
 
local armorSkills, weaponSkills;
-- Helper functions to function updateSpellbookSpells_func() --
local addSpellbookSpellToGeneral_func = function(spellName, spellSubName, spellID)
tinsert(DEBUGmsgs[DBG_CurrentEvent], tostring(GetTime()).. ": addSpellbookSpellToGeneral_func: START");
-- Store Passive and Active abilities into their own separate tables
if IsPassiveSpell(spellID) then
if spellName == "Armor Skills" then
armorSkills = spellID;
elseif spellName == "Weapon Skills" then
weaponSkills = spellID;
elseif strfind(spellName, "Riding") or strfind(spellName, "Pathfinder") then
if not SN2SID_PASSIVES_table[generalTabName].Riding then
SN2SID_PASSIVES_table[generalTabName].Riding = { [spellName] = spellID };
else
SN2SID_PASSIVES_table[generalTabName].Riding[spellName] = spellID;
end
-- NB: See "NB" for non-passive spells bellow
elseif spellSubName and strfind(spellSubName, "Racial") then
if not SN2SID_PASSIVES_table[generalTabName].Racials[universalRaceName] then
SN2SID_PASSIVES_table[generalTabName].Racials[universalRaceName] = { [spellName] = spellID };
else
SN2SID_PASSIVES_table[generalTabName].Racials[universalRaceName][spellName] = spellID;
end
elseif spellSubName and strfind(spellSubName, "Guild") then
if not SN2SID_PASSIVES_table[generalTabName].GuildPerks then
SN2SID_PASSIVES_table[generalTabName].GuildPerks = { [spellName] = spellID };
else
SN2SID_PASSIVES_table[generalTabName].GuildPerks[spellName] = spellID;
end
elseif spellSubName and strfind(spellSubName, "Azerite Essence") then
if not SN2SID_PASSIVES_table[generalTabName].AzeriteEssences then
SN2SID_PASSIVES_table[generalTabName].AzeriteEssences = { [spellName] = spellID };
else
SN2SID_PASSIVES_table[generalTabName].AzeriteEssences[spellName] = spellID;
end
-- Will now test for the hardcoded ZoneAbilities, to place them in the correct subcategory
elseif postUpdate_Spells2Add_PASSIVES.General.ZoneAbilities[spellName] then
if not SN2SID_table[generalTabName].ZoneAbilities then
SN2SID_PASSIVES_table[generalTabName].ZoneAbilities = { [spellName] = spellID };
else
SN2SID_PASSIVES_table[generalTabName].ZoneAbilities[spellName] = spellID;
end
-- All other spells go into the "Others" subcategory
elseif not SN2SID_PASSIVES_table[generalTabName].Others then
SN2SID_PASSIVES_table[generalTabName].Others = { [spellName] = spellID };
else
SN2SID_PASSIVES_table[generalTabName].Others[spellName] = spellID;
end
else
-- NB: There is at least one instance of a spell with the same name, but different IDs, that
-- is a Racial (that we fetch from the server) and also a hardcoded Zone ability: "Light's
-- Judgment".
if spellSubName and strfind(spellSubName, "Racial") then
if not SN2SID_table[generalTabName].Racials[universalRaceName] then
SN2SID_table[generalTabName].Racials[universalRaceName] = { [spellName] = spellID };
else
SN2SID_table[generalTabName].Racials[universalRaceName][spellName] = spellID;
end
elseif spellSubName and strfind(spellSubName, "Guild") then
if not SN2SID_table[generalTabName].GuildPerks then
SN2SID_table[generalTabName].GuildPerks = { [spellName] = spellID };
else
SN2SID_table[generalTabName].GuildPerks[spellName] = spellID;
end
elseif spellSubName and strfind(spellSubName, "Azerite Essence") then
if not SN2SID_table[generalTabName].AzeriteEssences then
SN2SID_table[generalTabName].AzeriteEssences = { [spellName] = spellID };
else
SN2SID_table[generalTabName].AzeriteEssences[spellName] = spellID;
end
-- Will now test for the hardcoded ZoneAbilities, to place them in the correct subcategory
elseif postUpdate_Spells2Add.General.ZoneAbilities[spellName] then
if not SN2SID_table[generalTabName].ZoneAbilities then
SN2SID_table[generalTabName].ZoneAbilities = { [spellName] = spellID };
else
SN2SID_table[generalTabName].ZoneAbilities[spellName] = spellID;
end
-- All other spells go into the "Others" subcategory
elseif not SN2SID_table[generalTabName].Others then
SN2SID_table[generalTabName].Others = { [spellName] = spellID };
else
SN2SID_table[generalTabName].Others[spellName] = spellID;
end
end
tinsert(DEBUGmsgs[DBG_CurrentEvent], tostring(GetTime()).. ": addSpellbookSpellToGeneral_func: END");
end
 
local addPolymorphOrHexFlyoutSpell_func = function(flyoutButton, flyoutSpellName, flyoutSpellSubname, flyoutSpellID)
tinsert(DEBUGmsgs[DBG_CurrentEvent], tostring(GetTime()).. ": addPolymorphOrHexFlyoutSpell_func: START");
local flyoutSpellFullName = flyoutSpellName.. "(".. flyoutSpellSubname.. ")";
if not SN2SID_table[universalClassName].Flyouts[flyoutButton][flyoutSpellFullName]
or SN2SID_table[universalClassName].Flyouts[flyoutButton][flyoutSpellFullName] ~= flyoutSpellID then
-- print(AddonName.. "Adding flyout spellFullName ".. flyoutSpellFullName.. " = ".. flyoutSpellID);
SN2SID_table[universalClassName].Flyouts[flyoutButton][flyoutSpellFullName] = flyoutSpellID;
end
tinsert(DEBUGmsgs[DBG_CurrentEvent], tostring(GetTime()).. ": addPolymorphOrHexFlyoutSpell_func: END");
end
 
local addFlyoutSpells_func = function(flyoutButtonName, flyoutButtonID)
tinsert(DEBUGmsgs[DBG_CurrentEvent], tostring(GetTime()).. ": addFlyoutSpells_func: START");
-- print(AddonName.. ": SpellID ".. flyoutButtonID.. " on SpecTab ".. i.. ", Pos ".. ii.. " is a FLYOUT button.");
-- NB: Creating SN2SID_table[universalClassName].Flyouts either via
-- SN2SID_table[universalClassName].Flyouts = []; or via
-- tinsert(SN2SID_table[universalClassName], "Flyouts"); was causing a bug where the same
-- table would have two "Flyouts" fields: one with the correct values and another empty
-- (as if it were a simple member of an array). So we create a STUB value if needed and
-- later remove it when we're done adding the spells.
if not SN2SID_table[universalClassName].Flyouts then
SN2SID_table[universalClassName].Flyouts = { ["STUB"] = 0, };
end
 
if (flyoutButtonName == "Portal") or (flyoutButtonName == "Teleport") then
-- There are spells with the same Name but different IDs, depending on the
-- character's faction, when it comes to Portals and Teleports. Hence, for now,
-- we add them only in Post. TODO: Fetch them here as well, but check that they
-- are not one of those (known) smae-name, diff-IDs cases (in that case do not add
-- them here, only in post).
else
-- Insert the flyout spell in its proper table
if not SN2SID_table[universalClassName].Flyouts[flyoutButtonName] then
-- print(AddonName.. ": Adding Flyouts.".. flyoutButtonName.. " to ".. universalClassName);
SN2SID_table[universalClassName].Flyouts[flyoutButtonName] = { ["STUB"] = 0, };
-- else
-- print(AddonName.. ": Flyouts.".. flyoutButtonName.. " is already in ".. universalClassName);
end
local _, _, numFlyouts, flyoutKnown = GetFlyoutInfo(flyoutButtonID);
-- print(AddonName.. ": ".. flyoutButtonName.. " | ".. flyoutButtonID.. " | Number of Slots = ".. numFlyouts);
for flyoutSlot = 1, numFlyouts do
-- local flyoutSpellID, overrideSpellID, flyoutSlotKnown, slotSpecID = GetFlyoutSlotInfo(flyoutButtonID, flyoutSlot);
local flyoutSpellID, _, _, _ = GetFlyoutSlotInfo(flyoutButtonID, flyoutSlot);
local flyoutSpellName, flyoutSpellSubname, _, _, _, _, _ = GetSpellInfo(flyoutSpellID);
if flyoutButtonName == "Polymorph Variants" or flyoutButtonName == "Hex Variants" then
-- Mage "Polymorph Variants", and Shaman "Hex Variants", are all called "Polymorph"
-- or "Hex", respectively. But they have a subname specifying the variant AND can
-- be addressed by suffixing the subname in parenthesis, as in e.g. "Polymorph
-- (Sheep)" or "Hex(Frog)". We'll do just that and store their names as "name
-- (subname)".
if (flyoutSpellSubname == nil) or (flyoutSpellSubname == "") then
-- print(AddonName.. ": ".. tostring(flyoutSpellName).. " = ".. tostring(flyoutSpellID));
-- Create an access to the info that will be fetched
delayedSpellsInfo_tbl["Id"..flyoutSpellID] = Spell:CreateFromSpellID(flyoutSpellID);
-- Actually get the info and use it to update our DB
delayedSpellsInfo_tbl["Id"..flyoutSpellID]:ContinueOnSpellLoad(function()
-- delayedSpellsInfo_tbl["Id"..flyoutSpellID]:ContinueOnSpellLoad(function(flyoutSpellID)
tinsert(DEBUGmsgs[DBG_CurrentEvent], tostring(GetTime()).. ": delayedFlyoutSpellInfo[Id".. flyoutSpellID.."]:ContinueOnSpellLoad: START");
-- print(AddonName.. ": Will now get the previously delayed information about flyoutSpellID: ".. flyoutSpellID);
-- Although we should only need to update spellSubName, we'll fetch a new
-- spellName + spellID by now. Thus, we'll update those fields too.
flyoutSpellName = delayedSpellsInfo_tbl["Id"..flyoutSpellID]:GetSpellName();
flyoutSpellSubname = delayedSpellsInfo_tbl["Id"..flyoutSpellID]:GetSpellSubtext(); -- NEEDED
flyoutSpellID = delayedSpellsInfo_tbl["Id"..flyoutSpellID]:GetSpellID();
-- Use the values above to add the spell
addPolymorphOrHexFlyoutSpell_func(flyoutButtonName, flyoutSpellName, flyoutSpellSubname, flyoutSpellID);
tinsert(DEBUGmsgs[DBG_CurrentEvent], tostring(GetTime()).. ": delayedFlyoutSpellInfo[Id".. flyoutSpellID.."]:ContinueOnSpellLoad: END");
-- Discard the no longer used delayed callback
delayedSpellsInfo_tbl["Id"..flyoutSpellID] = nil;
end);
else
-- print(AddonName.. ": ".. tostring(flyoutSpellName).. " = ".. tostring(flyoutSpellID));
addPolymorphOrHexFlyoutSpell_func(flyoutButtonName, flyoutSpellName, flyoutSpellSubname, flyoutSpellID);
end
-- Add the default Polymorph(Sheep) and Hex(Frog) to the spell lists -- NOT WORKING!! TODO: Fix!
if universalClassName == MAGE then
-- In case the regualr spell hasn't been added to the DB yet, add it:
if not (SN2SID_table.MAGE.Arcane["Polymorph"] and SN2SID_table.MAGE.Fire["Polymorph"] and SN2SID_table.MAGE.Frost["Polymorph"]) then
print(AddonName.. ": Adding \'Polymorph\' to the list of spells.");
local _, _, _, _, _, _, quickSpellID = GetSpellInfo("Polymorph");
SN2SID_table.MAGE.Arcane["Polymorph"] = quickSpellID;
SN2SID_table.MAGE.Fire["Polymorph"] = quickSpellID;
SN2SID_table.MAGE.Frost["Polymorph"] = quickSpellID;
end
SN2SID_table.MAGE.Arcane["Polymorph(Sheep)"] = SN2SID_table.MAGE.Arcane["Polymorph"] or nil;
SN2SID_table.MAGE.Fire["Polymorph(Sheep)"] = SN2SID_table.MAGE.Fire["Polymorph"] or nil;
SN2SID_table.MAGE.Frost["Polymorph(Sheep)"] = SN2SID_table.MAGE.Frost["Polymorph"] or nil;
end
if universalClassName == SHAMAN then
-- In case the regualr spell hasn't been added to the DB yet, add it:
if not (SN2SID_table.SHAMAN.Elemental["Hex"] and SN2SID_table.SHAMAN.Enhancement["Hex"] and SN2SID_table.SHAMAN.Restoration["Hex"]) then
print(AddonName.. ": Adding \'Hex\' to the list of spells.");
local _, _, _, _, _, _, quickSpellID = GetSpellInfo("Hex");
SN2SID_table.SHAMAN.Elemental["Hex"] = quickSpellID;
SN2SID_table.SHAMAN.Enhancement["Hex"] = quickSpellID;
SN2SID_table.SHAMAN.Restoration["Hex"] = quickSpellID;
end
SN2SID_table.SHAMAN.Elemental["Hex(Frog)"] = SN2SID_table.SHAMAN.Elemental["Hex"] or nil;
SN2SID_table.SHAMAN.Enhancement["Hex(Frog)"] = SN2SID_table.SHAMAN.Enhancement["Hex"] or nil;
SN2SID_table.SHAMAN.Restoration["Hex(Frog)"] = SN2SID_table.SHAMAN.Restoration["Hex"] or nil;
end
elseif flyoutSpellName and (not SN2SID_table[universalClassName].Flyouts[flyoutButtonName][flyoutSpellName])
or flyoutSpellName and (SN2SID_table[universalClassName].Flyouts[flyoutButtonName][flyoutSpellName] ~= flyoutSpellID) then
-- print(AddonName.. ": ".. tostring(flyoutSpellName).. " = ".. tostring(flyoutSpellID));
SN2SID_table[universalClassName].Flyouts[flyoutButtonName][flyoutSpellName] = flyoutSpellID;
end
end
-- Get rid of the STUB table member that was added upon its creation
SN2SID_table[universalClassName].Flyouts[flyoutButtonName]["STUB"] = nil;
end
-- Get rid of the STUB table member that was added upon its creation
SN2SID_table[universalClassName].Flyouts["STUB"] = nil;
tinsert(DEBUGmsgs[DBG_CurrentEvent], tostring(GetTime()).. ": addFlyoutSpells_func: END");
end
-- --
 
-- Update the Spellbook's GeneralTab and ClassTabs lists of spells
local updateSpellbookSpells_func = function(ClassNumSpecs)
tinsert(DEBUGmsgs[DBG_CurrentEvent], tostring(GetTime()).. ": updateSpellbookSpells_func: START");
-- "Armor Skills" and "Weapon Skills" are found on the Spellbook's General tab, but are indeed
-- different from one class to the other. Therefore, we'll save them into local variables upon
-- fetching the General tab spells and then insert them into the Class Specialisations' tables.
-- local armorSkills, weaponSkills;
 
-- General tab spells
-- if updateGeneralSpells then -- In current addon version, always true
-- print(AddonName.. ": Will now update the GeneralTab spells.");
local stubVal;
stubVal, universalRaceName = UnitRace("player");
if not SN2SID_table[generalTabName].Racials then
SN2SID_table[generalTabName].Racials = {};
end
if not SN2SID_PASSIVES_table[generalTabName].Racials then
SN2SID_PASSIVES_table[generalTabName].Racials = {};
end
if not SN2SID_PASSIVES_table[generalTabName].Riding then
SN2SID_PASSIVES_table[generalTabName].Riding = {};
end
if not SN2SID_table[generalTabName].GuildPerks then
SN2SID_table[generalTabName].GuildPerks = {};
end
if not SN2SID_PASSIVES_table[generalTabName].GuildPerks then
SN2SID_PASSIVES_table[generalTabName].GuildPerks = {};
end
if not SN2SID_table[generalTabName].AzeriteEssences then
SN2SID_table[generalTabName].AzeriteEssences = {};
end
-- if not SN2SID_PASSIVES_table[generalTabName].AzeriteEssences then
-- SN2SID_PASSIVES_table[generalTabName].AzeriteEssences = {};
-- end
if not SN2SID_table[generalTabName].Others then
SN2SID_table[generalTabName].Others = {};
end
if not SN2SID_PASSIVES_table[generalTabName].Others then
SN2SID_PASSIVES_table[generalTabName].Others = {};
end
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);
if spellName then
local _, spellID = GetSpellBookItemInfo(i, BOOKTYPE_SPELL);
if (spellSubName == nil) or (spellSubName == "") then
-- local delayedSpellInfo = Spell:CreateFromSpellID(spellID);
delayedSpellsInfo_tbl["Id"..spellID] = Spell:CreateFromSpellID(spellID);
-- I presume we don't actually need to cancel the request for the additional
-- information, i.e. presume once the information is given to us through the
-- function delayedSpellInfo:ContinueOnSpellLoad(), there will be no further
-- activity regarding this- But, just in case, we'll set up a function to
-- cancel the request after we got the information we need.
--
-- RESULT: The request-cancel function is being run BEFORE the requestFulfilled
-- one! But it's still storing the value NO PROB AT ALL! So, maybe we can just
-- do the whole add-spell-to-DB thing upon request cancelation? TODO: TRY IT!
--
-- FURTHER TESTING: Using only :ContinueWithCancelOnSpellLoad(), without
-- :ContinueOnSpellLoad(), does work. But the only spells added this way seem
-- to be spells that don't actually have a Spell Subname (with the eventual
-- exception of "Passive" spells). It would therefore seem we (usually?) get
-- every spell's subname from GetSpellBookItemName(). So, this test is not
-- conclusive. :-(
-- Better revert this to have both :ContinueWithCancelOnSpellLoad() and
-- ContinueOnSpellLoad() be run; ContinueOnSpellLoad() is run anyway after
-- ContinueWithCancelOnSpellLoad, so it should be alright... ?
--
-- MORE TESTING: With the 'Cache' folder and the saved variables' file deleted,
-- the results are the same (with calling only :ContinueWithCancelOnSpellLoad()
-- w/ no call to :ContinueOnSpellLoad() ). I will (again) revert to using both
-- functions, for the sake of safety.
--
-- ADENDA (from vague memory): :ContinueWithCancelOnSpellLoad() was causing some
-- problem (I can't remember what) and its removal had no ill effects.
--
-- local spellDataLoadedCancelFunc = delayedSpellInfo:ContinueWithCancelOnSpellLoad(function()
-- We don't need to do anything upon canceling the request
-- print(AddonName.. ": Now cancelling the request for delayed information about spell ID: ".. spellID);
-- end);
-- Actually get the information and use it to update our database:
delayedSpellsInfo_tbl["Id"..spellID]:ContinueOnSpellLoad(function()
-- delayedSpellsInfo_tbl["Id"..spellID]:ContinueOnSpellLoad(function(spellID)
tinsert(DEBUGmsgs[DBG_CurrentEvent], tostring(GetTime()).. ": delayedSpellInfo[Id".. spellID.."]:ContinueOnSpellLoad: START");
-- print(AddonName.. ": Will now get the previously delayed information about spell ID: ".. spellID);
-- -- Although we should only need to update spellSubName, we'll fetch a new
-- spellName + spellID by now. Thus, we'll update those fields too.
spellName = delayedSpellsInfo_tbl["Id"..spellID]:GetSpellName();
spellSubName = delayedSpellsInfo_tbl["Id"..spellID]:GetSpellSubtext(); -- Mandatory
spellID = delayedSpellsInfo_tbl["Id"..spellID]:GetSpellID();
-- Use the values above to add the spell
addSpellbookSpellToGeneral_func(spellName, spellSubName, spellID);
tinsert(DEBUGmsgs[DBG_CurrentEvent], tostring(GetTime()).. ": delayedSpellInfo[Id".. spellID.."]:ContinueOnSpellLoad: END");
-- Discard the no longer used delayed callback
delayedSpellsInfo_tbl["Id"..spellID] = nil;
end);
else
addSpellbookSpellToGeneral_func(spellName, spellSubName, spellID);
end
end
end
-- end
 
-- Class spells
-- if updateClassSpells then
-- print(AddonName.. ": Will now update the "..universalClassName .." spells.");
updateTalentSpells_func(ClassNumSpecs);
updatePVPTalentSpells_func(ClassNumSpecs);
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
-- print(AddonName.. ": numEntries = ".. numEntries);
for ii = offset +1, offset +numEntries do
-- local spellName, spellSubName = GetSpellBookItemName(ii, BOOKTYPE_SPELL);
local spellName = (GetSpellBookItemName(ii, BOOKTYPE_SPELL));
-- We actually don't use spellSubName on the population of the Class-spells list
-- (or at least currently we don't) ; thus we don't need to use the SpellMixin
-- API to retrieve it later; I.e. in this for loop, spellSubName is a stub val.
if spellName then
local spellType, spellID = GetSpellBookItemInfo(ii, BOOKTYPE_SPELL);
-- Store Passive and Active abilities into their own separate tables IF they
-- are not already stored in the respective Talents' tables.
if IsPassiveSpell(spellID) and ((not SN2SID_PASSIVES_table[universalClassName][locSpecName.."_Talents"])
or (not SN2SID_PASSIVES_table[universalClassName][locSpecName.."_Talents"][spellName])) then
-- print(AddonName.. ": Will add Passive: ".. spellName.. " / ID: ".. spellID);
if not SN2SID_PASSIVES_table[universalClassName][locSpecName] then
SN2SID_PASSIVES_table[universalClassName][locSpecName] ={ [spellName] = spellID, };
else
SN2SID_PASSIVES_table[universalClassName][locSpecName][spellName] = spellID;
end
elseif (not SN2SID_table[universalClassName][locSpecName.."_Talents"])
or (not SN2SID_table[universalClassName][locSpecName.."_Talents"][spellName]) then
-- print(AddonName.. ": Will add: ".. spellName.. " / ID: ".. spellID);
if not SN2SID_table[universalClassName][locSpecName] then
SN2SID_table[universalClassName][locSpecName] = { [spellName] = spellID, };
else
SN2SID_table[universalClassName][locSpecName][spellName] = spellID;
end
end
-- If it's a Flyout type of button (e.g. Mage Polymorph variants, Hunter Pet
-- Utility spells, etc), then fetch the spells that ... fly out.
if spellType == "FLYOUT" then
addFlyoutSpells_func(spellName, spellID);
end
end
end
SN2SID_PASSIVES_table[universalClassName][locSpecName]["Armor Skills"] = armorSkills;
-- print(AddonName.. ": Added Armor Skills = ".. armorSkills);
SN2SID_PASSIVES_table[universalClassName][locSpecName]["Weapon Skills"] = weaponSkills;
-- print(AddonName.. ": Added Weapon Skills = ".. weaponSkills);
end
end
updateClassSpells = false;
-- end
tinsert(DEBUGmsgs[DBG_CurrentEvent], tostring(GetTime()).. ": updateSpellbookSpells_func: END");
end
 
 
-- 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?
 
-- Add one Pet Spell to the apropriate subtable
local addSpellbookPetSpell_func = function(spellName, spellSubName, spellID)
tinsert(DEBUGmsgs[DBG_CurrentEvent], tostring(GetTime()).. ": addSpellbookPetSpell_func: START");
local isPassive = IsPassiveSpell(spellID);
if strfind(spellSubName, "Special") or strfind(spellSubName, "Bonus") or strfind(spellSubName, "Exotic") then -- Pet Family ability
if isPassive then
-- print(AddonName.. ": Add ".. petFamily.. " Passive : ".. spellName);
if not SN2SID_PASSIVES_table[universalClassName].Pets[petFamily] then
SN2SID_PASSIVES_table[universalClassName].Pets[petFamily] = { [spellName] = spellID, };
else
SN2SID_PASSIVES_table[universalClassName].Pets[petFamily][spellName] = spellID;
end
else
-- print(AddonName.. ": Add ".. petFamily.. " : ".. spellName);
if not SN2SID_table[universalClassName].Pets[petFamily] then
SN2SID_table[universalClassName].Pets[petFamily] = { [spellName] = spellID, };
else
SN2SID_table[universalClassName].Pets[petFamily][spellName] = spellID;
end
end
 
elseif strfind(spellSubName, "Basic") or ((not isPassive) and not
(strfind(spellSubName, "Ferocity") or strfind(spellSubName, "Tenacity")
or strfind(spellSubName, "Cunning"))) then -- All three Pet Specializations
-- print(AddonName.. ": Add All Specs : ".. spellName);
if not SN2SID_table[universalClassName].Pets["Ferocity"] then
SN2SID_table[universalClassName].Pets["Ferocity"] = { [spellName] = spellID, };
else
SN2SID_table[universalClassName].Pets["Ferocity"][spellName] = spellID;
end
if not SN2SID_table[universalClassName].Pets["Tenacity"] then
SN2SID_table[universalClassName].Pets["Tenacity"] = { [spellName] = spellID, };
else
SN2SID_table[universalClassName].Pets["Tenacity"][spellName] = spellID;
end
if not SN2SID_table[universalClassName].Pets["Cunning"] then
SN2SID_table[universalClassName].Pets["Cunning"] = { [spellName] = spellID, };
else
SN2SID_table[universalClassName].Pets["Cunning"][spellName] = spellID;
end
elseif isPassive and (not (strfind(spellSubName, "Ferocity") or strfind(spellSubName, "Tenacity")
or strfind(spellSubName, "Cunning"))) then
-- print(AddonName.. ": Add All Specs Passive : ".. spellName);
if not SN2SID_PASSIVES_table[universalClassName].Pets["Ferocity"] then
SN2SID_PASSIVES_table[universalClassName].Pets["Ferocity"] = { [spellName] = spellID, };
else
SN2SID_PASSIVES_table[universalClassName].Pets["Ferocity"][spellName] = spellID;
end
if not SN2SID_PASSIVES_table[universalClassName].Pets["Tenacity"] then
SN2SID_PASSIVES_table[universalClassName].Pets["Tenacity"] = { [spellName] = spellID, };
else
SN2SID_PASSIVES_table[universalClassName].Pets["Tenacity"][spellName] = spellID;
end
if not SN2SID_PASSIVES_table[universalClassName].Pets["Cunning"] then
SN2SID_PASSIVES_table[universalClassName].Pets["Cunning"] = { [spellName] = spellID, };
else
SN2SID_PASSIVES_table[universalClassName].Pets["Cunning"][spellName] = spellID;
end
else
if strfind(spellSubName, "Ferocity") then -- Ferocity
if isPassive then
-- print(AddonName.. ": Add Ferocity Passive : ".. spellName);
if not SN2SID_PASSIVES_table[universalClassName].Pets["Ferocity"] then
SN2SID_PASSIVES_table[universalClassName].Pets["Ferocity"] = { [spellName] = spellID, };
else
SN2SID_PASSIVES_table[universalClassName].Pets["Ferocity"][spellName] = spellID;
end
else
-- print(AddonName.. ": Add Ferocity : ".. spellName);
if not SN2SID_table[universalClassName].Pets["Ferocity"] then
SN2SID_table[universalClassName].Pets["Ferocity"] = { [spellName] = spellID, };
else
SN2SID_table[universalClassName].Pets["Ferocity"][spellName] = spellID;
end
end
elseif strfind(spellSubName, "Tenacity") then -- Tenacity
if isPassive then
-- print(AddonName.. ": Add Tenacity Passive : ".. spellName);
if not SN2SID_PASSIVES_table[universalClassName].Pets["Tenacity"] then
SN2SID_PASSIVES_table[universalClassName].Pets["Tenacity"] = { [spellName] = spellID, };
else
SN2SID_PASSIVES_table[universalClassName].Pets["Tenacity"][spellName] = spellID;
end
else
-- print(AddonName.. ": Add Tenacity : ".. spellName);
if not SN2SID_table[universalClassName].Pets["Tenacity"] then
SN2SID_table[universalClassName].Pets["Tenacity"] = { [spellName] = spellID, };
else
SN2SID_table[universalClassName].Pets["Tenacity"][spellName] = spellID;
end
end
elseif strfind(spellSubName, "Cunning") then -- Cunning
if isPassive then
-- print(AddonName.. ": Add Cunning Passive : ".. spellName);
if not SN2SID_PASSIVES_table[universalClassName].Pets["Cunning"] then
SN2SID_PASSIVES_table[universalClassName].Pets["Cunning"] = { [spellName] = spellID, };
else
SN2SID_PASSIVES_table[universalClassName].Pets["Cunning"][spellName] = spellID;
end
else
-- print(AddonName.. ": Add Cunning : ".. spellName);
if not SN2SID_table[universalClassName].Pets["Cunning"] then
SN2SID_table[universalClassName].Pets["Cunning"] = { [spellName] = spellID, };
else
SN2SID_table[universalClassName].Pets["Cunning"][spellName] = spellID;
end
end
end
end
tinsert(DEBUGmsgs[DBG_CurrentEvent], tostring(GetTime()).. ": addSpellbookPetSpell_func: END");
end
 
-- Pet Spells update function
local updatePetSpellNames = function()
tinsert(DEBUGmsgs[DBG_CurrentEvent], tostring(GetTime()).. ": updatePetSpellNames: START");
-- 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.
 
-- local petName = GetUnitName("pet", nil);
-- local petFamily = UnitCreatureFamily("pet");
petFamily = UnitCreatureFamily("pet");
if (not petFamily) or (petFamily == "") then -- First time UNIT_PET fires, the info on the Pet hasn't been loaded yet
tinsert(DEBUGmsgs[DBG_CurrentEvent], tostring(GetTime()).. ": Pet's family is n/a. Will not get any Pet spells.");
tinsert(DEBUGmsgs[DBG_CurrentEvent], tostring(GetTime()).. ": updatePetSpellNames: END");
return; -- UNIT_PET fires two to three times when a new pet is summoned.
end
-- print(AddonName.. ": Pet Family = ".. tostring(petFamily));
 
if not SN2SID_table[universalClassName].Pets then
SN2SID_table[universalClassName].Pets = {};
end
if not SN2SID_PASSIVES_table[universalClassName].Pets then
SN2SID_PASSIVES_table[universalClassName].Pets = {};
end
 
local _, isHunterPet = HasPetUI();
if isHunterPet then -- Hunter Pets, unlike all others, have specializations, thus we'll handle
-- their spells differently
local curPetSpecIndex = GetSpecialization(false, true);
local stubVal;
stubVal, petSpec = GetSpecializationInfo(curPetSpecIndex or 1, false, true);
-- print(AddonName.. ": Pet Spec #".. tostring(curPetSpecIndex).. "; Pet Family: ".. tostring(petFamily));
 
-- 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. Hunters and Warlocks under Level 10.
-- print(AddonName.. ": Getting SBook spells for pet: ".. petFamily);
local i = 0;
repeat
i = i + 1;
local spellName, spellSubName = GetSpellBookItemName(i, BOOKTYPE_PET);
-- print(AddonName.. ": Book: ".. tostring(spellName).. " ; ".. tostring(spellSubName));
if spellName then
-- No isToken flag from GetPetActionInfo() here, so do the check ourselves
local isToken = false;
if PetSpellNameExclusions[spellName] then
isToken = true;
end
if not isToken then
local _, _, _, _, _, _, spellID = GetSpellInfo(spellName);
-- local isPassive = IsPassiveSpell(spellID);
if spellID then -- Sanity check
-- NEW for 1.0.14 --
if (not spellSubName) or (spellSubName == "") then
delayedSpellsInfo_tbl["Id"..spellID] = Spell:CreateFromSpellID(spellID);
-- Actually get the information and use it to update our database:
-- delayedSpellInfo:ContinueOnSpellLoad(function()
delayedSpellsInfo_tbl["Id"..spellID]:ContinueOnSpellLoad(function()
-- delayedSpellsInfo_tbl["Id"..spellID]:ContinueOnSpellLoad(function(spellID)
tinsert(DEBUGmsgs[DBG_CurrentEvent], tostring(GetTime()).. ": delayedSpellInfo[Id".. spellID.."]:ContinueOnSpellLoad: START");
-- print(AddonName.. ": Will now get the previously delayed information about spell ID: ".. spellID);
-- Although we should only need to update spellSubName, we'll
-- get spellName and spellID too.
spellName = delayedSpellsInfo_tbl["Id"..spellID]:GetSpellName();
spellSubName = delayedSpellsInfo_tbl["Id"..spellID]:GetSpellSubtext(); -- Mandatory
spellID = delayedSpellsInfo_tbl["Id"..spellID]:GetSpellID();
addSpellbookPetSpell_func(spellName, spellSubName, spellID);
tinsert(DEBUGmsgs[DBG_CurrentEvent], tostring(GetTime()).. ": delayedSpellInfo[Id".. spellID.."]:ContinueOnSpellLoad: END");
-- Discard the no longer used delayed callback
delayedSpellsInfo_tbl["Id"..spellID] = nil;
end);
else
addSpellbookPetSpell_func(spellName, spellSubName, spellID);
end
-- --
-- else
-- print(AddonName.. ": Pet spell #".. i.. ": NO ID!");
end
-- else
-- print(AddonName.. ": Pet spell #".. i.." is a token.");
end
end
until spellName == nil;
-- petHasSpellsConfirmed = true;
end
 
-- GetSpellBookItemName(SpellbookIndex, BOOKTYPE_PET) + GetSpellInfo(spellName) --
elseif HasPetSpells() then -- I.e. whether there is a Pet Spellbook. WARNING: Will return TRUE
-- for all characters whose classes have pets, regardless of
-- whether or not the character's level is high enough to have
-- control over them; e.g. TRUE for Warlocks under Level 10.
-- print(AddonName.. ": Getting SBook spells for pet: ".. petFamily);
local i = 0;
repeat
i = i + 1;
-- local spellName, spellSubName = GetSpellBookItemName(i, BOOKTYPE_PET);
local spellName = (GetSpellBookItemName(i, BOOKTYPE_PET));
-- NB: We don't actually use the value of 'spellSubName' within the current scope;
-- the value is a stub. Thus there is no need to use the SpellMixin API here.
-- print(AddonName.. ": Book: ".. tostring(spellName));
if spellName then
local isToken = false;
if PetSpellNameExclusions[spellName] then
isToken = true;
end
if not isToken then
-- local _, spellID = GetSpellBookItemInfo(i, BOOKTYPE_PET);
local _, _, _, _, _, _, spellID = GetSpellInfo(spellName);
if spellID then -- Sanity check
if IsPassiveSpell(spellID) then
if not SN2SID_PASSIVES_table[universalClassName].Pets[petFamily] then
SN2SID_PASSIVES_table[universalClassName].Pets[petFamily] = { [spellName] = spellID, };
else
SN2SID_PASSIVES_table[universalClassName].Pets[petFamily][spellName] = spellID;
end
else
if not SN2SID_table[universalClassName].Pets[petFamily] then
SN2SID_table[universalClassName].Pets[petFamily] = { [spellName] = spellID, };
else
SN2SID_table[universalClassName].Pets[petFamily][spellName] = spellID;
end
end
end
end
end
until spellName == nil;
-- petHasSpellsConfirmed = true;
end
 
-- GetPetActionInfo(buttonNumber) + GetSpellInfo(spellName) --
if (not isHunterPet) and PetHasActionBar() then -- As all controllable pets are marked to have. 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 1 if a PetActionBar actually
-- should be shown (but regardless of the result of :IsShown).
-- print(AddonName.. ": Getting ABar spells for pet: ".. petFamily);
for i = 1, NUM_PET_ACTION_SLOTS do
-- local spellName, spellSubName, _, isToken, _, _, _ = GetPetActionInfo(i);
local spellName, _, _, isToken, _, _, _ = GetPetActionInfo(i);
-- NB: We don't actually use the value of 'spellSubName' within the current scope;
-- the value is a stub. Thus there is no need to use the SpellMixin API here.
-- print(AddonName.. ": BarButton".. i..": ".. tostring(spellName));
if spellName and (not isToken) then
local _, _, _, _, _, _, spellID = GetSpellInfo(spellName);
if spellID then -- Sanity check
if IsPassiveSpell(spellID) then
if not SN2SID_PASSIVES_table[universalClassName].Pets[petFamily] then
SN2SID_PASSIVES_table[universalClassName].Pets[petFamily] = { [spellName] = spellID, };
else
SN2SID_PASSIVES_table[universalClassName].Pets[petFamily][spellName] = spellID;
end
else
if not SN2SID_table[universalClassName].Pets[petFamily] then
SN2SID_table[universalClassName].Pets[petFamily] = { [spellName] = spellID, };
else
SN2SID_table[universalClassName].Pets[petFamily][spellName] = spellID;
end
end
end
end
end
-- petHasSpellsConfirmed = true;
end
-- print(AddonName.. ": Fetched? ".. tostring(petHasSpellsConfirmed));
tinsert(DEBUGmsgs[DBG_CurrentEvent], tostring(GetTime()).. ": updatePetSpellNames: END");
end
 
 
local addSpellsPostUpdate_func = function()
tinsert(DEBUGmsgs[DBG_CurrentEvent], tostring(GetTime()).. ": addSpellsPostUpdate_func: START");
if postUpdate_Spells2Add and SN2SID_table then -- Sanity check
for key, value in pairs(postUpdate_Spells2Add) do
if key == "General" or key == universalClassName then -- Only add hardcoded spells for
-- GeneralTab or Current Class
for keyk, valuev in pairs(value) do
if keyk == "FlyoutsTOGET" then
-- print(AddonName.. ": Will get flyout spells for FlyoutButtonName ".. keykk.. " with ID ".. valuevv);
for keykk, valuevv in pairs(valuev) do
addFlyoutSpells_func(keykk, valuevv);
end
elseif not SN2SID_table[key][keyk] then -- specName(..somethingMaybe)
-- OR "FlyoutsTOGET" OR
-- "Flyouts" OR "Pets" OR
-- someGeneralTabCategory.
-- print(AddonName.. ": Adding: ".. tostring(valuev));
SN2SID_table[key][keyk] = valuev;
elseif type(valuev) == "table" then
for keykk, valuevv in pairs(valuev) do
if not SN2SID_table[key][keyk][keykk] then -- Spell OR Flyouts_spell OR
-- PetFamily is not on the
-- target table yet
-- print(AddonName.. ": Adding: ".. tostring(valuevv));
SN2SID_table[key][keyk][keykk] = valuevv;
end
if type(valuevv) == "table" then -- Flyouts_spell OR PetFamily
for keykkk, valuevvv in pairs(valuevv) do
if not SN2SID_table[key][keyk][keykk][keykkk] then
-- Flyouts_spell_Spell OR
-- PetFamily_spell is not
-- yet on the table.
-- print(AddonName.. ": Adding: ".. tostring(valuevvv));
SN2SID_table[key][keyk][keykk][keykkk] = valuevvv;
end
end
end
end
end
end
end
end
end
 
if postUpdate_Spells2Add_PASSIVES and SN2SID_PASSIVES_table then
for key, value in pairs(postUpdate_Spells2Add_PASSIVES) do
if key == "General" or key == universalClassName then -- Only add hardcoded spells for
-- GeneralTab or Current Class
for keyk, valuev in pairs(value) do
-- if SN2SID_PASSIVES_table[key][keyk] == nil then -- "Spells" OR specName(..somethingMaybe) OR
if not SN2SID_PASSIVES_table[key][keyk] then -- "Spells" OR specName(..somethingMaybe) OR
-- "Pets" is not on the target table yet
-- print(AddonName.. ": Adding: ".. tostring(valuev));
SN2SID_PASSIVES_table[key][keyk] = valuev;
elseif type(valuev) == "table" then -- "Spells" OR specName(..somethingMaybe) OR
-- "Pets" table
for keykk, valuevv in pairs(valuev) do
if not SN2SID_PASSIVES_table[key][keyk][keykk] then -- Spell OR Flyouts_spell OR
-- PetFamily is not on the
-- target table yet
-- print(AddonName.. ": Adding: ".. tostring(valuevv));
SN2SID_PASSIVES_table[key][keyk][keykk] = valuevv;
elseif type(valuevv) == "table" then -- Flyouts_spell OR PetFamily
for keykkk, valuevvv in pairs(valuevv) do
-- if SN2SID_PASSIVES_table[key][keyk][keykk][keykkk] == nil then -- Flyouts_spell_Spell OR
if not SN2SID_PASSIVES_table[key][keyk][keykk][keykkk] then -- Flyouts_spell_Spell OR
-- PetFamily_spell is not
-- on the target table yet
-- print(AddonName.. ": Adding: ".. tostring(valuevvv));
SN2SID_PASSIVES_table[key][keyk][keykk][keykkk] = valuevvv;
end
end
 
end
end
end
end
 
end
end
end
tinsert(DEBUGmsgs[DBG_CurrentEvent], tostring(GetTime()).. ": addSpellsPostUpdate_func: END");
end
 
 
-- -- -- RUNTIME -- -- --
-------------------------
 
-- Frame to listen to game events
local SN2SID_frame, SN2SID_events = CreateFrame("Frame", nil), {};
-- NB: When ADDON_LOADED fires, the SpellBook etc aren't available yet, only upon PLAYER_LOGIN.
SN2SID_frame:RegisterEvent("PLAYER_LOGIN");
 
-- Function to call upon PLAYER_LOGIN (see bottom of file)
local lsn2sidpStartup = function()
tinsert(DEBUGmsgs[DBG_CurrentEvent], tostring(GetTime()).. ": lsn2sidpStartup: START");
-- Startup --
print(AddonName.. ": Startup!");
-- Copy the global saved-variables tables to our local tables
SN2SID_table = AddonEnv.SpellNamesAndIDs or SpellNamesAndIDs or {};
SN2SID_PASSIVES_table = AddonEnv.SpellNamesAndIDs_PASSIVES or SpellNamesAndIDs_PASSIVES or {};
-- DEBUGmsgs = AddonEnv.DEBUG_messages or DEBUG_messages or {};
METADATA_table = AddonEnv.METAdata or METAdata or {};
-- print(AddonName.. ": Made local copies of addon's Saved Variables.");
 
-- tinsert(DEBUGmsgs[DBG_CurrentEvent], tostring(GetTime()).. ": Print tables\' tostring to console: START");
-- print(AddonName.. ": AddonEnv.SpellNamesAndIDs = ".. tostring(AddonEnv.SpellNamesAndIDs)); -- nil
-- print(AddonName.. ": AddonEnv.SpellNamesAndIDs_PASSIVES = ".. tostring(AddonEnv.SpellNamesAndIDs_PASSIVES)); -- nil
-- print(AddonName.. ": AddonEnv.DEBUG_messages = ".. tostring(AddonEnv.DEBUG_messages)); -- nil
-- print(AddonName.. ": AddonEnv.METAdata = ".. tostring(AddonEnv.METAdata)); -- nil
-- print(AddonName.. ": SpellNamesAndIDs = ".. tostring(SpellNamesAndIDs)); -- TableA
-- print(AddonName.. ": SpellNamesAndIDs_PASSIVES = ".. tostring(SpellNamesAndIDs_PASSIVES)); -- TableB
-- print(AddonName.. ": DEBUG_messages = ".. tostring(DEBUG_messages)); -- TableB
-- print(AddonName.. ": METAdata = ".. tostring(METAdata)); -- TableB
-- print(AddonName.. ": SN2SID_table = ".. tostring(SN2SID_table));-- TableA
-- print(AddonName.. ": SN2SID_PASSIVES_table = ".. tostring(SN2SID_PASSIVES_table)); -- TableB
-- print(AddonName.. ": DEBUGmsgs = ".. tostring(DEBUGmsgs)); -- TableC
-- print(AddonName.. ": METADATA_table = ".. tostring(METADATA_table)); -- TableD
-- tinsert(DEBUGmsgs[DBG_CurrentEvent], tostring(GetTime()).. ": Print tables\' tostring to console: END");
 
-- -- Metadata fields: Data source, Class', ... -- --
-- Data source --
-- We're only interested in storing the English names, at least for now
local curLocale = GetLocale();
tinsert(DEBUGmsgs[DBG_CurrentEvent], tostring(GetTime()).. ": Got: curLocale = ".. curLocale);
if ( curLocale ~= "enUS") then
SN2SID_frame:UnregisterAllEvents();
error(AddonName.. " only retrieves data from English (enUS or enGB) clients.");
-- return;
end
tinsert(DEBUGmsgs[DBG_CurrentEvent], tostring(GetTime()).. ": Validated: curLocale");
local stubVal;
stubVal, universalRaceName = UnitRace("player");
tinsert(DEBUGmsgs[DBG_CurrentEvent], tostring(GetTime()).. ": Got: universalRaceName (no validation needed) = ".. universalRaceName);
-- Self-explanatory:
local _, gameBuild = GetBuildInfo();
tinsert(DEBUGmsgs[DBG_CurrentEvent], tostring(GetTime()).. ": Got: gameBuild");
-- For some reason, the variable gameBuild is being saved as a string; convert to number:
gameBuild = tonumber(gameBuild);
tinsert(DEBUGmsgs[DBG_CurrentEvent], tostring(GetTime()).. ": Validated that gameBuild is a number. gameBuild = ".. gameBuild.. ": Done.");
local charLevel = UnitLevel("player");
tinsert(DEBUGmsgs[DBG_CurrentEvent], tostring(GetTime()).. ": Got: charLevel (no validation needed) = ".. charLevel);
-- Spells in the General tab: Racial abilities, etc
-- local generalTabName = (GetSpellTabInfo(1)); -- Tab#1 = General
generalTabName = (GetSpellTabInfo(1)); -- Tab#1 = General
tinsert(DEBUGmsgs[DBG_CurrentEvent], tostring(GetTime()).. ": Got: generalTabName (no validation needed) = ".. generalTabName);
-- Class stuff --
stubVal, universalClassName = UnitClass("player"); -- Locale-independent Class name
tinsert(DEBUGmsgs[DBG_CurrentEvent], tostring(GetTime()).. ": Got: universalClassName (no validation needed) = ".. universalClassName);
local ClassNumSpecs = GetNumSpecializations(false, false); -- Number of Specialisations
tinsert(DEBUGmsgs[DBG_CurrentEvent], tostring(GetTime()).. ": Got: ClassNumSpecs (no validation needed) = ".. ClassNumSpecs);
-- Ordered list of Class specs' IDs and Names -- Do we still use this?
tinsert(DEBUGmsgs[DBG_CurrentEvent], tostring(GetTime()).. ": Order list of Class specs' IDs and Names: START");
local specID, specName = GetSpecializationInfo(1);
tinsert(DEBUGmsgs[DBG_CurrentEvent], tostring(GetTime()).. ": Order list of Class specs' IDs and Names: END");
 
---- Check the tables' skeleton structure and build whatever may be missing ----
--
if not SN2SID_table then -- sanity check
error("Local copy of saved variables is missing.");
end
if not SN2SID_PASSIVES_table then -- sanity check
error("Local copy of saved variables is missing.");
end
if not DEBUGmsgs then -- sanity check
error("Local copy of saved variables is missing.");
end
if not METADATA_table then -- sanity check
error("Local copy of saved variables is missing.");
end
 
--
-- If needed, create and populate the Metadata subtables; --
-- Flag spell-lists for update if applicable --
--
-- General tab skeleton + dataSource + raceBuilds
if not SN2SID_table[generalTabName] then
SN2SID_table[generalTabName] = {};
end
if not SN2SID_PASSIVES_table[generalTabName] then
SN2SID_PASSIVES_table[generalTabName] = {};
end
if not METADATA_table[generalTabName] then
tinsert(DEBUGmsgs[DBG_CurrentEvent], tostring(GetTime()).. ": Create the ".. generalTabName.. " dataSource: START");
-- print(AddonName.. ": Will now create the ".. generalTabName.. " dataSource.");
METADATA_table[generalTabName] = {
dataSource = {
clientLocale = curLocale, -- Currently always enUS
gameBuild = gameBuild,
charLevel = charLevel,
charMaxLevel = charLevel,
},
};
METADATA_table[generalTabName].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
tinsert(DEBUGmsgs[DBG_CurrentEvent], tostring(GetTime()).. ": Create the ".. generalTabName.. " dataSource: END");
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)
updateGeneralTabMetadata_func(curLocale, gameBuild, charLevel);
tinsert(DEBUGmsgs[DBG_CurrentEvent], tostring(GetTime()).. ": Updated the ".. generalTabName.. " Metadata \(or not\!\) for both Active and Passive spells.");
 
-- Class spells' skeleton + dataSource (class Specs will be handled afterwards)
if not SN2SID_table[universalClassName] then
-- print(AddonName.. ": Will now create the ".. universalClassName.. "'s table for Active spells.");
SN2SID_table[universalClassName] = {};
end
if not SN2SID_PASSIVES_table[universalClassName] then
-- print(AddonName.. ": Will now create the ".. universalClassName.. "'s table for Passive spells.");
SN2SID_PASSIVES_table[universalClassName] = {};
end
if not METADATA_table[universalClassName] then
tinsert(DEBUGmsgs[DBG_CurrentEvent], tostring(GetTime()).. ": Create the ".. universalClassName.. " dataSource: START");
METADATA_table[universalClassName] = {};
METADATA_table[universalClassName].dataSource = {
clientLocale = curLocale, -- Currently always enUS
gameBuild = gameBuild,
charLevel = charLevel,
charMaxLevel = charLevel,
};
-- 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.
tinsert(DEBUGmsgs[DBG_CurrentEvent], tostring(GetTime()).. ": Create the ".. universalClassName.. " dataSource: END");
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
-- Do the actual update of the Class dataSource
updateClassMetadata_func(curLocale, gameBuild, charLevel);
tinsert(DEBUGmsgs[DBG_CurrentEvent], tostring(GetTime()).. ": Ran updateClassMetadata_func().");
 
-- If needed, create and populate Class Specs' Active and Passive Spells --
-- Flag spell-lists for update if applicable --
if not METADATA_table[universalClassName].Specs then
tinsert(DEBUGmsgs[DBG_CurrentEvent], tostring(GetTime()).. ": Create the ".. universalClassName.. " \'Specs\' tables: START");
-- print(AddonName.. ": Will now create the ".. universalClassName.. "'s \'Specs\' tables.");
for i = 1, ClassNumSpecs do
local specID, specName = GetSpecializationInfo(i);
-- print(AddonName.. ": ".. i.. " = ".. specName.. " = ".. specID); -- For reference
if not METADATA_table[universalClassName].Specs then
METADATA_table[universalClassName].Specs = { [specName] = specID }; -- Reference
elseif not METADATA_table[universalClassName].Specs[i] then
METADATA_table[universalClassName].Specs[specName] = specID; -- Reference
end
SN2SID_table[universalClassName][specName] = {}; -- For "[SpellName] = SpellID"
SN2SID_PASSIVES_table[universalClassName][specName] = {}; -- For "[SpellName] = SpellID"
end
updateClassSpells = true; -- Do populate the actual list of spells.
-- print(AddonName.. ": ".. universalClassName.. "'s \'Specs\' tables created.");
tinsert(DEBUGmsgs[DBG_CurrentEvent], tostring(GetTime()).. ": Create the ".. universalClassName.. " \'Specs\' tables: END");
end
 
-- Update General (always ATM) and Class SpellNames2SIDs (both Actives and Passives) --
-- print(AddonName.. ": Will update ".. universalClassName.. " spells in its ".. ClassNumSpecs.. " Specs.");
updateGeneralSpells = true;
updateClassSpells = true;
updateSpellbookSpells_func(ClassNumSpecs);
-- print(AddonName.. ": Updated ".. universalClassName.. " spells in its ".. ClassNumSpecs.. " Specs.");
-- 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".
-- Adenda @WoW 8.1.5: For some reason, UNIT_PET seems to not be firing on PLAYER_LOGIN anymore
-- (or some other borkness), so we'll try and do a quick check here:
if UnitExists("pet") then
-- print(AddonName.. ": Will update ".. universalClassName.. " Pet spells.");
tinsert(DEBUGmsgs[DBG_CurrentEvent], tostring(GetTime()).. ": Get Pet spells: START");
updatePetSpellNames();
tinsert(DEBUGmsgs[DBG_CurrentEvent], tostring(GetTime()).. ": Get Pet spells: END");
-- print(AddonName.. ": Updated ".. universalClassName.. " Pet spells.");
end
 
 
-- Set up Other Event-Handlers --
---------------------------------
 
function SN2SID_events:PLAYER_TALENT_UPDATE(self)
DBG_CurrentEvent = "PLAYER_TALENT_UPDATE";
DEBUGmsgs["PLAYER_TALENT_UPDATE"] = { tostring(GetTime()).. ": PLAYER_TALENT_UPDATE: START", }
-- print(AddonName.. ": ".. tostring(GetTime()).. ": "..DBG_CurrentEvent .. ": START");
-- updateGeneralSpells = true; -- unneeded, placeholder for future version
updateClassSpells = true;
updateSpellbookSpells_func(ClassNumSpecs);
tinsert(DEBUGmsgs["PLAYER_TALENT_UPDATE"], tostring(GetTime()).. ": PLAYER_TALENT_UPDATE: END");
-- print(AddonName.. ": ".. tostring(GetTime()).. ": "..DBG_CurrentEvent .. ": END");
end
 
function SN2SID_events:PLAYER_LEVEL_UP(self, ...)
DBG_CurrentEvent = "PLAYER_LEVEL_UP";
DEBUGmsgs["PLAYER_LEVEL_UP"] = { tostring(GetTime()).. ": PLAYER_LEVEL_UP: START", }
-- print(AddonName.. ": ".. tostring(GetTime()).. ": "..DBG_CurrentEvent .. ": START");
-- 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.
updateGeneralTabMetadata_func(curLocale, gameBuild, charLevel);
updateClassMetadata_func(curLocale, gameBuild, charLevel);
updateSpellbookSpells_func(ClassNumSpecs);
tinsert(DEBUGmsgs["PLAYER_LEVEL_UP"], tostring(GetTime()).. ": PLAYER_LEVEL_UP: END");
-- print(AddonName.. ": ".. tostring(GetTime()).. ": "..DBG_CurrentEvent .. ": END");
end
 
-- Update pets' existence and spells when one comes up for "player"
-- NB: Fires on 'Pet Dismiss' and 'Summon Pet' button clicks.
-- function SN2SID_events:UNIT_PET(self, ...)
function SN2SID_events:UNIT_PET(...)
local arg1 = ...;
-- print(AddonName.. ": UNIT_PET fired with arg1 = ".. tostring(arg1));
if (not arg1) or (arg1 ~= "player") then
return;
end
DBG_CurrentEvent = "UNIT_PET";
DEBUGmsgs[DBG_CurrentEvent] = { tostring(GetTime()).. ": UNIT_PET: START", };
updatePetSpellNames();
tinsert(DEBUGmsgs["UNIT_PET"], tostring(GetTime()).. ": UNIT_PET: END");
end
 
function SN2SID_events:PLAYER_LOGOUT(self)
-- print(AddonName.. ": ".. tostring(GetTime()).. ": "..DBG_CurrentEvent .. ": START"); -- Meh!
DBG_CurrentEvent = "PLAYER_LOGOUT";
-- Set up DEBUG = { LOGOUT = {} } subtable of messages
if not DEBUGmsgs["PLAYER_LOGOUT"] then
DEBUGmsgs["PLAYER_LOGOUT"] = {
tostring(GetTime()).. ": PLAYER_LOGOUT: START",
tostring(GetTime()).. ": DEBUGmsgs.PLAYER_LOGOUT created.",
};
else
DEBUGmsgs["PLAYER_LOGOUT"] = {
tostring(GetTime()).. ": PLAYER_LOGOUT: START",
tostring(GetTime()).. ": DEBUGmsgs.PLAYER_LOGOUT cleared.",
};
end
-- Bring everything up to date
 
tinsert(DEBUGmsgs["PLAYER_LOGOUT"], tostring(GetTime()).. ": Update some variables\' values: START");
charLevel = UnitLevel("player");
tinsert(DEBUGmsgs["PLAYER_LOGOUT"], tostring(GetTime()).. ": charLevel's value = ".. tostring(charLevel));
updateGeneralTabMetadata = true;
tinsert(DEBUGmsgs["PLAYER_LOGOUT"], tostring(GetTime()).. ": updateGeneralTabMetadata's value = ".. tostring(updateGeneralTabMetadata));
updateClassMetadata = true;
tinsert(DEBUGmsgs["PLAYER_LOGOUT"], tostring(GetTime()).. ": updateClassMetadata's value = ".. tostring(updateClassMetadata));
tinsert(DEBUGmsgs["PLAYER_LOGOUT"], tostring(GetTime()).. ": Update some variables\' values: END");
 
--[[
tinsert(DEBUGmsgs["PLAYER_LOGOUT"], tostring(GetTime()).. ": Update Metadata: START");
updateGeneralTabMetadata_func(curLocale, gameBuild, charLevel);
tinsert(DEBUGmsgs["PLAYER_LOGOUT"], tostring(GetTime()).. ": Updated GeneralTab Metadata.");
updateClassMetadata_func(curLocale, gameBuild, charLevel);
tinsert(DEBUGmsgs["PLAYER_LOGOUT"], tostring(GetTime()).. ": Updated ".. universalClassName.. " Metadata.");
tinsert(DEBUGmsgs["PLAYER_LOGOUT"], tostring(GetTime()).. ": Update Metadata: END");
]]
 
tinsert(DEBUGmsgs["PLAYER_LOGOUT"], tostring(GetTime()).. ": Update Spellbook spells: START");
updateSpellbookSpells_func(ClassNumSpecs);
if SN2SID_table[universalClassName].Pets or SN2SID_PASSIVES_table[universalClassName].Pets
or UnitExists("pet") then
updatePetSpellNames();
tinsert(DEBUGmsgs["PLAYER_LOGOUT"], tostring(GetTime()).. ": Updated Pet spells.");
else
tinsert(DEBUGmsgs["PLAYER_LOGOUT"], tostring(GetTime()).. ": NO Pet Spells to get.");
end
tinsert(DEBUGmsgs["PLAYER_LOGOUT"], tostring(GetTime()).. ": Update Spellbook spells: END");
 
-- "Manually" add spells we cannot (or is not convenient to) get automatically
-- REENABLE THIS AFTER TEST:
addSpellsPostUpdate_func();
tinsert(DEBUGmsgs["PLAYER_LOGOUT"], tostring(GetTime()).. ": Added hardcoded spells to General and Class tables.");
 
-- Copy our local tables to the global saved-variables tables --
tinsert(DEBUGmsgs["PLAYER_LOGOUT"], tostring(GetTime()).. ": Copy session\'s Active and Passive Spells' tables, and METADATA_table, to SavedVariables: START");
AddonEnv.SpellNamesAndIDs = SN2SID_table;
SpellNamesAndIDs = SN2SID_table;
AddonEnv.SpellNamesAndIDs_PASSIVES = SN2SID_PASSIVES_table;
SpellNamesAndIDs_PASSIVES = SN2SID_PASSIVES_table;
AddonEnv.METAdata = METADATA_table;
METAdata = METADATA_table;
tinsert(DEBUGmsgs["PLAYER_LOGOUT"], tostring(GetTime()).. ": Copy session\'s Active and Passive Spells' tables, and METADATA_table, to SavedVariables: END");
tinsert(DEBUGmsgs["PLAYER_LOGOUT"], tostring(GetTime()).. ": Copy the DEBUG messages to SavedVariables: START");
AddonEnv.DEBUG_messages = DEBUGmsgs;
DEBUG_messages = DEBUGmsgs;
tinsert(DEBUGmsgs["PLAYER_LOGOUT"], tostring(GetTime()).. ": Copy the DEBUG messages to SavedVariables: END");
-- print(AddonName.. ": ".. tostring(GetTime()).. ": "..DBG_CurrentEvent .. ": END"); -- Meh!
tinsert(DEBUGmsgs["PLAYER_LOGOUT"], tostring(GetTime()).. ": PLAYER_LOGOUT: END");
end
 
-- Unregister the event (handler) in which we are now running, to free up RAM
SN2SID_frame:UnregisterEvent("PLAYER_LOGIN");
tinsert(DEBUGmsgs[DBG_CurrentEvent], tostring(GetTime()).. ": Unregistered Event: ".. DBG_CurrentEvent);
-- 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
if k == "UNIT_PET" then
SN2SID_frame:RegisterUnitEvent("UNIT_PET", "player");
else
SN2SID_frame:RegisterEvent(k);
end
if SN2SID_frame:IsEventRegistered(k) then
-- print(AddonName.. ": Registered event: ".. tostring(k));
end
tinsert(DEBUGmsgs[DBG_CurrentEvent], tostring(GetTime()).. ": Registered Event: ".. k);
end
tinsert(DEBUGmsgs[DBG_CurrentEvent], (GetTime()).. ": PLAYER_LOGIN: END");
end
 
-- PLAYER_LOGIN event handler; we set up the other events when this one fires --
SN2SID_frame:SetScript("OnEvent", function(self, event)
-- print(AddonName.. ": Event ".. event.. " fired.");
DBG_CurrentEvent = event;
DEBUGmsgs = AddonEnv.DEBUG_messages or DEBUG_messages or {};
if not DEBUGmsgs then
DEBUGmsgs = {
[DBG_CurrentEvent] = {
tostring(GetTime()).. ": ".. DBG_CurrentEvent.. ": START",
tostring(GetTime()).. ": Will startup in 5 seconds time.",
},
};
else
DEBUGmsgs[DBG_CurrentEvent] = {
tostring(GetTime()).. ": ".. DBG_CurrentEvent.. ": START",
tostring(GetTime()).. ": Will startup in 5 seconds time.",
};
end
C_Timer.After(5, lsn2sidpStartup);
-- print(AddonName.. ": Event ".. event.. " handled.");
end);