Skip to content

feat(cdm): Out of Range Coloring for spells added by Spell ID - #2084

Open
galadam4 wants to merge 1 commit into
EllesmereGaming:mainfrom
galadam4:feat/cdm-custom-spell-range-tint
Open

galadam4 wants to merge 1 commit into
EllesmereGaming:mainfrom
galadam4:feat/cdm-custom-spell-range-tint

Conversation

@galadam4

@galadam4 galadam4 commented Sep 14, 2026

Copy link
Copy Markdown

What does this PR do?

Spells added to a Cooldown Manager bar by Spell ID (the "Custom Spell ID" entry) render on EllesmereUI's own icon frames, because Blizzard's Cooldown Viewer has no frame for them. Blizzard's frames tint themselves when the target is out of range, but these icons never did, so a ranged custom spell looked castable from any distance.

This adds a per-spell Out of Range Coloring option (Off/On, default Off) to the right-click settings menu of spells added by Spell ID. When it is on, the icon uses Blizzard's own out-of-range color (CooldownViewerConstants.ITEM_NOT_IN_RANGE_COLOR), and out of range takes priority over the existing resource dim, the same order as Blizzard's RefreshIconColor. Racials and items are not offered the option. The setting is stored in customActiveStates, like the other per-spell settings for custom spells.

How it works:

  • Mirrors CooldownViewerCooldownItemMixin. The range check is armed with C_Spell.EnableSpellRangeCheck only when C_Spell.SpellHasRange is true, on the spell's live override id. Range is re-read with C_Spell.IsSpellInRange on SPELL_RANGE_CHECK_UPDATE and PLAYER_TARGET_CHANGED. A secret or nil answer leaves the color alone.
  • The two events live on a listener shell (ns.TakeShell) taken on the first arm. They are unregistered when the last armed icon releases (icon hidden, or the option turned off).
  • Registrations are per spell, so a release never disables an id that Blizzard's viewer or the existing override-range arming still holds. ArmOverrideRange and DisarmOverrideRanges got the matching check, so they never disable an id a custom icon holds.
  • The resource dim moved into a shared paint function with identical writes, so the event path and the existing preset pass paint the same way.

Note: CONTRIBUTING says feature requests are paused until a few weeks after 12.1. Opening this as a draft so it can wait for that, or be discussed first.

How was it tested?

  • Lua 5.1 syntax parse (luaparse in Lua 5.1 mode) passed for all three changed files. luac was not available locally.
  • The diff is ASCII-only and git diff --check passed. .tools/extract-locale-keys.sh was run and _keys.txt is unchanged (the row labels go through MakeSubnavRow's variable L() call).
  • API restrictions were checked against Blizzard's generated documentation. IsSpellInRange and SpellHasRange are SecretArguments = "AllowedWhenTainted". EnableSpellRangeCheck is "AllowedWhenUntainted", which only restricts secret arguments; the ids passed are plain numbers from saved settings. None of them are protected, and SPELL_RANGE_CHECK_UPDATE has no secret payload flag.
  • Not yet tested in game. Still to verify:
    • A ranged custom spell turns red walking out of range and clears walking back in, and updates on target swaps, in and out of combat and in a restricted instance.
    • Turning the option Off restores the normal and resource tint.
    • A spell with no range (self-cast) never tints.
    • Hiding the bar or changing spec leaves no stale tint.
    • Blizzard-tracked CDM icons and their override range tint are unaffected.

Screenshots

Not captured yet; pending in-game testing (before: the custom spell icon stays untinted out of range; after: it uses the red out-of-range tint).

Checklist

  • New settings default OFF (no behavior change without opt-in) - Out of Range Coloring is Off unless enabled per spell.
  • Zero cost while disabled: no events registered, no polling, no hooks doing work, no frames built - no range check armed, no listener events registered, no shell taken; the preset pass pays one flag check. The resource dim runs through a shared function with the same writes.
  • Cheap while enabled: event-driven (no polling, no timer-based logic, no per-frame allocations) - driven by SPELL_RANGE_CHECK_UPDATE / PLAYER_TARGET_CHANGED and touches only armed icons; no OnUpdate, no timers, no allocations per event.
  • No writes onto Blizzard-owned frames (weak-table pattern used); HookScript/hooksecurefunc only, never SetScript on Blizzard frames - writes only the addon-owned custom spell icon texture; no hooks or scripts on Blizzard frames.
  • Tested in-game on live; no version gates or pre-Midnight APIs added - in-game testing pending. No version gates or pre-Midnight APIs added.

🤖 Generated with Claude Code

Spells added by Spell ID render on EllesmereUI's own icon frames, so
Blizzard's viewer never tinted them out of range. Add a per-spell
Out of Range Coloring option (default Off) for those spells. When on,
the range check is armed only if the spell has a range, and the icon is
repainted on SPELL_RANGE_CHECK_UPDATE and PLAYER_TARGET_CHANGED with
Blizzard's out-of-range color, outranking the resource dim. Events
register on the first arm and drop when the last armed icon releases;
override-range disarming now leaves ids a custom icon still holds.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@galadam4

Copy link
Copy Markdown
Author
WhatsApp Image 2026-09-14 at 18 44 13 WhatsApp Image 2026-09-14 at 18 52 59

@galadam4

Copy link
Copy Markdown
Author

Settings is set to off,
You can see the manually added spell id goes back to previous behaviour (no color changing even though its not in range)
image

@galadam4
galadam4 marked this pull request as ready for review September 14, 2026 16:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant