feat: add companion system with quest-time reduction server validation

Introduces 10 unlockable companions (Lyra, Finn, Wren, Aldric, Sera, Kael,
Zuri, Mira, Vex, Pria), each providing a unique bonus: passive gold, click
gold, boss damage, essence income, or quest-time reduction.

Quest-time reduction is validated server-side: computeQuestRewards applies
the active companion's reduction to the effective duration check, and the
income validation budget accounts for passive gold and essence bonuses.
Server recomputes unlockedCompanionIds on every save using DB-authoritative
lifetime stats and validates the active companion ID.

Companion bonuses are also applied in the client tick engine and
boss.ts calculatePartyStats.
This commit is contained in:
2026-03-07 15:59:24 -08:00
committed by Naomi Carrigan
parent bcb523f598
commit db860ee5d3
12 changed files with 539 additions and 12 deletions
+4 -1
View File
@@ -22,10 +22,11 @@ import { UpgradePanel } from "./UpgradePanel.js";
import { DailyChallengePanel } from "./DailyChallengePanel.js";
import { ExplorationPanel } from "./ExplorationPanel.js";
import { CharacterSheetPanel } from "./CharacterSheetPanel.js";
import { CompanionPanel } from "./CompanionPanel.js";
import { CraftingPanel } from "./CraftingPanel.js";
import { LoginBonusModal } from "./LoginBonusModal.js";
type Tab = "adventurers" | "upgrades" | "quests" | "bosses" | "equipment" | "achievements" | "prestige" | "transcendence" | "apotheosis" | "statistics" | "daily" | "codex" | "about" | "exploration" | "crafting" | "character";
type Tab = "adventurers" | "upgrades" | "quests" | "bosses" | "equipment" | "achievements" | "prestige" | "transcendence" | "apotheosis" | "statistics" | "daily" | "codex" | "about" | "exploration" | "crafting" | "character" | "companions";
const BASE_TABS: { id: Tab; label: string }[] = [
{ id: "adventurers", label: "⚔️ Adventurers" },
@@ -40,6 +41,7 @@ const BASE_TABS: { id: Tab; label: string }[] = [
{ id: "transcendence", label: "🌌 Transcendence" },
{ id: "apotheosis", label: "✨ Apotheosis" },
{ id: "statistics", label: "📊 Statistics" },
{ id: "companions", label: "👥 Companions" },
{ id: "character", label: "📋 Character" },
{ id: "achievements", label: "🏆 Achievements" },
{ id: "codex", label: "📖 Codex" },
@@ -135,6 +137,7 @@ export const GameLayout = (): React.JSX.Element => {
{activeTab === "crafting" && <CraftingPanel />}
{activeTab === "statistics" && <StatisticsPanel />}
{activeTab === "daily" && <DailyChallengePanel />}
{activeTab === "companions" && <CompanionPanel />}
{activeTab === "character" && <CharacterSheetPanel />}
{activeTab === "codex" && <CodexPanel />}
{activeTab === "about" && <AboutPanel />}