78 lines
4.5 KiB
TypeScript
78 lines
4.5 KiB
TypeScript
import assert from 'node:assert/strict';
|
|
import { applyAction, createGame, joinGame, newPlayer, type Action, type Game } from '../game/engine';
|
|
import { territory } from '../game/board';
|
|
import { placeTerror } from '../game/moritani-terror';
|
|
import { nextStrongholdFactionsNativeStep } from './fixture-stronghold-factions';
|
|
|
|
export const extortionSeat = (game: Game, id: string) => {
|
|
const player = game.players.find(row => row.id === id); assert.ok(player); return player;
|
|
};
|
|
export const extortionAct = (game: Game, id: string, action: Action) => applyAction(game, id, action);
|
|
export function extortionEvent(game: Game): string {
|
|
assert.ok(game.decision?.kind === 'moritaniExtortion');
|
|
return game.decision.event;
|
|
}
|
|
export function extortionPayment(game: Game, pay: boolean): Action {
|
|
return {type:'decision', event:extortionEvent(game), pay};
|
|
}
|
|
export function finishExtortionGiftResponse(game: Game): Game {
|
|
for (let count = 0; game.response && count < 30; count++) {
|
|
const responder = game.players.find(player => !game.response!.passed.includes(player.id)); assert.ok(responder);
|
|
game = extortionAct(game, responder.id, {type:'passResponse'});
|
|
}
|
|
assert.equal(game.response, null);
|
|
return game;
|
|
}
|
|
|
|
/** A fresh public E3 Basic/Advanced start, genuine setup, shipment and Terror
|
|
* revelation. The alliance, movement boundary, token placement and wallets are
|
|
* staged; the original Extortion owner and subsequent choices are real. */
|
|
export function createExtortionBotPriority(advanced: boolean,
|
|
options: {unallied?: boolean; emperorSpice?: number; autopilot?: boolean} = {}) {
|
|
let game = createGame('EXTORTIONBOTPRIORITY', newPlayer('m', 'Moritani', 'moritani'), advanced, ['ecaz']);
|
|
for (const [id, name, faction] of [['e','Emperor','emperor'], ['a','Atreides','atreides'],
|
|
['h','Harkonnen','harkonnen']] as const) joinGame(game, newPlayer(id, name, faction));
|
|
for (const player of game.players) game = extortionAct(game, player.id, {type:'ready'});
|
|
game = extortionAct(game, 'm', advanced ? {type:'start', advancedPreview:true} : {type:'start'});
|
|
for (let count = 0; game.status === 'setup' && count < 100; count++) {
|
|
if (game.decision?.kind === 'moritaniSetup') game = extortionAct(game, 'm',
|
|
{type:'decision', territory:'sietch_tabr', sector:territory('sietch_tabr').sectors[0]});
|
|
else {
|
|
const step = nextStrongholdFactionsNativeStep(game); assert.ok(step);
|
|
game = extortionAct(game, step.actor, step.action);
|
|
}
|
|
}
|
|
assert.equal(game.status, 'playing');
|
|
if (!options.unallied) { extortionSeat(game, 'e').ally = 'a'; extortionSeat(game, 'a').ally = 'e'; }
|
|
const token = game.moritaniTerror!.tokens.find(row => row.kind === 'extortion'); assert.ok(token);
|
|
game.moritaniTerror = placeTerror(game.moritaniTerror!, token.id, 'habbanya_ridge_sietch', 1);
|
|
Object.assign(game, {phase:5, turn:2, storm:18, order:['e','a','h','m'], active:'e',
|
|
movementRemaining:['e','a','h','m'], response:null, decision:null, phaseOpening:null, ready:[]});
|
|
extortionSeat(game, 'e').spice = 10; extortionSeat(game, 'a').spice = 2;
|
|
const harkonnen = extortionSeat(game, 'h');
|
|
let card = harkonnen.hand.find(row => row.effect === 'karama');
|
|
if (!card) {
|
|
const sourceOwner = game.players.find(player => player.id !== 'h' && player.hand.some(row => row.effect === 'karama'));
|
|
const source = sourceOwner?.hand ?? game.deck, index = source.findIndex(row => row.effect === 'karama');
|
|
assert.ok(index >= 0); [card] = source.splice(index, 1); harkonnen.hand.push(card);
|
|
}
|
|
const karama = card.id;
|
|
game = extortionAct(game, 'e', {type:'ship', territory:'habbanya_ridge_sietch', sector:17, amount:1});
|
|
assert.equal(game.decision?.kind, 'moritaniTerror');
|
|
game = extortionAct(game, 'm', {type:'decision', reveal:true});
|
|
game.phase = 7; game.ready = [];
|
|
for (const player of game.players) game = extortionAct(game, player.id, {type:'ready'});
|
|
assert.equal(game.phase, 8);
|
|
assert.equal(game.decision?.kind, 'moritaniPlacement');
|
|
game = extortionAct(game, 'm', {type:'decision', decline:true});
|
|
assert.equal(game.decision?.kind, 'moritaniExtortion');
|
|
assert.equal(game.decision?.player, 'e');
|
|
if (options.autopilot) extortionSeat(game, 'a').autopilot = 'Easy';
|
|
else extortionSeat(game, 'a').bot = 'Easy';
|
|
if (options.emperorSpice !== undefined) extortionSeat(game, 'e').spice = options.emperorSpice;
|
|
game = extortionAct(game, 'e', extortionPayment(game, false));
|
|
assert.equal(game.decision?.kind, 'moritaniExtortion');
|
|
assert.equal(game.decision?.player, 'a');
|
|
return {game, token:token.id, karama};
|
|
}
|