From c5a57af0245202cc2d3f5f0eb5602e9a181c0506 Mon Sep 17 00:00:00 2001 From: Jrc13245 Date: Mon, 17 Nov 2025 20:28:22 -0500 Subject: [PATCH] Fix combo point tracking and queue glow for instant finishers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- ComboPointTracker.lua | 62 +++++++++++++++++++++++++++++------ Compatibility/pfUI.lua | 12 +++++++ Console.lua | 74 +++++++++++++++++++++++++++++++++++++++++- Core.lua | 25 ++++++++++++++ Init.lua | 4 +++ Utility.lua | 56 ++++++++++++++++++++++++++++++++ 6 files changed, 222 insertions(+), 11 deletions(-) diff --git a/ComboPointTracker.lua b/ComboPointTracker.lua index d72f9fb..edece79 100644 --- a/ComboPointTracker.lua +++ b/ComboPointTracker.lua @@ -9,8 +9,7 @@ local CleveRoids = _G.CleveRoids or {} -- Initialize combo point tracking table CleveRoids.ComboPointTracking = CleveRoids.ComboPointTracking or {} -CleveRoids.spell_tracking = CleveRoids.spell_tracking or {} -CleveRoids.lastComboPoints = CleveRoids.lastComboPoints or 0 -- Track last known CP count +-- Note: CleveRoids.lastComboPoints and CleveRoids.lastComboPointsTime are initialized in Init.lua -- Initialize SavedVariable for learned combo durations -- Structure: CleveRoids_ComboDurations[spellID][comboPoints] = duration @@ -61,6 +60,7 @@ function CleveRoids.UpdateComboPoints() local current = CleveRoids.GetComboPoints() if current > 0 then CleveRoids.lastComboPoints = current + CleveRoids.lastComboPointsTime = GetTime() end end @@ -264,10 +264,16 @@ function CleveRoids.TrackComboPointCastByID(spellID, targetGUID) -- If combo points are 0, try multiple fallback sources if comboPoints == 0 then - -- First, try lastComboPoints + -- First, try lastComboPoints (don't reset immediately - let it persist) if CleveRoids.lastComboPoints > 0 then comboPoints = CleveRoids.lastComboPoints - CleveRoids.lastComboPoints = 0 -- Reset after using + -- Don't reset here - let it persist for multiple events + if CleveRoids.debug then + DEFAULT_CHAT_FRAME:AddMessage( + string.format("|cffff9900[TrackComboByID]|r Using lastComboPoints: %d for spell ID %d", + comboPoints, spellID) + ) + end else -- Second, check if name-based tracking has recent data for this spell local spellName = SpellInfo(spellID) @@ -316,6 +322,16 @@ function CleveRoids.TrackComboPointCastByID(spellID, targetGUID) ) end + -- Reset lastComboPoints after successfully using it + if comboPoints > 0 and comboPoints == CleveRoids.lastComboPoints then + CleveRoids.lastComboPoints = 0 + if CleveRoids.debug then + DEFAULT_CHAT_FRAME:AddMessage( + string.format("|cff888888[TrackComboByID]|r Reset lastComboPoints after use") + ) + end + end + return duration end @@ -409,13 +425,39 @@ function Extension.OnLoad() CleveRoids.UpdateComboPoints() end) - -- Hook the spell cast functions if they exist - if CleveRoids.CastSpell then - Extension.Hook("CleveRoids.CastSpell", "CastSpell_Hook") - end - + -- Hook CastSpellByName to capture combo points BEFORE the cast if CastSpellByName then - Extension.Hook("CastSpellByName", "CastSpellByName_Hook") + local originalCastSpellByName = CastSpellByName + CastSpellByName = function(spellName, onSelf) + if spellName and CleveRoids.IsComboScalingSpell(spellName) then + -- Capture current combo points BEFORE the spell cast + local currentCP = CleveRoids.GetComboPoints() + if currentCP and currentCP > 0 then + CleveRoids.lastComboPoints = currentCP + CleveRoids.lastComboPointsTime = GetTime() + if CleveRoids.debug then + DEFAULT_CHAT_FRAME:AddMessage( + string.format("|cffaaff00[CastSpellByName Hook]|r Captured %d CP before casting %s", + currentCP, spellName) + ) + end + end + + CleveRoids.TrackComboPointCast(spellName) + + -- Confirm the tracking immediately - this only fires on actual casts + if CleveRoids.ComboPointTracking[spellName] then + CleveRoids.ComboPointTracking[spellName].confirmed = true + if CleveRoids.debug then + DEFAULT_CHAT_FRAME:AddMessage( + string.format("|cff00ff00[Confirmed]|r %s tracking confirmed (CastSpellByName)", + spellName) + ) + end + end + end + return originalCastSpellByName(spellName, onSelf) + end end -- Hook global CastSpell - minimal hook to avoid breaking action bars diff --git a/Compatibility/pfUI.lua b/Compatibility/pfUI.lua index 110fea1..10d8382 100644 --- a/Compatibility/pfUI.lua +++ b/Compatibility/pfUI.lua @@ -150,6 +150,13 @@ function Extension.HookPfUILibdebuff() pflib.AddEffect = function(self, unit, unitlevel, effect, duration, caster) -- effect is a spell name, not ID + if CleveRoids.debug then + DEFAULT_CHAT_FRAME:AddMessage( + string.format("|cffcccccc[pfUI AddEffect]|r Called for '%s' on %s, duration=%s", + effect, unit or "unknown", tostring(duration)) + ) + end + -- Check if this is a combo scaling spell by name if CleveRoids.IsComboScalingSpell and CleveRoids.IsComboScalingSpell(effect) then -- Use name-based tracking which is populated BEFORE pfUI's AddEffect @@ -172,6 +179,11 @@ function Extension.HookPfUILibdebuff() effect) ) end + elseif CleveRoids.debug then + DEFAULT_CHAT_FRAME:AddMessage( + string.format("|cffff9900[pfUI AddEffect]|r No tracking found for '%s'", + effect) + ) end end diff --git a/Console.lua b/Console.lua index ab9ef5c..607499b 100644 --- a/Console.lua +++ b/Console.lua @@ -43,7 +43,7 @@ SlashCmdList.EQUIP = CleveRoids.DoUse -- take back supermacro and pfUI /equip and /use SlashCmdList.SMEQUIP = CleveRoids.DoUse SlashCmdList.PFEQUIP = CleveRoids.DoUse -SlashCmdList.PFUSE = CleveRoids.DoUse +SlashCmdList.PFUSE = CleveRoids.DoUse SLASH_EQUIPMH1 = "/equipmh" SlashCmdList.EQUIPMH = CleveRoids.DoEquipMainhand @@ -160,6 +160,78 @@ SlashCmdList.CAST = function(msg) if msg and string.find(msg, "[%[%?!~{]") then CleveRoids.DoCast(msg) else + -- Use lastComboPoints which is updated on every OnUpdate tick + -- This is critical for instant-cast finishers where GetComboPoints() returns 0 immediately + local currentCP = CleveRoids.lastComboPoints or 0 + + -- Also try GetComboPoints as a fallback + if currentCP == 0 and GetComboPoints then + currentCP = GetComboPoints() + end + + if currentCP > 0 then + if CleveRoids.debug then + DEFAULT_CHAT_FRAME:AddMessage( + string.format("|cffaaff00[/cast Hook]|r Using %d CP for %s", + currentCP, msg) + ) + end + + -- Pre-inject combo duration into pfUI for instant-cast combo finishers + -- Get the spell data to find the proper spell name (handles case-insensitive input) + local spellData = CleveRoids.GetSpell and CleveRoids.GetSpell(msg) + local spellName = spellData and spellData.name or msg + + -- If GetSpell didn't find it, capitalize first letter as fallback + if not spellData and spellName then + spellName = string.upper(string.sub(spellName, 1, 1)) .. string.sub(spellName, 2) + end + + if CleveRoids.debug then + DEFAULT_CHAT_FRAME:AddMessage( + string.format("|cffcccccc[/cast Debug]|r input='%s', spellName='%s', GetSpell=%s, IsComboScalingSpell=%s", + msg, spellName or "nil", tostring(spellData ~= nil), tostring(CleveRoids.IsComboScalingSpell ~= nil)) + ) + end + + if CleveRoids.IsComboScalingSpell and CleveRoids.IsComboScalingSpell(spellName) then + if CleveRoids.debug then + DEFAULT_CHAT_FRAME:AddMessage("|cff00ff00[/cast Debug]|r IS combo scaling spell") + end + local duration = CleveRoids.CalculateComboScaledDuration and + CleveRoids.CalculateComboScaledDuration(spellName, currentCP) + if CleveRoids.debug then + DEFAULT_CHAT_FRAME:AddMessage( + string.format("|cffcccccc[/cast Debug]|r duration=%s, pfUI=%s, pfUI.api=%s, pfUI.api.libdebuff=%s, debuffs=%s", + tostring(duration), tostring(pfUI ~= nil), + tostring(pfUI and pfUI.api ~= nil), + tostring(pfUI and pfUI.api and pfUI.api.libdebuff ~= nil), + tostring(pfUI and pfUI.api and pfUI.api.libdebuff and pfUI.api.libdebuff.debuffs ~= nil)) + ) + end + if duration and CleveRoids.ComboPointTracking then + -- Remove rank from spell name for pfUI compatibility + local baseName = string.gsub(spellName, "%s*%(Rank %d+%)", "") + -- Populate name-based tracking BEFORE the spell is cast + -- This allows pfUI's AddEffect hook to find it + CleveRoids.ComboPointTracking[baseName] = { + combo_points = currentCP, + duration = duration, + cast_time = GetTime(), + target = UnitName("target") or "Unknown", + confirmed = true + } + if CleveRoids.debug then + DEFAULT_CHAT_FRAME:AddMessage( + string.format("|cffff00ff[/cast Pre-Tracking]|r Set tracking['%s'] = %ds (%d CP)", + baseName, duration, currentCP) + ) + end + end + elseif CleveRoids.debug and currentCP > 0 then + DEFAULT_CHAT_FRAME:AddMessage("|cffff9900[/cast Debug]|r NOT a combo scaling spell") + end + end CleveRoids.Hooks.CAST_SlashCmd(msg) end end diff --git a/Core.lua b/Core.lua index c0a45df..7f0b11f 100644 --- a/Core.lua +++ b/Core.lua @@ -2415,6 +2415,31 @@ function IsCurrentAction(slot) if actionToCheck.spell then local rank = actionToCheck.spell.rank or actionToCheck.spell.highest.rank name = actionToCheck.spell.name..(rank and ("("..rank..")")) + + -- Check if this spell is currently queued or being cast via Nampower + if GetCurrentCastingInfo then + local castId, visId, autoId, casting, channeling, onswing, autoattack = GetCurrentCastingInfo() + + -- Get spell ID for comparison + local spellId = actionToCheck.spell.id + if not spellId and GetSpellIdForName then + spellId = GetSpellIdForName(name) + end + + -- Only show glow if spell is actively casting, channeling, or queued + -- castId matches when spell is queued or being cast + -- visId matches during channeling + if spellId then + -- Show glow if actively casting/channeling this spell + if (casting == 1 and castId == spellId) or (channeling == 1 and visId == spellId) then + return true + end + -- Show glow if this spell is queued (castId set but not yet casting) + if casting == 0 and channeling == 0 and castId == spellId then + return true + end + end + end elseif actionToCheck.item then name = actionToCheck.item.name end diff --git a/Init.lua b/Init.lua index 6e7f033..caccea2 100644 --- a/Init.lua +++ b/Init.lua @@ -38,6 +38,10 @@ CleveRoids.unknownTexture = "Interface\\Icons\\INV_Misc_QuestionMark" CleveRoids.spell_tracking = {} +-- Combo point tracking (initialized early for /cast hook) +CleveRoids.lastComboPoints = 0 +CleveRoids.lastComboPointsTime = 0 + -- Holds information about the currently cast spell CleveRoids.CurrentSpell = { -- "channeled" or "cast" diff --git a/Utility.lua b/Utility.lua index 33db59d..0821d9e 100644 --- a/Utility.lua +++ b/Utility.lua @@ -1086,6 +1086,27 @@ ev:SetScript("OnEvent", function() local eventType = arg3 local spellID = arg4 + -- Capture combo points when cast STARTS (before they're consumed) + if (eventType == "START" or eventType == "CHANNEL") and spellID then + local _, playerGUID = UnitExists("player") + if casterGUID == playerGUID and targetGUID then + -- If this is a combo scaling spell, capture combo points NOW (before consumption) + if CleveRoids.IsComboScalingSpellID and CleveRoids.IsComboScalingSpellID(spellID) then + local currentCP = CleveRoids.GetComboPoints() + if currentCP and currentCP > 0 then + CleveRoids.lastComboPoints = currentCP + if CleveRoids.debug then + local spellName = SpellInfo(spellID) or "Unknown" + DEFAULT_CHAT_FRAME:AddMessage( + string.format("|cffaaaaff[UNIT_CASTEVENT START]|r Captured %d CP before casting %s (ID:%d)", + currentCP, spellName, spellID) + ) + end + end + end + end + end + if eventType == "CAST" and spellID then local _, playerGUID = UnitExists("player") if casterGUID == playerGUID and targetGUID then @@ -1127,6 +1148,41 @@ ev:SetScript("OnEvent", function() targetName = "Unknown" end end + + -- For combo spells, populate name-based tracking for pfUI compatibility + if comboPoints and comboPoints > 0 then + local spellName = SpellInfo(spellID) + if spellName and CleveRoids.ComboPointTracking then + -- Remove rank from spell name to match pfUI's format + local baseName = string.gsub(spellName, "%s*%(Rank %d+%)", "") + CleveRoids.ComboPointTracking[baseName] = { + combo_points = comboPoints, + duration = duration, + cast_time = GetTime(), + target = targetName, + confirmed = true -- This is from actual UNIT_CASTEVENT, always confirmed + } + if CleveRoids.debug then + DEFAULT_CHAT_FRAME:AddMessage( + string.format("|cff00ffff[Name-based tracking]|r Set %s: %d CP, %ds duration (for pfUI)", + baseName, comboPoints, duration) + ) + end + + -- CRITICAL: Update pfUI's duration database directly + if pfUI and pfUI.api and pfUI.api.libdebuff and pfUI.api.libdebuff.debuffs then + -- pfUI stores durations by spell name in its debuffs table + pfUI.api.libdebuff.debuffs[baseName] = duration + if CleveRoids.debug then + DEFAULT_CHAT_FRAME:AddMessage( + string.format("|cffff00ff[pfUI Duration Inject]|r Set pfUI.api.libdebuff.debuffs['%s'] = %ds", + baseName, duration) + ) + end + end + end + end + lib:AddEffect(targetGUID, targetName, spellID, duration, 0, "player") -- Sync combo duration to pfUI if it's loaded