51 lines
3.1 KiB
TypeScript
51 lines
3.1 KiB
TypeScript
import assert from 'node:assert/strict';
|
|
import test from 'node:test';
|
|
import { viewGame } from '../game/engine';
|
|
import { actTruthAlliance as act, advanceTruthAlliance as advance, createTruthAllianceFixture,
|
|
truthAllianceClean as clean, truthAllianceInventory as inventory, truthAlliancePlayer as player } from './fixture-truth-alliance';
|
|
import { declareTruthBribe } from './fixture-truth-bribe';
|
|
|
|
/** The original Basic H/A/E setup, real worm/Nexus alliance and later Bidding
|
|
* from the shared fixture. The offer, Truthtrance question, answer and final
|
|
* consent are all real actions; no wallet, pledge or commitment is staged. */
|
|
void test('a previously offered paid travel deal can release a later unaffordable pledge on recipient consent', () => {
|
|
const f = createTruthAllianceFixture({ consent: 'allied' });
|
|
let game = advance(f.game, state => state.phase === 3 && !!state.auction && clean(state));
|
|
assert.equal(player(game, f.target).ally, f.partner);
|
|
assert.equal(player(game, f.partner).ally, f.target);
|
|
assert.equal(player(game, f.asker).ally, null);
|
|
const minimum = 4, initialCash = player(game, f.target).spice;
|
|
const amount = initialCash - minimum + 1;
|
|
assert.ok(amount > 0);
|
|
game = act(game, f.target, { type: 'dealOffer', target: f.asker,
|
|
terms: 'Immediate payment for a current-turn travel restriction.',
|
|
payment: { kind: 'immediateBribe', payer: f.target, recipient: f.asker, amount },
|
|
travel: { kind: 'ship', territory: 'polar_sink', minimum: 1, answer: false } });
|
|
const offer = game.deals?.at(-1); assert.ok(offer);
|
|
game = declareTruthBribe(f, game).game;
|
|
assert.ok(viewGame(game, f.asker).truthPledgeTargets.includes(f.target));
|
|
game = act(game, f.asker, { type: 'truthAsk', question: { kind: 'pledgeAid', target: f.target,
|
|
turn: game.turn, phase: game.phase, ally: f.partner, minimum } });
|
|
assert.ok(viewGame(game, f.target).truthPledgeAnswers?.includes('yes'));
|
|
game = act(game, f.target, { type: 'truthAnswer', answer: 'yes' });
|
|
const pledge = game.pledgePromises?.at(-1); assert.ok(pledge);
|
|
assert.ok(!pledge.fulfilled && !pledge.released);
|
|
|
|
// A new voluntary payment cannot evade the later pledge, but the original
|
|
// offer already consented to payment before that answer was made.
|
|
const before = structuredClone(game);
|
|
assert.throws(() => act(game, f.target, { type: 'bribe', target: f.asker, amount }));
|
|
assert.deepEqual(game, before);
|
|
const incoming = player(game, f.asker).bribes;
|
|
const next = act(game, f.asker, { type: 'dealRespond', deal: offer.id, accept: true });
|
|
assert.equal(next.deals?.find(deal => deal.id === offer.id)?.status, 'active');
|
|
assert.equal(player(next, f.target).spice, initialCash - amount);
|
|
assert.equal(player(next, f.asker).bribes, incoming + amount);
|
|
assert.deepEqual(next.aid[f.target], before.aid[f.target]);
|
|
assert.equal(next.pledgePromises?.at(-1)?.released, true);
|
|
assert.ok(!next.pledgePromises?.at(-1)?.fulfilled);
|
|
assert.equal(next.travelPromises?.filter(row => row.sourceDeal === offer.id).length, 1);
|
|
assert.equal(viewGame(next, f.asker).dealTravelStatus[offer.id], 'pending');
|
|
assert.deepEqual(inventory(next), f.originalCards);
|
|
});
|