mirror of
https://github.com/brues-code/pfUI.git
synced 2026-11-01 08:26:57 +00:00
Every pfUI cooldown is now made by CreateCooldown(parent, kind) in the new api/cooldown.lua, which replaces the cooldown module. A kind names what the cooldown times: actionbar, bags, blizzard (spellbook and character), unitframe, indicator, nameplate, buff, tooltip, totem or lossofcontrol. The pfCooldownType, pfCooldownStyleText, pfCooldownStyleAnimation and pfCooldownSize fields are gone. The new file owns everything the cooldowns share: - the numbers' font and size - the formatter - each kind's numbers, sweep and sweep direction - the GCD threshold for spell kinds - the CooldownFrame_SetTimer hook for other addons' Cooldown frames UpdateCooldowns applies changed settings to every cooldown at once. GetAuraTimer moves here from the unit frames. All settings live in one C.cooldown table, on one page: Settings -> Cooldown. It has the shared font, size, threshold, tenths and colors, then "Show Numbers On", "Show Sweep On" and "Reverse Sweep On" lists with a checkbox per kind. The per-module options are removed: - each unit frame's timer text, animation and reverse, and the indicators' "Show Time Left" - the nameplate debuff timer options - the Blizzard and foreign font sizes and toggles - Action Bars' cooldown text size - the reverse options of bars, bags, buffs and totems The old appearance.cd settings are not migrated. The player buff frame and the tooltip aura icons now show the native countdown too, which replaces their own text and OnUpdate ticking. The buff frame keeps its inside or below-the-icon placement. Weapon enchants report only their time left, so they start through SetCooldownTimeLeft: numbers, no sweep. A slim poll remains for their charges and renewals, since no event reports those. Buff indicators now take the aura's real duration, which gives them a correct sweep. The spellbook and character slots now hide GCD numbers like the other spell cooldowns.
374 lines
13 KiB
Lua
374 lines
13 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
|
|
|
|
-- weapon enchants report only their time left, and no event as their
|
|
-- charges and time run down, so the OnUpdate below refreshes their buttons
|
|
-- too: the charges, and the timer when the enchant was renewed
|
|
local function RefreshWeaponButton(buff, timeleft, charges)
|
|
timeleft = (timeleft or 0) / 1000
|
|
charges = charges or 0
|
|
buff.stacks:SetText(charges > 1 and charges or "")
|
|
|
|
local expires = GetTime() + timeleft
|
|
if timeleft <= 0 then
|
|
buff.cd:Clear()
|
|
buff.cdExpires = nil
|
|
elseif not buff.cdExpires or abs(buff.cdExpires - expires) > 1 then
|
|
SetCooldownTimeLeft(buff.cd, timeleft)
|
|
buff.cdExpires = expires
|
|
end
|
|
buff.cdStart = nil
|
|
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, Border and Timer
|
|
if buff.mode == "MAINHAND" then
|
|
buff.texture:SetTexture(GetInventoryItemTexture("player", 16))
|
|
buff.backdrop:SetBackdropBorderColor(GetItemQualityColor(GetInventoryItemQuality("player", 16) or 1))
|
|
RefreshWeaponButton(buff, mhtime, mhcharge)
|
|
elseif buff.mode == "OFFHAND" then
|
|
buff.texture:SetTexture(GetInventoryItemTexture("player", 17))
|
|
buff.backdrop:SetBackdropBorderColor(GetItemQualityColor(GetInventoryItemQuality("player", 17) or 1))
|
|
RefreshWeaponButton(buff, ohtime, ohcharge)
|
|
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.spellId = spellId
|
|
buff.texture:SetTexture(icon)
|
|
buff.stacks:SetText((count or 0) > 1 and count or "")
|
|
|
|
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
|
|
|
|
-- start the timer from the aura's duration; permanent auras have none
|
|
local start, dur = GetAuraTimer(duration, expirationTime)
|
|
if dur <= 0 then
|
|
buff.cd:Clear()
|
|
buff.cdStart = nil
|
|
elseif buff.cdStart == nil or abs(buff.cdStart - start) > .5 or buff.cdDuration ~= dur then
|
|
CooldownFrame_SetTimer(buff.cd, start, dur, 1)
|
|
buff.cdStart = start
|
|
buff.cdDuration = dur
|
|
end
|
|
buff.cdExpires = nil
|
|
else
|
|
buff:Hide()
|
|
return
|
|
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 stacks above the sweep: a child frame renders above
|
|
-- all of its parent's own regions, so they would dim under the dark
|
|
-- wedge otherwise
|
|
buff.overlay = CreateFrame("Frame", nil, buff)
|
|
buff.overlay:SetAllPoints(buff)
|
|
|
|
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)
|
|
|
|
-- the sweep and the duration numbers (the template covers the button and
|
|
-- starts hidden); RefreshBuffButton starts its timer
|
|
buff.cd = CreateCooldown(buff, "buff", buttonName .. "Cooldown")
|
|
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)
|
|
|
|
-- the buttons that can show a weapon enchant: the first two buffs, or the
|
|
-- separate weapon buttons
|
|
local weaponButtons
|
|
|
|
-- weapon enchants, see RefreshWeaponButton
|
|
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
|
|
|
|
local _, mhtime, mhcharge, _, ohtime, ohcharge = GetWeaponEnchantInfo()
|
|
for _, buff in ipairs(weaponButtons) do
|
|
if buff:IsShown() then
|
|
if buff.mode == "MAINHAND" then
|
|
RefreshWeaponButton(buff, mhtime, mhcharge)
|
|
elseif buff.mode == "OFFHAND" then
|
|
RefreshWeaponButton(buff, ohtime, ohcharge)
|
|
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
|
|
|
|
weaponButtons = {
|
|
pfUI.buff.buffs.buttons[1], pfUI.buff.buffs.buttons[2],
|
|
pfUI.buff.wepbuffs.buttons[1], pfUI.buff.wepbuffs.buttons[2],
|
|
}
|
|
|
|
-- 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 rowextra = C.buffs.textinside == "1" and 0 or GetCooldownFontSize(buffSize) * 1.5
|
|
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) * (rowextra+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) * (rowextra+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) * (rowextra+buffSize+2*buffSpacing)
|
|
end
|
|
buff:SetSize(buffSize, buffSize)
|
|
buff:ClearAllPoints()
|
|
buff:SetPoint("TOPRIGHT", relFrame, "TOPRIGHT",offsetX, offsetY)
|
|
|
|
buff.stacks:SetFont(pfUI.font_default, fontsize+1, "OUTLINE")
|
|
|
|
-- the duration numbers sit inside the icon or below it
|
|
local countdown = buff.cd:GetCountdownFontString()
|
|
countdown:ClearAllPoints()
|
|
if C.buffs.textinside == "1" then
|
|
countdown:SetPoint("CENTER", buff, "CENTER", 0, 0)
|
|
else
|
|
countdown:SetPoint("TOP", buff, "BOTTOM", 0, -3)
|
|
end
|
|
end
|
|
|
|
function pfUI.buff:UpdateConfig()
|
|
local spacing = tonumber(C.buffs.spacing)
|
|
local cell = tonumber(C.buffs.size) + 2 * spacing
|
|
local rowextra = C.buffs.textinside == "1" and 0 or GetCooldownFontSize(tonumber(C.buffs.size)) * 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)
|