Files
Dune/tests/fixture-semuta-homeworld-choam-karama.ts
T

84 lines
4.0 KiB
TypeScript

import assert from 'node:assert/strict';
import { viewGame, type Action, type Game } from '../game/engine';
import { semutaEmperorPlayer } from './fixture-semuta-emperor-share';
import { applySemutaHomeworldChoamStep, holdSemutaHomeworldChoamCard } from './fixture-semuta-homeworld-choam';
import {
createSemutaHomeworldChoamMovementFixture,
type SemutaHomeworldChoamMovementFixture,
} from './fixture-semuta-homeworld-choam-movement';
import {
createSemutaHomeworldChoamReturnsFixture,
type SemutaHomeworldChoamReturnsFixture,
} from './fixture-semuta-homeworld-choam-returns';
import type { RicheseSkillsTechStep } from './fixture-richese-skills-tech';
export type SemutaHomeworldChoamKaramaPower = 'kulon' | 'baliset' | 'laLaLa' | 'gamont';
export type SemutaHomeworldChoamKaramaFixture = {
setup: Game;
beforeDeclaration: Game;
/** Exact original declaration response, before Emperor spends its Karama. */
game: Game;
owner: string;
holder: string;
target: string;
canceller: string;
card: string;
karama: string;
power: SemutaHomeworldChoamKaramaPower;
action: Action;
cancelAction: Action;
actions: RicheseSkillsTechStep[];
movement?: SemutaHomeworldChoamMovementFixture;
returns?: SemutaHomeworldChoamReturnsFixture;
};
/** Genuine native prefix and printed declaration. Only conserved original
* physical cards are positioned; the movement fixture already holds Karama. */
export function createSemutaHomeworldChoamKaramaFixture(
power: SemutaHomeworldChoamKaramaPower, advanced = false, fullHolder = false,
): SemutaHomeworldChoamKaramaFixture {
const movement = power === 'kulon' || power === 'baliset'
? createSemutaHomeworldChoamMovementFixture(power, advanced, fullHolder) : undefined;
const returns = power === 'laLaLa' || power === 'gamont'
? createSemutaHomeworldChoamReturnsFixture(power, advanced) : undefined;
const native = movement ?? returns;
assert.ok(native);
const beforeDeclaration = structuredClone(native.game);
const canceller = movement?.canceller
?? beforeDeclaration.players.find(player => player.faction === 'emperor')!.id;
assert.equal(semutaEmperorPlayer(beforeDeclaration, canceller).faction, 'emperor');
const held = semutaEmperorPlayer(beforeDeclaration, canceller).hand.find(card => card.effect === 'karama');
const karama = held?.id ?? holdSemutaHomeworldChoamCard(beforeDeclaration, canceller, 'Karama');
const actions = structuredClone(native.actions);
const game = applySemutaHomeworldChoamStep(beforeDeclaration, native.owner, native.action, actions);
assert.equal(game.response?.kind, 'choamWorthless');
assert.equal(game.response!.owner, native.owner);
assert.ok(viewGame(game, canceller).responseControls?.cancelCards.includes(karama));
return { setup: native.setup, beforeDeclaration, game,
owner: native.owner, holder: native.holder, target: native.target, canceller,
card: native.card, karama, power, action: native.action,
cancelAction: { type: 'card', mode: 'cancel', card: karama }, actions, movement, returns };
}
export function cancelSemutaHomeworldChoamKarama(
fixture: SemutaHomeworldChoamKaramaFixture, state = fixture.game, actions?: RicheseSkillsTechStep[],
): Game {
return applySemutaHomeworldChoamStep(state, fixture.canceller, fixture.cancelAction, actions);
}
/** Singleton printed Karama only; pass every still-entitled neutral participant. */
export function reactSemutaHomeworldChoamKarama(
state: Game, holder: string, claim: boolean, actions?: RicheseSkillsTechStep[],
): Game {
const pending = state.pendingTreacheryDiscard;
assert.ok(pending);
const reaction = pending.reaction;
if (reaction?.stage !== 'offer') throw Error('Expected the fresh native Karama discard offer');
const event = pending.batch.event;
if (claim) return applySemutaHomeworldChoamStep(state, holder, { type: 'semutaCommit', event }, actions);
let game = state;
for (const player of state.players.filter(player => !reaction.passed.includes(player.id)))
game = applySemutaHomeworldChoamStep(game, player.id, { type: 'semutaPass', event }, actions);
return game;
}