Drop the action-bar overrides now that ClassicAPI draws macro buttons

Removes the nine Lua replacements the macro display integration makes
redundant: GameTooltip.SetAction, GetActionCooldown, GetActionCount,
IsConsumableAction, IsUsableAction, IsActionInRange, ActionHasRange,
IsCurrentAction and GetActionTexture. The client now derives all of it from the
value published via C_Macro.SetMacroDisplay, including the drag cursor and macro
window grid that Lua could never reach, and answers range for the macro slot
itself instead of via a borrowed proxy slot. Also drops GetSlotMacroTexture,
which only GetActionTexture used.

Behavior change: a macro with a hand-picked icon now keeps that icon. The
deleted GetActionTexture substituted the active action's icon unconditionally;
the client only substitutes when the macro's own icon is the question mark.
That is the engine's rule, matching 3.3.5's macro icon getter.

Two things the integration guide expected to fall out did not, and are kept:

- GetProxyActionSlot still has six callers unrelated to macro display
  (/startattack, [stopattack], and [channeled] for Attack/Auto Shot/Shoot).
  Only three of its callers lived in the deleted range.
- Hooks.IsCurrentAction and Hooks.OriginalIsUsableAction are used outside the
  overrides they were saved for, so the aliases stay. They now simply name the
  unmodified globals. The auto-attack drift check specifically needs the real
  current-action state, which the old override could not give it.

