mirror of
https://github.com/brues-code/SuperCleveRoidMacros.git
synced 2026-09-16 03:38:00 +00:00
really fix checking your own debuff timers for personal debuffs
This commit is contained in:
+108
-82
@@ -755,9 +755,13 @@ function CleveRoids.ValidateAura(unit, args, isbuff)
|
||||
|
||||
if current_spellID and searchName then
|
||||
local auraName = SpellInfo(current_spellID)
|
||||
if auraName and string.lower(auraName) == searchName then
|
||||
found = true
|
||||
break
|
||||
if auraName then
|
||||
-- Strip rank for comparison (handles "Moonfire (Rank 7)" vs "moonfire")
|
||||
local baseName = string.gsub(auraName, "%s*%(%s*Rank%s+%d+%s*%)", "")
|
||||
if string.lower(baseName) == searchName or string.lower(auraName) == searchName then
|
||||
found = true
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -777,9 +781,13 @@ function CleveRoids.ValidateAura(unit, args, isbuff)
|
||||
|
||||
if current_spellID then
|
||||
local auraName = SpellInfo(current_spellID)
|
||||
if auraName and string.lower(auraName) == searchName then
|
||||
found = true
|
||||
break
|
||||
if auraName then
|
||||
-- Strip rank for comparison
|
||||
local baseName = string.gsub(auraName, "%s*%(%s*Rank%s+%d+%s*%)", "")
|
||||
if string.lower(baseName) == searchName or string.lower(auraName) == searchName then
|
||||
found = true
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -850,93 +858,97 @@ function CleveRoids.ValidateUnitDebuff(unit, args)
|
||||
return false
|
||||
end
|
||||
|
||||
-- For non-player units, use libdebuff with smart caster filtering
|
||||
-- Personal debuffs (Rake, Rip, etc.) filter by "player" caster
|
||||
-- Shared debuffs (Sunder, Thunder Clap, etc.) match any caster
|
||||
-- For non-player units, check tracking table directly
|
||||
-- SIMPLE: Did the player cast this spell? Is the timer still valid?
|
||||
if unit ~= "player" and CleveRoids.libdebuff then
|
||||
-- Determine if we should filter by player caster
|
||||
local filterCaster = nil
|
||||
local _, guid = UnitExists(unit)
|
||||
if not guid then return false end
|
||||
|
||||
-- Try to get spell ID to check if it's personal/shared
|
||||
-- Search through libdebuff tables first (most reliable for debuffs)
|
||||
local spellID = nil
|
||||
if CleveRoids.libdebuff and (CleveRoids.libdebuff.personalDebuffs or CleveRoids.libdebuff.sharedDebuffs) then
|
||||
-- Search personal debuffs by name
|
||||
if CleveRoids.libdebuff.personalDebuffs then
|
||||
for sid, _ in pairs(CleveRoids.libdebuff.personalDebuffs) do
|
||||
local name = SpellInfo(sid)
|
||||
if name then
|
||||
-- Strip rank from name
|
||||
name = string.gsub(name, "%s*%(%s*Rank%s+%d+%s*%)", "")
|
||||
if name == args.name then
|
||||
spellID = sid
|
||||
break
|
||||
end
|
||||
-- Normalize GUID to string for consistent table key lookups
|
||||
guid = CleveRoids.NormalizeGUID(guid)
|
||||
if not guid then return false end
|
||||
|
||||
-- Find ALL spell IDs that match this name (all ranks)
|
||||
local matchingSpellIDs = {}
|
||||
if CleveRoids.libdebuff.personalDebuffs then
|
||||
for sid, _ in pairs(CleveRoids.libdebuff.personalDebuffs) do
|
||||
local name = SpellInfo(sid)
|
||||
if name then
|
||||
name = string.gsub(name, "%s*%(%s*Rank%s+%d+%s*%)", "")
|
||||
if name == args.name then
|
||||
table.insert(matchingSpellIDs, sid)
|
||||
end
|
||||
end
|
||||
end
|
||||
-- Search shared debuffs by name if not found
|
||||
if not spellID and CleveRoids.libdebuff.sharedDebuffs then
|
||||
for sid, _ in pairs(CleveRoids.libdebuff.sharedDebuffs) do
|
||||
local name = SpellInfo(sid)
|
||||
if name then
|
||||
-- Strip rank from name
|
||||
name = string.gsub(name, "%s*%(%s*Rank%s+%d+%s*%)", "")
|
||||
if name == args.name then
|
||||
spellID = sid
|
||||
break
|
||||
end
|
||||
end
|
||||
if CleveRoids.libdebuff.sharedDebuffs then
|
||||
for sid, _ in pairs(CleveRoids.libdebuff.sharedDebuffs) do
|
||||
local name = SpellInfo(sid)
|
||||
if name then
|
||||
name = string.gsub(name, "%s*%(%s*Rank%s+%d+%s*%)", "")
|
||||
if name == args.name then
|
||||
table.insert(matchingSpellIDs, sid)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Check if this is a personal debuff (should filter by caster)
|
||||
if spellID and CleveRoids.libdebuff.IsPersonalDebuff then
|
||||
if CleveRoids.libdebuff:IsPersonalDebuff(spellID) then
|
||||
filterCaster = "player"
|
||||
end
|
||||
else
|
||||
-- Unknown debuffs default to personal (safer for multi-player)
|
||||
filterCaster = "player"
|
||||
end
|
||||
-- Check tracking table for ANY rank of this spell: Did player cast this? Is timer valid?
|
||||
if table.getn(matchingSpellIDs) > 0 then
|
||||
for _, spellID in ipairs(matchingSpellIDs) do
|
||||
local rec = CleveRoids.libdebuff.objects[guid] and CleveRoids.libdebuff.objects[guid][spellID]
|
||||
if rec and rec.caster == "player" and rec.duration and rec.start then
|
||||
local timeRemaining = rec.duration + rec.start - GetTime()
|
||||
if timeRemaining > 0 then
|
||||
found = true
|
||||
remaining = timeRemaining
|
||||
stacks = rec.stacks or 0
|
||||
|
||||
-- Search debuff slots
|
||||
i = 1
|
||||
while true do
|
||||
local name, rank, tex, stk, dtype, duration, timeleft, caster =
|
||||
CleveRoids.libdebuff:UnitDebuff(unit, i, filterCaster)
|
||||
if CleveRoids.debug then
|
||||
DEFAULT_CHAT_FRAME:AddMessage(
|
||||
string.format("|cff00ff00[Tracking]|r %s (ID:%d): %.1fs left", args.name, spellID, timeRemaining)
|
||||
)
|
||||
end
|
||||
|
||||
if not name then break end
|
||||
-- Get texture (optional, just for display)
|
||||
for i = 1, 16 do
|
||||
local _, _, _, sid = UnitDebuff(unit, i)
|
||||
if sid == spellID then
|
||||
texture = UnitDebuff(unit, i)
|
||||
break
|
||||
end
|
||||
end
|
||||
if not texture then
|
||||
for i = 1, 32 do
|
||||
local _, _, sid = UnitBuff(unit, i)
|
||||
if sid == spellID then
|
||||
texture = UnitBuff(unit, i)
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if name == args.name then
|
||||
found = true
|
||||
texture = tex
|
||||
stacks = stk
|
||||
remaining = timeleft
|
||||
break
|
||||
end
|
||||
i = i + 1
|
||||
end
|
||||
|
||||
-- If not found in debuffs, check buff slots (overflow debuffs)
|
||||
if not found then
|
||||
i = 1
|
||||
while true do
|
||||
local name, rank, tex, stk, dtype, duration, timeleft, caster =
|
||||
CleveRoids.libdebuff:UnitBuff(unit, i, filterCaster)
|
||||
|
||||
if not name then break end
|
||||
|
||||
if name == args.name then
|
||||
found = true
|
||||
texture = tex
|
||||
stacks = stk
|
||||
remaining = timeleft
|
||||
break
|
||||
-- Found active debuff, stop searching
|
||||
break
|
||||
elseif CleveRoids.debug then
|
||||
DEFAULT_CHAT_FRAME:AddMessage(
|
||||
string.format("|cffff6600[Tracking]|r %s (ID:%d) expired %.1fs ago",
|
||||
args.name, spellID, GetTime() - (rec.start + rec.duration))
|
||||
)
|
||||
end
|
||||
end
|
||||
i = i + 1
|
||||
end
|
||||
|
||||
if not found and CleveRoids.debug then
|
||||
DEFAULT_CHAT_FRAME:AddMessage(
|
||||
string.format("|cffff0000[Tracking]|r %s not in tracking table (checked %d ranks)",
|
||||
args.name, table.getn(matchingSpellIDs))
|
||||
)
|
||||
end
|
||||
elseif CleveRoids.debug then
|
||||
DEFAULT_CHAT_FRAME:AddMessage(
|
||||
string.format("|cffff0000[Tracking]|r Unknown spell: %s", args.name)
|
||||
)
|
||||
end
|
||||
-- For player unit, use standard search (player only sees own debuffs on self)
|
||||
elseif unit == "player" then
|
||||
@@ -946,8 +958,15 @@ function CleveRoids.ValidateUnitDebuff(unit, args)
|
||||
texture, stacks, spellID, remaining = CleveRoids.GetPlayerAura(i, false)
|
||||
if not texture then break end
|
||||
|
||||
if (CleveRoids.hasSuperwow and args.name == SpellInfo(spellID))
|
||||
or (not CleveRoids.hasSuperwow and texture == CleveRoids.auraTextures[args.name]) then
|
||||
if CleveRoids.hasSuperwow then
|
||||
local fullName = SpellInfo(spellID)
|
||||
-- Strip rank for comparison (handles "Moonfire (Rank 7)" vs "Moonfire")
|
||||
local baseName = string.gsub(fullName or "", "%s*%(%s*Rank%s+%d+%s*%)", "")
|
||||
if baseName == args.name or fullName == args.name then
|
||||
found = true
|
||||
break
|
||||
end
|
||||
elseif texture == CleveRoids.auraTextures[args.name] then
|
||||
found = true
|
||||
break
|
||||
end
|
||||
@@ -961,8 +980,15 @@ function CleveRoids.ValidateUnitDebuff(unit, args)
|
||||
texture, stacks, spellID, remaining = CleveRoids.GetPlayerAura(i, true)
|
||||
if not texture then break end
|
||||
|
||||
if (CleveRoids.hasSuperwow and args.name == SpellInfo(spellID))
|
||||
or (not CleveRoids.hasSuperwow and texture == CleveRoids.auraTextures[args.name]) then
|
||||
if CleveRoids.hasSuperwow then
|
||||
local fullName = SpellInfo(spellID)
|
||||
-- Strip rank for comparison
|
||||
local baseName = string.gsub(fullName or "", "%s*%(%s*Rank%s+%d+%s*%)", "")
|
||||
if baseName == args.name or fullName == args.name then
|
||||
found = true
|
||||
break
|
||||
end
|
||||
elseif texture == CleveRoids.auraTextures[args.name] then
|
||||
found = true
|
||||
break
|
||||
end
|
||||
|
||||
+104
-7
@@ -17,6 +17,13 @@ local tonumber = tonumber
|
||||
local tostring = tostring
|
||||
local GetTime = GetTime
|
||||
|
||||
-- GUID normalization: ensure all GUIDs are strings for consistent table key lookups
|
||||
-- In Lua, table["123"] is different from table[123], so we must normalize
|
||||
function CleveRoids.NormalizeGUID(guid)
|
||||
if not guid then return nil end
|
||||
return tostring(guid)
|
||||
end
|
||||
|
||||
if type(hooksecurefunc) ~= "function" then
|
||||
function hooksecurefunc(arg1, arg2, arg3)
|
||||
local tgt, fname, post
|
||||
@@ -808,6 +815,10 @@ end
|
||||
function lib:AddEffect(guid, unitName, spellID, duration, stacks, caster)
|
||||
if not guid or not spellID then return end
|
||||
|
||||
-- Normalize GUID to string for consistent table key lookups
|
||||
guid = CleveRoids.NormalizeGUID(guid)
|
||||
if not guid then return end
|
||||
|
||||
duration = duration or lib:GetDuration(spellID, caster)
|
||||
if duration <= 0 then return end
|
||||
|
||||
@@ -828,8 +839,8 @@ function lib:AddEffect(guid, unitName, spellID, duration, stacks, caster)
|
||||
local spellName = SpellInfo(spellID) or "Unknown"
|
||||
local casterStr = caster or "nil"
|
||||
DEFAULT_CHAT_FRAME:AddMessage(
|
||||
string.format("|cff00ffff[DEBUG AddEffect]|r %s (ID:%d) stored duration:%ds on %s, caster:%s",
|
||||
spellName, spellID, duration, unitName or "Unknown", casterStr)
|
||||
string.format("|cff00ffff[DEBUG AddEffect]|r %s (ID:%d) stored duration:%ds on %s, caster:%s, GUID:%s",
|
||||
spellName, spellID, duration, unitName or "Unknown", casterStr, tostring(guid))
|
||||
)
|
||||
end
|
||||
end
|
||||
@@ -838,6 +849,9 @@ function lib:UnitDebuff(unit, id, filterCaster)
|
||||
local _, guid = UnitExists(unit)
|
||||
if not guid then return nil end
|
||||
|
||||
-- Normalize GUID to string for consistent table key lookups
|
||||
guid = CleveRoids.NormalizeGUID(guid)
|
||||
|
||||
local texture, stacks, dtype, spellID = UnitDebuff(unit, id)
|
||||
|
||||
if not texture or not spellID then
|
||||
@@ -1116,6 +1130,9 @@ ev:SetScript("OnEvent", function()
|
||||
local eventType = arg3
|
||||
local spellID = arg4
|
||||
|
||||
-- Normalize targetGUID to string for consistent table key lookups
|
||||
targetGUID = CleveRoids.NormalizeGUID(targetGUID)
|
||||
|
||||
-- Capture combo points when cast STARTS (before they're consumed)
|
||||
if (eventType == "START" or eventType == "CHANNEL") and spellID then
|
||||
local _, playerGUID = UnitExists("player")
|
||||
@@ -1161,6 +1178,7 @@ ev:SetScript("OnEvent", function()
|
||||
local targetName = lib.guidToName[targetGUID]
|
||||
if not targetName then
|
||||
local _, currentTargetGUID = UnitExists("target")
|
||||
currentTargetGUID = CleveRoids.NormalizeGUID(currentTargetGUID)
|
||||
if currentTargetGUID == targetGUID then
|
||||
targetName = UnitName("target")
|
||||
lib.guidToName[targetGUID] = targetName
|
||||
@@ -1518,11 +1536,81 @@ ev:SetScript("OnEvent", function()
|
||||
end
|
||||
end)
|
||||
|
||||
-- Track recently cast debuffs to validate they actually landed (not dodged/missed/resisted)
|
||||
-- Format: [targetGUID][spellID] = { timestamp = GetTime(), validated = false }
|
||||
lib.pendingDebuffs = lib.pendingDebuffs or {}
|
||||
|
||||
local evLearn = CreateFrame("Frame", "CleveRoidsLibDebuffLearnFrame", UIParent)
|
||||
evLearn:RegisterEvent("RAW_COMBATLOG")
|
||||
evLearn:RegisterEvent("CHAT_MSG_SPELL_SELF_DAMAGE") -- For miss/dodge/parry detection
|
||||
|
||||
evLearn:SetScript("OnEvent", function()
|
||||
if event == "RAW_COMBATLOG" then
|
||||
-- Handle spell misses, dodges, parries, and resists
|
||||
if event == "CHAT_MSG_SPELL_SELF_DAMAGE" then
|
||||
local message = arg1
|
||||
if not message then return end
|
||||
|
||||
-- Check for miss/dodge/parry/resist messages
|
||||
local isMiss = find(message, "miss") or find(message, "MISS")
|
||||
local isDodge = find(message, "dodge") or find(message, "dodged")
|
||||
local isParry = find(message, "parry") or find(message, "parried") or find(message, "pariert")
|
||||
local isResist = find(message, "resist") and not find(message, "resisted%)") -- Exclude partial resists
|
||||
|
||||
if isMiss or isDodge or isParry or isResist then
|
||||
-- Extract spell name and target from various message formats
|
||||
local spellName, targetName
|
||||
|
||||
-- "Your [Spell] was dodged by [Target]"
|
||||
if not spellName then
|
||||
_, _, spellName, targetName = find(message, "Your%s+(.-)%s+was%s+[a-z]+%s+by%s+(.-)%.")
|
||||
end
|
||||
-- "Your [Spell] missed [Target]"
|
||||
if not spellName then
|
||||
_, _, spellName, targetName = find(message, "Your%s+(.-)%s+missed%s+(.-)%.")
|
||||
end
|
||||
-- "[Target] dodges your [Spell]"
|
||||
if not spellName then
|
||||
_, _, targetName, spellName = find(message, "^(.-)%s+[a-z]+s%s+your%s+(.-)%.")
|
||||
end
|
||||
|
||||
if spellName then
|
||||
-- Find the spell ID by name
|
||||
local spellID = nil
|
||||
if lib.personalDebuffs then
|
||||
for sid, _ in pairs(lib.personalDebuffs) do
|
||||
local name = SpellInfo(sid)
|
||||
if name then
|
||||
name = string.gsub(name, "%s*%(%s*Rank%s+%d+%s*%)", "")
|
||||
if lower(name) == lower(spellName) then
|
||||
spellID = sid
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Remove from tracking if it exists (the cast failed)
|
||||
if spellID then
|
||||
-- Find the target GUID (check current target first)
|
||||
local _, currentGUID = UnitExists("target")
|
||||
if currentGUID and lib.objects[currentGUID] and lib.objects[currentGUID][spellID] then
|
||||
-- Only remove if it was very recently added (within 0.5 seconds)
|
||||
local rec = lib.objects[currentGUID][spellID]
|
||||
if rec.start and (GetTime() - rec.start) < 0.5 then
|
||||
lib.objects[currentGUID][spellID] = nil
|
||||
if CleveRoids.debug then
|
||||
DEFAULT_CHAT_FRAME:AddMessage(
|
||||
string.format("|cffff6600[Miss/Dodge/Parry]|r Removed %s (ID:%d) - spell didn't land",
|
||||
spellName, spellID)
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
elseif event == "RAW_COMBATLOG" then
|
||||
local raw = arg2
|
||||
-- PERFORMANCE: Quick length check before string search
|
||||
if not raw or string.len(raw) < 12 then return end -- "X fades from Y" minimum length
|
||||
@@ -2392,10 +2480,14 @@ local function OnSpellDamageEvent()
|
||||
|
||||
if not spellId or not spellSchool then return end
|
||||
|
||||
-- PERFORMANCE: Skip if already learned (unless it might be a bleed upgrade)
|
||||
-- PERFORMANCE: Skip if already learned and finalized
|
||||
local currentSchool = CleveRoids.spellSchoolMapping[spellId]
|
||||
if currentSchool and currentSchool ~= "physical" then
|
||||
return -- Already learned and not physical (can't be upgraded to bleed)
|
||||
if currentSchool then
|
||||
-- If already learned as anything other than physical, we're done (can't be upgraded)
|
||||
if currentSchool ~= "physical" then
|
||||
return
|
||||
end
|
||||
-- If learned as physical, continue processing - might upgrade to bleed
|
||||
end
|
||||
|
||||
-- Convert school enum (0-6) to name
|
||||
@@ -2426,7 +2518,12 @@ local function OnSpellDamageEvent()
|
||||
end
|
||||
end
|
||||
|
||||
-- Only update if not already known or if this is more specific (e.g., bleed vs physical)
|
||||
-- PERFORMANCE: Skip if the detected school matches what we already know
|
||||
if currentSchool == schoolName then
|
||||
return -- No change needed
|
||||
end
|
||||
|
||||
-- Only update if not already known or if upgrading from physical to bleed
|
||||
if not currentSchool or (currentSchool == "physical" and schoolName == "bleed") then
|
||||
CleveRoids.spellSchoolMapping[spellId] = schoolName
|
||||
|
||||
|
||||
Reference in New Issue
Block a user