70 lines
3.7 KiB
TypeScript
70 lines
3.7 KiB
TypeScript
import assert from 'node:assert/strict';
|
||
import { test } from 'node:test';
|
||
import { applyAction, viewGame, type Game } from '../game/engine';
|
||
import {
|
||
completeHajrReplay, createHajrReplayFixture, hajrReplayPlayer,
|
||
} from './fixture-hajr-replay';
|
||
|
||
/** This reaches the native Advanced immediate-after-movement Hajr window via
|
||
* setup, auction, shipment, actual Hajr play, Box recovery and movement. The
|
||
* genuine fixture has spent its spice on those actions; only the payer's spice
|
||
* is explicitly staged so this independent deal payment can be exercised. */
|
||
function windowGame() {
|
||
const fixture = createHajrReplayFixture({ advanced: true });
|
||
const game = completeHajrReplay(fixture).beforeSecondHajr;
|
||
const payer = game.players.find(player => player.id === fixture.owner)!;
|
||
const recipient = game.players.find(player => player.id !== payer.id && !player.bot &&
|
||
player.id !== payer.ally && player.ally !== payer.id);
|
||
assert.ok(recipient);
|
||
assert.equal(payer.spice, 0, 'The original purchases, shipment and Box consumed the fixture spice.');
|
||
payer.spice = 4; // Controlled funding only; the native movement/window is not staged.
|
||
assert.ok(payer.hajrWindow);
|
||
assert.equal(available(game, payer.id), true);
|
||
return { fixture, game, payer: payer.id, recipient: recipient.id };
|
||
}
|
||
|
||
function available(game: Game, id: string) {
|
||
return viewGame(game, id).players.find(player => player.id === id)!.hajrAvailable;
|
||
}
|
||
|
||
function offer(game: Game, from: string, to: string, payer: string, recipient: string): Game {
|
||
return applyAction(game, from, {
|
||
type: 'dealOffer', target: to, terms: 'An immediate one-spice bribe.',
|
||
payment: { kind: 'immediateBribe', payer, recipient, amount: 1 },
|
||
});
|
||
}
|
||
|
||
void test('another seat accepting a prior-consented payment preserves the payer’s native Hajr opportunity', () => {
|
||
const { fixture, game: initial, payer, recipient } = windowGame();
|
||
const window = structuredClone(hajrReplayPlayer(initial).hajrWindow);
|
||
const beforeSpice = hajrReplayPlayer(initial).spice;
|
||
const beforeBribes = initial.players.find(player => player.id === recipient)!.bribes;
|
||
const offered = offer(initial, payer, recipient, payer, recipient);
|
||
assert.deepEqual(hajrReplayPlayer(offered).hajrWindow, window);
|
||
const deal = offered.deals!.at(-1)!;
|
||
const paid = applyAction(offered, recipient, { type: 'dealRespond', deal: deal.id, accept: true });
|
||
assert.equal(paid.deals!.at(-1)!.status, 'active');
|
||
assert.equal(hajrReplayPlayer(paid).spice, beforeSpice - 1);
|
||
assert.equal(paid.players.find(player => player.id === recipient)!.bribes, beforeBribes + 1);
|
||
assert.deepEqual(hajrReplayPlayer(paid).hajrWindow, window);
|
||
assert.equal(available(paid, payer), true);
|
||
const played = applyAction(paid, payer, { type: 'card', card: fixture.hajr });
|
||
assert.equal(hajrReplayPlayer(played).hajrPlays, 2);
|
||
assert.equal(hajrReplayPlayer(played).spice, beforeSpice - 1);
|
||
assert.equal(played.players.find(player => player.id === recipient)!.bribes, beforeBribes + 1);
|
||
});
|
||
|
||
void test('the payer’s own voluntary bribe or final acceptance closes the immediate Hajr window', () => {
|
||
const { game: initial, payer, recipient } = windowGame();
|
||
const direct = applyAction(initial, payer, { type: 'bribe', target: recipient, amount: 1 });
|
||
assert.equal(hajrReplayPlayer(direct).hajrWindow, undefined);
|
||
assert.equal(available(direct, payer), false);
|
||
|
||
const offered = offer(initial, recipient, payer, payer, recipient);
|
||
assert.equal(available(offered, payer), true);
|
||
const accepted = applyAction(offered, payer, { type: 'dealRespond', deal: offered.deals!.at(-1)!.id, accept: true });
|
||
assert.equal(hajrReplayPlayer(accepted).hajrWindow, undefined);
|
||
assert.equal(available(accepted, payer), false);
|
||
assert.equal(hajrReplayPlayer(accepted).spice, 3);
|
||
});
|