fix: adventurer unlocks not applied by force-unlock tool (#93)
Security Scan and Upload / Security & DefectDojo Upload (push) Successful in 1m3s
CI / Lint, Build & Test (push) Successful in 1m10s

The force-unlock debug route now scans completed quests for adventurer rewards and ensures those tiers are marked as unlocked in game state.

The UI and API response type both surface the new `adventurersUnlocked` count alongside the existing zone/quest/boss/exploration counts.

Closes #88

 This PR was created with help from Hikari~ 🌸

Reviewed-on: #93
Co-authored-by: Hikari <hikari@nhcarrigan.com>
Co-committed-by: Hikari <hikari@nhcarrigan.com>
This commit was merged in pull request #93.
This commit is contained in:
2026-03-20 10:28:17 -07:00
committed by Naomi Carrigan
parent bb60ae3390
commit 635c630e49
5 changed files with 442 additions and 27 deletions
+44 -23
View File
@@ -12,6 +12,49 @@ import { ConfirmationModal } from "../ui/confirmationModal.js";
type ActiveModal = "force-unlocks" | "hard-reset" | null;
interface ForceUnlocksResult {
adventurersUnlocked: number;
bossesUnlocked: number;
equipmentUnlocked: number;
explorationUnlocked: number;
questsUnlocked: number;
storyUnlocked: number;
upgradesUnlocked: number;
zonesUnlocked: number;
}
/**
* Builds a human-readable summary of what the force-unlock operation corrected.
* @param result - The counts returned by the force-unlock operation.
* @returns A message string describing what was fixed, or a confirmation that nothing needed fixing.
*/
const buildForceUnlocksMessage = (result: ForceUnlocksResult): string => {
const entries: Array<[ number, string ]> = [
[ result.zonesUnlocked, "zone(s)" ],
[ result.questsUnlocked, "quest(s)" ],
[ result.bossesUnlocked, "boss(es)" ],
[ result.explorationUnlocked, "exploration area(s)" ],
[ result.adventurersUnlocked, "adventurer tier(s)" ],
[ result.upgradesUnlocked, "upgrade(s)" ],
[ result.equipmentUnlocked, "equipment item(s)" ],
[ result.storyUnlocked, "story chapter(s)" ],
];
const parts = entries.
filter(([ count ]) => {
return count > 0;
}).
map(([ count, label ]) => {
return `${String(count)} ${label}`;
});
if (parts.length === 0) {
return "Everything looks correct — no missing unlocks were found.";
}
const total = entries.reduce((sum, [ count ]) => {
return sum + count;
}, 0);
return `Fixed ${String(total)} unlock(s): ${parts.join(", ")}.`;
};
/**
* Renders the debug panel with tools for fixing stuck game state.
* @returns The JSX element.
@@ -38,29 +81,7 @@ const DebugPanel = (): JSX.Element => {
setActiveModal(null);
void (async(): Promise<void> => {
const result = await forceUnlocks();
const parts: Array<string> = [];
if (result.zonesUnlocked > 0) {
parts.push(`${String(result.zonesUnlocked)} zone(s)`);
}
if (result.questsUnlocked > 0) {
parts.push(`${String(result.questsUnlocked)} quest(s)`);
}
if (result.bossesUnlocked > 0) {
parts.push(`${String(result.bossesUnlocked)} boss(es)`);
}
if (result.explorationUnlocked > 0) {
parts.push(`${String(result.explorationUnlocked)} exploration area(s)`);
}
const total
= result.zonesUnlocked
+ result.questsUnlocked
+ result.bossesUnlocked
+ result.explorationUnlocked;
const message
= parts.length === 0
? "Everything looks correct — no missing unlocks were found."
: `Fixed ${String(total)} unlock(s): ${parts.join(", ")}.`;
setForceUnlocksResult(message);
setForceUnlocksResult(buildForceUnlocksMessage(result));
})();
}
+12
View File
@@ -558,9 +558,13 @@ interface GameContextValue {
* @returns Counts of what was corrected.
*/
forceUnlocks: ()=> Promise<{
adventurersUnlocked: number;
bossesUnlocked: number;
equipmentUnlocked: number;
explorationUnlocked: number;
questsUnlocked: number;
storyUnlocked: number;
upgradesUnlocked: number;
zonesUnlocked: number;
}>;
@@ -2104,9 +2108,13 @@ export const GameProvider = ({
localStorage.setItem("elysium_save_signature", data.signature);
}
return {
adventurersUnlocked: data.adventurersUnlocked,
bossesUnlocked: data.bossesUnlocked,
equipmentUnlocked: data.equipmentUnlocked,
explorationUnlocked: data.explorationUnlocked,
questsUnlocked: data.questsUnlocked,
storyUnlocked: data.storyUnlocked,
upgradesUnlocked: data.upgradesUnlocked,
zonesUnlocked: data.zonesUnlocked,
};
} catch (error_: unknown) {
@@ -2116,9 +2124,13 @@ export const GameProvider = ({
: "Failed to force unlocks",
);
return {
adventurersUnlocked: 0,
bossesUnlocked: 0,
equipmentUnlocked: 0,
explorationUnlocked: 0,
questsUnlocked: 0,
storyUnlocked: 0,
upgradesUnlocked: 0,
zonesUnlocked: 0,
};
}