Files

86 lines
3.0 KiB
JavaScript
Raw Permalink Normal View History

'use strict';
const shared = require('@ttrpg/shared');
const { makeParticipant, startEncounter, nextTurn, applyHpChange, deathSave } = shared;
const { mockCtx } = require('./_helpers');
function pc(id, init, extra = {}) {
return makeParticipant({
id,
name: id,
type: 'character',
initiative: init,
maxHp: 100,
currentHp: 100,
...extra,
});
}
function enc(ps) {
return { name:'t', participants:ps, isStarted:false, isPaused:false,
round:0, currentTurnParticipantId:null, turnOrderIds:[] };
}
const byId = (e, id) => e.participants.find(p => p.id === id);
describe('death state: participant remains in initiative and encounter', () => {
test('dropping to 0 keeps PC active, in participants, and in turnOrderIds', async () => {
const { ctx } = mockCtx();
let e = enc([pc('a', 20), pc('b', 15), pc('c', 10)]);
e = await startEncounter(e, ctx);
const orderBefore = e.turnOrderIds.slice();
e = await applyHpChange(e, 'b', 'damage', 100, ctx);
expect(byId(e, 'b').status).toBe('dying');
expect(byId(e, 'b').isActive).not.toBe(false);
expect(e.participants.map(p => p.id)).toContain('b');
expect(e.turnOrderIds).toEqual(orderBefore);
});
test('dead PC remains in participants and turnOrderIds after three failures', async () => {
const { ctx } = mockCtx();
let e = enc([pc('a', 20), pc('b', 15), pc('c', 10)]);
e = await startEncounter(e, ctx);
const orderBefore = e.turnOrderIds.slice();
e = await applyHpChange(e, 'b', 'damage', 100, ctx);
e = (await deathSave(e, 'b', 'fail', ctx)).enc;
e = (await deathSave(e, 'b', 'fail', ctx)).enc;
e = (await deathSave(e, 'b', 'fail', ctx)).enc;
expect(byId(e, 'b').status).toBe('dead');
expect(byId(e, 'b').isActive).not.toBe(false);
expect(e.participants.map(p => p.id)).toContain('b');
expect(e.turnOrderIds).toEqual(orderBefore);
});
test('nextTurn may still land on dead PC because DM/tool events may matter', async () => {
const { ctx } = mockCtx();
let e = enc([pc('a', 20), pc('b', 15), pc('c', 10)]);
e = await startEncounter(e, ctx);
e = await applyHpChange(e, 'b', 'damage', 100, ctx);
e = (await deathSave(e, 'b', 'fail', ctx)).enc;
e = (await deathSave(e, 'b', 'fail', ctx)).enc;
e = (await deathSave(e, 'b', 'fail', ctx)).enc;
e = await nextTurn(e, ctx);
expect(e.currentTurnParticipantId).toBe('b');
expect(byId(e, 'b').status).toBe('dead');
});
test('deathSave rejected/no-op once dead', async () => {
const { ctx } = mockCtx();
let e = enc([pc('a', 20), pc('b', 15)]);
e = await startEncounter(e, ctx);
e = await applyHpChange(e, 'b', 'damage', 100, ctx);
e = (await deathSave(e, 'b', 'fail', ctx)).enc;
e = (await deathSave(e, 'b', 'fail', ctx)).enc;
e = (await deathSave(e, 'b', 'fail', ctx)).enc;
const before = byId(e, 'b');
try { e = (await deathSave(e, 'b', 'fail', ctx)).enc; } catch (err) {}
expect(byId(e, 'b')).toMatchObject(before);
});
});