slop game oder so

This commit is contained in:
2026-09-24 17:57:54 +02:00
commit 4c997eee21
166 changed files with 14976 additions and 0 deletions
+88
View File
@@ -0,0 +1,88 @@
import { describe, expect, it } from 'vitest';
import { SCORING } from '../../app/static/js/config.js';
import { multiplierForStreak, ScoreKeeper, waveBonus } from '../../app/static/js/logic/scoring.js';
describe('multiplierForStreak', () => {
it('steigt alle stepKills Abschüsse um stepValue', () => {
expect(multiplierForStreak(0)).toBe(1);
expect(multiplierForStreak(1)).toBe(1);
expect(multiplierForStreak(SCORING.stepKills - 1)).toBe(1);
expect(multiplierForStreak(SCORING.stepKills)).toBe(1 + SCORING.stepValue);
expect(multiplierForStreak(SCORING.stepKills * 2)).toBe(1 + 2 * SCORING.stepValue);
});
it('ist nach oben gedeckelt', () => {
expect(multiplierForStreak(10_000)).toBe(SCORING.maxMultiplier);
});
});
describe('waveBonus', () => {
it('wächst linear mit der Welle', () => {
expect(waveBonus(1)).toBe(SCORING.waveBonusPerWave);
expect(waveBonus(7)).toBe(7 * SCORING.waveBonusPerWave);
});
});
describe('ScoreKeeper', () => {
const cfg = { ...SCORING, streakWindowMs: 1000, stepKills: 2, stepValue: 1, maxMultiplier: 3 };
it('zählt Abschüsse ohne Serie mit Faktor 1', () => {
const keeper = new ScoreKeeper(cfg);
expect(keeper.registerKill(10, 0)).toEqual({ awarded: 10, multiplier: 1, streak: 1 });
expect(keeper.registerKill(10, 5000)).toEqual({ awarded: 10, multiplier: 1, streak: 1 });
expect(keeper.score).toBe(20);
expect(keeper.kills).toBe(2);
});
it('baut innerhalb des Fensters eine Serie mit Multiplikator auf', () => {
const keeper = new ScoreKeeper(cfg);
const results = [0, 500, 900, 1400, 1800].map((t) => keeper.registerKill(10, t));
expect(results.map((r) => r.multiplier)).toEqual([1, 2, 2, 3, 3]);
expect(keeper.score).toBe(10 + 20 + 20 + 30 + 30);
expect(keeper.bestStreak).toBe(5);
});
it('lässt die Serie nach Ablauf des Fensters verfallen', () => {
const keeper = new ScoreKeeper(cfg);
keeper.registerKill(10, 0);
keeper.registerKill(10, 100);
expect(keeper.multiplierAt(500)).toBe(2);
expect(keeper.multiplierAt(1200)).toBe(1);
expect(keeper.registerKill(10, 1200).streak).toBe(1);
expect(keeper.bestStreak).toBe(2);
});
it('beendet die Serie bei Treffern am Präsidenten', () => {
const keeper = new ScoreKeeper(cfg);
keeper.registerKill(10, 0);
keeper.registerKill(10, 100);
keeper.breakStreak();
expect(keeper.multiplierAt(200)).toBe(1);
expect(keeper.registerKill(10, 200)).toEqual({ awarded: 10, multiplier: 1, streak: 1 });
});
it('vergibt Bonuspunkte ohne Multiplikator und ignoriert negative Werte', () => {
const keeper = new ScoreKeeper(cfg);
keeper.registerKill(10, 0);
keeper.registerKill(10, 10);
expect(keeper.addBonus(100)).toBe(100);
expect(keeper.addBonus(-50)).toBe(0);
expect(keeper.score).toBe(10 + 20 + 100);
});
it('liefert eine Momentaufnahme mit Restzeit der Serie', () => {
const keeper = new ScoreKeeper(cfg);
keeper.registerKill(10, 0);
const snap = keeper.snapshot(250);
expect(snap).toMatchObject({ score: 10, kills: 1, streak: 1, multiplier: 1, bestStreak: 1 });
expect(snap.streakTimeLeft).toBeCloseTo(0.75);
expect(keeper.snapshot(5000)).toMatchObject({ streak: 0, streakTimeLeft: 0 });
});
it('rundet Punkte bei gebrochenen Multiplikatoren', () => {
const keeper = new ScoreKeeper({ ...cfg, stepValue: 0.5 });
keeper.registerKill(7, 0);
expect(keeper.registerKill(7, 10).awarded).toBe(Math.round(7 * 1.5));
});
});