Tornado disasters + settings toggle
- Monthly-chance tornadoes (after month 30 grace) carve a wide erratic path, flattening buildings into rubble; anchors stay consistent - 'Tornado disasters' toggle in menu settings, persisted - Help handbook documents the hazard and the rebuild loop - Engine suite grows to 45 assertions (spawn damage, event, anchors, suppression when disabled); soak keeps economy focus disaster-free
This commit is contained in:
@@ -217,5 +217,43 @@ console.log('— save / load integrity —');
|
||||
ok(c2.stats.powerCap >= 6000, 'power recomputed on load');
|
||||
}
|
||||
|
||||
// ---------------- tornado disasters ----------------
|
||||
{
|
||||
const c = new City(777, 'Tornadoville');
|
||||
for (let x = 8; x < 40; x++) c.placeStruct(STRUCT.ROAD, x, 30);
|
||||
const tiles = [];
|
||||
for (let x = 9; x < 30; x++) for (let z = 27; z <= 33; z++) tiles.push([x, z]);
|
||||
c.placeZone(ZONE.RES, tiles);
|
||||
const cp = findSpot(c, 2, 2, 12, 36);
|
||||
c.placeStruct(STRUCT.COAL, cp[0], cp[1]);
|
||||
for (let i = 0; i < 10; i++) c.tick();
|
||||
const devBefore = [...c.grid.level].filter(v => v > 0).length;
|
||||
ok(devBefore > 0, 'town exists before tornado');
|
||||
|
||||
let eventFired = false;
|
||||
c.on('disaster', (e) => { if (e.type === 'tornado' && e.destroyed > 0) eventFired = true; });
|
||||
c.spawnTornado();
|
||||
|
||||
const rubbleAfter = [...c.grid.rubble].filter(v => v > 0).length;
|
||||
ok(eventFired, 'disaster event emitted with damage count');
|
||||
ok(rubbleAfter > 0, `tornado left rubble behind (${rubbleAfter} tiles)`);
|
||||
let anchorBad = 0;
|
||||
for (let i = 0; i < c.grid.n; i++) {
|
||||
const s = c.grid.struct[i];
|
||||
if (!s || s === STRUCT.ROAD || c.grid.anchor[i] !== i) continue;
|
||||
if (c.grid.struct[c.grid.anchor[i]] !== s) anchorBad++;
|
||||
}
|
||||
ok(anchorBad === 0, 'anchors consistent after tornado destruction');
|
||||
|
||||
// disabled flag suppresses natural spawning
|
||||
c.disastersEnabled = false;
|
||||
let spawnedWhileOff = false;
|
||||
const origSpawn = c.spawnTornado.bind(c);
|
||||
c.spawnTornado = () => { spawnedWhileOff = true; return origSpawn(); };
|
||||
c.monthIndex = 60;
|
||||
for (let m = 0; m < 80; m++) c.tick();
|
||||
ok(!spawnedWhileOff, 'disabled flag prevents tornado spawns');
|
||||
}
|
||||
|
||||
console.log(`\n${pass} passed, ${fail} failed`);
|
||||
process.exit(fail ? 1 : 0);
|
||||
|
||||
@@ -10,6 +10,7 @@ let pass = 0, fail = 0;
|
||||
const ok = (cond, name) => { if (cond) { pass++; console.log(' ✔', name); } else { fail++; console.log(' ✘ FAIL:', name); } };
|
||||
|
||||
const c = new City(90210, 'Soakville');
|
||||
c.disastersEnabled = false; // economy focus here; tornado behaviour is covered by engine.mjs
|
||||
const g = c.grid;
|
||||
c.money = 60000;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user