Nothing arrives unannounced: the horde gets its breather, the boss gets a name
THEY KEEP COMING is a 2.4s 'over' beat again (warnHorde in beats.js) instead of a flash raised on the same frame the wave lands, and the chapter boss walks on behind an overlay — his name in red over ENTERED THE COURT — held for 3s by the new self-dismissing modal clock (m.hold) rather than announced on a routine-set card. startHorde returns a bool: if the court has been taken when the warning expires the pendingHorde latch is re-armed rather than the set losing the horde it paid for. The warning ticks on its own clock, not on the 'over' beat, so a beat that moves the phase underneath it can't strand it (the mgT lock, again). Three tests, 15 total. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
1f636530b9
commit
5ea84f8511
8 files changed
+132
-16
No files matched your search
@@ -64,7 +64,7 @@ const { G, P, score, ball, setupPoint } = await import('./src/state.js');
|
||||
const { update, forceZombies, splatPoint, restartRun } = await import('./src/gameplay.js');
|
||||
const { startDuel, resolveInterlude, startBossFight, endBossFight } = await import('./src/beats.js');
|
||||
const { zombies, spawnZombie } = await import('./src/zombies.js');
|
||||
const { TUNE } = await import('./src/config.js');
|
||||
const { TUNE, bossArt } = await import('./src/config.js');
|
||||
|
||||
const DT = 1 / 60;
|
||||
function freshSplatter() {
|
||||
@@ -217,5 +217,44 @@ test('a lost duel banks their game — and their set — without a horde', () =>
|
||||
assert.ok(!G.horde && !G.pendingHorde, 'their duel set carries no horde');
|
||||
});
|
||||
|
||||
// ---- the announcements: nothing that changes the control mode may arrive unannounced -----------
|
||||
|
||||
test('a set warns THEY KEEP COMING before the wave lands', () => {
|
||||
G.pendingHorde = true; G.seen.horde = true; // not the first horde: no teaching modal in the way
|
||||
G.phase = 'over'; G.overT = 0.01;
|
||||
update(DT);
|
||||
assert.equal(G.horde, null, 'the wave must not land on the same frame as its own announcement');
|
||||
assert.ok(G.hordeWarn > 0, 'the breather is running');
|
||||
assert.equal(G.flash && G.flash.text, 'THEY KEEP COMING', 'and it says so');
|
||||
for (let i = 0; i < 10 && !G.horde; i++) update(DT); // ...but not for a hundredth of a second
|
||||
assert.equal(G.horde, null, 'the breather actually holds');
|
||||
for (let i = 0; i < (TUNE.hordeWarnT + 1) * 60 && !G.horde; i++) update(DT);
|
||||
assert.ok(G.horde, 'and the wave lands when it runs out');
|
||||
});
|
||||
|
||||
test('a mode that steals the court during the warning re-arms the horde', () => {
|
||||
G.pendingHorde = true; G.seen.horde = true;
|
||||
G.phase = 'over'; G.overT = 0.01;
|
||||
update(DT);
|
||||
assert.ok(G.hordeWarn > 0, 'setup: warning running');
|
||||
startDuel(); // the court is calm during a breather, so a scheduled beat CAN grab it here
|
||||
G.modal = null; G.modalQ.length = 0; // (its first-sight popup would freeze the world we're stepping)
|
||||
for (let i = 0; i < (TUNE.hordeWarnT + 1) * 60 && !G.horde; i++) update(DT);
|
||||
assert.equal(G.horde, null, 'the wave must not land inside the duel');
|
||||
assert.ok(G.pendingHorde, 'the set is still owed its horde');
|
||||
});
|
||||
|
||||
test('a chapter boss announces itself and hands the court back on its own', () => {
|
||||
startBossFight(2);
|
||||
assert.ok(G.modal, 'the walk-on is an overlay, not a band card');
|
||||
assert.equal(G.modal.title, bossArt(2).name, 'it names the boss');
|
||||
assert.deepEqual(G.modal.body, ['ENTERED THE COURT']);
|
||||
for (let i = 0; i < (TUNE.modalIn + TUNE.bossIntroT) * 60 - 6; i++) update(DT);
|
||||
assert.ok(G.modal, 'and holds the frozen court while the player reads it');
|
||||
for (let i = 0; i < 20 && G.modal; i++) update(DT);
|
||||
assert.equal(G.modal, null, 'then lets go without waiting for a tap');
|
||||
assert.ok(G.bossFight, 'the fight is on');
|
||||
});
|
||||
|
||||
console.log(`\n${passed} tests passed`);
|
||||
process.exit(0); // render.js schedules viewport timers at load; don't let them outlive the report
|
||||
Reference in new issue
Block a user