46 lines
2.5 KiB
TypeScript
46 lines
2.5 KiB
TypeScript
import assert from 'node:assert/strict';
|
|
import test from 'node:test';
|
|
import { viewGame, type Game } from '../game/engine';
|
|
import {
|
|
actMentatBribe as act, createMentatBribeFixture as fixture,
|
|
mentatBribeInventory as inventory, mentatBribePlayer as player,
|
|
} from './fixture-mentat-bribes';
|
|
|
|
function agree(game: Game, proposer: string, payer: string) {
|
|
const offered = act(game, proposer, { type: 'dealOffer', target: payer, terms: 'Pay this turn.',
|
|
payment: { kind: 'deferredBribe', payer, recipient: proposer, amount: 4, dueTurn: game.turn } });
|
|
const id = offered.deals!.at(-1)!.id;
|
|
return { game: act(offered, payer, { type: 'dealRespond', deal: id, accept: true }), id };
|
|
}
|
|
const spice = (game: Game) => game.players.reduce((sum, seat) => sum + seat.spice + seat.bribes, 0);
|
|
|
|
for (const pick of ['first', 'second'] as const) {
|
|
void test(`external shortage preserves both individually payable deals until payer chooses ${pick}`, () => {
|
|
// The fixture reaches actual Basic Mentat with Emperor's original ten
|
|
// spice. Both independent agreements are really offered and accepted.
|
|
const f = fixture(), first = agree(f.game, f.asker, f.target);
|
|
const second = agree(first.game, f.asker, f.target);
|
|
const staged = structuredClone(second.game), target = player(staged, f.target), other = player(staged, f.opponent);
|
|
const originalSpice = spice(staged);
|
|
// Model an external loss: transfer five existing spice, not create or
|
|
// destroy it. Each four-spice payment is now possible on its own.
|
|
target.spice -= 5; other.spice += 5;
|
|
const waiting = act(staged, f.opponent, { type: 'ready' });
|
|
assert.equal(waiting.deals!.find(row => row.id === first.id)!.paymentStatus, 'pending');
|
|
assert.equal(waiting.deals!.find(row => row.id === second.id)!.paymentStatus, 'pending');
|
|
const options = viewGame(waiting, f.target).deferredDealPaymentOptions;
|
|
assert.equal(options[first.id]?.blocked, null);
|
|
assert.equal(options[second.id]?.blocked, null);
|
|
|
|
const chosen = pick === 'first' ? first.id : second.id;
|
|
const unchosen = pick === 'first' ? second.id : first.id;
|
|
const paid = act(waiting, f.target, { type: 'dealPay', deal: chosen });
|
|
assert.equal(paid.deals!.find(row => row.id === chosen)!.paymentStatus, 'paid');
|
|
assert.equal(paid.deals!.find(row => row.id === unchosen)!.paymentStatus, 'void');
|
|
assert.equal(player(paid, f.target).spice, 1);
|
|
assert.equal(player(paid, f.asker).bribes, 4);
|
|
assert.equal(spice(paid), originalSpice);
|
|
assert.deepEqual(inventory(paid), f.originalCards);
|
|
});
|
|
}
|