vanilla-wow-addons – Blame information for rev 1
?pathlinks?
Rev | Author | Line No. | Line |
---|---|---|---|
1 | office | 1 | ------------------------------------------------------ |
2 | -- HuntersHelper.lua |
||
3 | ------------------------------------------------------ |
||
4 | FHH_VERSION = "11000.1"; |
||
5 | ------------------------------------------------------ |
||
6 | |||
7 | -- Saved configuration & info |
||
8 | FHH_Config = { }; |
||
9 | FHH_Config.Tooltip = true; |
||
10 | |||
11 | --FHH_AbilityInfo = { }; |
||
12 | -- Has the following internal structure: |
||
13 | -- REALM_PLAYER = { |
||
14 | -- SKILL |
||
15 | -- } |
||
16 | |||
17 | -- Runtime state |
||
18 | FHH_State = { }; |
||
19 | FHH_State.RealmPlayer = nil; |
||
20 | FHH_State.TamingCritter = nil; |
||
21 | FHH_State.TamingType = nil; |
||
22 | |||
23 | -- Constants |
||
24 | MAX_REPORTED_ZONES = 4; |
||
25 | |||
26 | |||
27 | function FHH_OnLoad() |
||
28 | |||
29 | this:RegisterEvent("PLAYER_ENTERING_WORLD"); |
||
30 | this:RegisterEvent("UPDATE_MOUSEOVER_UNIT"); |
||
31 | |||
32 | -- Register Slash Commands |
||
33 | SLASH_FHH1 = "/huntershelper"; |
||
34 | SLASH_FHH2 = "/hh"; |
||
35 | SlashCmdList["FHH"] = function(msg) |
||
36 | FHH_ChatCommandHandler(msg); |
||
37 | end |
||
38 | |||
39 | GFWUtils.Print("Fizzwidget Hunter's Helper "..FHH_VERSION.." initialized!"); |
||
40 | |||
41 | end |
||
42 | |||
43 | function FHH_OnEvent(event, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9) |
||
44 | |||
45 | --DevTools_Dump({event=event, arg1=arg1, arg2=arg2, arg3=arg3, arg4=arg4, arg5=arg5, arg6=arg6, arg7=arg7, arg8=arg8, arg9=arg9}); |
||
46 | |||
47 | if ( event == "PLAYER_ENTERING_WORLD" ) then |
||
48 | |||
49 | _, realClass = UnitClass("player"); |
||
50 | if (realClass == "HUNTER") then |
||
51 | -- only do stuff related to taming and checking hunter spells if you're a hunter. |
||
52 | this:RegisterEvent("UNIT_AURA"); |
||
53 | this:RegisterEvent("UNIT_NAME_UPDATE"); |
||
54 | this:RegisterEvent("CRAFT_SHOW"); |
||
55 | this:RegisterEvent("CHAT_MSG_SYSTEM"); |
||
56 | |||
57 | if (FHH_State.RealmPlayer == nil) then |
||
58 | FHH_State.RealmPlayer = GetCVar("realmName") .. "." .. UnitName("player"); |
||
59 | end |
||
60 | if (FHH_AbilityInfo == nil or FHH_AbilityInfo[FHH_State.RealmPlayer] == nil or GFWTable.Count(FHH_AbilityInfo[FHH_State.RealmPlayer]) == 0) then |
||
61 | |||
62 | if (realClass == "HUNTER" and UnitLevel("player") > 9) then |
||
63 | GFWUtils.Print("Hunter's Helper needs to collect info about what pet skills you already know; please open your Beast Training window. (Info on future skills will be collected as they are learned.)"); |
||
64 | end |
||
65 | end |
||
66 | end |
||
67 | |||
68 | elseif ( event == "UPDATE_MOUSEOVER_UNIT" ) then |
||
69 | |||
70 | if ( UnitExists("mouseover") and not UnitPlayerControlled("mouseover") and FHH_Config.Tooltip ) then |
||
71 | |||
72 | local _, myClass = UnitClass("player"); |
||
73 | if (FHH_Config.Tooltip == "hunter" and myClass ~= "HUNTER") then return; end |
||
74 | |||
75 | FHH_ModifyTooltip("mouseover"); |
||
76 | |||
77 | end |
||
78 | |||
79 | elseif ( event == "UNIT_AURA" ) then |
||
80 | |||
81 | if ( arg1 == "player" and FHH_HasTameEffect("player") ) then |
||
82 | FHH_State.TamingCritter = UnitName("target"); |
||
83 | local unlocalizedCreepName = GFWTable.KeyOf(FHH_Localized, FHH_State.TamingCritter); |
||
84 | if (unlocalizedCreepName) then |
||
85 | FHH_State.TamingCritter = unlocalizedCreepName; |
||
86 | end |
||
87 | FHH_State.TamingType = UnitClassification("target"); |
||
88 | end |
||
89 | |||
90 | elseif ( event == "UNIT_NAME_UPDATE" ) then |
||
91 | |||
92 | if ( arg1 == "pet" and FHH_State.TamingCritter ) then |
||
93 | local loyaltyDescription = GetPetLoyalty(); |
||
94 | if (loyaltyDescription) then |
||
95 | local _, _, loyaltyLevel = string.find(loyaltyDescription, "(%d+)"); |
||
96 | if (tonumber(loyaltyLevel) and tonumber(loyaltyLevel) > 1) then |
||
97 | GFWUtils.Print("Got "..event.." but pet's loyalty > 1; ignoring."); |
||
98 | FHH_State.TamingCritter = nil; |
||
99 | FHH_State.TamingType = nil; |
||
100 | return; |
||
101 | end |
||
102 | end |
||
103 | if (UnitName("pet") ~= UnitCreatureFamily("pet")) then |
||
104 | GFWUtils.Print("Got "..event.." but pet's UnitName() ~= UnitCreatureFamily(); ignoring."); |
||
105 | FHH_State.TamingCritter = nil; |
||
106 | FHH_State.TamingType = nil; |
||
107 | return; |
||
108 | end |
||
109 | --GFWUtils.Print(event..": checking newly tamed pet"); |
||
110 | FHH_CheckPetSpells(); |
||
111 | FHH_State.TamingCritter = nil; |
||
112 | FHH_State.TamingType = nil; |
||
113 | end |
||
114 | |||
115 | elseif ( event == "CRAFT_SHOW" ) then |
||
116 | |||
117 | -- Beast Training uses the CraftFrame; we can tell it's not really a craft because it doesn't have a skill-level bar. |
||
118 | local name, rank, maxRank = GetCraftDisplaySkillLine(); |
||
119 | if ( name ) then return; end |
||
120 | |||
121 | FHH_ScanCraftFrame(); |
||
122 | |||
123 | elseif ( event == "CHAT_MSG_SYSTEM" ) then |
||
124 | |||
125 | local pattern = GFWUtils.FormatToPattern(ERR_LEARN_SPELL_S); -- "You have learned a new spell: %s." |
||
126 | local _, _, compositeSpellName = string.find(arg1, pattern); |
||
127 | if (compositeSpellName == nil) then return; end |
||
128 | |||
129 | local _, _, spellName, rankNum = string.find(compositeSpellName, "(.+) %(.+ (%d+)%)"); |
||
130 | if (spellName and rankNum and spellName ~= "" and rankNum ~= "" ) then |
||
131 | spellName = string.gsub(spellName, "^%s+", ""); -- strip leading spaces |
||
132 | spellName = string.gsub(spellName, "%s+$", ""); -- and trailing spaces |
||
133 | local spellID = FHH_SpellIDforName(spellName); |
||
134 | if (FHH_NewInfo and FHH_NewInfo.SpellIDAliases and FHH_NewInfo.SpellIDAliases[spellID]) then |
||
135 | spellID = FHH_NewInfo.SpellIDAliases[spellID]; |
||
136 | end |
||
137 | if (spellID and (FHH_RequiredLevel[spellID] or (FHH_NewInfo and FHH_NewInfo.RequiredLevel and FHH_NewInfo.RequiredLevel[spellID]))) then |
||
138 | -- only track spells we know are hunter pet spells |
||
139 | if (FHH_AbilityInfo == nil) then |
||
140 | FHH_AbilityInfo = {}; |
||
141 | end |
||
142 | if (FHH_AbilityInfo[FHH_State.RealmPlayer] == nil or table.getn(FHH_AbilityInfo[FHH_State.RealmPlayer]) == 0) then |
||
143 | FHH_AbilityInfo[FHH_State.RealmPlayer] = { }; |
||
144 | end |
||
145 | table.insert(FHH_AbilityInfo[FHH_State.RealmPlayer], spellName.." "..rankNum); |
||
146 | table.sort(FHH_AbilityInfo[FHH_State.RealmPlayer]); |
||
147 | end |
||
148 | end |
||
149 | |||
150 | end |
||
151 | |||
152 | end |
||
153 | |||
154 | function FHH_ChatCommandHandler(msg) |
||
155 | |||
156 | -- Print Help |
||
157 | if ( msg == "help" ) or ( msg == "" ) then |
||
158 | GFWUtils.Print("Fizzwidget Hunter's Helper "..FHH_VERSION..":"); |
||
159 | GFWUtils.Print("/huntershelper /hh <command>"); |
||
160 | GFWUtils.Print("- "..GFWUtils.Hilite("help").." - Print this helplist."); |
||
161 | GFWUtils.Print("- "..GFWUtils.Hilite("on").." | "..GFWUtils.Hilite("off").." | "..GFWUtils.Hilite("onlyhunter").." - Turn display of beast abilities in tooltips on or off, or make them only appear if you're playing a hunter."); |
||
162 | GFWUtils.Print("- "..GFWUtils.Hilite("status").." - Check current settings."); |
||
163 | GFWUtils.Print("- "..GFWUtils.Hilite("find <ability> <rank>").." - List where beasts with a given ability (e.g. Bite 6) can be found."); |
||
164 | return; |
||
165 | end |
||
166 | |||
167 | if (msg == "version") then |
||
168 | GFWUtils.Print("Fizzwidget Hunter's Helper "..FHH_VERSION); |
||
169 | return; |
||
170 | end |
||
171 | |||
172 | if (msg == "onlyhunter") then |
||
173 | FHH_Config.Tooltip = "hunter"; |
||
174 | GFWUtils.Print("Hunter's Helper is enabled; beast tooltips will display ability info only when playing a Hunter character."); |
||
175 | return; |
||
176 | end |
||
177 | if (msg == "on") then |
||
178 | FHH_Config.Tooltip = true; |
||
179 | GFWUtils.Print("Hunter's Helper is enabled; beast tooltips will display ability info."); |
||
180 | return; |
||
181 | end |
||
182 | if (msg == "off") then |
||
183 | FHH_Config.Tooltip = nil; |
||
184 | GFWUtils.Print("Hunter's Helper is disabled; no extra info added to tooltips."); |
||
185 | return; |
||
186 | end |
||
187 | |||
188 | -- Check Status |
||
189 | if ( msg == "status" ) then |
||
190 | if ( FHH_Config.Tooltip == "hunter" ) then |
||
191 | GFWUtils.Print("Hunter's Helper is enabled; beast tooltips will display ability info only when playing as a Hunter."); |
||
192 | elseif ( FHH_Config.Tooltip ) then |
||
193 | GFWUtils.Print("Hunter's Helper is enabled; beast tooltips will display ability info."); |
||
194 | else |
||
195 | GFWUtils.Print("Hunter's Helper is disabled; no extra info added to tooltips."); |
||
196 | end |
||
197 | return; |
||
198 | end |
||
199 | |||
200 | if (msg == "reset") then |
||
201 | FHH_Config = { }; |
||
202 | FHH_Config.Tooltip = true; |
||
203 | FHH_AbilityInfo = nil; |
||
204 | FHH_NewInfo = nil; |
||
205 | |||
206 | GFWUtils.Print("Hunter's Helper has been reset to default options and all stored data cleared."); |
||
207 | return; |
||
208 | end |
||
209 | |||
210 | if (msg == "test") then |
||
211 | FHH_RunAllTests(); |
||
212 | return; |
||
213 | end |
||
214 | |||
215 | if (msg == "dynamic") then |
||
216 | FHH_SpellNamesToIDs = {}; |
||
217 | FHH_SpellIDsToNames = {}; |
||
218 | FHH_LearnableBy = {}; |
||
219 | FHH_RequiredLevel = {}; |
||
220 | FHH_SpellInfo = {}; |
||
221 | FHH_BeastInfo = {}; |
||
222 | FHH_BeastLevels = {}; |
||
223 | GFWUtils.Print("Hunter's Helper: only consulting dynamic tables until next reload."); |
||
224 | return; |
||
225 | end |
||
226 | |||
227 | local _, _, cmd, spellName, rankNum = string.find(msg, "(find%w*) ([^%d]+) *(%d*)"); |
||
228 | if (cmd == "find" or cmd == "findall") then |
||
229 | if (spellName == nil or spellName == "") then |
||
230 | GFWUtils.Print("Usage: "..GFWUtils.Hilite("/hh find <ability> <rank>")); |
||
231 | return; |
||
232 | end |
||
233 | |||
234 | spellName = string.gsub(spellName, "^%s+", ""); -- strip leading spaces |
||
235 | spellName = string.gsub(spellName, "%s+$", ""); -- and trailing spaces |
||
236 | spellName = string.lower(spellName); |
||
237 | local spellID; |
||
238 | |||
239 | -- first, look up the input against our spell ID keys |
||
240 | if (FHH_SpellIDsToNames[spellName]) then |
||
241 | spellID = spellName; |
||
242 | end |
||
243 | if (spellID == nil and FHH_NewInfo and FHH_NewInfo.SpellIDsToNames and FHH_NewInfo.SpellIDsToNames[spellName]) then |
||
244 | spellID = spellName; |
||
245 | end |
||
246 | |||
247 | -- failing that, try looking it up as a proper name, case insensitively |
||
248 | if (spellID == nil) then |
||
249 | for properName in FHH_SpellNamesToIDs do |
||
250 | if (string.lower(properName) == spellName) then |
||
251 | spellID = FHH_SpellNamesToIDs[properName]; |
||
252 | end |
||
253 | end |
||
254 | if (spellID == nil and FHH_NewInfo and FHH_NewInfo.SpellNamesToIDs) then |
||
255 | for properName in FHH_NewInfo.SpellNamesToIDs do |
||
256 | if (string.lower(properName) == spellName) then |
||
257 | spellID = FHH_NewInfo.SpellNamesToIDs[properName]; |
||
258 | end |
||
259 | end |
||
260 | end |
||
261 | end |
||
262 | |||
263 | if (spellID == nil) then |
||
264 | GFWUtils.Print(GFWUtils.Hilite(spellName).." is not a known beast ability."); |
||
265 | return; |
||
266 | end |
||
267 | FHH_Find(spellID, rankNum); |
||
268 | return; |
||
269 | end |
||
270 | |||
271 | -- if we got all the way to here, we got invalid input. |
||
272 | FHH_ChatCommandHandler("help"); |
||
273 | |||
274 | end |
||
275 | |||
276 | function FHH_ModifyTooltip(unit) |
||
277 | local creepName = UnitName(unit); |
||
278 | local creepLevel = UnitLevel(unit); |
||
279 | local creepFamily = UnitCreatureFamily(unit); |
||
280 | local creepType = UnitClassification(unit); |
||
281 | local abilitiesLine; |
||
282 | |||
283 | local unlocalizedCreepName = GFWTable.KeyOf(FHH_Localized, creepName); |
||
284 | if (unlocalizedCreepName) then |
||
285 | creepName = unlocalizedCreepName; |
||
286 | end |
||
287 | |||
288 | -- if this beast is in our database, make sure we have the right level range & type info |
||
289 | FHH_CheckBeastLevel(creepName, creepLevel, creepType); |
||
290 | |||
291 | -- if this is a Beast Lore tooltip, parse out and use its tamed abilities info |
||
292 | if (FHH_TAMED_ABILS_PATTERN == nil) then |
||
293 | FHH_TAMED_ABILS_PATTERN = GFWUtils.FormatToPattern(PET_SPELLS_TEMPLATE); |
||
294 | end |
||
295 | for lineNum = 1, GameTooltip:NumLines() do |
||
296 | local lineText = getglobal("GameTooltipTextLeft"..lineNum):GetText(); |
||
297 | if (lineText) then |
||
298 | if (string.find(lineText, LIGHTYELLOW_FONT_COLOR_CODE)) then |
||
299 | return; -- if we've already added a line to this tooltip, we should stop. |
||
300 | end |
||
301 | local _, _, beastLoreInfo = string.find(lineText, FHH_TAMED_ABILS_PATTERN); |
||
302 | if (beastLoreInfo) then |
||
303 | abilitiesLine = lineNum; |
||
304 | local beastLoreList = GFWUtils.Split(beastLoreInfo, ", "); |
||
305 | local beastSpellTable = {}; |
||
306 | for _, niceSpellName in beastLoreList do |
||
307 | local _, _, spellName, rankNum = string.find(niceSpellName, "^(.+) %(.+ (%d+)%)$"); |
||
308 | if (spellName == nil or spellName == "" or tonumber(rankNum) == nil) then |
||
309 | GFWUtils.PrintOnce(GFWUtils.Red("Hunter's Helper Error: ").."Can't parse spell "..GFWUtils.Hilite(niceSpellName).." from "..GFWUtils.Hilite(critter).."."); |
||
310 | else |
||
311 | spellName = string.gsub(spellName, "^%s+", ""); -- strip leading spaces |
||
312 | spellName = string.gsub(spellName, "%s+$", ""); -- and trailing spaces |
||
313 | local spellID = FHH_SpellIDforName(spellName); |
||
314 | if (FHH_NewInfo and FHH_NewInfo.SpellIDAliases and FHH_NewInfo.SpellIDAliases[spellID]) then |
||
315 | spellID = FHH_NewInfo.SpellIDAliases[spellID]; |
||
316 | end |
||
317 | if (spellID == nil) then |
||
318 | spellID = FHH_RecordNewSpellID(spellName, true); |
||
319 | end |
||
320 | beastSpellTable[spellID] = tonumber(rankNum); |
||
321 | end |
||
322 | end |
||
323 | FHH_CheckSpellTables(creepName, beastSpellTable, creepLevel, creepFamily); |
||
324 | end |
||
325 | end |
||
326 | end |
||
327 | |||
328 | -- look up the list of abilities we think this critter has |
||
329 | local abilitiesList = nil; |
||
330 | if (FHH_NewInfo and FHH_NewInfo.BeastInfo and FHH_NewInfo.BeastInfo[creepName]) then |
||
331 | abilitiesList = FHH_NewInfo.BeastInfo[creepName]; |
||
332 | elseif (FHH_BeastInfo[creepName]) then |
||
333 | abilitiesList = FHH_BeastInfo[creepName]; |
||
334 | if (FHH_NewInfo and FHH_NewInfo.BadBeastInfo and FHH_NewInfo.BadBeastInfo[creepName]) then |
||
335 | local newAbilitiesList = {}; |
||
336 | for spellID, rankNum in abilitiesList do |
||
337 | if (FHH_NewInfo.BadBeastInfo[creepName][spellID] ~= rankNum) then |
||
338 | newAbilitiesList[spellID] = rankNum; |
||
339 | end |
||
340 | end |
||
341 | abilitiesList = newAbilitiesList; |
||
342 | end |
||
343 | end |
||
344 | |||
345 | if (abilitiesList and GFWTable.Count(abilitiesList) > 0) then |
||
346 | |||
347 | -- build textual description from that list (with color coding if you're a hunter) |
||
348 | local coloredList = {}; |
||
349 | local _, myClass = UnitClass("player"); |
||
350 | for spellName, rankNum in abilitiesList do |
||
351 | if (myClass == "HUNTER" and FHH_AbilityInfo and FHH_AbilityInfo[FHH_State.RealmPlayer] and GFWTable.Count(FHH_AbilityInfo[FHH_State.RealmPlayer]) > 0) then |
||
352 | local playerRanks = FHH_AbilityInfo[FHH_State.RealmPlayer][spellName]; |
||
353 | if (playerRanks and GFWTable.IndexOf(playerRanks, rankNum) ~= 0) then |
||
354 | table.insert(coloredList, GRAY_FONT_COLOR_CODE..FHH_SpellDescription(spellName, rankNum)..FONT_COLOR_CODE_CLOSE); |
||
355 | else |
||
356 | table.insert(coloredList, GREEN_FONT_COLOR_CODE..FHH_SpellDescription(spellName, rankNum)..FONT_COLOR_CODE_CLOSE); |
||
357 | end |
||
358 | else |
||
359 | table.insert(coloredList, FHH_SpellDescription(spellName, rankNum)); |
||
360 | end |
||
361 | end |
||
362 | local abilitiesText = table.concat(coloredList, ", "); |
||
363 | abilitiesText = string.gsub(abilitiesText, "( %d+)", " ("..RANK.."%1)"); |
||
364 | |||
365 | -- add it to the tooltip (or, if Beast Lore, replace its line with our color-coded one) |
||
366 | if (abilitiesLine) then |
||
367 | local lineText = getglobal("GameTooltipTextLeft"..abilitiesLine); |
||
368 | lineText:SetText(GFWUtils.LtY(string.format(PET_SPELLS_TEMPLATE, abilitiesText))); |
||
369 | else |
||
370 | GameTooltip:AddLine(GFWUtils.LtY(string.format(PET_SPELLS_TEMPLATE, abilitiesText)), 1.0, 1.0, 1.0); |
||
371 | GameTooltip:SetHeight(GameTooltip:GetHeight() + 14); |
||
372 | local width = 20 + getglobal(GameTooltip:GetName().."TextLeft"..GameTooltip:NumLines()):GetWidth(); |
||
373 | if ( GameTooltip:GetWidth() < width ) then |
||
374 | GameTooltip:SetWidth(width); |
||
375 | end |
||
376 | end |
||
377 | end |
||
378 | |||
379 | end |
||
380 | |||
381 | function FHH_ScanCraftFrame() |
||
382 | local numCrafts = GetNumCrafts(); |
||
383 | if not ( numCrafts > 0 )then return; end |
||
384 | |||
385 | if (FHH_AbilityInfo == nil) then |
||
386 | FHH_AbilityInfo = {}; |
||
387 | end |
||
388 | if (FHH_AbilityInfo[FHH_State.RealmPlayer] == nil or table.getn(FHH_AbilityInfo[FHH_State.RealmPlayer]) == 0) then |
||
389 | FHH_AbilityInfo[FHH_State.RealmPlayer] = { }; |
||
390 | end |
||
391 | |||
392 | for i=1, numCrafts do |
||
393 | local craftName, craftSubSpellName, _, _, _, _, requiredLevel = GetCraftInfo(i); |
||
394 | local _, _, rankNum = string.find(craftSubSpellName, "(%d)"); |
||
395 | if (rankNum and tonumber(rankNum)) then |
||
396 | rankNum = tonumber(rankNum); |
||
397 | end |
||
398 | local craftIcon = GetCraftIcon(i); |
||
399 | if (craftIcon) then |
||
400 | craftIcon = string.gsub(craftIcon, "^Interface\\Icons\\", ""); |
||
401 | end |
||
402 | |||
403 | local spellID = FHH_SpellIDforIcon(craftIcon, craftName); |
||
404 | local nameSpellID = FHH_SpellIDforName(craftName); |
||
405 | if (spellID and nameSpellID and spellID ~= nameSpellID) then |
||
406 | if (FHH_NewInfo == nil) then |
||
407 | FHH_NewInfo = {}; |
||
408 | end |
||
409 | if (FHH_NewInfo.SpellIDAliases == nil) then |
||
410 | FHH_NewInfo.SpellIDAliases = {}; |
||
411 | end |
||
412 | FHH_NewInfo.SpellIDAliases[nameSpellID] = spellID; |
||
413 | end |
||
414 | |||
415 | if (FHH_AbilityInfo[FHH_State.RealmPlayer][spellID] == nil) then |
||
416 | FHH_AbilityInfo[FHH_State.RealmPlayer][spellID] = {}; |
||
417 | end |
||
418 | if (GFWTable.IndexOf(FHH_AbilityInfo[FHH_State.RealmPlayer][spellID], rankNum) == 0) then |
||
419 | table.insert(FHH_AbilityInfo[FHH_State.RealmPlayer][spellID], rankNum) |
||
420 | end; |
||
421 | |||
422 | if ( requiredLevel and requiredLevel > 0 ) then |
||
423 | FHH_RecordNewRequiredLevel(spellID, tonumber(rankNum), requiredLevel, true); |
||
424 | end |
||
425 | end |
||
426 | FHH_ProcessAliases(); |
||
427 | end |
||
428 | |||
429 | function FHH_Find(spellID, rankNum) |
||
430 | local niceSpellName = FHH_SpellIDsToNames[spellID]; |
||
431 | if (niceSpellName == nil and FHH_NewInfo and FHH_NewInfo.SpellIDsToNames and FHH_NewInfo.SpellIDsToNames[spellID]) then |
||
432 | niceSpellName = FHH_NewInfo.SpellIDsToNames[spellID]; |
||
433 | end |
||
434 | |||
435 | local spellInfo = FHH_SpellInfo[spellID]; |
||
436 | local newSpellInfo; |
||
437 | if (FHH_NewInfo and FHH_NewInfo.SpellInfo) then |
||
438 | newSpellInfo = FHH_NewInfo.SpellInfo[spellID]; |
||
439 | end |
||
440 | if (spellInfo == nil or (type(spellInfo) == "table" and GFWTable.Count(spellInfo) == 0)) then |
||
441 | if (newSpellInfo == nil or GFWTable.Count(newSpellInfo) == 0) then |
||
442 | GFWUtils.Print("No info available for ".. GFWUtils.Hilite(niceSpellName).."."); |
||
443 | return; |
||
444 | else |
||
445 | spellInfo = newSpellInfo; |
||
446 | end |
||
447 | end |
||
448 | local rankTable = FHH_RequiredLevel[spellID]; |
||
449 | local newRankTable; |
||
450 | if (FHH_NewInfo and FHH_NewInfo.RequiredLevel) then |
||
451 | newRankTable = FHH_NewInfo.RequiredLevel[spellID]; |
||
452 | end |
||
453 | if (rankTable == nil or GFWTable.Count(rankTable) == 0) then |
||
454 | if (newRankTable == nil or GFWTable.Count(newRankTable) == 0) then |
||
455 | GFWUtils.Print(GFWUtils.Red("Hunter's Helper "..FHH_VERSION.." error:").." found "..GFWUtils.Hilite(niceSpellName).." but can't find rank info. Please report to gazmik@fizzwidget.com"); |
||
456 | return; |
||
457 | else |
||
458 | rankTable = newRankTable; |
||
459 | end |
||
460 | end |
||
461 | |||
462 | rankNum = tonumber(rankNum); |
||
463 | if (rankNum) then |
||
464 | if not (rankTable[rankNum]) then |
||
465 | GFWUtils.Print(GFWUtils.Hilite(niceSpellName).." is not known to have a rank "..GFWUtils.Hilite(rankNum).."."); |
||
466 | return; |
||
467 | end |
||
468 | |||
469 | -- report minimum pet level for ability |
||
470 | local minLevel = rankTable[rankNum]; |
||
471 | local petLevel = 60; |
||
472 | if (UnitExists("pet")) then |
||
473 | petLevel = tonumber(UnitLevel("pet")); |
||
474 | end |
||
475 | if (minLevel == nil) then |
||
476 | minLevel = newRankTable[rankNum]; |
||
477 | end |
||
478 | if (minLevel == nil) then |
||
479 | GFWUtils.Print(GFWUtils.Red("Hunter's Helper "..FHH_VERSION.." error:").." can't find required level for "..GFWUtils.Hilite(niceSpellName.." "..rankNum)..". Please report to gazmik@fizzwidget.com"); |
||
480 | else |
||
481 | if (type(minLevel) == "string") then |
||
482 | GFWUtils.Print(GFWUtils.Hilite(niceSpellName.." "..rankNum).." requires at least pet level "..GFWUtils.Hilite(minLevel)..". (Assumed because it was found on a beast of this level that you tamed. Open you Beast Training window and Hunter's Helper can collect more accurate information.)"); |
||
483 | elseif (petLevel >= minLevel) then |
||
484 | GFWUtils.Print(GFWUtils.Hilite(niceSpellName.." "..rankNum).." requires pet level "..GFWUtils.Hilite(minLevel).."."); |
||
485 | else |
||
486 | GFWUtils.Print(GFWUtils.Hilite(niceSpellName.." "..rankNum).." requires pet level "..GFWUtils.Red(minLevel).."."); |
||
487 | end |
||
488 | end |
||
489 | else |
||
490 | local knownRanks = {}; |
||
491 | for rankNum in rankTable do |
||
492 | table.insert(knownRanks, rankNum); |
||
493 | end |
||
494 | local newRanks = {}; |
||
495 | for rankNum in (newRankTable or {}) do |
||
496 | table.insert(newRanks, rankNum); |
||
497 | end |
||
498 | local allRanks = GFWTable.Merge(knownRanks, newRanks); |
||
499 | GFWUtils.Print("Ranks known about for "..GFWUtils.Hilite(niceSpellName)..": "..table.concat(allRanks, " ")); |
||
500 | if (type(spellInfo) ~= "string") then |
||
501 | GFWUtils.Print("Type "..GFWUtils.Hilite("/hh find "..spellID).." and a number to get info about that rank."); |
||
502 | end |
||
503 | end |
||
504 | |||
505 | -- report available creature families |
||
506 | local families = FHH_LearnableBy[spellID]; |
||
507 | if (type(families) == "table" and FHH_NewInfo and FHH_NewInfo.LearnableBy and FHH_NewInfo.LearnableBy[spellID]) then |
||
508 | families = GFWTable.Merge(families, FHH_NewInfo.LearnableBy[spellID]); |
||
509 | if (table.getn(GFWTable.Diff(families, FHH_AllFamilies)) == 0 ) then |
||
510 | families = FHH_ALL_FAMILIES; |
||
511 | end |
||
512 | end |
||
513 | if (families or (type(families) == "table" and table.getn(families) == 0)) then |
||
514 | if (type(families) == "string") then |
||
515 | GFWUtils.Print(GFWUtils.Hilite(niceSpellName).." is learnable by "..GFWUtils.Hilite(families).."."); |
||
516 | else |
||
517 | local listText = table.concat(families, ", "); |
||
518 | GFWUtils.Print(GFWUtils.Hilite(niceSpellName).." is learnable by: "..GFWUtils.Hilite(listText).."."); |
||
519 | end |
||
520 | end |
||
521 | |||
522 | -- case 1: first levels of Growl are innate |
||
523 | if (spellID == "growl" and rankNum and rankNum <= 2) then |
||
524 | GFWUtils.Print("You should already know "..GFWUtils.Hilite(niceSpellName.." "..rankNum).." if you've learned Beast Training."); |
||
525 | return; |
||
526 | end |
||
527 | |||
528 | -- case 2: spells taught by trainers, for which rank doesn't matter |
||
529 | if (type(spellInfo) == "string") then |
||
530 | local spellSummary = niceSpellName; |
||
531 | if (rankNum) then |
||
532 | spellSummary = spellSummary.." "..rankNum; |
||
533 | end |
||
534 | GFWUtils.Print(GFWUtils.Hilite(spellSummary).." is learned from "..spellInfo.."."); |
||
535 | return; |
||
536 | end |
||
537 | |||
538 | if (rankNum == nil) then return; end |
||
539 | |||
540 | --case 3: lookup by spell and rank, report by zone (sanity check first) |
||
541 | local spellRankInfo = spellInfo[rankNum]; |
||
542 | local maxZones = MAX_REPORTED_ZONES; |
||
543 | if (cmd == "findall") then |
||
544 | maxZones = 100; -- arbitrarily high so we find everything. |
||
545 | end |
||
546 | if (spellRankInfo == nil ) then |
||
547 | GFWUtils.Print("Hunter's Helper doesn't know about any creatures with "..GFWUtils.Hilite(niceSpellName.." "..rankNum).."."); |
||
548 | return; |
||
549 | end |
||
550 | GFWUtils.Print(GFWUtils.Hilite(niceSpellName.." "..rankNum).." can be learned from:"); |
||
551 | local numReportedZones = 0; |
||
552 | local zoneName = GFWZones.UnlocalizedZone(GetRealZoneText()); |
||
553 | local critterList = {}; |
||
554 | if (spellRankInfo[zoneName] and table.getn(spellRankInfo[zoneName]) > 0) then |
||
555 | critterList = GFWTable.Merge(critterList, spellRankInfo[zoneName]); |
||
556 | end |
||
557 | if (FHH_NewInfo and FHH_NewInfo.SpellInfo and FHH_NewInfo.SpellInfo[spellID] and FHH_NewInfo.SpellInfo[spellID][rankNum] and FHH_NewInfo.SpellInfo[spellID][rankNum][zoneName]) then |
||
558 | critterList = GFWTable.Merge(critterList, FHH_NewInfo.SpellInfo[spellID][rankNum][zoneName]); |
||
559 | end |
||
560 | if (table.getn(critterList) > 0) then |
||
561 | GFWUtils.Print(GFWZones.LocalizedZone(zoneName)..": "..GFWUtils.Hilite(FHH_CreatureListString(critterList))); |
||
562 | numReportedZones = numReportedZones + 1; |
||
563 | end |
||
564 | |||
565 | local zoneConnections = GFWZones.ConnectionsForZone(zoneName); |
||
566 | |||
567 | if (zoneConnections == nil) then |
||
568 | -- player is in an unknown zone; instead of doing nothing, let's pick a known zone to start searching from. |
||
569 | local _, race = UnitRace("player"); |
||
570 | if (race == "Night Elf") then |
||
571 | zoneName = "Teldrassil"; |
||
572 | elseif (race == "Dwarf") then |
||
573 | zoneName = "Dun Morogh"; |
||
574 | elseif (race == "Gnome") then |
||
575 | zoneName = "Dun Morogh"; |
||
576 | elseif (race == "Human") then |
||
577 | zoneName = "Elwynn Forest"; |
||
578 | elseif (race == "Tauren") then |
||
579 | zoneName = "Mulgore"; |
||
580 | elseif (race == "Orc") then |
||
581 | zoneName = "Durotar"; |
||
582 | elseif (race == "Troll") then |
||
583 | zoneName = "Durotar"; |
||
584 | elseif (race == "Scourge") then |
||
585 | zoneName = "Tirisfal Glades"; |
||
586 | else |
||
587 | -- unlikely, but in case we can't parse the race name... |
||
588 | local faction = UnitFactionGroup("player"); |
||
589 | if (faction == "Alliance") then |
||
590 | zoneName = "Ironforge"; |
||
591 | elseif (faction == "Horde") then |
||
592 | zoneName = "Orgrimmar"; |
||
593 | else |
||
594 | -- on the off chance we can't even parse a major-faction name... |
||
595 | zoneName = "Stranglethorn Vale"; |
||
596 | end |
||
597 | end |
||
598 | zoneConnections = GFWZones.ConnectionsForZone(zoneName); |
||
599 | end |
||
600 | |||
601 | for _, zones in zoneConnections do |
||
602 | for _, zoneName in zones do |
||
603 | local critterList = {}; |
||
604 | if (spellRankInfo[zoneName] and table.getn(spellRankInfo[zoneName]) > 0) then |
||
605 | critterList = GFWTable.Merge(critterList, spellRankInfo[zoneName]); |
||
606 | end |
||
607 | if (FHH_NewInfo and FHH_NewInfo.SpellInfo and FHH_NewInfo.SpellInfo[spellID] and FHH_NewInfo.SpellInfo[spellID][rankNum] and FHH_NewInfo.SpellInfo[spellID][rankNum][zoneName]) then |
||
608 | critterList = GFWTable.Merge(critterList, FHH_NewInfo.SpellInfo[spellID][rankNum][zoneName]); |
||
609 | end |
||
610 | if (table.getn(critterList) > 0) then |
||
611 | GFWUtils.Print(GFWZones.LocalizedZone(zoneName)..": "..GFWUtils.Hilite(FHH_CreatureListString(critterList))); |
||
612 | numReportedZones = numReportedZones + 1; |
||
613 | if (numReportedZones >= maxZones) then return; end |
||
614 | end |
||
615 | end |
||
616 | end |
||
617 | |||
618 | if (numReportedZones == 0) then |
||
619 | -- if we get here, we think we know about the spell but can't find beasts with it in our table. this shouldn't happen. |
||
620 | GFWUtils.Print(GFWUtils.Red("Hunter's Helper "..FHH_VERSION.." error:").." got spell info for "..GFWUtils.Hilite(niceSpellName.." "..rankNum).." but no zone info. Please report to gazmik@fizzwidget.com."); |
||
621 | end |
||
622 | end |
||
623 | |||
624 | function FHH_CreatureListString(critterList) |
||
625 | local listString = "" |
||
626 | for _, name in critterList do |
||
627 | local info = FHH_BeastLevels[name]; |
||
628 | if (info == nil and FHH_NewInfo and FHH_NewInfo.BeastLevels) then |
||
629 | info = FHH_NewInfo.BeastLevels[name]; |
||
630 | end |
||
631 | if (info == nil) then |
||
632 | listString = listString..", "; |
||
633 | else |
||
634 | local unlocalizedName = FHH_Localized[name]; |
||
635 | if (unlocalizedName) then |
||
636 | name = unlocalizedName; |
||
637 | end |
||
638 | listString = listString .. name .. " "; |
||
639 | local myLevel = UnitLevel("player"); |
||
640 | local minLevel = info.min; |
||
641 | local maxLevel = info.max; |
||
642 | if (info.min > UnitLevel("player")) then |
||
643 | minLevel = RED_FONT_COLOR_CODE..info.min..FONT_COLOR_CODE_CLOSE; |
||
644 | end |
||
645 | if (info.max and info.max > UnitLevel("player")) then |
||
646 | maxLevel = RED_FONT_COLOR_CODE..info.max..FONT_COLOR_CODE_CLOSE; |
||
647 | end |
||
648 | if (info.min == info.max or info.max == nil) then |
||
649 | listString = listString.."("..minLevel; |
||
650 | else |
||
651 | listString = listString.."("..minLevel.."-"..maxLevel; |
||
652 | end |
||
653 | if (info.type == nil) then |
||
654 | listString = listString.."), "; |
||
655 | else |
||
656 | listString = listString.." "..info.type.."), "; |
||
657 | end |
||
658 | end |
||
659 | end |
||
660 | listString = string.gsub(listString, ", $", ""); |
||
661 | return listString; |
||
662 | end |
||
663 | |||
664 | function FHH_HasTameEffect(unit) |
||
665 | |||
666 | local i = 1; |
||
667 | local buff; |
||
668 | buff = UnitBuff(unit, i); |
||
669 | while buff do |
||
670 | if ( string.find(buff, "Ability_Hunter_BeastTaming") ) then |
||
671 | return true; |
||
672 | end |
||
673 | i = i + 1; |
||
674 | buff = UnitBuff(unit, i); |
||
675 | end |
||
676 | return false; |
||
677 | |||
678 | end |
||
679 | |||
680 | function FHH_SpellIDforName(spellName) |
||
681 | local spellID = FHH_SpellNamesToIDs[spellName]; |
||
682 | if (spellID == nil and FHH_NewInfo and FHH_NewInfo.SpellNamesToIDs) then |
||
683 | spellID = FHH_NewInfo.SpellNamesToIDs[spellName]; |
||
684 | end |
||
685 | return spellID; |
||
686 | end |
||
687 | |||
688 | function FHH_SpellIDforIcon(spellIcon, spellName) |
||
689 | local spellID = FHH_SpellIcons[spellIcon]; |
||
690 | if (spellID == nil and FHH_NewInfo and FHH_NewInfo.SpellIcons) then |
||
691 | spellID = FHH_NewInfo.SpellIcons[spellIcon]; |
||
692 | end |
||
693 | if (spellID == nil) then |
||
694 | spellID = FHH_SpellIDforName(spellName); |
||
695 | end |
||
696 | if (spellID == nil) then |
||
697 | spellID = FHH_RecordNewSpellIcon(spellIcon, spellName); |
||
698 | end |
||
699 | return spellID; |
||
700 | end |
||
701 | |||
702 | function FHH_CheckPetSpells() |
||
703 | local currentPetSpells = { }; |
||
704 | local i = 1; |
||
705 | local spellName, spellRank = GetSpellName(i, BOOKTYPE_PET); |
||
706 | local spellIcon = GetSpellTexture(i, BOOKTYPE_PET); |
||
707 | while spellName do |
||
708 | local _, _, rankNum = string.find(spellRank, "(%d+)"); |
||
709 | if (spellIcon) then |
||
710 | spellIcon = string.gsub(spellIcon, "^Interface\\Icons\\", ""); |
||
711 | end |
||
712 | local spellID = FHH_SpellIDforIcon(spellIcon, spellName); |
||
713 | local nameSpellID = FHH_SpellIDforName(spellName); |
||
714 | if (spellID and nameSpellID and spellID ~= nameSpellID) then |
||
715 | if (FHH_NewInfo == nil) then |
||
716 | FHH_NewInfo = {}; |
||
717 | end |
||
718 | if (FHH_NewInfo.SpellIDAliases == nil) then |
||
719 | FHH_NewInfo.SpellIDAliases = {}; |
||
720 | end |
||
721 | FHH_NewInfo.SpellIDAliases[nameSpellID] = spellID; |
||
722 | end |
||
723 | |||
724 | currentPetSpells[spellID] = tonumber(rankNum); |
||
725 | i = i + 1; |
||
726 | spellName, spellRank = GetSpellName(i, BOOKTYPE_PET); |
||
727 | spellIcon = GetSpellTexture(i, BOOKTYPE_PET); |
||
728 | end |
||
729 | |||
730 | if (GFWTable.Count(currentPetSpells) > 0) then |
||
731 | FHH_ProcessAliases(); |
||
732 | FHH_CheckSpellTables(FHH_State.TamingCritter, currentPetSpells); |
||
733 | else |
||
734 | --GFWUtils.Print("pet has no spells"); |
||
735 | end |
||
736 | end |
||
737 | |||
738 | function FHH_SpellDescription(spellID, rankNum) |
||
739 | local niceSpellName = FHH_SpellIDsToNames[spellID]; |
||
740 | if (niceSpellName == nil and FHH_NewInfo and FHH_NewInfo.SpellIDsToNames and FHH_NewInfo.SpellIDsToNames[spellID]) then |
||
741 | niceSpellName = FHH_NewInfo.SpellIDsToNames[spellID]; |
||
742 | end |
||
743 | if (niceSpellName == nil) then |
||
744 | niceSpellName = spellID; |
||
745 | end |
||
746 | return niceSpellName.." "..rankNum; |
||
747 | end |
||
748 | |||
749 | function FHH_SpellDescriptions(spellList) |
||
750 | local descriptions = {}; |
||
751 | for spellID, rankNum in spellList do |
||
752 | table.insert(descriptions, FHH_SpellDescription(spellID, rankNum)); |
||
753 | end |
||
754 | return descriptions; |
||
755 | end |
||
756 | |||
757 | function FHH_SpellDescripionList(spellList) |
||
758 | return table.concat(FHH_SpellDescriptions(spellList), ", "); |
||
759 | end |
||
760 | |||
761 | function FHH_CheckSpellTables(critter, spellList, level, family) |
||
762 | |||
763 | if ( spellList == nil or GFWTable.Count(spellList) == 0 ) then return; end |
||
764 | |||
765 | -- process any recently learned spellID aliases so we record data correctly. |
||
766 | local newSpellList = {}; |
||
767 | local changed = false; |
||
768 | for spellID, rankNum in spellList do |
||
769 | if (FHH_NewInfo and FHH_NewInfo.SpellIDAliases and FHH_NewInfo.SpellIDAliases[spellID]) then |
||
770 | spellID = FHH_NewInfo.SpellIDAliases[spellID]; |
||
771 | changed = true; |
||
772 | end |
||
773 | newSpellList[spellID] = rankNum; |
||
774 | end |
||
775 | if (changed) then |
||
776 | spellList = newSpellList; |
||
777 | end |
||
778 | |||
779 | if (level == nil) then |
||
780 | level = UnitLevel("pet"); |
||
781 | end |
||
782 | if (family == nil) then |
||
783 | family = UnitCreatureFamily("pet"); |
||
784 | end |
||
785 | |||
786 | if ( FHH_BeastInfo[critter] ) then |
||
787 | |||
788 | -- record any spells the critter has that our built-in table doesn't know about |
||
789 | local unknownPetSpells = { }; |
||
790 | for spellID, rankNum in spellList do |
||
791 | if ( FHH_BeastInfo[critter][spellID] == nil ) then |
||
792 | unknownPetSpells[spellID] = rankNum; |
||
793 | end |
||
794 | end |
||
795 | if ( GFWTable.Count(unknownPetSpells) > 0 ) then |
||
796 | if (FHH_NewInfo == nil) then |
||
797 | FHH_NewInfo = {}; |
||
798 | end |
||
799 | if (FHH_NewInfo.BeastInfo == nil) then |
||
800 | FHH_NewInfo.BeastInfo = {}; |
||
801 | end |
||
802 | FHH_NewInfo.BeastInfo[critter] = spellList; -- we want to remember the entire current spells list |
||
803 | end |
||
804 | |||
805 | -- record any spells our built-in table thinks the critter has, but the critter actually doesn't |
||
806 | local wrongPetSpells = { }; |
||
807 | for spellID, rankNum in FHH_BeastInfo[critter] do |
||
808 | if ( spellList[spellID] ~= rankNum ) then |
||
809 | wrongPetSpells[spellID] = rankNum; |
||
810 | end |
||
811 | end |
||
812 | if ( GFWTable.Count(wrongPetSpells) > 0 ) then |
||
813 | if (FHH_NewInfo == nil) then |
||
814 | FHH_NewInfo = {}; |
||
815 | end |
||
816 | if (FHH_NewInfo.BadBeastInfo == nil) then |
||
817 | FHH_NewInfo.BadBeastInfo = {}; |
||
818 | end |
||
819 | FHH_NewInfo.BadBeastInfo[critter] = wrongPetSpells; |
||
820 | end |
||
821 | |||
822 | if (FHH_NewInfo and (( FHH_NewInfo.BeastInfo and FHH_NewInfo.BeastInfo[critter]) or (FHH_NewInfo.BadBeastInfo and FHH_NewInfo.BadBeastInfo[critter]))) then |
||
823 | local details = "(expected "..FHH_SpellDescripionList(FHH_BeastInfo[critter]).."; found "..FHH_SpellDescripionList(spellList)..")."; |
||
824 | GFWUtils.PrintOnce("Hunter's Helper "..FHH_VERSION.." has incorrect data on "..GFWUtils.Hilite(critter.." "..details).." Please submit a correction to gazmik@fizzwidget.com.)", 60); |
||
825 | end |
||
826 | |||
827 | else |
||
828 | |||
829 | -- this pet is entirely new to our list |
||
830 | if (FHH_NewInfo == nil) then |
||
831 | FHH_NewInfo = {}; |
||
832 | end |
||
833 | if (FHH_NewInfo.BeastInfo == nil) then |
||
834 | FHH_NewInfo.BeastInfo = {}; |
||
835 | end |
||
836 | FHH_NewInfo.BeastInfo[critter] = spellList; |
||
837 | FHH_CheckBeastLevel(critter, level, FHH_State.TamingType); |
||
838 | |||
839 | local details = "(found "..FHH_SpellDescripionList(spellList).." in "..GetRealZoneText()..")."; |
||
840 | GFWUtils.PrintOnce("Hunter's Helper "..FHH_VERSION.." has no data on "..GFWUtils.Hilite(critter.." "..details).." Please submit a correction to gazmik@fizzwidget.com.)", 60); |
||
841 | |||
842 | end |
||
843 | |||
844 | for spellID, rankNum in spellList do |
||
845 | FHH_RecordNewSpellInfo(spellID, rankNum, critter); |
||
846 | FHH_RecordNewRequiredFamily(spellID, family); |
||
847 | FHH_RecordNewRequiredLevel(spellID, rankNum, level); |
||
848 | end |
||
849 | |||
850 | end |
||
851 | |||
852 | function FHH_RecordNewSpellInfo(spellID, rankNum, critter) |
||
853 | if (FHH_SpellInfo[spellID] and FHH_SpellInfo[spellID][rankNum]) then |
||
854 | for zoneName, beastsTable in FHH_SpellInfo[spellID][rankNum] do |
||
855 | for _, aBeast in beastsTable do |
||
856 | if (aBeast == critter) then |
||
857 | return; -- we've already recorded this in our static data |
||
858 | end |
||
859 | end |
||
860 | end |
||
861 | end |
||
862 | |||
863 | if (FHH_NewInfo == nil) then |
||
864 | FHH_NewInfo = {}; |
||
865 | end |
||
866 | if (FHH_NewInfo.SpellInfo == nil) then |
||
867 | FHH_NewInfo.SpellInfo = {}; |
||
868 | end |
||
869 | if (FHH_NewInfo.SpellInfo[spellID] == nil) then |
||
870 | FHH_NewInfo.SpellInfo[spellID] = {}; |
||
871 | end |
||
872 | if (FHH_NewInfo.SpellInfo[spellID][rankNum] == nil) then |
||
873 | FHH_NewInfo.SpellInfo[spellID][rankNum] = {}; |
||
874 | end |
||
875 | local currentZone = GFWZones.UnlocalizedZone(GetRealZoneText()); |
||
876 | if (FHH_NewInfo.SpellInfo[spellID][rankNum][currentZone] == nil) then |
||
877 | FHH_NewInfo.SpellInfo[spellID][rankNum][currentZone] = {}; |
||
878 | end |
||
879 | if (not GFWTable.KeyOf(FHH_NewInfo.SpellInfo[spellID][rankNum][currentZone], critter)) then |
||
880 | table.insert(FHH_NewInfo.SpellInfo[spellID][rankNum][currentZone], critter); |
||
881 | end |
||
882 | end |
||
883 | |||
884 | function FHH_RecordNewRequiredFamily(spellID, family) |
||
885 | if (FHH_LearnableBy[spellID] and GFWTable.KeyOf(FHH_LearnableBy[spellID], family)) then |
||
886 | return; -- we've already recorded this in our static data |
||
887 | end |
||
888 | |||
889 | if (FHH_NewInfo == nil) then |
||
890 | FHH_NewInfo = {}; |
||
891 | end |
||
892 | if (FHH_NewInfo.LearnableBy == nil) then |
||
893 | FHH_NewInfo.LearnableBy = {}; |
||
894 | end |
||
895 | if (FHH_NewInfo.LearnableBy[spellID] == nil) then |
||
896 | FHH_NewInfo.LearnableBy[spellID] = {}; |
||
897 | end |
||
898 | if (not GFWTable.KeyOf(FHH_NewInfo.LearnableBy[spellID], family)) then |
||
899 | table.insert(FHH_NewInfo.LearnableBy[spellID], family); |
||
900 | end |
||
901 | end |
||
902 | |||
903 | function FHH_RecordNewRequiredLevel(spellID, rankNum, level, verified) |
||
904 | if (FHH_RequiredLevel[spellID] and FHH_RequiredLevel[spellID][rankNum]) then |
||
905 | return; -- we've already recorded this in our static data |
||
906 | end |
||
907 | |||
908 | if (FHH_NewInfo == nil) then |
||
909 | FHH_NewInfo = {}; |
||
910 | end |
||
911 | if (FHH_NewInfo.RequiredLevel == nil) then |
||
912 | FHH_NewInfo.RequiredLevel = {}; |
||
913 | end |
||
914 | if (FHH_NewInfo.RequiredLevel[spellID] == nil) then |
||
915 | FHH_NewInfo.RequiredLevel[spellID] = {}; |
||
916 | end |
||
917 | if (verified) then |
||
918 | FHH_NewInfo.RequiredLevel[spellID][rankNum] = level; |
||
919 | elseif (FHH_NewInfo.RequiredLevel[spellID][rankNum] == nil) then |
||
920 | FHH_NewInfo.RequiredLevel[spellID][rankNum] = tostring(level); |
||
921 | else |
||
922 | local existingRank = FHH_NewInfo.RequiredLevel[spellID][rankNum]; |
||
923 | if (type(existingRank) == "string") then |
||
924 | -- we don't have a certain answer yet, we'll use what we just got to refine it |
||
925 | FHH_NewInfo.RequiredLevel[spellID][rankNum] = tostring(math.min(level, tonumber(existingRank))); |
||
926 | end |
||
927 | end |
||
928 | end |
||
929 | |||
930 | function FHH_CheckBeastLevel(creepName, creepLevel, creepType) |
||
931 | if (creepLevel < 1) then |
||
932 | return; -- UnitLevel sometimes returns -1 for common mobs (maybe a WDB cache thing) so we toss nonsensical values. |
||
933 | end |
||
934 | |||
935 | if (FHH_NewInfo and FHH_NewInfo.BeastLevels and FHH_NewInfo.BeastLevels[creepName]) then |
||
936 | FHH_NewInfo.BeastLevels[creepName].min = math.min(FHH_NewInfo.BeastLevels[creepName].min, creepLevel); |
||
937 | FHH_NewInfo.BeastLevels[creepName].max = math.max(FHH_NewInfo.BeastLevels[creepName].max, creepLevel); |
||
938 | if (FHH_NewInfo.BeastLevels[creepName].type and creepType ~= "normal") then |
||
939 | FHH_NewInfo.BeastLevels[creepName].type = creepType; |
||
940 | end |
||
941 | elseif (FHH_BeastLevels[creepName]) then |
||
942 | if (creepLevel < FHH_BeastLevels[creepName].min or (FHH_BeastLevels[creepName].max and creepLevel > FHH_BeastLevels[creepName].max)) then |
||
943 | if (FHH_NewInfo == nil) then |
||
944 | FHH_NewInfo = {}; |
||
945 | end |
||
946 | if (FHH_NewInfo.BeastLevels == nil) then |
||
947 | FHH_NewInfo.BeastLevels = {}; |
||
948 | end |
||
949 | FHH_NewInfo.BeastLevels[creepName] = {}; |
||
950 | FHH_NewInfo.BeastLevels[creepName].min = math.min(FHH_BeastLevels[creepName].min, creepLevel); |
||
951 | FHH_NewInfo.BeastLevels[creepName].max = math.max(FHH_BeastLevels[creepName].max or FHH_BeastLevels[creepName].min, creepLevel); |
||
952 | end |
||
953 | if (creepType ~= "normal" and creepType ~= FHH_BeastLevels[creepName].type) then |
||
954 | if (FHH_NewInfo == nil) then |
||
955 | FHH_NewInfo = {}; |
||
956 | end |
||
957 | if (FHH_NewInfo.BeastLevels == nil) then |
||
958 | FHH_NewInfo.BeastLevels = {}; |
||
959 | end |
||
960 | if (FHH_NewInfo.BeastLevels[creepName] == nil) then |
||
961 | FHH_NewInfo.BeastLevels[creepName] = {}; |
||
962 | end |
||
963 | FHH_NewInfo.BeastLevels[creepName].min = math.min(FHH_BeastLevels[creepName].min, creepLevel); |
||
964 | FHH_NewInfo.BeastLevels[creepName].max = math.max(FHH_BeastLevels[creepName].max or FHH_BeastLevels[creepName].min, creepLevel); |
||
965 | FHH_NewInfo.BeastLevels[creepName].type = creepType; |
||
966 | end |
||
967 | end |
||
968 | end |
||
969 | |||
970 | function FHH_RecordNewSpellID(spellName) |
||
971 | -- we have a new spell on our hands; we'll use its lowercase name as a key for now. |
||
972 | spellID = string.lower(spellName); |
||
973 | if (FHH_NewInfo == nil) then |
||
974 | FHH_NewInfo = {}; |
||
975 | end |
||
976 | if (FHH_NewInfo.SpellNamesToIDs == nil) then |
||
977 | FHH_NewInfo.SpellNamesToIDs = {}; |
||
978 | end |
||
979 | if (FHH_NewInfo.SpellIDsToNames == nil) then |
||
980 | FHH_NewInfo.SpellIDsToNames = {}; |
||
981 | end |
||
982 | FHH_NewInfo.SpellNamesToIDs[spellName] = spellID; |
||
983 | FHH_NewInfo.SpellIDsToNames[spellID] = spellName; |
||
984 | return spellID; |
||
985 | end |
||
986 | |||
987 | function FHH_RecordNewSpellIcon(spellIcon, spellName) |
||
988 | spellID = FHH_RecordNewSpellID(spellName); |
||
989 | if (FHH_NewInfo == nil) then |
||
990 | FHH_NewInfo = {}; |
||
991 | end |
||
992 | if (FHH_NewInfo.SpellIcons == nil) then |
||
993 | FHH_NewInfo.SpellIcons = {}; |
||
994 | end |
||
995 | FHH_NewInfo.SpellIcons[spellIcon] = spellID; |
||
996 | return spellID; |
||
997 | end |
||
998 | |||
999 | function FHH_ProcessAliases() |
||
1000 | if (FHH_NewInfo and FHH_NewInfo.SpellIDAliases) then |
||
1001 | for oldID, newID in FHH_NewInfo.SpellIDAliases do |
||
1002 | |||
1003 | if (FHH_NewInfo.SpellNamesToIDs) then |
||
1004 | local newNamesToIDs = {}; |
||
1005 | local changed = false; |
||
1006 | for name, id in FHH_NewInfo.SpellNamesToIDs do |
||
1007 | if (id == oldID) then |
||
1008 | newNamesToIDs[name] = newID; |
||
1009 | changed = true; |
||
1010 | else |
||
1011 | newNamesToIDs[name] = id; |
||
1012 | end |
||
1013 | end |
||
1014 | if (changed) then |
||
1015 | FHH_NewInfo.SpellNamesToIDs = newNamesToIDs; |
||
1016 | end |
||
1017 | end |
||
1018 | |||
1019 | if (FHH_NewInfo.BeastInfo) then |
||
1020 | for beast, spellList in FHH_NewInfo.BeastInfo do |
||
1021 | if (spellList[oldID]) then |
||
1022 | spellList[newID] = spellList[oldID]; |
||
1023 | spellList[oldID] = nil; |
||
1024 | end |
||
1025 | end |
||
1026 | end |
||
1027 | |||
1028 | if (FHH_NewInfo.BadBeastInfo) then |
||
1029 | for beast, spellList in FHH_NewInfo.BadBeastInfo do |
||
1030 | if (spellList[oldID]) then |
||
1031 | spellList[newID] = spellList[oldID]; |
||
1032 | spellList[oldID] = nil; |
||
1033 | end |
||
1034 | end |
||
1035 | end |
||
1036 | |||
1037 | if (FHH_AbilityInfo) then |
||
1038 | for realmPlayer, abilityTable in FHH_AbilityInfo do |
||
1039 | if (abilityTable[oldID]) then |
||
1040 | abilityTable[newID] = abilityTable[oldID]; |
||
1041 | abilityTable[oldID] = nil; |
||
1042 | end |
||
1043 | end |
||
1044 | end |
||
1045 | |||
1046 | if (FHH_NewInfo.SpellIDsToNames and FHH_NewInfo.SpellIDsToNames[oldID]) then |
||
1047 | FHH_NewInfo.SpellIDsToNames[newID] = FHH_NewInfo.SpellIDsToNames[oldID]; |
||
1048 | FHH_NewInfo.SpellIDsToNames[oldID] = nil; |
||
1049 | end |
||
1050 | |||
1051 | if (FHH_NewInfo.RequiredLevel and FHH_NewInfo.RequiredLevel[oldID]) then |
||
1052 | FHH_NewInfo.RequiredLevel[newID] = FHH_NewInfo.RequiredLevel[oldID]; |
||
1053 | FHH_NewInfo.RequiredLevel[oldID] = nil; |
||
1054 | end |
||
1055 | |||
1056 | if (FHH_NewInfo.LearnableBy and FHH_NewInfo.LearnableBy[oldID]) then |
||
1057 | FHH_NewInfo.LearnableBy[newID] = FHH_NewInfo.LearnableBy[oldID]; |
||
1058 | FHH_NewInfo.LearnableBy[oldID] = nil; |
||
1059 | end |
||
1060 | |||
1061 | if (FHH_NewInfo.SpellInfo and FHH_NewInfo.SpellInfo[oldID]) then |
||
1062 | FHH_NewInfo.SpellInfo[newID] = FHH_NewInfo.SpellInfo[oldID]; |
||
1063 | FHH_NewInfo.SpellInfo[oldID] = nil; |
||
1064 | end |
||
1065 | end |
||
1066 | end |
||
1067 | end |
||
1068 |