Add files via upload

This commit is contained in:
Wurmschwanz
2026-10-02 01:19:39 +02:00
committed by GitHub
parent 6dc73952d8
commit 46eb343ff7
5 changed files with 4931 additions and 42 deletions
+44 -2
View File
@@ -82,9 +82,14 @@ BNP.defaults = BNP.defaults or {
personalNameplate = false,
personalNameplateCombatOnly = true,
personalNameplateClassColor = false,
personalNameplateHideLevel = false,
personalNameplateHealthText = "both",
personalNameplateDebuffs = false,
personalNameplateBuffs = false,
personalNameplateDebuffYOffset = 0,
personalNameplateBuffYOffset = 0,
personalNameplateDebuffXOffset = 0,
personalNameplateBuffXOffset = 0,
personalNameplateScale = 1.0,
personalNameplateYOffset = -90,
}
@@ -247,9 +252,14 @@ function BNP:InitConfig()
if BNP_DB.personalNameplate == nil then BNP_DB.personalNameplate = self.defaults.personalNameplate end
if BNP_DB.personalNameplateCombatOnly == nil then BNP_DB.personalNameplateCombatOnly = self.defaults.personalNameplateCombatOnly end
if BNP_DB.personalNameplateClassColor == nil then BNP_DB.personalNameplateClassColor = self.defaults.personalNameplateClassColor end
if BNP_DB.personalNameplateHideLevel == nil then BNP_DB.personalNameplateHideLevel = self.defaults.personalNameplateHideLevel end
if BNP_DB.personalNameplateHealthText == nil then BNP_DB.personalNameplateHealthText = self.defaults.personalNameplateHealthText end
if BNP_DB.personalNameplateDebuffs == nil then BNP_DB.personalNameplateDebuffs = self.defaults.personalNameplateDebuffs end
if BNP_DB.personalNameplateBuffs == nil then BNP_DB.personalNameplateBuffs = self.defaults.personalNameplateBuffs end
if BNP_DB.personalNameplateDebuffYOffset == nil then BNP_DB.personalNameplateDebuffYOffset = self.defaults.personalNameplateDebuffYOffset end
if BNP_DB.personalNameplateBuffYOffset == nil then BNP_DB.personalNameplateBuffYOffset = self.defaults.personalNameplateBuffYOffset end
if BNP_DB.personalNameplateDebuffXOffset == nil then BNP_DB.personalNameplateDebuffXOffset = self.defaults.personalNameplateDebuffXOffset end
if BNP_DB.personalNameplateBuffXOffset == nil then BNP_DB.personalNameplateBuffXOffset = self.defaults.personalNameplateBuffXOffset end
if BNP_DB.personalNameplateScale == nil then BNP_DB.personalNameplateScale = self.defaults.personalNameplateScale end
if BNP_DB.personalNameplateYOffset == nil then BNP_DB.personalNameplateYOffset = self.defaults.personalNameplateYOffset end
end
@@ -728,6 +738,10 @@ function BNP:IsPersonalNameplateClassColorEnabled()
return BNP_DB and BNP_DB.personalNameplateClassColor == true
end
function BNP:IsPersonalNameplateLevelHidden()
return BNP_DB and BNP_DB.personalNameplateHideLevel == true
end
function BNP:GetPersonalNameplateHealthTextMode()
local mode = (BNP_DB and BNP_DB.personalNameplateHealthText) or self.defaults.personalNameplateHealthText or "both"
if mode ~= "off" and mode ~= "percent" and mode ~= "hp" and mode ~= "both" then
@@ -740,10 +754,38 @@ function BNP:IsPersonalNameplateDebuffsEnabled()
return BNP_DB and BNP_DB.personalNameplateDebuffs == true
end
function BNP:IsPersonalNameplateBuffsEnabled()
return BNP_DB and BNP_DB.personalNameplateBuffs == true
end
function BNP:GetPersonalNameplateDebuffYOffset()
local value = (BNP_DB and tonumber(BNP_DB.personalNameplateDebuffYOffset)) or self.defaults.personalNameplateDebuffYOffset or 0
if value < -50 then value = -50 end
if value > 50 then value = 50 end
if value < -100 then value = -100 end
if value > 100 then value = 100 end
if value >= 0 then return math.floor(value + 0.5) end
return math.ceil(value - 0.5)
end
function BNP:GetPersonalNameplateBuffYOffset()
local value = (BNP_DB and tonumber(BNP_DB.personalNameplateBuffYOffset)) or self.defaults.personalNameplateBuffYOffset or 0
if value < -100 then value = -100 end
if value > 100 then value = 100 end
if value >= 0 then return math.floor(value + 0.5) end
return math.ceil(value - 0.5)
end
function BNP:GetPersonalNameplateDebuffXOffset()
local value = (BNP_DB and tonumber(BNP_DB.personalNameplateDebuffXOffset)) or self.defaults.personalNameplateDebuffXOffset or 0
if value < -100 then value = -100 end
if value > 100 then value = 100 end
if value >= 0 then return math.floor(value + 0.5) end
return math.ceil(value - 0.5)
end
function BNP:GetPersonalNameplateBuffXOffset()
local value = (BNP_DB and tonumber(BNP_DB.personalNameplateBuffXOffset)) or self.defaults.personalNameplateBuffXOffset or 0
if value < -100 then value = -100 end
if value > 100 then value = 100 end
if value >= 0 then return math.floor(value + 0.5) end
return math.ceil(value - 0.5)
end
+124 -19
View File
@@ -825,11 +825,12 @@ function BNP:CreateOptions()
local frame = CreateFrame("Frame", "BNPOptionsFrame", UIParent)
frame:SetWidth(470)
frame:SetHeight(comboOptionsClass and 735 or 710)
frame:SetHeight(comboOptionsClass and 963 or 883)
-- Keep the top edge in roughly the same place and add the extra room
-- downward. The Icons page uses the height for Totems, Raid Marks and
-- Quest Indicators without crowding or clipping.
frame:SetPoint("CENTER", UIParent, "CENTER", 0, -40)
-- downward. Rogue/Druid need more room because the Combo Points section
-- sits above Personal Nameplate; the larger frame lets those controls keep
-- comfortable vertical spacing instead of being packed against the border.
frame:SetPoint("CENTER", UIParent, "CENTER", 0, comboOptionsClass and -109 or -102)
frame:SetFrameStrata("DIALOG")
frame:SetBackdrop({
bgFile = "Interface\\DialogFrame\\UI-DialogBox-Background",
@@ -1305,11 +1306,11 @@ function BNP:CreateOptions()
-- Clean two-column grid: visibility, appearance, text/debuff positioning,
-- then plate scale/position. Rogue/Druid get a little extra window height
-- so the same layout stays intact below the Combo Points section.
local personalSectionY = comboOptionsClass and -494 or -442
local personalSectionY = comboOptionsClass and -500 or -448
CreateSection(nameplatesPage, "Personal Nameplate", personalSectionY)
-- Row 1: visibility.
local personalNameplate = CreateCheck(nameplatesPage, "Enable Personal Nameplate", personalSectionY - 22, function()
local personalNameplate = CreateCheck(nameplatesPage, "Enable Personal Nameplate", personalSectionY - 24, function()
BNP_DB.personalNameplate = this:GetChecked() and true or false
if BNP.RefreshPersonalNameplate then BNP:RefreshPersonalNameplate() end
if frame.UpdateDependentControls then frame:UpdateDependentControls() end
@@ -1323,7 +1324,7 @@ function BNP:CreateOptions()
personalNameplate:SetScript("OnLeave", function() GameTooltip:Hide() end)
frame.personalNameplateCheck = personalNameplate
local personalCombatOnly = CreateCheck(nameplatesPage, "Combat Only", personalSectionY - 22, function()
local personalCombatOnly = CreateCheck(nameplatesPage, "Combat Only", personalSectionY - 24, function()
BNP_DB.personalNameplateCombatOnly = this:GetChecked() and true or false
if BNP.RefreshPersonalNameplate then BNP:RefreshPersonalNameplate() end
end, 246)
@@ -1336,8 +1337,8 @@ function BNP:CreateOptions()
personalCombatOnly:SetScript("OnLeave", function() GameTooltip:Hide() end)
frame.personalNameplateCombatOnlyCheck = personalCombatOnly
-- Row 2: appearance / aura toggles.
local personalClassColor = CreateCheck(nameplatesPage, "Class Color", personalSectionY - 48, function()
-- Row 2: appearance.
local personalClassColor = CreateCheck(nameplatesPage, "Class Color", personalSectionY - 56, function()
BNP_DB.personalNameplateClassColor = this:GetChecked() and true or false
if BNP.RefreshPersonalNameplate then BNP:RefreshPersonalNameplate() end
end, 22)
@@ -1350,10 +1351,25 @@ function BNP:CreateOptions()
personalClassColor:SetScript("OnLeave", function() GameTooltip:Hide() end)
frame.personalNameplateClassColorCheck = personalClassColor
local personalDebuffs = CreateCheck(nameplatesPage, "Show Debuffs", personalSectionY - 48, function()
BNP_DB.personalNameplateDebuffs = this:GetChecked() and true or false
local personalHideLevel = CreateCheck(nameplatesPage, "Hide Level", personalSectionY - 56, function()
BNP_DB.personalNameplateHideLevel = this:GetChecked() and true or false
if BNP.RefreshPersonalNameplate then BNP:RefreshPersonalNameplate() end
end, 246)
personalHideLevel:SetScript("OnEnter", function()
GameTooltip:SetOwner(this, "ANCHOR_RIGHT")
GameTooltip:SetText("Hide Level", 1, 0.82, 0)
GameTooltip:AddLine("Hides the level and removes the round level medallion so the Personal Nameplate becomes a closed centered bar.", 1, 1, 1, true)
GameTooltip:Show()
end)
personalHideLevel:SetScript("OnLeave", function() GameTooltip:Hide() end)
frame.personalNameplateHideLevelCheck = personalHideLevel
-- Row 3: aura toggles. Buffs and debuffs are separate so either row can be
-- disabled without doing aura work for that type in the background.
local personalDebuffs = CreateCheck(nameplatesPage, "Show Debuffs", personalSectionY - 88, function()
BNP_DB.personalNameplateDebuffs = this:GetChecked() and true or false
if BNP.RefreshPersonalNameplate then BNP:RefreshPersonalNameplate() end
end, 22)
personalDebuffs:SetScript("OnEnter", function()
GameTooltip:SetOwner(this, "ANCHOR_RIGHT")
GameTooltip:SetText("Show Debuffs", 1, 0.82, 0)
@@ -1363,17 +1379,30 @@ function BNP:CreateOptions()
personalDebuffs:SetScript("OnLeave", function() GameTooltip:Hide() end)
frame.personalNameplateDebuffsCheck = personalDebuffs
-- Row 3: text mode on the left, debuff offset on the right.
local personalBuffs = CreateCheck(nameplatesPage, "Show Buffs", personalSectionY - 88, function()
BNP_DB.personalNameplateBuffs = this:GetChecked() and true or false
if BNP.RefreshPersonalNameplate then BNP:RefreshPersonalNameplate() end
end, 246)
personalBuffs:SetScript("OnEnter", function()
GameTooltip:SetOwner(this, "ANCHOR_RIGHT")
GameTooltip:SetText("Show Buffs", 1, 0.82, 0)
GameTooltip:AddLine("Shows short buffs such as Renew, Rejuvenation and shields. Long buffs over 60 seconds are ignored.", 1, 1, 1, true)
GameTooltip:Show()
end)
personalBuffs:SetScript("OnLeave", function() GameTooltip:Hide() end)
frame.personalNameplateBuffsCheck = personalBuffs
-- Row 4: text mode on the left, debuff Y offset on the right.
local personalHealthTextLabel = nameplatesPage:CreateFontString(nil, "OVERLAY", "GameFontNormal")
personalHealthTextLabel:SetPoint("TOPLEFT", nameplatesPage, "TOPLEFT", 28, personalSectionY - 72)
personalHealthTextLabel:SetPoint("TOPLEFT", nameplatesPage, "TOPLEFT", 28, personalSectionY - 120)
personalHealthTextLabel:SetText("Health Text")
frame.personalNameplateHealthTextLabel = personalHealthTextLabel
local personalHealthTextDropdown = CreateFrame("Frame", "BNPPersonalHealthTextDropdown", nameplatesPage, "UIDropDownMenuTemplate")
personalHealthTextDropdown:SetPoint("TOPLEFT", nameplatesPage, "TOPLEFT", 10, personalSectionY - 82)
personalHealthTextDropdown:SetPoint("TOPLEFT", nameplatesPage, "TOPLEFT", 10, personalSectionY - 132)
UIDropDownMenu_SetWidth(142, personalHealthTextDropdown)
local personalDebuffYOffset = CreateSlider(nameplatesPage, "Debuff Y Offset", -50, 50, 1, personalSectionY - 82, 246, 150)
local personalDebuffYOffset = CreateSlider(nameplatesPage, "Debuff Y Offset", -100, 100, 1, personalSectionY - 132, 246, 150)
personalDebuffYOffset:SetScript("OnValueChanged", function()
if not BNP_DB then return end
local value = RoundSignedInteger(this:GetValue())
@@ -1390,6 +1419,58 @@ function BNP:CreateOptions()
personalDebuffYOffset:SetScript("OnLeave", function() GameTooltip:Hide() end)
frame.personalNameplateDebuffYOffsetSlider = personalDebuffYOffset
-- Row 5: Buff Y on the left, Debuff X on the right.
local personalBuffYOffset = CreateSlider(nameplatesPage, "Buff Y Offset", -100, 100, 1, personalSectionY - 176, 28, 150)
personalBuffYOffset:SetScript("OnValueChanged", function()
if not BNP_DB then return end
local value = RoundSignedInteger(this:GetValue())
BNP_DB.personalNameplateBuffYOffset = value
getglobal(this:GetName() .. "Text"):SetText("Buff Y Offset: " .. (value > 0 and "+" or "") .. value)
if BNP.RefreshPersonalNameplate then BNP:RefreshPersonalNameplate() end
end)
personalBuffYOffset:SetScript("OnEnter", function()
GameTooltip:SetOwner(this, "ANCHOR_RIGHT")
GameTooltip:SetText("Personal Buff Y Offset", 1, 0.82, 0)
GameTooltip:AddLine("Moves the Personal Nameplate buff row up or down independently from debuffs.", 1, 1, 1, true)
GameTooltip:Show()
end)
personalBuffYOffset:SetScript("OnLeave", function() GameTooltip:Hide() end)
frame.personalNameplateBuffYOffsetSlider = personalBuffYOffset
local personalDebuffXOffset = CreateSlider(nameplatesPage, "Debuff X Offset", -100, 100, 1, personalSectionY - 176, 246, 150)
personalDebuffXOffset:SetScript("OnValueChanged", function()
if not BNP_DB then return end
local value = RoundSignedInteger(this:GetValue())
BNP_DB.personalNameplateDebuffXOffset = value
getglobal(this:GetName() .. "Text"):SetText("Debuff X Offset: " .. (value > 0 and "+" or "") .. value)
if BNP.RefreshPersonalNameplate then BNP:RefreshPersonalNameplate() end
end)
personalDebuffXOffset:SetScript("OnEnter", function()
GameTooltip:SetOwner(this, "ANCHOR_RIGHT")
GameTooltip:SetText("Personal Debuff X Offset", 1, 0.82, 0)
GameTooltip:AddLine("Moves the Personal Nameplate debuff row left or right so it does not run into the buff row or other UI.", 1, 1, 1, true)
GameTooltip:Show()
end)
personalDebuffXOffset:SetScript("OnLeave", function() GameTooltip:Hide() end)
frame.personalNameplateDebuffXOffsetSlider = personalDebuffXOffset
local personalBuffXOffset = CreateSlider(nameplatesPage, "Buff X Offset", -100, 100, 1, personalSectionY - 220, 28, 150)
personalBuffXOffset:SetScript("OnValueChanged", function()
if not BNP_DB then return end
local value = RoundSignedInteger(this:GetValue())
BNP_DB.personalNameplateBuffXOffset = value
getglobal(this:GetName() .. "Text"):SetText("Buff X Offset: " .. (value > 0 and "+" or "") .. value)
if BNP.RefreshPersonalNameplate then BNP:RefreshPersonalNameplate() end
end)
personalBuffXOffset:SetScript("OnEnter", function()
GameTooltip:SetOwner(this, "ANCHOR_RIGHT")
GameTooltip:SetText("Personal Buff X Offset", 1, 0.82, 0)
GameTooltip:AddLine("Moves the Personal Nameplate buff row left or right independently from debuffs.", 1, 1, 1, true)
GameTooltip:Show()
end)
personalBuffXOffset:SetScript("OnLeave", function() GameTooltip:Hide() end)
frame.personalNameplateBuffXOffsetSlider = personalBuffXOffset
local personalHealthModeLabels = {
off = "Off",
percent = "Percent",
@@ -1428,8 +1509,8 @@ function BNP:CreateOptions()
frame.personalNameplateHealthTextDropdown = personalHealthTextDropdown
frame.SetPersonalHealthTextMode = SetPersonalHealthTextMode
-- Row 4: plate size and position, aligned to the same two columns.
local personalScale = CreateSlider(nameplatesPage, "Scale", 0.70, 1.50, 0.05, personalSectionY - 116, 28, 150)
-- Row 6: remaining aura offset on the left and plate scale on the right.
local personalScale = CreateSlider(nameplatesPage, "Scale", 0.70, 1.50, 0.05, personalSectionY - 220, 246, 150)
personalScale:SetScript("OnValueChanged", function()
if not BNP_DB then return end
local value = Round(this:GetValue(), 0.05)
@@ -1446,7 +1527,8 @@ function BNP:CreateOptions()
personalScale:SetScript("OnLeave", function() GameTooltip:Hide() end)
frame.personalNameplateScaleSlider = personalScale
local personalYOffset = CreateSlider(nameplatesPage, "Y Offset", -250, 150, 5, personalSectionY - 116, 246, 150)
-- Row 7: plate position.
local personalYOffset = CreateSlider(nameplatesPage, "Y Offset", -250, 150, 5, personalSectionY - 264, 28, 150)
personalYOffset:SetScript("OnValueChanged", function()
if not BNP_DB then return end
local value = RoundSignedInteger(this:GetValue() / 5) * 5
@@ -2274,7 +2356,9 @@ function BNP:CreateOptions()
local personalEnabled = BNP.IsPersonalNameplateEnabled and BNP:IsPersonalNameplateEnabled() or false
SetCheckEnabled(self.personalNameplateCombatOnlyCheck, personalEnabled)
SetCheckEnabled(self.personalNameplateClassColorCheck, personalEnabled)
SetCheckEnabled(self.personalNameplateHideLevelCheck, personalEnabled)
SetCheckEnabled(self.personalNameplateDebuffsCheck, personalEnabled)
SetCheckEnabled(self.personalNameplateBuffsCheck, personalEnabled)
if self.personalNameplateHealthTextDropdown then
self.personalNameplateHealthTextDropdown:SetAlpha(personalEnabled and 1.0 or 0.45)
if personalEnabled then
@@ -2286,7 +2370,7 @@ function BNP:CreateOptions()
if self.personalNameplateHealthTextLabel then
self.personalNameplateHealthTextLabel:SetTextColor(personalEnabled and 1 or 0.5, personalEnabled and 0.82 or 0.5, personalEnabled and 0 or 0.5)
end
local personalSliders = { self.personalNameplateScaleSlider, self.personalNameplateYOffsetSlider, self.personalNameplateDebuffYOffsetSlider }
local personalSliders = { self.personalNameplateScaleSlider, self.personalNameplateYOffsetSlider, self.personalNameplateDebuffYOffsetSlider, self.personalNameplateBuffYOffsetSlider, self.personalNameplateDebuffXOffsetSlider, self.personalNameplateBuffXOffsetSlider }
local personalIndex
for personalIndex = 1, table.getn(personalSliders) do
local personalSlider = personalSliders[personalIndex]
@@ -2462,6 +2546,9 @@ function BNP:SyncOptions()
if frame.personalNameplateClassColorCheck then
frame.personalNameplateClassColorCheck:SetChecked(self.IsPersonalNameplateClassColorEnabled and self:IsPersonalNameplateClassColorEnabled() or false)
end
if frame.personalNameplateHideLevelCheck then
frame.personalNameplateHideLevelCheck:SetChecked(self.IsPersonalNameplateLevelHidden and self:IsPersonalNameplateLevelHidden() or false)
end
if frame.personalNameplateHealthTextDropdown then
local mode = self.GetPersonalNameplateHealthTextMode and self:GetPersonalNameplateHealthTextMode() or "both"
local labels = { off = "Off", percent = "Percent", hp = "HP", both = "HP + Percent" }
@@ -2471,6 +2558,9 @@ function BNP:SyncOptions()
if frame.personalNameplateDebuffsCheck then
frame.personalNameplateDebuffsCheck:SetChecked(self.IsPersonalNameplateDebuffsEnabled and self:IsPersonalNameplateDebuffsEnabled() or false)
end
if frame.personalNameplateBuffsCheck then
frame.personalNameplateBuffsCheck:SetChecked(self.IsPersonalNameplateBuffsEnabled and self:IsPersonalNameplateBuffsEnabled() or false)
end
if frame.personalNameplateScaleSlider then
local value = self.GetPersonalNameplateScale and self:GetPersonalNameplateScale() or 1.0
frame.personalNameplateScaleSlider:SetValue(value)
@@ -2486,6 +2576,21 @@ function BNP:SyncOptions()
frame.personalNameplateDebuffYOffsetSlider:SetValue(value)
getglobal(frame.personalNameplateDebuffYOffsetSlider:GetName() .. "Text"):SetText("Debuff Y Offset: " .. (value > 0 and "+" or "") .. value)
end
if frame.personalNameplateBuffYOffsetSlider then
local value = self.GetPersonalNameplateBuffYOffset and self:GetPersonalNameplateBuffYOffset() or 0
frame.personalNameplateBuffYOffsetSlider:SetValue(value)
getglobal(frame.personalNameplateBuffYOffsetSlider:GetName() .. "Text"):SetText("Buff Y Offset: " .. (value > 0 and "+" or "") .. value)
end
if frame.personalNameplateDebuffXOffsetSlider then
local value = self.GetPersonalNameplateDebuffXOffset and self:GetPersonalNameplateDebuffXOffset() or 0
frame.personalNameplateDebuffXOffsetSlider:SetValue(value)
getglobal(frame.personalNameplateDebuffXOffsetSlider:GetName() .. "Text"):SetText("Debuff X Offset: " .. (value > 0 and "+" or "") .. value)
end
if frame.personalNameplateBuffXOffsetSlider then
local value = self.GetPersonalNameplateBuffXOffset and self:GetPersonalNameplateBuffXOffset() or 0
frame.personalNameplateBuffXOffsetSlider:SetValue(value)
getglobal(frame.personalNameplateBuffXOffsetSlider:GetName() .. "Text"):SetText("Buff X Offset: " .. (value > 0 and "+" or "") .. value)
end
if frame.debuffYOffsetSlider then
local value = self:GetDebuffYOffset()
frame.debuffYOffsetSlider:SetValue(value)
+31 -5
View File
@@ -3175,14 +3175,14 @@ local function SyncAuraRemoval(unit, guid, now, snapshot, currentTargetGUID, eve
local i
local maxIndex = snapshot and snapshot.count or 64
for i = 1, maxIndex do
local texture, stacks, dtype, auraSpellID, source
local texture, stacks, dtype, auraSpellID, liveDuration, liveExpires, source
if snapshot then
local entry = snapshot.entries[i]
if not entry then break end
texture, stacks, dtype, auraSpellID, source = entry[1], entry[2], entry[3], entry[4], entry[7]
texture, stacks, dtype, auraSpellID, liveDuration, liveExpires, source =
entry[1], entry[2], entry[3], entry[4], entry[5], entry[6], entry[7]
else
local duration, expirationTime
texture, stacks, dtype, auraSpellID, duration, expirationTime, source = BNP:_ReadClassicDebuff(unit, i)
texture, stacks, dtype, auraSpellID, liveDuration, liveExpires, source = BNP:_ReadClassicDebuff(unit, i)
if not texture then break end
end
@@ -3193,7 +3193,8 @@ local function SyncAuraRemoval(unit, guid, now, snapshot, currentTargetGUID, eve
-- aura is safe when it is still ours OR ClassicAPI temporarily lost the
-- source metadata. A known foreign source alone is not enough to keep
-- our timer alive.
if not BNP:_IsKnownForeignClassicAuraSource(source) then
local knownForeign = BNP:_IsKnownForeignClassicAuraSource(source)
if not knownForeign then
BNP._RemovalPresentSafe[auraSpellID] = presentGeneration
end
@@ -3201,6 +3202,31 @@ local function SyncAuraRemoval(unit, guid, now, snapshot, currentTargetGUID, eve
for trackedKey, trackedAura in pairs(cache) do
if type(trackedAura) == "table" and trackedAura.spellID == auraSpellID then
trackedAura.stacks = tonumber(stacks) or 0
-- ClassicAPI is authoritative for the live expiration of our aura.
-- Some talents/procs (for example Turtle WoW Druid Carnage) renew an
-- existing bleed without another Rake/Rip cast. Previously BNP only
-- updated stacks here, so the cached cast timer expired even though
-- the real aura had already received a new expirationTime.
--
-- Never extend from a known foreign caster. Unknown source remains a
-- valid fallback because some custom-client packets omit ownership.
local apiDuration = tonumber(liveDuration)
local apiExpires = tonumber(liveExpires)
if not knownForeign and apiExpires and apiExpires > now then
local oldExpires = tonumber(trackedAura.expires)
if not oldExpires or math.abs(apiExpires - oldExpires) > 0.05 then
if apiDuration and apiDuration > 0 then
trackedAura.duration = apiDuration
end
trackedAura.expires = apiExpires
trackedAura.classicAPITiming = true
trackedAura.liveConfirmed = true
trackedAura.missingScans = nil
trackedAura.exactMissingScans = nil
RaidTrace("LIVE_REFRESH", guid, trackedKey, auraSpellID)
end
end
end
end
end
File diff suppressed because it is too large Load Diff
+290 -16
View File
@@ -15,6 +15,9 @@ local POWER_HEIGHT = 5
local PERSONAL_DEBUFF_MAX_DURATION = 60
local PERSONAL_DEBUFF_MAX_ICONS = 6
local PERSONAL_DEBUFF_SPACING = 1
local PERSONAL_BUFF_MAX_DURATION = 60
local PERSONAL_BUFF_MAX_ICONS = 6
local PERSONAL_BUFF_SPACING = 1
-- Match BNP health text anchoring: healthbar CENTER +3px. The personal frame
-- is wider than the healthbar because of the level medallion, so centering
-- debuffs on the whole frame makes the row look shifted to the right.
@@ -24,6 +27,14 @@ local PERSONAL_POWER_TEXT_Y = 1
local PERSONAL_CONTENT_CENTER_X = (5 + HEALTH_WIDTH / 2 + PERSONAL_HEALTH_TEXT_X) - (FRAME_WIDTH / 2)
local STATUS_TEXTURE = "Interface\\TargetingFrame\\UI-StatusBar"
local BORDER_TEXTURE = "Interface\\AddOns\\BlizzNameplatesPlus\\media\\classic_nameplate_border"
-- The classic texture's health-bar portion occupies the first 108/128 pixels;
-- the final 20 pixels are the round level medallion. Cropping at 108 gives us
-- a native-looking closed border when the personal level is hidden.
local NO_LEVEL_BORDER_WIDTH = 108
local NO_LEVEL_BORDER_TEX_RIGHT = 108 / 128
local NO_LEVEL_BORDER_X = (FRAME_WIDTH - NO_LEVEL_BORDER_WIDTH) / 2
local NO_LEVEL_HEALTH_X = (FRAME_WIDTH - HEALTH_WIDTH) / 2
local NO_LEVEL_POWER_X = NO_LEVEL_HEALTH_X
local FONT = "Fonts\\FRIZQT__.TTF"
local classFallback = {
@@ -97,6 +108,7 @@ local personalFrame
local inCombat = false
local updateElapsed = 0
local debuffScanElapsed = 0
local buffScanElapsed = 0
local function FormatValue(value)
value = tonumber(value) or 0
@@ -285,6 +297,52 @@ local function CreatePersonalFrame()
end
debuffHolder:Hide()
-- Short player buffs (HoTs, absorbs, short defensive effects) use a second
-- compact row. When debuffs are visible this row sits directly above them;
-- otherwise it drops down to the normal aura anchor above the plate.
local buffHolder = CreateFrame("Frame", nil, frame)
buffHolder:SetWidth(FRAME_WIDTH)
buffHolder:SetHeight(22)
buffHolder:SetPoint("BOTTOM", frame, "TOP", PERSONAL_CONTENT_CENTER_X, 1)
buffHolder:SetFrameLevel(frame:GetFrameLevel() + 6)
buffHolder:EnableMouse(false)
buffHolder.icons = {}
frame.buffHolder = buffHolder
for i = 1, PERSONAL_BUFF_MAX_ICONS do
local icon = CreateFrame("Frame", nil, buffHolder)
icon:SetWidth(18)
icon:SetHeight(18)
icon:SetFrameLevel(buffHolder:GetFrameLevel())
icon:EnableMouse(false)
local iconBG = CreateSolidTexture(icon, "BACKGROUND")
iconBG:SetPoint("TOPLEFT", icon, "TOPLEFT", -1, 1)
iconBG:SetPoint("BOTTOMRIGHT", icon, "BOTTOMRIGHT", 1, -1)
iconBG:SetVertexColor(0, 0, 0, 0.95)
local texture = icon:CreateTexture(nil, "ARTWORK")
texture:SetAllPoints(icon)
icon.texture = texture
local timer = icon:CreateFontString(nil, "OVERLAY")
timer:SetFont(FONT, 8, "OUTLINE")
timer:SetPoint("CENTER", icon, "CENTER", 0, 0)
timer:SetTextColor(1, 1, 1)
icon.timer = timer
local stack = icon:CreateFontString(nil, "OVERLAY")
stack:SetFont(FONT, 7, "OUTLINE")
stack:SetPoint("BOTTOMRIGHT", icon, "BOTTOMRIGHT", -1, 1)
stack:SetTextColor(1, 1, 1)
stack:SetText("")
icon.stack = stack
icon:Hide()
buffHolder.icons[i] = icon
end
buffHolder:Hide()
personalFrame = frame
BNP.personalNameplateFrame = frame
return frame
@@ -303,9 +361,43 @@ local function GetPlayerHealthColor()
return 0.10, 0.95, 0.10
end
local function ApplyLevelLayout(frame)
if not frame then return end
local hideLevel = BNP.IsPersonalNameplateLevelHidden and BNP:IsPersonalNameplateLevelHidden()
if hideLevel then
frame.border:ClearAllPoints()
frame.border:SetWidth(NO_LEVEL_BORDER_WIDTH)
frame.border:SetTexCoord(0, NO_LEVEL_BORDER_TEX_RIGHT, 0, 1)
frame.border:SetPoint("TOPLEFT", frame, "TOPLEFT", NO_LEVEL_BORDER_X, 0)
frame.healthbar:ClearAllPoints()
frame.healthbar:SetWidth(HEALTH_WIDTH)
frame.healthbar:SetPoint("TOPLEFT", frame, "TOPLEFT", NO_LEVEL_HEALTH_X, -19)
frame.powerHolder:ClearAllPoints()
frame.powerHolder:SetPoint("TOPLEFT", frame, "TOPLEFT", NO_LEVEL_POWER_X, -34)
frame.levelText:Hide()
else
frame.border:ClearAllPoints()
frame.border:SetWidth(128)
frame.border:SetTexCoord(0, 1, 0, 1)
frame.border:SetPoint("TOPLEFT", frame, "TOPLEFT", 0, 0)
frame.healthbar:ClearAllPoints()
frame.healthbar:SetWidth(HEALTH_WIDTH)
frame.healthbar:SetPoint("TOPLEFT", frame, "TOPLEFT", 5, -19)
frame.powerHolder:ClearAllPoints()
frame.powerHolder:SetPoint("TOPLEFT", frame, "TOPLEFT", 3, -34)
end
end
local function UpdateStyle(frame)
if not frame then return end
ApplyLevelLayout(frame)
local dark = BNP.IsDarkNameplateBorderEnabled and BNP:IsDarkNameplateBorderEnabled()
local hidden = BNP.IsNameplateBorderHidden and BNP:IsNameplateBorderHidden()
local blackBG = BNP.IsBlackHealthbarBackgroundEnabled and BNP:IsBlackHealthbarBackgroundEnabled()
@@ -332,12 +424,39 @@ local function UpdateStyle(frame)
frame.healthBG:SetVertexColor(0, 0, 0, 1)
end
if hidden then frame.levelText:Hide() else frame.levelText:Show() end
local hideLevel = BNP.IsPersonalNameplateLevelHidden and BNP:IsPersonalNameplateLevelHidden()
if hidden or hideLevel then frame.levelText:Hide() else frame.levelText:Show() end
local hr, hg, hb = GetPlayerHealthColor()
frame.healthbar:SetStatusBarColor(hr, hg, hb)
end
local function PositionPersonalAuraHolders(frame)
if not frame then return end
local hideLevel = BNP.IsPersonalNameplateLevelHidden and BNP:IsPersonalNameplateLevelHidden()
local contentCenterX = hideLevel and PERSONAL_HEALTH_TEXT_X or PERSONAL_CONTENT_CENTER_X
local debuffY = BNP.GetPersonalNameplateDebuffYOffset and BNP:GetPersonalNameplateDebuffYOffset() or 0
local buffY = BNP.GetPersonalNameplateBuffYOffset and BNP:GetPersonalNameplateBuffYOffset() or 0
local debuffX = BNP.GetPersonalNameplateDebuffXOffset and BNP:GetPersonalNameplateDebuffXOffset() or 0
local buffX = BNP.GetPersonalNameplateBuffXOffset and BNP:GetPersonalNameplateBuffXOffset() or 0
if frame.debuffHolder then
frame.debuffHolder:ClearAllPoints()
frame.debuffHolder:SetPoint("BOTTOM", frame, "TOP", contentCenterX + debuffX, 1 + debuffY)
end
if frame.buffHolder then
frame.buffHolder:ClearAllPoints()
if frame.debuffHolder and frame.debuffHolder:IsShown() then
frame.buffHolder:SetPoint("BOTTOM", frame, "TOP", contentCenterX + buffX, 25 + buffY)
else
frame.buffHolder:SetPoint("BOTTOM", frame, "TOP", contentCenterX + buffX, 1 + buffY)
end
end
end
local function UpdatePosition(frame)
if not frame then return end
local scale = BNP.GetPersonalNameplateScale and BNP:GetPersonalNameplateScale() or 1.0
@@ -346,12 +465,7 @@ local function UpdatePosition(frame)
frame:SetScale(scale)
frame:ClearAllPoints()
frame:SetPoint("CENTER", UIParent, "CENTER", 0, y)
if frame.debuffHolder then
local debuffY = BNP.GetPersonalNameplateDebuffYOffset and BNP:GetPersonalNameplateDebuffYOffset() or 0
frame.debuffHolder:ClearAllPoints()
frame.debuffHolder:SetPoint("BOTTOM", frame, "TOP", PERSONAL_CONTENT_CENTER_X, 1 + debuffY)
end
PositionPersonalAuraHolders(frame)
end
local function GetPersonalDebuffIconSize()
@@ -373,7 +487,13 @@ local function ReadPlayerDebuff(index)
if type(C_UnitAuras) == "table" and type(C_UnitAuras.GetDebuffDataByIndex) == "function" then
local ok, aura = pcall(C_UnitAuras.GetDebuffDataByIndex, "player", index)
if not ok or not aura then return nil end
return aura.icon, aura.applications or aura.count or 0, aura.duration, aura.expirationTime, aura.name, aura.spellId or aura.spellID
return aura.icon or aura.texture, aura.applications or aura.count or 0, aura.duration, aura.expirationTime, aura.name, aura.spellId or aura.spellID
end
if type(C_UnitAuras) == "table" and type(C_UnitAuras.GetAuraDataByIndex) == "function" then
local ok, aura = pcall(C_UnitAuras.GetAuraDataByIndex, "player", index, "HARMFUL")
if not ok or not aura then return nil end
return aura.icon or aura.texture, aura.applications or aura.count or 0, aura.duration, aura.expirationTime, aura.name, aura.spellId or aura.spellID
end
if type(C_UnitAuras) == "table" and type(C_UnitAuras.UnitDebuff) == "function" then
@@ -393,6 +513,35 @@ local function ReadPlayerDebuff(index)
return nil
end
local function ReadPlayerBuff(index)
if type(C_UnitAuras) == "table" and type(C_UnitAuras.GetBuffDataByIndex) == "function" then
local ok, aura = pcall(C_UnitAuras.GetBuffDataByIndex, "player", index)
if not ok or not aura then return nil end
return aura.icon or aura.texture, aura.applications or aura.count or 0, aura.duration, aura.expirationTime, aura.name, aura.spellId or aura.spellID
end
if type(C_UnitAuras) == "table" and type(C_UnitAuras.GetAuraDataByIndex) == "function" then
local ok, aura = pcall(C_UnitAuras.GetAuraDataByIndex, "player", index, "HELPFUL")
if not ok or not aura then return nil end
return aura.icon or aura.texture, aura.applications or aura.count or 0, aura.duration, aura.expirationTime, aura.name, aura.spellId or aura.spellID
end
if type(C_UnitAuras) == "table" and type(C_UnitAuras.UnitBuff) == "function" then
local name, icon, count, dispelType, duration, expirationTime, source, isStealable, nameplateShowPersonal, spellID = C_UnitAuras.UnitBuff("player", index)
if not name then return nil end
return icon, count or 0, duration, expirationTime, name, spellID
end
-- As with debuffs, legacy 1.12 UnitBuff has no dependable duration on its
-- own. Only use it when a custom client supplies duration + expiration.
if UnitBuff then
local texture, count, dispelType, spellID, duration, expirationTime = UnitBuff("player", index)
if not texture then return nil end
return texture, count or 0, duration, expirationTime, nil, spellID
end
return nil
end
local function HidePersonalDebuffs(frame)
if not frame or not frame.debuffHolder then return end
local i
@@ -403,6 +552,7 @@ local function HidePersonalDebuffs(frame)
icon:Hide()
end
frame.debuffHolder:Hide()
PositionPersonalAuraHolders(frame)
end
local function UpdatePersonalDebuffs(frame, forceScan)
@@ -489,6 +639,109 @@ local function UpdatePersonalDebuffs(frame, forceScan)
icon:Hide()
end
frame.debuffHolder:Show()
PositionPersonalAuraHolders(frame)
end
local function HidePersonalBuffs(frame)
if not frame or not frame.buffHolder then return end
local i
for i = 1, table.getn(frame.buffHolder.icons or {}) do
local icon = frame.buffHolder.icons[i]
icon.timer:SetText("")
icon.stack:SetText("")
icon:Hide()
end
frame.buffHolder:Hide()
end
local function UpdatePersonalBuffs(frame, forceScan)
if not frame or not frame.buffHolder then return end
if not (BNP.IsPersonalNameplateBuffsEnabled and BNP:IsPersonalNameplateBuffsEnabled()) then
frame.BNPPersonalBuffEntries = nil
HidePersonalBuffs(frame)
return
end
local now = GetTime()
local entries = frame.BNPPersonalBuffEntries
if forceScan or not entries then
entries = {}
local index
for index = 1, 64 do
local texture, count, duration, expirationTime, name, spellID = ReadPlayerBuff(index)
if not texture then break end
duration = tonumber(duration) or 0
expirationTime = tonumber(expirationTime) or 0
-- Keep this row focused on combat-relevant temporary effects: HoTs,
-- absorbs/shields and short cooldown buffs. Long raid/world buffs are
-- intentionally ignored.
if duration > 0 and duration <= PERSONAL_BUFF_MAX_DURATION and expirationTime > now then
table.insert(entries, {
texture = texture,
count = tonumber(count) or 0,
duration = duration,
expirationTime = expirationTime,
name = name,
spellID = spellID,
})
if table.getn(entries) >= PERSONAL_BUFF_MAX_ICONS then break end
end
end
frame.BNPPersonalBuffEntries = entries
end
local visible = 0
local i
for i = 1, table.getn(entries) do
if entries[i].expirationTime and entries[i].expirationTime > now then
visible = visible + 1
end
end
if visible < 1 then
HidePersonalBuffs(frame)
return
end
local size = GetPersonalDebuffIconSize()
local totalWidth = visible * size + (visible - 1) * PERSONAL_BUFF_SPACING
local startX = -totalWidth / 2
local displayIndex = 0
for i = 1, table.getn(entries) do
local entry = entries[i]
if entry.expirationTime and entry.expirationTime > now then
displayIndex = displayIndex + 1
local icon = frame.buffHolder.icons[displayIndex]
if icon then
if icon.BNPLastSize ~= size then
icon:SetWidth(size)
icon:SetHeight(size)
icon.timer:SetFont(FONT, math.max(7, math.floor(size * 0.44 + 0.5)), "OUTLINE")
icon.stack:SetFont(FONT, math.max(6, math.floor(size * 0.38 + 0.5)), "OUTLINE")
icon.BNPLastSize = size
end
icon:ClearAllPoints()
icon:SetPoint("LEFT", frame.buffHolder, "CENTER", startX + (displayIndex - 1) * (size + PERSONAL_BUFF_SPACING), 0)
if icon.BNPLastTexture ~= entry.texture then
icon.texture:SetTexture(entry.texture)
icon.BNPLastTexture = entry.texture
end
icon.timer:SetText(FormatDebuffTimer(entry.expirationTime - now))
icon.stack:SetText(entry.count > 1 and tostring(entry.count) or "")
icon:Show()
end
end
end
for i = displayIndex + 1, table.getn(frame.buffHolder.icons) do
local icon = frame.buffHolder.icons[i]
icon.timer:SetText("")
icon.stack:SetText("")
icon:Hide()
end
frame.buffHolder:Show()
PositionPersonalAuraHolders(frame)
end
local function UpdateValues(frame)
@@ -610,6 +863,7 @@ local function SetRuntimeEnabled(enabled)
updater:SetScript("OnUpdate", nil)
updateElapsed = 0
debuffScanElapsed = 0
buffScanElapsed = 0
if personalFrame then personalFrame:Hide() end
end
end
@@ -632,6 +886,7 @@ local function Refresh()
if ShouldShow() then
frame:Show()
UpdatePersonalDebuffs(frame, true)
UpdatePersonalBuffs(frame, true)
else
frame:Hide()
end
@@ -646,7 +901,10 @@ function BNP:RefreshPersonalNameplateStyle()
if not personalFrame then return end
UpdateStyle(personalFrame)
UpdateValues(personalFrame)
if personalFrame:IsShown() then UpdatePersonalDebuffs(personalFrame, true) end
if personalFrame:IsShown() then
UpdatePersonalDebuffs(personalFrame, true)
UpdatePersonalBuffs(personalFrame, true)
end
end
events:SetScript("OnEvent", function()
@@ -683,7 +941,10 @@ events:SetScript("OnEvent", function()
if personalFrame then
UpdateValues(personalFrame)
UpdateStyle(personalFrame)
if event == "UNIT_AURA" and personalFrame:IsShown() then UpdatePersonalDebuffs(personalFrame, true) end
if event == "UNIT_AURA" and personalFrame:IsShown() then
UpdatePersonalDebuffs(personalFrame, true)
UpdatePersonalBuffs(personalFrame, true)
end
end
end)
@@ -702,16 +963,29 @@ RuntimeOnUpdate = function()
if not personalFrame:IsShown() then
personalFrame:Show()
debuffScanElapsed = 0.50
buffScanElapsed = 0.50
end
UpdateValues(personalFrame)
debuffScanElapsed = debuffScanElapsed + 0.10
local forceScan = false
if debuffScanElapsed >= 0.50 then
debuffScanElapsed = 0
forceScan = true
local forceDebuffScan = false
if BNP.IsPersonalNameplateDebuffsEnabled and BNP:IsPersonalNameplateDebuffsEnabled() then
debuffScanElapsed = debuffScanElapsed + 0.10
if debuffScanElapsed >= 0.50 then
debuffScanElapsed = 0
forceDebuffScan = true
end
end
UpdatePersonalDebuffs(personalFrame, forceScan)
UpdatePersonalDebuffs(personalFrame, forceDebuffScan)
local forceBuffScan = false
if BNP.IsPersonalNameplateBuffsEnabled and BNP:IsPersonalNameplateBuffsEnabled() then
buffScanElapsed = buffScanElapsed + 0.10
if buffScanElapsed >= 0.50 then
buffScanElapsed = 0
forceBuffScan = true
end
end
UpdatePersonalBuffs(personalFrame, forceBuffScan)
elseif personalFrame:IsShown() then
personalFrame:Hide()
end