Commit Graph

9 Commits

Author SHA1 Message Date
Docker Build 6a1f8eec89 Paragon tester hunter BiS, mount cast QoL, learn all mounts RBAC, trade cap 11
- mod-paragon: .paragon tester bis hunter (Sanctified Ahn'Kahar Blood Hunter + Windrunner's Heartseeker), bis gems kits, AGI bow vs ranged/gun/crossbow, ranged for spi/hybrid weapons.
- .learn all mounts: RBAC 916 + db_auth migration 2026_05_12_00.sql.
- Cast-time mount spells: allow start/complete while moving; block in combat; interrupt mount cast on combat enter; relax movement prevention for NPCs/units.
- MaxPrimaryTradeSkill default 11 (all WotLK primary professions) in WorldConfig + worldserver.conf.dist.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-12 23:02:30 -04:00
Docker Build da17074a63 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>
2026-05-12 04:49:38 -04:00
Docker Build b8826370c6 Paragon: cross-class stance exclusivity + cancel, hunter ammo soft-fail, Feral Cat scaling, Pestilence DP spread
Server-side batch following v0.7.18, all gated to Paragon (or applied
server-wide where the design discussion called for it):

* Cross-class stance / form / presence / aspect exclusivity (server-wide).
  New `IsFracturedExclusiveStanceSpell()` (`Unit.cpp`/`Unit.h`) returns
  true for the union of warrior stances + druid forms (combat AND utility:
  Travel, Aquatic, Flight, Swift Flight) + Ghost Wolf + base Stealth +
  Shadowform + Metamorphosis + DK Presences + Hunter Aspects (combat AND
  utility: Cheetah, Pack). `Aura::CanStackWith` (`SpellAuras.cpp`) refuses
  to stack two spells from this set, which routes through
  `_RemoveNoStackAurasDueToAura` to drop the older aura -- the same
  mechanism Battle Elixirs / Curses use. Plugs the stock-AC gap where DK
  Presences and Hunter Aspects (regular auras, just rendered in the
  stance bar) coexisted with engine-shapeshifts.

