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>
- 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>
- 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>
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>
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>
Paragon is a classless concept layered on top of WotLK class data: stock items and class glyphs gate equip / vendor visibility / loot rolls / AH 'usable' filter via ItemTemplate.AllowableClass, which never has the class-12 bit (0x800). Bypassing the gate at the five enforcement sites lets Paragon equip any class-restricted item -- including class glyphs, since EffectApplyGlyph itself has no class check beyond the item gate. Race / level / proficiency / skill / required-spell checks still apply, so Paragon can't skip baseline progression.
Co-authored-by: Cursor <cursoragent@cursor.com>
Player::LearnTalent enforces the column-arrow prereq (talentInfo->DependsOn)
even when called with command=true, so Character Advancement's commit path
was silently dropping any talent whose Talent.dbc row points to an unrelated
sibling -- e.g. Deep Wounds (depends on Improved Heroic Strike), Bloody
Vengeance (depends on Dark Conviction), Expose Weakness (depends on Lethal
Shots). Players spent points in the panel, hit Learn All, and the talent
silently never reached addTalent / OnPlayerLearnTalents -- the snapshot came
back without it and the client repainted the points as "unspent."
The Character Advancement panel gates progression via AE/TE essence cost,
not via the spec-tree column arrows, so the DependsOn rule doesn't apply to
class 12. Skip it for Paragon, mirroring the existing class-mask bypass a
few lines above.
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>
Use utf8mb4_unicode_ci in base SQL (MariaDB lacks utf8mb4_0900_ai_ci).
Add Updates.ExceptionShutdownDelay to dbimport.conf.dist to match
DBUpdater expectations.
- Parse real MariaDB version after MySQL 5.5.5 compatibility prefix for
DatabaseIncompatibleVersion checks.
- Relax client checks when building against MariaDB C connector
(MARIADB_VERSION_ID); keep Oracle MySQL 8.0+ rules otherwise.
- Use mysql_stmt_bind_param on MariaDB; mysql_stmt_bind_named_param only for
MySQL 8.3+ without MariaDB headers.
- SSL: MYSQL_OPT_SSL_ENFORCE on MariaDB connector, MYSQL_OPT_SSL_MODE elsewhere.
- Track custom_script_loader.cpp so static script link succeeds; CMake
find_package(MySQL) requires COMPONENTS lib on CMake 3.16.