Paragon: Runeforging support (panel-purchasable, no anvil required)

Lets the Paragon class buy Runeforging from the Character Advancement
panel and apply rune enchants from anywhere in the world without needing
to be near a runeforge GameObject. Three carve-outs work together:

* Spell.cpp: bypass the SpellFocusObject GO proximity check when the
  caster is a Paragon and the spell belongs to SKILL_RUNEFORGING (776).
  Stock DK behaviour is unchanged -- the bypass is gated on
  getClass() == CLASS_PARAGON, not on the IsClass() context hook.

* Player.cpp: skip the Paragon class-skill cascade block for skill 776
  so the rune-enchant SLA cascade actually fires. Without this the
  player gets the Runeforging skill but no rune options at the anvil.

* Paragon_Essence.cpp:
  - Treat SKILL_RUNEFORGING children as a meta-skill cluster: cascade
    them like passives even though they're active casts, so they stick
    as panel_spell_children and get cleaned up via the standard refund
    path.
  - Whitelist the 8 basic rune-enchants in PruneSkillLineCascadeChildren
    so they don't get evicted as "active in children = legacy garbage".
  - Force-attach them in PanelLearnSpellChain (the SLA rows ship with
    AcquireMethod=0, so the engine cascade alone won't grant them).
  - Add an OnPlayerLogin fixup so existing Paragons who bought
    Runeforging before this change get the 8 runes retro-granted.
  - Stop filtering SPELL_ATTR0_DO_NOT_DISPLAY in PushSpellSnapshot --
    Runeforging itself is hidden in the DBC but is a real panel
    purchase that must show in the Overview tab.

The two advanced runes (Stoneskin Gargoyle, Nerubian Carapace) are
intentionally excluded from the auto-grant -- retail gates them behind
heroic dungeon / raid item drops and the SLA AcquireMethod=0 honours
that gating.

No SQL migration needed; works against existing DBC + SLA data.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Docker Build
2026-05-12 04:49:38 -04:00
parent b8826370c6
commit da17074a63
3 changed files with 220 additions and 8 deletions
+14 -1
View File
@@ -12048,7 +12048,20 @@ void Player::learnSkillRewardedSpells(uint32 skill_id, uint32 skill_value)
// weapon, language, and racial skill cascades stay enabled so things
// like recipe auto-learn, weapon proficiencies, and racial perks
// still work.
if (getClass() == CLASS_PARAGON)
//
// Carve-out: SKILL_RUNEFORGING (776) is a CLASS-category skill but
// behaves like a profession in this context — the player buys ONE
// panel ability (Runeforging, spell 53428) and the rune-enchant
// spells (Rune of the Fallen Crusader, Razorice, Cinderglacier, ...)
// are supposed to come along for the ride via the standard SLA
// cascade, exactly the same way they do for a stock DK. Without
// this carve-out, the early-return below blocks the cascade and a
// Paragon who buys Runeforging gets the skill but no actual rune
// options at the runeforge anvil. The cascade only fires once per
// skill-grant for 776 (it's not on UpdateSkillsForLevel) so the
// "leaking back into the spellbook" concern that motivates the
// early-return doesn't apply to this skill.
if (getClass() == CLASS_PARAGON && skill_id != SKILL_RUNEFORGING)
{
if (SkillLineEntry const* sl = sSkillLineStore.LookupEntry(skill_id))
if (sl->categoryId == SKILL_CATEGORY_CLASS)