first commmit
This commit is contained in:
@@ -0,0 +1,114 @@
|
||||
import { TutorialMgr } from '@logic/TutorialMgr';
|
||||
import { ScoreSystem, BASE_ENEMY_SCORE, COMBO_BONUS } from '@logic/ScoreSystem';
|
||||
import { WeaponType } from '@data/Interfaces';
|
||||
import { StorageMgr } from '@common/StorageMgr';
|
||||
|
||||
function mem() {
|
||||
const m = new Map<string, string>();
|
||||
return {
|
||||
getItem: (k: string) => (m.has(k) ? (m.get(k) as string) : null),
|
||||
setItem: (k: string, v: string) => {
|
||||
m.set(k, v);
|
||||
},
|
||||
removeItem: (k: string) => {
|
||||
m.delete(k);
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
describe('TutorialMgr — built-in sequences for 1-1..1-3 (req 11.1-11.3)', () => {
|
||||
it('maybeStart returns the first step of 1-1', () => {
|
||||
const t = new TutorialMgr(new StorageMgr(mem()));
|
||||
const step = t.maybeStart('1-1');
|
||||
expect(step).toBeDefined();
|
||||
expect(step!.id).toBe('attack');
|
||||
});
|
||||
|
||||
it('reportAction advances through the sequence', () => {
|
||||
const t = new TutorialMgr(new StorageMgr(mem()));
|
||||
t.maybeStart('1-1');
|
||||
expect(t.reportAction('fire_shuriken')).toMatchObject({ id: 'joystick' });
|
||||
expect(t.reportAction('move')).toMatchObject({ id: 'jump' });
|
||||
expect(t.reportAction('jump')).toBe('finished');
|
||||
});
|
||||
|
||||
it('completed tutorials are persisted and skipped on replay (req 11.4)', () => {
|
||||
const storage = new StorageMgr(mem());
|
||||
const t = new TutorialMgr(storage);
|
||||
t.maybeStart('1-1');
|
||||
t.reportAction('fire_shuriken');
|
||||
t.reportAction('move');
|
||||
t.reportAction('jump');
|
||||
expect(t.isCompleted('1-1')).toBe(true);
|
||||
expect(t.maybeStart('1-1')).toBeNull();
|
||||
});
|
||||
|
||||
it('resetAll clears the completion set (req 11.5)', () => {
|
||||
const t = new TutorialMgr(new StorageMgr(mem()));
|
||||
t.maybeStart('1-2');
|
||||
t.reportAction('parabolic_jump');
|
||||
t.reportAction('attack_switch');
|
||||
t.reportAction('parry');
|
||||
t.reportAction('jump_attack');
|
||||
t.reportAction('pickup_crystal');
|
||||
t.resetAll();
|
||||
expect(t.maybeStart('1-2')).toBeDefined();
|
||||
});
|
||||
|
||||
it('reportAction with wrong action is a no-op', () => {
|
||||
const t = new TutorialMgr(new StorageMgr(mem()));
|
||||
t.maybeStart('1-1');
|
||||
expect(t.reportAction('wrong')).toBe('no_op');
|
||||
expect(t.currentStep()!.id).toBe('attack');
|
||||
});
|
||||
});
|
||||
|
||||
describe('ScoreSystem — scoring table (req 12.1-12.6)', () => {
|
||||
it('sword kill is ×2, shuriken kill is ×1', () => {
|
||||
const s = new ScoreSystem();
|
||||
s.recordEnemyKill(WeaponType.NinjaSword);
|
||||
s.recordEnemyKill(WeaponType.Shuriken);
|
||||
expect(s.snapshot().baseScore).toBe(BASE_ENEMY_SCORE * 3);
|
||||
});
|
||||
|
||||
it('parry kill is ×3 base', () => {
|
||||
const s = new ScoreSystem();
|
||||
s.recordParryKill();
|
||||
expect(s.snapshot().baseScore).toBe(BASE_ENEMY_SCORE * 3);
|
||||
});
|
||||
|
||||
it('5 blade contacts award a +1500 combo bonus (req 12.4)', () => {
|
||||
const s = new ScoreSystem();
|
||||
for (let i = 0; i < 5; i++) s.recordBladeContact();
|
||||
const snap = s.snapshot();
|
||||
expect(snap.comboBonus).toBe(COMBO_BONUS);
|
||||
expect(snap.comboCount).toBe(1);
|
||||
expect(snap.consecutiveBladeHits).toBe(0);
|
||||
});
|
||||
|
||||
it('breakBladeChain resets the streak', () => {
|
||||
const s = new ScoreSystem();
|
||||
s.recordBladeContact();
|
||||
s.recordBladeContact();
|
||||
s.breakBladeChain();
|
||||
s.recordBladeContact();
|
||||
expect(s.snapshot().consecutiveBladeHits).toBe(1);
|
||||
});
|
||||
|
||||
it('flawless run triples total score; taking damage removes the bonus (req 12.5)', () => {
|
||||
const s = new ScoreSystem();
|
||||
s.recordEnemyKill(WeaponType.Shuriken);
|
||||
const flawlessSnap = s.snapshot();
|
||||
expect(flawlessSnap.flawlessMultiplier).toBe(3);
|
||||
s.markTaken();
|
||||
const damagedSnap = s.snapshot();
|
||||
expect(damagedSnap.flawlessMultiplier).toBe(1);
|
||||
});
|
||||
|
||||
it('remaining time bonus adds 10 pts / sec (req 12.6)', () => {
|
||||
const s = new ScoreSystem();
|
||||
s.recordEnemyKill(WeaponType.Shuriken);
|
||||
s.setRemainingTimeBonus(30);
|
||||
expect(s.snapshot().timeBonus).toBe(300);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user