mirror of
https://github.com/brues-code/SuperCleveRoidMacros.git
synced 2026-09-16 03:38:00 +00:00
fix reactive for overpower and revenge to see as active in any stance.
This commit is contained in:
+7
-1
@@ -1185,7 +1185,13 @@ function CleveRoids.GetActionButtonInfo(slot)
|
||||
end
|
||||
|
||||
function CleveRoids.IsReactiveUsable(spellName)
|
||||
-- First check combat log-based proc tracking (works across stances)
|
||||
if CleveRoids.HasReactiveProc and CleveRoids.HasReactiveProc(spellName) then
|
||||
return 1
|
||||
end
|
||||
|
||||
-- Use Nampower's IsSpellUsable if available (more accurate)
|
||||
-- Note: IsSpellUsable doesn't actually exist in Nampower, but keeping for future compatibility
|
||||
if IsSpellUsable then
|
||||
local usable, oom = IsSpellUsable(spellName)
|
||||
if usable == 1 and oom ~= 1 then
|
||||
@@ -1195,7 +1201,7 @@ function CleveRoids.IsReactiveUsable(spellName)
|
||||
end
|
||||
end
|
||||
|
||||
-- Fallback to original method
|
||||
-- Fallback to action bar slot checking (requires correct stance)
|
||||
if not CleveRoids.reactiveSlots[spellName] then return false end
|
||||
local actionSlot = CleveRoids.reactiveSlots[spellName]
|
||||
local isUsable, oom = CleveRoids.Hooks.OriginalIsUsableAction(actionSlot)
|
||||
|
||||
@@ -594,8 +594,18 @@ function CleveRoids.TestForActiveAction(actions)
|
||||
local onCooldown = (start > 0 and duration > 0)
|
||||
|
||||
if actions.active.isReactive then
|
||||
-- Use Nampower's IsSpellUsable if available for better detection
|
||||
if IsSpellUsable then
|
||||
-- Check combat log-based proc tracking first (stance-independent)
|
||||
if CleveRoids.HasReactiveProc and CleveRoids.HasReactiveProc(actions.active.action) then
|
||||
-- Proc is active, show as usable if in range and have enough rage/mana
|
||||
if actions.active.inRange ~= 0 and not actions.active.oom then
|
||||
actions.active.usable = 1
|
||||
elseif pfUI and pfUI.bars and actions.active.oom then
|
||||
actions.active.usable = 2 -- pfUI: out of mana/rage
|
||||
else
|
||||
actions.active.usable = nil
|
||||
end
|
||||
-- Use Nampower's IsSpellUsable if available (stance-aware fallback)
|
||||
elseif IsSpellUsable then
|
||||
local usable, oom = IsSpellUsable(actions.active.action)
|
||||
if usable == 1 and oom ~= 1 then
|
||||
actions.active.usable = (pfUI and pfUI.bars) and nil or 1
|
||||
@@ -3349,6 +3359,10 @@ SlashCmdList["CLEVEROID"] = function(msg)
|
||||
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("|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')
|
||||
return
|
||||
@@ -3811,6 +3825,84 @@ SlashCmdList["CLEVEROID"] = function(msg)
|
||||
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
|
||||
|
||||
-- Unknown command fallback
|
||||
CleveRoids.Print("Usage:")
|
||||
DEFAULT_CHAT_FRAME:AddMessage("/cleveroid - Show current settings")
|
||||
|
||||
@@ -231,18 +231,38 @@ end
|
||||
function CleveRoids.IndexActionSlot(slot)
|
||||
if not HasAction(slot) then
|
||||
CleveRoids.Actions[slot] = nil
|
||||
-- When clearing a reactive slot, check if we need to find it elsewhere
|
||||
local clearedReactiveName = CleveRoids.reactiveSlots[slot]
|
||||
CleveRoids.ClearSlot(CleveRoids.reactiveSlots, slot)
|
||||
CleveRoids.ClearSlot(CleveRoids.actionSlots, slot)
|
||||
|
||||
-- If we cleared a reactive spell, rescan to find it in another slot
|
||||
if clearedReactiveName then
|
||||
for i = 1, 120 do
|
||||
if i ~= slot and HasAction(i) then
|
||||
local _, _, scanName = CleveRoids.GetActionButtonInfo(i)
|
||||
if scanName == clearedReactiveName then
|
||||
CleveRoids.reactiveSlots[clearedReactiveName] = i
|
||||
CleveRoids.reactiveSlots[i] = clearedReactiveName
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
else
|
||||
local actionType, _, name, rank = CleveRoids.GetActionButtonInfo(slot)
|
||||
if name then
|
||||
local reactiveName = CleveRoids.reactiveSpells[name] and name
|
||||
local actionSlotName = name..(rank and ("("..rank..")") or "")
|
||||
if reactiveName then
|
||||
if not CleveRoids.reactiveSlots[reactiveName] then
|
||||
CleveRoids.reactiveSlots[reactiveName] = slot
|
||||
CleveRoids.reactiveSlots[slot] = reactiveName
|
||||
-- Always update the mapping to ensure we track the correct slot
|
||||
-- Clear old mapping for this spell name first
|
||||
local oldSlot = CleveRoids.reactiveSlots[reactiveName]
|
||||
if oldSlot and oldSlot ~= slot then
|
||||
CleveRoids.reactiveSlots[oldSlot] = nil
|
||||
end
|
||||
CleveRoids.reactiveSlots[reactiveName] = slot
|
||||
CleveRoids.reactiveSlots[slot] = reactiveName
|
||||
elseif not reactiveName then
|
||||
CleveRoids.ClearSlot(CleveRoids.reactiveSlots, slot)
|
||||
end
|
||||
|
||||
+188
@@ -2535,3 +2535,191 @@ immunityFrame:SetScript("OnEvent", function()
|
||||
ParseImmunityCombatLog()
|
||||
end
|
||||
end)
|
||||
|
||||
-- ============================================================================
|
||||
-- REACTIVE ABILITY PROC TRACKING SYSTEM
|
||||
-- ============================================================================
|
||||
-- Tracks reactive ability procs independently of stance/usability
|
||||
-- Allows detection of Overpower/Revenge/Riposte procs even when not in correct stance
|
||||
|
||||
-- Table to store reactive proc states with expiry times and target GUIDs
|
||||
-- Structure: { spellName = { expiry = time, targetGUID = guid } }
|
||||
CleveRoids.reactiveProcs = CleveRoids.reactiveProcs or {}
|
||||
|
||||
-- Proc durations (in seconds)
|
||||
-- Overpower and Revenge: 4 seconds
|
||||
-- Riposte: 5 seconds (keeping at 5 for safety, can be adjusted)
|
||||
local REACTIVE_PROC_DURATION = 4.0
|
||||
|
||||
-- Reactive ability trigger patterns for combat log
|
||||
local reactivePatterns = {
|
||||
Overpower = {
|
||||
-- Procs when ENEMY dodges YOUR attack (auto or ability)
|
||||
patterns = {
|
||||
-- Auto attack dodges
|
||||
"(.+) dodges", -- English: "Target dodges"
|
||||
"(.+) weicht aus", -- German
|
||||
"(.+) esquive", -- French
|
||||
"(.+)이%(가%) 회피", -- Korean
|
||||
"躲闪了(.+)", -- Chinese Simplified
|
||||
"躲閃了(.+)", -- Chinese Traditional
|
||||
|
||||
-- Ability dodges
|
||||
"was dodged by", -- English: "Your Mortal Strike was dodged by Target"
|
||||
"wurde von (.+) ausgewichen", -- German
|
||||
"a été esquivé par", -- French
|
||||
"을%(를%) (.+)이%(가%) 회피", -- Korean
|
||||
"被(.+)躲闪", -- Chinese Simplified
|
||||
"被(.+)躲閃", -- Chinese Traditional
|
||||
},
|
||||
type = "enemy_dodge",
|
||||
requiresTargetGUID = true,
|
||||
duration = 4.0 -- 4 second proc window
|
||||
},
|
||||
Riposte = {
|
||||
-- Procs when YOU parry an enemy attack
|
||||
patterns = {
|
||||
"You parry", -- English: "You parry X's Y"
|
||||
"Ihr pariert", -- German
|
||||
"Vous parez", -- French
|
||||
"막아냈습니다", -- Korean
|
||||
"你招架了", -- Chinese Simplified
|
||||
"你招架了", -- Chinese Traditional
|
||||
},
|
||||
type = "player_parry",
|
||||
requiresTargetGUID = true, -- Track which enemy you parried
|
||||
duration = 5.0 -- 5 second proc window (estimated, may be 4s)
|
||||
},
|
||||
Revenge = {
|
||||
-- Procs when YOU block, dodge, or parry an enemy attack (any stance)
|
||||
patterns = {
|
||||
"You block", -- English: "You block X's Y"
|
||||
"You dodge", -- English: "You dodge X's Y"
|
||||
"You parry", -- English: "You parry X's Y"
|
||||
"Ihr blockt", -- German block
|
||||
"Ihr weicht aus", -- German dodge
|
||||
"Ihr pariert", -- German parry
|
||||
"Vous bloquez", -- French block
|
||||
"Vous esquivez", -- French dodge
|
||||
"Vous parez", -- French parry
|
||||
"막았습니다", -- Korean block
|
||||
"회피했습니다", -- Korean dodge
|
||||
"막아냈습니다", -- Korean parry
|
||||
"你格挡了", -- Chinese Simplified block
|
||||
"你躲闪了", -- Chinese Simplified dodge
|
||||
"你招架了", -- Chinese Simplified parry
|
||||
"你格擋了", -- Chinese Traditional block
|
||||
"你躲閃了", -- Chinese Traditional dodge
|
||||
"你招架了", -- Chinese Traditional parry
|
||||
},
|
||||
type = "player_avoid",
|
||||
requiresTargetGUID = true, -- Track which enemy triggered it
|
||||
duration = 4.0 -- 4 second proc window
|
||||
}
|
||||
}
|
||||
|
||||
-- Set a reactive proc state with optional target GUID
|
||||
function CleveRoids.SetReactiveProc(spellName, duration, targetGUID)
|
||||
duration = duration or REACTIVE_PROC_DURATION
|
||||
CleveRoids.reactiveProcs[spellName] = {
|
||||
expiry = GetTime() + duration,
|
||||
targetGUID = targetGUID
|
||||
}
|
||||
end
|
||||
|
||||
-- Check if a reactive proc is active (with optional GUID check)
|
||||
function CleveRoids.HasReactiveProc(spellName)
|
||||
local procData = CleveRoids.reactiveProcs[spellName]
|
||||
if not procData or not procData.expiry then return false end
|
||||
|
||||
local now = GetTime()
|
||||
if now >= procData.expiry then
|
||||
-- Expired, clear it
|
||||
CleveRoids.reactiveProcs[spellName] = nil
|
||||
return false
|
||||
end
|
||||
|
||||
-- If proc has a target GUID requirement, check if current target matches
|
||||
if procData.targetGUID then
|
||||
local _, targetGUID = UnitExists("target")
|
||||
if not targetGUID or targetGUID ~= procData.targetGUID then
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
-- Clear a reactive proc
|
||||
function CleveRoids.ClearReactiveProc(spellName)
|
||||
CleveRoids.reactiveProcs[spellName] = nil
|
||||
end
|
||||
|
||||
-- Parse combat log for reactive ability triggers
|
||||
function CleveRoids.ParseReactiveCombatLog()
|
||||
if not arg1 then return end
|
||||
|
||||
local message = arg1
|
||||
local _, targetGUID = UnitExists("target")
|
||||
|
||||
-- Check each reactive ability's trigger patterns
|
||||
for spellName, config in pairs(reactivePatterns) do
|
||||
-- Skip if player doesn't know this spell
|
||||
if CleveRoids.GetSpell(spellName) then
|
||||
for _, pattern in ipairs(config.patterns) do
|
||||
if strfind(message, pattern) then
|
||||
-- Found a trigger event (works in any stance)
|
||||
local guid = config.requiresTargetGUID and targetGUID or nil
|
||||
local duration = config.duration or REACTIVE_PROC_DURATION
|
||||
CleveRoids.SetReactiveProc(spellName, duration, guid)
|
||||
|
||||
-- Update action buttons to reflect new state
|
||||
CleveRoids.QueueActionUpdate()
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Clear reactive proc when spell is cast
|
||||
function CleveRoids.ClearReactiveProcOnCast(spellName)
|
||||
if not spellName then return end
|
||||
|
||||
-- Check if this is a reactive spell
|
||||
if CleveRoids.reactiveSpells and CleveRoids.reactiveSpells[spellName] then
|
||||
CleveRoids.ClearReactiveProc(spellName)
|
||||
CleveRoids.QueueActionUpdate()
|
||||
end
|
||||
end
|
||||
|
||||
-- Hook UNIT_CASTEVENT to clear reactive procs
|
||||
local originalUnitCastEvent = CleveRoids.Frame and CleveRoids.Frame.UNIT_CASTEVENT
|
||||
if originalUnitCastEvent then
|
||||
CleveRoids.Frame.UNIT_CASTEVENT = function(...)
|
||||
-- Call original handler first
|
||||
if type(originalUnitCastEvent) == "function" then
|
||||
originalUnitCastEvent(unpack(arg))
|
||||
end
|
||||
|
||||
-- Clear reactive proc on spell cast start
|
||||
if arg1 == "player" and arg2 == "START" and arg4 then
|
||||
CleveRoids.ClearReactiveProcOnCast(arg4)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Register combat log event for reactive proc tracking
|
||||
local reactiveFrame = CreateFrame("Frame", "CleveRoidsReactiveFrame")
|
||||
reactiveFrame:RegisterEvent("RAW_COMBATLOG")
|
||||
reactiveFrame:RegisterEvent("CHAT_MSG_COMBAT_SELF_HITS")
|
||||
reactiveFrame:RegisterEvent("CHAT_MSG_COMBAT_SELF_MISSES")
|
||||
reactiveFrame:RegisterEvent("CHAT_MSG_SPELL_SELF_DAMAGE")
|
||||
reactiveFrame:SetScript("OnEvent", function()
|
||||
if event == "RAW_COMBATLOG" or
|
||||
event == "CHAT_MSG_COMBAT_SELF_HITS" or
|
||||
event == "CHAT_MSG_COMBAT_SELF_MISSES" or
|
||||
event == "CHAT_MSG_SPELL_SELF_DAMAGE" then
|
||||
CleveRoids.ParseReactiveCombatLog()
|
||||
end
|
||||
end)
|
||||
|
||||
Reference in New Issue
Block a user