Paragon: narrow weapon bypass; cascade talent ranks; Savage Defense
* Weapon-narrow: replace blanket EquippedItemSubClassMask bypass with an explicit allowlist (IsParagonWeaponSubclassWildcardSpell, currently Maelstrom Weapon 51528 only). Applied at all three gates: Player:: HasItemFitToSpellRequirements, Player::CheckAttackFitToAuraRequirement, and Aura::IsProcTriggeredOnEvent. Maelstrom Weapon still procs from any weapon for Paragon, but Hack and Slash / Sword / Mace Specialization remain correctly weapon-gated. * Talent ability-rank cascade: TeachLevelGatedAbilityChainNoPanel + CascadeRanksForTalentLearnSpellEffects walk the SPELL_EFFECT_LEARN_SPELL chain a talent rank grants and learn each rank up to the player's level. Wired into HandleCommit (on talent purchase) and OnPlayerLevelChanged (on level-up). Fixes Mangle (and any future LEARN_SPELL talent) being stuck at rank 1 because Player::learnSkillRewardedSpells is intentionally disabled for Paragon's class skill lines. * Riding-skill gate for flight forms (IsParagonSpellAllowedByRidingSkill): Flight Form (33943) requires Expert Riding (34090); Swift Flight Form (40120) requires Artisan Riding (34091). Applied in PanelLearnSpellChain and TeachLevelGatedAbilityChainNoPanel so the cascade can't push past a rank the player isn't trained for. Also backticks `rank` in the level-up query (MySQL reserved word). * Savage Defense (62600) on the panel: the SpellData bake's blanket SPELL_ATTR0_PASSIVE filter dropped Savage Defense even though Druid trainer 33 sells it at level 40. Bake (in fractured-tooling) now carves out a small PASSIVE_TRAINER_ALLOWLIST and the regenerated paragon_spell_ae_cost.sql + 2026_05_11_05.sql migration surface it on the Druid Feral spell tab. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -7143,14 +7143,16 @@ bool Player::CheckAttackFitToAuraRequirement(WeaponAttackType attackType, AuraEf
|
||||
if (spellInfo->EquippedItemClass == -1)
|
||||
return true;
|
||||
|
||||
// Fractured / Paragon: cross-class wildcard relaxes weapon-class subclass
|
||||
// gates on per-swing proc matches. A Paragon's talent list spans every
|
||||
// class so a stock weapon-subclass mask (e.g. Maelstrom Weapon's
|
||||
// axe/mace/staff/fist/dagger restriction) excludes weapons the player
|
||||
// can legitimately wield. Accept any equipped weapon in attackType slot
|
||||
// when listener is a Paragon AND the spell gates on ITEM_CLASS_WEAPON;
|
||||
// ITEM_CLASS_ARMOR (shield) gates still enforce the original mask.
|
||||
if (spellInfo->EquippedItemClass == ITEM_CLASS_WEAPON && IsParagonWildcardCaller(this))
|
||||
// Fractured / Paragon: cross-class wildcard relaxes the weapon-subclass
|
||||
// gate ONLY for the curated allowlist of cross-class proc talents
|
||||
// (currently just Maelstrom Weapon 51528-51532). Weapon-specialization
|
||||
// talents like Sword Specialization, Mace Specialization, Hack and
|
||||
// Slash, Two-Handed Weapon Specialization etc. deliberately stay
|
||||
// weapon-gated for Paragon -- the player picks a weapon and the
|
||||
// matching specialization passive activates, same as any class.
|
||||
if (spellInfo->EquippedItemClass == ITEM_CLASS_WEAPON
|
||||
&& IsParagonWildcardCaller(this)
|
||||
&& IsParagonWeaponSubclassWildcardSpell(spellInfo->Id))
|
||||
return GetWeaponForAttack(attackType, true) != nullptr;
|
||||
|
||||
Item* item = GetWeaponForAttack(attackType, true);
|
||||
@@ -12591,15 +12593,19 @@ bool Player::HasItemFitToSpellRequirements(SpellInfo const* spellInfo, Item cons
|
||||
if (spellInfo->EquippedItemClass < 0)
|
||||
return true;
|
||||
|
||||
// Fractured / Paragon: cross-class wildcard relaxes weapon-class subclass
|
||||
// gates so passive talent auras (e.g. Maelstrom Weapon talents 51528-51532)
|
||||
// attach for any equipped weapon, not just the talent's restrictive
|
||||
// subclass mask. Mirrors CheckAttackFitToAuraRequirement so per-swing
|
||||
// proc match agrees with talent-attach time. Still requires *some* weapon
|
||||
// to be equipped (otherwise unarmed Paragons would auto-activate every
|
||||
// weapon-gated talent in the game). ITEM_CLASS_ARMOR (shield) is left
|
||||
// alone -- shield-gated talents still need an actual shield.
|
||||
if (spellInfo->EquippedItemClass == ITEM_CLASS_WEAPON && IsParagonWildcardCaller(this))
|
||||
// Fractured / Paragon: cross-class wildcard relaxes the weapon-subclass
|
||||
// gate ONLY for the curated allowlist of cross-class proc talents
|
||||
// (currently just Maelstrom Weapon 51528-51532) so the passive talent
|
||||
// aura attaches when the player wields a non-stock weapon. Weapon-
|
||||
// specialization talents (Sword/Mace Specialization, Hack and Slash,
|
||||
// Two-Handed Weapon Specialization, etc.) deliberately stay weapon-
|
||||
// gated -- they're meant to bind to a specific weapon type. Still
|
||||
// requires *some* weapon equipped (unarmed Paragons don't auto-activate
|
||||
// weapon talents). ITEM_CLASS_ARMOR (shield) is left alone -- shield-
|
||||
// gated talents still need an actual shield.
|
||||
if (spellInfo->EquippedItemClass == ITEM_CLASS_WEAPON
|
||||
&& IsParagonWildcardCaller(this)
|
||||
&& IsParagonWeaponSubclassWildcardSpell(spellInfo->Id))
|
||||
{
|
||||
for (uint8 i = EQUIPMENT_SLOT_MAINHAND; i < EQUIPMENT_SLOT_TABARD; ++i)
|
||||
if (Item const* item = GetUseableItemByPos(INVENTORY_SLOT_BAG_0, i))
|
||||
|
||||
Reference in New Issue
Block a user