Swing timer: bars fill from duration objects, drop the OnUpdate

Each bar fills itself from a duration object of the swing, a text
binding counts it down, and the marker with its glows rides the fill's
edge. One C_Timer per bar ends the swing, runs the melee grace and
switches a hunter's reload to the deadzone. Colors update on the events
that change them, ACTIONBAR_UPDATE_STATE standing in for the per-tick
IsCurrentAction reconcile; a bar waiting past its grace hides on
STOP_AUTOATTACK or leaving combat. The three bar builders become one.

The Swing Timer throttle setting only paced the OnUpdate, so it goes.
This commit is contained in:
Brues
2026-11-03 01:07:02 -06:00
parent 9187155ea6
commit 14ae659f2a
3 changed files with 230 additions and 520 deletions
-2
View File
@@ -33,7 +33,6 @@ libthrottle.presetNames = {
libthrottle.defaults = { libthrottle.defaults = {
tooltip_cursor = "fastest", tooltip_cursor = "fastest",
chat_tab = "custom", chat_tab = "custom",
swingtimer = "custom",
} }
-- Convert FPS to throttle delay in seconds -- Convert FPS to throttle delay in seconds
@@ -156,7 +155,6 @@ libthrottle:SetScript("OnEvent", function()
-- Set defaults for custom fields if missing -- Set defaults for custom fields if missing
if not _G.pfUI_throttle.tooltip_cursor_custom then _G.pfUI_throttle.tooltip_cursor_custom = "10" end if not _G.pfUI_throttle.tooltip_cursor_custom then _G.pfUI_throttle.tooltip_cursor_custom = "10" end
if not _G.pfUI_throttle.chat_tab_custom then _G.pfUI_throttle.chat_tab_custom = "10" end if not _G.pfUI_throttle.chat_tab_custom then _G.pfUI_throttle.chat_tab_custom = "10" end
if not _G.pfUI_throttle.swingtimer_custom then _G.pfUI_throttle.swingtimer_custom = "50" end
this:UnregisterEvent("PLAYER_ENTERING_WORLD") this:UnregisterEvent("PLAYER_ENTERING_WORLD")
end end
-61
View File
@@ -1788,67 +1788,6 @@ pfUI:RegisterModule("gui", function ()
end, true) end, true)
end) end)
CreateGUIEntry(T["Throttling"], T["Swing Timer"], function()
local swingCustom
CreateConfig(function()
if swingCustom and swingCustom.input then
local isCustom = pfUI.throttle:IsCustom("swingtimer")
if not isCustom then
swingCustom.input:EnableMouse(false)
swingCustom.input:EnableKeyboard(false)
swingCustom.input:ClearFocus()
swingCustom.input:SetTextColor(.5,.5,.5,1)
swingCustom.input:SetText(tostring(pfUI.throttle:GetFps("swingtimer")))
else
swingCustom.input:EnableMouse(true)
swingCustom.input:EnableKeyboard(true)
swingCustom.input:SetTextColor(.2,1,.8,1)
if _G.pfUI_throttle.swingtimer_custom then
swingCustom.input:SetText(_G.pfUI_throttle.swingtimer_custom)
end
end
end
end, T["Swing Timer Update Rate"], _G.pfUI_throttle, "swingtimer", "dropdown", {
"very_slow:" .. T["Very Slow"] .. " (2 FPS)",
"slow:" .. T["Slow"] .. " (5 FPS)",
"normal:" .. T["Normal"] .. " (10 FPS)",
"fast:" .. T["Fast"] .. " (20 FPS)",
"very_fast:" .. T["Very Fast"] .. " (30 FPS)",
"fastest:" .. T["Fastest"] .. " (50 FPS)",
"custom:" .. T["Custom"],
})
swingCustom = CreateConfig(nil, T["Custom FPS"], _G.pfUI_throttle, "swingtimer_custom")
local isCustom = pfUI.throttle:IsCustom("swingtimer")
if not isCustom then
swingCustom.input:EnableMouse(false)
swingCustom.input:EnableKeyboard(false)
swingCustom.input:SetTextColor(.5,.5,.5,1)
swingCustom.input:SetText(tostring(pfUI.throttle:GetFps("swingtimer")))
else
swingCustom.input:EnableMouse(true)
swingCustom.input:EnableKeyboard(true)
swingCustom.input:SetTextColor(.2,1,.8,1)
if _G.pfUI_throttle.swingtimer_custom then
swingCustom.input:SetText(_G.pfUI_throttle.swingtimer_custom)
end
end
-- Spacer before reset button
local spacer = CreateConfig(nil, " ", nil, nil, "header")
spacer:GetParent().objectCount = spacer:GetParent().objectCount - 1
spacer:SetHeight(10)
-- Reset to defaults button
CreateConfig(nil, T["Reset to Defaults"], nil, nil, "button", function()
pfUI.throttle:ResetToDefault("swingtimer")
_G.pfUI_throttle.swingtimer_custom = "50"
Reload()
end, true)
end)
CreateGUIEntry(T["Unit Frames"], T["General"], function() CreateGUIEntry(T["Unit Frames"], T["General"], function()
CreateConfig(nil, T["Disable pfUI Unit Frames"], C.unitframes, "disable", "checkbox") CreateConfig(nil, T["Disable pfUI Unit Frames"], C.unitframes, "disable", "checkbox")
CreateConfig(nil, T["Animate Health And Power Bars"], C.unitframes, "animatebars", "checkbox") CreateConfig(nil, T["Animate Health And Power Bars"], C.unitframes, "animatebars", "checkbox")
+230 -457
View File
@@ -5,14 +5,16 @@ pfUI:RegisterModule("swingtimer", function ()
local ON_SWING_QUEUED = 0 local ON_SWING_QUEUED = 0
local ON_SWING_QUEUE_POPPED = 1 local ON_SWING_QUEUE_POPPED = 1
-- seconds a melee bar stays full after its swing is due, to bridge the gap
-- until PLAYER_SWING arrives; it then hides unless auto attack goes on
local GRACE = 0.15
-- the last half second of a hunter's ranged swing, when moving cancels the shot
local DEADZONE = 0.5
-- Consolidate state into a table to avoid Lua 5.0 upvalue limit (32 max) -- Consolidate state into a table to avoid Lua 5.0 upvalue limit (32 max)
local S = { local S = {
mhTimer = 0, mhTimerMax = 1,
ohTimer = 0, ohTimerMax = 1,
raTimer = 0, raTimerMax = 1,
mhSpeed = 0, ohSpeed = 0, raSpeed = 0, mhSpeed = 0, ohSpeed = 0, raSpeed = 0,
mhActive = false, ohActive = false, raActive = false,
lastMhMarkerX = -1, lastOhMarkerX = -1, lastRaMarkerX = -1,
autoAttackActive = false, autoAttackActive = false,
inCombat = false, inCombat = false,
hsQueued = false, cleaveQueued = false, maulQueued = false, hsQueued = false, cleaveQueued = false, maulQueued = false,
@@ -21,7 +23,6 @@ pfUI:RegisterModule("swingtimer", function ()
isDruid = false, isDruid = false,
cachedHSSlots = {}, cachedCleaveSlots = {}, cachedMaulSlots = {}, cachedHSSlots = {}, cachedCleaveSlots = {}, cachedMaulSlots = {},
useSpellQueueEvent = false, useSpellQueueEvent = false,
swingThrottle = 0,
onSwingCache = {}, onSwingCache = {},
outOfRange = {}, -- by Enum.PlayerSwingType outOfRange = {}, -- by Enum.PlayerSwingType
} }
@@ -70,196 +71,111 @@ pfUI:RegisterModule("swingtimer", function ()
local rwR, rwG, rwB, rwA = ParseColor(C.unitframes.swingtimerrangedwarncolor, 0.9, 0.0, 0.0, 1) local rwR, rwG, rwB, rwA = ParseColor(C.unitframes.swingtimerrangedwarncolor, 0.9, 0.0, 0.0, 1)
local orR, orG, orB = ParseColor(C.unitframes.swingtimeroutrangecolor, 0.5, 0.5, 0.5, 1) local orR, orG, orB = ParseColor(C.unitframes.swingtimeroutrangecolor, 0.5, 0.5, 0.5, 1)
local isHunter = UnitClassBase("player") == "HUNTER" local isHunter = UnitClassBase("player") == "HUNTER"
local mhDefaultR, mhDefaultG, mhDefaultB = mhR, mhG, mhB
-- the countdown text, cut down to tenths
local countdown = C_StringUtil.CreateNumericRuleFormatter()
countdown:AddBreakpoint({ threshold = 0, step = 0.1, rounding = Enum.NumericRuleFormatRounding.Down, format = "%.1f" })
-- the container keeps the public API
-- Create container frame
pfUI.swingtimer = CreateFrame("Frame", "pfSwingTimer", UIParent) pfUI.swingtimer = CreateFrame("Frame", "pfSwingTimer", UIParent)
pfUI.swingtimer:SetFrameStrata("MEDIUM")
pfUI.swingtimer:Hide() pfUI.swingtimer:Hide()
-- Mainhand bar -- A bar fills by itself from `swing`, the time span of the whole swing, and
pfUI.swingtimer.mainhand = CreateFrame("StatusBar", "pfSwingTimerMainhand", UIParent) -- its text binding counts it down. The marker and its glows ride the edge
pfUI.swingtimer.mainhand:SetPoint("BOTTOM", UIParent, "CENTER", -189, 103) -- of the fill. `shown` is whether the config lets the bar show at all.
pfUI.swingtimer.mainhand:SetWidth(sw_width) local function CreateSwingBar(name, label, shown)
pfUI.swingtimer.mainhand:SetHeight(sw_height) local bar = CreateFrame("StatusBar", name, UIParent)
pfUI.swingtimer.mainhand:SetMinMaxValues(0, 1) bar:SetWidth(sw_width)
pfUI.swingtimer.mainhand:SetValue(0) bar:SetHeight(sw_height)
pfUI.swingtimer.mainhand:SetStatusBarTexture(sw_texture) bar:SetStatusBarTexture(sw_texture)
pfUI.swingtimer.mainhand:SetStatusBarColor(mhR, mhG, mhB, mhA) bar:Hide()
pfUI.swingtimer.mainhand:Hide() bar.shown = shown
pfUI.swingtimer.mainhand.text = pfUI.swingtimer.mainhand:CreateFontString("Status", "DIALOG", "GameFontNormal") bar.swing = C_DurationUtil.CreateDuration()
pfUI.swingtimer.mainhand.text:SetPoint("CENTER", pfUI.swingtimer.mainhand, "CENTER", 0, 0) bar:SetTimerDuration(bar.swing, Enum.StatusBarInterpolation.Immediate, Enum.StatusBarTimerDirection.ElapsedTime)
pfUI.swingtimer.mainhand.text:SetFont(pfUI.font_default, sw_fontsize, "OUTLINE")
pfUI.swingtimer.mainhand.text:SetTextColor(1, 1, 1, 1)
pfUI.swingtimer.mainhand.text:SetText("")
if not sw_showtext then pfUI.swingtimer.mainhand.text:Hide() end
pfUI.swingtimer.mainhand.label = pfUI.swingtimer.mainhand:CreateFontString("Status", "DIALOG", "GameFontNormal") bar.text = bar:CreateFontString("Status", "DIALOG", "GameFontNormal")
pfUI.swingtimer.mainhand.label:SetPoint("RIGHT", pfUI.swingtimer.mainhand, "LEFT", -4, 0) bar.text:SetPoint("CENTER", bar, "CENTER", 0, 0)
pfUI.swingtimer.mainhand.label:SetFont(pfUI.font_default, sw_fontsize, "OUTLINE") bar.text:SetFont(pfUI.font_default, sw_fontsize, "OUTLINE")
pfUI.swingtimer.mainhand.label:SetTextColor(0.8, 0.8, 0.8, 1) bar.text:SetTextColor(1, 1, 1, 1)
pfUI.swingtimer.mainhand.label:SetText(sw_showlabel and "MH" or "") bar.text:SetShown(sw_showtext)
pfUI.swingtimer.mainhand.speed = pfUI.swingtimer.mainhand:CreateFontString("Status", "DIALOG", "GameFontNormal") bar.timer = C_DurationUtil.CreateDurationTextBinding()
pfUI.swingtimer.mainhand.speed:SetPoint("LEFT", pfUI.swingtimer.mainhand, "RIGHT", 4, 0) bar.timer:SetFontString(bar.text)
pfUI.swingtimer.mainhand.speed:SetFont(pfUI.font_default, sw_fontsize, "OUTLINE") bar.timer:SetDuration(bar.swing)
pfUI.swingtimer.mainhand.speed:SetTextColor(0.8, 0.8, 0.8, 1) bar.timer:SetFormatter(countdown)
pfUI.swingtimer.mainhand.speed:SetText("")
if not sw_showspeed then pfUI.swingtimer.mainhand.speed:Hide() end
CreateBackdrop(pfUI.swingtimer.mainhand) bar.label = bar:CreateFontString("Status", "DIALOG", "GameFontNormal")
bar.label:SetPoint("RIGHT", bar, "LEFT", -4, 0)
bar.label:SetFont(pfUI.font_default, sw_fontsize, "OUTLINE")
bar.label:SetTextColor(0.8, 0.8, 0.8, 1)
bar.label:SetText(sw_showlabel and label or "")
bar.speed = bar:CreateFontString("Status", "DIALOG", "GameFontNormal")
bar.speed:SetPoint("LEFT", bar, "RIGHT", 4, 0)
bar.speed:SetFont(pfUI.font_default, sw_fontsize, "OUTLINE")
bar.speed:SetTextColor(0.8, 0.8, 0.8, 1)
bar.speed:SetShown(sw_showspeed)
pfUI.swingtimer.mainhand.marker = pfUI.swingtimer.mainhand:CreateTexture(nil, "OVERLAY") CreateBackdrop(bar)
pfUI.swingtimer.mainhand.marker:SetColorTexture(1, 1, 1, 1.0)
pfUI.swingtimer.mainhand.marker:SetWidth(2)
pfUI.swingtimer.mainhand.marker:SetHeight(sw_height)
pfUI.swingtimer.mainhand.marker:Hide()
-- Left glow: fades from transparent to white (right edge = marker) bar.edge = CreateFrame("Frame", nil, bar)
pfUI.swingtimer.mainhand.markerGlowL = pfUI.swingtimer.mainhand:CreateTexture(nil, "OVERLAY") bar.edge:SetAllPoints(bar)
pfUI.swingtimer.mainhand.markerGlowL:SetColorTexture(1, 1, 1, 1) bar.edge:Hide()
pfUI.swingtimer.mainhand.markerGlowL:SetGradientAlpha("HORIZONTAL", 1, 1, 1, 0, 1, 1, 1, 0.35)
pfUI.swingtimer.mainhand.markerGlowL:SetWidth(10)
pfUI.swingtimer.mainhand.markerGlowL:SetHeight(sw_height)
pfUI.swingtimer.mainhand.markerGlowL:Hide()
-- Right glow: fades from white to transparent (left edge = marker) bar.marker = bar.edge:CreateTexture(nil, "OVERLAY")
pfUI.swingtimer.mainhand.markerGlowR = pfUI.swingtimer.mainhand:CreateTexture(nil, "OVERLAY") bar.marker:SetColorTexture(1, 1, 1, 1.0)
pfUI.swingtimer.mainhand.markerGlowR:SetColorTexture(1, 1, 1, 1) bar.marker:SetWidth(2)
pfUI.swingtimer.mainhand.markerGlowR:SetGradientAlpha("HORIZONTAL", 1, 1, 1, 0.35, 1, 1, 1, 0) bar.marker:SetHeight(sw_height)
pfUI.swingtimer.mainhand.markerGlowR:SetWidth(10) bar.marker:SetPoint("CENTER", bar:GetStatusBarTexture(), "RIGHT")
pfUI.swingtimer.mainhand.markerGlowR:SetHeight(sw_height)
pfUI.swingtimer.mainhand.markerGlowR:Hide()
CreateBackdropShadow(pfUI.swingtimer.mainhand) -- Left glow: fades from transparent to white (right edge = marker)
bar.markerGlowL = bar.edge:CreateTexture(nil, "OVERLAY")
bar.markerGlowL:SetColorTexture(1, 1, 1, 1)
bar.markerGlowL:SetGradientAlpha("HORIZONTAL", 1, 1, 1, 0, 1, 1, 1, 0.35)
bar.markerGlowL:SetWidth(10)
bar.markerGlowL:SetHeight(sw_height)
bar.markerGlowL:SetPoint("RIGHT", bar.marker, "LEFT", 0, 0)
-- Offhand bar -- Right glow: fades from white to transparent (left edge = marker)
pfUI.swingtimer.offhand = CreateFrame("StatusBar", "pfSwingTimerOffhand", UIParent) bar.markerGlowR = bar.edge:CreateTexture(nil, "OVERLAY")
pfUI.swingtimer.offhand:SetPoint("TOP", pfUI.swingtimer.mainhand, "BOTTOM", 0, -4) bar.markerGlowR:SetColorTexture(1, 1, 1, 1)
pfUI.swingtimer.offhand:SetWidth(sw_width) bar.markerGlowR:SetGradientAlpha("HORIZONTAL", 1, 1, 1, 0.35, 1, 1, 1, 0)
pfUI.swingtimer.offhand:SetHeight(sw_height) bar.markerGlowR:SetWidth(10)
pfUI.swingtimer.offhand:SetMinMaxValues(0, 1) bar.markerGlowR:SetHeight(sw_height)
pfUI.swingtimer.offhand:SetValue(0) bar.markerGlowR:SetPoint("LEFT", bar.marker, "RIGHT", 0, 0)
pfUI.swingtimer.offhand:SetStatusBarTexture(sw_texture)
pfUI.swingtimer.offhand:SetStatusBarColor(ohR, ohG, ohB, ohA)
pfUI.swingtimer.offhand:Hide()
pfUI.swingtimer.offhand.text = pfUI.swingtimer.offhand:CreateFontString("Status", "DIALOG", "GameFontNormal") CreateBackdropShadow(bar)
pfUI.swingtimer.offhand.text:SetPoint("CENTER", pfUI.swingtimer.offhand, "CENTER", 0, 0) return bar
pfUI.swingtimer.offhand.text:SetFont(pfUI.font_default, sw_fontsize, "OUTLINE") end
pfUI.swingtimer.offhand.text:SetTextColor(1, 1, 1, 1)
pfUI.swingtimer.offhand.text:SetText("")
if not sw_showtext then pfUI.swingtimer.offhand.text:Hide() end
pfUI.swingtimer.offhand.label = pfUI.swingtimer.offhand:CreateFontString("Status", "DIALOG", "GameFontNormal") local mainhand = CreateSwingBar("pfSwingTimerMainhand", "MH", true)
pfUI.swingtimer.offhand.label:SetPoint("RIGHT", pfUI.swingtimer.offhand, "LEFT", -4, 0) mainhand:SetPoint("BOTTOM", UIParent, "CENTER", -189, 103)
pfUI.swingtimer.offhand.label:SetFont(pfUI.font_default, sw_fontsize, "OUTLINE") mainhand.showmarker = true
pfUI.swingtimer.offhand.label:SetTextColor(0.8, 0.8, 0.8, 1)
pfUI.swingtimer.offhand.label:SetText(sw_showlabel and "OH" or "")
pfUI.swingtimer.offhand.speed = pfUI.swingtimer.offhand:CreateFontString("Status", "DIALOG", "GameFontNormal") local offhand = CreateSwingBar("pfSwingTimerOffhand", "OH", sw_showoh)
pfUI.swingtimer.offhand.speed:SetPoint("LEFT", pfUI.swingtimer.offhand, "RIGHT", 4, 0) offhand:SetPoint("TOP", mainhand, "BOTTOM", 0, -4)
pfUI.swingtimer.offhand.speed:SetFont(pfUI.font_default, sw_fontsize, "OUTLINE") offhand.showmarker = true
pfUI.swingtimer.offhand.speed:SetTextColor(0.8, 0.8, 0.8, 1)
pfUI.swingtimer.offhand.speed:SetText("")
if not sw_showspeed then pfUI.swingtimer.offhand.speed:Hide() end
CreateBackdrop(pfUI.swingtimer.offhand)
pfUI.swingtimer.offhand.marker = pfUI.swingtimer.offhand:CreateTexture(nil, "OVERLAY")
pfUI.swingtimer.offhand.marker:SetColorTexture(1, 1, 1, 1.0)
pfUI.swingtimer.offhand.marker:SetWidth(2)
pfUI.swingtimer.offhand.marker:SetHeight(sw_height)
pfUI.swingtimer.offhand.marker:Hide()
-- Left glow: fades from transparent to white (right edge = marker)
pfUI.swingtimer.offhand.markerGlowL = pfUI.swingtimer.offhand:CreateTexture(nil, "OVERLAY")
pfUI.swingtimer.offhand.markerGlowL:SetColorTexture(1, 1, 1, 1)
pfUI.swingtimer.offhand.markerGlowL:SetGradientAlpha("HORIZONTAL", 1, 1, 1, 0, 1, 1, 1, 0.35)
pfUI.swingtimer.offhand.markerGlowL:SetWidth(10)
pfUI.swingtimer.offhand.markerGlowL:SetHeight(sw_height)
pfUI.swingtimer.offhand.markerGlowL:Hide()
-- Right glow: fades from white to transparent (left edge = marker)
pfUI.swingtimer.offhand.markerGlowR = pfUI.swingtimer.offhand:CreateTexture(nil, "OVERLAY")
pfUI.swingtimer.offhand.markerGlowR:SetColorTexture(1, 1, 1, 1)
pfUI.swingtimer.offhand.markerGlowR:SetGradientAlpha("HORIZONTAL", 1, 1, 1, 0.35, 1, 1, 1, 0)
pfUI.swingtimer.offhand.markerGlowR:SetWidth(10)
pfUI.swingtimer.offhand.markerGlowR:SetHeight(sw_height)
pfUI.swingtimer.offhand.markerGlowR:Hide()
CreateBackdropShadow(pfUI.swingtimer.offhand)
-- Ranged bar
-- Hunters fill from the center: the bar drains toward the middle during -- Hunters fill from the center: the bar drains toward the middle during
-- the reload, then the auto shot deadzone grows back out in the warn color. -- the reload, then the auto shot deadzone grows back out in the warn color.
pfUI.swingtimer.ranged = CreateFrame("StatusBar", "pfSwingTimerRanged", UIParent) -- Each phase is a time span of its own on `phase`.
pfUI.swingtimer.ranged:SetPoint("BOTTOM", UIParent, "CENTER", -189, 83) local ranged = CreateSwingBar("pfSwingTimerRanged", "Ra", sw_showranged)
pfUI.swingtimer.ranged:SetWidth(sw_width) ranged:SetPoint("BOTTOM", UIParent, "CENTER", -189, 83)
pfUI.swingtimer.ranged:SetHeight(sw_height) ranged:SetFillStyle(isHunter and "CENTER" or "STANDARD")
pfUI.swingtimer.ranged:SetMinMaxValues(0, 1) ranged.showmarker = not isHunter
pfUI.swingtimer.ranged:SetValue(0) if isHunter then
pfUI.swingtimer.ranged:SetStatusBarTexture(sw_texture) ranged.phase = C_DurationUtil.CreateDuration()
pfUI.swingtimer.ranged:SetStatusBarColor(raR, raG, raB, raA) ranged.timer:SetDuration(ranged.phase)
pfUI.swingtimer.ranged:SetFillStyle(isHunter and "CENTER" or "STANDARD") end
pfUI.swingtimer.ranged:Hide()
pfUI.swingtimer.ranged.text = pfUI.swingtimer.ranged:CreateFontString("Status", "DIALOG", "GameFontNormal") pfUI.swingtimer.mainhand = mainhand
pfUI.swingtimer.ranged.text:SetPoint("CENTER", pfUI.swingtimer.ranged, "CENTER", 0, 0) pfUI.swingtimer.offhand = offhand
pfUI.swingtimer.ranged.text:SetFont(pfUI.font_default, sw_fontsize, "OUTLINE") pfUI.swingtimer.ranged = ranged
pfUI.swingtimer.ranged.text:SetTextColor(1, 1, 1, 1)
pfUI.swingtimer.ranged.text:SetText("")
if not sw_showtext then pfUI.swingtimer.ranged.text:Hide() end
pfUI.swingtimer.ranged.label = pfUI.swingtimer.ranged:CreateFontString("Status", "DIALOG", "GameFontNormal") UpdateMovable(mainhand)
pfUI.swingtimer.ranged.label:SetPoint("RIGHT", pfUI.swingtimer.ranged, "LEFT", -4, 0) UpdateMovable(ranged)
pfUI.swingtimer.ranged.label:SetFont(pfUI.font_default, sw_fontsize, "OUTLINE")
pfUI.swingtimer.ranged.label:SetTextColor(0.8, 0.8, 0.8, 1)
pfUI.swingtimer.ranged.label:SetText(sw_showlabel and "Ra" or "")
pfUI.swingtimer.ranged.speed = pfUI.swingtimer.ranged:CreateFontString("Status", "DIALOG", "GameFontNormal")
pfUI.swingtimer.ranged.speed:SetPoint("LEFT", pfUI.swingtimer.ranged, "RIGHT", 4, 0)
pfUI.swingtimer.ranged.speed:SetFont(pfUI.font_default, sw_fontsize, "OUTLINE")
pfUI.swingtimer.ranged.speed:SetTextColor(0.8, 0.8, 0.8, 1)
pfUI.swingtimer.ranged.speed:SetText("")
if not sw_showspeed then pfUI.swingtimer.ranged.speed:Hide() end
CreateBackdrop(pfUI.swingtimer.ranged)
pfUI.swingtimer.ranged.marker = pfUI.swingtimer.ranged:CreateTexture(nil, "OVERLAY")
pfUI.swingtimer.ranged.marker:SetColorTexture(1, 1, 1, 1.0)
pfUI.swingtimer.ranged.marker:SetWidth(2)
pfUI.swingtimer.ranged.marker:SetHeight(sw_height)
pfUI.swingtimer.ranged.marker:Hide()
-- Left glow: fades from transparent to white (right edge = marker)
pfUI.swingtimer.ranged.markerGlowL = pfUI.swingtimer.ranged:CreateTexture(nil, "OVERLAY")
pfUI.swingtimer.ranged.markerGlowL:SetColorTexture(1, 1, 1, 1)
pfUI.swingtimer.ranged.markerGlowL:SetGradientAlpha("HORIZONTAL", 1, 1, 1, 0, 1, 1, 1, 0.35)
pfUI.swingtimer.ranged.markerGlowL:SetWidth(10)
pfUI.swingtimer.ranged.markerGlowL:SetHeight(sw_height)
pfUI.swingtimer.ranged.markerGlowL:Hide()
-- Right glow: fades from white to transparent (left edge = marker)
pfUI.swingtimer.ranged.markerGlowR = pfUI.swingtimer.ranged:CreateTexture(nil, "OVERLAY")
pfUI.swingtimer.ranged.markerGlowR:SetColorTexture(1, 1, 1, 1)
pfUI.swingtimer.ranged.markerGlowR:SetGradientAlpha("HORIZONTAL", 1, 1, 1, 0.35, 1, 1, 1, 0)
pfUI.swingtimer.ranged.markerGlowR:SetWidth(10)
pfUI.swingtimer.ranged.markerGlowR:SetHeight(sw_height)
pfUI.swingtimer.ranged.markerGlowR:Hide()
CreateBackdropShadow(pfUI.swingtimer.ranged)
UpdateMovable(pfUI.swingtimer.mainhand)
UpdateMovable(pfUI.swingtimer.ranged)
-- OH weapon detection
-- OH weapon detection: slot 17 (off hand) accepts one-hand (13) and off-hand -- OH weapon detection: slot 17 (off hand) accepts one-hand (13) and off-hand
-- weapons (22); main-hand-only (21) can never sit there. -- weapons (22); main-hand-only (21) can never sit there.
local OH_WEAPON_TYPES = { [13]=true, [22]=true } local OH_WEAPON_TYPES = { [13]=true, [22]=true }
@@ -276,60 +192,6 @@ pfUI:RegisterModule("swingtimer", function ()
S.raSpeed = (rs and rs > 0) and rs or 0 S.raSpeed = (rs and rs > 0) and rs or 0
end end
-- Start* restart a countdown from a PLAYER_SWING reset. `remaining` can be
-- shorter than the weapon speed (parry haste, ranged wind-up), so the bar
-- length stays the full swing and the fill starts part-way along.
local function StartMH(remaining)
UpdateWeaponSpeeds()
pfUI.swingtimer.mhGraceAt = nil -- cancel any pending hide
S.mhTimerMax = math.max(S.mhSpeed, remaining)
S.mhTimer = remaining
S.mhActive = true
pfUI.swingtimer.mainhand:Show()
pfUI.swingtimer:Show()
end
local function StartOH(remaining)
UpdateWeaponSpeeds()
-- The off-hand attack time stays set with a shield equipped
if S.ohSpeed <= 0 then return end
pfUI.swingtimer.ohGraceAt = nil -- cancel any pending hide
S.ohTimerMax = math.max(S.ohSpeed, remaining)
S.ohTimer = remaining
S.ohActive = true
if sw_showoh then pfUI.swingtimer.offhand:Show() end
pfUI.swingtimer:Show()
end
local function StartRanged(remaining)
if not sw_showranged then return end
UpdateWeaponSpeeds()
if S.raSpeed <= 0 then return end
S.raTimerMax = math.max(S.raSpeed, remaining)
S.raTimer = remaining
S.raActive = true
pfUI.swingtimer.ranged:SetStatusBarColor(raR, raG, raB, raA)
pfUI.swingtimer.ranged:SetValue(isHunter and 1 or 0)
pfUI.swingtimer.ranged:Show()
pfUI.swingtimer:Show()
end
local function ResetAll()
S.mhActive = false
S.ohActive = false
S.raActive = false
S.mhTimer = 0
S.ohTimer = 0
S.raTimer = 0
pfUI.swingtimer.mhGraceAt = nil
pfUI.swingtimer.ohGraceAt = nil
pfUI.swingtimer.mainhand:Hide()
pfUI.swingtimer.offhand:Hide()
pfUI.swingtimer.ranged:Hide()
pfUI.swingtimer:Hide()
end
-- HS/Cleave/Maul helpers. Canonical rank-1 spellIDs resolve to the -- HS/Cleave/Maul helpers. Canonical rank-1 spellIDs resolve to the
-- localized spell name once, so per-spell classification is rank- and -- localized spell name once, so per-spell classification is rank- and
-- locale-independent without per-rank ID hardcoding (every rank of -- locale-independent without per-rank ID hardcoding (every rank of
@@ -419,236 +281,139 @@ pfUI:RegisterModule("swingtimer", function ()
return CheckQueuedAction(S.cachedHSSlots), CheckQueuedAction(S.cachedCleaveSlots) return CheckQueuedAction(S.cachedHSSlots), CheckQueuedAction(S.cachedCleaveSlots)
end end
-- OnUpdate: countdown all timers with delta, then render -- The bar colors follow the queued on-next-swing ability, the range state
pfUI.swingtimer:SetScript("OnUpdate", function() -- and the hunter deadzone. Runs on the events that change any of them;
S.swingThrottle = S.swingThrottle + arg1 -- ACTIONBAR_UPDATE_STATE covers the IsCurrentAction reconcile.
local swingDelay = pfUI.throttle and pfUI.throttle:Get("swingtimer") or 0.02 local function UpdateColors()
if S.swingThrottle < swingDelay then return end local r, g, b = mhR, mhG, mhB
local delta = S.swingThrottle
S.swingThrottle = 0
-- (out-of-combat hide handled naturally when timers expire)
local anyActive = false
-- Tick timers down. When a timer expires we give a short grace period before
-- hiding the bar, to bridge the 1-2 frame gap until PLAYER_SWING arrives.
-- If PLAYER_SWING arrives during the grace period it resets the timer
-- normally and the grace timer is cleared. If not (e.g. auto-attack was
-- turned off), the bar hides after the grace period ends.
local GRACE = 0.15 -- seconds to wait after timer hits 0 before hiding
if S.mhActive then
S.mhTimer = S.mhTimer - delta
if S.mhTimer <= 0 then
S.mhTimer = 0
if not pfUI.swingtimer.mhGraceAt then
pfUI.swingtimer.mhGraceAt = GetTime() + GRACE
elseif GetTime() >= pfUI.swingtimer.mhGraceAt then
pfUI.swingtimer.mhGraceAt = nil
if not S.inCombat or not S.autoAttackActive then
S.mhActive = false
pfUI.swingtimer.mainhand:Hide()
S.lastMhMarkerX = -1
pfUI.swingtimer.mainhand.marker:Hide()
pfUI.swingtimer.mainhand.markerGlowL:Hide()
pfUI.swingtimer.mainhand.markerGlowR:Hide()
end
end
end
end
if S.ohActive then
S.ohTimer = S.ohTimer - delta
if S.ohTimer <= 0 then
S.ohTimer = 0
if not pfUI.swingtimer.ohGraceAt then
pfUI.swingtimer.ohGraceAt = GetTime() + GRACE
elseif GetTime() >= pfUI.swingtimer.ohGraceAt then
pfUI.swingtimer.ohGraceAt = nil
if not S.inCombat or not S.autoAttackActive then
S.ohActive = false
pfUI.swingtimer.offhand:Hide()
S.lastOhMarkerX = -1
pfUI.swingtimer.offhand.marker:Hide()
pfUI.swingtimer.offhand.markerGlowL:Hide()
pfUI.swingtimer.offhand.markerGlowR:Hide()
end
end
end
end
if S.raActive then
S.raTimer = S.raTimer - delta
if S.raTimer <= 0 then
S.raTimer = 0
S.raActive = false
pfUI.swingtimer.ranged:Hide()
end
end
-- HS/Cleave color
local curR, curG, curB = mhDefaultR, mhDefaultG, mhDefaultB
if sw_hsqueue then if sw_hsqueue then
if S.isDruid and S.useSpellQueueEvent then if S.isDruid and S.useSpellQueueEvent then
S.maulQueued, S.maulSeenCurrent = S.maulQueued, S.maulSeenCurrent =
ReconcileQueued(S.maulQueued, S.cachedMaulSlots, S.maulSeenCurrent) ReconcileQueued(S.maulQueued, S.cachedMaulSlots, S.maulSeenCurrent)
end end
if S.maulQueued and S.isDruid then if S.maulQueued and S.isDruid then
curR, curG, curB = 1.0, 0.55, 0.0 -- orange for druid maul queue r, g, b = 1.0, 0.55, 0.0 -- orange for druid maul queue
elseif S.isWarrior then elseif S.isWarrior then
local hs, cl = IsHSOrCleaveQueued() local hs, cl = IsHSOrCleaveQueued()
if cl then if cl then
curR, curG, curB = 0.2, 0.9, 0.2 r, g, b = 0.2, 0.9, 0.2
elseif hs then elseif hs then
curR, curG, curB = 0.9, 0.9, 0.2 r, g, b = 0.9, 0.9, 0.2
end end
end end
end end
if S.outOfRange[MAINHAND] then r, g, b = orR, orG, orB end
mainhand:SetStatusBarColor(r, g, b, mhA)
-- Render MH if S.outOfRange[OFFHAND] then
if S.outOfRange[MAINHAND] then offhand:SetStatusBarColor(orR, orG, orB, ohA)
curR, curG, curB = orR, orG, orB else
offhand:SetStatusBarColor(ohR, ohG, ohB, ohA)
end end
if S.mhActive then local a
local progress = 1 - (S.mhTimer / S.mhTimerMax) if ranged.warn then
pfUI.swingtimer.mainhand:SetValue(progress) r, g, b, a = rwR, rwG, rwB, rwA
if S.mhTimer <= 0 then else
-- Timer expired: hide marker (no gap at right edge) r, g, b, a = raR, raG, raB, raA
if S.lastMhMarkerX ~= -1 then end
S.lastMhMarkerX = -1 if S.outOfRange[RANGED] then r, g, b = orR, orG, orB end
pfUI.swingtimer.mainhand.marker:Hide() ranged:SetStatusBarColor(r, g, b, a)
pfUI.swingtimer.mainhand.markerGlowL:Hide() end
pfUI.swingtimer.mainhand.markerGlowR:Hide()
end local function StopBar(bar)
if bar.wake then bar.wake:Cancel() end
bar.wake, bar.active, bar.graced = nil, nil, nil
bar.timer:Disable()
bar:Hide()
end
-- a melee bar that is due waits for the next swing; it hides after the
-- grace unless auto attack goes on, or on the event that stops it later
local function MeleeGrace(bar)
bar.graced = true
if not S.inCombat or not S.autoAttackActive then StopBar(bar) end
end
local function MeleeDue(bar)
bar.edge:Hide()
bar.wake = C_Timer.NewTimer(GRACE, function() MeleeGrace(bar) end)
end
local function RangedDue(bar)
StopBar(bar)
end
-- the hunter's reload is over: the deadzone grows out in the warn color
local function HunterDeadzone(bar)
local finish = bar.swing:GetEndTime()
bar.phase:SetTimeFromEnd(finish, DEADZONE)
bar:SetTimerDuration(bar.phase, Enum.StatusBarInterpolation.Immediate, Enum.StatusBarTimerDirection.ElapsedTime)
bar.warn = true
UpdateColors()
bar.wake = C_Timer.NewTimer(finish - GetTime(), function() RangedDue(bar) end)
end
-- Restarts a bar from a PLAYER_SWING reset. `remaining` can be shorter than
-- the weapon speed (parry haste, ranged wind-up), so the bar length stays
-- the full swing and the fill starts part-way along.
local function StartBar(bar, remaining, speed, due)
if bar.wake then bar.wake:Cancel() end
local now = GetTime()
bar.swing:SetTimeFromEnd(now + remaining, math.max(speed, remaining))
bar.active, bar.graced, bar.warn = true, nil, nil
if speed > 0 then bar.speed:SetFormattedText("%.2f", speed) end
if bar.phase then
if remaining > DEADZONE then
bar.phase:SetTimeFromEnd(now + remaining - DEADZONE, math.max(speed, remaining) - DEADZONE)
bar:SetTimerDuration(bar.phase, Enum.StatusBarInterpolation.Immediate, Enum.StatusBarTimerDirection.RemainingTime)
bar.wake = C_Timer.NewTimer(remaining - DEADZONE, function() HunterDeadzone(bar) end)
else else
local mhMarkerX = progress * sw_width HunterDeadzone(bar)
if mhMarkerX < 1 then mhMarkerX = 1 end
if mhMarkerX > sw_width - 2 then mhMarkerX = sw_width - 2 end
if mhMarkerX ~= S.lastMhMarkerX then
S.lastMhMarkerX = mhMarkerX
pfUI.swingtimer.mainhand.marker:SetPoint("LEFT", pfUI.swingtimer.mainhand, "LEFT", mhMarkerX - 1, 0)
pfUI.swingtimer.mainhand.markerGlowL:SetPoint("RIGHT", pfUI.swingtimer.mainhand.marker, "LEFT", 0, 0)
pfUI.swingtimer.mainhand.markerGlowR:SetPoint("LEFT", pfUI.swingtimer.mainhand.marker, "RIGHT", 0, 0)
pfUI.swingtimer.mainhand.marker:Show()
pfUI.swingtimer.mainhand.markerGlowL:Show()
pfUI.swingtimer.mainhand.markerGlowR:Show()
end
end end
pfUI.swingtimer.mainhand:SetStatusBarColor(curR, curG, curB, mhA) else
if sw_showtext then bar.wake = C_Timer.NewTimer(remaining, function() due(bar) end)
pfUI.swingtimer.mainhand.text:SetFormattedText("%.1f", math.floor(S.mhTimer * 10) / 10)
end
if sw_showspeed and S.mhSpeed > 0 then
pfUI.swingtimer.mainhand.speed:SetFormattedText("%.2f", S.mhSpeed)
end
anyActive = true
end end
-- Render OH UpdateColors()
if sw_showoh and S.ohActive then if bar.shown then
local progress = 1 - (S.ohTimer / S.ohTimerMax) bar.edge:SetShown(bar.showmarker)
pfUI.swingtimer.offhand:SetValue(progress) if sw_showtext then bar.timer:Enable() end
if S.outOfRange[OFFHAND] then bar:Show()
pfUI.swingtimer.offhand:SetStatusBarColor(orR, orG, orB, ohA)
else
pfUI.swingtimer.offhand:SetStatusBarColor(ohR, ohG, ohB, ohA)
end
if S.ohTimer <= 0 then
if S.lastOhMarkerX ~= -1 then
S.lastOhMarkerX = -1
pfUI.swingtimer.offhand.marker:Hide()
pfUI.swingtimer.offhand.markerGlowL:Hide()
pfUI.swingtimer.offhand.markerGlowR:Hide()
end
else
local ohMarkerX = progress * sw_width
if ohMarkerX < 1 then ohMarkerX = 1 end
if ohMarkerX > sw_width - 2 then ohMarkerX = sw_width - 2 end
if ohMarkerX ~= S.lastOhMarkerX then
S.lastOhMarkerX = ohMarkerX
pfUI.swingtimer.offhand.marker:SetPoint("LEFT", pfUI.swingtimer.offhand, "LEFT", ohMarkerX - 1, 0)
pfUI.swingtimer.offhand.markerGlowL:SetPoint("RIGHT", pfUI.swingtimer.offhand.marker, "LEFT", 0, 0)
pfUI.swingtimer.offhand.markerGlowR:SetPoint("LEFT", pfUI.swingtimer.offhand.marker, "RIGHT", 0, 0)
pfUI.swingtimer.offhand.marker:Show()
pfUI.swingtimer.offhand.markerGlowL:Show()
pfUI.swingtimer.offhand.markerGlowR:Show()
end
end
if sw_showtext then
pfUI.swingtimer.offhand.text:SetFormattedText("%.1f", math.floor(S.ohTimer * 10) / 10)
end
if sw_showspeed and S.ohSpeed > 0 then
pfUI.swingtimer.offhand.speed:SetFormattedText("%.2f", S.ohSpeed)
end
anyActive = true
elseif not sw_showoh then
pfUI.swingtimer.offhand:Hide()
end end
end
-- Render Ranged local function StartMH(remaining)
if sw_showranged and S.raActive then UpdateWeaponSpeeds()
local remaining = S.raTimer StartBar(mainhand, remaining, S.mhSpeed, MeleeDue)
local r, g, b, a = raR, raG, raB, raA end
if isHunter then
local DEADZONE = 0.5
if remaining > DEADZONE then
pfUI.swingtimer.ranged:SetValue((remaining - DEADZONE) / (S.raTimerMax - DEADZONE))
else
r, g, b, a = rwR, rwG, rwB, rwA
pfUI.swingtimer.ranged:SetValue(1 - (remaining / DEADZONE))
end
if sw_showtext then
if remaining <= 0.5 then
pfUI.swingtimer.ranged.text:SetFormattedText("%.1f", math.floor(remaining * 10) / 10)
else
pfUI.swingtimer.ranged.text:SetFormattedText("%.1f", math.floor((remaining - 0.5) * 10) / 10)
end
end
else
pfUI.swingtimer.ranged:SetValue(1 - (remaining / S.raTimerMax))
if sw_showtext then
pfUI.swingtimer.ranged.text:SetFormattedText("%.1f", math.floor(remaining * 10) / 10)
end
end
if S.outOfRange[RANGED] then
r, g, b = orR, orG, orB
end
pfUI.swingtimer.ranged:SetStatusBarColor(r, g, b, a)
if sw_showspeed and S.raSpeed > 0 then
pfUI.swingtimer.ranged.speed:SetFormattedText("%.2f", S.raSpeed)
end
local raProgress = 1 - (S.raTimer / S.raTimerMax)
local raMarkerX = raProgress * sw_width
if raMarkerX < 1 then raMarkerX = 1 end
if raMarkerX > sw_width - 2 then raMarkerX = sw_width - 2 end
if raMarkerX ~= S.lastRaMarkerX then
S.lastRaMarkerX = raMarkerX
if not isHunter then
pfUI.swingtimer.ranged.marker:SetPoint("LEFT", pfUI.swingtimer.ranged, "LEFT", raMarkerX - 1, 0)
pfUI.swingtimer.ranged.marker:Show()
pfUI.swingtimer.ranged.markerGlowL:SetPoint("RIGHT", pfUI.swingtimer.ranged.marker, "LEFT", 0, 0)
pfUI.swingtimer.ranged.markerGlowR:SetPoint("LEFT", pfUI.swingtimer.ranged.marker, "RIGHT", 0, 0)
pfUI.swingtimer.ranged.markerGlowL:Show()
pfUI.swingtimer.ranged.markerGlowR:Show()
else
pfUI.swingtimer.ranged.marker:Hide()
pfUI.swingtimer.ranged.markerGlowL:Hide()
pfUI.swingtimer.ranged.markerGlowR:Hide()
end
end
anyActive = true
elseif not sw_showranged then
pfUI.swingtimer.ranged:Hide()
end
if not anyActive then local function StartOH(remaining)
if not pfUI.swingtimer.mainhand:IsShown() UpdateWeaponSpeeds()
and not pfUI.swingtimer.offhand:IsShown() -- The off-hand attack time stays set with a shield equipped
and not pfUI.swingtimer.ranged:IsShown() then if S.ohSpeed <= 0 then return end
this:Hide() StartBar(offhand, remaining, S.ohSpeed, MeleeDue)
end end
end
end) local function StartRanged(remaining)
if not sw_showranged then return end
UpdateWeaponSpeeds()
if S.raSpeed <= 0 then return end
StartBar(ranged, remaining, S.raSpeed, RangedDue)
end
-- melee bars waiting past their grace hide once auto attack stops
local function StopWaitingBars()
if mainhand.graced then StopBar(mainhand) end
if offhand.graced then StopBar(offhand) end
end
local function ResetAll()
StopBar(mainhand)
StopBar(offhand)
StopBar(ranged)
end
local events = CreateFrame("Frame") local events = CreateFrame("Frame")
events:RegisterEvent("PLAYER_SWING") events:RegisterEvent("PLAYER_SWING")
@@ -658,6 +423,7 @@ pfUI:RegisterModule("swingtimer", function ()
events:RegisterEvent("PLAYER_REGEN_DISABLED") events:RegisterEvent("PLAYER_REGEN_DISABLED")
events:RegisterEvent("PLAYER_REGEN_ENABLED") events:RegisterEvent("PLAYER_REGEN_ENABLED")
events:RegisterEvent("ACTIONBAR_SLOT_CHANGED") events:RegisterEvent("ACTIONBAR_SLOT_CHANGED")
events:RegisterEvent("ACTIONBAR_UPDATE_STATE")
events:RegisterEvent("PLAYER_DEAD") events:RegisterEvent("PLAYER_DEAD")
events:RegisterUnitEvent("UNIT_SPELLCAST_SENT", "player") events:RegisterUnitEvent("UNIT_SPELLCAST_SENT", "player")
events:RegisterUnitEvent("UNIT_SPELLCAST_SUCCEEDED", "player") events:RegisterUnitEvent("UNIT_SPELLCAST_SUCCEEDED", "player")
@@ -682,6 +448,7 @@ pfUI:RegisterModule("swingtimer", function ()
-- arg1 = swingType, arg2 = isInRange, arg3 = checksRange; no check -- arg1 = swingType, arg2 = isInRange, arg3 = checksRange; no check
-- (no target, nothing to attack, no weapon) is not out of range -- (no target, nothing to attack, no weapon) is not out of range
S.outOfRange[arg1] = arg3 and not arg2 S.outOfRange[arg1] = arg3 and not arg2
UpdateColors()
elseif event == "UNIT_SPELLCAST_SENT" then elseif event == "UNIT_SPELLCAST_SENT" then
-- arg4 = spellID: an on-next-swing ability (HS / Cleave / Maul) queued -- arg4 = spellID: an on-next-swing ability (HS / Cleave / Maul) queued
@@ -689,6 +456,7 @@ pfUI:RegisterModule("swingtimer", function ()
if kind then if kind then
S.useSpellQueueEvent = true S.useSpellQueueEvent = true
SetQueuedKind(kind) SetQueuedKind(kind)
UpdateColors()
end end
elseif event == "UNIT_SPELLCAST_SUCCEEDED" then elseif event == "UNIT_SPELLCAST_SUCCEEDED" then
@@ -696,6 +464,7 @@ pfUI:RegisterModule("swingtimer", function ()
-- the queue, so drop the queued color -- the queue, so drop the queued color
if IsOnSwingSpell(arg3) then if IsOnSwingSpell(arg3) then
S.hsQueued = false; S.cleaveQueued = false; S.maulQueued = false S.hsQueued = false; S.cleaveQueued = false; S.maulQueued = false
UpdateColors()
end end
elseif event == "SPELL_QUEUE_EVENT" then elseif event == "SPELL_QUEUE_EVENT" then
@@ -707,12 +476,17 @@ pfUI:RegisterModule("swingtimer", function ()
elseif eventCode == ON_SWING_QUEUE_POPPED then elseif eventCode == ON_SWING_QUEUE_POPPED then
S.hsQueued = false; S.cleaveQueued = false; S.maulQueued = false S.hsQueued = false; S.cleaveQueued = false; S.maulQueued = false
end end
UpdateColors()
elseif event == "ACTIONBAR_UPDATE_STATE" then
if sw_hsqueue then UpdateColors() end
elseif event == "START_AUTOATTACK" then elseif event == "START_AUTOATTACK" then
S.autoAttackActive = true S.autoAttackActive = true
elseif event == "STOP_AUTOATTACK" then elseif event == "STOP_AUTOATTACK" then
S.autoAttackActive = false S.autoAttackActive = false
StopWaitingBars()
elseif event == "PLAYER_ENTERING_WORLD" then elseif event == "PLAYER_ENTERING_WORLD" then
local class = UnitClassBase("player") local class = UnitClassBase("player")
@@ -725,14 +499,8 @@ pfUI:RegisterModule("swingtimer", function ()
-- arg1 = changed slot; only weapon slots (main/off/ranged) affect swing speed -- arg1 = changed slot; only weapon slots (main/off/ranged) affect swing speed
if not INVSLOTS_EQUIPABLE_IN_COMBAT[arg1] then return end if not INVSLOTS_EQUIPABLE_IN_COMBAT[arg1] then return end
UpdateWeaponSpeeds() UpdateWeaponSpeeds()
if S.ohSpeed == 0 then if S.ohSpeed == 0 then StopBar(offhand) end
S.ohActive = false if S.raSpeed == 0 then StopBar(ranged) end
pfUI.swingtimer.offhand:Hide()
end
if S.raSpeed == 0 then
S.raActive = false
pfUI.swingtimer.ranged:Hide()
end
elseif event == "ACTIONBAR_SLOT_CHANGED" then elseif event == "ACTIONBAR_SLOT_CHANGED" then
RebuildQueueSlotCache() RebuildQueueSlotCache()
@@ -746,12 +514,22 @@ pfUI:RegisterModule("swingtimer", function ()
S.hsQueued = false S.hsQueued = false
S.cleaveQueued = false S.cleaveQueued = false
S.maulQueued = false S.maulQueued = false
UpdateColors()
StopWaitingBars()
elseif event == "PLAYER_DEAD" then elseif event == "PLAYER_DEAD" then
ResetAll() ResetAll()
end end
end) end)
local function Remaining(bar)
return bar.active and bar.swing:GetRemainingDuration() or 0
end
local function Progress(bar)
return bar.active and bar.swing:GetElapsedPercent() or 0
end
-- ------------------------------------------------------------------------- -- -------------------------------------------------------------------------
-- Public API for external addons (e.g. SCRM) -- Public API for external addons (e.g. SCRM)
-- Only available when the swingtimer module is loaded. -- Only available when the swingtimer module is loaded.
@@ -763,9 +541,9 @@ pfUI:RegisterModule("swingtimer", function ()
-- ------------------------------------------------------------------------- -- -------------------------------------------------------------------------
pfUI.swingtimer.api = { pfUI.swingtimer.api = {
-- Remaining time in seconds until next swing -- Remaining time in seconds until next swing
GetMHTimer = function() return S.mhTimer end, GetMHTimer = function() return Remaining(mainhand) end,
GetOHTimer = function() return S.ohTimer end, GetOHTimer = function() return Remaining(offhand) end,
GetRangedTimer = function() return S.raTimer end, GetRangedTimer = function() return Remaining(ranged) end,
-- Weapon speed (full swing duration in seconds) -- Weapon speed (full swing duration in seconds)
GetMHSpeed = function() return S.mhSpeed end, GetMHSpeed = function() return S.mhSpeed end,
@@ -773,20 +551,14 @@ pfUI:RegisterModule("swingtimer", function ()
GetRangedSpeed = function() return S.raSpeed end, GetRangedSpeed = function() return S.raSpeed end,
-- Whether each timer is currently running -- Whether each timer is currently running
IsMHActive = function() return S.mhActive end, IsMHActive = function() return mainhand.active == true end,
IsOHActive = function() return S.ohActive end, IsOHActive = function() return offhand.active == true end,
IsRangedActive = function() return S.raActive end, IsRangedActive = function() return ranged.active == true end,
-- Swing progress 0.0 (just reset) to 1.0 (about to swing) -- Swing progress 0.0 (just reset) to 1.0 (about to swing)
GetMHProgress = function() GetMHProgress = function() return Progress(mainhand) end,
return S.mhActive and S.mhTimerMax > 0 and (1 - S.mhTimer / S.mhTimerMax) or 0 GetOHProgress = function() return Progress(offhand) end,
end, GetRangedProgress = function() return Progress(ranged) end,
GetOHProgress = function()
return S.ohActive and S.ohTimerMax > 0 and (1 - S.ohTimer / S.ohTimerMax) or 0
end,
GetRangedProgress = function()
return S.raActive and S.raTimerMax > 0 and (1 - S.raTimer / S.raTimerMax) or 0
end,
-- Warrior HS/Cleave queue state -- Warrior HS/Cleave queue state
IsHSQueued = function() return S.hsQueued end, IsHSQueued = function() return S.hsQueued end,
@@ -804,4 +576,5 @@ pfUI:RegisterModule("swingtimer", function ()
if sw_showranged then EnableRangeCheck(RANGED) end if sw_showranged then EnableRangeCheck(RANGED) end
UpdateWeaponSpeeds() UpdateWeaponSpeeds()
end) UpdateColors()
end)