Give the machine, fire, gun and boss their missing sounds

All four synthesized in audio.js like every other weapon: a squeaking
castor, a court-wide crackle clock plus a throttled catch, a real gun
crack, and one shared boss voice (stomp per stride, wind-up breath,
bark, pain, death roar) pitched by body size. Closes OPEN 13 pending
the phone verdict. v355.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
wuwiandClaude Opus 5.5 committed 2026-09-23 09:16:27 +02:00
1 parent d05b49909e
commit 74aa209753
5 files changed
+248 -14

No files matched your search

+39 -1
View File
@@ -95,7 +95,7 @@ const { mirror, netMsg, netTest, netTick, netAgain } = await import('./src/net.j
// the drill's first-sight modal freezes the world (that is what modals do) — dismiss it the way a
// player would, so the tests step a live court
const startDrill = (...a) => { const r = _startDrill(...a); G.modal = null; G.modalQ.length = 0; return r; };
const { zombies, spawnZombie, pellets, parts, explode, hurtPlayer } = await import('./src/zombies.js');
const { zombies, spawnZombie, pellets, parts, explode, hurtPlayer, firePellet } = await import('./src/zombies.js');
const { killPlayer } = await import('./src/zombies.js');
const { drillQueue, drillLegal, arrival, drillMult, DRILL_TYPES } = await import('./src/drill.js');
const cfg = await import('./src/config.js');
@@ -2127,6 +2127,44 @@ test('netplay: the friend\'s strike makes a noise, pitched off the ball it just
audio.sfxTest.log = null;
});
// ---- OPEN 13: the four missing sounds (2026-09-23). Synthesized, so the ear is the phone's job;
// what the suite pins is that each one fires at its EVENT, and that fire stays one clock, not a
// sound per body.
test('the machine squeaks, fire crackles and catches, the gun cracks, the boss stomps and growls', () => {
const heard = n => audio.sfxTest.log.includes(n);
freshSplatter();
audio.sfxTest.log = [];
spawnZombie(0, 8, 'm');
const m = zombies[zombies.length - 1]; m.rollTo = 3; m.rollT = 0; m.fireT = 99;
for (let i = 0; i < 60 * 4 && !heard('squeak'); i++) { update(DT); G.hp = 9; }
assert.ok(heard('squeak'), 'a rolling machine announces itself');
freshSplatter();
audio.sfxTest.log = [];
for (let k = 0; k < 8; k++) spawnZombie(-1.4 + k * 0.4, 6, 'a');
zombies[0].burnT = 3;
update(DT);
assert.ok(heard('crackle'), 'a burning body crackles');
assert.equal(audio.sfxTest.log.filter(n => n === 'whump').length, 1, 'an epidemic lights the row, and says so ONCE');
const lit = zombies.filter(z => z.burnT > 0).length;
audio.sfxTest.log = [];
for (let i = 0; i < 60; i++) update(DT);
const crackles = audio.sfxTest.log.filter(n => n === 'crackle').length;
assert.ok(lit >= 3 && crackles >= 3 && crackles <= 16, `one court clock, not one per body: ${crackles} crackles/s for ${lit} lit`);
audio.sfxTest.log = [];
for (let k = 0; k < 4; k++) firePellet();
assert.equal(audio.sfxTest.log.filter(n => n === 'gunshot').length, 2, 'the gun cracks every other round');
freshSplatter();
startBossFight(1);
audio.sfxTest.log = [];
for (let i = 0; i < 60 * 30 && !(heard('stomp') && heard('growl')); i++) { update(DT); G.hp = 9; }
assert.ok(heard('stomp'), 'the boss has feet');
assert.ok(heard('growl'), 'and a throat: the wind-up draws breath');
audio.sfxTest.log = null;
});
// ---- THE REMATCH. The relay cannot re-pair (its room code is popped on pairing), so playing the
// same friend again is the SOCKET THAT IS STILL OPEN: one 'again' frame, both phones reset the run
// under the decisions the room already carries. The desync to guard against is the two courts