109 lines
3.9 KiB
JavaScript
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");
|
|
}
|
|
}
|