--[[ SuperMacro compatibility shim for CleveRoidMacros (1.12.1-safe) - Installs only when BOTH SuperMacro and SuperCleveRoidMacros/CleveRoidMacros are loaded - Hooks SuperMacro's RunLine order-agnostically (ADDON_LOADED + PLAYER_LOGIN) - Intercepts CRM-owned slashcommands (including {…}, […], !, ?, ~) - Forwards to CRM's SlashCmdList handlers; preserves /castsequence - Leaves SuperMacro unmodified; safe fallback to original RunLine - Redirects global RunMacro to SuperMacro_RunMacro so RunLine hook can intercept ]] do local _G = _G or getfenv(0) local CRM = _G.CleveRoids or {} _G.CleveRoids = CRM CRM.Hooks = CRM.Hooks or {} -- Commands owned by CRM (keep in sync with Console.lua registrations) -- NOTE: /runmacro is NOT intercepted here - we let SuperMacro's RunLine handle it -- naturally via SuperMacro_RunMacro. This avoids conflicts with SuperMacro's keybinding system. local INTERCEPT = { cast=true, castsequence=true, use=true, startattack=true, stopattack=true, stopcasting=true, stopmacro=true, skipmacro=true, firstaction=true, nofirstaction=true, target=true, retarget=true, cancelaura=true, unbuff=true, unqueue=true, unshift=true, equip=true, equipmh=true, equipoh=true, -- runmacro intentionally NOT included - see note above -- pet petattack=true, petfollow=true, petpassive=true, petaggressive=true, petdefensive=true, petwait=true, -- healing (requires QuickHeal addon) quickheal=true, qh=true, -- additional commands that were missing castpet=true, cleartarget=true, applymain=true, applyoff=true, -- slot-specific equip commands ["equip11"]=true, ["equip12"]=true, ["equip13"]=true, ["equip14"]=true, } -- alias map (if CRM only registers /cancelaura, but /unbuff appears) local ALIASES = { unbuff = "cancelaura" } local function normalize_cmd(cmd) if not cmd or cmd == "" then return nil end local _, _, s = string.find(cmd, "^(.*)$") s = s and string.lower(s) or nil if s and ALIASES[s] then s = ALIASES[s] end return s end local function has_handler(cmd) local list = _G.SlashCmdList return cmd and list and type(list[string.upper(cmd)]) == "function" end local function parse_slash(text) if type(text) ~= "string" then return nil, nil end text = (string.gsub(text, "^[%s]+", "")) if not string.find(text, "^/") then return nil, nil end local _, _, cmd, rest = string.find(text, "^/(%S+)%s*(.*)$") return cmd, rest end local function install_supermacro_hook() if CRM.SM_RunLineHooked then return end if type(_G.RunLine) ~= "function" then return end local orig_RunLine = _G.RunLine CRM.Hooks.RunLine = CRM.Hooks.RunLine or orig_RunLine _G.RunLine = function(...) -- SuperMacro calls RunLine(line) one line at a time; handle first arg. local text = arg and arg[1] -- FIX: Skip comment lines (SuperMacro uses -- for comments) -- Let SuperMacro handle these to avoid any processing if type(text) == "string" and string.find(text, "^%s*%-%-") then return orig_RunLine(text) end -- IMPORTANT: Check for /nofirstaction BEFORE the stop flag check -- This allows /nofirstaction to clear the stopMacroFlag set by /firstaction if type(text) == "string" then local _, _, nofirstactionArgs = string.find(text, "^%s*/nofirstaction%s*(.*)") if nofirstactionArgs then -- Capture stopOnCastFlag BEFORE DoNoFirstAction clears it local wasFirstActionActive = CRM.stopOnCastFlag if type(CleveRoids.DoNoFirstAction) == "function" then pcall(CleveRoids.DoNoFirstAction, nofirstactionArgs or "") end -- Also clear stopMacroFlag if it was set by firstaction mechanism if wasFirstActionActive and CRM.stopMacroFlag then CRM.stopMacroFlag = false end return true -- We handled it end end -- Check macro stop flags before processing any line -- (but /nofirstaction was already handled above) if CRM.stopMacroFlag or CRM.skipMacroFlag then -- If stopOnCastFlag is true, this is firstaction mode - skip but continue -- If stopOnCastFlag is false, this is /stopmacro - skip the line return true -- Skip this line, tell SM we handled it end if type(text) == "string" then -- 1) special-case /castsequence → call CRM directly and RETURN TRUE local b, e, rest = string.find(text, "^%s*/castsequence%s*(.*)") if b then if type(CleveRoids) == "table" and type(CleveRoids.DoCastSequence) == "function" then pcall(CleveRoids.DoCastSequence, rest or "") return true end -- fallback: slash handler if defined local fn = _G.SlashCmdList and _G.SlashCmdList["CASTSEQUENCE"] if type(fn) == "function" then pcall(fn, rest or "") return true end -- nothing to do; pass through to SM else -- 2) generic /cmd forwarding (lets CRM handlers parse []) -- FIX: Added %s* to handle leading whitespace (like /castsequence pattern above) local _, _, raw, msg = string.find(text, "^%s*/(%S+)%s*(.*)$") if raw then local cmd = string.lower(raw) -- alias map: /unbuff → /cancelaura if cmd == "unbuff" then cmd = "cancelaura" end if INTERCEPT[cmd] and has_handler(cmd) then pcall(_G.SlashCmdList[string.upper(cmd)], msg or "") return true -- IMPORTANT: tell SM we handled it end end -- 3) fast-path for extended/bracket tokens (/cast {…} [/…] ! ? ~) local hooks = { cast = CRM.DoCast, target = CRM.DoTarget, use = CRM.DoUse } for k, fn in pairs(hooks) do if type(fn) == "function" then local b2, e2 = string.find(text, "^%s*/" .. k .. "%s+[!%[%{%?~]") if b2 then local msg2 = string.gsub(string.sub(text, e2), "^%s+", "") pcall(fn, msg2) return true -- IMPORTANT end end end end end -- Not handled by CRM: let SuperMacro do its normal processing return orig_RunLine(text) end CRM.SM_RunLineHooked = true -- Hook SuperMacro_RunMacro to clear stopmacro flag at macro start -- and redirect global RunMacro so all macro execution goes through RunLine if type(_G.SuperMacro_RunMacro) == "function" then local orig_SuperMacro_RunMacro = _G.SuperMacro_RunMacro CRM.Hooks.SuperMacro_RunMacro = orig_SuperMacro_RunMacro local function hooked_RunMacro(index) -- Clear ALL macro stop flags at macro start (including firstaction flag) CRM.stopMacroFlag = false CRM.skipMacroFlag = false CRM.stopOnCastFlag = false -- FIX: Also clear firstaction flag return orig_SuperMacro_RunMacro(index) end _G.SuperMacro_RunMacro = hooked_RunMacro _G.RunMacro = hooked_RunMacro _G.Macro = hooked_RunMacro end -- Hook RunSuperMacro (for "Super" extended text macros) to clear stopmacro flag -- This is a separate function from SuperMacro_RunMacro and uses RunLine directly if type(_G.RunSuperMacro) == "function" then local orig_RunSuperMacro = _G.RunSuperMacro CRM.Hooks.RunSuperMacro = orig_RunSuperMacro _G.RunSuperMacro = function(index) -- Clear ALL macro stop flags at macro start (including firstaction flag) CRM.stopMacroFlag = false CRM.skipMacroFlag = false CRM.stopOnCastFlag = false -- FIX: Also clear firstaction flag return orig_RunSuperMacro(index) end end end -- ===== Order-agnostic loader: install only when BOTH addons are present ===== local SM_LOADED, CRM_LOADED = false, false local f = CreateFrame("Frame") f:RegisterEvent("ADDON_LOADED") f:RegisterEvent("PLAYER_LOGIN") local function note_loaded(name) if name == "SuperMacro" then SM_LOADED = true elseif name == "SuperCleveRoidMacros" or name == "CleveRoidMacros" then CRM_LOADED = true end end local function both_loaded() if SM_LOADED and CRM_LOADED then return true end -- heuristic fallback in case this file loads late: -- Check for SuperMacro's namespaced internal function (preferred) or RunLine local sm_ok = type(_G.SuperMacro_RunMacro) == "function" or type(_G.RunLine) == "function" local crm_ok = _G.CleveRoids and _G.SlashCmdList and type(_G.SlashCmdList.CAST) == "function" return sm_ok and crm_ok end local function try_install() if both_loaded() then install_supermacro_hook() end end f:SetScript("OnEvent", function() local evt = event local addon = arg1 if evt == "ADDON_LOADED" then if type(addon) == "string" then note_loaded(addon) end try_install() elseif evt == "PLAYER_LOGIN" then try_install() end end) end