Production origin used github.com:Dawnforger/Fractured; extend auto-migration
to match that legacy mirror (and tighten regex to repo name suffix).
Co-authored-by: Cursor <cursoragent@cursor.com>
Players on the old DDNS host can fetch this build from there once, then
patches and launcher updates use https://git.hisora.dev (Dawnsorrow/Fractured-Distro).
Co-authored-by: Cursor <cursoragent@cursor.com>
Rewrite start-azeroth-servers.sh to launch auth/worldserver in named
tmux sessions instead of nohup/disown. Add kill-azeroth-servers.sh to
tear down sessions and stray processes. Update vps-update-server.sh
with a --restart flag that stops servers before compile and restarts
them in tmux after.
Co-authored-by: Cursor <cursoragent@cursor.com>
The m_additionalSaveTimer was never processed in the update loop, so quick
partial saves after important events (rare+ item pickups, quest completions)
never fired. This caused players to lose progress on disconnect/crash since
only the 15-minute full autosave protected them.
- Add m_additionalSaveTimer tick logic to Player::Update
- Reduce default PlayerSaveInterval from 900000 (15 min) to 300000 (5 min)
Co-authored-by: Cursor <cursoragent@cursor.com>
- Allow multiple Devouring Plague DoTs on different targets (core + DK script).
- Warrior stance and DK presence clone spells for Character Advancement; spellbook SkillLineAbility rows and aura/shapeshift attribute fixes.
- World SQL updates 2026_05_12_02 through 07 (mod-paragon db-world).
Client patch-enUS-4/5/6 and Wow.exe ship on the matching GitHub Release (not in repo).
Co-authored-by: Cursor <cursoragent@cursor.com>
Lets the Paragon class buy Runeforging from the Character Advancement
panel and apply rune enchants from anywhere in the world without needing
to be near a runeforge GameObject. Three carve-outs work together:
* Spell.cpp: bypass the SpellFocusObject GO proximity check when the
caster is a Paragon and the spell belongs to SKILL_RUNEFORGING (776).
Stock DK behaviour is unchanged -- the bypass is gated on
getClass() == CLASS_PARAGON, not on the IsClass() context hook.
* Player.cpp: skip the Paragon class-skill cascade block for skill 776
so the rune-enchant SLA cascade actually fires. Without this the
player gets the Runeforging skill but no rune options at the anvil.
* Paragon_Essence.cpp:
- Treat SKILL_RUNEFORGING children as a meta-skill cluster: cascade
them like passives even though they're active casts, so they stick
as panel_spell_children and get cleaned up via the standard refund
path.
- Whitelist the 8 basic rune-enchants in PruneSkillLineCascadeChildren
so they don't get evicted as "active in children = legacy garbage".
- Force-attach them in PanelLearnSpellChain (the SLA rows ship with
AcquireMethod=0, so the engine cascade alone won't grant them).
- Add an OnPlayerLogin fixup so existing Paragons who bought
Runeforging before this change get the 8 runes retro-granted.
- Stop filtering SPELL_ATTR0_DO_NOT_DISPLAY in PushSpellSnapshot --
Runeforging itself is hidden in the DBC but is a real panel
purchase that must show in the Overview tab.
The two advanced runes (Stoneskin Gargoyle, Nerubian Carapace) are
intentionally excluded from the auto-grant -- retail gates them behind
heroic dungeon / raid item drops and the SLA AcquireMethod=0 honours
that gating.
No SQL migration needed; works against existing DBC + SLA data.
Co-authored-by: Cursor <cursoragent@cursor.com>
Server-side batch following v0.7.18, all gated to Paragon (or applied
server-wide where the design discussion called for it):
* Cross-class stance / form / presence / aspect exclusivity (server-wide).
New `IsFracturedExclusiveStanceSpell()` (`Unit.cpp`/`Unit.h`) returns
true for the union of warrior stances + druid forms (combat AND utility:
Travel, Aquatic, Flight, Swift Flight) + Ghost Wolf + base Stealth +
Shadowform + Metamorphosis + DK Presences + Hunter Aspects (combat AND
utility: Cheetah, Pack). `Aura::CanStackWith` (`SpellAuras.cpp`) refuses
to stack two spells from this set, which routes through
`_RemoveNoStackAurasDueToAura` to drop the older aura -- the same
mechanism Battle Elixirs / Curses use. Plugs the stock-AC gap where DK
Presences and Hunter Aspects (regular auras, just rendered in the
stance bar) coexisted with engine-shapeshifts.
* Stances / Presences / Aspects cancellable like Druid forms.
`SpellInfoCorrections.cpp` now zeroes `CategoryEntry` on warrior
stances, DK presences, and every rank of every hunter aspect (moves
them out of SpellCategory 47 "Combat States", which gates the client's
right-click / `/cancelaura` path), AND clears `AttributesEx6` bit
`0x1000` on warrior stances + DK presences (a second client-UI gate
surfaced via DBC diff -- aspects don't have it set). Mirrored client-
side by `_patch_spell_dbc_presences_cancelable.py`. Aspects / presences
do NOT swap action bars (those are owned by `SPELL_AURA_MOD_SHAPESHIFT`,
not by Category / AttrEx6) -- only warrior stances and druid forms keep
the bar swap, matching the design requirement that presences/aspects
not change the player's action bar.
* Hunter ammo soft-fail (server-wide).
Replaced both `SPELL_FAILED_NO_AMMO` returns in `Spell::CheckCast` with
`break;` so ranged + thrown abilities cast through with zero ammo;
`_ApplyAmmoBonuses` continues to gate the actual arrow/bullet DPS bonus
on a non-empty stack, so equipping ammo still pays off. New programmatic
`ApplySpellFix`-style block in `SpellInfoCorrections.cpp` iterates every
Hunter-family spell whose `EquippedItemClass == ITEM_CLASS_WEAPON` and
`EquippedItemSubClassMask` includes Bow/Gun/Crossbow and sets
`EquippedItemClass = -1` (skipping a small DENYLIST of Quiver / Ammo
Pouch passive haste auras + Aynasha's Bow + Legendary Bow Haste -- those
are item-equip-driven and must keep gating on the ranged weapon being
equipped). Server log: ">> Fractured: dropped EquippedItemClass on 196
hunter shot abilities". Mirrored client-side by the new
`_patch_spell_dbc_hunter_ammo.py` so the 3.3.5a client preflight stops
blocking the cast packet with "Ammo needs to be in the paper doll ammo
slot before it can be fired." `Spell::TakeAmmo` no longer clears
`PLAYER_AMMO_ID` to 0 when the bag empties (defense in depth so a half-
deployed pair degrades to soft-fail rather than hard-reject). Adds
`#include "ItemTemplate.h"` for `ITEM_SUBCLASS_WEAPON_*`.
* Feral Cat scaling (server-wide, cat-only).
`StatSystem.cpp` `UpdateAttackPowerAndDamage` FORM_CAT branch doubles
the AGI coefficient (1.0 -> 2.0). `SpellAuraEffects.cpp` Master
Shapeshifter FORM_CAT branch doubles the talent's bp before triggering
48420 (R1: 2% -> 4% crit, R2: 4% -> 8%). FORM_BEAR / FORM_DIREBEAR /
FORM_MOONKIN / FORM_TREE branches all left untouched so bear stays
"already fine" per the resident Feral expert. Client tooltip drift on
Cat Form (768) + Master Shapeshifter (48411 / 48412) + Pestilence
(50842) handled by `_patch_spell_dbc_feral_tooltips.py`.
* Pestilence spreads / refreshes Devouring Plague for Paragon casters.
`spell_dk.cpp` `spell_dk_pestilence::HandleScriptEffect` now also
spreads (and Glyph-of-Disease refreshes) Priest Devouring Plague when
`IsParagonWildcardCaller(caster)`. Uses `GetAuraOfRankedSpell(2944)` so
the spread copy carries the caster's actual rank. Stock DKs cannot
cast Devouring Plague at all, so this branch is a no-op for them.
* Dancing Rune Weapon: Paragon copies melee, not casts.
`spell_dk.cpp` `spell_dk_dancing_rune_weapon::CheckProc` for Paragon
callers requires `eventInfo.GetDamageInfo()` and
`spellInfo->DmgClass == SPELL_DAMAGE_CLASS_MELEE`, so the ghostly
weapon now copies cross-class melee strikes (Hamstring, Sinister Strike,
Heart Strike, Frost Strike, ...) and auto-attacks instead of re-casting
the DK's nukes. Stock DK gating below is untouched.
* Maelstrom Weapon: drop Arcane Blast from the allowlist.
`SpellInfo.cpp` and `spell_shaman.cpp` allowlists now match Fireball
and Frostbolt only -- Arcane Blast stacked with its own self-buff was
too potent.
* `BALANCE-TODO.md` added under `contrib/fractured-dev-extras/` to
capture the resident Feral expert's recommendation, the levers we
considered, and the cat-only Master-Shapeshifter / AGI-doubling
resolution we shipped, plus the next-lever knobs if field reports
still flag cat as weak.
DBC patcher pipeline (lives outside the repo in `fractured-tooling/`)
documented run order: runes -> reagents -> stances -> presences_cancelable
-> hunter_ammo -> feral_tooltips -> _make_paragon_dbc_patch.
No SQL migrations.
Co-authored-by: Cursor <cursoragent@cursor.com>
Start script now defaults to /home/fractured-panel/azeroth-server and
passes -c flags so binaries find configs regardless of compiled-in path.
Update script gains --prefix flag to override CMAKE_INSTALL_PREFIX
(persisted to conf/config.sh) during rebuild.
Co-authored-by: Cursor <cursoragent@cursor.com>
* 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>
Cross-class wildcard now also relaxes the EquippedItemSubClassMask
gate on weapon-class proc talents so e.g. Maelstrom Weapon procs
from any weapon a Paragon has equipped, not just the talent's stock
melee subset (axe / mace / staff / fist / dagger / 2H sword/axe/mace).
Three independent gates run in the proc chain; all three needed the
bypass for the proc to actually fire:
- Player::HasItemFitToSpellRequirements -- talent-attach check at
item-equip / login time. Without this the passive talent aura
never even applies for a Paragon wielding a non-stock weapon.
- Player::CheckAttackFitToAuraRequirement -- per-swing match the
proc engine uses to decide whether attackType + weapon is
compatible with the aura's EquippedItemClass / SubClassMask.
- Aura::IsProcTriggeredOnEvent (SpellAuras.cpp) -- per-event proc
evaluator that calls Item::IsFitToSpellRequirements again,
independently of the previous two. Was the proc-killing gate
before this commit: talent attached, swing matched, but this
evaluator returned 0 charges for any weapon outside the stock
subclass mask, so no stack was ever applied.
All three bypasses are gated on:
- IsParagonWildcardCaller(this) (player class 12 + config flag
Paragon.WildcardFamilyMatching = 1).
- spellInfo->EquippedItemClass == ITEM_CLASS_WEAPON. ARMOR-class
gates (shield) are deliberately left alone -- shield-required
talents (Shield Specialization, Shield Block, etc.) still need
an actual shield equipped.
Each bypass also requires *some* weapon to be in the relevant slot
(MAINHAND / OFFHAND / RANGED). Unarmed Paragons do not auto-activate
every weapon-gated talent in the game.
Net effect for Paragon characters with Maelstrom Weapon talented:
proc fires from any melee weapon -- 1H sword / polearm / spear /
fist / dagger / staff / 2H weapons / axes / maces. Stock Shamans
and every other non-Paragon class are unchanged.
Caveat (not addressed by this commit): the talent's stock ProcFlags
(0xC00014) only fire on melee swings + melee abilities. Ranged
auto-attacks (bow / gun / crossbow / wand) fire
PROC_FLAG_DONE_RANGED_AUTO_ATTACK (0x40), which the proc engine
never matches against this talent, so the new weapon-subclass
bypass is moot for those weapons. Adding ranged-auto-attack support
would require a Paragon-only ProcFlags expansion at the proc
engine layer; deferred until requested.
Co-authored-by: Cursor <cursoragent@cursor.com>
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>
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>
- 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>
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>
- 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>
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>
- 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>
- 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>
- 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>
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>
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>
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>
- 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>
- 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>
- 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>
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>