b8826370c6f7642e7f66a2ae5cd44f897ad76689
26 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
999f7e94bd |
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> |
||
|
|
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>
|
||
|
|
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> |
||
|
|
8ad6a2aca3 |
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> |
||
|
|
656cf2d07d |
Paragon panel: keep cascade passives, strip free actives; DK passive DBC fix
- PanelLearnSpellChain: record every non-chain passive as panel_spell_child; only revoke non-passive (Blood Presence, Death Coil, Death Grip, etc.). - RevokeUnwantedCascadeSpellsForPlayer: skip passive rewards on login sweep. - RevokeBlockedSpellsForPlayer: migrate legacy passive revoke rows to children; walk (parent, revoked) pairs from DB. - PruneSkillLineCascadeChildrenFromDb: only strip actives wrongly stored as children; never strip passives. - SpellInfoCorrections: set SPELL_ATTR0_PASSIVE on Forceful Deflection (49410) and Runic Focus (61455) so IsPassive() matches spellbook behavior. - PanelUnlearnTalentPurchase: mirror resetTalents (_removeTalentAurasAndSpells, _removeTalent, SendTalentsInfoData) so Beast Mastery loss triggers pet reset. - OnPlayerLogin: run legacy passive attach before scoped cascade sweep. - Add .paragon recalibrate GM command (RBAC modify): full panel reset + AE/TE reconciliation for selected player or self. Co-authored-by: Cursor <cursoragent@cursor.com> |
||
|
|
9fb80102c8 |
Paragon: spell unlearn queue + AE/TE reconciliation
Two related additions to mod-paragon:
* HandleCommit gains a third payload section, " u:<id>,...", carrying
spell IDs the player wants to refund + unlearn in the same commit
that learns / talents through. The protocol stays backward-compat
(older clients omit the section). PanelUnlearnSpellPurchase mirrors
the per-spell branch of HandleParagonResetAbilities: tracked passive
children are removed first, then the chain head, then panel_spells /
panel_spell_children / panel_spell_revoked rows for that purchase
are dropped, then LookupSpellAECost(head) is refunded into the
cache. Unlearns are applied before learns inside the commit so the
refund covers the same-commit spends. Allow-list for the silence
window now includes chain ranks + panel_spell_children for the
intentional unlearns so "You have unlearned X" toasts stay visible
for the targeted spell while cascade dependents stay silenced.
* ReconcileEssenceForPlayer reads panel_spells + panel_talents and
sets the cache to ComputeStartingAE/TE(level) - sum-of-spends.
Self-heals drift in either direction: clamps the cache down when
the player has more essence than their level + spends allow
(cheese clamp), and tops up when they have less (admin-tweak /
crash recovery). Wired into OnPlayerLogin (after LoadCurrencyFromDb,
before PushCurrency so the first balance the client sees is the
reconciled one) and OnPlayerLevelChanged (replaces the old
GrantLevelUpEssence delta -- Reconcile sets the absolute correct
balance from level + spend, so it subsumes the per-level grant and
the cheese clamp in one call). Costs come from the same
paragon_spell_ae_cost / config keys HandleCommit uses so the math
stays in lockstep across any future cost rebalance.
Both features ship in patch-enUS-6.MPQ v0.9.16: right-click a learned
spell row to queue an unlearn (header shows +N AE refund preview) and
hit Learn All to apply. The icon picker also got two fixes -- the
leading INV_Misc_QuestionMark is no longer duplicated, and the
selection ring is now a tooltip-border Frame anchored to the cell
bounds (the prior UI-ActionButton-Border texture rendered nearly
invisible at non-native sizes).
Co-authored-by: Cursor <cursoragent@cursor.com>
|
||
|
|
ef02839ea0 |
Paragon: Save-Current build, archive retired share codes, reset clears active
Server side of the v0.7.10 Builds drop. Squashes a few footguns from the original Builds catalog and adds a one-click "save what I have right now" path the Overview pane can hook directly into. - HandleBuildSaveCurrent: new C BUILD SAVE_CURRENT verb. Inserts a fresh build row, snapshots the live panel into its recipe, sets it active. No AE/TE motion, no relearning -- just a named slot for whatever the player already has. - Reset abilities / Reset talents now SetActiveBuildId(0) and re-push the catalog. Without this, the next swap silently overwrote the active build's saved recipe with the (now empty/partial) post-reset state -- effectively erasing the build. - Delete of the *active* build is now a hard reset (HandleParagonResetAll): unlearn everything the panel bought, refund all AE/TE. Deleting a non-active slot still just removes the saved recipe row + parked pet. - Load of the currently-active build is now a "revert to last snapshot" instead of a no-op refresh: keeps the saved recipe authoritative, parks the pet, resets, re-applies. Useful for discarding pending edits. - After a successful Learn All while a build is active: archive the build's previous share_code + recipe into character_paragon_build_share_archive* (so codes already posted to Discord keep importing the frozen loadout), snapshot the new panel into the live build, assign a fresh share_code, push catalog. - HandleBuildImport now falls back to the archive tables when a code isn't in the live catalog -- old shared codes resurrect the recipe they pointed at when they were retired. - Imports never copy pet_number (the parked pet belongs to the source player); if the imported recipe contains Tame Beast we hint that the importer needs to tame their own pet. - BuildPanelOwnedSpellsAllowlist now walks SPELL_EFFECT_LEARN_SPELL effects on talent rank spells (Mangle, Feral Charge, Mutilate, ...) so the login cascade sweep stops revoking talent-granted active abilities. Schema: new mod-paragon migration 2026_05_10_05.sql adds character_paragon_build_share_archive (+ _spells / _talents). Co-authored-by: Cursor <cursoragent@cursor.com> |
||
|
|
a251e56c59 |
Paragon: Builds QoL -- share codes, unload, remaining AE/TE on hover
- Replace the "favorite" toggle with import-by-share-code: every build gets a 6-char realm-unique alphanumeric code on creation; pasting one into the BuildsPane share box copies the recipe (name + icon + spells + talents) into the importer's catalog as a new build, with a fresh share code so the imported copy can be re-shared independently. - Add C BUILD UNLOAD verb so the client can clear a stale active-build pointer without forcing a swap. Wired to a new "Unload (clear active)" right-click context menu entry on the active build. - Per-build tooltip now shows "Remaining if loaded: X AE / Y TE", computed server-side as total_earned - recipe_cost. Negative renders red so the player sees insufficient-currency cases before clicking Load. Suppressed for the active build (HandleBuildLoad short-circuits on target == active so the line would be misleading). - Schema migration 2026_05_10_04.sql: drop is_favorite from character_paragon_builds and add share_code CHAR(6) UNIQUE NULL with lazy backfill on every PushBuildCatalog (so pre-migration rows pick up codes the first time the player opens the panel). Co-authored-by: Cursor <cursoragent@cursor.com> |
||
|
|
7de018f7eb |
Paragon: add Builds catalog (saved loadouts with pet park/unpark)
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>
|
||
|
|
abb25f56d1 |
Paragon: expand IsClass hooks and addon pet talent reset
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> |
||
|
|
f2952c905a |
Fractured: strip class-spell reagents at load; Paragon relic ranged slot
- 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> |
||
|
|
8abd40f217 |
Paragon: give class 12 intrinsic AP and SP scaling from stats
Stock 3.3.5 hardcodes per-class stat -> AP/SP formulas in
Player::UpdateAttackPowerAndDamage and Unit::SpellBase{Damage,Healing}BonusDone,
so class 12 fell into the default branches and ended up with 0 AP and 0 SP
regardless of STR / AGI / INT / SPI. The character sheet, combat log, and
ability damage all reflected this, and Mental Quickness-style AP->SP plumbing
silently no-oped on Paragon characters.
Add Paragon-specific branches in core (no PlayerScript hooks - those caused
SIGSEGVs when the new mid-list enum entry shifted later hook ordinals and
broke vtable dispatch):
- StatSystem.cpp: melee and ranged AP = level*2 + STR + AGI - 20, mirroring
the formula the UI patch already advertises in tooltips.
- Unit.cpp: intrinsic SP = level*2 + INT + SPI - 20 (clamped >=0),
added symmetrically to SpellBaseDamageBonusDone and
SpellBaseHealingBonusDone so the single advertised Spell Power value the
character sheet renders matches what spells actually use in combat.
Drop the now-unused UnitDefines.h include in Paragon_SC.cpp - it was only
needed by the AP PlayerScript hook that was rolled back in favor of the
core change.
Co-authored-by: Cursor <cursoragent@cursor.com>
|
||
|
|
34cc87a5f9 |
mod-paragon: fix panel cascade sweep revoking talent-granted spells
RevokeUnwantedCascadeSpellsForPlayer and RevokeBlockedSpellsForPlayer built their allowlist only from character_paragon_panel_spells and panel_spell_children. Many Character Advancement "abilities" (e.g. Scourge Strike) are panel talents stored in character_paragon_panel_talents, so learning Death Coil afterward activated DK skill lines and the sweep removed those spells as false orphans. Add BuildPanelOwnedSpellsAllowlist to union spell chains, talent rank spell IDs up to the purchased rank, and passive children. Also keep the prior fixes: clear stale panel_spell_revoked rows on purchase and skip+delete revoke entries that now match the allowlist on login. Co-authored-by: Cursor <cursoragent@cursor.com> |
||
|
|
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> |
||
|
|
7298d89c9a |
mod-paragon: default HasActivePowers on for rage from white hits
Paragon OnPlayerHasActivePowerType only reported POWER_RAGE when Paragon.MultiResource.HasActivePowers was true. Core melee rage uses Unit::DealDamage -> HasActivePowerType(POWER_RAGE) before RewardRage; missing module config (common on fresh clones / Docker without merged mod_paragon.conf) fell through to GetOption(..., false) and white swings never generated rage. Match mod_paragon.conf.dist and default the C++ fallback to true so Paragon behaves correctly out of the box. Set Paragon.MultiResource.HasActivePowers = 0 only for intentional test builds. Co-authored-by: Cursor <cursoragent@cursor.com> |
||
|
|
3a2ae82593 |
mod-paragon: combined Arcane Torrent also refunds 15 rage
Extend spell_paragon_arcane_torrent to EnergizeBySpell POWER_RAGE 150 (15 displayed; rage uses the same 10x internal scaling as runic power, see the `-20` rage decay step in Player::Regenerate). Paragon's combined Arcane Torrent now refunds mana, rage, energy, and runic power -- whichever pool the character is using at the moment. ModifyPower no-ops on pools with MaxPower == 0, so it's safe even before the Paragon picks up rage abilities. Co-authored-by: Cursor <cursoragent@cursor.com> |
||
|
|
16717acdd3 |
mod-paragon: combined Arcane Torrent that refunds mana, energy, and runic power
Building on the previous fix that hid the rogue and DK Arcane Torrent variants for Paragon Blood Elves: instead of just dropping the duplicates, turn the remaining mana variant (28730) into a single combined racial that refunds whichever resource pool the character is using at the moment. Add SpellScript spell_paragon_arcane_torrent in modules/mod-paragon/src/ Paragon_SC.cpp. Hooks AfterCast on 28730: when the caster is class 12 the script EnergizeBySpell's 15 energy and 150 internal runic power (= 15 displayed, matching stock 25046 / 50613 amounts) on top of the spell's stock mana effect. ModifyPower no-ops on pools the player has no max for, so it is safe even before the Paragon picks up energy- or RP-using abilities. Non-Paragon Blood Elves are untouched and keep learning their stock racial. Update migration 2026_05_10_03.sql to also register the script binding via spell_script_names (28730 -> 'spell_paragon_arcane_torrent'). Idempotent DELETE + INSERT. Co-authored-by: Cursor <cursoragent@cursor.com> |
||
|
|
d96123e661 |
mod-paragon: single Arcane Torrent for Paragon Blood Elves
Blood Elf racial skill line 756 grants three different Arcane Torrent spell IDs (28730 mana, 25046 rogue energy, 50613 DK runic power). The blanket SkillLineAbility overlay in 2026_05_10_02 OR'd class 12 into all three, so Paragon Blood Elves auto-learned every variant and the spellbook listed three identical "Arcane Torrent" entries. Add db-world migration 2026_05_10_03.sql to clear the class-12 bit on the rogue and DK rows only (SkillLineAbility IDs 13338 and 17510), leaving 28730 as the sole Paragon-visible racial cast. OnPlayerLogin removes 25046/50613 if still present so existing characters self-heal without a manual unlearn. The fractured-tooling DBC overlay generator is updated in the same workspace to skip those two rows when regenerating SkillLineAbility SQL. Co-authored-by: Cursor <cursoragent@cursor.com> |
||
|
|
8363b1b6c8 |
Paragon: ship class-12 SkillLineAbility overlay so proficiency passives auto-learn
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>
|
||
|
|
2874119c6d |
Paragon: ship class-12 weapon/armor proficiencies as SQL migration
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>
|
||
|
|
5deb9e3255 |
Paragon: ship class-12 starter spawn data so character creation works on fresh installs
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>
|
||
|
|
fae3ff5028 |
Paragon: ship server-side DBC overlay as SQL so fresh installs can roll class 12
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>
|
||
|
|
4d2a80ddb8 |
Paragon: server-authoritative CP/rune sync + cascade-spell revoke hardening
mod-paragon Paragon_Essence.cpp: - Broaden SkillLinesLinkedToSpell: collect every SkillLineAbility row for an anchor spell regardless of AcquireMethod, so anchor spells whose primary SLA uses AcquireMethod 0 (e.g. Blood Strike) correctly identify their skill lines and let the dependent classifier do its job. - IsSpellSkillLineCascadeDependent / RevokeUnwantedCascadeSpellsForPlayer use the broadened helper. HandleCommit calls the post-purchase sweep immediately so the spellbook never carries lingering cascade dependents (Blood Presence / Forceful Deflection / Death Coil / Death Grip). - New character_paragon_panel_spell_revoked table tracks which active dependents we've revoked per (guid, parent) so OnPlayerLogin can re-revoke them after AC's _LoadSkills -> learnSkillRewardedSpells silently re-grants them. - OnPlayerLogin opens the client SILENCE window via SendSilenceOpenForCommit with an empty allow list and intentionally omits the matching SendSilenceClose: the chat frame buffers CHAT_MSG_SYSTEM during the loading screen and only flushes after PLAYER_ENTERING_WORLD, so a paired CLOSE would shut the filter before the buffered "you have unlearned X" toasts hit it. The addon's 8s fail-open closes the window after the flush. - New `.paragon hat` chat command for diagnosing Honor Among Thieves triggers (talent rank, learned spell, applied aura, proc table entry). mod-paragon Paragon_SC.cpp: - OnPlayerUpdate pushes server-authoritative combo points to the client via PARAA "R CP <n>" whenever the count changes. The client-side ComboFrame Paragon simulator listens for this and updates the target frame, fixing HAT-generated CP not displaying (HAT's trigger casts with a null target, which the combat-log inference path can't see). - OnPlayerUpdate also pushes "R RUNES <cd0..cd5>" (ms remaining per rune slot) on rune mask changes, so the client RuneFrame simulator stays in lock-step with Spell::TakeRunePower instead of drifting through combat-log latency. mod-paragon SQL: - New updates/2026_05_09_00.sql migration creates character_paragon_panel_spell_revoked for AC's auto-DBUpdater so a fresh checkout can stand up an existing characters DB without manual intervention. Matching CREATE TABLE IF NOT EXISTS in base/character_paragon_panel_learned.sql for fresh installs. mod-paragon conf: - New Paragon.Diag.PanelLearn flag traces every PanelLearnSpellChain commit (chain ids, before/after spell-map sizes, side-spell classification) for diagnosing "spell reappears on relog" bugs. Co-authored-by: Cursor <cursoragent@cursor.com> |
||
|
|
df7e943a74 |
Paragon: move module SQL to AC's data/sql/db-* layout for auto-update
AzerothCore's DBUpdater scans modules/<mod>/data/sql/db-{world,characters,auth}/
(see src/server/database/Updater/UpdateFetcher.cpp). The previous
modules/mod-paragon/sql/{world,characters}/base/ layout was non-standard
and skipped by the updater, so a fresh deploy never had Paragon tables
created automatically.
Move all five SQL files into the standard layout. Files are idempotent
(CREATE TABLE IF NOT EXISTS plus a DELETE+INSERT for the cost table)
and now apply on every dbimport / worldserver start, recorded by hash
in <db>.updates so re-runs are skipped.
Update BUILD-NATIVE.md to drop the manual mysql import section, and
document the SQL layout in the mod-paragon README.
Co-authored-by: Cursor <cursoragent@cursor.com>
|
||
|
|
203356aca8 |
Paragon: AE/TE currency, Character Advancement commit/reset, panel SQL
- mod-paragon: Paragon_Essence addon channel (PARAA), commit queue, resets, spell chain learn with passive child tracking, silence-window hints for cascade learns, trainer exemptions for pet/portal trainers - SQL: character_paragon_panel_* tables, paragon_spell_ae_cost world data - Core: Player Paragon class talent learn hook; Trainer skip for Paragon where appropriate - Ignore local build-worldserver.log Co-authored-by: Cursor <cursoragent@cursor.com> |
||
|
|
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> |