import assert from 'node:assert/strict'; import test from 'node:test'; import { viewGame } from '../game/engine'; import { isAdvisor } from '../game/advisors'; import { botActions } from '../game/bots'; import { DIFFICULTIES } from '../game/bot-profiles'; import { createAdvisorWormRideFixture as fixture, actAdvisorWormRide as act, advisorWormRideInventory as inventory, advisorWormRidePlayer as player, passAdvisorWormRide as pass } from './fixture-advisor-worm-ride-flip'; import { sandmasterRide, sandmasterWormGame } from './fixture-sandmaster-worm'; for (const canceled of [false,true]) void test( `native worm ride remains committed when source advisor conversion is ${canceled ? 'prevented' : 'allowed'}`, () => { const f = fixture(), original = structuredClone(f.game); let game = act(f.game,f.fremen,f.action); assert.deepEqual(f.game,original); assert.equal(game.response?.kind,'advisorFlip'); assert.equal(game.response?.automaticAdvisorFlip?.producer,'wormRide'); assert.equal(player(game,f.fremen).forces[f.source] ?? 0,0); assert.equal(player(game,f.fremen).forces[f.destination],2); assert.equal(player(game,f.fremen).forces['hagga_basin:12'],1); assert.ok(isAdvisor(player(game,f.bg),f.origin)); assert.ok(viewGame(game,f.holder).responseControls?.cancelCards.includes(f.karama)); const committed = structuredClone(player(game,f.fremen)); game = canceled ? act(game,f.holder,{type:'card',card:f.karama,mode:'cancel'}) : pass(game); assert.deepEqual(player(game,f.fremen),committed); assert.equal(isAdvisor(player(game,f.bg),f.origin),canceled); assert.equal(game.pendingAutomaticAdvisorFlips,undefined); assert.equal(game.decision?.kind,'wormRide'); if (game.decision?.kind === 'wormRide') assert.equal(game.decision.territory,f.second); assert.deepEqual(game.wormRides,[]); assert.equal(game.discard.filter(card => card.id === f.karama).length,Number(canceled)); assert.deepEqual(inventory(game),f.originalCards); }, ); void test('a partial ride leaves Fremen in the source and produces no alone conversion', () => { const f=fixture({partial:true}), game=act(f.game,f.fremen,f.action); assert.equal(player(game,f.fremen).forces[f.source],1); assert.equal(player(game,f.fremen).forces[f.destination],1); assert.ok(isAdvisor(player(game,f.bg),f.origin)); assert.equal(game.response?.automaticAdvisorFlip,undefined); assert.deepEqual(inventory(game),f.originalCards); }); void test('source conversion precedes the real destination intrusion and resumes it once', () => { const f=fixture({intrusion:true}); let game=act(f.game,f.fremen,f.action); assert.equal(game.response?.automaticAdvisorFlip?.producer,'wormRide'); assert.equal(game.decision,null); game=pass(game); assert.equal(game.decision?.kind,'intrusion'); if (game.decision?.kind === 'intrusion') assert.equal(game.decision.territory,'imperial_basin'); assert.equal(player(game,f.fremen).forces[f.destination],2); assert.deepEqual(inventory(game),f.originalCards); }); void test('Fremen cannot nest a special worm during the committed source conversion', () => { const f=fixture(), source=structuredClone(f.game); // Transfer the remaining physical Karama from the original deck to Fremen; // the separately held Karama still keeps the advisor response open. const index=source.deck.findIndex(card => card.effect === 'karama'); assert.ok(index >= 0); const [card]=source.deck.splice(index,1); player(source,f.fremen).hand.push(card); const cards=inventory(source); const summon={type:'card',mode:'special',card:card.id,territory:'the_great_flat'}; let game=act(source,f.fremen,f.action); assert.equal(game.response?.automaticAdvisorFlip?.producer,'wormRide'); const before=structuredClone(game); assert.throws(() => act(game,f.fremen,summon)); assert.deepEqual(game,before); assert.ok(player(game,f.fremen).hand.some(candidate => candidate.id === card.id)); assert.equal(player(game,f.fremen).specialKaramaUsed ?? false,false); game=pass(game); assert.equal(game.decision?.kind,'wormRide'); assert.equal(player(game,f.fremen).forces[f.destination],2); game=act(game,f.fremen,summon); assert.equal(player(game,f.fremen).specialKaramaUsed,true); assert.equal(game.discard.filter(candidate => candidate.id === card.id).length,1); assert.deepEqual(inventory(game),cards); }); void test('all four bot profiles can resolve the original worm-ride conversion legally', () => { const f=fixture(), pending=act(f.game,f.fremen,f.action); for (const difficulty of DIFFICULTIES) { const view=viewGame(pending,f.holder); view.players.find(seat => seat.id === f.holder)!.bot=difficulty; const action=botActions(view)[0]; assert.ok(action); const game=pass(act(structuredClone(pending),f.holder,action)); assert.equal(game.decision?.kind,'wormRide'); if (game.decision?.kind === 'wormRide') assert.equal(game.decision.territory,f.second); assert.equal(player(game,f.fremen).forces[f.destination],2); assert.deepEqual(inventory(game),f.originalCards); } }); for (const canceled of [false,true]) void test( `Sandmaster's native worm-ride collection occurs once when origin conversion is ${canceled ? 'prevented' : 'allowed'}`, () => { // This fixture uses genuine Leader Skills setup and a staged, conserved // ride. Move the actual BG force from the destination to the ride origin, // and transfer one physical Karama to Fremen for the response. const source=sandmasterWormGame(true,true), bg=player(source,'h'), rider=player(source,'p'); bg.forces={'wind_pass:14':1}; bg.reserves=19; bg.advisors={wind_pass:{}}; const index=source.deck.findIndex(card => card.effect === 'karama'); assert.ok(index >= 0); const [card]=source.deck.splice(index,1); rider.hand.push(card); const cards=inventory(source), beforeSpice=rider.spice, beforePile=source.spice['red_chasm:7']; let game=act(source,'p',sandmasterRide()); assert.equal(game.response?.automaticAdvisorFlip?.producer,'wormRide'); assert.equal(player(game,'p').spice,beforeSpice+1); assert.equal(game.spice['red_chasm:7'],beforePile-1); assert.equal(game.log.filter(entry => entry.automatic?.name === 'Sandmaster collection').length,1); game=canceled ? act(game,'p',{type:'card',card:card.id,mode:'cancel'}) : pass(game); assert.equal(player(game,'p').spice,beforeSpice+1); assert.equal(game.spice['red_chasm:7'],beforePile-1); assert.equal(player(game,'p').forces['red_chasm:7'],4); assert.equal(isAdvisor(player(game,'h'),'wind_pass'),canceled); assert.equal(game.log.filter(entry => entry.automatic?.name === 'Sandmaster collection').length,1); assert.deepEqual(inventory(game),cards); }, );