phase 6: school data, run state, meta-progression, crisis system
- Add school data (Alchemist: H, O, C, Na, S, Fe starting kit) - Add run cycle types: phases, escalation, crisis, body composition - Implement run state management (create, advance phase, discoveries, spores) - Implement meta-progression (codex, spore accumulation, run history) - Implement crisis system (Chemical Plague with neutralization) - Add IndexedDB persistence for meta state - 42 new tests (335 total) Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
85
src/run/crisis.ts
Normal file
85
src/run/crisis.ts
Normal file
@@ -0,0 +1,85 @@
|
||||
/**
|
||||
* Crisis System — Chemical Plague
|
||||
*
|
||||
* When escalation reaches its threshold, a crisis activates.
|
||||
* The Chemical Plague poisons the atmosphere — player must craft
|
||||
* the correct neutralizing compound to stop it.
|
||||
*/
|
||||
|
||||
import type { CrisisConfig } from './types';
|
||||
|
||||
// ─── Chemical Plague Configuration ───────────────────────────────
|
||||
|
||||
export const CHEMICAL_PLAGUE: CrisisConfig = {
|
||||
type: 'chemical-plague',
|
||||
name: 'Chemical Plague',
|
||||
nameRu: 'Химическая Чума',
|
||||
description: 'A chain reaction is poisoning the atmosphere. Neutralize it with the right compound!',
|
||||
descriptionRu: 'Цепная реакция отравляет атмосферу. Нейтрализуй правильным соединением!',
|
||||
triggerThreshold: 0.8,
|
||||
neutralizer: 'CaO', // Calcium oxide (quicklime) — absorbs acid gases
|
||||
neutralizeAmount: 3, // need 3 units to fully neutralize
|
||||
};
|
||||
|
||||
// ─── Crisis State ────────────────────────────────────────────────
|
||||
|
||||
export interface CrisisState {
|
||||
config: CrisisConfig;
|
||||
active: boolean;
|
||||
/** Progress 0.0–1.0 — at 1.0 the world is fully poisoned */
|
||||
progress: number;
|
||||
resolved: boolean;
|
||||
/** How many neutralizer units have been applied */
|
||||
neutralizeApplied: number;
|
||||
}
|
||||
|
||||
/** Damage growth rate per second during active crisis */
|
||||
const CRISIS_DAMAGE_RATE = 0.01; // reaches 1.0 in ~100 seconds
|
||||
|
||||
/** Create a new crisis state from config */
|
||||
export function createCrisisState(config: CrisisConfig): CrisisState {
|
||||
return {
|
||||
config,
|
||||
active: true,
|
||||
progress: 0,
|
||||
resolved: false,
|
||||
neutralizeApplied: 0,
|
||||
};
|
||||
}
|
||||
|
||||
/** Advance crisis damage over time */
|
||||
export function applyCrisisDamage(crisis: CrisisState, deltaMs: number): void {
|
||||
if (!crisis.active || crisis.resolved) return;
|
||||
const deltaSec = deltaMs / 1000;
|
||||
crisis.progress = Math.min(1.0, crisis.progress + CRISIS_DAMAGE_RATE * deltaSec);
|
||||
}
|
||||
|
||||
/** Attempt to neutralize the crisis with a compound. Returns true if correct compound. */
|
||||
export function attemptNeutralize(
|
||||
crisis: CrisisState,
|
||||
compoundId: string,
|
||||
amount: number,
|
||||
): boolean {
|
||||
if (compoundId !== crisis.config.neutralizer) return false;
|
||||
if (crisis.resolved) return true;
|
||||
|
||||
crisis.neutralizeApplied += amount;
|
||||
|
||||
// Reduce progress proportionally
|
||||
const reductionPerUnit = 1.0 / crisis.config.neutralizeAmount;
|
||||
crisis.progress = Math.max(0, crisis.progress - amount * reductionPerUnit);
|
||||
|
||||
// Check if fully neutralized
|
||||
if (crisis.neutralizeApplied >= crisis.config.neutralizeAmount) {
|
||||
crisis.resolved = true;
|
||||
crisis.active = false;
|
||||
crisis.progress = 0;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/** Check if crisis has been resolved */
|
||||
export function isCrisisResolved(crisis: CrisisState): boolean {
|
||||
return crisis.resolved;
|
||||
}
|
||||
Reference in New Issue
Block a user