61 lines
3.1 KiB
TypeScript
61 lines
3.1 KiB
TypeScript
import assert from 'node:assert/strict';
|
|
import test from 'node:test';
|
|
import { createGame, newPlayer, type Game } from '../game/engine';
|
|
import { richeseRevealInterruptSupported as supported } from '../game/richese-reveal-interruption';
|
|
|
|
/** Quote-only staged response; native action and physical continuation are
|
|
* exercised separately by the integration owner. */
|
|
function source(target: 'richese' | 'atreides' = 'atreides'): Game {
|
|
const game = createGame('REVEALEXTRAREVIVAL', newPlayer('richese', 'Richese', 'richese'), false, ['choam']);
|
|
game.players.push(newPlayer('emperor', 'Emperor', 'emperor'), newPlayer('atreides', 'Atreides', 'atreides'));
|
|
game.status = 'playing'; game.phase = 4; game.turn = 2;
|
|
const emperor = game.players.find(player => player.id === 'emperor')!;
|
|
const recipient = game.players.find(player => player.id === target)!;
|
|
emperor.ally = target; recipient.ally = emperor.id; recipient.tanks = 2; emperor.spice = 10;
|
|
game.response = { kind: 'emperorRevival', owner: emperor.id, recipient: target, amount: 2, elite: 0, passed: [] };
|
|
return game;
|
|
}
|
|
|
|
void test('a clean Emperor extra revival preserves the accepted response for either ally', () => {
|
|
for (const recipient of ['richese', 'atreides'] as const) {
|
|
const game = source(recipient), before = structuredClone(game);
|
|
assert.equal(supported(game), true, recipient);
|
|
assert.deepEqual(game, before);
|
|
}
|
|
});
|
|
|
|
void test('extra revival admission checks its original funding, physical forces and mutual ally', () => {
|
|
for (const mutate of [
|
|
(g: Game) => { g.phase = 3; },
|
|
(g: Game) => { g.response!.owner = 'atreides'; },
|
|
(g: Game) => { g.response!.recipient = 'emperor'; },
|
|
(g: Game) => { g.players.find(p => p.id === 'atreides')!.ally = null; },
|
|
(g: Game) => { g.players.find(p => p.id === 'atreides')!.tanks = 1; },
|
|
(g: Game) => { g.players.find(p => p.id === 'emperor')!.spice = 3; },
|
|
(g: Game) => { g.response!.amount = 0; },
|
|
(g: Game) => { g.response!.elite = 1; },
|
|
(g: Game) => { g.emperorExtra.atreides = 2; },
|
|
(g: Game) => { g.revivalPrevention = {player:'atreides',turn:g.turn}; },
|
|
(g: Game) => { g.response!.passed = ['atreides','atreides']; },
|
|
(g: Game) => { g.response!.intent = 'other'; },
|
|
(g: Game) => { g.decision = {kind:'auctionPayment',player:'emperor'}; },
|
|
(g: Game) => { g.pendingRevival = {} as NonNullable<Game['pendingRevival']>; },
|
|
]) {
|
|
const game = source(); mutate(game);
|
|
const before = structuredClone(game);
|
|
assert.equal(supported(game), false);
|
|
assert.deepEqual(game, before);
|
|
}
|
|
});
|
|
|
|
void test('Ixian extra revivals retain the special-force price and typed tanks', () => {
|
|
const game = source(); game.expansions.push('ix');
|
|
const recipient = game.players.find(player => player.id === 'atreides')!;
|
|
recipient.faction = 'ixians'; recipient.elites = {reserves:0,tanks:1,forces:{},revived:0};
|
|
game.response!.elite = 1;
|
|
const emperor = game.players.find(player => player.id === 'emperor')!;
|
|
emperor.spice = 5; assert.equal(supported(game), true);
|
|
emperor.spice = 4; assert.equal(supported(game), false);
|
|
emperor.spice = 5; game.response!.elite = 2; assert.equal(supported(game), false);
|
|
});
|