Files
synthesis/tests/escalation.test.ts
Денис Шкабатур 493748f2b0 phase 6: escalation effects + enhanced crisis system
- Add escalation effects module: creature speed/aggro/damage multipliers,
  reaction instability, environmental damage — all scale 0→1
- Add getCrisisPlayerDamage/getCrisisTint to crisis module
- Integrate escalation effects into GameScene (env damage at high entropy)
- Dynamic crisis overlay tint that intensifies with progress
- Phase indicator shows entropy %, aggression multiplier, crisis status
- 14 new tests for escalation + crisis damage/tint (349 total)

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-12 15:24:48 +03:00

148 lines
5.0 KiB
TypeScript

import { describe, it, expect, beforeEach } from 'vitest';
import type { RunState } from '../src/run/types';
import { RunPhase, ESCALATION_RATE } from '../src/run/types';
import { createRunState, advancePhase, updateEscalation } from '../src/run/state';
import {
getEscalationEffects,
type EscalationEffects,
} from '../src/run/escalation';
import {
createCrisisState,
applyCrisisDamage,
attemptNeutralize,
isCrisisResolved,
getCrisisPlayerDamage,
getCrisisTint,
CHEMICAL_PLAGUE,
} from '../src/run/crisis';
// ─── Escalation Effects ──────────────────────────────────────────
describe('Escalation Effects', () => {
it('at 0 escalation, all multipliers are 1.0', () => {
const fx = getEscalationEffects(0);
expect(fx.creatureSpeedMultiplier).toBe(1.0);
expect(fx.creatureAggroRange).toBe(1.0);
expect(fx.creatureAttackMultiplier).toBe(1.0);
expect(fx.reactionInstability).toBe(0);
expect(fx.environmentalDamage).toBe(0);
});
it('at 0.5 escalation, effects are moderate', () => {
const fx = getEscalationEffects(0.5);
expect(fx.creatureSpeedMultiplier).toBeGreaterThan(1.0);
expect(fx.creatureSpeedMultiplier).toBeLessThan(2.0);
expect(fx.creatureAggroRange).toBeGreaterThan(1.0);
expect(fx.creatureAttackMultiplier).toBeGreaterThan(1.0);
expect(fx.reactionInstability).toBeGreaterThan(0);
});
it('at 1.0 escalation, effects are maximal', () => {
const fx = getEscalationEffects(1.0);
expect(fx.creatureSpeedMultiplier).toBe(1.5);
expect(fx.creatureAggroRange).toBe(1.8);
expect(fx.creatureAttackMultiplier).toBe(1.6);
expect(fx.reactionInstability).toBe(0.3);
expect(fx.environmentalDamage).toBeGreaterThan(0);
});
it('escalation clamps values correctly', () => {
const fx = getEscalationEffects(2.0); // over max
expect(fx.creatureSpeedMultiplier).toBe(1.5);
const fxNeg = getEscalationEffects(-1.0); // under min
expect(fxNeg.creatureSpeedMultiplier).toBe(1.0);
});
});
// ─── Crisis Damage ───────────────────────────────────────────────
describe('Crisis Player Damage', () => {
it('no damage below 30% progress', () => {
const crisis = createCrisisState(CHEMICAL_PLAGUE);
crisis.progress = 0.2;
expect(getCrisisPlayerDamage(crisis, 1000)).toBe(0);
});
it('damage increases with progress above 30%', () => {
const crisis = createCrisisState(CHEMICAL_PLAGUE);
crisis.progress = 0.5;
const dmg = getCrisisPlayerDamage(crisis, 1000);
expect(dmg).toBeGreaterThan(0);
});
it('damage scales with delta time', () => {
const crisis = createCrisisState(CHEMICAL_PLAGUE);
crisis.progress = 0.8;
const dmg1 = getCrisisPlayerDamage(crisis, 1000);
const dmg2 = getCrisisPlayerDamage(crisis, 2000);
expect(dmg2).toBeCloseTo(dmg1 * 2, 1);
});
it('no damage when resolved', () => {
const crisis = createCrisisState(CHEMICAL_PLAGUE);
crisis.progress = 0.8;
crisis.resolved = true;
expect(getCrisisPlayerDamage(crisis, 1000)).toBe(0);
});
});
describe('Crisis Visual Tint', () => {
it('returns no tint at 0 progress', () => {
const crisis = createCrisisState(CHEMICAL_PLAGUE);
crisis.progress = 0;
const tint = getCrisisTint(crisis);
expect(tint.alpha).toBe(0);
});
it('returns tint at high progress', () => {
const crisis = createCrisisState(CHEMICAL_PLAGUE);
crisis.progress = 0.8;
const tint = getCrisisTint(crisis);
expect(tint.alpha).toBeGreaterThan(0);
expect(tint.color).toBeDefined();
});
it('returns no tint when resolved', () => {
const crisis = createCrisisState(CHEMICAL_PLAGUE);
crisis.progress = 0.8;
crisis.resolved = true;
const tint = getCrisisTint(crisis);
expect(tint.alpha).toBe(0);
});
});
// ─── Escalation-Phase Integration ────────────────────────────────
describe('Escalation Integration', () => {
let state: RunState;
beforeEach(() => {
state = createRunState(1, 'alchemist');
state.phase = RunPhase.Escalation;
});
it('escalation grows steadily over time', () => {
// Simulate 30 seconds
for (let i = 0; i < 30; i++) {
updateEscalation(state, 1000);
}
expect(state.escalation).toBeCloseTo(ESCALATION_RATE * 30, 2);
});
it('effects scale linearly with escalation', () => {
updateEscalation(state, 100_000); // ~100 seconds
const fx = getEscalationEffects(state.escalation);
expect(fx.creatureSpeedMultiplier).toBeGreaterThan(1.0);
expect(fx.creatureAggroRange).toBeGreaterThan(1.0);
});
it('full escalation cycle reaches crisis threshold', () => {
// Simulate until threshold
for (let i = 0; i < 200; i++) {
updateEscalation(state, 1000);
}
expect(state.escalation).toBeGreaterThanOrEqual(CHEMICAL_PLAGUE.triggerThreshold);
});
});