mirror of
https://github.com/brues-code/pfUI.git
synced 2026-10-31 07:56:57 +00:00
The sweep options reached the frames only through the cooldown module's CooldownFrame_SetTimer hook, which set alpha 0 for a hidden animation and SetReverse(true) for a reversed one. With that module disabled, Show Timer Animation and Reverse did nothing, and reverse never turned back off without a reload. The player buff sweeps had no other path at all. Each owner now configures its own frame. Player buffs drive their Cooldown with SetCooldown and Clear, and only while Show Timer Animation is on. Unit frame auras, raid aura indicators and nameplate debuffs hide the sweep with SetDrawSwipe and SetDrawBling. Every frame with a reverse option calls SetReverse. The hook keeps the timer text and Hide Foreign Cooldown Animations. Nameplate debuffs hid the sweep with alpha, which the plate's SetAlpha copied down on every target change (ClassicAPI keeps 1.12's alpha under default plates), so hidden sweeps came back. Their settings now come from UpdateDebuffConfig alone. Bag slots get a native Cooldown like bank slots, in place of the template's indicator Model, so Reverse Cooldown Animation covers bags and Hide Foreign Cooldown Animations no longer hides them. The buff, unit frame, nameplate and totem options apply without a reload. Fixes #72.
411 lines
15 KiB
Lua
411 lines
15 KiB
Lua
pfUI:RegisterModule("buff", function ()
|
|
-- Hide Blizz
|
|
BuffFrame:Hide()
|
|
BuffFrame:UnregisterAllEvents()
|
|
TemporaryEnchantFrame:Hide()
|
|
TemporaryEnchantFrame:UnregisterAllEvents()
|
|
|
|
local br, bg, bb, ba = GetStringColor(pfUI_config.appearance.border.color)
|
|
|
|
-- Player aura slot ids, enumerated once per refresh pass (ScanPlayerAuraSlots)
|
|
-- and read per button by its aura index: one GetAuraSlots walk per range
|
|
-- instead of a by-index walk per button.
|
|
local helpfulSlots, harmfulSlots = {}, {}
|
|
local function ScanPlayerAuraSlots()
|
|
ScanAuraSlots("player", "HELPFUL", helpfulSlots, 32)
|
|
ScanAuraSlots("player", "HARMFUL", harmfulSlots, 16)
|
|
end
|
|
|
|
local function RefreshBuffButton(buff)
|
|
if buff.btype == "HELPFUL" then
|
|
if C.buffs.separateweapons == "1" then
|
|
buff.id = buff.gid - (buff.weapon ~= nil and buff.gid or 0)
|
|
else
|
|
buff.id = buff.gid - pfUI.buff.wepbuffs.count
|
|
end
|
|
else
|
|
buff.id = buff.gid
|
|
end
|
|
|
|
if not buff.backdrop then
|
|
CreateBackdrop(buff)
|
|
CreateBackdropShadow(buff)
|
|
end
|
|
|
|
local slots = buff.btype == "HELPFUL" and helpfulSlots or harmfulSlots
|
|
local name, icon, count, dispelType, duration, expirationTime, _, _, _, spellId = C_UnitAuras.UnitAuraBySlot("player", slots[buff.id])
|
|
|
|
--detect weapon buffs
|
|
if buff.btype == "HELPFUL" and ((C.buffs.separateweapons == "0" and buff.gid <= pfUI.buff.wepbuffs.count) or (pfUI.buff.wepbuffs.count > 0 and buff.weapon ~= nil)) then
|
|
local mh, mhtime, mhcharge, oh, ohtime, ohcharge = GetWeaponEnchantInfo()
|
|
if pfUI.buff.wepbuffs.count == 2 then
|
|
if buff.gid == 1 then
|
|
buff.mode = "MAINHAND"
|
|
else
|
|
buff.mode = "OFFHAND"
|
|
end
|
|
else
|
|
if C.buffs.separateweapons == "0" then
|
|
buff.mode = mh and "MAINHAND" or oh and "OFFHAND"
|
|
else
|
|
if buff.gid == 1 then
|
|
buff.mode = mh and "MAINHAND" or oh and "OFFHAND"
|
|
else
|
|
buff:Hide()
|
|
return
|
|
end
|
|
end
|
|
end
|
|
|
|
-- Set Weapon Texture and Border
|
|
if buff.mode == "MAINHAND" then
|
|
buff.texture:SetTexture(GetInventoryItemTexture("player", 16))
|
|
buff.backdrop:SetBackdropBorderColor(GetItemQualityColor(GetInventoryItemQuality("player", 16) or 1))
|
|
elseif buff.mode == "OFFHAND" then
|
|
buff.texture:SetTexture(GetInventoryItemTexture("player", 17))
|
|
buff.backdrop:SetBackdropBorderColor(GetItemQualityColor(GetInventoryItemQuality("player", 17) or 1))
|
|
end
|
|
elseif name and (( buff.btype == "HARMFUL" and C.buffs.debuffs == "1" ) or ( buff.btype == "HELPFUL" and C.buffs.buffs == "1" )) then
|
|
-- Set Buff Texture and Border
|
|
buff.mode = buff.btype
|
|
buff.expirationTime = expirationTime
|
|
buff.stackCount = count
|
|
buff.spellId = spellId
|
|
buff.texture:SetTexture(icon)
|
|
|
|
if buff.btype == "HARMFUL" then
|
|
local dispelColor = C_UnitAuras.GetAuraDispelTypeColor(dispelType)
|
|
buff.backdrop:SetBackdropBorderColor(dispelColor:GetRGBA())
|
|
else
|
|
buff.backdrop:SetBackdropBorderColor(br,bg,bb,ba)
|
|
end
|
|
else
|
|
buff:Hide()
|
|
return
|
|
end
|
|
|
|
-- drive the sweep from the aura duration (weapon enchants and permanent
|
|
-- auras report no usable total, so those buttons stay text-only)
|
|
if C.buffs.cooldown_anim == "1" and buff.mode == buff.btype and duration and duration > 0 and expirationTime and expirationTime > 0 then
|
|
local now = GetTime()
|
|
local timeleft = expirationTime - now
|
|
if timeleft > 0 then
|
|
local effDuration = duration > timeleft and duration or timeleft
|
|
local newStart = now + timeleft - effDuration
|
|
if buff.cdStart == nil or abs(buff.cdStart - newStart) > .5 or buff.cdDuration ~= effDuration then
|
|
buff.cd:SetCooldown(newStart, effDuration)
|
|
buff.cdStart = newStart
|
|
buff.cdDuration = effDuration
|
|
end
|
|
else
|
|
buff.cd:Clear()
|
|
buff.cdStart = nil
|
|
end
|
|
else
|
|
buff.cd:Clear()
|
|
buff.cdStart = nil
|
|
end
|
|
|
|
buff:Show()
|
|
end
|
|
|
|
local function CreateBuffButton(i, btype, weapon)
|
|
local buttonName, buttonParent
|
|
if btype == "HELPFUL" then
|
|
if weapon == 1 then
|
|
buttonName = "pfWepBuffFrame" .. i
|
|
buttonParent = pfUI.buff.wepbuffs
|
|
else
|
|
buttonName = "pfBuffFrameBuff" .. i
|
|
buttonParent = pfUI.buff.buffs
|
|
end
|
|
else
|
|
buttonName = "pfDebuffFrameBuff" .. i
|
|
buttonParent = pfUI.buff.debuffs
|
|
end
|
|
local buff = CreateFrame("Button", buttonName, buttonParent)
|
|
buff.texture = buff:CreateTexture("BuffIcon" .. i, "BACKGROUND")
|
|
buff.texture:SetTexCoord(.07,.93,.07,.93)
|
|
buff.texture:SetAllPoints(buff)
|
|
|
|
-- overlay lifts the texts above the sweep: a child frame renders above
|
|
-- all of its parent's own regions, so the timer would dim under the
|
|
-- dark wedge otherwise (same reason pfCooldownText is its own frame)
|
|
buff.overlay = CreateFrame("Frame", nil, buff)
|
|
buff.overlay:SetAllPoints(buff)
|
|
|
|
buff.timer = buff.overlay:CreateFontString(nil, "OVERLAY", "GameFontNormal")
|
|
buff.timer:SetTextColor(1,1,1,1)
|
|
buff.timer:SetJustifyH("CENTER")
|
|
buff.timer:SetJustifyV("CENTER")
|
|
|
|
buff.stacks = buff.overlay:CreateFontString(nil, "OVERLAY", "GameFontNormal")
|
|
buff.stacks:SetTextColor(1,1,1,1)
|
|
buff.stacks:SetJustifyH("RIGHT")
|
|
buff.stacks:SetJustifyV("BOTTOM")
|
|
buff.stacks:SetAllPoints(buff)
|
|
|
|
-- radial sweep (the template covers the button and starts hidden).
|
|
-- RefreshBuffButton drives it through the frame's own methods, never
|
|
-- CooldownFrame_SetTimer, so the cooldown module's hook leaves it alone;
|
|
-- text stays with buff.timer
|
|
buff.cd = CreateFrame("Cooldown", buttonName .. "Cooldown", buff, "CooldownFrameTemplate")
|
|
buff.cd:SetFrameLevel(buff:GetFrameLevel() + 1)
|
|
buff.overlay:SetFrameLevel(buff:GetFrameLevel() + 2)
|
|
|
|
buff:RegisterForClicks("RightButtonUp")
|
|
|
|
buff.weapon = weapon
|
|
buff.btype = btype
|
|
buff.gid = i
|
|
|
|
-- PERF: OnUpdate moved to consolidated parent frame handler (see pfUI.buff:SetScript("OnUpdate"))
|
|
-- Individual buff frames no longer have their own OnUpdate
|
|
|
|
buff:SetScript("OnEnter", function()
|
|
GameTooltip:SetOwner(this, "ANCHOR_BOTTOMRIGHT")
|
|
if this.mode == this.btype then
|
|
GameTooltip:SetUnitAura("player", this.id, this.btype)
|
|
|
|
if IsShiftKeyDown() then
|
|
local aura = C_UnitAuras.GetAuraDataByIndex("player", this.id, this.btype)
|
|
local playerlist = aura and GetUnbuffedRoster(aura.name) or ""
|
|
if strlen(playerlist) > 0 then
|
|
GameTooltip:AddLine(" ")
|
|
GameTooltip:AddLine(T["Unbuffed"] .. ":", .3, 1, .8)
|
|
GameTooltip:AddLine(playerlist,1,1,1,1)
|
|
GameTooltip:Show()
|
|
end
|
|
end
|
|
elseif this.mode == "MAINHAND" then
|
|
GameTooltip:SetInventoryItem("player", 16)
|
|
elseif this.mode == "OFFHAND" then
|
|
GameTooltip:SetInventoryItem("player", 17)
|
|
end
|
|
end)
|
|
|
|
buff:SetScript("OnLeave", GameTooltip_Hide)
|
|
|
|
buff:SetScript("OnClick", function()
|
|
if this.spellId then
|
|
C_Spell.CancelSpellByID(this.spellId)
|
|
end
|
|
end)
|
|
|
|
RefreshBuffButton(buff)
|
|
|
|
return buff
|
|
end
|
|
|
|
pfUI.buff = CreateFrame("Frame", "pfGlobalBuffFrame", UIParent)
|
|
pfUI.buff:RegisterEvent("PLAYER_AURAS_CHANGED")
|
|
pfUI.buff:RegisterEvent("PLAYER_EQUIPMENT_CHANGED")
|
|
pfUI.buff:RegisterUnitEvent("UNIT_MODEL_CHANGED", "player")
|
|
pfUI.buff:RegisterEvent("BUFF_UPDATE_DURATION_SELF")
|
|
pfUI.buff:RegisterEvent("DEBUFF_UPDATE_DURATION_SELF")
|
|
pfUI.buff:SetScript("OnEvent", function()
|
|
|
|
if C.buffs.weapons == "1" then
|
|
local mh, mhtime, mhcharge, oh, ohtime, ohcharge = GetWeaponEnchantInfo()
|
|
pfUI.buff.wepbuffs.count = (mh and 1 or 0) + (oh and 1 or 0)
|
|
else
|
|
pfUI.buff.wepbuffs.count = 0
|
|
end
|
|
|
|
ScanPlayerAuraSlots()
|
|
|
|
for i=1,32 do
|
|
RefreshBuffButton(pfUI.buff.buffs.buttons[i])
|
|
end
|
|
|
|
for i=1,16 do
|
|
RefreshBuffButton(pfUI.buff.debuffs.buttons[i])
|
|
end
|
|
|
|
if C.buffs.separateweapons == "1" then
|
|
for i=1,2 do
|
|
RefreshBuffButton(pfUI.buff.wepbuffs.buttons[i])
|
|
end
|
|
end
|
|
end)
|
|
|
|
-- PERF: Consolidated OnUpdate handler for all buff timers
|
|
-- This replaces 50 individual OnUpdate handlers with a single one
|
|
pfUI.buff:SetScript("OnUpdate", function()
|
|
local now = GetTime()
|
|
if not this.nextUpdate then this.nextUpdate = now + 0.1 end
|
|
if this.nextUpdate > now then return end
|
|
this.nextUpdate = now + 0.1
|
|
|
|
-- Cache weapon enchant info once per update cycle
|
|
local mh, mhtime, mhcharge, oh, ohtime, ohcharge = GetWeaponEnchantInfo()
|
|
|
|
-- Update all visible buff buttons
|
|
local buttons = pfUI.buff.buffs.buttons
|
|
for i = 1, 32 do
|
|
local buff = buttons[i]
|
|
if buff:IsShown() then
|
|
local timeleft, stacks = 0, 0
|
|
if buff.mode == buff.btype then
|
|
timeleft = buff.expirationTime > 0 and (buff.expirationTime - now) or 0
|
|
stacks = buff.stackCount or 0
|
|
elseif buff.mode == "MAINHAND" then
|
|
timeleft = mhtime and mhtime / 1000 or 0
|
|
stacks = mhcharge or 0
|
|
elseif buff.mode == "OFFHAND" then
|
|
timeleft = ohtime and ohtime / 1000 or 0
|
|
stacks = ohcharge or 0
|
|
end
|
|
buff.timer:SetText(timeleft > 0 and GetColoredTimeString(timeleft) or "")
|
|
buff.stacks:SetText(stacks > 1 and stacks or "")
|
|
end
|
|
end
|
|
|
|
-- Update all visible debuff buttons
|
|
buttons = pfUI.buff.debuffs.buttons
|
|
for i = 1, 16 do
|
|
local buff = buttons[i]
|
|
if buff:IsShown() then
|
|
local timeleft = buff.expirationTime > 0 and (buff.expirationTime - now) or 0
|
|
local stacks = buff.stackCount or 0
|
|
buff.timer:SetText(timeleft > 0 and GetColoredTimeString(timeleft) or "")
|
|
buff.stacks:SetText(stacks > 1 and stacks or "")
|
|
end
|
|
end
|
|
|
|
-- Update weapon buff buttons if separate
|
|
if C.buffs.separateweapons == "1" then
|
|
buttons = pfUI.buff.wepbuffs.buttons
|
|
for i = 1, 2 do
|
|
local buff = buttons[i]
|
|
if buff:IsShown() then
|
|
local timeleft, stacks = 0, 0
|
|
if buff.mode == "MAINHAND" then
|
|
timeleft = mhtime and mhtime / 1000 or 0
|
|
stacks = mhcharge or 0
|
|
elseif buff.mode == "OFFHAND" then
|
|
timeleft = ohtime and ohtime / 1000 or 0
|
|
stacks = ohcharge or 0
|
|
end
|
|
buff.timer:SetText(timeleft > 0 and GetColoredTimeString(timeleft) or "")
|
|
buff.stacks:SetText(stacks > 1 and stacks or "")
|
|
end
|
|
end
|
|
end
|
|
end)
|
|
|
|
-- CreateBuffButton refreshes each new button from the slot buffers
|
|
ScanPlayerAuraSlots()
|
|
|
|
-- Weapon Buffs
|
|
pfUI.buff.wepbuffs = CreateFrame("Frame", "pfWepBuffFrame", UIParent)
|
|
pfUI.buff.wepbuffs.count = 0
|
|
pfUI.buff.wepbuffs.buttons = {}
|
|
for i=1,2 do
|
|
pfUI.buff.wepbuffs.buttons[i] = CreateBuffButton(i, "HELPFUL", 1)
|
|
end
|
|
|
|
-- Buff Frame
|
|
pfUI.buff.buffs = CreateFrame("Frame", "pfBuffFrame", UIParent)
|
|
pfUI.buff.buffs.buttons = {}
|
|
for i=1,32 do
|
|
pfUI.buff.buffs.buttons[i] = CreateBuffButton(i, "HELPFUL")
|
|
end
|
|
|
|
-- Debuffs
|
|
pfUI.buff.debuffs = CreateFrame("Frame", "pfDebuffFrame", UIParent)
|
|
pfUI.buff.debuffs.buttons = {}
|
|
for i=1,16 do
|
|
pfUI.buff.debuffs.buttons[i] = CreateBuffButton(i, "HARMFUL")
|
|
end
|
|
|
|
-- config loading
|
|
function pfUI.buff:UpdateConfigBuffButton(buff)
|
|
local fontsize = C.buffs.fontsize == "-1" and C.global.font_size or C.buffs.fontsize
|
|
local buffSize, buffSpacing = tonumber(C.buffs.size), tonumber(C.buffs.spacing)
|
|
local rowcount, relFrame, offsetX, offsetY
|
|
if buff.btype == "HELPFUL" then
|
|
if buff.weapon == 1 and C.buffs.separateweapons == "1" then
|
|
rowcount = floor((buff.gid-1) / tonumber(C.buffs.wepbuffrowsize))
|
|
relFrame = pfUI.buff.wepbuffs
|
|
offsetX = -(buff.gid-1-rowcount*tonumber(C.buffs.wepbuffrowsize))*(buffSize+2*buffSpacing)
|
|
offsetY = -(rowcount) * ((C.buffs.textinside == "1" and 0 or (fontsize*1.5))+buffSize+2*buffSpacing)
|
|
else
|
|
rowcount = floor((buff.gid-1) / tonumber(C.buffs.buffrowsize))
|
|
relFrame = pfUI.buff.buffs
|
|
offsetX = -(buff.gid-1-rowcount*tonumber(C.buffs.buffrowsize))*(buffSize+2*buffSpacing)
|
|
offsetY = -(rowcount) * ((C.buffs.textinside == "1" and 0 or (fontsize*1.5))+buffSize+2*buffSpacing)
|
|
end
|
|
else
|
|
rowcount = floor((buff.gid-1) / tonumber(C.buffs.debuffrowsize))
|
|
relFrame = pfUI.buff.debuffs
|
|
offsetX = -(buff.gid-1-rowcount*tonumber(C.buffs.debuffrowsize))*(buffSize+2*buffSpacing)
|
|
offsetY = -(rowcount) * ((C.buffs.textinside == "1" and 0 or (fontsize*1.5))+buffSize+2*buffSpacing)
|
|
end
|
|
buff:SetSize(buffSize, buffSize)
|
|
buff.cd:SetReverse(C.buffs.cooldown_reverse == "1")
|
|
buff:ClearAllPoints()
|
|
buff:SetPoint("TOPRIGHT", relFrame, "TOPRIGHT",offsetX, offsetY)
|
|
|
|
buff.timer:SetFont(pfUI.font_default, fontsize, "OUTLINE")
|
|
buff.stacks:SetFont(pfUI.font_default, fontsize+1, "OUTLINE")
|
|
|
|
buff.timer:SetHeight(fontsize * 1.3)
|
|
|
|
buff.timer:ClearAllPoints()
|
|
if C.buffs.textinside == "1" then
|
|
buff.timer:SetAllPoints(buff)
|
|
else
|
|
buff.timer:SetPoint("TOP", buff, "BOTTOM", 0, -3)
|
|
end
|
|
end
|
|
|
|
function pfUI.buff:UpdateConfig()
|
|
local fontsize = C.buffs.fontsize == "-1" and C.global.font_size or C.buffs.fontsize
|
|
|
|
local spacing = tonumber(C.buffs.spacing)
|
|
local cell = tonumber(C.buffs.size) + 2 * spacing
|
|
local rowextra = C.buffs.textinside == "1" and 0 or (fontsize * 1.5)
|
|
|
|
local function SizeBuffFrame(frame, rowsize, count)
|
|
rowsize = tonumber(rowsize)
|
|
frame:SetSize(rowsize * cell, ceil(count / rowsize) * (rowextra + cell))
|
|
end
|
|
|
|
SizeBuffFrame(pfUI.buff.buffs, C.buffs.buffrowsize, 32)
|
|
pfUI.buff.buffs:SetPoint("TOPRIGHT", pfUI.minimap or UIParent, "TOPLEFT", -4 * spacing, 0)
|
|
UpdateMovable(pfUI.buff.buffs)
|
|
|
|
SizeBuffFrame(pfUI.buff.debuffs, C.buffs.debuffrowsize, 16)
|
|
pfUI.buff.debuffs:SetPoint("TOPRIGHT", pfUI.buff.buffs, "BOTTOMRIGHT", 0, 0)
|
|
UpdateMovable(pfUI.buff.debuffs)
|
|
|
|
if C.buffs.separateweapons == "1" then
|
|
pfUI.buff.wepbuffs:ClearAllPoints()
|
|
SizeBuffFrame(pfUI.buff.wepbuffs, C.buffs.wepbuffrowsize, 2)
|
|
pfUI.buff.wepbuffs:SetPoint("TOPRIGHT", pfUI.buff.debuffs, "BOTTOMRIGHT", 0, 0)
|
|
pfUI.buff.wepbuffs:Show()
|
|
UpdateMovable(pfUI.buff.wepbuffs)
|
|
else
|
|
pfUI.buff.wepbuffs:Hide()
|
|
RemoveMovable(pfUI.buff.wepbuffs)
|
|
end
|
|
|
|
for i=1,32 do
|
|
pfUI.buff:UpdateConfigBuffButton(pfUI.buff.buffs.buttons[i])
|
|
end
|
|
|
|
for i=1,16 do
|
|
pfUI.buff:UpdateConfigBuffButton(pfUI.buff.debuffs.buttons[i])
|
|
end
|
|
|
|
for i=1,2 do
|
|
pfUI.buff:UpdateConfigBuffButton(pfUI.buff.wepbuffs.buttons[i])
|
|
end
|
|
|
|
pfUI.buff:GetScript("OnEvent")()
|
|
end
|
|
|
|
pfUI.buff:UpdateConfig()
|
|
end)
|