vanilla-wow-addons – Blame information for rev 1

Subversion Repositories:
Rev:
Rev Author Line No. Line
1 office 1 --------------------------------------------------
2 -- BonusScanner v1.1
3 -- by Crowley <crowley@headshot.de>
4 -- performance improvements by Archarodim
5 --
6 -- get the latest version here:
7 -- http://ui.worldofwar.net/ui.php?id=1461
8 -- http://www.curse-gaming.com/mod.php?addid=2384
9 --------------------------------------------------
10  
11 BONUSSCANNER_VERSION = "v1.0";
12  
13  
14 BONUSSCANNER_PATTERN_SETNAME = "^(.*) %(%d/%d%)$";
15 BONUSSCANNER_PATTERN_GENERIC_PREFIX = "^%+(%d+)%%?(.*)$";
16 BONUSSCANNER_PATTERN_GENERIC_SUFFIX = "^(.*)%+(%d+)%%?$";
17  
18 BonusScanner = {
19 bonuses = {};
20 bonuses_details = {};
21  
22 IsUpdating = false; -- not sure if this check is needed but who knows with multithreading...
23 MinCheckInterval = 1; -- Minimum time to wait between each scan
24 CheckIntervalCounter = 0; -- counter, do not change
25 CheckForBonusPlease = 0; -- The flag that when set makes BonusScanner scan the equipment and call the update function
26 ShowDebug = false; -- tells when the equipment is scanned
27  
28 active = nil;
29 temp = {
30 sets = {},
31 set = "",
32 slot = "",
33 bonuses = {},
34 details = {}
35 };
36  
37 types = {
38 "STR", -- strength
39 "AGI", -- agility
40 "STA", -- stamina
41 "INT", -- intellect
42 "SPI", -- spirit
43 "ARMOR", -- reinforced armor (not base armor)
44  
45 "ARCANERES", -- arcane resistance
46 "FIRERES", -- fire resistance
47 "NATURERES", -- nature resistance
48 "FROSTRES", -- frost resistance
49 "SHADOWRES", -- shadow resistance
50  
51 "FISHING", -- fishing skill
52 "MINING", -- mining skill
53 "HERBALISM", -- herbalism skill
54 "SKINNING", -- skinning skill
55 "DEFENSE", -- defense skill
56  
57 "BLOCK", -- chance to block
58 "DODGE", -- chance to dodge
59 "PARRY", -- chance to parry
60 "ATTACKPOWER", -- attack power
61 "ATTACKPOWERUNDEAD", -- attack power against undead
62  
63 "CRIT", -- chance to get a critical strike
64 "RANGEDATTACKPOWER", -- ranged attack power
65 "RANGEDCRIT", -- chance to get a crit with ranged weapons
66 "TOHIT", -- chance to hit
67  
68 "DMG", -- spell damage
69 "DMGUNDEAD", -- spell damage against undead
70  
71 "ARCANEDMG", -- arcane spell damage
72 "FIREDMG", -- fire spell damage
73 "FROSTDMG", -- frost spell damage
74 "HOLYDMG", -- holy spell damage
75 "NATUREDMG", -- nature spell damage
76 "SHADOWDMG", -- shadow spell damage
77 "SPELLCRIT", -- chance to crit with spells
78 "HEAL", -- healing
79 "HOLYCRIT", -- chance to crit with holy spells
80 "SPELLTOHIT", -- Chance to Hit with spells
81  
82 "SPELLPEN", -- amount of spell resist reduction
83  
84 "HEALTHREG", -- health regeneration per 5 sec.
85 "MANAREG", -- mana regeneration per 5 sec.
86 "HEALTH", -- health points
87 "MANA", -- mana points
88 };
89  
90 slots = {
91 "Head",
92 "Neck",
93 "Shoulder",
94 "Shirt",
95 "Chest",
96 "Waist",
97 "Legs",
98 "Feet",
99 "Wrist",
100 "Hands",
101 "Finger0",
102 "Finger1",
103 "Trinket0",
104 "Trinket1",
105 "Back",
106 "MainHand",
107 "SecondaryHand",
108 "Ranged",
109 "Tabard",
110 };
111 }
112  
113 -- Update function to hook into.
114 -- Gets called, when Equipment changes (after UNIT_INVENTORY_CHANGED)
115 function BonusScanner_Update()
116 end
117  
118 function BonusScanner:GetBonus(bonus)
119 if(BonusScanner.bonuses[bonus]) then
120 return BonusScanner.bonuses[bonus];
121 end;
122 return 0;
123 end
124  
125 function BonusScanner:GetSlotBonuses(slotname)
126 local i, bonus, details;
127 local bonuses = {};
128 for bonus, details in BonusScanner.bonuses_details do
129 if(details[slotname]) then
130 bonuses[bonus] = details[slotname];
131 end
132 end
133 return bonuses;
134 end
135  
136 function BonusScanner:GetBonusDetails(bonus)
137 if(BonusScanner.bonuses_details[bonus]) then
138 return BonusScanner.bonuses_details[bonus];
139 end;
140 return {};
141 end
142  
143 function BonusScanner:GetSlotBonus(bonus, slotname)
144 if(BonusScanner.bonuses_details[bonus]) then
145 if(BonusScanner.bonuses_details[bonus][slotname]) then
146 return BonusScanner.bonuses_details[bonus][slotname];
147 end;
148 end;
149 return 0;
150 end
151  
152  
153 function BonusScanner:OnLoad()
154 this:RegisterEvent("PLAYER_ENTERING_WORLD");
155 this:RegisterEvent("PLAYER_LEAVING_WORLD");
156 end
157  
158 function BonusScanner:OnEvent()
159  
160 BonusScanner:Debug(event);
161  
162 if ((event == "UNIT_INVENTORY_CHANGED") and BonusScanner.active) then
163 BonusScanner.CheckForBonusPlease = 1;
164 return;
165 end
166 if (event == "PLAYER_ENTERING_WORLD") then
167 BonusScanner.active = 1;
168 BonusScanner.CheckForBonusPlease = 1;
169 this:RegisterEvent("UNIT_INVENTORY_CHANGED");
170 return;
171 end
172 if (event == "PLAYER_LEAVING_WORLD") then
173 this:UnregisterEvent("UNIT_INVENTORY_CHANGED");
174 return;
175 end
176 end
177  
178  
179 -- A little debug function
180 function BonusScanner:Debug( Message )
181 if (BonusScanner.ShowDebug) then
182 DEFAULT_CHAT_FRAME:AddMessage("Bonnus-Scanner: " .. Message, 0.5, 0.8, 1);
183 end
184 end
185  
186 -- The use of the <OnUpdate></OnUpdate> *feature* avoid freezes and lags caused by the useless repeated call of BonusScanner:ScanEquipment()...
187 function BonusScanner:OnUpdate (elapsed)
188  
189 -- BonusScanner:Debug(elapsed);
190 if (BonusScanner.IsUpdating) then
191 return;
192 end
193  
194 BonusScanner.IsUpdating = true;
195  
196 -- if the equipment has changed then check if we are allowed to test for bonuses
197 if (BonusScanner.CheckForBonusPlease == 1) then
198  
199 BonusScanner.CheckIntervalCounter = BonusScanner.CheckIntervalCounter + elapsed;
200  
201 -- if we have wait long enough then proceed...
202 if (BonusScanner.CheckIntervalCounter > BonusScanner.MinCheckInterval) then
203 BonusScanner.CheckForBonusPlease = 2; -- means we are currently checking
204 BonusScanner:ScanEquipment(); -- scan the equiped items
205 BonusScanner_Update(); -- call the update function (for the mods using this library)
206 if (BonusScanner.CheckForBonusPlease ~= 1) then -- if no other update has been requested
207 BonusScanner.CheckForBonusPlease = 0;
208 end
209 BonusScanner.CheckIntervalCounter = 0;
210 end
211 end
212  
213 BonusScanner.IsUpdating = false;
214 end
215  
216 function BonusScanner:ScanEquipment()
217 local slotid, slotname, hasItem, i;
218  
219 BonusScannerTooltip:SetOwner(UIParent, "ANCHOR_NONE");
220  
221 BonusScanner:Debug("Scanning Equipment has requested");
222  
223 BonusScanner.temp.bonuses = {};
224 BonusScanner.temp.details = {};
225 BonusScanner.temp.sets = {};
226 BonusScanner.temp.set = "";
227  
228 for i, slotname in BonusScanner.slots do
229 slotid, _ = GetInventorySlotInfo(slotname.. "Slot");
230 hasItem = BonusScannerTooltip:SetInventoryItem("player", slotid);
231  
232 if ( hasItem ) then
233 BonusScanner.temp.slot = slotname;
234 BonusScanner:ScanTooltip();
235 -- if set item, mark set as already scanned
236 if(BonusScanner.temp.set ~= "") then
237 BonusScanner.temp.sets[BonusScanner.temp.set] = 1;
238 end;
239 end
240 end
241 BonusScanner.bonuses = BonusScanner.temp.bonuses;
242 BonusScanner.bonuses_details = BonusScanner.temp.details;
243 end
244  
245 function BonusScanner:ScanItem(itemlink)
246 local name = GetItemInfo(itemlink);
247 if(name) then
248 BonusScanner.temp.bonuses = {};
249 BonusScanner.temp.sets = {};
250 BonusScanner.temp.set = "";
251 BonusScanner.temp.slot = "";
252 BonusScannerTooltip:SetHyperlink(itemlink);
253 BonusScanner:ScanTooltip();
254 return BonusScanner.temp.bonuses;
255 end
256 return false;
257 end
258  
259 function BonusScanner:ScanTooltip()
260 local tmpTxt, line;
261 local lines = BonusScannerTooltip:NumLines();
262  
263 for i=2, lines, 1 do
264 tmpText = getglobal("BonusScannerTooltipTextLeft"..i);
265 val = nil;
266 if (tmpText:GetText()) then
267 line = tmpText:GetText();
268 BonusScanner:ScanLine(line);
269 end
270 end
271 end
272  
273 function BonusScanner:AddValue(effect, value)
274 local i,e;
275  
276 if(type(effect) == "string") then
277 if(BonusScanner.temp.bonuses[effect]) then
278 BonusScanner.temp.bonuses[effect] = BonusScanner.temp.bonuses[effect] + value;
279 else
280 BonusScanner.temp.bonuses[effect] = value;
281 end
282  
283 if(BonusScanner.temp.slot) then
284 if(BonusScanner.temp.details[effect]) then
285 if(BonusScanner.temp.details[effect][BonusScanner.temp.slot]) then
286 BonusScanner.temp.details[effect][BonusScanner.temp.slot] = BonusScanner.temp.details[effect][BonusScanner.temp.slot] + value;
287 else
288 BonusScanner.temp.details[effect][BonusScanner.temp.slot] = value;
289 end
290 else
291 BonusScanner.temp.details[effect] = {};
292 BonusScanner.temp.details[effect][BonusScanner.temp.slot] = value;
293 end
294 end;
295 else
296 -- list of effects
297 if(type(value) == "table") then
298 for i,e in effect do
299 BonusScanner:AddValue(e, value[i]);
300 end
301 else
302 for i,e in effect do
303 BonusScanner:AddValue(e, value);
304 end
305 end
306 end
307 end;
308  
309 function BonusScanner:ScanLine(line)
310 local tmpStr, found;
311 -- Check for "Equip: "
312 if(string.sub(line,0,string.len(BONUSSCANNER_PREFIX_EQUIP)) == BONUSSCANNER_PREFIX_EQUIP) then
313  
314 tmpStr = string.sub(line,string.len(BONUSSCANNER_PREFIX_EQUIP)+1);
315 BonusScanner:CheckPassive(tmpStr);
316  
317 -- Check for "Set: "
318 elseif(string.sub(line,0,string.len(BONUSSCANNER_PREFIX_SET)) == BONUSSCANNER_PREFIX_SET
319 and BonusScanner.temp.set ~= ""
320 and not BonusScanner.temp.sets[BonusScanner.temp.set]) then
321  
322 tmpStr = string.sub(line,string.len(BONUSSCANNER_PREFIX_SET)+1);
323 BonusScanner.temp.slot = "Set";
324 BonusScanner:CheckPassive(tmpStr);
325  
326 -- any other line (standard stats, enchantment, set name, etc.)
327 else
328 -- Check for set name
329 _, _, tmpStr = string.find(line, BONUSSCANNER_PATTERN_SETNAME);
330 if(tmpStr) then
331 BonusScanner.temp.set = tmpStr;
332 else
333 found = BonusScanner:CheckGeneric(line);
334 if(not found) then
335 BonusScanner:CheckOther(line);
336 end;
337 end
338 end
339 end;
340  
341  
342 -- Scans passive bonuses like "Set: " and "Equip: "
343 function BonusScanner:CheckPassive(line)
344 local i, p, value, found;
345  
346 found = nil;
347 for i,p in BONUSSCANNER_PATTERNS_PASSIVE do
348 _, _, value = string.find(line, "^" .. p.pattern);
349 if(value) then
350 BonusScanner:AddValue(p.effect, value)
351 found = 1;
352 break; -- prevent duplicated patterns to cause bonuses to be counted several times
353 end
354 end
355 if(not found) then
356 BonusScanner:Debug("\"" .. line .. "\"");
357 BonusScanner:CheckGeneric(line);
358 end
359 end
360  
361  
362 -- Scans generic bonuses like "+3 Intellect" or "Arcane Resistance +4"
363 function BonusScanner:CheckGeneric(line)
364 local value, token, pos, tmpStr, found;
365  
366 -- split line at "/" for enchants with multiple effects
367 found = false;
368 while(string.len(line) > 0) do
369 pos = string.find(line, "/", 1, true);
370 if(pos) then
371 tmpStr = string.sub(line,1,pos-1);
372 line = string.sub(line,pos+1);
373 else
374 tmpStr = line;
375 line = "";
376 end
377  
378 -- trim line
379 tmpStr = string.gsub( tmpStr, "^%s+", "" );
380 tmpStr = string.gsub( tmpStr, "%s+$", "" );
381 tmpStr = string.gsub( tmpStr, "%.$", "" );
382  
383 _, _, value, token = string.find(tmpStr, BONUSSCANNER_PATTERN_GENERIC_PREFIX);
384 if(not value) then
385 _, _, token, value = string.find(tmpStr, BONUSSCANNER_PATTERN_GENERIC_SUFFIX);
386 end
387 if(token and value) then
388 -- trim token
389 token = string.gsub( token, "^%s+", "" );
390 token = string.gsub( token, "%s+$", "" );
391 token = string.gsub( token, "%.$", "" );
392  
393 if(BonusScanner:CheckToken(token,value)) then
394 found = true;
395 end
396 end
397 end
398 return found;
399 end
400  
401  
402 -- Identifies simple tokens like "Intellect" and composite tokens like "Fire damage" and
403 -- add the value to the respective bonus.
404 -- returns true if some bonus is found
405 function BonusScanner:CheckToken(token, value)
406 local i, p, s1, s2;
407  
408 if(BONUSSCANNER_PATTERNS_GENERIC_LOOKUP[token]) then
409 BonusScanner:AddValue(BONUSSCANNER_PATTERNS_GENERIC_LOOKUP[token], value);
410 return true;
411 else
412 s1 = nil;
413 s2 = nil;
414 for i,p in BONUSSCANNER_PATTERNS_GENERIC_STAGE1 do
415 if(string.find(token,p.pattern,1,1)) then
416 s1 = p.effect;
417 end
418 end
419 for i,p in BONUSSCANNER_PATTERNS_GENERIC_STAGE2 do
420 if(string.find(token,p.pattern,1,1)) then
421 s2 = p.effect;
422 end
423 end
424 if(s1 and s2) then
425 BonusScanner:AddValue(s1..s2, value);
426 return true;
427 end
428 end
429 return false;
430 end
431  
432 -- Last fallback for non generic enchants, like "Mana Regen x per 5 sec."
433 function BonusScanner:CheckOther(line)
434 local i, p, value, start, found;
435  
436 for i,p in BONUSSCANNER_PATTERNS_OTHER do
437 start, _, value = string.find(line, "^" .. p.pattern);
438 if(start) then
439 if(p.value) then
440 BonusScanner:AddValue(p.effect, p.value)
441 elseif(value) then
442 BonusScanner:AddValue(p.effect, value)
443 end
444 return true;
445 end
446 end
447 return false;
448 end
449  
450  
451  
452 -- Slash Command functions
453  
454 function BonusScanner_Cmd(cmd)
455  
456 local _, _, itemlink, itemid = string.find(cmd, "|c%x+|H(item:(%d+):%d+:%d+:%d+)|h%[.-%]|h|r");
457 if(itemid) then
458 local name = GetItemInfo(itemid);
459 if(name) then
460 DEFAULT_CHAT_FRAME:AddMessage(GREEN_FONT_COLOR_CODE .. "Item bonuses of: " .. HIGHLIGHT_FONT_COLOR_CODE .. name);
461 local bonuses = BonusScanner:ScanItem(itemlink);
462 if(not bonuses) then
463 DEFAULT_CHAT_FRAME:AddMessage(GREEN_FONT_COLOR_CODE .. "error scanning item (probably not cached)");
464 else
465 BonusScanner:PrintInfo(bonuses);
466 end
467 end
468 return;
469 end
470 if(string.lower(cmd) == "show") then
471 DEFAULT_CHAT_FRAME:AddMessage(GREEN_FONT_COLOR_CODE .. "Current equipment bonuses:");
472 BonusScanner:PrintInfo(BonusScanner.bonuses);
473 return;
474 end
475 if(string.lower(cmd) == "details") then
476 DEFAULT_CHAT_FRAME:AddMessage(GREEN_FONT_COLOR_CODE .. "Current equipment bonus details:");
477 BonusScanner:PrintInfoDetailed();
478 return;
479 end
480 for i, slotname in BonusScanner.slots do
481 if(string.lower(cmd) == string.lower(slotname)) then
482 DEFAULT_CHAT_FRAME:AddMessage(GREEN_FONT_COLOR_CODE .. "Bonuses of '"..LIGHTYELLOW_FONT_COLOR_CODE .. slotname .. GREEN_FONT_COLOR_CODE .. "' slot:");
483 local bonuses = BonusScanner:GetSlotBonuses(slotname);
484 BonusScanner:PrintInfo(bonuses);
485 return
486 end;
487 end
488 DEFAULT_CHAT_FRAME:AddMessage(GREEN_FONT_COLOR_CODE .. "BonusScanner " .. BONUSSCANNER_VERSION .. " by Crowley");
489 DEFAULT_CHAT_FRAME:AddMessage(GREEN_FONT_COLOR_CODE .. "/bscan show - shows all bonus of the current equipment");
490 DEFAULT_CHAT_FRAME:AddMessage(GREEN_FONT_COLOR_CODE .. "/bscan details - shows bonuses with slot distribution");
491 DEFAULT_CHAT_FRAME:AddMessage(GREEN_FONT_COLOR_CODE .. "/bscan <itemlink> - shows bonuses of linked item (insert link with Shift-Click)");
492 DEFAULT_CHAT_FRAME:AddMessage(GREEN_FONT_COLOR_CODE .. "/bscan <slotname> - shows bonuses of given equipment slot");
493 end
494  
495 SLASH_BONUSSCANNER1 = "/bonusscanner";
496 SLASH_BONUSSCANNER2 = "/bscan";
497 SlashCmdList["BONUSSCANNER"] = BonusScanner_Cmd;
498  
499  
500 function BonusScanner:PrintInfoDetailed()
501 local bonus, name, i, j, slot, first, s;
502 for i, bonus in BonusScanner.types do
503 if(BonusScanner.bonuses[bonus]) then
504 first = true;
505 s = "(";
506 for j, slot in BonusScanner.slots do
507 if(BonusScanner.bonuses_details[bonus][slot]) then
508 if(not first) then
509 s = s .. ", ";
510 else
511 first = false;
512 end
513 s = s .. LIGHTYELLOW_FONT_COLOR_CODE .. slot ..
514 HIGHLIGHT_FONT_COLOR_CODE .. ": " .. BonusScanner.bonuses_details[bonus][slot];
515 end
516 end;
517 if(BonusScanner.bonuses_details[bonus]["Set"]) then
518 if(not first) then
519 s = s .. ", ";
520 end
521 s = s .. LIGHTYELLOW_FONT_COLOR_CODE .. "Set" ..
522 HIGHLIGHT_FONT_COLOR_CODE .. ": " .. BonusScanner.bonuses_details[bonus]["Set"];
523 end
524 s = s .. ")";
525 DEFAULT_CHAT_FRAME:AddMessage(GREEN_FONT_COLOR_CODE .. BONUSSCANNER_NAMES[bonus] .. ": " .. HIGHLIGHT_FONT_COLOR_CODE .. BonusScanner.bonuses[bonus] .. " " .. s);
526 end
527 end
528 end
529  
530 function BonusScanner:PrintInfo(bonuses)
531 local bonus, i;
532 for i, bonus in BonusScanner.types do
533 if(bonuses[bonus]) then
534 DEFAULT_CHAT_FRAME:AddMessage(GREEN_FONT_COLOR_CODE .. BONUSSCANNER_NAMES[bonus] .. ": " .. HIGHLIGHT_FONT_COLOR_CODE .. bonuses[bonus]);
535 end
536 end
537 end