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
@@ -12017,6 +12017,28 @@ void Player::learnSkillRewardedSpells(uint32 skill_id, uint32 skill_value)
uint32 raceMask = getRaceMask();
uint32 classMask = getClassMask();
// Fractured / Paragon: the Character Advancement panel is the sole
// authority over which class abilities a Paragon owns. The skill-line
// cascade 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 of those re-grants every SLA-tagged class ability on the
// matching skill line — leaking Blood Presence / Death Coil / Death
// Grip / etc. back into the spellbook within seconds even after the
// player intentionally refunded them via the panel. Skip the cascade
// for class-category skill lines on Paragon characters; mod-paragon
// calls Player::learnSpell directly for the abilities the player
// actually purchased, including their attached passives. Profession,
// 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)
{
if (SkillLineEntry const* sl = sSkillLineStore.LookupEntry(skill_id))
if (sl->categoryId == SKILL_CATEGORY_CLASS)
return;
}
// Get all abilities for this skill and sort by MinSkillLineRank (lowest to highest)
auto abilities = GetSkillLineAbilitiesBySkillLine(skill_id);
std::vector<SkillLineAbilityEntry const*> sortedAbilities(abilities.begin(), abilities.end());