Add files via upload

This commit is contained in:
Relationship
2026-07-10 09:44:50 +01:00
committed by GitHub
parent 16705f72ac
commit 77154b7b11
6 changed files with 141 additions and 93 deletions
+1 -1
View File
@@ -2,7 +2,7 @@
## Title: RelationshipsThreatPlates - OctoWoW ## Title: RelationshipsThreatPlates - OctoWoW
## Notes: OctoWoW-compatible RelationshipsThreatPlates ## Notes: OctoWoW-compatible RelationshipsThreatPlates
## Author: Packaged By Relationship ## Author: Packaged By Relationship
## Version: 1.2 ## Version: 1.3
## SavedVariables: RelationshipsThreatPlatesDB ## SavedVariables: RelationshipsThreatPlatesDB
## X-Website: https://github.com/Relationship-OctoWoW/RelationshipsThreatPlates ## X-Website: https://github.com/Relationship-OctoWoW/RelationshipsThreatPlates
## X-GitHub: https://github.com/Relationship-OctoWoW/RelationshipsThreatPlates ## X-GitHub: https://github.com/Relationship-OctoWoW/RelationshipsThreatPlates
+1 -1
View File
@@ -12,7 +12,7 @@ addon.MAJOR = 1
addon.MINOR = 1 addon.MINOR = 1
-- Version string -- Version string
TP_VERSION = "2.4.0" TP_VERSION = "2.5.0"
TP_ADDON_NAME = "RelationshipsThreatPlates" TP_ADDON_NAME = "RelationshipsThreatPlates"
-- ================================================================== -- ==================================================================
+30 -2
View File
@@ -44,6 +44,34 @@ local FONT_SIZE = 10
-- Widget references for refresh -- Widget references for refresh
local widgets = {} local widgets = {}
-- Only settings that change the visual STRUCTURE of a bar need a full
-- RecreateAll (which tears every bar down and re-attaches on the next
-- scan). Everything else — filters, modes, alpha, colours — just needs
-- a soft UpdateAll, which is far less likely to leave plates without
-- bars while pooled nameplate frames are hidden.
local NEEDS_RECREATE = {
barHeight = true,
barWidthScale= true,
barOffsetY = true,
barOffsetX = true,
glowEnabled = true,
glowAsShadow = true,
glowSize = true,
showSpark = true,
showFillBG = true,
showText = true,
fontOutline = true,
fontSize = true,
}
local function ApplySettingChange(configKey)
if NEEDS_RECREATE[configKey] then
addon.Nameplates:RecreateAll()
else
addon.Nameplates:UpdateAll()
end
end
-- ================================================================== -- ==================================================================
-- Helper: safely set backdrop on a frame -- Helper: safely set backdrop on a frame
-- ================================================================== -- ==================================================================
@@ -302,7 +330,7 @@ function addon.GUI:BuildSettings(parent)
else else
this.checkMark:Hide() this.checkMark:Hide()
end end
addon.Nameplates:RecreateAll() ApplySettingChange(configKey)
end) end)
local label = parent:CreateFontString(nil, "OVERLAY") local label = parent:CreateFontString(nil, "OVERLAY")
@@ -393,7 +421,7 @@ function addon.GUI:BuildSettings(parent)
else else
valText:SetText(math.floor(val + 0.5) .. suffix) valText:SetText(math.floor(val + 0.5) .. suffix)
end end
addon.Nameplates:RecreateAll() ApplySettingChange(configKey)
end) end)
y = y + 24 y = y + 24
+45 -31
View File
@@ -390,21 +390,24 @@ function addon.Nameplates:ScanForNameplates()
local nameplate = children[i] local nameplate = children[i]
if nameplate and not knownPlates[nameplate] then if nameplate and not knownPlates[nameplate] then
-- Quick visibility filter - don't scan invisible frames -- Only mark a plate as "known" once we have actually
-- attached a threat bar to it. Vanilla recycles nameplate
-- frames from a pool: a currently-invisible plate frame
-- can (and usually will) reappear later for another mob.
-- If we flagged it known while invisible, we would never
-- attach a bar when it became visible again — that is the
-- root cause of "plates stop appearing after changing a
-- setting" (RecreateAll clears knownPlates, then this
-- scan runs while some pooled plates are hidden).
if nameplate:IsVisible() then if nameplate:IsVisible() then
knownPlates[nameplate] = true
-- Check if this frame is a nameplate
local healthBar, nameText = self:IdentifyNameplate(nameplate) local healthBar, nameText = self:IdentifyNameplate(nameplate)
if healthBar then if healthBar then
knownPlates[nameplate] = true
self:AttachThreatBar(nameplate, healthBar, nameText) self:AttachThreatBar(nameplate, healthBar, nameText)
end end
else
-- Mark as known even if invisible; we'll handle
-- visibility in the update loop
knownPlates[nameplate] = true
end end
-- Invisible plates are intentionally left un-flagged so
-- the periodic scan will re-check them once they show.
end end
end end
end end
@@ -894,26 +897,34 @@ function addon.Nameplates:ApplyThreatToPlate(data, pct, situation)
data.container:Show() data.container:Show()
-- Smooth the percentage -- Preserve the RAW threat percent (may exceed 100 when the player
-- is the top threat holder and well ahead of the runner-up). The
-- text label shows this uncapped value so the user can see e.g.
-- "185%" for a tank comfortably holding threat. The bar fill
-- itself is clamped to 0-100 because the statusbar range is fixed.
local rawPct = pct or 0
-- Smooth the percentage (bar fill only — clamp to 0..100)
local oldPct = data.lastPct or 0 local oldPct = data.lastPct or 0
local barPct = math.min(100, math.max(0, rawPct))
local smoothPct local smoothPct
-- Snap instantly when jumping to full aggro (100%) or dropping to 0 -- Snap instantly when jumping to full aggro or dropping to 0
-- (mob switched target). Smooth intermediate transitions moderately. -- (mob switched target). Smooth intermediate transitions moderately.
if pct == 0 or pct >= 99.5 or math.abs(pct - oldPct) > 40 then if barPct == 0 or barPct >= 99.5 or math.abs(barPct - oldPct) > 40 then
smoothPct = pct smoothPct = barPct
else else
smoothPct = oldPct + (pct - oldPct) * 0.6 smoothPct = oldPct + (barPct - oldPct) * 0.6
end end
data.lastPct = smoothPct data.lastPct = smoothPct
smoothPct = math.min(100, math.max(0, smoothPct)) smoothPct = math.min(100, math.max(0, smoothPct))
pct = math.min(100, math.max(0, pct))
-- Update bar value -- Update bar value (0-100 range)
data.bar:SetValue(smoothPct) data.bar:SetValue(smoothPct)
-- Update bar colour (smooth gradient) -- Update bar colour (smooth gradient) — driven by barPct so colours
local r, g, b = addon.Media.GetThreatColour(pct) -- top out at aggro red even if rawPct exceeds 100.
local r, g, b = addon.Media.GetThreatColour(barPct)
data.bar:SetStatusBarColor(r, g, b, RelationshipsThreatPlatesDB.barAlpha or 1) data.bar:SetStatusBarColor(r, g, b, RelationshipsThreatPlatesDB.barAlpha or 1)
-- Update statusbar texture vertex colour -- Update statusbar texture vertex colour
@@ -948,7 +959,7 @@ function addon.Nameplates:ApplyThreatToPlate(data, pct, situation)
end end
end end
-- Update text -- Update text — uses rawPct so values above 100% are shown as-is.
if data.text then if data.text then
local textStr local textStr
if RelationshipsThreatPlatesDB.tankMode and data.plateName then if RelationshipsThreatPlatesDB.tankMode and data.plateName then
@@ -958,26 +969,29 @@ function addon.Nameplates:ApplyThreatToPlate(data, pct, situation)
textStr = addon.Threat:GetTankDisplayForMob(data.plateName) textStr = addon.Threat:GetTankDisplayForMob(data.plateName)
if not textStr or textStr == "--" then if not textStr or textStr == "--" then
-- Fall back to % when no absolute values are available. -- Fall back to % when no absolute values are available.
textStr = math.floor(pct + 0.5) .. "%" textStr = math.floor(rawPct + 0.5) .. "%"
end end
else else
textStr = math.floor(pct + 0.5) .. "%" textStr = math.floor(rawPct + 0.5) .. "%"
end end
data.text:SetText(textStr) data.text:SetText(textStr)
if pct >= 90 then if rawPct >= 100 then
-- Aggro / over-aggro: bright red text so the top holder
-- stands out even when the bar itself is pegged at full.
data.text:SetTextColor(1, 0.2, 0.2, 1) data.text:SetTextColor(1, 0.2, 0.2, 1)
elseif pct >= 60 then elseif rawPct >= 60 then
data.text:SetTextColor(1, 0.9, 0.8, 1) data.text:SetTextColor(1, 0.9, 0.8, 1)
else else
data.text:SetTextColor(1, 1, 1, 1) data.text:SetTextColor(1, 1, 1, 1)
end end
end end
-- Update threat glow -- Update threat glow (drive by clamped barPct so it caps at max intensity)
if data.threatGlow then if data.threatGlow then
if pct >= 80 then if barPct >= 80 then
local intensity = (pct - 80) / 20 local intensity = (barPct - 80) / 20
if intensity > 1 then intensity = 1 end
data.threatGlow:SetVertexColor(0.9, 0, 0, 0.6 * intensity) data.threatGlow:SetVertexColor(0.9, 0, 0, 0.6 * intensity)
data.threatGlow:Show() data.threatGlow:Show()
else else
@@ -1213,7 +1227,7 @@ function addon.Nameplates:UpdateAllPlates()
-- If a group member is in combat, show a default -- If a group member is in combat, show a default
-- threat bar. The mob is fighting someone. -- threat bar. The mob is fighting someone.
if groupInCombat then if groupInCombat then
self:ApplyThreatToPlate(data, 100, 3) self:ApplyThreatToPlate(data, 20, 0) -- was 100,3: showing full aggro for any party-combat mob with no threat data was misleading
else else
data.container:Hide() data.container:Hide()
end end
@@ -1232,7 +1246,7 @@ function addon.Nameplates:UpdateAllPlates()
if pct > 0 then if pct > 0 then
self:ApplyThreatToPlate(data, pct, sit or 0) self:ApplyThreatToPlate(data, pct, sit or 0)
else else
self:ApplyThreatToPlate(data, 100, 3) self:ApplyThreatToPlate(data, 20, 0) -- was 100,3: showing full aggro for any party-combat mob with no threat data was misleading
end end
else else
-- Grace period expired and health still at 100%. -- Grace period expired and health still at 100%.
@@ -1265,7 +1279,7 @@ function addon.Nameplates:UpdateAllPlates()
if not data.combatDetectedAt then if not data.combatDetectedAt then
data.combatDetectedAt = now data.combatDetectedAt = now
end end
self:ApplyThreatToPlate(data, 100, 3) self:ApplyThreatToPlate(data, 20, 0) -- was 100,3: showing full aggro for any party-combat mob with no threat data was misleading
else else
-- Can't confirm mob is attacking anyone. -- Can't confirm mob is attacking anyone.
-- It might be idle. Don't show bar. -- It might be idle. Don't show bar.
@@ -1307,7 +1321,7 @@ function addon.Nameplates:UpdateAllPlates()
-- In combat but no threat data — mob is being -- In combat but no threat data — mob is being
-- attacked by someone we can't track. -- attacked by someone we can't track.
if groupInCombat then if groupInCombat then
self:ApplyThreatToPlate(data, 100, 3) self:ApplyThreatToPlate(data, 20, 0) -- was 100,3: showing full aggro for any party-combat mob with no threat data was misleading
else else
data.container:Hide() data.container:Hide()
end end
@@ -1316,7 +1330,7 @@ function addon.Nameplates:UpdateAllPlates()
-- In combat (health dropping) but no ThreatEngine data. -- In combat (health dropping) but no ThreatEngine data.
-- Show default high-threat bar. -- Show default high-threat bar.
if groupInCombat then if groupInCombat then
self:ApplyThreatToPlate(data, 100, 3) self:ApplyThreatToPlate(data, 20, 0) -- was 100,3: showing full aggro for any party-combat mob with no threat data was misleading
else else
data.container:Hide() data.container:Hide()
end end
+39 -56
View File
@@ -420,61 +420,33 @@ function addon.Threat:GetThreatPercent(unit)
-- If the mob is targeting an outsider -> show player's threat -- If the mob is targeting an outsider -> show player's threat
-- Otherwise -> show the best (highest) threat from any member -- Otherwise -> show the best (highest) threat from any member
-- The threat bar on a nameplate is always displayed from the
-- PLAYER's point of view: "how close am I to pulling aggro
-- off whoever currently has it?". Showing another group
-- member's percentage would incorrectly make every mob a
-- party member is tanking read as 100% — that is the bug
-- users describe as "snap causes all party-combat enemies
-- to show 100%". So: always return the player's own value
-- here. If the player has no threat on this mob, return 0
-- so the bar hides.
if mobTargetName == playerName then if mobTargetName == playerName then
-- Mob is attacking the player - show player's own threat -- Mob is attacking the player - show player's own threat
return playerPct, playerSit return playerPct, playerSit
elseif mobTargetName and partyNames[mobTargetName] then elseif mobTargetName and partyNames[mobTargetName] then
-- Mob is attacking a group member - show that member's threat -- Mob is attacking a group member. Show the player's
-- Look up that member's threat from the group scan -- own relative threat, not the party member's.
local memberUnit = partyNames[mobTargetName]
local memberPct = nil
local memberSit = nil
if hasUnitDetailedThreatSituation then
local _, status, _, rawPct = SafeCall5(UnitDetailedThreatSituation, memberUnit, unit)
if rawPct then
memberPct = math.min(100, math.max(0, rawPct))
memberSit = status or 0
end
end
if not memberPct and hasGetThreatPercent then
local pct = SafeCall2(GetThreatPercent, memberUnit, unit)
if pct then
memberPct = math.min(100, math.max(0, pct))
if hasUnitThreatSituation then
memberSit = SafeCall2(UnitThreatSituation, memberUnit, unit) or 0
else
if memberPct >= 100 then memberSit = 3
elseif memberPct >= 60 then memberSit = 2
elseif memberPct >= 30 then memberSit = 1
else memberSit = 0 end
end
end
end
if not memberPct and hasUnitThreatSituation then
memberSit = SafeCall2(UnitThreatSituation, memberUnit, unit) or 0
if memberSit == 0 then memberPct = 0
elseif memberSit == 1 then memberPct = 25
elseif memberSit == 2 then memberPct = 60
elseif memberSit == 3 then memberPct = 100 end
end
if memberPct then
return memberPct, memberSit or 0
end
-- Fallback: can't get specific member data, use best
return bestPct, bestSit
else
-- Mob targets an outsider, or we can't see its target.
-- Show player's threat if they have any, otherwise the
-- best group threat.
if playerPct > 0 then if playerPct > 0 then
return playerPct, playerSit return playerPct, playerSit
end end
return bestPct, bestSit return 0, 0
else
-- Mob targets an outsider, or we can't see its target.
-- Show player's own threat only.
if playerPct > 0 then
return playerPct, playerSit
end
return 0, 0
end end
end end
@@ -600,13 +572,18 @@ function addon.Threat:GetThreatPercent(unit)
threatPct = 100 threatPct = 100
situation = 3 situation = 3
elseif partyNames[mobTargetName] then elseif partyNames[mobTargetName] then
-- Mob is targeting a PARTY/RAID member. -- Mob is targeting a PARTY/RAID member. The party member
-- That member has aggro - show high threat. -- has aggro, NOT the player. Showing 100% here would
-- This is the KEY fix: previously showed only 60%/30% -- incorrectly light every mob in party combat up as full
-- for mobs targeting group members. Now shows 100% -- aggro on the player. Show a low estimate instead — the
-- because that group member IS the one being attacked. -- player is not in the aggro seat.
threatPct = 100 if UnitIsUnit("target", unit) then
situation = 3 threatPct = 20
situation = 0
else
threatPct = 0
situation = 0
end
else else
-- Mob is targeting someone outside the party -- Mob is targeting someone outside the party
-- (another player, a pet, etc.) -- (another player, a pet, etc.)
@@ -663,7 +640,13 @@ function addon.Threat:UpdateUnitThreat(unit)
and mobTargetName and playerName and mobTargetName == playerName then and mobTargetName and playerName and mobTargetName == playerName then
local ok_pc, pc = pcall(UnitAffectingCombat, "player") local ok_pc, pc = pcall(UnitAffectingCombat, "player")
if ok_pc and pc then if ok_pc and pc then
pct = 100 -- Player is being targeted, so they have aggro. Force
-- pct to at least 100 without clobbering a real value
-- above 100 (which happens when the player is top and
-- well ahead of the second-highest threat holder).
if not pct or pct < 100 then
pct = 100
end
situation = 3 situation = 3
targetSnapped = true targetSnapped = true
end end
+25 -2
View File
@@ -1298,8 +1298,31 @@ function addon.ThreatEngine:GetThreatOnTarget(mobName)
return 0, 0, 0, 0, false, nil, 0 return 0, 0, 0, 0, false, nil, 0
end end
-- Calculate the player's percentage relative to top threat -- Calculate the player's threat percentage.
local pct = (playerThreat / topThreat) * 100 --
-- Two-mode display so the number matches user intuition:
-- * If the player IS the current top-threat holder, show how far
-- ahead they are of the runner-up: pct = playerThreat/second * 100.
-- A tank comfortably tanking a mob will read something like 120%
-- or 200% — anything > 100 means "you are above the next player".
-- * If the player is NOT top, show their share of the top holder's
-- threat: pct = playerThreat/top * 100. This is 0-100 and answers
-- "how close am I to pulling aggro off the current top holder".
--
-- This lets the plate show > 100% for the actual threat leader
-- instead of clamping everyone with aggro to a flat 100%.
local pct
if topPlayer == playerName then
if secondThreat > 0 then
pct = (playerThreat / secondThreat) * 100
else
pct = 100
end
if pct < 100 then pct = 100 end -- safety: top holder never below 100
else
pct = (playerThreat / topThreat) * 100
if pct > 100 then pct = 100 end -- non-top can't exceed the leader
end
-- Determine threat situation based on the player's threat -- Determine threat situation based on the player's threat
local sit = 0 local sit = 0