Files
Dune/tests/fixture-nexus-sardaukar.ts
T

123 lines
3.9 KiB
TypeScript

import assert from 'node:assert/strict';
import { applyAction, viewGame, type Game } from '../game/engine';
import {
nexusTraitorFixture,
nexusTraitorInventory,
} from './fixture-nexus-traitors';
import { nexusAllow } from './fixture-nexus-cards';
export function nexusSardaukarFixture(
options: {
seatIds?: [string, string, string];
advanced?: boolean;
opponentFaction?: 'guild' | 'atreides' | 'fremen';
normal?: number;
starred?: number;
emperorCardHolder?: string;
} = {},
): Game {
let g = nexusTraitorFixture({
ownerFaction: 'emperor',
opponentFaction:
options.opponentFaction === 'fremen'
? undefined
: options.opponentFaction,
advanced: options.advanced ?? true,
seatIds: options.seatIds,
phase: 6,
});
const owner = g.players[0],
opponent = g.players[options.opponentFaction === 'fremen' ? 2 : 1];
const normal = options.normal ?? 7,
starred = options.starred ?? 0;
assert.ok(normal >= 0 && normal <= 12 && starred >= 0 && starred <= 5);
const cards = g.nexusCards!.cards!;
const index = cards.deck.indexOf('emperor');
assert.ok(index >= 0);
cards.deck[index] = cards.hands[owner.id]!;
cards.hands[owner.id] = 'emperor';
if (options.emperorCardHolder) {
const holder = g.players.find((p) => p.id === options.emperorCardHolder);
assert.ok(holder && holder.id !== owner.id);
if (cards.hands[holder.id]) cards.deck.push(cards.hands[holder.id]!);
cards.hands[holder.id] = cards.hands[owner.id];
cards.hands[owner.id] = null;
}
for (const p of g.players) {
p.forces = {};
p.reserves = 20;
p.tanks = 0;
if (p.elites) {
p.elites.forces = {};
p.elites.tanks = 0;
p.elites.reserves = p.faction === 'emperor' ? 5 : 3;
}
}
owner.forces = { 'pasty_mesa:5': normal + starred, 'hagga_basin:12': 3 };
owner.reserves = 17 - normal - starred;
if (owner.elites) {
owner.elites.reserves = 5 - starred;
if (starred) owner.elites.forces = { 'pasty_mesa:5': starred };
}
opponent.forces = { 'pasty_mesa:5': 2, 'hagga_basin:12': 2 };
opponent.reserves = 16;
Object.assign(g, {
active: owner.id,
order: g.players.map((p) => p.id),
ready: [],
response: null,
decision: null,
phaseOpening: null,
});
g = applyAction(g, owner.id, {
type: 'chooseBattle',
territory: 'pasty_mesa',
target: opponent.id,
});
for (const id of [owner.id, opponent.id])
if (g.battle!.preLeader && !g.battle!.preLeader.closed)
g = applyAction(g, id, {
type: 'battlePreparationReady',
event: g.battle!.event,
});
while (!g.response && g.battle?.preparation?.kind === 'nexusVoice')
g = applyAction(g, g.battle.preparation.owner, { type: 'declineBattlePower' });
nexusSardaukarInventory(g);
return g;
}
export const nexusSardaukarPlayer = (g: Game) =>
g.players.find((p) => p.faction === 'emperor')!;
export function nexusSardaukarInventory(g: Game): void {
nexusTraitorInventory(g);
const emperor = nexusSardaukarPlayer(g);
if (!emperor.elites) {
assert.equal(g.advanced, false);
return;
}
assert.equal(
emperor.elites!.reserves +
emperor.elites!.tanks +
Object.values(emperor.elites!.forces).reduce((sum, n) => sum + n, 0),
5,
);
}
export function prepareSardaukarBattle(g: Game): Game {
while (g.battle!.preparation)
g = applyAction(g, g.battle!.preparation.owner, {
type: 'declineBattlePower',
});
if (g.decision?.kind === 'fullPlanOffer')
g = applyAction(g, g.decision.player, { type: 'decision', decline: true });
return g;
}
export function beginNexusSardaukar(g: Game): Game {
const owner = nexusSardaukarPlayer(g);
const offer = viewGame(g, owner.id).nexusSardaukar!.offer!;
assert.equal(offer.blocked, null);
return applyAction(g, owner.id, {
type: 'nexusSardaukar',
event: offer.event,
});
}
export const allowNexusSardaukar = nexusAllow;