feat: add /stopchanneling command (#5)

* feat: add /stopchannel command

* review: give /stopchanneling a real handler and warn when nampower can't honor it

---------

Co-authored-by: Brues <5278969+brues-code@users.noreply.github.com>
This commit is contained in:
liiora
2026-09-10 14:39:16 -05:00
committed by GitHub
co-authored by Brues
parent 00caff0c9b
commit 9f8a5553bc
3 changed files with 74 additions and 0 deletions
+24
View File
@@ -130,6 +130,12 @@ local StopAttack = function(msg)
CleveRoids.DeferStopAttack()
end
local StopChanneling = function(msg)
-- No Blizzard equivalent: 1.12 has SpellStopCasting (immediate) and nothing
-- that waits for the next channel tick, so this is nampower-only.
CleveRoids.StopChanneling()
end
-- Register slash commands and assign original handlers.
-- These will be hooked immediately after.
SLASH_STARTATTACK1 = "/startattack"
@@ -141,6 +147,9 @@ SlashCmdList.STOPATTACK = StopAttack
SLASH_STOPCASTING1 = "/stopcasting"
SlashCmdList.STOPCASTING = SpellStopCasting
SLASH_STOPCHANNELING1 = "/stopchanneling"
SlashCmdList.STOPCHANNELING = StopChanneling
SLASH_CLEARTARGET1 = "/cleartarget"
SlashCmdList.CLEARTARGET = ClearTarget
@@ -202,6 +211,21 @@ SlashCmdList.STOPCASTING = function(msg)
end
end
-- /stopchanneling hook
CleveRoids.Hooks.STOPCHANNELING_SlashCmd = SlashCmdList.STOPCHANNELING
SlashCmdList.STOPCHANNELING = function(msg)
if CleveRoids.stopMacroFlag then return end
msg = msg or ""
if string.find(msg, "%[") then
-- If conditionals are present, let the function handle it.
-- It will only stop the channel if the conditions are met.
CleveRoids.DoConditionalStopChanneling(msg)
else
-- If no conditionals, run the original command.
CleveRoids.Hooks.STOPCHANNELING_SlashCmd(msg)
end
end
-- /unqueue hook
CleveRoids.Hooks.UNQUEUE_SlashCmd = SlashCmdList.UNQUEUE
SlashCmdList.UNQUEUE = function(msg)
+49
View File
@@ -3005,6 +3005,37 @@ function CleveRoids.DoConditionalStartAttack(msg)
return false
end
-- Stop channeling on the next tick (nampower v2.18+), behind /stopchanneling.
-- The underlying API no-ops in two cases and a command that does nothing
-- without saying why reads as broken, so each gets a one-shot warning -- the
-- same treatment the [rooted] conditional gives a too-old nampower.
local _stopChannelingWarned = {}
local function warnStopChanneling(key, reason)
if _stopChannelingWarned[key] then return end
_stopChannelingWarned[key] = true
DEFAULT_CHAT_FRAME:AddMessage("|cffff0000[SuperCleveRoidMacros]|r /stopchanneling "
.. reason .. ".", 1, 0.5, 0.5)
end
function CleveRoids.StopChanneling()
local API = CleveRoids.NampowerAPI
-- Nothing was sent: nampower is absent or predates ChannelStopCastingNextTick.
if not API.StopChannelNextTick() then
warnStopChanneling("version", "requires Nampower v2.18.0 or newer")
return false
end
-- The call went through, but nampower only acts on it while channel
-- queueing is on, so the channel would run to completion regardless.
if not API.IsQueueingEnabled("channeling") then
warnStopChanneling("setting", "requires Nampower's NP_QueueChannelingSpells setting to be enabled")
return false
end
return true
end
-- PERFORMANCE: Module-level actions to avoid closure allocation per call
local function _stopAttackAction()
CleveRoids.DeferStopAttack()
@@ -3014,6 +3045,10 @@ local function _stopCastingAction()
SpellStopCasting()
end
local function _stopChannelingAction()
CleveRoids.StopChanneling()
end
-- Attempts to conditionally stop an attack. Returns false if no conditionals are found.
function CleveRoids.DoConditionalStopAttack(msg)
if not string.find(msg, "%[") then return false end
@@ -3042,6 +3077,20 @@ function CleveRoids.DoConditionalStopCasting(msg)
return false
end
-- Attempts to conditionally interrupt channeling. Returns false if no conditionals are found.
function CleveRoids.DoConditionalStopChanneling(msg)
if not string.find(msg, "%[") then return false end
-- PERFORMANCE: Use numeric iteration to avoid pairs() iterator allocation
local parts = CleveRoids.splitStringIgnoringQuotes(msg)
for i = 1, table.getn(parts) do
if CleveRoids.DoWithConditionals(parts[i], nil, CleveRoids.FixEmptyTarget, false, _stopChannelingAction) then
return true
end
end
return false
end
local function _clearTargetAction()
ClearTarget()
end
+1
View File
@@ -506,6 +506,7 @@ local COMMANDS_NO_ACTION_NEEDED = {
["/startattack"] = true,
["/stopattack"] = true,
["/stopcasting"] = true,
["/stopchanneling"] = true,
["/unqueue"] = true,
["/retarget"] = true,
["/stopmacro"] = true,