PickupAction is untouched: it invalidates our per-slot caches on drag, which is
not display and is still needed.
This commit is contained in:
Brues
2026-09-10 14:40:16 -05:00
parent c5ddc6c313
commit 4dd5326172
+8 -566
View File
@@ -4286,104 +4286,8 @@ function CleveRoids.OnUpdate(self)
end
end
-- Initialize the nested table for the GameTooltip hooks if it doesn't exist
if not CleveRoids.Hooks.GameTooltip then CleveRoids.Hooks.GameTooltip = {} end
-- Save the original GameTooltip.SetAction function before we override it
CleveRoids.Hooks.GameTooltip.SetAction = GameTooltip.SetAction
-- Now, define our custom version of the function
function GameTooltip.SetAction(self, slot)
if not slot then return end
local actions = CleveRoids.GetAction(slot)
-- If this is our macro but has no active action, show just the macro name
if actions and not actions.active then
local macroName = GetActionText(slot)
if macroName then
GameTooltip:SetText(macroName)
GameTooltip:Show()
return
end
end
local action_to_display_info = nil
if actions then
-- Only show spell/item tooltip when there's an active action
if actions.active then
action_to_display_info = actions.active
end
end
if action_to_display_info and action_to_display_info.action then
local action_name = action_to_display_info.action
-- NEW: Check if action is a slot ID for tooltip
local slotId = tonumber(action_name)
if slotId and slotId >= 1 and slotId <= 19 then
-- Use the more specific SetInventoryItem function to prevent conflicts with other addons.
GameTooltip:SetInventoryItem("player", slotId)
GameTooltip:Show()
return
end
-- End new logic
local current_spell_data = CleveRoids.GetSpell(action_name)
if current_spell_data and current_spell_data.id then
GameTooltip:SetSpellByID(current_spell_data.id)
GameTooltip:Show()
return
end
local current_item_data = CleveRoids.GetItem(action_name)
if current_item_data then
-- Use specific functions based on where the item is located.
if current_item_data.inventoryID then
GameTooltip:SetInventoryItem("player", current_item_data.inventoryID)
elseif current_item_data.bagID and current_item_data.slot then
GameTooltip:SetBagItem(current_item_data.bagID, current_item_data.slot)
else
-- Fallback to the original method if location is unknown.
GameTooltip:SetHyperlink(current_item_data.link)
end
GameTooltip:Show()
return
end
if action_to_display_info.macro and type(action_to_display_info.macro) == "table" then
local nested_action_info = action_to_display_info.macro
local nested_action_name = nested_action_info.action
current_spell_data = CleveRoids.GetSpell(nested_action_name)
if current_spell_data and current_spell_data.id then
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()
return
end
current_item_data = CleveRoids.GetItem(nested_action_name)
if current_item_data then
if current_item_data.inventoryID then
GameTooltip:SetInventoryItem("player", current_item_data.inventoryID)
elseif current_item_data.bagID and current_item_data.slot then
GameTooltip:SetBagItem(current_item_data.bagID, current_item_data.slot)
else
GameTooltip:SetHyperlink(current_item_data.link)
end
GameTooltip:Show()
return
end
end
end
-- If none of our custom logic handled it, call the original function we saved earlier.
CleveRoids.Hooks.GameTooltip.SetAction(self, slot)
end
-- Not a display override: this invalidates our per-slot caches when an action is
-- dragged off a slot, so it stays regardless of who draws the button.
CleveRoids.Hooks.PickupAction = PickupAction
function PickupAction(slot)
if not slot then return end
@@ -4393,224 +4297,14 @@ function PickupAction(slot)
return CleveRoids.Hooks.PickupAction(slot)
end
CleveRoids.Hooks.ActionHasRange = ActionHasRange
function ActionHasRange(slot)
if not slot then return nil end
local actions = CleveRoids.GetAction(slot)
-- Only override for our macros with #showtooltip
if actions and actions.tooltip then
-- If we have an active action with valid range data, use it
if actions.active then
if actions.active.inRange ~= -1 then
return 1 -- Has range check with valid data
else
-- For channeled spells (inRange == -1), try proxy slot lookup
local spellName = actions.active.spell and actions.active.spell.name
local proxySlot = spellName and CleveRoids.GetProxyActionSlot(spellName)
if proxySlot then
return CleveRoids.Hooks.ActionHasRange(proxySlot)
end
end
end
-- FIX: Even without actions.active, if the macro has potential spell actions,
-- return 1 to ensure pfUI calls IsActionInRange (which will do proper checks)
-- This fixes Super macros where actions.active might not be populated yet
if actions.tooltip.spell or actions.tooltip.type == "spell" then
return 1 -- Tooltip is a spell - has range
end
-- Check if any action in the list is a spell
if actions.list then
for i = 1, table.getn(actions.list) do
local action = actions.list[i]
if action and (action.spell or action.type == "spell") then
return 1 -- Has at least one spell action
end
end
end
end
-- Not a macro we're tracking - pass through to original
return CleveRoids.Hooks.ActionHasRange(slot)
end
CleveRoids.Hooks.IsActionInRange = IsActionInRange
function IsActionInRange(slot, unit)
if not slot then return nil end
local actions = CleveRoids.GetAction(slot)
-- Only override for our macros with #showtooltip
if actions and actions.tooltip then
-- If we have an active spell action, use its range data
if actions.active and actions.active.type == "spell" then
if actions.active.inRange ~= -1 then
return actions.active.inRange
else
-- For channeled spells (inRange == -1), try proxy slot lookup
local spellName = actions.active.spell and actions.active.spell.name
local proxySlot = spellName and CleveRoids.GetProxyActionSlot(spellName)
if proxySlot then
return CleveRoids.Hooks.IsActionInRange(proxySlot, unit)
end
end
end
-- FIX: If no active action but macro has tooltip spell, check its range directly
-- This ensures range coloring works even when actions.active hasn't been populated
if not actions.active and actions.tooltip.spell then
local spell = actions.tooltip.spell
local spellName = spell.name
if spellName and IsSpellInRange then
local targetUnit = unit or "target"
if UnitExists(targetUnit) then
-- FIX: Wrap in pcall - spell might not be in spellbook (items, other class spells, etc.)
local ok, result = pcall(IsSpellInRange, spellName, targetUnit)
if ok then
if result == 0 then
return 0 -- Out of range
elseif result == 1 then
return 1 -- In range
end
end
end
end
-- Try proxy slot as fallback
local proxySlot = spellName and CleveRoids.GetProxyActionSlot(spellName)
if proxySlot then
return CleveRoids.Hooks.IsActionInRange(proxySlot, unit)
end
end
end
-- Not a macro we're tracking - pass through to original
return CleveRoids.Hooks.IsActionInRange(slot, unit)
end
-- These two aliases outlived the overrides they were saved for: ClassicAPI now
-- draws the buttons, but callers still need the unmodified globals, which is all
-- these names are now. IsReactiveUsable (Conditionals.lua) reads the raw usable
-- state of a proxy slot; DeferStopAttack and the auto-attack drift check read the
-- true current-action state, which the old override could not report because it
-- only echoed our cached flag.
CleveRoids.Hooks.OriginalIsUsableAction = IsUsableAction
CleveRoids.Hooks.IsUsableAction = IsUsableAction
function IsUsableAction(slot, unit)
if not slot then return nil, nil end
local actions = CleveRoids.GetAction(slot)
-- If this is one of our macros AND it uses #showtooltip
if actions and actions.tooltip then
-- IMPORTANT: Only override usability when #showtooltip is present
-- Macros without #showtooltip should use default game behavior
if actions.active then
-- We have an active action - return its usable state
-- FIX: Convert oom boolean to number (1/nil) for Blizzard's button code
local oomValue = actions.active.oom and 1 or nil
return actions.active.usable, oomValue
else
-- FIX: If no active action but tooltip has a spell, check its usability directly
-- This ensures usability coloring works even when actions.active hasn't been populated
if actions.tooltip.spell then
local spell = actions.tooltip.spell
local spellName = spell.name
if spellName and IsSpellUsable then
-- FIX: Wrap in pcall - spell might not be in spellbook (items, other class spells, etc.)
local ok, usable, notEnoughMana = pcall(IsSpellUsable, spellName)
if ok then
if usable == 1 then
return 1, nil -- Usable
elseif notEnoughMana == 1 then
return nil, 1 -- Out of mana
else
return nil, nil -- Not usable (wrong stance, etc.)
end
end
end
-- Fallback: check if spell has a cost and compare to current mana
if spell.cost and spell.cost > 0 then
local currentMana = UnitMana("player")
if currentMana < spell.cost then
return nil, 1 -- Out of mana
end
end
-- Default to usable if we can't determine otherwise
return 1, nil
elseif actions.tooltip.item then
-- FIX: Handle item tooltips - items are always usable unless on cooldown
-- The cooldown is handled separately by GetActionCooldown hook
return 1, nil
end
-- No tooltip spell or item - this macro's conditionals all failed
-- Return nil to make the icon dark
return nil, nil
end
else
-- Not our macro OR no #showtooltip - use game's default behavior
return CleveRoids.Hooks.IsUsableAction(slot, unit)
end
end
CleveRoids.Hooks.IsCurrentAction = IsCurrentAction
function IsCurrentAction(slot)
if not slot then return nil end
local actions = CleveRoids.GetAction(slot)
-- When no action is active (all conditionals failed), don't check tooltip's "current" status
if actions and not actions.active and not actions.explicitTooltip and actions.list and table.getn(actions.list) > 0 then
return CleveRoids.Hooks.IsCurrentAction(slot)
end
-- Use the same priority as GetActionTexture: active first, then tooltip
local actionToCheck = (actions and actions.active) or (actions and actions.tooltip)
if not actionToCheck then
return CleveRoids.Hooks.IsCurrentAction(slot)
else
local name
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
name = actionToCheck.spell.name..(rank and ("("..rank..")"))
-- Check if this spell is currently queued or being cast via Nampower
-- Get spell ID for comparison
local spellId = actionToCheck.spell.id
if not spellId and GetSpellIdForName then
spellId = GetSpellIdForName(name)
end
if spellId then
-- Prefer GetCastInfo (Nampower 2.18+) for cleaner API
if GetCastInfo then
local ok, info = pcall(GetCastInfo)
if ok and info and info.spellId == spellId then
-- Spell is actively being cast/channeled
return true
end
end
-- Also check GetCurrentCastingInfo for queued spell detection
if GetCurrentCastingInfo then
local castId, visId, autoId, casting, channeling = GetCurrentCastingInfo()
-- 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
return CleveRoids.Hooks.IsCurrentAction(CleveRoids.GetProxyActionSlot(name) or slot)
end
end
local function GetSlotMacroTexture(slot)
local kind, macroId = CleveRoids.ClassicAPI.GetActionInfo(slot)
if kind == "macro" and macroId then
local _, texture = GetMacroInfo(macroId)
return texture
end
return nil
end
local function IsAutoAttackSpell(spell)
if not spell then return false end
@@ -4624,258 +4318,6 @@ local function IsAutoAttackSpell(spell)
end
CleveRoids.IsAutoAttackSpell = IsAutoAttackSpell
CleveRoids.Hooks.GetActionTexture = GetActionTexture
function GetActionTexture(slot)
if not slot then return nil end
local actions = CleveRoids.GetAction(slot)
-- Check if this is one of our macros
if actions and (actions.active or actions.tooltip) then
-- This block handles the case where all conditionals fail and no explicit
-- #showtooltip was set. It defaults to the macro's chosen icon.
if not actions.active and not actions.explicitTooltip and actions.list and table.getn(actions.list) > 0 then
-- Get the macro's own icon as fallback
local macroTexture = GetSlotMacroTexture(slot)
-- When no conditionals pass, use macro icon (not first action's icon)
-- The actions.tooltip is just the first action which didn't pass conditionals
if macroTexture then
return macroTexture
end
-- Should never reach here, but return unknown as last resort
return CleveRoids.unknownTexture
end
-- Prioritize active action, fall back to tooltip
local a = actions.active or actions.tooltip
-- Handle numeric slot actions (e.g., /use 13)
local slotId = tonumber(a.action)
if slotId and slotId >= 1 and slotId <= 19 then
local currentTexture = GetInventoryItemTexture("player", slotId)
if currentTexture then
return currentTexture
end
-- Slot is empty, fall back to macro icon
local macroTexture = GetSlotMacroTexture(slot)
if macroTexture then
return macroTexture
end
return CleveRoids.unknownTexture
end
-- *** THIS IS THE FIX ***
-- If an action is active, return its texture directly.
-- If no action is active, return the tooltip's texture.
-- If neither has a texture, fall back to the macro's icon.
local texture = (actions.active and actions.active.texture) or (actions.tooltip and actions.tooltip.texture)
-- Check if this is a shapeshift form spell and use active texture if toggled on
if a and a.spell and a.action then
-- Strip rank info and underscores from spell name for comparison
local spellName = string.gsub(a.action, "%s*%(.-%)%s*$", "")
spellName = string.gsub(spellName, "_", " ")
-- Check all shapeshift forms to see if this spell matches and is active
for i = 1, GetNumShapeshiftForms() do
local icon, name, isActive, isCastable = GetShapeshiftFormInfo(i)
if name and string.lower(name) == string.lower(spellName) and isActive and icon then
texture = icon
break
end
end
end
-- Check if this is a toggled buff ability (Prowl, Shadowmeld) and swap icon based on buff state
-- Note: Stealth is handled above by shapeshift form logic
if a and a.spell and a.action then
local spellName = string.gsub(a.action, "%s*%(.-%)%s*$", "")
spellName = string.gsub(spellName, "_", " ")
-- Check if this is one of our toggled buff abilities (not shapeshift forms)
local toggledAbilities = {
[CleveRoids.Localized.Spells["Prowl"]] = true,
[CleveRoids.Localized.Spells["Shadowmeld"]] = true,
}
if toggledAbilities[spellName] then
-- Check if the buff is active
if CleveRoids.ValidatePlayerBuff(spellName) then
-- Buff is active, use the active texture from auraTextures
local activeTexture = CleveRoids.auraTextures[spellName]
if activeTexture then
texture = activeTexture
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
return texture
end
-- Final fallback: get the macro's icon
local macroTexture = GetSlotMacroTexture(slot)
if macroTexture then
return macroTexture
end
-- Should never reach here
return CleveRoids.unknownTexture
end
-- Not one of our macros, use the original function
return CleveRoids.Hooks.GetActionTexture(slot)
end
-- TODO: Look into https://github.com/Stanzilla/WoWUIBugs/issues/47 if needed
CleveRoids.Hooks.GetActionCooldown = GetActionCooldown
function GetActionCooldown(slot)
-- Guard against nil/invalid slot
if not slot then return 0, 0, 0 end
local actions = CleveRoids.GetAction(slot)
-- Check for actions.active OR actions.tooltip
if actions and (actions.active or actions.tooltip) then
-- When no action is active (all conditionals failed) but tooltip exists from #showtooltip,
-- don't show the tooltip's cooldown - fall back to the original function (no cooldown)
-- This matches the icon behavior in GetActionTexture (lines 3958-3977)
if not actions.active and not actions.explicitTooltip and actions.list and table.getn(actions.list) > 0 then
return CleveRoids.Hooks.GetActionCooldown(slot)
end
-- Prioritize the active action, but fall back to the tooltip action
local a = actions.active or actions.tooltip
local slotId = tonumber(a.action)
if slotId and slotId >= 1 and slotId <= 19 then
return GetInventoryItemCooldown("player", slotId)
end
if a.spell and a.spell.spellSlot then
return GetSpellCooldown(a.spell.spellSlot, a.spell.bookType)
elseif a.item then
if a.item.bagID and a.item.slot then
return GetContainerItemCooldown(a.item.bagID, a.item.slot)
elseif a.item.inventoryID then
return GetInventoryItemCooldown("player", a.item.inventoryID)
end
end
-- DEBUG: Log when we fall through without finding spell/item data (once per slot)
if CleveRoids.cooldownDebug and not CleveRoids.cooldownDebugLogged[slot] then
CleveRoids.cooldownDebugLogged[slot] = true
DEFAULT_CHAT_FRAME:AddMessage(string.format(
"|cffff0000[CD Issue]|r Slot %d: No cooldown data! action='%s' type=%s spell=%s item=%s",
slot,
tostring(a.action),
tostring(a.type),
tostring(a.spell ~= nil),
tostring(a.item ~= nil)
))
DEFAULT_CHAT_FRAME:AddMessage("|cffff8800[CD Issue]|r This slot will show incorrect cooldown. Report macro text to developer.")
end
-- Fallback to original function (preserves SuperWoW's #showtooltip handling)
return CleveRoids.Hooks.GetActionCooldown(slot)
else
return CleveRoids.Hooks.GetActionCooldown(slot)
end
end
CleveRoids.Hooks.GetActionCount = GetActionCount
function GetActionCount(slot)
-- Guard against nil/invalid slot
if not slot then return 0 end
local action = CleveRoids.GetAction(slot)
local count
-- When no action is active (all conditionals failed), don't show tooltip's count
if action and not action.active and not action.explicitTooltip and action.list and table.getn(action.list) > 0 then
return CleveRoids.Hooks.GetActionCount(slot)
end
-- Use the same priority as GetActionTexture: active first, then tooltip
local actionToCheck = (action and action.active) or (action and action.tooltip)
if actionToCheck then
local slotId = tonumber(actionToCheck.action)
if slotId and slotId >= 1 and slotId <= 19 then
return GetInventoryItemCount("player", slotId)
end
if actionToCheck.item then
count = CleveRoids.GetLiveItemCount(actionToCheck.item.name or actionToCheck.action)
elseif actionToCheck.spell then
local reagentId = actionToCheck.spell.reagentId
if not reagentId then
local ss, bt = actionToCheck.spell.spellSlot, actionToCheck.spell.bookType
if ss and bt then
local _, _, rid = CleveRoids.GetSpellCost(ss, bt, actionToCheck.spell.id)
actionToCheck.spell.reagentId = rid -- cache itemID so we don't re-derive every frame
reagentId = rid
end
end
if reagentId then
count = CleveRoids.GetReagentCount(reagentId) -- id-based bag scan
end
end
end
return count or CleveRoids.Hooks.GetActionCount(slot)
end
CleveRoids.Hooks.IsConsumableAction = IsConsumableAction
function IsConsumableAction(slot)
-- Guard against nil/invalid slot
if not slot then return nil end
local action = CleveRoids.GetAction(slot)
-- When no action is active (all conditionals failed), don't show tooltip's consumable status
if action and not action.active and not action.explicitTooltip and action.list and table.getn(action.list) > 0 then
return CleveRoids.Hooks.IsConsumableAction(slot)
end
-- Use the same priority as GetActionTexture: active first, then tooltip
local actionToCheck = (action and action.active) or (action and action.tooltip)
if actionToCheck then
local slotId = tonumber(actionToCheck.action)
if slotId and slotId >= 1 and slotId <= 19 then
local _, count = GetInventoryItemCount("player", slotId)
if count and count > 0 then return 1 end
end
if actionToCheck.item and
(CleveRoids.countedItemTypes[actionToCheck.item.type]
or CleveRoids.countedItemTypes[actionToCheck.item.name])
then
return 1
end
if actionToCheck.spell and actionToCheck.spell.reagentId then
return 1
end
end
return CleveRoids.Hooks.IsConsumableAction(slot)
end
-- ============================================================================
-- RunMacro Hook - Use our own macro execution system
-- ============================================================================