From e980e4a93502888a4334a83f8ac0f48ec333bec8 Mon Sep 17 00:00:00 2001 From: Derek Mikesell Date: Sat, 20 Jun 2026 13:51:45 -0700 Subject: [PATCH] fix(tracking-bars): track hero-talent spells in both override directions A tracking bar saved for a hero-talent override spell (e.g. DK "Death Charge") stopped showing once the talent was removed, even though casting the base spell ("Death's Advance") should still drive it. A bar saved for the base spell already worked when talented into the override, so the behaviour was asymmetric. Cause: Blizzard's cooldownInfo always reports the base in info.spellID but only reports the override in info.overrideSpellID WHILE the talent is active. So a base-saved bar matched in every state, while an override-saved bar matched only while talented. Fix: persist the base spell id on the bar config as cfg.baseSpellID and match against it too. - Capture at pick time from the live cooldownInfo (spell picker). - Self-healing backfill in MatchFrameToConfig: when matched via the override while talented, record info.spellID so the bar keeps matching after untalenting (also upgrades bars created before this change). - Clear baseSpellID on the other spell-assignment paths (new-bar reset, popular preset, manual-id popup) to avoid stale values. Confirmed in-game in both directions. --- .../EUI_CooldownManager_Options.lua | 16 ++++++++++++++ .../EllesmereUICdmBuffBars.lua | 22 ++++++++++++++++++- 2 files changed, 37 insertions(+), 1 deletion(-) diff --git a/EllesmereUICooldownManager/EUI_CooldownManager_Options.lua b/EllesmereUICooldownManager/EUI_CooldownManager_Options.lua index 22e70871..ac0cb12e 100644 --- a/EllesmereUICooldownManager/EUI_CooldownManager_Options.lua +++ b/EllesmereUICooldownManager/EUI_CooldownManager_Options.lua @@ -1880,6 +1880,9 @@ initFrame:SetScript("OnEvent", function(self) barCfg.popularKey = nil barCfg.glowBased = nil barCfg.customDuration = dur + -- Manually-entered id: no live frame to read the base from. Clear any + -- stale base; MatchFrameToConfig self-heals it if/when talented. + barCfg.baseSpellID = nil barCfg.name = C_Spell.GetSpellName(sid) Refresh() ns.BuildTrackedBuffBars() @@ -2010,6 +2013,7 @@ initFrame:SetScript("OnEvent", function(self) barCfg.glowBased = entry.glowBased or nil barCfg.customDuration = entry.customDuration barCfg.spellID = entry.spellIDs and entry.spellIDs[1] or 0 + barCfg.baseSpellID = nil barCfg.name = entry.name Refresh() ns.BuildTrackedBuffBars() @@ -2104,6 +2108,18 @@ initFrame:SetScript("OnEvent", function(self) barCfg.glowBased = nil barCfg.customDuration = nil barCfg.name = sp.name + -- Capture the BASE spell id for hero-talent override spells so + -- the bar keeps tracking after the talent is removed. When the + -- picked spell is an active override (e.g. Death Charge), the + -- live cooldownInfo reports the base (Death's Advance) in + -- info.spellID; store it only when it differs from the picked id. + barCfg.baseSpellID = nil + if sp.cdID and C_CooldownViewer and C_CooldownViewer.GetCooldownViewerCooldownInfo then + local info = C_CooldownViewer.GetCooldownViewerCooldownInfo(sp.cdID) + if info and info.spellID and info.spellID > 0 and info.spellID ~= sp.spellID then + barCfg.baseSpellID = info.spellID + end + end Refresh() ns.BuildTrackedBuffBars() if onChanged then onChanged() end diff --git a/EllesmereUICooldownManager/EllesmereUICdmBuffBars.lua b/EllesmereUICooldownManager/EllesmereUICdmBuffBars.lua index 278819cc..07e75d68 100644 --- a/EllesmereUICooldownManager/EllesmereUICdmBuffBars.lua +++ b/EllesmereUICooldownManager/EllesmereUICdmBuffBars.lua @@ -287,6 +287,7 @@ function ns.AddTrackedBuffBar() newBar.name = "Bar " .. (#tbb.bars + 1) newBar.popularKey = nil newBar.spellIDs = nil + newBar.baseSpellID = nil -- A new bar joins the group only if EVERY existing bar is already checked, -- otherwise it starts unchecked (independent). Vacuously true for the 1st bar. local allGrouped = true @@ -903,6 +904,19 @@ local function MatchFrameToConfig(frame, cfg) if not gci then return false end local info = gci(cdID) if not info then return false end + -- Self-healing base capture for hero-talent override spells. When a bar was + -- saved for the OVERRIDE form (e.g. Death Charge) and is currently matched + -- while talented, the frame reports the override in info.overrideSpellID and + -- the BASE form (Death's Advance) in info.spellID. Record that base on the + -- config so the bar keeps matching once the talent is removed: cooldownInfo + -- only carries the override id WHILE talented, so without the stored base the + -- bar would go dark when untalented (cast becomes the base spell). This + -- backfills bars created before baseSpellID was captured at pick time. + if cfg.spellID and cfg.spellID > 0 and not cfg.baseSpellID + and info.overrideSpellID == cfg.spellID + and info.spellID and info.spellID > 0 and info.spellID ~= cfg.spellID then + cfg.baseSpellID = info.spellID + end -- Fast path: match via cooldownInfo struct fields. if cfg.spellIDs then for _, sid in ipairs(cfg.spellIDs) do @@ -910,6 +924,11 @@ local function MatchFrameToConfig(frame, cfg) end elseif cfg.spellID and cfg.spellID > 0 then if MatchesSID(info, cfg.spellID) then return true end + -- Talent-override fallback: a bar saved for the override form also + -- tracks its base form, so it keeps showing after the talent is removed. + if cfg.baseSpellID and cfg.baseSpellID > 0 and MatchesSID(info, cfg.baseSpellID) then + return true + end else return false end @@ -925,7 +944,8 @@ local function MatchFrameToConfig(frame, cfg) if frameSID == sid then return true end end elseif cfg.spellID and cfg.spellID > 0 then - return frameSID == cfg.spellID + if frameSID == cfg.spellID then return true end + if cfg.baseSpellID and frameSID == cfg.baseSpellID then return true end end end end