Commit Graph

78 Commits

Author SHA1 Message Date
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>
v0.7.15-paragon-cross-class
2026-05-11 01:25:18 -04:00
Docker Build b408c8a95d Add script to start auth and world servers detached from SSH
Runs authserver then worldserver from /root/azeroth-server/bin by default,
kills existing instances, and uses nohup/disown so processes survive logout.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-11 00:15:36 -05:00
Docker Build f88a303327 feat(launcher): Linux play wrapper, patch UX, Gitea sync cleanup
- Play on Linux: use launch.linux_wrapper (wine) or linux_steam_uri; chmod .exe after install
- Windows: retry EBUSY on MPQ replace; download to .new before rename
- After successful sync: remove .bak-* backups; realmlist only Data/enUS (ignore enGB)
- Gitea/distro merge: skip Fractured-Launcher* from GitHub assets (CI default-branch build wins)
- Omit blockmap and builder-debug from staged artifacts and Gitea uploads; upload script validates before clearing attachments
- README and launcher version 1.0.12

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-10 23:20:22 -05:00
Docker Build 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>
v0.7.14-paragon-talent-search v0.7.13-paragon-cascade-guard
2026-05-10 23:53:13 -04:00
Docker Build 36ac3dbd1d fix(launcher): force .MPQ extension uppercase on disk for WoW compatibility
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-10 22:09:01 -05:00
Docker Build 24d1ae71d9 fix(launcher): install release MPQs under Data/enUS (not Data root)
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-10 22:06:48 -05:00
Docker Build 9cef99f0ff feat(launcher): sync release assets from manifest or attachment list (no fixed exe name)
- default files []: resolve sync list from patch-manifest keys, else discover
  release attachments (exclude launcher artifacts).
- Explicit files[] still overrides; strip deprecated Wow-patched.exe on merge.
- listReleaseAttachmentNames + fetchGiteaReleaseRecord helpers.
- Version 1.0.7; README config docs.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-10 22:04:48 -05:00
Docker Build f409ffad12 fix(launcher): Gitea http URL; Wine Z: path + Wow.exe case check
- baked-gitea-channel: http:// for brassnet mirror.
- win-game-dir: map Unix /home/... to Z:\ under win32 (Wine folder picker).
- resolveGameDir + saveGameDir + patch paths use it; Wow.exe resolved case-insensitively.
- Version 1.0.6; README checklist for Wine.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-10 21:54:04 -05:00
Docker Build c1f7eaa153 fix(launcher): clearer fetch errors for Gitea TLS/DNS (fetch failed)
- fetchOrThrow wraps global fetch with TLS/DNS/refused hints + URL (sanitized).
- Use in gitea-release, github paths; fetchToFile already benefits.
- README checklist for sync Wow.exe fetch failed; version 1.0.5.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-10 21:46:48 -05:00
Docker Build b455db0db8 fix(launcher): drop patch-Z.MPQ from default files and migrate old configs
- default-launcher.json files: only Wow-patched.exe from release.
- config-store: strip deprecated patch-Z.MPQ from merged files; rewrite
  launcher.json on load if user still had that entry.
- Docs/scripts examples updated; version 1.0.4.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-10 21:36:50 -05:00
Docker Build 1fb284cb5c docs(launcher): clarify userData path wording for Linux config
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-10 21:33:07 -05:00
Docker Build ebd8d81924 fix(launcher): Linux/macOS packaged config in userData (AppImage EROFS)
AppImage mounts read-only at /tmp/.mount_*; writing launcher.json beside
execPath failed. Use app.getPath('userData') for linux/darwin when packaged.
Bump version to 1.0.3.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-10 21:32:43 -05:00
Docker Build 362084b829 ci(gitea-sync): validate workflow_dispatch tag; reject release title as ref
- Trim input; fail fast if tag contains whitespace (common mistake: pasting
  release title instead of git tag).
- Multiline GITHUB_OUTPUT for tag value safety.
- README checklist + input description clarify tag vs title.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-10 21:21:45 -05:00
Docker Build 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>
v0.7.12-paragon-cascade-passives
2026-05-10 22:20:13 -04:00
Docker Build bfe51f6ad4 docs(launcher): note manual Windows pack for local test
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-10 20:50:16 -05:00
Docker Build 2a3107a78d feat(launcher): Linux AppImage 1.0.2, Gitea sync + CI, manual pack script
- Add pack:linux (AppImage x64), linux/appImage artifact names in package.json.
- Gitea sync: parallel build-electron-linux, merge Windows+Linux into Gitea upload;
  rename Windows artifact to electron-dist-windows.
- Fractured launcher CI: electron-launcher-windows + electron-launcher-linux jobs.
- scripts/manual-pack-linux.sh for local test builds from current tree.
- Normalize Gitea base_url (prepend https if missing); baked channel uses full URL.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-10 20:50:06 -05:00
Docker Build 48826e21d6 refactor(launcher): hardcode Gitea channel in lib/baked-gitea-channel.js
- Merge baked base_url/owner/repo/release_tag at load time (no inject script,
  no fractured-release-channel.json, no CI env for pack).
