70 lines
3.6 KiB
TypeScript
70 lines
3.6 KiB
TypeScript
import assert from 'node:assert/strict';
|
|
import { applyAction, createGame, joinGame, newPlayer, type Action, type Game } from '../game/engine';
|
|
import { initializeClassicNexusSkillsPaymentsSetup, nextClassicNexusSkillsPaymentsNativeStep } from './fixture-classic-nexus-skills-payments';
|
|
|
|
/** Original skill offers/setup and actual turn-two worm alliance. Conserved
|
|
* starting counters are staged into reserves to isolate payment, not combat.
|
|
* Wallets, alliances, clocks and payment records are never assigned. */
|
|
export function createBureaucratSplitThresholdFixture(advanced = false) {
|
|
const lobby = createGame('BUREAUCRATTHRESHOLD', newPlayer('b', 'Bureaucrat', 'atreides'), advanced);
|
|
for (const [id, faction] of [['p', 'harkonnen'], ['f', 'fremen'], ['e', 'emperor'], ['g', 'guild']] as const)
|
|
joinGame(lobby, newPlayer(id, faction, faction));
|
|
let game = initializeClassicNexusSkillsPaymentsSetup({ initial: lobby, skill: 'bureaucrat' });
|
|
const actions: { actor: string; action: Action }[] = [];
|
|
const step = () => {
|
|
const next = nextClassicNexusSkillsPaymentsNativeStep(game);
|
|
assert.ok(next, `Native payment setup/progression stalled at ${game.phase}/${game.setupStage}`);
|
|
actions.push(next);
|
|
game = applyAction(game, next.actor, next.action);
|
|
};
|
|
for (let n = 0; game.status === 'setup' && n < 240; n++) step();
|
|
assert.equal(game.status, 'playing');
|
|
assert.ok(game.leaderSkills!.assignments.some(a => a.owner === 'b' && a.skill === 'bureaucrat'));
|
|
for (const player of game.players) {
|
|
player.reserves += Object.values(player.forces).reduce((a, b) => a + b, 0);
|
|
player.forces = {};
|
|
if (player.elites) {
|
|
player.elites.reserves += Object.values(player.elites.forces).reduce((a, b) => a + b, 0);
|
|
player.elites.forces = {};
|
|
}
|
|
if (player.advisors) player.advisors = {};
|
|
}
|
|
const orderSpice = (kinds: ('land' | 'worm')[]) => {
|
|
const front = kinds.map(kind => {
|
|
const index = game.spiceDeck.findIndex(card => kind === 'land' ? 'territory' in card : 'worm' in card);
|
|
assert.ok(index >= 0);
|
|
return game.spiceDeck.splice(index, 1)[0];
|
|
});
|
|
game.spiceDeck.unshift(...front);
|
|
};
|
|
orderSpice(['land', 'land']);
|
|
for (let n = 0; !(game.turn === 2 && game.phase === 1) && n < 1800; n++) step();
|
|
assert.equal(game.turn, 2); assert.equal(game.phase, 1);
|
|
orderSpice(['worm', 'land', 'land']);
|
|
let allied = false;
|
|
for (let n = 0; !(allied && game.phase === 3 && game.auction && !game.phaseOpening && !game.response && !game.decision) && n < 600; n++) {
|
|
if (game.nexus && !game.phaseOpening && !game.response && !game.decision && !game.spiceWindow && !allied) {
|
|
for (const [actor, target] of [['p', 'f'], ['f', 'p']]) {
|
|
const action: Action = { type: 'alliance', target };
|
|
actions.push({ actor, action }); game = applyAction(game, actor, action);
|
|
}
|
|
allied = true;
|
|
} else step();
|
|
}
|
|
assert.ok(allied && game.auction);
|
|
assert.equal(game.players.find(p => p.id === 'p')!.ally, 'f');
|
|
assert.equal(game.players.find(p => p.id === 'f')!.ally, 'p');
|
|
return { game, actions, payer: 'p', donor: 'f', trainer: 'b', guild: 'g', emperor: 'e' };
|
|
}
|
|
|
|
export function advanceBureaucratThresholdToMovement(state: Game, actor: string): Game {
|
|
let game = state;
|
|
for (let n = 0; !(game.phase === 5 && game.active === actor && !game.phaseOpening && !game.response && !game.decision) && n < 600; n++) {
|
|
const next = nextClassicNexusSkillsPaymentsNativeStep(game);
|
|
assert.ok(next, 'Native payment continuation stalled');
|
|
game = applyAction(game, next.actor, next.action);
|
|
}
|
|
assert.equal(game.phase, 5); assert.equal(game.active, actor);
|
|
return game;
|
|
}
|