import assert from 'node:assert/strict'; import test from 'node:test'; import { viewGame, type Game } from '../game/engine'; import { actAdvancedCharityOrder as act, advancedCharityOrderInventory as inventory, advancedCharityOrderPlayer as player, allowAdvancedCharityOpening as allow, createAdvancedCharityOrderFixture, passAdvancedCharityResponses as pass } from './fixture-advanced-charity-order'; let cached: ReturnType | undefined; const source = () => cached ??= createAdvancedCharityOrderFixture(); /** Genuine Advanced CHOAM/Bene Gesserit setup, phase opening and original * ordered Charity. Exchange one conserved physical Truthtrance into CHOAM's * hand for an existing card; no wallet, order, response or promise is staged. */ function beforeAnswer() { const f = source(); let game = allow(structuredClone(f.game)); const asker = player(game,'choam'), target = 'beneGesserit'; const index = game.deck.findIndex(card => card.effect === 'truthtrance'); assert.ok(index >= 0); assert.ok(asker.hand.length > 0); [asker.hand[0],game.deck[index]] = [game.deck[index],asker.hand[0]]; const truth = asker.hand[0].id; assert.ok(player(game,target).spice >= 2); assert.ok(game.charityOrder?.remaining.includes(target)); assert.deepEqual(inventory(game),f.original); game = act(game,'choam',{type:'card',card:truth}); while (game.truthtrance?.stage === 'priority') { const actor = game.players.find(candidate => !game.truthtrance!.passed.includes(candidate.id)); assert.ok(actor); game = act(game,actor.id,{type:'truthPass'}); } assert.equal(game.truthtrance?.stage,'ask'); game = act(game,'choam',{type:'truthAsk',question:{kind:'charity',target,turn:game.turn}}); assert.ok(viewGame(game,target).truthCharityAnswers?.includes('yes')); game = act(game,target,{type:'truthAnswer',answer:'yes'}); const promise = viewGame(game,target).truthCharityPromises.find(row => row.answer); assert.ok(promise); return {f,game,target,truth,event:promise.event}; } function reachBeneGesserit(sourceGame:Game):Game { let game = sourceGame; for (let count = 0; game.charityOrder?.remaining[0] !== 'beneGesserit' && count < 4; count++) { const actor = game.charityOrder?.remaining[0]; assert.ok(actor); game = act(game,actor,{type:'ready'}); } assert.equal(game.charityOrder?.remaining[0],'beneGesserit'); return game; } for (const cancel of [false,true]) void test( `Advanced wealthy Bene Gesserit promised Charity retains its native ${cancel ? 'cancellation' : 'payment'} response`, () => { const f = beforeAnswer(); let game = reachBeneGesserit(f.game); const bgSpice = player(game,f.target).spice, choamSpice = player(game,'choam').spice; const order = structuredClone(game.charityOrder), guide = viewGame(game,f.target).truthCharityGuide; assert.ok(guide); assert.equal(guide.action.type,'charity'); game = act(game,f.target,guide.action); assert.equal(game.response?.kind,'bgCharity'); assert.equal(game.response?.owner,f.target); assert.deepEqual(game.charityOrder,order); assert.equal(player(game,f.target).charityTurn,game.turn); assert.equal(viewGame(game,f.target).truthCharityPromises.find(row => row.event === f.event)?.fulfilled,true); assert.equal(player(game,f.target).spice,bgSpice); if (cancel) { assert.ok(player(game,'atreides').hand.some(card => card.id === f.f.karama)); game = act(game,'atreides',{type:'card',card:f.f.karama,mode:'cancel'}); } else game = pass(game); assert.equal(game.response ?? null,null); assert.deepEqual(game.charityOrder,order); assert.equal(player(game,f.target).spice,bgSpice + (cancel ? 0 : 2)); assert.equal(player(game,'choam').spice,choamSpice - (cancel ? 0 : 2)); assert.equal(viewGame(game,f.target).truthCharityPromises.find(row => row.event === f.event)?.fulfilled,true); assert.equal(player(game,f.target).charityTurn,game.turn); game = act(game,f.target,{type:'ready'}); assert.ok(game.phase !== 2 || !game.charityOrder?.remaining.includes(f.target)); assert.deepEqual(inventory(game),f.f.original); }, );