Enable Advanced classic group preview
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
89386af95b
commit
d8d3cfd26c
8 files changed
+138
-20
No files matched your search
@@ -0,0 +1,82 @@
|
||||
import assert from 'node:assert/strict';
|
||||
import test from 'node:test';
|
||||
import { botActions } from '../game/bots';
|
||||
import { DIFFICULTIES } from '../game/bot-profiles';
|
||||
import { coalitionOf } from '../game/coalition-alliance';
|
||||
import { applyAction, createGame, joinGame, newPlayer, viewGame, type Action, type Game } from '../game/engine';
|
||||
import { advanceShortAlliance, type ShortAllianceStep } from './fixture-short-alliance-victory';
|
||||
|
||||
const apply = (game: Game, actor: string, action: Action) => applyAction(game, actor, action);
|
||||
function lobby(): Game {
|
||||
const game = createGame('ADVGROUPPREVIEW',newPlayer('at','Atreides','atreides'));
|
||||
joinGame(game,newPlayer('em','Emperor','emperor'));
|
||||
joinGame(game,newPlayer('ha','Harkonnen','harkonnen'));
|
||||
return game;
|
||||
}
|
||||
function prepare(variant: 'three' | 'three-short' | 'unlimited'): Game {
|
||||
let game = apply(lobby(),'at',{type:'rules',advanced:true});
|
||||
game = apply(game,'at',{type:'coalitionPreview',variant});
|
||||
for (const seat of game.players) game = apply(game,seat.id,{type:'ready'});
|
||||
assert.throws(() => apply(game,'at',{type:'start'}), /advanced|preview/i);
|
||||
return apply(game,'at',{type:'start',advancedPreview:true});
|
||||
}
|
||||
function accept(game: Game, actor: string): Game {
|
||||
const offer = game.coalitionState?.proposal; assert.ok(offer);
|
||||
return apply(game,actor,{type:'coalitionAnswer',event:offer.event,nexus:offer.nexus,
|
||||
turn:offer.turn,accept:true,expectedRevision:game.coalitionState!.revision});
|
||||
}
|
||||
|
||||
void test('fresh Advanced classic group variants require explicit preview and retain their selected target', () => {
|
||||
for (const variant of ['three','three-short','unlimited'] as const) {
|
||||
const game = prepare(variant);
|
||||
assert.equal(game.status,'setup');
|
||||
assert.equal(game.advanced,true);
|
||||
assert.equal(game.advancedPreview,true);
|
||||
assert.equal(viewGame(game,'em').coalitionPreview,variant);
|
||||
assert.ok(game.coalitionState);
|
||||
assert.equal(game.coalitionState.variant,variant === 'three' ? undefined : variant);
|
||||
assert.deepEqual(game.coalitionState.groups,[]);
|
||||
assert.equal(game.coalitionState.proposal,null);
|
||||
}
|
||||
});
|
||||
|
||||
/** Actual Advanced setup and first turn. Only unopened original Spice cards
|
||||
* are reordered to select a normal worm at the next Spice Blow. */
|
||||
function pairAtNexus(): Game {
|
||||
let game = prepare('three-short');
|
||||
const actions: ShortAllianceStep[] = [];
|
||||
game = advanceShortAlliance(game, state => state.status === 'playing' && state.turn === 2 && state.phase === 0, actions);
|
||||
const worm = game.spiceDeck.findIndex(card => 'worm' in card && !card.greatMaker && !card.suppressed && !card.thumper);
|
||||
assert.ok(worm >= 0);
|
||||
const inventory = game.spiceDeck.map(card => JSON.stringify(card)).sort();
|
||||
game.spiceDeck.unshift(game.spiceDeck.splice(worm,1)[0]);
|
||||
assert.deepEqual(game.spiceDeck.map(card => JSON.stringify(card)).sort(),inventory);
|
||||
game = advanceShortAlliance(game, state => state.nexus && !state.spiceWindow && !state.spiceResolution &&
|
||||
!state.response && !state.decision && !state.truthtrance && !state.phaseOpening, actions);
|
||||
game = apply(game,'at',{type:'alliance',target:'em'});
|
||||
return apply(game,'em',{type:'alliance',target:'at'});
|
||||
}
|
||||
|
||||
void test('a genuine Advanced preview reaches group formation, legal bots, and the next turn', () => {
|
||||
const original = pairAtNexus();
|
||||
const pair = coalitionOf(original.players,original.coalitionState,'at'); assert.ok(pair);
|
||||
assert.deepEqual(new Set(pair.members),new Set(['at','em']));
|
||||
let formed: Game | undefined;
|
||||
for (const difficulty of DIFFICULTIES) {
|
||||
const view = viewGame(original,'ha'); view.players.find(player => player.id === 'ha')!.bot = difficulty;
|
||||
const proposal = botActions(view).find(action => action.type === 'coalitionPropose'); assert.ok(proposal,difficulty);
|
||||
let game = apply(original,'ha',proposal);
|
||||
game = accept(game,'at'); game = accept(game,'em');
|
||||
assert.deepEqual(new Set(coalitionOf(game.players,game.coalitionState,'at')!.members),new Set(['at','em','ha']));
|
||||
assert.equal(game.coalitionState!.proposal,null);
|
||||
const progress = viewGame(game,'at').victoryProgress.find(row => row.player === 'at'); assert.ok(progress);
|
||||
assert.equal(progress.target,3);
|
||||
formed = game;
|
||||
}
|
||||
assert.ok(formed);
|
||||
for (const seat of formed.players)
|
||||
if (formed.nexus && !formed.ready.includes(seat.id)) formed = apply(formed,seat.id,{type:'ready'});
|
||||
const continued = advanceShortAlliance(formed,
|
||||
state => state.status === 'playing' && state.turn === 3 && state.phase === 0, []);
|
||||
assert.deepEqual(new Set(coalitionOf(continued.players,continued.coalitionState,'at')!.members),new Set(['at','em','ha']));
|
||||
});
|
||||
@@ -61,3 +61,12 @@ void test('selected preview warns in the lobby and through real setup', () => {
|
||||
assert.match(html,/Some faction powers and interactions are incomplete/);
|
||||
}
|
||||
});
|
||||
|
||||
void test('Advanced group preview keeps the explicit opt-in and incompatibility warning', () => {
|
||||
let game = applyAction(lobby(),'at',{type:'coalitionPreview',variant:'three'});
|
||||
game = applyAction(game,'at',{type:'rules',advanced:true});
|
||||
const html = table(viewGame(game,'at'));
|
||||
assert.match(html,/Advanced rules require their separate preview start/);
|
||||
assert.match(html,/without expansion decks, other optional modules/);
|
||||
assert.match(html,/Begin Advanced preview/);
|
||||
});
|
||||
@@ -56,7 +56,7 @@ void test('group preview refuses incompatible rules and optional alliance settin
|
||||
let advanced = apply(lobby(),'at',{type:'coalitionPreview',variant:'three'});
|
||||
advanced = apply(advanced,'at',{type:'rules',advanced:true});
|
||||
advanced = ready(advanced);
|
||||
assert.throws(() => apply(advanced,'at',{type:'start',advancedPreview:true}), /group|alliance/i);
|
||||
assert.throws(() => apply(advanced,'at',{type:'start'}), /Advanced.*preview/i);
|
||||
let shortened = apply(lobby(),'at',{type:'coalitionPreview',variant:'three'});
|
||||
shortened = apply(shortened,'at',{type:'shortAllianceVictory',enabled:true});
|
||||
shortened = ready(shortened);
|
||||
|
||||
Reference in new issue
Block a user