fix: real-time companion unlocks, persist exploration endsAt, correct auto-prestige formula, and quest balance
Security Scan and Upload / Security & DefectDojo Upload (pull_request) Successful in 1m3s
CI / Lint, Build & Test (pull_request) Failing after 1m13s

Closes #191
Closes #205
Closes #206
Closes #212
Closes #214
Closes #216
Closes #224
This commit is contained in:
2026-04-06 13:39:35 -07:00
committed by Naomi Carrigan
parent 69579e166a
commit 99ca3083a1
4 changed files with 82 additions and 14 deletions
+54 -2
View File
@@ -22,6 +22,7 @@ import {
type NumberFormat,
type Quest,
type TranscendenceResponse,
computeUnlockedCompanionIds,
isStoryChapterUnlocked,
} from "@elysium/types";
import {
@@ -72,7 +73,6 @@ import { playSound } from "../utils/sound.js";
const autoSaveIntervalMs = 30_000;
const autoPrestigeThresholdBase = 1_000_000;
const autoPrestigeThresholdScale = 5;
/**
* Pure function — applies a boss challenge result to the game state.
@@ -1119,6 +1119,57 @@ export const GameProvider = ({
});
}, [ state ]);
// Detect newly unlocked companions whenever relevant state changes
useEffect(() => {
if (state === null) {
return;
}
const computedUnlocks = computeUnlockedCompanionIds({
apotheosisCount: state.apotheosis?.count ?? 0,
lifetimeBossesDefeated: state.player.lifetimeBossesDefeated,
lifetimeGoldEarned: state.player.lifetimeGoldEarned,
lifetimeQuestsCompleted: state.player.lifetimeQuestsCompleted,
prestigeCount: state.prestige.count,
transcendenceCount: state.transcendence?.count ?? 0,
});
const currentUnlocks = state.companions?.unlockedCompanionIds ?? [];
const toAdd = computedUnlocks.filter((id) => {
return !currentUnlocks.includes(id);
});
if (toAdd.length === 0) {
return;
}
setState((previous) => {
if (previous === null) {
return previous;
}
const existingUnlocks = previous.companions?.unlockedCompanionIds ?? [];
const addedIds = computedUnlocks.filter((id) => {
return !existingUnlocks.includes(id);
});
if (addedIds.length === 0) {
return previous;
}
const updatedUnlocks = [ ...existingUnlocks, ...addedIds ];
const activeId = previous.companions?.activeCompanionId ?? null;
const validatedActiveId
= activeId !== null && updatedUnlocks.includes(activeId)
? activeId
: null;
return {
...previous,
companions: {
activeCompanionId: validatedActiveId,
unlockedCompanionIds: updatedUnlocks,
},
};
});
}, [ state ]);
// Game loop via requestAnimationFrame
useEffect(() => {
@@ -1347,7 +1398,8 @@ export const GameProvider = ({
&& autoState.prestige.autoPrestigeEnabled === true
&& autoState.player.totalGoldEarned
>= autoPrestigeThresholdBase
* Math.pow(autoPrestigeThresholdScale, autoState.prestige.count)
* Math.pow(autoState.prestige.count + 1, 2.5)
* (autoState.transcendence?.echoPrestigeThresholdMultiplier ?? 1)
) {
isAutoPrestigingReference.current = true;
void prestigeApi({}).