A clause may now carry a leading run of [group] blocks sharing one action;
groups are OR'd, first pass wins, and [] always passes. The existing
;-separated single-block form is unchanged and mixes freely.
The OR loop lives in the two single-clause evaluators, DoWithConditionals
and TestAction, which expand a multi-group clause into one-group variants
and recurse. That covers every ;-split site, /castsequence (where ; is not
a separator and the sequence is keyed by the full args), /cancelaura,
/stopmacro and the editor highlight without rewriting strings, so
action.args, the ParsedMsg/Sequences caches and highlight offsets keep
their identity.
ParseMsg scans the leading group run (quote-aware) instead of the greedy
%[(.+)%], which previously turned [a][b] into the bogus key a][b and made
such clauses fail silently on both the cast and icon paths. The flag
pattern still runs on the whole clause when there are no groups, so !Spell
is byte-identical.
TestAction reports which variant passed and TestForActiveAction stores its
conditionals, so range/usable colouring follows the passing group's @unit
rather than group 1's. /target gains ; and group support; /pfcast injects
the resolved unit into every group, not just the first. The macro checker
validates every leading block, drops the EMPTY_CONDITIONAL error, and
catches a missing action after the last group.
Assume a modern pfUI, and drop the version-tiered branching entirely: 31 call
sites across five files, plus the flag and its detector.
Note which side was actually dead. HasPfUI76() required four things -- pfUI
version >= 7.6, Nampower >= 2.40, pfUI.libdebuff_objects_guid, and
pfUI.libdebuff_casts. The last one does not exist: pfUI exports 28 libdebuff_*
tables and libdebuff_casts is not among them (libdebuff_recent_casts is a
dedup table keyed [targetGuid][spellName][casterGuid], a different shape). So
the detector returned false at any version, and it was the hasPfUI76-TRUE
branches that never ran, not the fallbacks. Removing those is behaviour-
preserving; keeping SCRM as the owner of castTracking is what the code has
always actually done.
Removed accordingly:
- lib:HasPfUI76(), both flag declarations, and the block that would have aliased
castTracking to pfUI.libdebuff_casts and re-pointed lib.objects/iconCache.
- HookPfUILibdebuff's "7.6 handles durations internally" early return, so the
GetDuration/AddEffect hooks below it are visibly the live path again.
- The SPELL_START_OTHER / SPELL_FAILED_OTHER unregister arm, the pfUI branch of
GetAuraTrackingData, the pfUI76 arm of the libdebuff zone/death cleanup, the
pfUI backing table in the /cleveroid aura dump, and two status-string suffixes.
- SyncComboDurationToPfUI (77 lines) with its two call sites: it returned
immediately whenever hasPfUI76, and is inert once the tier split is gone.
Unconditionalised the paths that were gated on `not hasPfUI76`: the castTracking
populate/clear/sweep, InitPfUIIntegration on login, and ten libdebuff duration
lookups.
Verified no hasPfUI76 reference remains, and that per-file block balance is
unchanged from HEAD.
Hands ClassicAPI the action this addon resolved for each macro, so the icon,
tooltip, cooldown sweep, range and usable state come from the client instead of
from replaced action-bar globals. That also reaches the drag cursor and the macro
window grid, which Lua cannot touch, and lets the client answer range for a macro
slot directly rather than borrowing a proxy slot.
- CleveRoids.useClassicAPIDisplay feature-detects C_Macro.SetMacroDisplay rather
than checking CLASSIC_API_VERSION, which reports a dev sentinel while the API is
unreleased. ClassicAPIMacroDisplay tells ClassicAPI we drive macro display, which
it otherwise stands down from when it sees this addon.
- macro.actions.macroID back-references the Blizzard index, since the update loop
walks actions objects rather than macros. nil for SuperMacro macros, which have
no index and so cannot be published.
- PublishDisplay sends false, not nothing, when no action matched: that claims the
macro and shows the question mark, where silence would hand it back to
ClassicAPI's own #showtooltip parser.
- PublishAllDisplays runs once the addon is ready and after every re-parse, since
ClassicAPI re-evaluates nothing for us. It covers macros that aren't on a bar,
which is what keeps the macro window grid correct. Deferred past load because
SetMacroDisplay returns false until the player is in the world.
- ReleaseDisplays hands every macro back on DisableAddon.
The per-slot ACTIONBAR_SLOT_CHANGED fan-out is kept for the non-integrated path.
Publishing repaints every slot holding the macro through the client's own notifier,
so it is redundant when the API is present, but removing it outright would leave
buttons never repainting on a ClassicAPI build without the API.
Adds CleveRoids.conditionalAliases, applied in ParseMsg so a deprecated name
is rewritten to its current keyword before anything downstream (evaluation,
_groups) sees it. This is the mechanism for renamed modifiers, which -- unlike
predicates such as [stl] -> [stealth] -- have no Keywords function an alias
could simply point at.
[mouseuse] now resolves to [cursor], routing old macros through ClassicAPI's
C_Spell.CastAtCursor / C_Item.UseAtCursor. Drops the post-cast block that cast
normally and then faked a mouse click via CameraOrSelectOrMoveStart/Stop to
place the AoE circle, along with its workaround for that call spuriously
starting auto-attack.
MacroErrorChecker seeds VALID_CONDITIONALS from the alias table, so the old
names stay valid syntax without needing a placeholder ignoreKeywords entry.
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).
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.