69 lines
4.0 KiB
TypeScript
69 lines
4.0 KiB
TypeScript
import assert from 'node:assert/strict';
|
|
import test from 'node:test';
|
|
import { createGame, joinGame, newPlayer, viewGame, type Game } from '../game/engine';
|
|
import { act, advance, clean, inventory, player } from './fixture-kull-native-ix';
|
|
|
|
/** Genuine public Basic setup and movement; only unopened card and Spice
|
|
* order is selected. The live whole answer and both overlapping response
|
|
* windows arise through original actions, not installed pending state. */
|
|
function source() {
|
|
let game=createGame('KULLBGGUILD',newPlayer('choam','CHOAM','choam'),false,['choam','ix']);
|
|
for (const id of ['emperor','beneGesserit','guild','harkonnen'] as const)
|
|
joinGame(game,newPlayer(id,id,id));
|
|
game=act(game,'choam',{type:'moduleOption',module:'kullPreview',enabled:true});
|
|
for (const seat of game.players) game=act(game,seat.id,{type:'ready'});
|
|
game=act(game,'choam',{type:'start'});
|
|
assert.equal(game.status,'setup'); assert.ok(game.kullPreview);
|
|
const originalCards=inventory(game), selected:Game['deck']=[];
|
|
for (const kind of ['kull','karama','filler','truth','karama','filler'] as const) {
|
|
const index=game.deck.findIndex(card=>kind==='kull'?card.id==='ix-kull-wahad':
|
|
kind==='truth'?card.effect==='truthtrance':kind==='karama'?card.effect==='karama':
|
|
card.kind==='worthless' && card.id!=='ix-kull-wahad');
|
|
assert.ok(index>=0); selected.push(game.deck.splice(index,1)[0]);
|
|
}
|
|
game.deck.unshift(...selected);
|
|
game=advance(game,state=>state.status==='playing');
|
|
const [,karama,,truth]=selected.map(card=>card.id);
|
|
assert.ok(player(game,'emperor').hand.some(card=>card.id===karama));
|
|
assert.ok(player(game,'guild').hand.some(card=>card.id===truth));
|
|
const safe=game.spiceDeck.findIndex(card=>'territory' in card && !card.discovery); assert.ok(safe>=0);
|
|
game.spiceDeck.unshift(game.spiceDeck.splice(safe,1)[0]);
|
|
game=advance(game,state=>state.phase===2 && clean(state) && state.choamCharity?.turn===state.turn);
|
|
game=act(game,'guild',{type:'card',card:truth});
|
|
while (game.truthtrance?.stage==='priority') {
|
|
const seat=game.players.find(row=>!game.truthtrance!.passed.includes(row.id)); assert.ok(seat);
|
|
game=act(game,seat.id,{type:'truthPass'});
|
|
}
|
|
game=act(game,'guild',{type:'truthAsk',question:{kind:'turnActions',target:'emperor',turn:game.turn,
|
|
mixed:{kind:'action',action:{kind:'payment',recipient:'harkonnen',minimum:1}}}});
|
|
assert.ok(viewGame(game,'emperor').truthTurnActionAnswers?.includes('yes'));
|
|
game=act(game,'emperor',{type:'truthAnswer',answer:'yes'});
|
|
const promise=game.turnActionPromises?.at(-1); assert.ok(promise);
|
|
game=advance(game,state=>state.phase===5 && state.active==='emperor' && clean(state));
|
|
game=act(game,'emperor',{type:'ship',territory:'polar_sink',sector:0,amount:1,elite:0,allyPayment:0});
|
|
assert.equal(game.response?.kind,'guildIncome');
|
|
assert.equal(game.decision?.kind,'advisor');
|
|
assert.ok(!promise.released);
|
|
return {game,karama,event:promise.event,originalCards};
|
|
}
|
|
|
|
void test('live whole-answer preflight fences Guild income cancellation without consuming a simultaneous BG arrival decision',()=>{
|
|
const f=source(); let game=f.game;
|
|
const before=structuredClone(game);
|
|
assert.ok(!viewGame(game,'emperor').responseControls?.cancelCards.includes(f.karama));
|
|
assert.throws(()=>act(game,'emperor',{type:'card',mode:'cancel',card:f.karama}));
|
|
assert.deepEqual(game,before);
|
|
assert.equal(game.pendingKull ?? null,null);
|
|
assert.deepEqual(game.decision,before.decision);
|
|
assert.ok(game.turnActionPromises?.some(row=>row.event===f.event && !row.released));
|
|
for (let count=0;game.response?.kind==='guildIncome' && count<game.players.length;count++) {
|
|
const seat=game.players.find(row=>!game.response!.passed.includes(row.id)); assert.ok(seat);
|
|
game=act(game,seat.id,{type:'passResponse'});
|
|
}
|
|
assert.equal(game.response,null);
|
|
assert.deepEqual(game.decision,before.decision);
|
|
game=act(game,'beneGesserit',{type:'decision',accept:false});
|
|
assert.equal(game.decision,null);
|
|
assert.deepEqual(inventory(game),f.originalCards);
|
|
});
|