Support mixed Discovery decks with Leader Skills
Verify and publish checkpoint container / container (push) Canceled after 0s
Verify and publish checkpoint container / container (push) Canceled after 0s
This commit is contained in:
1 parent
7c1f4b4e09
commit
77eb2392eb
15 files changed
+420
-11
No files matched your search
@@ -0,0 +1,63 @@
|
||||
import assert from 'node:assert/strict';
|
||||
import { createGame, joinGame, newPlayer, type Action, type Game } from '../game/engine';
|
||||
import type { FactionId } from '../game/catalog';
|
||||
import { withClassicDiscoveryNexusLottery } from './fixture-discovery-classic-nexus';
|
||||
import { nextPairedChoamSkillsStep } from './fixture-paired-choam-nexus-skills';
|
||||
import { actSelectedIndependentNexus, advanceSelectedIndependentNexus,
|
||||
type SelectedIndependentNexusStep } from './fixture-selected-independent-nexus-cards';
|
||||
|
||||
export type DiscoverySkillsOptions = {
|
||||
advanced: boolean;
|
||||
factions: readonly FactionId[];
|
||||
expansions?: Game['expansions'];
|
||||
};
|
||||
|
||||
/** Fresh public lobby, real original private training and native setup. Only
|
||||
* the original random lottery is fixed; no cards, leaders or forces are added. */
|
||||
export function selectedDiscoverySkillsLobby(options: DiscoverySkillsOptions) {
|
||||
const [host, ...others] = options.factions;
|
||||
const expansions = options.expansions ?? ['ecaz', 'ix', 'choam'];
|
||||
let game = withClassicDiscoveryNexusLottery(() => createGame('SELECTEDDISCOVERYSKILLS',
|
||||
newPlayer(host, host, host), options.advanced, expansions));
|
||||
for (const faction of others) joinGame(game, newPlayer(faction, faction, faction));
|
||||
const actions: SelectedIndependentNexusStep[] = [];
|
||||
const step = (actor: string, action: Action) => {
|
||||
game = actSelectedIndependentNexus(game, actor, action, actions);
|
||||
};
|
||||
if (expansions.includes('ix') && expansions.includes('choam'))
|
||||
step(host, {type:'moduleOption', module:'kullPreview', enabled:false});
|
||||
step(host, {type:'moduleOption', module:'leaderSkills', enabled:true});
|
||||
step(host, {type:'moduleOption', module:'discoveries', enabled:true});
|
||||
for (const player of game.players) step(player.id, {type:'ready'});
|
||||
return {game, host, step, actions};
|
||||
}
|
||||
|
||||
export function selectedDiscoverySkillsStart(options: DiscoverySkillsOptions) {
|
||||
const fixture = selectedDiscoverySkillsLobby(options);
|
||||
let game = fixture.game;
|
||||
const lobby = structuredClone(game);
|
||||
const start: Action = options.advanced ? {type:'start', advancedPreview:true} : {type:'start'};
|
||||
game = actSelectedIndependentNexus(game, fixture.host, start, fixture.actions);
|
||||
const setup = structuredClone(game);
|
||||
for (let count = 0; game.status === 'setup' && count < 300; count++) {
|
||||
const next = nextPairedChoamSkillsStep(game);
|
||||
assert.ok(next, `Original setup must expose a choice at ${game.setupStage ?? game.decision?.kind}`);
|
||||
game = actSelectedIndependentNexus(game, next.actor, next.action, fixture.actions);
|
||||
}
|
||||
assert.equal(game.status, 'playing');
|
||||
return {...fixture, game, lobby, setup};
|
||||
}
|
||||
|
||||
/** Reorder only the unopened original Spice Cards. The engine resolves the
|
||||
* Discovery and the following bidding and movement through ordinary actions. */
|
||||
export function advanceDiscoverySkillsBlow(game: Game, actions: SelectedIndependentNexusStep[]) {
|
||||
for (const position of game.advanced ? [0, 1] : [0]) {
|
||||
const index = game.spiceDeck.findIndex((card, i) => i >= position && 'territory' in card &&
|
||||
(position === 0 ? card.discovery === 'discovery-hagga-basin' : !card.discovery));
|
||||
assert.ok(index >= position);
|
||||
[game.spiceDeck[position], game.spiceDeck[index]] = [game.spiceDeck[index], game.spiceDeck[position]];
|
||||
}
|
||||
return advanceSelectedIndependentNexus(game, state => state.turn === 1 && state.phase === 5 &&
|
||||
!state.phaseOpening && !state.response && !state.decision && !state.truthtrance &&
|
||||
!state.pendingTreacheryDiscard, actions);
|
||||
}
|
||||
Reference in new issue
Block a user