86d6d157f0
Очередь NPC/игроков с DnD, курсором на сцене, состояниями и запасом; сброс при смене сцены. Co-authored-by: Cursor <cursoragent@cursor.com>
106 lines
3.7 KiB
TypeScript
106 lines
3.7 KiB
TypeScript
import assert from 'node:assert/strict';
|
|
import test from 'node:test';
|
|
|
|
import { InitiativeSessionStore } from './initiativeSessionStore';
|
|
import {
|
|
initiativeNpcEntryId,
|
|
initiativePlayerEntryId,
|
|
} from '../../shared/types/initiative';
|
|
|
|
void test('initiative: addManual + next cycles order', () => {
|
|
const store = new InitiativeSessionStore();
|
|
store.dispatch({ kind: 'addManual', name: 'A' });
|
|
store.dispatch({ kind: 'addManual', name: 'B' });
|
|
const a = store.getState().order[0]!;
|
|
const b = store.getState().order[1]!;
|
|
assert.equal(store.getState().activeId, a);
|
|
store.dispatch({ kind: 'next' });
|
|
assert.equal(store.getState().activeId, b);
|
|
store.dispatch({ kind: 'next' });
|
|
assert.equal(store.getState().activeId, a);
|
|
});
|
|
|
|
void test('initiative: syncPresence adds npcs and players', () => {
|
|
const store = new InitiativeSessionStore();
|
|
store.dispatch({
|
|
kind: 'syncPresence',
|
|
npcs: [{ placementId: 'p1', npcId: 'n1', name: 'Goblin', avatarAssetId: null }],
|
|
players: [{ playerId: 'pl1', name: 'Hero' }],
|
|
playersVisible: true,
|
|
});
|
|
const st = store.getState();
|
|
assert.ok(st.entries[initiativeNpcEntryId('p1')]);
|
|
assert.ok(st.entries[initiativePlayerEntryId('pl1')]);
|
|
assert.deepEqual(st.order, [initiativeNpcEntryId('p1'), initiativePlayerEntryId('pl1')]);
|
|
});
|
|
|
|
void test('initiative: hide players moves them to reserve', () => {
|
|
const store = new InitiativeSessionStore();
|
|
store.dispatch({
|
|
kind: 'syncPresence',
|
|
npcs: [],
|
|
players: [{ playerId: 'pl1', name: 'Hero' }],
|
|
playersVisible: true,
|
|
});
|
|
const pid = initiativePlayerEntryId('pl1');
|
|
assert.ok(store.getState().order.includes(pid));
|
|
store.dispatch({
|
|
kind: 'syncPresence',
|
|
npcs: [],
|
|
players: [{ playerId: 'pl1', name: 'Hero' }],
|
|
playersVisible: false,
|
|
});
|
|
assert.ok(!store.getState().order.includes(pid));
|
|
assert.ok(store.getState().reserve.includes(pid));
|
|
store.dispatch({
|
|
kind: 'syncPresence',
|
|
npcs: [],
|
|
players: [{ playerId: 'pl1', name: 'Hero' }],
|
|
playersVisible: true,
|
|
});
|
|
assert.ok(store.getState().reserve.includes(pid));
|
|
assert.ok(!store.getState().order.includes(pid));
|
|
});
|
|
|
|
void test('initiative: conditions unique + reserve/restore', () => {
|
|
const store = new InitiativeSessionStore();
|
|
store.dispatch({ kind: 'addManual', name: 'X' });
|
|
const id = store.getState().order[0]!;
|
|
store.dispatch({ kind: 'addCondition', id, conditionId: 'poisoned' });
|
|
store.dispatch({ kind: 'addCondition', id, conditionId: 'poisoned' });
|
|
assert.deepEqual(store.getState().conditions[id], ['poisoned']);
|
|
store.dispatch({ kind: 'moveToReserve', id });
|
|
assert.deepEqual(store.getState().order, []);
|
|
assert.deepEqual(store.getState().reserve, [id]);
|
|
store.dispatch({ kind: 'restoreFromReserve', id });
|
|
assert.deepEqual(store.getState().order, [id]);
|
|
assert.deepEqual(store.getState().conditions[id], ['poisoned']);
|
|
});
|
|
|
|
void test('initiative: clear keeps enabled', () => {
|
|
const store = new InitiativeSessionStore();
|
|
store.dispatch({ kind: 'setEnabled', enabled: true });
|
|
store.dispatch({ kind: 'addManual', name: 'Z' });
|
|
store.clear();
|
|
assert.equal(store.getState().enabled, true);
|
|
assert.deepEqual(store.getState().order, []);
|
|
});
|
|
|
|
void test('initiative: despawn removes npc entry', () => {
|
|
const store = new InitiativeSessionStore();
|
|
store.dispatch({
|
|
kind: 'syncPresence',
|
|
npcs: [{ placementId: 'p1', npcId: 'n1', name: 'Goblin', avatarAssetId: null }],
|
|
players: [],
|
|
playersVisible: false,
|
|
});
|
|
store.dispatch({
|
|
kind: 'syncPresence',
|
|
npcs: [],
|
|
players: [],
|
|
playersVisible: false,
|
|
});
|
|
assert.deepEqual(store.getState().order, []);
|
|
assert.deepEqual(Object.keys(store.getState().entries), []);
|
|
});
|