Handle advisor conversion after worm rides
Verify and publish checkpoint container / container (push) Canceled after 0s
Verify and publish checkpoint container / container (push) Canceled after 0s
This commit is contained in:
1 parent
ad0abfef98
commit
c608d6fea6
15 files changed
+507
-14
No files matched your search
@@ -78,6 +78,17 @@ export type AutomaticAdvisorRelocation = {
|
||||
sector: number;
|
||||
};
|
||||
|
||||
/** Completed native Fremen ride, retained while its original arrival waits. */
|
||||
export type AutomaticAdvisorWormRide = {
|
||||
event: string;
|
||||
player: string;
|
||||
origin: string;
|
||||
destination: string;
|
||||
sector: number;
|
||||
amount: number;
|
||||
elite: number;
|
||||
};
|
||||
|
||||
export type AutomaticAdvisorFlipSource = {
|
||||
event: string;
|
||||
owner: string;
|
||||
@@ -94,6 +105,7 @@ export type AutomaticAdvisorFlipSource = {
|
||||
| { producer: 'faceDance'; faceDance: AutomaticAdvisorFaceDance }
|
||||
| { producer: 'storm'; storm: AutomaticAdvisorStorm }
|
||||
| { producer: 'specialRelocation'; relocation: AutomaticAdvisorRelocation }
|
||||
| { producer: 'wormRide'; wormRide: AutomaticAdvisorWormRide }
|
||||
| { producer: 'spiritualArrival'; spiritual: SpiritualAdvisorSource }
|
||||
);
|
||||
|
||||
@@ -104,6 +116,7 @@ export type AutomaticAdvisorFlipPlayer = ForcePresence & {
|
||||
moved?: number;
|
||||
shipped?: boolean;
|
||||
reserves?: number;
|
||||
elites?: { forces: Readonly<Record<string, number>> };
|
||||
};
|
||||
|
||||
export type AdvisorSettlementContext = {
|
||||
@@ -445,6 +458,31 @@ function validateRelocationSource(
|
||||
'Automatic advisor conversion lost the original relocated actor at its destination.');
|
||||
}
|
||||
|
||||
function validateWormRideSource(
|
||||
ctx: AutomaticAdvisorFlipContext,
|
||||
source: Extract<AutomaticAdvisorFlipSource, { producer: 'wormRide' }>,
|
||||
) {
|
||||
const ride = source.wormRide;
|
||||
requireFlip(record(ride) &&
|
||||
Object.keys(ride).sort().join(',') === 'amount,destination,elite,event,origin,player,sector' &&
|
||||
identifier(ride.event) && identifier(ride.player) && identifier(ride.origin) &&
|
||||
identifier(ride.destination) && ride.origin !== ride.destination &&
|
||||
nonnegative(ride.sector) && positive(ride.amount) && nonnegative(ride.elite) && ride.elite <= ride.amount,
|
||||
'Automatic advisor conversion lost its exact completed worm ride.');
|
||||
const places = gameTerritories(ctx);
|
||||
requireFlip(places.some(place => place.id === ride.origin) &&
|
||||
places.some(place => place.id === ride.destination && place.sectors.includes(ride.sector)) &&
|
||||
(source.territory === ride.origin || source.territory === ride.destination),
|
||||
'Automatic advisor conversion must belong to the original worm ride origin or destination.');
|
||||
const riders = ctx.players.filter(player => player.id === ride.player);
|
||||
const rider = riders[0], location = `${ride.destination}:${ride.sector}`;
|
||||
const deposited = rider?.forces[location], elite = rider?.elites?.forces[location] ?? 0;
|
||||
requireFlip(riders.length === 1 && rider.faction === 'fremen' &&
|
||||
nonnegative(deposited) && nonnegative(elite) && elite <= deposited &&
|
||||
elite >= ride.elite && deposited - elite >= ride.amount - ride.elite,
|
||||
'Automatic advisor conversion lost the original native Fremen ride and deposited forces.');
|
||||
}
|
||||
|
||||
function validateSpiritualArrivalSource(
|
||||
ctx: AutomaticAdvisorFlipContext,
|
||||
source: Extract<AutomaticAdvisorFlipSource, { producer: 'spiritualArrival' }>,
|
||||
@@ -484,6 +522,8 @@ export function validateAutomaticAdvisorFlip(
|
||||
Object.keys(source).sort().join(',') === 'event,forces,owner,phase,producer,storm,territory,turn') ||
|
||||
(source.producer === 'specialRelocation' &&
|
||||
Object.keys(source).sort().join(',') === 'event,forces,owner,phase,producer,relocation,territory,turn') ||
|
||||
(source.producer === 'wormRide' &&
|
||||
Object.keys(source).sort().join(',') === 'event,forces,owner,phase,producer,territory,turn,wormRide') ||
|
||||
(source.producer === 'spiritualArrival' &&
|
||||
Object.keys(source).sort().join(',') === 'event,forces,owner,phase,producer,spiritual,territory,turn')) &&
|
||||
identifier(source.event) && identifier(source.owner) && identifier(source.territory) &&
|
||||
@@ -492,7 +532,7 @@ export function validateAutomaticAdvisorFlip(
|
||||
? record(source.relocation) && (source.relocation.kind === 'discovery'
|
||||
? source.phase === 0 : source.relocation.kind === 'ambassador' && [1, 3, 5, 8].includes(source.phase))
|
||||
: source.producer === 'spiritualArrival' ? [1, 3, 4, 5, 6, 8].includes(source.phase)
|
||||
: source.phase === (source.producer === 'storm' ? 0 : source.producer === 'gamont' ? 8 :
|
||||
: source.phase === (source.producer === 'storm' ? 0 : source.producer === 'wormRide' ? 1 : source.producer === 'gamont' ? 8 :
|
||||
source.producer === 'battleLosses' || source.producer === 'faceDance' ? 6 : 5)) &&
|
||||
currentWindow(ctx) && source.phase === ctx.phase,
|
||||
'Automatic advisor conversion lost its original current-turn committed producer.');
|
||||
@@ -514,6 +554,7 @@ export function validateAutomaticAdvisorFlip(
|
||||
else if (source.producer === 'faceDance') validateFaceDanceSource(ctx, source);
|
||||
else if (source.producer === 'storm') validateStormSource(ctx, source);
|
||||
else if (source.producer === 'specialRelocation') validateRelocationSource(ctx, source);
|
||||
else if (source.producer === 'wormRide') validateWormRideSource(ctx, source);
|
||||
else validateSpiritualArrivalSource(ctx, source);
|
||||
const forces = physicalGroup(owner, source.territory);
|
||||
requireFlip(record(source.forces) && Object.keys(forces).length > 0 &&
|
||||
|
||||
Reference in new issue
Block a user