Support Sapho ordering at Testing Station
Verify and publish checkpoint container / container (push) Successful in 10m32s
Verify and publish checkpoint container / container (push) Successful in 10m32s
This commit is contained in:
1 parent
220d78c779
commit
1972622c11
11 files changed
+445
-9
No files matched your search
+63
-2
@@ -30,6 +30,14 @@ export type DiscoveryStorm = {
|
||||
order: string[];
|
||||
choices: { owner: string; delta: -1 | 0 | 1 }[];
|
||||
};
|
||||
/** One provisional Sapho reorder, bound to the original physical order. */
|
||||
sapho?: {
|
||||
event: string;
|
||||
nextEvent: string;
|
||||
originalOrder: string[];
|
||||
holder: string;
|
||||
mode: 'first' | 'last';
|
||||
};
|
||||
};
|
||||
export type DiscoveryStormContext = Pick<
|
||||
Game,
|
||||
@@ -85,6 +93,7 @@ export function discoveryStormSignature(
|
||||
frame.stage,
|
||||
];
|
||||
if (frame.queue) values.push(frame.queue.order, frame.queue.choices);
|
||||
if (frame.sapho) values.push(frame.sapho);
|
||||
return JSON.stringify(values);
|
||||
}
|
||||
export function discoveryStormDistance(frame: DiscoveryStorm): number {
|
||||
@@ -164,7 +173,9 @@ export function validateDiscoveryStorm(
|
||||
need(
|
||||
record(frame) &&
|
||||
Object.keys(frame).sort().join(',') === (frame.queue
|
||||
? 'base,delta,event,from,owner,queue,signature,stage,token,turn'
|
||||
? (frame.sapho
|
||||
? 'base,delta,event,from,owner,queue,sapho,signature,stage,token,turn'
|
||||
: 'base,delta,event,from,owner,queue,signature,stage,token,turn')
|
||||
: 'base,delta,event,from,owner,signature,stage,token,turn') &&
|
||||
typeof frame.event === 'string' &&
|
||||
frame.event.length > 0 &&
|
||||
@@ -211,6 +222,20 @@ export function validateDiscoveryStorm(
|
||||
distance += choice.delta;
|
||||
need(distance >= 0 && distance <= 40, 'Every station choice must retain a legal current distance.');
|
||||
}
|
||||
if (frame.sapho) {
|
||||
const sapho = frame.sapho;
|
||||
need(record(sapho) && Object.keys(sapho).sort().join(',') === 'event,holder,mode,nextEvent,originalOrder' &&
|
||||
typeof sapho.event === 'string' && sapho.event.length > 0 &&
|
||||
typeof sapho.nextEvent === 'string' && sapho.nextEvent.length > 0 && sapho.nextEvent !== sapho.event &&
|
||||
Array.isArray(sapho.originalOrder) && sapho.originalOrder.length === 2 &&
|
||||
new Set(sapho.originalOrder).size === 2 &&
|
||||
sapho.originalOrder.every(id => typeof id === 'string' && g.players.some(p => p.id === id)) &&
|
||||
sapho.originalOrder.includes(sapho.holder) && ['first', 'last'].includes(sapho.mode) &&
|
||||
(sapho.mode === 'first' ? sapho.originalOrder[1] === sapho.holder : sapho.originalOrder[0] === sapho.holder) &&
|
||||
JSON.stringify(queue.order) === JSON.stringify([...sapho.originalOrder].reverse()) &&
|
||||
frame.event === (queue.choices.length ? `${sapho.nextEvent}:1` : sapho.nextEvent),
|
||||
'The station must retain the original Sapho ordering and event.');
|
||||
}
|
||||
}
|
||||
need(
|
||||
discoveryStormDistance(frame) >= 0 &&
|
||||
@@ -250,7 +275,7 @@ export function validateDiscoveryStorm(
|
||||
if (frame.stage === 'choose') {
|
||||
const occupants = stationOccupants(g);
|
||||
need(
|
||||
JSON.stringify(occupants) === JSON.stringify(frame.queue?.order ?? [frame.owner]) &&
|
||||
JSON.stringify(occupants) === JSON.stringify(frame.sapho?.originalOrder ?? frame.queue?.order ?? [frame.owner]) &&
|
||||
g.stormPending === discoveryStormDistance(frame),
|
||||
'The station choice no longer belongs to its original occupant and storm.',
|
||||
);
|
||||
@@ -260,6 +285,42 @@ export function validateDiscoveryStorm(
|
||||
'The adjusted storm must retain the chosen distance.',
|
||||
);
|
||||
}
|
||||
|
||||
/** Available position changes before either original station occupant chooses.
|
||||
* Card ownership, disposal and any external interrupt belong to the caller. */
|
||||
export function discoveryStormSaphoModes(
|
||||
g: DiscoveryStormContext,
|
||||
frame: DiscoveryStorm,
|
||||
holder: string,
|
||||
): Array<'first' | 'last'> {
|
||||
validateDiscoveryStorm(g, frame);
|
||||
if (frame.stage !== 'choose' || !frame.queue || frame.queue.choices.length || frame.sapho) return [];
|
||||
const index = frame.queue.order.indexOf(holder);
|
||||
return index === 0 ? ['last'] : index === 1 ? ['first'] : [];
|
||||
}
|
||||
|
||||
/** Bind a single meaningful reorder and invalidate all old station actions. */
|
||||
export function reorderDiscoveryStorm(
|
||||
g: DiscoveryStormContext,
|
||||
frame: DiscoveryStorm,
|
||||
input: {holder: string; event: unknown; mode: 'first' | 'last'; nextEvent: string},
|
||||
): DiscoveryStorm {
|
||||
const modes = discoveryStormSaphoModes(g, frame, input.holder);
|
||||
need(input.event === frame.event && modes.includes(input.mode) &&
|
||||
typeof input.nextEvent === 'string' && input.nextEvent.length > 0 && input.nextEvent !== frame.event,
|
||||
'Choose an available Sapho ordering for the current station event.');
|
||||
const originalOrder = [...frame.queue!.order];
|
||||
const order = [...originalOrder].reverse();
|
||||
const next: DiscoveryStorm = {
|
||||
...frame, event: input.nextEvent, owner: order[0],
|
||||
queue: {order, choices: []},
|
||||
sapho: {event: frame.event, nextEvent: input.nextEvent, originalOrder, holder: input.holder, mode: input.mode},
|
||||
signature: '',
|
||||
};
|
||||
next.signature = discoveryStormSignature(next);
|
||||
validateDiscoveryStorm(g, next);
|
||||
return next;
|
||||
}
|
||||
export function chooseDiscoveryStorm(
|
||||
g: DiscoveryStormContext,
|
||||
frame: DiscoveryStorm,
|
||||
|
||||
Reference in new issue
Block a user