diff --git a/RelationshipsPVP.lua b/RelationshipsPVP.lua index 375852f..0282370 100644 --- a/RelationshipsPVP.lua +++ b/RelationshipsPVP.lua @@ -99,6 +99,11 @@ local function EnsureDB() -- { key = , value = } -- Persisted so a disconnect/relog mid-BG still resolves to a correct delta. db.honorSnap = db.honorSnap or nil + -- Enemy kill tracking (BGs only) + db.killedByAll = db.killedByAll or {} + db.lastMatchKilledBy = db.lastMatchKilledBy or {} + db.lastMatchKey = db.lastMatchKey or nil + db.currentMatch = db.currentMatch or nil for i = 1, table.getn(ALL_KEYS) do local k = ALL_KEYS[i] local s = db.stats[k] or NewStatBlock() @@ -157,7 +162,102 @@ local function OnCurrentBGChanged(prevKey, newKey) CaptureSpendableHonor(newKey) elseif prevKey and not newKey then FinalizeSpendableHonor(prevKey, true) + FinalizeMatchKillers() end + if newKey and newKey ~= prevKey then + -- Starting a fresh BG: clear any stale currentMatch that didn't belong to this key. + local db = RelationshipsPVPCharDB + if db and db.currentMatch and db.currentMatch.key ~= newKey then + FinalizeMatchKillers() + end + end +end + +--------------------------------------------------------------- +-- Enemy kill tracking (who kills you the most) +--------------------------------------------------------------- +local lastAttackerName = nil +local lastAttackerTime = 0 +local ATTACKER_WINDOW = 15 -- seconds a hostile hit counts as "the killer" + +-- Pull an attacker name out of a hostile combat log message. Handles: +-- "Name hits you for X." (melee) +-- "Name crits you for X." (melee crit) +-- "Name's Spell hits you for X Fire damage." (direct spell) +-- "You suffer X Shadow damage from Name's Curse of Agony." (periodic) +local function ExtractAttackerName(msg) + if not msg then return nil end + local n = string.gfind and nil -- unused; keep 1.12-safe + local from = string.find(msg, "from ") + if from then + local rest = string.sub(msg, from + 5) + local nm = string.gsub(rest, "'s.*$", "") + nm = string.gsub(nm, "%..*$", "") + nm = string.gsub(nm, "%s.*$", "") + if nm and nm ~= "" then return nm end + end + -- Fall back to the first token (attacker name, possibly with "'s") + local first = msg + local space = string.find(first, " ") + if space then first = string.sub(first, 1, space - 1) end + first = string.gsub(first, "'s$", "") + if first == "" then return nil end + -- Ignore garbage tokens that clearly aren't a player name. + if string.find(first, "^[%l]") then return nil end + if first == "You" or first == "you" then return nil end + return first +end + +local function NoteHostileHit(msg) + if not currentBG then return end + local name = ExtractAttackerName(msg) + if not name then return end + lastAttackerName = name + lastAttackerTime = GetTime() +end + +-- Called on PLAYER_DEAD while in a BG: credit the most recent hostile hit +-- as the killer. Only tracked for real battlegrounds (AV/WSG/AB), not arenas. +local function RegisterDeath() + if not currentBG then return end + if currentBG ~= "AV" and currentBG ~= "WSG" and currentBG ~= "AB" then return end + if not lastAttackerName then return end + if (GetTime() - lastAttackerTime) > ATTACKER_WINDOW then return end + local db = EnsureDB() + if not db.currentMatch or db.currentMatch.key ~= currentBG then + db.currentMatch = { key = currentBG, killedBy = {} } + end + local n = lastAttackerName + db.currentMatch.killedBy[n] = (db.currentMatch.killedBy[n] or 0) + 1 +end + +-- Called when we transition out of a BG: promote currentMatch tallies to +-- "last match" and roll them into the all-time KOS table. +local function FinalizeMatchKillers() + local db = RelationshipsPVPCharDB + if not db or not db.currentMatch then return end + local cm = db.currentMatch + local hasAny = false + local newLast = {} + for name, cnt in pairs(cm.killedBy or {}) do + newLast[name] = cnt + db.killedByAll[name] = (db.killedByAll[name] or 0) + cnt + hasAny = true + end + if hasAny then + db.lastMatchKilledBy = newLast + db.lastMatchKey = cm.key + end + db.currentMatch = nil +end + +local function TopKiller(tbl) + if not tbl then return nil, 0 end + local best, count = nil, 0 + for name, c in pairs(tbl) do + if c > count then best, count = name, c end + end + return best, count end -- Clamp a UIParent-relative CENTER offset so the button stays visible on screen. @@ -1051,6 +1151,32 @@ function RelationshipsPVP_Refresh() ) end + if RelationshipsPVPNemesisText then + local nm, cnt = TopKiller(db.lastMatchKilledBy) + if nm then + local bgTag = "" + if db.lastMatchKey and BG_NAMES[db.lastMatchKey] then + bgTag = " |cff888888(" .. BG_NAMES[db.lastMatchKey] .. ")|r" + end + RelationshipsPVPNemesisText:SetText( + "|cffff9966Last BG Nemesis:|r |cffffffff" .. nm .. "|r |cffff6666x" .. cnt .. "|r" .. bgTag + ) + else + RelationshipsPVPNemesisText:SetText("|cffff9966Last BG Nemesis:|r |cff888888none yet|r") + end + end + + if RelationshipsPVPKOSText then + local nm, cnt = TopKiller(db.killedByAll) + if nm then + RelationshipsPVPKOSText:SetText( + "|cffff3333KOS:|r |cffffffff" .. nm .. "|r |cffff6666x" .. cnt .. "|r" + ) + else + RelationshipsPVPKOSText:SetText("|cffff3333KOS:|r |cff888888none yet|r") + end + end + local qtext = FormatQueueLine() if currentBG then qtext = qtext .. "\n |cff66ff66Currently inside: " .. BG_NAMES[currentBG] .. "|r" @@ -1111,6 +1237,9 @@ function RelationshipsPVP_OnLoad() this:RegisterEvent("CHAT_MSG_COMBAT_HONOR_GAIN") this:RegisterEvent("PLAYER_PVP_KILLS_CHANGED") this:RegisterEvent("HONOR_CURRENCY_UPDATE") + this:RegisterEvent("CHAT_MSG_COMBAT_HOSTILEPLAYER_HITS") + this:RegisterEvent("CHAT_MSG_SPELL_HOSTILEPLAYER_DAMAGE") + this:RegisterEvent("CHAT_MSG_SPELL_PERIODIC_HOSTILEPLAYER_DAMAGE") SLASH_RELATIONSHIPSPVP1 = "/rpvp" SLASH_RELATIONSHIPSPVP2 = "/relpvp" @@ -1141,6 +1270,13 @@ function RelationshipsPVP_OnLoad() RelationshipsPVP_ResetPositions() elseif msg == "clear" or msg == "wipe" then RelationshipsPVP_ResetStats() + elseif msg == "clearkos" or msg == "kos" then + RelationshipsPVPCharDB.killedByAll = {} + RelationshipsPVPCharDB.lastMatchKilledBy = {} + RelationshipsPVPCharDB.lastMatchKey = nil + RelationshipsPVPCharDB.currentMatch = nil + Print("Enemy kill tracking cleared.") + RelationshipsPVP_Refresh() else if RelationshipsPVPFrame:IsVisible() then RelationshipsPVPFrame:Hide() @@ -1197,6 +1333,15 @@ function RelationshipsPVP_OnEvent(event) or event == "CHAT_MSG_BG_SYSTEM_HORDE" then RequestBattlefieldScoreData() + elseif event == "CHAT_MSG_COMBAT_HOSTILEPLAYER_HITS" + or event == "CHAT_MSG_SPELL_HOSTILEPLAYER_DAMAGE" + or event == "CHAT_MSG_SPELL_PERIODIC_HOSTILEPLAYER_DAMAGE" then + NoteHostileHit(arg1) + + elseif event == "PLAYER_DEAD" then + RegisterDeath() + RelationshipsPVP_Refresh() + elseif event == "CHAT_MSG_COMBAT_HONOR_GAIN" or event == "PLAYER_PVP_KILLS_CHANGED" or event == "HONOR_CURRENCY_UPDATE" then diff --git a/RelationshipsPVP.xml b/RelationshipsPVP.xml index 456693c..7542552 100644 --- a/RelationshipsPVP.xml +++ b/RelationshipsPVP.xml @@ -147,11 +147,25 @@ - + + + + + + + + + + + + + + +