import assert from 'node:assert/strict'; import test from 'node:test'; import { applyAction, viewGame } from '../game/engine'; import { DUKE_VIDAL_ID } from '../game/duke-vidal'; import { advanceNexusDuke, createNexusDukeCaptureFixture, nexusDukeClean, quietPlan, sealNexusDukeBattle, stepNexusDuke, type NexusDukeSeatPlan } from './fixture-nexus-duke-capture'; /** Genuine Advanced Nexus faction setup and real Duke battle. The marker is * explicitly staged to represent either a prior ambiguous capture or a legacy * save; original leaders, forces, cards and parent decisions are not staged. */ function publicDukeBattle(marker: true | undefined) { const source = createNexusDukeCaptureFixture({variant:'used'}); const game = structuredClone(source.battle.after); if (marker === undefined) delete game.dukeCaptureUncertain; else game.dukeCaptureUncertain = marker; const sealed = source.sealed.battle; assert.ok(sealed?.revealed); const plans: NexusDukeSeatPlan[] = [source.owner, source.captor].map(actor => { const plan = sealed.plans[actor]; assert.ok(plan); return {actor, leader:plan.leader, dial:plan.dial, support:plan.support, ...(plan.weapon ? {weapon:plan.weapon} : {}), ...(plan.defense ? {defense:plan.defense} : {})}; }); const plan = quietPlan(game, {owner:source.owner, captor:source.captor, entrant:source.entrant, others:source.others, token:source.token, destination:source.destination, capture:'decline'}); const revealed = sealNexusDukeBattle(game, plan, [], plans); assert.equal(revealed.battle?.plans[source.owner]?.leader, DUKE_VIDAL_ID); const pending = advanceNexusDuke(revealed, state => state.decision?.kind === 'captureOffer', plan); assert.equal(pending.dukeCaptureUncertain, false, 'Public Duke battle resolves earlier uncertainty'); return {source, pending, plan}; } for (const marker of [true, undefined] as const) void test(`public Duke battle clears ${marker === undefined ? 'legacy unknown' : 'prior capture uncertainty'} before a later Ambassador grant`, () => { const {source, pending, plan} = publicDukeBattle(marker); assert.ok(pending.decision?.kind === 'captureOffer'); let game = stepNexusDuke(pending, plan, {actor:pending.decision.player, action:{type:'decision',accept:false}}); game = advanceNexusDuke(game, state => !state.battle && !state.pendingCapture && nexusDukeClean(state), plan); assert.equal(game.dukeCaptureUncertain, false); const future = quietPlan(game, {owner:source.owner, captor:source.captor, entrant:source.entrant, others:source.others, place:true}); game = advanceNexusDuke(game, state => state.ecazAmbassadors!.tokens.some(token => token.id === future.token && token.zone === 'placed'), future); future.place = false; future.ship = {[source.entrant]:{territory:future.destination, amount:1}}; game = advanceNexusDuke(game, state => state.pendingAmbassador?.stage === 'offer' && state.pendingAmbassador.token === future.token, future); const view = viewGame(game, source.owner); assert.equal(view.ambassadorEntry?.dukeAcquisition?.blocked, null); const event = game.pendingAmbassador!.event; const after = applyAction(game, source.owner, {type:'decision',event,trigger:true,beneficiary:source.owner,choice:'duke'}); assert.equal(after.dukeVidal?.controller, source.owner); assert.equal(after.dukeVidal?.source, 'ecaz'); assert.equal(after.ecazAmbassadors!.tokens.find(token => token.id === future.token)?.zone, 'supply'); }); void test('a new Duke-possible capture after a public Duke battle restores uncertainty', () => { const {pending, plan} = publicDukeBattle(true); assert.ok(pending.decision?.kind === 'captureOffer'); let game = stepNexusDuke(pending, plan, {actor:pending.decision.player, action:{type:'decision',accept:true}}); game = advanceNexusDuke(game, state => state.decision?.kind === 'capturedLeader', plan); assert.equal(game.dukeCaptureUncertain, true); });