Paragon: cascade guard for class skill lines + panel catalog backfill

The skill-line cascade in Player::learnSkillRewardedSpells re-fires from
_LoadSkills (every login), UpdateSkillsForLevel (every level-up),
UpdateSkillPro (every weapon-skill tick on a training dummy), and
SetSkill (first time a class skill is granted). Each pass re-grants
every SkillLineAbility-tagged class ability on the matching skill line,
which leaks Blood Presence / Death Coil / Death Grip / etc. back into
the spellbook within seconds even after the player intentionally
refunded them via the Character Advancement panel.

Path B fix: a 5-line guard at the top of learnSkillRewardedSpells skips
the cascade for class-category skill lines on CLASS_PARAGON characters.
mod-paragon already calls Player::learnSpell directly for the abilities
the player actually purchased (and their attached passives), so the
panel becomes the sole authority over class abilities. Profession,
weapon, language, and racial cascades stay enabled so recipe auto-learn,
weapon proficiencies, and racial perks still work.

Side effect: passives that previously rode along on the cascade
(Forceful Deflection on Blood Strike, Runic Focus on Icy Touch) must be
force-attached the same way Blood Plague / Frost Fever already are.
Extend kAttached and kFixup in Paragon_Essence.cpp to do that; existing
characters self-heal on next login.

Backfill paragon_spell_ae_cost for 42 spells newly exposed by the panel
after the ClassMask=0 filter was removed from the client catalog
generator (Lava Burst, Hex, Evocation, Kill Shot, Path of Frost,
Horn of Winter, Rune Strike, Raise Ally, Dark Command, etc.). Migration
is INSERT IGNORE so any per-spell tuning on existing rows is preserved.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Docker Build
2026-05-10 23:52:23 -04:00
parent 36ac3dbd1d
commit 8ad6a2aca3
4 changed files with 159 additions and 19 deletions
+29 -9
View File
@@ -1203,10 +1203,21 @@ void PanelLearnSpellChain(Player* pl, uint32 baseSpellId)
// spellbook icons. The correct *passive* spellbook entries the
// player is supposed to see are 59879 / 59921 (the descriptive
// "Passive disease" rows; SPELL_ATTR0_PASSIVE bit set).
// After the Paragon class-skill cascade guard landed in
// Player::learnSkillRewardedSpells, NONE of the DK skill-line
// cascade rewards are auto-granted any more — so passives that
// used to ride along on a class skill cascade (Forceful
// Deflection on Blood Strike, Runic Focus on Icy Touch) must be
// explicitly attached here, the same way Blood Plague / Frost
// Fever are. Add new entries when a panel-purchased active is
// expected to come with a passive spellbook entry that no
// SPELL_EFFECT_LEARN_SPELL on the parent provides.
struct AttachedPassive { uint32 parentHead; uint32 attachedSpell; };
static AttachedPassive const kAttached[] = {
{ 45462, 59879 }, // Plague Strike -> Blood Plague (passive entry)
{ 45477, 59921 }, // Icy Touch -> Frost Fever (passive entry)
{ 45477, 59921 }, // Icy Touch -> Frost Fever (passive entry)
{ 45477, 61455 }, // Icy Touch -> Runic Focus (parry from spell power)
{ 45902, 49410 }, // Blood Strike -> Forceful Deflection (parry from strength)
};
// Self-heal: a previous build of mod-paragon (briefly shipped)
@@ -3889,16 +3900,25 @@ public:
lb.child, lb.parent, player->GetName());
}
}
// 2b) Re-attach the correct passive spellbook entry (59879 /
// 59921) for any panel-purchased Plague Strike / Icy Touch
// that's missing it. `learnSpell` here can re-fire the DK
// skill-line cascade and re-grant Blood Presence / Death
// Coil / Death Grip / Forceful Deflection — Step 3's
// scoped sweep is what cleans those up.
// 2b) Re-attach the correct passive spellbook entries for any
// panel-purchased parent that is missing them. After the
// class-skill cascade guard in
// Player::learnSkillRewardedSpells, the cascade no longer
// fires for Paragons, so these attachments are the ONLY
// source for the disease passive icons (Blood Plague /
// Frost Fever) and the small DK weapon passives (Forceful
// Deflection from Blood Strike, Runic Focus from Icy
// Touch). Existing characters predating the guard may
// have FD/RF in their spellbook from the cascade but no
// panel_spell_children row tying them to the parent;
// re-running learnSpell when they already have the spell
// just records the child row and is a no-op otherwise.
struct LegacyFix { uint32 parent; uint32 correctChild; };
static LegacyFix const kFixup[] = {
{ 45462, 59879 },
{ 45477, 59921 },
{ 45462, 59879 }, // Plague Strike -> Blood Plague (passive)
{ 45477, 59921 }, // Icy Touch -> Frost Fever (passive)
{ 45477, 61455 }, // Icy Touch -> Runic Focus
{ 45902, 49410 }, // Blood Strike -> Forceful Deflection
};
for (auto const& lf : kFixup)
{