clean debug and add movingand nomoving conditionals that use monkeyspeed

This commit is contained in:
Jrc13245
2026-01-24 15:39:08 -05:00
parent 31835f2fd3
commit ce4e4eb95f
3 changed files with 208 additions and 887 deletions
+169
View File
@@ -2023,6 +2023,100 @@ function CleveRoids.ValidateTTE(operator, amount)
return false
end
-- ============================================================================
-- MONKEYSPEED ADDON INTEGRATION
-- ============================================================================
-- Integrates with MonkeySpeed addon for accurate movement speed detection
-- MonkeySpeed uses SuperWoW's UnitPosition to calculate actual movement speed
--- Check if MonkeySpeed addon is available and loaded
--- @return boolean True if MonkeySpeed is available with speed data
function CleveRoids.HasMonkeySpeed()
return type(MonkeySpeed) == "table" and
MonkeySpeed.m_bLoaded == true and
MonkeySpeed.m_fSpeed ~= nil
end
--- Require MonkeySpeed for a feature, warn once if missing
--- @param feature string Feature name for warning message
--- @return boolean True if MonkeySpeed is available
function CleveRoids.RequireMonkeySpeed(feature)
if CleveRoids.HasMonkeySpeed() then
return true
end
if not CleveRoids._monkeySpeedErrorShown then
DEFAULT_CHAT_FRAME:AddMessage("|cffff0000[SuperCleveRoidMacros]|r The [moving] speed conditional requires the MonkeySpeed addon.", 1, 0.5, 0.5)
CleveRoids._monkeySpeedErrorShown = true
end
return false
end
--- Get current player movement speed as percentage (100 = normal run speed)
--- @return number|nil Speed percentage, or nil if MonkeySpeed not available
function CleveRoids.GetPlayerSpeed()
if not CleveRoids.HasMonkeySpeed() then
return nil
end
return MonkeySpeed.m_fSpeed or 0
end
--- Check if player is currently moving (speed > 0)
--- Falls back to basic position checking if MonkeySpeed isn't available
--- @return boolean True if player is moving
function CleveRoids.IsPlayerMoving()
-- If MonkeySpeed is available, use it for accurate detection
if CleveRoids.HasMonkeySpeed() then
return (MonkeySpeed.m_fSpeed or 0) > 0
end
-- Fallback: use SuperWoW's UnitPosition for basic moving detection
-- We store last position and compare
if UnitPosition then
local x, y = UnitPosition("player")
if x and y then
if CleveRoids._lastPlayerPos then
local dx = x - CleveRoids._lastPlayerPos.x
local dy = y - CleveRoids._lastPlayerPos.y
local dist = math.sqrt(dx * dx + dy * dy)
CleveRoids._lastPlayerPos = { x = x, y = y, time = GetTime() }
-- Moving if distance > small threshold (account for floating point)
return dist > 0.001
else
CleveRoids._lastPlayerPos = { x = x, y = y, time = GetTime() }
return false -- Can't determine on first call
end
end
end
return false
end
--- Validates a movement speed conditional.
--- Usage: [moving:>100] [moving:<50] [moving:=0]
--- operator: Comparison operator (>, <, =, >=, <=, ~=)
--- amount: Speed percentage (100 = normal run speed)
--- returns: True if speed [operator] amount
function CleveRoids.ValidateMovingSpeed(operator, amount)
if not operator or not amount then return false end
-- Check if MonkeySpeed is available for speed comparisons
if not CleveRoids.RequireMonkeySpeed("moving speed comparison") then
return false
end
local speed = CleveRoids.GetPlayerSpeed()
if speed == nil then
return false
end
-- Compare speed against threshold
if CleveRoids.operators[operator] then
return CleveRoids.comparators[operator](speed, amount)
end
return false
end
-- ============================================================================
-- CURSIVE ADDON INTEGRATION
-- ============================================================================
@@ -6268,6 +6362,81 @@ CleveRoids.Keywords = {
nobuffcapped = function(conditionals)
local target = conditionals.target or "target"
return not CleveRoids.IsTargetBuffCapped(target)
end,
-- =========================================================================
-- MOVEMENT SPEED CONDITIONALS (MonkeySpeed integration)
-- =========================================================================
-- [moving] - Player is moving (speed > 0)
-- [moving:>100] - Player speed is above 100% (faster than normal run)
-- [moving:<50] - Player speed is below 50% (slower than half speed)
-- Requires MonkeySpeed addon for speed comparisons (basic moving check uses fallback)
moving = function(conditionals)
-- Boolean form [moving] - just check if moving at all
if conditionals.moving == true then
return CleveRoids.IsPlayerMoving()
end
-- Operator form [moving:>100] - check speed percentage
return Multi(conditionals.moving, function(args)
if type(args) ~= "table" then return false end
-- Handle multi-comparison (e.g., >50&<150)
if args.comparisons and type(args.comparisons) == "table" then
local speed = CleveRoids.GetPlayerSpeed()
if speed == nil then
CleveRoids.RequireMonkeySpeed("moving speed comparison")
return false
end
-- ALL comparisons must pass (AND logic)
for _, comp in ipairs(args.comparisons) do
if not CleveRoids.operators[comp.operator] then
return false
end
if not CleveRoids.comparators[comp.operator](speed, comp.amount) then
return false
end
end
return true
end
return CleveRoids.ValidateMovingSpeed(args.operator, args.amount)
end, conditionals, "moving")
end,
-- [nomoving] - Player is NOT moving (speed == 0)
-- [nomoving:>100] - Player speed is NOT above 100% (at or below normal run)
nomoving = function(conditionals)
-- Boolean form [nomoving] - check if NOT moving
if conditionals.nomoving == true then
return not CleveRoids.IsPlayerMoving()
end
-- Operator form [nomoving:>100] - negate speed comparison
return NegatedMulti(conditionals.nomoving, function(args)
if type(args) ~= "table" then return false end
if args.comparisons and type(args.comparisons) == "table" then
local speed = CleveRoids.GetPlayerSpeed()
if speed == nil then
-- If MonkeySpeed not available, negated returns true (fail-safe)
return true
end
for _, comp in ipairs(args.comparisons) do
if not CleveRoids.operators[comp.operator] then
return true
end
if not CleveRoids.comparators[comp.operator](speed, comp.amount) then
return true
end
end
return false
end
return not CleveRoids.ValidateMovingSpeed(args.operator, args.amount)
end, conditionals, "nomoving")
end
}
+3 -886
View File
@@ -96,6 +96,8 @@ local BOOLEAN_CONDITIONALS = {
noohimbue = true,
group = true,
nogroup = true,
moving = true,
nomoving = true,
}
local requirementCheckFrame = CreateFrame("Frame")
@@ -5285,11 +5287,7 @@ SlashCmdList["CLEVEROID"] = function(msg)
DEFAULT_CHAT_FRAME:AddMessage("/cleveroid forget <spellID|all> - Forget learned duration(s)")
DEFAULT_CHAT_FRAME:AddMessage("/cleveroid debug [0|1] - Toggle learning debug messages")
end
DEFAULT_CHAT_FRAME:AddMessage("/cleveroid macrodebug - Toggle macro length warning debug")
DEFAULT_CHAT_FRAME:AddMessage("/cleveroid macrorefdebug - Toggle macro reference {Name} execution debug")
DEFAULT_CHAT_FRAME:AddMessage("/cleveroid macrostatus - Check macro length warning status")
DEFAULT_CHAT_FRAME:AddMessage("|cffffaa00Spell School Detection:|r")
DEFAULT_CHAT_FRAME:AddMessage('/cleveroid schooltest <spellID or name> - Test spell school detection')
DEFAULT_CHAT_FRAME:AddMessage("|cffffaa00Spell Schools:|r")
DEFAULT_CHAT_FRAME:AddMessage('/cleveroid listschools - List all learned spell schools')
DEFAULT_CHAT_FRAME:AddMessage('/cleveroid clearschools - Clear learned spell school data')
DEFAULT_CHAT_FRAME:AddMessage("|cffffaa00Immunity Tracking:|r")
@@ -5312,24 +5310,6 @@ SlashCmdList["CLEVEROID"] = function(msg)
DEFAULT_CHAT_FRAME:AddMessage('/cleveroid listtab <tab> - List all talents in a tab with their IDs')
DEFAULT_CHAT_FRAME:AddMessage('/cleveroid talents - Show current talent ranks')
DEFAULT_CHAT_FRAME:AddMessage('/cleveroid testtalent <spellID> - Test talent modifier for a spell')
DEFAULT_CHAT_FRAME:AddMessage('/cleveroid diagnosetalent <spellID> - Diagnose talent modifier issues')
DEFAULT_CHAT_FRAME:AddMessage("|cffffaa00Equipment Modifiers:|r")
DEFAULT_CHAT_FRAME:AddMessage('/cleveroid testequip <spellID> - Test equipment modifier for a spell')
DEFAULT_CHAT_FRAME:AddMessage('/cleveroid equipdebug <item name> - Debug item lookup for /equip')
DEFAULT_CHAT_FRAME:AddMessage('/cleveroid equiplog - Toggle real-time equip command logging')
DEFAULT_CHAT_FRAME:AddMessage("|cffffaa00Reactive Proc Tracking:|r")
DEFAULT_CHAT_FRAME:AddMessage('/cleveroid listprocs - Show active reactive ability procs')
DEFAULT_CHAT_FRAME:AddMessage('/cleveroid setproc <spell> [duration] - Manually set proc (testing)')
DEFAULT_CHAT_FRAME:AddMessage('/cleveroid clearproc [spell|all] - Clear reactive proc(s)')
DEFAULT_CHAT_FRAME:AddMessage("|cffffaa00Casting Detection:|r")
DEFAULT_CHAT_FRAME:AddMessage('/cleveroid testcasting - Test [selfcasting]/[noselfcasting] conditionals')
DEFAULT_CHAT_FRAME:AddMessage('/cleveroid testchannel - Test [channeltime] conditional tracking')
DEFAULT_CHAT_FRAME:AddMessage('/cleveroid channeldebug - Toggle [channeltime] conditional debug output')
DEFAULT_CHAT_FRAME:AddMessage("|cffffaa00Action Slot Debug:|r")
DEFAULT_CHAT_FRAME:AddMessage('/cleveroid slotdebug <slot> - Debug action slot state (tooltip/range/mana)')
DEFAULT_CHAT_FRAME:AddMessage('/cleveroid rangedebug <spell> - Debug spell range checking (channeled spells)')
DEFAULT_CHAT_FRAME:AddMessage("|cffffaa00Slam Rotation (Warrior):|r")
DEFAULT_CHAT_FRAME:AddMessage('/cleveroid slamdebug - Show Slam cast time and clip window calculations')
DEFAULT_CHAT_FRAME:AddMessage("|cffffaa00Debuff Tracking Debug:|r")
DEFAULT_CHAT_FRAME:AddMessage('/cleveroid debuffdebug [spell] - Debug debuff tracking on target')
return
@@ -5422,342 +5402,6 @@ SlashCmdList["CLEVEROID"] = function(msg)
return
end
-- macrodebug (toggle macro length warning debug messages)
if cmd == "macrodebug" then
CleveRoids.MacroLengthDebug = not CleveRoids.MacroLengthDebug
CleveRoids.Print("Macro length warning debug " .. (CleveRoids.MacroLengthDebug and "enabled" or "disabled"))
return
end
-- macrorefdebug (toggle macro reference execution debug messages)
if cmd == "macrorefdebug" or cmd == "refdebug" then
CleveRoids.macroRefDebug = not CleveRoids.macroRefDebug
CleveRoids.Print("Macro reference debug " .. (CleveRoids.macroRefDebug and "enabled" or "disabled"))
CleveRoids.Print("Use /cast [cond] {MacroName} and watch for [MacroRef] messages")
return
end
-- cooldowndebug (toggle cooldown update debug messages)
if cmd == "cooldowndebug" or cmd == "cddebug" then
CleveRoids.cooldownDebug = not CleveRoids.cooldownDebug
-- Clear the logged cache when enabling to get fresh output
if CleveRoids.cooldownDebug then
CleveRoids.cooldownDebugLogged = {}
end
CleveRoids.Print("Cooldown debug " .. (CleveRoids.cooldownDebug and "enabled" or "disabled"))
if CleveRoids.cooldownDebug then
CleveRoids.Print("Cast spells with broken cooldowns - issues will be logged once per slot.")
CleveRoids.Print("Use /cleveroid slotdebug <slot> for detailed slot info.")
local handlerCount = CleveRoids.actionEventHandlers and table.getn(CleveRoids.actionEventHandlers) or 0
CleveRoids.Print("Action event handlers: " .. handlerCount .. " (0 = Blizzard UI only)")
end
return
end
-- slotdebug <slot> - Debug action slot state for tooltip/range/mana issues
if cmd == "slotdebug" then
local slot = tonumber(val)
if not slot then
CleveRoids.Print("Usage: /cleveroid slotdebug <slot> - Debug action slot (1-120)")
return
end
local actions = CleveRoids.GetAction(slot)
CleveRoids.Print("|cff00ff00=== Slot " .. slot .. " Debug ===|r")
if not actions then
CleveRoids.Print("No actions data for slot " .. slot)
CleveRoids.Print("GetActionText: " .. tostring(GetActionText(slot)))
return
end
CleveRoids.Print("actions.tooltip: " .. tostring(actions.tooltip ~= nil))
CleveRoids.Print("actions.explicitTooltip: " .. tostring(actions.explicitTooltip))
CleveRoids.Print("actions.list count: " .. tostring(actions.list and table.getn(actions.list) or 0))
if actions.active then
CleveRoids.Print("|cff00ffffActive action:|r")
CleveRoids.Print(" .action: " .. tostring(actions.active.action))
CleveRoids.Print(" .type: " .. tostring(actions.active.type))
CleveRoids.Print(" .spell: " .. tostring(actions.active.spell ~= nil))
if actions.active.spell then
CleveRoids.Print(" .spell.name: " .. tostring(actions.active.spell.name))
CleveRoids.Print(" .spell.cost: " .. tostring(actions.active.spell.cost))
end
CleveRoids.Print(" .usable: " .. tostring(actions.active.usable))
CleveRoids.Print(" .oom: " .. tostring(actions.active.oom))
CleveRoids.Print(" .inRange: " .. tostring(actions.active.inRange))
CleveRoids.Print(" .conditionals: " .. tostring(actions.active.conditionals ~= nil))
if actions.active.conditionals then
CleveRoids.Print(" .target: " .. tostring(actions.active.conditionals.target))
end
else
CleveRoids.Print("|cffff0000No active action|r")
end
CleveRoids.Print("|cffaaaa00Hook conditions:|r")
local hasTooltip = actions.tooltip ~= nil
local hasActive = actions.active ~= nil
local typeIsSpell = actions.active and actions.active.type == "spell"
CleveRoids.Print(" actions.tooltip: " .. tostring(hasTooltip))
CleveRoids.Print(" actions.active: " .. tostring(hasActive))
CleveRoids.Print(" .type == 'spell': " .. tostring(typeIsSpell))
CleveRoids.Print(" Range hook would: " .. (hasTooltip and hasActive and typeIsSpell and "USE CUSTOM" or "FALLBACK"))
return
end
-- macrostatus (check macro length warning status)
if cmd == "macrostatus" then
CleveRoids.Print("|cff00ff00=== MacroLengthWarn Status ===|r")
-- Check if file loaded
if CleveRoids.MacroLengthWarnLoaded then
CleveRoids.Print("File: |cff00ff00LOADED|r")
else
CleveRoids.Print("File: |cffff0000NOT LOADED|r - Check for Lua errors!")
end
-- Check if extension is registered
local ext = CleveRoids.Extensions and CleveRoids.Extensions["MacroLengthWarn"]
if ext then
CleveRoids.Print("Extension: |cff00ff00REGISTERED|r")
-- Check if OnLoad was called
if ext.ShowMessages then
CleveRoids.Print("OnLoad: |cff00ff00CALLED|r")
-- Call the status function
ext.ShowMessages()
else
CleveRoids.Print("OnLoad: |cffff0000NOT CALLED|r")
end
else
CleveRoids.Print("Extension: |cffff0000NOT REGISTERED|r")
CleveRoids.Print("The MacroLengthWarn extension failed to register!")
end
-- Check key functions
CleveRoids.Print(" ")
CleveRoids.Print("Function Status:")
CleveRoids.Print(" EditMacro: " .. (EditMacro and "|cff00ff00EXISTS|r" or "|cffff0000MISSING|r"))
CleveRoids.Print(" MacroFrame_SaveMacro: " .. (MacroFrame_SaveMacro and "|cff00ff00EXISTS|r" or "|cffffff00NOT LOADED YET|r"))
return
end
-- channeldebug (toggle channeltime conditional debug)
if cmd == "channeldebug" then
CleveRoids.ChannelTimeDebug = not CleveRoids.ChannelTimeDebug
CleveRoids.Print("Channel time debug " .. (CleveRoids.ChannelTimeDebug and "enabled" or "disabled"))
if CleveRoids.ChannelTimeDebug then
CleveRoids.Print("You will see messages every time [channeltime] is evaluated")
CleveRoids.Print("This shows if your macro is re-evaluating during the channel")
end
return
end
-- testchannel (debug channel time detection)
if cmd == "testchannel" or cmd == "channeltest" then
CleveRoids.Print("|cff00ff00=== Channel Time Test ===|r")
-- Check spell tracking
local playerCast = CleveRoids.spell_tracking[CleveRoids.playerGuid]
if not playerCast then
CleveRoids.Print("|cffffff00No spell tracking data for player|r")
CleveRoids.Print("You must be casting or channeling a spell for this to show data")
else
CleveRoids.Print("Spell tracking found:")
CleveRoids.Print(" Type: " .. tostring(playerCast.type))
CleveRoids.Print(" Spell ID: " .. tostring(playerCast.spell_id))
if playerCast.spell_id and SpellInfo then
local spellName = SpellInfo(playerCast.spell_id)
CleveRoids.Print(" Spell Name: " .. tostring(spellName))
end
if playerCast.expires then
local timeLeft = playerCast.expires - GetTime()
CleveRoids.Print(" Expires at: " .. tostring(playerCast.expires))
CleveRoids.Print(" Time left: " .. string.format("%.2f", timeLeft) .. "s")
-- Test conditionals
CleveRoids.Print(" ")
CleveRoids.Print("Conditional tests:")
CleveRoids.Print(" [channeltime:<0.5]: " .. (timeLeft < 0.5 and "|cff00ff00TRUE|r" or "|cffff0000FALSE|r"))
CleveRoids.Print(" [channeltime:<1.0]: " .. (timeLeft < 1.0 and "|cff00ff00TRUE|r" or "|cffff0000FALSE|r"))
CleveRoids.Print(" [channeltime:>2.0]: " .. (timeLeft > 2.0 and "|cff00ff00TRUE|r" or "|cffff0000FALSE|r"))
else
CleveRoids.Print(" Expires: NOT SET")
end
end
CleveRoids.Print(" ")
CleveRoids.Print("|cff00ffffInstructions:|r")
CleveRoids.Print("1. Start channeling Arcane Missiles")
CleveRoids.Print("2. Run /cleveroid testchannel while channeling")
CleveRoids.Print("3. Check if spell tracking is working")
CleveRoids.Print("|cff00ff00=== End Test ===|r")
return
end
-- rangedebug <spell> - Debug range checking for a spell
if cmd == "rangedebug" or cmd == "testrange" then
-- Combine val and val2 for multi-word spell names
local spellName = val
if val2 and val2 ~= "" then
spellName = val .. " " .. val2
end
if not spellName or spellName == "" then
CleveRoids.Print("Usage: /cleveroid rangedebug <spell name>")
CleveRoids.Print("Example: /cleveroid rangedebug Arcane Missiles")
return
end
CleveRoids.Print("|cff00ff00=== Range Debug: " .. spellName .. " ===|r")
-- Get spell ID
local spellId = nil
if GetSpellIdForName then
spellId = GetSpellIdForName(spellName)
CleveRoids.Print("Spell ID: " .. (spellId and tostring(spellId) or "|cffff0000NOT FOUND|r"))
else
CleveRoids.Print("GetSpellIdForName: |cffff0000NOT AVAILABLE|r")
end
if spellId and spellId > 0 then
-- Check native IsSpellInRange
if IsSpellInRange then
local target = UnitExists("target") and "target" or nil
if target then
local result = IsSpellInRange(spellId, target)
CleveRoids.Print("Native IsSpellInRange: " .. tostring(result))
if result == -1 then
CleveRoids.Print(" |cffffff00(-1 means non-unit-targeted spell, using fallback)|r")
elseif result == nil then
CleveRoids.Print(" |cffffff00(nil means error or unknown spell)|r")
end
else
CleveRoids.Print("Native IsSpellInRange: |cffffff00No target selected|r")
end
end
-- Check GetSpellRec fields
local API = CleveRoids.NampowerAPI
if API then
-- Try rangeMax (may not exist)
local rangeMax = API.GetSpellField(spellId, "rangeMax")
CleveRoids.Print("rangeMax field: " .. (rangeMax and tostring(rangeMax) or "|cffffff00nil|r"))
-- Try rangeIndex
local rangeIndex = API.GetSpellField(spellId, "rangeIndex")
CleveRoids.Print("rangeIndex field: " .. (rangeIndex and tostring(rangeIndex) or "|cffffff00nil|r"))
if rangeIndex and API.SpellRangeTable then
local lookupRange = API.SpellRangeTable[rangeIndex]
CleveRoids.Print("SpellRangeTable[" .. rangeIndex .. "]: " .. (lookupRange and (tostring(lookupRange) .. " yards") or "|cffffff00not found|r"))
end
-- Final GetSpellRange result
local finalRange = API.GetSpellRange(spellId)
CleveRoids.Print("API.GetSpellRange: " .. (finalRange and (tostring(finalRange) .. " yards") or "|cffff0000nil|r"))
-- UnitXP distance check
if CleveRoids.hasUnitXP and UnitExists("target") then
local distance = UnitXP("distanceBetween", "player", "target")
CleveRoids.Print("Distance to target: " .. (distance and (string.format("%.1f", distance) .. " yards") or "|cffffff00nil|r"))
if finalRange and distance then
local inRange = distance <= finalRange
CleveRoids.Print("In range (distance <= spellRange): " .. (inRange and "|cff00ff00YES|r" or "|cffff0000NO|r"))
end
elseif not CleveRoids.hasUnitXP then
CleveRoids.Print("UnitXP: |cffff0000NOT INSTALLED (required for fallback)|r")
else
CleveRoids.Print("Distance check: |cffffff00No target selected|r")
end
-- Final API.IsSpellInRange result
if UnitExists("target") then
local finalResult = API.IsSpellInRange(spellId, "target")
CleveRoids.Print("API.IsSpellInRange: " .. tostring(finalResult))
else
-- Test without target
local finalResult = API.IsSpellInRange(spellId, "player")
CleveRoids.Print("API.IsSpellInRange (no target, using player): " .. tostring(finalResult))
end
-- Target type detection
local targetA = API.GetSpellField(spellId, "effectImplicitTargetA")
local targetB = API.GetSpellField(spellId, "effectImplicitTargetB")
-- Format target data (handle tables)
local function formatTarget(t)
if not t then return "|cffffff00nil|r" end
if type(t) == "table" then
local parts = {}
for i = 1, 3 do
table.insert(parts, tostring(t[i] or 0))
end
return "{" .. table.concat(parts, ", ") .. "}"
end
return tostring(t)
end
CleveRoids.Print("effectImplicitTargetA: " .. formatTarget(targetA))
CleveRoids.Print("effectImplicitTargetB: " .. formatTarget(targetB))
local isUnitTargeted = API.IsUnitTargetedSpell(spellId)
CleveRoids.Print("Is unit-targeted spell: " .. (isUnitTargeted == true and "|cff00ff00YES|r" or isUnitTargeted == false and "|cffff0000NO|r" or "|cffffff00UNKNOWN|r"))
-- Self-cast/ground-targeted detection summary
local isSelfCast = (isUnitTargeted == false)
CleveRoids.Print("Detected as self/ground-targeted: " .. (isSelfCast and "|cff00ff00YES|r" or "|cffff0000NO|r"))
end
end
CleveRoids.Print("|cff00ff00=== End Range Debug ===|r")
return
end
-- testcasting (debug casting state detection)
if cmd == "testcasting" or cmd == "casttest" then
CleveRoids.Print("|cff00ff00=== Casting State Test ===|r")
-- Check GetCurrentCastingInfo availability
if not GetCurrentCastingInfo then
CleveRoids.Print("|cffff0000ERROR: GetCurrentCastingInfo not available!|r")
CleveRoids.Print("This requires Nampower to be installed.")
return
end
-- Get current casting info
local castId, visId, autoId, casting, channeling, onswing, autoattack = GetCurrentCastingInfo()
CleveRoids.Print("GetCurrentCastingInfo() values:")
CleveRoids.Print(" castId: " .. tostring(castId))
CleveRoids.Print(" visId: " .. tostring(visId))
CleveRoids.Print(" autoId: " .. tostring(autoId))
CleveRoids.Print(" casting: " .. tostring(casting))
CleveRoids.Print(" channeling: " .. tostring(channeling))
CleveRoids.Print(" onswing: " .. tostring(onswing))
CleveRoids.Print(" autoattack: " .. tostring(autoattack))
-- Test conditionals
local isCasting = (casting and casting == 1) or false
local isChanneling = (channeling and channeling == 1) or false
CleveRoids.Print(" ")
CleveRoids.Print("Conditional results:")
CleveRoids.Print(" [selfcasting]: " .. tostring(isCasting or isChanneling))
CleveRoids.Print(" [noselfcasting]: " .. tostring(not isCasting and not isChanneling))
CleveRoids.Print(" ")
if isCasting then
CleveRoids.Print("|cffff00ffYou ARE currently CASTING|r")
elseif isChanneling then
CleveRoids.Print("|cffff00ffYou ARE currently CHANNELING|r")
else
CleveRoids.Print("|cff00ff00You are NOT casting or channeling|r")
end
CleveRoids.Print("|cff00ff00=== End Test ===|r")
return
end
-- listimmune (list immunity data)
if cmd == "listimmune" or cmd == "immunelist" then
CleveRoids.ListImmunities(val ~= "" and val or nil)
@@ -5880,43 +5524,6 @@ SlashCmdList["CLEVEROID"] = function(msg)
return
end
-- schooltest (test spell school detection)
if cmd == "schooltest" or cmd == "testschool" then
local input = val
if input == "" then
CleveRoids.Print("Usage: /cleveroid schooltest <spellID or name>")
CleveRoids.Print("Example: /cleveroid schooltest 133")
CleveRoids.Print("Example: /cleveroid schooltest Fireball")
return
end
local spellID = tonumber(input)
local spellName = nil
local school = nil
if spellID then
-- Input is a spell ID
spellName = SpellInfo and SpellInfo(spellID)
school = CleveRoids.GetSpellSchoolByID(spellID)
else
-- Input is a spell name
spellName = input
spellID = CleveRoids.GetSpellIdForName and CleveRoids.GetSpellIdForName(spellName)
school = CleveRoids.GetSpellSchool(spellName, spellID)
end
CleveRoids.Print("|cff88ff88=== Spell School Test ===|r")
CleveRoids.Print("Spell: " .. (spellName or "Unknown") .. " (ID:" .. (spellID or "Unknown") .. ")")
CleveRoids.Print("School: " .. (school or "|cffff0000Unknown|r"))
if spellID and CleveRoids_SpellSchools[spellID] then
CleveRoids.Print("|cff00ff00Source:|r Learned from Nampower damage events")
elseif school then
CleveRoids.Print("|cffffaa00Source:|r Tooltip/pattern matching")
end
return
end
-- listschools (show learned spell schools)
if cmd == "listschools" or cmd == "schools" then
CleveRoids.Print("|cff88ff88=== Learned Spell Schools ===|r")
@@ -6069,74 +5676,6 @@ SlashCmdList["CLEVEROID"] = function(msg)
return
end
-- diagnosetalent (comprehensive diagnostic for talent modifier)
if cmd == "diagnosetalent" or cmd == "diagtalent" then
local spellID = tonumber(val)
if not spellID then
CleveRoids.Print("Usage: /cleveroid diagnosetalent <spellID>")
CleveRoids.Print("Example: /cleveroid diagnosetalent 1943 (Rupture Rank 1)")
return
end
-- Inline diagnostic
local baseDuration = 10
DEFAULT_CHAT_FRAME:AddMessage("|cff00ff00=== Talent Modifier Diagnostic ===|r")
local spellName = SpellInfo(spellID)
if not spellName then
DEFAULT_CHAT_FRAME:AddMessage("|cffff0000ERROR: Invalid spell ID " .. tostring(spellID) .. "|r")
return
end
DEFAULT_CHAT_FRAME:AddMessage("Spell: " .. spellName .. " (ID: " .. spellID .. ")")
local modifier = CleveRoids.talentModifiers and CleveRoids.talentModifiers[spellID]
if not modifier then
DEFAULT_CHAT_FRAME:AddMessage("|cffff0000No talent modifier registered for this spell|r")
return
end
local talentDesc = modifier.talent or ("Tab " .. tostring(modifier.tab) .. " ID " .. tostring(modifier.id))
DEFAULT_CHAT_FRAME:AddMessage("Modifier registered: " .. talentDesc)
-- Test position-based lookup
local talentRank = 0
local lookupMethod = "none"
if modifier.tab and modifier.id then
local _, name, _, _, rank = GetTalentInfo(modifier.tab, modifier.id)
talentRank = tonumber(rank) or 0
lookupMethod = "position"
DEFAULT_CHAT_FRAME:AddMessage("|cff00ff00Position lookup (Tab " .. modifier.tab .. ", ID " .. modifier.id .. "):|r")
DEFAULT_CHAT_FRAME:AddMessage(" Talent name: " .. tostring(name))
DEFAULT_CHAT_FRAME:AddMessage(" Rank: " .. talentRank)
end
if modifier.talent and CleveRoids.GetTalentRank then
local nameRank = CleveRoids.GetTalentRank(modifier.talent)
DEFAULT_CHAT_FRAME:AddMessage("|cffaaaa00Name lookup (" .. modifier.talent .. "):|r")
DEFAULT_CHAT_FRAME:AddMessage(" Rank: " .. nameRank)
if talentRank == 0 and nameRank > 0 then
talentRank = nameRank
lookupMethod = "name"
end
end
DEFAULT_CHAT_FRAME:AddMessage("Final rank: " .. talentRank .. " (via " .. lookupMethod .. ")")
if talentRank > 0 then
local modifiedDuration = modifier.modifier(baseDuration, talentRank)
DEFAULT_CHAT_FRAME:AddMessage("|cff00ff00Test calculation:|r")
DEFAULT_CHAT_FRAME:AddMessage(" Base: " .. baseDuration .. "s")
DEFAULT_CHAT_FRAME:AddMessage(" Modified: " .. modifiedDuration .. "s")
DEFAULT_CHAT_FRAME:AddMessage(" Bonus: +" .. (modifiedDuration - baseDuration) .. "s")
else
DEFAULT_CHAT_FRAME:AddMessage("|cffff0000You don't have " .. talentDesc .. "!|r")
end
DEFAULT_CHAT_FRAME:AddMessage("|cff00ff00=== End Diagnostic ===|r")
return
end
-- testtalent (test talent modifier for a spell)
if cmd == "testtalent" or cmd == "talenttest" then
local spellID = tonumber(val)
@@ -6190,349 +5729,6 @@ SlashCmdList["CLEVEROID"] = function(msg)
return
end
-- testequip (test equipment modifier for a spell)
if cmd == "testequip" or cmd == "equiptest" then
local spellID = tonumber(val)
if not spellID then
CleveRoids.Print("Usage: /cleveroid testequip <spellID>")
CleveRoids.Print("Example: /cleveroid testequip 1079 (Rip Rank 1)")
return
end
local spellName = SpellInfo(spellID) or ("Spell " .. spellID)
local modifier = CleveRoids.equipmentModifiers and CleveRoids.equipmentModifiers[spellID]
if not modifier then
CleveRoids.Print(spellName .. " (ID:" .. spellID .. ") has no equipment modifier configured")
return
end
local itemID = CleveRoids.GetEquippedItemID and CleveRoids.GetEquippedItemID(modifier.slot)
local itemName = "None"
if itemID then
local itemLink = GetInventoryItemLink("player", modifier.slot)
if itemLink then
itemName = string.match(itemLink, "%[(.-)%]") or ("Item " .. itemID)
end
end
CleveRoids.Print("=== Equipment Modifier Test ===")
CleveRoids.Print("Spell: " .. spellName .. " (ID:" .. spellID .. ")")
CleveRoids.Print("Slot: " .. modifier.slot .. " (Ranged/Relic)")
CleveRoids.Print("Equipped: " .. itemName .. (itemID and (" [" .. itemID .. "]") or ""))
if not itemID then
CleveRoids.Print("|cffff0000No item equipped in this slot!|r")
else
-- Test with a base duration (use 10s as example)
local baseDur = 10
local modDur = modifier.modifier(baseDur, itemID)
if modDur ~= baseDur then
CleveRoids.Print("Example: 10s base -> " .. modDur .. "s modified")
if modDur < baseDur then
CleveRoids.Print("|cffff0000Duration reduced by " .. (baseDur - modDur) .. "s|r")
else
CleveRoids.Print("|cff00ff00Duration increased by " .. (modDur - baseDur) .. "s|r")
end
else
CleveRoids.Print("|cffffaa00This item has no effect on this spell|r")
end
end
return
end
-- equiplog (toggle real-time equip logging)
if cmd == "equiplog" then
CleveRoids.equipDebugLog = not CleveRoids.equipDebugLog
CleveRoids.Print("Equip command logging " .. (CleveRoids.equipDebugLog and "|cff00ff00ENABLED|r" or "|cffff0000DISABLED|r"))
if CleveRoids.equipDebugLog then
CleveRoids.Print("Use /equip commands to see detailed lookup info")
end
return
end
-- equipdebug (debug item lookup for /equip command)
if cmd == "equipdebug" then
local itemName = val
if val2 and val2 ~= "" then
itemName = val .. " " .. val2
end
if not itemName or itemName == "" then
CleveRoids.Print("Usage: /cleveroid equipdebug <item name>")
CleveRoids.Print('Example: /cleveroid equipdebug Idol of Ferocity')
return
end
-- Strip quotes if present
itemName = string.gsub(itemName, '"', "")
itemName = string.gsub(itemName, "_", " ")
CleveRoids.Print("|cff00ff00=== Equipment Debug: " .. itemName .. " ===|r")
-- Check equipped slot 18 (relic/idol)
local slot18Link = GetInventoryItemLink("player", 18)
if slot18Link then
local _, _, slot18Name = string.find(slot18Link, "|h%[(.-)%]|h")
CleveRoids.Print("Slot 18 equipped: " .. (slot18Name or "unknown"))
else
CleveRoids.Print("Slot 18 equipped: (empty)")
end
-- Check cache
local Items = CleveRoids.Items or {}
local cached = Items[itemName]
CleveRoids.Print("|cffffaa00Cache lookup:|r")
if cached then
if type(cached) == "table" then
if cached.inventoryID then
CleveRoids.Print(" Found in cache: EQUIPPED (inventoryID=" .. cached.inventoryID .. ")")
elseif cached.bagID then
CleveRoids.Print(" Found in cache: BAG (bag=" .. cached.bagID .. ", slot=" .. cached.slot .. ")")
else
CleveRoids.Print(" Found in cache: (type unknown)")
end
elseif type(cached) == "string" then
CleveRoids.Print(" Found in cache: -> " .. cached .. " (canonical name)")
end
else
CleveRoids.Print(" Not in cache")
end
-- Try GetItemFast
CleveRoids.Print("|cffffaa00GetItemFast:|r")
local fastItem = CleveRoids.GetItemFast and CleveRoids.GetItemFast(itemName)
if fastItem then
if fastItem.inventoryID then
CleveRoids.Print(" Returns: EQUIPPED (inventoryID=" .. fastItem.inventoryID .. ")")
elseif fastItem.bagID then
CleveRoids.Print(" Returns: BAG (bag=" .. fastItem.bagID .. ", slot=" .. fastItem.slot .. ")")
end
else
CleveRoids.Print(" Returns: nil")
end
-- Try FindItemQuick
CleveRoids.Print("|cffffaa00FindItemQuick (scans equipped then bags):|r")
local quickItem = CleveRoids.FindItemQuick and CleveRoids.FindItemQuick(itemName)
if quickItem then
if quickItem.inventoryID then
CleveRoids.Print(" Returns: EQUIPPED (inventoryID=" .. quickItem.inventoryID .. ")")
elseif quickItem.bagID then
CleveRoids.Print(" Returns: BAG (bag=" .. quickItem.bagID .. ", slot=" .. quickItem.slot .. ")")
end
else
CleveRoids.Print(" Returns: nil (item not found)")
end
-- Check HasGearEquipped (used by [equipped] conditional)
CleveRoids.Print("|cffffaa00HasGearEquipped (conditional check):|r")
local hasEquipped = CleveRoids.HasGearEquipped and CleveRoids.HasGearEquipped(itemName)
CleveRoids.Print(" [equipped:" .. itemName .. "] = " .. (hasEquipped and "|cff00ff00TRUE|r" or "|cffff0000FALSE|r"))
-- Combat state
CleveRoids.Print("|cffffaa00Combat state:|r")
CleveRoids.Print(" UnitAffectingCombat: " .. (UnitAffectingCombat("player") and "IN COMBAT" or "not in combat"))
CleveRoids.Print(" playerClass: " .. (CleveRoids.playerClass or "unknown"))
return
end
-- listprocs (show active reactive procs)
if cmd == "listprocs" or cmd == "procs" or cmd == "reactive" then
CleveRoids.Print("=== Active Reactive Procs ===")
local found = false
local now = GetTime()
local _, currentTargetGUID = UnitExists("target")
if CleveRoids.reactiveProcs then
for spellName, procData in pairs(CleveRoids.reactiveProcs) do
if procData and procData.expiry and procData.expiry > now then
local remaining = procData.expiry - now
local guidInfo = ""
if procData.targetGUID then
local matches = currentTargetGUID and (currentTargetGUID == procData.targetGUID)
if matches then
guidInfo = " |cff00ff00[Current Target]|r"
else
local targetName = UnitName("target")
if targetName then
guidInfo = " |cffff0000[Wrong Target: " .. targetName .. "]|r"
else
guidInfo = " |cffff0000[No Target]|r"
end
end
end
CleveRoids.Print(spellName .. ": " .. string.format("%.1fs", remaining) .. " remaining" .. guidInfo)
found = true
end
end
end
if not found then
CleveRoids.Print("|cffffaa00No active reactive procs|r")
end
return
end
-- setproc (manually set a reactive proc for testing)
if cmd == "setproc" or cmd == "procset" then
if val == "" then
CleveRoids.Print("Usage: /cleveroid setproc <spell> [duration]")
CleveRoids.Print("Example: /cleveroid setproc Overpower 5")
CleveRoids.Print("Note: Uses current target's GUID for target-specific procs")
return
end
local duration = tonumber(val2) or 5.0
local _, targetGUID = UnitExists("target")
if CleveRoids.SetReactiveProc then
CleveRoids.SetReactiveProc(val, duration, targetGUID)
local guidMsg = targetGUID and (" for target [" .. (UnitName("target") or "Unknown") .. "]") or ""
CleveRoids.Print("Set " .. val .. " proc for " .. duration .. " seconds" .. guidMsg)
else
CleveRoids.Print("|cffff0000Reactive proc system not loaded!|r")
end
return
end
-- clearproc (clear a reactive proc)
if cmd == "clearproc" or cmd == "procclear" then
if val == "" or val == "all" then
CleveRoids.reactiveProcs = {}
CleveRoids.Print("Cleared all reactive procs")
else
if CleveRoids.ClearReactiveProc then
CleveRoids.ClearReactiveProc(val)
CleveRoids.Print("Cleared " .. val .. " proc")
else
CleveRoids.Print("|cffff0000Reactive proc system not loaded!|r")
end
end
CleveRoids.QueueActionUpdate()
return
end
-- slamdebug (show Slam cast time and window calculations for Warrior rotation)
if cmd == "slamdebug" or cmd == "slam" or cmd == "slamtime" then
CleveRoids.Print("|cff88ff88=== Slam Clip Window Debug ===|r")
-- Get swing timer info
local attackSpeed = UnitAttackSpeed("player")
if not attackSpeed or attackSpeed <= 0 then
CleveRoids.Print("|cffff0000No attack speed available!|r")
CleveRoids.Print("You need to be in combat or have a weapon equipped.")
return
end
-- Check SP_SwingTimer
if st_timer == nil then
CleveRoids.Print("|cffff0000SP_SwingTimer not detected!|r")
CleveRoids.Print("The [noslamclip] conditionals require SP_SwingTimer addon.")
CleveRoids.Print("Get it at: https://github.com/jrc13245/SP_SwingTimer")
else
local timeElapsed = attackSpeed - st_timer
local percentElapsed = (timeElapsed / attackSpeed) * 100
CleveRoids.Print("|cffffaa00SP_SwingTimer:|r st_timer=" .. string.format("%.3f", st_timer) .. "s")
CleveRoids.Print("Swing elapsed: " .. string.format("%.2f", percentElapsed) .. "%")
end
CleveRoids.Print(" ")
CleveRoids.Print("|cffffaa00Swing Timer:|r " .. string.format("%.3f", attackSpeed) .. "s")
-- Get Slam cast time from tooltip scanning
local slamCastTime = CleveRoids.GetSlamCastTime()
local isDefault = (slamCastTime == 1.5)
CleveRoids.Print("|cffffaa00Slam Cast Time:|r " .. string.format("%.3f", slamCastTime) .. "s" .. (isDefault and " (default)" or " (from tooltip)"))
-- Show tooltip scanning diagnostic info
if CleveRoids.GetSlamSpellSlot then
local slot = CleveRoids.GetSlamSpellSlot()
if slot then
CleveRoids.Print(" Slam found in spellbook slot: " .. slot)
else
CleveRoids.Print(" |cffff0000Slam not found in spellbook!|r Are you a Warrior?")
end
end
if isDefault then
CleveRoids.Print(" Note: Could not read from tooltip, using default 1.5s")
end
-- Calculate windows
CleveRoids.Print(" ")
local slamWindowTime = attackSpeed - slamCastTime
local slamWindow = 0
if slamWindowTime > 0 then
slamWindow = (slamWindowTime / attackSpeed) * 100
end
local instantWindowTime = (2 * attackSpeed) - slamCastTime - 1.5
local instantWindow = 0
if instantWindowTime > 0 then
instantWindow = (instantWindowTime / attackSpeed) * 100
end
CleveRoids.Print("|cff00ff00=== Window Calculations ===|r")
CleveRoids.Print("|cffffaa00Slam Window:|r " .. string.format("%.2f", slamWindow) .. "%")
CleveRoids.Print(" Formula: (SwingTimer - SlamCast) / SwingTimer")
CleveRoids.Print(" (" .. string.format("%.3f", attackSpeed) .. " - " .. string.format("%.3f", slamCastTime) .. ") / " .. string.format("%.3f", attackSpeed) .. " = " .. string.format("%.2f", slamWindow) .. "%")
CleveRoids.Print(" Max time to cast Slam: " .. string.format("%.3f", slamWindowTime) .. "s into swing")
CleveRoids.Print(" ")
CleveRoids.Print("|cffffaa00Instant Window:|r " .. string.format("%.2f", instantWindow) .. "%")
CleveRoids.Print(" Formula: (2×SwingTimer - SlamCast - GCD) / SwingTimer")
CleveRoids.Print(" (2×" .. string.format("%.3f", attackSpeed) .. " - " .. string.format("%.3f", slamCastTime) .. " - 1.5) / " .. string.format("%.3f", attackSpeed) .. " = " .. string.format("%.2f", instantWindow) .. "%")
CleveRoids.Print(" Max time to cast instant: " .. string.format("%.3f", instantWindowTime) .. "s into swing")
-- Show current status
if st_timer ~= nil then
CleveRoids.Print(" ")
CleveRoids.Print("|cff00ff00=== Current Status ===|r")
local timeElapsed = attackSpeed - st_timer
local percentElapsed = (timeElapsed / attackSpeed) * 100
local inSlamWindow = percentElapsed <= slamWindow
local inInstantWindow = percentElapsed <= instantWindow
CleveRoids.Print("[noslamclip]: " .. (inSlamWindow and "|cff00ff00TRUE|r (safe to Slam)" or "|cffff0000FALSE|r (would clip)"))
CleveRoids.Print("[nonextslamclip]: " .. (inInstantWindow and "|cff00ff00TRUE|r (safe to instant)" or "|cffff0000FALSE|r (would clip next Slam)"))
end
return
end
-- formdebug (debug shapeshift form detection)
if cmd == "formdebug" or cmd == "form" or cmd == "shapeshiftdebug" then
CleveRoids.Print("|cff88ff88=== Shapeshift Form Debug ===|r")
CleveRoids.Print("Player class: " .. tostring(CleveRoids.playerClass))
local numForms = GetNumShapeshiftForms()
CleveRoids.Print("Number of forms: " .. tostring(numForms))
local currentIndex = CleveRoids.GetCurrentShapeshiftIndex()
CleveRoids.Print("Current form index: " .. tostring(currentIndex))
CleveRoids.Print(" ")
CleveRoids.Print("|cff00ff00=== Form Details ===|r")
for i = 1, numForms do
local icon, name, isActive, isCastable = GetShapeshiftFormInfo(i)
local activeStr = isActive and "|cff00ff00ACTIVE|r" or "|cff888888inactive|r"
local castableStr = isCastable and "castable" or "not castable"
CleveRoids.Print(string.format("Form %d: %s - %s (%s)", i, tostring(name), activeStr, castableStr))
end
CleveRoids.Print(" ")
CleveRoids.Print("|cff00ff00=== ValidatePlayerBuff Tests ===|r")
local testForms = {"Cat Form", "Bear Form", "Dire Bear Form", "Travel Form", "Aquatic Form", "Moonkin Form"}
for _, formName in ipairs(testForms) do
local result = CleveRoids.ValidatePlayerBuff(formName)
local resultStr = result and "|cff00ff00true|r" or "|cffff0000false|r"
CleveRoids.Print(" ValidatePlayerBuff('" .. formName .. "') = " .. resultStr)
end
return
end
-- debuffdebug (debug debuff tracking on target)
if cmd == "debuffdebug" or cmd == "debuff" or cmd == "trackdebug" then
local searchName = val
@@ -6687,85 +5883,6 @@ SlashCmdList["CLEVEROID"] = function(msg)
return
end
-- tooltipdebug (debug spell tooltip scanning)
if cmd == "tooltipdebug" or cmd == "ttdebug" or cmd == "spelltooltip" then
local spellName = val
if val2 and val2 ~= "" then
spellName = val .. " " .. val2
end
if not spellName or spellName == "" then
spellName = "Arcane Missiles" -- Default to Arcane Missiles
end
-- Strip underscores
spellName = string.gsub(spellName, "_", " ")
CleveRoids.Print("|cff88ff88=== Tooltip Scan Debug: " .. spellName .. " ===|r")
-- Find highest rank spell in spellbook (same logic as GetSpellSlotByName)
local slot, bookType = nil, nil
local foundRank = nil
local i = 1
while true do
local name, rank = GetSpellName(i, BOOKTYPE_SPELL)
if not name then break end
if name == spellName then
-- Keep updating to find the last (highest) rank
slot = i
bookType = BOOKTYPE_SPELL
foundRank = rank
end
i = i + 1
end
if not slot then
CleveRoids.Print("|cffff0000Spell not found in spellbook!|r")
return
end
CleveRoids.Print("Found in spellbook slot: " .. slot .. " (rank: " .. (foundRank or "none") .. ")")
-- Create tooltip if needed
if not CleveRoidsDebugTooltip then
CreateFrame("GameTooltip", "CleveRoidsDebugTooltip", nil, "GameTooltipTemplate")
CleveRoidsDebugTooltip:SetOwner(WorldFrame, "ANCHOR_NONE")
end
CleveRoidsDebugTooltip:ClearLines()
CleveRoidsDebugTooltip:SetSpell(slot, bookType)
CleveRoids.Print("Tooltip lines (" .. CleveRoidsDebugTooltip:NumLines() .. "):")
for lineNum = 1, CleveRoidsDebugTooltip:NumLines() do
local leftText = getglobal("CleveRoidsDebugTooltipTextLeft" .. lineNum)
local rightText = getglobal("CleveRoidsDebugTooltipTextRight" .. lineNum)
local leftStr = leftText and leftText:GetText() or ""
local rightStr = rightText and rightText:GetText() or ""
if leftStr and leftStr ~= "" then
CleveRoids.Print(" L" .. lineNum .. ": " .. leftStr)
-- Check for duration pattern
local duration = string.match(leftStr, "for (%d+%.?%d*) sec")
if duration then
CleveRoids.Print(" |cff00ff00^ Found 'for X sec': " .. duration .. "s|r")
end
local duration2 = string.match(leftStr, "over (%d+%.?%d*) sec")
if duration2 then
CleveRoids.Print(" |cff00ff00^ Found 'over X sec': " .. duration2 .. "s|r")
end
end
if rightStr and rightStr ~= "" then
CleveRoids.Print(" R" .. lineNum .. ": " .. rightStr)
end
end
-- Show what GetSpellDurationFromTooltip returns
local cachedDuration = CleveRoids.GetSpellDurationFromTooltip and CleveRoids.GetSpellDurationFromTooltip(spellName)
CleveRoids.Print(" ")
CleveRoids.Print("GetSpellDurationFromTooltip result: " .. (cachedDuration and (cachedDuration .. "s") or "|cffff0000nil|r"))
return
end
-- Unknown command fallback
CleveRoids.Print("Usage:")
DEFAULT_CHAT_FRAME:AddMessage("/cleveroid - Show current settings")
+36 -1
View File
@@ -68,6 +68,7 @@ All conditionals support negation with `no` prefix (e.g., `[nocombat]`, `[nobuff
| `group` | `[group]` `[group:party/raid]` | Player in group type |
| `resting` | `[resting]` | In rest area |
| `swimming` | `[swimming]` | Can use aquatic form |
| `moving` | `[moving]` `[moving:>100]` | Moving / speed % (MonkeySpeed) |
| `zone` | `[zone:"Ironforge"]` | Current zone name |
### Resources
@@ -200,6 +201,7 @@ All conditionals support negation with `no` prefix (e.g., `[nocombat]`, `[nobuff
| `ttk` | TimeToKill | `[ttk:<10]` | Time to kill (seconds) |
| `tte` | TimeToKill | `[tte:<5]` | Time to execute (20% HP) |
| `cursive` | Cursive | `[cursive:Rake>3]` | GUID debuff tracking |
| `moving` | MonkeySpeed | `[moving:>100]` | Speed % (100=normal run) |
### Warrior Slam Conditionals
For optimizing Slam rotations without clipping auto-attacks:
@@ -552,6 +554,39 @@ The addon checks debuffs on the target:
- Works at debuff cap
- More accurate timing
### MonkeySpeed Integration (`[moving]`)
[MonkeySpeed](https://github.com/jrc13245/MonkeySpeed) provides accurate movement speed detection via SuperWoW's `UnitPosition` API:
```lua
-- Only cast if standing still
/cast [nomoving] Aimed Shot
-- Cast instant ability while moving
/cast [moving] Arcane Shot
-- Check speed percentage (100 = normal run speed)
/cast [moving:>100] Sprint -- Already faster than normal
/cast [moving:<50] Escape Artist -- Currently slowed
-- Combined with other conditionals
/cast [nomoving, harm] Aimed Shot
/cast [moving, harm] Arcane Shot
```
**Speed Reference:**
| Speed | Description |
|-------|-------------|
| `0` | Standing still |
| `100` | Normal run speed |
| `160` | Level 40 mount |
| `200` | Epic mount |
**Notes:**
- Basic `[moving]`/`[nomoving]` works without MonkeySpeed (position fallback)
- Speed comparisons (`[moving:>100]`) require MonkeySpeed addon
- Speed values vary with buffs/debuffs affecting movement
### Recommended DoT Macro Patterns
**Druid Feral (with Cursive):**
@@ -612,7 +647,7 @@ The addon checks debuffs on the target:
**Action Bars:** Blizzard, [pfUI](https://github.com/jrc13245/pfUI), Bongos, Discord Action Bars
**Integrations:** SP_SwingTimer, TWThreat, TimeToKill, QuickHeal, Cursive (with mouseover support for DoT timer bars), ClassicFocus, SuperMacro
**Integrations:** SP_SwingTimer, TWThreat, TimeToKill, QuickHeal, Cursive (with mouseover support for DoT timer bars), ClassicFocus, SuperMacro, MonkeySpeed
> **Note:** For pfUI users, the [jrc13245/pfUI fork](https://github.com/jrc13245/pfUI) includes native SuperCleveRoidMacros integration for proper cooldown, icon, and tooltip display on conditional macros.