111 lines
3.6 KiB
JavaScript
111 lines
3.6 KiB
JavaScript
import { describe, expect, it } from 'vitest';
|
|
|
|
import { WAVES } from '../../app/static/js/config.js';
|
|
import { createRng } from '../../app/static/js/logic/rng.js';
|
|
import { WaveDirector } from '../../app/static/js/logic/waveDirector.js';
|
|
|
|
/** Minimaler Spielersatz: zählt gespawnte Gegner und lässt sie auf Befehl sterben. */
|
|
function harness(cfgOverrides = {}) {
|
|
const log = { spawned: 0, started: [], cleared: [] };
|
|
let alive = 0;
|
|
const director = new WaveDirector({
|
|
rng: createRng(1),
|
|
cfg: { ...WAVES, ...cfgOverrides },
|
|
spawnGroup: (group) => {
|
|
log.spawned += group.count;
|
|
alive += group.count;
|
|
},
|
|
aliveCount: () => alive,
|
|
onWaveStart: (plan) => log.started.push(plan.number),
|
|
onWaveCleared: (n) => log.cleared.push(n),
|
|
});
|
|
return {
|
|
director,
|
|
log,
|
|
killAll: () => {
|
|
alive = 0;
|
|
},
|
|
get alive() {
|
|
return alive;
|
|
},
|
|
};
|
|
}
|
|
|
|
/** Lässt die Zeit in 50-ms-Schritten laufen. */
|
|
function run(director, from, until, step = 50) {
|
|
let now = from;
|
|
while (now < until) {
|
|
now += step;
|
|
director.update(now, step);
|
|
}
|
|
return now;
|
|
}
|
|
|
|
describe('WaveDirector', () => {
|
|
it('startet die erste Welle nach der Startverzögerung', () => {
|
|
const { director, log } = harness();
|
|
director.start(0);
|
|
expect(director.state).toBe('intermission');
|
|
run(director, 0, WAVES.firstWaveDelayMs - 50);
|
|
expect(log.started).toEqual([]);
|
|
run(director, WAVES.firstWaveDelayMs - 50, WAVES.firstWaveDelayMs);
|
|
expect(log.started).toEqual([1]);
|
|
expect(director.state).toBe('active');
|
|
});
|
|
|
|
it('spawnt alle Gruppen der Welle nach Plan', () => {
|
|
const { director, log } = harness();
|
|
director.start(0);
|
|
const now = run(director, 0, WAVES.firstWaveDelayMs);
|
|
const planned = director.plan.totalEnemies;
|
|
run(director, now, now + 60_000);
|
|
expect(log.spawned).toBe(planned);
|
|
expect(director.pendingEnemies).toBe(0);
|
|
});
|
|
|
|
it('meldet eine Welle erst als geschafft, wenn alle Gegner besiegt sind', () => {
|
|
const h = harness();
|
|
h.director.start(0);
|
|
let now = run(h.director, 0, 60_000);
|
|
expect(h.log.cleared).toEqual([]);
|
|
h.killAll();
|
|
now = run(h.director, now, now + 100);
|
|
expect(h.log.cleared).toEqual([1]);
|
|
expect(h.director.state).toBe('intermission');
|
|
expect(h.director.intermissionRemaining(now)).toBeGreaterThan(WAVES.intermissionMs - 200);
|
|
});
|
|
|
|
it('startet nach der Pause die nächste, größere Welle', () => {
|
|
const h = harness();
|
|
h.director.start(0);
|
|
let now = run(h.director, 0, 60_000);
|
|
const firstSize = h.director.plan.totalEnemies;
|
|
h.killAll();
|
|
now = run(h.director, now, now + WAVES.intermissionMs + 200);
|
|
expect(h.log.started).toEqual([1, 2]);
|
|
run(h.director, now, now + 60_000);
|
|
expect(h.director.plan.totalEnemies).toBeGreaterThan(firstSize);
|
|
});
|
|
|
|
it('hält den Spawn-Ablauf an, solange zu viele Gegner leben', () => {
|
|
const h = harness({ maxAliveEnemies: 3 });
|
|
h.director.start(0);
|
|
// Wellenstart plus ein Frame: Die erste Gruppe (≥4 Krabbler) überschreitet das Limit sofort.
|
|
let now = run(h.director, 0, WAVES.firstWaveDelayMs + 50);
|
|
const spawnedBefore = h.log.spawned;
|
|
expect(h.alive).toBeGreaterThanOrEqual(3);
|
|
now = run(h.director, now, now + 60_000);
|
|
expect(h.log.spawned).toBe(spawnedBefore);
|
|
h.killAll();
|
|
run(h.director, now, now + 60_000);
|
|
expect(h.log.spawned).toBeGreaterThan(spawnedBefore);
|
|
});
|
|
|
|
it('tut vor dem Start nichts', () => {
|
|
const { director, log } = harness();
|
|
run(director, 0, 10_000);
|
|
expect(log.started).toEqual([]);
|
|
expect(director.pendingEnemies).toBe(0);
|
|
});
|
|
});
|