import { makeWorld, tick, sim, aimAt, check, section, report, CFG, Input, ROOMS } from './harness.mjs'; const { Arena } = await import('../src/arena.js'); section('OVERLOAD — build a bomb out of charge'); { const w = makeWorld(5); w.load(ROOMS[1]); w.particles.length = 0; const p = w.spawn({ x: 640, y: 360, el: 'C' }); p.fixed = true; w.molly.x = 300; w.molly.y = 360; aimAt(w, 640, 360); check('starts unloaded', !p.fuse, `load=${p.load||0}`); for (let k = 0; k < CFG.OVERLOAD_MAX; k++) { w.molly.cool = 0; w.bolts.fire(w, 1); for (let i = 0; i < 200 && w.bolts.list.length; i++) tick(w); } check('3 proton bolts light a fuse', p.fuse > 0, `fuse=${(p.fuse||0).toFixed(2)}s`); let boomT = null; for (let i = 0; i < 400 && boomT === null; i++) { tick(w); if (!p.fuse) boomT = i / 120; } check('fuse detonates', boomT !== null, boomT ? `after ${boomT.toFixed(2)}s` : 'never'); check('detonation counted', w.overload.detonations === 1, `n=${w.overload.detonations}`); } section('OVERLOAD — the cascade'); { const w = makeWorld(5); w.load(ROOMS[1]); w.particles.length = 0; // a tight cluster: one blast should tip the neighbours over too for (let i = 0; i < 10; i++) w.spawn({ x: 560 + (i % 5) * 46, y: 320 + Math.floor(i / 5) * 46, el: 'H' }); w.molly.x = 200; w.molly.y = 100; const seed = w.particles[0]; seed.load = CFG.OVERLOAD_MAX; seed.fuse = 0.1; seed.fuseMax = 0.1; for (let i = 0; i < 600; i++) tick(w); check('one blast triggers others (CASCADE)', w.overload.detonations > 1, `${w.overload.detonations} detonations from 1 seed`); check('blast makes radicals (your mess now)', w.radicals.chain >= 0, `radicals spawned=${w.particles.filter(p=>p.radical).length}`); } section('OVERLOAD — the juice budget holds'); { const { Juice } = await import('../src/juice.js'); Juice.reset(); let granted = 0; for (let i = 0; i < 30; i++) granted += Juice.hitstop(CFG.BLAST_HITSTOP); check('30 simultaneous blasts cannot freeze the screen', granted <= CFG.JUICE_HITSTOP_CAP, `${granted}ms granted of ${30*CFG.BLAST_HITSTOP}ms requested`); } section('PERF — the densest arena'); { const w = makeWorld(2); const a = new Arena(); w.load(a.room(7)); a.enter(w, 7); sim(w, 6); const t0 = process.hrtime.bigint(); for (let i = 0; i < 600; i++) tick(w); // 5 sim-seconds const ms = Number(process.hrtime.bigint() - t0) / 1e6; const perStep = ms / 600; check('sim step is fast enough for 60fps', perStep < 4, `${perStep.toFixed(2)}ms/step, ${w.particles.length} atoms, ${w.radicals.count} radicals`); } process.exit(report() ? 0 : 1);