From 7c57abd69f6aef34d27732b3652a9cd5c4387534 Mon Sep 17 00:00:00 2001 From: Docker Build Date: Mon, 11 May 2026 18:19:42 -0400 Subject: [PATCH] Paragon: weapon-class subclass bypass for proc talents (Maelstrom Weapon any weapon) Cross-class wildcard now also relaxes the EquippedItemSubClassMask gate on weapon-class proc talents so e.g. Maelstrom Weapon procs from any weapon a Paragon has equipped, not just the talent's stock melee subset (axe / mace / staff / fist / dagger / 2H sword/axe/mace). Three independent gates run in the proc chain; all three needed the bypass for the proc to actually fire: - Player::HasItemFitToSpellRequirements -- talent-attach check at item-equip / login time. Without this the passive talent aura never even applies for a Paragon wielding a non-stock weapon. - Player::CheckAttackFitToAuraRequirement -- per-swing match the proc engine uses to decide whether attackType + weapon is compatible with the aura's EquippedItemClass / SubClassMask. - Aura::IsProcTriggeredOnEvent (SpellAuras.cpp) -- per-event proc evaluator that calls Item::IsFitToSpellRequirements again, independently of the previous two. Was the proc-killing gate before this commit: talent attached, swing matched, but this evaluator returned 0 charges for any weapon outside the stock subclass mask, so no stack was ever applied. All three bypasses are gated on: - IsParagonWildcardCaller(this) (player class 12 + config flag Paragon.WildcardFamilyMatching = 1). - spellInfo->EquippedItemClass == ITEM_CLASS_WEAPON. ARMOR-class gates (shield) are deliberately left alone -- shield-required talents (Shield Specialization, Shield Block, etc.) still need an actual shield equipped. Each bypass also requires *some* weapon to be in the relevant slot (MAINHAND / OFFHAND / RANGED). Unarmed Paragons do not auto-activate every weapon-gated talent in the game. Net effect for Paragon characters with Maelstrom Weapon talented: proc fires from any melee weapon -- 1H sword / polearm / spear / fist / dagger / staff / 2H weapons / axes / maces. Stock Shamans and every other non-Paragon class are unchanged. Caveat (not addressed by this commit): the talent's stock ProcFlags (0xC00014) only fire on melee swings + melee abilities. Ranged auto-attacks (bow / gun / crossbow / wand) fire PROC_FLAG_DONE_RANGED_AUTO_ATTACK (0x40), which the proc engine never matches against this talent, so the new weapon-subclass bypass is moot for those weapons. Adding ranged-auto-attack support would require a Paragon-only ProcFlags expansion at the proc engine layer; deferred until requested. Co-authored-by: Cursor --- src/server/game/Entities/Player/Player.cpp | 31 +++++++++++++++++++++ src/server/game/Spells/Auras/SpellAuras.cpp | 20 ++++++++++++- 2 files changed, 50 insertions(+), 1 deletion(-) diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index 6d09301..3d4219d 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -7143,6 +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)) + return GetWeaponForAttack(attackType, true) != nullptr; + Item* item = GetWeaponForAttack(attackType, true); if (!item || !item->IsFitToSpellRequirements(spellInfo)) return false; @@ -12581,6 +12591,27 @@ 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)) + { + for (uint8 i = EQUIPMENT_SLOT_MAINHAND; i < EQUIPMENT_SLOT_TABARD; ++i) + if (Item const* item = GetUseableItemByPos(INVENTORY_SLOT_BAG_0, i)) + if (item != ignoreItem) + if (ItemTemplate const* proto = item->GetTemplate()) + if (proto->Class == ITEM_CLASS_WEAPON) + return true; + // No weapon equipped at all -- fall through to stock logic, which + // returns false for passive talent auras (correct: an unarmed + // Paragon shouldn't have weapon talents active). + } + // scan other equipped items for same requirements (mostly 2 daggers/etc) // for optimize check 2 used cases only switch (spellInfo->EquippedItemClass) diff --git a/src/server/game/Spells/Auras/SpellAuras.cpp b/src/server/game/Spells/Auras/SpellAuras.cpp index 5398ca5..97c8457 100644 --- a/src/server/game/Spells/Auras/SpellAuras.cpp +++ b/src/server/game/Spells/Auras/SpellAuras.cpp @@ -2251,8 +2251,26 @@ uint8 Aura::GetProcEffectMask(AuraApplication* aurApp, ProcEventInfo& eventInfo, item = target->ToPlayer()->GetUseableItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_OFFHAND); } - if (!item || item->IsBroken() || !item->IsFitToSpellRequirements(GetSpellInfo())) + if (!item || item->IsBroken()) return 0; + if (!item->IsFitToSpellRequirements(GetSpellInfo())) + { + // Fractured / Paragon: cross-class wildcard relaxes weapon- + // class subclass gates on per-event proc evaluation. This + // mirrors Player::CheckAttackFitToAuraRequirement and + // Player::HasItemFitToSpellRequirements -- without this + // third bypass, the talent attaches (HasItemFit lets it), + // the per-swing match accepts the weapon (CheckAttackFit + // lets it), but IsProcTriggeredOnEvent still kills the + // proc here for any weapon outside the talent's stock + // subclass mask (e.g. Maelstrom Weapon on a Paragon + // wielding a 1H sword or polearm). Restricted to + // ITEM_CLASS_WEAPON so shield-gated talents still need + // an actual shield. + if (!(GetSpellInfo()->EquippedItemClass == ITEM_CLASS_WEAPON + && IsParagonWildcardCaller(target))) + return 0; + } } }