vanilla-wow-addons – Blame information for rev 1

Subversion Repositories:
Rev:
Rev Author Line No. Line
1 office 1 -- 09/04/2005 12:30:49 PIng: Replace hardcoded strings for UI by localized variables
2 -- 09/04/2005 12:31:41 PIng: Bug fix. Replace ShM_PrintMessage by SkM_PrintMessage
3 -- 09/04/2005 15:52:09 PIng: Add guild support
4 -- 09/04/2005 16:18:34 PIng: Update war info on target frame when status is changed
5  
6 SKM_UNIT_PLAYER = "player";
7 SKM_UNIT_TARGET = "target";
8 SKM_UNIT_MOUSEOVER = "mouseover";
9 SKM_UNIT_PARTY = "party";
10 SKM_UNIT_PET = "pet";
11  
12 SKM_UNIT_PARTY_1 = SKM_UNIT_PARTY.."1";
13 SKM_UNIT_PARTY_2 = SKM_UNIT_PARTY.."2";
14 SKM_UNIT_PARTY_3 = SKM_UNIT_PARTY.."3";
15 SKM_UNIT_PARTY_4 = SKM_UNIT_PARTY.."4";
16  
17  
18  
19 _RealmName = nil;
20 _PlayerName = nil;
21  
22  
23 SKM_MAX_MAP_NOTES = 200;
24  
25  
26 local TXT_NIL = "nil";
27  
28 local SKM_MESSAGE_PREFIX = "SKM: ";
29  
30 local SKM_TRACE_MODE_NONE = 0;
31 local SKM_TRACE_MODE_PRINT = 1;
32 local SKM_TRACE_MODE_CHATMSG = 2;
33  
34 local SKM_TRACE_NIL = false;
35  
36 local TXT_NIL = "nil";
37  
38 --local SKM_TRACE_MODE = SKM_TRACE_MODE_NONE;
39 --local SKM_TRACE_MODE = SKM_TRACE_MODE_PRINT;
40 local SKM_TRACE_MODE = SKM_TRACE_MODE_CHATMSG;
41  
42  
43  
44 -- number of days in a month for a non leap year
45 local DaysInMonth = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
46  
47 -- list of leap years for the first half of the 21st century
48 local LeapYears = { 2000, 2004, 2008, 2012, 2016, 2020, 2024, 2028, 2032, 2036, 2040, 2044, 2048 };
49  
50  
51  
52 -- List of ennemy player factions races (alliance and horde)
53 -- (could easily add more by altering the list, though it probably won't happen !)
54 SKM_PlayerFaction = {
55 { Faction = "Alliance",
56 RaceList = { SKM_RACE.Dwarf, SKM_RACE.Gnome, SKM_RACE.Human, SKM_RACE.NightElf }
57 };
58  
59 { Faction = "Horde",
60 RaceList = { SKM_RACE.Orc, SKM_RACE.Tauren, SKM_RACE.Troll, SKM_RACE.Undead }
61 };
62 };
63  
64 SKM_HonorKillPerDay = 4;
65  
66  
67 SKM_ToStandardCase = {
68 ["A"] = { "\195\128", "\195\129", "\195\130", "\195\131", "\195\132", "\195\133" },
69 ["E"] = { "\195\136", "\195\137", "\195\138", "\195\139"},
70 ["I"] = { "\195\140", "\195\141", "\195\142", "\195\143"},
71 ["O"] = { "\195\146", "\195\147", "\195\148", "\195\149", "\195\150", "\195\152" },
72 ["U"] = { "\195\153", "\195\154", "\195\155", "\195\156" },
73 ["Y"] = { "\195\157", "\195\191", "\197\184" },
74  
75 ["C"] = { "\195\135" },
76 ["D"] = { "\195\144" },
77 ["N"] = { "\195\145" },
78 ["S"] = { "\197\160", "\197\161"}
79 };
80  
81  
82 SKM_GuildChannelPrefix = "SKM";
83  
84  
85  
86 -- OLD table indexes - before data migration - SKMap 1.4
87 -- -----------------------------------------------------
88 _SKM_OLD = {
89 _name = "name";
90 _class = "class";
91 _guild = "guild";
92 _race = "race";
93 _level = "level";
94  
95 _playerNote = "playerNote";
96  
97 _playerKill = "playerKill";
98 _playerAssistKill = "playerAssistKill";
99 _playerFullKill = "playerFullKill";
100  
101 _honorKill = "honorKill";
102 _honorCount = "honorCount";
103 _honorLastKill = "honorLastKill";
104 _rank = "rank";
105  
106 _meetCount = "meetCount";
107 _atWar = "atWar";
108 -- _guildAtWar = "guildAtWar";
109 _warDate = "warDate";
110  
111 _continent = "continent";
112 _zone = "zone";
113 _xPos = "xPos";
114 _yPos = "yPos";
115 _zoneName = "zoneName";
116  
117 -- _lastUpdate = "lastUpdate";
118 _lastView = "lastView";
119 _lastPlayerViewed = "lastPlayerViewed";
120  
121 _enemyKillPlayer = "enemyKillPlayer";
122 _enemyKillBG = "enemyKillBG";
123 _playerBGKill = "playerBGKill";
124  
125 _members = "members";
126  
127 _type = "type";
128 _date = "date";
129 _enemyType = "enemyType";
130 _enemyPlayer = "enemyPlayer";
131 _enemyCreature = "enemyCreature";
132  
133 _playerDeath = "playerDeath";
134 _playerDeathPvP = "playerDeathPvP";
135 _playerDeathPvE = "playerDeathPvE";
136 _creatureKill_Target = "creatureKill_Target";
137 _creatureKill_Xp = "creatureKill_Xp";
138 _levelUp = "levelUp";
139  
140 _loneWolfKill = "loneWolfKill";
141  
142 _storedInfo = "storedInfo";
143  
144 _win = "win";
145 _loss = "loss";
146 _duel = "duel";
147 _lastDuel = "lastDuel";
148 -- _score = "score";
149 };
150  
151 -- new table indexes - after data migration - SKMap 1.4
152 -- ----------------------------------------------------
153 _SKM = {
154 _name = "Na";
155 _class = "Cl";
156 _guild = "Gu";
157 _race = "Ra";
158 _level = "Lv";
159  
160 _playerNote = "PlN";
161  
162 _playerKill = "PK";
163 _playerAssistKill = "PaK";
164 _playerFullKill = "PfK";
165  
166 _honorKill = "hK";
167 _honorCount = "hC";
168 _honorLastKill = "hLK";
169 _rank = "Rk";
170  
171 _meetCount = "mC";
172 _atWar = "Wr";
173 _guildAtWar = "gWr"; -- not saved
174 _warDate = "WD";
175  
176 _continent = "Co";
177 _zone = "Zo";
178 _xPos = "x";
179 _yPos = "y";
180 _zoneName = "ZN";
181  
182 _lastUpdate = "lU"; -- not saved
183 _lastView = "lV";
184 _lastPlayerViewed = "lPV";
185  
186  
187 _enemyKillPlayer = "EKP";
188 _enemyKillBG = "EKb";
189 _playerBGKill = "PbK";
190  
191 _members = "Mb"; -- not saved
192  
193 _type = "Ty";
194 _date = "Da";
195 _enemyType = "ETy";
196 _enemyPlayer = "EPl";
197 _enemyCreature = "ECr";
198  
199 _playerDeath = "PD";
200 _playerDeathPvP = "PDp";
201 _playerDeathPvE = "PDc";
202 _creatureKill_Target = "CKt";
203 _creatureKill_Xp = "CKx";
204 _levelUp = "LvU";
205  
206 _loneWolfKill = "LwK";
207  
208 _storedInfo = "Inf";
209  
210 _win = "Win";
211 _loss = "Los";
212 _duel = "Du";
213 _lastDuel = "lDu";
214 _score = "Scr"; -- not saved
215  
216  
217 -- following indexes are for temporary use (ie not saved in SavedVariables.lua, so it's
218 -- not as important if they're a bit longer)
219  
220 _noteIndex = "NIn";
221 _default = "Def";
222 _multiType = "MTy";
223 _playerKillAndDeath = "PKaD";
224  
225 _totalDamage = "tDm";
226 _groupDamage = "gDm";
227 _lastHateUpdate = "lHU";
228 _hateLevel = "HLv";
229 _damage = "Dm";
230 _hatePercent = "HPct";
231  
232 _time = "Ti";
233  
234 _owner = "Own";
235 _player = "Ply";
236 _other = "Oth";
237  
238 _players = "players";
239 _guilds = "guilds";
240 _duels = "duels";
241  
242 _bookCredits = "bookCredits";
243 _bookGeneralStat = "bookGeneralStat";
244 _bookClassStat = "bookClassStat";
245 _bookRaceStat = "bookRaceStat";
246 _bookPlayerStat = "bookPlayerStat";
247 _bookGuildStat = "bookGuildStat";
248 _bookMapStat = "bookMapStat";
249 _bookDateStat = "bookDateStat";
250  
251 _bookBGDateMapStat = "bookBGDateMapStat";
252 _bookBGDateStat = "bookBGDateStat";
253 _bookBGMapStat = "bookBGMapStat";
254  
255 _checkButton = "CBtn";
256 _slider = "Slid";
257  
258 };
259  
260  
261  
262 SKM_IndexMigr = {
263 [2] = {
264 EnemyHistory = {
265 {Old=_SKM_OLD._name, New=_SKM._name},
266 {Old=_SKM_OLD._class, New=_SKM._class},
267 {Old=_SKM_OLD._guild, New=_SKM._guild},
268 {Old=_SKM_OLD._race, New=_SKM._race},
269 {Old=_SKM_OLD._level, New=_SKM._level},
270 {Old=_SKM_OLD._playerNote, New=_SKM._playerNote},
271 {Old=_SKM_OLD._playerKill, New=_SKM._playerKill},
272 {Old=_SKM_OLD._playerAssistKill, New=_SKM._playerAssistKill},
273 {Old=_SKM_OLD._playerFullKill, New=_SKM._playerFullKill},
274 {Old=_SKM_OLD._honorKill, New=_SKM._honorKill},
275 {Old=_SKM_OLD._honorCount, New=_SKM._honorCount},
276 {Old=_SKM_OLD._honorLastKill, New=_SKM._honorLastKill},
277 {Old=_SKM_OLD._rank, New=_SKM._rank},
278 {Old=_SKM_OLD._meetCount, New=_SKM._meetCount},
279 {Old=_SKM_OLD._atWar, New=_SKM._atWar},
280 {Old=_SKM_OLD._warDate, New=_SKM._warDate},
281 {Old=_SKM_OLD._continent, New=_SKM._continent},
282 {Old=_SKM_OLD._zone, New=_SKM._zone},
283 {Old=_SKM_OLD._xPos, New=_SKM._xPos},
284 {Old=_SKM_OLD._yPos, New=_SKM._yPos},
285 {Old=_SKM_OLD._zoneName, New=_SKM._zoneName},
286 -- {Old=_SKM_OLD._lastUpdate, New=_SKM._lastUpdate},
287 {Old=_SKM_OLD._lastView, New=_SKM._lastView},
288 {Old=_SKM_OLD._enemyKillPlayer, New=_SKM._enemyKillPlayer},
289 {Old=_SKM_OLD._enemyKillBG, New=_SKM._enemyKillBG},
290 {Old=_SKM_OLD._playerBGKill, New=_SKM._playerBGKill},
291 };
292 GuildHistory = {
293 {Old=_SKM_OLD._name, New=_SKM._name},
294 -- {Old=_SKM_OLD._members, New=_SKM._members},
295 {Old=_SKM_OLD._meetCount, New=_SKM._meetCount},
296 {Old=_SKM_OLD._atWar, New=_SKM._atWar},
297 {Old=_SKM_OLD._warDate, New=_SKM._warDate},
298 {Old=_SKM_OLD._playerKill, New=_SKM._playerKill},
299 {Old=_SKM_OLD._playerAssistKill, New=_SKM._playerAssistKill},
300 {Old=_SKM_OLD._playerFullKill, New=_SKM._playerFullKill},
301 {Old=_SKM_OLD._enemyKillPlayer, New=_SKM._enemyKillPlayer},
302 {Old=_SKM_OLD._lastView, New=_SKM._lastView},
303 {Old=_SKM_OLD._lastPlayerViewed, New=_SKM._lastPlayerViewed},
304 };
305 GlobalMapData = {
306 {Old=_SKM_OLD._continent, New=_SKM._continent},
307 {Old=_SKM_OLD._zone, New=_SKM._zone},
308 {Old=_SKM_OLD._xPos, New=_SKM._xPos},
309 {Old=_SKM_OLD._yPos, New=_SKM._yPos},
310 {Old=_SKM_OLD._storedInfo, New=_SKM._storedInfo},
311 };
312 StoredInfo = {
313 {Old=_SKM_OLD._type, New=_SKM._type},
314 {Old=_SKM_OLD._date, New=_SKM._date},
315 {Old=_SKM_OLD._name, New=_SKM._name},
316 {Old=_SKM_OLD._level, New=_SKM._level},
317 {Old=_SKM_OLD._enemyType, New=_SKM._enemyType},
318 {Old=_SKM_OLD._loneWolfKill, New=_SKM._loneWolfKill},
319 {Old=_SKM_OLD._honorKill, New=_SKM._honorKill},
320 };
321 EnemyType = {
322 [_SKM_OLD._enemyPlayer] = _SKM._enemyPlayer;
323 [_SKM_OLD._enemyCreature] = _SKM._enemyCreature;
324 };
325 RecordType = {
326  
327 [_SKM_OLD._playerKill] = _SKM._playerKill;
328 [_SKM_OLD._playerAssistKill] = _SKM._playerAssistKill;
329 [_SKM_OLD._playerFullKill] = _SKM._playerFullKill;
330 [_SKM_OLD._playerDeath] = _SKM._playerDeath;
331 [_SKM_OLD._playerDeathPvP] = _SKM._playerDeathPvP;
332 [_SKM_OLD._playerDeathPvE] = _SKM._playerDeathPvE;
333 [_SKM_OLD._creatureKill_Target] = _SKM._creatureKill_Target;
334 [_SKM_OLD._creatureKill_Xp] = _SKM._creatureKill_Xp;
335 [_SKM_OLD._levelUp] = _SKM._levelUp;
336 };
337 DuelHistory = {
338 {Old=_SKM_OLD._name, New=_SKM._name},
339 {Old=_SKM_OLD._class, New=_SKM._class},
340 {Old=_SKM_OLD._guild, New=_SKM._guild},
341 {Old=_SKM_OLD._race, New=_SKM._race},
342 {Old=_SKM_OLD._level, New=_SKM._level},
343 {Old=_SKM_OLD._playerNote, New=_SKM._playerNote},
344 {Old=_SKM_OLD._win, New=_SKM._win},
345 {Old=_SKM_OLD._loss, New=_SKM._loss},
346 {Old=_SKM_OLD._duel, New=_SKM._duel},
347 {Old=_SKM_OLD._lastDuel, New=_SKM._lastDuel},
348 };
349 BGStatDate = {
350 {Old=_SKM_OLD._enemyKillBG, New=_SKM._enemyKillBG},
351 {Old=_SKM_OLD._playerBGKill, New=_SKM._playerBGKill},
352 };
353 };
354  
355 };
356  
357  
358  
359  
360  
361  
362  
363 --_time = "time";
364  
365 --_type = "type";
366  
367 --_name = "name";
368 --_class = "class";
369 --_guild = "guild"; -- PIng: Add guild support
370 --_race = "race";
371 --_level = "level";
372 --_date = "date";
373 --_sortdate = "sortdate";
374  
375 --_killedBy = "killBy";
376  
377 --_playerNote = "playerNote";
378  
379 --_noteIndex = "noteIndex";
380  
381 --_icon_PlayerKill = "icon_PlayerKill";
382 --_icon_PlayerDeath = "icon_PlayerDeath";
383  
384 -- type of map events
385 --_playerKill = "playerKill";
386 --_playerAssistKill = "playerAssistKill";
387 --_playerFullKill = "playerFullKill";
388 --_playerDeath = "playerDeath";
389 --_playerDeathPvP = "playerDeathPvP";
390 --_playerDeathPvE = "playerDeathPvE";
391 --_creatureKill_Target = "creatureKill_Target";
392 --_creatureKill_Xp = "creatureKill_Xp";
393 --_levelUp = "levelUp";
394  
395 --_loneWolfKill = "loneWolfKill";
396  
397 --_honorKill = "honorKill";
398 --_honorCount = "honorCount";
399 --_honorLastKill = "honorLastKill";
400 --_rank = "rank";
401  
402 --_win = "win";
403 --_loss = "loss";
404 --_duel = "duel";
405 --_lastDuel = "lastDuel";
406 --_score = "score";
407  
408 --_default = "default";
409 --_multiType = "multiType";
410 --_playerKillAndDeath = "playerKillAndDeath";
411  
412 --_enemyKillPlayer = "enemyKillPlayer";
413  
414 --_enemyKillBG = "enemyKillBG";
415 --_playerBGKill = "playerBGKill";
416  
417  
418 --_meetCount = "meetCount";
419 --_atWar = "atWar";
420 --_guildAtWar = "guildAtWar";
421 --_warDate = "warDate";
422  
423 --_continent = "continent";
424 --_zone = "zone";
425 --_xPos = "xPos";
426 --_yPos = "yPos";
427 --_icon = "icon";
428 --_storedInfo = "storedInfo";
429  
430 --_zoneName = "zoneName";
431  
432  
433 --_lastUpdate = "lastUpdate";
434 --_totalDamage = "totalDamage";
435 --_groupDamage = "groupDamage";
436  
437 --_lastHateUpdate = "lastHateUpdate";
438 --_hateLevel = "hateLevel";
439 --_enemyType = "enemyType";
440 --_damage = "damage";
441  
442 --_lastView = "lastView";
443 --_lastPlayerViewed = "lastPlayerViewed";
444  
445 --_enemyPlayer = "enemyPlayer";
446 --_enemyCreature = "enemyCreature";
447  
448 --_owner = "owner";
449 --_player = "player";
450 --_other = "other";
451  
452 --_players = "players";
453 --_guilds = "guilds";
454 --_duels = "duels";
455 --_members = "members";
456  
457 --_bookCredits = "bookCredits";
458 --_bookGeneralStat = "bookGeneralStat";
459 --_bookClassStat = "bookClassStat";
460 --_bookRaceStat = "bookRaceStat";
461 --_bookPlayerStat = "bookPlayerStat";
462 --_bookGuildStat = "bookGuildStat";
463 --_bookMapStat = "bookMapStat";
464 --_bookDateStat = "bookDateStat";
465  
466 --_bookBGDateMapStat = "bookBGDateMapStat";
467 --_bookBGDateStat = "bookBGDateStat";
468 --_bookBGMapStat = "bookBGMapStat";
469  
470  
471 --_checkButton = "checkButton";
472  
473 --_slider = "slider";
474  
475  
476  
477  
478  
479 function SkM_TableInsertMaxLengthLine(Lines, sLine, iMaxLen, iThreshold, sColorPrefix)
480 local FName = "SkM_TableInsertMaxLengthLine";
481 local sTmp = sLine;
482 local SeparList = {" ", "-", ".", ",", ":", ";"};
483 local sColor = "";
484 if (sColorPrefix) then
485 sColor = sColorPrefix;
486 end
487 while (string.len(sTmp) > 0) do
488 if (string.len(sTmp) <= iMaxLen) then
489 table.insert(Lines, sColor..sTmp);
490 sTmp = "";
491 else
492 local iPos = iMaxLen;
493 local sChar = string.sub(sTmp, iPos, iPos);
494 while (iPos > iMaxLen - iThreshold) and not (intable(sChar, SeparList)) do
495 iPos = iPos - 1;
496 sChar = string.sub(sTmp, iPos, iPos);
497 end
498 if (intable(sChar, SeparList)) then
499 table.insert(Lines, sColor..string.sub(sTmp, 1, iPos));
500 sTmp = string.sub(sTmp, iPos+1, string.len(sTmp));
501 else
502 table.insert(Lines, sColor..string.sub(sTmp, 1, iMaxLen));
503 sTmp = string.sub(sTmp, iMaxLen+1, string.len(sTmp));
504 end
505 end
506 end
507  
508 end
509  
510  
511  
512 -- --------------------------------------------------------------------------------------
513 -- ifnil
514 -- --------------------------------------------------------------------------------------
515 -- Return input value if it's not nil, else return alternative value specified.
516 -- --------------------------------------------------------------------------------------
517 function ifnil( iVal, iNewVal)
518 if ( iVal == nil) then
519 return iNewVal;
520 else
521 return iVal;
522 end
523 end
524  
525  
526 -- --------------------------------------------------------------------------------------
527 -- snil
528 -- --------------------------------------------------------------------------------------
529 -- Return the input string, or the string "nil" if the variable is nil
530 -- --------------------------------------------------------------------------------------
531 function snil_old( Val )
532 if ( Val == nil ) then
533 return TXT_NIL;
534 else
535 return Val;
536 end
537 end
538  
539 function snil( Val )
540 if ( Val == nil ) then
541 return TXT_NIL;
542 else
543 if ( Val == true) then
544 return "true";
545 elseif ( Val == false) then
546 return "false";
547 else
548 return Val;
549 end
550 end
551 end
552  
553  
554 -- --------------------------------------------------------------------------------------
555 -- copytable
556 -- --------------------------------------------------------------------------------------
557 -- Make a copy of a table
558 -- --------------------------------------------------------------------------------------
559 function copytable(MyTable)
560 if (type(MyTable) ~= "table" ) then
561 return MyTable;
562 end
563 local idx, val;
564 local NewTable = {};
565 for idx, val in MyTable do
566 NewTable[idx] = copytable(val);
567 end
568 return NewTable;
569 end
570  
571  
572 -- --------------------------------------------------------------------------------------
573 -- intable
574 -- --------------------------------------------------------------------------------------
575 -- Return true if "Val" is in table "TheTable"
576 -- --------------------------------------------------------------------------------------
577 function intable( Val, TheTable)
578 local idx, TableValue;
579 for idx, TableValue in TheTable do
580 if Val == TableValue then
581 return true;
582 end
583 end
584 return false;
585 end
586  
587  
588 -- remove "Val" if found in list "TheTable"
589 -- return resulting list
590 function removefromlist( Val, TheTable )
591 local MyTable = TheTable;
592 local iSize = table.getn(MyTable);
593 local i = 1;
594 while (i <= iSize) do
595 if (MyTable[i] == Val) then
596 table.remove(MyTable, i);
597 iSize = iSize - 1;
598 else
599 i = i + 1;
600 end
601 end
602 return MyTable;
603 end
604  
605  
606 -- --------------------------------------------------------------------------------------
607 -- appendtables
608 -- --------------------------------------------------------------------------------------
609 -- Append several list tables and returns the resulting table.
610 -- Can take single elements also, in that case convert them to tables.
611 -- --------------------------------------------------------------------------------------
612 function appendtables( ... )
613  
614 local TableRes = { };
615 local iNbArg = arg.n;
616 local i;
617  
618 for i=1, iNbArg do
619 local MyTable;
620 local Table = arg[i];
621 if (type(Table) ~= "table" ) then
622 MyTable = { Table };
623 else
624 MyTable = Table;
625 end
626  
627 local idx, TableValue;
628 for idx, TableValue in MyTable do
629 table.insert(TableRes, TableValue);
630 end
631 end
632  
633 return TableRes;
634 end
635  
636  
637 -- --------------------------------------------------------------------------------------
638 -- mergetables
639 -- --------------------------------------------------------------------------------------
640 -- Merge two list tables and returns the resulting table.
641 -- If both tables contain the same indexes, the first tables values will be returned for
642 -- this index.
643 -- Recursively merge sub tables if needed.
644 -- --------------------------------------------------------------------------------------
645 function mergetables(Table1, Table2)
646  
647 if (type(Table1) ~= "table") and (type(Table2) ~= "table") then
648 return Table1;
649 end
650 if (type(Table1) ~= "table") then
651 return Table2;
652 end
653 if (type(Table2) ~= "table") then
654 return Table1;
655 end
656  
657 local idx, TableValue;
658 local TableRes = Table1;
659 for idx, TableValue in Table2 do
660 if (not Table1[idx]) then
661 TableRes[idx] = TableValue;
662 else
663 TableRes[idx] = mergetables(Table1[idx], TableValue);
664  
665 end
666 end
667  
668 return TableRes;
669 end
670  
671  
672 -- --------------------------------------------------------------------------------------
673 -- revlist
674 -- --------------------------------------------------------------------------------------
675 -- Returns a list in reverse order
676 -- --------------------------------------------------------------------------------------
677 function revlist(ListIn)
678 local ListOut = {};
679 local MyList;
680  
681 if (type(ListIn) ~= "table" ) then
682 MyList = { ListIn };
683 else
684 MyList = ListIn;
685 end
686  
687 local idx, TableValue;
688 for idx, TableValue in MyList do
689 table.insert(ListOut, 1, TableValue);
690 end
691  
692 return ListOut;
693 end
694  
695  
696 function tablesize(Table)
697 local idx, val
698 local iSize = 0
699 for idx, val in Table do
700 iSize = iSize + 1;
701 end
702 return iSize;
703 end
704  
705  
706  
707 -- **************************************************************************************
708 -- Logs, debug and display functions
709 -- **************************************************************************************
710  
711 -- --------------------------------------------------------------------------------------
712 -- SkM_Trace
713 -- --------------------------------------------------------------------------------------
714 -- Debug function. Display information on screen, or on the default chat frame.
715 -- FName = calling function name
716 -- Level = level of trace, used to check if this debug will be displayed
717 -- Message = message to trace
718 -- --------------------------------------------------------------------------------------
719 function SkM_Trace( FName, Level, Message )
720 local OutMessage;
721  
722 if (Level <= SKM_Config.DebugLevel) then
723  
724 if (SKM_Config.DebugMaxFuncLen) and (string.len(FName) > SKM_Config.DebugMaxFuncLen) then
725 if (SKM_Config.DebugMaxFuncLen < 10) then
726 OutMessage = string.sub(FName, 1, SKM_Config.DebugMaxFuncLen).."/"..snil(Message);
727 else
728 OutMessage = string.sub(FName, 1, SKM_Config.DebugMaxFuncLen - 7)..".."
729 ..string.sub(FName, string.len(FName)-4, string.len(FName)).."/"..snil(Message);
730 end
731 else
732 OutMessage = FName.."/"..snil(Message);
733 end
734  
735 if (SKM_Config.RecordDebug) then
736 local sDate = SkM_GetDate();
737 local sRecordMsg = "["..sDate.."]<"..Level.."> "..snil(FName).."/"..snil(Message);
738 table.insert(SKM_Debug, sRecordMsg);
739  
740 SKM_Context.RecLines = SKM_Context.RecLines + 1;
741 SKM_Context.TmpRecLines = SKM_Context.TmpRecLines + 1;
742 if (SKM_Context.TmpRecLines >= SKM_Config.RecordIntervalInfo) then
743 SkM_ChatMessageCol("Lines recorded : "..SKM_Context.RecLines.." (Total : "..table.getn(SKM_Debug)..")");
744 SKM_Context.TmpRecLines = 0;
745 end
746  
747 return;
748 end
749  
750 if (SKM_TRACE_MODE == SKM_TRACE_MODE_PRINT) then
751 print(OutMessage);
752 elseif (SKM_TRACE_MODE == SKM_TRACE_MODE_CHATMSG) then
753 if not DEFAULT_CHAT_FRAME then
754 return;
755 end
756 local r = SKM_Config.RGB_Debug[Level].r;
757 local g = SKM_Config.RGB_Debug[Level].g;
758 local b = SKM_Config.RGB_Debug[Level].b;
759 SkM_PrintMessage(OutMessage, r, g, b); -- PIng: Bug Fix.Replace ShM_PrintMessage by SkM_PrintMessage
760 end
761 end
762 end
763  
764  
765 -- --------------------------------------------------------------------------------------
766 -- SkM_PrintMessage
767 -- --------------------------------------------------------------------------------------
768 -- Display a message in a frame in a specified RGB color, calling Blizz function
769 -- <frame>:AddMessage.
770 -- I don't know what the two last parameters stand for :/
771 -- --------------------------------------------------------------------------------------
772 function SkM_PrintMessage(msg, r, g, b, frame, id, unknown4th)
773 local OutMessage;
774  
775 if(unknown4th) then
776 local temp = id;
777 id = unknown4th;
778 unknown4th = id;
779 end
780  
781 OutMessage = snil(msg);
782  
783 if (not r) then r = 1.0; end
784 if (not g) then g = 1.0; end
785 if (not b) then b = 1.0; end
786 if ( frame ) then
787 frame:AddMessage(OutMessage, r, g, b, id, unknown4th);
788 else
789 if ( DEFAULT_CHAT_FRAME ) then
790 DEFAULT_CHAT_FRAME:AddMessage(OutMessage, r, g, b, id, unknown4th);
791 end
792 end
793 end
794  
795  
796 -- --------------------------------------------------------------------------------------
797 -- SkM_ChatMessageCol
798 -- --------------------------------------------------------------------------------------
799 -- Display a message on the default chat frame, with the module prefix.
800 -- Color is the module global chat color, if it has been set (default : white).
801 -- --------------------------------------------------------------------------------------
802 function SkM_ChatMessageCol( Message )
803 local OutMessage;
804 local r = SKM_Config.RGB_Msg.r;
805  
806 local g = SKM_Config.RGB_Msg.g;
807 local b = SKM_Config.RGB_Msg.b;
808  
809 if not DEFAULT_CHAT_FRAME then
810 return;
811 end
812 OutMessage = SKM_MESSAGE_PREFIX..snil(Message);
813 SkM_PrintMessage(OutMessage, r, g, b);
814 end
815  
816  
817 -- --------------------------------------------------------------------------------------
818 -- SkM_ChatMessageColP
819 -- --------------------------------------------------------------------------------------
820 -- Display a message on the default chat frame, with the module prefix.
821 -- RBGTriplet specifies the text color.
822 -- --------------------------------------------------------------------------------------
823 function SkM_ChatMessageColP( Message, RGBTriplet )
824 local OutMessage;
825 local r = RGBTriplet.r;
826 local g = RGBTriplet.g;
827 local b = RGBTriplet.b;
828  
829 if not DEFAULT_CHAT_FRAME then
830 return;
831 end
832 OutMessage = SKM_MESSAGE_PREFIX..snil(Message);
833 SkM_PrintMessage(OutMessage, r, g, b);
834 end
835  
836  
837  
838  
839  
840  
841  
842 -- --------------------------------------------------------------------------------------
843 -- SkM_Initialize
844 -- --------------------------------------------------------------------------------------
845 -- Module initialization
846 -- --------------------------------------------------------------------------------------
847 function SkM_Initialize()
848  
849 SKM_Context = {
850  
851 MapOpen = false;
852  
853 -- record damage done by player to enemies
854 EnemyCombat = { };
855  
856 -- record damage done by enemies to player
857 PlayerCombat = { };
858  
859  
860 -- record recent enemy kills
861 RecentEnemyKill = { };
862  
863 -- record recent WAR warnings to reduce spam
864 RecentWarWarning = { };
865  
866 --DuelEnemy = nil;
867  
868 -- list of player names in group
869 GroupList = { };
870  
871 -- list of player names in guild
872 GuildList = { };
873  
874 -- list of notes associated to a physical POI on the world map
875 WorldMapPOINotes = { };
876  
877 PlayerAlive = true;
878  
879 DataInit = false;
880  
881 -- parse patterns
882 Pattern = { };
883  
884 };
885  
886 SKM_Context.Continents = { GetMapContinents() } ;
887 SKM_Context.Zones = { };
888  
889 for idx, val in SKM_Context.Continents do
890 SKM_Context.Zones[idx] = { GetMapZones(idx) } ;
891 end
892  
893 SkM_BuildParsePatterns();
894  
895 SKM_Context.Race = {
896 IndexToString = {
897 [1] = SKM_RACE.Dwarf;
898 [2] = SKM_RACE.Gnome;
899  
900 [3] = SKM_RACE.Human;
901 [4] = SKM_RACE.NightElf;
902 [5] = SKM_RACE.Orc;
903 [6] = SKM_RACE.Tauren;
904  
905 [7] = SKM_RACE.Troll;
906 [8] = SKM_RACE.Undead;
907 };
908 StringToIndex = {
909 [SKM_RACE.Dwarf] = 1;
910 [SKM_RACE.Gnome] = 2;
911 [SKM_RACE.Human] = 3;
912 [SKM_RACE.NightElf] = 4;
913 [SKM_RACE.Orc] = 5;
914 [SKM_RACE.Tauren] = 6;
915 [SKM_RACE.Troll] = 7;
916 [SKM_RACE.Undead] = 8;
917 };
918 };
919  
920  
921 SKM_Context.Class = {
922 IndexToString = {
923 [1] = SKM_CLASS.Druid;
924 [2] = SKM_CLASS.Hunter;
925 [3] = SKM_CLASS.Mage;
926 [4] = SKM_CLASS.Paladin;
927 [5] = SKM_CLASS.Priest;
928 [6] = SKM_CLASS.Rogue;
929 [7] = SKM_CLASS.Shaman;
930 [8] = SKM_CLASS.Warrior;
931 [9] = SKM_CLASS.Warlock;
932 };
933 StringToIndex = {
934 [SKM_CLASS.Druid] = 1;
935 [SKM_CLASS.Hunter] = 2;
936 [SKM_CLASS.Mage] = 3;
937 [SKM_CLASS.Paladin] = 4;
938 [SKM_CLASS.Priest] = 5;
939 [SKM_CLASS.Rogue] = 6;
940 [SKM_CLASS.Shaman] = 7;
941 [SKM_CLASS.Warrior] = 8;
942 [SKM_CLASS.Warlock] = 9;
943 };
944 };
945  
946 SkM_InitData(false);
947 end
948  
949  
950 -- --------------------------------------------------------------------------------------
951 -- SkM_InitData
952  
953 -- --------------------------------------------------------------------------------------
954 -- Initialization of data saved across sessions
955 -- --------------------------------------------------------------------------------------
956 function SkM_InitData(bForceInit)
957 local FName = "SkM_InitData";
958  
959 -- context not yet created
960 if (not SKM_Context) then
961 return false;
962 end
963  
964 -- initialization already performed
965 if (SKM_Context.DataInit == true) and (not bForceInit) then
966 return true;
967 end
968  
969 _PlayerName = SkM_UnitName(SKM_UNIT_PLAYER);
970 _RealmName = GetCVar("realmName");
971  
972 -- if player name or realm name can't be retrieved yet, abort initialization
973 if (not _PlayerName) or (not _RealmName) then
974 return false;
975 end
976  
977 SKM_Context.PlayerName = _PlayerName;
978 SKM_Context.RealmName = _RealmName;
979  
980 -- store player current level, because we get old level upon event "level up", but I'm
981 -- not sure it would always be the case.
982 --SKM_Context.PlayerLevel = UnitLevel(SKM_UNIT_PLAYER);
983 -- since 1.5 it returns 0 at this point... have to do it later.
984  
985 -- global module data
986 if (not SKM_Data) then
987 SKM_Data = { } ;
988 end
989  
990 -- for recording debug messages
991 if (not SKM_Debug) then
992 SKM_Debug = { };
993 end
994  
995 -- module data for current realm
996 if (not SKM_Data[_RealmName]) then
997 SKM_Data[_RealmName] = { };
998 end
999  
1000 -- module data for current player of current realm
1001 if (not SKM_Data[_RealmName][_PlayerName]) then
1002 SKM_Data[_RealmName][_PlayerName] = { };
1003 SKM_Data[_RealmName][_PlayerName].PlayerName = SKM_Context.PlayerName;
1004  
1005 local sDate = SkM_GetDate();
1006 SKM_Data[_RealmName][_PlayerName].InitDate = sDate;
1007 end
1008  
1009 -- dunno when it happenned, but some chars do not have a "PlayerName". Fix it...
1010 if (not SKM_Data[_RealmName][_PlayerName].PlayerName) then
1011 SKM_Data[_RealmName][_PlayerName].PlayerName = _PlayerName;
1012 end
1013  
1014 -- sub maps of player data
1015  
1016 if (not SKM_Data[_RealmName][_PlayerName].GlobalMapData) then
1017 SKM_Data[_RealmName][_PlayerName].GlobalMapData = { };
1018 end
1019 if (not SKM_Data[_RealmName][_PlayerName].MapData) then
1020 SKM_Data[_RealmName][_PlayerName].MapData = { };
1021  
1022 local idx_c, val_c;
1023 for idx_c, val_c in SKM_Context.Continents do
1024 SKM_Data[_RealmName][_PlayerName].MapData[idx_c] = { };
1025  
1026 local idx_z, val_z
1027 for idx_z, val_z in SKM_Context.Zones[idx_c] do
1028 SKM_Data[_RealmName][_PlayerName].MapData[idx_c][idx_z] = { };
1029 end
1030 end
1031 end
1032  
1033 if (not SKM_Data[_RealmName][_PlayerName].EnemyHistory) then
1034 SKM_Data[_RealmName][_PlayerName].EnemyHistory = { };
1035 end
1036  
1037 -- 09/04/2005 16:28:31 PIng: Add Guild support
1038 if (not SKM_Data[_RealmName][_PlayerName].GuildHistory) then
1039 SKM_Data[_RealmName][_PlayerName].GuildHistory = { };
1040 end
1041  
1042 if (not SKM_Data[_RealmName][_PlayerName].UnknownEnemy) then
1043 SKM_Data[_RealmName][_PlayerName].UnknownEnemy = { };
1044 end
1045  
1046 if (not SKM_Data[_RealmName][_PlayerName].DuelHistory) then
1047 SKM_Data[_RealmName][_PlayerName].DuelHistory = { };
1048 end
1049  
1050 if (not SKM_Data[_RealmName][_PlayerName].BGStats) then
1051 SKM_Data[_RealmName][_PlayerName].BGStats = { };
1052 end
1053  
1054  
1055 local sGuildName = GetGuildInfo(SKM_UNIT_PLAYER);
1056 SkM_Trace(FName, 3, "Player guild = "..snil(sGuildName));
1057 if (sGuildName) and (sGuildName ~= "") and (false) then
1058 -- build guild list : open guild roster to retrieve guild players list
1059 GuildRoster();
1060 --SetGuildRosterShowOffline(1);
1061 SkM_BuildGuildList();
1062 --FriendsFrame:Hide();
1063 HideUIPanel(FriendsFrame);
1064 end
1065  
1066 -- Global settings
1067 if (not SKM_Settings) then
1068 SKM_Settings = { };
1069 end
1070 SkM_LoadDefaultSettings(false);
1071  
1072 SkM_RecordVersionHistory();
1073  
1074 SKM_Context.DataInit = true;
1075 SkM_Trace(FName, 3, "Done");
1076 return true;
1077 end
1078  
1079  
1080 -- --------------------------------------------------------------------------------------
1081 -- SkM_LoadDefaultSettings
1082 -- --------------------------------------------------------------------------------------
1083 -- Load (or reload) setting default values from configuration file
1084 -- --------------------------------------------------------------------------------------
1085 function SkM_LoadDefaultSettings(bForceReload)
1086 local FName = "SkM_LoadDefaultSettings";
1087  
1088 if (not SKM_Settings) then
1089 SKM_Settings = { };
1090 end
1091  
1092 if (bForceReload) then
1093  
1094 SkM_Trace(FName, 3, "Force reload default settings");
1095  
1096 for i=1, table.getn(SKM_OPTION_LIST), 1 do
1097 local key = SKM_OPTION_LIST[i];
1098 SKM_Settings[key] = SKM_Config[key];
1099 end
1100  
1101 else
1102 SkM_Trace(FName, 3, "Load missing default settings");
1103  
1104 for i=1, table.getn(SKM_OPTION_LIST), 1 do
1105 local key = SKM_OPTION_LIST[i];
1106 SkM_Trace(FName, 3, "key = "..key);
1107 if (SKM_Settings[key] == nil) then
1108 SKM_Settings[key] = SKM_Config[key];
1109 end
1110 end
1111  
1112 end
1113  
1114 if (SKM_Settings.CreatureKillRecordsByZone > SKM_MAX_CREEP_RECORD_BY_ZONE) then
1115 SKM_Settings.CreatureKillRecordsByZone = SKM_MAX_CREEP_RECORD_BY_ZONE;
1116 end
1117  
1118  
1119 -- for management of data migration. No use for now, but might be needed later on.
1120 if (SKM_Settings.DataModel == nil) then
1121 SKM_Settings.DataModel = SKM_VERSION;
1122 else
1123 SKM_Settings.DataModel = SKM_VERSION;
1124 end
1125  
1126 end
1127  
1128  
1129 -- --------------------------------------------------------------------------------------
1130 -- SkM_ResetData
1131 -- --------------------------------------------------------------------------------------
1132 -- Warning : this deletes ALL module data (for all players and realms)
1133 -- Use with caution !
1134 -- --------------------------------------------------------------------------------------
1135 function SkM_ResetData()
1136 SKM_Data = nil;
1137 SkM_InitData(true);
1138 end
1139  
1140  
1141 -- --------------------------------------------------------------------------------------
1142 -- SkM_ResetPlayerData
1143 -- --------------------------------------------------------------------------------------
1144 -- Delete all current player data
1145 -- --------------------------------------------------------------------------------------
1146 function SkM_ResetPlayerData()
1147 SKM_Data[_RealmName][_PlayerName] = nil;
1148 SkM_InitData(true);
1149 end
1150  
1151  
1152 -- --------------------------------------------------------------------------------------
1153 -- SkM_ResetPlayerData
1154 -- --------------------------------------------------------------------------------------
1155 -- Delete current player map data only
1156 -- --------------------------------------------------------------------------------------
1157 function SkM_ResetPlayerMapData()
1158 SKM_Data[_RealmName][_PlayerName].GlobalMapData = nil;
1159 SKM_Data[_RealmName][_PlayerName].MapData = nil;
1160 SkM_InitData(true);
1161 end
1162  
1163  
1164 -- --------------------------------------------------------------------------------------
1165 -- SkM_ResetAccountMapData
1166 -- --------------------------------------------------------------------------------------
1167 -- Delete all map data on a given account
1168 -- USE WITH CAUTION !!!
1169 -- --------------------------------------------------------------------------------------
1170 function SkM_ResetAccountMapData()
1171 local FName = "SkM_ResetAccountMapData";
1172  
1173 local idx_realm, val_realm, idx_char, val_char, idx_enemy, val_enemy;
1174  
1175 for idx_realm, val_realm in SKM_Data do
1176 for idx_char, val_char in SKM_Data[idx_realm] do
1177  
1178 if (SKM_Data[idx_realm][idx_char].PlayerName == idx_char) then
1179 SkM_Trace(FName, 1, "Cleaning for "..idx_realm.." / "..idx_char);
1180  
1181 -- clean up map data
1182 SKM_Data[idx_realm][idx_char].GlobalMapData = nil;
1183 SKM_Data[_RealmName][_PlayerName].MapData = nil;
1184  
1185 -- clean up zone stored in enemy information
1186 for idx_enemy, val_enemy in SKM_Data[idx_realm][idx_char].EnemyHistory do
1187 SKM_Data[idx_realm][idx_char].EnemyHistory[idx_enemy][_SKM._continent] = nil;
1188 SKM_Data[idx_realm][idx_char].EnemyHistory[idx_enemy][_SKM._zone] = nil;
1189 SKM_Data[idx_realm][idx_char].EnemyHistory[idx_enemy][_SKM._xPos] = nil;
1190 SKM_Data[idx_realm][idx_char].EnemyHistory[idx_enemy][_SKM._yPos] = nil;
1191 end
1192 end
1193 end
1194 end
1195  
1196 SkM_InitData(true);
1197 end
1198  
1199  
1200 -- --------------------------------------------------------------------------------------
1201 -- SkM_GetOption
1202 -- --------------------------------------------------------------------------------------
1203 -- Get a player option value
1204 -- --------------------------------------------------------------------------------------
1205 function SkM_GetOption(sConfigKey)
1206 local FName = "SkM_GetOption";
1207 if (SKM_Settings == nil) then
1208 SkM_Trace(FName, 1, "Settings not initialized, can't get value for "..snil(sConfigKey));
1209 return;
1210 end
1211 if (sConfigKey == nil) then
1212 SkM_Trace(FName, 1, "received nil param");
1213 return;
1214 end
1215 --return (SKM_Data[_RealmName][_PlayerName].Settings[sConfigKey]);
1216 return (SKM_Settings[sConfigKey]);
1217 end
1218  
1219  
1220 -- --------------------------------------------------------------------------------------
1221 -- SkM_SetOption
1222 -- --------------------------------------------------------------------------------------
1223 -- Set a player option to a given value
1224 -- --------------------------------------------------------------------------------------
1225 function SkM_SetOption(sConfigKey, Value)
1226 local FName = "SkM_SetOption";
1227 if (SKM_Settings == nil) then
1228 SkM_Trace(FName, 1, "Settings not initialized, can't set value for "..snil(sConfigKey));
1229 return;
1230 end
1231 if (sConfigKey == nil) then
1232 SkM_Trace(FName, 1, "received nil param");
1233 return;
1234 end
1235 --SKM_Data[_RealmName][_PlayerName].Settings[sConfigKey] = Value;
1236 SKM_Settings[sConfigKey] = Value;
1237 end
1238  
1239  
1240 function SkM_GetRaceText(Index)
1241 return SKM_Context.Race.IndexToString[Index];
1242 end
1243  
1244 function SkM_GetRaceIndex(Text)
1245 return SKM_Context.Race.StringToIndex[Text];
1246 end
1247  
1248 function SkM_GetClassText(Index)
1249 return SKM_Context.Class.IndexToString[Index];
1250 end
1251  
1252 function SkM_GetClassIndex(Text)
1253 return SKM_Context.Class.StringToIndex[Text];
1254 end
1255  
1256  
1257 -- --------------------------------------------------------------------------------------
1258 -- SkM_ExtractParam
1259 -- --------------------------------------------------------------------------------------
1260 -- Extract parameters from a string. Delimiter is the blank character (space).
1261 -- Return the first parameter and the rest of the string ("" if empty).
1262 -- --------------------------------------------------------------------------------------
1263 function SkM_ExtractParam(msg)
1264 local params = msg;
1265 local command = params;
1266 local index = strfind(command, " ");
1267  
1268 if ( index ) then
1269 command = strsub(command, 1, index-1);
1270 params = strsub(params, index+1);
1271 else
1272 params = "";
1273 end
1274 return command, params;
1275 end
1276  
1277  
1278 -- --------------------------------------------------------------------------------------
1279 -- SkM_IdentifyCommand
1280 -- --------------------------------------------------------------------------------------
1281 -- Check if the given command matches a module command.
1282 -- it's the case if the passed in command starts with the module command
1283 -- eg. : module command "fort" allows to type in "fortitude".
1284 -- --------------------------------------------------------------------------------------
1285 function SkM_IdentifyCommand(sCmd, sModuleCommand)
1286  
1287 if ((not sModuleCommand) or (sModuleCommand == "")) then
1288 return false;
1289 end
1290 if ((not sCmd) or (sCmd == "")) then
1291 return false;
1292 end
1293  
1294 local iLen = string.len(sModuleCommand);
1295  
1296 if ( string.sub(sCmd, 1, iLen) == sModuleCommand) then
1297 return true;
1298 else
1299 return false;
1300 end
1301 end
1302  
1303  
1304 -- --------------------------------------------------------------------------------------
1305 -- SkM_SetDebugLevel
1306 -- --------------------------------------------------------------------------------------
1307 -- Set the module debug level (-1, 0, 1, 2, 3)
1308 -- --------------------------------------------------------------------------------------
1309 function SkM_SetDebugLevel( iLevel )
1310 local iNewLevel = ifnil(iLevel, -1);
1311  
1312 SKM_Config.DebugLevel = iNewLevel;
1313 SkM_ChatMessageCol("Debug level set to "..iNewLevel);
1314 end
1315  
1316  
1317 function SkM_StartDebugRecord()
1318 SKM_Context.RecLines = 0;
1319 SKM_Context.TmpRecLines = 0;
1320 SKM_Config.RecordDebug = true;
1321 SkM_ChatMessageCol("Started recording debug messages");
1322 end
1323  
1324  
1325 function SkM_StopDebugRecord()
1326 SKM_Config.RecordDebug = false;
1327 SKM_Context.RecLines = nil;
1328 SKM_Context.TmpRecLines = nil;
1329 SkM_ChatMessageCol("Stopped recording debug messages");
1330 end
1331  
1332  
1333 function SkM_ClearDebugRecord()
1334 SKM_Debug = { };
1335 SKM_Context.RecLines = 0;
1336 SKM_Context.TmpRecLines = 0;
1337 SkM_ChatMessageCol("Recorded debug messages cleared");
1338 end
1339  
1340  
1341  
1342 -- --------------------------------------------------------------------------------------
1343 -- SkM_GetDate
1344 -- --------------------------------------------------------------------------------------
1345 -- Get current date in two formats :
1346 -- DD/MM/YYYY HH:MI:SS
1347 -- YYYY/MM/DD HH:MI:SS (this is a sortable date)
1348 -- --------------------------------------------------------------------------------------
1349 function SkM_GetDate()
1350 -- date is a shortcut to "os.date" (os package is not available, but Blizz provided
1351 -- us the date function :)
1352 local CurDate = date("*t");
1353 local sYear = string.format("%0.04d", CurDate.year);
1354 local sMonth = string.format("%0.02d", CurDate.month);
1355 local sDay = string.format("%0.02d", CurDate.day);
1356 local sHour = string.format("%0.02d", CurDate.hour);
1357 local sMin = string.format("%0.02d", CurDate.min);
1358 local sSec = string.format("%0.02d", CurDate.sec);
1359  
1360 -- date in format DD/MM/YYYY HH:MI:SS
1361 local StrDate1 = sDay.."/"..sMonth.."/"..sYear.." "..sHour..":"..sMin..":"..sSec;
1362  
1363 -- date in format YYYY/MM/DD HH:MI:SS (useful for sorting !)
1364 local StrDate2 = sYear.."/"..sMonth.."/"..sDay.." "..sHour..":"..sMin..":"..sSec;
1365  
1366 return StrDate1, StrDate2;
1367 end
1368  
1369  
1370 function SkM_GetDay()
1371 local sDate1, sDate2 = SkM_GetDate();
1372 local sDay1, sDay2;
1373 sDay1 = string.sub(sDate1, 1, 10);
1374 sDay2 = string.sub(sDate2, 1, 10);
1375 return sDay1, sDay2;
1376 end
1377  
1378  
1379 -- --------------------------------------------------------------------------------------
1380 -- SkM_GetSortableDate
1381 -- --------------------------------------------------------------------------------------
1382 -- Convert date to sortable format :
1383 -- from DD/MM/YYYY HH:MI:SS format to YYYY/MM/DD HH:MI:SS format
1384 -- or, from DD/MM/YYYY format to YYYY/MM/DD format
1385 -- --------------------------------------------------------------------------------------
1386 function SkM_GetSortableDate(sDate)
1387 if (not sDate) then
1388 return nil;
1389 end
1390  
1391 local sMonth, sDay, sYear, sHour, sMin, sSec;
1392 local sSortDate;
1393  
1394 sDay = string.sub(sDate, 1, 2);
1395 sMonth = string.sub(sDate, 4, 5);
1396 sYear = string.sub(sDate, 7, 10);
1397  
1398 if (string.len(sDate) == 19) then
1399 sHour = string.sub(sDate, 12, 13);
1400 sMin = string.sub(sDate, 15, 16);
1401 sSec = string.sub(sDate, 18, 19);
1402  
1403 SortDate = sYear.."/"..sMonth.."/"..sDay.." "..sHour..":"..sMin..":"..sSec;
1404 else
1405 SortDate = sYear.."/"..sMonth.."/"..sDay;
1406 end
1407  
1408 -- sortable date
1409 return SortDate;
1410 end
1411  
1412  
1413 function SkM_GetZoneText()
1414 local sText = GetZoneText();
1415 -- apply fix if needed.
1416 for idx, val in SKM_ZoneFix do
1417 if sText == val.Val_ZoneText then
1418 return val.Val_MapZones;
1419 end
1420 end
1421 return sText;
1422 end
1423  
1424  
1425 -- Return continent and zone number shifted to english order
1426 function SkM_GetCurrentMapZone_Shift()
1427 local FName = "SkM_GetCurrentMapZone_Shift";
1428  
1429 local iCont = GetCurrentMapContinent();
1430 local iZone = GetCurrentMapZone();
1431 if (iCont) and (iCont ~= 0) and (iZone) and (iZone ~= 0) and (SKM_ZoneShift) then
1432 if (SKM_ZoneShift[iCont]) and (SKM_ZoneShift[iCont][iZone]) then
1433 iZone = SKM_ZoneShift[iCont][iZone];
1434 else
1435 SkM_Trace(FName, 1, "Undefined shift : cont = "..iCont.." / zone = "..iZone);
1436 end
1437 end
1438 return iCont, iZone;
1439 end
1440  
1441  
1442 -- --------------------------------------------------------------------------------------
1443 -- SkM_GetZone
1444 -- --------------------------------------------------------------------------------------
1445 -- Return continent and zone number
1446 -- or (nil, nil) if GetZoneText() does not match any known zone
1447 -- --------------------------------------------------------------------------------------
1448 function SkM_GetZone()
1449 for i=1, getn(SKM_Context.Continents), 1 do
1450 for j=1, getn(SKM_Context.Zones[i]), 1 do
1451 --if (SKM_Context.Zones[i][j] == GetZoneText()) then
1452 if (SKM_Context.Zones[i][j] == SkM_GetZoneText()) then
1453 return i, j;
1454 end
1455 end
1456 end
1457 return nil, nil;
1458 end
1459  
1460  
1461 function SkM_GetZone_Shift(p_iCont, p_iZone)
1462 local iCont, iZone;
1463 if (p_iCont) and (p_iZone) then
1464 iCont = p_iCont;
1465 iZone = p_iZone;
1466 else
1467 iCont, iZone = SkM_GetZone();
1468 end
1469  
1470 if (iCont) and (iZone) and (SKM_ZoneShift) then
1471 iZone = SKM_ZoneShift[iCont][iZone];
1472 end
1473 return iCont, iZone;
1474 end
1475  
1476  
1477 -- get zone text from shifted zone index (english order)
1478 function SkM_GetZoneTextFromIndex(p_iCont, p_iZone)
1479 return ifnil(SKM_ZoneText[p_iCont][p_iZone], "");
1480 end
1481  
1482  
1483 function SkM_IsInBattleground()
1484 local FName = "SkM_IsInBattleground";
1485 local sZone = SkM_GetZoneText();
1486 if (intable(sZone, SKM_BATTLEGROUNDS)) then
1487 return true;
1488 else
1489 return false;
1490 end
1491 end
1492  
1493  
1494 -- --------------------------------------------------------------------------------------
1495 -- SkM_CheckNearNotes
1496 -- --------------------------------------------------------------------------------------
1497 -- Check if there are notes nearby given location
1498 -- OBSOLETE. I don't use it any more.
1499 -- --------------------------------------------------------------------------------------
1500 function SkM_CheckNearNotes(idx_c, idx_z, xPos, yPos, icon)
1501 local iNoteCount = getn(SKM_Data[_RealmName][_PlayerName].MapData[idx_c][idx_z]);
1502  
1503 for i=1, iNoteCount, 1 do
1504 local idx_gn = SKM_Data[_RealmName][_PlayerName].MapData[idx_c][idx_z][i];
1505 local Note = SKM_Data[_RealmName][_PlayerName].GlobalMapData[idx_gn];
1506  
1507 if (abs(Note[_SKM._xPos] - xPos) <= 0.0009765625 * SKM_Config.MapNotes_MinDiff)
1508 and (abs(Note[_SKM._yPos] - yPos) <= 0.0013020833 * SKM_Config.MapNotes_MinDiff)
1509 then
1510 return true;
1511 end
1512 end
1513 return false;
1514 end
1515  
1516  
1517 -- --------------------------------------------------------------------------------------
1518 -- SkM_FindNotePOINum
1519 -- --------------------------------------------------------------------------------------
1520 -- Retrieve which POI object is associated to a given map note
1521 -- --------------------------------------------------------------------------------------
1522 function SkM_FindNotePOINum(idx_n)
1523 for idx_poi, val_poi in SKM_Context.WorldMapPOINotes do
1524 if (intable(idx_n, val_poi)) then
1525 return idx_poi;
1526 end
1527 end
1528 return nil;
1529 end
1530  
1531  
1532 -- --------------------------------------------------------------------------------------
1533 -- SkM_CheckNearNotesPOI
1534 -- --------------------------------------------------------------------------------------
1535 -- For a given map note, try and find nearby allocated POI so that we may group
1536 -- current note to the notes associated to this POI.
1537 -- --------------------------------------------------------------------------------------
1538 function SkM_CheckNearNotesPOI(idx_c, idx_z, xPos, yPos, index, DiscardedNotes)
1539 local iNoteCount = getn(SKM_Data[_RealmName][_PlayerName].MapData[idx_c][idx_z]);
1540  
1541 local i;
1542 for i=1, iNoteCount, 1 do
1543 -- don't check notes > current note, because they've not been treated yet
1544 if (i == index) then
1545 return nil;
1546 end
1547  
1548 if (intable(i, DiscardedNotes)) then
1549 -- that note has been discarded, so don't check if it's too close !
1550 else
1551 local idx_gn = SKM_Data[_RealmName][_PlayerName].MapData[idx_c][idx_z][i];
1552 local Note = SKM_Data[_RealmName][_PlayerName].GlobalMapData[idx_gn];
1553  
1554 if (abs(Note[_SKM._xPos] - xPos) <= 0.0009765625 * SKM_Config.MapNotes_MinDiff)
1555 and (abs(Note[_SKM._yPos] - yPos) <= 0.0013020833 * SKM_Config.MapNotes_MinDiff)
1556 then
1557 -- we're close to another note that has an associated POI
1558 -- find this POI number and return it
1559 local iPOINum = SkM_FindNotePOINum(i);
1560 return iPOINum;
1561 end
1562 end
1563 end
1564 return nil;
1565 end
1566  
1567  
1568 -- --------------------------------------------------------------------------------------
1569 -- SkM_AddMapNote
1570 -- --------------------------------------------------------------------------------------
1571 -- Add a new player map note
1572 -- --------------------------------------------------------------------------------------
1573 function SkM_AddMapNote(idx_c, idx_z, Note)
1574 local FName = "SkM_AddMapNote";
1575  
1576 -- insert note to global data in last position
1577 table.insert(SKM_Data[_RealmName][_PlayerName].GlobalMapData, Note);
1578  
1579 -- retrieve index of inserted note
1580 local idx_gn = table.getn(SKM_Data[_RealmName][_PlayerName].GlobalMapData);
1581  
1582 -- insert new global note index to map note list
1583 table.insert(SKM_Data[_RealmName][_PlayerName].MapData[idx_c][idx_z], idx_gn);
1584 end
1585  
1586  
1587 -- --------------------------------------------------------------------------------------
1588 -- SkM_AddMapData
1589 -- --------------------------------------------------------------------------------------
1590 -- Create a new note from input stored data and store it in current zone records
1591 -- --------------------------------------------------------------------------------------
1592 function SkM_AddMapData(p_StoreInfo)
1593 local FName = "SkM_AddMapData";
1594  
1595 local idx_c, idx_z = SkM_GetZone();
1596  
1597 SkM_Trace(FName, 3, "idx_c = "..snil(idx_c)..", idx_z = "..snil(idx_z));
1598  
1599 if (idx_z) then
1600 SetMapZoom(idx_c, idx_z);
1601 local xPos, yPos = GetPlayerMapPosition(SKM_UNIT_PLAYER);
1602  
1603 local cont_shift, zone_shift = SkM_GetZone_Shift(idx_c, idx_z);
1604  
1605 SkM_Trace(FName, 3, "Player Position : x = "..snil(xPos)..", y = "..snil(yPos));
1606  
1607 --if ((not SkM_CheckNearNotes(idx_c, idx_z, xPos, yPos, icon)) and xPos ~= 0 and yPos ~= 0 ) then
1608 if (xPos ~= 0 and yPos ~= 0) then
1609  
1610 local Note = { };
1611 --Note[_SKM._continent] = idx_c;
1612 --Note[_SKM._zone] = idx_z;
1613 Note[_SKM._continent] = cont_shift;
1614 Note[_SKM._zone] = zone_shift;
1615 Note[_SKM._xPos] = xPos;
1616 Note[_SKM._yPos] = yPos;
1617 Note[_SKM._storedInfo] = p_StoreInfo;
1618  
1619 -- DOH !! forgot this one in 1.4. Now all records are messed up :(
1620 --SkM_AddMapNote(idx_c, idx_z, Note);
1621 SkM_AddMapNote(cont_shift, zone_shift, Note);
1622 SKM_Context.RecordingDisabled = false;
1623 return true;
1624 end
1625 end
1626  
1627 if (not SKM_Context.RecordingDisabled) then
1628 -- 1.5 : removed message that is of no use !
1629 --SkM_ChatMessageCol("Event recording is disabled in this location");
1630 SKM_Context.RecordingDisabled = true;
1631 end
1632  
1633 return false;
1634 end
1635  
1636  
1637 -- --------------------------------------------------------------------------------------
1638 -- SkM_RecordPlayerDeath
1639 -- --------------------------------------------------------------------------------------
1640 -- Record player death event.
1641 -- Find if it's a PvE or PvP or unknown death, determine responsibilities for this
1642 -- death, and create a record of the appropriate type.
1643 -- --------------------------------------------------------------------------------------
1644 function SkM_RecordPlayerDeath()
1645 local FName = "SkM_RecordPlayerDeath";
1646  
1647 local StoreInfo = { };
1648  
1649 StoreInfo[_SKM._type] = _SKM._playerDeath;
1650  
1651 local sDate1, sDate2 = SkM_GetDate();
1652 StoreInfo[_SKM._date] = sDate1;
1653 --StoreInfo[_sortdate] = sDate2;
1654  
1655 local sKiller, KillerType, HateList = SkM_PlayerDeathResp();
1656  
1657 -- check if in battleground
1658 local bBattleground = SkM_IsInBattleground();
1659  
1660 -- if killer is known, and if its type (player or creature) is also known, record
1661 -- specific death event
1662  
1663 -- note : it's possible that we determined that a given unit is responsible for our
1664 -- death, but we don't know if it's a player or a creature. It can happen if this
1665 -- unit killed us with dots only. In that case, the death type will be undetermined.
1666  
1667 -- addition : it can happen also because pets and players trigger the same events, thus
1668 -- if we never targetted or mouse-overed a given player, we will not know if he is
1669 -- a player or a pet.
1670  
1671 if (sKiller) and (KillerType == nil) then
1672 -- try to target to see if this is a player
1673 TargetByName(sKiller);
1674 SkM_UpdateUnitData();
1675  
1676 -- if this is an enemy player, then he should have been stored !
1677 if (SKM_Data[_RealmName][_PlayerName].EnemyHistory[sKiller]) then
1678 KillerType = _SKM._enemyPlayer;
1679 end
1680 end
1681  
1682 if (sKiller) and (KillerType) then
1683 StoreInfo[_SKM._name] = sKiller;
1684 StoreInfo[_SKM._enemyType] = KillerType;
1685  
1686 if (KillerType == _SKM._enemyPlayer) then
1687 SkM_UpdateEnemyLastView(sKiller, sDate1, false);
1688  
1689 StoreInfo[_SKM._type] = _SKM._playerDeathPvP;
1690  
1691 SkM_UpdateEnemy_IncrKillPlayer(sKiller, 1, bBattleground);
1692  
1693 if (bBattleground) then
1694 SkM_BGStats_AddDeath();
1695 end
1696  
1697 -- update target info if needed
1698 SkM_SetTargetInfo();
1699  
1700 else
1701 StoreInfo[_SKM._type] = _SKM._playerDeathPvE;
1702 end
1703 end
1704  
1705 -- check if world record are disabled, if it's the case return
1706 if (StoreInfo[_SKM._type] == _SKM._playerDeathPvP) then
1707 if (not SkM_GetOption("RecordPlayerDeath")) then
1708 return;
1709 end
1710 else
1711 if (not SkM_GetOption("RecordPlayerDeathNonPvP")) then
1712 return;
1713 end
1714 end
1715  
1716  
1717 if (SkM_AddMapData(StoreInfo)) then
1718  
1719 if (SkM_GetOption("DisplayDeathRecord")) then
1720 if (sKiller) and (KillerType) then
1721 if (KillerType == _SKM._enemyPlayer) then
1722 SkM_ChatMessageColP(string.format(SKM_UI_STRINGS.RecordMessage_PlayerPvPDeath, sKiller), SKM_Config.RGB_PlayerPvPDeath);
1723 else
1724 SkM_ChatMessageColP(string.format(SKM_UI_STRINGS.RecordMessage_PlayerPvEDeath, sKiller), SKM_Config.RGB_PlayerPvEDeath);
1725 end
1726 else
1727 SkM_ChatMessageColP(SKM_UI_STRINGS.RecordMessage_PlayerDeath, SKM_Config.RGB_PlayerDeath);
1728 end
1729 end
1730  
1731 end
1732  
1733 if (SkM_GetOption("ReportPlayerDeath")) then
1734 local iNbLine = math.min(SKM_Config.ReportDeathMaxLines, table.getn(HateList));
1735 if (iNbLine > 0) then
1736 SkM_ChatMessageColP(string.format(SKM_UI_STRINGS.ReportMessage_PlayerDeath, iNbLine),
1737 SKM_Config.RGB_ReportDeath);
1738  
1739 for i=1, iNbLine, 1 do
1740 SkM_ChatMessageColP(string.format("%d. %s (%d %%)", i, HateList[i][_SKM._name], HateList[i][_SKM._hatePercent]),
1741 SKM_Config.RGB_ReportDeath);
1742 end
1743 end
1744 end
1745  
1746 end
1747  
1748  
1749 -- --------------------------------------------------------------------------------------
1750 -- SkM_PlayerAlive
1751 -- --------------------------------------------------------------------------------------
1752 -- Player is back to life, remember it.
1753 -- --------------------------------------------------------------------------------------
1754 function SkM_PlayerAlive()
1755 SKM_Context.PlayerAlive = true;
1756 end
1757  
1758  
1759 -- --------------------------------------------------------------------------------------
1760 -- SkM_PlayerDeath
1761 -- --------------------------------------------------------------------------------------
1762 -- Handle player death event.
1763 -- --------------------------------------------------------------------------------------
1764 function SkM_PlayerDeath()
1765 local FName = "SkM_PlayerDeath";
1766  
1767 -- check if player was alive because in some cases we get two death messages for the
1768 -- same death
1769 if (SKM_Context.PlayerAlive == false) then
1770 SkM_Trace(FName, 3, "Not alive, discard death event");
1771 return;
1772 end
1773  
1774 SKM_Context.PlayerAlive = false;
1775  
1776 -- if (not SkM_GetOption("RecordPlayerDeath")) then
1777 -- return;
1778 -- end
1779  
1780 SkM_RecordPlayerDeath();
1781 end
1782  
1783  
1784 -- --------------------------------------------------------------------------------------
1785 -- SkM_WorldMapUpdate
1786 -- --------------------------------------------------------------------------------------
1787 -- Handle World Map Update event
1788 -- --------------------------------------------------------------------------------------
1789 function SkM_WorldMapUpdate()
1790 local FName = "SkM_WorldMapUpdate";
1791  
1792 if (WorldMapFrame:IsVisible()) then
1793 -- world map is visible, draw all that need to be !
1794  
1795 --local serverTime = GetTime();
1796 SKM_Context.MapOpen = true;
1797 --local mapContinent = GetCurrentMapContinent();
1798 --local mapZone = GetCurrentMapZone();
1799 local mapContinent, mapZone = SkM_GetCurrentMapZone_Shift();
1800 SKM_Context.CloseMap = { continent = mapContinent, zone = mapZone, time = GetTime() };
1801 SkM_MainDraw();
1802  
1803 elseif (SKM_Context.MapOpen) then
1804 -- Map is not visible, but recorded as opened. Close it.
1805 SKM_Context.MapOpen = false;
1806 SkM_MainDraw();
1807 --SkM_ChangeMap();
1808 else
1809 -- Map not visible, probably closed
1810 end
1811  
1812 end
1813  
1814  
1815 -- --------------------------------------------------------------------------------------
1816 -- SkM_CloseWorldMap
1817 -- --------------------------------------------------------------------------------------
1818 -- Handle Close World Map event
1819 -- --------------------------------------------------------------------------------------
1820 function SkM_CloseWorldMap()
1821 local FName = "SkM_CloseWorldMap";
1822  
1823 SKM_Context.MapOpen = false;
1824 SkM_MainDraw();
1825 --SkM_ChangeMap();
1826 end
1827  
1828  
1829 -- --------------------------------------------------------------------------------------
1830 -- SkM_MainDraw
1831 -- --------------------------------------------------------------------------------------
1832 -- Display our records as custom POI on the world map, and hide unused POI.
1833 -- --------------------------------------------------------------------------------------
1834 function SkM_MainDraw()
1835 local FName = "SkM_MainDraw";
1836  
1837 SKM_Context.WorldMapPOINotes = { };
1838  
1839 local lastUnused = 1;
1840 local maxNotes = SKM_MAX_MAP_NOTES;
1841 local iNbNotes = 0;
1842  
1843 --local idx_c = GetCurrentMapContinent();
1844 --local idx_z = GetCurrentMapZone();
1845 local idx_c, idx_z = SkM_GetCurrentMapZone_Shift();
1846  
1847 if (idx_c ~= 0) and (idx_z ~= 0)
1848 and (SKM_Data[_RealmName][_PlayerName].MapData[idx_c])
1849 and (SKM_Data[_RealmName][_PlayerName].MapData[idx_c][idx_z])
1850 then
1851 iNbNotes = table.getn(SKM_Data[_RealmName][_PlayerName].MapData[idx_c][idx_z]);
1852 end
1853  
1854 if (SKM_Context.MapOpen) and (SkM_GetOption("MapDisplayRecords")) then
1855  
1856 if (idx_c ~= 0) and (idx_z ~= 0)
1857 and (SKM_Data[_RealmName][_PlayerName].MapData[idx_c])
1858 and (SKM_Data[_RealmName][_PlayerName].MapData[idx_c][idx_z])
1859 then
1860  
1861 --iNbNotes = table.getn(SKM_Data[_RealmName][_PlayerName].MapData[idx_c][idx_z]);
1862  
1863 local DiscardedNotes = { };
1864  
1865 for idx_n, val_n in SKM_Data[_RealmName][_PlayerName].MapData[idx_c][idx_z] do
1866  
1867 local idx_gn = SKM_Data[_RealmName][_PlayerName].MapData[idx_c][idx_z][idx_n];
1868 local Note = SKM_Data[_RealmName][_PlayerName].GlobalMapData[idx_gn];
1869  
1870 if (Note[_SKM._xPos]) and (Note[_SKM._yPos]) and (lastUnused <= maxNotes) then
1871 local iPOINum = SkM_CheckNearNotesPOI(idx_c, idx_z, Note[_SKM._xPos], Note[_SKM._yPos], idx_n, DiscardedNotes);
1872 if (iPOINum) then
1873 SkM_Trace(FName, 3, "Already too close POI, discard this one : "..snil(idx_n));
1874  
1875 table.insert(DiscardedNotes, idx_n);
1876  
1877 -- and insert it in the close POI list
1878 table.insert(SKM_Context.WorldMapPOINotes[iPOINum], idx_n);
1879 else
1880 local mainNote = getglobal("SKMapPOI"..lastUnused);
1881  
1882 SKM_Context.WorldMapPOINotes[lastUnused] = { };
1883 table.insert(SKM_Context.WorldMapPOINotes[lastUnused], idx_n);
1884  
1885 local mnX,mnY;
1886 mnX = Note[_SKM._xPos] * WorldMapDetailFrame:GetWidth();
1887 mnY = -Note[_SKM._yPos] * WorldMapDetailFrame:GetHeight();
1888 mainNote:SetAlpha(0.8);
1889  
1890 -- SkM_Trace(FName, 3, "Attach position : x = "..snil(mnX)..", y = "..snil(mnY));
1891  
1892  
1893 mainNote:SetPoint("CENTER", "WorldMapDetailFrame", "TOPLEFT", mnX, mnY);
1894 mainNote:SetFrameLevel(WorldMapPlayer:GetFrameLevel() - 1);
1895 mainNote.toolTip = idx_n;
1896  
1897 -- icon is determined below
1898  
1899 lastUnused = lastUnused + 1;
1900 end
1901  
1902 end
1903 end -- for map notes
1904  
1905 for i=1, getn(SKM_Context.WorldMapPOINotes), 1 do
1906 local mainNote = getglobal("SKMapPOI"..i);
1907 local mainNoteTexture = getglobal("SKMapPOI"..i.."Texture");
1908  
1909 local iNbNotes = getn(SKM_Context.WorldMapPOINotes[i]);
1910 local icon;
1911  
1912 local iNumOfTypes, iNumOfPlayerKillTypes, iNumOfPlayerDeathTypes,
1913 iNumOfCreatureKillTypes, TypeCount = SkM_CountPOIEventType(idx_c, idx_z, i);
1914  
1915 SkM_Trace(FName, 3, "Number of different types = "..iNumOfTypes..", of player kill = "..iNumOfPlayerKillTypes..", of death = "..iNumOfPlayerDeathTypes);
1916  
1917 if (iNumOfTypes == 1) then
1918 -- several notes, but of a single type. Pick the first !
1919  
1920 local idx_n = SKM_Context.WorldMapPOINotes[i][1];
1921 local idx_gn = SKM_Data[_RealmName][_PlayerName].MapData[idx_c][idx_z][idx_n];
1922 local Note = SKM_Data[_RealmName][_PlayerName].GlobalMapData[idx_gn];
1923  
1924 local noteType = Note[_SKM._storedInfo][_SKM._type];
1925 SkM_Trace(FName, 3, "Single type = "..noteType);
1926  
1927 icon = SKM_Config.IconsByType[noteType];
1928 if (not icon) then
1929 icon = SKM_Config.IconsByType[_SKM._default];
1930 end
1931  
1932 else
1933  
1934 if (iNumOfPlayerDeathTypes == iNumOfTypes) then
1935 icon = SKM_Config.IconsByType[_SKM._playerDeath];
1936 elseif (iNumOfPlayerKillTypes == iNumOfTypes) then
1937 icon = SKM_Config.IconsByType[_SKM._playerKill];
1938 elseif (iNumOfCreatureKillTypes == iNumOfTypes) then
1939 icon = SKM_Config.IconsByType[_SKM._creatureKill_Target];
1940 elseif (iNumOfPlayerDeathTypes + iNumOfPlayerKillTypes == iNumOfTypes) then
1941 icon = SKM_Config.IconsByType[_SKM._playerKillAndDeath];
1942 else
1943 icon = SKM_Config.IconsByType[_SKM._multiType];
1944 end
1945  
1946 end
1947  
1948 local texture = SKM_Config.IconPath .. "\\" .. icon;
1949 SkM_Trace(FName, 3, "texture = "..texture);
1950  
1951 mainNoteTexture:SetTexture(texture);
1952 mainNote:Show();
1953 end
1954  
1955 end -- if known zone info
1956 end -- if display map
1957  
1958 -- hide unused notes
1959 for i=lastUnused, maxNotes, 1 do
1960 local mainNote = getglobal("SKMapPOI"..i);
1961 mainNote:Hide();
1962 end
1963  
1964  
1965  
1966 if (not SkM_GetOption("ShowWorldMapControl")) then
1967 SKMapWorldMapControl:Hide();
1968 else
1969  
1970 if (SKM_Context.MapOpen) and (idx_z ~= 0) and (iNbNotes > 0) then
1971 local idx=1;
1972 local MyButton = getglobal("SKMapWorldMapControl_CheckButton"..idx);
1973 local ButtonText = getglobal("SKMapWorldMapControl_CheckButton"..idx.."Text");
1974 ButtonText:SetText(SKM_UI_STRINGS.WorldMap_Button_ShowRecords);
1975  
1976 if (SkM_GetOption("MapDisplayRecords")) then
1977 MyButton:SetChecked(1);
1978 else
1979 MyButton:SetChecked(0);
1980 end
1981  
1982 SKMapWorldMapControl:Show();
1983 else
1984 SKMapWorldMapControl:Hide();
1985 end
1986 end
1987  
1988 end
1989  
1990  
1991 -- --------------------------------------------------------------------------------------
1992 -- SkM_CountPOIEventType
1993 -- --------------------------------------------------------------------------------------
1994 -- Count the different types of records attached to a given POI.
1995 -- Will be useful to allocate an icon to this POI.
1996 -- --------------------------------------------------------------------------------------
1997 function SkM_CountPOIEventType(idx_c, idx_z, iPOINum)
1998 local FName = "SkM_CountPOIEventType";
1999  
2000 local iNbNotes = getn(SKM_Context.WorldMapPOINotes[iPOINum]);
2001 local TypeCount = { };
2002  
2003 local iPlayerDeathTypes = 0;
2004 local iPlayerKillTypes = 0;
2005 local iCreatureKillTypes = 0;
2006  
2007 for i=1, iNbNotes, 1 do
2008 local idx_n = SKM_Context.WorldMapPOINotes[iPOINum][i];
2009 local idx_gn = SKM_Data[_RealmName][_PlayerName].MapData[idx_c][idx_z][idx_n];
2010 local Note = SKM_Data[_RealmName][_PlayerName].GlobalMapData[idx_gn];
2011  
2012 local noteType = Note[_SKM._storedInfo][_SKM._type];
2013  
2014  
2015 if (not TypeCount[noteType]) then
2016 TypeCount[noteType] = 0;
2017 end
2018 TypeCount[noteType] = TypeCount[noteType] + 1;
2019 end
2020 local iTypes = 0;
2021 for idx, val in TypeCount do
2022 iTypes = iTypes + 1;
2023 if (idx == _SKM._playerAssistKill) or (idx == _SKM._playerKill) or (idx == _SKM._playerFullKill) then
2024 iPlayerKillTypes = iPlayerKillTypes + 1;
2025 elseif (idx == _SKM._playerDeath) or (idx == _SKM._playerDeathPvE) or (idx == _SKM._playerDeathPvP) then
2026 iPlayerDeathTypes = iPlayerDeathTypes + 1;
2027 elseif (idx == _SKM._creatureKill_Xp) or (idx == _SKM._creatureKill_Target) then
2028 iCreatureKillTypes = iCreatureKillTypes + 1;
2029 end
2030  
2031 SkM_Trace(FName, 3, "Type = "..idx..", Count = "..val);
2032 end
2033 return iTypes, iPlayerKillTypes, iPlayerDeathTypes, iCreatureKillTypes, TypeCount;
2034 end
2035  
2036  
2037 -- --------------------------------------------------------------------------------------
2038 -- SkM_GetNoteMessage
2039 -- --------------------------------------------------------------------------------------
2040 -- Build a note string message from a pattern and an information structure
2041 -- --------------------------------------------------------------------------------------
2042 function SkM_GetNoteMessage(Info, sMessagePattern)
2043 local FName = "SkM_GetNoteMessage";
2044  
2045 if (not Info) then
2046 SkM_Trace(FName, 3, "Info is nil");
2047 return nil;
2048 end
2049 if (not sMessagePattern) then
2050 SkM_Trace(FName, 3, "Pattern is nil");
2051 return nil;
2052 end
2053  
2054 local sMessage = sMessagePattern;
2055  
2056 local sVal_Name = ifnil(Info[_SKM._name], "??");
2057 local sVal_Guild = ifnil(Info[_SKM._guild], "??");
2058 local sVal_Class = ifnil(Info[_SKM._class], "??");
2059 local sVal_Race = ifnil(Info[_SKM._race], "??");
2060 local sVal_Level = ifnil(Info[_SKM._level], "??");
2061 local sVal_Player = ifnil(_PlayerName, "??");
2062 local sVal_Date = ifnil(Info[_SKM._date], "??");
2063  
2064 if (sVal_Level == -1) then
2065 sVal_Level = "++";
2066 end
2067  
2068 sMessage = string.gsub(sMessage, "%%name", sVal_Name);
2069 sMessage = string.gsub(sMessage, "%%race", sVal_Race);
2070 sMessage = string.gsub(sMessage, "%%guild", sVal_Guild);
2071 sMessage = string.gsub(sMessage, "%%class", sVal_Class);
2072 sMessage = string.gsub(sMessage, "%%level", sVal_Level);
2073 sMessage = string.gsub(sMessage, "%%player", sVal_Player);
2074 sMessage = string.gsub(sMessage, "%%date", sVal_Date);
2075  
2076 return sMessage;
2077 end
2078  
2079  
2080 -- --------------------------------------------------------------------------------------
2081 -- SkM_FillWorldMapToolTip
2082 -- --------------------------------------------------------------------------------------
2083 -- Builds the ToolTip for one of our custom POI that just got mouse focus.
2084 -- --------------------------------------------------------------------------------------
2085 function SkM_FillWorldMapToolTip(idx_c, idx_z, idx_n, idx_poi)
2086 local FName = "SkM_FillWorldMapToolTip";
2087  
2088 SkM_Trace(FName, 3, "idx_n = "..snil(idx_n)..", idx_poi = "..snil(idx_poi));
2089 local iLineCount = 0;
2090  
2091 local idx, val;
2092  
2093 if (not SKM_Context.WorldMapPOINotes[idx_poi]) then
2094 SkM_Trace(FName, 3, "WorldMapPOINotes not defined for POI "..idx_poi);
2095 return;
2096 end
2097 for idx, val in SKM_Context.WorldMapPOINotes[idx_poi] do
2098  
2099 local idx_gn = SKM_Data[_RealmName][_PlayerName].MapData[idx_c][idx_z][val];
2100 local Note = SKM_Data[_RealmName][_PlayerName].GlobalMapData[idx_gn];
2101  
2102 SkM_Trace(FName, 4, "idx_gn = "..snil(idx_gn));
2103  
2104 --local StoredInfo = Note[_SKM._storedInfo];
2105 local StoredInfo = copytable(Note[_SKM._storedInfo]);
2106  
2107 iLineCount = iLineCount + 1;
2108 if (iLineCount > SKM_Config.MapNotes_MaxLines) then
2109 return false;
2110 end
2111  
2112 local sPattern;
2113 local sName = StoredInfo[_SKM._name];
2114  
2115 SkM_Trace(FName, 3, "Type = "..snil(StoredInfo[_SKM._type]));
2116 SkM_Trace(FName, 3, "Name = "..snil(sName)..", Enemy Type = "..snil(StoredInfo[_SKM._enemyType]));
2117  
2118 local Enemy;
2119 if (sName) then
2120 if not (StoredInfo[_SKM._enemyType] == _SKM._enemyCreature
2121 or StoredInfo[_SKM._type] == _SKM._creatureKill_Target
2122 or StoredInfo[_SKM._type] == _SKM._creatureKill_Xp) then
2123 Enemy = SKM_Data[_RealmName][_PlayerName].EnemyHistory[sName];
2124 end
2125 end
2126  
2127  
2128 local bNoEnemyData = true;
2129 if (Enemy) then
2130 StoredInfo[_SKM._class] = SkM_GetClassText(Enemy[_SKM._class]);
2131 StoredInfo[_SKM._race] = SkM_GetRaceText(Enemy[_SKM._race]);
2132 StoredInfo[_SKM._level] = Enemy[_SKM._level];
2133  
2134 if (StoredInfo[_SKM._class]) or (StoredInfo[_SKM._race]) or (StoredInfo[_SKM._level]) then
2135 bNoEnemyData = false;
2136 end
2137  
2138 SkM_Trace(FName, 3, "Class = "..snil(Enemy[_SKM._class])..", Race = "..snil(Enemy[_SKM._race])..", Level = "..snil(Enemy[_SKM._level]));
2139 end
2140  
2141  
2142 local RGB;
2143 local sPattern;
2144  
2145 if (StoredInfo[_SKM._type] == _SKM._playerAssistKill) then
2146 sPattern = SKM_Config.Message_PlayerKill;
2147 RGB = SKM_Config.RGB_PlayerAssistKill;
2148  
2149 elseif (StoredInfo[_SKM._type] == _SKM._playerKill) then
2150 sPattern = SKM_Config.Message_PlayerKill;
2151 RGB = SKM_Config.RGB_PlayerKill;
2152  
2153  
2154 elseif (StoredInfo[_SKM._type] == _SKM._playerFullKill) then
2155 sPattern = SKM_Config.Message_PlayerKill;
2156  
2157 if (StoredInfo[_SKM._loneWolfKill]) then
2158 RGB = SKM_Config.RGB_LoneWolfKill;
2159 else
2160 RGB = SKM_Config.RGB_PlayerFullKill;
2161 end
2162  
2163 elseif (StoredInfo[_SKM._type] == _SKM._playerDeath) then
2164 sPattern = SKM_Config.Message_PlayerDeath;
2165 RGB = SKM_Config.RGB_PlayerDeath;
2166  
2167 elseif (StoredInfo[_SKM._type] == _SKM._playerDeathPvE) then
2168 sPattern = SKM_Config.Message_PlayerDeath_PvE;
2169 RGB = SKM_Config.RGB_PlayerPvEDeath;
2170  
2171 elseif (StoredInfo[_SKM._type] == _SKM._playerDeathPvP) then
2172 if (bNoEnemyData == false) then
2173 sPattern = SKM_Config.Message_PlayerDeath_PvP;
2174 else
2175 sPattern = SKM_Config.Message_PlayerDeath_PvP_NoData;
2176 end
2177 RGB = SKM_Config.RGB_PlayerPvPDeath;
2178  
2179 elseif (StoredInfo[_SKM._type] == _SKM._creatureKill_Target) then
2180 if (StoredInfo[_SKM._class]) then
2181 sPattern = SKM_Config.Message_CreatureKill_RareDetail;
2182 else
2183 sPattern = SKM_Config.Message_CreatureKill_Detail;
2184 end
2185 RGB = SKM_Config.RGB_CreatureKill;
2186  
2187 elseif (StoredInfo[_SKM._type] == _SKM._creatureKill_Xp) then
2188 sPattern = SKM_Config.Message_CreatureKill_Basic;
2189 RGB = SKM_Config.RGB_CreatureKill;
2190  
2191 elseif (StoredInfo[_SKM._type] == _SKM._levelUp) then
2192 sPattern = SKM_Config.Message_LevelUp;
2193 RGB = SKM_Config.RGB_LevelUp;
2194 end
2195  
2196 if (StoredInfo[_SKM._honorKill]) then
2197 sPattern = sPattern.." "..SKM_Config.SubMessage_HonorKill;
2198 end
2199  
2200 local sLine = SkM_GetNoteMessage(StoredInfo, sPattern);
2201 WorldMapTooltip:AddLine(sLine, RGB.r, RGB.g, RGB.b);
2202 end
2203  
2204 return true;
2205 end
2206  
2207  
2208 -- --------------------------------------------------------------------------------------
2209 -- SkM_WorldMapEnterPOI
2210 -- --------------------------------------------------------------------------------------
2211 -- Handle POI "OnEnter" event :
2212 -- Acquire and prepare ToolTip, then display it.
2213 -- --------------------------------------------------------------------------------------
2214 function SkM_WorldMapEnterPOI(id)
2215 local FName = "SkM_WorldMapEnterPOI";
2216  
2217 SkM_Trace(FName, 3, "id = "..id);
2218  
2219 --if ((not MapNotesPOIMenuFrame:IsVisible()) and (not MapNotesNewMenuFrame:IsVisible()) and MapNotes_BlockingFrame()) then
2220 if (true) then
2221 local x, y = this:GetCenter();
2222 local x2, y2 = WorldMapButton:GetCenter();
2223 local anchor = "";
2224 if (x > x2) then
2225 anchor = "ANCHOR_LEFT";
2226 else
2227 anchor = "ANCHOR_RIGHT";
2228 end
2229  
2230 --local idx_z = GetCurrentMapZone();
2231 --local idx_c = GetCurrentMapContinent();
2232 local idx_c, idx_z = SkM_GetCurrentMapZone_Shift();
2233  
2234 local idx_n = this.toolTip;
2235  
2236 local idx_gn = SKM_Data[_RealmName][_PlayerName].MapData[idx_c][idx_z][idx_n];
2237 local Note = SKM_Data[_RealmName][_PlayerName].GlobalMapData[idx_gn];
2238  
2239  
2240 SkM_Trace(FName, 3, "this.toolTip = "..this.toolTip);
2241  
2242 WorldMapTooltip:SetOwner(this, anchor);
2243  
2244 --WorldMapTooltip:SetText(""); -- doesn't display if no title
2245 WorldMapTooltip:SetText(SKM_UI_STRINGS.Map_Window_Title);
2246  
2247 local xPos = Note[_SKM._xPos];
2248 local yPos = Note[_SKM._yPos];
2249  
2250  
2251 --SkM_FillWorldMapToolTip(idx_c, idx_z, xPos, yPos);
2252 SkM_FillWorldMapToolTip(idx_c, idx_z, idx_n, id);
2253  
2254 WorldMapTooltip:Show();
2255 else
2256 WorldMapTooltip:Hide();
2257 end
2258  
2259 end
2260  
2261  
2262 -- --------------------------------------------------------------------------------------
2263 -- SkM_WorldMapLeavePOI
2264 -- --------------------------------------------------------------------------------------
2265 -- Handle POI "OnLeave" event :
2266 -- Hide ToolTip.
2267 -- --------------------------------------------------------------------------------------
2268 function SkM_WorldMapLeavePOI(id)
2269 local FName = "SkM_WorldMapLeavePOI";
2270 WorldMapTooltip:Hide();
2271 end
2272  
2273  
2274 -- --------------------------------------------------------------------------------------
2275 -- SkM_FormatParsePattern
2276 -- --------------------------------------------------------------------------------------
2277 -- Format a parsing pattern.
2278 -- Input pattern is a readable string that contains %s and %d for substitutions.
2279 -- Return value is a regular expression, with special characters escaped by '%'.
2280 -- --------------------------------------------------------------------------------------
2281 function SkM_FormatParsePattern(sTemplate)
2282 local FName = "SkM_FormatParsePattern";
2283  
2284 local sPattern = sTemplate;
2285  
2286 sPattern = string.gsub(sPattern, "%(", "%%(");
2287 sPattern = string.gsub(sPattern, "%)", "%%)");
2288 sPattern = string.gsub(sPattern, "%.", "%%.");
2289 sPattern = string.gsub(sPattern, "%+", "%%+");
2290 sPattern = string.gsub(sPattern, "%[", "%%[");
2291 sPattern = string.gsub(sPattern, "%]", "%%]");
2292  
2293 sPattern = string.gsub(sPattern, "%%d", "([0-9]+)");
2294 sPattern = string.gsub(sPattern, "%%s", "(.+)");
2295  
2296 return sPattern;
2297 end
2298  
2299  
2300 -- --------------------------------------------------------------------------------------
2301 -- SkM_BuildParsePatterns
2302 -- --------------------------------------------------------------------------------------
2303 -- Format as regular expressions all the parsing patterns that we need.
2304 -- --------------------------------------------------------------------------------------
2305 function SkM_BuildParsePatterns()
2306 local FName = "SkM_BuildParsePatterns";
2307  
2308 for idx, val in SKM_PATTERN do
2309 local sPattern = SkM_FormatParsePattern(val);
2310 SKM_Context.Pattern[idx] = sPattern;
2311 end
2312 end
2313  
2314  
2315 -- --------------------------------------------------------------------------------------
2316 -- SkM_ParseCombatChat_XpGain
2317 -- --------------------------------------------------------------------------------------
2318 -- Handle "player receives combat xp" chat event.
2319 -- If we can match one of the "creature kill" messages, then record the creature kill.
2320 -- --------------------------------------------------------------------------------------
2321 function SkM_ParseCombatChat_XpGain(sMsg)
2322 local FName = "SkM_ParseCombatChat_XpGain";
2323  
2324 SkM_Trace(FName, 3, "You gain combat xp");
2325  
2326 for sFoe, iXpGain, iBaseXp, iRestXp in string.gfind(sMsg, SKM_Context.Pattern.XpGain_Rested_Solo) do
2327 if (sFoe and iXpGain and iBaseXp and iRestXp) then
2328 SkM_Trace(FName, 3, "XpGain_Rested_Solo : Foe = "..sFoe..", Xp = "..iXpGain);
2329  
2330 SkM_RecordCreatureKill_Xp(sFoe);
2331 return;
2332 end
2333 end
2334  
2335 for sFoe, iXpGain, iBaseXp, iRestXp, iGroupBonus in string.gfind(sMsg, SKM_Context.Pattern.XpGain_Rested_Group) do
2336 if (sFoe and iXpGain and iBaseXp and iRestXp and iGroupBonus) then
2337 SkM_Trace(FName, 3, "XpGain_Rested_Group : Foe = "..sFoe..", Xp = "..iXpGain);
2338  
2339 SkM_RecordCreatureKill_Xp(sFoe);
2340 return;
2341 end
2342 end
2343  
2344 for sFoe, iXpGain, iBaseXp, iRestXp, iRaidPenalty in string.gfind(sMsg, SKM_Context.Pattern.XpGain_Rested_Raid) do
2345 if (sFoe and iXpGain and iBaseXp and iRestXp and iRaidPenalty) then
2346 SkM_Trace(FName, 3, "XpGain_Rested_Raid : Foe = "..sFoe..", Xp = "..iXpGain);
2347  
2348 SkM_RecordCreatureKill_Xp(sFoe);
2349 return;
2350 end
2351 end
2352  
2353 for sFoe, iXpGain in string.gfind(sMsg, SKM_Context.Pattern.XpGain_Solo) do
2354 if (sFoe and iXpGain) then
2355 SkM_Trace(FName, 3, "XpGain_Solo : Foe = "..sFoe..", Xp = "..iXpGain);
2356  
2357 SkM_RecordCreatureKill_Xp(sFoe);
2358 return;
2359 end
2360 end
2361  
2362 for sFoe, iXpGain, iGroupBonus in string.gfind(sMsg, SKM_Context.Pattern.XpGain_Group) do
2363 if (sFoe and iXpGain and iGroupBonus) then
2364 SkM_Trace(FName, 3, "XpGain_Group : Foe = "..sFoe..", Xp = "..iXpGain);
2365  
2366 SkM_RecordCreatureKill_Xp(sFoe);
2367 return;
2368 end
2369 end
2370  
2371 for sFoe, iXpGain, iRaidPenalty in string.gfind(sMsg, SKM_Context.Pattern.XpGain_Raid) do
2372 if (sFoe and iXpGain and iRaidPenalty) then
2373 SkM_Trace(FName, 3, "XpGain_Raid : Foe = "..sFoe..", Xp = "..iXpGain);
2374  
2375 SkM_RecordCreatureKill_Xp(sFoe);
2376 return;
2377 end
2378 end
2379  
2380 end
2381  
2382  
2383 -- --------------------------------------------------------------------------------------
2384 -- SkM_ParseCombatChat_SelfCombatHit
2385 -- --------------------------------------------------------------------------------------
2386 -- Handle "Player hits something" chat event.
2387 -- Record damage done to this enemy.
2388 -- Note that this may be a player or a creature. We don't check it yet as enemy player
2389 -- may not be yet known, it's better to check on death event.
2390 -- --------------------------------------------------------------------------------------
2391 function SkM_ParseCombatChat_SelfCombatHit(sMsg)
2392 local FName = "SkM_ParseCombatChat_SelfCombatHit";
2393  
2394 SkM_Trace(FName, 3, "You do physical damage to something");
2395  
2396 for sFoe, iDamage in string.gfind(sMsg, SKM_Context.Pattern.Player_HitDamage) do
2397 if (sFoe and iDamage) then
2398 SkM_Trace(FName, 3, "Player_HitDamage : Foe = "..sFoe..", Damage = "..iDamage);
2399  
2400 SkM_LogDamage_OnPvpEnemy(iDamage, _PlayerName, sFoe);
2401 return;
2402 end
2403 end
2404  
2405 for sFoe, iDamage in string.gfind(sMsg, SKM_Context.Pattern.Player_HitCritDamage) do
2406 if (sFoe and iDamage) then
2407 SkM_Trace(FName, 3, "Player_HitDamage : Foe = "..sFoe..", Damage = "..iDamage);
2408  
2409 SkM_LogDamage_OnPvpEnemy(iDamage, _PlayerName, sFoe);
2410 return;
2411 end
2412 end
2413  
2414 end
2415  
2416  
2417 -- --------------------------------------------------------------------------------------
2418 -- SkM_ParseCombatChat_SelfCombatSpell
2419 -- --------------------------------------------------------------------------------------
2420 -- Handle "Player does spell damage on something" chat event.
2421 -- Record damage done to this enemy.
2422 -- Note that this may be a player or a creature. We don't check it yet as enemy player
2423 -- may not be yet known, it's better to check on death event.
2424 -- --------------------------------------------------------------------------------------
2425 function SkM_ParseCombatChat_SelfCombatSpell(sMsg)
2426 local FName = "SkM_ParseCombatChat_SelfCombatSpell";
2427  
2428 SkM_Trace(FName, 3, "You do spell damage to something");
2429  
2430 for sSpell, sFoe, iDamage in string.gfind(sMsg, SKM_Context.Pattern.Player_SpellDamage) do
2431 if (sSpell and sFoe and iDamage) then
2432 SkM_Trace(FName, 3, "Player_SpellDamage : Spell = "..sSpell..", Foe = "..sFoe..", Damage = "..iDamage);
2433  
2434 SkM_LogDamage_OnPvpEnemy(iDamage, _PlayerName, sFoe);
2435 return;
2436 end
2437 end
2438  
2439 for sSpell, sFoe, iDamage in string.gfind(sMsg, SKM_Context.Pattern.Player_SpellCritDamage) do
2440 if (sSpell and sFoe and iDamage) then
2441 SkM_Trace(FName, 3, "Player_SpellCritDamage : Spell = "..sSpell..", Foe = "..sFoe..", Damage = "..iDamage);
2442  
2443 SkM_LogDamage_OnPvpEnemy(iDamage, _PlayerName, sFoe);
2444 return;
2445 end
2446 end
2447  
2448 end
2449  
2450  
2451 -- --------------------------------------------------------------------------------------
2452 -- SkM_ParseCombatChat_FriendCombatHit
2453 -- --------------------------------------------------------------------------------------
2454 -- Handle "Friendly player hits something" chat event.
2455 -- Record damage done to this enemy.
2456 -- Note that this may be a player or a creature. We don't check it yet as enemy player
2457 -- may not be yet known, it's better to check on death event.
2458 -- --------------------------------------------------------------------------------------
2459 function SkM_ParseCombatChat_FriendCombatHit(sMsg)
2460 local FName = "SkM_ParseCombatChat_FriendCombatHit";
2461  
2462 SkM_Trace(FName, 3, "A friend do physical damage to something");
2463  
2464 for sAttacker, sFoe, iDamage in string.gfind(sMsg, SKM_Context.Pattern.Other_HitDamage) do
2465 if (sAttacker and sFoe and iDamage) then
2466 SkM_Trace(FName, 3, "Other_HitDamage : Attacker = "..sAttacker..", Foe = "..sFoe..", Damage = "..iDamage);
2467  
2468 SkM_LogDamage_OnPvpEnemy(iDamage, sAttacker, sFoe);
2469 return;
2470 end
2471 end
2472  
2473 for sAttacker, sFoe, iDamage in string.gfind(sMsg, SKM_Context.Pattern.Other_HitCritDamage) do
2474 if (sAttacker and sFoe and iDamage) then
2475 SkM_Trace(FName, 3, "Other_HitCritDamage : Attacker = "..sAttacker..", Foe = "..sFoe..", Damage = "..iDamage);
2476  
2477  
2478 SkM_LogDamage_OnPvpEnemy(iDamage, sAttacker, sFoe);
2479 return;
2480 end
2481 end
2482  
2483 end
2484  
2485  
2486 -- --------------------------------------------------------------------------------------
2487 -- SkM_ParseCombatChat_FriendCombatSpell
2488 -- --------------------------------------------------------------------------------------
2489 -- Handle "Friendly player does spell damage to something" chat event.
2490 -- Record damage done to this enemy.
2491 -- Note that this may be a player or a creature. We don't check it yet as enemy player
2492 -- may not be yet known, it's better to check on death event.
2493 -- --------------------------------------------------------------------------------------
2494 function SkM_ParseCombatChat_FriendCombatSpell(sMsg)
2495 local FName = "SkM_ParseCombatChat_FriendCombatSpell";
2496  
2497 SkM_Trace(FName, 3, "A friend do spell damage to something");
2498  
2499 -- PIng: Patch for French version where attacker and spell are inversed
2500  
2501 if ( GetLocale() == "frFR" ) then
2502  
2503 for sSpell, sAttacker, sFoe, iDamage in string.gfind(sMsg, SKM_Context.Pattern.Other_SpellDamage) do
2504 if (sAttacker and sSpell and sFoe and iDamage) then
2505 SkM_Trace(FName, 3, "Other_SpellDamage : Attacker = "..sAttacker..", Spell = "..sSpell..", Foe = "..sFoe..", Damage = "..iDamage);
2506  
2507 if (SkM_IsTotem(sAttacker)) then
2508 -- ignore totem damage
2509 return;
2510 end
2511  
2512 SkM_LogDamage_OnPvpEnemy(iDamage, sAttacker, sFoe);
2513 return;
2514 end
2515 end
2516 else
2517  
2518 for sAttacker, sSpell, sFoe, iDamage in string.gfind(sMsg, SKM_Context.Pattern.Other_SpellDamage) do
2519 if (sAttacker and sSpell and sFoe and iDamage) then
2520 SkM_Trace(FName, 3, "Other_SpellDamage : Attacker = "..sAttacker..", Spell = "..sSpell..", Foe = "..sFoe..", Damage = "..iDamage);
2521  
2522 if (SkM_IsTotem(sAttacker)) then
2523 -- ignore totem damage
2524 return;
2525 end
2526  
2527 SkM_LogDamage_OnPvpEnemy(iDamage, sAttacker, sFoe);
2528 return;
2529 end
2530 end
2531 end
2532  
2533 for sAttacker, sSpell, sFoe, iDamage in string.gfind(sMsg, SKM_Context.Pattern.Other_SpellCritDamage) do
2534 if (sAttacker and sSpell and sFoe and iDamage) then
2535 SkM_Trace(FName, 3, "Other_SpellCritDamage : Attacker = "..sAttacker..", Spell = "..sSpell..", Foe = "..sFoe..", Damage = "..iDamage);
2536  
2537 SkM_LogDamage_OnPvpEnemy(iDamage, sAttacker, sFoe);
2538 return;
2539 end
2540 end
2541  
2542 end
2543  
2544  
2545 -- --------------------------------------------------------------------------------------
2546 -- SkM_ParseCombatChat_PetCombatHit
2547 -- --------------------------------------------------------------------------------------
2548 -- Handle "Our pet hits something" chat event.
2549 -- Record damage (for pet owner !) done to this enemy.
2550 -- Note that this may be a player or a creature. We don't check it yet as enemy player
2551 -- may not be yet known, it's better to check on death event.
2552 -- --------------------------------------------------------------------------------------
2553 function SkM_ParseCombatChat_PetCombatHit(sMsg)
2554 local FName = "SkM_ParseCombatChat_PetCombatHit";
2555  
2556 SkM_Trace(FName, 3, "Your pet does physical damage to something");
2557  
2558 for sAttacker, sFoe, iDamage in string.gfind(sMsg, SKM_Context.Pattern.Other_HitDamage) do
2559 if (sAttacker and sFoe and iDamage) then
2560 SkM_Trace(FName, 3, "Other_HitDamage : Attacker = "..sAttacker..", Foe = "..sFoe..", Damage = "..iDamage);
2561  
2562 SkM_LogDamage_OnPvpEnemy(iDamage, _PlayerName, sFoe);
2563 return;
2564 end
2565 end
2566  
2567 for sAttacker, sFoe, iDamage in string.gfind(sMsg, SKM_Context.Pattern.Other_HitCritDamage) do
2568 if (sAttacker and sFoe and iDamage) then
2569 SkM_Trace(FName, 3, "Other_HitCritDamage : Attacker = "..sAttacker..", Foe = "..sFoe..", Damage = "..iDamage);
2570  
2571 SkM_LogDamage_OnPvpEnemy(iDamage, _PlayerName, sFoe);
2572 return;
2573 end
2574 end
2575  
2576 end
2577  
2578  
2579 -- --------------------------------------------------------------------------------------
2580 -- SkM_ParseCombatChat_PetCombatSpell
2581 -- --------------------------------------------------------------------------------------
2582 -- Handle "Our pet does spell damage to something" chat event.
2583 -- Record damage (for pet owner !) done to this enemy.
2584 -- Note that this may be a player or a creature. We don't check it yet as enemy player
2585 -- may not be yet known, it's better to check on death event.
2586 -- --------------------------------------------------------------------------------------
2587 function SkM_ParseCombatChat_PetCombatSpell(sMsg)
2588 local FName = "SkM_ParseCombatChat_PetCombatSpell";
2589  
2590 SkM_Trace(FName, 3, "Your pet does spell damage to something");
2591  
2592 -- Note : it may be your totem if you are a shaman
2593 -- in this case, we don't ignore it : we count it as player damage also.
2594  
2595  
2596  
2597 for sAttacker, sSpell, sFoe, iDamage in string.gfind(sMsg, SKM_Context.Pattern.Other_SpellDamage) do
2598 if (sAttacker and sSpell and sFoe and iDamage) then
2599 SkM_Trace(FName, 3, "Other_SpellDamage : Attacker = "..sAttacker..", Spell = "..sSpell..", Foe = "..sFoe..", Damage = "..iDamage);
2600  
2601 SkM_LogDamage_OnPvpEnemy(iDamage, _PlayerName, sFoe);
2602 return;
2603 end
2604  
2605 end
2606  
2607 for sAttacker, sSpell, sFoe, iDamage in string.gfind(sMsg, SKM_Context.Pattern.Other_SpellCritDamage) do
2608 if (sAttacker and sSpell and sFoe and iDamage) then
2609 SkM_Trace(FName, 3, "Other_SpellCritDamage : Attacker = "..sAttacker..", Spell = "..sSpell..", Foe = "..sFoe..", Damage = "..iDamage);
2610  
2611 SkM_LogDamage_OnPvpEnemy(iDamage, _PlayerName, sFoe);
2612 return;
2613 end
2614 end
2615  
2616 end
2617  
2618  
2619 -- --------------------------------------------------------------------------------------
2620 -- SkM_ParseCombatChat_EnemyDot
2621 -- --------------------------------------------------------------------------------------
2622 -- Handle "Enemy player suffers from DoT" chat event.
2623 -- Record damage done (by either self of another player) to this enemy.
2624 -- --------------------------------------------------------------------------------------
2625 function SkM_ParseCombatChat_EnemyDot(sMsg)
2626 local FName = "SkM_ParseCombatChat_EnemyDot";
2627  
2628 SkM_Trace(FName, 3, "An enemy suffers from DoT damage");
2629  
2630 -- PIng: Patch for French version
2631  
2632 if ( GetLocale() == "frFR" ) then
2633 for sSpell, iDamage, sDamageType, sFoe in string.gfind(sMsg, SKM_Context.Pattern.Player_DotDamage) do
2634 if (sFoe and iDamage and sDamageType and sSpell) then
2635 SkM_Trace(FName, 3, "Player_DotDamage : Foe = "..sFoe..", Damage = "..iDamage..", Damage type = "..sDamageType..", Spell = "..sSpell);
2636  
2637 SkM_LogDamage_OnPvpEnemy(iDamage, _PlayerName, sFoe);
2638 return;
2639 end
2640 end
2641 for sSpell, sAttacker, sFoe, iDamage, sDamageType in string.gfind(sMsg, SKM_Context.Pattern.Other_DotDamage) do
2642 if (sFoe and iDamage and sDamageType and sAttacker and sSpell) then
2643 SkM_Trace(FName, 3, "Other_DotDamage : Attacker = "..sAttacker..", Foe = "..sFoe..", Damage = "..iDamage..", Damage type = "..sDamageType..", Spell = "..sSpell);
2644  
2645 SkM_LogDamage_OnPvpEnemy(iDamage, sAttacker, sFoe);
2646 return;
2647 end
2648 end
2649  
2650 else
2651 for sFoe, iDamage, sDamageType, sSpell in string.gfind(sMsg, SKM_Context.Pattern.Player_DotDamage) do
2652 if (sFoe and iDamage and sDamageType and sSpell) then
2653 SkM_Trace(FName, 3, "Player_DotDamage : Foe = "..sFoe..", Damage = "..iDamage..", Damage type = "..sDamageType..", Spell = "..sSpell);
2654  
2655 SkM_LogDamage_OnPvpEnemy(iDamage, _PlayerName, sFoe);
2656 return;
2657 end
2658 end
2659 for sFoe, iDamage, sDamageType, sAttacker, sSpell in string.gfind(sMsg, SKM_Context.Pattern.Other_DotDamage) do
2660 if (sFoe and iDamage and sDamageType and sAttacker and sSpell) then
2661 SkM_Trace(FName, 3, "Other_DotDamage : Attacker = "..sAttacker..", Foe = "..sFoe..", Damage = "..iDamage..", Damage type = "..sDamageType..", Spell = "..sSpell);
2662  
2663 SkM_LogDamage_OnPvpEnemy(iDamage, sAttacker, sFoe);
2664 return;
2665 end
2666 end
2667 end
2668  
2669 end
2670  
2671  
2672 -- --------------------------------------------------------------------------------------
2673  
2674 -- SkM_ParseCombatChat_SelfDot
2675 -- --------------------------------------------------------------------------------------
2676 -- Handle "Self suffers from DoT" chat event.
2677 -- Record damage done to self, without any "enemy type" as we don't know if the enemy
2678  
2679 -- is a player or a creep.
2680 -- --------------------------------------------------------------------------------------
2681 function SkM_ParseCombatChat_SelfDot(sMsg)
2682 local FName = "SkM_ParseCombatChat_SelfDot";
2683  
2684 SkM_Trace(FName, 3, "Self suffers from DoT damage");
2685  
2686 -- We suffered from a DoT : in this case, log damage without enemy type, because
2687 -- we do *not* know from the event if it's a player or a creature that cast the DoT !
2688  
2689 if ( GetLocale() == "frFR" ) then
2690 -- 0.09.1 Begin of modification Fix ?
2691 for sSpell, sAttacker, iDamage, sDamageType in string.gfind(sMsg, SKM_Context.Pattern.Self_DotDamage) do
2692 if (iDamage and sDamageType and sAttacker and sSpell) then
2693 SkM_Trace(FName, 3, "Self_DotDamage : Attacker = "..sAttacker..", Damage = "..iDamage..", Damage type = "..sDamageType..", Spell = "..sSpell);
2694  
2695 SkM_LogDamage_OnSelf(iDamage, sAttacker, nil);
2696 return;
2697 end
2698 end
2699 -- 0.09.1 End of modification
2700  
2701 else
2702  
2703 for iDamage, sDamageType, sAttacker, sSpell in string.gfind(sMsg, SKM_Context.Pattern.Self_DotDamage) do
2704 if (iDamage and sDamageType and sAttacker and sSpell) then
2705 SkM_Trace(FName, 3, "Self_DotDamage : Attacker = "..sAttacker..", Damage = "..iDamage..", Damage type = "..sDamageType..", Spell = "..sSpell);
2706  
2707 SkM_LogDamage_OnSelf(iDamage, sAttacker, nil);
2708 return;
2709 end
2710 end
2711  
2712 end
2713  
2714 end
2715  
2716  
2717 -- --------------------------------------------------------------------------------------
2718 -- SkM_ParseCombatChat_EnemyCombatHit
2719 -- --------------------------------------------------------------------------------------
2720 -- Handle "Enemy player hits something" chat event.
2721 -- If we are the victim, record damage done to self by that enemy.
2722 -- --------------------------------------------------------------------------------------
2723 function SkM_ParseCombatChat_EnemyCombatHit(sMsg)
2724 local FName = "SkM_ParseCombatChat_EnemyCombatHit";
2725  
2726 SkM_Trace(FName, 3, "A player enemy does physical damage to something");
2727  
2728 -- that may be an enemy PET also ! so we need to check if we know this enemy
2729 -- if not, log it without "enemy type" filled...
2730  
2731 for sAttacker, iDamage in string.gfind(sMsg, SKM_Context.Pattern.Self_HitDamage) do
2732 if (sAttacker and iDamage) then
2733 SkM_Trace(FName, 3, "Self_HitDamage : Attacker = "..sAttacker..", Damage = "..iDamage);
2734  
2735 SkM_LogDamage_OnSelf(iDamage, sAttacker, SkM_GetKnownEnemyType(sAttacker));
2736 return;
2737 end
2738 end
2739  
2740 for sAttacker, iDamage in string.gfind(sMsg, SKM_Context.Pattern.Self_HitCritDamage) do
2741 if (sAttacker and iDamage) then
2742 SkM_Trace(FName, 3, "Self_CritHitDamage : Attacker = "..sAttacker..", Damage = "..iDamage);
2743  
2744 SkM_LogDamage_OnSelf(iDamage, sAttacker, SkM_GetKnownEnemyType(sAttacker));
2745 return;
2746 end
2747 end
2748  
2749 -- Self is not the target
2750 -- we don't care who the hostile player hits and for which amount !
2751 SkM_Trace(FName, 3, "Hostile picks on other player or mob : do nothing");
2752 end
2753  
2754  
2755 -- --------------------------------------------------------------------------------------
2756 -- SkM_ParseCombatChat_EnemyCombatSpell
2757 -- --------------------------------------------------------------------------------------
2758 -- Handle "Enemy player does spell damage to something" chat event.
2759 -- If we are the victim, record damage done to self by that enemy.
2760 -- --------------------------------------------------------------------------------------
2761 function SkM_ParseCombatChat_EnemyCombatSpell(sMsg)
2762 local FName = "SkM_ParseCombatChat_EnemyCombatSpell";
2763  
2764 SkM_Trace(FName, 3, "A player enemy does spell damage to something");
2765  
2766 -- that may be an enemy PET also ! so we need to check if we know this enemy
2767 -- if not, log it without "enemy type" filled...
2768  
2769 -- Is Self the target ?
2770  
2771 -- PIng: Patch for French version
2772  
2773 if ( GetLocale() == "frFR" ) then
2774  
2775 for sSpell, sAttacker, iDamage in string.gfind(sMsg, SKM_Context.Pattern.Self_SpellDamage) do
2776 if (sAttacker and sSpell and iDamage) then
2777 SkM_Trace(FName, 3, "Self_SpellDamage : Attacker = "..sAttacker..", Spell = "..sSpell..", Damage = "..iDamage);
2778  
2779 if (SkM_IsTotem(sAttacker)) then
2780  
2781 -- ignore totem damage
2782 return;
2783 end
2784  
2785 SkM_LogDamage_OnSelf(iDamage, sAttacker, SkM_GetKnownEnemyType(sAttacker));
2786 return;
2787 end
2788 end
2789 else
2790  
2791 for sAttacker, sSpell, iDamage in string.gfind(sMsg, SKM_Context.Pattern.Self_SpellDamage) do
2792 if (sAttacker and sSpell and iDamage) then
2793 SkM_Trace(FName, 3, "Self_SpellDamage : Attacker = "..sAttacker..", Spell = "..sSpell..", Damage = "..iDamage);
2794  
2795 if (SkM_IsTotem(sAttacker)) then
2796 -- ignore totem damage
2797 return;
2798 end
2799  
2800 SkM_LogDamage_OnSelf(iDamage, sAttacker, SkM_GetKnownEnemyType(sAttacker));
2801 return;
2802 end
2803 end
2804 end
2805  
2806 for sAttacker, sSpell, iDamage in string.gfind(sMsg, SKM_Context.Pattern.Self_SpellCritDamage) do
2807 if (sAttacker and sSpell and iDamage) then
2808 SkM_Trace(FName, 3, "Self_SpellCritDamage : Attacker = "..sAttacker..", Spell = "..sSpell..", Damage = "..iDamage);
2809  
2810 SkM_LogDamage_OnSelf(iDamage, sAttacker, SkM_GetKnownEnemyType(sAttacker));
2811 return;
2812 end
2813 end
2814  
2815  
2816  
2817 -- Self is not the target
2818 -- we don't care who the hostile player hits and for which amount !
2819 SkM_Trace(FName, 3, "Hostile picks on other player or mob : do nothing");
2820 end
2821  
2822  
2823 -- --------------------------------------------------------------------------------------
2824 -- SkM_ParseCombatChat_CreatureCombatHit
2825 -- --------------------------------------------------------------------------------------
2826 -- Handle "Creature hits something" chat event.
2827 -- If we are the victim, record damage done to self by that creature.
2828 -- --------------------------------------------------------------------------------------
2829 function SkM_ParseCombatChat_CreatureCombatHit(sMsg)
2830 local FName = "SkM_ParseCombatChat_CreatureCombatHit";
2831  
2832 SkM_Trace(FName, 3, "A creature does physical damage to something");
2833  
2834 for sAttacker, iDamage in string.gfind(sMsg, SKM_Context.Pattern.Self_HitDamage) do
2835 if (sAttacker and iDamage) then
2836 SkM_Trace(FName, 3, "Self_HitDamage : Attacker = "..sAttacker..", Damage = "..iDamage);
2837  
2838 SkM_LogDamage_OnSelf(iDamage, sAttacker, _SKM._enemyCreature);
2839 return;
2840 end
2841 end
2842  
2843 for sAttacker, iDamage in string.gfind(sMsg, SKM_Context.Pattern.Self_HitCritDamage) do
2844 if (sAttacker and iDamage) then
2845 SkM_Trace(FName, 3, "Self_CritHitDamage : Attacker = "..sAttacker..", Damage = "..iDamage);
2846  
2847 SkM_LogDamage_OnSelf(iDamage, sAttacker, _SKM._enemyCreature);
2848 return;
2849 end
2850 end
2851  
2852 -- Self is not the target
2853 -- we don't care who the creature hits and for which amount !
2854 SkM_Trace(FName, 3, "Creature picks on other player or mob : do nothing");
2855 end
2856  
2857  
2858 -- --------------------------------------------------------------------------------------
2859 -- SkM_ParseCombatChat_CreatureCombatSpell
2860 -- --------------------------------------------------------------------------------------
2861 -- Handle "Creature does spell damage to something" chat event.
2862 -- If we are the victim, record damage done to self by that creature.
2863 -- --------------------------------------------------------------------------------------
2864 function SkM_ParseCombatChat_CreatureCombatSpell(sMsg)
2865 local FName = "SkM_ParseCombatChat_CreatureCombatSpell";
2866  
2867 SkM_Trace(FName, 3, "A creature does spell damage to something");
2868  
2869 -- 0.08.1 Begin of modification: Patch for French version
2870  
2871 if ( GetLocale() == "frFR" ) then
2872  
2873 for sSpell, sAttacker, iDamage in string.gfind(sMsg, SKM_Context.Pattern.Self_SpellDamage) do
2874 if (sAttacker and sSpell and iDamage) then
2875 SkM_Trace(FName, 3, "Self_SpellDamage : Attacker = "..sAttacker..", Spell = "..sSpell..", Damage = "..iDamage);
2876  
2877 if (SkM_IsTotem(sAttacker)) then
2878 -- ignore totem damage
2879  
2880 return;
2881 end
2882  
2883 SkM_LogDamage_OnSelf(iDamage, sAttacker, _SKM._enemyCreature);
2884 return;
2885 end
2886 end
2887 else
2888  
2889 for sAttacker, sSpell, iDamage in string.gfind(sMsg, SKM_Context.Pattern.Self_SpellDamage) do
2890 if (sAttacker and sSpell and iDamage) then
2891 SkM_Trace(FName, 3, "Self_SpellDamage : Attacker = "..sAttacker..", Spell = "..sSpell..", Damage = "..iDamage);
2892  
2893 if (SkM_IsTotem(sAttacker)) then
2894 -- ignore totem damage
2895 return;
2896 end
2897  
2898 SkM_LogDamage_OnSelf(iDamage, sAttacker, _SKM._enemyCreature);
2899 return;
2900 end
2901 end
2902 end
2903 -- 0.08.1 End of modification
2904  
2905 for sAttacker, sSpell, iDamage in string.gfind(sMsg, SKM_Context.Pattern.Self_SpellCritDamage) do
2906 if (sAttacker and sSpell and iDamage) then
2907 SkM_Trace(FName, 3, "Self_SpellCritDamage : Attacker = "..sAttacker..", Spell = "..sSpell..", Damage = "..iDamage);
2908  
2909 SkM_LogDamage_OnSelf(iDamage, sAttacker, _SKM._enemyCreature);
2910 return;
2911 end
2912 end
2913  
2914 -- Self is not the target
2915 -- we don't care who the creature hits and for which amount !
2916 SkM_Trace(FName, 3, "Creature picks on other player or mob : do nothing");
2917 end
2918  
2919  
2920 -- --------------------------------------------------------------------------------------
2921 -- SkM_ParseCombatChat_HostileDeath
2922 -- --------------------------------------------------------------------------------------
2923 -- Handle "Enemy player dies" chat event.
2924 -- Find out from information previously gathered if we can be awarded this kill,
2925 -- and if so record it.
2926 -- --------------------------------------------------------------------------------------
2927 function SkM_ParseCombatChat_HostileDeath(sMsg)
2928 local FName = "SkM_ParseCombatChat_HostileDeath";
2929  
2930 for sFoe in string.gfind(sMsg, SKM_Context.Pattern.Other_Death) do
2931 if (sFoe) then
2932 SkM_Trace(FName, 3, "Other_Death : Foe = "..sFoe);
2933  
2934  
2935 SkM_Trace(FName, 2, "Enemy player death detected (from chat msg) : "..snil(sFoe));
2936 SkM_PvpEnemyDeath(sFoe);
2937 return;
2938 end
2939 end
2940  
2941 end
2942  
2943  
2944 -- --------------------------------------------------------------------------------------
2945 -- SkM_ParseCombatChat_HonorKill
2946 -- --------------------------------------------------------------------------------------
2947 -- Handle "Enemy player dies and is worth honor" chat event.
2948 -- Find out from information previously gathered if we can be awarded this kill,
2949 -- and if so record it.
2950  
2951 -- --------------------------------------------------------------------------------------
2952 function SkM_ParseCombatChat_HonorKill(sMsg)
2953 local FName = "SkM_ParseCombatChat_HonorKill";
2954  
2955 for sFoe, sRank in string.gfind(sMsg, SKM_Context.Pattern.Honor_Kill) do
2956 if (sFoe and sRank) then
2957 SkM_Trace(FName, 3, "Honor_Kill : Foe = "..sFoe..", Rank = "..sRank);
2958  
2959 SkM_Trace(FName, 2, "Enemy player death detected (from chat, honor) : "..snil(sFoe));
2960 SkM_PvpEnemyDeath(sFoe, true, sRank);
2961 end
2962 end
2963  
2964 end
2965  
2966  
2967 -- --------------------------------------------------------------------------------------
2968 -- SkM_RecordCreatureKill_Xp
2969 -- --------------------------------------------------------------------------------------
2970 -- Record a creature kill by "combat xp message".
2971 -- --------------------------------------------------------------------------------------
2972 function SkM_RecordCreatureKill_Xp(sName)
2973 local FName = "SkM_RecordCreatureKill_Xp";
2974  
2975 if (not SkM_GetOption("RecordCreatureKill")) then
2976 return;
2977 end
2978  
2979  
2980 local curTime = GetTime();
2981  
2982 SkM_Trace(FName, 3, "Creature by xp kill : "..sName.." (time = "..curTime..")");
2983  
2984 -- check if we're already processed this kill on health change
2985 if (SKM_Context.LastCreatureKill) then
2986  
2987 SkM_Trace(FName, 3, "Recent creature kill : "..snil(SKM_Context.LastCreatureKill[_SKM._name]).." (time = "..snil(SKM_Context.LastCreatureKill[_SKM._time])..")");
2988  
2989 if (SKM_Context.LastCreatureKill[_SKM._name] == sName) and (curTime < SKM_Context.LastCreatureKill[_SKM._time] + 1) then
2990 SkM_Trace(FName, 2, "Already processed kill : "..sName);
2991  
2992 -- clear last creature kill and return
2993 SKM_Context.LastCreatureKill = nil;
2994 return;
2995 end
2996 end
2997  
2998 -- kill not recorded by target kill, process it
2999 local StoreInfo = { };
3000  
3001 StoreInfo[_SKM._type] = _SKM._creatureKill_Xp;
3002  
3003 local sDate1, sDate2 = SkM_GetDate();
3004 StoreInfo[_SKM._date] = sDate1;
3005 --StoreInfo[_sortdate] = sDate2;
3006  
3007 StoreInfo[_SKM._name] = sName;
3008  
3009 if (not SkM_AddMapData(StoreInfo)) then
3010 return;
3011 end
3012  
3013  
3014 if (SkM_GetOption("DisplayCreatureKillRecord")) then
3015 SkM_ChatMessageColP(string.format(SKM_UI_STRINGS.RecordMessage_CreatureKill, sName), SKM_Config.RGB_CreatureKill);
3016 end
3017  
3018 -- memorize killed mob to that we don't count it again when receiving xp message
3019 SKM_Context.LastCreatureKill = { };
3020 SKM_Context.LastCreatureKill[_SKM._name] = sName;
3021 SKM_Context.LastCreatureKill[_SKM._time] = GetTime();
3022  
3023 --local idx_c, idx_z = SkM_GetZone();
3024 local idx_c, idx_z = SkM_GetZone_Shift();
3025 if (idx_z) then
3026 SkM_CleanZoneCreatureKill(idx_c, idx_z);
3027 end
3028  
3029 end
3030  
3031  
3032 -- --------------------------------------------------------------------------------------
3033 -- SkM_RecordCreatureKill_Target
3034 -- --------------------------------------------------------------------------------------
3035 -- Record a creature kill by target (the creature we are currently targetting dies,
3036 -- and it was tapped by us).
3037 -- --------------------------------------------------------------------------------------
3038 function SkM_RecordCreatureKill_Target(sName, iLevel, sCreatureClass)
3039 local FName = "SkM_RecordCreatureKill_Target";
3040  
3041 if (not SkM_GetOption("RecordCreatureKill")) then
3042 return;
3043 end
3044  
3045  
3046 local curTime = GetTime();
3047  
3048 SkM_Trace(FName, 3, "Creature by target kill : "..sName.." (time = "..curTime..")");
3049  
3050 -- check if we're already processed this kill on combat xp message
3051 if (SKM_Context.LastCreatureKill) then
3052  
3053 SkM_Trace(FName, 3, "Recent creature kill : "..snil(SKM_Context.LastCreatureKill[_SKM._name]).." (time = "..snil(SKM_Context.LastCreatureKill[_SKM._time])..")");
3054  
3055 if (SKM_Context.LastCreatureKill[_SKM._name] == sName) and (curTime < SKM_Context.LastCreatureKill[_SKM._time] + 1) then
3056 SkM_Trace(FName, 2, "Already processed kill : "..sName);
3057  
3058 -- clear last creature kill and return
3059 SKM_Context.LastCreatureKill = nil;
3060 return;
3061 end
3062 end
3063  
3064 local StoreInfo = { };
3065  
3066 StoreInfo[_SKM._type] = _SKM._creatureKill_Target;
3067  
3068 local sDate1, sDate2 = SkM_GetDate();
3069 StoreInfo[_SKM._date] = sDate1;
3070 --StoreInfo[_sortdate] = sDate2;
3071  
3072 StoreInfo[_SKM._name] = sName;
3073 StoreInfo[_SKM._level] = iLevel;
3074 StoreInfo[_SKM._class] = SKM_Config.CreatureClassLabel[sCreatureClass];
3075  
3076 if (not SkM_AddMapData(StoreInfo)) then
3077 return;
3078 end
3079  
3080 if (SkM_GetOption("DisplayCreatureKillRecord")) then
3081 SkM_ChatMessageColP(string.format(SKM_UI_STRINGS.RecordMessage_CreatureKill, sName), SKM_Config.RGB_CreatureKill);
3082 end
3083  
3084  
3085 -- memorize killed mob to that we don't count it again when receiving xp message
3086 SKM_Context.LastCreatureKill = { };
3087 SKM_Context.LastCreatureKill[_SKM._name] = sName;
3088 SKM_Context.LastCreatureKill[_SKM._time] = GetTime();
3089  
3090 --local idx_c, idx_z = SkM_GetZone();
3091 local idx_c, idx_z = SkM_GetZone_Shift();
3092 if (idx_z) then
3093 SkM_CleanZoneCreatureKill(idx_c, idx_z);
3094 end
3095  
3096 end
3097  
3098  
3099 -- --------------------------------------------------------------------------------------
3100 -- SkM_DeleteNote
3101 -- --------------------------------------------------------------------------------------
3102 -- Delete a global note. Remove this note from global and zone map data, and recompute
3103 -- indexes of more recent notes.
3104 -- --------------------------------------------------------------------------------------
3105 function SkM_DeleteNote(RealmName, PlayerName, idx_gn)
3106 local FName = "SkM_DeleteNote";
3107  
3108 SkM_Trace(FName, 3, "Removing note ("..RealmName.." / "..PlayerName..") : global index = "..idx_gn);
3109  
3110 local idx_c, idx_z, idx_n;
3111 local val_c, val_z, val_n;
3112  
3113 local cont_rem, zone_rem, note_rem;
3114  
3115 for idx_c = 1,getn(SKM_Data[RealmName][PlayerName].MapData),1 do
3116 for idx_z = 1,getn(SKM_Data[RealmName][PlayerName].MapData[idx_c]) do
3117 for idx_n = 1,getn(SKM_Data[RealmName][PlayerName].MapData[idx_c][idx_z]) do
3118 local val_n = SKM_Data[RealmName][PlayerName].MapData[idx_c][idx_z][idx_n];
3119 if (val_n == idx_gn) then
3120 cont_rem = idx_c;
3121 zone_rem = idx_z;
3122 note_rem = idx_n;
3123 elseif (val_n > idx_gn) then
3124 SKM_Data[RealmName][PlayerName].MapData[idx_c][idx_z][idx_n] = val_n - 1;
3125 end
3126 end
3127 end
3128 end
3129  
3130  
3131 SkM_Trace(FName, 3, "Removing note : continent = "..snil(cont_rem)..", zone = "..snil(zone_rem)..", note = "..snil(note_rem));
3132  
3133 table.remove(SKM_Data[RealmName][PlayerName].MapData[cont_rem][zone_rem], note_rem);
3134 table.remove(SKM_Data[RealmName][PlayerName].GlobalMapData, idx_gn);
3135 end
3136  
3137  
3138 -- --------------------------------------------------------------------------------------
3139 -- SkM_CleanZoneCreatureKill
3140 -- --------------------------------------------------------------------------------------
3141 -- A creature kill has been recorded, clean older creature kill records if necessary
3142 -- (from configurable maximum number of creature records by zone).
3143 -- --------------------------------------------------------------------------------------
3144 function SkM_CleanZoneCreatureKill(idx_c, idx_z)
3145 local FName = "SkM_CleanZoneCreatureKill";
3146  
3147  
3148 SkM_Trace(FName, 3, "Continent = "..idx_c..", Zone = "..idx_z);
3149  
3150 local iZoneNoteCount = getn(SKM_Data[_RealmName][_PlayerName].MapData[idx_c][idx_z]);
3151 --iZoneNoteCount = tablesize(SKM_Data[_RealmName][_PlayerName].MapData[idx_c][idx_z]);
3152  
3153 SkM_Trace(FName, 3, "Notes in zone = "..iZoneNoteCount);
3154  
3155 local iCreatureKill = 0;
3156 local i;
3157  
3158 for i=iZoneNoteCount, 1, -1 do
3159 local idx_gn = SKM_Data[_RealmName][_PlayerName].MapData[idx_c][idx_z][i];
3160 local Note = SKM_Data[_RealmName][_PlayerName].GlobalMapData[idx_gn];
3161  
3162 if ((Note) and (Note[_SKM._storedInfo]))
3163 and ((Note[_SKM._storedInfo][_SKM._type] == _SKM._creatureKill_Target) or (Note[_SKM._storedInfo][_SKM._type] == _SKM._creatureKill_Xp)) then
3164 if (iCreatureKill >= SkM_GetOption("CreatureKillRecordsByZone")) then
3165  
3166 -- already reached the max count of creature kill notes by zone
3167 -- have to delete this one.
3168  
3169 -- remove from GlobalMapData and from MapData
3170 SkM_Trace(FName, 3, "Removing note : global index = "..idx_gn..", map index = "..i);
3171  
3172 SkM_DeleteNote(_RealmName, _PlayerName, idx_gn);
3173  
3174 else
3175 iCreatureKill = iCreatureKill + 1;
3176 end
3177 end
3178 end
3179  
3180 end
3181  
3182  
3183 -- --------------------------------------------------------------------------------------
3184 -- SkM_CheckForgetEnemy
3185 -- --------------------------------------------------------------------------------------
3186 -- Check if we can forget an enemy that has engaged in combat against us.
3187 -- If no update has been received in a given time frame, then forget him.
3188 -- --------------------------------------------------------------------------------------
3189 function SkM_CheckForgetEnemy(sName)
3190 local Name = "SkM_CheckForgetEnemy";
3191  
3192 local curTime = GetTime();
3193  
3194 if (SKM_Context.EnemyCombat[sName]) then
3195 -- there exists information about that enemy.
3196 -- check when last updated
3197 if (curTime - SKM_Context.EnemyCombat[sName][_SKM._lastUpdate] > SKM_Config.ForgetEnemyTimer) then
3198 SKM_Context.EnemyCombat[sName] = nil;
3199 end
3200 end
3201  
3202 end
3203  
3204  
3205 -- --------------------------------------------------------------------------------------
3206 -- SkM_BuildGroupList
3207 -- --------------------------------------------------------------------------------------
3208 -- Build a list of players currently in the group. Called each time the group members
3209 -- change.
3210 -- --------------------------------------------------------------------------------------
3211 function SkM_BuildGroupList()
3212 local FName = "SkM_BuildGroupList";
3213  
3214 SkM_Trace(FName, 2, "Party changed, rebuild group list");
3215  
3216  
3217 SKM_Context.GroupList = { };
3218  
3219 local i;
3220 for i=1,GetNumPartyMembers() do
3221 local sUnit = SKM_UNIT_PARTY .. i;
3222 local sName = SkM_UnitName(sUnit);
3223  
3224 if (sName) then
3225 table.insert(SKM_Context.GroupList, sName);
3226 end
3227 end
3228  
3229 end
3230  
3231  
3232 -- --------------------------------------------------------------------------------------
3233 -- SkM_IsNameInGroup
3234 -- --------------------------------------------------------------------------------------
3235 -- Check if given player name is in party.
3236 -- --------------------------------------------------------------------------------------
3237 function SkM_IsNameInGroup(sName)
3238 return ( (sName == _PlayerName)
3239 or (intable(sName, SKM_Context.GroupList))
3240 );
3241 end
3242  
3243  
3244 -- --------------------------------------------------------------------------------------
3245 -- SkM_LogDamage_OnPvpEnemy
3246 -- --------------------------------------------------------------------------------------
3247 -- Keep track of damage done on an enemy, and who did this damage (self or our group,
3248 -- or someone else).
3249 -- --------------------------------------------------------------------------------------
3250 function SkM_LogDamage_OnPvpEnemy(iDamage, sFriendName, sName)
3251 local FName = "SkM_LogDamage_OnPvpEnemy";
3252  
3253 local curTime = GetTime();
3254  
3255 -- first check if we remember this enemy and if no update was received for a long time,
3256 -- then forget him and start anew.
3257 SkM_CheckForgetEnemy(sName);
3258  
3259 if (not SKM_Context.EnemyCombat[sName]) then
3260 SKM_Context.EnemyCombat[sName] = { };
3261 SKM_Context.EnemyCombat[sName][_SKM._name] = sName;
3262 SKM_Context.EnemyCombat[sName][_SKM._totalDamage] = 0;
3263 SKM_Context.EnemyCombat[sName][_SKM._groupDamage] = 0;
3264 end
3265  
3266 SKM_Context.EnemyCombat[sName][_SKM._lastUpdate] = curTime;
3267  
3268 SKM_Context.EnemyCombat[sName][_SKM._totalDamage] = SKM_Context.EnemyCombat[sName][_SKM._totalDamage] + iDamage;
3269  
3270 if (SkM_IsNameInGroup(sFriendName)) then
3271 SKM_Context.EnemyCombat[sName][_SKM._groupDamage] = SKM_Context.EnemyCombat[sName][_SKM._groupDamage] + iDamage;
3272 end
3273  
3274 SkM_Trace(FName, 3, "EnemyCombat updated for "..sName.." : Total damage = ".. SKM_Context.EnemyCombat[sName][_SKM._totalDamage] ..", Group damage = ".. SKM_Context.EnemyCombat[sName][_SKM._groupDamage]);
3275 end
3276  
3277  
3278 function SkM_UpdateEnemyHistory()
3279 SKM_Context.PlayerDataChanged = true;
3280 end
3281  
3282  
3283 -- --------------------------------------------------------------------------------------
3284 -- SkM_UpdateEnemy_IncrCounter
3285 -- --------------------------------------------------------------------------------------
3286 -- Increment enemy counter for a given type, and enemy guild counter if applicable
3287 -- --------------------------------------------------------------------------------------
3288 function SkM_UpdateEnemy_IncrCounter(sName, sType, iValue, bPropagateToGuild)
3289 SkM_UpdateEnemyHistory();
3290  
3291 SKM_Data[_RealmName][_PlayerName].EnemyHistory[sName][sType] = ifnil(SKM_Data[_RealmName][_PlayerName].EnemyHistory[sName][sType], 0) + iValue;
3292  
3293 if (bPropagateToGuild) then
3294 local sGuildName = SKM_Data[_RealmName][_PlayerName].EnemyHistory[sName][_SKM._guild];
3295 if ((sGuildName ~= nil) and (sGuildName ~= "")) then
3296 SkM_UpdateGuild_IncrCounter(sGuildName, sType, iValue);
3297 end
3298 end
3299 end
3300  
3301  
3302 -- --------------------------------------------------------------------------------------
3303 -- SkM_UpdateEnemy_IncrPlayerKill
3304 -- --------------------------------------------------------------------------------------
3305 -- Increment enemy kill count, and enemy guild kill count if applicable
3306 -- --------------------------------------------------------------------------------------
3307 function SkM_UpdateEnemy_IncrPlayerKill(sName, iValue)
3308 SkM_UpdateEnemy_IncrCounter(sName, _SKM._playerKill, iValue, true);
3309 end
3310  
3311  
3312 -- --------------------------------------------------------------------------------------
3313 -- SkM_UpdateEnemy_IncrPlayerFullKill
3314 -- --------------------------------------------------------------------------------------
3315 -- Increment enemy full kill count, and enemy guild full kill count if applicable
3316 -- --------------------------------------------------------------------------------------
3317 function SkM_UpdateEnemy_IncrPlayerFullKill(sName, iValue)
3318 SkM_UpdateEnemy_IncrCounter(sName, _SKM._playerFullKill, iValue, true);
3319 end
3320  
3321  
3322 -- --------------------------------------------------------------------------------------
3323 -- SkM_UpdateEnemy_IncrPlayerAssistKill
3324 -- --------------------------------------------------------------------------------------
3325 -- Increment enemy assist kill count, and enemy guild assist kill count if applicable
3326 -- --------------------------------------------------------------------------------------
3327 function SkM_UpdateEnemy_IncrPlayerAssistKill(sName, iValue)
3328 SkM_UpdateEnemy_IncrCounter(sName, _SKM._playerAssistKill, iValue, true);
3329 end
3330  
3331  
3332 -- --------------------------------------------------------------------------------------
3333 -- SkM_UpdateEnemy_IncrKillPlayer
3334 -- --------------------------------------------------------------------------------------
3335 -- Increment enemy kill player count, and enemy guild kill player count if applicable
3336 -- --------------------------------------------------------------------------------------
3337 function SkM_UpdateEnemy_IncrKillPlayer(sName, iValue, bBattleground)
3338 local sType;
3339 if (bBattleground) then
3340 sType = _SKM._enemyKillBG;
3341 else
3342 sType = _SKM._enemyKillPlayer;
3343 end
3344 SkM_UpdateEnemy_IncrCounter(sName, sType, iValue, true);
3345 end
3346  
3347 -- --------------------------------------------------------------------------------------
3348 -- SkM_UpdateEnemy_IncrHonorKill
3349 -- --------------------------------------------------------------------------------------
3350 -- Increment enemy honor kill count, and enemy guild kill count if applicable
3351 -- --------------------------------------------------------------------------------------
3352 function SkM_UpdateEnemy_IncrHonorKill(sName, iValue)
3353 SkM_UpdateEnemy_IncrCounter(sName, _SKM._honorKill, iValue, true);
3354 end
3355  
3356 function SkM_UpdateEnemy_IncrLoneWolfKill(sName, iValue)
3357 SkM_UpdateEnemy_IncrCounter(sName, _SKM._loneWolfKill, iValue, true);
3358 end
3359  
3360  
3361  
3362 -- --------------------------------------------------------------------------------------
3363 -- SkM_UpdateEnemy_IncrMeet
3364 -- --------------------------------------------------------------------------------------
3365 -- Increment enemy meet count
3366 -- --------------------------------------------------------------------------------------
3367 function SkM_UpdateEnemy_IncrMeet(sName, iValue)
3368 SkM_UpdateEnemy_IncrCounter(sName, _SKM._meetCount, iValue, false);
3369 end
3370  
3371  
3372 -- --------------------------------------------------------------------------------------
3373 -- SkM_UpdateEnemy_SetLastView
3374 -- --------------------------------------------------------------------------------------
3375 -- Update enemy last view date/time
3376 -- --------------------------------------------------------------------------------------
3377 function SkM_UpdateEnemy_SetLastView(sName, sDate)
3378 SkM_UpdateEnemyHistory();
3379  
3380 SKM_Data[_RealmName][_PlayerName].EnemyHistory[sName][_SKM._lastView] = sDate;
3381 end
3382  
3383  
3384 -- --------------------------------------------------------------------------------------
3385 -- SkM_UpdateEnemy_SetLastUpdate
3386  
3387 -- --------------------------------------------------------------------------------------
3388 -- Update enemy last update date/time
3389 -- --------------------------------------------------------------------------------------
3390 function SkM_UpdateEnemy_SetLastUpdate(sName, sDate)
3391 SkM_UpdateEnemyHistory();
3392  
3393 SKM_Data[_RealmName][_PlayerName].EnemyHistory[sName][_SKM._lastUpdate] = sDate;
3394 end
3395  
3396  
3397 -- --------------------------------------------------------------------------------------
3398 -- SkM_UpdateEnemy_SetLevel
3399 -- --------------------------------------------------------------------------------------
3400 -- Update enemy level
3401 -- --------------------------------------------------------------------------------------
3402 function SkM_UpdateEnemy_SetLevel(sName, iLevel)
3403 SkM_UpdateEnemyHistory();
3404  
3405 SKM_Data[_RealmName][_PlayerName].EnemyHistory[sName][_SKM._level] = iLevel;
3406 end
3407  
3408  
3409 -- --------------------------------------------------------------------------------------
3410 -- SkM_UpdateEnemy_SetClass
3411 -- --------------------------------------------------------------------------------------
3412 -- Update enemy class
3413 -- --------------------------------------------------------------------------------------
3414 function SkM_UpdateEnemy_SetClass(sName, sClass)
3415 SkM_UpdateEnemyHistory();
3416  
3417 if (not SKM_Data[_RealmName][_PlayerName].EnemyHistory[sName][_SKM._class]) then
3418 SKM_Data[_RealmName][_PlayerName].EnemyHistory[sName][_SKM._class] = sClass;
3419 end
3420 end
3421  
3422  
3423 -- --------------------------------------------------------------------------------------
3424 -- SkM_UpdateEnemy_SetRace
3425 -- --------------------------------------------------------------------------------------
3426 -- Update enemy race
3427 -- --------------------------------------------------------------------------------------
3428 function SkM_UpdateEnemy_SetRace(sName, sRace)
3429 SkM_UpdateEnemyHistory();
3430  
3431 if (not SKM_Data[_RealmName][_PlayerName].EnemyHistory[sName][_SKM._race]) then
3432 SKM_Data[_RealmName][_PlayerName].EnemyHistory[sName][_SKM._race] = sRace;
3433 end
3434 end
3435  
3436  
3437 -- --------------------------------------------------------------------------------------
3438 -- SkM_UpdateEnemy_SetLocation
3439 -- --------------------------------------------------------------------------------------
3440 -- Update enemy last seen location
3441 -- --------------------------------------------------------------------------------------
3442 function SkM_UpdateEnemy_SetLocation(sName, idx_c, idx_z, xPos, yPos)
3443 SkM_UpdateEnemyHistory();
3444  
3445 SKM_Data[_RealmName][_PlayerName].EnemyHistory[sName][_SKM._zoneName] = nil;
3446  
3447 SKM_Data[_RealmName][_PlayerName].EnemyHistory[sName][_SKM._continent] = idx_c;
3448 SKM_Data[_RealmName][_PlayerName].EnemyHistory[sName][_SKM._zone] = idx_z;
3449 SKM_Data[_RealmName][_PlayerName].EnemyHistory[sName][_SKM._xPos] = xPos;
3450 SKM_Data[_RealmName][_PlayerName].EnemyHistory[sName][_SKM._yPos] = yPos;
3451 end
3452  
3453 function SkM_UpdateEnemy_SetLocationName(sName, sZoneName)
3454 SkM_UpdateEnemyHistory();
3455  
3456 SKM_Data[_RealmName][_PlayerName].EnemyHistory[sName][_SKM._continent] = nil;
3457 SKM_Data[_RealmName][_PlayerName].EnemyHistory[sName][_SKM._zone] = nil;
3458 SKM_Data[_RealmName][_PlayerName].EnemyHistory[sName][_SKM._xPos] = nil;
3459 SKM_Data[_RealmName][_PlayerName].EnemyHistory[sName][_SKM._yPos] = nil;
3460  
3461 SKM_Data[_RealmName][_PlayerName].EnemyHistory[sName][_SKM._zoneName] = sZoneName;
3462 end
3463  
3464  
3465 -- --------------------------------------------------------------------------------------
3466 -- SkM_UpdateEnemy_SetWar
3467 -- --------------------------------------------------------------------------------------
3468 -- Update enemy 'at war' status, and war date
3469 -- --------------------------------------------------------------------------------------
3470 function SkM_UpdateEnemy_SetWar(sName, bWar, sDate)
3471 SkM_UpdateEnemyHistory();
3472  
3473 SKM_Data[_RealmName][_PlayerName].EnemyHistory[sName][_SKM._atWar] = bWar;
3474 if (bWar) then
3475 SKM_Data[_RealmName][_PlayerName].EnemyHistory[sName][_SKM._warDate] = sDate;
3476 else
3477 SKM_Data[_RealmName][_PlayerName].EnemyHistory[sName][_SKM._warDate] = nil;
3478 end
3479 end
3480  
3481  
3482 -- --------------------------------------------------------------------------------------
3483 -- SkM_UpdateEnemyLastView
3484 -- --------------------------------------------------------------------------------------
3485 -- Received some information about an enemy : update this enemy information
3486 -- --------------------------------------------------------------------------------------
3487 function SkM_UpdateEnemyLastView(sName, sDate, bTarget, sUnit)
3488 local FName = "SkM_UpdateEnemyLastView";
3489  
3490 SkM_UpdateEnemyHistory();
3491  
3492 local sTheUnit;
3493 if (sUnit) then
3494 sTheUnit = sUnit;
3495 else
3496 sTheUnit = SKM_UNIT_TARGET;
3497 end
3498  
3499 -- if we have unit on target (or mouseover), check if we should ignore or not
3500 if (bTarget) then
3501  
3502 -- if we already have recorded this player, we update his information anyway,
3503 -- even if he's low level, and even if he has no PvP flag
3504  
3505 -- if we have added this enemy to the unknown enemy at war, then we record him anyway
3506  
3507 if (not SKM_Data[_RealmName][_PlayerName].EnemyHistory[sName])
3508 and (not SKM_Data[_RealmName][_PlayerName].UnknownEnemy[sName])
3509 then
3510  
3511 if (not SkM_GetOption("StoreEnemyPlayers")) then
3512 SkM_Trace(FName, 2, "Storing disabled");
3513 return;
3514 end
3515  
3516 if (SkM_GetOption("IgnoreLowerEnemies")) then
3517 local iUnitLevel = UnitLevel(sTheUnit);
3518 if (iUnitLevel == -1) then
3519 iUnitLevel = 500;
3520 end
3521 local iMinLevel = math.floor( UnitLevel(SKM_UNIT_PLAYER) * SkM_GetOption("IgnoreLevelThreshold") / 100 );
3522 if ( iUnitLevel < iMinLevel ) then
3523 SkM_Trace(FName, 1, "Not storing, too low level : "..iUnitLevel..", min. = "..iMinLevel);
3524 return;
3525 end
3526 end
3527 end
3528  
3529 if (SkM_GetOption("IgnoreNoPvPFlag")) then
3530 if not (UnitIsPVP(sTheUnit) or UnitIsPVPFreeForAll(sTheUnit)) then
3531 SkM_Trace(FName, 1, "Not storing, Unit "..snil(sTheUnit).." is not PvP flagged");
3532 return;
3533 end
3534 end
3535  
3536 end
3537  
3538 if (not SKM_Data[_RealmName][_PlayerName].EnemyHistory[sName]) then
3539 SKM_Data[_RealmName][_PlayerName].EnemyHistory[sName] = { };
3540 SKM_Data[_RealmName][_PlayerName].EnemyHistory[sName][_SKM._name] = sName;
3541 SKM_Data[_RealmName][_PlayerName].EnemyHistory[sName][_SKM._playerAssistKill] = 0;
3542 SKM_Data[_RealmName][_PlayerName].EnemyHistory[sName][_SKM._playerKill] = 0;
3543 SKM_Data[_RealmName][_PlayerName].EnemyHistory[sName][_SKM._playerFullKill] = 0;
3544 SKM_Data[_RealmName][_PlayerName].EnemyHistory[sName][_SKM._enemyKillPlayer] = 0;
3545 SKM_Data[_RealmName][_PlayerName].EnemyHistory[sName][_SKM._enemyKillBG] = 0;
3546 SKM_Data[_RealmName][_PlayerName].EnemyHistory[sName][_SKM._playerBGKill] = 0;
3547 SKM_Data[_RealmName][_PlayerName].EnemyHistory[sName][_SKM._meetCount] = 1;
3548  
3549 if (SKM_Data[_RealmName][_PlayerName].UnknownEnemy[sName]) then
3550 SKM_Data[_RealmName][_PlayerName].EnemyHistory[sName][_SKM._meetCount] = 1;
3551 SKM_Data[_RealmName][_PlayerName].UnknownEnemy[sName] = nil;
3552  
3553 SkM_Trace(FName, 2, snil(sName).."Added with 'at WAR' status");
3554 end
3555  
3556 SkM_Trace(FName, 1, "First encounter of enemy : "..snil(sName));
3557 else
3558  
3559 if ((not SKM_Data[_RealmName][_PlayerName].EnemyHistory[sName][_SKM._meetCount]
3560 or (not SKM_Data[_RealmName][_PlayerName].EnemyHistory[sName][_SKM._lastView]))) then
3561  
3562 -- 09/04/2005 18:44:32 PIng Add a check since LastView is updated later now.
3563 SkM_UpdateEnemy_IncrMeet(sName, 1);
3564 else
3565 -- increase number of time player met this enemy if last viewed time is older than
3566 -- configurable value
3567 local iDiffTime = SkM_DiffDate(sDate, SKM_Data[_RealmName][_PlayerName].EnemyHistory[sName][_SKM._lastView]);
3568 if (iDiffTime ~= nil) and (iDiffTime > SKM_Config.TimeRangeForNewMeeting) then
3569 SkM_UpdateEnemy_IncrMeet(sName, 1);
3570 end
3571 end
3572  
3573 end
3574  
3575 -- if we have unit on target (or mouseover), update information
3576 if (bTarget) then
3577 SkM_UpdateEnemy_SetLevel(sName, UnitLevel(sTheUnit));
3578 SkM_UpdateEnemy_SetClass(sName, SkM_GetClassIndex(UnitClass(sTheUnit)));
3579 SkM_UpdateEnemy_SetRace(sName, SkM_GetRaceIndex(UnitRace(sTheUnit)));
3580 SkM_UpdateEnemy_SetGuild(sName, ifnil(GetGuildInfo(sTheUnit),"")); -- PIng Add guild support
3581 --SkM_UpdateEnemy_SetLastUpdate(sName, sDate);
3582  
3583 -- get/update rank also
3584 local iRank = UnitPVPRank(sTheUnit);
3585 if (iRank >= 1) then
3586 local sRank = GetPVPRankInfo(iRank, sTheUnit);
3587 if (sRank) then
3588 SkM_UpdateEnemyRank(sName, sRank);
3589 end
3590 end
3591  
3592 end
3593  
3594 local idx_c, idx_z = SkM_GetZone();
3595 if (idx_z) then
3596 SetMapZoom(idx_c, idx_z);
3597 local xPos, yPos = GetPlayerMapPosition(SKM_UNIT_PLAYER);
3598  
3599 --SkM_UpdateEnemy_SetLocation(sName, idx_c, idx_z, xPos, yPos);
3600  
3601 local cont_shift, zone_shift = SkM_GetZone_Shift(idx_c, idx_z);
3602 SkM_UpdateEnemy_SetLocation(sName, cont_shift, zone_shift, xPos, yPos);
3603 else
3604 local sZoneName = SkM_GetZoneText();
3605 SkM_UpdateEnemy_SetLocationName(sName, sZoneName);
3606 end
3607  
3608 -- 09/04/2005 16:46:34 PIng: Add guild support
3609  
3610 -- Update guild if known
3611 local sGuildName = SKM_Data[_RealmName][_PlayerName].EnemyHistory[sName][_SKM._guild];
3612 -- if ((sGuildName ~= nil) and (sGuildName ~= "not in a guild")) then
3613 if ((sGuildName ~= nil) and (sGuildName ~= "")) then
3614 SkM_UpdateGuildHistory(sGuildName, sDate, sName);
3615 end
3616  
3617 -- 09/04/2005 16:46:43 End of modification
3618  
3619 SkM_UpdateEnemy_SetLastView(sName, sDate); -- 09/04/2005 18:30:05 PIng: Moved in order to have the information available for guild update
3620  
3621 end
3622  
3623  
3624 function SkM_UpdateEnemyRank(sName, sRank)
3625 SkM_UpdateEnemyHistory();
3626  
3627 SKM_Data[_RealmName][_PlayerName].EnemyHistory[sName][_SKM._rank] = sRank;
3628 end
3629  
3630  
3631 function SkM_UpdateEnemy_SetGuild(sName, sGuild)
3632 SkM_UpdateEnemyHistory();
3633  
3634 --if (not SKM_Data[_RealmName][_PlayerName].EnemyHistory[sName][_SKM._guild]) then
3635 SKM_Data[_RealmName][_PlayerName].EnemyHistory[sName][_SKM._guild] = sGuild;
3636 --end
3637 end
3638  
3639 function SkM_UpdateGuild_SetLastView(sGuildName, sDate, sPlayerName)
3640 SKM_Data[_RealmName][_PlayerName].GuildHistory[sGuildName][_SKM._lastView] = sDate;
3641 SKM_Data[_RealmName][_PlayerName].GuildHistory[sGuildName][_SKM._lastPlayerViewed] = sPlayerName;
3642 end
3643  
3644 function SkM_UpdateGuild_IncrCounter(sGuildName, sType, iValue)
3645 SKM_Data[_RealmName][_PlayerName].GuildHistory[sGuildName][sType] = ifnil(SKM_Data[_RealmName][_PlayerName].GuildHistory[sGuildName][sType], 0) + iValue;
3646 end
3647  
3648 function SkM_UpdateGuild_IncrPlayerKill(sGuildName, iValue)
3649 SkM_UpdateGuild_IncrCounter(sGuildName, _SKM._playerKill, iValue);
3650 end
3651  
3652 function SkM_UpdateGuild_IncrPlayerFullKill(sGuildName, iValue)
3653 SkM_UpdateGuild_IncrCounter(sGuildName, _SKM._playerFullKill, iValue);
3654 end
3655  
3656 function SkM_UpdateGuild_IncrPlayerAssistKill(sGuildName, iValue)
3657 SkM_UpdateGuild_IncrCounter(sGuildName, _SKM._playerAssistKill, iValue);
3658 end
3659  
3660 function SkM_UpdateGuild_IncrKillPlayer(sGuildName, iValue, bBattleground)
3661 local sType;
3662 if (bBattleground) then
3663 sType = _SKM._enemyKillBG;
3664 else
3665 sType = _SKM._enemyKillPlayer;
3666 end
3667 SkM_UpdateGuild_IncrCounter(sGuildName, sType, iValue);
3668 end
3669  
3670 function SkM_UpdateGuild_IncrHonorKill(sGuildName, iValue)
3671 SkM_UpdateGuild_IncrCounter(sGuildName, _SKM._honorKill, iValue);
3672 end
3673  
3674 function SkM_UpdateGuild_IncrMeet(sGuildName, iValue)
3675 SkM_UpdateGuild_IncrCounter(sGuildName, _SKM._meetCount, iValue);
3676 end
3677  
3678  
3679 -- --------------------------------------------------------------------------------------
3680  
3681 -- SkM_UpdateGuildHistory
3682 -- --------------------------------------------------------------------------------------
3683 -- Update guild information when receiving an update of a enemy from this guild
3684 -- --------------------------------------------------------------------------------------
3685 function SkM_UpdateGuildHistory(sGuildName, sDate, sName)
3686 local FName = "SkM_UpdateGuildHistory";
3687  
3688 SkM_Trace(FName, 2, "Guild Name : "..sGuildName..", Date : ".. sDate.. ", Player Name : "..sName);
3689  
3690 if (not SKM_Data[_RealmName][_PlayerName].GuildHistory[sGuildName]) then
3691 SKM_Data[_RealmName][_PlayerName].GuildHistory[sGuildName] = { };
3692 SKM_Data[_RealmName][_PlayerName].GuildHistory[sGuildName][_SKM._name] = sGuildName;
3693 SKM_Data[_RealmName][_PlayerName].GuildHistory[sGuildName][_SKM._playerAssistKill] = 0;
3694 SKM_Data[_RealmName][_PlayerName].GuildHistory[sGuildName][_SKM._playerKill] = 0;
3695 SKM_Data[_RealmName][_PlayerName].GuildHistory[sGuildName][_SKM._playerFullKill] = 0;
3696 SKM_Data[_RealmName][_PlayerName].GuildHistory[sGuildName][_SKM._enemyKillPlayer] = 0;
3697 SKM_Data[_RealmName][_PlayerName].GuildHistory[sGuildName][_SKM._enemyKillBG] = 0;
3698 SKM_Data[_RealmName][_PlayerName].GuildHistory[sGuildName][_SKM._playerBGKill] = 0;
3699 SKM_Data[_RealmName][_PlayerName].GuildHistory[sGuildName][_SKM._meetCount] = 1;
3700 else
3701 if ((not SKM_Data[_RealmName][_PlayerName].GuildHistory[sGuildName][_SKM._meetCount])
3702 or (not SKM_Data[_RealmName][_PlayerName].EnemyHistory[sName][_SKM._lastView])) then
3703 SkM_Trace(FName, 2, "Increment Meet count for Guild for first time"..sGuildName);
3704 SkM_UpdateGuild_IncrMeet(sGuildName, 1);
3705 else
3706 -- increase number of time player met this guild if last viewed time for this enemy is older than
3707 -- configurable value
3708 SkM_Trace(FName, 2, "check if we need to increment");
3709 local iDiffTime = SkM_DiffDate(sDate, SKM_Data[_RealmName][_PlayerName].EnemyHistory[sName][_SKM._lastView]);
3710 if (iDiffTime ~= nil) and (iDiffTime > SKM_Config.TimeRangeForNewMeeting) then
3711 SkM_Trace(FName, 1, "Increment Meet count for Guild "..sGuildName);
3712 SkM_UpdateGuild_IncrMeet(sGuildName, 1);
3713 end
3714 end
3715 SkM_Trace(FName, 2, "Exit");
3716  
3717 end
3718  
3719 SkM_UpdateGuild_SetLastView(sGuildName, sDate, sName);
3720 end
3721  
3722  
3723  
3724 -- --------------------------------------------------------------------------------------
3725 -- SkM_UpdateGuild_SetWar
3726 -- --------------------------------------------------------------------------------------
3727 -- Update guild 'at war' status and war date
3728 -- --------------------------------------------------------------------------------------
3729 function SkM_UpdateGuild_SetWar(sName, bWar, sDate)
3730 SKM_Data[_RealmName][_PlayerName].GuildHistory[sName][_SKM._atWar] = bWar;
3731 if (bWar) then
3732 SKM_Data[_RealmName][_PlayerName].GuildHistory[sName][_SKM._warDate] = sDate;
3733 else
3734 SKM_Data[_RealmName][_PlayerName].GuildHistory[sName][_SKM._warDate] = nil;
3735 end
3736 end
3737  
3738  
3739 function SkM_GetRecentEnemyKill(sName)
3740 local bFound = false;
3741 local iNoteIndex;
3742 local sDate = SkM_GetDate();
3743 local i;
3744 for i=table.getn(SKM_Context.RecentEnemyKill), 1, -1 do
3745 if (SKM_Context.RecentEnemyKill[i][_SKM._name] == sName) then
3746 local iDiffTime = SkM_DiffDate(sDate, SKM_Context.RecentEnemyKill[i][_SKM._date]);
3747 if (iDiffTime ~= nil) and (iDiffTime <= SKM_Config.RecentEnemyKillDelay) then
3748 bFound = true;
3749 iNoteIndex = SKM_Context.RecentEnemyKill[i][_SKM._noteIndex];
3750 return bFound, iNoteIndex;
3751 end
3752 end
3753 end
3754 return bFound, iNoteIndex;
3755 end
3756  
3757  
3758 function SkM_AddRecentEnemyKill(sName, sDate, iGlobalNote)
3759 local FName = "SkM_AddRecentEnemyKill";
3760  
3761 SkM_Trace(FName, 2, "Name = "..snil(sName)..", G. Note = "..snil(iGlobalNote));
3762  
3763 local Record = { };
3764 Record[_SKM._name] = sName;
3765 Record[_SKM._date] = sDate;
3766 Record[_SKM._noteIndex] = iGlobalNote;
3767 table.insert(SKM_Context.RecentEnemyKill, Record);
3768  
3769 while (table.getn(SKM_Context.RecentEnemyKill) > SKM_Config.MaxRecentEnemyKill) do
3770 table.remove(SKM_Context.RecentEnemyKill, 1);
3771 end
3772 end
3773  
3774  
3775 function SkM_GetRecentWarWarning(sName)
3776 local bFound = false;
3777 local sDate = SkM_GetDate();
3778 local i;
3779 for i=table.getn(SKM_Context.RecentWarWarning), 1, -1 do
3780 if (SKM_Context.RecentWarWarning[i][_SKM._name] == sName) then
3781 local iDiffTime = SkM_DiffDate(sDate, SKM_Context.RecentWarWarning[i][_SKM._date]);
3782 if (iDiffTime ~= nil) and (iDiffTime <= SKM_Config.RecentWarWarningDelay) then
3783 bFound = true;
3784 return bFound;
3785 end
3786 end
3787 end
3788 return bFound;
3789 end
3790  
3791 function SkM_AddRecentWarWarning(sName, sDate)
3792 local Record = { };
3793 Record[_SKM._name] = sName;
3794 Record[_SKM._date] = sDate;
3795 table.insert(SKM_Context.RecentWarWarning, Record);
3796  
3797 while (table.getn(SKM_Context.RecentWarWarning) > SKM_Config.MaxRecentWarWarning) do
3798 table.remove(SKM_Context.RecentWarWarning, 1);
3799 end
3800 end
3801  
3802  
3803  
3804 -- --------------------------------------------------------------------------------------
3805 -- SkM_PvpEnemyDeath
3806 -- --------------------------------------------------------------------------------------
3807 -- An enemy dies...
3808 -- Check from his name if we know him as an enemy player. If it's the case, check how
3809 -- much relative damage did the group to this enemy, and record appropriate kill event.
3810 -- --------------------------------------------------------------------------------------
3811 function SkM_PvpEnemyDeath(sName, bHonorKill, sRank)
3812 local FName = "SkM_PvpEnemyDeath";
3813  
3814 SkM_Trace(FName, 3, "Name = "..snil(sName));
3815 if (not sName) then
3816 SkM_Trace(FName, 1, "nil parameter received !");
3817 return;
3818 end
3819  
3820 SkM_CheckForgetEnemy(sName);
3821  
3822 -- if (not SkM_GetOption("RecordPlayerKill")) then
3823 -- return;
3824 -- end
3825  
3826  
3827 -- check if in battleground
3828 local bBattleground = SkM_IsInBattleground();
3829  
3830 if (not SKM_Context.EnemyCombat[sName]) and (not bHonorKill) then
3831 -- no information about this enemy
3832 return;
3833 end
3834  
3835 if (not SKM_Data[_RealmName][_PlayerName].EnemyHistory[sName]) then
3836 -- if this is a honor kill, then we *know* it is a player
3837 -- also check that "store enemy players" is enabled.
3838  
3839 if (not bHonorKill) or (not SkM_GetOption("StoreEnemyPlayers")) then
3840 -- we have no information about the enemy just killed.
3841 -- maybe he's a player that has never been targeted, but maybe not...
3842 -- in doubt we do nothing
3843 SkM_Trace(FName, 3, sName.." : type unknown...");
3844  
3845 SKM_Context.EnemyCombat[sName] = nil;
3846 return;
3847 end
3848  
3849 end
3850  
3851 local sDate1, sDate2 = SkM_GetDate();
3852  
3853 SkM_UpdateEnemyLastView(sName, sDate1, false);
3854 if (sRank) then
3855 SkM_UpdateEnemyRank(sName, sRank);
3856 end
3857  
3858 -- check if we have already recorded this kill
3859 local bRecorded, iNoteIndex;
3860 bRecorded, iNoteIndex = SkM_GetRecentEnemyKill(sName);
3861 if (bRecorded) then
3862 -- already recorded
3863 SkM_Trace(FName, 3, "Kill already recorded : idx_gn = "..snil(iNoteIndex));
3864  
3865 if (bHonorKill) then
3866 SkM_Trace(FName, 3, "Adjust as honor kill");
3867  
3868 -- we received an "honor kill", it means the kill was previously recorded due to
3869 -- a event that was not an "honor kill" : now take honor info into account
3870 -- SKM_Data[_RealmName][_PlayerName].EnemyHistory[sName][_SKM._honorKill] = ifnil(SKM_Data[_RealmName][_PlayerName].EnemyHistory[sName][_SKM._honorKill], 0) + 1;
3871 SkM_UpdateEnemy_IncrHonorKill(sName, 1);
3872  
3873 SkM_SetHonorFlags(sName);
3874  
3875 -- local sGuildName = SKM_Data[_RealmName][_PlayerName].EnemyHistory[sName][_SKM._guild];
3876 -- if ((sGuildName ~= nil) and (sGuildName ~= "")) then
3877 -- SKM_Data[_RealmName][_PlayerName].GuildHistory[sGuildName][_SKM._honorKill] = ifnil(SKM_Data[_RealmName][_PlayerName].GuildHistory[sGuildName][_SKM._honorKill], 0) + 1;
3878 -- end
3879  
3880 if (iNoteIndex) then
3881 SKM_Data[_RealmName][_PlayerName].GlobalMapData[iNoteIndex][_SKM._storedInfo][_SKM._honorKill] = true;
3882 end
3883  
3884 end
3885  
3886 return;
3887 end
3888  
3889 SkM_Trace(FName, 3, "Kill not yet recorded");
3890  
3891 local KillType;
3892  
3893 if (not SKM_Context.EnemyCombat[sName]) then
3894 -- did not receive any combat information about this player, but
3895 -- we received an "honor" kill : award an "assist kill" by default
3896 SkM_Trace(FName, 3, "No combat info, but honor kill : award Assist Kill");
3897  
3898 KillType = _SKM._playerAssistKill;
3899  
3900 elseif (SKM_Context.EnemyCombat[sName][_SKM._groupDamage] == 0) then
3901 SkM_Trace(FName, 3, "Group didn't do any damage");
3902  
3903 if (bHonorKill) then
3904 -- no damage recorded by our group, but we received an "honor kill" :
3905 -- award an "assist kill" by default
3906 KillType = _SKM._playerAssistKill;
3907 end
3908  
3909 else
3910 local iPercent = SKM_Context.EnemyCombat[sName][_SKM._groupDamage] / SKM_Context.EnemyCombat[sName][_SKM._totalDamage];
3911  
3912 if (iPercent < 0.50) then
3913 SkM_Trace(FName, 3, "Group damage < 50% : award Assist Kill");
3914 KillType = _SKM._playerAssistKill;
3915 elseif (iPercent < 1.00) then
3916 SkM_Trace(FName, 3, "Group damage >= 50% and < 100% : award Kill");
3917 KillType = _SKM._playerKill;
3918 else
3919 SkM_Trace(FName, 3, "Group damage = 100% : award Full Kill");
3920 KillType = _SKM._playerFullKill;
3921 end
3922  
3923 end
3924  
3925 if (KillType ~= nil) then
3926  
3927 if (bBattleground == true) then
3928 KillType = _SKM._playerBGKill;
3929 end
3930  
3931 if (SkM_GetOption("DisplayKillRecord")) then
3932 if (KillType == _SKM._playerAssistKill) then
3933 SkM_ChatMessageColP(string.format(SKM_UI_STRINGS.RecordMessage_AssistKill, sName), SKM_Config.RGB_PlayerAssistKill);
3934 elseif (KillType == _SKM._playerKill) then
3935 SkM_ChatMessageColP(string.format(SKM_UI_STRINGS.RecordMessage_Kill, sName), SKM_Config.RGB_PlayerKill);
3936 elseif (KillType == _SKM._playerFullKill) then
3937 SkM_ChatMessageColP(string.format(SKM_UI_STRINGS.RecordMessage_FullKill, sName), SKM_Config.RGB_PlayerFullKill);
3938 end
3939 end
3940  
3941 --SKM_Data[_RealmName][_PlayerName].EnemyHistory[sName][KillType] = ifnil(SKM_Data[_RealmName][_PlayerName].EnemyHistory[sName][KillType], 0) + 1;
3942 SkM_UpdateEnemy_IncrCounter(sName, KillType, 1, true);
3943  
3944 if (bBattleground == true) then
3945 SkM_BGStats_AddKill();
3946 end
3947  
3948  
3949 if (bHonorKill) then
3950 --SKM_Data[_RealmName][_PlayerName].EnemyHistory[sName][_SKM._honorKill] = ifnil(SKM_Data[_RealmName][_PlayerName].EnemyHistory[sName][_SKM._honorKill], 0) + 1;
3951 SkM_UpdateEnemy_IncrHonorKill(sName, 1);
3952  
3953 SkM_SetHonorFlags(sName);
3954 end
3955  
3956 -- asked by Fumus : record special count for solo kills for which player did full damage
3957 if (KillType == _SKM._playerFullKill) and (getn(SKM_Context.GroupList) == 1) then
3958 SkM_Trace(FName, 3, "Group damage = 100% + solo : lone wolf kill");
3959 --SKM_Data[_RealmName][_PlayerName].EnemyHistory[sName][_SKM._loneWolfKill] = ifnil(SKM_Data[_RealmName][_PlayerName].EnemyHistory[sName][_SKM._loneWolfKill], 0) + 1;
3960 SkM_UpdateEnemy_IncrLoneWolfKill(sName, 1);
3961 end
3962  
3963 -- local sGuildName = SKM_Data[_RealmName][_PlayerName].EnemyHistory[sName][_SKM._guild];
3964 -- if ((sGuildName ~= nil) and (sGuildName ~= "")) then
3965 -- SKM_Data[_RealmName][_PlayerName].GuildHistory[sGuildName][KillType] = ifnil(SKM_Data[_RealmName][_PlayerName].GuildHistory[sGuildName][KillType], 0) + 1;
3966 --
3967 -- if (bHonorKill) then
3968  
3969 -- SKM_Data[_RealmName][_PlayerName].GuildHistory[sGuildName][_SKM._honorKill] = ifnil(SKM_Data[_RealmName][_PlayerName].GuildHistory[sGuildName][_SKM._honorKill], 0) + 1;
3970 -- end
3971 --
3972 -- -- asked by Fumus : record special count for solo kills for which player did full damage
3973 -- if (KillType == _SKM._playerFullKill) and (getn(SKM_Context.GroupList) == 1) then
3974 -- SkM_Trace(FName, 3, "Group damage = 100% + solo : lone wolf kill");
3975 -- SKM_Data[_RealmName][_PlayerName].GuildHistory[sGuildName][_SKM._loneWolfKill] = ifnil(SKM_Data[_RealmName][_PlayerName].GuildHistory[sGuildName][_SKM._loneWolfKill], 0) + 1;
3976 -- end
3977 -- end
3978  
3979 --local Enemy = SKM_Data[_RealmName][_PlayerName].EnemyHistory[sName];
3980  
3981 local StoreInfo = { };
3982  
3983 StoreInfo[_SKM._type] = KillType;
3984 StoreInfo[_SKM._name] = sName;
3985 StoreInfo[_SKM._date] = sDate1;
3986 --StoreInfo[_sortdate] = sDate2;
3987  
3988 -- asked by Fumus : record special count for solo kills for which player did full damage
3989 if (KillType == _SKM._playerFullKill) and (getn(SKM_Context.GroupList) == 1) then
3990 StoreInfo[_SKM._loneWolfKill] = true;
3991 end
3992  
3993 if (bHonorKill) then
3994 StoreInfo[_SKM._honorKill] = true;
3995 end
3996  
3997 StoreInfo[_SKM._enemyType] = _SKM._enemyPlayer;
3998  
3999 if (SkM_GetOption("RecordPlayerKill")) then
4000 local idx_gn;
4001 if (SkM_AddMapData(StoreInfo)) then
4002 idx_gn = table.getn(SKM_Data[_RealmName][_PlayerName].GlobalMapData);
4003 end
4004  
4005 SkM_AddRecentEnemyKill(sName, sDate1, idx_gn);
4006 end
4007  
4008 -- update target info if needed
4009 SkM_SetTargetInfo();
4010 end
4011  
4012 SKM_Context.EnemyCombat[sName] = nil;
4013 end
4014  
4015  
4016 function SkM_SetHonorFlags(sName)
4017 local FName = "SkM_SetHonorFlags";
4018  
4019 if (not sName) then
4020 SkM_Trace(FName, 1, "Name is nil");
4021 return;
4022 end
4023 if (not SKM_Data[_RealmName][_PlayerName].EnemyHistory[sName]) then
4024 SkM_Trace(FName, 1, "Enemy "..snil(sName).." not known");
4025 return;
4026 end
4027  
4028 local sDate = SkM_GetDate();
4029 local sDateLast = SKM_Data[_RealmName][_PlayerName].EnemyHistory[sName][_SKM._honorLastKill];
4030  
4031 if (not sDateLast) then
4032 SKM_Data[_RealmName][_PlayerName].EnemyHistory[sName][_SKM._honorLastKill] = sDate;
4033 SKM_Data[_RealmName][_PlayerName].EnemyHistory[sName][_SKM._honorCount] = 1;
4034 elseif (string.sub(sDate, 1, 10) ~= string.sub(sDateLast, 1, 10)) then
4035 SKM_Data[_RealmName][_PlayerName].EnemyHistory[sName][_SKM._honorLastKill] = sDate;
4036 SKM_Data[_RealmName][_PlayerName].EnemyHistory[sName][_SKM._honorCount] = 1;
4037 else
4038 SKM_Data[_RealmName][_PlayerName].EnemyHistory[sName][_SKM._honorCount] = ifnil(SKM_Data[_RealmName][_PlayerName].EnemyHistory[sName][_SKM._honorCount], 0) + 1;
4039 end
4040  
4041 end
4042  
4043  
4044 function SkM_GetHonorRemainingKills(sName)
4045 local FName = "SkM_GetHonorRemainingKills";
4046  
4047 if (not sName) then
4048 SkM_Trace(FName, 1, "Name is nil");
4049 return;
4050 end
4051 if (not SKM_Data[_RealmName][_PlayerName].EnemyHistory[sName]) then
4052 SkM_Trace(FName, 1, "Enemy "..snil(sName).." not known");
4053 return;
4054 end
4055  
4056 local iCount;
4057 local sDate = SkM_GetDate();
4058 local sDateLast = SKM_Data[_RealmName][_PlayerName].EnemyHistory[sName][_SKM._honorLastKill];
4059  
4060 if (not sDateLast) then
4061 iCount = SKM_HonorKillPerDay;
4062 elseif (string.sub(sDate, 1, 10) ~= string.sub(sDateLast, 1, 10)) then
4063 iCount = SKM_HonorKillPerDay;
4064 else
4065 iCount = SKM_HonorKillPerDay - ifnil(SKM_Data[_RealmName][_PlayerName].EnemyHistory[sName][_SKM._honorCount], 0);
4066 if (iCount < 0) then
4067 iCount = 0;
4068 end
4069 end
4070 return iCount;
4071 end
4072  
4073  
4074 function SkM_StoreDuelEnemyInfo(sUnit)
4075 local FName = "SkM_StoreDuelEnemyInfo";
4076  
4077 local sName = UnitName(sUnit);
4078 if (not sName) then
4079 return;
4080 end
4081  
4082 if (SKM_Context.DuelEnemy) and (SKM_Context.DuelEnemy[_SKM._name] == sName) then
4083 -- already stored
4084 return;
4085 end
4086  
4087 SKM_Context.DuelEnemy = { };
4088 SKM_Context.DuelEnemy[_SKM._name] = sName;
4089 SKM_Context.DuelEnemy[_SKM._race] = SkM_GetRaceIndex(UnitRace(sUnit));
4090 SKM_Context.DuelEnemy[_SKM._class] = SkM_GetClassIndex(UnitClass(sUnit));
4091 SKM_Context.DuelEnemy[_SKM._level] = UnitLevel(sUnit);
4092 SKM_Context.DuelEnemy[_SKM._guild] = GetGuildInfo(sUnit);
4093  
4094 end
4095  
4096  
4097 -- --------------------------------------------------------------------------------------
4098 -- SkM_UpdateUnitData
4099 -- --------------------------------------------------------------------------------------
4100 -- Target unit has been updated. If it's an enemy, update that player information.
4101 -- If it's a creep, store creature information.
4102 -- --------------------------------------------------------------------------------------
4103 function SkM_UpdateUnitData()
4104 local FName = "SkM_UpdateUnitData";
4105  
4106 local sName = SkM_UnitName(SKM_UNIT_TARGET);
4107  
4108 if (not sName) then
4109 -- clear target info
4110 SKM_Context.TargetInfo = nil;
4111 else
4112 if (SkM_UnitIsEnemyPlayer(SKM_UNIT_TARGET)) then
4113 local sDate1, sDate2 = SkM_GetDate();
4114 SkM_UpdateEnemyLastView(sName, sDate1, true, SKM_UNIT_TARGET);
4115 end
4116  
4117 if (not UnitIsPlayer(SKM_UNIT_TARGET)) then
4118 SkM_StoreTargetInfo(_SKM._enemyCreature);
4119 elseif (SkM_UnitIsEnemyPlayer(SKM_UNIT_TARGET)) then
4120 SkM_StoreTargetInfo(_SKM._enemyPlayer);
4121 else
4122 SKM_Context.TargetInfo = nil;
4123 end
4124  
4125 if (SkM_GetOption("StoreDuels")) then
4126 if (SkM_UnitIsDuelingPlayer(SKM_UNIT_TARGET)) then
4127 SkM_StoreDuelEnemyInfo(SKM_UNIT_TARGET);
4128 end
4129 end
4130  
4131 end
4132  
4133  
4134 end
4135  
4136  
4137 -- --------------------------------------------------------------------------------------
4138 -- SkM_MouseOverUnitData
4139 -- --------------------------------------------------------------------------------------
4140 -- Get information on enemy player on mouse-over
4141 -- --------------------------------------------------------------------------------------
4142 function SkM_MouseOverUnitData()
4143 local FName = "SkM_MouseOverUnitData";
4144  
4145 local sName = SkM_UnitName(SKM_UNIT_MOUSEOVER);
4146  
4147 if (sName) then
4148 if (SkM_UnitIsEnemyPlayer(SKM_UNIT_MOUSEOVER)) then
4149 local sDate1, sDate2 = SkM_GetDate();
4150 SkM_UpdateEnemyLastView(sName, sDate1, true, SKM_UNIT_MOUSEOVER);
4151  
4152 --local iLevel = UnitLevel(SKM_UNIT_MOUSEOVER);
4153 --local sClass = UnitClass(SKM_UNIT_MOUSEOVER);
4154 --local sRace = UnitRace(SKM_UNIT_MOUSEOVER);
4155 --local sGuild = GetGuildInfo(SKM_UNIT_MOUSEOVER);
4156 --SkM_Trace(FName, 1, "Name = "..snil(sName)..", Level = "..snil(iLevel)..", Class = "..snil(sClass)..", Race = "..snil(sRace)..", Guild = "..snil(sGuild));
4157  
4158 elseif (SkM_GetOption("StoreDuels")) and (SkM_UnitIsDuelingPlayer(SKM_UNIT_MOUSEOVER)) then
4159 SkM_StoreDuelEnemyInfo(SKM_UNIT_MOUSEOVER);
4160 end
4161  
4162 end
4163  
4164 end
4165  
4166  
4167 -- --------------------------------------------------------------------------------------
4168 -- SkM_ForgetPlayerHate
4169 -- --------------------------------------------------------------------------------------
4170 -- For all enemies in player hate list, recompute hate level from time elapsed since
4171 -- last update.
4172 -- "forget" enemy if hate reaches zero or if no update has been
4173 -- received for a given time.
4174 -- --------------------------------------------------------------------------------------
4175 function SkM_ForgetPlayerHate()
4176 local FName = "SkM_ForgetPlayerHate";
4177  
4178 local curTime = GetTime();
4179  
4180 for sName, Enemy in SKM_Context.PlayerCombat do
4181  
4182 if (curTime - Enemy[_SKM._lastUpdate] > SKM_Config.ForgetAggressorTimer) then
4183 -- no update since given time interval, forget, whatever the hate level may be
4184 SKM_Context.PlayerCombat[sName] = nil;
4185 else
4186 -- don't forget, but reduce hate from time elapsed
4187 local iTime = curTime - Enemy[_SKM._lastHateUpdate];
4188  
4189 nHateReduction = Enemy[_SKM._hateLevel] * (iTime / 100) * SKM_Config.HateReductionCoeff;
4190  
4191 SKM_Context.PlayerCombat[sName][_SKM._hateLevel] = Enemy[_SKM._hateLevel] - nHateReduction;
4192 SKM_Context.PlayerCombat[sName][_SKM._lastHateUpdate] = curTime;
4193  
4194 -- if hate is reduced to zero (or less), forget
4195 if (SKM_Context.PlayerCombat[sName][_SKM._hateLevel] <= 0) then
4196 SKM_Context.PlayerCombat[sName] = nil;
4197 end
4198 end
4199 end
4200  
4201 end
4202  
4203  
4204 -- --------------------------------------------------------------------------------------
4205 -- SkM_LogDamage_OnSelf
4206 -- --------------------------------------------------------------------------------------
4207 -- Keep track of damage done on self and update "hate level" associated to the damage
4208 -- dealer.
4209 -- --------------------------------------------------------------------------------------
4210 function SkM_LogDamage_OnSelf(iDamage, sName, EnemyType)
4211 local FName = "SkM_LogDamage_OnSelf";
4212  
4213 local curTime = GetTime();
4214  
4215 SkM_ForgetPlayerHate();
4216  
4217 if (not SKM_Context.PlayerCombat[sName]) then
4218 SKM_Context.PlayerCombat[sName] = { };
4219 SKM_Context.PlayerCombat[sName][_SKM._name] = sName;
4220 SKM_Context.PlayerCombat[sName][_SKM._enemyType] = EnemyType;
4221 SKM_Context.PlayerCombat[sName][_SKM._hateLevel] = 0;
4222 SKM_Context.PlayerCombat[sName][_SKM._damage] = 0;
4223 SKM_Context.PlayerCombat[sName][_SKM._lastHateUpdate] = curTime;
4224 SKM_Context.PlayerCombat[sName][_SKM._lastUpdate] = curTime;
4225 end
4226  
4227 -- store enemy type if we have it now and it was not previously stored
4228 if (not SKM_Context.PlayerCombat[sName][_SKM._enemyType]) and (EnemyType ~= nil) then
4229 SKM_Context.PlayerCombat[sName][_SKM._enemyType] = EnemyType;
4230 end
4231  
4232 SKM_Context.PlayerCombat[sName][_SKM._damage] = SKM_Context.PlayerCombat[sName][_SKM._damage] + iDamage;
4233 SKM_Context.PlayerCombat[sName][_SKM._hateLevel] = SKM_Context.PlayerCombat[sName][_SKM._hateLevel] + iDamage;
4234  
4235 SkM_Trace(FName, 3, "PlayerCombat updated for "..sName.." : damage = ".. SKM_Context.PlayerCombat[sName][_SKM._damage] ..", hate level = ".. SKM_Context.PlayerCombat[sName][_SKM._hateLevel]);
4236 end
4237  
4238  
4239 -- --------------------------------------------------------------------------------------
4240 -- SkM_HateList_Dump
4241 -- --------------------------------------------------------------------------------------
4242 -- Debug function. Dump content of "PlayerCombat" (hate list).
4243 -- --------------------------------------------------------------------------------------
4244 function SkM_HateList_Dump()
4245 local FName = "SkM_HateList_Dump";
4246  
4247 local curTime = GetTime();
4248  
4249  
4250 SkM_ForgetPlayerHate();
4251  
4252 for idx, Elem in SKM_Context.PlayerCombat do
4253 local iTime = math.ceil(curTime - Elem[_SKM._lastUpdate]);
4254 local sReport = Elem[_SKM._name].." (last update : "..iTime.." s ago) -> damage = "..Elem[_SKM._damage]..", hate = "..Elem[_SKM._hateLevel];
4255  
4256 SkM_ChatMessageCol(sReport);
4257 end
4258 end
4259  
4260  
4261 -- --------------------------------------------------------------------------------------
4262 -- SkM_SortPlayerCombat_ByHate
4263 -- --------------------------------------------------------------------------------------
4264 -- Sort "PlayerCombat" list by hate level.
4265 -- --------------------------------------------------------------------------------------
4266 function SkM_SortPlayerCombat_ByHate(e1, e2)
4267 if (not e2[_SKM._hateLevel]) then
4268 return true;
4269 end
4270 if (not e1[_SKM._hateLevel]) then
4271 return false;
4272 end
4273 return (e1[_SKM._hateLevel] > e2[_SKM._hateLevel]);
4274 end
4275  
4276  
4277 -- --------------------------------------------------------------------------------------
4278 -- SkM_PlayerDeathResp
4279 -- --------------------------------------------------------------------------------------
4280 -- Find who is responsible for your death, if any. This is the most hated enemy player
4281 -- or creature from "PlayerCombat" list.
4282 -- Also reset hate list afterwards.
4283 -- --------------------------------------------------------------------------------------
4284 function SkM_PlayerDeathResp()
4285 local FName = "SkM_PlayerDeathResp";
4286  
4287 SkM_ForgetPlayerHate();
4288  
4289 local HateList = {};
4290 local EnemyName, EnemyType;
4291 local iTotal = 0;
4292  
4293 local idx, val;
4294 for idx, val in SKM_Context.PlayerCombat do
4295 local Elem = copytable(val);
4296 iTotal = iTotal + Elem[_SKM._hateLevel];
4297 table.insert(HateList, Elem);
4298 end
4299  
4300 table.sort(HateList, SkM_SortPlayerCombat_ByHate);
4301  
4302 if (table.getn(HateList) > 0) then
4303 EnemyName = HateList[1][_SKM._name];
4304 EnemyType = HateList[1][_SKM._enemyType];
4305 end
4306  
4307 for idx, val in HateList do
4308 val[_SKM._hatePercent] = math.floor(100 * val[_SKM._hateLevel] / iTotal);
4309 end
4310  
4311 SkM_Trace(FName, 2, "Most hated = "..snil(EnemyName)..", type = "..snil(EnemyType));
4312  
4313 SKM_Context.PlayerCombat = { };
4314  
4315 return EnemyName, EnemyType, HateList;
4316 end
4317  
4318  
4319 -- --------------------------------------------------------------------------------------
4320 -- SkM_DumpEnemyCombat
4321 -- --------------------------------------------------------------------------------------
4322 -- Debug function. Dump content of "EnemyCombat" list.
4323 -- --------------------------------------------------------------------------------------
4324 function SkM_DumpEnemyCombat()
4325 local FName = "SkM_DumpEnemyCombat";
4326 local curTime = GetTime();
4327  
4328 for idx, val in SKM_Context.EnemyCombat do
4329 local iTime = math.ceil(curTime - val[_SKM._lastUpdate]);
4330  
4331 sReport = val[_SKM._name] .. " (last update : "..iTime.." s ago) -> total damage = ".. val[_SKM._totalDamage] .. ", group damage = " .. val[_SKM._groupDamage];
4332 SkM_ChatMessageCol(sReport);
4333 end
4334 end
4335  
4336  
4337 -- --------------------------------------------------------------------------------------
4338 -- SkM_IsLeapYear
4339 -- --------------------------------------------------------------------------------------
4340 -- Is given year a leap year ?
4341 -- --------------------------------------------------------------------------------------
4342 function SkM_IsLeapYear(iYear)
4343 return intable(iYear, LeapYears);
4344 end
4345  
4346  
4347 -- --------------------------------------------------------------------------------------
4348 -- SkM_DaysInYear
4349 -- --------------------------------------------------------------------------------------
4350 -- Return number of days in given year
4351 -- --------------------------------------------------------------------------------------
4352 function SkM_DaysInYear(iYear)
4353 if (SkM_IsLeapYear(iYear)) then
4354 return 366;
4355 else
4356 return 365;
4357 end
4358 end
4359  
4360  
4361 -- --------------------------------------------------------------------------------------
4362 -- SkM_DaysInMonth
4363 -- --------------------------------------------------------------------------------------
4364 -- Return number of days in given month of a given year
4365 -- --------------------------------------------------------------------------------------
4366 function SkM_DaysInMonth(iMonth, iYear)
4367 local iDays = DaysInMonth[iMonth];
4368 if (iMonth == 2) and SkM_IsLeapYear(iYear) then
4369 iDays = 29;
4370 end
4371 return iDays;
4372 end
4373  
4374  
4375 -- --------------------------------------------------------------------------------------
4376 -- SkM_TimeSinceEpoch
4377 -- --------------------------------------------------------------------------------------
4378 -- Return the number of seconds since "epoch", fixed at 01/01/2004 00:00:00.
4379 -- (we do not need to handle time periods prior to WoW release, so this does not need
4380 -- to be less than this time)
4381 -- --------------------------------------------------------------------------------------
4382 function SkM_TimeSinceEpoch(sDate)
4383 local FName = "SkM_TimeSinceEpoch";
4384  
4385 SkM_Trace(FName, 3, "Date = "..snil(sDate));
4386  
4387 local iDay, iMonth, iYear, iHour, iMin, iSec;
4388  
4389 iDay = tonumber( string.sub(sDate, 1, 2) );
4390 iMonth = tonumber( string.sub(sDate, 4, 5) );
4391 iYear = tonumber( string.sub(sDate, 7, 10) ) ;
4392  
4393 iHour = tonumber( string.sub(sDate, 12, 13) );
4394 iMin = tonumber( string.sub(sDate, 15, 16) );
4395 iSec = tonumber( string.sub(sDate, 18, 19) );
4396  
4397 if (iDay == nil) or (iMonth == nil) or (iYear == nil) or (iHour == nil) or (iMin == nil) or (iSec == nil) then
4398 return nil;
4399 end
4400  
4401 local iTime = 0;
4402  
4403 iIndYear = 2004;
4404 while (iIndYear < iYear) do
4405 iTime = iTime + SkM_DaysInYear(iIndYear); iIndYear = iIndYear + 1;
4406 end
4407  
4408 iIndMonth = 1;
4409 while (iIndMonth < iMonth) do
4410 iTime = iTime + SkM_DaysInMonth(iIndMonth, iYear); iIndMonth = iIndMonth + 1;
4411 end
4412  
4413 iTime = (iTime + (iDay - 1)) * 24;
4414 iTime = (iTime + (iHour - 1)) * 60;
4415 iTime = (iTime + (iMin - 1)) * 60;
4416 iTime = iTime + iSec;
4417  
4418 SkM_Trace(FName, 3, "Sec num since 01/01/2004 = "..snil(iTime));
4419 return iTime;
4420 end
4421  
4422  
4423 -- --------------------------------------------------------------------------------------
4424 -- SkM_DiffDate
4425 -- --------------------------------------------------------------------------------------
4426 -- Return the difference in seconds between two dates in format DD/MM/YYYY HH:MI:SS
4427 -- --------------------------------------------------------------------------------------
4428 function SkM_DiffDate(sDate1, sDate2)
4429 local FName = "SkM_DiffDate";
4430  
4431 if (sDate1 == nil) or (sDate2 == nil) then
4432 return nil;
4433 end
4434  
4435 local iTime1, iTime2, iTime;
4436  
4437 iTime1 = SkM_TimeSinceEpoch(sDate1);
4438 iTime2 = SkM_TimeSinceEpoch(sDate2);
4439  
4440 if (iTime1 == nil) or (iTime2 == nil) then
4441 return nil;
4442 end
4443  
4444 iTime = iTime1 - iTime2;
4445 SkM_Trace(FName, 3, "Time difference = "..snil(iTime));
4446 return iTime;
4447 end
4448  
4449  
4450 -- --------------------------------------------------------------------------------------
4451 -- SkM_SetTargetInfoText
4452 -- --------------------------------------------------------------------------------------
4453 -- Set a line of text of SKMapTargetInfoButton
4454 -- --------------------------------------------------------------------------------------
4455 function SkM_SetTargetInfoText(id, sLabel, sValue, sDetail)
4456 local FName = "SkM_SetTargetInfoText";
4457  
4458 local TextLabe, ValueLabel, DetailLabel;
4459 if (sLabel) then
4460 TextLabel = getglobal("SKMapTargetInfoButton"..id.."Label");
4461 if (not TextLabel) then return false; end
4462 end
4463 if (sValue) then
4464 ValueLabel = getglobal("SKMapTargetInfoButton"..id.."Value");
4465 if (not ValueLabel) then return false; end
4466 end
4467 if (sDetail) then
4468 DetailLabel = getglobal("SKMapTargetInfoButton"..id.."Detail");
4469 if (not DetailLabel) then return false; end
4470 end
4471  
4472 if (sLabel) then
4473 TextLabel:SetText(sLabel);
4474 end
4475 if (sValue) then
4476 ValueLabel:SetText(sValue);
4477 end
4478 if (sDetail) then
4479 DetailLabel:SetText(sDetail);
4480 end
4481  
4482 return true;
4483 end
4484  
4485  
4486 -- --------------------------------------------------------------------------------------
4487 -- SkM_SetSmallTargetInfoText
4488 -- --------------------------------------------------------------------------------------
4489 -- Set a line of text of SKMapSmallTargetInfoButton
4490 -- --------------------------------------------------------------------------------------
4491 function SkM_SetSmallTargetInfoText(id, sLabel, sValue)
4492 local FName = "SkM_SetTargetInfoText";
4493  
4494 local TextLabe, ValueLabel;
4495 if (sLabel) then
4496 TextLabel = getglobal("SKMapSmallTargetInfoButton"..id.."Label");
4497 if (not TextLabel) then return false; end
4498 end
4499 if (sValue) then
4500 ValueLabel = getglobal("SKMapSmallTargetInfoButton"..id.."Value");
4501 if (not ValueLabel) then return false; end
4502 end
4503  
4504 if (sLabel) then
4505 TextLabel:SetText(sLabel);
4506 end
4507 if (sValue) then
4508 ValueLabel:SetText(sValue);
4509 end
4510  
4511 return true;
4512 end
4513  
4514  
4515 -- --------------------------------------------------------------------------------------
4516 -- SkM_ShowTargetGuildInfo
4517 -- --------------------------------------------------------------------------------------
4518 -- Display or hide guild info mini frame
4519 -- --------------------------------------------------------------------------------------
4520 function SkM_ShowTargetGuildInfo(bShow, sGuildName, bGuildWar)
4521  
4522 if (not SkM_GetOption("ShowTargetGuildInfo")) then
4523 SKMapTargetGuildInfo:Hide();
4524 else
4525 if (bShow ~= true) or (sGuildName == nil) or (sGuildName == "") then
4526 SKMapTargetGuildInfo:Hide();
4527 else
4528 local id=1;
4529 TextValue = getglobal("SKMapTargetGuildInfoButton"..id.."Value");
4530  
4531 local sText;
4532 if (bGuildWar) then
4533 sText = SKM_Config.Col_PlayerWar;
4534 else
4535 sText = SKM_Config.Col_Label;
4536 end
4537 sText = sText..sGuildName;
4538 TextValue:SetText(sText);
4539  
4540 SKMapTargetGuildInfo:Show();
4541 end
4542 end
4543 end
4544  
4545  
4546 -- --------------------------------------------------------------------------------------
4547 -- SkM_ShowTargetClassInfo
4548 -- --------------------------------------------------------------------------------------
4549 -- Display or hide class info mini frame
4550 -- --------------------------------------------------------------------------------------
4551 function SkM_ShowTargetClassInfo(bShow, sClass)
4552  
4553 if (not SkM_GetOption("ShowTargetClassInfo")) then
4554 SKMapTargetClassInfo:Hide();
4555 else
4556 if (bShow ~= true) or (sClass == nil) or (sClass == "") then
4557 SKMapTargetClassInfo:Hide();
4558 else
4559 local id=1;
4560 TextValue = getglobal("SKMapTargetClassInfoButton"..id.."Value");
4561  
4562 sText = SKM_Config.Col_Label;
4563 sText = sText..sClass;
4564 TextValue:SetText(sText);
4565  
4566 SKMapTargetClassInfo:Show();
4567 end
4568 end
4569  
4570 end
4571  
4572  
4573 -- --------------------------------------------------------------------------------------
4574 -- SkM_SetTargetInfo
4575 -- --------------------------------------------------------------------------------------
4576 -- Fill and display or hidel TargetInfo frame(s) according to current target
4577 -- --------------------------------------------------------------------------------------
4578 function SkM_SetTargetInfo()
4579 local FName = "SkM_SetTargetInfo";
4580  
4581 local sName = SkM_UnitName(SKM_UNIT_TARGET);
4582 --local sName = "Abaddon";
4583 if (not sName) then
4584 -- no target
4585 SkM_HideTargetInfoFrame();
4586 SkM_ShowTargetGuildInfo(false, nil, nil);
4587 SkM_ShowTargetClassInfo(false, nil);
4588 SkM_SetWarDragon(false, false);
4589 return false;
4590 end
4591  
4592 local sClass = UnitClass(SKM_UNIT_TARGET);
4593  
4594 if (SkM_UnitIsEnemyPlayer(SKM_UNIT_TARGET)) then
4595 --if (true) then
4596  
4597 local bWar = false;
4598 local bGuildWar = false;
4599  
4600 local Enemy = SKM_Data[_RealmName][_PlayerName].EnemyHistory[sName];
4601 if (not Enemy) then
4602 SkM_HideTargetInfoFrame();
4603 SkM_SetWarDragon(false, false);
4604 return false;
4605 end
4606  
4607 -- 09/04/2005 17:23:14 PIng Add guild support
4608 local sGuildName = Enemy[_SKM._guild];
4609 if (sGuildName == "") then sGuildName = nil; end
4610 local Guild = SKM_Data[_RealmName][_PlayerName].GuildHistory[sGuildName];
4611 -- 09/04/2005 17:24:33 End of modification
4612  
4613 if (Enemy[_SKM._atWar]) then
4614 bWar = true;
4615 end
4616 if (Guild) and (Guild[_SKM._atWar]) then
4617 bGuildWar = true;
4618 end
4619  
4620 SkM_ShowTargetGuildInfo(true, sGuildName, bGuildWar);
4621 SkM_ShowTargetClassInfo(true, sClass);
4622  
4623 local iKill = ifnil(Enemy[_SKM._playerKill], 0);
4624 local iAssistKill = ifnil(Enemy[_SKM._playerAssistKill], 0);
4625 local iFullKill = ifnil(Enemy[_SKM._playerFullKill], 0);
4626 local iTotalKill = iKill + iAssistKill + iFullKill;
4627 local iHonorKill = ifnil(Enemy[_SKM._honorKill], 0);
4628  
4629 local iRemaining = SkM_GetHonorRemainingKills(sName);
4630  
4631 -- 09/04/2005 17:25:03 PIng Add guild support
4632 local gKill = "";
4633 local gAssistKill = "";
4634 local gFullKill = "";
4635 local gTotalKill = "";
4636 local gDeath = "";
4637 local gMet = "";
4638 if (sGuildName ~= nil) then
4639 gKill = ifnil(Guild[_SKM._playerKill], 0);
4640 gAssistKill = ifnil(Guild[_SKM._playerAssistKill], 0);
4641 gFullKill = ifnil(Guild[_SKM._playerFullKill], 0);
4642 gTotalKill = gKill + gAssistKill + gFullKill;
4643 gDeath = ifnil(Guild[_SKM._enemyKillPlayer], 0);
4644 gMet = ifnil(Guild[_SKM._meetCount], 0);
4645 end
4646 -- 09/04/2005 17:25:12 End of modification
4647  
4648 local iDeath = ifnil(Enemy[_SKM._enemyKillPlayer], 0);
4649 local iMet = ifnil(Enemy[_SKM._meetCount], 0);
4650  
4651 SkM_Trace(FName, 3, "Kill = "..iKill..", AssistKill = "..iAssistKill..", FullKill = "..iFullKill..", Met = "..iMet);
4652 -- 09/04/2005 17:25:03 PIng Add guild support
4653 if (sGuildName ~= nil) then
4654 SkM_Trace(FName, 3, "Guild Kill = "..gKill..", Guild AssistKill = "..gAssistKill..", Guild FullKill = "..gFullKill..", Guild Met = "..gMet);
4655 end
4656 -- 09/04/2005 17:25:12 End of modification
4657  
4658 local sKill = SKM_Config.Col_PlayerTotalKill .. iTotalKill;
4659 local sKillDetail;
4660 -- only display detail kill count if there's at least one kill
4661 -- if (iTotalKill == 0) then
4662 -- sKillDetail = "";
4663 -- else
4664 -- sKillDetail = SKM_Config.Col_Label .. "( " .. SKM_Config.Col_PlayerFullKill .. iFullKill .. SKM_Config.Col_Label .. " + " .. SKM_Config.Col_PlayerKill .. iKill .. SKM_Config.Col_Label .. " + " .. SKM_Config.Col_PlayerAssistKill .. iAssistKill .. SKM_Config.Col_Label .. " )";
4665 -- end
4666  
4667 sKillDetail = SKM_UI_STRINGS.Small_Target_Honor..SKM_Config.Col_HonorKill..iHonorKill.." ";
4668 --local FrameColor;
4669 local LabelColor;
4670 if (iRemaining == 0) then
4671  
4672 sKillDetail = sKillDetail..SKM_Config.Col_Label.."( "..SKM_Config.Col_Honorless..SKM_UI_STRINGS.Small_Target_NoHonor..SKM_Config.Col_Label.." )";
4673 --FrameColor = { r = 0.0, g = 0.0, b = 0.0 };
4674 LabelColor = SKM_Config.Col_LabelTitle;
4675 else
4676 sKillDetail = sKillDetail..SKM_Config.Col_Label.."( "..SKM_Config.Col_HonorKill..iRemaining..SKM_Config.Col_Label.." )";
4677 --FrameColor = { r = 0.3, g = 1.0, b = 1.0 };
4678 LabelColor = SKM_Config.Col_HonorKill;
4679 end
4680  
4681 local sDeath = SKM_Config.Col_PlayerDeath .. iDeath;
4682 local sMet = SKM_Config.Col_PlayerMet .. iMet;
4683  
4684 local sWar1 = "";
4685 local sWar2 = "";
4686  
4687 if (Enemy[_SKM._atWar] == true) then
4688 sWar1 = SKM_Config.Col_PlayerWar.. SKM_UI_STRINGS.Small_Target_War;
4689 sWar2 = "";
4690 if (Enemy[_SKM._warDate]) then
4691 local sDisplayDate = string.sub(Enemy[_SKM._warDate], 1, 10);
4692 sWar2 = SKM_Config.Col_PlayerWar .. SKM_UI_STRINGS.Since .. sDisplayDate;
4693 end
4694 end
4695  
4696 local bRes1, bRes2, bRes3, bRes4;
4697  
4698 if (SkM_GetOption("SmallTargetInfo")) then
4699 bRes1 = SkM_SetSmallTargetInfoText(1, LabelColor..SKM_UI_STRINGS.Small_Target_Info_Kill, sKill);
4700 bRes2 = SkM_SetSmallTargetInfoText(2, SKM_UI_STRINGS.Small_Target_Info_Death, sDeath);
4701 bRes3 = SkM_SetSmallTargetInfoText(3, SKM_UI_STRINGS.Small_Target_Info_Met, sMet);
4702 bRes4 = SkM_SetSmallTargetInfoText(4, sWar1);
4703 else
4704 bRes1 = SkM_SetTargetInfoText(1, SKM_UI_STRINGS.Small_Target_Info_Kill, sKill, sKillDetail);
4705 bRes2 = SkM_SetTargetInfoText(2, SKM_UI_STRINGS.Small_Target_Info_Death, sDeath, "");
4706 bRes3 = SkM_SetTargetInfoText(3, SKM_UI_STRINGS.Small_Target_Info_Met, sMet, "");
4707 bRes4 = SkM_SetTargetInfoText(4, sWar1, "", sWar2);
4708 end
4709  
4710 SkM_ShowTargetFrameWarButtons(Enemy[_SKM._atWar]);
4711  
4712 SkM_SetWarDragon(bWar, bGuildWar);
4713  
4714 if (bRes1 and bRes2 and bRes3 and bRes4) then
4715 SkM_ShowTargetInfoFrame();
4716 return true;
4717 else
4718 SkM_HideTargetInfoFrame();
4719 return false;
4720 end
4721  
4722 else
4723 SkM_HideTargetInfoFrame();
4724 SkM_SetWarDragon(false, false);
4725  
4726 if (UnitIsPlayer(SKM_UNIT_TARGET)) then
4727 local sGuildName = GetGuildInfo(SKM_UNIT_TARGET);
4728 SkM_ShowTargetGuildInfo(true, sGuildName, false);
4729 SkM_ShowTargetClassInfo(true, sClass);
4730 else
4731 SkM_ShowTargetGuildInfo(false, nil, nil);
4732 SkM_ShowTargetClassInfo(false, nil);
4733 end
4734  
4735  
4736  
4737 -- if we switch from a player dragon to an elite mob, we must keep the "elite" frame !
4738 --if (UnitIsPlusMob(SKM_UNIT_TARGET)) then
4739 local sUnitClassification = UnitClassification(SKM_UNIT_TARGET);
4740 if (UnitIsPlusMob(SKM_UNIT_TARGET))
4741 or ( (sUnitClassification ~= nil) and (sUnitClassification ~= "") and (sUnitClassification ~= "normal") )
4742 then
4743 TargetFrameTexture:SetTexture("Interface\\TargetingFrame\\UI-TargetingFrame-Elite");
4744 end
4745  
4746 return false;
4747 end
4748  
4749 end
4750  
4751  
4752 -- --------------------------------------------------------------------------------------
4753 -- SkM_SetWarDragon
4754 -- --------------------------------------------------------------------------------------
4755 -- Display or hide the red "elite dragon" around target portrait.
4756 -- If this enemy or his guild is set "at war", then the dragon is shown
4757 -- Otherwise, color is reset and the "elite dragon" is hidden
4758 -- --------------------------------------------------------------------------------------
4759 function SkM_SetWarDragon(bWar, bGuildWar)
4760 local FName = "SkM_SetWarDragon";
4761  
4762 if (bWar) or (bGuildWar) then
4763 --Set Red Dragon Overlay on Texture to Target
4764 TargetFrameTexture:SetVertexColor(1.0, 200.0, 1.0, TargetFrameTexture:GetAlpha());
4765 TargetFrameTexture:SetTexture("Interface\\TargetingFrame\\UI-TargetingFrame-Elite");
4766  
4767 else
4768 -- not at war with target
4769 TargetFrameTexture:SetVertexColor(1.0, 1.0, 1.0, TargetFrameTexture:GetAlpha());
4770 TargetFrameTexture:SetTexture("Interface\\TargetingFrame\\UI-TargetingFrame");
4771 end
4772 end
4773  
4774  
4775 -- --------------------------------------------------------------------------------------
4776 -- SkM_EnemyWar
4777 -- --------------------------------------------------------------------------------------
4778 -- Declare war to an enemy player, or call a truce with this player
4779 -- --------------------------------------------------------------------------------------
4780 function SkM_EnemyWar(bWar, sEnemyName)
4781 local FName = "SkM_EnemyWar";
4782  
4783 SkM_Trace(FName, 3, "War button pressed");
4784  
4785 local sName;
4786 if (sEnemyName) then
4787 sName = sEnemyName;
4788 else
4789 local sTargetName = SkM_UnitName(SKM_UNIT_TARGET);
4790 sName = sTargetName;
4791 end
4792  
4793 if (not sName) then
4794 SkM_Trace(FName, 1, "No enemy specified");
4795 return;
4796 end
4797  
4798 local Enemy = SKM_Data[_RealmName][_PlayerName].EnemyHistory[sName];
4799 if (not Enemy) then
4800 SkM_Trace(FName, 1, "Enemy not found : "..snil(sName));
4801 return;
4802 end
4803  
4804 local sGuildName = Enemy[_SKM._guild];
4805 local Guild;
4806 local bGuildWar = false;
4807 if (sGuildName) and (sGuildName ~= "") then
4808 Guild = SKM_Data[_RealmName][_PlayerName].GuildHistory[sGuildName];
4809 end
4810 if (Guild) and (Guild[_SKM._atWar]) then
4811 bGuildWar = true;
4812 end
4813  
4814 local sDate = SkM_GetDate();
4815  
4816 SkM_UpdateEnemy_SetWar(sName, bWar, sDate);
4817  
4818 SkM_ShowTargetFrameWarButtons(Enemy[_SKM._atWar]);
4819  
4820 -- 09/04/2005 16:18:34 PIng: Update war info on target frame when status is changed
4821 local sWar1 = "";
4822 local sWar2 = "";
4823  
4824 if (Enemy[_SKM._atWar] == true) then
4825 sWar1 = SKM_Config.Col_PlayerWar.. SKM_UI_STRINGS.Small_Target_War;
4826 sWar2 = "";
4827 if (Enemy[_SKM._warDate]) then
4828 local sDisplayDate = string.sub(Enemy[_SKM._warDate], 1, 10);
4829 sWar2 = SKM_Config.Col_PlayerWar .. SKM_UI_STRINGS.Since .. sDisplayDate;
4830 end
4831 end
4832  
4833 local bRes4;
4834  
4835 if (SkM_GetOption("SmallTargetInfo")) then
4836 bRes4 = SkM_SetSmallTargetInfoText(4, sWar1);
4837 else
4838 bRes4 = SkM_SetTargetInfoText(4, sWar1, "", sWar2);
4839 end
4840 -- 09/04/2005 16:18:31 End of modification
4841  
4842 if (sName == sTargetName) then
4843 SkM_SetWarDragon(bWar, bGuildWar);
4844 end
4845 end
4846  
4847  
4848 -- --------------------------------------------------------------------------------------
4849 -- SkM_UnknownEnemyWar
4850 -- --------------------------------------------------------------------------------------
4851 -- Declare war to an enemy player that can is potentially not known yet
4852 -- --------------------------------------------------------------------------------------
4853 function SkM_UnknownEnemyWar(sName, bWar, bDisplay)
4854 local FName = "SkM_UnknownEnemyWar";
4855  
4856  
4857 SkM_Trace(FName, 3, "Enemy player = "..snil(sName));
4858  
4859 local sDate = SkM_GetDate();
4860  
4861 if (sName) then
4862 local Enemy = SKM_Data[_RealmName][_PlayerName].EnemyHistory[sName];
4863 if (Enemy) then
4864 local bWarPrev = Enemy[_SKM._atWar];
4865 SkM_UpdateEnemy_SetWar(sName, bWar, sDate);
4866 if (bDisplay) then
4867 if (bWar) and (not bWarPrev) then
4868 SkM_ChatMessageCol("Now at WAR with "..sName);
4869 elseif (not bWar) and (bWarPrev) then
4870 SkM_ChatMessageCol("No longer at WAR with "..sName);
4871 end
4872 end
4873  
4874 -- update target info if needed
4875 SkM_SetTargetInfo();
4876  
4877 -- update interface enemy list if needed
4878 local bVisible, sFrame = SKMap_IsUIVisible();
4879  
4880 if (bVisible) and (sFrame == "SKMap_ListFrame") and (SKM_List_ActiveList == _SKM._players) then
4881 SKMap_ListFrame_UpdateList();
4882 if (SKM_List_SelectedPlayer) then
4883 SKMap_ListFrame_ShowWarButton(bWar);
4884 end
4885 end
4886 if (SKM_List_ActiveList == _SKM._players) and (SKM_List_SelectedPlayer) then
4887 SKMap_ListFrame_SelectElement(SKM_List_SelectedPlayer);
4888 end
4889  
4890 else
4891 -- unknown enemy
4892 if (bWar) then
4893 SKM_Data[_RealmName][_PlayerName].UnknownEnemy[sName] = 1;
4894 if (bDisplay) then
4895 SkM_ChatMessageCol("Now at WAR with "..sName.." (not yet known)");
4896 end
4897 else
4898 if (SKM_Data[_RealmName][_PlayerName].UnknownEnemy[sName]) then
4899 SKM_Data[_RealmName][_PlayerName].UnknownEnemy[sName] = nil;
4900 if (bDisplay) then
4901 SkM_ChatMessageCol("No longer at WAR with "..sName.." (not yet known)");
4902 end
4903 end
4904 end
4905  
4906 end
4907  
4908 end
4909 end
4910  
4911  
4912 function SkM_ShowUnknownEnemyWar()
4913 local sMsg = "";
4914 local iCount = 0;
4915  
4916 local idx, val;
4917 for idx, val in SKM_Data[_RealmName][_PlayerName].UnknownEnemy do
4918 sMsg = sMsg..idx.." ";
4919 iCount = iCount + 1;
4920 end
4921  
4922 if (iCount == 0) then
4923 SkM_ChatMessageCol("Unknown players WAR list is empty");
4924 else
4925 SkM_ChatMessageCol("Unknown players WAR list ("..iCount..") :");
4926 SkM_ChatMessageCol(sMsg);
4927 end
4928  
4929 end
4930  
4931  
4932 function SkM_ClearUnknownEnemyWar()
4933 SKM_Data[_RealmName][_PlayerName].UnknownEnemy = { };
4934 SkM_ChatMessageCol("Unknown players WAR list cleared");
4935 end
4936  
4937  
4938 function SkM_FindSharedEnemyWar(sName)
4939 local FName = "SkM_FindSharedEnemyWar";
4940  
4941 -- parse all characters of the same realm
4942 local idx_char, val_char;
4943 for idx_char, val_char in SKM_Data[_RealmName] do
4944 if (SKM_Data[_RealmName][idx_char].PlayerName == idx_char) then
4945 local Enemy = SKM_Data[_RealmName][idx_char].EnemyHistory[sName];
4946  
4947 -- if enemy known to this player, and set "at war", return him
4948 if (Enemy) and (Enemy[_SKM._atWar]) then
4949 return Enemy, idx_char;
4950 end
4951 end
4952 end
4953  
4954 end
4955  
4956  
4957 -- --------------------------------------------------------------------------------------
4958 -- SkM_MouseOverUnit
4959 -- --------------------------------------------------------------------------------------
4960 -- Handle "mouseover unit" event.
4961 -- If that unit is an enemy player that is "at war", or whose guild is "at war" :
4962 -- Display floating message (if configured)
4963 -- Play warning sound (if configured)
4964 -- If unit is an unknown enemy and we have no current target, target him to store
4965 -- information, then clear target again.
4966 -- --------------------------------------------------------------------------------------
4967 function SkM_MouseOverUnit()
4968 local FName = "SkM_MouseOverUnit";
4969  
4970 local sDate = SkM_GetDate();
4971  
4972 -- store information related to mouse-overed unit
4973 SkM_MouseOverUnitData();
4974  
4975 if (SkM_UnitIsEnemyPlayer(SKM_UNIT_MOUSEOVER)) then
4976 -- if (true) then
4977 -- Grab the name of who we've moused-over
4978 local sName = SkM_UnitName(SKM_UNIT_MOUSEOVER);
4979 --local sName = "Ledieu";
4980 if (not sName) then
4981 return;
4982 end
4983  
4984 local sGuildName = GetGuildInfo(SKM_UNIT_MOUSEOVER);
4985  
4986 local bWar = false;
4987 local bGuildWar = false;
4988 local bSharedWar = false;
4989  
4990 local Enemy = SKM_Data[_RealmName][_PlayerName].EnemyHistory[sName];
4991 local SharedEnemy, SharedChar;
4992 local Guild;
4993  
4994 if (Enemy) and (Enemy[_SKM._atWar]) then
4995 bWar = true;
4996 end
4997  
4998 if (sGuildName ~= nil) and (sGuildName ~= "") then
4999 Guild = SKM_Data[_RealmName][_PlayerName].GuildHistory[sGuildName];
5000 if (Guild ~= nil) and (Guild[_SKM._atWar]) then
5001 bGuildWar = true;
5002 end
5003 end
5004  
5005 if not (bWar or bGuildWar) then
5006 if (SkM_GetOption("SharedWarMode")) then
5007 SharedEnemy, SharedChar = SkM_FindSharedEnemyWar(sName);
5008 if (SharedEnemy) and (SharedEnemy[_SKM._atWar]) then
5009 bSharedWar = true;
5010 end
5011 end
5012 end
5013  
5014 if (bWar) or (bGuildWar) or (bSharedWar) then
5015 local bFilter = false;
5016  
5017 if (SkM_GetOption("WarEnableFilter")) then
5018 -- check against global "last warning date"
5019 if (SKM_Context.LastWarWarning) then
5020 local iDiffTime = SkM_DiffDate(sDate, SKM_Context.LastWarWarning);
5021 if (iDiffTime ~= nil) and (iDiffTime <= SkM_GetOption("WarFilterDelay")) then
5022 -- Filter out to reduce spam
5023 bFilter = true;
5024 end
5025 end
5026  
5027 end
5028  
5029 -- check against last warning for given enemy
5030 -- (independently of filter option)
5031 if (SkM_GetRecentWarWarning(sName)) then
5032 -- Filter out to reduce spam
5033 bFilter = true;
5034 end
5035  
5036 if (not bFilter) then
5037 SKM_Context.LastWarWarning = sDate;
5038 SkM_AddRecentWarWarning(sName, sDate);
5039  
5040 SkM_Trace(FName, 3, "Last War Warning = "..snil(SKM_Context.LastWarWarning));
5041  
5042 if (SkM_GetOption("WarSoundWarning")) then
5043 --PlaySound("AuctionWindowClose");
5044 PlaySoundFile(SKM_Config.WarSoundFile);
5045 end
5046  
5047 if (SkM_GetOption("WarFloatingMessage")) then
5048 local sWarMessage = "";
5049 if (bWar) and (bGuildWar) then
5050 sWarMessage = sName.." / "..sGuildName;
5051 elseif (bWar) then
5052 sWarMessage = sName;
5053 elseif (bGuildWar) then
5054 sWarMessage = sGuildName;
5055 elseif (bSharedWar) then
5056 sWarMessage = sName..SKM_Config.Col_SharedWar.." ["..SharedChar.."]".."|r";
5057 end
5058 UIErrorsFrame:AddMessage(SKM_UI_STRINGS.War_Floating_Message..sWarMessage, 1.0, 0.0, 0.0, 1.0, UIERRORS_HOLD_TIME);
5059 end
5060  
5061 if (SkM_GetOption("WarChatMessage")) then
5062 local sWarMessage = "";
5063 if (bWar) and (bGuildWar) then
5064 sWarMessage = sName.." / "..sGuildName;
5065 elseif (bWar) then
5066 sWarMessage = sName;
5067 elseif (bGuildWar) then
5068 sWarMessage = sGuildName;
5069 elseif (bSharedWar) then
5070 sWarMessage = sName..SKM_Config.Col_SharedWar.." ["..SharedChar.."]".."|r";
5071 end
5072 if (SkM_GetOption("WarShowNote")) then
5073 if (not bSharedWar) then
5074 if (Enemy) and (Enemy[_SKM._playerNote] ~= nil) and (Enemy[_SKM._playerNote] ~= "") then
5075 sWarMessage = sWarMessage .. SKM_Config.Col_Label.." - " .. SKM_Config.Col_PlayerNote.. Enemy[_SKM._playerNote];
5076 end
5077 else
5078 if (SharedEnemy) and (SharedEnemy[_SKM._playerNote]) and (SharedEnemy[_SKM._playerNote] ~= "") then
5079 sWarMessage = sWarMessage .. SKM_Config.Col_Label.." - " .. SKM_Config.Col_PlayerNote .. SharedEnemy[_SKM._playerNote];
5080 end
5081 end
5082 end
5083 SkM_PrintMessage(SKM_UI_STRINGS.War_Floating_Message..sWarMessage, 1.0, 0.0, 0.0);
5084 end
5085  
5086 end
5087  
5088 if (SkM_GetOption("WarAutoTarget") and (not UnitName(SKM_UNIT_TARGET))) then
5089 TargetByName(sName);
5090 end
5091 end
5092  
5093 -- Add information to tooltip (if option enabled)
5094 if (SkM_GetOption("TooltipTargetInfo")) then
5095 SKMap_TooltipEnemyInfo(sName);
5096 end
5097  
5098 -- Add player note to tooltip (if option enabled)
5099 if (SkM_GetOption("TooltipPlayerNote")) then
5100 SKMap_TooltipEnemyNote(sName);
5101 end
5102  
5103 end
5104  
5105 --if (SkM_GetOption("TooltipTargetInfo")) then
5106 -- SKMap_TooltipEnemyInfo("Ledieu");
5107 --end
5108 --if (SkM_GetOption("TooltipPlayerNote")) then
5109 -- SKMap_TooltipEnemyNote("Ledieu");
5110 --end
5111  
5112  
5113 end
5114  
5115  
5116 -- --------------------------------------------------------------------------------------
5117 -- SkM_ShowTargetInfoFrame
5118 -- --------------------------------------------------------------------------------------
5119 -- Show one of the SKMap TargetInfo frames (small or normal), and hide the other.
5120 -- --------------------------------------------------------------------------------------
5121 function SkM_ShowTargetInfoFrame()
5122 local FName = "SkM_ShowTargetInfoFrame";
5123  
5124 local bShow = SkM_GetOption("ShowTargetInfo");
5125  
5126 if (SkM_GetOption("SmallTargetInfo")) then
5127 SkM_DisplayTargetInfoFrames(false, bShow);
5128 else
5129 SkM_DisplayTargetInfoFrames(bShow, false);
5130 end
5131 end
5132  
5133  
5134 -- --------------------------------------------------------------------------------------
5135 -- SkM_HideTargetInfoFrame
5136 -- --------------------------------------------------------------------------------------
5137 -- Hide both SKMap TargetInfo frames.
5138 -- --------------------------------------------------------------------------------------
5139 function SkM_HideTargetInfoFrame()
5140 local FName = "SkM_HideTargetInfoFrame";
5141  
5142 SkM_DisplayTargetInfoFrames(false, false);
5143 end
5144  
5145  
5146 -- --------------------------------------------------------------------------------------
5147 -- SkM_ShowTargetFrameWarButtons
5148 -- --------------------------------------------------------------------------------------
5149 -- Show/hide war and truce button on the currently active SKMap TargetInfo frame,
5150 -- according to war status.
5151 -- --------------------------------------------------------------------------------------
5152 function SkM_ShowTargetFrameWarButtons(bWar)
5153 local FName = "SkM_ShowTargetFrameWarButtons";
5154  
5155 if (SkM_GetOption("SmallTargetInfo")) then
5156 if (bWar == true) then
5157 SKMapSmallPvPTruceButton:Show();
5158 SKMapSmallPvPWarButton:Hide();
5159 else
5160  
5161 SKMapSmallPvPTruceButton:Hide();
5162 SKMapSmallPvPWarButton:Show();
5163 end
5164  
5165 else
5166 if (bWar == true) then
5167 SKMapPvPTruceButton:Show();
5168 SKMapPvPWarButton:Hide();
5169 else
5170 SKMapPvPTruceButton:Hide();
5171 SKMapPvPWarButton:Show();
5172 end
5173 end
5174  
5175 end
5176  
5177  
5178 -- --------------------------------------------------------------------------------------
5179 -- SkM_DisplayTargetInfoFrames
5180 -- --------------------------------------------------------------------------------------
5181 -- Show or Hide the large or small target info frame
5182 -- --------------------------------------------------------------------------------------
5183 function SkM_DisplayTargetInfoFrames(bLarge, bSmall)
5184 local FName = "SkM_DisplayTargetInfoFrames";
5185  
5186 if (bLarge == true) then
5187 SKMapTargetInfoFrame:Show();
5188 elseif (bLarge == false) then
5189 SKMapTargetInfoFrame:Hide();
5190 end
5191  
5192 if (bSmall == true) then
5193 SKMapSmallTargetInfoFrame:Show();
5194 elseif (bSmall == false) then
5195 SKMapSmallTargetInfoFrame:Hide();
5196 end
5197  
5198 end
5199  
5200  
5201 -- --------------------------------------------------------------------------------------
5202 -- SkM_TargetInfoResize
5203 -- --------------------------------------------------------------------------------------
5204 -- Switch from one size of the SKMap TargetInfo frame to the other
5205 -- --------------------------------------------------------------------------------------
5206 function SkM_TargetInfoResize()
5207 local FName = "SkM_TargetInfoResize";
5208  
5209 SkM_SetOption("SmallTargetInfo", not (SkM_GetOption("SmallTargetInfo")) );
5210  
5211 SkM_SetTargetInfo();
5212 end
5213  
5214  
5215 -- --------------------------------------------------------------------------------------
5216 -- SkM_StoreTargetInfo
5217 -- --------------------------------------------------------------------------------------
5218 -- Store currently targetted creature information.
5219 -- Remember if it's tapped and by who.
5220 -- --------------------------------------------------------------------------------------
5221 function SkM_StoreTargetInfo(sTargetType)
5222 local sName = SkM_UnitName(SKM_UNIT_TARGET);
5223  
5224 if (not sName) then
5225 SKM_Context.TargetInfo = nil;
5226 else
5227 if (not SKM_Context.TargetInfo) or (SKM_Context.TargetInfo[_SKM._name] ~= sName) then
5228 SKM_Context.TargetInfo = { };
5229 SKM_Context.TargetInfo[_SKM._name] = sName;
5230 end
5231  
5232 SKM_Context.TargetInfo[_SKM._type] = sTargetType;
5233  
5234 if (sTargetType == _SKM._enemyCreature) then
5235  
5236 if (UnitIsTapped(SKM_UNIT_TARGET)) then
5237 if (UnitIsTappedByPlayer(SKM_UNIT_TARGET)) then
5238 SKM_Context.TargetInfo[_SKM._owner] = _SKM._player;
5239 else
5240 SKM_Context.TargetInfo[_SKM._owner] = _SKM._other;
5241 end
5242 end
5243  
5244 end
5245  
5246 end
5247 end
5248  
5249  
5250 -- --------------------------------------------------------------------------------------
5251 -- SkM_TargetHealthUpdated
5252 -- --------------------------------------------------------------------------------------
5253 -- Target unit health has changed.
5254 -- If this is a creature and if it just died, record creature kill if need be.
5255 -- If this is a creature and it's still alive, update information.
5256 -- --------------------------------------------------------------------------------------
5257 function SkM_TargetHealthUpdated()
5258 local FName = "SkM_TargetHealthUpdated";
5259  
5260 local sName = SkM_UnitName(SKM_UNIT_TARGET);
5261 if (not sName) then
5262 return;
5263 end
5264  
5265 if (UnitHealth(SKM_UNIT_TARGET) == 0 or UnitIsCorpse(SKM_UNIT_TARGET) or UnitIsDeadOrGhost(SKM_UNIT_TARGET)) then
5266  
5267 -- we use this event to track pve kills for unit currently targetted
5268 -- (player kills are tracked by damage done)
5269  
5270 if (not UnitIsPlayer(SKM_UNIT_TARGET)) then
5271  
5272 -- award kill to player if : we have previously stored the creature information
5273 -- in context, and if it was tapped by player
5274 -- in all cases, clear target info.
5275 if (SKM_Context.TargetInfo) and (SKM_Context.TargetInfo[_SKM._name] == sName) then
5276  
5277 if (SKM_Context.TargetInfo[_SKM._owner] == _SKM._player) then
5278  
5279 SkM_Trace(FName, 3, "Target creature (".. sName ..") kill detected - by player");
5280  
5281 local iLevel = UnitLevel(SKM_UNIT_TARGET);
5282 local bElite = UnitIsPlusMob(SKM_UNIT_TARGET);
5283 local sClassification = UnitClassification(SKM_UNIT_TARGET);
5284  
5285 SkM_RecordCreatureKill_Target(sName, iLevel, sClassification);
5286 else
5287 SkM_Trace(FName, 3, "Target creature (".. sName ..") kill detected, but by other");
5288 end
5289 end
5290  
5291 elseif (SkM_UnitIsEnemyPlayer(SKM_UNIT_TARGET)) then
5292 SkM_Trace(FName, 2, "Enemy player death detected (from target) : "..snil(sName));
5293 SkM_PvpEnemyDeath(sName);
5294 end
5295  
5296 SKM_Context.TargetInfo = nil;
5297  
5298 else
5299 -- unit is alive
5300 if (not UnitIsPlayer(SKM_UNIT_TARGET)) then
5301 -- not a player, update owner information
5302 SkM_StoreTargetInfo(_SKM._enemyCreature);
5303 end
5304 end
5305  
5306 end
5307  
5308  
5309 -- --------------------------------------------------------------------------------------
5310 -- SkM_PlayerLevelUp
5311 -- --------------------------------------------------------------------------------------
5312 -- Handle "player level up" event : record event, and store new level.
5313 -- --------------------------------------------------------------------------------------
5314 function SkM_PlayerLevelUp()
5315 local FName = "SkM_PlayerLevelUp";
5316  
5317 local StoreInfo = { };
5318  
5319 StoreInfo[_SKM._type] = _SKM._levelUp;
5320  
5321 local sDate1, sDate2 = SkM_GetDate();
5322 StoreInfo[_SKM._date] = sDate1;
5323 --StoreInfo[_sortdate] = sDate2;
5324  
5325 StoreInfo[_SKM._name] = _PlayerName;
5326  
5327 local iNewLevel;
5328 if (SKM_Context.PlayerLevel) then
5329 iNewLevel = SKM_Context.PlayerLevel + 1;
5330 else
5331 iNewLevel = UnitLevel(SKM_UNIT_PLAYER) + 1;
5332 end
5333 StoreInfo[_SKM._level] = iNewLevel;
5334 SKM_Context.PlayerLevel = iNewLevel;
5335  
5336 if (not SkM_AddMapData(StoreInfo)) then
5337 return;
5338 end
5339  
5340 end
5341  
5342  
5343 -- --------------------------------------------------------------------------------------
5344 -- SkM_CountGuildMembers
5345 -- --------------------------------------------------------------------------------------
5346 -- Count number of members known for a given guild.
5347 -- --------------------------------------------------------------------------------------
5348 function SkM_CountGuildMembers(sGuild, sRealm, sPlayer)
5349 local FName = "SkM_CountGuildMembers";
5350  
5351 local sRealmName = sRealm;
5352 local sPlayerName = sPlayer;
5353  
5354 SkM_Trace(FName, 4, "Get member count for guild : "..snil(sGuild));
5355  
5356 if (sRealmName == nil) then
5357 sRealmName = _RealmName;
5358 end
5359  
5360 if (sPlayerName == nil) then
5361 sPlayerName = _PlayerName;
5362 end
5363  
5364 if (SKM_Data[sRealmName] == nil) then
5365 return nil;
5366 end
5367 if (SKM_Data[sRealmName][sPlayerName] == nil) then
5368 return nil;
5369 end
5370  
5371 local iCount = 0;
5372  
5373 for idx, val in SKM_Data[sRealmName][sPlayerName].EnemyHistory do
5374 local sName = val[_SKM._name];
5375 if (sName) then
5376 if (val[_SKM._guild] == sGuild) then
5377 iCount = iCount + 1;
5378 end
5379 end
5380 end
5381  
5382 return iCount;
5383 end
5384  
5385  
5386 -- --------------------------------------------------------------------------------------
5387 -- SkM_ComputeStatistics
5388 -- --------------------------------------------------------------------------------------
5389 -- Compute various statistics that will be used in the report frame.
5390 -- --------------------------------------------------------------------------------------
5391 function SkM_ComputeStatistics()
5392 local FName = "SkM_ComputeStatistics";
5393  
5394 SKM_Context.Statistics = { };
5395  
5396 SKM_Context.Statistics.Globals = { };
5397 SKM_Context.Statistics.Race = { };
5398 SKM_Context.Statistics.Class = { };
5399 SKM_Context.Statistics.Zone = { };
5400 SKM_Context.Statistics.Date = { };
5401 SKM_Context.Statistics.Enemy = { };
5402 SKM_Context.Statistics.Guild = { };
5403  
5404 SKM_Context.Statistics.BGZone = { };
5405 SKM_Context.Statistics.BGDate = { };
5406 SKM_Context.Statistics.BGDateZone = { };
5407  
5408 local iDeathForLevel = 0;
5409 local iKillForLevel = 0;
5410 local iTotalLevelDeath = 0;
5411 local iTotalLevelKill = 0;
5412  
5413 -- compute : global, by race, by class, by enemy
5414 -- statistics from EnemyHistory map
5415 for idx, val in SKM_Data[_RealmName][_PlayerName].EnemyHistory do
5416  
5417 SKM_Context.Statistics.Globals.EnemyPlayers = ifnil(SKM_Context.Statistics.Globals.EnemyPlayers, 0) + 1;
5418  
5419 local iDeath = ifnil(val[_SKM._enemyKillPlayer], 0);
5420 --local iKill = ifnil(val[_SKM._playerAssistKill], 0) + ifnil(val[_SKM._playerKill], 0) + ifnil(val[_SKM._playerFullKill], 0);
5421 local iKill = ifnil(val[_SKM._playerKill], 0) + ifnil(val[_SKM._playerFullKill], 0);
5422 if (SkM_GetOption("AssistKillStat")) then
5423 iKill = iKill + ifnil(val[_SKM._playerAssistKill], 0)
5424 end
5425  
5426  
5427 SKM_Context.Statistics.Globals.Death = ifnil(SKM_Context.Statistics.Globals.Death, 0) + iDeath;
5428 SKM_Context.Statistics.Globals.Kill = ifnil(SKM_Context.Statistics.Globals.Kill, 0) + iKill;
5429  
5430 -- for computing averages
5431 if (val[_SKM._level]) and (val[_SKM._level] ~= -1) then
5432 iDeathForLevel = iDeathForLevel + iDeath;
5433 iKillForLevel = iKillForLevel + iKill;
5434 iTotalLevelDeath = iTotalLevelDeath + ( val[_SKM._level] * iDeath );
5435 iTotalLevelKill = iTotalLevelKill + ( val[_SKM._level] * iKill );
5436 end
5437  
5438 local sRace = SkM_GetRaceText(val[_SKM._race]);
5439 if (sRace) then
5440 if (SKM_Context.Statistics.Race[sRace] == nil) then
5441 SKM_Context.Statistics.Race[sRace] = { };
5442 end
5443 SKM_Context.Statistics.Race[sRace].Death = ifnil(SKM_Context.Statistics.Race[sRace].Death, 0) + iDeath;
5444 SKM_Context.Statistics.Race[sRace].Kill = ifnil(SKM_Context.Statistics.Race[sRace].Kill, 0) + iKill;
5445 end
5446  
5447 local sClass = SkM_GetClassText(val[_SKM._class]);
5448 if (sClass) then
5449 if (SKM_Context.Statistics.Class[sClass] == nil) then
5450 SKM_Context.Statistics.Class[sClass] = { };
5451 end
5452 SKM_Context.Statistics.Class[sClass].Death = ifnil(SKM_Context.Statistics.Class[sClass].Death, 0) + iDeath;
5453 SKM_Context.Statistics.Class[sClass].Kill = ifnil(SKM_Context.Statistics.Class[sClass].Kill, 0) + iKill;
5454 end
5455  
5456 sEnemyName = val[_SKM._name];
5457 if (sEnemyName) and ( (iDeath > 0) or (iKill > 0) ) then
5458 SKM_Context.Statistics.Enemy[sEnemyName] = { };
5459 SKM_Context.Statistics.Enemy[sEnemyName].Death = iDeath;
5460 SKM_Context.Statistics.Enemy[sEnemyName].Kill = iKill;
5461 end
5462  
5463 end
5464  
5465  
5466 -- compute : global, by race, by class, by enemy
5467 -- statistics from EnemyHistory map
5468 for idx, val in SKM_Data[_RealmName][_PlayerName].GuildHistory do
5469 --for idx, val in SkM_GetPlayerData("GuildHistory") do
5470  
5471 SKM_Context.Statistics.Globals.EnemyGuilds = ifnil(SKM_Context.Statistics.Globals.EnemyGuilds, 0) + 1;
5472  
5473 local iDeath = ifnil(val[_SKM._enemyKillPlayer], 0);
5474 local iKill = ifnil(val[_SKM._playerAssistKill], 0) + ifnil(val[_SKM._playerKill], 0) + ifnil(val[_SKM._playerFullKill], 0);
5475  
5476 local sGuildName = val[_SKM._name];
5477 if (sGuildName) and ( (iDeath > 0) or (iKill > 0) ) then
5478 SKM_Context.Statistics.Guild[sGuildName] = { };
5479 SKM_Context.Statistics.Guild[sGuildName].Death = iDeath;
5480 SKM_Context.Statistics.Guild[sGuildName].Kill = iKill;
5481 end
5482 end
5483  
5484  
5485 -- compute averages
5486 if (iDeathForLevel > 0) then
5487 SkM_Trace(FName, 3, "iDeathForLevel = "..iDeathForLevel..", iTotalLevelDeath = "..iTotalLevelDeath);
5488 SKM_Context.Statistics.Globals.DeathAverageLevel = math.floor (iTotalLevelDeath / iDeathForLevel);
5489 end
5490 if (iKillForLevel > 0) then
5491 SkM_Trace(FName, 3, "iKillForLevel = "..iKillForLevel..", iTotalLevelKill = "..iTotalLevelKill);
5492 SKM_Context.Statistics.Globals.KillAverageLevel = math.floor (iTotalLevelKill / iKillForLevel);
5493 end
5494  
5495 SkM_Trace(FName, 3, "Average level of victims : "..snil(SKM_Context.Statistics.Globals.KillAverageLevel));
5496 SkM_Trace(FName, 3, "Average level of executioners : "..snil(SKM_Context.Statistics.Globals.DeathAverageLevel));
5497  
5498  
5499 -- compute : by zone, by date
5500 -- statistics from GlobalMapData map
5501 local i;
5502 local iNbNotes = getn(SKM_Data[_RealmName][_PlayerName].GlobalMapData);
5503  
5504 SKM_Context.Statistics.Globals.MapRecords = iNbNotes;
5505  
5506 SkM_Trace(FName, 3, "Global notes count = "..iNbNotes);
5507 for i=1, iNbNotes, 1 do
5508 local Note = SKM_Data[_RealmName][_PlayerName].GlobalMapData[i];
5509  
5510 local StoredInfo = Note[_SKM._storedInfo];
5511 if (StoredInfo) then
5512  
5513 local iKill = 0;
5514 local iDeath = 0;
5515  
5516 -- if (StoredInfo[_SKM._type] == _SKM._playerAssistKill)
5517 if (StoredInfo[_SKM._type] == _SKM._playerAssistKill) and (SkM_GetOption("AssistKillStat"))
5518 or (StoredInfo[_SKM._type] == _SKM._playerKill)
5519 or (StoredInfo[_SKM._type] == _SKM._playerFullKill) then
5520 iKill = 1;
5521 SkM_Trace(FName, 3, "PvP Kill : global note = "..i);
5522  
5523 elseif (StoredInfo[_SKM._type] == _SKM._playerDeathPvP) then
5524 iDeath = 1;
5525 SkM_Trace(FName, 3, "PvP Death : global note = "..i);
5526 end
5527  
5528 if (iKill > 0) or (iDeath > 0) then
5529  
5530 --local sZoneText = SKM_Context.Zones[Note[_SKM._continent]][Note[_SKM._zone]];
5531 local sZoneText = SkM_GetZoneTextFromIndex(Note[_SKM._continent], Note[_SKM._zone]);
5532 if (sZoneText) then
5533 if (SKM_Context.Statistics.Zone[sZoneText] == nil) then
5534 SKM_Context.Statistics.Zone[sZoneText] = { };
5535 end
5536 SKM_Context.Statistics.Zone[sZoneText].Death = ifnil(SKM_Context.Statistics.Zone[sZoneText].Death, 0) + iDeath;
5537 SKM_Context.Statistics.Zone[sZoneText].Kill = ifnil(SKM_Context.Statistics.Zone[sZoneText].Kill, 0) + iKill;
5538 end
5539  
5540 local sDate = string.sub(StoredInfo[_SKM._date], 1, 10);
5541 if (sDate) then
5542 if (SKM_Context.Statistics.Date[sDate] == nil) then
5543 SKM_Context.Statistics.Date[sDate] = { };
5544 end
5545 SKM_Context.Statistics.Date[sDate].Death = ifnil(SKM_Context.Statistics.Date[sDate].Death, 0) + iDeath;
5546 SKM_Context.Statistics.Date[sDate].Kill = ifnil(SKM_Context.Statistics.Date[sDate].Kill, 0) + iKill;
5547 end
5548  
5549 end
5550 end
5551 end
5552  
5553 -- compute : battlegrounds by zone, by date, by date and zone
5554 for idx1, val1 in SKM_Data[_RealmName][_PlayerName].BGStats do
5555 local sZone = idx1;
5556 if (SKM_Context.Statistics.BGZone[sZone] == nil) then
5557 SKM_Context.Statistics.BGZone[sZone] = { };
5558 end
5559  
5560 for idx2, val2 in val1 do
5561 local sDate = idx2;
5562 local iDeath = ifnil(val2[_SKM._enemyKillBG], 0);
5563 local iKill = ifnil(val2[_SKM._playerBGKill], 0);
5564  
5565 SKM_Context.Statistics.BGZone[sZone].Death = ifnil(SKM_Context.Statistics.BGZone[sZone].Death, 0) + iDeath;
5566 SKM_Context.Statistics.BGZone[sZone].Kill = ifnil(SKM_Context.Statistics.BGZone[sZone].Kill, 0) + iKill;
5567  
5568 if (SKM_Context.Statistics.BGDate[sDate] == nil) then
5569 SKM_Context.Statistics.BGDate[sDate] = { };
5570 end
5571 SKM_Context.Statistics.BGDate[sDate].Death = ifnil(SKM_Context.Statistics.BGDate[sDate].Death, 0) + iDeath;
5572 SKM_Context.Statistics.BGDate[sDate].Kill = ifnil(SKM_Context.Statistics.BGDate[sDate].Kill, 0) + iKill;
5573  
5574 local sDateZone = idx2.." - "..idx1;
5575 if (SKM_Context.Statistics.BGDateZone[sDateZone] == nil) then
5576 SKM_Context.Statistics.BGDateZone[sDateZone] = { };
5577 SKM_Context.Statistics.BGDateZone[sDateZone].Zone = idx1;
5578 SKM_Context.Statistics.BGDateZone[sDateZone].Date = idx2;
5579 end
5580 SKM_Context.Statistics.BGDateZone[sDateZone].Death = ifnil(SKM_Context.Statistics.BGDateZone[sDateZone].Death, 0) + iDeath;
5581 SKM_Context.Statistics.BGDateZone[sDateZone].Kill = ifnil(SKM_Context.Statistics.BGDateZone[sDateZone].Kill, 0) + iKill;
5582 end
5583 end
5584  
5585  
5586  
5587 -- provide sortable lists
5588 SKM_Context.Statistics.ClassList = {};
5589 for idx, val in SKM_Context.Statistics.Class do
5590 val.SortKey = idx;
5591 val.Key = idx;
5592 table.insert(SKM_Context.Statistics.ClassList, val);
5593 end
5594 table.sort(SKM_Context.Statistics.ClassList, SkM_SortStatList);
5595  
5596 SKM_Context.Statistics.RaceList = {};
5597 for idx, val in SKM_Context.Statistics.Race do
5598 val.SortKey = idx;
5599 val.Key = idx;
5600 table.insert(SKM_Context.Statistics.RaceList, val);
5601 end
5602  
5603 table.sort(SKM_Context.Statistics.RaceList, SkM_SortStatList);
5604  
5605 SKM_Context.Statistics.EnemyList = {};
5606 for idx, val in SKM_Context.Statistics.Enemy do
5607 --val.SortKey = string.upper(idx);
5608 val.SortKey = SkM_NormalizeString(idx);
5609 val.Key = idx;
5610 table.insert(SKM_Context.Statistics.EnemyList, val);
5611 end
5612 table.sort(SKM_Context.Statistics.EnemyList, SkM_SortStatList);
5613  
5614 SKM_Context.Statistics.GuildList = {};
5615 for idx, val in SKM_Context.Statistics.Guild do
5616 --val.SortKey = string.upper(idx);
5617 val.SortKey = SkM_NormalizeString(idx);
5618 val.Key = idx;
5619 table.insert(SKM_Context.Statistics.GuildList, val);
5620 end
5621 table.sort(SKM_Context.Statistics.GuildList, SkM_SortStatList);
5622  
5623 SKM_Context.Statistics.ZoneList = {};
5624 for idx, val in SKM_Context.Statistics.Zone do
5625 val.SortKey = idx;
5626 val.Key = idx;
5627 table.insert(SKM_Context.Statistics.ZoneList, val);
5628 end
5629 table.sort(SKM_Context.Statistics.ZoneList, SkM_SortStatList);
5630  
5631 SKM_Context.Statistics.DateList = {};
5632 for idx, val in SKM_Context.Statistics.Date do
5633 val.SortKey = SkM_GetSortableDate(idx);
5634 val.Key = idx;
5635 table.insert(SKM_Context.Statistics.DateList, val);
5636 end
5637 table.sort(SKM_Context.Statistics.DateList, SkM_SortStatList);
5638  
5639 SKM_Context.Statistics.BGDateList = {};
5640 for idx, val in SKM_Context.Statistics.BGDate do
5641 val.SortKey = SkM_GetSortableDate(idx);
5642 val.Key = idx;
5643 table.insert(SKM_Context.Statistics.BGDateList, val);
5644 end
5645 table.sort(SKM_Context.Statistics.BGDateList, SkM_SortStatList);
5646  
5647 SKM_Context.Statistics.BGZoneList = {};
5648 for idx, val in SKM_Context.Statistics.BGZone do
5649 val.SortKey = idx;
5650 val.Key = idx;
5651 table.insert(SKM_Context.Statistics.BGZoneList, val);
5652 end
5653 table.sort(SKM_Context.Statistics.BGZoneList, SkM_SortStatList);
5654  
5655 SKM_Context.Statistics.BGDateZoneList = {};
5656 for idx, val in SKM_Context.Statistics.BGDateZone do
5657 val.SortKey = SkM_GetSortableDate(val.Date)..val.Zone;
5658 val.Key = idx;
5659 table.insert(SKM_Context.Statistics.BGDateZoneList, val);
5660 end
5661 table.sort(SKM_Context.Statistics.BGDateZoneList, SkM_SortStatList);
5662  
5663  
5664 end
5665  
5666  
5667 -- --------------------------------------------------------------------------------------
5668 -- SkM_SortStatList
5669 -- --------------------------------------------------------------------------------------
5670 -- Statistics sorting function
5671 -- --------------------------------------------------------------------------------------
5672 function SkM_SortStatList(e1, e2)
5673 if (e1.SortKey < e2.SortKey) then
5674 return true;
5675 elseif (e2.SortKey < e1.SortKey) then
5676 return false;
5677 end
5678 return false;
5679 end
5680  
5681  
5682 -- --------------------------------------------------------------------------------------
5683 -- SkM_GetUnitFaction
5684 -- --------------------------------------------------------------------------------------
5685 -- Find player faction for a given unit
5686 -- --------------------------------------------------------------------------------------
5687 function SkM_GetUnitFaction(sUnit)
5688 if (sUnit == nil) then
5689 return nil;
5690 end
5691 local sRace = UnitRace(sUnit);
5692 if (sRace == nil) then
5693 return nil;
5694 end
5695 local i;
5696 for i=1, getn(SKM_PlayerFaction), 1 do
5697 if ( intable(sRace, SKM_PlayerFaction[i].RaceList) ) then
5698 return i, SKM_PlayerFaction[i].Faction;
5699 end
5700 end
5701 return nil;
5702 end
5703  
5704  
5705 -- --------------------------------------------------------------------------------------
5706 -- SkM_UnitIsEnemyPlayer
5707 -- --------------------------------------------------------------------------------------
5708 -- Is unit an enemy player of the opposite faction ?
5709 -- --------------------------------------------------------------------------------------
5710 function SkM_UnitIsEnemyPlayer(sUnit)
5711 if (sUnit == nil) then
5712 return nil;
5713 end
5714 return ( (UnitIsPlayer(sUnit))
5715 and (UnitIsEnemy(SKM_UNIT_PLAYER, sUnit))
5716 and (SkM_UnitIsOppositeFaction(SKM_UNIT_PLAYER, sUnit))
5717 );
5718 end
5719  
5720  
5721 -- --------------------------------------------------------------------------------------
5722 -- SkM_UnitIsDuelingPlayer
5723 -- --------------------------------------------------------------------------------------
5724 -- Is unit a player you are currently dueling ?
5725 -- ie, if he is a player, tagged as "enemy" but of your faction.
5726 -- --------------------------------------------------------------------------------------
5727 function SkM_UnitIsDuelingPlayer(sUnit)
5728 if (sUnit == nil) then
5729 return nil;
5730 end
5731 return ( (UnitIsPlayer(sUnit))
5732 and (UnitIsEnemy(SKM_UNIT_PLAYER, sUnit))
5733 and (not SkM_UnitIsOppositeFaction(SKM_UNIT_PLAYER, sUnit))
5734 );
5735 end
5736  
5737  
5738 -- --------------------------------------------------------------------------------------
5739 -- SkM_UnitIsOppositeFaction
5740 -- --------------------------------------------------------------------------------------
5741 -- Check if two units are on opposite faction or not, using their race.
5742 -- Return true if it's the case, false if not, and nil if indeterminate
5743 -- --------------------------------------------------------------------------------------
5744 function SkM_UnitIsOppositeFaction(sUnit1, sUnit2)
5745 local FName = "SkM_UnitIsOppositeFaction";
5746  
5747 local Faction1 = SkM_GetUnitFaction(sUnit1);
5748 local Faction2 = SkM_GetUnitFaction(sUnit2);
5749  
5750 if (Faction1 == nil) then
5751 SkM_Trace(FName, 1, "Unknown faction for "..snil(sUnit1));
5752 return nil;
5753 end
5754 if (Faction2 == nil) then
5755 SkM_Trace(FName, 1, "Unknown faction for "..snil(sUnit2));
5756 return nil;
5757 end
5758  
5759 if (Faction1 == Faction2) then
5760 return false;
5761 else
5762 return true;
5763 end
5764  
5765 end
5766  
5767  
5768 -- --------------------------------------------------------------------------------------
5769 -- SkM_DeleteEnemy
5770 -- --------------------------------------------------------------------------------------
5771 -- Delete an enemy player and all associated map records (kills or deaths).
5772 -- --------------------------------------------------------------------------------------
5773 function SkM_DeleteEnemy(sName)
5774 local FName = "SkM_DeleteEnemy";
5775  
5776 local Enemy = SKM_Data[_RealmName][_PlayerName].EnemyHistory[sName];
5777  
5778 if (Enemy == nil) then
5779 SkM_Trace(FName, 1, "Enemy not found : "..snil(sName));
5780 return;
5781 end
5782  
5783 SkM_Trace(FName, 1, "Removing Enemy : "..sName);
5784  
5785 SkM_UpdateEnemyHistory();
5786  
5787 -- remove all recorded events associated to this enemy : kills and deaths
5788 local i;
5789 local iNbNotes = table.getn(SKM_Data[_RealmName][_PlayerName].GlobalMapData);
5790 for i=iNbNotes, 1, -1 do
5791 local Note = SKM_Data[_RealmName][_PlayerName].GlobalMapData[i];
5792  
5793 local StoredInfo = Note[_SKM._storedInfo];
5794  
5795 if (StoredInfo) and (StoredInfo[_SKM._name] == sName) then
5796  
5797 -- remove from GlobalMapData and from MapData
5798 SkM_Trace(FName, 3, "Removing note : global index = "..i);
5799  
5800 SkM_DeleteNote(_RealmName, _PlayerName, i);
5801 end
5802 end
5803  
5804 -- finally, delete the enemy. Bye bye !
5805 SKM_Data[_RealmName][_PlayerName].EnemyHistory[sName] = nil;
5806 end
5807  
5808  
5809 -- --------------------------------------------------------------------------------------
5810 -- SkM_DeleteDuelEnemy
5811 -- --------------------------------------------------------------------------------------
5812 -- Delete all duel information associated to a given player
5813 -- --------------------------------------------------------------------------------------
5814 function SkM_DeleteDuelEnemy(sName)
5815 local FName = "SkM_DeleteDuelEnemy";
5816  
5817 SKM_Data[_RealmName][_PlayerName].DuelHistory[sName] = nil;
5818 end
5819  
5820  
5821 -- --------------------------------------------------------------------------------------
5822 -- SkM_GetKnownEnemyType
5823 -- --------------------------------------------------------------------------------------
5824 -- Return _SKM._enemyPlayer if given name matches a known player, otherwise return nil
5825 -- (ie, we do not know for now if it's a player or not, but we may get the information
5826 -- later on)
5827 -- --------------------------------------------------------------------------------------
5828 function SkM_GetKnownEnemyType(sName)
5829 local EnemyType;
5830 local Enemy = SKM_Data[_RealmName][_PlayerName].EnemyHistory[sName];
5831 if (Enemy) then
5832 EnemyType = _SKM._enemyPlayer;
5833 end
5834 return EnemyType;
5835 end
5836  
5837  
5838 -- --------------------------------------------------------------------------------------
5839 -- SkM_UnitName
5840 -- --------------------------------------------------------------------------------------
5841 -- Call UnitName to get unit name.
5842 -- Return nil if we get "Unknown Entity".
5843 -- --------------------------------------------------------------------------------------
5844 function SkM_UnitName(sUnit)
5845 local sName = UnitName(sUnit);
5846  
5847 -- if we got "unknown entity", try again, maybe it will work this time
5848 if (sName == SKM_UNKNOWN_ENTITY) then
5849 sName = UnitName(sUnit);
5850 end
5851  
5852 if (sName == "") or (sName == SKM_UNKNOWN_ENTITY) then
5853 sName = nil;
5854 end
5855 return sName;
5856 end
5857  
5858  
5859 -- --------------------------------------------------------------------------------------
5860 -- SkM_IsTotem
5861 -- --------------------------------------------------------------------------------------
5862 -- Check if given name matches a totem (and *not* a player)
5863 -- --------------------------------------------------------------------------------------
5864 function SkM_IsTotem(sName)
5865 local FName = "SkM_IsTotem";
5866  
5867 if (sName) then
5868 for sType in string.gfind(sName, SKM_Context.Pattern.Totem) do
5869 if (sType) then
5870 SkM_Trace(FName, 2, "Name = "..snil(sName).." : this is a totem. Type = "..sType);
5871 return true;
5872 end
5873 end
5874 end
5875  
5876 SkM_Trace(FName, 3, "Name = "..snil(sName).." : not a totem");
5877 return false;
5878  
5879 -- if (string.find(sName, SKM_Context.Pattern.Totem)) then
5880 -- SkM_Trace(FName, 2, "Name = "..snil(sName).." : this is a totem");
5881 -- return true;
5882 -- else
5883 -- SkM_Trace(FName, 3, "Name = "..snil(sName).." : not a totem");
5884 -- return false;
5885 -- end
5886  
5887 end
5888  
5889  
5890 function SkM_NormalizeString(sName)
5891 local FName = "SkM_NormalizeString";
5892  
5893 if (sName == nil) then
5894 return nil;
5895 end
5896  
5897 local sString = string.upper(sName);
5898 i=1;
5899 while (string.sub(sString, i, i) == " ") and (i < string.len(sString)) do
5900 i = i + 1;
5901 end
5902 if (i > 1 ) then
5903 sString = string.sub(sString, i, string.len(sString));
5904 end
5905  
5906 sString = SkM_NormString(sString, 2); -- only need to normalize the first two chars to provide an accurate sort
5907 return sString;
5908 end
5909  
5910  
5911 function SkM_LogDuel(sWinner, sLoser)
5912 local FName = "SkM_LogDuel";
5913  
5914 local sName;
5915 local sDate = SkM_GetDate();
5916 local bWin;
5917  
5918 if (sWinner == _PlayerName) then
5919 sName = sLoser;
5920 bWin = true;
5921 else
5922 sName = sWinner;
5923 bWin = false;
5924 end
5925  
5926 if (SKM_Context.DuelEnemy == nil) or (SKM_Context.DuelEnemy[_SKM._name] ~= sName) then
5927 -- rare case of a finished duel but we did not see at any time our enemy.
5928 -- okay, force target him then.
5929 -- I agree that messing with player target is a bad idea in most cases, but at the end
5930 -- of a duel it should not matter much.
5931  
5932 SkM_Trace(FName, 2, "End of duel but no info about enemy "..snil(sName).." : force target");
5933  
5934 TargetByName(sName);
5935 SkM_StoreDuelEnemyInfo(SKM_UNIT_TARGET);
5936  
5937 if (SKM_Context.DuelEnemy == nil) or (SKM_Context.DuelEnemy[_SKM._name] ~= sName) then
5938 -- might potentially happen if enemy is too far away. Even more unlikely, but
5939 -- just in case...
5940 SkM_Trace(FName, 1, "Still no info about enemy !");
5941 SKM_Context.DuelEnemy = nil;
5942 return;
5943 end
5944  
5945 end
5946  
5947 if (not SKM_Data[_RealmName][_PlayerName].DuelHistory[sName]) then
5948 SKM_Data[_RealmName][_PlayerName].DuelHistory[sName] = { };
5949 SKM_Data[_RealmName][_PlayerName].DuelHistory[sName][_SKM._name] = sName;
5950  
5951 SKM_Data[_RealmName][_PlayerName].DuelHistory[sName][_SKM._race] = SKM_Context.DuelEnemy[_SKM._race];
5952 SKM_Data[_RealmName][_PlayerName].DuelHistory[sName][_SKM._class] = SKM_Context.DuelEnemy[_SKM._class];
5953 SKM_Data[_RealmName][_PlayerName].DuelHistory[sName][_SKM._win] = 0;
5954 SKM_Data[_RealmName][_PlayerName].DuelHistory[sName][_SKM._loss] = 0;
5955 SKM_Data[_RealmName][_PlayerName].DuelHistory[sName][_SKM._duel] = 0;
5956 else
5957 if (not SKM_Data[_RealmName][_PlayerName].DuelHistory[sName][_SKM._race]) then
5958 SKM_Data[_RealmName][_PlayerName].DuelHistory[sName][_SKM._race] = SKM_Context.DuelEnemy[_SKM._race];
5959 end
5960 if (not SKM_Data[_RealmName][_PlayerName].DuelHistory[sName][_SKM._class]) then
5961 SKM_Data[_RealmName][_PlayerName].DuelHistory[sName][_SKM._class] = SKM_Context.DuelEnemy[_SKM._class];
5962 end
5963 end
5964  
5965 SKM_Data[_RealmName][_PlayerName].DuelHistory[sName][_SKM._level] = SKM_Context.DuelEnemy[_SKM._level];
5966 SKM_Data[_RealmName][_PlayerName].DuelHistory[sName][_SKM._guild] = SKM_Context.DuelEnemy[_SKM._guild];
5967 SKM_Data[_RealmName][_PlayerName].DuelHistory[sName][_SKM._lastDuel] = sDate;
5968  
5969 SKM_Data[_RealmName][_PlayerName].DuelHistory[sName][_SKM._duel] = ifnil(SKM_Data[_RealmName][_PlayerName].DuelHistory[sName][_SKM._duel], 0) + 1;
5970 if (bWin) then
5971 SKM_Data[_RealmName][_PlayerName].DuelHistory[sName][_SKM._win] = ifnil(SKM_Data[_RealmName][_PlayerName].DuelHistory[sName][_SKM._win], 0) + 1;
5972 SkM_Trace(FName, 1, "Duel won vs "..sName..", Win = "..SKM_Data[_RealmName][_PlayerName].DuelHistory[sName][_SKM._win]..", Loss = "..SKM_Data[_RealmName][_PlayerName].DuelHistory[sName][_SKM._loss]..", Total = "..SKM_Data[_RealmName][_PlayerName].DuelHistory[sName][_SKM._duel]);
5973 else
5974 SKM_Data[_RealmName][_PlayerName].DuelHistory[sName][_SKM._loss] = ifnil(SKM_Data[_RealmName][_PlayerName].DuelHistory[sName][_SKM._loss], 0) + 1;
5975 SkM_Trace(FName, 1, "Duel lost vs "..sName..", Win = "..SKM_Data[_RealmName][_PlayerName].DuelHistory[sName][_SKM._win]..", Loss = "..SKM_Data[_RealmName][_PlayerName].DuelHistory[sName][_SKM._loss]..", Total = "..SKM_Data[_RealmName][_PlayerName].DuelHistory[sName][_SKM._duel]);
5976 end
5977  
5978 -- clear duel information
5979 SKM_Context.DuelEnemy = nil;
5980 end
5981  
5982  
5983 function SkM_ParseDuelResult(sMsg)
5984 local FName = "SkM_ParseDuelResult";
5985  
5986 local sWinner, sLoser;
5987  
5988 if (not SkM_GetOption("StoreDuels")) then
5989 return;
5990 end
5991  
5992 for sWinner, sLoser in string.gfind(sMsg, SKM_Context.Pattern.Duel_Won) do
5993 if (sWinner and sLoser) then
5994 if (sWinner == _PlayerName) or (sLoser == _PlayerName) then
5995 SkM_Trace(FName, 3, "Duel_Won : Winner = "..sWinner..", Loser = "..sLoser);
5996  
5997 SkM_LogDuel(sWinner, sLoser);
5998 return;
5999 end
6000 end
6001 end
6002  
6003 end
6004  
6005  
6006 function SkM_UpdateBGStats(sZoneName, sDate, iDeath, iKill)
6007  
6008 if (not SKM_Data[_RealmName][_PlayerName].BGStats[sZoneName]) then
6009 SKM_Data[_RealmName][_PlayerName].BGStats[sZoneName] = { };
6010 end
6011  
6012 if (not SKM_Data[_RealmName][_PlayerName].BGStats[sZoneName][sDate]) then
6013 SKM_Data[_RealmName][_PlayerName].BGStats[sZoneName][sDate] = { };
6014 SKM_Data[_RealmName][_PlayerName].BGStats[sZoneName][sDate][_SKM._enemyKillBG] = 0;
6015 SKM_Data[_RealmName][_PlayerName].BGStats[sZoneName][sDate][_SKM._playerBGKill] = 0;
6016 end
6017  
6018 if (iDeath) then
6019 SKM_Data[_RealmName][_PlayerName].BGStats[sZoneName][sDate][_SKM._enemyKillBG] = ifnil(SKM_Data[_RealmName][_PlayerName].BGStats[sZoneName][sDate][_SKM._enemyKillBG], 0) + iDeath;
6020 end
6021  
6022 if (iKill) then
6023 SKM_Data[_RealmName][_PlayerName].BGStats[sZoneName][sDate][_SKM._playerBGKill] = ifnil(SKM_Data[_RealmName][_PlayerName].BGStats[sZoneName][sDate][_SKM._playerBGKill], 0) + iKill;
6024 end
6025 end
6026  
6027  
6028 function SkM_BGStats_AddDeath()
6029 local sZone = SkM_GetZoneText();
6030 local sDate = SkM_GetDay();
6031 SkM_UpdateBGStats(sZone, sDate, 1, nil);
6032 end
6033  
6034  
6035 function SkM_BGStats_AddKill()
6036 local sZone = SkM_GetZoneText();
6037 local sDate = SkM_GetDay();
6038 SkM_UpdateBGStats(sZone, sDate, nil, 1);
6039 end
6040  
6041  
6042 function SkM_NormString2(sString)
6043 local sRes = sString;
6044 local idx, val, i;
6045 for idx, val in SKM_ToStandardCase do
6046 for i=1, table.getn(val), 1 do
6047 sRes = string.gsub(sRes, val[i], idx);
6048 end
6049 end
6050 return sRes;
6051 end
6052  
6053  
6054 function SkM_NormString(sInputString, iNormMinLen)
6055 local FName = "SkM_NormString";
6056 local sString = string.upper(sInputString);
6057 local iLen = string.len(sString);
6058 local sRes = "";
6059 local sNonStd = "";
6060  
6061 local iByte_A = string.byte("A");
6062 local iByte_Z = string.byte("Z");
6063 local iByte_a = string.byte("a");
6064 local iByte_z = string.byte("z");
6065  
6066 local i;
6067 for i=1,iLen,1 do
6068 --SkM_Trace(FName, 3, i.." Res="..sRes);
6069  
6070 local sChar = string.sub(sString, i, i);
6071 local iByte = string.byte(sString, i);
6072 if ((iByte >= iByte_A) and (iByte <= iByte_Z))
6073 or ((iByte >= iByte_a) and (iByte <= iByte_z))
6074 or (intable(sChar, { " ", "-" } ))
6075 then
6076 if (string.len(sNonStd) > 0) then
6077 sRes = sRes..SkM_NormString2(sNonStd);
6078 sNonStd = "";
6079 end
6080 sRes = sRes..sChar;
6081 if (i<iLen) and (iNormMinLen) and (string.len(sRes) >= iNormMinLen) then
6082 sRes = sRes..string.sub(sString, i+1, iLen);
6083 return sRes;
6084 end
6085 else
6086 sNonStd = sNonStd..sChar;
6087 end
6088 end
6089 if (string.len(sNonStd) > 0) then
6090 sRes = sRes..SkM_NormString2(sNonStd);
6091 sNonStd = "";
6092 end
6093  
6094 return sRes;
6095 end
6096  
6097  
6098 function SkM_GetEnemyList(sName, bNormalize, bPrefix)
6099 local FName = "SkM_GetEnemyList";
6100 local TheList = { };
6101  
6102 local sEnemyName = string.upper(sName);
6103 if (bNormalize) then
6104 sEnemyName = SkM_NormString(sName);
6105 end
6106 local iNameLen = string.len(sEnemyName);
6107  
6108 SkM_Trace(FName, 3, "Name = "..sName);
6109  
6110 local ResList = {};
6111 for idx, val in SKM_Data[_RealmName][_PlayerName].EnemyHistory do
6112 local sCurName = string.upper(idx);
6113 local bMatch = false;
6114 if (bNormalize) then
6115 sCurName = SkM_NormString(sCurName, iNameLen);
6116 end
6117 SkM_Trace(FName, 3, "CurName = "..sCurName);
6118 if (not bPrefix) then
6119 if (sCurName == sEnemyName) then
6120 bMatch = true;
6121 end
6122 else
6123 if (string.sub(sCurName, 1, iNameLen) == sEnemyName) then
6124 bMatch = true;
6125 end
6126 end
6127  
6128 if (bMatch) then
6129 table.insert(TheList, idx);
6130 end
6131 end
6132  
6133 table.sort(TheList, function(e1,e2) return e1<e2; end);
6134  
6135 return TheList;
6136 end
6137  
6138  
6139 function SkM_GetEnemyInfo(sName, bMatchFullName, bMatchSpecialChar)
6140 local FName = "SkM_GetEnemyInfo";
6141  
6142 SkM_Trace(FName, 2, "Name = "..sName..", FullName = "..snil(bMatchFullName)..", MatchSpec = "..snil(bMatchSpecialChar));
6143  
6144 local bNormalize = true;
6145 local bPrefix = true;
6146  
6147 if (bMatchSpecialChar) then
6148 bNormalize = false;
6149 end
6150 if (bMatchFullName) then
6151 bPrefix = false;
6152 end
6153  
6154 SkM_ChatMessageCol("Looking for : "..sName);
6155  
6156 local EnemyList = SkM_GetEnemyList(sName, bNormalize, bPrefix);
6157 local iEnemyCount = table.getn(EnemyList);
6158  
6159 for i=1,iEnemyCount,1 do
6160 local Enemy = SKM_Data[_RealmName][_PlayerName].EnemyHistory[EnemyList[i]];
6161 if (Enemy) then
6162 local Lines = {};
6163  
6164 local iKill = ifnil(Enemy[_SKM._playerKill], 0);
6165 local iAssistKill = ifnil(Enemy[_SKM._playerAssistKill], 0);
6166 local iFullKill = ifnil(Enemy[_SKM._playerFullKill], 0);
6167 local iTotalKill = iKill + iAssistKill + iFullKill;
6168 local iDeath = ifnil(Enemy[_SKM._enemyKillPlayer], 0);
6169 local iMet = ifnil(Enemy[_SKM._meetCount], 0);
6170 local sDisplayDate = string.sub(Enemy[_SKM._lastView], 1, 10);
6171  
6172 local Guild;
6173 local bGuildWar = false;
6174 if (Enemy[_SKM._guild] ~= nil) and (Enemy[_SKM._guild] ~= "") then
6175 Guild = SKM_Data[_RealmName][_PlayerName].GuildHistory[Enemy[_SKM._guild]];
6176 bGuildWar = Guild[_SKM._atWar];
6177 end
6178  
6179 -- line 1 : <rank> <player> <guild> : level <level> <race> <class>
6180  
6181 local sLine = "";
6182 if (Enemy[_SKM._rank]) then
6183 sLine = sLine..SKM_Config.Col_Rank..Enemy[_SKM._rank].." ";
6184 end
6185  
6186 if (Enemy[_SKM._atWar]) then
6187 sLine = sLine..SKM_Config.Col_PlayerWar;
6188 else
6189 sLine = sLine..SKM_Config.Col_Label;
6190 end
6191 sLine = sLine..Enemy[_SKM._name]..SKM_Config.Col_Label;
6192  
6193 if (Guild) then
6194 sLine = sLine.." <";
6195 if (Guild[_SKM._atWar]) then
6196 sLine = sLine..SKM_Config.Col_PlayerWar;
6197 end
6198 sLine = sLine..Enemy[_SKM._guild]..SKM_Config.Col_Label..">";
6199 end
6200  
6201 if (Enemy[_SKM._level] ~= nil) and (Enemy[_SKM._race] ~= nil) and (Enemy[_SKM._class] ~= nil) then
6202 sLine = sLine.." : "..SKM_UI_STRINGS.List_Frame_Level..Enemy[_SKM._level].." "..SkM_GetRaceText(Enemy[_SKM._race]).." "..SkM_GetClassText(Enemy[_SKM._class]);
6203 end
6204  
6205 table.insert(Lines, sLine);
6206  
6207 if (iEnemyCount == 1) then
6208  
6209 -- line 2 : <met> <kill> <death> <last seen date and location>
6210 sLine = "";
6211  
6212 sLine = sLine..SKM_Config.Col_LabelTitle..SKM_UI_STRINGS.List_Frame_Met..SKM_Config.Col_Label..iMet;
6213 sLine = sLine.." "..SKM_Config.Col_LabelTitle..SKM_UI_STRINGS.List_Frame_Kill..SKM_Config.Col_Label..iTotalKill;
6214 sLine = sLine.." "..SKM_Config.Col_LabelTitle..SKM_UI_STRINGS.List_Frame_Death..SKM_Config.Col_Label .. iDeath;
6215  
6216 sLine = sLine.." "..SKM_Config.Col_LabelTitle..SKM_UI_STRINGS.List_Frame_Last_Seen;
6217 sLine = sLine..SKM_Config.Col_Label..sDisplayDate;
6218  
6219 if (Enemy[_SKM._continent] ~= nil) and (Enemy[_SKM._zone] ~= nil) then
6220 local sZoneText = SkM_GetZoneTextFromIndex(Enemy[_SKM._continent], Enemy[_SKM._zone]);
6221 sLine = sLine.." - "..sZoneText;
6222  
6223 elseif (Enemy[_SKM._zoneName] ~= nil) then
6224 sLine = sLine.." - "..Enemy[_SKM._zoneName];
6225 end
6226  
6227 table.insert(Lines, sLine);
6228  
6229  
6230 if (Enemy[_SKM._playerNote] ~= nil) and (Enemy[_SKM._playerNote] ~= "") then
6231  
6232 local sLine = "";
6233  
6234 sLine = sLine..SKM_Config.Col_LabelTitle..SKM_UI_STRINGS.List_Frame_Note;
6235 sLine = sLine..SKM_Config.Col_Label..Enemy[_SKM._playerNote];
6236  
6237 table.insert(Lines, sLine);
6238 end
6239  
6240  
6241 end
6242  
6243 for i=1,table.getn(Lines),1 do
6244 DEFAULT_CHAT_FRAME:AddMessage(Lines[i]);
6245 end
6246  
6247 end
6248 end
6249  
6250 --SkM_ChatMessageCol("Enemy matching : "..iEnemyCount);
6251 SkM_ChatMessageCol("Found : "..iEnemyCount);
6252 end
6253  
6254  
6255 function SkM_DataCleanUp()
6256 local FName = "SkM_DataCleanUp";
6257 if (not SKM_Data) then
6258 return;
6259 end
6260 if (not SKM_Settings) then
6261 return;
6262 end
6263  
6264 if (SkM_GetOption("DataCleanUp")) then
6265 local sDate = SkM_GetDate();
6266 local iDiffTime = SkM_DiffDate(sDate, SKM_Settings.LastDataCleanUp);
6267 if (SKM_Settings.LastDataCleanUp == nil) or (iDiffTime == nil) or (iDiffTime > SkM_GetOption("DataCleanUpInterval") * 3600 * 24) then
6268  
6269 SkM_DoCleanUp();
6270  
6271 SKM_Settings.LastDataCleanUp = sDate;
6272 end
6273 end
6274  
6275 end
6276  
6277  
6278 function SkM_DoCleanUp()
6279 local FName = "SkM_DoCleanUp";
6280  
6281 local sDate = SkM_GetDate();
6282  
6283 if (SkM_GetOption("CleanInactiveEnemies")) then
6284  
6285 for idx_realm, val_realm in SKM_Data do
6286 for idx_char, val_char in SKM_Data[idx_realm] do
6287 if (SKM_Data[idx_realm][idx_char].PlayerName == idx_char) then
6288  
6289 SkM_Trace(FName, 1, "Cleaning for "..idx_realm.." / "..idx_char);
6290 for idx_enemy, val_enemy in SKM_Data[idx_realm][idx_char].EnemyHistory do
6291  
6292 local iDiffTime = SkM_DiffDate(sDate, val_enemy[_SKM._lastView]);
6293 if (iDiffTime ~= nil) and (iDiffTime > SkM_GetOption("CleanInactiveEnemiesDelay") * 3600 * 24) then
6294 -- long time no see. Check if we have to remove him
6295 if (ifnil(val_enemy[_SKM._playerAssistKill], 0) + ifnil(val_enemy[_SKM._playerKill], 0) + ifnil(val_enemy[_SKM._playerFullKill], 0) == 0)
6296 and (ifnil(val_enemy[_SKM._enemyKillPlayer], 0) == 0)
6297 and (ifnil(val_enemy[_SKM._enemyKillBG], 0) == 0)
6298 and (ifnil(val_enemy[_SKM._playerBGKill], 0) == 0)
6299 and not (val_enemy[_SKM._atWar])
6300 and ( (val_enemy[_SKM._playerNote] == nil) or (val_enemy[_SKM._playerNote] == "") )
6301 then
6302 SkM_Trace(FName, 2, idx_realm.." / "..idx_char.." : remove "..idx_enemy);
6303  
6304 SKM_Data[idx_realm][idx_char].EnemyHistory[idx_enemy] = nil;
6305 end
6306  
6307 end
6308 end
6309 end
6310 end
6311 end
6312 end
6313  
6314 if (SkM_GetOption("CleanEmptyGuilds")) then
6315 for idx_realm, val_realm in SKM_Data do
6316 for idx_char, val_char in SKM_Data[idx_realm] do
6317 if (SKM_Data[idx_realm][idx_char].PlayerName == idx_char) then
6318 for idx_guild, val_guild in SKM_Data[idx_realm][idx_char].GuildHistory do
6319  
6320 if (SkM_CountGuildMembers(idx_guild, idx_realm, idx_char) == 0) then
6321 SkM_Trace(FName, 2, idx_realm.." / "..idx_char.." : remove "..idx_guild);
6322 SKM_Data[idx_realm][idx_char].GuildHistory[idx_guild] = nil;
6323 end
6324 end
6325 end
6326 end
6327 end
6328 end
6329  
6330 end
6331  
6332  
6333  
6334 function SkM_ZoneRematch(RealmName, PlayerName, ZoneShift, minDate, maxDate)
6335 local FName = "SkM_ZoneRematch";
6336 local idx_c, val_c, idx_z, val_z, idx_gn, Note;
6337 local cont_shift, zone_shift;
6338  
6339 local iCountShift = 0;
6340 local iCountNoShift = 0;
6341  
6342 if (ZoneShift == nil) then
6343 SkM_Trace(FName, 1, "ZoneShift is nil ! ");
6344 return;
6345 end
6346  
6347 -- reinitialize map data
6348 SKM_Data[RealmName][PlayerName].MapData = { };
6349  
6350 for idx_c, val_c in SKM_Context.Continents do
6351 SKM_Data[RealmName][PlayerName].MapData[idx_c] = { };
6352  
6353 for idx_z, val_z in SKM_Context.Zones[idx_c] do
6354 SKM_Data[RealmName][PlayerName].MapData[idx_c][idx_z] = { };
6355 end
6356 end
6357  
6358  
6359 -- parse global map data to rebuild local map data
6360 if (SKM_Data[RealmName][PlayerName].GlobalMapData) then
6361 for idx_gn, Note in SKM_Data[RealmName][PlayerName].GlobalMapData do
6362 local bDoShift = true;
6363 idx_c = Note[_SKM._continent];
6364 idx_z = Note[_SKM._zone];
6365  
6366 local StoredInfo = Note[_SKM._storedInfo];
6367  
6368 if (StoredInfo) and (StoredInfo[_SKM._date]) then
6369 if (maxDate) then
6370 local iDiffTime = SkM_DiffDate(maxDate, StoredInfo[_SKM._date]);
6371 if (iDiffTime < 0) then
6372 -- Note generated after max date, skip
6373 bDoShift = false;
6374 end
6375 end
6376 if (minDate) then
6377 local iDiffTime = SkM_DiffDate(minDate, StoredInfo[_SKM._date]);
6378 if (iDiffTime > 0) then
6379 -- Note generated before min date, skip
6380 bDoShift = false;
6381 end
6382 end
6383 end
6384  
6385 if (bDoShift) then
6386 zone_shift = ZoneShift[idx_c][idx_z];
6387  
6388 -- insert new map note
6389 table.insert(SKM_Data[RealmName][PlayerName].MapData[idx_c][zone_shift], idx_gn);
6390  
6391 -- update global note zone index
6392 SKM_Data[RealmName][PlayerName].GlobalMapData[idx_gn][_SKM._zone] = zone_shift;
6393  
6394 iCountShift = iCountShift + 1;
6395 else
6396 -- insert unchanged map note
6397 table.insert(SKM_Data[RealmName][PlayerName].MapData[idx_c][idx_z], idx_gn);
6398  
6399 iCountNoShift = iCountNoShift + 1;
6400 end
6401 end
6402  
6403 end
6404  
6405  
6406 -- parse enemy information and shift zone where last seen
6407 for idx_enemy, val_enemy in SKM_Data[RealmName][PlayerName].EnemyHistory do
6408 idx_c = val_enemy[_SKM._continent];
6409 idx_z = val_enemy[_SKM._zone];
6410 local bDoShift = true;
6411  
6412 if (idx_c == nil) or (idx_z == nil) then
6413 bDoShift = false;
6414  
6415 if (val_enemy[_SKM._lastView]) then
6416 if (maxDate) then
6417 local iDiffTime = SkM_DiffDate(maxDate, val_enemy[_SKM._lastView]);
6418 if (iDiffTime < 0) then
6419 -- generated after max date, skip
6420 bDoShift = false;
6421 end
6422 end
6423 if (minDate) then
6424 local iDiffTime = SkM_DiffDate(minDate, val_enemy[_SKM._lastView]);
6425 if (iDiffTime > 0) then
6426 -- generated before min date, skip
6427 bDoShift = false;
6428 end
6429 end
6430 end
6431 end
6432  
6433 if (bDoShift) then
6434 zone_shift = ZoneShift[idx_c][idx_z];
6435  
6436 SKM_Data[RealmName][PlayerName].EnemyHistory[idx_enemy][_SKM._zone] = zone_shift;
6437 end
6438 end
6439  
6440 SkM_Trace(FName, 1, "Realm = "..RealmName.." / Player = "..PlayerName.." : Zone Rematch completed, shift count = "..iCountShift..", 'no shift' count = "..iCountNoShift);
6441 end
6442  
6443  
6444 function SkM_AccountZoneRematch(ZoneShift, minDate, maxDate)
6445 local FName = "SkM_AccountZoneRematch";
6446  
6447 if (ZoneShift == nil) then
6448 SkM_Trace(FName, 1, "ZoneShift is nil ! ");
6449 return;
6450 end
6451  
6452 local idx_realm, val_realm, idx_char, val_char;
6453  
6454 for idx_realm, val_realm in SKM_Data do
6455 for idx_char, val_char in SKM_Data[idx_realm] do
6456 if (SKM_Data[idx_realm][idx_char].PlayerName == idx_char) then
6457 SkM_ZoneRematch(idx_realm, idx_char, ZoneShift, minDate, maxDate)
6458 end
6459 end
6460 end
6461 end
6462  
6463  
6464 function SkM_DoMapShift(Source, Dest, ZoneShift, minDate, maxDate)
6465 local FName = "SkM_DoMapShift";
6466  
6467 local sDate = SkM_GetDate();
6468  
6469 if (ZoneShift == nil) then
6470 SkM_Trace(FName, 1, "ZoneShift is nil ! ");
6471 return;
6472 end
6473  
6474 SkM_Trace(FName, 1, "Do shift ("..snil(Source).." -> "..snil(Dest)..")");
6475 SkM_Trace(FName, 1, "Shift interval = ["..snil(minDate).." -> "..snil(maxDate).."]");
6476  
6477 SkM_AccountZoneRematch(ZoneShift, minDate, maxDate);
6478  
6479 if (SKM_Settings.ZoneShifts == nil) then
6480 SKM_Settings.ZoneShifts = {};
6481 end
6482 local ZoneShiftRecord = {
6483 Date = sDate;
6484 Source = Source;
6485 Dest = Dest;
6486 minDate = minDate;
6487 maxDate = maxDate;
6488 };
6489 table.insert(SKM_Settings.ZoneShifts, ZoneShiftRecord);
6490  
6491 end
6492  
6493  
6494 function SkM_GetShiftTable(source, dest)
6495 if (SKM_ShiftTables == nil) then
6496 return nil;
6497 end
6498 if (SKM_ShiftTables[source] == nil) then
6499 return nil;
6500 end
6501 return SKM_ShiftTables[source][dest];
6502 end
6503  
6504  
6505 -- --------------------------------------------------------------------------------------
6506 -- SkM_MapShiftMigration
6507 -- --------------------------------------------------------------------------------------
6508 -- Proceed to all map shift migrations, if needed.
6509 -- If no new zone shift is defined since last migration, nothing will be done.
6510 -- --------------------------------------------------------------------------------------
6511 function SkM_MapShiftMigration()
6512 local FName = "SkM_MapShiftMigration";
6513  
6514 local bShift = false;
6515 local curTime = GetTime();
6516  
6517 -- check if there are map migrations that need be done
6518  
6519 -- NOTE : the following case is not handled and WILL NOT BE !!
6520 -- if user changes his locale interface language while there has been a new locale
6521 -- shift defined on his previous language, before installing the new version of SKMap.
6522 -- too bad !
6523  
6524  
6525 SkM_Trace(FName, 1, "Automatic map migration starting...");
6526  
6527 local bNewLocale = false;
6528 -- if we don't have information of last local language, we assume there were no
6529 -- language change... otherwise, there's nothing we can do...
6530 if (SKM_Settings.LastLocale ~= nil) then
6531 if (SKM_CurrentLocale ~= SKM_Settings.LastLocale) then
6532 bNewLocale = true;
6533 end
6534 else
6535 SKM_Settings.LastLocale = SKM_CurrentLocale;
6536 end
6537  
6538  
6539 -- are there new locale shift defines for previous language ?
6540 local iNbLocalShift = 0;
6541 local iNextLocalShift = 0;
6542 local bNewLocalShift = false;
6543 if (SKM_Locale[SKM_Settings.LastLocale]) and (SKM_Locale[SKM_Settings.LastLocale].LocalShift) then
6544 iNbLocalShift = table.getn(SKM_Locale[SKM_Settings.LastLocale].LocalShift);
6545 end
6546 if (iNbLocalShift > ifnil(SKM_Settings.LastLocalShift, 0)) then
6547 bNewLocalShift = true;
6548 iNextLocalShift = ifnil(SKM_Settings.LastLocalShift, 0) + 1;
6549 end
6550  
6551  
6552 if (bNewLocalShift) then
6553  
6554 if (SKM_Settings.ZoneShiftDest) and (SKM_Settings.ZoneShiftSource) then
6555 -- apply reverse shift first for all data ulterior to next local shift
6556  
6557 SkM_DoMapShift(
6558 SKM_Settings.ZoneShiftDest, SKM_Settings.ZoneShiftSource,
6559 SkM_GetShiftTable(SKM_Settings.ZoneShiftDest, SKM_Settings.ZoneShiftSource),
6560 SKM_Locale[SKM_Settings.LastLocale].LocalShift[iNextShift].DateShift, nil);
6561  
6562 bShift = true;
6563 end
6564  
6565 SKM_Settings.LastLocalShift = 0;
6566 SKM_Settings.LastCurrentShift = 0;
6567  
6568 -- now perform all new local shifts
6569 -- each local shift is performed on all data up to the local shift date
6570 local i;
6571 for i=iNextLocalShift,iNbLocalShift, 1 do
6572  
6573 SkM_Trace(FName, 3, "Performing local shift "..i);
6574 local Source = SKM_Locale[SKM_Settings.LastLocale].LocalShift[i].Source;
6575 local Dest = SKM_Locale[SKM_Settings.LastLocale].LocalShift[i].Dest;
6576 local DateShift = SKM_Locale[SKM_Settings.LastLocale].LocalShift[i].DateShift;
6577  
6578 SkM_DoMapShift(Source, Dest, SkM_GetShiftTable(Source, Dest), nil, DateShift)
6579  
6580 bShift = true;
6581  
6582 SKM_Settings.LastLocalShift = i;
6583 end
6584  
6585 -- now apply current shift if need be
6586 -- moved out of if condition, see below
6587 end
6588  
6589 -- now apply current shift if need be
6590 if (ifnil(SKM_Settings.LastCurrentShift, 0) == 0) then
6591 if (SKM_Locale[SKM_Settings.LastLocale].CurrentShift) then
6592  
6593 local Source = SKM_Locale[SKM_Settings.LastLocale].CurrentShift.Source;
6594 local Dest = SKM_Locale[SKM_Settings.LastLocale].CurrentShift.Dest;
6595  
6596 if (Source == SKM_Settings.ZoneShiftSource) and (Dest == SKM_Settings.ZoneShiftDest) then
6597 SkM_Trace(FName, 3, "current shift already performed");
6598 else
6599  
6600 SkM_Trace(FName, 3, "Perform final shift (current)");
6601  
6602 local DateMin = nil;
6603 local DateMax = nil;
6604  
6605 -- fix for 1.4 bug for DE version
6606 if (SKM_CurrentLocale == "DE") then
6607 DateMax = SKM_Context.DateIndexBug;
6608 end
6609  
6610 SkM_DoMapShift(Source, Dest, SkM_GetShiftTable(Source, Dest), DateMin, DateMax);
6611  
6612 bShift = true;
6613 end
6614  
6615 SKM_Settings.LastCurrentShift = 1;
6616  
6617 SKM_Settings.ZoneShiftSource = Source;
6618 SKM_Settings.ZoneShiftDest = Dest;
6619 else
6620 -- no current shift
6621 SKM_Settings.ZoneShiftSource = nil;
6622 SKM_Settings.ZoneShiftDest = nil;
6623 end
6624 end
6625  
6626  
6627 if (bNewLocale) then
6628  
6629 if (SKM_Locale[SKM_CurrentLocale]) and (SKM_Locale[SKM_CurrentLocale].CurrentShift) then
6630 SKM_Settings.ZoneShiftSource = SKM_Locale[SKM_CurrentLocale].CurrentShift.Source;
6631 SKM_Settings.ZoneShiftDest = SKM_Locale[SKM_CurrentLocale].CurrentShift.Dest;
6632 else
6633 -- no current shift
6634  
6635 SKM_Settings.ZoneShiftSource = nil;
6636 SKM_Settings.ZoneShiftDest = nil;
6637 end
6638  
6639 -- now we can safely store the new language as the current one.
6640 SKM_Settings.LastLocale = SKM_CurrentLocale;
6641  
6642 -- also store LastLocalShift as the latest local shift, if any
6643 if (SKM_Locale[SKM_Settings.LastLocale]) and (SKM_Locale[SKM_Settings.LastLocale].LocalShift) then
6644 iNbLocalShift = table.getn(SKM_Locale[SKM_Settings.LastLocale].LocalShift);
6645 SKM_Settings.LastLocalShift = iNbLocalShift;
6646 else
6647 SKM_Settings.LastLocalShift = nil;
6648 end
6649  
6650 end
6651  
6652  
6653 SkM_Trace(FName, 3, "Zone Shift performed ? "..snil(bShift));
6654  
6655 if (bShift) then
6656 local endTime = GetTime();
6657 local elapsedTime = math.floor(100 * (endTime - curTime)) / 100;
6658 SkM_ChatMessageCol("Zone order shift(s) performed, elapsed time : "..elapsedTime.." s");
6659 end
6660  
6661 end
6662  
6663  
6664 function SkM_ReverseZoneShift(ZoneShift)
6665 local NewShift = { };
6666  
6667 local i,j;
6668 for i=1,table.getn(ZoneShift),1 do
6669 local Line = { };
6670 for j=1,table.getn(ZoneShift[i]),1 do
6671 Line[ZoneShift[i][j]] = j;
6672 end
6673 NewShift[i] = Line;
6674 end
6675 return NewShift;
6676 end
6677  
6678  
6679 function SkM_CharDataMigration(Ver, RealmName, PlayerName)
6680 local FName = "SkM_CharDataMigration";
6681  
6682 -- Migration of EnemyHistory
6683 if (SKM_Data[RealmName][PlayerName].EnemyHistory) then
6684 local idx_enemy, val_enemy;
6685 for idx_enemy, val_enemy in SKM_Data[RealmName][PlayerName].EnemyHistory do
6686 local EnemyMigr = {};
6687 local idx, val;
6688 for idx, val in SKM_IndexMigr[Ver].EnemyHistory do
6689 if (val_enemy[val.Old]) then
6690 EnemyMigr[val.New] = val_enemy[val.Old];
6691 end
6692 end
6693  
6694 SKM_Data[RealmName][PlayerName].EnemyHistory[idx_enemy] = nil;
6695 SKM_Data[RealmName][PlayerName].EnemyHistory[idx_enemy] = EnemyMigr;
6696  
6697 -- now migration of race and class to indexes
6698 local sRace = SKM_Data[RealmName][PlayerName].EnemyHistory[idx_enemy][_SKM._race];
6699 local sClass = SKM_Data[RealmName][PlayerName].EnemyHistory[idx_enemy][_SKM._class];
6700 local id_race = SKM_Context.Race.StringToIndex[sRace];
6701 local id_class = SKM_Context.Class.StringToIndex[sClass];
6702 SKM_Data[RealmName][PlayerName].EnemyHistory[idx_enemy][_SKM._race] = id_race;
6703 SKM_Data[RealmName][PlayerName].EnemyHistory[idx_enemy][_SKM._class] = id_class;
6704 end
6705 end
6706  
6707 -- Migration of DuelHistory
6708 if (SKM_Data[RealmName][PlayerName].DuelHistory) then
6709 local idx_enemy, val_enemy;
6710 for idx_enemy, val_enemy in SKM_Data[RealmName][PlayerName].DuelHistory do
6711 local DuelMigr = {};
6712 local idx, val;
6713 for idx, val in SKM_IndexMigr[Ver].DuelHistory do
6714 if (val_enemy[val.Old]) then
6715 DuelMigr[val.New] = val_enemy[val.Old];
6716 end
6717 end
6718  
6719 SKM_Data[RealmName][PlayerName].DuelHistory[idx_enemy] = nil;
6720 SKM_Data[RealmName][PlayerName].DuelHistory[idx_enemy] = DuelMigr;
6721  
6722 -- now migration of race and class to indexes
6723 local sRace = SKM_Data[RealmName][PlayerName].DuelHistory[idx_enemy][_SKM._race];
6724 local sClass = SKM_Data[RealmName][PlayerName].DuelHistory[idx_enemy][_SKM._class];
6725 local id_race = SKM_Context.Race.StringToIndex[sRace];
6726 local id_class = SKM_Context.Class.StringToIndex[sClass];
6727 SKM_Data[RealmName][PlayerName].DuelHistory[idx_enemy][_SKM._race] = id_race;
6728 SKM_Data[RealmName][PlayerName].DuelHistory[idx_enemy][_SKM._class] = id_class;
6729 end
6730 end
6731  
6732 -- Migration of GuildHistory
6733 if (SKM_Data[RealmName][PlayerName].GuildHistory) then
6734 local idx_guild, val_guild;
6735 for idx_guild, val_guild in SKM_Data[RealmName][PlayerName].GuildHistory do
6736 local GuildMigr = {};
6737 local idx, val;
6738 for idx, val in SKM_IndexMigr[Ver].GuildHistory do
6739 if (val_guild[val.Old]) then
6740 GuildMigr[val.New] = val_guild[val.Old];
6741 end
6742 end
6743  
6744 SKM_Data[RealmName][PlayerName].GuildHistory[idx_guild] = nil;
6745 SKM_Data[RealmName][PlayerName].GuildHistory[idx_guild] = GuildMigr;
6746 end
6747 end
6748  
6749 -- Migration of BGStats
6750 if (SKM_Data[RealmName][PlayerName].BGStats) then
6751 local idx_zone, val_zone;
6752 for idx_zone, val_zone in SKM_Data[RealmName][PlayerName].BGStats do
6753 local idx_date, val_date;
6754 for idx_date, val_date in SKM_Data[RealmName][PlayerName].BGStats[idx_zone] do
6755 local StatMigr = {};
6756 local idx, val;
6757 for idx, val in SKM_IndexMigr[Ver].BGStatDate do
6758 if (val_date[val.Old]) then
6759 StatMigr[val.New] = val_date[val.Old];
6760 end
6761 end
6762  
6763 SKM_Data[RealmName][PlayerName].BGStats[idx_zone][idx_date] = nil;
6764 SKM_Data[RealmName][PlayerName].BGStats[idx_zone][idx_date] = StatMigr;
6765 end
6766 end
6767 end
6768  
6769 -- Migration of GlobalMapData
6770 if (SKM_Data[RealmName][PlayerName].GlobalMapData) then
6771 local iNbNotes = table.getn(SKM_Data[RealmName][PlayerName].GlobalMapData);
6772 local i;
6773 for i=1, iNbNotes, 1 do
6774 local Note = SKM_Data[RealmName][PlayerName].GlobalMapData[i];
6775 local NoteMigr = {};
6776 local idx, val;
6777 for idx, val in SKM_IndexMigr[Ver].GlobalMapData do
6778 if (Note[val.Old]) then
6779 NoteMigr[val.New] = Note[val.Old];
6780 end
6781 end
6782  
6783 SKM_Data[RealmName][PlayerName].GlobalMapData[i] = nil;
6784  
6785 SKM_Data[RealmName][PlayerName].GlobalMapData[i] = NoteMigr;
6786  
6787 local StoredInfo = NoteMigr[_SKM._storedInfo];
6788 if (StoredInfo) then
6789 local InfoMigr = {};
6790 for idx, val in SKM_IndexMigr[Ver].StoredInfo do
6791 if (StoredInfo[val.Old]) then
6792 InfoMigr[val.New] = StoredInfo[val.Old];
6793 end
6794 end
6795 InfoMigr[_SKM._type] = SKM_IndexMigr[Ver].RecordType[InfoMigr[_SKM._type]];
6796 InfoMigr[_SKM._enemyType] = SKM_IndexMigr[Ver].EnemyType[InfoMigr[_SKM._enemyType]];
6797  
6798 -- fix level if not "level up" event
6799 if not (InfoMigr[_SKM._type] == _SKM._levelUp
6800 or InfoMigr[_SKM._type] == _SKM._creatureKill_Target
6801 or InfoMigr[_SKM._type] == _SKM._creatureKill_Xp
6802 ) then
6803 InfoMigr[_SKM._level] = nil;
6804 end
6805  
6806 SKM_Data[RealmName][PlayerName].GlobalMapData[i][_SKM._storedInfo] = InfoMigr;
6807 end
6808 end
6809 end
6810  
6811 -- fix battleground stats bug
6812 if (SKM_Data[RealmName][PlayerName].BGStats) then
6813 local idx_bg, val_bg
6814 for idx_bg, val_bg in SKM_Data[RealmName][PlayerName].BGStats do
6815 if not (intable(idx_bg, SKM_BATTLEGROUNDS)) then
6816 SKM_Data[RealmName][PlayerName].BGStats[idx_bg] = nil;
6817 end
6818 end
6819 end
6820  
6821 -- fix wrong "level up" records
6822 if (SKM_Data[RealmName][PlayerName].GlobalMapData) then
6823 local i = 1;
6824 local iMaxLevel = 0;
6825 local iNbNotes = table.getn(SKM_Data[RealmName][PlayerName].GlobalMapData);
6826 while (i < iNbNotes) do
6827 local Note = SKM_Data[RealmName][PlayerName].GlobalMapData[i];
6828  
6829 local StoredInfo = Note[_SKM._storedInfo];
6830 if (StoredInfo) and (StoredInfo[_SKM._type] == _SKM._levelUp) then
6831  
6832 if (StoredInfo[_SKM._level] > 1) and (StoredInfo[_SKM._level] > iMaxLevel) then
6833 iMaxLevel = StoredInfo[_SKM._level];
6834 i = i + 1;
6835 else
6836 -- remove from GlobalMapData and from MapData
6837 SkM_Trace(FName, 3, "Previous max level = "..iMaxLevel..", Note level up = "..StoredInfo[_SKM._level]);
6838 SkM_Trace(FName, 3, "Removing note for "..PlayerName.." : global index = "..i);
6839  
6840 SkM_DeleteNote(RealmName, PlayerName, i);
6841 iNbNotes = iNbNotes - 1;
6842 end
6843  
6844 else
6845 i = i + 1;
6846 end
6847 end
6848 end
6849  
6850  
6851  
6852 end
6853  
6854  
6855 function SkM_AccountDataMigration(Ver)
6856 local FName = "SkM_AccountDataMigration";
6857  
6858 local idx_realm, val_realm, idx_char, val_char;
6859 for idx_realm, val_realm in SKM_Data do
6860 for idx_char, val_char in SKM_Data[idx_realm] do
6861 if (SKM_Data[idx_realm][idx_char].PlayerName == idx_char) then
6862 SkM_CharDataMigration(Ver, idx_realm, idx_char);
6863 end
6864 end
6865 end
6866 end
6867  
6868  
6869 function SkM_DataModelMigration()
6870 local FName = "SkM_DataModelMigration";
6871  
6872 local curTime = GetTime();
6873 local bMigr = false;
6874  
6875 if (SKM_Settings.SavedDataVersion == nil) then
6876 SKM_Settings.SavedDataVersion = 1;
6877 end
6878  
6879 if (SKM_Settings.SavedDataVersion < 2) then
6880 SkM_AccountDataMigration(2);
6881 SKM_Settings.SavedDataVersion = 2;
6882 bMigr = true;
6883 end
6884  
6885 if (bMigr) then
6886 local endTime = GetTime();
6887 local elapsedTime = math.floor(100 * (endTime - curTime)) / 100;
6888 SkM_ChatMessageCol("Data migrated to v."..SKM_Settings.SavedDataVersion..", elapsed time : "..elapsedTime.." s");
6889 end
6890  
6891 end
6892  
6893  
6894 -- function provided to fix MapData indexes from GlobalMapData (which is supposed to be
6895 -- correct !)
6896 function SkM_FixMapIndexes(RealmName, PlayerName)
6897 local FName = "SkM_FixMapIndexes";
6898 local idx_c, val_c, idx_z, val_z, idx_gn;
6899  
6900 SkM_Trace(FName, 3, "Realm = "..snil(RealmName).. " / Player = "..snil(PlayerName));
6901  
6902 -- reinitialize map data
6903 SKM_Data[RealmName][PlayerName].MapData = { };
6904  
6905 for idx_c, val_c in SKM_Context.Continents do
6906 SKM_Data[RealmName][PlayerName].MapData[idx_c] = { };
6907  
6908 for idx_z, val_z in SKM_Context.Zones[idx_c] do
6909 SKM_Data[RealmName][PlayerName].MapData[idx_c][idx_z] = { };
6910 end
6911 end
6912  
6913 -- parse global map data to rebuild local map data
6914 if (SKM_Data[RealmName][PlayerName].GlobalMapData) then
6915 for idx_gn, Note in SKM_Data[RealmName][PlayerName].GlobalMapData do
6916 idx_c = Note[_SKM._continent];
6917 idx_z = Note[_SKM._zone];
6918  
6919 -- insert new map note
6920 table.insert(SKM_Data[RealmName][PlayerName].MapData[idx_c][idx_z], idx_gn);
6921 end
6922 end
6923  
6924 end
6925  
6926 -- function provided to fix MapData indexes from GlobalMapData (which is supposed to be
6927 -- correct !)
6928 function SkM_AccountFixMapIndexes()
6929 local idx_realm, val_realm, idx_char, val_char;
6930  
6931 for idx_realm, val_realm in SKM_Data do
6932 for idx_char, val_char in SKM_Data[idx_realm] do
6933 if (SKM_Data[idx_realm][idx_char].PlayerName == idx_char) then
6934 SkM_FixMapIndexes(idx_realm, idx_char);
6935 end
6936 end
6937 end
6938 end
6939  
6940  
6941 -- get date of first record affected by the index bug since 1.4
6942 -- needed to fix german data !
6943 function SkM_GetDateIndexBug(bIgnoreLocale)
6944 local FName = "SkM_GetDateIndexBug";
6945  
6946 SKM_Context.DateIndexBug = nil;
6947  
6948 local iBug = 0;
6949 local iOK = 0;
6950  
6951 if not (bIgnoreLocale) then
6952 if (SKM_CurrentLocale ~= "DE") then
6953 SkM_Trace(FName, 1, "Non DE locale");
6954 return;
6955 end
6956 end
6957  
6958 local idx_realm, val_realm, idx_char, val_char;
6959 local idx_c, val_c, idx_z, val_z, idx_n, val_n, Note;
6960  
6961 local r_c, r_z, r_n, r_gn, r_realm, r_char;
6962  
6963 for idx_realm, val_realm in SKM_Data do
6964 for idx_char, val_char in SKM_Data[idx_realm] do
6965 if (SKM_Data[idx_realm][idx_char].PlayerName == idx_char) then
6966 for idx_c, val_c in SKM_Data[idx_realm][idx_char].MapData do
6967 for idx_z, val_z in SKM_Data[idx_realm][idx_char].MapData[idx_c] do
6968 for idx_n, val_n in SKM_Data[idx_realm][idx_char].MapData[idx_c][idx_z] do
6969 Note = SKM_Data[idx_realm][idx_char].GlobalMapData[val_n];
6970 if not ((Note[_SKM._continent] == idx_c) and (Note[_SKM._zone] == idx_z)) then
6971 -- bad index !
6972 iBug = iBug + 1;
6973 if (Note[_SKM._storedInfo]) and (Note[_SKM._storedInfo][_SKM._date]) then
6974  
6975 if (SKM_Context.DateIndexBug == nil) then
6976 SKM_Context.DateIndexBug = Note[_SKM._storedInfo][_SKM._date];
6977 r_c = idx_c; r_z = idx_z; r_n = idx_n; r_gn = val_n; r_realm = idx_realm; r_char = idx_char;
6978 else
6979 local iDiffTime = SkM_DiffDate(SKM_Context.DateIndexBug, Note[_SKM._storedInfo][_SKM._date]);
6980 if (iDiffTime ~= nil) and (iDiffTime > 0) then
6981 SKM_Context.DateIndexBug = Note[_SKM._storedInfo][_SKM._date];
6982 r_c = idx_c; r_z = idx_z; r_n = idx_n; r_gn = val_n; r_realm = idx_realm; r_char = idx_char;
6983 end
6984 end
6985 end
6986 else
6987 iOK = iOK + 1;
6988 end
6989 end
6990 end
6991 end
6992  
6993 end
6994 end
6995 end
6996  
6997 SkM_Trace(FName, 1, "OK = "..iOK.." / Bugged = "..iBug);
6998 SkM_Trace(FName, 1, "DateIndexBug = ".. snil(SKM_Context.DateIndexBug));
6999 SkM_Trace(FName, 1, "realm = "..snil(r_realm).." / char = "..snil(r_char));
7000 SkM_Trace(FName, 1, "cont. = "..snil(r_c).." / zone = "..snil(r_z).." / note = "..snil(r_n).." / gn = "..snil(r_gn));
7001 end
7002  
7003  
7004 function SkM_DataFixMapIndexes()
7005 if (SKM_Settings.FixMapIndexes == nil) then
7006 SkM_GetDateIndexBug();
7007  
7008 --if (SKM_CurrentLocale ~= "EN") then
7009 SkM_AccountFixMapIndexes();
7010 --end
7011 local sDate = SkM_GetDate();
7012 SKM_Settings.FixMapIndexes = sDate;
7013 end
7014 end
7015  
7016  
7017 -- keep track of history of versions installed.
7018 function SkM_RecordVersionHistory()
7019 local sLastVer;
7020 if (SKM_Settings.VersionHistory == nil) then
7021 SKM_Settings.VersionHistory = {};
7022 else
7023 local iCount = table.getn(SKM_Settings.VersionHistory);
7024 if (iCount > 0) then
7025 sLastVer = SKM_Settings.VersionHistory[iCount].Version;
7026 end
7027 end
7028 if (sLastVer ~= SKM_VERSION) then
7029 local sDate = SkM_GetDate();
7030 local VersionRecord = {
7031 Date = sDate;
7032 Version = SKM_VERSION;
7033 };
7034 table.insert(SKM_Settings.VersionHistory, VersionRecord);
7035 end
7036 end
7037  
7038  
7039  
7040 -- nchnch - new
7041 -- --------------------------------------------------------------------------------------
7042  
7043  
7044  
7045 -- --------------------------------------------------------------------------------------
7046 -- SkM_GetGuildChannelName
7047 -- --------------------------------------------------------------------------------------
7048 -- Build a unique channel name from the realm name and the player guild name
7049 -- --------------------------------------------------------------------------------------
7050 function SkM_GetGuildChannel()
7051 local FName = "SkM_GetGuildChannel";
7052  
7053 local sName;
7054  
7055 --if (not SKM_Context.RealmName) then
7056 -- SkM_Trace(FName, 1, "Realm not known !");
7057 -- return nil;
7058 --end
7059  
7060 local sGuildName = GetGuildInfo(SKM_UNIT_PLAYER);
7061 if (not sGuildName) then
7062 SkM_Trace(FName, 2, "Not in a guild");
7063 return nil;
7064 end
7065  
7066 sName = SKM_GuildChannelPrefix.." - "..sGuildName;
7067  
7068 SkM_Trace(FName, 3, "Channel name : "..snil(sName));
7069 return sName;
7070 end
7071  
7072  
7073 -- --------------------------------------------------------------------------------------
7074 -- SkM_IsNameInGuild
7075 -- --------------------------------------------------------------------------------------
7076  
7077 -- Check if given player name is in guild/
7078 -- --------------------------------------------------------------------------------------
7079 function SkM_IsNameInGuild(sName)
7080 return ( (sName == _PlayerName)
7081 or (intable(sName, SKM_Context.GuildList))
7082 );
7083 end
7084  
7085  
7086 function SkM_JoinGuildChannel()
7087 local FName = "SkM_JoinGuildChannel";
7088 local sChannel = SkM_GetGuildChannel();
7089  
7090 if (not sChannel) then
7091 SkM_Trace(FName, 1, "Unable to get SKMap guild channel name");
7092 return false;
7093 end
7094  
7095 JoinChannelByName(sChannel, nil, nil);
7096  
7097 SKM_Context.GuildChannel = sChannel;
7098 return true;
7099 end
7100  
7101  
7102 function SkM_LeaveGuildChannel()
7103 local FName = "SkM_LeaveGuildChannel";
7104  
7105 if (not SKM_Context.GuildChannel) then
7106 SkM_Trace(FName, 1, "SKMap guild channel name not defined");
7107 return;
7108 end
7109  
7110 LeaveChannelByName(SKM_Context.GuildChannel);
7111 SKM_Context.GuildChannel = nil;
7112 end
7113  
7114  
7115  
7116  
7117 function SkM_GetChannelIndex(sName)
7118 local FName = "SkM_GetChannelIndex";
7119  
7120 if (not sName) then
7121 SkM_Trace(FName, 1, "Channel name not specified");
7122 return nil;
7123 end
7124  
7125 SkM_Trace(FName, 3, "Looking for index for channel : "..snil(sName));
7126  
7127 local MyChannelList = GetChannelList();
7128  
7129 local idx, val;
7130 for idx, val in MyChannelList do
7131 if (val == sName) then
7132 SkM_Trace(FName, 3, "Channel number = "..idx);
7133 return idx;
7134 end
7135 end
7136 SkM_Trace(FName, 2, "Channel not found");
7137 return nil;
7138 end
7139  
7140  
7141 function SkM_SendGuildChannelMessage(sMsg)
7142 local FName = "SkM_SendGuildChannelMessage";
7143 local iChannelIndex = SkM_GetChannelIndex(SKM_Context.GuildChannel);
7144  
7145 if (iChannelIndex) then
7146 SendChatMessage(sMsg, "CHANNEL", nil, iChannelIndex);
7147 end
7148 end
7149  
7150  
7151 function SkM_GuildChannelMessage(iCode, ...)
7152 local FName = "SkM_GuildChannelMessage";
7153 local sMsg;
7154 local sParam = "";
7155  
7156 local i;
7157 for i=1, arg.n do
7158 local sField = SkM_FormatMessageField(arg[i]);
7159 sParam = sParam..sField.." ";
7160 end
7161  
7162 sMsg = string.format("<SKM=%d>%s</SKM>", iCode, sParam);
7163  
7164 SkM_Trace(FName, 3, "Formated message = "..snil(sMsg));
7165  
7166 SkM_SendGuildChannelMessage(sMsg);
7167 end
7168  
7169  
7170 function SkM_FormatMessageField(sField)
7171 local sOutput = sField;
7172  
7173 sOutput = string.gsub(sOutput, "\\", "\\\\");
7174 sOutput = string.gsub(sOutput, "\"", "\\\"");
7175  
7176 return sOutput;
7177 end
7178  
7179  
7180 function SkM_GetMessageFields(sMsg)
7181 local FName = "SkM_GetMessageFields";
7182  
7183 local i=1;
7184 local iLen = string.len(sMsg);
7185 local iStartField;
7186 local bSpecial = false;
7187 local bInField = false;
7188 local sField = "";
7189 local Fields = { };
7190  
7191 while (i <= iLen) do
7192 local sChar = string.sub(sMsg, i, i);
7193  
7194 if (not bInField) then
7195 if (sChar == "\"") then
7196 bInField = true;
7197 elseif (sChar == " ") then
7198 -- skip
7199 else
7200 -- error
7201 SkM_Trace(FName, 1, "Unexpected character : '"..sChar.."' at position "..i);
7202 return nil;
7203 end
7204 else
7205  
7206 if (sChar == "\\") then
7207 if ( bSpecial) then
7208 sField = sField..sChar;
7209 bSpecial = false;
7210 else
7211 bSpecial = true;
7212 end
7213 else
7214 if (sChar == "\"") then
7215 if (bSpecial) then
7216 sField = sField..sChar;
7217 bSpecial = false;
7218 else
7219 table.insert(Fields, sField);
7220 sField = "";
7221 bInField = false;
7222 end
7223 else
7224 sField = sField..sChar;
7225 end
7226  
7227 end
7228 end
7229 i = i + 1;
7230 end
7231 return Fields;
7232 end
7233  
7234  
7235 function SkM_ProcessChannelMessage(iCode, sValue)
7236 local FName = "SkM_ProcessChannelMessage";
7237  
7238 local Fields = SkM_GetMessageFields(sValue);
7239  
7240 if (iCode == 1) then
7241 -- message = update player information
7242 if (table.getn(Fields) == 4) then
7243 local sName = Fields[1];
7244 local sRace = Fields[2];
7245  
7246 local sClass = Fields[3];
7247 local sLevel = Fields[4];
7248 SkM_Trace(FName, 3, "Player update: Name="..sName..", Race="..sRace..", Class="..sClass..", Lvl="..sLevel);
7249  
7250  
7251 end
7252 else
7253  
7254 end
7255 end
7256  
7257  
7258 function SkM_HandleChannelMessage(sMsg, sChannel, sSender)
7259 local FName = "SkM_HandleChannelMessage";
7260  
7261 if (sChannel == SKM_Context.GuildChannel) then
7262 SkM_Trace(FName, 3, "Message = "..snil(sMsg));
7263  
7264  
7265 -- check if sender is a guild member, if not he should not be sending
7266 -- messages on this channel !
7267  
7268 if (not SkM_IsNameInGuild(sSender)) then
7269 SkM_Trace(FName, 2, "Sender : "..snil(sSender)..", not in your guild !");
7270 else
7271 -- now handle the message
7272 --for iCode, sValue in string.gfind(sMsg, SKM_Context.Pattern.) do
7273 --"<SKM=%d>%s</SKM>"
7274 for iCode, sValue in string.gfind(sMsg, "<SKM=([0-9]+)>(.+)</SKM>") do
7275 if (sCode and sValue) then
7276 SkM_ProcessChannelMessage(iCode, sValue);
7277 end
7278 end
7279 end
7280 end
7281 end
7282  
7283  
7284 -- --------------------------------------------------------------------------------------
7285 -- SkM_BuildGuildList
7286 -- --------------------------------------------------------------------------------------
7287 -- Build a list of players currently in the guild.
7288 -- --------------------------------------------------------------------------------------
7289 function SkM_BuildGuildList()
7290 local FName = "SkM_BuildGuildList";
7291  
7292 SkM_Trace(FName, 2, "Rebuild guild list");
7293  
7294 SKM_Context.GuildList = { };
7295  
7296 local iNumGuildMembers = GetNumGuildMembers();
7297  
7298 local i;
7299 for i=1, iNumGuildMembers, 1 do
7300 --Usage: name, rank, rankIndex, level, class, zone, group, note, officernote, online = GetGuildRosterInfo(index);
7301 local sName = GetGuildRosterInfo(i);
7302  
7303 if (sName) then
7304 table.insert(SKM_Context.GuildList, sName);
7305 end
7306 end
7307  
7308 end
7309  
7310  
7311  
7312  
7313 function SkM_AddGuildMessageToQueue(sMsg, iPriority)
7314 local FName = "SkM_AddGuildMessageToQueue";
7315  
7316 if (SKM_Context.QueueSendMessage == nil) then
7317 SKM_Context.QueueSendMessage = { };
7318 end
7319  
7320 local iMessagePriority = ifnil(iPriority, 0);
7321  
7322 if (iMessagePriority == 0) then
7323 table.insert(SKM_Context.QueueSendMessage, { Message = sMsg; Priority = iMessagePriority } );
7324 return;
7325 end
7326  
7327 local i;
7328 local iQueueSize = table.getn(SKM_Context.QueueSendMessage);
7329 for i=1,iQueueSize,1 do
7330 if (SKM_Context.QueueSendMessage[i].Priority < iMessagePriority) then
7331 table.insert(SKM_Context.QueueSendMessage, { Message = sMsg; Priority = iMessagePriority }, i);
7332 return;
7333 end
7334 end
7335 table.insert(SKM_Context.QueueSendMessage, { Message = sMsg; Priority = iMessagePriority } );
7336  
7337 end
7338  
7339  
7340  
7341 function SkM_ProcessQueue()
7342 local FName = "SkM_ProcessQueue";
7343  
7344 --local sDate = SkM_GetDate();
7345 local sTime = GetTime();
7346 local bProcess = false;
7347  
7348 if (SKM_Context.QueueLastSentMessage == nil) then
7349 bProcess = true;
7350 else
7351 local iDiffTime = sTime - SKM_Context.QueueLastSentMessage;
7352  
7353 --if (iDiffTime > SkM_GetOption("SendMessageMinDelay")) then
7354 if (iDiffTime > 1) then
7355 bProcess = true;
7356 end
7357 end
7358  
7359 if (bProcess) then
7360 local sMsg = SKM_Context.QueueSendMessage[1].Message;
7361 table.remove(SKM_Context.QueueSendMessage, 1);
7362  
7363 SkM_SendGuildChannelMessage(sMsg);
7364  
7365 SKM_Context.QueueLastSentMessage = sTime;
7366 end
7367  
7368 end
7369  
7370  
7371  
7372 function SkM_SendWarList()
7373 local FName = "SkM_SendWarList";
7374 local idx, val;
7375 for idx, val in SKM_Data[_RealmName][_PlayerName].EnemyHistory do
7376 -- nchnch
7377  
7378 if (val[_SKM._atWar]) then
7379 -- local sMsg =
7380  
7381 SkM_AddGuildMessageToQueue(sMsg, 0);
7382 end
7383  
7384 end
7385  
7386 end
7387  
7388  
7389  
7390  
7391 -- TEST functions
7392  
7393 function SkM_CharCode(sIn)
7394 --local List = { };
7395 local sOut = "";
7396 local i;
7397 for i=1, string.len(sIn), 1 do
7398 --List.insert(string.byte(sIn, i));
7399 sOut = sOut.."\\";
7400 sOut = sOut..string.byte(sIn, i);
7401 end
7402 --return List;
7403 return sOut;
7404 end
7405  
7406 function SkM_TestHonor()
7407 local FName = "SkM_TestHonor";
7408 local sMsg = "Gorwald dies, honorable kill Rank: First Sergeant (Estimated Honor Points: 67)";
7409  
7410  
7411 for sFoe, sRank in string.gfind(sMsg, SKM_Context.Pattern.Honor_Kill) do
7412 if (sFoe and sRank) then
7413 SkM_Trace(FName, 0, "Honor_Kill : Foe = "..sFoe..", Rank = "..sRank);
7414  
7415 SkM_Trace(FName, 0, "Enemy player death detected (from chat, honor) : "..snil(sFoe));
7416 --SkM_PvpEnemyDeath(sFoe, true, sRank);
7417 end
7418 end
7419  
7420 end
7421  
7422  
7423 function SkM_RecMapZones()
7424 local FName = "SkM_RecMapZones";
7425  
7426 SkM_ClearDebugRecord();
7427 SkM_SetDebugLevel(1);
7428 SkM_StartDebugRecord();
7429  
7430 local lv_Continents = { GetMapContinents() } ;
7431 for idx, val in lv_Continents do
7432 SkM_Trace(FName, 1, "Continent "..idx.." = "..val);
7433 local lv_Zones = { GetMapZones(idx) };
7434 for idx2, val2 in lv_Zones do
7435 SkM_Trace(FName, 1, "Cont. "..idx..", Zone "..idx2.." = "..val2);
7436 end
7437 end
7438  
7439 SkM_StopDebugRecord();
7440 SkM_SetDebugLevel(-1);
7441 end
7442  
7443  
7444  
7445 function test()
7446 local FName = "test";
7447 local idx, val;
7448 for idx, val in getfenv() do
7449 if (type(val) == "string" ) then
7450 SkM_Trace(FName, 0, idx.." = "..val);
7451 end
7452 end
7453 end
7454  
7455 -- OBSOLETE stuff
7456  
7457  
7458  
7459