Implement Moritani Nexus placement and preserve later Terror custody
This commit is contained in:
1 parent
290259bac2
commit
ae66668e2e
27 files changed
+2208
-73
No files matched your search
@@ -0,0 +1,32 @@
|
||||
import type { Game } from './engine';
|
||||
import { TERRITORIES } from './board';
|
||||
import { TERROR_STRONGHOLDS } from './moritani-terror';
|
||||
import { validateNexusMoritani } from './nexus-moritani';
|
||||
|
||||
export type TerrorLocationContext = Pick<Game,'players'> & Partial<Pick<Game,'turn'|'nexusMoritaniHistory'|'nexusMoritaniLocations'>>;
|
||||
type Record = NonNullable<Game['nexusMoritaniHistory']>[number];
|
||||
export function nexusMoritaniRecordSignature(record: Record): string {
|
||||
return JSON.stringify([record.receipt.signature,record.stage,record.before,record.frame]);
|
||||
}
|
||||
/** A historical grant survives card disposal, population changes and revelation.
|
||||
* It never grants a new placement action or admits Homeworld/HMS destinations. */
|
||||
export function terrorLocationAllowed(context: TerrorLocationContext, token: string, territory: string, event?: string, pending = false, historical = false): boolean {
|
||||
if (!event && TERROR_STRONGHOLDS.includes(territory)) return true;
|
||||
if (!TERRITORIES.some(t => t.id === territory) || !Number.isSafeInteger(context.turn)) return false;
|
||||
const record = context.nexusMoritaniHistory?.find(candidate =>
|
||||
candidate.receipt?.token === token && candidate.receipt.territory === territory &&
|
||||
(!event || candidate.receipt.event === event) && candidate.stage === (pending ? 'pending' : 'complete'));
|
||||
if (!record || record.signature !== nexusMoritaniRecordSignature(record)) return false;
|
||||
try { validateNexusMoritani({turn:context.turn!,players:context.players},record.receipt); }
|
||||
catch { return false; }
|
||||
if (pending) return record.receipt.turn === context.turn;
|
||||
return historical || (context.nexusMoritaniLocations?.[token]?.event === record.receipt.event &&
|
||||
context.nexusMoritaniLocations[token].territory === territory);
|
||||
}
|
||||
export function terrorEntryLocationAllowed(context: TerrorLocationContext, entry: NonNullable<Game['pendingTerrorEntry']>): boolean {
|
||||
if (TERROR_STRONGHOLDS.includes(entry.territory) && !entry.nexusPlacements) return true;
|
||||
const ids = entry.candidates ?? [entry.token];
|
||||
return !!entry.nexusPlacements && Object.keys(entry.nexusPlacements).length === ids.length && ids.every(id =>
|
||||
typeof entry.nexusPlacements?.[id] === 'string' &&
|
||||
terrorLocationAllowed(context,id,entry.territory,entry.nexusPlacements[id],false,true));
|
||||
}
|
||||
Reference in new issue
Block a user