first commmit
This commit is contained in:
@@ -0,0 +1,67 @@
|
||||
import { DropSystem } from '@logic/DropSystem';
|
||||
import { EnemyType, ItemType } from '@data/Interfaces';
|
||||
|
||||
describe('DropSystem — crystal jade deterministic rule (req 7.1)', () => {
|
||||
it('spawns a crystal jade on exactly the 12th kill', () => {
|
||||
const ds = new DropSystem({ random: () => 1 });
|
||||
let crystalEvents = 0;
|
||||
for (let i = 1; i <= 24; i++) {
|
||||
const drops = ds.onEnemyKilled(EnemyType.YaoFang, { x: 100, y: 0 });
|
||||
if (drops.some((d) => d.item === ItemType.CrystalJade)) crystalEvents++;
|
||||
}
|
||||
expect(crystalEvents).toBe(2);
|
||||
});
|
||||
|
||||
it('spawns the crystal above the kill point', () => {
|
||||
const ds = new DropSystem({ random: () => 1 });
|
||||
for (let i = 0; i < 11; i++) ds.onEnemyKilled(EnemyType.QingRen, { x: 0, y: 0 });
|
||||
const drops = ds.onEnemyKilled(EnemyType.QingRen, { x: 300, y: 20 });
|
||||
const crystal = drops.find((d) => d.item === ItemType.CrystalJade);
|
||||
expect(crystal!.y).toBeGreaterThan(20);
|
||||
});
|
||||
});
|
||||
|
||||
describe('DropSystem — Chi Ren consecutive rule (req 7.3)', () => {
|
||||
it('drops dian_wan or shu_wan on the 3rd consecutive Chi Ren kill if RNG <0.5', () => {
|
||||
const ds = new DropSystem({
|
||||
dianShuWanProbability: 0.5,
|
||||
random: (() => {
|
||||
// probability check then which-item check both pass
|
||||
const vals = [0.1, 0.2];
|
||||
let i = 0;
|
||||
return () => vals[i++ % vals.length];
|
||||
})(),
|
||||
});
|
||||
ds.onEnemyKilled(EnemyType.ChiRen, { x: 0, y: 0 });
|
||||
ds.onEnemyKilled(EnemyType.ChiRen, { x: 0, y: 0 });
|
||||
const drops = ds.onEnemyKilled(EnemyType.ChiRen, { x: 50, y: 10 });
|
||||
expect(drops.find((d) => d.item === ItemType.DianWan)).toBeDefined();
|
||||
});
|
||||
|
||||
it('does not drop when RNG fails probability', () => {
|
||||
const ds = new DropSystem({ dianShuWanProbability: 0.5, random: () => 0.95 });
|
||||
ds.onEnemyKilled(EnemyType.ChiRen, { x: 0, y: 0 });
|
||||
ds.onEnemyKilled(EnemyType.ChiRen, { x: 0, y: 0 });
|
||||
const drops = ds.onEnemyKilled(EnemyType.ChiRen, { x: 0, y: 0 });
|
||||
expect(drops.filter((d) => d.item !== ItemType.CrystalJade).length).toBe(0);
|
||||
});
|
||||
|
||||
it('non-Chi-Ren kill resets the consecutive counter', () => {
|
||||
const ds = new DropSystem({ dianShuWanProbability: 1.0, random: () => 0 });
|
||||
ds.onEnemyKilled(EnemyType.ChiRen, { x: 0, y: 0 });
|
||||
ds.onEnemyKilled(EnemyType.ChiRen, { x: 0, y: 0 });
|
||||
ds.onEnemyKilled(EnemyType.QingRen, { x: 0, y: 0 });
|
||||
const drops = ds.onEnemyKilled(EnemyType.ChiRen, { x: 0, y: 0 });
|
||||
// Only 1 Chi Ren kill since reset — below threshold.
|
||||
expect(drops.filter((d) => d.item === ItemType.DianWan || d.item === ItemType.ShuWan).length).toBe(0);
|
||||
});
|
||||
});
|
||||
|
||||
describe('DropSystem — reset()', () => {
|
||||
it('zeroes kill counters', () => {
|
||||
const ds = new DropSystem();
|
||||
ds.onEnemyKilled(EnemyType.QingRen, { x: 0, y: 0 });
|
||||
ds.reset();
|
||||
expect(ds.kills).toBe(0);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user