2 Commits

Author SHA1 Message Date
Relationship 16705f72ac Add files via upload 2026-07-08 18:24:21 +01:00
Relationship d0a77fe622 Update RelationshipsThreatPlates.toc 2026-07-04 03:37:43 +01:00
6 changed files with 195 additions and 17 deletions
+1 -1
View File
@@ -2,7 +2,7 @@
## Title: RelationshipsThreatPlates - OctoWoW
## Notes: OctoWoW-compatible RelationshipsThreatPlates
## Author: Packaged By Relationship
## Version: 1.0
## Version: 1.2
## SavedVariables: RelationshipsThreatPlatesDB
## X-Website: https://github.com/Relationship-OctoWoW/RelationshipsThreatPlates
## X-GitHub: https://github.com/Relationship-OctoWoW/RelationshipsThreatPlates
+4 -2
View File
@@ -12,7 +12,7 @@ addon.MAJOR = 1
addon.MINOR = 1
-- Version string
TP_VERSION = "2.3.1"
TP_VERSION = "2.4.0"
TP_ADDON_NAME = "RelationshipsThreatPlates"
-- ==================================================================
@@ -21,9 +21,11 @@ TP_ADDON_NAME = "RelationshipsThreatPlates"
local DEFAULT_CONFIG = {
enabled = true,
showText = true,
tankMode = false,
targetSnap100 = true,
barHeight = 6,
barAlpha = 0.5,
barOffsetY = 20,
barOffsetY = 24,
barOffsetX = -17.8,
barWidthScale = 0.8,
fontSize = 9,
+45 -3
View File
@@ -341,7 +341,7 @@ function addon.GUI:BuildSettings(parent)
local slider = CreateFrame("Slider", "RelationshipsThreatPlatesSlider_" .. configKey, parent, "OptionsSliderTemplate")
slider:SetWidth(W - 60)
slider:SetHeight(16)
slider:SetHeight(10)
slider:SetPoint("TOPLEFT", parent, "TOPLEFT", MARGIN, -y)
slider:SetOrientation("HORIZONTAL")
slider:SetMinMaxValues(minVal, maxVal)
@@ -364,6 +364,8 @@ function addon.GUI:BuildSettings(parent)
if thumbTexture then
thumbTexture:SetTexture(C.SOLID)
thumbTexture:SetVertexColor(unpack(C.ACCENT))
thumbTexture:SetWidth(8)
thumbTexture:SetHeight(14)
end
local lowText = getglobal(sliderName .. "Low")
@@ -403,7 +405,9 @@ function addon.GUI:BuildSettings(parent)
-- ==============================================================
SectionLabel("General")
CheckBox("Enable Threat Plates", "enabled", "Show threat bars above nameplates")
CheckBox("Show Threat Text", "showText", "Display percentage in the bar")
CheckBox("Show Threat Text", "showText", "Display value in the bar")
CheckBox("Tank Mode", "tankMode", "Show raw threat lead over 2nd place instead of %")
CheckBox("Snap to 100% when Targeted", "targetSnap100", "Force 100% while a mob is focused on you")
CheckBox("Smooth Colours", "smoothColors", "Gradient colour transition")
-- ==============================================================
@@ -412,7 +416,7 @@ function addon.GUI:BuildSettings(parent)
SectionLabel("Appearance")
Slider("Bar Height", "barHeight", 2, 20, 1, "px")
Slider("Bar Width Scale", "barWidthScale", 0.3, 1.0, 0.05, "")
Slider("Bar Offset Y", "barOffsetY", 0, 20, 1, "px")
Slider("Bar Offset Y", "barOffsetY", 0, 50, 1, "px")
Slider("Bar Offset X", "barOffsetX", -50, 50, 0.1, "px")
Slider("Bar Alpha", "barAlpha", 0.1, 1.0, 0.1, "")
Slider("Font Size", "fontSize", 6, 16, 1, "pt")
@@ -437,6 +441,44 @@ function addon.GUI:BuildSettings(parent)
CheckBox("Show on Neutral", "showOnNeutral", "Show threat bars on neutral units")
CheckBox("Show on Friendly", "showOnFriendly", "Show threat bars on friendly units")
-- ==============================================================
-- Reset button at bottom
-- ==============================================================
y = y + 10
local resetBtn = CreateFrame("Button", nil, parent)
resetBtn:SetWidth(W - MARGIN * 2)
resetBtn:SetHeight(22)
resetBtn:SetPoint("TOPLEFT", parent, "TOPLEFT", MARGIN, -y)
SafeSetBackdrop(resetBtn, {
bgFile = C.SOLID,
edgeFile = C.SOLID,
tile = false, tileSize = 0,
edgeSize = 1,
})
resetBtn:SetBackdropColor(unpack(C.BUTTON_BG))
resetBtn:SetBackdropBorderColor(unpack(C.BORDER))
local resetText = resetBtn:CreateFontString(nil, "OVERLAY")
resetText:SetFont(FONT_NORMAL, FONT_SIZE, "OUTLINE")
resetText:SetPoint("CENTER", resetBtn, "CENTER", 0, 0)
resetText:SetTextColor(unpack(C.BUTTON_TEXT))
resetText:SetText("Reset to Defaults")
resetBtn:SetFontString(resetText)
resetBtn:SetScript("OnEnter", function()
this:SetBackdropColor(unpack(C.BUTTON_HOVER))
end)
resetBtn:SetScript("OnLeave", function()
this:SetBackdropColor(unpack(C.BUTTON_BG))
end)
resetBtn:SetScript("OnClick", function()
SlashCmdList["THREATPLATES"]("reset")
if addon.Nameplates and addon.Nameplates.RecreateAll then
addon.Nameplates:RecreateAll()
end
end)
y = y + 22 + 8
-- Return total content height for scroll setup
return y
end
+19 -5
View File
@@ -897,10 +897,12 @@ function addon.Nameplates:ApplyThreatToPlate(data, pct, situation)
-- Smooth the percentage
local oldPct = data.lastPct or 0
local smoothPct
if pct == 0 then
smoothPct = 0
-- Snap instantly when jumping to full aggro (100%) or dropping to 0
-- (mob switched target). Smooth intermediate transitions moderately.
if pct == 0 or pct >= 99.5 or math.abs(pct - oldPct) > 40 then
smoothPct = pct
else
smoothPct = oldPct + (pct - oldPct) * 0.3
smoothPct = oldPct + (pct - oldPct) * 0.6
end
data.lastPct = smoothPct
@@ -948,8 +950,20 @@ function addon.Nameplates:ApplyThreatToPlate(data, pct, situation)
-- Update text
if data.text then
local displayPct = math.floor(pct + 0.5)
data.text:SetText(displayPct .. "%")
local textStr
if RelationshipsThreatPlatesDB.tankMode and data.plateName then
-- Tank mode: show raw threat lead over the 2nd-highest player
-- (positive = you have that much lead as top-threat holder;
-- negative = you're that much behind the current top).
textStr = addon.Threat:GetTankDisplayForMob(data.plateName)
if not textStr or textStr == "--" then
-- Fall back to % when no absolute values are available.
textStr = math.floor(pct + 0.5) .. "%"
end
else
textStr = math.floor(pct + 0.5) .. "%"
end
data.text:SetText(textStr)
if pct >= 90 then
data.text:SetTextColor(1, 0.2, 0.2, 1)
+117 -1
View File
@@ -57,7 +57,11 @@ local partyNames = {}
local partyUnits = {}
-- Update throttle (seconds)
local THROTTLE = 0.2
local THROTTLE = 0.1
-- Cache of per-mob tank-mode details, keyed by mob UID (name in vanilla).
-- Populated by UpdateUnitThreat via ThreatEngine, and read by the Nameplates
-- module when rendering the tank-mode text (raw threat lead).
local tankDetailsCache = {}
-- ==================================================================
-- Safe API call helpers
@@ -647,12 +651,54 @@ function addon.Threat:UpdateUnitThreat(unit)
mobTargetName = mt
end
-- ------------------------------------------------------------
-- TARGET-SNAP override: if the mob is currently targeting the
-- player, force display to 100% (aggro). Some mobs pick focused
-- / random targets regardless of threat, so the plate should
-- immediately snap to 100% while targeted, and fall back to the
-- real threat % when the mob switches targets.
-- ------------------------------------------------------------
local targetSnapped = false
if RelationshipsThreatPlatesDB and RelationshipsThreatPlatesDB.targetSnap100
and mobTargetName and playerName and mobTargetName == playerName then
local ok_pc, pc = pcall(UnitAffectingCombat, "player")
if ok_pc and pc then
pct = 100
situation = 3
targetSnapped = true
end
end
-- ------------------------------------------------------------
-- Compute raw tank-mode details (player threat vs 2nd highest).
-- Uses ThreatEngine's combat-log-parsed absolute values when
-- available. This is what the nameplate renders in Tank Mode.
-- ------------------------------------------------------------
local ok_mn, mobName = pcall(UnitName, unit)
if ok_mn and mobName then
local ePct, eSit, ePlayerThreat, eTopThreat, eHasGroup, eTopPlayer, eSecondThreat =
addon.ThreatEngine:GetThreatOnTarget(mobName)
tankDetailsCache[uid] = {
playerThreat = ePlayerThreat or 0,
topThreat = eTopThreat or 0,
secondThreat = eSecondThreat or 0,
topPlayer = eTopPlayer,
hasAggro = (eTopPlayer == playerName) or targetSnapped,
hasGroupData = eHasGroup or false,
targetSnapped = targetSnapped,
mobTargetName = mobTargetName,
lastUpdate = GetTime(),
}
end
threatCache[uid] = {
pct = pct,
situation = situation,
unit = unit,
lastUpdate = GetTime(),
mobTargetName = mobTargetName,
targetSnapped = targetSnapped,
}
-- Also store in group threat cache for cross-reference
@@ -681,6 +727,76 @@ function addon.Threat:GetCachedThreat(uid)
return 0, 0
end
-- ==================================================================
-- Tank-mode details for a mob (by UID / name in vanilla).
-- Returns a table (or nil) with:
-- playerThreat, topThreat, secondThreat, topPlayer,
-- hasAggro, hasGroupData, targetSnapped, mobTargetName
-- ==================================================================
function addon.Threat:GetTankDetails(uid)
if not uid then return nil end
local d = tankDetailsCache[uid]
if not d then return nil end
if GetTime() - d.lastUpdate > 5 then return nil end
return d
end
-- ==================================================================
-- Format a raw threat value as a compact signed string.
-- Examples: 12345 -> "+12.3K", -845 -> "-845", 0 -> "0"
-- ==================================================================
function addon.Threat:FormatThreatLead(v)
if not v then return "--" end
local a = math.abs(v)
local sign = ""
if v > 0 then sign = "+" elseif v < 0 then sign = "-" end
if a >= 100000 then
return sign .. string.format("%.0fK", a / 1000)
elseif a >= 10000 then
return sign .. string.format("%.1fK", a / 1000)
elseif a >= 1000 then
return sign .. string.format("%.2fK", a / 1000)
else
return sign .. string.format("%d", a)
end
end
-- ==================================================================
-- Return the display string for tank mode given a plate's mob name.
-- Uses the ThreatEngine directly (works even without a unit token,
-- e.g. for unique-name plates).
-- Returns: string like "+1.20K" or "-450", or "--" if unknown.
-- ==================================================================
function addon.Threat:GetTankDisplayForMob(mobName)
if not mobName then return "--" end
local d = tankDetailsCache[mobName]
if not d or (GetTime() - d.lastUpdate > 5) then
-- Query ThreatEngine on demand (no cache hit).
local _, _, playerThreat, topThreat, _, topPlayer, secondThreat =
addon.ThreatEngine:GetThreatOnTarget(mobName)
if not playerThreat or playerThreat <= 0 then
return "--"
end
local lead
if topPlayer == playerName then
lead = playerThreat - (secondThreat or 0)
else
lead = playerThreat - (topThreat or 0)
end
return self:FormatThreatLead(lead)
end
if d.playerThreat <= 0 then return "--" end
local lead
if d.hasAggro then
lead = d.playerThreat - (d.secondThreat or 0)
else
lead = d.playerThreat - (d.topThreat or 0)
end
return self:FormatThreatLead(lead)
end
-- ==================================================================
-- Get threat percentage by mob NAME (no unit token required)
-- This is the fallback for when FindUnitByName couldn't resolve
+9 -5
View File
@@ -1268,30 +1268,34 @@ end
-- ============================================================
function addon.ThreatEngine:GetThreatOnTarget(mobName)
if not mobName then return 0, 0, 0, 0, false, nil end
if not mobName then return 0, 0, 0, 0, false, nil, 0 end
-- Check if we have threat data for this mob
local mobThreat = threatData[mobName]
if not mobThreat then
return 0, 0, 0, 0, false, nil
return 0, 0, 0, 0, false, nil, 0
end
-- Find player's threat and top threat
-- Find player's threat, top threat and second-highest threat
local playerThreat = mobThreat[playerName] or 0
local topThreat = 0
local topPlayer = nil
local secondThreat = 0
local sourceCount = 0
for source, value in pairs(mobThreat) do
sourceCount = sourceCount + 1
if value > topThreat then
secondThreat = topThreat
topThreat = value
topPlayer = source
elseif value > secondThreat then
secondThreat = value
end
end
if topThreat <= 0 then
return 0, 0, 0, 0, false, nil
return 0, 0, 0, 0, false, nil, 0
end
-- Calculate the player's percentage relative to top threat
@@ -1314,7 +1318,7 @@ function addon.ThreatEngine:GetThreatOnTarget(mobName)
-- (via addon communication or party combat log parsing).
local hasGroupData = (sourceCount > 1)
return pct, sit, playerThreat, topThreat, hasGroupData, topPlayer
return pct, sit, playerThreat, topThreat, hasGroupData, topPlayer, secondThreat
end
-- ============================================================