Files
Dune/tests/advanced-mentat-moritani-victory.test.ts
T
Quintine 64706cc7e0
Verify and publish checkpoint container / container (push) Successful in 10m42s
Check Advanced victory after Mentat actions
2026-10-29 09:15:34 +11:00

98 lines
4.8 KiB
TypeScript

import assert from 'node:assert/strict';
import test from 'node:test';
import { applyAction, type Game } from '../game/engine';
import { territory } from '../game/board';
import { createMoritaniStrongholdsFixture } from './fixture-moritani-strongholds';
/** This inherited fixture uses real Advanced Moritani/Guild/Emperor setup and
* native phase actions through the opening Moritani placement decision, with
* the Stronghold Cards module. Only physical board groups are staged after
* that opening to expose a rare three-stronghold Guild victory. The prevention
* case also transfers one original Karama to Guild's hand without duplication.
* It is not a naturally earned full game or module-combination certification. */
function position() {
const fixture = createMoritaniStrongholdsFixture();
const game = structuredClone(fixture.beforePlacement);
assert.equal(game.phase, 8); assert.equal(game.decision?.kind, 'moritaniPlacement');
for (const player of game.players) {
player.reserves += Object.values(player.forces).reduce((sum, count) => sum + count, 0);
player.forces = {};
if (player.elites) {
player.elites.reserves += Object.values(player.elites.forces).reduce((sum, count) => sum + count, 0);
player.elites.forces = {};
}
}
const winner = game.players.find(player => player.faction === 'guild')!;
for (const name of ['arrakeen', 'carthag', 'sietch_tabr'])
winner.forces[`${name}:${territory(name).sectors[0]}`] = 1;
winner.reserves -= 3;
const owner = game.players.find(player => player.faction === 'moritani')!;
return { game, winner: winner.id, owner: owner.id };
}
function pending(game: Game) {
assert.equal(game.phase, 8); assert.equal(game.status, 'playing');
assert.deepEqual(game.winner, []); assert.ok(!game.victoryContinuation);
}
function finish(game: Game, winner: string) {
const turn = game.turn;
for (const player of game.players) game = applyAction(game, player.id, { type: 'ready' });
assert.equal(game.turn, turn); assert.equal(game.status, 'finished');
assert.deepEqual(game.winner, [winner]);
assert.equal(game.strongholdCards?.claimedTurn, turn);
}
function passPlacement(game: Game) {
while (game.response) {
const actor = game.players.find(player => !game.response!.passed.includes(player.id));
assert.ok(actor);
game = applyAction(game, actor.id, { type: 'passResponse' });
}
return game;
}
function stageKarama(game: Game, id: string) {
const player = game.players.find(seat => seat.id === id)!;
const held = player.hand.find(card => card.effect === 'karama');
if (held) return held.id;
const deckIndex = game.deck.findIndex(card => card.effect === 'karama');
let card = deckIndex >= 0 ? game.deck.splice(deckIndex, 1)[0] : undefined;
if (!card) {
const donor = game.players.find(seat => seat.id !== id && seat.hand.some(candidate => candidate.effect === 'karama'));
assert.ok(donor, 'One original Karama is still in the unplayed supply');
card = donor.hand.splice(donor.hand.findIndex(candidate => candidate.effect === 'karama'), 1)[0];
}
if (player.hand.length >= 4) game.deck.push(player.hand.pop()!);
player.hand.push(card);
return card.id;
}
void test('Advanced Moritani declining placement leaves the winner pending until Mentat closes', () => {
const f = position();
const game = applyAction(f.game, f.owner, { type: 'decision', decline: true });
pending(game); assert.equal(game.decision, null);
assert.equal(game.moritaniTerror!.placementTurn, game.turn);
finish(game, f.winner);
});
void test('Advanced Moritani placement completes before the later victory check', () => {
const f = position();
const token = f.game.moritaniTerror!.tokens.find(candidate => candidate.status === 'available')!;
let game = applyAction(f.game, f.owner, { type: 'decision', token: token.id, territory: 'tueks_sietch' });
game = passPlacement(game);
pending(game); assert.equal(game.moritaniTerror!.placementTurn, game.turn);
assert.equal(game.moritaniTerror!.tokens.find(candidate => candidate.id === token.id)?.location, 'tueks_sietch');
finish(game, f.winner);
});
void test('Advanced Moritani placement canceled by Karama still leaves victory until Mentat closes', () => {
const f = position(), card = stageKarama(f.game, f.winner);
const token = f.game.moritaniTerror!.tokens.find(candidate => candidate.status === 'available')!;
const original = structuredClone(f.game.moritaniTerror!.tokens);
let game = applyAction(f.game, f.owner, { type: 'decision', token: token.id, territory: 'tueks_sietch' });
assert.equal(game.response?.kind, 'moritaniPlacement');
game = applyAction(game, f.winner, { type: 'card', mode: 'cancel', card });
pending(game); assert.equal(game.moritaniTerror!.placementTurn, game.turn);
assert.deepEqual(game.moritaniTerror!.tokens, original);
assert.ok(game.discard.some(candidate => candidate.id === card));
finish(game, f.winner);
});