/** * Run Cycle Types — schools, run phases, meta-progression * * Defines the structure of a single run (birth → death → rebirth) * and the persistent meta-progression between runs. */ // ─── Schools ───────────────────────────────────────────────────── export interface SchoolData { id: string; name: string; nameRu: string; description: string; descriptionRu: string; /** Starting element symbols (looked up in element registry) */ startingElements: string[]; /** Quantity of each starting element */ startingQuantities: Record; /** Scientific principle the school teaches */ principle: string; principleRu: string; /** Play style description */ playstyle: string; playstyleRu: string; /** Hex color for UI representation */ color: string; /** Passive gameplay bonuses from this school's principle */ bonuses: Record; /** Condition to unlock this school (absent = always unlocked) */ unlockCondition?: SchoolUnlockCondition; } /** Condition that must be met to unlock a school */ export interface SchoolUnlockCondition { /** What metric to check */ type: 'elements_discovered' | 'creatures_discovered' | 'runs_completed'; /** How many needed */ threshold: number; /** Hint text (English) shown when locked */ hint: string; /** Hint text (Russian) shown when locked */ hintRu: string; } /** Resolved school bonuses with all multipliers filled in (defaults = 1.0) */ export interface ResolvedSchoolBonuses { /** Projectile damage multiplier */ projectileDamage: number; /** Player movement speed multiplier */ movementSpeed: number; /** Creature aggro/flee range multiplier (< 1 = less aggro) */ creatureAggroRange: number; /** Reaction efficiency multiplier */ reactionEfficiency: number; } /** Default bonuses (no school effect) */ export const DEFAULT_SCHOOL_BONUSES: ResolvedSchoolBonuses = { projectileDamage: 1.0, movementSpeed: 1.0, creatureAggroRange: 1.0, reactionEfficiency: 1.0, }; // ─── Run Phases ────────────────────────────────────────────────── /** Phases of a single run in order */ export enum RunPhase { Awakening = 0, Exploration = 1, Escalation = 2, Crisis = 3, Resolution = 4, } /** Human-readable names for RunPhase */ export const RUN_PHASE_NAMES: Record = { [RunPhase.Awakening]: 'Awakening', [RunPhase.Exploration]: 'Exploration', [RunPhase.Escalation]: 'Escalation', [RunPhase.Crisis]: 'Crisis', [RunPhase.Resolution]: 'Resolution', }; export const RUN_PHASE_NAMES_RU: Record = { [RunPhase.Awakening]: 'Пробуждение', [RunPhase.Exploration]: 'Исследование', [RunPhase.Escalation]: 'Эскалация', [RunPhase.Crisis]: 'Кризис', [RunPhase.Resolution]: 'Развязка', }; // ─── Crisis Types ──────────────────────────────────────────────── export type CrisisType = 'chemical-plague'; export interface CrisisConfig { type: CrisisType; name: string; nameRu: string; description: string; descriptionRu: string; /** Escalation threshold (0-1) at which crisis triggers */ triggerThreshold: number; /** Compound that neutralizes the crisis */ neutralizer: string; /** Amount needed to neutralize */ neutralizeAmount: number; } // ─── Run State ─────────────────────────────────────────────────── /** State of the current run */ export interface RunState { /** Unique run identifier */ runId: number; /** Selected school id */ schoolId: string; /** Biome being explored this run */ biomeId: string; /** Current phase */ phase: RunPhase; /** Time spent in current phase (ms) */ phaseTimer: number; /** Total run elapsed time (ms) */ elapsed: number; /** Escalation level 0.0 – 1.0 */ escalation: number; /** Whether crisis has been triggered */ crisisActive: boolean; /** Whether crisis has been resolved */ crisisResolved: boolean; /** Discoveries made this run */ discoveries: RunDiscoveries; /** Whether the player is alive */ alive: boolean; /** World seed for this run */ worldSeed: number; /** Player death position in tile coords (set on death) */ deathPosition: { tileX: number; tileY: number } | null; } export interface RunDiscoveries { elements: Set; reactions: Set; compounds: Set; creatures: Set; } // ─── Meta-Progression (persists between runs) ──────────────────── export interface CodexEntry { id: string; type: 'element' | 'reaction' | 'compound' | 'creature' | 'boss'; discoveredOnRun: number; } export interface MetaState { /** Total spores earned across all runs */ spores: number; /** All codex entries (permanent knowledge) */ codex: CodexEntry[]; /** Total runs completed */ totalRuns: number; /** Total deaths */ totalDeaths: number; /** Unlocked school ids */ unlockedSchools: string[]; /** Best run statistics */ bestRunTime: number; bestRunDiscoveries: number; /** Run history summaries */ runHistory: RunSummary[]; /** Mycelium knowledge graph (persistent between runs) */ mycelium: MyceliumGraphData; /** Great cycle state (7-run macro cycles) */ greatCycle: GreatCycleState; } /** Serializable Mycelium graph data (stored in MetaState) */ export interface MyceliumGraphData { /** Knowledge nodes */ nodes: MyceliumNodeData[]; /** Connections between nodes */ edges: MyceliumEdgeData[]; /** Total deposits across all runs */ totalDeposits: number; /** Total extractions across all runs */ totalExtractions: number; } /** A knowledge node in the persistent Mycelium graph */ export interface MyceliumNodeData { /** Unique node ID (format: "type:id", e.g. "element:Na") */ id: string; /** Knowledge category */ type: 'element' | 'reaction' | 'compound' | 'creature'; /** Reference to the specific knowledge item */ knowledgeId: string; /** Run on which this was first deposited */ depositedOnRun: number; /** Knowledge strength 0–1 (increases with repeated deposits) */ strength: number; } /** An edge connecting two knowledge nodes in the Mycelium */ export interface MyceliumEdgeData { /** Source node ID */ from: string; /** Target node ID */ to: string; /** Connection strength 0–1 */ weight: number; } export interface RunSummary { runId: number; schoolId: string; duration: number; phase: RunPhase; discoveries: number; sporesEarned: number; crisisResolved: boolean; /** Biome explored (added Phase 11) */ biomeId?: string; /** Great cycle number when this run occurred */ cycleNumber?: number; } // ─── Body Composition (for death animation) ────────────────────── /** Real elemental composition of the human body (simplified) */ export const BODY_COMPOSITION: { symbol: string; fraction: number }[] = [ { symbol: 'O', fraction: 0.65 }, { symbol: 'C', fraction: 0.18 }, { symbol: 'H', fraction: 0.10 }, { symbol: 'N', fraction: 0.03 }, { symbol: 'Ca', fraction: 0.015 }, { symbol: 'P', fraction: 0.01 }, { symbol: 'S', fraction: 0.003 }, { symbol: 'Na', fraction: 0.002 }, { symbol: 'K', fraction: 0.002 }, { symbol: 'Fe', fraction: 0.001 }, ]; // ─── Great Cycle (every 7 runs) ────────────────────────────────── /** Narrative themes for each great cycle (GDD Section IV) */ export type CycleTheme = | 'awakening' // Cycle 1 (runs 1-7): learning the world | 'doubt' // Cycle 2 (runs 8-14): finding traces of past adepts | 'realization' // Cycle 3 (runs 15-21): understanding the nature of cycles | 'attempt' // Cycle 4 (runs 22-28): first attempts to transcend | 'acceptance' // Cycle 5 (runs 29-35): cycle is not a prison | 'synthesis'; // Cycle 6+ (runs 36+): unifying all knowledge /** Human-readable names for CycleTheme */ export const CYCLE_THEME_NAMES: Record = { awakening: 'Awakening', doubt: 'Doubt', realization: 'Realization', attempt: 'Attempt', acceptance: 'Acceptance', synthesis: 'Synthesis', }; export const CYCLE_THEME_NAMES_RU: Record = { awakening: 'Пробуждение', doubt: 'Сомнение', realization: 'Осознание', attempt: 'Попытка', acceptance: 'Принятие', synthesis: 'Синтез', }; /** Ordered themes by cycle number (0-indexed, cycles beyond 6 repeat 'synthesis') */ export const CYCLE_THEMES: CycleTheme[] = [ 'awakening', 'doubt', 'realization', 'attempt', 'acceptance', 'synthesis', ]; /** A trace left by a completed run within a great cycle */ export interface RunTrace { /** Run ID this trace belongs to */ runId: number; /** Position within the great cycle (1-7) */ runInCycle: number; /** School used this run */ schoolId: string; /** Biome explored */ biomeId: string; /** Death location (tile coords), null if run completed via boss victory */ deathPosition: { tileX: number; tileY: number } | null; /** Phase reached when run ended */ phaseReached: RunPhase; /** Was the crisis resolved? */ crisisResolved: boolean; /** Number of unique discoveries */ discoveryCount: number; /** Key element discoveries (up to 5 symbols for trace markers) */ keyElements: string[]; /** Duration of the run in ms */ duration: number; /** World seed used for this run */ worldSeed: number; } /** Persistent great cycle state (stored in MetaState) */ export interface GreatCycleState { /** Current great cycle number (1-based) */ cycleNumber: number; /** Current run within the cycle (1-7, resets on renewal) */ runInCycle: number; /** Current cycle's theme */ theme: CycleTheme; /** Traces from runs in the CURRENT cycle (cleared on renewal) */ currentCycleTraces: RunTrace[]; /** Traces from the PREVIOUS cycle (for cross-cycle references) */ previousCycleTraces: RunTrace[]; /** Total great renewals completed */ renewalsCompleted: number; /** Mycelium maturation level (increases each renewal) */ myceliumMaturation: number; } /** Number of runs per great cycle */ export const RUNS_PER_CYCLE = 7; /** World generation modifiers based on cycle number */ export interface CycleWorldModifiers { /** Elevation noise scale multiplier (world shape variation) */ elevationScaleMultiplier: number; /** Detail noise scale multiplier */ detailScaleMultiplier: number; /** Resource density multiplier */ resourceDensityMultiplier: number; /** Creature spawn rate multiplier */ creatureSpawnMultiplier: number; /** Escalation rate multiplier (difficulty) */ escalationRateMultiplier: number; } // ─── Constants ─────────────────────────────────────────────────── /** Phase durations in ms (approximate, can be adjusted) */ export const PHASE_DURATIONS: Record = { [RunPhase.Awakening]: 0, // ends when player leaves Cradle [RunPhase.Exploration]: 180_000, // 3 minutes [RunPhase.Escalation]: 120_000, // 2 minutes [RunPhase.Crisis]: 0, // ends when resolved or player dies [RunPhase.Resolution]: 60_000, // 1 minute }; /** Escalation growth rate per second (0→1 over Escalation phase) */ export const ESCALATION_RATE = 0.005; /** Spores awarded per discovery type */ export const SPORE_REWARDS = { element: 5, reaction: 10, compound: 8, creature: 15, crisisResolved: 50, runCompleted: 20, };