From c0a23544f1bfb61b70c4ee52e6c7a5a7416b6aeb Mon Sep 17 00:00:00 2001 From: Florian Berthold Date: Mon, 25 May 2026 11:51:11 +0200 Subject: [PATCH] feat(totems): right-click dismiss, Witchdoctor 3-slot cap, seconds counter - Right-click on a populated totem slot calls DestroyTotem(slot). EnableMouse on the strip absorbs clicks (loses click-to-target on the totem-bar pixels only; health/power bar still targets normally). - COA_CLASS_TOTEMS table overrides MAX_TOTEMS per class. WITCHDOCTOR capped to 3 so the 4th unused slot no longer renders. Easy to extend for any future custom totem classes. - Integer-seconds countdown text centred on each slot. totemMonitor only repaints the FontString when the integer changes so OnUpdate stays cheap. Cleared on expiry / dismiss. --- ShadowedUnitFrames/modules/totems.lua | 47 ++++++++++++++++++++++++--- 1 file changed, 43 insertions(+), 4 deletions(-) diff --git a/ShadowedUnitFrames/modules/totems.lua b/ShadowedUnitFrames/modules/totems.lua index 6f5373a..a1c7cb2 100644 --- a/ShadowedUnitFrames/modules/totems.lua +++ b/ShadowedUnitFrames/modules/totems.lua @@ -2,6 +2,11 @@ local Totems = {} local totemColors = {} local MAX_TOTEMS = MAX_TOTEMS +-- CoA: per-class slot count override (different from shaman's 4). +local COA_CLASS_TOTEMS = { + WITCHDOCTOR = 3, +} + -- Death Knights untalented ghouls are guardians and are considered totems........... so set it up for them local playerClass = select(2, UnitClass("player")) if( playerClass == "DEATHKNIGHT" ) then @@ -15,6 +20,9 @@ else local hasTotems = (MAX_TOTEMS and MAX_TOTEMS > 1) or (type(HasMultiCastActionBar) == "function" and HasMultiCastActionBar()) or playerClass == "SHAMAN" + if COA_CLASS_TOTEMS[playerClass] then + MAX_TOTEMS = COA_CLASS_TOTEMS[playerClass] + end if( hasTotems ) then ShadowUF:RegisterModule(Totems, "totemBar", ShadowUF.L["Totem bar"], true) else @@ -33,13 +41,27 @@ function Totems:OnEnable(frame) totem:SetMinMaxValues(0, 1) totem:SetValue(0) totem.id = MAX_TOTEMS == 1 and 1 or TOTEM_PRIORITIES[id] - + + -- Right-click dismisses the totem in this slot. EnableMouse on the strip + -- absorbs clicks here (loses click-to-target on the totem bar only). + totem:EnableMouse(true) + totem:SetScript("OnMouseUp", function(self, button) + if button == "RightButton" and self.have then + DestroyTotem(self.id) + end + end) + + -- Seconds-remaining text, centred on the bar; updated by totemMonitor. + totem.timeText = totem:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall") + totem.timeText:SetPoint("CENTER", totem, "CENTER", 0, 0) + totem.timeText:SetText("") + if( id > 1 ) then totem:SetPoint("TOPLEFT", frame.totemBar.totems[id - 1], "TOPRIGHT", 1, 0) else totem:SetPoint("TOPLEFT", frame.totemBar, "TOPLEFT", 0, 0) end - + table.insert(frame.totemBar.totems, totem) end @@ -86,10 +108,23 @@ end local function totemMonitor(self, elapsed) local time = GetTime() - self:SetValue(self.endTime - time) - + local remaining = self.endTime - time + self:SetValue(remaining) + + if self.timeText then + local intSec = remaining > 0 and math.floor(remaining) or 0 + if intSec ~= self.lastIntSec then + self.lastIntSec = intSec + self.timeText:SetText(intSec > 0 and intSec or "") + end + end + if( time >= self.endTime ) then self:SetValue(0) + if self.timeText then + self.timeText:SetText("") + self.lastIntSec = nil + end self:SetScript("OnUpdate", nil) end end @@ -113,6 +148,10 @@ function Totems:Update(frame) indicator:SetScript("OnUpdate", nil) indicator:SetMinMaxValues(0, 1) indicator:SetValue(0) + if indicator.timeText then + indicator.timeText:SetText("") + indicator.lastIntSec = nil + end end end