Add files via upload
This commit is contained in:
@@ -99,6 +99,11 @@ local function EnsureDB()
|
|||||||
-- { key = <BG_KEY>, value = <spendable honor when we entered> }
|
-- { key = <BG_KEY>, value = <spendable honor when we entered> }
|
||||||
-- Persisted so a disconnect/relog mid-BG still resolves to a correct delta.
|
-- Persisted so a disconnect/relog mid-BG still resolves to a correct delta.
|
||||||
db.honorSnap = db.honorSnap or nil
|
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
|
for i = 1, table.getn(ALL_KEYS) do
|
||||||
local k = ALL_KEYS[i]
|
local k = ALL_KEYS[i]
|
||||||
local s = db.stats[k] or NewStatBlock()
|
local s = db.stats[k] or NewStatBlock()
|
||||||
@@ -157,7 +162,102 @@ local function OnCurrentBGChanged(prevKey, newKey)
|
|||||||
CaptureSpendableHonor(newKey)
|
CaptureSpendableHonor(newKey)
|
||||||
elseif prevKey and not newKey then
|
elseif prevKey and not newKey then
|
||||||
FinalizeSpendableHonor(prevKey, true)
|
FinalizeSpendableHonor(prevKey, true)
|
||||||
|
FinalizeMatchKillers()
|
||||||
end
|
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
|
end
|
||||||
|
|
||||||
-- Clamp a UIParent-relative CENTER offset so the button stays visible on screen.
|
-- Clamp a UIParent-relative CENTER offset so the button stays visible on screen.
|
||||||
@@ -1051,6 +1151,32 @@ function RelationshipsPVP_Refresh()
|
|||||||
)
|
)
|
||||||
end
|
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()
|
local qtext = FormatQueueLine()
|
||||||
if currentBG then
|
if currentBG then
|
||||||
qtext = qtext .. "\n |cff66ff66Currently inside: " .. BG_NAMES[currentBG] .. "|r"
|
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("CHAT_MSG_COMBAT_HONOR_GAIN")
|
||||||
this:RegisterEvent("PLAYER_PVP_KILLS_CHANGED")
|
this:RegisterEvent("PLAYER_PVP_KILLS_CHANGED")
|
||||||
this:RegisterEvent("HONOR_CURRENCY_UPDATE")
|
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_RELATIONSHIPSPVP1 = "/rpvp"
|
||||||
SLASH_RELATIONSHIPSPVP2 = "/relpvp"
|
SLASH_RELATIONSHIPSPVP2 = "/relpvp"
|
||||||
@@ -1141,6 +1270,13 @@ function RelationshipsPVP_OnLoad()
|
|||||||
RelationshipsPVP_ResetPositions()
|
RelationshipsPVP_ResetPositions()
|
||||||
elseif msg == "clear" or msg == "wipe" then
|
elseif msg == "clear" or msg == "wipe" then
|
||||||
RelationshipsPVP_ResetStats()
|
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
|
else
|
||||||
if RelationshipsPVPFrame:IsVisible() then
|
if RelationshipsPVPFrame:IsVisible() then
|
||||||
RelationshipsPVPFrame:Hide()
|
RelationshipsPVPFrame:Hide()
|
||||||
@@ -1197,6 +1333,15 @@ function RelationshipsPVP_OnEvent(event)
|
|||||||
or event == "CHAT_MSG_BG_SYSTEM_HORDE" then
|
or event == "CHAT_MSG_BG_SYSTEM_HORDE" then
|
||||||
RequestBattlefieldScoreData()
|
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"
|
elseif event == "CHAT_MSG_COMBAT_HONOR_GAIN"
|
||||||
or event == "PLAYER_PVP_KILLS_CHANGED"
|
or event == "PLAYER_PVP_KILLS_CHANGED"
|
||||||
or event == "HONOR_CURRENCY_UPDATE" then
|
or event == "HONOR_CURRENCY_UPDATE" then
|
||||||
|
|||||||
+15
-1
@@ -147,11 +147,25 @@
|
|||||||
</Texture>
|
</Texture>
|
||||||
|
|
||||||
<FontString name="RelationshipsPVPExtrasText" inherits="GameFontHighlightSmall" justifyH="LEFT">
|
<FontString name="RelationshipsPVPExtrasText" inherits="GameFontHighlightSmall" justifyH="LEFT">
|
||||||
<Size><AbsDimension x="846" y="16"/></Size>
|
<Size><AbsDimension x="640" y="16"/></Size>
|
||||||
<Anchors>
|
<Anchors>
|
||||||
<Anchor point="BOTTOMLEFT"><Offset><AbsDimension x="14" y="10"/></Offset></Anchor>
|
<Anchor point="BOTTOMLEFT"><Offset><AbsDimension x="14" y="10"/></Offset></Anchor>
|
||||||
</Anchors>
|
</Anchors>
|
||||||
</FontString>
|
</FontString>
|
||||||
|
|
||||||
|
<FontString name="RelationshipsPVPNemesisText" inherits="GameFontHighlightSmall" justifyH="CENTER">
|
||||||
|
<Size><AbsDimension x="200" y="16"/></Size>
|
||||||
|
<Anchors>
|
||||||
|
<Anchor point="BOTTOM"><Offset><AbsDimension x="220" y="10"/></Offset></Anchor>
|
||||||
|
</Anchors>
|
||||||
|
</FontString>
|
||||||
|
|
||||||
|
<FontString name="RelationshipsPVPKOSText" inherits="GameFontHighlightSmall" justifyH="RIGHT">
|
||||||
|
<Size><AbsDimension x="80" y="16"/></Size>
|
||||||
|
<Anchors>
|
||||||
|
<Anchor point="BOTTOMRIGHT"><Offset><AbsDimension x="-14" y="10"/></Offset></Anchor>
|
||||||
|
</Anchors>
|
||||||
|
</FontString>
|
||||||
</Layer>
|
</Layer>
|
||||||
</Layers>
|
</Layers>
|
||||||
</Frame>
|
</Frame>
|
||||||
|
|||||||
Reference in New Issue
Block a user