From 5e067afd261ef50ff9c730e26ed8e9f62a7e215e Mon Sep 17 00:00:00 2001 From: Jrc13245 Date: Thu, 19 Feb 2026 22:10:32 -0500 Subject: [PATCH] update pfcast and pfui markertracker compatibility --- Conditionals.lua | 25 +++++++++----- Core.lua | 63 +++++++++++++++++++++++++++++++++++ Extensions/Mouseover/pfUI.lua | 46 +++++++++++++++++++++++++ NampowerAPI.lua | 36 ++++++++++++++++++-- 4 files changed, 159 insertions(+), 11 deletions(-) diff --git a/Conditionals.lua b/Conditionals.lua index dbab3c9..722d753 100644 --- a/Conditionals.lua +++ b/Conditionals.lua @@ -1256,14 +1256,6 @@ autoAttackFrame:SetScript("OnEvent", function() -- Register removal events for instant AllCasterAuraTracking cleanup this:RegisterEvent("BUFF_REMOVED_OTHER") this:RegisterEvent("DEBUFF_REMOVED_OTHER") - - -- Check if the CVar is enabled (required for all-caster buff tracking) - local auraCastEnabled = GetCVar("NP_EnableAuraCastEvents") - if auraCastEnabled ~= "1" then - CleveRoids.Print("|cFFFFFF00Warning:|r All-caster buff/debuff time tracking requires:") - CleveRoids.Print(" |cFF00FFFF/run SetCVar(\"NP_EnableAuraCastEvents\", \"1\")|r") - CleveRoids.Print(" Without this, |cFFFF9900[buff:X= 1 and n <= 8 then return "mark" .. n end + return nil +end + -- Priority types for multiscan -- String values = custom handling, number values = raid mark index CleveRoids.MULTISCAN_PRIORITIES = { @@ -7852,9 +7856,12 @@ CleveRoids.MULTISCAN_PRIORITIES = { lowestrawhp = "lowestrawhp", -- Raid mark order (skull → cross → square → moon → triangle → diamond → circle → star) markorder = "markorder", - -- Individual raid marks (direct unit reference via SuperWoW "mark#" tokens) + -- Individual raid marks by name (direct unit reference via SuperWoW "mark#" tokens) skull = 8, cross = 7, square = 6, moon = 5, triangle = 4, diamond = 3, circle = 2, star = 1, + -- Individual raid marks by number (mark1=star through mark8=skull) + mark1 = 1, mark2 = 2, mark3 = 3, mark4 = 4, + mark5 = 5, mark6 = 6, mark7 = 7, mark8 = 8, } -- Static conditionals that don't depend on target (checked before scanning) diff --git a/Core.lua b/Core.lua index c303348..a3292d4 100644 --- a/Core.lua +++ b/Core.lua @@ -887,6 +887,8 @@ function CleveRoids.TestForActiveAction(actions) if unit == "focus" and pfUI and pfUI.uf and pfUI.uf.focus and pfUI.uf.focus.label and pfUI.uf.focus.id then unit = pfUI.uf.focus.label .. pfUI.uf.focus.id end + local resolvedMark = CleveRoids.ResolveRaidMarkUnit(unit) + if resolvedMark then unit = resolvedMark end -- PERFORMANCE: Cache spell name construction using two-level cache (no string concat for lookup) local castName = actions.active.action @@ -2237,6 +2239,12 @@ function CleveRoids.TestAction(cmd, args) end end + -- Resolve named raid marks (skull/cross/etc.) and mark1-mark8 to native mark# unit tokens + if conditionals.target then + local resolvedMark = CleveRoids.ResolveRaidMarkUnit(conditionals.target) + if resolvedMark then conditionals.target = resolvedMark end + end + CleveRoids.FixEmptyTarget(conditionals) -- PERFORMANCE: Use next() directly instead of pairs() to avoid iterator allocation @@ -2360,6 +2368,12 @@ function CleveRoids.DoWithConditionals(msg, hook, fixEmptyTargetFunc, targetBefo end end + -- Resolve named raid marks (skull/cross/etc.) and mark1-mark8 to native mark# unit tokens + if conditionals.target then + local resolvedMark = CleveRoids.ResolveRaidMarkUnit(conditionals.target) + if resolvedMark then conditionals.target = resolvedMark end + end + -- Handle [multiscan:priority] - scan enemies and find best target -- Must be processed BEFORE the Keywords loop since it sets conditionals.target -- Pass origTarget so @unit syntax makes that unit exempt from combat check @@ -2546,6 +2560,51 @@ function CleveRoids.DoCast(msg) return false end +-- Resolve unit for /pfcast: mouseover → GetMouseFocus label+id → mouseoverUnit → target → player +-- Mirrors pfUI's own unit resolution order so /pfcast conditionals evaluate against the same unit +-- that pfUI would cast on. +local function ResolvePfCastUnit() + if UnitExists("mouseover") then + return "mouseover" + end + local frame = GetMouseFocus and GetMouseFocus() + if frame and frame.label and frame.id then + return frame.label .. frame.id + elseif CleveRoids.mouseoverUnit and UnitExists(CleveRoids.mouseoverUnit) then + return CleveRoids.mouseoverUnit + elseif UnitExists("target") then + return "target" + elseif GetCVar and GetCVar("autoSelfCast") == "1" then + return "player" + end + return nil +end + +-- /pfcast with CleveRoids conditionals: evaluate conditionals then cast via pfUI's mouseover chain. +-- Called from the SlashCmdList.PFCAST hook (set up by Extensions/Mouseover/pfUI.lua after pfUI loads). +function CleveRoids.DoPfCast(msg) + local parts = CleveRoids.splitStringIgnoringQuotes(msg) + for i = 1, table.getn(parts) do + local v = parts[i] + -- If conditionals are present but no explicit @unit, inject the pfUI-resolved unit so + -- all conditionals ([help], [nodebuff:X], etc.) evaluate against the same unit pfUI + -- would cast on, and the final CastSpellByName gets the correct unit token. + if string.find(v, "%[") and not string.find(v, "@") then + local unit = ResolvePfCastUnit() + if unit then + v = string.gsub(v, "%[", "[@" .. unit .. ",", 1) + end + end + if CleveRoids.DoWithConditionals(v, CleveRoids.Hooks.PFCAST_SlashCmd, CleveRoids.FixEmptyTarget, not CleveRoids.hasSuperwow, CastSpellByName) then + if CleveRoids.stopOnCastFlag then + CleveRoids.stopMacroFlag = true + end + return true + end + end + return false +end + -- PERFORMANCE: Module-level pet cast action to avoid closure allocation per call local function _petCastAction(spellName) local petSpell = CleveRoids.GetPetSpell(spellName) @@ -2643,6 +2702,10 @@ function CleveRoids.DoTarget(msg) if UnitExists(fTok) then unitTok = fTok else unitTok = nil end end + -- Resolve named raid marks (skull/cross/etc.) and mark1-mark8 to native mark# unit tokens + local resolvedMark = CleveRoids.ResolveRaidMarkUnit(unitTok) + if resolvedMark then unitTok = resolvedMark end + if unitTok and UnitExists(unitTok) and IsGuidValid(unitTok, conditionals) then TargetUnit(unitTok) return true diff --git a/Extensions/Mouseover/pfUI.lua b/Extensions/Mouseover/pfUI.lua index 325312a..e5bb7d7 100644 --- a/Extensions/Mouseover/pfUI.lua +++ b/Extensions/Mouseover/pfUI.lua @@ -290,6 +290,50 @@ function Extension.RegisterPartyTargetScripts() --- END OF FIX --- end +-- RAID MARKERS (pfUI raidmarkers module) +-- Rows are plain Buttons with label="mark" and id=1-8. They have no OnEnter/OnLeave +-- by default, so [mouseover] macros are blind to them. We hook each row so hovering +-- registers "mark1".."mark8" through the normal priority system. +function Extension.RegisterRaidMarkScripts() + if not pfUI or not pfUI.raidmarkers or not pfUI.raidmarkers.rows then return end + + local i + for i = 1, 8 do + local row = pfUI.raidmarkers.rows[i] + if row then + local onEnterFunc = row:GetScript("OnEnter") + local onLeaveFunc = row:GetScript("OnLeave") + + row:SetScript("OnEnter", function() + PfSet(this) -- resolves to "mark1".."mark8" via label..id + if onEnterFunc then onEnterFunc(this) end + end) + + row:SetScript("OnLeave", function() + PfClear(this) + if onLeaveFunc then onLeaveFunc(this) end + end) + end + end +end + +-- /pfcast hook: deferred until PLAYER_ENTERING_WORLD because pfUI defines SlashCmdList.PFCAST +-- inside pfUI:RegisterModule() which runs during pfUI's PLAYER_LOGIN init, after our addon loads. +-- Guard ensures we only hook once across multiple zone transitions. +function Extension.HookPfCast() + if not SlashCmdList.PFCAST then return end + if CleveRoids.Hooks.PFCAST_SlashCmd then return end -- already hooked + CleveRoids.Hooks.PFCAST_SlashCmd = SlashCmdList.PFCAST + SlashCmdList.PFCAST = function(msg) + if CleveRoids.stopMacroFlag or CleveRoids.skipMacroFlag then return end + if msg and string.find(msg, "[%[%?!~{]") then + CleveRoids.DoPfCast(msg) + else + CleveRoids.Hooks.PFCAST_SlashCmd(msg) + end + end +end + function Extension.PLAYER_ENTERING_WORLD() if not pfUI or not pfUI.uf then return end Extension.RegisterPlayerScripts() @@ -300,4 +344,6 @@ function Extension.PLAYER_ENTERING_WORLD() Extension.RegisterRaidScripts() Extension.RegisterFocusScripts() Extension.RegisterFocusTargetScripts() + Extension.RegisterRaidMarkScripts() + Extension.HookPfCast() end diff --git a/NampowerAPI.lua b/NampowerAPI.lua index 6c2a7b1..cb655ff 100644 --- a/NampowerAPI.lua +++ b/NampowerAPI.lua @@ -245,9 +245,12 @@ API.VERSION_REQUIREMENTS = { -- v2.24+ - Auto-attack events ["AutoAttackEvents"] = { 2, 24, 0 }, -- AUTO_ATTACK_SELF/OTHER events - -- v2.25+ - Spell start/go events (improved granularity over UNIT_CASTEVENT) + -- v2.25+ - Spell start/go/failed/delayed/channel events ["SpellStartEvents"] = { 2, 25, 0 }, -- SPELL_START_SELF/OTHER events ["SpellGoEvents"] = { 2, 25, 0 }, -- SPELL_GO_SELF/OTHER events + ["SpellFailedEvents"] = { 2, 25, 0 }, -- SPELL_FAILED_SELF/OTHER events + ["SpellDelayedEvents"] = { 2, 25, 0 }, -- SPELL_DELAYED_SELF/OTHER events (OTHER does not fire; server only sends to affected player) + ["SpellChannelEvents"] = { 2, 25, 0 }, -- SPELL_CHANNEL_START / SPELL_CHANNEL_UPDATE events (self-only) -- v2.26+ - Spell heal/energize events ["SpellHealEvents"] = { 2, 26, 0 }, -- SPELL_HEAL_BY_SELF/OTHER/ON_SELF events @@ -405,9 +408,12 @@ local function InitializeFeatures() -- v2.24+ Auto-attack events f.hasAutoAttackEvents = API.HasFeature("AutoAttackEvents") - -- v2.25+ Spell start/go events + -- v2.25+ Spell start/go/failed/delayed/channel events f.hasSpellStartEvents = API.HasFeature("SpellStartEvents") f.hasSpellGoEvents = API.HasFeature("SpellGoEvents") + f.hasSpellFailedEvents = API.HasFeature("SpellFailedEvents") + f.hasSpellDelayedEvents = API.HasFeature("SpellDelayedEvents") + f.hasSpellChannelEvents = API.HasFeature("SpellChannelEvents") -- v2.26+ Spell heal/energize events f.hasSpellHealEvents = API.HasFeature("SpellHealEvents") @@ -2593,6 +2599,32 @@ function API.Initialize() -- Detect enhanced spell functions DetectEnhancedSpellFunctions() + -- Auto-enable required Nampower event CVars. + -- Nampower reads CVars at DLL load time, so changes take effect on next reload. + -- We set them now so every subsequent session works automatically. + if SetCVar and GetCVar then + local f = API.features + + -- NP_EnableAuraCastEvents (v2.20+) - required for [debuffcapped], [mybuffcapped], overflow buff tracking + if f.hasAuraCastEvents and GetCVar("NP_EnableAuraCastEvents") ~= "1" then + SetCVar("NP_EnableAuraCastEvents", "1") + end + + -- NP_EnableAutoAttackEvents (v2.24+) - required for [lastswing], [incominghit] + if f.hasAutoAttackEvents and GetCVar("NP_EnableAutoAttackEvents") ~= "1" then + SetCVar("NP_EnableAutoAttackEvents", "1") + end + + -- NP_EnableSpellStartEvents (v2.25+) - required for SPELL_START_SELF/OTHER cast tracking + if f.hasSpellStartEvents and GetCVar("NP_EnableSpellStartEvents") ~= "1" then + SetCVar("NP_EnableSpellStartEvents", "1") + end + + -- NP_EnableSpellGoEvents (v2.25+) - required for SPELL_GO_SELF/OTHER cast tracking + if f.hasSpellGoEvents and GetCVar("NP_EnableSpellGoEvents") ~= "1" then + SetCVar("NP_EnableSpellGoEvents", "1") + end + end end -- Clear caches (call on respec/spell change)