import { describe, expect, it } from 'vitest'; import { generateWorld } from './world'; import { applyWear, deriveHandling, freshCondition, repair, SUBSYSTEMS, type CarCondition } from './car'; describe('world generation', () => { it('is reproducible from a seed', () => { expect(generateWorld(42)).toEqual(generateWorld(42)); }); it('differs between seeds', () => { expect(generateWorld(42)).not.toEqual(generateWorld(43)); }); it('keeps the spawn point clear', () => { const world = generateWorld(7); for (const o of world.obstacles) { expect(Math.hypot(o.x - world.spawn.x, o.z - world.spawn.z)).toBeGreaterThanOrEqual(12); } }); }); describe('car condition', () => { it('never recovers on its own', () => { let c = freshCondition(); for (let i = 0; i < 600; i++) { const next = applyWear(c, { dt: 1 / 60, distance: 0.4, throttle: 1, impactForce: 0 }); expect(next.level.engine).toBeLessThanOrEqual(c.level.engine); expect(next.level.tires).toBeLessThanOrEqual(c.level.tires); c = next; } }); it('bottoms out rather than going negative', () => { let c = freshCondition(); for (let i = 0; i < 200; i++) { c = applyWear(c, { dt: 1 / 60, distance: 5, throttle: 1, impactForce: 5e5 }); } expect(c.level.chassis).toBe(0); expect(c.level.tires).toBe(0); }); /** * The force magnitude Rapier actually reports for a head-on into a building * at 85 km/h, read off the running game. Every number below is anchored to it * rather than to a guess about what a collision "should" be worth. */ const HARD_CRASH = 2.47e6; it('leaves a car driveable after one hard crash', () => { const c = applyWear(freshCondition(), { dt: 1 / 60, distance: 0.4, throttle: 0, impactForce: HARD_CRASH, }); // Expensive — the worst single thing that can happen to the car — but the // campaign continues. The first pass wrote off the chassis in this one step. expect(c.level.chassis).toBeGreaterThan(0.7); expect(c.level.chassis).toBeLessThan(0.95); expect(c.ceiling.chassis).toBeGreaterThan(0.9); }); it('caps what a single step can take, however violent the contact', () => { // A pileup reports contact forces without any natural bound; without a cap // one frame of a bad landing is worth more than the crash that caused it. const c = applyWear(freshCondition(), { dt: 1 / 60, distance: 0.4, throttle: 1, impactForce: 1e9, }); for (const part of SUBSYSTEMS) { expect(c.level[part]).toBeGreaterThanOrEqual(0.74); } }); it('takes a sustained battering to write the car off', () => { let c = freshCondition(); let crashes = 0; while (c.level.chassis > 0 && crashes < 100) { c = applyWear(c, { dt: 1 / 60, distance: 0.4, throttle: 0, impactForce: HARD_CRASH }); crashes++; } // Enough hard crashes to be a story about the driver, not one bad corner. expect(crashes).toBeGreaterThan(5); }); it('makes a worn car measurably worse to drive', () => { const fresh = deriveHandling(freshCondition()); const worn = deriveHandling({ level: { engine: 0.3, tires: 0.3, chassis: 0.3 }, ceiling: { engine: 1, tires: 1, chassis: 1 }, }); expect(worn.engineForce).toBeLessThan(fresh.engineForce); expect(worn.frictionSlip).toBeLessThan(fresh.frictionSlip); expect(worn.steeringPull).toBeGreaterThan(fresh.steeringPull); }); }); describe('repair', () => { const damaged = () => { let c = freshCondition(); for (let i = 0; i < 40; i++) { c = applyWear(c, { dt: 1 / 60, distance: 3, throttle: 1, impactForce: 2e5 }); } return c; }; it('lowers the ceiling permanently, so a car never comes back whole', () => { const c = damaged(); expect(c.ceiling.chassis).toBeLessThan(1); // No amount of parts can undo it. const restored = repair(c, 99).condition; expect(restored.level.chassis).toBeLessThan(1); expect(restored.level.chassis).toBeCloseTo(c.ceiling.chassis, 6); }); it('never lifts a subsystem above its ceiling', () => { const c = damaged(); const restored = repair(c, 99).condition; for (const part of SUBSYSTEMS) { expect(restored.level[part]).toBeLessThanOrEqual(restored.ceiling[part] + 1e-9); } }); it('hands back parts it could not use', () => { const { unused } = repair(freshCondition(), 5); expect(unused).toBeCloseTo(5, 6); }); it('spends a scarce part on the worst subsystem', () => { const c: CarCondition = { level: { engine: 0.9, tires: 0.2, chassis: 0.8 }, ceiling: { engine: 1, tires: 1, chassis: 1 }, }; const restored = repair(c, 0.1).condition; expect(restored.level.tires).toBeCloseTo(0.3, 6); expect(restored.level.engine).toBe(0.9); }); it('ratchets down over repeated damage-and-repair cycles', () => { let c = freshCondition(); let previousCeiling = 1; for (let cycle = 0; cycle < 5; cycle++) { for (let i = 0; i < 30; i++) { c = applyWear(c, { dt: 1 / 60, distance: 3, throttle: 1, impactForce: 2e4 }); } c = repair(c, 99).condition; // Fully repaired every cycle, and still worse off every cycle. expect(c.level.chassis).toBeCloseTo(c.ceiling.chassis, 6); expect(c.ceiling.chassis).toBeLessThan(previousCeiling); previousCeiling = c.ceiling.chassis; } expect(previousCeiling).toBeGreaterThan(0); }); });