diff --git a/apps/api/prisma/schema.prisma b/apps/api/prisma/schema.prisma index d739288..b7c34e4 100644 --- a/apps/api/prisma/schema.prisma +++ b/apps/api/prisma/schema.prisma @@ -18,8 +18,14 @@ model Player { profileSettings Json? createdAt Float lastSavedAt Float - totalGoldEarned Float @default(0) - totalClicks Float @default(0) + totalGoldEarned Float @default(0) + totalClicks Float @default(0) + lifetimeGoldEarned Float @default(0) + lifetimeClicks Float @default(0) + lifetimeBossesDefeated Float @default(0) + lifetimeQuestsCompleted Float @default(0) + lifetimeAdventurersRecruited Float @default(0) + lifetimeAchievementsUnlocked Float @default(0) } model GameState { diff --git a/apps/api/src/routes/auth.ts b/apps/api/src/routes/auth.ts index 022d4e3..c1e6bc9 100644 --- a/apps/api/src/routes/auth.ts +++ b/apps/api/src/routes/auth.ts @@ -62,6 +62,12 @@ authRouter.get("/callback", async (context) => { lastSavedAt: player.lastSavedAt, totalGoldEarned: player.totalGoldEarned, totalClicks: player.totalClicks, + lifetimeGoldEarned: player.lifetimeGoldEarned, + lifetimeClicks: player.lifetimeClicks, + lifetimeBossesDefeated: player.lifetimeBossesDefeated, + lifetimeQuestsCompleted: player.lifetimeQuestsCompleted, + lifetimeAdventurersRecruited: player.lifetimeAdventurersRecruited, + lifetimeAchievementsUnlocked: player.lifetimeAchievementsUnlocked, }; const initialState = INITIAL_GAME_STATE(playerShape, playerShape.characterName); diff --git a/apps/api/src/routes/prestige.ts b/apps/api/src/routes/prestige.ts index 589d25f..5656a60 100644 --- a/apps/api/src/routes/prestige.ts +++ b/apps/api/src/routes/prestige.ts @@ -63,6 +63,12 @@ prestigeRouter.post("/", async (context) => { }, }; + // Capture current-run stats to accumulate into lifetime totals before resetting + const runBossesDefeated = state.bosses.filter((b) => b.status === "defeated").length; + const runQuestsCompleted = state.quests.filter((q) => q.status === "completed").length; + const runAdventurersRecruited = state.adventurers.reduce((sum, a) => sum + a.count, 0); + const runAchievementsUnlocked = (state.achievements ?? []).filter((a) => a.unlockedAt !== null).length; + const now = Date.now(); await prisma.gameState.update({ where: { discordId }, @@ -73,8 +79,16 @@ prestigeRouter.post("/", async (context) => { where: { discordId }, data: { characterName, + // Reset current-run counters totalGoldEarned: 0, totalClicks: 0, + // Accumulate into lifetime totals — never reset + lifetimeGoldEarned: { increment: state.player.totalGoldEarned }, + lifetimeClicks: { increment: state.player.totalClicks }, + lifetimeBossesDefeated: { increment: runBossesDefeated }, + lifetimeQuestsCompleted: { increment: runQuestsCompleted }, + lifetimeAdventurersRecruited: { increment: runAdventurersRecruited }, + lifetimeAchievementsUnlocked: { increment: runAchievementsUnlocked }, lastSavedAt: now, }, }); diff --git a/apps/api/src/routes/profile.ts b/apps/api/src/routes/profile.ts index ad93078..dc711ae 100644 --- a/apps/api/src/routes/profile.ts +++ b/apps/api/src/routes/profile.ts @@ -22,8 +22,14 @@ const parseProfileSettings = (raw: unknown): ProfileSettings => { return { showTotalGold: obj.showTotalGold !== false, showTotalClicks: obj.showTotalClicks !== false, - showPrestige: obj.showPrestige !== false, + showLifetimeBossesDefeated: obj.showLifetimeBossesDefeated !== false, + showLifetimeQuestsCompleted: obj.showLifetimeQuestsCompleted !== false, + showLifetimeAdventurersRecruited: obj.showLifetimeAdventurersRecruited !== false, + showLifetimeAchievementsUnlocked: obj.showLifetimeAchievementsUnlocked !== false, showGuildFounded: obj.showGuildFounded !== false, + showCurrentGold: obj.showCurrentGold !== false, + showCurrentClicks: obj.showCurrentClicks !== false, + showPrestige: obj.showPrestige !== false, showBossesDefeated: obj.showBossesDefeated !== false, showQuestsCompleted: obj.showQuestsCompleted !== false, showAdventurersRecruited: obj.showAdventurersRecruited !== false, @@ -63,14 +69,22 @@ profileRouter.get("/:discordId", async (context) => { avatar: player.avatar ?? null, bio: player.bio ?? "", profileSettings, + createdAt: player.createdAt, + // All Time stats — cumulative across all runs, never reset + totalGoldEarned: player.lifetimeGoldEarned, + totalClicks: player.lifetimeClicks, + lifetimeBossesDefeated: player.lifetimeBossesDefeated, + lifetimeQuestsCompleted: player.lifetimeQuestsCompleted, + lifetimeAdventurersRecruited: player.lifetimeAdventurersRecruited, + lifetimeAchievementsUnlocked: player.lifetimeAchievementsUnlocked, + // Current Run stats — from live GameState, reset on prestige & transcendence + currentRunGold: state?.player.totalGoldEarned ?? 0, + currentRunClicks: state?.player.totalClicks ?? 0, prestigeCount, - totalGoldEarned: player.totalGoldEarned, - totalClicks: player.totalClicks, bossesDefeated, questsCompleted, adventurersRecruited, achievementsUnlocked, - createdAt: player.createdAt, }); }); @@ -86,8 +100,14 @@ profileRouter.put("/", authMiddleware, async (context) => { const profileSettings: ProfileSettings = { showTotalGold: body.profileSettings?.showTotalGold !== false, showTotalClicks: body.profileSettings?.showTotalClicks !== false, - showPrestige: body.profileSettings?.showPrestige !== false, + showLifetimeBossesDefeated: body.profileSettings?.showLifetimeBossesDefeated !== false, + showLifetimeQuestsCompleted: body.profileSettings?.showLifetimeQuestsCompleted !== false, + showLifetimeAdventurersRecruited: body.profileSettings?.showLifetimeAdventurersRecruited !== false, + showLifetimeAchievementsUnlocked: body.profileSettings?.showLifetimeAchievementsUnlocked !== false, showGuildFounded: body.profileSettings?.showGuildFounded !== false, + showCurrentGold: body.profileSettings?.showCurrentGold !== false, + showCurrentClicks: body.profileSettings?.showCurrentClicks !== false, + showPrestige: body.profileSettings?.showPrestige !== false, showBossesDefeated: body.profileSettings?.showBossesDefeated !== false, showQuestsCompleted: body.profileSettings?.showQuestsCompleted !== false, showAdventurersRecruited: body.profileSettings?.showAdventurersRecruited !== false, diff --git a/apps/web/src/components/game/EditProfileModal.tsx b/apps/web/src/components/game/EditProfileModal.tsx index 51d0514..d805dae 100644 --- a/apps/web/src/components/game/EditProfileModal.tsx +++ b/apps/web/src/components/game/EditProfileModal.tsx @@ -8,14 +8,29 @@ interface EditProfileModalProps { onClose: () => void; } -const STAT_TOGGLES: { key: keyof ProfileSettings; label: string; icon: string }[] = [ - { key: "showTotalGold", label: "Total Gold Earned", icon: "🪙" }, - { key: "showTotalClicks", label: "Total Clicks", icon: "👆" }, +interface StatToggle { + key: keyof ProfileSettings; + label: string; + icon: string; +} + +const CURRENT_RUN_TOGGLES: StatToggle[] = [ + { key: "showCurrentGold", label: "Gold Earned This Run", icon: "🪙" }, + { key: "showCurrentClicks", label: "Clicks This Run", icon: "👆" }, { key: "showPrestige", label: "Prestige Level", icon: "⭐" }, { key: "showBossesDefeated", label: "Bosses Defeated", icon: "💀" }, { key: "showQuestsCompleted", label: "Quests Completed", icon: "📜" }, { key: "showAdventurersRecruited", label: "Adventurers Recruited", icon: "⚔️" }, { key: "showAchievementsUnlocked", label: "Achievements Unlocked", icon: "🏆" }, +]; + +const ALL_TIME_TOGGLES: StatToggle[] = [ + { key: "showTotalGold", label: "Total Gold Earned", icon: "🪙" }, + { key: "showTotalClicks", label: "Total Clicks", icon: "👆" }, + { key: "showLifetimeBossesDefeated", label: "Bosses Defeated", icon: "💀" }, + { key: "showLifetimeQuestsCompleted", label: "Quests Completed", icon: "📜" }, + { key: "showLifetimeAdventurersRecruited", label: "Adventurers Recruited", icon: "⚔️" }, + { key: "showLifetimeAchievementsUnlocked", label: "Achievements Unlocked", icon: "🏆" }, { key: "showGuildFounded", label: "Guild Founded Date", icon: "📅" }, ]; @@ -126,8 +141,27 @@ export const EditProfileModal = ({ onClose }: EditProfileModalProps): React.JSX.
Visible Stats
Choose which stats appear on your public profile.
+ +Current Run
All Time
+