Connect native Guild and BG own-arrival continuations

This commit is contained in:
Quintine committed 2026-10-15 19:53:15 +11:00
1 parent e265af3cb3
commit c10fe0b48c
19 files changed
+1051 -268

No files matched your search

+3 -85
View File
@@ -2,81 +2,20 @@ import assert from 'node:assert/strict';
import test from 'node:test';
import { applyAction, type Action, type Game } from '../game/engine';
import {
addShipmentArrivalAmbassador,
legacyGuildArrival,
richeseNoFieldArrivalAction,
shipmentArrivalAction,
shipmentArrivalGame,
shipmentArrivalPlayer,
shipmentArrivalReload,
shipmentArrivalResources,
} from './fixture-deferred-shipment-arrival';
const overlap = /Ambassadors combined with another arrival reaction/;
function reject(g: Game, player: string, action: Action, pattern: RegExp) {
function reject(g: Game, player: string, action: Action) {
const before = structuredClone(g);
assert.throws(() => applyAction(g, player, action), pattern);
assert.throws(() => applyAction(g, player, action));
assert.deepEqual(g, before);
}
void test('an ordinary Guild shipment rejects a known Ambassador and advisor overlap before declaration or payment', (t) => {
const g = shipmentArrivalGame();
addShipmentArrivalAmbassador(g);
const resources = structuredClone(shipmentArrivalResources(g));
const uuid = t.mock.method(crypto, 'randomUUID', () => {
throw Error('Unsupported shipment allocated an event');
});
reject(g, 'guild', shipmentArrivalAction, overlap);
assert.deepEqual(shipmentArrivalResources(g), resources);
assert.equal(g.pendingShipment, null);
assert.equal(g.decision, null);
assert.equal(uuid.mock.callCount(), 0);
});
void test('an own Richese No-Field rejects the unsupported arrival before saving its private cancellation response', () => {
const g = shipmentArrivalGame();
g.active = 'richese';
shipmentArrivalPlayer(g, 'richese').shipped = false;
addShipmentArrivalAmbassador(g);
const action = richeseNoFieldArrivalAction(g);
const before = structuredClone(g);
assert.throws(() => applyAction(g, 'richese', action), overlap);
assert.deepEqual(g, before);
assert.equal(g.pendingShipment, null);
assert.equal(g.response, null);
assert.equal(g.decision, null);
assert.equal(shipmentArrivalPlayer(g, 'richese').noField!.deployed, null);
});
void test('a saved Guild allowance returns only the uncommitted ordinary shipment and permits a safe replacement', () => {
const g = legacyGuildArrival();
const before = structuredClone(g);
const resources = structuredClone(shipmentArrivalResources(g));
const returned = applyAction(shipmentArrivalReload(g), 'guild', {
type: 'decision',
allow: true,
});
assert.deepEqual(g, before);
assert.deepEqual(shipmentArrivalResources(returned), resources);
assert.equal(returned.pendingShipment, null);
assert.equal(returned.decision, null);
assert.equal(shipmentArrivalPlayer(returned, 'guild').shipped, false);
assert.deepEqual(shipmentArrivalPlayer(returned, 'guild').forces, {});
assert.match(returned.log.at(-1)!.text, overlap);
assert.match(
returned.log.at(-1)!.text,
/No forces, spice, cards or shipment allowance were spent/,
);
const retried = applyAction(returned, 'guild', {
...shipmentArrivalAction,
territory: 'polar_sink',
sector: 0,
});
assert.equal(retried.decision?.kind, 'guildShipment');
assert.equal(retried.pendingShipment?.territory, 'polar_sink');
});
void test('a supported Guild allowance still commits once and opens the advisor choice', () => {
let g = shipmentArrivalGame();
@@ -99,27 +38,6 @@ void test('a supported Guild allowance still commits once and opens the advisor
void test('a malformed saved shipment remains rejected and is not treated as a recoverable arrival overlap', () => {
const g = legacyGuildArrival();
g.pendingShipment!.cost++;
reject(
g,
'guild',
{ type: 'decision', allow: true },
/declared shipment price is no longer current/,
);
reject(g, 'guild', { type: 'decision', allow: true });
});
void test('forged or null special receipts cannot enter the ordinary legacy return path', () => {
for (const corrupt of [
(g: Game) => {
g.pendingShipment!.ambassadorEvent = 'forged';
},
(g: Game) => {
g.pendingShipment!.guildSecretEvent = null as unknown as string;
},
]) {
const g = legacyGuildArrival();
corrupt(g);
reject(g, 'guild', { type: 'decision', allow: true }, overlap);
assert.ok(g.pendingShipment);
assert.equal(g.decision?.kind, 'guildShipment');
}
});