Files
Dune/tests/choam-skills-ghola-fixture.ts

92 lines
4.8 KiB
TypeScript

import assert from 'node:assert/strict';
import { applyAction, type Action, type Game } from '../game/engine';
import {
assertChoamSkillsCustody,
choamSkillsPlayer,
completedChoamSkillsGame,
reloadChoamSkillsGame,
} from './choam-skills-fixture';
export const actChoamGhola = (game: Game, owner: string, action: Action): Game =>
reloadChoamSkillsGame(applyAction(reloadChoamSkillsGame(game), owner, action));
export function passChoamGholaResponses(game: Game): Game {
for (let step = 0; game.response && step < 20; step++) {
const player = game.players.find(candidate => !game.response!.passed.includes(candidate.id));
assert.ok(player);
game = actChoamGhola(game, player.id, { type: 'passResponse' });
}
assert.equal(game.response, null);
return game;
}
/** Genuine setup, conserved staged positions, then an actual lethal battle and phase-end sale. */
export function stagedMarketGhola(
initial = completedChoamSkillsGame({ requestedSkill: 'warmaster' }),
keepAssignedSkill = false,
) {
let game = reloadChoamSkillsGame(initial);
const owner = game.players.find(player => player.faction === 'choam')!.id;
const opponent = game.players.find(player => player.faction === 'emperor')!.id;
const assignment = game.leaderSkills!.assignments.find(candidate => candidate.owner === owner)!;
assert.equal(assignment.skill, 'warmaster');
const leader = keepAssignedSkill
? choamSkillsPlayer(game, owner).leaders.find(candidate => candidate.id !== assignment.leader)!.id
: assignment.leader;
const lostSkill = assignment.skill;
for (const player of game.players) {
game.deck.push(...player.hand);
player.hand = [];
player.forces = [owner, opponent].includes(player.id) ? { 'wind_pass:14': 8 } : {};
player.reserves = [owner, opponent].includes(player.id) ? 12 : 20;
player.tanks = 0;
player.battleLosses = 0;
player.spice = 20;
}
Object.assign(game, { phase: 6, active: owner, storm: 18, ready: [],
order: [owner, opponent, ...game.players.map(player => player.id).filter(id => ![owner, opponent].includes(id))],
decision: null, response: null, phaseOpening: null, spice: {} });
const take = (id: string, predicate: (card: Game['deck'][number]) => boolean) => {
const index = game.deck.findIndex(predicate);
assert.ok(index >= 0);
const card = game.deck.splice(index, 1)[0];
choamSkillsPlayer(game, id).hand.push(card);
return card.id;
};
const ghola = take(owner, card => card.effect === 'ghola');
const sale = take(owner, card => card.kind === 'worthless');
const poison = take(opponent, card => card.kind === 'poison');
const karama = take(opponent, card => card.effect === 'karama');
assertChoamSkillsCustody(game);
game = actChoamGhola(game, owner, { type: 'chooseBattle', territory: 'wind_pass', target: opponent });
for (let step = 0; step < 30; step++) {
if (game.response) game = passChoamGholaResponses(game);
else if (game.decision?.kind === 'mentatQuestion')
game = actChoamGhola(game, game.decision.player, { type: 'decision', event: game.decision.event, decline: true });
else if (game.decision?.kind === 'leaderSkillVisibility')
game = actChoamGhola(game, game.decision.player, { type: 'leaderSkillVisibility', event: game.decision.event, hide: true });
else if (game.battle?.preparation)
game = actChoamGhola(game, game.battle.preparation.owner, { type: 'declineBattlePower' });
else break;
}
assert.equal(game.decision, null);
assert.equal(game.battle?.preparation, undefined);
game = actChoamGhola(game, owner, { type: 'battlePlan', dial: 0, leader });
const opponentLeader = choamSkillsPlayer(game, opponent).leaders.find(candidate =>
!candidate.dead && !game.leaderSkills!.assignments.some(skill => skill.leader === candidate.id))!;
game = actChoamGhola(game, opponent, { type: 'battlePlan', dial: 4, leader: opponentLeader.id, weapon: poison });
game = actChoamGhola(game, owner, { type: 'traitorCall', call: false });
game = actChoamGhola(game, opponent, { type: 'traitorCall', call: false });
assert.equal(game.decision?.kind, 'battleCards');
game = actChoamGhola(game, opponent, { type: 'decision', discard: [] });
assert.equal(choamSkillsPlayer(game, owner).leaders.find(candidate => candidate.id === leader)!.dead, true);
assert.equal(game.leaderSkills!.assignments.some(candidate => candidate.owner === owner), keepAssignedSkill);
assert.equal(game.leaderSkills!.deck.filter(skill => skill === lostSkill).length, keepAssignedSkill ? 0 : 1);
assert.equal(game.phase, 6);
assert.equal(game.decision?.kind, 'choamMarket');
game = actChoamGhola(game, owner, { type: 'decision', mode: 'sell', card: sale });
assert.equal(game.response?.kind, 'choamSale');
assertChoamSkillsCustody(game);
return { game, owner, opponent, leader, ghola, sale, karama, lostSkill };
}