Files
ShaguTweaks-ClassicAPI/mods/improved-castbar.lua
T

198 lines
6.8 KiB
Lua

local T = ShaguTweaks.T
local module = ShaguTweaks:register({
title = T["Improved Castbar"],
description = T["Adds a spell icon and remaining cast time to the cast bar."],
expansions = { ["vanilla"] = true },
category = T["General"],
enabled = nil,
})
module.enable = function(self)
local _G = ShaguTweaks.GetGlobalEnv()
local API = ShaguTweaks.API
local LegacyCastingInfo = ShaguTweaks.UnitCastingInfo
local LegacyChannelInfo = ShaguTweaks.UnitChannelInfo
local castbar = CreateFrame("FRAME", "STImprovedCastbar", CastingBarFrame)
castbar:Hide()
castbar.texture = CreateFrame("Frame", nil, castbar)
castbar.texture:SetPoint("RIGHT", CastingBarFrame, "LEFT", -10, 2)
castbar.texture:SetWidth(28)
castbar.texture:SetHeight(28)
castbar.texture.icon = castbar.texture:CreateTexture(nil, "BACKGROUND")
castbar.texture.icon:SetPoint("CENTER", 0, 0)
castbar.texture.icon:SetWidth(24)
castbar.texture.icon:SetHeight(24)
castbar.texture:SetBackdrop({
edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border",
tile = true, tileSize = 8, edgeSize = 12,
insets = { left = 2, right = 2, top = 2, bottom = 2 }
})
if ShaguTweaks.DarkMode then
castbar.texture:SetBackdropBorderColor(.3, .3, .3, .9)
end
castbar.spellText = castbar:CreateFontString(nil, "HIGH", "GameFontWhite")
castbar.spellText:SetPoint("CENTER", CastingBarFrame, "CENTER", 0, 3)
local font, size, opts = castbar.spellText:GetFont()
castbar.spellText:SetFont(font, size, "THINOUTLINE")
castbar.timerText = castbar:CreateFontString(nil, "HIGH", "GameFontWhite")
castbar.timerText:SetPoint("RIGHT", CastingBarFrame, "RIGHT", -5, 3)
castbar.timerText:SetFont(font, size, "THINOUTLINE")
CastingBarText:Hide()
local function QueryPlayerCast()
if API and API.casts then
local cast, nameSubtext, text, texture, startTime, endTime, isTradeSkill = API.GetCastInfo("player")
if cast then
return cast, nameSubtext, text, texture, startTime, endTime, isTradeSkill, false
end
local channel
channel, nameSubtext, text, texture, startTime, endTime, isTradeSkill = API.GetChannelInfo("player")
if channel then
return channel, nameSubtext, text, texture, startTime, endTime, isTradeSkill, true
end
end
local cast, nameSubtext, text, texture, startTime, endTime, isTradeSkill = LegacyCastingInfo("player")
if cast then
return cast, nameSubtext, text, texture, startTime, endTime, isTradeSkill, false
end
local channel
channel, nameSubtext, text, texture, startTime, endTime, isTradeSkill = LegacyChannelInfo("player")
if channel then
return channel, nameSubtext, text, texture, startTime, endTime, isTradeSkill, true
end
end
local function UpdateTimer()
castbar:SetAlpha(CastingBarFrame:GetAlpha())
local startTime = castbar.startTime
local endTime = castbar.endTime
if not startTime or not endTime or endTime <= startTime then
if CastingBarFrame:GetAlpha() == 0 then
castbar:Hide()
end
return
end
local now = GetTime()
local max = endTime - startTime
local cur
if castbar.isChannel then
cur = endTime - now
else
cur = now - startTime
end
cur = cur > max and max or cur
cur = cur < 0 and 0 or cur
local rem = castbar.isChannel and cur or (max - cur)
rem = rem < 0 and 0 or rem
castbar.timerText:SetText(string.format("%.1f"..T["s"], rem))
if now >= endTime then
castbar.startTime = nil
castbar.endTime = nil
end
end
local function RefreshCast()
local cast, nameSubtext, text, texture, startTime, endTime, isTradeSkill, isChannel = QueryPlayerCast()
if not cast or not startTime or not endTime or endTime <= startTime then
-- Preserve Blizzard's normal fade-out: keep our last icon/text
-- attached until the native castbar has finished fading.
castbar.startTime = nil
castbar.endTime = nil
castbar.isChannel = nil
if CastingBarFrame:GetAlpha() == 0 then
castbar:Hide()
end
return
end
castbar.startTime = startTime / 1000
castbar.endTime = endTime / 1000
castbar.isChannel = isChannel
castbar.spellText:SetText(cast)
if texture then
castbar.texture.icon:SetTexture(texture)
castbar.texture.icon:Show()
else
castbar.texture.icon:Hide()
end
castbar.elapsed = 0
castbar:Show()
UpdateTimer()
end
-- The expensive cast/channel query now runs only on state-change events.
-- While visible, OnUpdate only animates the remaining-time text and alpha.
castbar.elapsed = 0
castbar:SetScript("OnUpdate", function()
this.elapsed = (this.elapsed or 0) + arg1
if this.elapsed < .05 then return end
this.elapsed = 0
UpdateTimer()
end)
local events = CreateFrame("Frame", nil, UIParent)
events:RegisterEvent("PLAYER_ENTERING_WORLD")
local classicEvents = {
"UNIT_SPELLCAST_START",
"UNIT_SPELLCAST_STOP",
"UNIT_SPELLCAST_INTERRUPTED",
"UNIT_SPELLCAST_FAILED",
"UNIT_SPELLCAST_DELAYED",
"UNIT_SPELLCAST_CHANNEL_START",
"UNIT_SPELLCAST_CHANNEL_STOP",
"UNIT_SPELLCAST_CHANNEL_UPDATE",
}
local hasClassicEvents = false
if API and API.eventutils and _G.C_EventUtils and _G.C_EventUtils.IsEventValid then
for _, eventName in pairs(classicEvents) do
if _G.C_EventUtils.IsEventValid(eventName) then
events:RegisterEvent(eventName)
hasClassicEvents = true
end
end
end
if not hasClassicEvents then
-- Compatibility with older ClassicAPI/plain 1.12: use the original
-- player spellcast events as state-change triggers, not as a poller.
events:RegisterEvent("SPELLCAST_START")
events:RegisterEvent("SPELLCAST_STOP")
events:RegisterEvent("SPELLCAST_FAILED")
events:RegisterEvent("SPELLCAST_INTERRUPTED")
events:RegisterEvent("SPELLCAST_DELAYED")
events:RegisterEvent("SPELLCAST_CHANNEL_START")
events:RegisterEvent("SPELLCAST_CHANNEL_STOP")
events:RegisterEvent("SPELLCAST_CHANNEL_UPDATE")
end
events:SetScript("OnEvent", function()
if event == "PLAYER_ENTERING_WORLD" then
RefreshCast()
return
end
if hasClassicEvents and arg1 ~= "player" then return end
RefreshCast()
end)
end