52 lines
3.0 KiB
TypeScript
52 lines
3.0 KiB
TypeScript
import assert from 'node:assert/strict';
|
|
import test from 'node:test';
|
|
import { TERRITORIES } from '../game/board';
|
|
import { applyAction, viewGame, type Action } from '../game/engine';
|
|
import { junctionTransportActions, junctionTransportChoice } from '../game/junction-transport-options';
|
|
import { TERROR_STRONGHOLDS } from '../game/moritani-terror';
|
|
import { createJunctionPurchasedPrice, type PurchasedJunctionRoute } from './fixture-junction-purchased-price';
|
|
|
|
/** Original public setup, physical purchased rate and Guild's actual Junction
|
|
* offer come from the native fixture. To examine the later persisted state,
|
|
* Atomics' removed token, original victim and hand-limit marker are staged;
|
|
* any excess held card is moved into the original deck, not duplicated. */
|
|
function staged(route: PurchasedJunctionRoute) {
|
|
const f=createJunctionPurchasedPrice({route});
|
|
const g=structuredClone(f.beforeAction);
|
|
const available=TERRITORIES.filter(t=>TERROR_STRONGHOLDS.includes(t.id)).flatMap(t=>
|
|
t.sectors.map(sector=>`${t.id}:${sector}`)).find(destination=>
|
|
!!junctionTransportChoice(viewGame(g,f.shipper),destination,f.sources).action);
|
|
assert.ok(available,'An original offered Junction route needs an eligible stronghold.');
|
|
const target=available.split(':')[0];
|
|
const owner=g.players.find(player=>player.faction==='moritani'); assert.ok(owner);
|
|
const token=g.moritaniTerror?.tokens.find(candidate=>candidate.kind==='atomics'); assert.ok(token);
|
|
token.status='removed'; token.location=null;
|
|
owner.atomicsHandLimitPenalty=true;
|
|
if (owner.hand.length>3) g.deck.push(...owner.hand.splice(3));
|
|
g.moritaniAtomics={territory:target,turn:g.turn,moritaniId:owner.id,
|
|
allyAtActivation:null,alliancePolicy:'activation-targets'};
|
|
return {f,g,destination:available,target};
|
|
}
|
|
|
|
for (const route of ['nativeArrival','arrakisReturn'] as const) {
|
|
void test(`Junction ${route==='nativeArrival'?'Homeworld-to-Arrakis':'Arrakis-to-Arrakis'} cannot enter Atomics Aftermath`,()=>{
|
|
const {f,g,destination,target}=staged(route);
|
|
const view=viewGame(g,f.shipper);
|
|
const quoted=junctionTransportChoice(view,destination,f.sources);
|
|
assert.match(quoted.blocked??'',/Atomics Aftermath/);
|
|
assert.equal(quoted.action,null);
|
|
const offer=view.junctionTransport?.offer; assert.ok(offer);
|
|
const declaration: Action={type:'junctionShip',event:view.junctionTransport!.event,
|
|
offer:offer.event,destination,sources:f.sources,allyPayment:0,forfeitPurchasedRate:true};
|
|
const before=structuredClone(g);
|
|
assert.throws(()=>applyAction(g,f.shipper,declaration),/Atomics Aftermath/);
|
|
assert.deepEqual(g,before);
|
|
for (let level=0;level<4;level++)
|
|
assert.ok(!junctionTransportActions(view,level).some(action=>
|
|
action.type==='junctionShip' && typeof action.destination==='string' && action.destination.split(':')[0]===target));
|
|
// A Homeworld destination remains legal because the marker affects only Arrakis.
|
|
const world=junctionTransportChoice(view,'homeworld:ecaz',f.sources);
|
|
assert.ok(!world.blocked?.includes('Atomics'));
|
|
});
|
|
}
|