-- 09/04/2005 12:30:49 PIng: Replace hardcoded strings for UI by localized variables -- 09/04/2005 12:31:41 PIng: Bug fix. Replace ShM_PrintMessage by SkM_PrintMessage -- 09/04/2005 15:52:09 PIng: Add guild support -- 09/04/2005 16:18:34 PIng: Update war info on target frame when status is changed SKM_UNIT_PLAYER = "player"; SKM_UNIT_TARGET = "target"; SKM_UNIT_MOUSEOVER = "mouseover"; SKM_UNIT_PARTY = "party"; SKM_UNIT_PET = "pet"; SKM_UNIT_PARTY_1 = SKM_UNIT_PARTY.."1"; SKM_UNIT_PARTY_2 = SKM_UNIT_PARTY.."2"; SKM_UNIT_PARTY_3 = SKM_UNIT_PARTY.."3"; SKM_UNIT_PARTY_4 = SKM_UNIT_PARTY.."4"; _RealmName = nil; _PlayerName = nil; SKM_MAX_MAP_NOTES = 200; local TXT_NIL = "nil"; local SKM_MESSAGE_PREFIX = "SKM: "; local SKM_TRACE_MODE_NONE = 0; local SKM_TRACE_MODE_PRINT = 1; local SKM_TRACE_MODE_CHATMSG = 2; local SKM_TRACE_NIL = false; local TXT_NIL = "nil"; --local SKM_TRACE_MODE = SKM_TRACE_MODE_NONE; --local SKM_TRACE_MODE = SKM_TRACE_MODE_PRINT; local SKM_TRACE_MODE = SKM_TRACE_MODE_CHATMSG; -- number of days in a month for a non leap year local DaysInMonth = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; -- list of leap years for the first half of the 21st century local LeapYears = { 2000, 2004, 2008, 2012, 2016, 2020, 2024, 2028, 2032, 2036, 2040, 2044, 2048 }; -- List of ennemy player factions races (alliance and horde) -- (could easily add more by altering the list, though it probably won't happen !) SKM_PlayerFaction = { { Faction = "Alliance", RaceList = { SKM_RACE.Dwarf, SKM_RACE.Gnome, SKM_RACE.Human, SKM_RACE.NightElf } }; { Faction = "Horde", RaceList = { SKM_RACE.Orc, SKM_RACE.Tauren, SKM_RACE.Troll, SKM_RACE.Undead } }; }; SKM_HonorKillPerDay = 4; SKM_ToStandardCase = { ["A"] = { "\195\128", "\195\129", "\195\130", "\195\131", "\195\132", "\195\133" }, ["E"] = { "\195\136", "\195\137", "\195\138", "\195\139"}, ["I"] = { "\195\140", "\195\141", "\195\142", "\195\143"}, ["O"] = { "\195\146", "\195\147", "\195\148", "\195\149", "\195\150", "\195\152" }, ["U"] = { "\195\153", "\195\154", "\195\155", "\195\156" }, ["Y"] = { "\195\157", "\195\191", "\197\184" }, ["C"] = { "\195\135" }, ["D"] = { "\195\144" }, ["N"] = { "\195\145" }, ["S"] = { "\197\160", "\197\161"} }; SKM_GuildChannelPrefix = "SKM"; -- OLD table indexes - before data migration - SKMap 1.4 -- ----------------------------------------------------- _SKM_OLD = { _name = "name"; _class = "class"; _guild = "guild"; _race = "race"; _level = "level"; _playerNote = "playerNote"; _playerKill = "playerKill"; _playerAssistKill = "playerAssistKill"; _playerFullKill = "playerFullKill"; _honorKill = "honorKill"; _honorCount = "honorCount"; _honorLastKill = "honorLastKill"; _rank = "rank"; _meetCount = "meetCount"; _atWar = "atWar"; -- _guildAtWar = "guildAtWar"; _warDate = "warDate"; _continent = "continent"; _zone = "zone"; _xPos = "xPos"; _yPos = "yPos"; _zoneName = "zoneName"; -- _lastUpdate = "lastUpdate"; _lastView = "lastView"; _lastPlayerViewed = "lastPlayerViewed"; _enemyKillPlayer = "enemyKillPlayer"; _enemyKillBG = "enemyKillBG"; _playerBGKill = "playerBGKill"; _members = "members"; _type = "type"; _date = "date"; _enemyType = "enemyType"; _enemyPlayer = "enemyPlayer"; _enemyCreature = "enemyCreature"; _playerDeath = "playerDeath"; _playerDeathPvP = "playerDeathPvP"; _playerDeathPvE = "playerDeathPvE"; _creatureKill_Target = "creatureKill_Target"; _creatureKill_Xp = "creatureKill_Xp"; _levelUp = "levelUp"; _loneWolfKill = "loneWolfKill"; _storedInfo = "storedInfo"; _win = "win"; _loss = "loss"; _duel = "duel"; _lastDuel = "lastDuel"; -- _score = "score"; }; -- new table indexes - after data migration - SKMap 1.4 -- ---------------------------------------------------- _SKM = { _name = "Na"; _class = "Cl"; _guild = "Gu"; _race = "Ra"; _level = "Lv"; _playerNote = "PlN"; _playerKill = "PK"; _playerAssistKill = "PaK"; _playerFullKill = "PfK"; _honorKill = "hK"; _honorCount = "hC"; _honorLastKill = "hLK"; _rank = "Rk"; _meetCount = "mC"; _atWar = "Wr"; _guildAtWar = "gWr"; -- not saved _warDate = "WD"; _continent = "Co"; _zone = "Zo"; _xPos = "x"; _yPos = "y"; _zoneName = "ZN"; _lastUpdate = "lU"; -- not saved _lastView = "lV"; _lastPlayerViewed = "lPV"; _enemyKillPlayer = "EKP"; _enemyKillBG = "EKb"; _playerBGKill = "PbK"; _members = "Mb"; -- not saved _type = "Ty"; _date = "Da"; _enemyType = "ETy"; _enemyPlayer = "EPl"; _enemyCreature = "ECr"; _playerDeath = "PD"; _playerDeathPvP = "PDp"; _playerDeathPvE = "PDc"; _creatureKill_Target = "CKt"; _creatureKill_Xp = "CKx"; _levelUp = "LvU"; _loneWolfKill = "LwK"; _storedInfo = "Inf"; _win = "Win"; _loss = "Los"; _duel = "Du"; _lastDuel = "lDu"; _score = "Scr"; -- not saved -- following indexes are for temporary use (ie not saved in SavedVariables.lua, so it's -- not as important if they're a bit longer) _noteIndex = "NIn"; _default = "Def"; _multiType = "MTy"; _playerKillAndDeath = "PKaD"; _totalDamage = "tDm"; _groupDamage = "gDm"; _lastHateUpdate = "lHU"; _hateLevel = "HLv"; _damage = "Dm"; _hatePercent = "HPct"; _time = "Ti"; _owner = "Own"; _player = "Ply"; _other = "Oth"; _players = "players"; _guilds = "guilds"; _duels = "duels"; _bookCredits = "bookCredits"; _bookGeneralStat = "bookGeneralStat"; _bookClassStat = "bookClassStat"; _bookRaceStat = "bookRaceStat"; _bookPlayerStat = "bookPlayerStat"; _bookGuildStat = "bookGuildStat"; _bookMapStat = "bookMapStat"; _bookDateStat = "bookDateStat"; _bookBGDateMapStat = "bookBGDateMapStat"; _bookBGDateStat = "bookBGDateStat"; _bookBGMapStat = "bookBGMapStat"; _checkButton = "CBtn"; _slider = "Slid"; }; SKM_IndexMigr = { [2] = { EnemyHistory = { {Old=_SKM_OLD._name, New=_SKM._name}, {Old=_SKM_OLD._class, New=_SKM._class}, {Old=_SKM_OLD._guild, New=_SKM._guild}, {Old=_SKM_OLD._race, New=_SKM._race}, {Old=_SKM_OLD._level, New=_SKM._level}, {Old=_SKM_OLD._playerNote, New=_SKM._playerNote}, {Old=_SKM_OLD._playerKill, New=_SKM._playerKill}, {Old=_SKM_OLD._playerAssistKill, New=_SKM._playerAssistKill}, {Old=_SKM_OLD._playerFullKill, New=_SKM._playerFullKill}, {Old=_SKM_OLD._honorKill, New=_SKM._honorKill}, {Old=_SKM_OLD._honorCount, New=_SKM._honorCount}, {Old=_SKM_OLD._honorLastKill, New=_SKM._honorLastKill}, {Old=_SKM_OLD._rank, New=_SKM._rank}, {Old=_SKM_OLD._meetCount, New=_SKM._meetCount}, {Old=_SKM_OLD._atWar, New=_SKM._atWar}, {Old=_SKM_OLD._warDate, New=_SKM._warDate}, {Old=_SKM_OLD._continent, New=_SKM._continent}, {Old=_SKM_OLD._zone, New=_SKM._zone}, {Old=_SKM_OLD._xPos, New=_SKM._xPos}, {Old=_SKM_OLD._yPos, New=_SKM._yPos}, {Old=_SKM_OLD._zoneName, New=_SKM._zoneName}, -- {Old=_SKM_OLD._lastUpdate, New=_SKM._lastUpdate}, {Old=_SKM_OLD._lastView, New=_SKM._lastView}, {Old=_SKM_OLD._enemyKillPlayer, New=_SKM._enemyKillPlayer}, {Old=_SKM_OLD._enemyKillBG, New=_SKM._enemyKillBG}, {Old=_SKM_OLD._playerBGKill, New=_SKM._playerBGKill}, }; GuildHistory = { {Old=_SKM_OLD._name, New=_SKM._name}, -- {Old=_SKM_OLD._members, New=_SKM._members}, {Old=_SKM_OLD._meetCount, New=_SKM._meetCount}, {Old=_SKM_OLD._atWar, New=_SKM._atWar}, {Old=_SKM_OLD._warDate, New=_SKM._warDate}, {Old=_SKM_OLD._playerKill, New=_SKM._playerKill}, {Old=_SKM_OLD._playerAssistKill, New=_SKM._playerAssistKill}, {Old=_SKM_OLD._playerFullKill, New=_SKM._playerFullKill}, {Old=_SKM_OLD._enemyKillPlayer, New=_SKM._enemyKillPlayer}, {Old=_SKM_OLD._lastView, New=_SKM._lastView}, {Old=_SKM_OLD._lastPlayerViewed, New=_SKM._lastPlayerViewed}, }; GlobalMapData = { {Old=_SKM_OLD._continent, New=_SKM._continent}, {Old=_SKM_OLD._zone, New=_SKM._zone}, {Old=_SKM_OLD._xPos, New=_SKM._xPos}, {Old=_SKM_OLD._yPos, New=_SKM._yPos}, {Old=_SKM_OLD._storedInfo, New=_SKM._storedInfo}, }; StoredInfo = { {Old=_SKM_OLD._type, New=_SKM._type}, {Old=_SKM_OLD._date, New=_SKM._date}, {Old=_SKM_OLD._name, New=_SKM._name}, {Old=_SKM_OLD._level, New=_SKM._level}, {Old=_SKM_OLD._enemyType, New=_SKM._enemyType}, {Old=_SKM_OLD._loneWolfKill, New=_SKM._loneWolfKill}, {Old=_SKM_OLD._honorKill, New=_SKM._honorKill}, }; EnemyType = { [_SKM_OLD._enemyPlayer] = _SKM._enemyPlayer; [_SKM_OLD._enemyCreature] = _SKM._enemyCreature; }; RecordType = { [_SKM_OLD._playerKill] = _SKM._playerKill; [_SKM_OLD._playerAssistKill] = _SKM._playerAssistKill; [_SKM_OLD._playerFullKill] = _SKM._playerFullKill; [_SKM_OLD._playerDeath] = _SKM._playerDeath; [_SKM_OLD._playerDeathPvP] = _SKM._playerDeathPvP; [_SKM_OLD._playerDeathPvE] = _SKM._playerDeathPvE; [_SKM_OLD._creatureKill_Target] = _SKM._creatureKill_Target; [_SKM_OLD._creatureKill_Xp] = _SKM._creatureKill_Xp; [_SKM_OLD._levelUp] = _SKM._levelUp; }; DuelHistory = { {Old=_SKM_OLD._name, New=_SKM._name}, {Old=_SKM_OLD._class, New=_SKM._class}, {Old=_SKM_OLD._guild, New=_SKM._guild}, {Old=_SKM_OLD._race, New=_SKM._race}, {Old=_SKM_OLD._level, New=_SKM._level}, {Old=_SKM_OLD._playerNote, New=_SKM._playerNote}, {Old=_SKM_OLD._win, New=_SKM._win}, {Old=_SKM_OLD._loss, New=_SKM._loss}, {Old=_SKM_OLD._duel, New=_SKM._duel}, {Old=_SKM_OLD._lastDuel, New=_SKM._lastDuel}, }; BGStatDate = { {Old=_SKM_OLD._enemyKillBG, New=_SKM._enemyKillBG}, {Old=_SKM_OLD._playerBGKill, New=_SKM._playerBGKill}, }; }; }; --_time = "time"; --_type = "type"; --_name = "name"; --_class = "class"; --_guild = "guild"; -- PIng: Add guild support --_race = "race"; --_level = "level"; --_date = "date"; --_sortdate = "sortdate"; --_killedBy = "killBy"; --_playerNote = "playerNote"; --_noteIndex = "noteIndex"; --_icon_PlayerKill = "icon_PlayerKill"; --_icon_PlayerDeath = "icon_PlayerDeath"; -- type of map events --_playerKill = "playerKill"; --_playerAssistKill = "playerAssistKill"; --_playerFullKill = "playerFullKill"; --_playerDeath = "playerDeath"; --_playerDeathPvP = "playerDeathPvP"; --_playerDeathPvE = "playerDeathPvE"; --_creatureKill_Target = "creatureKill_Target"; --_creatureKill_Xp = "creatureKill_Xp"; --_levelUp = "levelUp"; --_loneWolfKill = "loneWolfKill"; --_honorKill = "honorKill"; --_honorCount = "honorCount"; --_honorLastKill = "honorLastKill"; --_rank = "rank"; --_win = "win"; --_loss = "loss"; --_duel = "duel"; --_lastDuel = "lastDuel"; --_score = "score"; --_default = "default"; --_multiType = "multiType"; --_playerKillAndDeath = "playerKillAndDeath"; --_enemyKillPlayer = "enemyKillPlayer"; --_enemyKillBG = "enemyKillBG"; --_playerBGKill = "playerBGKill"; --_meetCount = "meetCount"; --_atWar = "atWar"; --_guildAtWar = "guildAtWar"; --_warDate = "warDate"; --_continent = "continent"; --_zone = "zone"; --_xPos = "xPos"; --_yPos = "yPos"; --_icon = "icon"; --_storedInfo = "storedInfo"; --_zoneName = "zoneName"; --_lastUpdate = "lastUpdate"; --_totalDamage = "totalDamage"; --_groupDamage = "groupDamage"; --_lastHateUpdate = "lastHateUpdate"; --_hateLevel = "hateLevel"; --_enemyType = "enemyType"; --_damage = "damage"; --_lastView = "lastView"; --_lastPlayerViewed = "lastPlayerViewed"; --_enemyPlayer = "enemyPlayer"; --_enemyCreature = "enemyCreature"; --_owner = "owner"; --_player = "player"; --_other = "other"; --_players = "players"; --_guilds = "guilds"; --_duels = "duels"; --_members = "members"; --_bookCredits = "bookCredits"; --_bookGeneralStat = "bookGeneralStat"; --_bookClassStat = "bookClassStat"; --_bookRaceStat = "bookRaceStat"; --_bookPlayerStat = "bookPlayerStat"; --_bookGuildStat = "bookGuildStat"; --_bookMapStat = "bookMapStat"; --_bookDateStat = "bookDateStat"; --_bookBGDateMapStat = "bookBGDateMapStat"; --_bookBGDateStat = "bookBGDateStat"; --_bookBGMapStat = "bookBGMapStat"; --_checkButton = "checkButton"; --_slider = "slider"; function SkM_TableInsertMaxLengthLine(Lines, sLine, iMaxLen, iThreshold, sColorPrefix) local FName = "SkM_TableInsertMaxLengthLine"; local sTmp = sLine; local SeparList = {" ", "-", ".", ",", ":", ";"}; local sColor = ""; if (sColorPrefix) then sColor = sColorPrefix; end while (string.len(sTmp) > 0) do if (string.len(sTmp) <= iMaxLen) then table.insert(Lines, sColor..sTmp); sTmp = ""; else local iPos = iMaxLen; local sChar = string.sub(sTmp, iPos, iPos); while (iPos > iMaxLen - iThreshold) and not (intable(sChar, SeparList)) do iPos = iPos - 1; sChar = string.sub(sTmp, iPos, iPos); end if (intable(sChar, SeparList)) then table.insert(Lines, sColor..string.sub(sTmp, 1, iPos)); sTmp = string.sub(sTmp, iPos+1, string.len(sTmp)); else table.insert(Lines, sColor..string.sub(sTmp, 1, iMaxLen)); sTmp = string.sub(sTmp, iMaxLen+1, string.len(sTmp)); end end end end -- -------------------------------------------------------------------------------------- -- ifnil -- -------------------------------------------------------------------------------------- -- Return input value if it's not nil, else return alternative value specified. -- -------------------------------------------------------------------------------------- function ifnil( iVal, iNewVal) if ( iVal == nil) then return iNewVal; else return iVal; end end -- -------------------------------------------------------------------------------------- -- snil -- -------------------------------------------------------------------------------------- -- Return the input string, or the string "nil" if the variable is nil -- -------------------------------------------------------------------------------------- function snil_old( Val ) if ( Val == nil ) then return TXT_NIL; else return Val; end end function snil( Val ) if ( Val == nil ) then return TXT_NIL; else if ( Val == true) then return "true"; elseif ( Val == false) then return "false"; else return Val; end end end -- -------------------------------------------------------------------------------------- -- copytable -- -------------------------------------------------------------------------------------- -- Make a copy of a table -- -------------------------------------------------------------------------------------- function copytable(MyTable) if (type(MyTable) ~= "table" ) then return MyTable; end local idx, val; local NewTable = {}; for idx, val in MyTable do NewTable[idx] = copytable(val); end return NewTable; end -- -------------------------------------------------------------------------------------- -- intable -- -------------------------------------------------------------------------------------- -- Return true if "Val" is in table "TheTable" -- -------------------------------------------------------------------------------------- function intable( Val, TheTable) local idx, TableValue; for idx, TableValue in TheTable do if Val == TableValue then return true; end end return false; end -- remove "Val" if found in list "TheTable" -- return resulting list function removefromlist( Val, TheTable ) local MyTable = TheTable; local iSize = table.getn(MyTable); local i = 1; while (i <= iSize) do if (MyTable[i] == Val) then table.remove(MyTable, i); iSize = iSize - 1; else i = i + 1; end end return MyTable; end -- -------------------------------------------------------------------------------------- -- appendtables -- -------------------------------------------------------------------------------------- -- Append several list tables and returns the resulting table. -- Can take single elements also, in that case convert them to tables. -- -------------------------------------------------------------------------------------- function appendtables( ... ) local TableRes = { }; local iNbArg = arg.n; local i; for i=1, iNbArg do local MyTable; local Table = arg[i]; if (type(Table) ~= "table" ) then MyTable = { Table }; else MyTable = Table; end local idx, TableValue; for idx, TableValue in MyTable do table.insert(TableRes, TableValue); end end return TableRes; end -- -------------------------------------------------------------------------------------- -- mergetables -- -------------------------------------------------------------------------------------- -- Merge two list tables and returns the resulting table. -- If both tables contain the same indexes, the first tables values will be returned for -- this index. -- Recursively merge sub tables if needed. -- -------------------------------------------------------------------------------------- function mergetables(Table1, Table2) if (type(Table1) ~= "table") and (type(Table2) ~= "table") then return Table1; end if (type(Table1) ~= "table") then return Table2; end if (type(Table2) ~= "table") then return Table1; end local idx, TableValue; local TableRes = Table1; for idx, TableValue in Table2 do if (not Table1[idx]) then TableRes[idx] = TableValue; else TableRes[idx] = mergetables(Table1[idx], TableValue); end end return TableRes; end -- -------------------------------------------------------------------------------------- -- revlist -- -------------------------------------------------------------------------------------- -- Returns a list in reverse order -- -------------------------------------------------------------------------------------- function revlist(ListIn) local ListOut = {}; local MyList; if (type(ListIn) ~= "table" ) then MyList = { ListIn }; else MyList = ListIn; end local idx, TableValue; for idx, TableValue in MyList do table.insert(ListOut, 1, TableValue); end return ListOut; end function tablesize(Table) local idx, val local iSize = 0 for idx, val in Table do iSize = iSize + 1; end return iSize; end -- ************************************************************************************** -- Logs, debug and display functions -- ************************************************************************************** -- -------------------------------------------------------------------------------------- -- SkM_Trace -- -------------------------------------------------------------------------------------- -- Debug function. Display information on screen, or on the default chat frame. -- FName = calling function name -- Level = level of trace, used to check if this debug will be displayed -- Message = message to trace -- -------------------------------------------------------------------------------------- function SkM_Trace( FName, Level, Message ) local OutMessage; if (Level <= SKM_Config.DebugLevel) then if (SKM_Config.DebugMaxFuncLen) and (string.len(FName) > SKM_Config.DebugMaxFuncLen) then if (SKM_Config.DebugMaxFuncLen < 10) then OutMessage = string.sub(FName, 1, SKM_Config.DebugMaxFuncLen).."/"..snil(Message); else OutMessage = string.sub(FName, 1, SKM_Config.DebugMaxFuncLen - 7)..".." ..string.sub(FName, string.len(FName)-4, string.len(FName)).."/"..snil(Message); end else OutMessage = FName.."/"..snil(Message); end if (SKM_Config.RecordDebug) then local sDate = SkM_GetDate(); local sRecordMsg = "["..sDate.."]<"..Level.."> "..snil(FName).."/"..snil(Message); table.insert(SKM_Debug, sRecordMsg); SKM_Context.RecLines = SKM_Context.RecLines + 1; SKM_Context.TmpRecLines = SKM_Context.TmpRecLines + 1; if (SKM_Context.TmpRecLines >= SKM_Config.RecordIntervalInfo) then SkM_ChatMessageCol("Lines recorded : "..SKM_Context.RecLines.." (Total : "..table.getn(SKM_Debug)..")"); SKM_Context.TmpRecLines = 0; end return; end if (SKM_TRACE_MODE == SKM_TRACE_MODE_PRINT) then print(OutMessage); elseif (SKM_TRACE_MODE == SKM_TRACE_MODE_CHATMSG) then if not DEFAULT_CHAT_FRAME then return; end local r = SKM_Config.RGB_Debug[Level].r; local g = SKM_Config.RGB_Debug[Level].g; local b = SKM_Config.RGB_Debug[Level].b; SkM_PrintMessage(OutMessage, r, g, b); -- PIng: Bug Fix.Replace ShM_PrintMessage by SkM_PrintMessage end end end -- -------------------------------------------------------------------------------------- -- SkM_PrintMessage -- -------------------------------------------------------------------------------------- -- Display a message in a frame in a specified RGB color, calling Blizz function -- :AddMessage. -- I don't know what the two last parameters stand for :/ -- -------------------------------------------------------------------------------------- function SkM_PrintMessage(msg, r, g, b, frame, id, unknown4th) local OutMessage; if(unknown4th) then local temp = id; id = unknown4th; unknown4th = id; end OutMessage = snil(msg); if (not r) then r = 1.0; end if (not g) then g = 1.0; end if (not b) then b = 1.0; end if ( frame ) then frame:AddMessage(OutMessage, r, g, b, id, unknown4th); else if ( DEFAULT_CHAT_FRAME ) then DEFAULT_CHAT_FRAME:AddMessage(OutMessage, r, g, b, id, unknown4th); end end end -- -------------------------------------------------------------------------------------- -- SkM_ChatMessageCol -- -------------------------------------------------------------------------------------- -- Display a message on the default chat frame, with the module prefix. -- Color is the module global chat color, if it has been set (default : white). -- -------------------------------------------------------------------------------------- function SkM_ChatMessageCol( Message ) local OutMessage; local r = SKM_Config.RGB_Msg.r; local g = SKM_Config.RGB_Msg.g; local b = SKM_Config.RGB_Msg.b; if not DEFAULT_CHAT_FRAME then return; end OutMessage = SKM_MESSAGE_PREFIX..snil(Message); SkM_PrintMessage(OutMessage, r, g, b); end -- -------------------------------------------------------------------------------------- -- SkM_ChatMessageColP -- -------------------------------------------------------------------------------------- -- Display a message on the default chat frame, with the module prefix. -- RBGTriplet specifies the text color. -- -------------------------------------------------------------------------------------- function SkM_ChatMessageColP( Message, RGBTriplet ) local OutMessage; local r = RGBTriplet.r; local g = RGBTriplet.g; local b = RGBTriplet.b; if not DEFAULT_CHAT_FRAME then return; end OutMessage = SKM_MESSAGE_PREFIX..snil(Message); SkM_PrintMessage(OutMessage, r, g, b); end -- -------------------------------------------------------------------------------------- -- SkM_Initialize -- -------------------------------------------------------------------------------------- -- Module initialization -- -------------------------------------------------------------------------------------- function SkM_Initialize() SKM_Context = { MapOpen = false; -- record damage done by player to enemies EnemyCombat = { }; -- record damage done by enemies to player PlayerCombat = { }; -- record recent enemy kills RecentEnemyKill = { }; -- record recent WAR warnings to reduce spam RecentWarWarning = { }; --DuelEnemy = nil; -- list of player names in group GroupList = { }; -- list of player names in guild GuildList = { }; -- list of notes associated to a physical POI on the world map WorldMapPOINotes = { }; PlayerAlive = true; DataInit = false; -- parse patterns Pattern = { }; }; SKM_Context.Continents = { GetMapContinents() } ; SKM_Context.Zones = { }; for idx, val in SKM_Context.Continents do SKM_Context.Zones[idx] = { GetMapZones(idx) } ; end SkM_BuildParsePatterns(); SKM_Context.Race = { IndexToString = { [1] = SKM_RACE.Dwarf; [2] = SKM_RACE.Gnome; [3] = SKM_RACE.Human; [4] = SKM_RACE.NightElf; [5] = SKM_RACE.Orc; [6] = SKM_RACE.Tauren; [7] = SKM_RACE.Troll; [8] = SKM_RACE.Undead; }; StringToIndex = { [SKM_RACE.Dwarf] = 1; [SKM_RACE.Gnome] = 2; [SKM_RACE.Human] = 3; [SKM_RACE.NightElf] = 4; [SKM_RACE.Orc] = 5; [SKM_RACE.Tauren] = 6; [SKM_RACE.Troll] = 7; [SKM_RACE.Undead] = 8; }; }; SKM_Context.Class = { IndexToString = { [1] = SKM_CLASS.Druid; [2] = SKM_CLASS.Hunter; [3] = SKM_CLASS.Mage; [4] = SKM_CLASS.Paladin; [5] = SKM_CLASS.Priest; [6] = SKM_CLASS.Rogue; [7] = SKM_CLASS.Shaman; [8] = SKM_CLASS.Warrior; [9] = SKM_CLASS.Warlock; }; StringToIndex = { [SKM_CLASS.Druid] = 1; [SKM_CLASS.Hunter] = 2; [SKM_CLASS.Mage] = 3; [SKM_CLASS.Paladin] = 4; [SKM_CLASS.Priest] = 5; [SKM_CLASS.Rogue] = 6; [SKM_CLASS.Shaman] = 7; [SKM_CLASS.Warrior] = 8; [SKM_CLASS.Warlock] = 9; }; }; SkM_InitData(false); end -- -------------------------------------------------------------------------------------- -- SkM_InitData -- -------------------------------------------------------------------------------------- -- Initialization of data saved across sessions -- -------------------------------------------------------------------------------------- function SkM_InitData(bForceInit) local FName = "SkM_InitData"; -- context not yet created if (not SKM_Context) then return false; end -- initialization already performed if (SKM_Context.DataInit == true) and (not bForceInit) then return true; end _PlayerName = SkM_UnitName(SKM_UNIT_PLAYER); _RealmName = GetCVar("realmName"); -- if player name or realm name can't be retrieved yet, abort initialization if (not _PlayerName) or (not _RealmName) then return false; end SKM_Context.PlayerName = _PlayerName; SKM_Context.RealmName = _RealmName; -- store player current level, because we get old level upon event "level up", but I'm -- not sure it would always be the case. --SKM_Context.PlayerLevel = UnitLevel(SKM_UNIT_PLAYER); -- since 1.5 it returns 0 at this point... have to do it later. -- global module data if (not SKM_Data) then SKM_Data = { } ; end -- for recording debug messages if (not SKM_Debug) then SKM_Debug = { }; end -- module data for current realm if (not SKM_Data[_RealmName]) then SKM_Data[_RealmName] = { }; end -- module data for current player of current realm if (not SKM_Data[_RealmName][_PlayerName]) then SKM_Data[_RealmName][_PlayerName] = { }; SKM_Data[_RealmName][_PlayerName].PlayerName = SKM_Context.PlayerName; local sDate = SkM_GetDate(); SKM_Data[_RealmName][_PlayerName].InitDate = sDate; end -- dunno when it happenned, but some chars do not have a "PlayerName". Fix it... if (not SKM_Data[_RealmName][_PlayerName].PlayerName) then SKM_Data[_RealmName][_PlayerName].PlayerName = _PlayerName; end -- sub maps of player data if (not SKM_Data[_RealmName][_PlayerName].GlobalMapData) then SKM_Data[_RealmName][_PlayerName].GlobalMapData = { }; end if (not SKM_Data[_RealmName][_PlayerName].MapData) then SKM_Data[_RealmName][_PlayerName].MapData = { }; local idx_c, val_c; for idx_c, val_c in SKM_Context.Continents do SKM_Data[_RealmName][_PlayerName].MapData[idx_c] = { }; local idx_z, val_z for idx_z, val_z in SKM_Context.Zones[idx_c] do SKM_Data[_RealmName][_PlayerName].MapData[idx_c][idx_z] = { }; end end end if (not SKM_Data[_RealmName][_PlayerName].EnemyHistory) then SKM_Data[_RealmName][_PlayerName].EnemyHistory = { }; end -- 09/04/2005 16:28:31 PIng: Add Guild support if (not SKM_Data[_RealmName][_PlayerName].GuildHistory) then SKM_Data[_RealmName][_PlayerName].GuildHistory = { }; end if (not SKM_Data[_RealmName][_PlayerName].UnknownEnemy) then SKM_Data[_RealmName][_PlayerName].UnknownEnemy = { }; end if (not SKM_Data[_RealmName][_PlayerName].DuelHistory) then SKM_Data[_RealmName][_PlayerName].DuelHistory = { }; end if (not SKM_Data[_RealmName][_PlayerName].BGStats) then SKM_Data[_RealmName][_PlayerName].BGStats = { }; end local sGuildName = GetGuildInfo(SKM_UNIT_PLAYER); SkM_Trace(FName, 3, "Player guild = "..snil(sGuildName)); if (sGuildName) and (sGuildName ~= "") and (false) then -- build guild list : open guild roster to retrieve guild players list GuildRoster(); --SetGuildRosterShowOffline(1); SkM_BuildGuildList(); --FriendsFrame:Hide(); HideUIPanel(FriendsFrame); end -- Global settings if (not SKM_Settings) then SKM_Settings = { }; end SkM_LoadDefaultSettings(false); SkM_RecordVersionHistory(); SKM_Context.DataInit = true; SkM_Trace(FName, 3, "Done"); return true; end -- -------------------------------------------------------------------------------------- -- SkM_LoadDefaultSettings -- -------------------------------------------------------------------------------------- -- Load (or reload) setting default values from configuration file -- -------------------------------------------------------------------------------------- function SkM_LoadDefaultSettings(bForceReload) local FName = "SkM_LoadDefaultSettings"; if (not SKM_Settings) then SKM_Settings = { }; end if (bForceReload) then SkM_Trace(FName, 3, "Force reload default settings"); for i=1, table.getn(SKM_OPTION_LIST), 1 do local key = SKM_OPTION_LIST[i]; SKM_Settings[key] = SKM_Config[key]; end else SkM_Trace(FName, 3, "Load missing default settings"); for i=1, table.getn(SKM_OPTION_LIST), 1 do local key = SKM_OPTION_LIST[i]; SkM_Trace(FName, 3, "key = "..key); if (SKM_Settings[key] == nil) then SKM_Settings[key] = SKM_Config[key]; end end end if (SKM_Settings.CreatureKillRecordsByZone > SKM_MAX_CREEP_RECORD_BY_ZONE) then SKM_Settings.CreatureKillRecordsByZone = SKM_MAX_CREEP_RECORD_BY_ZONE; end -- for management of data migration. No use for now, but might be needed later on. if (SKM_Settings.DataModel == nil) then SKM_Settings.DataModel = SKM_VERSION; else SKM_Settings.DataModel = SKM_VERSION; end end -- -------------------------------------------------------------------------------------- -- SkM_ResetData -- -------------------------------------------------------------------------------------- -- Warning : this deletes ALL module data (for all players and realms) -- Use with caution ! -- -------------------------------------------------------------------------------------- function SkM_ResetData() SKM_Data = nil; SkM_InitData(true); end -- -------------------------------------------------------------------------------------- -- SkM_ResetPlayerData -- -------------------------------------------------------------------------------------- -- Delete all current player data -- -------------------------------------------------------------------------------------- function SkM_ResetPlayerData() SKM_Data[_RealmName][_PlayerName] = nil; SkM_InitData(true); end -- -------------------------------------------------------------------------------------- -- SkM_ResetPlayerData -- -------------------------------------------------------------------------------------- -- Delete current player map data only -- -------------------------------------------------------------------------------------- function SkM_ResetPlayerMapData() SKM_Data[_RealmName][_PlayerName].GlobalMapData = nil; SKM_Data[_RealmName][_PlayerName].MapData = nil; SkM_InitData(true); end -- -------------------------------------------------------------------------------------- -- SkM_ResetAccountMapData -- -------------------------------------------------------------------------------------- -- Delete all map data on a given account -- USE WITH CAUTION !!! -- -------------------------------------------------------------------------------------- function SkM_ResetAccountMapData() local FName = "SkM_ResetAccountMapData"; local idx_realm, val_realm, idx_char, val_char, idx_enemy, val_enemy; for idx_realm, val_realm in SKM_Data do for idx_char, val_char in SKM_Data[idx_realm] do if (SKM_Data[idx_realm][idx_char].PlayerName == idx_char) then SkM_Trace(FName, 1, "Cleaning for "..idx_realm.." / "..idx_char); -- clean up map data SKM_Data[idx_realm][idx_char].GlobalMapData = nil; SKM_Data[_RealmName][_PlayerName].MapData = nil; -- clean up zone stored in enemy information for idx_enemy, val_enemy in SKM_Data[idx_realm][idx_char].EnemyHistory do SKM_Data[idx_realm][idx_char].EnemyHistory[idx_enemy][_SKM._continent] = nil; SKM_Data[idx_realm][idx_char].EnemyHistory[idx_enemy][_SKM._zone] = nil; SKM_Data[idx_realm][idx_char].EnemyHistory[idx_enemy][_SKM._xPos] = nil; SKM_Data[idx_realm][idx_char].EnemyHistory[idx_enemy][_SKM._yPos] = nil; end end end end SkM_InitData(true); end -- -------------------------------------------------------------------------------------- -- SkM_GetOption -- -------------------------------------------------------------------------------------- -- Get a player option value -- -------------------------------------------------------------------------------------- function SkM_GetOption(sConfigKey) local FName = "SkM_GetOption"; if (SKM_Settings == nil) then SkM_Trace(FName, 1, "Settings not initialized, can't get value for "..snil(sConfigKey)); return; end if (sConfigKey == nil) then SkM_Trace(FName, 1, "received nil param"); return; end --return (SKM_Data[_RealmName][_PlayerName].Settings[sConfigKey]); return (SKM_Settings[sConfigKey]); end -- -------------------------------------------------------------------------------------- -- SkM_SetOption -- -------------------------------------------------------------------------------------- -- Set a player option to a given value -- -------------------------------------------------------------------------------------- function SkM_SetOption(sConfigKey, Value) local FName = "SkM_SetOption"; if (SKM_Settings == nil) then SkM_Trace(FName, 1, "Settings not initialized, can't set value for "..snil(sConfigKey)); return; end if (sConfigKey == nil) then SkM_Trace(FName, 1, "received nil param"); return; end --SKM_Data[_RealmName][_PlayerName].Settings[sConfigKey] = Value; SKM_Settings[sConfigKey] = Value; end function SkM_GetRaceText(Index) return SKM_Context.Race.IndexToString[Index]; end function SkM_GetRaceIndex(Text) return SKM_Context.Race.StringToIndex[Text]; end function SkM_GetClassText(Index) return SKM_Context.Class.IndexToString[Index]; end function SkM_GetClassIndex(Text) return SKM_Context.Class.StringToIndex[Text]; end -- -------------------------------------------------------------------------------------- -- SkM_ExtractParam -- -------------------------------------------------------------------------------------- -- Extract parameters from a string. Delimiter is the blank character (space). -- Return the first parameter and the rest of the string ("" if empty). -- -------------------------------------------------------------------------------------- function SkM_ExtractParam(msg) local params = msg; local command = params; local index = strfind(command, " "); if ( index ) then command = strsub(command, 1, index-1); params = strsub(params, index+1); else params = ""; end return command, params; end -- -------------------------------------------------------------------------------------- -- SkM_IdentifyCommand -- -------------------------------------------------------------------------------------- -- Check if the given command matches a module command. -- it's the case if the passed in command starts with the module command -- eg. : module command "fort" allows to type in "fortitude". -- -------------------------------------------------------------------------------------- function SkM_IdentifyCommand(sCmd, sModuleCommand) if ((not sModuleCommand) or (sModuleCommand == "")) then return false; end if ((not sCmd) or (sCmd == "")) then return false; end local iLen = string.len(sModuleCommand); if ( string.sub(sCmd, 1, iLen) == sModuleCommand) then return true; else return false; end end -- -------------------------------------------------------------------------------------- -- SkM_SetDebugLevel -- -------------------------------------------------------------------------------------- -- Set the module debug level (-1, 0, 1, 2, 3) -- -------------------------------------------------------------------------------------- function SkM_SetDebugLevel( iLevel ) local iNewLevel = ifnil(iLevel, -1); SKM_Config.DebugLevel = iNewLevel; SkM_ChatMessageCol("Debug level set to "..iNewLevel); end function SkM_StartDebugRecord() SKM_Context.RecLines = 0; SKM_Context.TmpRecLines = 0; SKM_Config.RecordDebug = true; SkM_ChatMessageCol("Started recording debug messages"); end function SkM_StopDebugRecord() SKM_Config.RecordDebug = false; SKM_Context.RecLines = nil; SKM_Context.TmpRecLines = nil; SkM_ChatMessageCol("Stopped recording debug messages"); end function SkM_ClearDebugRecord() SKM_Debug = { }; SKM_Context.RecLines = 0; SKM_Context.TmpRecLines = 0; SkM_ChatMessageCol("Recorded debug messages cleared"); end -- -------------------------------------------------------------------------------------- -- SkM_GetDate -- -------------------------------------------------------------------------------------- -- Get current date in two formats : -- DD/MM/YYYY HH:MI:SS -- YYYY/MM/DD HH:MI:SS (this is a sortable date) -- -------------------------------------------------------------------------------------- function SkM_GetDate() -- date is a shortcut to "os.date" (os package is not available, but Blizz provided -- us the date function :) local CurDate = date("*t"); local sYear = string.format("%0.04d", CurDate.year); local sMonth = string.format("%0.02d", CurDate.month); local sDay = string.format("%0.02d", CurDate.day); local sHour = string.format("%0.02d", CurDate.hour); local sMin = string.format("%0.02d", CurDate.min); local sSec = string.format("%0.02d", CurDate.sec); -- date in format DD/MM/YYYY HH:MI:SS local StrDate1 = sDay.."/"..sMonth.."/"..sYear.." "..sHour..":"..sMin..":"..sSec; -- date in format YYYY/MM/DD HH:MI:SS (useful for sorting !) local StrDate2 = sYear.."/"..sMonth.."/"..sDay.." "..sHour..":"..sMin..":"..sSec; return StrDate1, StrDate2; end function SkM_GetDay() local sDate1, sDate2 = SkM_GetDate(); local sDay1, sDay2; sDay1 = string.sub(sDate1, 1, 10); sDay2 = string.sub(sDate2, 1, 10); return sDay1, sDay2; end -- -------------------------------------------------------------------------------------- -- SkM_GetSortableDate -- -------------------------------------------------------------------------------------- -- Convert date to sortable format : -- from DD/MM/YYYY HH:MI:SS format to YYYY/MM/DD HH:MI:SS format -- or, from DD/MM/YYYY format to YYYY/MM/DD format -- -------------------------------------------------------------------------------------- function SkM_GetSortableDate(sDate) if (not sDate) then return nil; end local sMonth, sDay, sYear, sHour, sMin, sSec; local sSortDate; sDay = string.sub(sDate, 1, 2); sMonth = string.sub(sDate, 4, 5); sYear = string.sub(sDate, 7, 10); if (string.len(sDate) == 19) then sHour = string.sub(sDate, 12, 13); sMin = string.sub(sDate, 15, 16); sSec = string.sub(sDate, 18, 19); SortDate = sYear.."/"..sMonth.."/"..sDay.." "..sHour..":"..sMin..":"..sSec; else SortDate = sYear.."/"..sMonth.."/"..sDay; end -- sortable date return SortDate; end function SkM_GetZoneText() local sText = GetZoneText(); -- apply fix if needed. for idx, val in SKM_ZoneFix do if sText == val.Val_ZoneText then return val.Val_MapZones; end end return sText; end -- Return continent and zone number shifted to english order function SkM_GetCurrentMapZone_Shift() local FName = "SkM_GetCurrentMapZone_Shift"; local iCont = GetCurrentMapContinent(); local iZone = GetCurrentMapZone(); if (iCont) and (iCont ~= 0) and (iZone) and (iZone ~= 0) and (SKM_ZoneShift) then if (SKM_ZoneShift[iCont]) and (SKM_ZoneShift[iCont][iZone]) then iZone = SKM_ZoneShift[iCont][iZone]; else SkM_Trace(FName, 1, "Undefined shift : cont = "..iCont.." / zone = "..iZone); end end return iCont, iZone; end -- -------------------------------------------------------------------------------------- -- SkM_GetZone -- -------------------------------------------------------------------------------------- -- Return continent and zone number -- or (nil, nil) if GetZoneText() does not match any known zone -- -------------------------------------------------------------------------------------- function SkM_GetZone() for i=1, getn(SKM_Context.Continents), 1 do for j=1, getn(SKM_Context.Zones[i]), 1 do --if (SKM_Context.Zones[i][j] == GetZoneText()) then if (SKM_Context.Zones[i][j] == SkM_GetZoneText()) then return i, j; end end end return nil, nil; end function SkM_GetZone_Shift(p_iCont, p_iZone) local iCont, iZone; if (p_iCont) and (p_iZone) then iCont = p_iCont; iZone = p_iZone; else iCont, iZone = SkM_GetZone(); end if (iCont) and (iZone) and (SKM_ZoneShift) then iZone = SKM_ZoneShift[iCont][iZone]; end return iCont, iZone; end -- get zone text from shifted zone index (english order) function SkM_GetZoneTextFromIndex(p_iCont, p_iZone) return ifnil(SKM_ZoneText[p_iCont][p_iZone], ""); end function SkM_IsInBattleground() local FName = "SkM_IsInBattleground"; local sZone = SkM_GetZoneText(); if (intable(sZone, SKM_BATTLEGROUNDS)) then return true; else return false; end end -- -------------------------------------------------------------------------------------- -- SkM_CheckNearNotes -- -------------------------------------------------------------------------------------- -- Check if there are notes nearby given location -- OBSOLETE. I don't use it any more. -- -------------------------------------------------------------------------------------- function SkM_CheckNearNotes(idx_c, idx_z, xPos, yPos, icon) local iNoteCount = getn(SKM_Data[_RealmName][_PlayerName].MapData[idx_c][idx_z]); for i=1, iNoteCount, 1 do local idx_gn = SKM_Data[_RealmName][_PlayerName].MapData[idx_c][idx_z][i]; local Note = SKM_Data[_RealmName][_PlayerName].GlobalMapData[idx_gn]; if (abs(Note[_SKM._xPos] - xPos) <= 0.0009765625 * SKM_Config.MapNotes_MinDiff) and (abs(Note[_SKM._yPos] - yPos) <= 0.0013020833 * SKM_Config.MapNotes_MinDiff) then return true; end end return false; end -- -------------------------------------------------------------------------------------- -- SkM_FindNotePOINum -- -------------------------------------------------------------------------------------- -- Retrieve which POI object is associated to a given map note -- -------------------------------------------------------------------------------------- function SkM_FindNotePOINum(idx_n) for idx_poi, val_poi in SKM_Context.WorldMapPOINotes do if (intable(idx_n, val_poi)) then return idx_poi; end end return nil; end -- -------------------------------------------------------------------------------------- -- SkM_CheckNearNotesPOI -- -------------------------------------------------------------------------------------- -- For a given map note, try and find nearby allocated POI so that we may group -- current note to the notes associated to this POI. -- -------------------------------------------------------------------------------------- function SkM_CheckNearNotesPOI(idx_c, idx_z, xPos, yPos, index, DiscardedNotes) local iNoteCount = getn(SKM_Data[_RealmName][_PlayerName].MapData[idx_c][idx_z]); local i; for i=1, iNoteCount, 1 do -- don't check notes > current note, because they've not been treated yet if (i == index) then return nil; end if (intable(i, DiscardedNotes)) then -- that note has been discarded, so don't check if it's too close ! else local idx_gn = SKM_Data[_RealmName][_PlayerName].MapData[idx_c][idx_z][i]; local Note = SKM_Data[_RealmName][_PlayerName].GlobalMapData[idx_gn]; if (abs(Note[_SKM._xPos] - xPos) <= 0.0009765625 * SKM_Config.MapNotes_MinDiff) and (abs(Note[_SKM._yPos] - yPos) <= 0.0013020833 * SKM_Config.MapNotes_MinDiff) then -- we're close to another note that has an associated POI -- find this POI number and return it local iPOINum = SkM_FindNotePOINum(i); return iPOINum; end end end return nil; end -- -------------------------------------------------------------------------------------- -- SkM_AddMapNote -- -------------------------------------------------------------------------------------- -- Add a new player map note -- -------------------------------------------------------------------------------------- function SkM_AddMapNote(idx_c, idx_z, Note) local FName = "SkM_AddMapNote"; -- insert note to global data in last position table.insert(SKM_Data[_RealmName][_PlayerName].GlobalMapData, Note); -- retrieve index of inserted note local idx_gn = table.getn(SKM_Data[_RealmName][_PlayerName].GlobalMapData); -- insert new global note index to map note list table.insert(SKM_Data[_RealmName][_PlayerName].MapData[idx_c][idx_z], idx_gn); end -- -------------------------------------------------------------------------------------- -- SkM_AddMapData -- -------------------------------------------------------------------------------------- -- Create a new note from input stored data and store it in current zone records -- -------------------------------------------------------------------------------------- function SkM_AddMapData(p_StoreInfo) local FName = "SkM_AddMapData"; local idx_c, idx_z = SkM_GetZone(); SkM_Trace(FName, 3, "idx_c = "..snil(idx_c)..", idx_z = "..snil(idx_z)); if (idx_z) then SetMapZoom(idx_c, idx_z); local xPos, yPos = GetPlayerMapPosition(SKM_UNIT_PLAYER); local cont_shift, zone_shift = SkM_GetZone_Shift(idx_c, idx_z); SkM_Trace(FName, 3, "Player Position : x = "..snil(xPos)..", y = "..snil(yPos)); --if ((not SkM_CheckNearNotes(idx_c, idx_z, xPos, yPos, icon)) and xPos ~= 0 and yPos ~= 0 ) then if (xPos ~= 0 and yPos ~= 0) then local Note = { }; --Note[_SKM._continent] = idx_c; --Note[_SKM._zone] = idx_z; Note[_SKM._continent] = cont_shift; Note[_SKM._zone] = zone_shift; Note[_SKM._xPos] = xPos; Note[_SKM._yPos] = yPos; Note[_SKM._storedInfo] = p_StoreInfo; -- DOH !! forgot this one in 1.4. Now all records are messed up :( --SkM_AddMapNote(idx_c, idx_z, Note); SkM_AddMapNote(cont_shift, zone_shift, Note); SKM_Context.RecordingDisabled = false; return true; end end if (not SKM_Context.RecordingDisabled) then -- 1.5 : removed message that is of no use ! --SkM_ChatMessageCol("Event recording is disabled in this location"); SKM_Context.RecordingDisabled = true; end return false; end -- -------------------------------------------------------------------------------------- -- SkM_RecordPlayerDeath -- -------------------------------------------------------------------------------------- -- Record player death event. -- Find if it's a PvE or PvP or unknown death, determine responsibilities for this -- death, and create a record of the appropriate type. -- -------------------------------------------------------------------------------------- function SkM_RecordPlayerDeath() local FName = "SkM_RecordPlayerDeath"; local StoreInfo = { }; StoreInfo[_SKM._type] = _SKM._playerDeath; local sDate1, sDate2 = SkM_GetDate(); StoreInfo[_SKM._date] = sDate1; --StoreInfo[_sortdate] = sDate2; local sKiller, KillerType, HateList = SkM_PlayerDeathResp(); -- check if in battleground local bBattleground = SkM_IsInBattleground(); -- if killer is known, and if its type (player or creature) is also known, record -- specific death event -- note : it's possible that we determined that a given unit is responsible for our -- death, but we don't know if it's a player or a creature. It can happen if this -- unit killed us with dots only. In that case, the death type will be undetermined. -- addition : it can happen also because pets and players trigger the same events, thus -- if we never targetted or mouse-overed a given player, we will not know if he is -- a player or a pet. if (sKiller) and (KillerType == nil) then -- try to target to see if this is a player TargetByName(sKiller); SkM_UpdateUnitData(); -- if this is an enemy player, then he should have been stored ! if (SKM_Data[_RealmName][_PlayerName].EnemyHistory[sKiller]) then KillerType = _SKM._enemyPlayer; end end if (sKiller) and (KillerType) then StoreInfo[_SKM._name] = sKiller; StoreInfo[_SKM._enemyType] = KillerType; if (KillerType == _SKM._enemyPlayer) then SkM_UpdateEnemyLastView(sKiller, sDate1, false); StoreInfo[_SKM._type] = _SKM._playerDeathPvP; SkM_UpdateEnemy_IncrKillPlayer(sKiller, 1, bBattleground); if (bBattleground) then SkM_BGStats_AddDeath(); end -- update target info if needed SkM_SetTargetInfo(); else StoreInfo[_SKM._type] = _SKM._playerDeathPvE; end end -- check if world record are disabled, if it's the case return if (StoreInfo[_SKM._type] == _SKM._playerDeathPvP) then if (not SkM_GetOption("RecordPlayerDeath")) then return; end else if (not SkM_GetOption("RecordPlayerDeathNonPvP")) then return; end end if (SkM_AddMapData(StoreInfo)) then if (SkM_GetOption("DisplayDeathRecord")) then if (sKiller) and (KillerType) then if (KillerType == _SKM._enemyPlayer) then SkM_ChatMessageColP(string.format(SKM_UI_STRINGS.RecordMessage_PlayerPvPDeath, sKiller), SKM_Config.RGB_PlayerPvPDeath); else SkM_ChatMessageColP(string.format(SKM_UI_STRINGS.RecordMessage_PlayerPvEDeath, sKiller), SKM_Config.RGB_PlayerPvEDeath); end else SkM_ChatMessageColP(SKM_UI_STRINGS.RecordMessage_PlayerDeath, SKM_Config.RGB_PlayerDeath); end end end if (SkM_GetOption("ReportPlayerDeath")) then local iNbLine = math.min(SKM_Config.ReportDeathMaxLines, table.getn(HateList)); if (iNbLine > 0) then SkM_ChatMessageColP(string.format(SKM_UI_STRINGS.ReportMessage_PlayerDeath, iNbLine), SKM_Config.RGB_ReportDeath); for i=1, iNbLine, 1 do SkM_ChatMessageColP(string.format("%d. %s (%d %%)", i, HateList[i][_SKM._name], HateList[i][_SKM._hatePercent]), SKM_Config.RGB_ReportDeath); end end end end -- -------------------------------------------------------------------------------------- -- SkM_PlayerAlive -- -------------------------------------------------------------------------------------- -- Player is back to life, remember it. -- -------------------------------------------------------------------------------------- function SkM_PlayerAlive() SKM_Context.PlayerAlive = true; end -- -------------------------------------------------------------------------------------- -- SkM_PlayerDeath -- -------------------------------------------------------------------------------------- -- Handle player death event. -- -------------------------------------------------------------------------------------- function SkM_PlayerDeath() local FName = "SkM_PlayerDeath"; -- check if player was alive because in some cases we get two death messages for the -- same death if (SKM_Context.PlayerAlive == false) then SkM_Trace(FName, 3, "Not alive, discard death event"); return; end SKM_Context.PlayerAlive = false; -- if (not SkM_GetOption("RecordPlayerDeath")) then -- return; -- end SkM_RecordPlayerDeath(); end -- -------------------------------------------------------------------------------------- -- SkM_WorldMapUpdate -- -------------------------------------------------------------------------------------- -- Handle World Map Update event -- -------------------------------------------------------------------------------------- function SkM_WorldMapUpdate() local FName = "SkM_WorldMapUpdate"; if (WorldMapFrame:IsVisible()) then -- world map is visible, draw all that need to be ! --local serverTime = GetTime(); SKM_Context.MapOpen = true; --local mapContinent = GetCurrentMapContinent(); --local mapZone = GetCurrentMapZone(); local mapContinent, mapZone = SkM_GetCurrentMapZone_Shift(); SKM_Context.CloseMap = { continent = mapContinent, zone = mapZone, time = GetTime() }; SkM_MainDraw(); elseif (SKM_Context.MapOpen) then -- Map is not visible, but recorded as opened. Close it. SKM_Context.MapOpen = false; SkM_MainDraw(); --SkM_ChangeMap(); else -- Map not visible, probably closed end end -- -------------------------------------------------------------------------------------- -- SkM_CloseWorldMap -- -------------------------------------------------------------------------------------- -- Handle Close World Map event -- -------------------------------------------------------------------------------------- function SkM_CloseWorldMap() local FName = "SkM_CloseWorldMap"; SKM_Context.MapOpen = false; SkM_MainDraw(); --SkM_ChangeMap(); end -- -------------------------------------------------------------------------------------- -- SkM_MainDraw -- -------------------------------------------------------------------------------------- -- Display our records as custom POI on the world map, and hide unused POI. -- -------------------------------------------------------------------------------------- function SkM_MainDraw() local FName = "SkM_MainDraw"; SKM_Context.WorldMapPOINotes = { }; local lastUnused = 1; local maxNotes = SKM_MAX_MAP_NOTES; local iNbNotes = 0; --local idx_c = GetCurrentMapContinent(); --local idx_z = GetCurrentMapZone(); local idx_c, idx_z = SkM_GetCurrentMapZone_Shift(); if (idx_c ~= 0) and (idx_z ~= 0) and (SKM_Data[_RealmName][_PlayerName].MapData[idx_c]) and (SKM_Data[_RealmName][_PlayerName].MapData[idx_c][idx_z]) then iNbNotes = table.getn(SKM_Data[_RealmName][_PlayerName].MapData[idx_c][idx_z]); end if (SKM_Context.MapOpen) and (SkM_GetOption("MapDisplayRecords")) then if (idx_c ~= 0) and (idx_z ~= 0) and (SKM_Data[_RealmName][_PlayerName].MapData[idx_c]) and (SKM_Data[_RealmName][_PlayerName].MapData[idx_c][idx_z]) then --iNbNotes = table.getn(SKM_Data[_RealmName][_PlayerName].MapData[idx_c][idx_z]); local DiscardedNotes = { }; for idx_n, val_n in SKM_Data[_RealmName][_PlayerName].MapData[idx_c][idx_z] do local idx_gn = SKM_Data[_RealmName][_PlayerName].MapData[idx_c][idx_z][idx_n]; local Note = SKM_Data[_RealmName][_PlayerName].GlobalMapData[idx_gn]; if (Note[_SKM._xPos]) and (Note[_SKM._yPos]) and (lastUnused <= maxNotes) then local iPOINum = SkM_CheckNearNotesPOI(idx_c, idx_z, Note[_SKM._xPos], Note[_SKM._yPos], idx_n, DiscardedNotes); if (iPOINum) then SkM_Trace(FName, 3, "Already too close POI, discard this one : "..snil(idx_n)); table.insert(DiscardedNotes, idx_n); -- and insert it in the close POI list table.insert(SKM_Context.WorldMapPOINotes[iPOINum], idx_n); else local mainNote = getglobal("SKMapPOI"..lastUnused); SKM_Context.WorldMapPOINotes[lastUnused] = { }; table.insert(SKM_Context.WorldMapPOINotes[lastUnused], idx_n); local mnX,mnY; mnX = Note[_SKM._xPos] * WorldMapDetailFrame:GetWidth(); mnY = -Note[_SKM._yPos] * WorldMapDetailFrame:GetHeight(); mainNote:SetAlpha(0.8); -- SkM_Trace(FName, 3, "Attach position : x = "..snil(mnX)..", y = "..snil(mnY)); mainNote:SetPoint("CENTER", "WorldMapDetailFrame", "TOPLEFT", mnX, mnY); mainNote:SetFrameLevel(WorldMapPlayer:GetFrameLevel() - 1); mainNote.toolTip = idx_n; -- icon is determined below lastUnused = lastUnused + 1; end end end -- for map notes for i=1, getn(SKM_Context.WorldMapPOINotes), 1 do local mainNote = getglobal("SKMapPOI"..i); local mainNoteTexture = getglobal("SKMapPOI"..i.."Texture"); local iNbNotes = getn(SKM_Context.WorldMapPOINotes[i]); local icon; local iNumOfTypes, iNumOfPlayerKillTypes, iNumOfPlayerDeathTypes, iNumOfCreatureKillTypes, TypeCount = SkM_CountPOIEventType(idx_c, idx_z, i); SkM_Trace(FName, 3, "Number of different types = "..iNumOfTypes..", of player kill = "..iNumOfPlayerKillTypes..", of death = "..iNumOfPlayerDeathTypes); if (iNumOfTypes == 1) then -- several notes, but of a single type. Pick the first ! local idx_n = SKM_Context.WorldMapPOINotes[i][1]; local idx_gn = SKM_Data[_RealmName][_PlayerName].MapData[idx_c][idx_z][idx_n]; local Note = SKM_Data[_RealmName][_PlayerName].GlobalMapData[idx_gn]; local noteType = Note[_SKM._storedInfo][_SKM._type]; SkM_Trace(FName, 3, "Single type = "..noteType); icon = SKM_Config.IconsByType[noteType]; if (not icon) then icon = SKM_Config.IconsByType[_SKM._default]; end else if (iNumOfPlayerDeathTypes == iNumOfTypes) then icon = SKM_Config.IconsByType[_SKM._playerDeath]; elseif (iNumOfPlayerKillTypes == iNumOfTypes) then icon = SKM_Config.IconsByType[_SKM._playerKill]; elseif (iNumOfCreatureKillTypes == iNumOfTypes) then icon = SKM_Config.IconsByType[_SKM._creatureKill_Target]; elseif (iNumOfPlayerDeathTypes + iNumOfPlayerKillTypes == iNumOfTypes) then icon = SKM_Config.IconsByType[_SKM._playerKillAndDeath]; else icon = SKM_Config.IconsByType[_SKM._multiType]; end end local texture = SKM_Config.IconPath .. "\\" .. icon; SkM_Trace(FName, 3, "texture = "..texture); mainNoteTexture:SetTexture(texture); mainNote:Show(); end end -- if known zone info end -- if display map -- hide unused notes for i=lastUnused, maxNotes, 1 do local mainNote = getglobal("SKMapPOI"..i); mainNote:Hide(); end if (not SkM_GetOption("ShowWorldMapControl")) then SKMapWorldMapControl:Hide(); else if (SKM_Context.MapOpen) and (idx_z ~= 0) and (iNbNotes > 0) then local idx=1; local MyButton = getglobal("SKMapWorldMapControl_CheckButton"..idx); local ButtonText = getglobal("SKMapWorldMapControl_CheckButton"..idx.."Text"); ButtonText:SetText(SKM_UI_STRINGS.WorldMap_Button_ShowRecords); if (SkM_GetOption("MapDisplayRecords")) then MyButton:SetChecked(1); else MyButton:SetChecked(0); end SKMapWorldMapControl:Show(); else SKMapWorldMapControl:Hide(); end end end -- -------------------------------------------------------------------------------------- -- SkM_CountPOIEventType -- -------------------------------------------------------------------------------------- -- Count the different types of records attached to a given POI. -- Will be useful to allocate an icon to this POI. -- -------------------------------------------------------------------------------------- function SkM_CountPOIEventType(idx_c, idx_z, iPOINum) local FName = "SkM_CountPOIEventType"; local iNbNotes = getn(SKM_Context.WorldMapPOINotes[iPOINum]); local TypeCount = { }; local iPlayerDeathTypes = 0; local iPlayerKillTypes = 0; local iCreatureKillTypes = 0; for i=1, iNbNotes, 1 do local idx_n = SKM_Context.WorldMapPOINotes[iPOINum][i]; local idx_gn = SKM_Data[_RealmName][_PlayerName].MapData[idx_c][idx_z][idx_n]; local Note = SKM_Data[_RealmName][_PlayerName].GlobalMapData[idx_gn]; local noteType = Note[_SKM._storedInfo][_SKM._type]; if (not TypeCount[noteType]) then TypeCount[noteType] = 0; end TypeCount[noteType] = TypeCount[noteType] + 1; end local iTypes = 0; for idx, val in TypeCount do iTypes = iTypes + 1; if (idx == _SKM._playerAssistKill) or (idx == _SKM._playerKill) or (idx == _SKM._playerFullKill) then iPlayerKillTypes = iPlayerKillTypes + 1; elseif (idx == _SKM._playerDeath) or (idx == _SKM._playerDeathPvE) or (idx == _SKM._playerDeathPvP) then iPlayerDeathTypes = iPlayerDeathTypes + 1; elseif (idx == _SKM._creatureKill_Xp) or (idx == _SKM._creatureKill_Target) then iCreatureKillTypes = iCreatureKillTypes + 1; end SkM_Trace(FName, 3, "Type = "..idx..", Count = "..val); end return iTypes, iPlayerKillTypes, iPlayerDeathTypes, iCreatureKillTypes, TypeCount; end -- -------------------------------------------------------------------------------------- -- SkM_GetNoteMessage -- -------------------------------------------------------------------------------------- -- Build a note string message from a pattern and an information structure -- -------------------------------------------------------------------------------------- function SkM_GetNoteMessage(Info, sMessagePattern) local FName = "SkM_GetNoteMessage"; if (not Info) then SkM_Trace(FName, 3, "Info is nil"); return nil; end if (not sMessagePattern) then SkM_Trace(FName, 3, "Pattern is nil"); return nil; end local sMessage = sMessagePattern; local sVal_Name = ifnil(Info[_SKM._name], "??"); local sVal_Guild = ifnil(Info[_SKM._guild], "??"); local sVal_Class = ifnil(Info[_SKM._class], "??"); local sVal_Race = ifnil(Info[_SKM._race], "??"); local sVal_Level = ifnil(Info[_SKM._level], "??"); local sVal_Player = ifnil(_PlayerName, "??"); local sVal_Date = ifnil(Info[_SKM._date], "??"); if (sVal_Level == -1) then sVal_Level = "++"; end sMessage = string.gsub(sMessage, "%%name", sVal_Name); sMessage = string.gsub(sMessage, "%%race", sVal_Race); sMessage = string.gsub(sMessage, "%%guild", sVal_Guild); sMessage = string.gsub(sMessage, "%%class", sVal_Class); sMessage = string.gsub(sMessage, "%%level", sVal_Level); sMessage = string.gsub(sMessage, "%%player", sVal_Player); sMessage = string.gsub(sMessage, "%%date", sVal_Date); return sMessage; end -- -------------------------------------------------------------------------------------- -- SkM_FillWorldMapToolTip -- -------------------------------------------------------------------------------------- -- Builds the ToolTip for one of our custom POI that just got mouse focus. -- -------------------------------------------------------------------------------------- function SkM_FillWorldMapToolTip(idx_c, idx_z, idx_n, idx_poi) local FName = "SkM_FillWorldMapToolTip"; SkM_Trace(FName, 3, "idx_n = "..snil(idx_n)..", idx_poi = "..snil(idx_poi)); local iLineCount = 0; local idx, val; if (not SKM_Context.WorldMapPOINotes[idx_poi]) then SkM_Trace(FName, 3, "WorldMapPOINotes not defined for POI "..idx_poi); return; end for idx, val in SKM_Context.WorldMapPOINotes[idx_poi] do local idx_gn = SKM_Data[_RealmName][_PlayerName].MapData[idx_c][idx_z][val]; local Note = SKM_Data[_RealmName][_PlayerName].GlobalMapData[idx_gn]; SkM_Trace(FName, 4, "idx_gn = "..snil(idx_gn)); --local StoredInfo = Note[_SKM._storedInfo]; local StoredInfo = copytable(Note[_SKM._storedInfo]); iLineCount = iLineCount + 1; if (iLineCount > SKM_Config.MapNotes_MaxLines) then return false; end local sPattern; local sName = StoredInfo[_SKM._name]; SkM_Trace(FName, 3, "Type = "..snil(StoredInfo[_SKM._type])); SkM_Trace(FName, 3, "Name = "..snil(sName)..", Enemy Type = "..snil(StoredInfo[_SKM._enemyType])); local Enemy; if (sName) then if not (StoredInfo[_SKM._enemyType] == _SKM._enemyCreature or StoredInfo[_SKM._type] == _SKM._creatureKill_Target or StoredInfo[_SKM._type] == _SKM._creatureKill_Xp) then Enemy = SKM_Data[_RealmName][_PlayerName].EnemyHistory[sName]; end end local bNoEnemyData = true; if (Enemy) then StoredInfo[_SKM._class] = SkM_GetClassText(Enemy[_SKM._class]); StoredInfo[_SKM._race] = SkM_GetRaceText(Enemy[_SKM._race]); StoredInfo[_SKM._level] = Enemy[_SKM._level]; if (StoredInfo[_SKM._class]) or (StoredInfo[_SKM._race]) or (StoredInfo[_SKM._level]) then bNoEnemyData = false; end SkM_Trace(FName, 3, "Class = "..snil(Enemy[_SKM._class])..", Race = "..snil(Enemy[_SKM._race])..", Level = "..snil(Enemy[_SKM._level])); end local RGB; local sPattern; if (StoredInfo[_SKM._type] == _SKM._playerAssistKill) then sPattern = SKM_Config.Message_PlayerKill; RGB = SKM_Config.RGB_PlayerAssistKill; elseif (StoredInfo[_SKM._type] == _SKM._playerKill) then sPattern = SKM_Config.Message_PlayerKill; RGB = SKM_Config.RGB_PlayerKill; elseif (StoredInfo[_SKM._type] == _SKM._playerFullKill) then sPattern = SKM_Config.Message_PlayerKill; if (StoredInfo[_SKM._loneWolfKill]) then RGB = SKM_Config.RGB_LoneWolfKill; else RGB = SKM_Config.RGB_PlayerFullKill; end elseif (StoredInfo[_SKM._type] == _SKM._playerDeath) then sPattern = SKM_Config.Message_PlayerDeath; RGB = SKM_Config.RGB_PlayerDeath; elseif (StoredInfo[_SKM._type] == _SKM._playerDeathPvE) then sPattern = SKM_Config.Message_PlayerDeath_PvE; RGB = SKM_Config.RGB_PlayerPvEDeath; elseif (StoredInfo[_SKM._type] == _SKM._playerDeathPvP) then if (bNoEnemyData == false) then sPattern = SKM_Config.Message_PlayerDeath_PvP; else sPattern = SKM_Config.Message_PlayerDeath_PvP_NoData; end RGB = SKM_Config.RGB_PlayerPvPDeath; elseif (StoredInfo[_SKM._type] == _SKM._creatureKill_Target) then if (StoredInfo[_SKM._class]) then sPattern = SKM_Config.Message_CreatureKill_RareDetail; else sPattern = SKM_Config.Message_CreatureKill_Detail; end RGB = SKM_Config.RGB_CreatureKill; elseif (StoredInfo[_SKM._type] == _SKM._creatureKill_Xp) then sPattern = SKM_Config.Message_CreatureKill_Basic; RGB = SKM_Config.RGB_CreatureKill; elseif (StoredInfo[_SKM._type] == _SKM._levelUp) then sPattern = SKM_Config.Message_LevelUp; RGB = SKM_Config.RGB_LevelUp; end if (StoredInfo[_SKM._honorKill]) then sPattern = sPattern.." "..SKM_Config.SubMessage_HonorKill; end local sLine = SkM_GetNoteMessage(StoredInfo, sPattern); WorldMapTooltip:AddLine(sLine, RGB.r, RGB.g, RGB.b); end return true; end -- -------------------------------------------------------------------------------------- -- SkM_WorldMapEnterPOI -- -------------------------------------------------------------------------------------- -- Handle POI "OnEnter" event : -- Acquire and prepare ToolTip, then display it. -- -------------------------------------------------------------------------------------- function SkM_WorldMapEnterPOI(id) local FName = "SkM_WorldMapEnterPOI"; SkM_Trace(FName, 3, "id = "..id); --if ((not MapNotesPOIMenuFrame:IsVisible()) and (not MapNotesNewMenuFrame:IsVisible()) and MapNotes_BlockingFrame()) then if (true) then local x, y = this:GetCenter(); local x2, y2 = WorldMapButton:GetCenter(); local anchor = ""; if (x > x2) then anchor = "ANCHOR_LEFT"; else anchor = "ANCHOR_RIGHT"; end --local idx_z = GetCurrentMapZone(); --local idx_c = GetCurrentMapContinent(); local idx_c, idx_z = SkM_GetCurrentMapZone_Shift(); local idx_n = this.toolTip; local idx_gn = SKM_Data[_RealmName][_PlayerName].MapData[idx_c][idx_z][idx_n]; local Note = SKM_Data[_RealmName][_PlayerName].GlobalMapData[idx_gn]; SkM_Trace(FName, 3, "this.toolTip = "..this.toolTip); WorldMapTooltip:SetOwner(this, anchor); --WorldMapTooltip:SetText(""); -- doesn't display if no title WorldMapTooltip:SetText(SKM_UI_STRINGS.Map_Window_Title); local xPos = Note[_SKM._xPos]; local yPos = Note[_SKM._yPos]; --SkM_FillWorldMapToolTip(idx_c, idx_z, xPos, yPos); SkM_FillWorldMapToolTip(idx_c, idx_z, idx_n, id); WorldMapTooltip:Show(); else WorldMapTooltip:Hide(); end end -- -------------------------------------------------------------------------------------- -- SkM_WorldMapLeavePOI -- -------------------------------------------------------------------------------------- -- Handle POI "OnLeave" event : -- Hide ToolTip. -- -------------------------------------------------------------------------------------- function SkM_WorldMapLeavePOI(id) local FName = "SkM_WorldMapLeavePOI"; WorldMapTooltip:Hide(); end -- -------------------------------------------------------------------------------------- -- SkM_FormatParsePattern -- -------------------------------------------------------------------------------------- -- Format a parsing pattern. -- Input pattern is a readable string that contains %s and %d for substitutions. -- Return value is a regular expression, with special characters escaped by '%'. -- -------------------------------------------------------------------------------------- function SkM_FormatParsePattern(sTemplate) local FName = "SkM_FormatParsePattern"; local sPattern = sTemplate; sPattern = string.gsub(sPattern, "%(", "%%("); sPattern = string.gsub(sPattern, "%)", "%%)"); sPattern = string.gsub(sPattern, "%.", "%%."); sPattern = string.gsub(sPattern, "%+", "%%+"); sPattern = string.gsub(sPattern, "%[", "%%["); sPattern = string.gsub(sPattern, "%]", "%%]"); sPattern = string.gsub(sPattern, "%%d", "([0-9]+)"); sPattern = string.gsub(sPattern, "%%s", "(.+)"); return sPattern; end -- -------------------------------------------------------------------------------------- -- SkM_BuildParsePatterns -- -------------------------------------------------------------------------------------- -- Format as regular expressions all the parsing patterns that we need. -- -------------------------------------------------------------------------------------- function SkM_BuildParsePatterns() local FName = "SkM_BuildParsePatterns"; for idx, val in SKM_PATTERN do local sPattern = SkM_FormatParsePattern(val); SKM_Context.Pattern[idx] = sPattern; end end -- -------------------------------------------------------------------------------------- -- SkM_ParseCombatChat_XpGain -- -------------------------------------------------------------------------------------- -- Handle "player receives combat xp" chat event. -- If we can match one of the "creature kill" messages, then record the creature kill. -- -------------------------------------------------------------------------------------- function SkM_ParseCombatChat_XpGain(sMsg) local FName = "SkM_ParseCombatChat_XpGain"; SkM_Trace(FName, 3, "You gain combat xp"); for sFoe, iXpGain, iBaseXp, iRestXp in string.gfind(sMsg, SKM_Context.Pattern.XpGain_Rested_Solo) do if (sFoe and iXpGain and iBaseXp and iRestXp) then SkM_Trace(FName, 3, "XpGain_Rested_Solo : Foe = "..sFoe..", Xp = "..iXpGain); SkM_RecordCreatureKill_Xp(sFoe); return; end end for sFoe, iXpGain, iBaseXp, iRestXp, iGroupBonus in string.gfind(sMsg, SKM_Context.Pattern.XpGain_Rested_Group) do if (sFoe and iXpGain and iBaseXp and iRestXp and iGroupBonus) then SkM_Trace(FName, 3, "XpGain_Rested_Group : Foe = "..sFoe..", Xp = "..iXpGain); SkM_RecordCreatureKill_Xp(sFoe); return; end end for sFoe, iXpGain, iBaseXp, iRestXp, iRaidPenalty in string.gfind(sMsg, SKM_Context.Pattern.XpGain_Rested_Raid) do if (sFoe and iXpGain and iBaseXp and iRestXp and iRaidPenalty) then SkM_Trace(FName, 3, "XpGain_Rested_Raid : Foe = "..sFoe..", Xp = "..iXpGain); SkM_RecordCreatureKill_Xp(sFoe); return; end end for sFoe, iXpGain in string.gfind(sMsg, SKM_Context.Pattern.XpGain_Solo) do if (sFoe and iXpGain) then SkM_Trace(FName, 3, "XpGain_Solo : Foe = "..sFoe..", Xp = "..iXpGain); SkM_RecordCreatureKill_Xp(sFoe); return; end end for sFoe, iXpGain, iGroupBonus in string.gfind(sMsg, SKM_Context.Pattern.XpGain_Group) do if (sFoe and iXpGain and iGroupBonus) then SkM_Trace(FName, 3, "XpGain_Group : Foe = "..sFoe..", Xp = "..iXpGain); SkM_RecordCreatureKill_Xp(sFoe); return; end end for sFoe, iXpGain, iRaidPenalty in string.gfind(sMsg, SKM_Context.Pattern.XpGain_Raid) do if (sFoe and iXpGain and iRaidPenalty) then SkM_Trace(FName, 3, "XpGain_Raid : Foe = "..sFoe..", Xp = "..iXpGain); SkM_RecordCreatureKill_Xp(sFoe); return; end end end -- -------------------------------------------------------------------------------------- -- SkM_ParseCombatChat_SelfCombatHit -- -------------------------------------------------------------------------------------- -- Handle "Player hits something" chat event. -- Record damage done to this enemy. -- Note that this may be a player or a creature. We don't check it yet as enemy player -- may not be yet known, it's better to check on death event. -- -------------------------------------------------------------------------------------- function SkM_ParseCombatChat_SelfCombatHit(sMsg) local FName = "SkM_ParseCombatChat_SelfCombatHit"; SkM_Trace(FName, 3, "You do physical damage to something"); for sFoe, iDamage in string.gfind(sMsg, SKM_Context.Pattern.Player_HitDamage) do if (sFoe and iDamage) then SkM_Trace(FName, 3, "Player_HitDamage : Foe = "..sFoe..", Damage = "..iDamage); SkM_LogDamage_OnPvpEnemy(iDamage, _PlayerName, sFoe); return; end end for sFoe, iDamage in string.gfind(sMsg, SKM_Context.Pattern.Player_HitCritDamage) do if (sFoe and iDamage) then SkM_Trace(FName, 3, "Player_HitDamage : Foe = "..sFoe..", Damage = "..iDamage); SkM_LogDamage_OnPvpEnemy(iDamage, _PlayerName, sFoe); return; end end end -- -------------------------------------------------------------------------------------- -- SkM_ParseCombatChat_SelfCombatSpell -- -------------------------------------------------------------------------------------- -- Handle "Player does spell damage on something" chat event. -- Record damage done to this enemy. -- Note that this may be a player or a creature. We don't check it yet as enemy player -- may not be yet known, it's better to check on death event. -- -------------------------------------------------------------------------------------- function SkM_ParseCombatChat_SelfCombatSpell(sMsg) local FName = "SkM_ParseCombatChat_SelfCombatSpell"; SkM_Trace(FName, 3, "You do spell damage to something"); for sSpell, sFoe, iDamage in string.gfind(sMsg, SKM_Context.Pattern.Player_SpellDamage) do if (sSpell and sFoe and iDamage) then SkM_Trace(FName, 3, "Player_SpellDamage : Spell = "..sSpell..", Foe = "..sFoe..", Damage = "..iDamage); SkM_LogDamage_OnPvpEnemy(iDamage, _PlayerName, sFoe); return; end end for sSpell, sFoe, iDamage in string.gfind(sMsg, SKM_Context.Pattern.Player_SpellCritDamage) do if (sSpell and sFoe and iDamage) then SkM_Trace(FName, 3, "Player_SpellCritDamage : Spell = "..sSpell..", Foe = "..sFoe..", Damage = "..iDamage); SkM_LogDamage_OnPvpEnemy(iDamage, _PlayerName, sFoe); return; end end end -- -------------------------------------------------------------------------------------- -- SkM_ParseCombatChat_FriendCombatHit -- -------------------------------------------------------------------------------------- -- Handle "Friendly player hits something" chat event. -- Record damage done to this enemy. -- Note that this may be a player or a creature. We don't check it yet as enemy player -- may not be yet known, it's better to check on death event. -- -------------------------------------------------------------------------------------- function SkM_ParseCombatChat_FriendCombatHit(sMsg) local FName = "SkM_ParseCombatChat_FriendCombatHit"; SkM_Trace(FName, 3, "A friend do physical damage to something"); for sAttacker, sFoe, iDamage in string.gfind(sMsg, SKM_Context.Pattern.Other_HitDamage) do if (sAttacker and sFoe and iDamage) then SkM_Trace(FName, 3, "Other_HitDamage : Attacker = "..sAttacker..", Foe = "..sFoe..", Damage = "..iDamage); SkM_LogDamage_OnPvpEnemy(iDamage, sAttacker, sFoe); return; end end for sAttacker, sFoe, iDamage in string.gfind(sMsg, SKM_Context.Pattern.Other_HitCritDamage) do if (sAttacker and sFoe and iDamage) then SkM_Trace(FName, 3, "Other_HitCritDamage : Attacker = "..sAttacker..", Foe = "..sFoe..", Damage = "..iDamage); SkM_LogDamage_OnPvpEnemy(iDamage, sAttacker, sFoe); return; end end end -- -------------------------------------------------------------------------------------- -- SkM_ParseCombatChat_FriendCombatSpell -- -------------------------------------------------------------------------------------- -- Handle "Friendly player does spell damage to something" chat event. -- Record damage done to this enemy. -- Note that this may be a player or a creature. We don't check it yet as enemy player -- may not be yet known, it's better to check on death event. -- -------------------------------------------------------------------------------------- function SkM_ParseCombatChat_FriendCombatSpell(sMsg) local FName = "SkM_ParseCombatChat_FriendCombatSpell"; SkM_Trace(FName, 3, "A friend do spell damage to something"); -- PIng: Patch for French version where attacker and spell are inversed if ( GetLocale() == "frFR" ) then for sSpell, sAttacker, sFoe, iDamage in string.gfind(sMsg, SKM_Context.Pattern.Other_SpellDamage) do if (sAttacker and sSpell and sFoe and iDamage) then SkM_Trace(FName, 3, "Other_SpellDamage : Attacker = "..sAttacker..", Spell = "..sSpell..", Foe = "..sFoe..", Damage = "..iDamage); if (SkM_IsTotem(sAttacker)) then -- ignore totem damage return; end SkM_LogDamage_OnPvpEnemy(iDamage, sAttacker, sFoe); return; end end else for sAttacker, sSpell, sFoe, iDamage in string.gfind(sMsg, SKM_Context.Pattern.Other_SpellDamage) do if (sAttacker and sSpell and sFoe and iDamage) then SkM_Trace(FName, 3, "Other_SpellDamage : Attacker = "..sAttacker..", Spell = "..sSpell..", Foe = "..sFoe..", Damage = "..iDamage); if (SkM_IsTotem(sAttacker)) then -- ignore totem damage return; end SkM_LogDamage_OnPvpEnemy(iDamage, sAttacker, sFoe); return; end end end for sAttacker, sSpell, sFoe, iDamage in string.gfind(sMsg, SKM_Context.Pattern.Other_SpellCritDamage) do if (sAttacker and sSpell and sFoe and iDamage) then SkM_Trace(FName, 3, "Other_SpellCritDamage : Attacker = "..sAttacker..", Spell = "..sSpell..", Foe = "..sFoe..", Damage = "..iDamage); SkM_LogDamage_OnPvpEnemy(iDamage, sAttacker, sFoe); return; end end end -- -------------------------------------------------------------------------------------- -- SkM_ParseCombatChat_PetCombatHit -- -------------------------------------------------------------------------------------- -- Handle "Our pet hits something" chat event. -- Record damage (for pet owner !) done to this enemy. -- Note that this may be a player or a creature. We don't check it yet as enemy player -- may not be yet known, it's better to check on death event. -- -------------------------------------------------------------------------------------- function SkM_ParseCombatChat_PetCombatHit(sMsg) local FName = "SkM_ParseCombatChat_PetCombatHit"; SkM_Trace(FName, 3, "Your pet does physical damage to something"); for sAttacker, sFoe, iDamage in string.gfind(sMsg, SKM_Context.Pattern.Other_HitDamage) do if (sAttacker and sFoe and iDamage) then SkM_Trace(FName, 3, "Other_HitDamage : Attacker = "..sAttacker..", Foe = "..sFoe..", Damage = "..iDamage); SkM_LogDamage_OnPvpEnemy(iDamage, _PlayerName, sFoe); return; end end for sAttacker, sFoe, iDamage in string.gfind(sMsg, SKM_Context.Pattern.Other_HitCritDamage) do if (sAttacker and sFoe and iDamage) then SkM_Trace(FName, 3, "Other_HitCritDamage : Attacker = "..sAttacker..", Foe = "..sFoe..", Damage = "..iDamage); SkM_LogDamage_OnPvpEnemy(iDamage, _PlayerName, sFoe); return; end end end -- -------------------------------------------------------------------------------------- -- SkM_ParseCombatChat_PetCombatSpell -- -------------------------------------------------------------------------------------- -- Handle "Our pet does spell damage to something" chat event. -- Record damage (for pet owner !) done to this enemy. -- Note that this may be a player or a creature. We don't check it yet as enemy player -- may not be yet known, it's better to check on death event. -- -------------------------------------------------------------------------------------- function SkM_ParseCombatChat_PetCombatSpell(sMsg) local FName = "SkM_ParseCombatChat_PetCombatSpell"; SkM_Trace(FName, 3, "Your pet does spell damage to something"); -- Note : it may be your totem if you are a shaman -- in this case, we don't ignore it : we count it as player damage also. for sAttacker, sSpell, sFoe, iDamage in string.gfind(sMsg, SKM_Context.Pattern.Other_SpellDamage) do if (sAttacker and sSpell and sFoe and iDamage) then SkM_Trace(FName, 3, "Other_SpellDamage : Attacker = "..sAttacker..", Spell = "..sSpell..", Foe = "..sFoe..", Damage = "..iDamage); SkM_LogDamage_OnPvpEnemy(iDamage, _PlayerName, sFoe); return; end end for sAttacker, sSpell, sFoe, iDamage in string.gfind(sMsg, SKM_Context.Pattern.Other_SpellCritDamage) do if (sAttacker and sSpell and sFoe and iDamage) then SkM_Trace(FName, 3, "Other_SpellCritDamage : Attacker = "..sAttacker..", Spell = "..sSpell..", Foe = "..sFoe..", Damage = "..iDamage); SkM_LogDamage_OnPvpEnemy(iDamage, _PlayerName, sFoe); return; end end end -- -------------------------------------------------------------------------------------- -- SkM_ParseCombatChat_EnemyDot -- -------------------------------------------------------------------------------------- -- Handle "Enemy player suffers from DoT" chat event. -- Record damage done (by either self of another player) to this enemy. -- -------------------------------------------------------------------------------------- function SkM_ParseCombatChat_EnemyDot(sMsg) local FName = "SkM_ParseCombatChat_EnemyDot"; SkM_Trace(FName, 3, "An enemy suffers from DoT damage"); -- PIng: Patch for French version if ( GetLocale() == "frFR" ) then for sSpell, iDamage, sDamageType, sFoe in string.gfind(sMsg, SKM_Context.Pattern.Player_DotDamage) do if (sFoe and iDamage and sDamageType and sSpell) then SkM_Trace(FName, 3, "Player_DotDamage : Foe = "..sFoe..", Damage = "..iDamage..", Damage type = "..sDamageType..", Spell = "..sSpell); SkM_LogDamage_OnPvpEnemy(iDamage, _PlayerName, sFoe); return; end end for sSpell, sAttacker, sFoe, iDamage, sDamageType in string.gfind(sMsg, SKM_Context.Pattern.Other_DotDamage) do if (sFoe and iDamage and sDamageType and sAttacker and sSpell) then SkM_Trace(FName, 3, "Other_DotDamage : Attacker = "..sAttacker..", Foe = "..sFoe..", Damage = "..iDamage..", Damage type = "..sDamageType..", Spell = "..sSpell); SkM_LogDamage_OnPvpEnemy(iDamage, sAttacker, sFoe); return; end end else for sFoe, iDamage, sDamageType, sSpell in string.gfind(sMsg, SKM_Context.Pattern.Player_DotDamage) do if (sFoe and iDamage and sDamageType and sSpell) then SkM_Trace(FName, 3, "Player_DotDamage : Foe = "..sFoe..", Damage = "..iDamage..", Damage type = "..sDamageType..", Spell = "..sSpell); SkM_LogDamage_OnPvpEnemy(iDamage, _PlayerName, sFoe); return; end end for sFoe, iDamage, sDamageType, sAttacker, sSpell in string.gfind(sMsg, SKM_Context.Pattern.Other_DotDamage) do if (sFoe and iDamage and sDamageType and sAttacker and sSpell) then SkM_Trace(FName, 3, "Other_DotDamage : Attacker = "..sAttacker..", Foe = "..sFoe..", Damage = "..iDamage..", Damage type = "..sDamageType..", Spell = "..sSpell); SkM_LogDamage_OnPvpEnemy(iDamage, sAttacker, sFoe); return; end end end end -- -------------------------------------------------------------------------------------- -- SkM_ParseCombatChat_SelfDot -- -------------------------------------------------------------------------------------- -- Handle "Self suffers from DoT" chat event. -- Record damage done to self, without any "enemy type" as we don't know if the enemy -- is a player or a creep. -- -------------------------------------------------------------------------------------- function SkM_ParseCombatChat_SelfDot(sMsg) local FName = "SkM_ParseCombatChat_SelfDot"; SkM_Trace(FName, 3, "Self suffers from DoT damage"); -- We suffered from a DoT : in this case, log damage without enemy type, because -- we do *not* know from the event if it's a player or a creature that cast the DoT ! if ( GetLocale() == "frFR" ) then -- 0.09.1 Begin of modification Fix ? for sSpell, sAttacker, iDamage, sDamageType in string.gfind(sMsg, SKM_Context.Pattern.Self_DotDamage) do if (iDamage and sDamageType and sAttacker and sSpell) then SkM_Trace(FName, 3, "Self_DotDamage : Attacker = "..sAttacker..", Damage = "..iDamage..", Damage type = "..sDamageType..", Spell = "..sSpell); SkM_LogDamage_OnSelf(iDamage, sAttacker, nil); return; end end -- 0.09.1 End of modification else for iDamage, sDamageType, sAttacker, sSpell in string.gfind(sMsg, SKM_Context.Pattern.Self_DotDamage) do if (iDamage and sDamageType and sAttacker and sSpell) then SkM_Trace(FName, 3, "Self_DotDamage : Attacker = "..sAttacker..", Damage = "..iDamage..", Damage type = "..sDamageType..", Spell = "..sSpell); SkM_LogDamage_OnSelf(iDamage, sAttacker, nil); return; end end end end -- -------------------------------------------------------------------------------------- -- SkM_ParseCombatChat_EnemyCombatHit -- -------------------------------------------------------------------------------------- -- Handle "Enemy player hits something" chat event. -- If we are the victim, record damage done to self by that enemy. -- -------------------------------------------------------------------------------------- function SkM_ParseCombatChat_EnemyCombatHit(sMsg) local FName = "SkM_ParseCombatChat_EnemyCombatHit"; SkM_Trace(FName, 3, "A player enemy does physical damage to something"); -- that may be an enemy PET also ! so we need to check if we know this enemy -- if not, log it without "enemy type" filled... for sAttacker, iDamage in string.gfind(sMsg, SKM_Context.Pattern.Self_HitDamage) do if (sAttacker and iDamage) then SkM_Trace(FName, 3, "Self_HitDamage : Attacker = "..sAttacker..", Damage = "..iDamage); SkM_LogDamage_OnSelf(iDamage, sAttacker, SkM_GetKnownEnemyType(sAttacker)); return; end end for sAttacker, iDamage in string.gfind(sMsg, SKM_Context.Pattern.Self_HitCritDamage) do if (sAttacker and iDamage) then SkM_Trace(FName, 3, "Self_CritHitDamage : Attacker = "..sAttacker..", Damage = "..iDamage); SkM_LogDamage_OnSelf(iDamage, sAttacker, SkM_GetKnownEnemyType(sAttacker)); return; end end -- Self is not the target -- we don't care who the hostile player hits and for which amount ! SkM_Trace(FName, 3, "Hostile picks on other player or mob : do nothing"); end -- -------------------------------------------------------------------------------------- -- SkM_ParseCombatChat_EnemyCombatSpell -- -------------------------------------------------------------------------------------- -- Handle "Enemy player does spell damage to something" chat event. -- If we are the victim, record damage done to self by that enemy. -- -------------------------------------------------------------------------------------- function SkM_ParseCombatChat_EnemyCombatSpell(sMsg) local FName = "SkM_ParseCombatChat_EnemyCombatSpell"; SkM_Trace(FName, 3, "A player enemy does spell damage to something"); -- that may be an enemy PET also ! so we need to check if we know this enemy -- if not, log it without "enemy type" filled... -- Is Self the target ? -- PIng: Patch for French version if ( GetLocale() == "frFR" ) then for sSpell, sAttacker, iDamage in string.gfind(sMsg, SKM_Context.Pattern.Self_SpellDamage) do if (sAttacker and sSpell and iDamage) then SkM_Trace(FName, 3, "Self_SpellDamage : Attacker = "..sAttacker..", Spell = "..sSpell..", Damage = "..iDamage); if (SkM_IsTotem(sAttacker)) then -- ignore totem damage return; end SkM_LogDamage_OnSelf(iDamage, sAttacker, SkM_GetKnownEnemyType(sAttacker)); return; end end else for sAttacker, sSpell, iDamage in string.gfind(sMsg, SKM_Context.Pattern.Self_SpellDamage) do if (sAttacker and sSpell and iDamage) then SkM_Trace(FName, 3, "Self_SpellDamage : Attacker = "..sAttacker..", Spell = "..sSpell..", Damage = "..iDamage); if (SkM_IsTotem(sAttacker)) then -- ignore totem damage return; end SkM_LogDamage_OnSelf(iDamage, sAttacker, SkM_GetKnownEnemyType(sAttacker)); return; end end end for sAttacker, sSpell, iDamage in string.gfind(sMsg, SKM_Context.Pattern.Self_SpellCritDamage) do if (sAttacker and sSpell and iDamage) then SkM_Trace(FName, 3, "Self_SpellCritDamage : Attacker = "..sAttacker..", Spell = "..sSpell..", Damage = "..iDamage); SkM_LogDamage_OnSelf(iDamage, sAttacker, SkM_GetKnownEnemyType(sAttacker)); return; end end -- Self is not the target -- we don't care who the hostile player hits and for which amount ! SkM_Trace(FName, 3, "Hostile picks on other player or mob : do nothing"); end -- -------------------------------------------------------------------------------------- -- SkM_ParseCombatChat_CreatureCombatHit -- -------------------------------------------------------------------------------------- -- Handle "Creature hits something" chat event. -- If we are the victim, record damage done to self by that creature. -- -------------------------------------------------------------------------------------- function SkM_ParseCombatChat_CreatureCombatHit(sMsg) local FName = "SkM_ParseCombatChat_CreatureCombatHit"; SkM_Trace(FName, 3, "A creature does physical damage to something"); for sAttacker, iDamage in string.gfind(sMsg, SKM_Context.Pattern.Self_HitDamage) do if (sAttacker and iDamage) then SkM_Trace(FName, 3, "Self_HitDamage : Attacker = "..sAttacker..", Damage = "..iDamage); SkM_LogDamage_OnSelf(iDamage, sAttacker, _SKM._enemyCreature); return; end end for sAttacker, iDamage in string.gfind(sMsg, SKM_Context.Pattern.Self_HitCritDamage) do if (sAttacker and iDamage) then SkM_Trace(FName, 3, "Self_CritHitDamage : Attacker = "..sAttacker..", Damage = "..iDamage); SkM_LogDamage_OnSelf(iDamage, sAttacker, _SKM._enemyCreature); return; end end -- Self is not the target -- we don't care who the creature hits and for which amount ! SkM_Trace(FName, 3, "Creature picks on other player or mob : do nothing"); end -- -------------------------------------------------------------------------------------- -- SkM_ParseCombatChat_CreatureCombatSpell -- -------------------------------------------------------------------------------------- -- Handle "Creature does spell damage to something" chat event. -- If we are the victim, record damage done to self by that creature. -- -------------------------------------------------------------------------------------- function SkM_ParseCombatChat_CreatureCombatSpell(sMsg) local FName = "SkM_ParseCombatChat_CreatureCombatSpell"; SkM_Trace(FName, 3, "A creature does spell damage to something"); -- 0.08.1 Begin of modification: Patch for French version if ( GetLocale() == "frFR" ) then for sSpell, sAttacker, iDamage in string.gfind(sMsg, SKM_Context.Pattern.Self_SpellDamage) do if (sAttacker and sSpell and iDamage) then SkM_Trace(FName, 3, "Self_SpellDamage : Attacker = "..sAttacker..", Spell = "..sSpell..", Damage = "..iDamage); if (SkM_IsTotem(sAttacker)) then -- ignore totem damage return; end SkM_LogDamage_OnSelf(iDamage, sAttacker, _SKM._enemyCreature); return; end end else for sAttacker, sSpell, iDamage in string.gfind(sMsg, SKM_Context.Pattern.Self_SpellDamage) do if (sAttacker and sSpell and iDamage) then SkM_Trace(FName, 3, "Self_SpellDamage : Attacker = "..sAttacker..", Spell = "..sSpell..", Damage = "..iDamage); if (SkM_IsTotem(sAttacker)) then -- ignore totem damage return; end SkM_LogDamage_OnSelf(iDamage, sAttacker, _SKM._enemyCreature); return; end end end -- 0.08.1 End of modification for sAttacker, sSpell, iDamage in string.gfind(sMsg, SKM_Context.Pattern.Self_SpellCritDamage) do if (sAttacker and sSpell and iDamage) then SkM_Trace(FName, 3, "Self_SpellCritDamage : Attacker = "..sAttacker..", Spell = "..sSpell..", Damage = "..iDamage); SkM_LogDamage_OnSelf(iDamage, sAttacker, _SKM._enemyCreature); return; end end -- Self is not the target -- we don't care who the creature hits and for which amount ! SkM_Trace(FName, 3, "Creature picks on other player or mob : do nothing"); end -- -------------------------------------------------------------------------------------- -- SkM_ParseCombatChat_HostileDeath -- -------------------------------------------------------------------------------------- -- Handle "Enemy player dies" chat event. -- Find out from information previously gathered if we can be awarded this kill, -- and if so record it. -- -------------------------------------------------------------------------------------- function SkM_ParseCombatChat_HostileDeath(sMsg) local FName = "SkM_ParseCombatChat_HostileDeath"; for sFoe in string.gfind(sMsg, SKM_Context.Pattern.Other_Death) do if (sFoe) then SkM_Trace(FName, 3, "Other_Death : Foe = "..sFoe); SkM_Trace(FName, 2, "Enemy player death detected (from chat msg) : "..snil(sFoe)); SkM_PvpEnemyDeath(sFoe); return; end end end -- -------------------------------------------------------------------------------------- -- SkM_ParseCombatChat_HonorKill -- -------------------------------------------------------------------------------------- -- Handle "Enemy player dies and is worth honor" chat event. -- Find out from information previously gathered if we can be awarded this kill, -- and if so record it. -- -------------------------------------------------------------------------------------- function SkM_ParseCombatChat_HonorKill(sMsg) local FName = "SkM_ParseCombatChat_HonorKill"; for sFoe, sRank in string.gfind(sMsg, SKM_Context.Pattern.Honor_Kill) do if (sFoe and sRank) then SkM_Trace(FName, 3, "Honor_Kill : Foe = "..sFoe..", Rank = "..sRank); SkM_Trace(FName, 2, "Enemy player death detected (from chat, honor) : "..snil(sFoe)); SkM_PvpEnemyDeath(sFoe, true, sRank); end end end -- -------------------------------------------------------------------------------------- -- SkM_RecordCreatureKill_Xp -- -------------------------------------------------------------------------------------- -- Record a creature kill by "combat xp message". -- -------------------------------------------------------------------------------------- function SkM_RecordCreatureKill_Xp(sName) local FName = "SkM_RecordCreatureKill_Xp"; if (not SkM_GetOption("RecordCreatureKill")) then return; end local curTime = GetTime(); SkM_Trace(FName, 3, "Creature by xp kill : "..sName.." (time = "..curTime..")"); -- check if we're already processed this kill on health change if (SKM_Context.LastCreatureKill) then SkM_Trace(FName, 3, "Recent creature kill : "..snil(SKM_Context.LastCreatureKill[_SKM._name]).." (time = "..snil(SKM_Context.LastCreatureKill[_SKM._time])..")"); if (SKM_Context.LastCreatureKill[_SKM._name] == sName) and (curTime < SKM_Context.LastCreatureKill[_SKM._time] + 1) then SkM_Trace(FName, 2, "Already processed kill : "..sName); -- clear last creature kill and return SKM_Context.LastCreatureKill = nil; return; end end -- kill not recorded by target kill, process it local StoreInfo = { }; StoreInfo[_SKM._type] = _SKM._creatureKill_Xp; local sDate1, sDate2 = SkM_GetDate(); StoreInfo[_SKM._date] = sDate1; --StoreInfo[_sortdate] = sDate2; StoreInfo[_SKM._name] = sName; if (not SkM_AddMapData(StoreInfo)) then return; end if (SkM_GetOption("DisplayCreatureKillRecord")) then SkM_ChatMessageColP(string.format(SKM_UI_STRINGS.RecordMessage_CreatureKill, sName), SKM_Config.RGB_CreatureKill); end -- memorize killed mob to that we don't count it again when receiving xp message SKM_Context.LastCreatureKill = { }; SKM_Context.LastCreatureKill[_SKM._name] = sName; SKM_Context.LastCreatureKill[_SKM._time] = GetTime(); --local idx_c, idx_z = SkM_GetZone(); local idx_c, idx_z = SkM_GetZone_Shift(); if (idx_z) then SkM_CleanZoneCreatureKill(idx_c, idx_z); end end -- -------------------------------------------------------------------------------------- -- SkM_RecordCreatureKill_Target -- -------------------------------------------------------------------------------------- -- Record a creature kill by target (the creature we are currently targetting dies, -- and it was tapped by us). -- -------------------------------------------------------------------------------------- function SkM_RecordCreatureKill_Target(sName, iLevel, sCreatureClass) local FName = "SkM_RecordCreatureKill_Target"; if (not SkM_GetOption("RecordCreatureKill")) then return; end local curTime = GetTime(); SkM_Trace(FName, 3, "Creature by target kill : "..sName.." (time = "..curTime..")"); -- check if we're already processed this kill on combat xp message if (SKM_Context.LastCreatureKill) then SkM_Trace(FName, 3, "Recent creature kill : "..snil(SKM_Context.LastCreatureKill[_SKM._name]).." (time = "..snil(SKM_Context.LastCreatureKill[_SKM._time])..")"); if (SKM_Context.LastCreatureKill[_SKM._name] == sName) and (curTime < SKM_Context.LastCreatureKill[_SKM._time] + 1) then SkM_Trace(FName, 2, "Already processed kill : "..sName); -- clear last creature kill and return SKM_Context.LastCreatureKill = nil; return; end end local StoreInfo = { }; StoreInfo[_SKM._type] = _SKM._creatureKill_Target; local sDate1, sDate2 = SkM_GetDate(); StoreInfo[_SKM._date] = sDate1; --StoreInfo[_sortdate] = sDate2; StoreInfo[_SKM._name] = sName; StoreInfo[_SKM._level] = iLevel; StoreInfo[_SKM._class] = SKM_Config.CreatureClassLabel[sCreatureClass]; if (not SkM_AddMapData(StoreInfo)) then return; end if (SkM_GetOption("DisplayCreatureKillRecord")) then SkM_ChatMessageColP(string.format(SKM_UI_STRINGS.RecordMessage_CreatureKill, sName), SKM_Config.RGB_CreatureKill); end -- memorize killed mob to that we don't count it again when receiving xp message SKM_Context.LastCreatureKill = { }; SKM_Context.LastCreatureKill[_SKM._name] = sName; SKM_Context.LastCreatureKill[_SKM._time] = GetTime(); --local idx_c, idx_z = SkM_GetZone(); local idx_c, idx_z = SkM_GetZone_Shift(); if (idx_z) then SkM_CleanZoneCreatureKill(idx_c, idx_z); end end -- -------------------------------------------------------------------------------------- -- SkM_DeleteNote -- -------------------------------------------------------------------------------------- -- Delete a global note. Remove this note from global and zone map data, and recompute -- indexes of more recent notes. -- -------------------------------------------------------------------------------------- function SkM_DeleteNote(RealmName, PlayerName, idx_gn) local FName = "SkM_DeleteNote"; SkM_Trace(FName, 3, "Removing note ("..RealmName.." / "..PlayerName..") : global index = "..idx_gn); local idx_c, idx_z, idx_n; local val_c, val_z, val_n; local cont_rem, zone_rem, note_rem; for idx_c = 1,getn(SKM_Data[RealmName][PlayerName].MapData),1 do for idx_z = 1,getn(SKM_Data[RealmName][PlayerName].MapData[idx_c]) do for idx_n = 1,getn(SKM_Data[RealmName][PlayerName].MapData[idx_c][idx_z]) do local val_n = SKM_Data[RealmName][PlayerName].MapData[idx_c][idx_z][idx_n]; if (val_n == idx_gn) then cont_rem = idx_c; zone_rem = idx_z; note_rem = idx_n; elseif (val_n > idx_gn) then SKM_Data[RealmName][PlayerName].MapData[idx_c][idx_z][idx_n] = val_n - 1; end end end end SkM_Trace(FName, 3, "Removing note : continent = "..snil(cont_rem)..", zone = "..snil(zone_rem)..", note = "..snil(note_rem)); table.remove(SKM_Data[RealmName][PlayerName].MapData[cont_rem][zone_rem], note_rem); table.remove(SKM_Data[RealmName][PlayerName].GlobalMapData, idx_gn); end -- -------------------------------------------------------------------------------------- -- SkM_CleanZoneCreatureKill -- -------------------------------------------------------------------------------------- -- A creature kill has been recorded, clean older creature kill records if necessary -- (from configurable maximum number of creature records by zone). -- -------------------------------------------------------------------------------------- function SkM_CleanZoneCreatureKill(idx_c, idx_z) local FName = "SkM_CleanZoneCreatureKill"; SkM_Trace(FName, 3, "Continent = "..idx_c..", Zone = "..idx_z); local iZoneNoteCount = getn(SKM_Data[_RealmName][_PlayerName].MapData[idx_c][idx_z]); --iZoneNoteCount = tablesize(SKM_Data[_RealmName][_PlayerName].MapData[idx_c][idx_z]); SkM_Trace(FName, 3, "Notes in zone = "..iZoneNoteCount); local iCreatureKill = 0; local i; for i=iZoneNoteCount, 1, -1 do local idx_gn = SKM_Data[_RealmName][_PlayerName].MapData[idx_c][idx_z][i]; local Note = SKM_Data[_RealmName][_PlayerName].GlobalMapData[idx_gn]; if ((Note) and (Note[_SKM._storedInfo])) and ((Note[_SKM._storedInfo][_SKM._type] == _SKM._creatureKill_Target) or (Note[_SKM._storedInfo][_SKM._type] == _SKM._creatureKill_Xp)) then if (iCreatureKill >= SkM_GetOption("CreatureKillRecordsByZone")) then -- already reached the max count of creature kill notes by zone -- have to delete this one. -- remove from GlobalMapData and from MapData SkM_Trace(FName, 3, "Removing note : global index = "..idx_gn..", map index = "..i); SkM_DeleteNote(_RealmName, _PlayerName, idx_gn); else iCreatureKill = iCreatureKill + 1; end end end end -- -------------------------------------------------------------------------------------- -- SkM_CheckForgetEnemy -- -------------------------------------------------------------------------------------- -- Check if we can forget an enemy that has engaged in combat against us. -- If no update has been received in a given time frame, then forget him. -- -------------------------------------------------------------------------------------- function SkM_CheckForgetEnemy(sName) local Name = "SkM_CheckForgetEnemy"; local curTime = GetTime(); if (SKM_Context.EnemyCombat[sName]) then -- there exists information about that enemy. -- check when last updated if (curTime - SKM_Context.EnemyCombat[sName][_SKM._lastUpdate] > SKM_Config.ForgetEnemyTimer) then SKM_Context.EnemyCombat[sName] = nil; end end end -- -------------------------------------------------------------------------------------- -- SkM_BuildGroupList -- -------------------------------------------------------------------------------------- -- Build a list of players currently in the group. Called each time the group members -- change. -- -------------------------------------------------------------------------------------- function SkM_BuildGroupList() local FName = "SkM_BuildGroupList"; SkM_Trace(FName, 2, "Party changed, rebuild group list"); SKM_Context.GroupList = { }; local i; for i=1,GetNumPartyMembers() do local sUnit = SKM_UNIT_PARTY .. i; local sName = SkM_UnitName(sUnit); if (sName) then table.insert(SKM_Context.GroupList, sName); end end end -- -------------------------------------------------------------------------------------- -- SkM_IsNameInGroup -- -------------------------------------------------------------------------------------- -- Check if given player name is in party. -- -------------------------------------------------------------------------------------- function SkM_IsNameInGroup(sName) return ( (sName == _PlayerName) or (intable(sName, SKM_Context.GroupList)) ); end -- -------------------------------------------------------------------------------------- -- SkM_LogDamage_OnPvpEnemy -- -------------------------------------------------------------------------------------- -- Keep track of damage done on an enemy, and who did this damage (self or our group, -- or someone else). -- -------------------------------------------------------------------------------------- function SkM_LogDamage_OnPvpEnemy(iDamage, sFriendName, sName) local FName = "SkM_LogDamage_OnPvpEnemy"; local curTime = GetTime(); -- first check if we remember this enemy and if no update was received for a long time, -- then forget him and start anew. SkM_CheckForgetEnemy(sName); if (not SKM_Context.EnemyCombat[sName]) then SKM_Context.EnemyCombat[sName] = { }; SKM_Context.EnemyCombat[sName][_SKM._name] = sName; SKM_Context.EnemyCombat[sName][_SKM._totalDamage] = 0; SKM_Context.EnemyCombat[sName][_SKM._groupDamage] = 0; end SKM_Context.EnemyCombat[sName][_SKM._lastUpdate] = curTime; SKM_Context.EnemyCombat[sName][_SKM._totalDamage] = SKM_Context.EnemyCombat[sName][_SKM._totalDamage] + iDamage; if (SkM_IsNameInGroup(sFriendName)) then SKM_Context.EnemyCombat[sName][_SKM._groupDamage] = SKM_Context.EnemyCombat[sName][_SKM._groupDamage] + iDamage; end SkM_Trace(FName, 3, "EnemyCombat updated for "..sName.." : Total damage = ".. SKM_Context.EnemyCombat[sName][_SKM._totalDamage] ..", Group damage = ".. SKM_Context.EnemyCombat[sName][_SKM._groupDamage]); end function SkM_UpdateEnemyHistory() SKM_Context.PlayerDataChanged = true; end -- -------------------------------------------------------------------------------------- -- SkM_UpdateEnemy_IncrCounter -- -------------------------------------------------------------------------------------- -- Increment enemy counter for a given type, and enemy guild counter if applicable -- -------------------------------------------------------------------------------------- function SkM_UpdateEnemy_IncrCounter(sName, sType, iValue, bPropagateToGuild) SkM_UpdateEnemyHistory(); SKM_Data[_RealmName][_PlayerName].EnemyHistory[sName][sType] = ifnil(SKM_Data[_RealmName][_PlayerName].EnemyHistory[sName][sType], 0) + iValue; if (bPropagateToGuild) then local sGuildName = SKM_Data[_RealmName][_PlayerName].EnemyHistory[sName][_SKM._guild]; if ((sGuildName ~= nil) and (sGuildName ~= "")) then SkM_UpdateGuild_IncrCounter(sGuildName, sType, iValue); end end end -- -------------------------------------------------------------------------------------- -- SkM_UpdateEnemy_IncrPlayerKill -- -------------------------------------------------------------------------------------- -- Increment enemy kill count, and enemy guild kill count if applicable -- -------------------------------------------------------------------------------------- function SkM_UpdateEnemy_IncrPlayerKill(sName, iValue) SkM_UpdateEnemy_IncrCounter(sName, _SKM._playerKill, iValue, true); end -- -------------------------------------------------------------------------------------- -- SkM_UpdateEnemy_IncrPlayerFullKill -- -------------------------------------------------------------------------------------- -- Increment enemy full kill count, and enemy guild full kill count if applicable -- -------------------------------------------------------------------------------------- function SkM_UpdateEnemy_IncrPlayerFullKill(sName, iValue) SkM_UpdateEnemy_IncrCounter(sName, _SKM._playerFullKill, iValue, true); end -- -------------------------------------------------------------------------------------- -- SkM_UpdateEnemy_IncrPlayerAssistKill -- -------------------------------------------------------------------------------------- -- Increment enemy assist kill count, and enemy guild assist kill count if applicable -- -------------------------------------------------------------------------------------- function SkM_UpdateEnemy_IncrPlayerAssistKill(sName, iValue) SkM_UpdateEnemy_IncrCounter(sName, _SKM._playerAssistKill, iValue, true); end -- -------------------------------------------------------------------------------------- -- SkM_UpdateEnemy_IncrKillPlayer -- -------------------------------------------------------------------------------------- -- Increment enemy kill player count, and enemy guild kill player count if applicable -- -------------------------------------------------------------------------------------- function SkM_UpdateEnemy_IncrKillPlayer(sName, iValue, bBattleground) local sType; if (bBattleground) then sType = _SKM._enemyKillBG; else sType = _SKM._enemyKillPlayer; end SkM_UpdateEnemy_IncrCounter(sName, sType, iValue, true); end -- -------------------------------------------------------------------------------------- -- SkM_UpdateEnemy_IncrHonorKill -- -------------------------------------------------------------------------------------- -- Increment enemy honor kill count, and enemy guild kill count if applicable -- -------------------------------------------------------------------------------------- function SkM_UpdateEnemy_IncrHonorKill(sName, iValue) SkM_UpdateEnemy_IncrCounter(sName, _SKM._honorKill, iValue, true); end function SkM_UpdateEnemy_IncrLoneWolfKill(sName, iValue) SkM_UpdateEnemy_IncrCounter(sName, _SKM._loneWolfKill, iValue, true); end -- -------------------------------------------------------------------------------------- -- SkM_UpdateEnemy_IncrMeet -- -------------------------------------------------------------------------------------- -- Increment enemy meet count -- -------------------------------------------------------------------------------------- function SkM_UpdateEnemy_IncrMeet(sName, iValue) SkM_UpdateEnemy_IncrCounter(sName, _SKM._meetCount, iValue, false); end -- -------------------------------------------------------------------------------------- -- SkM_UpdateEnemy_SetLastView -- -------------------------------------------------------------------------------------- -- Update enemy last view date/time -- -------------------------------------------------------------------------------------- function SkM_UpdateEnemy_SetLastView(sName, sDate) SkM_UpdateEnemyHistory(); SKM_Data[_RealmName][_PlayerName].EnemyHistory[sName][_SKM._lastView] = sDate; end -- -------------------------------------------------------------------------------------- -- SkM_UpdateEnemy_SetLastUpdate -- -------------------------------------------------------------------------------------- -- Update enemy last update date/time -- -------------------------------------------------------------------------------------- function SkM_UpdateEnemy_SetLastUpdate(sName, sDate) SkM_UpdateEnemyHistory(); SKM_Data[_RealmName][_PlayerName].EnemyHistory[sName][_SKM._lastUpdate] = sDate; end -- -------------------------------------------------------------------------------------- -- SkM_UpdateEnemy_SetLevel -- -------------------------------------------------------------------------------------- -- Update enemy level -- -------------------------------------------------------------------------------------- function SkM_UpdateEnemy_SetLevel(sName, iLevel) SkM_UpdateEnemyHistory(); SKM_Data[_RealmName][_PlayerName].EnemyHistory[sName][_SKM._level] = iLevel; end -- -------------------------------------------------------------------------------------- -- SkM_UpdateEnemy_SetClass -- -------------------------------------------------------------------------------------- -- Update enemy class -- -------------------------------------------------------------------------------------- function SkM_UpdateEnemy_SetClass(sName, sClass) SkM_UpdateEnemyHistory(); if (not SKM_Data[_RealmName][_PlayerName].EnemyHistory[sName][_SKM._class]) then SKM_Data[_RealmName][_PlayerName].EnemyHistory[sName][_SKM._class] = sClass; end end -- -------------------------------------------------------------------------------------- -- SkM_UpdateEnemy_SetRace -- -------------------------------------------------------------------------------------- -- Update enemy race -- -------------------------------------------------------------------------------------- function SkM_UpdateEnemy_SetRace(sName, sRace) SkM_UpdateEnemyHistory(); if (not SKM_Data[_RealmName][_PlayerName].EnemyHistory[sName][_SKM._race]) then SKM_Data[_RealmName][_PlayerName].EnemyHistory[sName][_SKM._race] = sRace; end end -- -------------------------------------------------------------------------------------- -- SkM_UpdateEnemy_SetLocation -- -------------------------------------------------------------------------------------- -- Update enemy last seen location -- -------------------------------------------------------------------------------------- function SkM_UpdateEnemy_SetLocation(sName, idx_c, idx_z, xPos, yPos) SkM_UpdateEnemyHistory(); SKM_Data[_RealmName][_PlayerName].EnemyHistory[sName][_SKM._zoneName] = nil; SKM_Data[_RealmName][_PlayerName].EnemyHistory[sName][_SKM._continent] = idx_c; SKM_Data[_RealmName][_PlayerName].EnemyHistory[sName][_SKM._zone] = idx_z; SKM_Data[_RealmName][_PlayerName].EnemyHistory[sName][_SKM._xPos] = xPos; SKM_Data[_RealmName][_PlayerName].EnemyHistory[sName][_SKM._yPos] = yPos; end function SkM_UpdateEnemy_SetLocationName(sName, sZoneName) SkM_UpdateEnemyHistory(); SKM_Data[_RealmName][_PlayerName].EnemyHistory[sName][_SKM._continent] = nil; SKM_Data[_RealmName][_PlayerName].EnemyHistory[sName][_SKM._zone] = nil; SKM_Data[_RealmName][_PlayerName].EnemyHistory[sName][_SKM._xPos] = nil; SKM_Data[_RealmName][_PlayerName].EnemyHistory[sName][_SKM._yPos] = nil; SKM_Data[_RealmName][_PlayerName].EnemyHistory[sName][_SKM._zoneName] = sZoneName; end -- -------------------------------------------------------------------------------------- -- SkM_UpdateEnemy_SetWar -- -------------------------------------------------------------------------------------- -- Update enemy 'at war' status, and war date -- -------------------------------------------------------------------------------------- function SkM_UpdateEnemy_SetWar(sName, bWar, sDate) SkM_UpdateEnemyHistory(); SKM_Data[_RealmName][_PlayerName].EnemyHistory[sName][_SKM._atWar] = bWar; if (bWar) then SKM_Data[_RealmName][_PlayerName].EnemyHistory[sName][_SKM._warDate] = sDate; else SKM_Data[_RealmName][_PlayerName].EnemyHistory[sName][_SKM._warDate] = nil; end end -- -------------------------------------------------------------------------------------- -- SkM_UpdateEnemyLastView -- -------------------------------------------------------------------------------------- -- Received some information about an enemy : update this enemy information -- -------------------------------------------------------------------------------------- function SkM_UpdateEnemyLastView(sName, sDate, bTarget, sUnit) local FName = "SkM_UpdateEnemyLastView"; SkM_UpdateEnemyHistory(); local sTheUnit; if (sUnit) then sTheUnit = sUnit; else sTheUnit = SKM_UNIT_TARGET; end -- if we have unit on target (or mouseover), check if we should ignore or not if (bTarget) then -- if we already have recorded this player, we update his information anyway, -- even if he's low level, and even if he has no PvP flag -- if we have added this enemy to the unknown enemy at war, then we record him anyway if (not SKM_Data[_RealmName][_PlayerName].EnemyHistory[sName]) and (not SKM_Data[_RealmName][_PlayerName].UnknownEnemy[sName]) then if (not SkM_GetOption("StoreEnemyPlayers")) then SkM_Trace(FName, 2, "Storing disabled"); return; end if (SkM_GetOption("IgnoreLowerEnemies")) then local iUnitLevel = UnitLevel(sTheUnit); if (iUnitLevel == -1) then iUnitLevel = 500; end local iMinLevel = math.floor( UnitLevel(SKM_UNIT_PLAYER) * SkM_GetOption("IgnoreLevelThreshold") / 100 ); if ( iUnitLevel < iMinLevel ) then SkM_Trace(FName, 1, "Not storing, too low level : "..iUnitLevel..", min. = "..iMinLevel); return; end end end if (SkM_GetOption("IgnoreNoPvPFlag")) then if not (UnitIsPVP(sTheUnit) or UnitIsPVPFreeForAll(sTheUnit)) then SkM_Trace(FName, 1, "Not storing, Unit "..snil(sTheUnit).." is not PvP flagged"); return; end end end if (not SKM_Data[_RealmName][_PlayerName].EnemyHistory[sName]) then SKM_Data[_RealmName][_PlayerName].EnemyHistory[sName] = { }; SKM_Data[_RealmName][_PlayerName].EnemyHistory[sName][_SKM._name] = sName; SKM_Data[_RealmName][_PlayerName].EnemyHistory[sName][_SKM._playerAssistKill] = 0; SKM_Data[_RealmName][_PlayerName].EnemyHistory[sName][_SKM._playerKill] = 0; SKM_Data[_RealmName][_PlayerName].EnemyHistory[sName][_SKM._playerFullKill] = 0; SKM_Data[_RealmName][_PlayerName].EnemyHistory[sName][_SKM._enemyKillPlayer] = 0; SKM_Data[_RealmName][_PlayerName].EnemyHistory[sName][_SKM._enemyKillBG] = 0; SKM_Data[_RealmName][_PlayerName].EnemyHistory[sName][_SKM._playerBGKill] = 0; SKM_Data[_RealmName][_PlayerName].EnemyHistory[sName][_SKM._meetCount] = 1; if (SKM_Data[_RealmName][_PlayerName].UnknownEnemy[sName]) then SKM_Data[_RealmName][_PlayerName].EnemyHistory[sName][_SKM._meetCount] = 1; SKM_Data[_RealmName][_PlayerName].UnknownEnemy[sName] = nil; SkM_Trace(FName, 2, snil(sName).."Added with 'at WAR' status"); end SkM_Trace(FName, 1, "First encounter of enemy : "..snil(sName)); else if ((not SKM_Data[_RealmName][_PlayerName].EnemyHistory[sName][_SKM._meetCount] or (not SKM_Data[_RealmName][_PlayerName].EnemyHistory[sName][_SKM._lastView]))) then -- 09/04/2005 18:44:32 PIng Add a check since LastView is updated later now. SkM_UpdateEnemy_IncrMeet(sName, 1); else -- increase number of time player met this enemy if last viewed time is older than -- configurable value local iDiffTime = SkM_DiffDate(sDate, SKM_Data[_RealmName][_PlayerName].EnemyHistory[sName][_SKM._lastView]); if (iDiffTime ~= nil) and (iDiffTime > SKM_Config.TimeRangeForNewMeeting) then SkM_UpdateEnemy_IncrMeet(sName, 1); end end end -- if we have unit on target (or mouseover), update information if (bTarget) then SkM_UpdateEnemy_SetLevel(sName, UnitLevel(sTheUnit)); SkM_UpdateEnemy_SetClass(sName, SkM_GetClassIndex(UnitClass(sTheUnit))); SkM_UpdateEnemy_SetRace(sName, SkM_GetRaceIndex(UnitRace(sTheUnit))); SkM_UpdateEnemy_SetGuild(sName, ifnil(GetGuildInfo(sTheUnit),"")); -- PIng Add guild support --SkM_UpdateEnemy_SetLastUpdate(sName, sDate); -- get/update rank also local iRank = UnitPVPRank(sTheUnit); if (iRank >= 1) then local sRank = GetPVPRankInfo(iRank, sTheUnit); if (sRank) then SkM_UpdateEnemyRank(sName, sRank); end end end local idx_c, idx_z = SkM_GetZone(); if (idx_z) then SetMapZoom(idx_c, idx_z); local xPos, yPos = GetPlayerMapPosition(SKM_UNIT_PLAYER); --SkM_UpdateEnemy_SetLocation(sName, idx_c, idx_z, xPos, yPos); local cont_shift, zone_shift = SkM_GetZone_Shift(idx_c, idx_z); SkM_UpdateEnemy_SetLocation(sName, cont_shift, zone_shift, xPos, yPos); else local sZoneName = SkM_GetZoneText(); SkM_UpdateEnemy_SetLocationName(sName, sZoneName); end -- 09/04/2005 16:46:34 PIng: Add guild support -- Update guild if known local sGuildName = SKM_Data[_RealmName][_PlayerName].EnemyHistory[sName][_SKM._guild]; -- if ((sGuildName ~= nil) and (sGuildName ~= "not in a guild")) then if ((sGuildName ~= nil) and (sGuildName ~= "")) then SkM_UpdateGuildHistory(sGuildName, sDate, sName); end -- 09/04/2005 16:46:43 End of modification SkM_UpdateEnemy_SetLastView(sName, sDate); -- 09/04/2005 18:30:05 PIng: Moved in order to have the information available for guild update end function SkM_UpdateEnemyRank(sName, sRank) SkM_UpdateEnemyHistory(); SKM_Data[_RealmName][_PlayerName].EnemyHistory[sName][_SKM._rank] = sRank; end function SkM_UpdateEnemy_SetGuild(sName, sGuild) SkM_UpdateEnemyHistory(); --if (not SKM_Data[_RealmName][_PlayerName].EnemyHistory[sName][_SKM._guild]) then SKM_Data[_RealmName][_PlayerName].EnemyHistory[sName][_SKM._guild] = sGuild; --end end function SkM_UpdateGuild_SetLastView(sGuildName, sDate, sPlayerName) SKM_Data[_RealmName][_PlayerName].GuildHistory[sGuildName][_SKM._lastView] = sDate; SKM_Data[_RealmName][_PlayerName].GuildHistory[sGuildName][_SKM._lastPlayerViewed] = sPlayerName; end function SkM_UpdateGuild_IncrCounter(sGuildName, sType, iValue) SKM_Data[_RealmName][_PlayerName].GuildHistory[sGuildName][sType] = ifnil(SKM_Data[_RealmName][_PlayerName].GuildHistory[sGuildName][sType], 0) + iValue; end function SkM_UpdateGuild_IncrPlayerKill(sGuildName, iValue) SkM_UpdateGuild_IncrCounter(sGuildName, _SKM._playerKill, iValue); end function SkM_UpdateGuild_IncrPlayerFullKill(sGuildName, iValue) SkM_UpdateGuild_IncrCounter(sGuildName, _SKM._playerFullKill, iValue); end function SkM_UpdateGuild_IncrPlayerAssistKill(sGuildName, iValue) SkM_UpdateGuild_IncrCounter(sGuildName, _SKM._playerAssistKill, iValue); end function SkM_UpdateGuild_IncrKillPlayer(sGuildName, iValue, bBattleground) local sType; if (bBattleground) then sType = _SKM._enemyKillBG; else sType = _SKM._enemyKillPlayer; end SkM_UpdateGuild_IncrCounter(sGuildName, sType, iValue); end function SkM_UpdateGuild_IncrHonorKill(sGuildName, iValue) SkM_UpdateGuild_IncrCounter(sGuildName, _SKM._honorKill, iValue); end function SkM_UpdateGuild_IncrMeet(sGuildName, iValue) SkM_UpdateGuild_IncrCounter(sGuildName, _SKM._meetCount, iValue); end -- -------------------------------------------------------------------------------------- -- SkM_UpdateGuildHistory -- -------------------------------------------------------------------------------------- -- Update guild information when receiving an update of a enemy from this guild -- -------------------------------------------------------------------------------------- function SkM_UpdateGuildHistory(sGuildName, sDate, sName) local FName = "SkM_UpdateGuildHistory"; SkM_Trace(FName, 2, "Guild Name : "..sGuildName..", Date : ".. sDate.. ", Player Name : "..sName); if (not SKM_Data[_RealmName][_PlayerName].GuildHistory[sGuildName]) then SKM_Data[_RealmName][_PlayerName].GuildHistory[sGuildName] = { }; SKM_Data[_RealmName][_PlayerName].GuildHistory[sGuildName][_SKM._name] = sGuildName; SKM_Data[_RealmName][_PlayerName].GuildHistory[sGuildName][_SKM._playerAssistKill] = 0; SKM_Data[_RealmName][_PlayerName].GuildHistory[sGuildName][_SKM._playerKill] = 0; SKM_Data[_RealmName][_PlayerName].GuildHistory[sGuildName][_SKM._playerFullKill] = 0; SKM_Data[_RealmName][_PlayerName].GuildHistory[sGuildName][_SKM._enemyKillPlayer] = 0; SKM_Data[_RealmName][_PlayerName].GuildHistory[sGuildName][_SKM._enemyKillBG] = 0; SKM_Data[_RealmName][_PlayerName].GuildHistory[sGuildName][_SKM._playerBGKill] = 0; SKM_Data[_RealmName][_PlayerName].GuildHistory[sGuildName][_SKM._meetCount] = 1; else if ((not SKM_Data[_RealmName][_PlayerName].GuildHistory[sGuildName][_SKM._meetCount]) or (not SKM_Data[_RealmName][_PlayerName].EnemyHistory[sName][_SKM._lastView])) then SkM_Trace(FName, 2, "Increment Meet count for Guild for first time"..sGuildName); SkM_UpdateGuild_IncrMeet(sGuildName, 1); else -- increase number of time player met this guild if last viewed time for this enemy is older than -- configurable value SkM_Trace(FName, 2, "check if we need to increment"); local iDiffTime = SkM_DiffDate(sDate, SKM_Data[_RealmName][_PlayerName].EnemyHistory[sName][_SKM._lastView]); if (iDiffTime ~= nil) and (iDiffTime > SKM_Config.TimeRangeForNewMeeting) then SkM_Trace(FName, 1, "Increment Meet count for Guild "..sGuildName); SkM_UpdateGuild_IncrMeet(sGuildName, 1); end end SkM_Trace(FName, 2, "Exit"); end SkM_UpdateGuild_SetLastView(sGuildName, sDate, sName); end -- -------------------------------------------------------------------------------------- -- SkM_UpdateGuild_SetWar -- -------------------------------------------------------------------------------------- -- Update guild 'at war' status and war date -- -------------------------------------------------------------------------------------- function SkM_UpdateGuild_SetWar(sName, bWar, sDate) SKM_Data[_RealmName][_PlayerName].GuildHistory[sName][_SKM._atWar] = bWar; if (bWar) then SKM_Data[_RealmName][_PlayerName].GuildHistory[sName][_SKM._warDate] = sDate; else SKM_Data[_RealmName][_PlayerName].GuildHistory[sName][_SKM._warDate] = nil; end end function SkM_GetRecentEnemyKill(sName) local bFound = false; local iNoteIndex; local sDate = SkM_GetDate(); local i; for i=table.getn(SKM_Context.RecentEnemyKill), 1, -1 do if (SKM_Context.RecentEnemyKill[i][_SKM._name] == sName) then local iDiffTime = SkM_DiffDate(sDate, SKM_Context.RecentEnemyKill[i][_SKM._date]); if (iDiffTime ~= nil) and (iDiffTime <= SKM_Config.RecentEnemyKillDelay) then bFound = true; iNoteIndex = SKM_Context.RecentEnemyKill[i][_SKM._noteIndex]; return bFound, iNoteIndex; end end end return bFound, iNoteIndex; end function SkM_AddRecentEnemyKill(sName, sDate, iGlobalNote) local FName = "SkM_AddRecentEnemyKill"; SkM_Trace(FName, 2, "Name = "..snil(sName)..", G. Note = "..snil(iGlobalNote)); local Record = { }; Record[_SKM._name] = sName; Record[_SKM._date] = sDate; Record[_SKM._noteIndex] = iGlobalNote; table.insert(SKM_Context.RecentEnemyKill, Record); while (table.getn(SKM_Context.RecentEnemyKill) > SKM_Config.MaxRecentEnemyKill) do table.remove(SKM_Context.RecentEnemyKill, 1); end end function SkM_GetRecentWarWarning(sName) local bFound = false; local sDate = SkM_GetDate(); local i; for i=table.getn(SKM_Context.RecentWarWarning), 1, -1 do if (SKM_Context.RecentWarWarning[i][_SKM._name] == sName) then local iDiffTime = SkM_DiffDate(sDate, SKM_Context.RecentWarWarning[i][_SKM._date]); if (iDiffTime ~= nil) and (iDiffTime <= SKM_Config.RecentWarWarningDelay) then bFound = true; return bFound; end end end return bFound; end function SkM_AddRecentWarWarning(sName, sDate) local Record = { }; Record[_SKM._name] = sName; Record[_SKM._date] = sDate; table.insert(SKM_Context.RecentWarWarning, Record); while (table.getn(SKM_Context.RecentWarWarning) > SKM_Config.MaxRecentWarWarning) do table.remove(SKM_Context.RecentWarWarning, 1); end end -- -------------------------------------------------------------------------------------- -- SkM_PvpEnemyDeath -- -------------------------------------------------------------------------------------- -- An enemy dies... -- Check from his name if we know him as an enemy player. If it's the case, check how -- much relative damage did the group to this enemy, and record appropriate kill event. -- -------------------------------------------------------------------------------------- function SkM_PvpEnemyDeath(sName, bHonorKill, sRank) local FName = "SkM_PvpEnemyDeath"; SkM_Trace(FName, 3, "Name = "..snil(sName)); if (not sName) then SkM_Trace(FName, 1, "nil parameter received !"); return; end SkM_CheckForgetEnemy(sName); -- if (not SkM_GetOption("RecordPlayerKill")) then -- return; -- end -- check if in battleground local bBattleground = SkM_IsInBattleground(); if (not SKM_Context.EnemyCombat[sName]) and (not bHonorKill) then -- no information about this enemy return; end if (not SKM_Data[_RealmName][_PlayerName].EnemyHistory[sName]) then -- if this is a honor kill, then we *know* it is a player -- also check that "store enemy players" is enabled. if (not bHonorKill) or (not SkM_GetOption("StoreEnemyPlayers")) then -- we have no information about the enemy just killed. -- maybe he's a player that has never been targeted, but maybe not... -- in doubt we do nothing SkM_Trace(FName, 3, sName.." : type unknown..."); SKM_Context.EnemyCombat[sName] = nil; return; end end local sDate1, sDate2 = SkM_GetDate(); SkM_UpdateEnemyLastView(sName, sDate1, false); if (sRank) then SkM_UpdateEnemyRank(sName, sRank); end -- check if we have already recorded this kill local bRecorded, iNoteIndex; bRecorded, iNoteIndex = SkM_GetRecentEnemyKill(sName); if (bRecorded) then -- already recorded SkM_Trace(FName, 3, "Kill already recorded : idx_gn = "..snil(iNoteIndex)); if (bHonorKill) then SkM_Trace(FName, 3, "Adjust as honor kill"); -- we received an "honor kill", it means the kill was previously recorded due to -- a event that was not an "honor kill" : now take honor info into account -- SKM_Data[_RealmName][_PlayerName].EnemyHistory[sName][_SKM._honorKill] = ifnil(SKM_Data[_RealmName][_PlayerName].EnemyHistory[sName][_SKM._honorKill], 0) + 1; SkM_UpdateEnemy_IncrHonorKill(sName, 1); SkM_SetHonorFlags(sName); -- local sGuildName = SKM_Data[_RealmName][_PlayerName].EnemyHistory[sName][_SKM._guild]; -- if ((sGuildName ~= nil) and (sGuildName ~= "")) then -- SKM_Data[_RealmName][_PlayerName].GuildHistory[sGuildName][_SKM._honorKill] = ifnil(SKM_Data[_RealmName][_PlayerName].GuildHistory[sGuildName][_SKM._honorKill], 0) + 1; -- end if (iNoteIndex) then SKM_Data[_RealmName][_PlayerName].GlobalMapData[iNoteIndex][_SKM._storedInfo][_SKM._honorKill] = true; end end return; end SkM_Trace(FName, 3, "Kill not yet recorded"); local KillType; if (not SKM_Context.EnemyCombat[sName]) then -- did not receive any combat information about this player, but -- we received an "honor" kill : award an "assist kill" by default SkM_Trace(FName, 3, "No combat info, but honor kill : award Assist Kill"); KillType = _SKM._playerAssistKill; elseif (SKM_Context.EnemyCombat[sName][_SKM._groupDamage] == 0) then SkM_Trace(FName, 3, "Group didn't do any damage"); if (bHonorKill) then -- no damage recorded by our group, but we received an "honor kill" : -- award an "assist kill" by default KillType = _SKM._playerAssistKill; end else local iPercent = SKM_Context.EnemyCombat[sName][_SKM._groupDamage] / SKM_Context.EnemyCombat[sName][_SKM._totalDamage]; if (iPercent < 0.50) then SkM_Trace(FName, 3, "Group damage < 50% : award Assist Kill"); KillType = _SKM._playerAssistKill; elseif (iPercent < 1.00) then SkM_Trace(FName, 3, "Group damage >= 50% and < 100% : award Kill"); KillType = _SKM._playerKill; else SkM_Trace(FName, 3, "Group damage = 100% : award Full Kill"); KillType = _SKM._playerFullKill; end end if (KillType ~= nil) then if (bBattleground == true) then KillType = _SKM._playerBGKill; end if (SkM_GetOption("DisplayKillRecord")) then if (KillType == _SKM._playerAssistKill) then SkM_ChatMessageColP(string.format(SKM_UI_STRINGS.RecordMessage_AssistKill, sName), SKM_Config.RGB_PlayerAssistKill); elseif (KillType == _SKM._playerKill) then SkM_ChatMessageColP(string.format(SKM_UI_STRINGS.RecordMessage_Kill, sName), SKM_Config.RGB_PlayerKill); elseif (KillType == _SKM._playerFullKill) then SkM_ChatMessageColP(string.format(SKM_UI_STRINGS.RecordMessage_FullKill, sName), SKM_Config.RGB_PlayerFullKill); end end --SKM_Data[_RealmName][_PlayerName].EnemyHistory[sName][KillType] = ifnil(SKM_Data[_RealmName][_PlayerName].EnemyHistory[sName][KillType], 0) + 1; SkM_UpdateEnemy_IncrCounter(sName, KillType, 1, true); if (bBattleground == true) then SkM_BGStats_AddKill(); end if (bHonorKill) then --SKM_Data[_RealmName][_PlayerName].EnemyHistory[sName][_SKM._honorKill] = ifnil(SKM_Data[_RealmName][_PlayerName].EnemyHistory[sName][_SKM._honorKill], 0) + 1; SkM_UpdateEnemy_IncrHonorKill(sName, 1); SkM_SetHonorFlags(sName); end -- asked by Fumus : record special count for solo kills for which player did full damage if (KillType == _SKM._playerFullKill) and (getn(SKM_Context.GroupList) == 1) then SkM_Trace(FName, 3, "Group damage = 100% + solo : lone wolf kill"); --SKM_Data[_RealmName][_PlayerName].EnemyHistory[sName][_SKM._loneWolfKill] = ifnil(SKM_Data[_RealmName][_PlayerName].EnemyHistory[sName][_SKM._loneWolfKill], 0) + 1; SkM_UpdateEnemy_IncrLoneWolfKill(sName, 1); end -- local sGuildName = SKM_Data[_RealmName][_PlayerName].EnemyHistory[sName][_SKM._guild]; -- if ((sGuildName ~= nil) and (sGuildName ~= "")) then -- SKM_Data[_RealmName][_PlayerName].GuildHistory[sGuildName][KillType] = ifnil(SKM_Data[_RealmName][_PlayerName].GuildHistory[sGuildName][KillType], 0) + 1; -- -- if (bHonorKill) then -- SKM_Data[_RealmName][_PlayerName].GuildHistory[sGuildName][_SKM._honorKill] = ifnil(SKM_Data[_RealmName][_PlayerName].GuildHistory[sGuildName][_SKM._honorKill], 0) + 1; -- end -- -- -- asked by Fumus : record special count for solo kills for which player did full damage -- if (KillType == _SKM._playerFullKill) and (getn(SKM_Context.GroupList) == 1) then -- SkM_Trace(FName, 3, "Group damage = 100% + solo : lone wolf kill"); -- SKM_Data[_RealmName][_PlayerName].GuildHistory[sGuildName][_SKM._loneWolfKill] = ifnil(SKM_Data[_RealmName][_PlayerName].GuildHistory[sGuildName][_SKM._loneWolfKill], 0) + 1; -- end -- end --local Enemy = SKM_Data[_RealmName][_PlayerName].EnemyHistory[sName]; local StoreInfo = { }; StoreInfo[_SKM._type] = KillType; StoreInfo[_SKM._name] = sName; StoreInfo[_SKM._date] = sDate1; --StoreInfo[_sortdate] = sDate2; -- asked by Fumus : record special count for solo kills for which player did full damage if (KillType == _SKM._playerFullKill) and (getn(SKM_Context.GroupList) == 1) then StoreInfo[_SKM._loneWolfKill] = true; end if (bHonorKill) then StoreInfo[_SKM._honorKill] = true; end StoreInfo[_SKM._enemyType] = _SKM._enemyPlayer; if (SkM_GetOption("RecordPlayerKill")) then local idx_gn; if (SkM_AddMapData(StoreInfo)) then idx_gn = table.getn(SKM_Data[_RealmName][_PlayerName].GlobalMapData); end SkM_AddRecentEnemyKill(sName, sDate1, idx_gn); end -- update target info if needed SkM_SetTargetInfo(); end SKM_Context.EnemyCombat[sName] = nil; end function SkM_SetHonorFlags(sName) local FName = "SkM_SetHonorFlags"; if (not sName) then SkM_Trace(FName, 1, "Name is nil"); return; end if (not SKM_Data[_RealmName][_PlayerName].EnemyHistory[sName]) then SkM_Trace(FName, 1, "Enemy "..snil(sName).." not known"); return; end local sDate = SkM_GetDate(); local sDateLast = SKM_Data[_RealmName][_PlayerName].EnemyHistory[sName][_SKM._honorLastKill]; if (not sDateLast) then SKM_Data[_RealmName][_PlayerName].EnemyHistory[sName][_SKM._honorLastKill] = sDate; SKM_Data[_RealmName][_PlayerName].EnemyHistory[sName][_SKM._honorCount] = 1; elseif (string.sub(sDate, 1, 10) ~= string.sub(sDateLast, 1, 10)) then SKM_Data[_RealmName][_PlayerName].EnemyHistory[sName][_SKM._honorLastKill] = sDate; SKM_Data[_RealmName][_PlayerName].EnemyHistory[sName][_SKM._honorCount] = 1; else SKM_Data[_RealmName][_PlayerName].EnemyHistory[sName][_SKM._honorCount] = ifnil(SKM_Data[_RealmName][_PlayerName].EnemyHistory[sName][_SKM._honorCount], 0) + 1; end end function SkM_GetHonorRemainingKills(sName) local FName = "SkM_GetHonorRemainingKills"; if (not sName) then SkM_Trace(FName, 1, "Name is nil"); return; end if (not SKM_Data[_RealmName][_PlayerName].EnemyHistory[sName]) then SkM_Trace(FName, 1, "Enemy "..snil(sName).." not known"); return; end local iCount; local sDate = SkM_GetDate(); local sDateLast = SKM_Data[_RealmName][_PlayerName].EnemyHistory[sName][_SKM._honorLastKill]; if (not sDateLast) then iCount = SKM_HonorKillPerDay; elseif (string.sub(sDate, 1, 10) ~= string.sub(sDateLast, 1, 10)) then iCount = SKM_HonorKillPerDay; else iCount = SKM_HonorKillPerDay - ifnil(SKM_Data[_RealmName][_PlayerName].EnemyHistory[sName][_SKM._honorCount], 0); if (iCount < 0) then iCount = 0; end end return iCount; end function SkM_StoreDuelEnemyInfo(sUnit) local FName = "SkM_StoreDuelEnemyInfo"; local sName = UnitName(sUnit); if (not sName) then return; end if (SKM_Context.DuelEnemy) and (SKM_Context.DuelEnemy[_SKM._name] == sName) then -- already stored return; end SKM_Context.DuelEnemy = { }; SKM_Context.DuelEnemy[_SKM._name] = sName; SKM_Context.DuelEnemy[_SKM._race] = SkM_GetRaceIndex(UnitRace(sUnit)); SKM_Context.DuelEnemy[_SKM._class] = SkM_GetClassIndex(UnitClass(sUnit)); SKM_Context.DuelEnemy[_SKM._level] = UnitLevel(sUnit); SKM_Context.DuelEnemy[_SKM._guild] = GetGuildInfo(sUnit); end -- -------------------------------------------------------------------------------------- -- SkM_UpdateUnitData -- -------------------------------------------------------------------------------------- -- Target unit has been updated. If it's an enemy, update that player information. -- If it's a creep, store creature information. -- -------------------------------------------------------------------------------------- function SkM_UpdateUnitData() local FName = "SkM_UpdateUnitData"; local sName = SkM_UnitName(SKM_UNIT_TARGET); if (not sName) then -- clear target info SKM_Context.TargetInfo = nil; else if (SkM_UnitIsEnemyPlayer(SKM_UNIT_TARGET)) then local sDate1, sDate2 = SkM_GetDate(); SkM_UpdateEnemyLastView(sName, sDate1, true, SKM_UNIT_TARGET); end if (not UnitIsPlayer(SKM_UNIT_TARGET)) then SkM_StoreTargetInfo(_SKM._enemyCreature); elseif (SkM_UnitIsEnemyPlayer(SKM_UNIT_TARGET)) then SkM_StoreTargetInfo(_SKM._enemyPlayer); else SKM_Context.TargetInfo = nil; end if (SkM_GetOption("StoreDuels")) then if (SkM_UnitIsDuelingPlayer(SKM_UNIT_TARGET)) then SkM_StoreDuelEnemyInfo(SKM_UNIT_TARGET); end end end end -- -------------------------------------------------------------------------------------- -- SkM_MouseOverUnitData -- -------------------------------------------------------------------------------------- -- Get information on enemy player on mouse-over -- -------------------------------------------------------------------------------------- function SkM_MouseOverUnitData() local FName = "SkM_MouseOverUnitData"; local sName = SkM_UnitName(SKM_UNIT_MOUSEOVER); if (sName) then if (SkM_UnitIsEnemyPlayer(SKM_UNIT_MOUSEOVER)) then local sDate1, sDate2 = SkM_GetDate(); SkM_UpdateEnemyLastView(sName, sDate1, true, SKM_UNIT_MOUSEOVER); --local iLevel = UnitLevel(SKM_UNIT_MOUSEOVER); --local sClass = UnitClass(SKM_UNIT_MOUSEOVER); --local sRace = UnitRace(SKM_UNIT_MOUSEOVER); --local sGuild = GetGuildInfo(SKM_UNIT_MOUSEOVER); --SkM_Trace(FName, 1, "Name = "..snil(sName)..", Level = "..snil(iLevel)..", Class = "..snil(sClass)..", Race = "..snil(sRace)..", Guild = "..snil(sGuild)); elseif (SkM_GetOption("StoreDuels")) and (SkM_UnitIsDuelingPlayer(SKM_UNIT_MOUSEOVER)) then SkM_StoreDuelEnemyInfo(SKM_UNIT_MOUSEOVER); end end end -- -------------------------------------------------------------------------------------- -- SkM_ForgetPlayerHate -- -------------------------------------------------------------------------------------- -- For all enemies in player hate list, recompute hate level from time elapsed since -- last update. -- "forget" enemy if hate reaches zero or if no update has been -- received for a given time. -- -------------------------------------------------------------------------------------- function SkM_ForgetPlayerHate() local FName = "SkM_ForgetPlayerHate"; local curTime = GetTime(); for sName, Enemy in SKM_Context.PlayerCombat do if (curTime - Enemy[_SKM._lastUpdate] > SKM_Config.ForgetAggressorTimer) then -- no update since given time interval, forget, whatever the hate level may be SKM_Context.PlayerCombat[sName] = nil; else -- don't forget, but reduce hate from time elapsed local iTime = curTime - Enemy[_SKM._lastHateUpdate]; nHateReduction = Enemy[_SKM._hateLevel] * (iTime / 100) * SKM_Config.HateReductionCoeff; SKM_Context.PlayerCombat[sName][_SKM._hateLevel] = Enemy[_SKM._hateLevel] - nHateReduction; SKM_Context.PlayerCombat[sName][_SKM._lastHateUpdate] = curTime; -- if hate is reduced to zero (or less), forget if (SKM_Context.PlayerCombat[sName][_SKM._hateLevel] <= 0) then SKM_Context.PlayerCombat[sName] = nil; end end end end -- -------------------------------------------------------------------------------------- -- SkM_LogDamage_OnSelf -- -------------------------------------------------------------------------------------- -- Keep track of damage done on self and update "hate level" associated to the damage -- dealer. -- -------------------------------------------------------------------------------------- function SkM_LogDamage_OnSelf(iDamage, sName, EnemyType) local FName = "SkM_LogDamage_OnSelf"; local curTime = GetTime(); SkM_ForgetPlayerHate(); if (not SKM_Context.PlayerCombat[sName]) then SKM_Context.PlayerCombat[sName] = { }; SKM_Context.PlayerCombat[sName][_SKM._name] = sName; SKM_Context.PlayerCombat[sName][_SKM._enemyType] = EnemyType; SKM_Context.PlayerCombat[sName][_SKM._hateLevel] = 0; SKM_Context.PlayerCombat[sName][_SKM._damage] = 0; SKM_Context.PlayerCombat[sName][_SKM._lastHateUpdate] = curTime; SKM_Context.PlayerCombat[sName][_SKM._lastUpdate] = curTime; end -- store enemy type if we have it now and it was not previously stored if (not SKM_Context.PlayerCombat[sName][_SKM._enemyType]) and (EnemyType ~= nil) then SKM_Context.PlayerCombat[sName][_SKM._enemyType] = EnemyType; end SKM_Context.PlayerCombat[sName][_SKM._damage] = SKM_Context.PlayerCombat[sName][_SKM._damage] + iDamage; SKM_Context.PlayerCombat[sName][_SKM._hateLevel] = SKM_Context.PlayerCombat[sName][_SKM._hateLevel] + iDamage; SkM_Trace(FName, 3, "PlayerCombat updated for "..sName.." : damage = ".. SKM_Context.PlayerCombat[sName][_SKM._damage] ..", hate level = ".. SKM_Context.PlayerCombat[sName][_SKM._hateLevel]); end -- -------------------------------------------------------------------------------------- -- SkM_HateList_Dump -- -------------------------------------------------------------------------------------- -- Debug function. Dump content of "PlayerCombat" (hate list). -- -------------------------------------------------------------------------------------- function SkM_HateList_Dump() local FName = "SkM_HateList_Dump"; local curTime = GetTime(); SkM_ForgetPlayerHate(); for idx, Elem in SKM_Context.PlayerCombat do local iTime = math.ceil(curTime - Elem[_SKM._lastUpdate]); local sReport = Elem[_SKM._name].." (last update : "..iTime.." s ago) -> damage = "..Elem[_SKM._damage]..", hate = "..Elem[_SKM._hateLevel]; SkM_ChatMessageCol(sReport); end end -- -------------------------------------------------------------------------------------- -- SkM_SortPlayerCombat_ByHate -- -------------------------------------------------------------------------------------- -- Sort "PlayerCombat" list by hate level. -- -------------------------------------------------------------------------------------- function SkM_SortPlayerCombat_ByHate(e1, e2) if (not e2[_SKM._hateLevel]) then return true; end if (not e1[_SKM._hateLevel]) then return false; end return (e1[_SKM._hateLevel] > e2[_SKM._hateLevel]); end -- -------------------------------------------------------------------------------------- -- SkM_PlayerDeathResp -- -------------------------------------------------------------------------------------- -- Find who is responsible for your death, if any. This is the most hated enemy player -- or creature from "PlayerCombat" list. -- Also reset hate list afterwards. -- -------------------------------------------------------------------------------------- function SkM_PlayerDeathResp() local FName = "SkM_PlayerDeathResp"; SkM_ForgetPlayerHate(); local HateList = {}; local EnemyName, EnemyType; local iTotal = 0; local idx, val; for idx, val in SKM_Context.PlayerCombat do local Elem = copytable(val); iTotal = iTotal + Elem[_SKM._hateLevel]; table.insert(HateList, Elem); end table.sort(HateList, SkM_SortPlayerCombat_ByHate); if (table.getn(HateList) > 0) then EnemyName = HateList[1][_SKM._name]; EnemyType = HateList[1][_SKM._enemyType]; end for idx, val in HateList do val[_SKM._hatePercent] = math.floor(100 * val[_SKM._hateLevel] / iTotal); end SkM_Trace(FName, 2, "Most hated = "..snil(EnemyName)..", type = "..snil(EnemyType)); SKM_Context.PlayerCombat = { }; return EnemyName, EnemyType, HateList; end -- -------------------------------------------------------------------------------------- -- SkM_DumpEnemyCombat -- -------------------------------------------------------------------------------------- -- Debug function. Dump content of "EnemyCombat" list. -- -------------------------------------------------------------------------------------- function SkM_DumpEnemyCombat() local FName = "SkM_DumpEnemyCombat"; local curTime = GetTime(); for idx, val in SKM_Context.EnemyCombat do local iTime = math.ceil(curTime - val[_SKM._lastUpdate]); sReport = val[_SKM._name] .. " (last update : "..iTime.." s ago) -> total damage = ".. val[_SKM._totalDamage] .. ", group damage = " .. val[_SKM._groupDamage]; SkM_ChatMessageCol(sReport); end end -- -------------------------------------------------------------------------------------- -- SkM_IsLeapYear -- -------------------------------------------------------------------------------------- -- Is given year a leap year ? -- -------------------------------------------------------------------------------------- function SkM_IsLeapYear(iYear) return intable(iYear, LeapYears); end -- -------------------------------------------------------------------------------------- -- SkM_DaysInYear -- -------------------------------------------------------------------------------------- -- Return number of days in given year -- -------------------------------------------------------------------------------------- function SkM_DaysInYear(iYear) if (SkM_IsLeapYear(iYear)) then return 366; else return 365; end end -- -------------------------------------------------------------------------------------- -- SkM_DaysInMonth -- -------------------------------------------------------------------------------------- -- Return number of days in given month of a given year -- -------------------------------------------------------------------------------------- function SkM_DaysInMonth(iMonth, iYear) local iDays = DaysInMonth[iMonth]; if (iMonth == 2) and SkM_IsLeapYear(iYear) then iDays = 29; end return iDays; end -- -------------------------------------------------------------------------------------- -- SkM_TimeSinceEpoch -- -------------------------------------------------------------------------------------- -- Return the number of seconds since "epoch", fixed at 01/01/2004 00:00:00. -- (we do not need to handle time periods prior to WoW release, so this does not need -- to be less than this time) -- -------------------------------------------------------------------------------------- function SkM_TimeSinceEpoch(sDate) local FName = "SkM_TimeSinceEpoch"; SkM_Trace(FName, 3, "Date = "..snil(sDate)); local iDay, iMonth, iYear, iHour, iMin, iSec; iDay = tonumber( string.sub(sDate, 1, 2) ); iMonth = tonumber( string.sub(sDate, 4, 5) ); iYear = tonumber( string.sub(sDate, 7, 10) ) ; iHour = tonumber( string.sub(sDate, 12, 13) ); iMin = tonumber( string.sub(sDate, 15, 16) ); iSec = tonumber( string.sub(sDate, 18, 19) ); if (iDay == nil) or (iMonth == nil) or (iYear == nil) or (iHour == nil) or (iMin == nil) or (iSec == nil) then return nil; end local iTime = 0; iIndYear = 2004; while (iIndYear < iYear) do iTime = iTime + SkM_DaysInYear(iIndYear); iIndYear = iIndYear + 1; end iIndMonth = 1; while (iIndMonth < iMonth) do iTime = iTime + SkM_DaysInMonth(iIndMonth, iYear); iIndMonth = iIndMonth + 1; end iTime = (iTime + (iDay - 1)) * 24; iTime = (iTime + (iHour - 1)) * 60; iTime = (iTime + (iMin - 1)) * 60; iTime = iTime + iSec; SkM_Trace(FName, 3, "Sec num since 01/01/2004 = "..snil(iTime)); return iTime; end -- -------------------------------------------------------------------------------------- -- SkM_DiffDate -- -------------------------------------------------------------------------------------- -- Return the difference in seconds between two dates in format DD/MM/YYYY HH:MI:SS -- -------------------------------------------------------------------------------------- function SkM_DiffDate(sDate1, sDate2) local FName = "SkM_DiffDate"; if (sDate1 == nil) or (sDate2 == nil) then return nil; end local iTime1, iTime2, iTime; iTime1 = SkM_TimeSinceEpoch(sDate1); iTime2 = SkM_TimeSinceEpoch(sDate2); if (iTime1 == nil) or (iTime2 == nil) then return nil; end iTime = iTime1 - iTime2; SkM_Trace(FName, 3, "Time difference = "..snil(iTime)); return iTime; end -- -------------------------------------------------------------------------------------- -- SkM_SetTargetInfoText -- -------------------------------------------------------------------------------------- -- Set a line of text of SKMapTargetInfoButton -- -------------------------------------------------------------------------------------- function SkM_SetTargetInfoText(id, sLabel, sValue, sDetail) local FName = "SkM_SetTargetInfoText"; local TextLabe, ValueLabel, DetailLabel; if (sLabel) then TextLabel = getglobal("SKMapTargetInfoButton"..id.."Label"); if (not TextLabel) then return false; end end if (sValue) then ValueLabel = getglobal("SKMapTargetInfoButton"..id.."Value"); if (not ValueLabel) then return false; end end if (sDetail) then DetailLabel = getglobal("SKMapTargetInfoButton"..id.."Detail"); if (not DetailLabel) then return false; end end if (sLabel) then TextLabel:SetText(sLabel); end if (sValue) then ValueLabel:SetText(sValue); end if (sDetail) then DetailLabel:SetText(sDetail); end return true; end -- -------------------------------------------------------------------------------------- -- SkM_SetSmallTargetInfoText -- -------------------------------------------------------------------------------------- -- Set a line of text of SKMapSmallTargetInfoButton -- -------------------------------------------------------------------------------------- function SkM_SetSmallTargetInfoText(id, sLabel, sValue) local FName = "SkM_SetTargetInfoText"; local TextLabe, ValueLabel; if (sLabel) then TextLabel = getglobal("SKMapSmallTargetInfoButton"..id.."Label"); if (not TextLabel) then return false; end end if (sValue) then ValueLabel = getglobal("SKMapSmallTargetInfoButton"..id.."Value"); if (not ValueLabel) then return false; end end if (sLabel) then TextLabel:SetText(sLabel); end if (sValue) then ValueLabel:SetText(sValue); end return true; end -- -------------------------------------------------------------------------------------- -- SkM_ShowTargetGuildInfo -- -------------------------------------------------------------------------------------- -- Display or hide guild info mini frame -- -------------------------------------------------------------------------------------- function SkM_ShowTargetGuildInfo(bShow, sGuildName, bGuildWar) if (not SkM_GetOption("ShowTargetGuildInfo")) then SKMapTargetGuildInfo:Hide(); else if (bShow ~= true) or (sGuildName == nil) or (sGuildName == "") then SKMapTargetGuildInfo:Hide(); else local id=1; TextValue = getglobal("SKMapTargetGuildInfoButton"..id.."Value"); local sText; if (bGuildWar) then sText = SKM_Config.Col_PlayerWar; else sText = SKM_Config.Col_Label; end sText = sText..sGuildName; TextValue:SetText(sText); SKMapTargetGuildInfo:Show(); end end end -- -------------------------------------------------------------------------------------- -- SkM_ShowTargetClassInfo -- -------------------------------------------------------------------------------------- -- Display or hide class info mini frame -- -------------------------------------------------------------------------------------- function SkM_ShowTargetClassInfo(bShow, sClass) if (not SkM_GetOption("ShowTargetClassInfo")) then SKMapTargetClassInfo:Hide(); else if (bShow ~= true) or (sClass == nil) or (sClass == "") then SKMapTargetClassInfo:Hide(); else local id=1; TextValue = getglobal("SKMapTargetClassInfoButton"..id.."Value"); sText = SKM_Config.Col_Label; sText = sText..sClass; TextValue:SetText(sText); SKMapTargetClassInfo:Show(); end end end -- -------------------------------------------------------------------------------------- -- SkM_SetTargetInfo -- -------------------------------------------------------------------------------------- -- Fill and display or hidel TargetInfo frame(s) according to current target -- -------------------------------------------------------------------------------------- function SkM_SetTargetInfo() local FName = "SkM_SetTargetInfo"; local sName = SkM_UnitName(SKM_UNIT_TARGET); --local sName = "Abaddon"; if (not sName) then -- no target SkM_HideTargetInfoFrame(); SkM_ShowTargetGuildInfo(false, nil, nil); SkM_ShowTargetClassInfo(false, nil); SkM_SetWarDragon(false, false); return false; end local sClass = UnitClass(SKM_UNIT_TARGET); if (SkM_UnitIsEnemyPlayer(SKM_UNIT_TARGET)) then --if (true) then local bWar = false; local bGuildWar = false; local Enemy = SKM_Data[_RealmName][_PlayerName].EnemyHistory[sName]; if (not Enemy) then SkM_HideTargetInfoFrame(); SkM_SetWarDragon(false, false); return false; end -- 09/04/2005 17:23:14 PIng Add guild support local sGuildName = Enemy[_SKM._guild]; if (sGuildName == "") then sGuildName = nil; end local Guild = SKM_Data[_RealmName][_PlayerName].GuildHistory[sGuildName]; -- 09/04/2005 17:24:33 End of modification if (Enemy[_SKM._atWar]) then bWar = true; end if (Guild) and (Guild[_SKM._atWar]) then bGuildWar = true; end SkM_ShowTargetGuildInfo(true, sGuildName, bGuildWar); SkM_ShowTargetClassInfo(true, sClass); local iKill = ifnil(Enemy[_SKM._playerKill], 0); local iAssistKill = ifnil(Enemy[_SKM._playerAssistKill], 0); local iFullKill = ifnil(Enemy[_SKM._playerFullKill], 0); local iTotalKill = iKill + iAssistKill + iFullKill; local iHonorKill = ifnil(Enemy[_SKM._honorKill], 0); local iRemaining = SkM_GetHonorRemainingKills(sName); -- 09/04/2005 17:25:03 PIng Add guild support local gKill = ""; local gAssistKill = ""; local gFullKill = ""; local gTotalKill = ""; local gDeath = ""; local gMet = ""; if (sGuildName ~= nil) then gKill = ifnil(Guild[_SKM._playerKill], 0); gAssistKill = ifnil(Guild[_SKM._playerAssistKill], 0); gFullKill = ifnil(Guild[_SKM._playerFullKill], 0); gTotalKill = gKill + gAssistKill + gFullKill; gDeath = ifnil(Guild[_SKM._enemyKillPlayer], 0); gMet = ifnil(Guild[_SKM._meetCount], 0); end -- 09/04/2005 17:25:12 End of modification local iDeath = ifnil(Enemy[_SKM._enemyKillPlayer], 0); local iMet = ifnil(Enemy[_SKM._meetCount], 0); SkM_Trace(FName, 3, "Kill = "..iKill..", AssistKill = "..iAssistKill..", FullKill = "..iFullKill..", Met = "..iMet); -- 09/04/2005 17:25:03 PIng Add guild support if (sGuildName ~= nil) then SkM_Trace(FName, 3, "Guild Kill = "..gKill..", Guild AssistKill = "..gAssistKill..", Guild FullKill = "..gFullKill..", Guild Met = "..gMet); end -- 09/04/2005 17:25:12 End of modification local sKill = SKM_Config.Col_PlayerTotalKill .. iTotalKill; local sKillDetail; -- only display detail kill count if there's at least one kill -- if (iTotalKill == 0) then -- sKillDetail = ""; -- else -- 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 .. " )"; -- end sKillDetail = SKM_UI_STRINGS.Small_Target_Honor..SKM_Config.Col_HonorKill..iHonorKill.." "; --local FrameColor; local LabelColor; if (iRemaining == 0) then sKillDetail = sKillDetail..SKM_Config.Col_Label.."( "..SKM_Config.Col_Honorless..SKM_UI_STRINGS.Small_Target_NoHonor..SKM_Config.Col_Label.." )"; --FrameColor = { r = 0.0, g = 0.0, b = 0.0 }; LabelColor = SKM_Config.Col_LabelTitle; else sKillDetail = sKillDetail..SKM_Config.Col_Label.."( "..SKM_Config.Col_HonorKill..iRemaining..SKM_Config.Col_Label.." )"; --FrameColor = { r = 0.3, g = 1.0, b = 1.0 }; LabelColor = SKM_Config.Col_HonorKill; end local sDeath = SKM_Config.Col_PlayerDeath .. iDeath; local sMet = SKM_Config.Col_PlayerMet .. iMet; local sWar1 = ""; local sWar2 = ""; if (Enemy[_SKM._atWar] == true) then sWar1 = SKM_Config.Col_PlayerWar.. SKM_UI_STRINGS.Small_Target_War; sWar2 = ""; if (Enemy[_SKM._warDate]) then local sDisplayDate = string.sub(Enemy[_SKM._warDate], 1, 10); sWar2 = SKM_Config.Col_PlayerWar .. SKM_UI_STRINGS.Since .. sDisplayDate; end end local bRes1, bRes2, bRes3, bRes4; if (SkM_GetOption("SmallTargetInfo")) then bRes1 = SkM_SetSmallTargetInfoText(1, LabelColor..SKM_UI_STRINGS.Small_Target_Info_Kill, sKill); bRes2 = SkM_SetSmallTargetInfoText(2, SKM_UI_STRINGS.Small_Target_Info_Death, sDeath); bRes3 = SkM_SetSmallTargetInfoText(3, SKM_UI_STRINGS.Small_Target_Info_Met, sMet); bRes4 = SkM_SetSmallTargetInfoText(4, sWar1); else bRes1 = SkM_SetTargetInfoText(1, SKM_UI_STRINGS.Small_Target_Info_Kill, sKill, sKillDetail); bRes2 = SkM_SetTargetInfoText(2, SKM_UI_STRINGS.Small_Target_Info_Death, sDeath, ""); bRes3 = SkM_SetTargetInfoText(3, SKM_UI_STRINGS.Small_Target_Info_Met, sMet, ""); bRes4 = SkM_SetTargetInfoText(4, sWar1, "", sWar2); end SkM_ShowTargetFrameWarButtons(Enemy[_SKM._atWar]); SkM_SetWarDragon(bWar, bGuildWar); if (bRes1 and bRes2 and bRes3 and bRes4) then SkM_ShowTargetInfoFrame(); return true; else SkM_HideTargetInfoFrame(); return false; end else SkM_HideTargetInfoFrame(); SkM_SetWarDragon(false, false); if (UnitIsPlayer(SKM_UNIT_TARGET)) then local sGuildName = GetGuildInfo(SKM_UNIT_TARGET); SkM_ShowTargetGuildInfo(true, sGuildName, false); SkM_ShowTargetClassInfo(true, sClass); else SkM_ShowTargetGuildInfo(false, nil, nil); SkM_ShowTargetClassInfo(false, nil); end -- if we switch from a player dragon to an elite mob, we must keep the "elite" frame ! --if (UnitIsPlusMob(SKM_UNIT_TARGET)) then local sUnitClassification = UnitClassification(SKM_UNIT_TARGET); if (UnitIsPlusMob(SKM_UNIT_TARGET)) or ( (sUnitClassification ~= nil) and (sUnitClassification ~= "") and (sUnitClassification ~= "normal") ) then TargetFrameTexture:SetTexture("Interface\\TargetingFrame\\UI-TargetingFrame-Elite"); end return false; end end -- -------------------------------------------------------------------------------------- -- SkM_SetWarDragon -- -------------------------------------------------------------------------------------- -- Display or hide the red "elite dragon" around target portrait. -- If this enemy or his guild is set "at war", then the dragon is shown -- Otherwise, color is reset and the "elite dragon" is hidden -- -------------------------------------------------------------------------------------- function SkM_SetWarDragon(bWar, bGuildWar) local FName = "SkM_SetWarDragon"; if (bWar) or (bGuildWar) then --Set Red Dragon Overlay on Texture to Target TargetFrameTexture:SetVertexColor(1.0, 200.0, 1.0, TargetFrameTexture:GetAlpha()); TargetFrameTexture:SetTexture("Interface\\TargetingFrame\\UI-TargetingFrame-Elite"); else -- not at war with target TargetFrameTexture:SetVertexColor(1.0, 1.0, 1.0, TargetFrameTexture:GetAlpha()); TargetFrameTexture:SetTexture("Interface\\TargetingFrame\\UI-TargetingFrame"); end end -- -------------------------------------------------------------------------------------- -- SkM_EnemyWar -- -------------------------------------------------------------------------------------- -- Declare war to an enemy player, or call a truce with this player -- -------------------------------------------------------------------------------------- function SkM_EnemyWar(bWar, sEnemyName) local FName = "SkM_EnemyWar"; SkM_Trace(FName, 3, "War button pressed"); local sName; if (sEnemyName) then sName = sEnemyName; else local sTargetName = SkM_UnitName(SKM_UNIT_TARGET); sName = sTargetName; end if (not sName) then SkM_Trace(FName, 1, "No enemy specified"); return; end local Enemy = SKM_Data[_RealmName][_PlayerName].EnemyHistory[sName]; if (not Enemy) then SkM_Trace(FName, 1, "Enemy not found : "..snil(sName)); return; end local sGuildName = Enemy[_SKM._guild]; local Guild; local bGuildWar = false; if (sGuildName) and (sGuildName ~= "") then Guild = SKM_Data[_RealmName][_PlayerName].GuildHistory[sGuildName]; end if (Guild) and (Guild[_SKM._atWar]) then bGuildWar = true; end local sDate = SkM_GetDate(); SkM_UpdateEnemy_SetWar(sName, bWar, sDate); SkM_ShowTargetFrameWarButtons(Enemy[_SKM._atWar]); -- 09/04/2005 16:18:34 PIng: Update war info on target frame when status is changed local sWar1 = ""; local sWar2 = ""; if (Enemy[_SKM._atWar] == true) then sWar1 = SKM_Config.Col_PlayerWar.. SKM_UI_STRINGS.Small_Target_War; sWar2 = ""; if (Enemy[_SKM._warDate]) then local sDisplayDate = string.sub(Enemy[_SKM._warDate], 1, 10); sWar2 = SKM_Config.Col_PlayerWar .. SKM_UI_STRINGS.Since .. sDisplayDate; end end local bRes4; if (SkM_GetOption("SmallTargetInfo")) then bRes4 = SkM_SetSmallTargetInfoText(4, sWar1); else bRes4 = SkM_SetTargetInfoText(4, sWar1, "", sWar2); end -- 09/04/2005 16:18:31 End of modification if (sName == sTargetName) then SkM_SetWarDragon(bWar, bGuildWar); end end -- -------------------------------------------------------------------------------------- -- SkM_UnknownEnemyWar -- -------------------------------------------------------------------------------------- -- Declare war to an enemy player that can is potentially not known yet -- -------------------------------------------------------------------------------------- function SkM_UnknownEnemyWar(sName, bWar, bDisplay) local FName = "SkM_UnknownEnemyWar"; SkM_Trace(FName, 3, "Enemy player = "..snil(sName)); local sDate = SkM_GetDate(); if (sName) then local Enemy = SKM_Data[_RealmName][_PlayerName].EnemyHistory[sName]; if (Enemy) then local bWarPrev = Enemy[_SKM._atWar]; SkM_UpdateEnemy_SetWar(sName, bWar, sDate); if (bDisplay) then if (bWar) and (not bWarPrev) then SkM_ChatMessageCol("Now at WAR with "..sName); elseif (not bWar) and (bWarPrev) then SkM_ChatMessageCol("No longer at WAR with "..sName); end end -- update target info if needed SkM_SetTargetInfo(); -- update interface enemy list if needed local bVisible, sFrame = SKMap_IsUIVisible(); if (bVisible) and (sFrame == "SKMap_ListFrame") and (SKM_List_ActiveList == _SKM._players) then SKMap_ListFrame_UpdateList(); if (SKM_List_SelectedPlayer) then SKMap_ListFrame_ShowWarButton(bWar); end end if (SKM_List_ActiveList == _SKM._players) and (SKM_List_SelectedPlayer) then SKMap_ListFrame_SelectElement(SKM_List_SelectedPlayer); end else -- unknown enemy if (bWar) then SKM_Data[_RealmName][_PlayerName].UnknownEnemy[sName] = 1; if (bDisplay) then SkM_ChatMessageCol("Now at WAR with "..sName.." (not yet known)"); end else if (SKM_Data[_RealmName][_PlayerName].UnknownEnemy[sName]) then SKM_Data[_RealmName][_PlayerName].UnknownEnemy[sName] = nil; if (bDisplay) then SkM_ChatMessageCol("No longer at WAR with "..sName.." (not yet known)"); end end end end end end function SkM_ShowUnknownEnemyWar() local sMsg = ""; local iCount = 0; local idx, val; for idx, val in SKM_Data[_RealmName][_PlayerName].UnknownEnemy do sMsg = sMsg..idx.." "; iCount = iCount + 1; end if (iCount == 0) then SkM_ChatMessageCol("Unknown players WAR list is empty"); else SkM_ChatMessageCol("Unknown players WAR list ("..iCount..") :"); SkM_ChatMessageCol(sMsg); end end function SkM_ClearUnknownEnemyWar() SKM_Data[_RealmName][_PlayerName].UnknownEnemy = { }; SkM_ChatMessageCol("Unknown players WAR list cleared"); end function SkM_FindSharedEnemyWar(sName) local FName = "SkM_FindSharedEnemyWar"; -- parse all characters of the same realm local idx_char, val_char; for idx_char, val_char in SKM_Data[_RealmName] do if (SKM_Data[_RealmName][idx_char].PlayerName == idx_char) then local Enemy = SKM_Data[_RealmName][idx_char].EnemyHistory[sName]; -- if enemy known to this player, and set "at war", return him if (Enemy) and (Enemy[_SKM._atWar]) then return Enemy, idx_char; end end end end -- -------------------------------------------------------------------------------------- -- SkM_MouseOverUnit -- -------------------------------------------------------------------------------------- -- Handle "mouseover unit" event. -- If that unit is an enemy player that is "at war", or whose guild is "at war" : -- Display floating message (if configured) -- Play warning sound (if configured) -- If unit is an unknown enemy and we have no current target, target him to store -- information, then clear target again. -- -------------------------------------------------------------------------------------- function SkM_MouseOverUnit() local FName = "SkM_MouseOverUnit"; local sDate = SkM_GetDate(); -- store information related to mouse-overed unit SkM_MouseOverUnitData(); if (SkM_UnitIsEnemyPlayer(SKM_UNIT_MOUSEOVER)) then -- if (true) then -- Grab the name of who we've moused-over local sName = SkM_UnitName(SKM_UNIT_MOUSEOVER); --local sName = "Ledieu"; if (not sName) then return; end local sGuildName = GetGuildInfo(SKM_UNIT_MOUSEOVER); local bWar = false; local bGuildWar = false; local bSharedWar = false; local Enemy = SKM_Data[_RealmName][_PlayerName].EnemyHistory[sName]; local SharedEnemy, SharedChar; local Guild; if (Enemy) and (Enemy[_SKM._atWar]) then bWar = true; end if (sGuildName ~= nil) and (sGuildName ~= "") then Guild = SKM_Data[_RealmName][_PlayerName].GuildHistory[sGuildName]; if (Guild ~= nil) and (Guild[_SKM._atWar]) then bGuildWar = true; end end if not (bWar or bGuildWar) then if (SkM_GetOption("SharedWarMode")) then SharedEnemy, SharedChar = SkM_FindSharedEnemyWar(sName); if (SharedEnemy) and (SharedEnemy[_SKM._atWar]) then bSharedWar = true; end end end if (bWar) or (bGuildWar) or (bSharedWar) then local bFilter = false; if (SkM_GetOption("WarEnableFilter")) then -- check against global "last warning date" if (SKM_Context.LastWarWarning) then local iDiffTime = SkM_DiffDate(sDate, SKM_Context.LastWarWarning); if (iDiffTime ~= nil) and (iDiffTime <= SkM_GetOption("WarFilterDelay")) then -- Filter out to reduce spam bFilter = true; end end end -- check against last warning for given enemy -- (independently of filter option) if (SkM_GetRecentWarWarning(sName)) then -- Filter out to reduce spam bFilter = true; end if (not bFilter) then SKM_Context.LastWarWarning = sDate; SkM_AddRecentWarWarning(sName, sDate); SkM_Trace(FName, 3, "Last War Warning = "..snil(SKM_Context.LastWarWarning)); if (SkM_GetOption("WarSoundWarning")) then --PlaySound("AuctionWindowClose"); PlaySoundFile(SKM_Config.WarSoundFile); end if (SkM_GetOption("WarFloatingMessage")) then local sWarMessage = ""; if (bWar) and (bGuildWar) then sWarMessage = sName.." / "..sGuildName; elseif (bWar) then sWarMessage = sName; elseif (bGuildWar) then sWarMessage = sGuildName; elseif (bSharedWar) then sWarMessage = sName..SKM_Config.Col_SharedWar.." ["..SharedChar.."]".."|r"; end UIErrorsFrame:AddMessage(SKM_UI_STRINGS.War_Floating_Message..sWarMessage, 1.0, 0.0, 0.0, 1.0, UIERRORS_HOLD_TIME); end if (SkM_GetOption("WarChatMessage")) then local sWarMessage = ""; if (bWar) and (bGuildWar) then sWarMessage = sName.." / "..sGuildName; elseif (bWar) then sWarMessage = sName; elseif (bGuildWar) then sWarMessage = sGuildName; elseif (bSharedWar) then sWarMessage = sName..SKM_Config.Col_SharedWar.." ["..SharedChar.."]".."|r"; end if (SkM_GetOption("WarShowNote")) then if (not bSharedWar) then if (Enemy) and (Enemy[_SKM._playerNote] ~= nil) and (Enemy[_SKM._playerNote] ~= "") then sWarMessage = sWarMessage .. SKM_Config.Col_Label.." - " .. SKM_Config.Col_PlayerNote.. Enemy[_SKM._playerNote]; end else if (SharedEnemy) and (SharedEnemy[_SKM._playerNote]) and (SharedEnemy[_SKM._playerNote] ~= "") then sWarMessage = sWarMessage .. SKM_Config.Col_Label.." - " .. SKM_Config.Col_PlayerNote .. SharedEnemy[_SKM._playerNote]; end end end SkM_PrintMessage(SKM_UI_STRINGS.War_Floating_Message..sWarMessage, 1.0, 0.0, 0.0); end end if (SkM_GetOption("WarAutoTarget") and (not UnitName(SKM_UNIT_TARGET))) then TargetByName(sName); end end -- Add information to tooltip (if option enabled) if (SkM_GetOption("TooltipTargetInfo")) then SKMap_TooltipEnemyInfo(sName); end -- Add player note to tooltip (if option enabled) if (SkM_GetOption("TooltipPlayerNote")) then SKMap_TooltipEnemyNote(sName); end end --if (SkM_GetOption("TooltipTargetInfo")) then -- SKMap_TooltipEnemyInfo("Ledieu"); --end --if (SkM_GetOption("TooltipPlayerNote")) then -- SKMap_TooltipEnemyNote("Ledieu"); --end end -- -------------------------------------------------------------------------------------- -- SkM_ShowTargetInfoFrame -- -------------------------------------------------------------------------------------- -- Show one of the SKMap TargetInfo frames (small or normal), and hide the other. -- -------------------------------------------------------------------------------------- function SkM_ShowTargetInfoFrame() local FName = "SkM_ShowTargetInfoFrame"; local bShow = SkM_GetOption("ShowTargetInfo"); if (SkM_GetOption("SmallTargetInfo")) then SkM_DisplayTargetInfoFrames(false, bShow); else SkM_DisplayTargetInfoFrames(bShow, false); end end -- -------------------------------------------------------------------------------------- -- SkM_HideTargetInfoFrame -- -------------------------------------------------------------------------------------- -- Hide both SKMap TargetInfo frames. -- -------------------------------------------------------------------------------------- function SkM_HideTargetInfoFrame() local FName = "SkM_HideTargetInfoFrame"; SkM_DisplayTargetInfoFrames(false, false); end -- -------------------------------------------------------------------------------------- -- SkM_ShowTargetFrameWarButtons -- -------------------------------------------------------------------------------------- -- Show/hide war and truce button on the currently active SKMap TargetInfo frame, -- according to war status. -- -------------------------------------------------------------------------------------- function SkM_ShowTargetFrameWarButtons(bWar) local FName = "SkM_ShowTargetFrameWarButtons"; if (SkM_GetOption("SmallTargetInfo")) then if (bWar == true) then SKMapSmallPvPTruceButton:Show(); SKMapSmallPvPWarButton:Hide(); else SKMapSmallPvPTruceButton:Hide(); SKMapSmallPvPWarButton:Show(); end else if (bWar == true) then SKMapPvPTruceButton:Show(); SKMapPvPWarButton:Hide(); else SKMapPvPTruceButton:Hide(); SKMapPvPWarButton:Show(); end end end -- -------------------------------------------------------------------------------------- -- SkM_DisplayTargetInfoFrames -- -------------------------------------------------------------------------------------- -- Show or Hide the large or small target info frame -- -------------------------------------------------------------------------------------- function SkM_DisplayTargetInfoFrames(bLarge, bSmall) local FName = "SkM_DisplayTargetInfoFrames"; if (bLarge == true) then SKMapTargetInfoFrame:Show(); elseif (bLarge == false) then SKMapTargetInfoFrame:Hide(); end if (bSmall == true) then SKMapSmallTargetInfoFrame:Show(); elseif (bSmall == false) then SKMapSmallTargetInfoFrame:Hide(); end end -- -------------------------------------------------------------------------------------- -- SkM_TargetInfoResize -- -------------------------------------------------------------------------------------- -- Switch from one size of the SKMap TargetInfo frame to the other -- -------------------------------------------------------------------------------------- function SkM_TargetInfoResize() local FName = "SkM_TargetInfoResize"; SkM_SetOption("SmallTargetInfo", not (SkM_GetOption("SmallTargetInfo")) ); SkM_SetTargetInfo(); end -- -------------------------------------------------------------------------------------- -- SkM_StoreTargetInfo -- -------------------------------------------------------------------------------------- -- Store currently targetted creature information. -- Remember if it's tapped and by who. -- -------------------------------------------------------------------------------------- function SkM_StoreTargetInfo(sTargetType) local sName = SkM_UnitName(SKM_UNIT_TARGET); if (not sName) then SKM_Context.TargetInfo = nil; else if (not SKM_Context.TargetInfo) or (SKM_Context.TargetInfo[_SKM._name] ~= sName) then SKM_Context.TargetInfo = { }; SKM_Context.TargetInfo[_SKM._name] = sName; end SKM_Context.TargetInfo[_SKM._type] = sTargetType; if (sTargetType == _SKM._enemyCreature) then if (UnitIsTapped(SKM_UNIT_TARGET)) then if (UnitIsTappedByPlayer(SKM_UNIT_TARGET)) then SKM_Context.TargetInfo[_SKM._owner] = _SKM._player; else SKM_Context.TargetInfo[_SKM._owner] = _SKM._other; end end end end end -- -------------------------------------------------------------------------------------- -- SkM_TargetHealthUpdated -- -------------------------------------------------------------------------------------- -- Target unit health has changed. -- If this is a creature and if it just died, record creature kill if need be. -- If this is a creature and it's still alive, update information. -- -------------------------------------------------------------------------------------- function SkM_TargetHealthUpdated() local FName = "SkM_TargetHealthUpdated"; local sName = SkM_UnitName(SKM_UNIT_TARGET); if (not sName) then return; end if (UnitHealth(SKM_UNIT_TARGET) == 0 or UnitIsCorpse(SKM_UNIT_TARGET) or UnitIsDeadOrGhost(SKM_UNIT_TARGET)) then -- we use this event to track pve kills for unit currently targetted -- (player kills are tracked by damage done) if (not UnitIsPlayer(SKM_UNIT_TARGET)) then -- award kill to player if : we have previously stored the creature information -- in context, and if it was tapped by player -- in all cases, clear target info. if (SKM_Context.TargetInfo) and (SKM_Context.TargetInfo[_SKM._name] == sName) then if (SKM_Context.TargetInfo[_SKM._owner] == _SKM._player) then SkM_Trace(FName, 3, "Target creature (".. sName ..") kill detected - by player"); local iLevel = UnitLevel(SKM_UNIT_TARGET); local bElite = UnitIsPlusMob(SKM_UNIT_TARGET); local sClassification = UnitClassification(SKM_UNIT_TARGET); SkM_RecordCreatureKill_Target(sName, iLevel, sClassification); else SkM_Trace(FName, 3, "Target creature (".. sName ..") kill detected, but by other"); end end elseif (SkM_UnitIsEnemyPlayer(SKM_UNIT_TARGET)) then SkM_Trace(FName, 2, "Enemy player death detected (from target) : "..snil(sName)); SkM_PvpEnemyDeath(sName); end SKM_Context.TargetInfo = nil; else -- unit is alive if (not UnitIsPlayer(SKM_UNIT_TARGET)) then -- not a player, update owner information SkM_StoreTargetInfo(_SKM._enemyCreature); end end end -- -------------------------------------------------------------------------------------- -- SkM_PlayerLevelUp -- -------------------------------------------------------------------------------------- -- Handle "player level up" event : record event, and store new level. -- -------------------------------------------------------------------------------------- function SkM_PlayerLevelUp() local FName = "SkM_PlayerLevelUp"; local StoreInfo = { }; StoreInfo[_SKM._type] = _SKM._levelUp; local sDate1, sDate2 = SkM_GetDate(); StoreInfo[_SKM._date] = sDate1; --StoreInfo[_sortdate] = sDate2; StoreInfo[_SKM._name] = _PlayerName; local iNewLevel; if (SKM_Context.PlayerLevel) then iNewLevel = SKM_Context.PlayerLevel + 1; else iNewLevel = UnitLevel(SKM_UNIT_PLAYER) + 1; end StoreInfo[_SKM._level] = iNewLevel; SKM_Context.PlayerLevel = iNewLevel; if (not SkM_AddMapData(StoreInfo)) then return; end end -- -------------------------------------------------------------------------------------- -- SkM_CountGuildMembers -- -------------------------------------------------------------------------------------- -- Count number of members known for a given guild. -- -------------------------------------------------------------------------------------- function SkM_CountGuildMembers(sGuild, sRealm, sPlayer) local FName = "SkM_CountGuildMembers"; local sRealmName = sRealm; local sPlayerName = sPlayer; SkM_Trace(FName, 4, "Get member count for guild : "..snil(sGuild)); if (sRealmName == nil) then sRealmName = _RealmName; end if (sPlayerName == nil) then sPlayerName = _PlayerName; end if (SKM_Data[sRealmName] == nil) then return nil; end if (SKM_Data[sRealmName][sPlayerName] == nil) then return nil; end local iCount = 0; for idx, val in SKM_Data[sRealmName][sPlayerName].EnemyHistory do local sName = val[_SKM._name]; if (sName) then if (val[_SKM._guild] == sGuild) then iCount = iCount + 1; end end end return iCount; end -- -------------------------------------------------------------------------------------- -- SkM_ComputeStatistics -- -------------------------------------------------------------------------------------- -- Compute various statistics that will be used in the report frame. -- -------------------------------------------------------------------------------------- function SkM_ComputeStatistics() local FName = "SkM_ComputeStatistics"; SKM_Context.Statistics = { }; SKM_Context.Statistics.Globals = { }; SKM_Context.Statistics.Race = { }; SKM_Context.Statistics.Class = { }; SKM_Context.Statistics.Zone = { }; SKM_Context.Statistics.Date = { }; SKM_Context.Statistics.Enemy = { }; SKM_Context.Statistics.Guild = { }; SKM_Context.Statistics.BGZone = { }; SKM_Context.Statistics.BGDate = { }; SKM_Context.Statistics.BGDateZone = { }; local iDeathForLevel = 0; local iKillForLevel = 0; local iTotalLevelDeath = 0; local iTotalLevelKill = 0; -- compute : global, by race, by class, by enemy -- statistics from EnemyHistory map for idx, val in SKM_Data[_RealmName][_PlayerName].EnemyHistory do SKM_Context.Statistics.Globals.EnemyPlayers = ifnil(SKM_Context.Statistics.Globals.EnemyPlayers, 0) + 1; local iDeath = ifnil(val[_SKM._enemyKillPlayer], 0); --local iKill = ifnil(val[_SKM._playerAssistKill], 0) + ifnil(val[_SKM._playerKill], 0) + ifnil(val[_SKM._playerFullKill], 0); local iKill = ifnil(val[_SKM._playerKill], 0) + ifnil(val[_SKM._playerFullKill], 0); if (SkM_GetOption("AssistKillStat")) then iKill = iKill + ifnil(val[_SKM._playerAssistKill], 0) end SKM_Context.Statistics.Globals.Death = ifnil(SKM_Context.Statistics.Globals.Death, 0) + iDeath; SKM_Context.Statistics.Globals.Kill = ifnil(SKM_Context.Statistics.Globals.Kill, 0) + iKill; -- for computing averages if (val[_SKM._level]) and (val[_SKM._level] ~= -1) then iDeathForLevel = iDeathForLevel + iDeath; iKillForLevel = iKillForLevel + iKill; iTotalLevelDeath = iTotalLevelDeath + ( val[_SKM._level] * iDeath ); iTotalLevelKill = iTotalLevelKill + ( val[_SKM._level] * iKill ); end local sRace = SkM_GetRaceText(val[_SKM._race]); if (sRace) then if (SKM_Context.Statistics.Race[sRace] == nil) then SKM_Context.Statistics.Race[sRace] = { }; end SKM_Context.Statistics.Race[sRace].Death = ifnil(SKM_Context.Statistics.Race[sRace].Death, 0) + iDeath; SKM_Context.Statistics.Race[sRace].Kill = ifnil(SKM_Context.Statistics.Race[sRace].Kill, 0) + iKill; end local sClass = SkM_GetClassText(val[_SKM._class]); if (sClass) then if (SKM_Context.Statistics.Class[sClass] == nil) then SKM_Context.Statistics.Class[sClass] = { }; end SKM_Context.Statistics.Class[sClass].Death = ifnil(SKM_Context.Statistics.Class[sClass].Death, 0) + iDeath; SKM_Context.Statistics.Class[sClass].Kill = ifnil(SKM_Context.Statistics.Class[sClass].Kill, 0) + iKill; end sEnemyName = val[_SKM._name]; if (sEnemyName) and ( (iDeath > 0) or (iKill > 0) ) then SKM_Context.Statistics.Enemy[sEnemyName] = { }; SKM_Context.Statistics.Enemy[sEnemyName].Death = iDeath; SKM_Context.Statistics.Enemy[sEnemyName].Kill = iKill; end end -- compute : global, by race, by class, by enemy -- statistics from EnemyHistory map for idx, val in SKM_Data[_RealmName][_PlayerName].GuildHistory do --for idx, val in SkM_GetPlayerData("GuildHistory") do SKM_Context.Statistics.Globals.EnemyGuilds = ifnil(SKM_Context.Statistics.Globals.EnemyGuilds, 0) + 1; local iDeath = ifnil(val[_SKM._enemyKillPlayer], 0); local iKill = ifnil(val[_SKM._playerAssistKill], 0) + ifnil(val[_SKM._playerKill], 0) + ifnil(val[_SKM._playerFullKill], 0); local sGuildName = val[_SKM._name]; if (sGuildName) and ( (iDeath > 0) or (iKill > 0) ) then SKM_Context.Statistics.Guild[sGuildName] = { }; SKM_Context.Statistics.Guild[sGuildName].Death = iDeath; SKM_Context.Statistics.Guild[sGuildName].Kill = iKill; end end -- compute averages if (iDeathForLevel > 0) then SkM_Trace(FName, 3, "iDeathForLevel = "..iDeathForLevel..", iTotalLevelDeath = "..iTotalLevelDeath); SKM_Context.Statistics.Globals.DeathAverageLevel = math.floor (iTotalLevelDeath / iDeathForLevel); end if (iKillForLevel > 0) then SkM_Trace(FName, 3, "iKillForLevel = "..iKillForLevel..", iTotalLevelKill = "..iTotalLevelKill); SKM_Context.Statistics.Globals.KillAverageLevel = math.floor (iTotalLevelKill / iKillForLevel); end SkM_Trace(FName, 3, "Average level of victims : "..snil(SKM_Context.Statistics.Globals.KillAverageLevel)); SkM_Trace(FName, 3, "Average level of executioners : "..snil(SKM_Context.Statistics.Globals.DeathAverageLevel)); -- compute : by zone, by date -- statistics from GlobalMapData map local i; local iNbNotes = getn(SKM_Data[_RealmName][_PlayerName].GlobalMapData); SKM_Context.Statistics.Globals.MapRecords = iNbNotes; SkM_Trace(FName, 3, "Global notes count = "..iNbNotes); for i=1, iNbNotes, 1 do local Note = SKM_Data[_RealmName][_PlayerName].GlobalMapData[i]; local StoredInfo = Note[_SKM._storedInfo]; if (StoredInfo) then local iKill = 0; local iDeath = 0; -- if (StoredInfo[_SKM._type] == _SKM._playerAssistKill) if (StoredInfo[_SKM._type] == _SKM._playerAssistKill) and (SkM_GetOption("AssistKillStat")) or (StoredInfo[_SKM._type] == _SKM._playerKill) or (StoredInfo[_SKM._type] == _SKM._playerFullKill) then iKill = 1; SkM_Trace(FName, 3, "PvP Kill : global note = "..i); elseif (StoredInfo[_SKM._type] == _SKM._playerDeathPvP) then iDeath = 1; SkM_Trace(FName, 3, "PvP Death : global note = "..i); end if (iKill > 0) or (iDeath > 0) then --local sZoneText = SKM_Context.Zones[Note[_SKM._continent]][Note[_SKM._zone]]; local sZoneText = SkM_GetZoneTextFromIndex(Note[_SKM._continent], Note[_SKM._zone]); if (sZoneText) then if (SKM_Context.Statistics.Zone[sZoneText] == nil) then SKM_Context.Statistics.Zone[sZoneText] = { }; end SKM_Context.Statistics.Zone[sZoneText].Death = ifnil(SKM_Context.Statistics.Zone[sZoneText].Death, 0) + iDeath; SKM_Context.Statistics.Zone[sZoneText].Kill = ifnil(SKM_Context.Statistics.Zone[sZoneText].Kill, 0) + iKill; end local sDate = string.sub(StoredInfo[_SKM._date], 1, 10); if (sDate) then if (SKM_Context.Statistics.Date[sDate] == nil) then SKM_Context.Statistics.Date[sDate] = { }; end SKM_Context.Statistics.Date[sDate].Death = ifnil(SKM_Context.Statistics.Date[sDate].Death, 0) + iDeath; SKM_Context.Statistics.Date[sDate].Kill = ifnil(SKM_Context.Statistics.Date[sDate].Kill, 0) + iKill; end end end end -- compute : battlegrounds by zone, by date, by date and zone for idx1, val1 in SKM_Data[_RealmName][_PlayerName].BGStats do local sZone = idx1; if (SKM_Context.Statistics.BGZone[sZone] == nil) then SKM_Context.Statistics.BGZone[sZone] = { }; end for idx2, val2 in val1 do local sDate = idx2; local iDeath = ifnil(val2[_SKM._enemyKillBG], 0); local iKill = ifnil(val2[_SKM._playerBGKill], 0); SKM_Context.Statistics.BGZone[sZone].Death = ifnil(SKM_Context.Statistics.BGZone[sZone].Death, 0) + iDeath; SKM_Context.Statistics.BGZone[sZone].Kill = ifnil(SKM_Context.Statistics.BGZone[sZone].Kill, 0) + iKill; if (SKM_Context.Statistics.BGDate[sDate] == nil) then SKM_Context.Statistics.BGDate[sDate] = { }; end SKM_Context.Statistics.BGDate[sDate].Death = ifnil(SKM_Context.Statistics.BGDate[sDate].Death, 0) + iDeath; SKM_Context.Statistics.BGDate[sDate].Kill = ifnil(SKM_Context.Statistics.BGDate[sDate].Kill, 0) + iKill; local sDateZone = idx2.." - "..idx1; if (SKM_Context.Statistics.BGDateZone[sDateZone] == nil) then SKM_Context.Statistics.BGDateZone[sDateZone] = { }; SKM_Context.Statistics.BGDateZone[sDateZone].Zone = idx1; SKM_Context.Statistics.BGDateZone[sDateZone].Date = idx2; end SKM_Context.Statistics.BGDateZone[sDateZone].Death = ifnil(SKM_Context.Statistics.BGDateZone[sDateZone].Death, 0) + iDeath; SKM_Context.Statistics.BGDateZone[sDateZone].Kill = ifnil(SKM_Context.Statistics.BGDateZone[sDateZone].Kill, 0) + iKill; end end -- provide sortable lists SKM_Context.Statistics.ClassList = {}; for idx, val in SKM_Context.Statistics.Class do val.SortKey = idx; val.Key = idx; table.insert(SKM_Context.Statistics.ClassList, val); end table.sort(SKM_Context.Statistics.ClassList, SkM_SortStatList); SKM_Context.Statistics.RaceList = {}; for idx, val in SKM_Context.Statistics.Race do val.SortKey = idx; val.Key = idx; table.insert(SKM_Context.Statistics.RaceList, val); end table.sort(SKM_Context.Statistics.RaceList, SkM_SortStatList); SKM_Context.Statistics.EnemyList = {}; for idx, val in SKM_Context.Statistics.Enemy do --val.SortKey = string.upper(idx); val.SortKey = SkM_NormalizeString(idx); val.Key = idx; table.insert(SKM_Context.Statistics.EnemyList, val); end table.sort(SKM_Context.Statistics.EnemyList, SkM_SortStatList); SKM_Context.Statistics.GuildList = {}; for idx, val in SKM_Context.Statistics.Guild do --val.SortKey = string.upper(idx); val.SortKey = SkM_NormalizeString(idx); val.Key = idx; table.insert(SKM_Context.Statistics.GuildList, val); end table.sort(SKM_Context.Statistics.GuildList, SkM_SortStatList); SKM_Context.Statistics.ZoneList = {}; for idx, val in SKM_Context.Statistics.Zone do val.SortKey = idx; val.Key = idx; table.insert(SKM_Context.Statistics.ZoneList, val); end table.sort(SKM_Context.Statistics.ZoneList, SkM_SortStatList); SKM_Context.Statistics.DateList = {}; for idx, val in SKM_Context.Statistics.Date do val.SortKey = SkM_GetSortableDate(idx); val.Key = idx; table.insert(SKM_Context.Statistics.DateList, val); end table.sort(SKM_Context.Statistics.DateList, SkM_SortStatList); SKM_Context.Statistics.BGDateList = {}; for idx, val in SKM_Context.Statistics.BGDate do val.SortKey = SkM_GetSortableDate(idx); val.Key = idx; table.insert(SKM_Context.Statistics.BGDateList, val); end table.sort(SKM_Context.Statistics.BGDateList, SkM_SortStatList); SKM_Context.Statistics.BGZoneList = {}; for idx, val in SKM_Context.Statistics.BGZone do val.SortKey = idx; val.Key = idx; table.insert(SKM_Context.Statistics.BGZoneList, val); end table.sort(SKM_Context.Statistics.BGZoneList, SkM_SortStatList); SKM_Context.Statistics.BGDateZoneList = {}; for idx, val in SKM_Context.Statistics.BGDateZone do val.SortKey = SkM_GetSortableDate(val.Date)..val.Zone; val.Key = idx; table.insert(SKM_Context.Statistics.BGDateZoneList, val); end table.sort(SKM_Context.Statistics.BGDateZoneList, SkM_SortStatList); end -- -------------------------------------------------------------------------------------- -- SkM_SortStatList -- -------------------------------------------------------------------------------------- -- Statistics sorting function -- -------------------------------------------------------------------------------------- function SkM_SortStatList(e1, e2) if (e1.SortKey < e2.SortKey) then return true; elseif (e2.SortKey < e1.SortKey) then return false; end return false; end -- -------------------------------------------------------------------------------------- -- SkM_GetUnitFaction -- -------------------------------------------------------------------------------------- -- Find player faction for a given unit -- -------------------------------------------------------------------------------------- function SkM_GetUnitFaction(sUnit) if (sUnit == nil) then return nil; end local sRace = UnitRace(sUnit); if (sRace == nil) then return nil; end local i; for i=1, getn(SKM_PlayerFaction), 1 do if ( intable(sRace, SKM_PlayerFaction[i].RaceList) ) then return i, SKM_PlayerFaction[i].Faction; end end return nil; end -- -------------------------------------------------------------------------------------- -- SkM_UnitIsEnemyPlayer -- -------------------------------------------------------------------------------------- -- Is unit an enemy player of the opposite faction ? -- -------------------------------------------------------------------------------------- function SkM_UnitIsEnemyPlayer(sUnit) if (sUnit == nil) then return nil; end return ( (UnitIsPlayer(sUnit)) and (UnitIsEnemy(SKM_UNIT_PLAYER, sUnit)) and (SkM_UnitIsOppositeFaction(SKM_UNIT_PLAYER, sUnit)) ); end -- -------------------------------------------------------------------------------------- -- SkM_UnitIsDuelingPlayer -- -------------------------------------------------------------------------------------- -- Is unit a player you are currently dueling ? -- ie, if he is a player, tagged as "enemy" but of your faction. -- -------------------------------------------------------------------------------------- function SkM_UnitIsDuelingPlayer(sUnit) if (sUnit == nil) then return nil; end return ( (UnitIsPlayer(sUnit)) and (UnitIsEnemy(SKM_UNIT_PLAYER, sUnit)) and (not SkM_UnitIsOppositeFaction(SKM_UNIT_PLAYER, sUnit)) ); end -- -------------------------------------------------------------------------------------- -- SkM_UnitIsOppositeFaction -- -------------------------------------------------------------------------------------- -- Check if two units are on opposite faction or not, using their race. -- Return true if it's the case, false if not, and nil if indeterminate -- -------------------------------------------------------------------------------------- function SkM_UnitIsOppositeFaction(sUnit1, sUnit2) local FName = "SkM_UnitIsOppositeFaction"; local Faction1 = SkM_GetUnitFaction(sUnit1); local Faction2 = SkM_GetUnitFaction(sUnit2); if (Faction1 == nil) then SkM_Trace(FName, 1, "Unknown faction for "..snil(sUnit1)); return nil; end if (Faction2 == nil) then SkM_Trace(FName, 1, "Unknown faction for "..snil(sUnit2)); return nil; end if (Faction1 == Faction2) then return false; else return true; end end -- -------------------------------------------------------------------------------------- -- SkM_DeleteEnemy -- -------------------------------------------------------------------------------------- -- Delete an enemy player and all associated map records (kills or deaths). -- -------------------------------------------------------------------------------------- function SkM_DeleteEnemy(sName) local FName = "SkM_DeleteEnemy"; local Enemy = SKM_Data[_RealmName][_PlayerName].EnemyHistory[sName]; if (Enemy == nil) then SkM_Trace(FName, 1, "Enemy not found : "..snil(sName)); return; end SkM_Trace(FName, 1, "Removing Enemy : "..sName); SkM_UpdateEnemyHistory(); -- remove all recorded events associated to this enemy : kills and deaths local i; local iNbNotes = table.getn(SKM_Data[_RealmName][_PlayerName].GlobalMapData); for i=iNbNotes, 1, -1 do local Note = SKM_Data[_RealmName][_PlayerName].GlobalMapData[i]; local StoredInfo = Note[_SKM._storedInfo]; if (StoredInfo) and (StoredInfo[_SKM._name] == sName) then -- remove from GlobalMapData and from MapData SkM_Trace(FName, 3, "Removing note : global index = "..i); SkM_DeleteNote(_RealmName, _PlayerName, i); end end -- finally, delete the enemy. Bye bye ! SKM_Data[_RealmName][_PlayerName].EnemyHistory[sName] = nil; end -- -------------------------------------------------------------------------------------- -- SkM_DeleteDuelEnemy -- -------------------------------------------------------------------------------------- -- Delete all duel information associated to a given player -- -------------------------------------------------------------------------------------- function SkM_DeleteDuelEnemy(sName) local FName = "SkM_DeleteDuelEnemy"; SKM_Data[_RealmName][_PlayerName].DuelHistory[sName] = nil; end -- -------------------------------------------------------------------------------------- -- SkM_GetKnownEnemyType -- -------------------------------------------------------------------------------------- -- Return _SKM._enemyPlayer if given name matches a known player, otherwise return nil -- (ie, we do not know for now if it's a player or not, but we may get the information -- later on) -- -------------------------------------------------------------------------------------- function SkM_GetKnownEnemyType(sName) local EnemyType; local Enemy = SKM_Data[_RealmName][_PlayerName].EnemyHistory[sName]; if (Enemy) then EnemyType = _SKM._enemyPlayer; end return EnemyType; end -- -------------------------------------------------------------------------------------- -- SkM_UnitName -- -------------------------------------------------------------------------------------- -- Call UnitName to get unit name. -- Return nil if we get "Unknown Entity". -- -------------------------------------------------------------------------------------- function SkM_UnitName(sUnit) local sName = UnitName(sUnit); -- if we got "unknown entity", try again, maybe it will work this time if (sName == SKM_UNKNOWN_ENTITY) then sName = UnitName(sUnit); end if (sName == "") or (sName == SKM_UNKNOWN_ENTITY) then sName = nil; end return sName; end -- -------------------------------------------------------------------------------------- -- SkM_IsTotem -- -------------------------------------------------------------------------------------- -- Check if given name matches a totem (and *not* a player) -- -------------------------------------------------------------------------------------- function SkM_IsTotem(sName) local FName = "SkM_IsTotem"; if (sName) then for sType in string.gfind(sName, SKM_Context.Pattern.Totem) do if (sType) then SkM_Trace(FName, 2, "Name = "..snil(sName).." : this is a totem. Type = "..sType); return true; end end end SkM_Trace(FName, 3, "Name = "..snil(sName).." : not a totem"); return false; -- if (string.find(sName, SKM_Context.Pattern.Totem)) then -- SkM_Trace(FName, 2, "Name = "..snil(sName).." : this is a totem"); -- return true; -- else -- SkM_Trace(FName, 3, "Name = "..snil(sName).." : not a totem"); -- return false; -- end end function SkM_NormalizeString(sName) local FName = "SkM_NormalizeString"; if (sName == nil) then return nil; end local sString = string.upper(sName); i=1; while (string.sub(sString, i, i) == " ") and (i < string.len(sString)) do i = i + 1; end if (i > 1 ) then sString = string.sub(sString, i, string.len(sString)); end sString = SkM_NormString(sString, 2); -- only need to normalize the first two chars to provide an accurate sort return sString; end function SkM_LogDuel(sWinner, sLoser) local FName = "SkM_LogDuel"; local sName; local sDate = SkM_GetDate(); local bWin; if (sWinner == _PlayerName) then sName = sLoser; bWin = true; else sName = sWinner; bWin = false; end if (SKM_Context.DuelEnemy == nil) or (SKM_Context.DuelEnemy[_SKM._name] ~= sName) then -- rare case of a finished duel but we did not see at any time our enemy. -- okay, force target him then. -- I agree that messing with player target is a bad idea in most cases, but at the end -- of a duel it should not matter much. SkM_Trace(FName, 2, "End of duel but no info about enemy "..snil(sName).." : force target"); TargetByName(sName); SkM_StoreDuelEnemyInfo(SKM_UNIT_TARGET); if (SKM_Context.DuelEnemy == nil) or (SKM_Context.DuelEnemy[_SKM._name] ~= sName) then -- might potentially happen if enemy is too far away. Even more unlikely, but -- just in case... SkM_Trace(FName, 1, "Still no info about enemy !"); SKM_Context.DuelEnemy = nil; return; end end if (not SKM_Data[_RealmName][_PlayerName].DuelHistory[sName]) then SKM_Data[_RealmName][_PlayerName].DuelHistory[sName] = { }; SKM_Data[_RealmName][_PlayerName].DuelHistory[sName][_SKM._name] = sName; SKM_Data[_RealmName][_PlayerName].DuelHistory[sName][_SKM._race] = SKM_Context.DuelEnemy[_SKM._race]; SKM_Data[_RealmName][_PlayerName].DuelHistory[sName][_SKM._class] = SKM_Context.DuelEnemy[_SKM._class]; SKM_Data[_RealmName][_PlayerName].DuelHistory[sName][_SKM._win] = 0; SKM_Data[_RealmName][_PlayerName].DuelHistory[sName][_SKM._loss] = 0; SKM_Data[_RealmName][_PlayerName].DuelHistory[sName][_SKM._duel] = 0; else if (not SKM_Data[_RealmName][_PlayerName].DuelHistory[sName][_SKM._race]) then SKM_Data[_RealmName][_PlayerName].DuelHistory[sName][_SKM._race] = SKM_Context.DuelEnemy[_SKM._race]; end if (not SKM_Data[_RealmName][_PlayerName].DuelHistory[sName][_SKM._class]) then SKM_Data[_RealmName][_PlayerName].DuelHistory[sName][_SKM._class] = SKM_Context.DuelEnemy[_SKM._class]; end end SKM_Data[_RealmName][_PlayerName].DuelHistory[sName][_SKM._level] = SKM_Context.DuelEnemy[_SKM._level]; SKM_Data[_RealmName][_PlayerName].DuelHistory[sName][_SKM._guild] = SKM_Context.DuelEnemy[_SKM._guild]; SKM_Data[_RealmName][_PlayerName].DuelHistory[sName][_SKM._lastDuel] = sDate; SKM_Data[_RealmName][_PlayerName].DuelHistory[sName][_SKM._duel] = ifnil(SKM_Data[_RealmName][_PlayerName].DuelHistory[sName][_SKM._duel], 0) + 1; if (bWin) then SKM_Data[_RealmName][_PlayerName].DuelHistory[sName][_SKM._win] = ifnil(SKM_Data[_RealmName][_PlayerName].DuelHistory[sName][_SKM._win], 0) + 1; 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]); else SKM_Data[_RealmName][_PlayerName].DuelHistory[sName][_SKM._loss] = ifnil(SKM_Data[_RealmName][_PlayerName].DuelHistory[sName][_SKM._loss], 0) + 1; 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]); end -- clear duel information SKM_Context.DuelEnemy = nil; end function SkM_ParseDuelResult(sMsg) local FName = "SkM_ParseDuelResult"; local sWinner, sLoser; if (not SkM_GetOption("StoreDuels")) then return; end for sWinner, sLoser in string.gfind(sMsg, SKM_Context.Pattern.Duel_Won) do if (sWinner and sLoser) then if (sWinner == _PlayerName) or (sLoser == _PlayerName) then SkM_Trace(FName, 3, "Duel_Won : Winner = "..sWinner..", Loser = "..sLoser); SkM_LogDuel(sWinner, sLoser); return; end end end end function SkM_UpdateBGStats(sZoneName, sDate, iDeath, iKill) if (not SKM_Data[_RealmName][_PlayerName].BGStats[sZoneName]) then SKM_Data[_RealmName][_PlayerName].BGStats[sZoneName] = { }; end if (not SKM_Data[_RealmName][_PlayerName].BGStats[sZoneName][sDate]) then SKM_Data[_RealmName][_PlayerName].BGStats[sZoneName][sDate] = { }; SKM_Data[_RealmName][_PlayerName].BGStats[sZoneName][sDate][_SKM._enemyKillBG] = 0; SKM_Data[_RealmName][_PlayerName].BGStats[sZoneName][sDate][_SKM._playerBGKill] = 0; end if (iDeath) then SKM_Data[_RealmName][_PlayerName].BGStats[sZoneName][sDate][_SKM._enemyKillBG] = ifnil(SKM_Data[_RealmName][_PlayerName].BGStats[sZoneName][sDate][_SKM._enemyKillBG], 0) + iDeath; end if (iKill) then SKM_Data[_RealmName][_PlayerName].BGStats[sZoneName][sDate][_SKM._playerBGKill] = ifnil(SKM_Data[_RealmName][_PlayerName].BGStats[sZoneName][sDate][_SKM._playerBGKill], 0) + iKill; end end function SkM_BGStats_AddDeath() local sZone = SkM_GetZoneText(); local sDate = SkM_GetDay(); SkM_UpdateBGStats(sZone, sDate, 1, nil); end function SkM_BGStats_AddKill() local sZone = SkM_GetZoneText(); local sDate = SkM_GetDay(); SkM_UpdateBGStats(sZone, sDate, nil, 1); end function SkM_NormString2(sString) local sRes = sString; local idx, val, i; for idx, val in SKM_ToStandardCase do for i=1, table.getn(val), 1 do sRes = string.gsub(sRes, val[i], idx); end end return sRes; end function SkM_NormString(sInputString, iNormMinLen) local FName = "SkM_NormString"; local sString = string.upper(sInputString); local iLen = string.len(sString); local sRes = ""; local sNonStd = ""; local iByte_A = string.byte("A"); local iByte_Z = string.byte("Z"); local iByte_a = string.byte("a"); local iByte_z = string.byte("z"); local i; for i=1,iLen,1 do --SkM_Trace(FName, 3, i.." Res="..sRes); local sChar = string.sub(sString, i, i); local iByte = string.byte(sString, i); if ((iByte >= iByte_A) and (iByte <= iByte_Z)) or ((iByte >= iByte_a) and (iByte <= iByte_z)) or (intable(sChar, { " ", "-" } )) then if (string.len(sNonStd) > 0) then sRes = sRes..SkM_NormString2(sNonStd); sNonStd = ""; end sRes = sRes..sChar; if (i= iNormMinLen) then sRes = sRes..string.sub(sString, i+1, iLen); return sRes; end else sNonStd = sNonStd..sChar; end end if (string.len(sNonStd) > 0) then sRes = sRes..SkM_NormString2(sNonStd); sNonStd = ""; end return sRes; end function SkM_GetEnemyList(sName, bNormalize, bPrefix) local FName = "SkM_GetEnemyList"; local TheList = { }; local sEnemyName = string.upper(sName); if (bNormalize) then sEnemyName = SkM_NormString(sName); end local iNameLen = string.len(sEnemyName); SkM_Trace(FName, 3, "Name = "..sName); local ResList = {}; for idx, val in SKM_Data[_RealmName][_PlayerName].EnemyHistory do local sCurName = string.upper(idx); local bMatch = false; if (bNormalize) then sCurName = SkM_NormString(sCurName, iNameLen); end SkM_Trace(FName, 3, "CurName = "..sCurName); if (not bPrefix) then if (sCurName == sEnemyName) then bMatch = true; end else if (string.sub(sCurName, 1, iNameLen) == sEnemyName) then bMatch = true; end end if (bMatch) then table.insert(TheList, idx); end end table.sort(TheList, function(e1,e2) return e1 : level local sLine = ""; if (Enemy[_SKM._rank]) then sLine = sLine..SKM_Config.Col_Rank..Enemy[_SKM._rank].." "; end if (Enemy[_SKM._atWar]) then sLine = sLine..SKM_Config.Col_PlayerWar; else sLine = sLine..SKM_Config.Col_Label; end sLine = sLine..Enemy[_SKM._name]..SKM_Config.Col_Label; if (Guild) then sLine = sLine.." <"; if (Guild[_SKM._atWar]) then sLine = sLine..SKM_Config.Col_PlayerWar; end sLine = sLine..Enemy[_SKM._guild]..SKM_Config.Col_Label..">"; end if (Enemy[_SKM._level] ~= nil) and (Enemy[_SKM._race] ~= nil) and (Enemy[_SKM._class] ~= nil) then sLine = sLine.." : "..SKM_UI_STRINGS.List_Frame_Level..Enemy[_SKM._level].." "..SkM_GetRaceText(Enemy[_SKM._race]).." "..SkM_GetClassText(Enemy[_SKM._class]); end table.insert(Lines, sLine); if (iEnemyCount == 1) then -- line 2 : sLine = ""; sLine = sLine..SKM_Config.Col_LabelTitle..SKM_UI_STRINGS.List_Frame_Met..SKM_Config.Col_Label..iMet; sLine = sLine.." "..SKM_Config.Col_LabelTitle..SKM_UI_STRINGS.List_Frame_Kill..SKM_Config.Col_Label..iTotalKill; sLine = sLine.." "..SKM_Config.Col_LabelTitle..SKM_UI_STRINGS.List_Frame_Death..SKM_Config.Col_Label .. iDeath; sLine = sLine.." "..SKM_Config.Col_LabelTitle..SKM_UI_STRINGS.List_Frame_Last_Seen; sLine = sLine..SKM_Config.Col_Label..sDisplayDate; if (Enemy[_SKM._continent] ~= nil) and (Enemy[_SKM._zone] ~= nil) then local sZoneText = SkM_GetZoneTextFromIndex(Enemy[_SKM._continent], Enemy[_SKM._zone]); sLine = sLine.." - "..sZoneText; elseif (Enemy[_SKM._zoneName] ~= nil) then sLine = sLine.." - "..Enemy[_SKM._zoneName]; end table.insert(Lines, sLine); if (Enemy[_SKM._playerNote] ~= nil) and (Enemy[_SKM._playerNote] ~= "") then local sLine = ""; sLine = sLine..SKM_Config.Col_LabelTitle..SKM_UI_STRINGS.List_Frame_Note; sLine = sLine..SKM_Config.Col_Label..Enemy[_SKM._playerNote]; table.insert(Lines, sLine); end end for i=1,table.getn(Lines),1 do DEFAULT_CHAT_FRAME:AddMessage(Lines[i]); end end end --SkM_ChatMessageCol("Enemy matching : "..iEnemyCount); SkM_ChatMessageCol("Found : "..iEnemyCount); end function SkM_DataCleanUp() local FName = "SkM_DataCleanUp"; if (not SKM_Data) then return; end if (not SKM_Settings) then return; end if (SkM_GetOption("DataCleanUp")) then local sDate = SkM_GetDate(); local iDiffTime = SkM_DiffDate(sDate, SKM_Settings.LastDataCleanUp); if (SKM_Settings.LastDataCleanUp == nil) or (iDiffTime == nil) or (iDiffTime > SkM_GetOption("DataCleanUpInterval") * 3600 * 24) then SkM_DoCleanUp(); SKM_Settings.LastDataCleanUp = sDate; end end end function SkM_DoCleanUp() local FName = "SkM_DoCleanUp"; local sDate = SkM_GetDate(); if (SkM_GetOption("CleanInactiveEnemies")) then for idx_realm, val_realm in SKM_Data do for idx_char, val_char in SKM_Data[idx_realm] do if (SKM_Data[idx_realm][idx_char].PlayerName == idx_char) then SkM_Trace(FName, 1, "Cleaning for "..idx_realm.." / "..idx_char); for idx_enemy, val_enemy in SKM_Data[idx_realm][idx_char].EnemyHistory do local iDiffTime = SkM_DiffDate(sDate, val_enemy[_SKM._lastView]); if (iDiffTime ~= nil) and (iDiffTime > SkM_GetOption("CleanInactiveEnemiesDelay") * 3600 * 24) then -- long time no see. Check if we have to remove him if (ifnil(val_enemy[_SKM._playerAssistKill], 0) + ifnil(val_enemy[_SKM._playerKill], 0) + ifnil(val_enemy[_SKM._playerFullKill], 0) == 0) and (ifnil(val_enemy[_SKM._enemyKillPlayer], 0) == 0) and (ifnil(val_enemy[_SKM._enemyKillBG], 0) == 0) and (ifnil(val_enemy[_SKM._playerBGKill], 0) == 0) and not (val_enemy[_SKM._atWar]) and ( (val_enemy[_SKM._playerNote] == nil) or (val_enemy[_SKM._playerNote] == "") ) then SkM_Trace(FName, 2, idx_realm.." / "..idx_char.." : remove "..idx_enemy); SKM_Data[idx_realm][idx_char].EnemyHistory[idx_enemy] = nil; end end end end end end end if (SkM_GetOption("CleanEmptyGuilds")) then for idx_realm, val_realm in SKM_Data do for idx_char, val_char in SKM_Data[idx_realm] do if (SKM_Data[idx_realm][idx_char].PlayerName == idx_char) then for idx_guild, val_guild in SKM_Data[idx_realm][idx_char].GuildHistory do if (SkM_CountGuildMembers(idx_guild, idx_realm, idx_char) == 0) then SkM_Trace(FName, 2, idx_realm.." / "..idx_char.." : remove "..idx_guild); SKM_Data[idx_realm][idx_char].GuildHistory[idx_guild] = nil; end end end end end end end function SkM_ZoneRematch(RealmName, PlayerName, ZoneShift, minDate, maxDate) local FName = "SkM_ZoneRematch"; local idx_c, val_c, idx_z, val_z, idx_gn, Note; local cont_shift, zone_shift; local iCountShift = 0; local iCountNoShift = 0; if (ZoneShift == nil) then SkM_Trace(FName, 1, "ZoneShift is nil ! "); return; end -- reinitialize map data SKM_Data[RealmName][PlayerName].MapData = { }; for idx_c, val_c in SKM_Context.Continents do SKM_Data[RealmName][PlayerName].MapData[idx_c] = { }; for idx_z, val_z in SKM_Context.Zones[idx_c] do SKM_Data[RealmName][PlayerName].MapData[idx_c][idx_z] = { }; end end -- parse global map data to rebuild local map data if (SKM_Data[RealmName][PlayerName].GlobalMapData) then for idx_gn, Note in SKM_Data[RealmName][PlayerName].GlobalMapData do local bDoShift = true; idx_c = Note[_SKM._continent]; idx_z = Note[_SKM._zone]; local StoredInfo = Note[_SKM._storedInfo]; if (StoredInfo) and (StoredInfo[_SKM._date]) then if (maxDate) then local iDiffTime = SkM_DiffDate(maxDate, StoredInfo[_SKM._date]); if (iDiffTime < 0) then -- Note generated after max date, skip bDoShift = false; end end if (minDate) then local iDiffTime = SkM_DiffDate(minDate, StoredInfo[_SKM._date]); if (iDiffTime > 0) then -- Note generated before min date, skip bDoShift = false; end end end if (bDoShift) then zone_shift = ZoneShift[idx_c][idx_z]; -- insert new map note table.insert(SKM_Data[RealmName][PlayerName].MapData[idx_c][zone_shift], idx_gn); -- update global note zone index SKM_Data[RealmName][PlayerName].GlobalMapData[idx_gn][_SKM._zone] = zone_shift; iCountShift = iCountShift + 1; else -- insert unchanged map note table.insert(SKM_Data[RealmName][PlayerName].MapData[idx_c][idx_z], idx_gn); iCountNoShift = iCountNoShift + 1; end end end -- parse enemy information and shift zone where last seen for idx_enemy, val_enemy in SKM_Data[RealmName][PlayerName].EnemyHistory do idx_c = val_enemy[_SKM._continent]; idx_z = val_enemy[_SKM._zone]; local bDoShift = true; if (idx_c == nil) or (idx_z == nil) then bDoShift = false; if (val_enemy[_SKM._lastView]) then if (maxDate) then local iDiffTime = SkM_DiffDate(maxDate, val_enemy[_SKM._lastView]); if (iDiffTime < 0) then -- generated after max date, skip bDoShift = false; end end if (minDate) then local iDiffTime = SkM_DiffDate(minDate, val_enemy[_SKM._lastView]); if (iDiffTime > 0) then -- generated before min date, skip bDoShift = false; end end end end if (bDoShift) then zone_shift = ZoneShift[idx_c][idx_z]; SKM_Data[RealmName][PlayerName].EnemyHistory[idx_enemy][_SKM._zone] = zone_shift; end end SkM_Trace(FName, 1, "Realm = "..RealmName.." / Player = "..PlayerName.." : Zone Rematch completed, shift count = "..iCountShift..", 'no shift' count = "..iCountNoShift); end function SkM_AccountZoneRematch(ZoneShift, minDate, maxDate) local FName = "SkM_AccountZoneRematch"; if (ZoneShift == nil) then SkM_Trace(FName, 1, "ZoneShift is nil ! "); return; end local idx_realm, val_realm, idx_char, val_char; for idx_realm, val_realm in SKM_Data do for idx_char, val_char in SKM_Data[idx_realm] do if (SKM_Data[idx_realm][idx_char].PlayerName == idx_char) then SkM_ZoneRematch(idx_realm, idx_char, ZoneShift, minDate, maxDate) end end end end function SkM_DoMapShift(Source, Dest, ZoneShift, minDate, maxDate) local FName = "SkM_DoMapShift"; local sDate = SkM_GetDate(); if (ZoneShift == nil) then SkM_Trace(FName, 1, "ZoneShift is nil ! "); return; end SkM_Trace(FName, 1, "Do shift ("..snil(Source).." -> "..snil(Dest)..")"); SkM_Trace(FName, 1, "Shift interval = ["..snil(minDate).." -> "..snil(maxDate).."]"); SkM_AccountZoneRematch(ZoneShift, minDate, maxDate); if (SKM_Settings.ZoneShifts == nil) then SKM_Settings.ZoneShifts = {}; end local ZoneShiftRecord = { Date = sDate; Source = Source; Dest = Dest; minDate = minDate; maxDate = maxDate; }; table.insert(SKM_Settings.ZoneShifts, ZoneShiftRecord); end function SkM_GetShiftTable(source, dest) if (SKM_ShiftTables == nil) then return nil; end if (SKM_ShiftTables[source] == nil) then return nil; end return SKM_ShiftTables[source][dest]; end -- -------------------------------------------------------------------------------------- -- SkM_MapShiftMigration -- -------------------------------------------------------------------------------------- -- Proceed to all map shift migrations, if needed. -- If no new zone shift is defined since last migration, nothing will be done. -- -------------------------------------------------------------------------------------- function SkM_MapShiftMigration() local FName = "SkM_MapShiftMigration"; local bShift = false; local curTime = GetTime(); -- check if there are map migrations that need be done -- NOTE : the following case is not handled and WILL NOT BE !! -- if user changes his locale interface language while there has been a new locale -- shift defined on his previous language, before installing the new version of SKMap. -- too bad ! SkM_Trace(FName, 1, "Automatic map migration starting..."); local bNewLocale = false; -- if we don't have information of last local language, we assume there were no -- language change... otherwise, there's nothing we can do... if (SKM_Settings.LastLocale ~= nil) then if (SKM_CurrentLocale ~= SKM_Settings.LastLocale) then bNewLocale = true; end else SKM_Settings.LastLocale = SKM_CurrentLocale; end -- are there new locale shift defines for previous language ? local iNbLocalShift = 0; local iNextLocalShift = 0; local bNewLocalShift = false; if (SKM_Locale[SKM_Settings.LastLocale]) and (SKM_Locale[SKM_Settings.LastLocale].LocalShift) then iNbLocalShift = table.getn(SKM_Locale[SKM_Settings.LastLocale].LocalShift); end if (iNbLocalShift > ifnil(SKM_Settings.LastLocalShift, 0)) then bNewLocalShift = true; iNextLocalShift = ifnil(SKM_Settings.LastLocalShift, 0) + 1; end if (bNewLocalShift) then if (SKM_Settings.ZoneShiftDest) and (SKM_Settings.ZoneShiftSource) then -- apply reverse shift first for all data ulterior to next local shift SkM_DoMapShift( SKM_Settings.ZoneShiftDest, SKM_Settings.ZoneShiftSource, SkM_GetShiftTable(SKM_Settings.ZoneShiftDest, SKM_Settings.ZoneShiftSource), SKM_Locale[SKM_Settings.LastLocale].LocalShift[iNextShift].DateShift, nil); bShift = true; end SKM_Settings.LastLocalShift = 0; SKM_Settings.LastCurrentShift = 0; -- now perform all new local shifts -- each local shift is performed on all data up to the local shift date local i; for i=iNextLocalShift,iNbLocalShift, 1 do SkM_Trace(FName, 3, "Performing local shift "..i); local Source = SKM_Locale[SKM_Settings.LastLocale].LocalShift[i].Source; local Dest = SKM_Locale[SKM_Settings.LastLocale].LocalShift[i].Dest; local DateShift = SKM_Locale[SKM_Settings.LastLocale].LocalShift[i].DateShift; SkM_DoMapShift(Source, Dest, SkM_GetShiftTable(Source, Dest), nil, DateShift) bShift = true; SKM_Settings.LastLocalShift = i; end -- now apply current shift if need be -- moved out of if condition, see below end -- now apply current shift if need be if (ifnil(SKM_Settings.LastCurrentShift, 0) == 0) then if (SKM_Locale[SKM_Settings.LastLocale].CurrentShift) then local Source = SKM_Locale[SKM_Settings.LastLocale].CurrentShift.Source; local Dest = SKM_Locale[SKM_Settings.LastLocale].CurrentShift.Dest; if (Source == SKM_Settings.ZoneShiftSource) and (Dest == SKM_Settings.ZoneShiftDest) then SkM_Trace(FName, 3, "current shift already performed"); else SkM_Trace(FName, 3, "Perform final shift (current)"); local DateMin = nil; local DateMax = nil; -- fix for 1.4 bug for DE version if (SKM_CurrentLocale == "DE") then DateMax = SKM_Context.DateIndexBug; end SkM_DoMapShift(Source, Dest, SkM_GetShiftTable(Source, Dest), DateMin, DateMax); bShift = true; end SKM_Settings.LastCurrentShift = 1; SKM_Settings.ZoneShiftSource = Source; SKM_Settings.ZoneShiftDest = Dest; else -- no current shift SKM_Settings.ZoneShiftSource = nil; SKM_Settings.ZoneShiftDest = nil; end end if (bNewLocale) then if (SKM_Locale[SKM_CurrentLocale]) and (SKM_Locale[SKM_CurrentLocale].CurrentShift) then SKM_Settings.ZoneShiftSource = SKM_Locale[SKM_CurrentLocale].CurrentShift.Source; SKM_Settings.ZoneShiftDest = SKM_Locale[SKM_CurrentLocale].CurrentShift.Dest; else -- no current shift SKM_Settings.ZoneShiftSource = nil; SKM_Settings.ZoneShiftDest = nil; end -- now we can safely store the new language as the current one. SKM_Settings.LastLocale = SKM_CurrentLocale; -- also store LastLocalShift as the latest local shift, if any if (SKM_Locale[SKM_Settings.LastLocale]) and (SKM_Locale[SKM_Settings.LastLocale].LocalShift) then iNbLocalShift = table.getn(SKM_Locale[SKM_Settings.LastLocale].LocalShift); SKM_Settings.LastLocalShift = iNbLocalShift; else SKM_Settings.LastLocalShift = nil; end end SkM_Trace(FName, 3, "Zone Shift performed ? "..snil(bShift)); if (bShift) then local endTime = GetTime(); local elapsedTime = math.floor(100 * (endTime - curTime)) / 100; SkM_ChatMessageCol("Zone order shift(s) performed, elapsed time : "..elapsedTime.." s"); end end function SkM_ReverseZoneShift(ZoneShift) local NewShift = { }; local i,j; for i=1,table.getn(ZoneShift),1 do local Line = { }; for j=1,table.getn(ZoneShift[i]),1 do Line[ZoneShift[i][j]] = j; end NewShift[i] = Line; end return NewShift; end function SkM_CharDataMigration(Ver, RealmName, PlayerName) local FName = "SkM_CharDataMigration"; -- Migration of EnemyHistory if (SKM_Data[RealmName][PlayerName].EnemyHistory) then local idx_enemy, val_enemy; for idx_enemy, val_enemy in SKM_Data[RealmName][PlayerName].EnemyHistory do local EnemyMigr = {}; local idx, val; for idx, val in SKM_IndexMigr[Ver].EnemyHistory do if (val_enemy[val.Old]) then EnemyMigr[val.New] = val_enemy[val.Old]; end end SKM_Data[RealmName][PlayerName].EnemyHistory[idx_enemy] = nil; SKM_Data[RealmName][PlayerName].EnemyHistory[idx_enemy] = EnemyMigr; -- now migration of race and class to indexes local sRace = SKM_Data[RealmName][PlayerName].EnemyHistory[idx_enemy][_SKM._race]; local sClass = SKM_Data[RealmName][PlayerName].EnemyHistory[idx_enemy][_SKM._class]; local id_race = SKM_Context.Race.StringToIndex[sRace]; local id_class = SKM_Context.Class.StringToIndex[sClass]; SKM_Data[RealmName][PlayerName].EnemyHistory[idx_enemy][_SKM._race] = id_race; SKM_Data[RealmName][PlayerName].EnemyHistory[idx_enemy][_SKM._class] = id_class; end end -- Migration of DuelHistory if (SKM_Data[RealmName][PlayerName].DuelHistory) then local idx_enemy, val_enemy; for idx_enemy, val_enemy in SKM_Data[RealmName][PlayerName].DuelHistory do local DuelMigr = {}; local idx, val; for idx, val in SKM_IndexMigr[Ver].DuelHistory do if (val_enemy[val.Old]) then DuelMigr[val.New] = val_enemy[val.Old]; end end SKM_Data[RealmName][PlayerName].DuelHistory[idx_enemy] = nil; SKM_Data[RealmName][PlayerName].DuelHistory[idx_enemy] = DuelMigr; -- now migration of race and class to indexes local sRace = SKM_Data[RealmName][PlayerName].DuelHistory[idx_enemy][_SKM._race]; local sClass = SKM_Data[RealmName][PlayerName].DuelHistory[idx_enemy][_SKM._class]; local id_race = SKM_Context.Race.StringToIndex[sRace]; local id_class = SKM_Context.Class.StringToIndex[sClass]; SKM_Data[RealmName][PlayerName].DuelHistory[idx_enemy][_SKM._race] = id_race; SKM_Data[RealmName][PlayerName].DuelHistory[idx_enemy][_SKM._class] = id_class; end end -- Migration of GuildHistory if (SKM_Data[RealmName][PlayerName].GuildHistory) then local idx_guild, val_guild; for idx_guild, val_guild in SKM_Data[RealmName][PlayerName].GuildHistory do local GuildMigr = {}; local idx, val; for idx, val in SKM_IndexMigr[Ver].GuildHistory do if (val_guild[val.Old]) then GuildMigr[val.New] = val_guild[val.Old]; end end SKM_Data[RealmName][PlayerName].GuildHistory[idx_guild] = nil; SKM_Data[RealmName][PlayerName].GuildHistory[idx_guild] = GuildMigr; end end -- Migration of BGStats if (SKM_Data[RealmName][PlayerName].BGStats) then local idx_zone, val_zone; for idx_zone, val_zone in SKM_Data[RealmName][PlayerName].BGStats do local idx_date, val_date; for idx_date, val_date in SKM_Data[RealmName][PlayerName].BGStats[idx_zone] do local StatMigr = {}; local idx, val; for idx, val in SKM_IndexMigr[Ver].BGStatDate do if (val_date[val.Old]) then StatMigr[val.New] = val_date[val.Old]; end end SKM_Data[RealmName][PlayerName].BGStats[idx_zone][idx_date] = nil; SKM_Data[RealmName][PlayerName].BGStats[idx_zone][idx_date] = StatMigr; end end end -- Migration of GlobalMapData if (SKM_Data[RealmName][PlayerName].GlobalMapData) then local iNbNotes = table.getn(SKM_Data[RealmName][PlayerName].GlobalMapData); local i; for i=1, iNbNotes, 1 do local Note = SKM_Data[RealmName][PlayerName].GlobalMapData[i]; local NoteMigr = {}; local idx, val; for idx, val in SKM_IndexMigr[Ver].GlobalMapData do if (Note[val.Old]) then NoteMigr[val.New] = Note[val.Old]; end end SKM_Data[RealmName][PlayerName].GlobalMapData[i] = nil; SKM_Data[RealmName][PlayerName].GlobalMapData[i] = NoteMigr; local StoredInfo = NoteMigr[_SKM._storedInfo]; if (StoredInfo) then local InfoMigr = {}; for idx, val in SKM_IndexMigr[Ver].StoredInfo do if (StoredInfo[val.Old]) then InfoMigr[val.New] = StoredInfo[val.Old]; end end InfoMigr[_SKM._type] = SKM_IndexMigr[Ver].RecordType[InfoMigr[_SKM._type]]; InfoMigr[_SKM._enemyType] = SKM_IndexMigr[Ver].EnemyType[InfoMigr[_SKM._enemyType]]; -- fix level if not "level up" event if not (InfoMigr[_SKM._type] == _SKM._levelUp or InfoMigr[_SKM._type] == _SKM._creatureKill_Target or InfoMigr[_SKM._type] == _SKM._creatureKill_Xp ) then InfoMigr[_SKM._level] = nil; end SKM_Data[RealmName][PlayerName].GlobalMapData[i][_SKM._storedInfo] = InfoMigr; end end end -- fix battleground stats bug if (SKM_Data[RealmName][PlayerName].BGStats) then local idx_bg, val_bg for idx_bg, val_bg in SKM_Data[RealmName][PlayerName].BGStats do if not (intable(idx_bg, SKM_BATTLEGROUNDS)) then SKM_Data[RealmName][PlayerName].BGStats[idx_bg] = nil; end end end -- fix wrong "level up" records if (SKM_Data[RealmName][PlayerName].GlobalMapData) then local i = 1; local iMaxLevel = 0; local iNbNotes = table.getn(SKM_Data[RealmName][PlayerName].GlobalMapData); while (i < iNbNotes) do local Note = SKM_Data[RealmName][PlayerName].GlobalMapData[i]; local StoredInfo = Note[_SKM._storedInfo]; if (StoredInfo) and (StoredInfo[_SKM._type] == _SKM._levelUp) then if (StoredInfo[_SKM._level] > 1) and (StoredInfo[_SKM._level] > iMaxLevel) then iMaxLevel = StoredInfo[_SKM._level]; i = i + 1; else -- remove from GlobalMapData and from MapData SkM_Trace(FName, 3, "Previous max level = "..iMaxLevel..", Note level up = "..StoredInfo[_SKM._level]); SkM_Trace(FName, 3, "Removing note for "..PlayerName.." : global index = "..i); SkM_DeleteNote(RealmName, PlayerName, i); iNbNotes = iNbNotes - 1; end else i = i + 1; end end end end function SkM_AccountDataMigration(Ver) local FName = "SkM_AccountDataMigration"; local idx_realm, val_realm, idx_char, val_char; for idx_realm, val_realm in SKM_Data do for idx_char, val_char in SKM_Data[idx_realm] do if (SKM_Data[idx_realm][idx_char].PlayerName == idx_char) then SkM_CharDataMigration(Ver, idx_realm, idx_char); end end end end function SkM_DataModelMigration() local FName = "SkM_DataModelMigration"; local curTime = GetTime(); local bMigr = false; if (SKM_Settings.SavedDataVersion == nil) then SKM_Settings.SavedDataVersion = 1; end if (SKM_Settings.SavedDataVersion < 2) then SkM_AccountDataMigration(2); SKM_Settings.SavedDataVersion = 2; bMigr = true; end if (bMigr) then local endTime = GetTime(); local elapsedTime = math.floor(100 * (endTime - curTime)) / 100; SkM_ChatMessageCol("Data migrated to v."..SKM_Settings.SavedDataVersion..", elapsed time : "..elapsedTime.." s"); end end -- function provided to fix MapData indexes from GlobalMapData (which is supposed to be -- correct !) function SkM_FixMapIndexes(RealmName, PlayerName) local FName = "SkM_FixMapIndexes"; local idx_c, val_c, idx_z, val_z, idx_gn; SkM_Trace(FName, 3, "Realm = "..snil(RealmName).. " / Player = "..snil(PlayerName)); -- reinitialize map data SKM_Data[RealmName][PlayerName].MapData = { }; for idx_c, val_c in SKM_Context.Continents do SKM_Data[RealmName][PlayerName].MapData[idx_c] = { }; for idx_z, val_z in SKM_Context.Zones[idx_c] do SKM_Data[RealmName][PlayerName].MapData[idx_c][idx_z] = { }; end end -- parse global map data to rebuild local map data if (SKM_Data[RealmName][PlayerName].GlobalMapData) then for idx_gn, Note in SKM_Data[RealmName][PlayerName].GlobalMapData do idx_c = Note[_SKM._continent]; idx_z = Note[_SKM._zone]; -- insert new map note table.insert(SKM_Data[RealmName][PlayerName].MapData[idx_c][idx_z], idx_gn); end end end -- function provided to fix MapData indexes from GlobalMapData (which is supposed to be -- correct !) function SkM_AccountFixMapIndexes() local idx_realm, val_realm, idx_char, val_char; for idx_realm, val_realm in SKM_Data do for idx_char, val_char in SKM_Data[idx_realm] do if (SKM_Data[idx_realm][idx_char].PlayerName == idx_char) then SkM_FixMapIndexes(idx_realm, idx_char); end end end end -- get date of first record affected by the index bug since 1.4 -- needed to fix german data ! function SkM_GetDateIndexBug(bIgnoreLocale) local FName = "SkM_GetDateIndexBug"; SKM_Context.DateIndexBug = nil; local iBug = 0; local iOK = 0; if not (bIgnoreLocale) then if (SKM_CurrentLocale ~= "DE") then SkM_Trace(FName, 1, "Non DE locale"); return; end end local idx_realm, val_realm, idx_char, val_char; local idx_c, val_c, idx_z, val_z, idx_n, val_n, Note; local r_c, r_z, r_n, r_gn, r_realm, r_char; for idx_realm, val_realm in SKM_Data do for idx_char, val_char in SKM_Data[idx_realm] do if (SKM_Data[idx_realm][idx_char].PlayerName == idx_char) then for idx_c, val_c in SKM_Data[idx_realm][idx_char].MapData do for idx_z, val_z in SKM_Data[idx_realm][idx_char].MapData[idx_c] do for idx_n, val_n in SKM_Data[idx_realm][idx_char].MapData[idx_c][idx_z] do Note = SKM_Data[idx_realm][idx_char].GlobalMapData[val_n]; if not ((Note[_SKM._continent] == idx_c) and (Note[_SKM._zone] == idx_z)) then -- bad index ! iBug = iBug + 1; if (Note[_SKM._storedInfo]) and (Note[_SKM._storedInfo][_SKM._date]) then if (SKM_Context.DateIndexBug == nil) then SKM_Context.DateIndexBug = Note[_SKM._storedInfo][_SKM._date]; r_c = idx_c; r_z = idx_z; r_n = idx_n; r_gn = val_n; r_realm = idx_realm; r_char = idx_char; else local iDiffTime = SkM_DiffDate(SKM_Context.DateIndexBug, Note[_SKM._storedInfo][_SKM._date]); if (iDiffTime ~= nil) and (iDiffTime > 0) then SKM_Context.DateIndexBug = Note[_SKM._storedInfo][_SKM._date]; r_c = idx_c; r_z = idx_z; r_n = idx_n; r_gn = val_n; r_realm = idx_realm; r_char = idx_char; end end end else iOK = iOK + 1; end end end end end end end SkM_Trace(FName, 1, "OK = "..iOK.." / Bugged = "..iBug); SkM_Trace(FName, 1, "DateIndexBug = ".. snil(SKM_Context.DateIndexBug)); SkM_Trace(FName, 1, "realm = "..snil(r_realm).." / char = "..snil(r_char)); SkM_Trace(FName, 1, "cont. = "..snil(r_c).." / zone = "..snil(r_z).." / note = "..snil(r_n).." / gn = "..snil(r_gn)); end function SkM_DataFixMapIndexes() if (SKM_Settings.FixMapIndexes == nil) then SkM_GetDateIndexBug(); --if (SKM_CurrentLocale ~= "EN") then SkM_AccountFixMapIndexes(); --end local sDate = SkM_GetDate(); SKM_Settings.FixMapIndexes = sDate; end end -- keep track of history of versions installed. function SkM_RecordVersionHistory() local sLastVer; if (SKM_Settings.VersionHistory == nil) then SKM_Settings.VersionHistory = {}; else local iCount = table.getn(SKM_Settings.VersionHistory); if (iCount > 0) then sLastVer = SKM_Settings.VersionHistory[iCount].Version; end end if (sLastVer ~= SKM_VERSION) then local sDate = SkM_GetDate(); local VersionRecord = { Date = sDate; Version = SKM_VERSION; }; table.insert(SKM_Settings.VersionHistory, VersionRecord); end end -- nchnch - new -- -------------------------------------------------------------------------------------- -- -------------------------------------------------------------------------------------- -- SkM_GetGuildChannelName -- -------------------------------------------------------------------------------------- -- Build a unique channel name from the realm name and the player guild name -- -------------------------------------------------------------------------------------- function SkM_GetGuildChannel() local FName = "SkM_GetGuildChannel"; local sName; --if (not SKM_Context.RealmName) then -- SkM_Trace(FName, 1, "Realm not known !"); -- return nil; --end local sGuildName = GetGuildInfo(SKM_UNIT_PLAYER); if (not sGuildName) then SkM_Trace(FName, 2, "Not in a guild"); return nil; end sName = SKM_GuildChannelPrefix.." - "..sGuildName; SkM_Trace(FName, 3, "Channel name : "..snil(sName)); return sName; end -- -------------------------------------------------------------------------------------- -- SkM_IsNameInGuild -- -------------------------------------------------------------------------------------- -- Check if given player name is in guild/ -- -------------------------------------------------------------------------------------- function SkM_IsNameInGuild(sName) return ( (sName == _PlayerName) or (intable(sName, SKM_Context.GuildList)) ); end function SkM_JoinGuildChannel() local FName = "SkM_JoinGuildChannel"; local sChannel = SkM_GetGuildChannel(); if (not sChannel) then SkM_Trace(FName, 1, "Unable to get SKMap guild channel name"); return false; end JoinChannelByName(sChannel, nil, nil); SKM_Context.GuildChannel = sChannel; return true; end function SkM_LeaveGuildChannel() local FName = "SkM_LeaveGuildChannel"; if (not SKM_Context.GuildChannel) then SkM_Trace(FName, 1, "SKMap guild channel name not defined"); return; end LeaveChannelByName(SKM_Context.GuildChannel); SKM_Context.GuildChannel = nil; end function SkM_GetChannelIndex(sName) local FName = "SkM_GetChannelIndex"; if (not sName) then SkM_Trace(FName, 1, "Channel name not specified"); return nil; end SkM_Trace(FName, 3, "Looking for index for channel : "..snil(sName)); local MyChannelList = GetChannelList(); local idx, val; for idx, val in MyChannelList do if (val == sName) then SkM_Trace(FName, 3, "Channel number = "..idx); return idx; end end SkM_Trace(FName, 2, "Channel not found"); return nil; end function SkM_SendGuildChannelMessage(sMsg) local FName = "SkM_SendGuildChannelMessage"; local iChannelIndex = SkM_GetChannelIndex(SKM_Context.GuildChannel); if (iChannelIndex) then SendChatMessage(sMsg, "CHANNEL", nil, iChannelIndex); end end function SkM_GuildChannelMessage(iCode, ...) local FName = "SkM_GuildChannelMessage"; local sMsg; local sParam = ""; local i; for i=1, arg.n do local sField = SkM_FormatMessageField(arg[i]); sParam = sParam..sField.." "; end sMsg = string.format("%s", iCode, sParam); SkM_Trace(FName, 3, "Formated message = "..snil(sMsg)); SkM_SendGuildChannelMessage(sMsg); end function SkM_FormatMessageField(sField) local sOutput = sField; sOutput = string.gsub(sOutput, "\\", "\\\\"); sOutput = string.gsub(sOutput, "\"", "\\\""); return sOutput; end function SkM_GetMessageFields(sMsg) local FName = "SkM_GetMessageFields"; local i=1; local iLen = string.len(sMsg); local iStartField; local bSpecial = false; local bInField = false; local sField = ""; local Fields = { }; while (i <= iLen) do local sChar = string.sub(sMsg, i, i); if (not bInField) then if (sChar == "\"") then bInField = true; elseif (sChar == " ") then -- skip else -- error SkM_Trace(FName, 1, "Unexpected character : '"..sChar.."' at position "..i); return nil; end else if (sChar == "\\") then if ( bSpecial) then sField = sField..sChar; bSpecial = false; else bSpecial = true; end else if (sChar == "\"") then if (bSpecial) then sField = sField..sChar; bSpecial = false; else table.insert(Fields, sField); sField = ""; bInField = false; end else sField = sField..sChar; end end end i = i + 1; end return Fields; end function SkM_ProcessChannelMessage(iCode, sValue) local FName = "SkM_ProcessChannelMessage"; local Fields = SkM_GetMessageFields(sValue); if (iCode == 1) then -- message = update player information if (table.getn(Fields) == 4) then local sName = Fields[1]; local sRace = Fields[2]; local sClass = Fields[3]; local sLevel = Fields[4]; SkM_Trace(FName, 3, "Player update: Name="..sName..", Race="..sRace..", Class="..sClass..", Lvl="..sLevel); end else end end function SkM_HandleChannelMessage(sMsg, sChannel, sSender) local FName = "SkM_HandleChannelMessage"; if (sChannel == SKM_Context.GuildChannel) then SkM_Trace(FName, 3, "Message = "..snil(sMsg)); -- check if sender is a guild member, if not he should not be sending -- messages on this channel ! if (not SkM_IsNameInGuild(sSender)) then SkM_Trace(FName, 2, "Sender : "..snil(sSender)..", not in your guild !"); else -- now handle the message --for iCode, sValue in string.gfind(sMsg, SKM_Context.Pattern.) do --"%s" for iCode, sValue in string.gfind(sMsg, "(.+)") do if (sCode and sValue) then SkM_ProcessChannelMessage(iCode, sValue); end end end end end -- -------------------------------------------------------------------------------------- -- SkM_BuildGuildList -- -------------------------------------------------------------------------------------- -- Build a list of players currently in the guild. -- -------------------------------------------------------------------------------------- function SkM_BuildGuildList() local FName = "SkM_BuildGuildList"; SkM_Trace(FName, 2, "Rebuild guild list"); SKM_Context.GuildList = { }; local iNumGuildMembers = GetNumGuildMembers(); local i; for i=1, iNumGuildMembers, 1 do --Usage: name, rank, rankIndex, level, class, zone, group, note, officernote, online = GetGuildRosterInfo(index); local sName = GetGuildRosterInfo(i); if (sName) then table.insert(SKM_Context.GuildList, sName); end end end function SkM_AddGuildMessageToQueue(sMsg, iPriority) local FName = "SkM_AddGuildMessageToQueue"; if (SKM_Context.QueueSendMessage == nil) then SKM_Context.QueueSendMessage = { }; end local iMessagePriority = ifnil(iPriority, 0); if (iMessagePriority == 0) then table.insert(SKM_Context.QueueSendMessage, { Message = sMsg; Priority = iMessagePriority } ); return; end local i; local iQueueSize = table.getn(SKM_Context.QueueSendMessage); for i=1,iQueueSize,1 do if (SKM_Context.QueueSendMessage[i].Priority < iMessagePriority) then table.insert(SKM_Context.QueueSendMessage, { Message = sMsg; Priority = iMessagePriority }, i); return; end end table.insert(SKM_Context.QueueSendMessage, { Message = sMsg; Priority = iMessagePriority } ); end function SkM_ProcessQueue() local FName = "SkM_ProcessQueue"; --local sDate = SkM_GetDate(); local sTime = GetTime(); local bProcess = false; if (SKM_Context.QueueLastSentMessage == nil) then bProcess = true; else local iDiffTime = sTime - SKM_Context.QueueLastSentMessage; --if (iDiffTime > SkM_GetOption("SendMessageMinDelay")) then if (iDiffTime > 1) then bProcess = true; end end if (bProcess) then local sMsg = SKM_Context.QueueSendMessage[1].Message; table.remove(SKM_Context.QueueSendMessage, 1); SkM_SendGuildChannelMessage(sMsg); SKM_Context.QueueLastSentMessage = sTime; end end function SkM_SendWarList() local FName = "SkM_SendWarList"; local idx, val; for idx, val in SKM_Data[_RealmName][_PlayerName].EnemyHistory do -- nchnch if (val[_SKM._atWar]) then -- local sMsg = SkM_AddGuildMessageToQueue(sMsg, 0); end end end -- TEST functions function SkM_CharCode(sIn) --local List = { }; local sOut = ""; local i; for i=1, string.len(sIn), 1 do --List.insert(string.byte(sIn, i)); sOut = sOut.."\\"; sOut = sOut..string.byte(sIn, i); end --return List; return sOut; end function SkM_TestHonor() local FName = "SkM_TestHonor"; local sMsg = "Gorwald dies, honorable kill Rank: First Sergeant (Estimated Honor Points: 67)"; for sFoe, sRank in string.gfind(sMsg, SKM_Context.Pattern.Honor_Kill) do if (sFoe and sRank) then SkM_Trace(FName, 0, "Honor_Kill : Foe = "..sFoe..", Rank = "..sRank); SkM_Trace(FName, 0, "Enemy player death detected (from chat, honor) : "..snil(sFoe)); --SkM_PvpEnemyDeath(sFoe, true, sRank); end end end function SkM_RecMapZones() local FName = "SkM_RecMapZones"; SkM_ClearDebugRecord(); SkM_SetDebugLevel(1); SkM_StartDebugRecord(); local lv_Continents = { GetMapContinents() } ; for idx, val in lv_Continents do SkM_Trace(FName, 1, "Continent "..idx.." = "..val); local lv_Zones = { GetMapZones(idx) }; for idx2, val2 in lv_Zones do SkM_Trace(FName, 1, "Cont. "..idx..", Zone "..idx2.." = "..val2); end end SkM_StopDebugRecord(); SkM_SetDebugLevel(-1); end function test() local FName = "test"; local idx, val; for idx, val in getfenv() do if (type(val) == "string" ) then SkM_Trace(FName, 0, idx.." = "..val); end end end -- OBSOLETE stuff