Migrate the link-scrape-then-discard sites to direct ClassicAPI reads:
- IndexEquippedItems / IndexEquipSlot: GetInventoryItemID for the id
(GetItemInfo still supplies the stored base link/texture)
- IndexItems bag+equip scans: GetContainerItemID/GetInventoryItemID +
C_Item.GetItemName (decorated) for the dedup fast-path; drop the now
dead GetContainerItemLink/GetInventoryItemLink locals
- GetItemFast cache validation: alloc-free id compare via
GetInventoryItemID/GetContainerItemID, decorated-name compare otherwise
- IsItemEquipped: GetInventoryItemID + C_Item.GetItemName
Left untouched: makeInventoryItem/makeBagItem and the GetItem/GetItemFast
scan loops, which build a real link that is stored on the item and later
fed to GameTooltip:SetHyperlink.
Note: the equipped-scan loops now start at slot 1 (GetInventoryItemID
requires slot>=1), so the ammo slot (0) is no longer walked by these
indexers -- ammo is not referenced by name anywhere in the addon.
Replace GetInventoryItemLink/GetContainerItemLink link-scraping with
direct ClassicAPI reads across the item conditionals:
- [equipped] cache build: GetInventoryItemID + C_Item.GetItemName
(decorated name replaces the old bracket-name / GetItemInfo two-step)
- slot-number -> item name resolves ([cd], [usable]/[nousable]):
C_Item.GetItemName location form
- HasItem / GetItemCooldown substring fallbacks: match the decorated
name instead of the raw link string
- numeric-slot presence check: GetInventoryItemID
Suffix decoration is preserved via the location form, so partial/
suffixed [equipped:...] matches behave as before.
Replace GetInventoryItemLink/GetContainerItemLink link-scraping (built
solely to regex out item:ID or the bracketed name) with direct ClassicAPI
reads:
- id/presence: GetInventoryItemID, C_Container.GetContainerItemID
- suffix-sensitive names (equip-by-name on gear): C_Item.GetItemName
location form, which now carries random-suffix decoration
- suffix-free names (consumables/reagents/poisons) in hot bag scans:
id + C_Item.GetItemNameByID (base name, zero table allocation)
Also covers /use equipped-slot resolution and the WDB warm scans. Drops
the now-dead GetContainerItemLink/GetInventoryItemLink/string_find
upvalue aliases. No behavior change; equip-by-name keeps full suffixed
matching via the decorated location form.
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.
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.
Register PLAYER_STARTED_MOVING (ClassicAPI, edge-detected off the WASD/
autorun key state) and queue an action update so [moving]/[nomoving] macro
icons repaint when movement starts.
PLAYER_STOPPED_MOVING is deliberately NOT used -- it's key-release based and
misses real stops (running into geometry, click-to-move, roots, knockback).
Instead, STARTED kicks off a 0.1s C_Timer.NewTicker that watches
IsPlayerMoving() (the same speed>0/falling signal [moving] evaluates) and, on
the actual stop, refreshes once and cancels itself. No timer exists while
stopped, so there's no idle cost; guarded on isShuttingDown and event-driven
mode (realtime==0).
Macros with no chosen icon (e.g. "#showtooltip Shoot") display Blizzard's
default question mark in the macro UI. After each MacroFrame_Update, swap
that placeholder for the icon the action bar would show, resolved from the
macro's #showtooltip/first action via GetMacroByIndex.
- Only replaces icons that are currently the question mark, so user-chosen
icons are never touched.
- Covers both the list buttons (MacroButtonNIcon) and the selected-macro
detail icon.
- Purely cosmetic: never changes the saved icon; Blizzard repaints the
default on the next refresh if resolution fails or the macro changes.
- Installed in MacroErrorUI's existing hook path (gated on Blizzard_MacroUI
load and the SuperMacro guard).
Item-set membership and set info now read ItemSet.dbc directly through
ClassicAPI instead of the nampower/Reliquary glue, so set features no
longer require the Reliquary DLL to be installed.
- ClassicAPI.lua: add GetItemSetIDByID and GetItemSetInfo wrappers.
- Utility.lua: repoint ResolveSetItems, CountEquippedSetItemsBySetId,
GetEquippedItemSetInfo, and GetEquippedSetPieceCount at the ClassicAPI
accessors. Set-name matching now uses the DBC name (localized; identical
to the old enUS path on English clients).
- NampowerAPI.lua: remove the now-unused GetItemSet/GetItemSetId/
GetItemSetItems/GetItemSetBonuses, the dead GetSpellEffectRadius (no
callers, only radius source was Reliquary), and the orphaned RQ_SafeCall.
- Init.lua: drop hasReliquary detection and its startup feature line.
- Conditionals.lua: update the [set:] comment (no longer Reliquary-gated).
HasWeaponEquipped matched the localized GetItemInfo subtype string, which
required a hand-maintained translation of all 13 weapon/shield subtypes per
locale plus brittle "^Fist"/last-word string parsing.
Use the locale-independent class/subclass IDs from C_Item.GetItemInfoInstant
instead:
- Init.lua: WeaponTypeNames entries now carry numeric class + subClass set
(Axes/Swords/Maces span their 1H+2H subclasses; Shields are armor class 4).
- Conditionals.lua: HasWeaponEquipped resolves the slot's itemID via
ClassicAPI GetInventoryItemID, then compares classID/subClassID -- no link
parsing, no string munging.
- Localization.lua: drop the now-unused weapon-subtype strings from every
locale block (112 lines).
Remove localization data with no consumers anywhere in the addon:
- ItemTypes tables (Consumable/Reagent/Projectile/Trade Goods) - unused
- SpellRank patterns - unused (the live GetSpellRank is a BuffLib method)
- Spells keys Revenge, Overpower, Riposte, Surprise Attack, Lacerate,
Baited Shot, Counterattack, Arcane Surge - unused; only Shadowform,
Stealth, Prowl, Shadowmeld are referenced.
133 lines removed across all locale blocks; no behavior change.
Lean on ClassicAPI's backported readers instead of link-string parsing
and a hand-maintained mechanic table.
- ClassicAPI.lua: add wrappers GetCursorInfo/CursorHoldsItemID,
GetContainerItemID, GetInventoryItemID, and GetSpellMechanicByID.
- Core.lua: in the manual equip fallback, verify the cursor holds the
intended item (CursorHoldsItemID) before EquipCursorItem, aborting only
on a definitive mismatch so empty/unknown cursors behave as before.
- NampowerAPI.lua / Utility.lua: replace GetContainerItemLink /
GetInventoryItemLink + "item:(%d+)" parsing with direct C_Container/
inventory ID lookups at the sites that only need the itemID; route the
equipped-set scans through the GetEquippedItemID helper.
- Conditionals.lua / Utility.lua: replace the 785-entry CCSpellMechanics
fallback table with C_Spell.GetSpellMechanicByID in GetSpellMechanic and
GetSpellCCType (BuffLib / nampower paths unchanged); delete the table.
Unify both ! mechanisms (bare !spell gate-injection and bracketed
[cond] !spell dispatch skip) on ClassicAPI's CastSpellNoToggle, which
no-ops auto-repeat (Shoot/Auto Shot/Wand) and toggle auras
(forms/stances/aspects/seals) instead of toggling them off.
- Bare !spell now just sets conditionals.noSpam (no injected gate
conditional); removed spamConditions and GetSpammableConditional.
- Dispatch: melee Attack still uses AttackTarget (CastSpellNoToggle
doesn't cover the melee swing). For everything else under !, keep the
ValidatePlayerBuff anti-refresh skip (CastSpellNoToggle only covers
true toggle auras, not regular self-buffs like Mark of the Wild),
otherwise CastSpellNoToggle. This is more reliable for auto-repeat
than the old CheckChanneled path.
CheckChanneled is retained (still used by the [channeled]/[checkchanneled]
conditionals).
Per design preference, drop the @ and the ParseMsg special-casing:
[cursor] is now a normal modifier keyword (added to ignoreKeywords,
mirroring [mouseuse]) rather than a pseudo unit token. The cast/use
dispatch still routes through ClassicAPI's CastAtCursor / UseAtCursor
(checked via conditionals.cursor). Reverts the @cursor ParseMsg branch.
@cursor places a ground-target spell or on-use item at the cursor via
ClassicAPI's engine-level placement instead of the [mouseuse] reticle-
click simulation (so no auto-attack side effect).
- ParseMsg flags @cursor as conditionals.atCursor rather than setting a
bogus "cursor" unit target, so it doesn't affect help/harm/exists/range
checks or pass an invalid token to CastSpellByName.
- DoWithConditionals routes atCursor casts through C_Spell.CastAtCursor
(spellID resolved from the spell index / GetSpellIdForName) and item
uses through C_Item.UseAtCursor. Both fall back to a normal cast/use
for non-ground actions.
New syntax, so existing macros are unaffected; MacroErrorChecker already
accepts @cursor.
Add ClassicAPI.IsSwimming wrapper and route [swimming]/[noswimming] and
the swim/noswim aliases through it. Removes the Nampower v2.36
hasPlayerIsSwimming version gate and the "requires Nampower 2.36"
warning (ClassicAPI's IsSwimming is always available). Same semantics.
The AuraScanTooltip scanning frame was only used by CancelAura's legacy
tooltip path, which was removed when CancelAura moved to ClassicAPI's
C_Spell.CancelSpellByID. Nothing references it now.
- CancelAura: cancel matched buffs through ClassicAPI's
C_Spell.CancelSpellByID instead of nampower CancelPlayerAuraSpellId
and the legacy slot-based CancelPlayerBuff + tooltip-scan path. The
buff scan (SuperWoW GetPlayerBuffID / nampower raw GetPlayerAuraDuration
+ overflow tracking) and the boolean return are preserved, so the
~spell cancel-vs-cast toggle still works. CancelSpellByName isn't usable
here because it reports no match.
- Focus: GetFocusUnitId no longer warns when no focus is set. In a
fallback macro ([@focus] as one alternative) that's a normal state;
the clause now silently falls through like any unresolved @unit.
Dropped the unused warn parameter and updated both callers.
- ScheduleTimer now wraps C_Timer.After, removing the dedicated timer
frame + per-frame OnUpdate loop + timers queue.
- Aura-tracking cleanup -> C_Timer.NewTicker(5) (_auraCleanupTicker);
drop the UnitXP arm, the named global CleveRoids_AuraTrackingCleanupTimer,
and the inline "not hasUnitXP" fallback in OnAuraCastOther.
- Libdebuff cleanup -> C_Timer.NewTicker(30) (_cleanupTicker); drop the
UnitXP arm and CleveRoids_LibDebuffCleanupTimer.
- Shutdown cancels the tickers instead of UnitXP timer disarm.
Cleanup now always runs (was gated on hasUnitXP) and no longer depends
on UnitXP threaded timers or named global callbacks. Tickers self-guard
on isShuttingDown and are cancelled on shutdown.
Document the audit results in the backlog: the do-not-migrate traps
(C_UnitAuras expirationTime player-only, GetShapeshiftFormID != bar
index, DBC cast time base-only, UnitXP range superiority, nampower
FindPlayerItemSlot, [known]/[usable] richer than ClassicAPI), the wins
already done, and the marginal follow-ups. Also correct the stale
"graceful fallback" cross-cutting note to the mandatory/no-fallbacks
policy.
ClassicAPI exposes a native "focus" unit token (set via its own /focus
/ FOCUSTARGET keybind), accepted by every UnitX call.
- GetFocusUnitId falls back to the native "focus" token after the pfUI
emulated-focus check, so @focus / [cond:focus] / focus range checks
now work for non-pfUI users (previously focus only worked via pfUI).
- TryTargetFocus uses TargetUnit("focus") for an exact switch before the
fragile name-based TargetByName path.
- Add [focus]/[nofocus] conditionals (GetFocusUnitId ~= nil), covering
both pfUI and native focus; registered as boolean conditionals.
No addon /focus command is needed: ClassicAPI's companion addon already
registers /focus and /clearfocus.
- GetItemCooldownCached: resolve via ClassicAPI GetItemCooldown (by item
id/name) instead of FindItemLocation + nampower GetItemIdCooldown +
link parsing; equipment slots (1-19) still query the inventory slot.
- [stealth]/[nostealth] and [stl]/[nostl], and the Rogue branch of
GetCurrentShapeshiftIndex, now use ClassicAPI IsStealthed() (covers
Rogue Stealth + Druid Prowl) instead of class-gated localized buff
lookups. Note: [nostealth] is now true for non-stealth classes.
- CountEnemiesMatching nameplate scan uses C_NamePlate.GetNamePlateGUIDs()
instead of walking WorldFrame children and extracting GUIDs via
pcall(frame.GetName).
- Add ClassicAPI.IsStealthed / GetNamePlateGUIDs wrappers.
Resolve a slot's macro by its Blizzard macro index via ClassicAPI's
GetActionInfo instead of GetActionText -> name -> GetMacro, so action-bar
macros no longer depend on the macro name.
- Core.lua: GetAction uses GetActionInfo(slot) -> macro index ->
GetMacroByIndex; falls back to the name path for SuperMacro (no index).
ParseMacro split into a shared BuildMacro + ParseMacroByIndex (caches by
index) + ParseMacro(name). Added GetMacroByIndex. The macro cache is now
keyed by index for action-bar macros, so blank/duplicate names no longer
collide. GetMacroIndexByName remains only for genuine name references
({MacroName}, /runmacro, /macrocheck).
- MacroErrorUI.lua: remove the now-obsolete macro-name warnings (duplicate,
blank, spell-conflict, item-conflict) from both the live editor validation
and the on-close report; delete the unused name-set helpers.
- README: update the known-issue to note only name-referenced macros need
unique names.
Replace the three duplicated GetActionText -> GetMacroIndexByName ->
GetMacroInfo blocks in the GetActionTexture hook with a single
GetSlotMacroTexture helper that gets the macro slot directly from
ClassicAPI's GetActionInfo. More robust (no dependence on macro-name
lookups) and DRYs the fallback logic.
GetActionInfo:
- Add ClassicAPI.GetActionInfo wrapper; rewrite GetActionButtonInfo
(Generic.lua) to use it and resolve names via GetSpellRecField /
GetItem / GetMacroInfo, replacing the per-slot GameTooltip scan +
texture heuristic. Powers reactive-ability slot detection.
- Delete the dead SuperWoW-GetActionText copy of GetActionButtonInfo.
Spell IDs in the index:
- IndexSpells now uses ClassicAPI GetSpellInfo(slot, bookType), whose
10th return is the spellID, so every Spells entry carries .id (one
call also replaces GetSpellName + GetSpellTexture).
Dynamic pfUI action-button icons (pairs with the pfUI fork change):
- GameTooltip.SetAction hook renders spells via ClassicAPI
SetSpellByID(spell.id) instead of SetSpell(spellSlot, bookType) +
manual rank text. Items stay location-based (instance data).
- Drop the redundant GetActionSpellSlot -> GetSpellCooldown cooldown
shim in the pfUI handler; pfUI now routes through the hooked
GetActionCooldown when it defers macro scanning to us.
ClassicAPI is now required, not optional. The load-time requirement
check warns when it's missing (Core.lua), the same as Nampower/UnitXP,
and ClassicAPI-backed code calls the API directly with no fallbacks.
- ClassicAPI.lua: drop the HasUnitAuras/HasUnitSpeed/HasIsFalling
capability gates and pcall hedging; wrappers call C_UnitAuras /
GetUnitSpeed / IsFalling directly. Keep IsAvailable (used by the
requirement check) and the version helpers.
- [moving]: ClassicAPI GetUnitSpeed is the only source. Removed the
MonkeySpeed integration, the Nampower PlayerIsMoving branch, and the
100 Hz position-tracking buffer in Core.lua's OnUpdate (with its
POS_TRACK_INTERVAL constant and UnitPosition upvalue). Removed the
now-dead speed==nil guards and WarnNoSpeedSource.
- README: ClassicAPI moved to Required; MonkeySpeed dropped from
Supported Addons.
- docs/CLASSICAPI-TODO.md: record the mandatory/no-fallbacks policy.
List ClassicAPI in the Requirements table as Optional — it enables the
dispel-type conditionals ([magic], [curse], [disease], [poison],
[dispellable], [magicbuff]), which degrade gracefully without it.
Introduce ClassicAPI.lua, a feature-detection layer for the ClassicAPI
client mod that mirrors NampowerAPI's HasMinimumVersion pattern
(IsAvailable / HasMinimumVersion / HasUnitAuras). UnitHasDispelType
scans a unit's auras via C_UnitAuras and reports the dispel type,
scanning debuffs or buffs based on a helpful flag.
Add conditionals backed by it:
- Debuff side (defensive cleanse): [magic] [curse] [disease] [poison]
[dispellable] + negations
- Buff side (offensive dispel/strip): [magicbuff] [dispellablebuff]
+ negations
All are no-arg booleans, default to @target (honor @unit), and degrade
gracefully without ClassicAPI: positive checks return false, negated
return true, since vanilla cannot read aura dispel types. The existing
ValidateAura path is untouched. MacroErrorChecker auto-accepts them via
the Keywords table; they're registered in BOOLEAN_CONDITIONALS so they
parse as flags. Loaded after NampowerAPI in the TOC.
The wiki lives on the brues-code fork; update all 10 Full Documentation
links from jrc13245 to brues-code. SP_SwingTimer download links (a
separate project) are left untouched.
Document opportunities to use ClassicAPI (modern C_* API backport for
the 1.12 client) in the addon: C_UnitAuras for target aura/dispel-type
conditionals, GetWeaponEnchantInfo enchant IDs for poison/imbue checks,
GetUnitSpeed to drop the MonkeySpeed dependency, plus C_Spell, C_Timer,
UnitGUID, native focus, and Tier-3 items.
Each entry cites API.md line refs and the addon files it touches, and
notes the cross-cutting requirement to feature-detect with fallback
(mirroring the nampower HasMinimumVersion pattern).
The macro syntax checker validated commands against a hardcoded
VALID_COMMANDS table, so any command not on the list (e.g. /dump) was
flagged "Unknown command" even when the client/addon accepted it.
Add CleveRoids.IsRegisteredCommand: scans SlashCmdList and its
SLASH_<KEY>N globals into a cache (rebuilt on PLAYER_ENTERING_WORLD,
lazy-built on first use) so any command registered the addon way is
accepted automatically. Wire it into the validator alongside the
hardcoded table and the user whitelist.
Trim now-redundant hardcoded entries: the third-party addon block
(/aux, /rinse, /cursive, ...) and this addon's own self-registering
commands. Keep only commands NOT in SlashCmdList: Blizzard builtins
(/cast, /target, /run, ...), /focus (pfUI, only present when loaded),
and the chat/social/emote builtins FrameXML handles internally.
Uses GetBattlefieldStatus to check whether any battlefield queue
slot is in the "active" state, which indicates the player is
currently inside a battleground instance.
pet and nopet were missing from BOOLEAN_CONDITIONALS, so bare
[pet] (no type argument) was parsed as a spell-name match against
UnitCreatureFamily instead of a simple existence check.