Files
Battle-for-Tismo/tests/bombing_test.js

109 lines
3.9 KiB
JavaScript

import { TestCase } from "./framework/test_case.js";
import {
BombardmentSfx,
AirStrikeSfx,
zoomVolume,
BOMB_VOLUME,
BOMB_CLIP_S,
BOMB_GAP_MS,
BOMB_IDLE_MS,
AIR_BOMB_BURST,
} from "../client/js/game_screen/bombing.js";
export class BombingTest extends TestCase {
test_volume_grows_with_zoom() {
this.assertLess(zoomVolume(0.2), zoomVolume(1.0), "closer is louder");
this.assertLess(zoomVolume(1.0), zoomVolume(2.0), "and louder still up close");
this.assertApprox(zoomVolume(0.2), BOMB_VOLUME.min);
this.assertApprox(zoomVolume(2.0), BOMB_VOLUME.max);
// Out-of-range zooms clamp rather than going silent or overdriven.
this.assertApprox(zoomVolume(-5), BOMB_VOLUME.min);
this.assertApprox(zoomVolume(50), BOMB_VOLUME.max);
}
test_silent_while_nothing_is_bombing() {
const plays = [];
const sfx = new BombardmentSfx((volume, duration) => plays.push({ volume, duration }));
for (let i = 0; i < 50; i++) sfx.update(100, false, 0.5);
this.assertEqual(plays.length, 0);
}
test_bursts_play_short_clips_at_the_zoom_volume() {
const plays = [];
let now = 0;
const sfx = new BombardmentSfx(
(volume, duration) => plays.push({ volume, duration, at: now }),
() => 0.5
);
// Ten seconds of frames, 100 ms apart, with a bombardment in view.
for (let i = 0; i < 100; i++) {
now += 100;
sfx.update(100, true, 0.4);
}
this.assertGreater(plays.length, 0, "impacts play");
this.assertLess(plays.length, 100, "the impacts arrive in bursts, not every frame");
for (const play of plays) {
this.assertApprox(play.volume, 0.4, 1e-9, "the impact uses the zoom volume");
this.assertGreaterOrEqual(play.duration, BOMB_CLIP_S.min);
this.assertLess(play.duration, BOMB_CLIP_S.max + 1e-9, "each clip is cut short");
}
}
test_impacts_keep_their_spacing() {
const times = [];
let now = 0;
const sfx = new BombardmentSfx(() => times.push(now), () => 0.99);
// Forty seconds of frames, 100 ms apart.
for (let i = 0; i < 400; i++) {
now += 100;
sfx.update(100, true, 0.5);
}
this.assertGreater(times.length, 3, "impacts play");
const gaps = [];
for (let i = 1; i < times.length; i++) gaps.push(times[i] - times[i - 1]);
for (const gap of gaps) {
this.assertGreaterOrEqual(gap, BOMB_GAP_MS.min, "impacts never bunch up");
}
this.assertTrue(
gaps.some((gap) => gap >= BOMB_IDLE_MS.min),
"and there are quiet gaps between bursts"
);
}
test_air_strike_is_one_large_one_shot_burst() {
const plays = [];
let now = 0;
const sfx = new AirStrikeSfx(
(volume, duration) => plays.push({ volume, duration, at: now }),
() => 0.99
);
sfx.trigger(0.5);
// Two seconds of frames, 50 ms apart, cover the whole burst.
for (let i = 0; i < 40; i++) {
now += 50;
sfx.update(50);
}
this.assertGreaterOrEqual(plays.length, AIR_BOMB_BURST.min, "at least seven explosions");
for (const play of plays) this.assertApprox(play.volume, 0.5, 1e-9);
// It is a one-shot: no further impacts once the burst has run out.
const after = plays.length;
for (let i = 0; i < 20; i++) {
now += 50;
sfx.update(50);
}
this.assertEqual(plays.length, after, "the burst does not keep repeating");
}
test_stopping_the_bombing_stops_the_sound() {
const plays = [];
const sfx = new BombardmentSfx((volume, duration) => plays.push(duration), () => 0);
for (let i = 0; i < 10; i++) sfx.update(100, true, 0.5);
const before = plays.length;
this.assertGreater(before, 0, "something played while active");
for (let i = 0; i < 10; i++) sfx.update(100, false, 0.5);
this.assertEqual(plays.length, before, "no impacts once the bombing stops");
for (let i = 0; i < 5; i++) sfx.update(100, true, 0.5);
this.assertGreater(plays.length, before, "the ambience resumes with the next barrage");
}
}