Add [totem] and [nototem] conditionals

A totem is a summoned creature, not an aura, so nothing in the addon could see
one. Strength of Earth and Mana Spring could be faked through [nomybuff], but
Searing, Magma, Fire Nova, Tremor and Grounding put nothing on the player at
all, and those are the ones worth conditioning a recast on. There was no
workaround.

ClassicAPI backports the TBC totem bar (src/totem/Tracker.cpp), tracking the
player's own summons from their SMSG_SPELL_GO and classifying them by the
summon spell's SUMMON_TOTEM_SLOT1..4 effect, so Turtle's custom totems
self-classify. Ungated like GLOBAL_MOUSE_*: the tracker landed in v1.10.0, far
below the v1.15.0 floor the addon already refuses to run below.

[totem:X] takes an element (fire/earth/water/air), a slot number, or the totem's
own name -- ResolveTotemSlot tries the slot table first, then matches X against
the name standing in each slot, so [totem:Searing_Totem] asks for that totem
rather than whatever holds the fire slot. Bare [totem] takes the action as its
argument the way [mybuff] does, making /cast [nototem] Searing Totem a complete
recast macro.

Comparisons follow the aura precedent exactly: an empty slot reads -1, the same
"missing counts as least" ValidateAura uses, so [totem:Searing_Totem<5] passes
while the totem is expiring AND while it is absent -- one clause, no [nototem]
needed. A totem is either up or it isn't, so #N stack comparisons read 1 for a
standing totem. The parser needed nothing: its name/operator/amount capture is
generic, so multi-comparisons ([totem:X>2&<8]), OR groups and the De Morgan
flip all came for free.

Occupancy is read from GetTotemInfo's totemName, never from the time left.
GetTotemInfo's first return is TOOL presence -- whether the player carries the
slot's Earth/Fire/Water/Air Totem item -- not whether a totem is out, and a
summon spell with no SpellDuration row reports 0 seconds, which is "up with no
timer", not "absent".

Icon refresh needs two feeds. PLAYER_TOTEM_UPDATE covers a slot changing hands
(dropped, expired, killed, recalled). It does not fire as a totem counts toward
zero, and unlike an aura there is no ambient event stream to ride -- UNIT_AURA
is what quietly keeps [mybuff:X<N] honest -- so a [totem:X<N] icon held its last
answer until some unrelated event queued a refresh: the macro sat on the
question mark through the window it should have lit up. Hence the once-a-second
re-test in OnUpdate while any totem timer runs, skipped in realtime mode, which
re-tests everything anyway. Only the icon was ever at stake; the click path
evaluates conditionals live.
This commit is contained in:
Brues
2026-09-14 19:28:24 -05:00
parent 891467cd7e
commit b82d06d061
2 changed files with 143 additions and 0 deletions
+27
View File
@@ -4190,6 +4190,21 @@ function CleveRoids.OnUpdate(self)
end
end
-- A totem's timer runs down with nothing behind it: PLAYER_TOTEM_UPDATE fires
-- when a slot changes hands, never as one counts toward zero, so a
-- [totem:X<N] icon would hold the answer from its last refresh until some
-- unrelated event queued another. Unlike an aura, there is no ambient event
-- stream to ride -- UNIT_AURA is what quietly keeps [mybuff:X<N] honest -- so
-- a re-test once a second while any totem timer runs is the whole mechanism.
-- Only the icon is at stake: the click path evaluates conditionals live.
-- Realtime mode re-tests everything each tick and needs none of this.
if CRM.realtime == 0 and time >= (CR.nextTotemPoll or 0) then
CR.nextTotemPoll = time + 1
if CR.AnyTotemTimerRunning() then
CR.isActionUpdateQueued = true
end
end
-- Check the saved variable to decide which update mode to use.
if CRM.realtime == 1 then
-- Realtime Mode: Force an update on every throttled tick for maximum responsiveness.
@@ -4522,6 +4537,10 @@ end
CleveRoids.Frame:RegisterEvent("GLOBAL_MOUSE_DOWN")
CleveRoids.Frame:RegisterEvent("GLOBAL_MOUSE_UP")
-- ClassicAPI totem-bar tracking, for [totem:X] icon refresh. Ungated for the
-- same reason.
CleveRoids.Frame:RegisterEvent("PLAYER_TOTEM_UPDATE")
-- NOTE: SuperMacro hook installation is handled by Compatibility/SuperMacro.lua
-- which has the complete implementation including the INTERCEPT path for all commands
@@ -5589,6 +5608,14 @@ function CleveRoids.Frame:GLOBAL_MOUSE_UP()
CleveRoids.isActionUpdateQueued = true
end
-- ClassicAPI PLAYER_TOTEM_UPDATE: arg1 = the slot (1 Fire .. 4 Air) whose totem
-- was dropped, expired, killed or recalled. The slot goes unread for the same
-- reason the mouse handlers ignore their button -- a [totem:X] macro may name
-- any slot, and [nototem:X] flips on any of them.
function CleveRoids.Frame:PLAYER_TOTEM_UPDATE()
CleveRoids.QueueActionUpdate()
end
-- Base SendChatMessage captured at first hook; used to break a hook cycle.
local baseSendChatMessage = SendChatMessage
local sendingChatMessage = false