75 lines
2.5 KiB
TypeScript
75 lines
2.5 KiB
TypeScript
import { describe, expect, it } from 'vitest';
|
|
import {
|
|
BUILD_FIZZLE_BARS,
|
|
DROP_CLEAN_MS,
|
|
DROP_LATE_MS,
|
|
DROP_PAYOUT,
|
|
REQUEST_HIT,
|
|
judgeDrop,
|
|
msToNearestBar,
|
|
} from '../../src/scenes/floor/djShift';
|
|
import { DJ_REQUESTS } from '../../src/data/strings/floor';
|
|
|
|
describe('judgeDrop', () => {
|
|
it('rewards the bar line, forgives near misses, punishes the clang', () => {
|
|
expect(judgeDrop(0)).toBe('clean');
|
|
expect(judgeDrop(DROP_CLEAN_MS)).toBe('clean');
|
|
expect(judgeDrop(-DROP_CLEAN_MS)).toBe('clean');
|
|
expect(judgeDrop(DROP_CLEAN_MS + 1)).toBe('late');
|
|
expect(judgeDrop(-DROP_LATE_MS)).toBe('late');
|
|
expect(judgeDrop(DROP_LATE_MS + 1)).toBe('clang');
|
|
});
|
|
|
|
it('early and late are the same offence — the room only hears wrong', () => {
|
|
for (const d of [50, 200, 500]) expect(judgeDrop(d)).toBe(judgeDrop(-d));
|
|
});
|
|
});
|
|
|
|
describe('msToNearestBar', () => {
|
|
const BEAT = 500; // 120bpm
|
|
it('is zero exactly on the bar', () => {
|
|
expect(msToNearestBar(0, 0, BEAT)).toBe(0);
|
|
});
|
|
|
|
it('measures behind the last bar early in the bar', () => {
|
|
expect(msToNearestBar(0, 120, BEAT)).toBe(120);
|
|
expect(msToNearestBar(1, 0, BEAT)).toBe(500);
|
|
});
|
|
|
|
it('measures ahead (negative) late in the bar', () => {
|
|
expect(msToNearestBar(3, 400, BEAT)).toBe(-(4 * BEAT - (3 * BEAT + 400)));
|
|
expect(msToNearestBar(3, 499, BEAT)).toBe(-1);
|
|
});
|
|
|
|
it('a mid-bar drop is maximally wrong from either side', () => {
|
|
expect(Math.abs(msToNearestBar(2, 0, BEAT))).toBe(2 * BEAT);
|
|
});
|
|
});
|
|
|
|
describe('the shift is priced, not graded', () => {
|
|
it('a clean drop pays, a clang costs — and neither is free', () => {
|
|
expect(DROP_PAYOUT.clean.vibe).toBeGreaterThan(0);
|
|
expect(DROP_PAYOUT.clang.vibe).toBeLessThan(0);
|
|
expect(DROP_PAYOUT.clang.aggro).toBeGreaterThan(0);
|
|
expect(DROP_PAYOUT.late.vibe).toBeLessThan(DROP_PAYOUT.clean.vibe);
|
|
});
|
|
|
|
it('a build cannot be held forever', () => {
|
|
expect(BUILD_FIZZLE_BARS).toBeLessThanOrEqual(8);
|
|
});
|
|
});
|
|
|
|
describe('booth requests', () => {
|
|
it('every scripted request has odds, and every odds entry has a script', () => {
|
|
const scriptIds = DJ_REQUESTS.map((r) => r.id);
|
|
expect(new Set(scriptIds).size).toBe(scriptIds.length);
|
|
for (const id of scriptIds) {
|
|
expect(REQUEST_HIT[id], `no odds for '${id}'`).toBeGreaterThan(0);
|
|
expect(REQUEST_HIT[id]).toBeLessThan(1); // nothing is a sure thing at the booth
|
|
}
|
|
for (const id of Object.keys(REQUEST_HIT)) {
|
|
expect(scriptIds).toContain(id);
|
|
}
|
|
});
|
|
});
|