55 lines
3.7 KiB
TypeScript
55 lines
3.7 KiB
TypeScript
import assert from 'node:assert/strict';
|
|
import test from 'node:test';
|
|
import { viewGame } from '../game/engine';
|
|
import { windowCardOpportunity } from '../game/window-card-play';
|
|
import { createTruthBidFixture, declareTruthBid, actTruthBid as act, advanceTruthBid as advance,
|
|
truthBidClean as clean, truthBidPlayer as player, truthBidInventory as inventory } from './fixture-truth-bid';
|
|
import { truthTraitorDecisionTraitors as traitors } from './fixture-truth-traitor-decision';
|
|
import { askTruthTurnKaramaShipment as ask, truthTurnKaramaShipmentGroup as group,
|
|
truthTurnKaramaShipmentPlay as play, truthTurnKaramaShipmentPayment as payment } from './fixture-truth-turn-karama-shipment';
|
|
|
|
/** Original unopened H2/A1/E1/G1 deal, genuine remaining auction/Revival turns,
|
|
* and actual pre-answer bribe. No played purse, response or promise is installed. */
|
|
function source(remaining: 2 | 4) {
|
|
const f = createTruthBidFixture({ advanced: true, extraGuild: true, targetKarama: true, window: 'active' });
|
|
const actions = structuredClone(f.sourceActions);
|
|
let game = advance(f.game, state => state.phase === 5 && state.active === f.target && clean(state), actions);
|
|
game = act(game, f.target, { type: 'bribe', target: f.asker, amount: 10 - remaining }, actions);
|
|
assert.equal(player(game, f.target).spice, remaining);
|
|
assert.equal(traitors(game).length, 20); assert.deepEqual(inventory(game), f.originalCards);
|
|
const window = windowCardOpportunity(game, 'karamaShipment'); assert.ok(window);
|
|
const declared = declareTruthBid(f, game); actions.push(...declared.actions);
|
|
game = ask(declared.game, f.asker, f.target, group('or', play(window.source), payment(f.asker)), actions);
|
|
assert.ok(viewGame(game, f.target).truthTurnActionAnswers?.includes('yes'));
|
|
game = act(game, f.target, { type: 'truthAnswer', answer: 'yes' }, actions);
|
|
return { f, game, actions, window };
|
|
}
|
|
|
|
void test('an own shipment cannot spend its remaining payment alternative before a foreign Guild stop decision', () => {
|
|
const { f, game, actions } = source(2), before = structuredClone(game);
|
|
assert.throws(() => act(game, f.target, { type: 'ship', territory: 'polar_sink', sector: 0,
|
|
amount: 1, elite: 0, allyPayment: 0 }, actions), /Truthtrance|completion/);
|
|
assert.deepEqual(game, before);
|
|
let paid = act(game, f.target, { type: 'bribe', target: f.asker, amount: 2 }, actions);
|
|
assert.equal(paid.turnActionPromises![0].fulfilled, true); assert.equal(player(paid, f.target).spice, 0);
|
|
paid = act(paid, f.target, { type: 'endMovement' }, actions);
|
|
assert.equal(paid.discard.filter(card => card.id === f.karama).length, 0);
|
|
assert.deepEqual(inventory(paid), f.originalCards); assert.equal(traitors(paid).length, 20);
|
|
});
|
|
|
|
void test('a funded payment alternative survives actual unpriced delivery and Guild income before being paid', () => {
|
|
const { f, actions, game: initial } = source(4);
|
|
let game = initial;
|
|
game = act(game, f.target, { type: 'ship', territory: 'polar_sink', sector: 0,
|
|
amount: 1, elite: 0, allyPayment: 0 }, actions);
|
|
assert.equal(game.decision?.kind, 'guildShipment');
|
|
assert.equal(game.decision?.player, 'guild'); assert.equal(player(game, f.target).spice, 4);
|
|
game = advance(game, clean, actions);
|
|
assert.equal(player(game, f.target).spice, 2); assert.equal(player(game, f.target).forces['polar_sink:0'], 1);
|
|
assert.equal(game.turnActionPromises![0].released, false);
|
|
game = act(game, f.target, { type: 'bribe', target: f.asker, amount: 2 }, actions);
|
|
assert.equal(player(game, f.target).spice, 0); assert.equal(game.turnActionPromises![0].fulfilled, true);
|
|
assert.ok(player(game, f.target).hand.some(card => card.id === f.karama));
|
|
assert.deepEqual(inventory(game), f.originalCards); assert.equal(traitors(game).length, 20);
|
|
});
|