* Stances / Presences / Aspects cancellable like Druid forms.
  `SpellInfoCorrections.cpp` now zeroes `CategoryEntry` on warrior
  stances, DK presences, and every rank of every hunter aspect (moves
  them out of SpellCategory 47 "Combat States", which gates the client's
  right-click / `/cancelaura` path), AND clears `AttributesEx6` bit
  `0x1000` on warrior stances + DK presences (a second client-UI gate
  surfaced via DBC diff -- aspects don't have it set). Mirrored client-
  side by `_patch_spell_dbc_presences_cancelable.py`. Aspects / presences
  do NOT swap action bars (those are owned by `SPELL_AURA_MOD_SHAPESHIFT`,
  not by Category / AttrEx6) -- only warrior stances and druid forms keep
  the bar swap, matching the design requirement that presences/aspects
  not change the player's action bar.

* Hunter ammo soft-fail (server-wide).
  Replaced both `SPELL_FAILED_NO_AMMO` returns in `Spell::CheckCast` with
  `break;` so ranged + thrown abilities cast through with zero ammo;
  `_ApplyAmmoBonuses` continues to gate the actual arrow/bullet DPS bonus
  on a non-empty stack, so equipping ammo still pays off. New programmatic
  `ApplySpellFix`-style block in `SpellInfoCorrections.cpp` iterates every
  Hunter-family spell whose `EquippedItemClass == ITEM_CLASS_WEAPON` and
  `EquippedItemSubClassMask` includes Bow/Gun/Crossbow and sets
  `EquippedItemClass = -1` (skipping a small DENYLIST of Quiver / Ammo
  Pouch passive haste auras + Aynasha's Bow + Legendary Bow Haste -- those
  are item-equip-driven and must keep gating on the ranged weapon being
  equipped). Server log: ">> Fractured: dropped EquippedItemClass on 196
  hunter shot abilities". Mirrored client-side by the new
  `_patch_spell_dbc_hunter_ammo.py` so the 3.3.5a client preflight stops
  blocking the cast packet with "Ammo needs to be in the paper doll ammo
  slot before it can be fired." `Spell::TakeAmmo` no longer clears
  `PLAYER_AMMO_ID` to 0 when the bag empties (defense in depth so a half-
  deployed pair degrades to soft-fail rather than hard-reject). Adds
  `#include "ItemTemplate.h"` for `ITEM_SUBCLASS_WEAPON_*`.

* Feral Cat scaling (server-wide, cat-only).
  `StatSystem.cpp` `UpdateAttackPowerAndDamage` FORM_CAT branch doubles
  the AGI coefficient (1.0 -> 2.0). `SpellAuraEffects.cpp` Master
  Shapeshifter FORM_CAT branch doubles the talent's bp before triggering
  48420 (R1: 2% -> 4% crit, R2: 4% -> 8%). FORM_BEAR / FORM_DIREBEAR /
  FORM_MOONKIN / FORM_TREE branches all left untouched so bear stays
  "already fine" per the resident Feral expert. Client tooltip drift on
  Cat Form (768) + Master Shapeshifter (48411 / 48412) + Pestilence
  (50842) handled by `_patch_spell_dbc_feral_tooltips.py`.

* Pestilence spreads / refreshes Devouring Plague for Paragon casters.
  `spell_dk.cpp` `spell_dk_pestilence::HandleScriptEffect` now also
  spreads (and Glyph-of-Disease refreshes) Priest Devouring Plague when
  `IsParagonWildcardCaller(caster)`. Uses `GetAuraOfRankedSpell(2944)` so
  the spread copy carries the caster's actual rank. Stock DKs cannot
  cast Devouring Plague at all, so this branch is a no-op for them.

* Dancing Rune Weapon: Paragon copies melee, not casts.
  `spell_dk.cpp` `spell_dk_dancing_rune_weapon::CheckProc` for Paragon
  callers requires `eventInfo.GetDamageInfo()` and
  `spellInfo->DmgClass == SPELL_DAMAGE_CLASS_MELEE`, so the ghostly
  weapon now copies cross-class melee strikes (Hamstring, Sinister Strike,
  Heart Strike, Frost Strike, ...) and auto-attacks instead of re-casting
  the DK's nukes. Stock DK gating below is untouched.

* Maelstrom Weapon: drop Arcane Blast from the allowlist.
  `SpellInfo.cpp` and `spell_shaman.cpp` allowlists now match Fireball
  and Frostbolt only -- Arcane Blast stacked with its own self-buff was
  too potent.

* `BALANCE-TODO.md` added under `contrib/fractured-dev-extras/` to
  capture the resident Feral expert's recommendation, the levers we
  considered, and the cat-only Master-Shapeshifter / AGI-doubling
  resolution we shipped, plus the next-lever knobs if field reports
  still flag cat as weak.

DBC patcher pipeline (lives outside the repo in `fractured-tooling/`)
documented run order: runes -> reagents -> stances -> presences_cancelable
-> hunter_ammo -> feral_tooltips -> _make_paragon_dbc_patch.

No SQL migrations.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-11 23:17:37 -04:00
Docker Build e649402163 Paragon: cross-class talents + Warrior stance bypass + Mirror Image spellbook draw
Server-side cross-class wildcard pass for several talents that were
previously locked to a single SpellFamilyName, plus a server+client
Warrior stance bypass and a Paragon-aware Mirror Image rebuild that
mimics the owner's spellbook instead of stock Frostbolt/Fire Blast.

Talent expansions (Paragon owners only; stock classes unchanged):
- Cold Snap (11958): resets cooldown of any Frost-school spell.
- Nature's Swiftness (17116, 16188) + Predator's Swiftness (69369):
  instant-cast on any Nature-school spell.
- Vampiric Embrace (15286): leech-heals from any single-target
  Shadow-school spell.
- Fingers of Frost (44543/44545) + Frostbite (11071/12496/12497):
  proc from any Frost-school chill effect (DK Howling Blast / Icy
  Touch / Chains of Ice, Hunter Frost Trap, Shaman Frost Shock,
  cross-class chill auras via SPELL_AURA_MOD_DECREASE_SPEED).
- Maelstrom Weapon (53817): now also affects Mage Fireball (133),
  Frostbolt (116), and Arcane Blast (30451) at every rank, both
  for cast-time/cost spellmod and for stack consumption.

Warrior stance bypass:
- SpellInfo::CheckShapeshift returns SPELL_CAST_OK whenever a
  Paragon caster hits any Stances!=0 spell (no SpellFamilyName
  gate). Stock classes still see the regular form rules.
- Client side: patch-enUS-4.MPQ now zeroes Stances on every
  SPELLFAMILY_WARRIOR Spell.dbc row (105 spells) so the engine's
  pre-cast "Must be in Battle/Defensive/Berserker Stance" check
  no longer eats CMSG_CAST_SPELL packets for Paragons. Server
  bypass enforces the actual decision; stock Warriors still
  error mid-cast if they actually click while out of stance.
- patch-enUS-5.MPQ Lua tooltip post-processor recolors and
  appends "(Paragon: bypassed)" to "Requires *Stance*" lines on
  Warrior abilities, plus Paragon notes on Maelstrom Weapon and
  Mirror Image tooltips. Action-bar UseAction wrapper routes
  stance-gated Warrior spell clicks through CastSpellByName so
  the stance-zero DBC + server bypass actually run.

Mirror Image:
- npc_pet_mage_mirror_image rebuilds its spell list from the
  Paragon owner's spellbook on InitializeAI AND JustEngagedWith
  (the second pass + events.Reset clears any stale events the
  CasterAI base scheduler may have queued from stock 59637 /
  59638 entries before the rebuild ran).
- Curated filter keeps single-target damaging spells (instant,
  cast-time, or channeled) with a base cooldown <=10s, with the
  "damaging" definition expanded to include
  SPELL_EFFECT_TRIGGER_MISSILE and
  SPELL_AURA_PERIODIC_TRIGGER_SPELL so Arcane Missiles
  qualifies. Rejects passives, AoE, melee/ranged weapon strikes,
  item/reagent/stance/equip-gated, and lower spell ranks.
- UpdateAI picks a random spell from the curated list per cast
  and reschedules the next pick by the actually-cast spell's
  cast/channel duration + 750ms breather, so a 5s Arcane
  Missiles channel waits its full duration before re-rolling
  rather than visually looping across four images.

Helpers:
- Unit::IsParagonWildcardCaller / Unit::ParagonFamilyMatches
  used by Spell.cpp, SpellInfo.cpp, Player.cpp,
  SpellAuraEffects.cpp, and the spell scripts.
- SpellInfo::CheckShapeshift signature gains an optional caster
  pointer; all call sites updated.

SQL migrations under modules/mod-paragon/data/sql/db-world/updates/:
- 2026_05_11_01.sql  Vampiric Embrace spell_proc relax + script
                     gate (CheckProc enforces stock for non-Paragon).
- 2026_05_11_02.sql  Maelstrom Weapon spell_proc relax (initial,
                     superseded by _04 below for stack-consumption fix).
- 2026_05_11_03.sql  Fingers of Frost / Frostbite spell_proc relax
                     and spell_script_names binding.
- 2026_05_11_04.sql  Maelstrom Weapon spell_proc fixup: restore
                     SpellPhaseMask=1 (CAST) and AttributesMask=8
                     (REQ_SPELLMOD); previous _02 set 8/0 which
                     silently dropped every proc event.

Diagnostics from this debugging session demoted from LOG_INFO to
LOG_DEBUG (silent at default info level) so production logs stay
quiet but the probes remain available for reproducing future
regressions: pet_mage.cpp MirrorImage probe/kept/rebuild/init/
engage/cast lines and SpellInfo.cpp CheckShapeshift bypass line.

CLIENT-PATCHES.md updated to document the new Warrior stance DBC
patcher (_patch_spell_dbc_stances.py), the spell-tooltip post-
processor and stance UseAction wrapper in patch-enUS-5.MPQ, and
the Mirror Image / Maelstrom Weapon Paragon notes.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-11 14:54:05 -04:00
Docker Build a1c9172beb Paragon cross-class family wildcard + Predatory Strikes proc
- CONFIG_PARAGON_WILDCARD_FAMILY + Paragon.WildcardFamilyMatching (reloadable)
- SpellInfo::IsAffected / IsAffectedBySpellMod(listenerOwner) for Paragon proc/mod wildcard
- SpellMgr::CanSpellTriggerProcOnEvent(procOwner) + Aura::IsProcTriggeredOnEvent wiring
- Player::IsAffectedBySpellmod passes listener for SpellMod wildcard
- ParagonFamilyMatches helper + Nourish / Shred-Maul bleed gate usage in Unit.cpp
- Spell::prepare: Paragon consumes 69369 for Nature spells <10s base cast (non-channeled)
- spell_paragon_predatory_strikes + SQL 2026_05_11_00.sql (spell_proc + spell_script_names)

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-11 01:25:18 -04:00
Docker Build f986fdcddd mod-paragon: let class 12 actually USE class-restricted glyphs / items
Two paths still rejected glyph use on Paragon characters even after the
earlier AllowableClass server bypass:

1. Spell::CheckItems (server) treated cast-from-glyph as a normal
   "equipped item required" cast and called HasItemFitToSpellRequirements,
   which only handles weapon/armor and falls through default for
   ITEM_CLASS_GLYPH -> SPELL_FAILED_EQUIPPED_ITEM_CLASS. Skip that check
   when the cast item itself is the glyph.

2. The 3.3.5 client engine pre-checks ItemTemplate.AllowableClass against
   the player's class locally and refuses the right-click before sending
   CMSG_USE_ITEM, regardless of what the server would do. Bake the
   Paragon class bit (1<<11 = 2048) into AllowableClass for every
   class-restricted item via a mod-paragon SQL migration so the engine's
   pre-check passes for class 12.

Cache caveat: clients that previously inspected an affected item have
the old AllowableClass cached in Cache/<locale>/itemcache.wdb; deleting
the Cache folder forces a re-query. The server also caches item_template
in memory at boot, so this migration only takes effect for clients after
a worldserver restart (or .reload item_template) once the SQL has been
applied -- DBUpdater handles the SQL automatically on the next start.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-09 16:52:37 -04:00
Dawnforger 22e79a4f32 fix(core): DK ToT off-hand strikes and Titan Grip for classless
- Item: 2H weapon subclass/inventory masks for strike spells (ToT / dual 2H).
- Player: allow SPELL_EFFECT_TITAN_GRIP through skill validation; clear TG on
  talent/spec reset only for warriors.
- PlayerStorage: sync m_canTitanGrip from spellbook before inventory load.
- Spell: treat Thassarian off-hand strike spells as OFF_ATTACK when DBC omits
  SPELL_ATTR3_REQUIRES_OFF_HAND_WEAPON.
2026-05-07 23:40:40 -05:00
Docker Build 8e4c8f57e4 Fractured: Paragon core hooks, mod-paragon, mod-ale, Docker build cap
- Track mod-paragon and mod-ale (un-ignore modules in .gitignore).
- Ship docker-compose.override.yml with CMAKE_EXTRA_OPTIONS for LuaJIT (mod-ale).
- Dockerfile: CBUILD_PARALLEL default to limit OOM under Docker/WSL2.
- Core: CLASS_PARAGON sticky combo points (DetachComboTarget), selection rebind,
  Spell::CheckPower rune path for multi-resource Paragon.
- spell_dk_death_rune: IsClass(CLASS_DEATH_KNIGHT, CLASS_CONTEXT_ABILITY) for
  Blood of the North / Reaping / DRM on Paragon.
- Remove temporary Paragon CheckPower logging.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-08 00:03:09 -04:00
Docker Build 72dd540b67 Local snapshot for Docker build (includes mod-ale)
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-06 21:18:20 -04:00