- Fix mergeConfig deep-merge for gitea, patch_manifest, launcher_updates_from_github.
- Remove inject-release-channel.js and fractured-release-channel.json.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-10 20:15:38 -05:00
Docker Build 15c476c12d ci(gitea-sync): overlay launcher from default branch before pack
Release tags can point at commits older than launcher lib additions; building
only from the tag omitted gitea-release.js etc. Fetch default branch and
checkout tools/fractured-launcher-electron from it before npm ci/pack.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-10 19:15:27 -05:00
Docker Build 6c4d7244c3 fix(launcher): add missing gitea-release and patch-manifest to repo
These modules were required by main.js / auto-update.js / github.js but never
committed, so packaged builds lacked them and crashed at startup.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-10 19:08:55 -05:00
Docker Build 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>
v0.7.11-paragon-unlearn-reconcile
2026-05-10 19:57:47 -04:00
Docker Build 7028258084 feat(launcher): bake Gitea base_url/owner/repo into pack from env or channel file
- inject-release-channel.js merges GITEA_* (or fractured-release-channel.json) into
  default-launcher.json before electron-builder.
- CI passes existing GITEA_BASE_URL/OWNER/REPO secrets into the Windows pack job.
- npm run pack:win/publish:win run the injector; workflows use npm run pack:win.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-10 17:33:28 -05:00
Docker Build 5966eb0ffc scripts: document default mysql acore/acore for FRACTURED_MYSQL example
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-10 16:24:37 -05:00
Docker Build 90c8db0b04 scripts: tee vps-paragon-diagnostics output to var/vps-paragon-diagnostics-last.txt
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-10 15:57:54 -05:00
Docker Build 9240bf1243 scripts: clarify empty spell_dbc samples; add version + rune override probes
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-10 15:53:57 -05:00
Docker Build 88f8dcb0e7 scripts: extend vps-paragon-diagnostics for rune/RP DBC and binary parity
- Binary sha256 + revision-like strings for dev vs VPS compare
- worldserver.conf Rate.RunicPower and mod_paragon.conf Paragon.* keys
- MySQL: chrclasses_dbc 6/12, spell_dbc sample, spellrunecost join
- FRACTURED_SPELL_IDS override for custom spell spot-checks

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-10 15:46:35 -05:00
Docker Build 9cb3c79dbe fix(launcher): opt-in GitHub auto-update; clarify Gitea for from_release
- Gate electron-updater GitHub provider on launcher_updates_from_github (default false)
  so GITHUB_TOKEN no longer targets the source repo without latest.yml.
- Improve GitHub releases 404 hint when assets are on Gitea.
- Document in README and default-launcher.json.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-10 15:38:07 -05:00
Docker Build 75e3b59442 chore(gitea): add bootstrap-gitea-repo.sh for initial README commit
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-10 15:29:07 -05:00
Docker Build 030c2307c2 scripts: add vps-paragon-diagnostics.sh for native VPS triage
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-10 15:19:59 -05:00
Docker Build 27d54f15a2 fix(gitea): document and explain HTTP 422 repo is empty on release create
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-10 14:37:02 -05:00
Docker Build 5e18c2b766 docs(ci): explain Re-run vs Run workflow for Gitea sync (GH_TOKEN error)
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-10 14:29:21 -05:00
Docker Build 1c85341b1f ci: disable electron-builder GitHub publish; add Gitea sync workflow
- Use --publish never in pack/CI so tagged builds do not require GH_TOKEN.
- Set build.publish to null and align publish:win with local-only packaging.
- Add Gitea release sync workflow and upload script; fetch script from default
  branch so reruns work for tags that predate the script.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-10 14:24:42 -05:00
Docker Build 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>
v0.7.10-paragon-save-current
2026-05-10 15:12:12 -04:00
Docker Build 377927b878 chore(launcher): Electron-only distro, CI sync with Windows pack 2026-05-10 12:34:43 -05:00
Docker Build 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>
v0.7.9-paragon-builds-qol
2026-05-10 04:15:11 -04:00
Docker Build 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>
v0.7.8-paragon-builds
2026-05-10 02:35:55 -04:00
Docker Build 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>
v0.7.7-paragon-pet-client-ws
2026-05-10 01:36:54 -04:00
Docker Build 7a92231614 Add scripts/vps-update-server.sh for native VPS git pull and compile
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-09 21:42:38 -05:00
Docker Build 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>
v0.7.6-paragon-client-data
2026-05-09 22:38:32 -04:00
Docker Build 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>
2026-05-09 20:39:23 -04:00
Docker Build 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>
v0.7.5-paragon-fixes
2026-05-09 17:37:08 -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
Docker Build a212717c37 docs: note tooltip 'Classes:' patcher in patch-enUS-5 description
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-09 16:08:19 -04:00
Docker Build 49cb354133 mod-paragon: ignore item AllowableClass for class 12 (gear + glyphs)
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>
2026-05-09 16:07:01 -04:00
Docker Build 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>
2026-05-09 15:54:39 -04:00
Docker Build 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>
2026-05-09 15:51:37 -04:00
Docker Build 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>
2026-05-09 15:44:42 -04:00
Docker Build 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>
2026-05-09 15:34:02 -04:00
Docker Build 8a0da95ed2 mod-paragon: bypass talent DependsOn check for Paragon class
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>
2026-05-09 15:16:30 -04:00
Docker Build 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>
2026-05-09 14:38:55 -04:00
Docker Build 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>
2026-05-09 13:38:27 -04:00