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>
Server-side Character Advancement now stores named, icon-tagged build
recipes (panel-purchased spells + per-spec talent ranks) and atomically
swaps between them by snapshotting the active build, refunding AE/TE
through HandleParagonReset{Talents,Abilities}, and re-spending on the
target recipe. Hunter pets attached to a build are parked to
PET_SAVE_NOT_IN_SLOT (mirroring HandleStableSwapPet) so name, talents,
and exp survive swaps; non-hunter pets (warlock demon, DK ghoul, mage
water elemental) are NOT parked because the engine resummons them from
a fresh template each cast.
New PARAA verbs: Q BUILDS / C BUILD NEW / C BUILD EDIT / C BUILD
DELETE / C BUILD FAVORITE / C BUILD LOAD. The catalog is pushed on
login and after every mutation as a single addon message.
Schema (mod-paragon migration 2026_05_10_03.sql):
- character_paragon_builds (build_id PK, guid, name, icon, is_favorite,
pet_number, created_at)
- character_paragon_build_spells (build_id, spell_id)
- character_paragon_build_talents (build_id, spec, talent_id, rank)
- character_paragon_active_build (guid PK, build_id)
The talent recipe table is spec-keyed so a build remembers tank/dps
dual-spec layouts independently. Swaps are blocked while in combat.
Co-authored-by: Cursor <cursoragent@cursor.com>
Broaden OnPlayerIsClass for CLASS_CONTEXT_ABILITY, pet/charm/equip contexts; add PARAA C RESET PET TALENTS handler. Update CLIENT-PATCHES.md for patch-enUS-5/6 and PARAA.
Co-authored-by: Cursor <cursoragent@cursor.com>
- SpellInfoCorrections: zero Reagent/ReagentCount on spells with non-zero
SpellFamilyName so class abilities no longer require shards, candles,
etc., while profession crafts (SpellFamilyName 0) keep mats. Matches
the client Spell.dbc bake in patch-enUS-4.MPQ.
- Paragon_SC: OnPlayerIsClass returns true for CLASS_CONTEXT_EQUIP_RELIC
for paladin/druid/shaman/warlock/dk so Paragon can equip all relic types
in the ranged slot.
- CLIENT-PATCHES: document Spell.dbc reagent pass, rune script order, and
stock ammo slot behavior in patch-enUS-5.
Co-authored-by: Cursor <cursoragent@cursor.com>
Companion to 2026_05_09_00.sql (DBC overlay for chrclasses + srci) and
2026_05_10_01.sql (proficiency skill rows in playercreateinfo_skills).
Those two grant the SKILL (Maces, Shield, Cloth, ...) to Paragon at
character creation; this one opens the SkillLineAbility rows that
CASCADE skill -> passive spell, so when a fresh Paragon is created
AC's `Player::LearnDefaultSkill` actually grants the proficiency
passives:
Block (107), Parry (3127), Dual Wield (674), Defense, weapon Shoot,
racial Mace/Sword Specialization, ...
Without this overlay, a class-12 Paragon spawns with the right skill
rows but a near-empty spellbook past the racials and class defaults
that come from playercreateinfo_action.
How it works
------------
AC's DBCStores.cpp::LoadDBC loads each store from the on-disk .dbc
file first, then merges <table>_dbc world-DB rows on top. Our patched
client SkillLineAbility.dbc (in patch-enUS-4.MPQ) OR's the class-12
bit (0x800) into ClassMask on 3,314 rows -- the same rows the server
needs for the cascade to fire on Paragon. Stock Docker installs use
the upstream `ac-wotlk-client-data` image which fills data/dbc/ from
a vanilla 3.3.5a extract, so without this SQL overlay the server
runs against an unmodified SkillLineAbility.dbc and the cascade
never fires.
Generation
----------
Auto-generated end-to-end by
`fractured-tooling/from-workspace-root/_gen_paragon_dbc_overlay_sql.py`,
extended in this commit to handle SkillLineAbility.dbc (14-int
WotLK layout, 56 bytes per record). The script diffs patched vs
stock by ID, keeps only rows whose stock ClassMask did NOT include
the class-12 bit but whose patched ClassMask does, and emits the
3,314 REPLACE INTO rows. Re-running with the same inputs is byte-
stable.
Verified locally
----------------
- Migration applies twice in a row at exactly 3,314 SQL overlay rows
(idempotent: DELETE WHERE ID IN (...) before INSERT).
- ac-worldserver restart logs:
>> Loaded 10219 SkillLineAbility MultiMap Data
-- the same total as stock (10,219 rows), confirming our overlay
REPLACES existing rows by ID rather than appending duplicates.
- Spot-checked spell IDs: 107 (Block, ClassMask 2115 = warrior +
paladin + dk + Paragon), 3127 (Parry, 2063), 674 (Dual Wield,
2157), 75 (Auto Shoot, 2052) all carry the 0x800 bit.
Existing characters
-------------------
The cascade fires inside Player::Create and Player::LearnDefaultSkill
at character spawn, so existing class-12 characters created before
this migration keep their broken state. Delete and re-roll, or hand-
grant the missing spells via .learn for individual existing chars.
CLIENT-PATCHES.md updated to add the third symptom ("proficiency
skills exist but passive spells don't auto-learn") and document
this migration as the fourth piece of the class-12 bootstrap.
Co-authored-by: Cursor <cursoragent@cursor.com>
Companion to 2026_05_10_00.sql. The spawn-data migration teaches the
worldserver where Paragon characters spawn and what per-level base
stats they have; this one teaches it which weapon/armor skill lines
to grant at first character login.
Without these rows a fresh Paragon character lands in their newbie
zone with no weapon or armor proficiencies (auto-attack greys out
on anything beyond a fist) -- the universal classMask=0 rows in
playercreateinfo_skills only cover Defense, Unarmed, Cloth,
languages, Mounts, and Companion Pets.
Adds 20 rows in playercreateinfo_skills with classMask=2048 (class
12 only) for every weapon and armor proficiency:
- Weapons: Swords, Axes, Bows, Guns, Maces, 2H Swords, Dual Wield,
Staves, 2H Maces, 2H Axes, Daggers, Thrown, Crossbows,
Wands, Polearms, Fist Weapons.
- Armor: Plate Mail, Mail, Leather, Shield. (Cloth already
granted via the classMask=0 universal row.)
Idempotent: DELETE WHERE classMask=2048 then INSERT, so it replays
cleanly on a partially-seeded DB (e.g. one where a contributor hand-
patched these rows before the migration landed).
Verified locally: applies cleanly twice in a row, worldserver restart
now logs `>> Loaded 1391 Player Create Skills` (was 1371 pre-Paragon
= +20 class-12 rows) and a freshly-rolled Draenei Paragon spawns with
the full weapon/armor kit.
CLIENT-PATCHES.md troubleshooting block updated to call out the
"Paragon spawns naked / can't equip anything" failure mode and list
all three migrations in the current rebuild recipe.
Co-authored-by: Cursor <cursoragent@cursor.com>
Companion to 2026_05_09_00.sql (DBC overlay). The DBC overlay teaches
the world server that class 12 (Paragon) exists; this migration
teaches it WHERE class-12 characters spawn, what action bar they boot
with, and what per-level base stats Player::InitStatsForLevel uses.
Without these rows, contributors hit:
- Player::Create -> "invalid race/class pair (R/12) - refusing"
and the client shows "Error creating character".
- WorldServer load -> "class-12 Level-L does not have stats data!"
integrity warnings.
Tables touched (idempotent: DELETE WHERE class=12 then INSERT):
- playercreateinfo : 10 rows, every DK-eligible race spawning
in their racial newbie zone (Northshire,
Valley of Trials, Ammen Vale, ...).
NOT Acherus -- Paragon is from-level-1.
- playercreateinfo_action : 46 rows, default action bar layout
per race (attack 6603, eat 78, racial,
etc.).
- player_class_stats : 80 rows, per-level base HP/Mana/STR/AGI/
STA/INT/SPI. Curve mirrors Warrior to
level 60, Paladin-style HP inflation
past 60 to keep Paragon competitive
in Wrath content.
Tables intentionally untouched: playercreateinfo_item is empty for
class 12 (Paragon ships no per-class starting items, only racial
kit), and the mask-based playercreateinfo_skills/_cast_spell/
_spell_custom rows already cover class 12 via their classMask=0
"all classes" entries.
Verified locally: applies cleanly twice in a row (idempotent),
worldserver restart now logs `>> Loaded 72 Player Create Definitions`
(was 62 pre-Paragon = +10 races for class 12) and creates a Draenei
Paragon without rejection.
CLIENT-PATCHES.md troubleshooting block updated to merge the two
"Character Creation Failed" modes (DBC overlay missing + spawn data
missing) into a single fix recipe. Existing contributors with a
pre-built dbimport image need
`docker compose build ac-db-import ac-worldserver` before this
migration is visible to DBUpdater; fresh clones get it on first
`docker compose up`.
Co-authored-by: Cursor <cursoragent@cursor.com>
The previous seed pinned auth/realmlist to production values
(`hsrwow.net` + RealmServerPort 47497), which silently bricked every
fresh local install: after auth login the realm hand-off pointed
clients at our public host, where their local credentials don't
exist, and they were dropped within a frame.
Seed now matches stock AzerothCore for solo dev:
- realmlist.address = 127.0.0.1 (was hsrwow.net)
- RealmServerPort = 3724 (was 47497)
Production owners apply both overrides post-dbimport via a one-shot
SQL UPDATE + an authserver.conf edit. Documented end-to-end in
contrib/fractured-dev-extras/BUILD-NATIVE.md (new "Production
deployment overrides" section) and the disconnect-after-login
symptom is called out in CLIENT-PATCHES.md.
Co-authored-by: Cursor <cursoragent@cursor.com>
Stock Docker installs fill data/dbc/ from the vanilla 3.3.5a extract
in `ac-wotlk-client-data`, which has no class 12 in ChrClasses.dbc and
no class-12 bit on SkillRaceClassInfo.dbc. CharacterHandler.cpp's
sChrClassesStore.LookupEntry(12) returns null and the create fails
with CHAR_CREATE_FAILED ("Class (12) not found in DBC ...") before the
contributor ever sees the panel. Fixing it required hand-copying the
patched DBCs onto the named volume — undocumented, fragile, and not
portable to native installs.
DBCStores.cpp::LoadDBC merges every <table>_dbc world-DB row on top of
the on-disk DBC store (storage.LoadFromDB after storage.Load). We use
that merge layer to ship Paragon's class-12 deltas as SQL:
- chrclasses_dbc: 1 row defining class 12 (Paragon, power=Mana,
family=Warrior, expansion=2). Resolves CHAR_CREATE_FAILED.
- skillraceclassinfo_dbc: 235 rows REPLACEing stock entries with the
patched ClassMask (class-12 bit OR'd in) so baseline skills (defense,
weapon skills, etc.) are available to Paragon characters.
The new `modules/mod-paragon/data/sql/db-world/updates/2026_05_09_00.sql`
is applied automatically by AC's DBUpdater on every fresh `ac-db-import`
run (Docker) or first worldserver boot (native). End-to-end verified
locally: truncate -> docker compose up ac-db-import -> rows reappear
with hash 33B1A05 recorded in updates table.
The migration is auto-generated by
fractured-tooling/from-workspace-root/_gen_paragon_dbc_overlay_sql.py
(outside this repo per the repo-tidy policy). Re-run it whenever the
DBC bake changes.
CLIENT-PATCHES.md is rewritten so contributors no longer need the
manual DBC sync section as their primary install path. Manual overlay
is preserved as a labelled fallback for tools that read data/dbc/
directly.
Co-authored-by: Cursor <cursoragent@cursor.com>
Explains why Character Creation Failed occurs when the client has
patch-enUS-4 but Docker/native data/dbc is still vanilla: ChrClasses
row 12 only exists in the patched DBC set. Adds Docker volume copy
steps, native install path, and log verification.
Co-authored-by: Cursor <cursoragent@cursor.com>
Documents the four binary artifacts that pair with this server
(patch-enUS-4/5/6.MPQ + patched Wow.exe), where they live (the
Releases page; not in the tree per the repo-tidy policy), and how a
contributor installs them on top of a clean 3.3.5a client. Cross-
referenced from the contrib/fractured-dev-extras README.
Co-authored-by: Cursor <cursoragent@cursor.com>
Stock AzerothCore does not ship CLAUDE.md, BUILD-NATIVE.md, or local build
logs at repo root. Park them under contrib/fractured-dev-extras/ so the
repo root stays close to upstream and dev clutter is contained.
- mv CLAUDE.md, BUILD-NATIVE.md -> contrib/fractured-dev-extras/
- mv build-worldserver.log + _build_paragon_*.log there (untracked / ignored)
- add contrib/fractured-dev-extras/README.txt explaining the layout
- gitignore: contrib/fractured-dev-extras/*.log
Co-authored-by: Cursor <cursoragent@cursor.com>