Files
Dune/tests/truthtrance-no-field-movement-completion.test.ts
T
Quintine ab7a947833
Verify and publish checkpoint container / container (push) Successful in 10m49s
Support bribes during Basic movement decisions
2026-10-29 10:19:31 +11:00

64 lines
3.4 KiB
TypeScript

import assert from 'node:assert/strict';
import test from 'node:test';
import { viewGame, type Action } from '../game/engine';
import type { TruthQuestion } from '../game/truthtrance';
import {
createTruthtranceRichesePromisesFixture as fixture,
actTruthtranceRichesePromises as act,
askTruthtranceRichesePromises as ask,
advanceTruthtranceRichesePromises as advance,
truthtranceRichesePromisesClean as clean,
truthtranceRichesePromisesPlayer as player,
truthtranceRichesePromisesInventory as inventory,
} from './fixture-truthtrance-richese-promises';
void test('a No-Field shipment guide preserves an earlier physical ground-movement Yes', () => {
const f = fixture({kind:'movement'}), source = structuredClone(f.game);
// Controlled conserved supplement: acquire the other original physical
// Truthtrance from the unopened deck, leaving every card in one location.
const at = source.deck.findIndex(card => card.effect === 'truthtrance');
assert.ok(at >= 0);
const extra = source.deck.splice(at, 1)[0];
player(source, f.asker).hand.push(extra);
assert.deepEqual(inventory(source), f.originalInventory);
let game = ask(source, f);
assert.ok(viewGame(game, f.target).truthMovementAnswers?.includes('yes'));
game = advance(act(game, f.target, {type:'truthAnswer', answer:'yes'}), clean);
game = act(game, f.asker, {type:'card', card:extra.id});
game = advance(game, state => state.truthtrance?.stage === 'ask');
const markerQuestion = {kind:'shipment', target:f.target,
claim:{kind:'noField', territory:'arrakeen', sector:10}} as unknown as TruthQuestion;
game = act(game, f.asker, {type:'truthAsk', question:markerQuestion});
assert.ok(viewGame(game, f.target).truthShipmentAnswers?.includes('yes'));
game = advance(act(game, f.target, {type:'truthAnswer', answer:'yes'}), clean);
game = advance(game, state => state.phase === 5 && state.active === f.target && clean(state));
assert.equal(game.movementPromises?.[0].answer, true);
assert.equal(game.shipmentPromises?.[0].answer, true);
assert.equal(game.movementPromises?.[0].released, undefined);
const first = viewGame(game, f.target).shipmentCompletion?.actions[0];
assert.equal(first?.type, 'ship');
assert.equal(typeof first.noField, 'string');
const selected = player(game).noField!.tokens.find(token => token.id === first.noField);
assert.ok(selected && selected.value >= 1, 'A zero marker cannot supply the promised physical movement');
const otherView = viewGame(game, f.asker);
assert.equal(otherView.shipmentCompletion, null);
assert.equal(otherView.richeseNoField?.private, null);
assert.equal(JSON.stringify(otherView).includes(first.noField as string), false);
game = advance(act(game, f.target, first), clean);
assert.equal(game.shipmentPromises![0].fulfilled, true);
// Follow the same private legal guidance to reveal the marker and move its
// actual physical forces; neither promise is satisfied by the marker alone.
for (let step = 0; !game.movementPromises![0].fulfilled && step < 4; step++) {
const next: Action | undefined = viewGame(game, f.target).movementPromisePolicy?.[0];
assert.ok(next, 'An owned completion must remain available after the shipment');
game = advance(act(game, f.target, next), clean);
}
assert.equal(game.movementPromises![0].fulfilled, true);
assert.equal(game.movementPromises![0].released, undefined);
assert.ok(player(game).forces['carthag:11'] >= 1);
assert.deepEqual(inventory(game), f.originalInventory);
});