Compare commits

..

5 Commits

Author SHA1 Message Date
Timmy
6803ef80af beacon: persist the Unbuilding defer cooldown
Some checks failed
Accessibility Checks / a11y-audit (pull_request) Successful in 6s
Smoke Test / smoke (pull_request) Failing after 9s
2026-04-14 11:43:51 -04:00
Timmy
4f0b54a970 beacon: persist stage-five dissolve progress 2026-04-14 11:36:31 -04:00
Timmy
cff3d1715b beacon: suppress drift UI during the Unbuilding 2026-04-14 11:36:31 -04:00
Timmy
f1bed950e6 beacon: preserve the Unbuilding prompt during renders 2026-04-14 11:36:31 -04:00
Timmy
4c162ed123 beacon: implement the Unbuilding endgame 2026-04-14 11:36:31 -04:00
4 changed files with 3 additions and 59 deletions

View File

@@ -105,16 +105,7 @@ This game is a **decision simulator** for our actual work.
## Files
- `index.html` — Game UI
- `js/data.js`Game data, buildings, projects, upgrades
- `js/utils.js` — Utility functions and formatters
- `js/combat.js` — Combat and corruption event logic
- `js/strategy.js` — Strategy and decision systems
- `js/sound.js` — Audio engine and sound effects
- `js/engine.js` — Core engine (tick loop, resource generation, state)
- `js/render.js` — DOM rendering and UI updates
- `js/tutorial.js` — New player tutorial flow
- `js/dismantle.js` — Dismantle/ending mechanics
- `js/main.js` — Entry point, initialization, game loop
- `game.js`Core engine (tick loop, buildings, projects, events)
- `DESIGN.md` — Full design document with narrative arc and mechanics
- `README.md` — This file

View File

@@ -481,11 +481,6 @@ const Dismantle = {
this.triggered = true;
this.renderChoice();
}
// Restore defer cooldown even if not triggered
if (G.dismantleDeferUntilAt > 0) {
this.deferUntilAt = G.dismantleDeferUntilAt;
}
},
/**

View File

@@ -35,7 +35,7 @@ window.addEventListener('load', function () {
if (G.driftEnding) {
G.running = false;
renderDriftEnding();
} else if (typeof Dismantle !== 'undefined' && (G.dismantleTriggered || G.dismantleActive || G.dismantleComplete || G.dismantleDeferUntilAt > 0)) {
} else if (typeof Dismantle !== 'undefined' && (G.dismantleTriggered || G.dismantleActive || G.dismantleComplete)) {
Dismantle.restore();
} else if (G.beaconEnding) {
G.running = false;

View File

@@ -409,46 +409,4 @@ test('restore re-renders an offered but not-yet-started Unbuilding prompt', () =
Dismantle.restore();
assert.match(document.getElementById('alignment-ui').innerHTML, /THE UNBUILDING/);
});
test('defer cooldown persists after save/load when dismantleTriggered is false', () => {
const { G, Dismantle, saveGame, loadGame } = loadBeacon({ includeRender: true });
G.startedAt = Date.now();
G.totalCode = 1_000_000_000;
G.phase = 6;
G.pactFlag = 1;
// Trigger the Unbuilding
Dismantle.checkTrigger();
assert.equal(G.dismantleTriggered, true);
// Defer it
Dismantle.defer();
assert.equal(G.dismantleTriggered, false);
assert.ok((Dismantle.deferUntilAt || 0) > Date.now());
assert.ok((G.dismantleDeferUntilAt || 0) > Date.now());
// Save the game
saveGame();
// Clear state (simulate reload)
G.dismantleTriggered = false;
G.dismantleActive = false;
G.dismantleComplete = false;
G.dismantleDeferUntilAt = 0;
Dismantle.triggered = false;
Dismantle.deferUntilAt = 0;
// Load the game
assert.equal(loadGame(), true);
Dismantle.restore(); // Call restore to restore defer cooldown
// The cooldown should be restored
assert.ok((Dismantle.deferUntilAt || 0) > Date.now(), 'deferUntilAt should be restored');
assert.ok((G.dismantleDeferUntilAt || 0) > Date.now(), 'G.dismantleDeferUntilAt should be restored');
// checkTrigger should not trigger because cooldown is active
Dismantle.checkTrigger();
assert.equal(G.dismantleTriggered, false, 'dismantleTriggered should remain false during cooldown');
});
});