feat: v1 prototype — core game systems #30

Merged
naomi merged 84 commits from feat/prototype into main 2026-03-08 15:53:39 -07:00
Showing only changes of commit c40ec41dd6 - Show all commits
+32 -2
View File
@@ -10,7 +10,7 @@ import { DEFAULT_BOSSES } from "../data/bosses.js";
import { DEFAULT_EQUIPMENT } from "../data/equipment.js";
import { DEFAULT_EQUIPMENT_SETS } from "../data/equipmentSets.js";
import { DEFAULT_EXPLORATIONS } from "../data/explorations.js";
import { INITIAL_EXPLORATION } from "../data/initialState.js";
import { INITIAL_EXPLORATION, INITIAL_GAME_STATE } from "../data/initialState.js";
import { DAILY_REWARDS } from "../data/loginBonus.js";
import { DEFAULT_QUESTS } from "../data/quests.js";
import { authMiddleware } from "../middleware/auth.js";
@@ -364,7 +364,37 @@ gameRouter.get("/load", async (context) => {
]);
if (!record) {
return context.json({ error: "No save found" }, 404);
// No save found — create a fresh state (handles nuked DB or first-time load race)
if (!playerRecord) {
return context.json({ error: "No player found" }, 404);
}
const freshState = INITIAL_GAME_STATE(
{
discordId: playerRecord.discordId,
username: playerRecord.username,
discriminator: playerRecord.discriminator,
avatar: playerRecord.avatar,
characterName: playerRecord.characterName,
createdAt: playerRecord.createdAt,
lastSavedAt: Date.now(),
totalGoldEarned: 0,
totalClicks: 0,
lifetimeGoldEarned: playerRecord.lifetimeGoldEarned,
lifetimeClicks: playerRecord.lifetimeClicks,
lifetimeBossesDefeated: playerRecord.lifetimeBossesDefeated,
lifetimeQuestsCompleted: playerRecord.lifetimeQuestsCompleted,
lifetimeAdventurersRecruited: playerRecord.lifetimeAdventurersRecruited,
lifetimeAchievementsUnlocked: playerRecord.lifetimeAchievementsUnlocked,
},
playerRecord.characterName,
);
const createdAt = Date.now();
await prisma.gameState.create({
data: { discordId, state: freshState as object, updatedAt: createdAt },
});
const secret = process.env.ANTI_CHEAT_SECRET;
const signature = secret ? computeHmac(JSON.stringify(freshState), secret) : undefined;
return context.json({ state: freshState, offlineGold: 0, offlineEssence: 0, offlineSeconds: 0, signature, loginBonus: null, loginStreak: playerRecord.loginStreak ?? 1 });
}
const state = record.state as unknown as GameState;