This commit is contained in:
59
packages/game-engine/src/index.test.ts
Normal file
59
packages/game-engine/src/index.test.ts
Normal file
@@ -0,0 +1,59 @@
|
||||
import { describe, expect, it } from 'vitest'
|
||||
import { abilityModifier, applyMechanicalEvents, bindMechanicalEventsToRolls, resolveCheck, shouldCloseRound, type RandomSource } from './index'
|
||||
import type { Character } from '@dng/shared'
|
||||
|
||||
const fixed: RandomSource = { integer: () => 12 }
|
||||
const hero: Character = {
|
||||
id: 'hero', name: 'Rook', concept: 'Relic runner', controller: 'human', userId: 'user',
|
||||
abilities: { str: 14, dex: 16, con: 12, int: 10, wis: 8, cha: 13 },
|
||||
hp: 10, maxHp: 12, defense: 14, proficiency: 2, inventory: [], statuses: [],
|
||||
}
|
||||
|
||||
describe('game engine', () => {
|
||||
it('calculates ability modifiers', () => {
|
||||
expect(abilityModifier(8)).toBe(-1)
|
||||
expect(abilityModifier(16)).toBe(3)
|
||||
})
|
||||
|
||||
it('keeps dice server-owned and auditable', () => {
|
||||
const roll = resolveCheck({ actorId: 'hero', kind: 'ability', ability: 'dex', difficulty: 15, mode: 'normal', reason: 'Leap' }, hero, fixed)
|
||||
expect(roll.rolls).toEqual([12])
|
||||
expect(roll.total).toBe(17)
|
||||
expect(roll.success).toBe(true)
|
||||
})
|
||||
|
||||
it('labels disadvantage rolls correctly', () => {
|
||||
const values = [18, 4]
|
||||
const roll = resolveCheck(
|
||||
{ actorId: 'hero', kind: 'ability', ability: 'dex', difficulty: 10, mode: 'disadvantage', reason: 'Sneak' },
|
||||
hero,
|
||||
{ integer: () => values.shift()! },
|
||||
)
|
||||
expect(roll.formula).toBe('2d20kl1+5')
|
||||
expect(roll.kept).toEqual([4])
|
||||
})
|
||||
|
||||
it('replaces model-proposed damage with the authoritative roll total', () => {
|
||||
const damage = resolveCheck(
|
||||
{ actorId: 'hero', targetId: 'target', kind: 'damage', dice: '1d6+2', mode: 'normal', reason: 'Strike' },
|
||||
hero,
|
||||
{ integer: () => 4 },
|
||||
)
|
||||
const events = bindMechanicalEventsToRolls([
|
||||
{ type: 'damage', actorId: 'hero', targetId: 'target', value: 999, item: null, description: 'Strike' },
|
||||
], [damage])
|
||||
expect(events[0]?.value).toBe(6)
|
||||
})
|
||||
|
||||
it('clamps mechanical state', () => {
|
||||
const result = applyMechanicalEvents([hero], [{ type: 'damage', actorId: null, targetId: 'hero', value: 99, item: null, description: 'Catastrophic hit' }])
|
||||
expect(result.characters[0]?.hp).toBe(0)
|
||||
expect(result.audit).toHaveLength(1)
|
||||
})
|
||||
|
||||
it('closes only complete or forced rounds', () => {
|
||||
expect(shouldCloseRound(['a', 'b'], ['a'])).toBe(false)
|
||||
expect(shouldCloseRound(['a', 'b'], ['a', 'b'])).toBe(true)
|
||||
expect(shouldCloseRound(['a', 'b'], [], true)).toBe(true)
|
||||
})
|
||||
})
|
||||
Reference in New Issue
Block a user