4 Commits
Author SHA1 Message Date
Brues 653f8db3d7 Reconcile /startattack against real action-bar state, not cached flag
The autoAttack flag could drift stale-true (optimistic set after
AttackTarget, or a target dying without PLAYER_LEAVE_COMBAT), making
/startattack skip the attack until the target was dropped and reselected.
The old fallback called the overridden IsCurrentAction, which just echoes
the cached flag for the attack slot, so it never detected drift. Use the
original Hooks.IsCurrentAction as ground truth and sync the flag to it.
2026-07-04 19:38:37 -05:00
Brues 86fb0254e6 Show autoattack icon and glow 2026-06-30 12:34:34 -05:00
Brues fc640abb07 Render known-spell action tooltips via spellbook slot, not spellID
GameTooltip.SetAction used GameTooltip:SetSpellByID for spell actions, which
renders the static DBC tooltip. For spells we resolved from the player's own
spellbook, use GameTooltip:SetSpell(spellSlot, bookType) instead so the
tooltip shows live player-accurate data (mana cost, cooldown, range coloring,
reagent counts). spellSlot/bookType/id all come from the same spellbook index
entry, so it renders the identical spell and rank. SetSpellByID remains as a
defensive fallback for entries without a slot. Applied to both the direct and
nested-macro tooltip paths.
2026-06-23 12:41:17 -05:00
Brues 3384765faa dont need pcall around registering events 2026-06-22 13:04:05 -05:00
+44 -24
View File
@@ -3100,15 +3100,17 @@ end
-- PERFORMANCE: Module-level action to avoid closure allocation per call -- PERFORMANCE: Module-level action to avoid closure allocation per call
local function _startAttackAction() local function _startAttackAction()
if not UnitExists("target") or CleveRoids.IsUnitDead("target") then TargetNearestEnemy() end if not UnitExists("target") or CleveRoids.IsUnitDead("target") then TargetNearestEnemy() end
-- Check both event-based flag AND action bar state for reliable detection -- Ground truth is the real action-bar state, NOT the cached autoAttack flag.
-- The flag can drift stale-true (e.g. set optimistically after AttackTarget below,
-- or a target dying without PLAYER_LEAVE_COMBAT firing), which would make us wrongly
-- believe we're already swinging and skip the attack. Use the ORIGINAL API here:
-- the overridden global IsCurrentAction just echoes the cached flag for the attack
-- slot, so it can't detect drift. Fall back to the flag only if the slot is unknown.
local isAttacking = CleveRoids.CurrentSpell.autoAttack local isAttacking = CleveRoids.CurrentSpell.autoAttack
if not isAttacking then local slot = CleveRoids.GetProxyActionSlot(CleveRoids.Localized.Attack)
-- Fallback: check action bar state via IsCurrentAction if slot then
local slot = CleveRoids.GetProxyActionSlot(CleveRoids.Localized.Attack) isAttacking = CleveRoids.Hooks.IsCurrentAction(slot) and true or false
if slot and IsCurrentAction(slot) then CleveRoids.CurrentSpell.autoAttack = isAttacking
CleveRoids.CurrentSpell.autoAttack = true
isAttacking = true
end
end end
if not isAttacking and not CleveRoids.CurrentSpell.autoAttackLock and UnitExists("target") and UnitCanAttack("player", "target") then if not isAttacking and not CleveRoids.CurrentSpell.autoAttackLock and UnitExists("target") and UnitCanAttack("player", "target") then
CleveRoids.CurrentSpell.autoAttackLock = true CleveRoids.CurrentSpell.autoAttackLock = true
@@ -4425,9 +4427,11 @@ function GameTooltip.SetAction(self, slot)
local current_spell_data = CleveRoids.GetSpell(action_name) local current_spell_data = CleveRoids.GetSpell(action_name)
if current_spell_data and current_spell_data.id then if current_spell_data and current_spell_data.id then
-- ClassicAPI: render by spellID (rank included) instead of routing if current_spell_data.spellSlot and current_spell_data.bookType then
-- through the spellbook slot via SetSpell(spellSlot, bookType). GameTooltip:SetSpell(current_spell_data.spellSlot, current_spell_data.bookType)
GameTooltip:SetSpellByID(current_spell_data.id) else
GameTooltip:SetSpellByID(current_spell_data.id)
end
GameTooltip:Show() GameTooltip:Show()
return return
end end
@@ -4453,7 +4457,11 @@ function GameTooltip.SetAction(self, slot)
current_spell_data = CleveRoids.GetSpell(nested_action_name) current_spell_data = CleveRoids.GetSpell(nested_action_name)
if current_spell_data and current_spell_data.id then if current_spell_data and current_spell_data.id then
GameTooltip:SetSpellByID(current_spell_data.id) if current_spell_data.spellSlot and current_spell_data.bookType then
GameTooltip:SetSpell(current_spell_data.spellSlot, current_spell_data.bookType)
else
GameTooltip:SetSpellByID(current_spell_data.id)
end
GameTooltip:Show() GameTooltip:Show()
return return
end end
@@ -4650,6 +4658,10 @@ function IsCurrentAction(slot)
else else
local name local name
if actionToCheck.spell then if actionToCheck.spell then
if CleveRoids.IsAutoAttackSpell(actionToCheck.spell) then
return CleveRoids.CurrentSpell.autoAttack and 1 or nil
end
local rank = actionToCheck.spell.rank or actionToCheck.spell.highest.rank local rank = actionToCheck.spell.rank or actionToCheck.spell.highest.rank
name = actionToCheck.spell.name..(rank and ("("..rank..")")) name = actionToCheck.spell.name..(rank and ("("..rank..")"))
@@ -4692,9 +4704,6 @@ function IsCurrentAction(slot)
end end
end end
-- Macro icon for an action slot, via ClassicAPI's GetActionInfo (macro slot
-- directly, no GetActionText -> GetMacroIndexByName name round-trip).
-- Returns the macro texture, or nil if the slot isn't a macro / has no icon.
local function GetSlotMacroTexture(slot) local function GetSlotMacroTexture(slot)
local kind, macroId = CleveRoids.ClassicAPI.GetActionInfo(slot) local kind, macroId = CleveRoids.ClassicAPI.GetActionInfo(slot)
if kind == "macro" and macroId then if kind == "macro" and macroId then
@@ -4704,6 +4713,18 @@ local function GetSlotMacroTexture(slot)
return nil return nil
end end
local function IsAutoAttackSpell(spell)
if not spell then return false end
if C_Spell and C_Spell.IsAutoAttackSpell and spell.id then
return C_Spell.IsAutoAttackSpell(spell.id)
end
if C_SpellBook and C_SpellBook.IsAutoAttackSpellBookItem and spell.spellSlot then
return C_SpellBook.IsAutoAttackSpellBookItem(spell.spellSlot, spell.bookType)
end
return false
end
CleveRoids.IsAutoAttackSpell = IsAutoAttackSpell
CleveRoids.Hooks.GetActionTexture = GetActionTexture CleveRoids.Hooks.GetActionTexture = GetActionTexture
function GetActionTexture(slot) function GetActionTexture(slot)
if not slot then return nil end if not slot then return nil end
@@ -4792,6 +4813,13 @@ function GetActionTexture(slot)
end end
end end
if a and a.spell and CleveRoids.IsAutoAttackSpell(a.spell) then
local mainHandTexture = GetInventoryItemTexture("player", 16)
if mainHandTexture then
texture = mainHandTexture
end
end
if texture then if texture then
return texture return texture
end end
@@ -5088,15 +5116,7 @@ CleveRoids.Frame:RegisterEvent("PLAYER_REGEN_DISABLED") -- Entered actual combat
CleveRoids.Frame:RegisterEvent("PLAYER_REGEN_ENABLED") -- Left actual combat (no threat) CleveRoids.Frame:RegisterEvent("PLAYER_REGEN_ENABLED") -- Left actual combat (no threat)
CleveRoids.Frame:RegisterEvent("UPDATE_SHAPESHIFT_FORM") CleveRoids.Frame:RegisterEvent("UPDATE_SHAPESHIFT_FORM")
CleveRoids.Frame:RegisterEvent("SPELL_UPDATE_COOLDOWN") CleveRoids.Frame:RegisterEvent("SPELL_UPDATE_COOLDOWN")
-- ClassicAPI fires PLAYER_STARTED_MOVING (edge-detected off the WASD/autorun CleveRoids.Frame:RegisterEvent("PLAYER_STARTED_MOVING")
-- key state). We DON'T trust PLAYER_STOPPED_MOVING -- it's key-release based and
-- misses real stops (geometry, click-to-move, roots, knockback) -- and instead
-- poll for the actual stop after STARTED (see the handler below). pcall-guarded:
-- older ClassicAPI builds may not have reserved the event name, and
-- RegisterEvent errors on an unknown event in 1.12.
pcall(function()
CleveRoids.Frame:RegisterEvent("PLAYER_STARTED_MOVING")
end)
-- Use GUID events when available (v2.39+), fall back to standard per-token events -- Use GUID events when available (v2.39+), fall back to standard per-token events
if CleveRoids.NampowerAPI.features.hasUnitGuidEvents then if CleveRoids.NampowerAPI.features.hasUnitGuidEvents then
CleveRoids.Frame:RegisterEvent("UNIT_AURA_GUID") CleveRoids.Frame:RegisterEvent("UNIT_AURA_GUID")