vanilla-wow-addons – Blame information for rev 1

Subversion Repositories:
Rev:
Rev Author Line No. Line
1 office 1 --[[
2  
3 PvPLog
4 Author: Josh Estelle
5 Version: 0.4.6
6 Last Modified: 2005-04-27
7  
8 ]]
9  
10 -- version information
11 local VER_NUM = 0;
12 local VER_SUB = 4;
13 local VER_REL = 6;
14  
15 -- Function hooks
16 local lOriginalChatFrame_OnEvent;
17  
18 -- Local variables
19 local variablesLoaded = false;
20 local initialized = false;
21  
22 local realm = "";
23 local player = "";
24 local plevel = -1;
25  
26 local NUMRECENT = 10;
27 local recentTargets = { };
28  
29 local NUMDAMAGED = 5;
30 local damagedTargets = { };
31  
32 local lastDamagerToMe = "";
33  
34 local lastDing = -1000;
35  
36 local yourDamageMatch = {
37 -- Your damage or healing
38  
39 -- ENGLISH
40 { pattern = "Your (.+) hits (.+) for (%d+)", spell = 0, mob = 1, pts = 2 },
41 { pattern = "Your (.+) crits (.+) for (%d+)", spell = 0, mob = 1, pts = 2 },
42 { pattern = "You drain (%d+) (.+) from (.+)", mob = 2, pts = 0, stat = 1 },
43 { pattern = "Your (.+) causes (.+) (%d+) damage", spell = 0, mob = 1, pts = 2 },
44 { pattern = "You reflect (%d+) (.+) damage to (.+)", mob = 2, pts = 0, type = 1 },
45 { pattern = "(.+) suffers (%d+) (.+) damage from your (.+)", spell = 3, mob = 0,
46 pts = 1, type = 2 },
47 { pattern = "You hit (.+) for (%d+)", mob = 0, pts = 1 },
48 { pattern = "You crit (.+) for (%d+)", mob = 0, pts = 1 }
49  
50 -- GERMAN
51 };
52  
53 local damageToYouMatch = {
54 { pattern = "(.+)'s (.+) hits you for (%d+)", spell = 1, pts = 2, cause = 0 },
55 { pattern = "(.+)'s (.+) crits you for (%d+)", spell = 1, pts = 2, cause = 0 },
56 { pattern = "(.+) drains (%d+) (.+) from you", pts = 1, stat = 2, cause = 0 },
57 { pattern = "(.+)'s (.+) causes you (%d+) damage", spell = 1, pts = 2, cause = 0 },
58 { pattern = "(.+) reflects (%d+) (.+) damage to you", pts = 1, type = 2, cause = 0 },
59 { pattern = "You suffer (%d+) (.+) damage from (.+)'s (.+)", spell = 3, pts = 0,
60 type = 1, cause = 2 },
61 { pattern = "(.+) hits you for (%d+)", pts = 1, cause = 0 },
62 { pattern = "(.+) crits you for (%d+)", pts = 1, cause = 0 }
63 };
64  
65 local RED = "|cffff0000";
66 local GREEN = "|cff00ff00";
67 local BLUE = "|cff0000ff";
68 local MAGENTA = "|cffff00ff";
69 local YELLOW = "|cffffff00";
70 local CYAN = "|cff00ffff";
71 local WHITE = "|cffffffff";
72  
73 -- Called OnLoad of the add on
74 function PvPLogOnLoad()
75  
76 PvPLogChatMsg(CYAN .. "PvPLog Loaded, type " ..
77 RED .. "/pvplog" .. CYAN .. " for useage");
78  
79 -- respond to saved variable load
80 this:RegisterEvent("VARIABLES_LOADED");
81  
82 -- respond to player entering the world
83 this:RegisterEvent("PLAYER_ENTERING_WORLD");
84  
85 -- respond to player name update
86 this:RegisterEvent("UNIT_NAME_UPDATE");
87  
88 -- respond when player dies
89 this:RegisterEvent("PLAYER_DEAD");
90  
91 -- respond to when hostiles die
92 this:RegisterEvent("CHAT_MSG_COMBAT_HOSTILE_DEATH");
93  
94 -- respond when our target changes
95 this:RegisterEvent("PLAYER_TARGET_CHANGED");
96  
97 -- respond to when you change mouseovers
98 this:RegisterEvent("UPDATE_MOUSEOVER_UNIT");
99  
100 -- keep track of players level
101 this:RegisterEvent("PLAYER_LEVEL_UP");
102 end
103  
104 function PvPLogOnEvent()
105 -- loads and initializes our variables
106 if (event == "VARIABLES_LOADED") then
107 variablesLoaded = true;
108 PvPLogInitialize();
109  
110 -- initialize when entering world
111 elseif( event == "PLAYER_ENTERING_WORLD" ) then
112 PvPLogInitialize();
113  
114 -- initialize when name changes
115 elseif( event == "UNIT_NAME_UPDATE" ) then
116 PvPLogInitialize();
117  
118 -- keep track of players level
119 elseif( event == "PLAYER_LEVEL_UP" ) then
120 plevel = UnitLevel("player");
121  
122 -- respond to player death, tracking if another player killed us
123 elseif( event == "PLAYER_DEAD" ) then
124 -- initialize if we're not for some reason
125 PvPLogInitialize();
126 if( not initialized ) then
127 return;
128 end
129  
130 -- did we find in target list
131 local found = false;
132  
133 -- make sure we have a last damager
134 -- and are enabled
135 if( lastDamagerToMe == nil or
136 lastDamagerToMe == "" or
137 not PvPLogData[realm][player].enabled) then
138 return;
139 end
140  
141 -- search in player list
142 table.foreach( recentTargets,
143 function(i,v)
144 if( v.name == lastDamagerToMe ) then
145 PvPLogChatMsg(CYAN .. "PvP death logged, killed by: " .. RED .. v.name);
146  
147 PvPLogRecord(v.name, v.level, v.race, v.class, v.guild, true, false);
148  
149 found = true;
150  
151 return 1;
152 end
153 end);
154  
155 -- if killer not found in targets, try to target them so we can check they are a PC
156 if( not found ) then
157 TargetByName(lastDamagerToMe);
158 if( UnitName("target") == lastDamagerToMe and
159 UnitIsPlayer("target") ) then
160  
161 PvPLogChatMsg(CYAN .. "PvP death logged, killed by: " ..
162 RED .. lastDamagerToMe);
163  
164 PvPLogRecord(lastDamagerToMe, UnitLevel("target"), UnitRace("target"),
165 UnitClass("target"), GetGuildInfo("target"), true, false);
166 end
167 end
168  
169 -- add record to mouseover
170 elseif( event == "UPDATE_MOUSEOVER_UNIT" ) then
171 -- initialize if we're not for some reason
172 PvPLogInitialize();
173 if( not initialized ) then
174 return;
175 end
176  
177 -- adds record to mouseover if it exists
178 if( UnitExists("mouseover") and PvPLogData[realm][player].enabled ) then
179 local total = PvPLogGetPvPTotals(UnitName("mouseover"));
180 local guildTotal = PvPLogGetGuildTotals(GetGuildInfo("mouseover"));
181  
182 -- local tooltipcount = 4;
183  
184 if( total and (total.wins > 0 or total.loss > 0) ) then
185 if( PvPLogData[realm][player].battles[UnitName("mouseover")].enemy ) then
186 GameTooltip:AddLine(CYAN .. "PvP: " .. GREEN .. total.wins ..
187 CYAN .. " / " .. RED .. total.loss,
188 1.0, 1.0, 1.0, 0 );
189 else
190 GameTooltip:AddLine(CYAN .. "Duels: " .. GREEN .. total.wins ..
191 CYAN .. " / " .. RED .. total.loss,
192 1.0, 1.0, 1.0, 0 );
193 end
194 -- getglobal(GameTooltip:GetName().."TextLeft"..tooltipcount):SetTextColor( 0.05, 1.0, 0.05 );
195 -- tooltipcount = tooltipcount + 1;
196  
197 GameTooltip:SetHeight( GameTooltip:GetHeight() +
198 GameTooltip:GetHeight() / GameTooltip:NumLines() );
199 end
200  
201 if( guildTotal and (guildTotal.wins > 0 or guildTotal.loss > 0) and
202 (not total or total.wins ~= guildTotal.wins or total.loss ~= guildTotal.loss) ) then
203 if( not PvPLogFriends(UnitRace("mouseover"), UnitRace("player")) ) then
204 GameTooltip:AddLine(CYAN .. "Guild PvP: " .. GREEN .. guildTotal.wins ..
205 CYAN .. " / " .. RED .. guildTotal.loss,
206 1.0, 1.0, 1.0, 0 );
207 else
208 GameTooltip:AddLine(CYAN .. "Guild Duels: " .. GREEN .. guildTotal.wins ..
209 CYAN .. " / " .. RED .. guildTotal.loss,
210 1.0, 1.0, 1.0, 0 );
211 end
212 -- getglobal(GameTooltip:GetName().."TextLeft"..tooltipcount):SetTextColor( 0.05, 1.0, 0.05 );
213 -- tooltipcount = tooltipcount + 1;
214  
215 GameTooltip:SetHeight( GameTooltip:GetHeight() +
216 GameTooltip:GetHeight() / GameTooltip:NumLines() );
217 end
218  
219 -- if( GetGuildInfo("mouseover") ) then
220 -- GameTooltip:AddLine(WHITE .. GetGuildInfo("mouseover"));
221 -- GameTooltip:SetHeight( GameTooltip:GetHeight() +
222 -- GameTooltip:GetHeight() / GameTooltip:NumLines() );
223 -- end
224  
225  
226 if( lastDing <= GetTime()-PvPLogData[realm][player].dingTimeout and
227 not UnitInParty("mouseover") and
228 UnitIsPlayer("mouseover") and
229 ((total and
230 (total.wins > 0 or total.loss > 0) and
231 PvPLogData[realm][player].ding ~= "never") or
232 (guildTotal and (guildTotal.wins > 0 or guildTotal.loss > 0) and
233 PvPLogData[realm][player].ding ~= "noguild" and
234 PvPLogData[realm][player].ding ~= "noguildorduel" and
235 PvPLogData[realm][player].ding ~= "never"
236 )) and
237 (UnitIsEnemy("player", "mouseover") or
238 (PvPLogData[realm][player].ding ~= "noduel" and
239 PvPLogData[realm][player].ding ~= "never" and
240 PvPLogData[realm][player].ding ~= "noguildorduel"))
241 ) then
242 if( PvPLogData[realm][player].dispLocation == "chat" ) then
243 local msg = CYAN .. "PvPLog: " .. RED .. UnitName("mouseover") ..
244 CYAN .. " (" .. UnitLevel("mouseover") .. "," ..
245 UnitRace("mouseover") .. "," .. UnitClass("mouseover");
246 if( GetGuildInfo("mouseover") ) then
247 msg = msg .. ", " .. GetGuildInfo("mouseover");
248 end
249 msg = msg .. ") -- ";
250 if( total and (total.wins > 0 or total.loss > 0) ) then
251 msg = msg .. GREEN .. total.wins .. CYAN .. " / " ..
252 RED .. total.loss;
253 end
254 if( GetGuildInfo("mouseover") and guildTotal and
255 (guildTotal.wins > 0 or guildTotal.loss > 0) and
256 (not total or total.wins ~= guildTotal.wins or total.loss ~= guildTotal.loss) ) then
257 msg = msg .. CYAN .. " (Guild: " .. GREEN .. guildTotal.wins..
258 CYAN .. " / " .. RED .. guildTotal.loss.. CYAN .. ")";
259 end
260 PvPLogChatMsg(msg);
261 else
262 local msg = "PvPLog: " .. UnitName("mouseover") ..
263 " (" .. UnitLevel("mouseover") .. "," ..
264 UnitRace("mouseover") .. "," .. UnitClass("mouseover");
265 if( GetGuildInfo("mouseover") ) then
266 msg = msg .. ", " .. GetGuildInfo("mouseover");
267 end
268 msg = msg .. ") -- ";
269 if( total and (total.wins > 0 or total.loss > 0) ) then
270 msg = msg .. total.wins.. " / " .. total.loss;
271 end
272 if( GetGuildInfo("mouseover") and guildTotal and
273 (guildTotal.wins > 0 or guildTotal.loss > 0) and
274 (not total or total.wins ~= guildTotal.wins or total.loss ~= guildTotal.loss) ) then
275 msg = msg .. " (Guild: " .. guildTotal.wins.. " / "
276 .. guildTotal.loss.. ")";
277 end
278 PvPLogFloatMsg(msg, "cyan");
279 end
280 PlaySound(PvPLogData[realm][player].dingSound);
281 lastDing = GetTime();
282 end
283 end
284  
285 -- keep track of those we've targeted
286 elseif (event == "PLAYER_TARGET_CHANGED") then
287 -- initialize if we're not for some reason
288 PvPLogInitialize();
289 if( not initialized ) then
290 return;
291 end
292  
293 local field = getglobal("PvPLogTargetText");
294 field:Hide();
295 field:SetText("");
296  
297 -- if we're enabled
298 if( PvPLogData[realm][player].enabled ) then
299 PvPLogUpdateTargetText();
300  
301 -- if we have a vaild target, its a player, and its an enemy
302 if( UnitName("target") and
303 UnitIsPlayer("target") and
304 UnitIsEnemy("player", "target")
305 ) then
306 -- will contain about target
307 local target = { };
308 target.name = UnitName("target");
309 target.level = UnitLevel("target");
310 target.race = UnitRace("target");
311 target.class = UnitClass("target");
312 target.guild = GetGuildInfo("target");
313  
314 -- add to our list of recent targets
315 table.insert( recentTargets, target );
316 -- remove if we've hit our cap
317 if( table.getn( recentTargets ) > NUMRECENT ) then
318 table.remove( recentTargets, 1 );
319 end
320 end
321 end
322  
323 -- record a hostile death, if we killed them
324 elseif( event == "CHAT_MSG_COMBAT_HOSTILE_DEATH" ) then
325 -- initialize if we're not for some reason
326 PvPLogInitialize();
327 if( not initialized ) then
328 return;
329 end
330  
331 -- if we're enabled
332 if( PvPLogData[realm][player].enabled ) then
333 -- get name
334 local index = string.find( arg1, " dies." );
335 if( not index ) then
336 return;
337 end
338 local value = string.sub( arg1, 0, index-1 );
339 -- if we have a name
340 if( value ) then
341 -- search in damaged list
342 table.foreach( damagedTargets,
343 function(i,v)
344 if( v.name == value ) then
345 PvPLogChatMsg(CYAN .. "PvP kill logged: " .. GREEN .. v.name);
346  
347 PvPLogRecord(v.name, v.level, v.race, v.class, v.guild, true, true);
348  
349 return 1;
350 end
351 end);
352 end
353 end
354 end
355 end
356  
357 -- Helper Functions
358 function PvPLogSetEnabled(toggle)
359 toggle = string.lower(toggle);
360 if (toggle == "off") then
361 PvPLogData[realm][player].enabled = false;
362 PvPLogFloatMsg(CYAN .. "PvPLog " .. WHITE .. "Off");
363 else
364 PvPLogData[realm][player].enabled = true;
365 PvPLogFloatMsg(CYAN .. "PvPLog " .. WHITE .. "On");
366 end
367 end
368  
369 function PvPLogSetDisplayLoc(loc)
370 PvPLogData[realm][player].dispLocation = loc;
371 PvPLogFloatMsg(CYAN .. "PvPLog display location: " .. WHITE .. loc);
372 end
373  
374 function PvPLogSlashHandler(msg)
375 -- initialize if we're not for some reason
376 PvPLogInitialize();
377 if( not initialized ) then
378 return;
379 end
380  
381 local firsti, lasti, command, value = string.find (msg, "(%w+) \"(.*)\"");
382 if (command == nil) then
383 firsti, lasti, command, value = string.find (msg, "(%w+) (%w+)");
384 end
385 if (command == nil) then
386 firsti, lasti, command = string.find(msg, "(%w+)");
387 end
388 --PvPLogChatMsg(msg);
389 --PvPLogChatMsg(command);
390 --PvPLogChatMsg(value);
391 -- respond to commands
392 if (command == nil) then
393 PvPLogDisplayUsage();
394 elseif (string.lower(command) == "reset") then
395 if( value == "confirm" ) then
396 PvPLogData[realm][player] = { };
397 PvPLogData[realm][player].battles = { };
398 PvPLogData[realm][player].enabled = true;
399 PvPLogData[realm][player].dispLocation = "overhead";
400 PvPLogData[realm][player].ding = "always";
401 PvPLogData[realm][player].dingSound = "AuctionWindowOpen";
402 PvPLogData[realm][player].dingTimeout = 120.0;
403 PvPLogData[realm][player].notifyKill = "party";
404 PvPLogData[realm][player].notifyDeath = "guild";
405 PvPLogData[realm][player].notifyKillText = "I killed $n (Level $l %r %c) at [%x,%y] in %z.";
406 PvPLogData[realm][player].notifyDeathText = "%n (Level %l %r %c) killed me at [%x,%y] in %z.";
407 PvPLogData[realm][player].version = VER_NUM.."."..VER_SUB.."."..VER_REL;
408 PvPLogChatMsg(CYAN .. "PvPLog " .. MAGENTA .. "Reset" .. CYAN .. " Completely!");
409 end
410 elseif( string.lower(command) == "notifykillstext") then
411 if( value == "long" ) then
412 value = "I killed %n (Level %l %r %c) at [%x,%y] in %z.";
413 elseif( value == "medium" ) then
414 value = "I killed %n (Level %l %r %c) at [%x,%y].";
415 elseif( value == "short" ) then
416 value = "Killed Level %l %r %c.";
417 elseif( value == "custom" ) then
418 PvPLogChatMsg(CYAN .. "PvPLog: Custom Chat Noftifications\n");
419 PvPLogChatMsg(CYAN .. " Type the following to use a custom chat notification:\n");
420 PvPLogChatMsg(CYAN .. " /pvplog notifykillstext \"custom string\" -- or --\n");
421 PvPLogChatMsg(CYAN .. " /pvplog notifydeathtext \"custom string\"\n");
422 PvPLogChatMsg(CYAN .. " Where <custom string> is the text you want used, with\n");
423 PvPLogChatMsg(CYAN .. " format codes as follows:\n");
424 PvPLogChatMsg(CYAN .. " %n - name, %l - level, %r - race, %c - class, %g - guild\n");
425 PvPLogChatMsg(CYAN .. " %x - X:coordinate, %y - Y:coordinate, %z - zone\n");
426 PvPLogChatMsg(CYAN .. " Example:\n");
427 PvPLogChatMsg(CYAN .. " /pvplog notifykillstext \"I killed %n (Level %l %r %c) at [%x,%y] in %z.\"\n");
428 PvPLogChatMsg(CYAN .. " Current setting: " .. PvPLogData[realm][player].notifyKillText .. "\n");
429 value = nil;
430 else
431 firsti, lasti, value = string.find( msg, "\"(.*)\"" );
432 end
433 if( value ~= nil ) then
434 PvPLogData[realm][player].notifyKillText = value;
435 PvPLogFloatMsg(CYAN .. "PvPLog Set " .. WHITE .. "notifykillstext" .. CYAN .. " to " .. MAGENTA .. value);
436 end
437 elseif( string.lower(command) == "notifydeathtext") then
438 if( value == "long" ) then
439 value = "%n (Level %l %r %c) killed me at [%x,%y] in %z.";
440 elseif( value == "medium" ) then
441 value = "%n (Level %l %r %c) killed me at [%x,%y].";
442 elseif( value == "short" ) then
443 value = "Level %l %r %c killed me.";
444 elseif( value == "custom" ) then
445 PvPLogChatMsg(CYAN .. "PvPLog: Custom Chat Noftifications\n");
446 PvPLogChatMsg(CYAN .. " Type the following to use a custom chat notification:\n");
447 PvPLogChatMsg(CYAN .. " /pvplog notifykillstext \"custom string\" -- or --\n");
448 PvPLogChatMsg(CYAN .. " /pvplog notifydeathtext \"custom string\"\n");
449 PvPLogChatMsg(CYAN .. " Where <custom string> is the text you want used, with\n");
450 PvPLogChatMsg(CYAN .. " format codes as follows:\n");
451 PvPLogChatMsg(CYAN .. " %n - name, %l - level, %r - race, %c - class,\n");
452 PvPLogChatMsg(CYAN .. " %x - X:coordinate, %y - Y:coordinate, %z - zone\n");
453 PvPLogChatMsg(CYAN .. " Example:\n");
454 PvPLogChatMsg(CYAN .. " /pvplog notifydeathtext \"%n (Level %l %r %c) killed me at [%x,%y] in %z.\"\n");
455 PvPLogChatMsg(CYAN .. " Current setting: " .. PvPLogData[realm][player].notifyDeathText .. "\n");
456 value = nil
457 else
458 firsti, lasti, value = string.find( msg, "\"(.*)\"" );
459 end
460 if( value ~= nil ) then
461 PvPLogData[realm][player].notifyDeathText = value;
462 PvPLogFloatMsg(CYAN .. "PvPLog Set " .. WHITE .. "notifydeathtext" .. CYAN .. " to " .. MAGENTA .. value);
463 end
464 elseif( string.lower(command) == "notifykills") then
465 if( value ~= nil ) then
466 PvPLogData[realm][player].notifyKill = value;
467 PvPLogFloatMsg(CYAN .. "PvPLog Set " .. WHITE .. "notifykills" .. CYAN .. " to " .. MAGENTA .. value);
468 else
469 PvPLogDisplayUsage();
470 end
471 elseif( string.lower(command) == "notifydeath") then
472 if( value ~= nil ) then
473 PvPLogData[realm][player].notifyDeath = value;
474 PvPLogFloatMsg(CYAN .. "PvPLog Set " .. WHITE .. "notifydeath" .. CYAN .. " to " .. MAGENTA .. value);
475 else
476 PvPLogDisplayUsage();
477 end
478 elseif (string.lower(command) == "targetreset") then
479 PvPLogTargetFrame:ClearAllPoints();
480 PvPLogTargetFrame:SetPoint("TOP", "TargetFrameHealthBar", "BOTTOM", -2, -5);
481 elseif (string.lower(command) == "enable") then
482 PvPLogSetEnabled("on");
483 elseif (string.lower(command) == "disable") then
484 PvPLogSetEnabled("off");
485 elseif (string.lower(command) == "location") then
486 if (value ~= nil) then
487 PvPLogSetDisplayLoc(string.lower(value));
488 else
489 PvPLogDisplayUsage();
490 end
491 elseif( string.lower(command) == "version" ) then
492 PvPLogChatMsg(CYAN .. "PvPLog version " .. WHITE .. VER_NUM .. "." .. VER_SUB .. "." .. VER_REL);
493 elseif( string.lower(command) == "dingsound" ) then
494 if( value ~= nil ) then
495 PvPLogData[realm][player].dingSound = value;
496 PvPLogFloatMsg(CYAN .. "PvPLog ding sound: " .. WHITE .. value);
497 else
498 PvPLogDisplayUsage();
499 end
500 elseif( string.lower(command) == "dingtimeout" ) then
501 if( value ~= nil ) then
502 PvPLogData[realm][player].dingTimeout = value;
503 PvPLogFloatMsg(CYAN .. "PvPLog ding timeout: " .. WHITE .. value);
504 else
505 PvPLogDisplayUsage();
506 end
507 elseif( string.lower(command) == "ding" ) then
508 if( value ~= nil ) then
509 PvPLogData[realm][player].ding = string.lower(value);
510 PvPLogFloatMsg(CYAN .. "PvPLog ding setting: " .. WHITE .. value);
511 else
512 PvPLogDisplayUsage();
513 end
514 elseif( string.lower(command) == "stats") then
515 local stats = PvPLogGetStats();
516 local gankLevel = "Fair Fighter";
517 if( stats.pvpWinAvgLevelDiff <= -25 ) then
518 gankLevel = "I Have No Mercy";
519 elseif( stats.pvpWinAvgLevelDiff <= -20 ) then
520 gankLevel = "Newb Masher";
521 elseif( stats.pvpWinAvgLevelDiff <= -15 ) then
522 gankLevel = "No Seriously, Get a Life";
523 elseif( stats.pvpWinAvgLevelDiff <= -12 ) then
524 gankLevel = "Get a Life";
525 elseif( stats.pvpWinAvgLevelDiff <= -9 ) then
526 gankLevel = "Gankity Gank Gank";
527 elseif( stats.pvpWinAvgLevelDiff <= -6 ) then
528 gankLevel = "Major Ganker";
529 elseif( stats.pvpWinAvgLevelDiff <= -3 ) then
530 gankLevel = "Minor Ganker";
531 elseif( stats.pvpWinAvgLevelDiff >= 8 ) then
532 gankLevel = "I Gank GameMasters";
533 elseif( stats.pvpWinAvgLevelDiff >= 5 ) then
534 gankLevel = "PvP God";
535 elseif( stats.pvpWinAvgLevelDiff >= 4 ) then
536 gankLevel = "PvP Legend";
537 elseif( stats.pvpWinAvgLevelDiff >= 3 ) then
538 gankLevel = "Ungankable";
539 elseif( stats.pvpWinAvgLevelDiff >= 2 ) then
540 gankLevel = "Just try to gank me";
541 elseif( stats.pvpWinAvgLevelDiff >= 1 ) then
542 gankLevel = "Difficult to Gank";
543 end
544 PvPLogChatMsg("|cff33ffffPvPLog Statistics:");
545 PvPLogChatMsg("|cff33ffff Total wins: " .. stats.totalWins .. " (avg.level.diff: " .. (math.floor(stats.totalWinAvgLevelDiff*100)/100) .. ")");
546 PvPLogChatMsg("|cff33ffff Total losses: " .. stats.totalLoss .. " (avg.level.diff: " .. (math.floor(stats.totalLossAvgLevelDiff*100)/100) .. ")");
547 PvPLogChatMsg("|cff33ffff PvP wins: " .. stats.pvpWins .. " (avg.level.diff: " .. (math.floor(stats.pvpWinAvgLevelDiff*100)/100) .. ", " .. gankLevel .. ")");
548 PvPLogChatMsg("|cff33ffff PvP losses: " .. stats.pvpLoss .. " (avg.level.diff: " .. (math.floor(stats.pvpLossAvgLevelDiff*100)/100) .. ")");
549 PvPLogChatMsg("|cff33ffff Duel wins: " .. stats.duelWins .. " (avg.level.diff: " .. (math.floor(stats.duelWinAvgLevelDiff*100)/100) .. ")");
550 PvPLogChatMsg("|cff33ffff Duel losses: " .. stats.duelLoss .. " (avg.level.diff: " .. (math.floor(stats.duelLossAvgLevelDiff*100)/100) .. ")");
551 elseif( string.lower(command) == "find") then
552 PvPLogFind(value);
553 elseif( string.lower(command) == "listall") then
554 PvPLogListAll();
555 else
556 PvPLogDisplayUsage();
557 end
558 end
559  
560 function PvPLogDisplayUsage()
561 local text;
562  
563 text = CYAN .. "Usage:\n /PvPLog <";
564 if( PvPLogData[realm][player].enabled ) then
565 text = text .. WHITE .. "enable" .. CYAN .. " | disable>\n";
566 else
567 text = text .. "enable | " .. WHITE .. "disable" .. CYAN .. ">\n";
568 end
569 PvPLogChatMsg(text);
570  
571 PvPLogChatMsg(CYAN .. " /PvPLog reset confirm (DANGER -- erases all records)\n");
572 PvPLogChatMsg(CYAN .. " /PvPLog listall\n");
573 text = CYAN .. " /PvPLog location <";
574 if( PvPLogData[realm][player].dispLocation == "chat" ) then
575 text = text .. WHITE .. "chat" .. CYAN .. " | ";
576 else
577 text = text .. "chat | ";
578 end
579 if( PvPLogData[realm][player].dispLocation == "overhead" ) then
580 text = text .. WHITE .. "overhead" .. CYAN .. " | ";
581 else
582 text = text .. "overhead | ";
583 end
584 if( PvPLogData[realm][player].dispLocation == "none" ) then
585 text = text .. WHITE .. "overhead" .. CYAN .. ">\n";
586 else
587 text = text .. "none>\n";
588 end
589 PvPLogChatMsg(text);
590  
591 PvPLogChatMsg(CYAN .. " /PvPLog find <search string>\n");
592 PvPLogChatMsg(CYAN .. " /PvPLog stats\n");
593  
594 text = CYAN .. " /PvPLog ding <";
595 if( PvPLogData[realm][player].ding == "always" ) then
596 text = text .. WHITE .. "always" .. CYAN .. " | ";
597 else
598 text = text .. "always | ";
599 end
600 if( PvPLogData[realm][player].ding == "never" ) then
601 text = text .. WHITE .. "never" .. CYAN .. " | ";
602 else
603 text = text .. "never | ";
604 end
605 if( PvPLogData[realm][player].ding == "noguild" ) then
606 text = text .. WHITE .. "noGuild" .. CYAN .. " | ";
607 else
608 text = text .. "noGuild | ";
609 end
610 if( PvPLogData[realm][player].ding == "noduel" ) then
611 text = text .. WHITE .. "noDuel" .. CYAN .. " | ";
612 else
613 text = text .. "noDuel | ";
614 end
615 if( PvPLogData[realm][player].ding == "noguildorduel" ) then
616 text = text .. WHITE .. "noGuildOrDuel" .. CYAN .. ">\n";
617 else
618 text = text .. "noGuildOrDuel>\n";
619 end
620 PvPLogChatMsg(text);
621  
622 PvPLogChatMsg(CYAN .. " /PvPLog dingsound <soundfile> (default=AuctionWindowOpen, current=" .. WHITE .. PvPLogData[realm][player].dingSound .. CYAN .. ")\n");
623 PvPLogChatMsg(CYAN .. " /PvPLog dingtimeout <seconds> (default=120.0, current=" .. WHITE .. PvPLogData[realm][player].dingTimeout .. CYAN .. ")\n");
624  
625 local nkills = 0;
626 text = CYAN .. " /PvPLog notifykills <";
627 if( PvPLogData[realm][player].notifyKill == "none" ) then
628 text = text .. WHITE .. "none" .. CYAN .. " | ";
629 nkills = 1;
630 else
631 text = text .. "none | ";
632 end
633 if( PvPLogData[realm][player].notifyKill == "party" ) then
634 text = text .. WHITE .. "party" .. CYAN .. " | ";
635 nkills = 1;
636 else
637 text = text .. "party | ";
638 end
639 if( PvPLogData[realm][player].notifyKill == "guild" ) then
640 text = text .. WHITE .. "guild" .. CYAN .. " | ";
641 nkills = 1;
642 else
643 text = text .. "guild | ";
644 end
645 if( PvPLogData[realm][player].notifyKill == "raid" ) then
646 text = text .. WHITE .. "raid" .. CYAN .. " | ";
647 nkills = 1;
648 else
649 text = text .. "raid | ";
650 end
651 if( not nkills ) then
652 text = text .. WHITE .. "channelname=" .. PvPLogData[realm][player].notifyKill .. CYAN .. ">\n";
653 else
654 text = text .. "channelname>\n";
655 end
656 PvPLogChatMsg(text);
657  
658 nkills = 0;
659 text = CYAN .. " /PvPLog notifydeath <";
660 if( PvPLogData[realm][player].notifyDeath == "none" ) then
661 text = text .. WHITE .. "none" .. CYAN .. " | ";
662 nkills = 1;
663 else
664 text = text .. "none | ";
665 end
666 if( PvPLogData[realm][player].notifyDeath == "party" ) then
667 text = text .. WHITE .. "party" .. CYAN .. " | ";
668 nkills = 1;
669 else
670 text = text .. "party | ";
671 end
672 if( PvPLogData[realm][player].notifyDeath == "guild" ) then
673 text = text .. WHITE .. "guild" .. CYAN .. " | ";
674 nkills = 1;
675 else
676 text = text .. "guild | ";
677 end
678 if( PvPLogData[realm][player].notifyDeath == "raid" ) then
679 text = text .. WHITE .. "raid" .. CYAN .. " | ";
680 nkills = 1;
681 else
682 text = text .. "raid | ";
683 end
684 if( not nkills ) then
685 text = text .. WHITE .. "channelname=" .. PvPLogData[realm][player].notifyDeath .. CYAN .. ">\n";
686 else
687 text = text .. "channelname>\n";
688 end
689 PvPLogChatMsg(text);
690  
691 PvPLogChatMsg(CYAN .. " /PvPLog notifykillstext <short | medium | long | custom>\n");
692 PvPLogChatMsg(CYAN .. " /PvPLog notifydeathtext <short | medium | long | custom>\n");
693 PvPLogChatMsg(CYAN .. " /PvPLog version\n");
694 PvPLogChatMsg(CYAN .. " /PvPLog targetreset\n");
695 end
696  
697 function PvPLogChatMsg(msg)
698 if( DEFAULT_CHAT_FRAME ) then
699 DEFAULT_CHAT_FRAME:AddMessage(msg);
700 end
701 end
702  
703 function PvPLogFloatMsg(msg, color)
704 -- Display overhead message. 7 basic colors available
705 -- Use at most 3 lines here - the rest get lost
706 local r, g, b
707  
708 if (color == nil) then
709 color = "white";
710 end
711  
712 if (string.lower(color) == "red") then
713 r, g, b = 1.0, 0.0, 0.0;
714 elseif (string.lower(color) == "green") then
715 r, g, b = 0.0, 1.0, 0.0;
716 elseif (string.lower(color) == "blue") then
717 r, g, b = 0.0, 0.0, 1.0;
718 elseif (string.lower(color) == "magenta") then
719 r, g, b = 1.0, 0.0, 1.0;
720 elseif (string.lower(color) == "yellow") then
721 r, g, b = 1.0, 1.0, 0.0;
722 elseif (string.lower(color) == "cyan") then
723 r, g, b = 0.0, 1.0, 1.0;
724 else
725 r, g, b = 1.0, 1.0, 1.0;
726 end
727  
728 UIErrorsFrame:AddMessage(msg, r, g, b, 1.0, UIERRORS_HOLD_TIME);
729  
730 end
731  
732  
733 function PvPLogInitialize()
734 -- get realm and player
735 realm = GetCVar("realmName");
736 player = UnitName("player");
737 plevel = UnitLevel("player");
738  
739 -- check for valid realm and player
740 if( initialized or (not variablesLoaded) or (not realm) or
741 (not plevel) or (not player) or (player == "Unknown Entity")
742 ) then
743 return;
744 end
745 initialized = true;
746  
747 -- Register command handler and new commands
748 SlashCmdList["PvPLogCOMMAND"] = PvPLogSlashHandler;
749 SLASH_PvPLogCOMMAND1 = "/pvplog";
750 SLASH_PvPLogCOMMAND2 = "/pl";
751  
752 -- Hook the ChatFrame_OnEvent function
753 lOriginalChatFrame_OnEvent = ChatFrame_OnEvent;
754 ChatFrame_OnEvent = PvPLog_ChatFrame_OnEvent;
755  
756 -- initialize data structure
757 if( PvPLogData == nil ) then
758 PvPLogData = { };
759 end
760 if( PvPLogData[realm] == nil ) then
761 PvPLogData[realm] = { };
762 end
763 if( PvPLogData[realm][player] == nil ) then
764 PvPLogData[realm][player] = { };
765 PvPLogData[realm][player].battles = { };
766 PvPLogData[realm][player].enabled = true;
767 PvPLogData[realm][player].dispLocation = "overhead";
768 PvPLogData[realm][player].ding = "always";
769 PvPLogData[realm][player].dingSound = "AuctionWindowOpen";
770 PvPLogData[realm][player].dingTimeout = 120.0;
771 PvPLogData[realm][player].notifyKill = "party";
772 PvPLogData[realm][player].notifyDeath = "guild";
773 PvPLogData[realm][player].notifyKillText = "I killed %n (Level %l %r %c) at [%x,%y] in %z.";
774 PvPLogData[realm][player].notifyDeathText = "%n (Level %l %r %c) killed me at [%x,%y] in %z.";
775 PvPLogData[realm][player].version = VER_NUM.."."..VER_SUB.."."..VER_REL;
776 end
777 if( PvPLogData[realm][player].battles == nil ) then
778 PvPLogData[realm][player].battles = { };
779 end
780 if( PvPLogData[realm][player].enabled == nil ) then
781 PvPLogData[realm][player].enabled = true;
782 end
783 if( PvPLogData[realm][player].dispLocation == nil ) then
784 PvPLogData[realm][player].dispLocation = "overhead";
785 end
786 if( PvPLogData[realm][player].dingSound == nil ) then
787 PvPLogData[realm][player].dingSound = "AuctionWindowOpen";
788 end
789 if( PvPLogData[realm][player].ding == nil ) then
790 PvPLogData[realm][player].ding = "always";
791 end
792 if( PvPLogData[realm][player].dingTimeout == nil ) then
793 PvPLogData[realm][player].dingTimeout = 120.0;
794 end
795 if( PvPLogData[realm][player].notifyKill == nil ) then
796 PvPLogData[realm][player].notifyKill = "party";
797 end
798 if( PvPLogData[realm][player].notifyDeath == nil ) then
799 PvPLogData[realm][player].notifyDeath = "guild";
800 end
801 if( PvPLogData[realm][player].notifyKillText == nil ) then
802 PvPLogData[realm][player].notifyKillText = "I killed %n (Level %l %r %c) at [%x,%y] in %z.";
803 end
804 if( PvPLogData[realm][player].notifyDeathText == nil ) then
805 PvPLogData[realm][player].notifyDeathText = "%n (Level %l %r %c) killed me at [%x,%y] in %z.";
806 end
807 if( PvPLogData[realm][player].version == nil ) then
808 PvPLogData[realm][player].version = VER_NUM.."."..VER_SUB.."."..VER_REL;
809 end
810  
811 local stats = PvPLogGetStats();
812 local allRecords = stats.totalWins + stats.totalLoss;
813  
814 -- Report load
815 PvPLogChatMsg("PvPLog variables loaded: " .. allRecords .. " records (" ..
816 stats.totalWins .. "/" .. stats.totalLoss .. ") for " ..
817 player .. " | " .. realm);
818 end
819  
820  
821 function PvPLogListAll()
822 table.foreach( PvPLogData[realm][player].battles,
823 function( target,v1 )
824 PvPLogData[realm][player].battles[target].enemy = not PvPLogFriends(UnitRace("player"), v1.race);
825 table.foreach( v1,
826 function( targLevel,v2 )
827 if( targLevel ~= "race" and
828 targLevel ~= "class" and
829 targLevel ~= "enemy" and
830 targLevel ~= "guild" ) then
831 table.foreach( v2,
832 function( playerLevel, v3 )
833 local msg = "|cff00ffffPvP: "..target.." ("..targLevel..",".. v1.race ..",".. v1.class;
834 if( v1.guild ) then
835 msg = msg .. "," .. v1.guild;
836 end
837 msg = msg .. ") [".. playerLevel ..",".. v3.wins .."," .. v3.loss .. "]";
838 PvPLogChatMsg(msg);
839 end);
840 end
841 end)
842 end)
843 end
844  
845 function PvPLog_ChatFrame_OnEvent()
846 lOriginalChatFrame_OnEvent(event, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9);
847  
848 -- initialize if we're not for some reason
849 PvPLogInitialize();
850 if( not initialized ) then
851 return;
852 end
853  
854 -- occasionally I was getting a nil value on the
855 -- if statement after this one so this is a check
856 -- to make sure that doesn't happen
857 if( not PvPLogData[realm][player] ) then
858 return;
859 end
860  
861 -- check to see if we're enabled
862 if( not PvPLogData[realm][player].enabled ) then
863 return;
864 end
865  
866 if( event and arg1 ) then
867 local s, e;
868 s, e, winner, loser = string.find(arg1, "(.+) has defeated (.+) in a duel");
869 if( winner ) then
870 --- CHAT_MSG_SYSTEM
871 if( player == winner ) then
872 local v = { };
873 v.name = loser;
874 TargetByName(loser);
875 if( UnitName("target") == loser ) then
876 v.level = UnitLevel("target");
877 v.class = UnitClass("target");
878 v.guild = GetGuildInfo("target");
879 v.race = UnitRace("target");
880 else
881 v.level = -1;
882 end
883  
884 PvPLogChatMsg(CYAN .. "PvP duel win logged against: " .. GREEN .. v.name);
885  
886 PvPLogRecord(v.name, v.level, v.race, v.class, v.guild, false, true);
887  
888 elseif( player == loser ) then
889 local v = { };
890 v.name = winner;
891 TargetByName(winner);
892 if( UnitName("target") == winner ) then
893 v.level = UnitLevel("target");
894 v.class = UnitClass("target");
895 v.guild = GetGuildInfo("target");
896 v.race = UnitRace("target");
897 else
898 v.level = -1;
899 end
900  
901 PvPLogChatMsg(CYAN .. "PvP duel loss logged against: " .. RED .. v.name);
902  
903 PvPLogRecord(v.name, v.level, v.race, v.class, v.guild, false, false);
904 end
905 end
906 end
907  
908 if( event and (strsub(event, 1, 15) == "CHAT_MSG_COMBAT" or strsub(event, 1, 14) == "CHAT_MSG_SPELL") ) then
909 for index, value in yourDamageMatch do
910 local s, e;
911 local results = { };
912 s, e, results[0], results[1], results[2], results[3], results[4] = string.find(arg1, value.pattern);
913 if( results[0] ~= nil ) then
914 table.foreach( recentTargets,
915 function(i,v)
916 if( v.name == results[value.mob] ) then
917 table.insert( damagedTargets, v );
918 if( table.getn( damagedTargets ) > NUMDAMAGED ) then
919 table.remove( damagedTargets, 1 );
920 end
921 return 1;
922 end
923 end);
924 return;
925 end
926 end
927 for index, value in damageToYouMatch do
928 local s, e;
929 local results = { };
930 s, e, results[0], results[1], results[2], results[3], results[4] = string.find(arg1, value.pattern);
931 if( results[0] ~= nil ) then
932 lastDamagerToMe = results[value.cause];
933 return;
934 end
935 end
936 end
937 end
938  
939 function PvPLogFind(search)
940 if( not search ) then
941 return;
942 end
943 search = string.lower(search);
944 table.foreach( PvPLogData[realm][player].battles,
945 function( target,v1 )
946 local found = string.find( string.lower(target), search );
947 if( not found) then found = string.find( string.lower(v1.race), search ) end
948 if( not found) then found = string.find( string.lower(v1.class), search ) end
949 if( not found and v1.guild ) then found = string.find( string.lower(v1.guild), search ) end
950 if( found ) then
951 local totals = PvPLogGetPvPTotals(target);
952 local msg = "|cff00ffffPvP: "..target.." (" ..totals.highestLevel .. "," .. v1.race ..",".. v1.class;
953 if( v1.guild ) then
954 msg = msg .. "," .. v1.guild;
955 end
956 msg = msg .. ") Wins: ".. totals.wins ..", Losses:" .. totals.loss .. ", Avg. Level Difference: " .. totals.avgLevelDiff;
957 PvPLogChatMsg(msg);
958 end
959 end)
960 end
961  
962 function PvPLogGetPvPTotals(name)
963 if( not name ) then
964 return nil;
965 end
966  
967 if( not PvPLogData[realm][player].battles[name] ) then
968 return nil;
969 end
970  
971 local total = { };
972 total.wins = 0;
973 total.loss = 0;
974 total.highestLevel = 0;
975 total.avgLevelDiff = 0;
976 total.winsStr = "";
977 total.lossStr = "";
978 total.slashy = true;
979  
980 table.foreach( PvPLogData[realm][player].battles[name],
981 function( targLevel,v2 )
982 if( targLevel ~= "race" and
983 targLevel ~= "class" and
984 targLevel ~= "enemy" and
985 targLevel ~= "guild" ) then
986 if( targLevel > total.highestLevel ) then
987 total.highestLevel = targLevel;
988 end
989 table.foreach( v2,
990 function( playerLevel, v3 )
991 total.wins = total.wins + v3.wins;
992 total.loss = total.loss + v3.loss;
993 total.avgLevelDiff = total.avgLevelDiff + (v3.wins+v3.loss)*(targLevel-playerLevel);
994 end);
995 end
996 end);
997 total.avgLevelDiff = total.avgLevelDiff / (total.wins + total.loss);
998  
999 if( total.wins == 1 ) then
1000 total.winsStr = "1 win";
1001 elseif( total.wins > 1 ) then
1002 total.winsStr = total.wins .. " wins";
1003 else
1004 total.slashy = false;
1005 end
1006  
1007 if( total.loss == 1 ) then
1008 total.lossStr = "1 loss";
1009 elseif( total.loss > 1 ) then
1010 total.lossStr = total.loss .. " losses";
1011 end
1012  
1013 if( total.slashy and total.loss > 0 ) then
1014 total.slashy = " / ";
1015 else
1016 total.slashy = "";
1017 end
1018  
1019 return total;
1020 end
1021  
1022  
1023 function PvPLogGetGuildTotals(guild)
1024 if( not guild ) then
1025 return nil;
1026 end
1027 guild = string.lower(guild);
1028 local total = { };
1029 total.wins = 0;
1030 total.loss = 0;
1031 total.winsStr = "";
1032 total.lossStr = "";
1033 total.slashy = true;
1034  
1035 table.foreach( PvPLogData[realm][player].battles,
1036 function( target,v1 )
1037 if( v1.guild and guild == string.lower(v1.guild) ) then
1038 local indiv = PvPLogGetPvPTotals(target);
1039 total.wins = total.wins + indiv.wins;
1040 total.loss = total.loss + indiv.loss;
1041 end
1042 end)
1043  
1044 if( total.wins == 1 ) then
1045 total.winsStr = "1 win";
1046 elseif( total.wins > 1 ) then
1047 total.winsStr = total.wins .. " wins";
1048 else
1049 total.slashy = false;
1050 end
1051  
1052 if( total.loss == 1 ) then
1053 total.lossStr = "1 loss";
1054 elseif( total.loss > 1 ) then
1055 total.lossStr = total.loss .. " losses";
1056 end
1057  
1058 if( total.slashy and total.loss > 0 ) then
1059 total.slashy = " / ";
1060 else
1061 total.slashy = "";
1062 end
1063  
1064 return total;
1065 end
1066  
1067 function PvPLogGetStats()
1068 local stats = { };
1069 stats.totalWins = 0;
1070 stats.totalWinAvgLevelDiff = 0;
1071 stats.totalLoss = 0;
1072 stats.totalLossAvgLevelDiff = 0;
1073 stats.pvpWins = 0;
1074 stats.pvpWinAvgLevelDiff = 0;
1075 stats.pvpLoss = 0;
1076 stats.pvpLossAvgLevelDiff = 0;
1077 stats.duelWins = 0;
1078 stats.duelWinAvgLevelDiff = 0;
1079 stats.duelLoss = 0;
1080 stats.duelLossAvgLevelDiff = 0;
1081 stats.levels = { };
1082 stats.levels[0] = { };
1083 stats.levels[1] = { };
1084 stats.levels[2] = { };
1085 stats.levels[3] = { };
1086 stats.levels[4] = { };
1087 stats.levels[5] = { };
1088 stats.levels[6] = { };
1089 stats.levels[7] = { };
1090 stats.levels[8] = { };
1091 stats.levels[9] = { };
1092 stats.levels[10] = { };
1093 stats.levels[0].wins = 0;
1094 stats.levels[1].wins = 0;
1095 stats.levels[2].wins = 0;
1096 stats.levels[3].wins = 0;
1097 stats.levels[4].wins = 0;
1098 stats.levels[5].wins = 0;
1099 stats.levels[6].wins = 0;
1100 stats.levels[7].wins = 0;
1101 stats.levels[8].wins = 0;
1102 stats.levels[9].wins = 0;
1103 stats.levels[10].wins = 0;
1104 stats.levels[0].loss = 0;
1105 stats.levels[1].loss = 0;
1106 stats.levels[2].loss = 0;
1107 stats.levels[3].loss = 0;
1108 stats.levels[4].loss = 0;
1109 stats.levels[5].loss = 0;
1110 stats.levels[6].loss = 0;
1111 stats.levels[7].loss = 0;
1112 stats.levels[8].loss = 0;
1113 stats.levels[9].loss = 0;
1114 stats.levels[10].loss = 0;
1115 stats.classes = { };
1116 stats.punchingbag = "";
1117 stats.punchingbagkills = 0;
1118 stats.feared = "";
1119 stats.feareddeaths = 0;
1120  
1121 table.foreach( PvPLogData[realm][player].battles,
1122 function( target,v1 )
1123 if( v1.enemy == nil ) then
1124 PvPLogData[realm][player].battles[target].enemy = not PvPLogFriends( UnitRace("player"), v1.race );
1125 end
1126  
1127 table.foreach( v1,
1128 function( targLevel,v2 )
1129 if( targLevel ~= "race" and
1130 targLevel ~= "class" and
1131 targLevel ~= "enemy" and
1132 targLevel ~= "guild" ) then
1133 table.foreach( v2,
1134 function( playerLevel, v3 )
1135 stats.totalWins = stats.totalWins + v3.wins;
1136 if( targLevel < 0 ) then
1137 stats.totalWinAvgLevelDiff = stats.totalWinAvgLevelDiff + v3.wins*(-targLevel-playerLevel);
1138 else
1139 stats.totalWinAvgLevelDiff = stats.totalWinAvgLevelDiff + v3.wins*(targLevel-playerLevel);
1140 end
1141 stats.totalLoss = stats.totalLoss + v3.loss;
1142 if( targLevel < 0 ) then
1143 stats.totalLossAvgLevelDiff = stats.totalLossAvgLevelDiff + v3.loss*(-targLevel-playerLevel);
1144 else
1145 stats.totalLossAvgLevelDiff = stats.totalLossAvgLevelDiff + v3.loss*(targLevel-playerLevel);
1146 end
1147 if( v1.enemy ) then
1148 stats.pvpWins = stats.pvpWins + v3.wins;
1149 if( targLevel < 0 ) then
1150 stats.pvpWinAvgLevelDiff = stats.pvpWinAvgLevelDiff + v3.wins*(targLevel-playerLevel);
1151 else
1152 stats.pvpWinAvgLevelDiff = stats.pvpWinAvgLevelDiff + v3.wins*(targLevel-playerLevel);
1153 end
1154 stats.pvpLoss = stats.pvpLoss + v3.loss;
1155 if( targLevel < 0 ) then
1156 stats.pvpLossAvgLevelDiff = stats.pvpLossAvgLevelDiff + v3.loss*(targLevel-playerLevel);
1157 else
1158 stats.pvpLossAvgLevelDiff = stats.pvpLossAvgLevelDiff + v3.loss*(targLevel-playerLevel);
1159 end
1160 else
1161 stats.duelWins = stats.duelWins + v3.wins;
1162 if( targLevel < 0 ) then
1163 stats.duelWinAvgLevelDiff = stats.duelWinAvgLevelDiff + v3.wins*(targLevel-playerLevel);
1164 else
1165 stats.duelWinAvgLevelDiff = stats.duelWinAvgLevelDiff + v3.wins*(targLevel-playerLevel);
1166 end
1167 stats.duelLoss = stats.duelLoss + v3.loss;
1168 if( targLevel < 0 ) then
1169 stats.duelLossAvgLevelDiff = stats.duelLossAvgLevelDiff + v3.loss*(targLevel-playerLevel);
1170 else
1171 stats.duelLossAvgLevelDiff = stats.duelLossAvgLevelDiff + v3.loss*(targLevel-playerLevel);
1172 end
1173 end
1174 end);
1175 end
1176 end);
1177 end);
1178  
1179 stats.totalWinAvgLevelDiff = stats.totalWinAvgLevelDiff / stats.totalWins;
1180 stats.totalLossAvgLevelDiff = stats.totalLossAvgLevelDiff / stats.totalLoss;
1181 stats.pvpWinAvgLevelDiff = stats.pvpWinAvgLevelDiff / stats.pvpWins;
1182 stats.pvpLossAvgLevelDiff = stats.pvpLossAvgLevelDiff / stats.pvpLoss;
1183 stats.duelWinAvgLevelDiff = stats.duelWinAvgLevelDiff / stats.duelWins;
1184 stats.duelLossAvgLevelDiff = stats.duelLossAvgLevelDiff / stats.duelLoss;
1185  
1186 return stats;
1187 end
1188  
1189 function PvPLogFriends(race1, race2)
1190 local alliance = { "Human", "Night Elf", "Dwarf", "Gnome" };
1191 local horde = { "Orc", "Tauren", "Undead", "Troll" };
1192  
1193 local found1 = false;
1194 local found2 = false;
1195  
1196 table.foreach( alliance,
1197 function( i,v )
1198 if( v == race1 ) then
1199 found1 = true;
1200 end
1201 if( v == race2 ) then
1202 found2 = true;
1203 end
1204 end);
1205  
1206 if( found1 and found2 ) then
1207 return true;
1208 end
1209  
1210 found1 = false;
1211 found2 = false;
1212  
1213 table.foreach( horde,
1214 function( i,v )
1215 if( v == race1 ) then
1216 found1 = true;
1217 end
1218 if( v == race2 ) then
1219 found2 = true;
1220 end
1221 end);
1222  
1223 return (found1 and found2);
1224 end
1225  
1226 function PvPLogRecord(vname,vlevel,vrace,vclass,vguild,venemy,win)
1227 -- deal with vlevel being negative 1 when they're 10 levels
1228 -- or more greater
1229 if( vlevel == -1 ) then
1230 vlevel = -plevel - 11;
1231 end
1232  
1233 -- check to see if we've encountered this person before
1234 if( PvPLogData[realm][player].battles[vname] == nil ) then
1235 PvPLogData[realm][player].battles[vname] = { };
1236 end
1237 if( PvPLogData[realm][player].battles[vname][vlevel] == nil ) then
1238 PvPLogData[realm][player].battles[vname][vlevel] = { };
1239 end
1240 if( PvPLogData[realm][player].battles[vname][vlevel][plevel] == nil ) then
1241 PvPLogData[realm][player].battles[vname][vlevel][plevel] = { };
1242 PvPLogData[realm][player].battles[vname][vlevel][plevel].wins = 0;
1243 PvPLogData[realm][player].battles[vname][vlevel][plevel].loss = 0;
1244 end
1245  
1246 -- record info
1247 PvPLogData[realm][player].battles[vname].race = vrace;
1248 PvPLogData[realm][player].battles[vname].class = vclass;
1249 PvPLogData[realm][player].battles[vname].guild = vguild;
1250 PvPLogData[realm][player].battles[vname].enemy = venemy;
1251  
1252 local x, y = GetPlayerMapPosition("player");
1253 x = math.floor(x*100);
1254 y = math.floor(y*100);
1255 local notifyMsg = "";
1256 local notifySystem = nil;
1257  
1258 local vleveltext = vlevel;
1259 if( vlevel < 0 ) then
1260 vleveltext = (-vlevel) .. "+";
1261 end
1262  
1263 if( win ) then
1264 PvPLogData[realm][player].battles[vname][vlevel][plevel].wins =
1265 PvPLogData[realm][player].battles[vname][vlevel][plevel].wins + 1;
1266  
1267 notifyMsg = PvPLogData[realm][player].notifyKillText;
1268 notifyMsg = string.gsub( notifyMsg, "%%n", vname );
1269 notifyMsg = string.gsub( notifyMsg, "%%l", vleveltext );
1270 notifyMsg = string.gsub( notifyMsg, "%%r", vrace );
1271 notifyMsg = string.gsub( notifyMsg, "%%c", vclass );
1272 if( vguild ) then
1273 notifyMsg = string.gsub( notifyMsg, "%%g", vguild );
1274 end
1275 notifyMsg = string.gsub( notifyMsg, "%%x", x );
1276 notifyMsg = string.gsub( notifyMsg, "%%y", y );
1277 notifyMsg = string.gsub( notifyMsg, "%%z", GetZoneText() );
1278 --notifyMsg = notifyMsg .. "I killed " .. vname ..
1279 -- " (Level " .. vleveltext .. " " .. vrace .. " " .. vclass;
1280 --if( vguild ) then
1281 -- notifyMsg = notifyMsg .. ", from " .. vguild;
1282 --end
1283 --notifyMsg = notifyMsg .. ") at [" ..x..","..y .. "] in " .. GetZoneText();
1284 --notifyMsg = notifyMsg .. ") at [" ..x..","..y .. "]";
1285  
1286 notifySystem = PvPLogData[realm][player].notifyKill;
1287 else
1288 PvPLogData[realm][player].battles[vname][vlevel][plevel].loss =
1289 PvPLogData[realm][player].battles[vname][vlevel][plevel].loss + 1;
1290  
1291 --notifyMsg = notifyMsg .. vname ..
1292 -- " (Level " .. vleveltext .. " " .. vrace .. " " .. vclass;
1293 --if( vguild ) then
1294 -- notifyMsg = notifyMsg .. ", from " .. vguild;
1295 --end
1296 --notifyMsg = notifyMsg .. ") just killed me at [" ..x..","..y .. "]";
1297  
1298 notifyMsg = PvPLogData[realm][player].notifyDeathText;
1299 notifyMsg = string.gsub( notifyMsg, "%%n", vname );
1300 notifyMsg = string.gsub( notifyMsg, "%%l", vleveltext );
1301 notifyMsg = string.gsub( notifyMsg, "%%r", vrace );
1302 notifyMsg = string.gsub( notifyMsg, "%%c", vclass );
1303 if( vguild ) then
1304 notifyMsg = string.gsub( notifyMsg, "%%g", vguild );
1305 end
1306 notifyMsg = string.gsub( notifyMsg, "%%x", x );
1307 notifyMsg = string.gsub( notifyMsg, "%%y", y );
1308 notifyMsg = string.gsub( notifyMsg, "%%z", GetZoneText() );
1309  
1310 notifySystem = PvPLogData[realm][player].notifyDeath;
1311  
1312 -- fix to double recording of deaths
1313 -- likely caused by blizzard sending PLAYER_DEAD twice
1314 lastDamagerToMe = "";
1315 end
1316  
1317 if( venemy and
1318 ((notifySystem == "party" and GetNumPartyMembers() > 0) or
1319 (notifySystem == "guild" and GetGuildInfo("player") ) or
1320 (notifySystem == "raid" and GetNumRaidMembers() > 0)) ) then
1321 SendChatMessage(notifyMsg, notifySystem);
1322 elseif( venemy and notifySystem ~= "none" and notifySystem ~= "party" and
1323 notifySystem ~= "guild" and notifySystem ~= "raid" ) then
1324 PvPLogSendMessageOnChannel(notifyMsg, notifySystem);
1325 end
1326  
1327 PvPLogUpdateTargetText();
1328 end
1329  
1330  
1331 function PvPLogUpdateTargetText()
1332 local field = getglobal("PvPLogTargetText");
1333  
1334 if( UnitName("target") ) then
1335 local total = PvPLogGetPvPTotals(UnitName("target"));
1336 local guildTotal = PvPLogGetGuildTotals(GetGuildInfo("target"));
1337 local msg = "";
1338 local show = false;
1339 if( total and (total.wins > 0 or total.loss > 0) ) then
1340 msg = msg .. CYAN .. "PvP: " .. GREEN .. total.wins.. CYAN .. " / " .. RED .. total.loss;
1341 show = true;
1342 end
1343 if( guildTotal and (guildTotal.wins > 0 or guildTotal.loss > 0) and
1344 (not total or total.wins ~= guildTotal.wins or total.loss ~= guildTotal.loss) ) then
1345 if( show ) then
1346 msg = msg .. CYAN .. " - ";
1347 end
1348 msg = msg .. CYAN .. "Guild: ";
1349 msg = msg .. GREEN .. guildTotal.wins.. CYAN .. " / ".. RED .. guildTotal.loss;
1350 show = true;
1351 end
1352 if( show ) then
1353 field:SetText(msg);
1354 field:Show();
1355 end
1356 end
1357 end
1358  
1359 function PvPLogSendMessageOnChannel(message, channelName)
1360 local channelNum = PvPLogGetChannelNumber(channelName);
1361  
1362 if (not channelNum or channelNum == 0) then
1363 PvPLogJoinChannel(channelName);
1364 channelNum = PvPLogGetChannelNumber(channelName);
1365 end
1366  
1367 if (not channelNum or channelNum == 0) then
1368 PvPLogChatMsg(MAGENTA.."PvPLog Error: Not in notification channel \""..channelName.."\".");
1369 return;
1370 end
1371  
1372 SendChatMessage(message, "CHANNEL", GetLanguageByIndex(0), channelNum);
1373 end
1374  
1375  
1376 function PvPLogGetChannelNumber(channel)
1377 local num = 0;
1378 for i = 1, 200, 1 do
1379 local channelNum, channelName = GetChannelName(i);
1380  
1381 if ((channelNum > 0) and channelName and (string.lower(channelName) == string.lower(channel))) then
1382 num = channelNum;
1383 break;
1384 end
1385 end
1386  
1387 return num;
1388 end
1389  
1390 function PvPLogJoinChannel(channelName)
1391 local channelNumber = PvPLogGetChannelNumber(channelName);
1392 local needToJoin = (channelNumber <= 0);
1393  
1394 if( needToJoin ) then
1395 local i = 1;
1396 while ( DEFAULT_CHAT_FRAME.channelList[i] ) do
1397 local zoneValue = "nil";
1398 if (DEFAULT_CHAT_FRAME.zoneChannelList[i])
1399 then
1400 zoneValue = DEFAULT_CHAT_FRAME.zoneChannelList[i];
1401 end
1402 if ( string.lower(DEFAULT_CHAT_FRAME.channelList[i]) == string.lower(channelName) and
1403 DEFAULT_CHAT_FRAME.zoneChannelList[i] and DEFAULT_CHAT_FRAME.zoneChannelList[i] > 0)
1404 then
1405 needToJoin = false;
1406 break;
1407 end
1408 i = i + 1;
1409 end
1410  
1411 JoinChannelByName(channelName, "", DEFAULT_CHAT_FRAME:GetID());
1412 DEFAULT_CHAT_FRAME.channelList[i] = channelName;
1413 DEFAULT_CHAT_FRAME.zoneChannelList[i] = 0;
1414 end
1415 end