fix: resolve sync inflation, signature mismatch, CP accuracy, auto-buy cap, unlock hints
Security Scan and Upload / Security & DefectDojo Upload (pull_request) Successful in 1m3s
CI / Lint, Build & Test (pull_request) Failing after 1m8s

- #147: Guard all patch functions with hasChanged before incrementing
  sync counter to prevent inflation on no-op patches
- #148: Clear stale HMAC signature after each boss fight so subsequent
  auto-saves do not send a mismatched signature
- #146: Auto-unlock adventurer-specific upgrades in applyTick when
  their adventurer count > 0; show recruit hint in upgrade panel
- #149: Add Essence/s row to resource bar dropdown
- #150: Fix broken auto-quest CP reduce formula; centralise via
  computePartyCombatPower which applies all multipliers correctly
- #151: Cap auto-buy at 100 for non-max-tier adventurers; max tier
  (highest level unlocked) remains uncapped
- #152: Export computePartyCombatPower from tick, applying global
  upgrades, prestige, equipment, set bonuses, echo, crafted, and
  companion multipliers; use it in resource bar and boss panel
This commit is contained in:
2026-03-25 16:47:53 -07:00
committed by Naomi Carrigan
parent b6e218167d
commit 4c297f1ce1
6 changed files with 315 additions and 88 deletions
+28 -7
View File
@@ -58,6 +58,7 @@ import {
RESOURCE_CAP,
applyTick,
calculateClickPower,
computePartyCombatPower,
} from "../engine/tick.js";
import { updateChallengeProgress } from "../utils/dailyChallenges.js";
import { formatNumber as formatNumberUtil } from "../utils/format.js";
@@ -1078,11 +1079,7 @@ export const GameProvider = ({
return q.status === "active";
});
if (!hasActiveQuest) {
// eslint-disable-next-line unicorn/no-array-reduce -- Need the total!
const partyCombatPower = next.adventurers.reduce((total, a) => {
const power = total + a.combatPower;
return power * a.count;
}, 0);
const partyCombatPower = computePartyCombatPower(next);
const zoneOrder = new Map(
next.zones.map((z, index) => {
return [ z.id, index ];
@@ -1120,14 +1117,31 @@ export const GameProvider = ({
next.autoAdventurer === true
&& next.prestige.purchasedUpgradeIds.includes("auto_adventurer")
) {
const maxAdventurerLevel = Math.max(
...next.adventurers.
filter((a) => {
return a.unlocked;
}).
map((a) => {
return a.level;
}),
);
const autoBuyCap = 100;
const [ bestAdventurer ] = next.adventurers.
filter((adventurer) => {
const cost
= adventurer.baseCost * Math.pow(1.15, adventurer.count);
return adventurer.unlocked && next.resources.gold >= cost;
const isMaxTier = adventurer.level === maxAdventurerLevel;
const withinCap
= isMaxTier || adventurer.count < autoBuyCap;
return (
adventurer.unlocked
&& next.resources.gold >= cost
&& withinCap
);
}).
sort((adventurerA, adventurerB) => {
return adventurerB.combatPower - adventurerA.combatPower;
return adventurerB.level - adventurerA.level;
});
if (bestAdventurer !== undefined) {
const purchaseCost
@@ -1346,6 +1360,13 @@ export const GameProvider = ({
}
return afterBoss;
});
/*
* Boss fight modifies server state; clear stale signature so
* the next pre-save or auto-save does not send a mismatched one.
*/
signatureReference.current = null;
localStorage.removeItem("elysium_save_signature");
setAutoBossLastResult({
at: Date.now(),
bossName: bossName,