62 lines
3.3 KiB
TypeScript
62 lines
3.3 KiB
TypeScript
import assert from 'node:assert/strict';
|
|
import {
|
|
applyAction, createGame, initializeSemutaGameForAudit, joinGame, newPlayer,
|
|
type Action, type Game,
|
|
} from '../game/engine';
|
|
import { SEMUTA_DRUG_ID } from '../game/semuta-drug';
|
|
import { nextSemutaGuildIncomeNativeStep } from './fixture-semuta-guild-income';
|
|
import { moveSemutaEmperorCard, semutaEmperorCardId } from './fixture-semuta-emperor-share';
|
|
|
|
export const shrinePlayer = (game: Game, id: string) => game.players.find(p => p.id === id)!;
|
|
export function semutaShrineLobby(advanced = true) {
|
|
let game = createGame('SEMUTASHRINE', newPlayer('r', 'Richese', 'richese'), advanced, ['choam']);
|
|
joinGame(game, newPlayer('e', 'Emperor', 'emperor'));
|
|
joinGame(game, newPlayer('g', 'Guild', 'guild'));
|
|
game.discoveryEnabled = true;
|
|
for (const player of game.players) game = applyAction(game, player.id, { type: 'ready' });
|
|
return game;
|
|
}
|
|
|
|
/** Original ready lobby/setup and first Movement; then CONTROLLED physical
|
|
* Shrine placement/occupation and conserved hand acquisition. Not an original
|
|
* Discovery draw/entry journey or full-game acceptance. */
|
|
export function createControlledSemutaShrine(advanced = true) {
|
|
let game = initializeSemutaGameForAudit(semutaShrineLobby(advanced));
|
|
for (const position of [0, 1]) {
|
|
const index = game.spiceDeck.findIndex((card, i) => i >= position && 'territory' in card && !card.discovery);
|
|
assert.ok(index >= position);
|
|
game.spiceDeck.splice(position, 0, game.spiceDeck.splice(index, 1)[0]);
|
|
}
|
|
for (let n = 0; n < 600; n++) {
|
|
if (game.phase === 5 && game.active === 'g' && !game.phaseOpening && !game.response && !game.decision) break;
|
|
const step = nextSemutaGuildIncomeNativeStep(game);
|
|
game = applyAction(game, step.actor, step.action);
|
|
}
|
|
assert.equal(game.phase, 5);
|
|
assert.ok(!game.response && !game.decision && !game.phaseOpening);
|
|
for (const player of game.players) game.deck.push(...player.hand.splice(0));
|
|
const shrine = game.discoveries!.tokens.find(token => token.face === 'shrine')!;
|
|
Object.assign(shrine, { status: 'placed', territory: 'gara_kulon', sector: 8, revealedTurn: game.turn });
|
|
shrinePlayer(game, 'e').reserves--;
|
|
shrinePlayer(game, 'e').forces['shrine:0'] = 1;
|
|
const truth = semutaEmperorCardId(game, card => card.effect === 'truthtrance');
|
|
const karama = semutaEmperorCardId(game, card => card.effect === 'karama');
|
|
moveSemutaEmperorCard(game, truth, 'e');
|
|
moveSemutaEmperorCard(game, karama, 'e');
|
|
moveSemutaEmperorCard(game, SEMUTA_DRUG_ID, 'r');
|
|
return { game, truth, karama, holder: 'r', owner: 'e',
|
|
provenance: 'CONTROLLED Shrine placement/occupation and conserved hand acquisition after genuine ready/setup/first Movement.' };
|
|
}
|
|
|
|
export function startShrineTruth(game: Game, karama: string): Game {
|
|
game = applyAction(game, 'e', { type: 'card', card: karama, shrineTruthtrance: [karama] });
|
|
while (game.truthtrance?.stage === 'priority') {
|
|
const actor = game.players.find(p => !game.truthtrance!.passed.includes(p.id))!;
|
|
game = applyAction(game, actor.id, { type: 'truthPass' });
|
|
}
|
|
const ask: Action = { type: 'truthAsk', question: { kind: 'fact', target: 'r',
|
|
fact: { kind: 'hand', name: 'Semuta Drug' } } };
|
|
game = applyAction(game, 'e', ask);
|
|
return applyAction(game, 'r', { type: 'truthAnswer', answer: 'yes' });
|
|
}
|