Files
Dune/game/ambassador-phase.ts
T

79 lines
2.5 KiB
TypeScript

import type { Game } from './engine';
import { location } from './board';
import { validAmbassadorResume } from './ambassador-resume';
import { currentHomeworldRevivalArrival, validateHomeworldRevivalReturn } from './homeworld-revival-return';
import { validateHomeworldVictoryReturn } from './homeworld-victory-return';
import {
validateHomeworldArrival,
type HomeworldArrivalFrame,
type HomeworldArrivalTag,
} from './homeworld-arrival';
export type AmbassadorPhaseContext = Pick<
Game,
| 'turn'
| 'phase'
| 'players'
| 'homeworlds'
| 'homeworldRevivalReturn'
| 'homeworldRevivalProgress'
| 'homeworldVictoryReinforcement'
| 'lastBattleContext'
| 'pendingAmbassador'
>;
/** Extra phases belong only to the recorded arrival and its actual BG arrivals. */
export function ambassadorPhaseAllowed(g: AmbassadorPhaseContext): boolean {
const entry = g.pendingAmbassador;
const candidates: {
tag: HomeworldArrivalTag;
frame: HomeworldArrivalFrame | undefined;
}[] = [
{ tag: 'revivalEvent', frame: currentHomeworldRevivalArrival(g.homeworldRevivalReturn) ?? undefined },
{ tag: 'victoryEvent', frame: g.homeworldVictoryReinforcement },
];
const matching = candidates.filter(
({ tag, frame }) =>
entry &&
(entry[tag] !== undefined ||
(Array.isArray(frame?.ambassadors) &&
frame.ambassadors.some((record) => record?.event === entry.event))),
);
if (!matching.length) return g.phase === 1 || g.phase === 5;
if (matching.length !== 1) return false;
const { tag, frame } = matching[0];
if (
!entry ||
!frame ||
entry[tag] !== frame.event ||
frame.stage !== 'arrival' ||
frame.turn !== g.turn ||
frame.phase !== g.phase ||
entry.turn !== g.turn ||
entry.phase !== g.phase ||
entry.resume !== 'none' ||
!validAmbassadorResume(g, entry)
)
return false;
try {
if (tag === 'revivalEvent')
validateHomeworldRevivalReturn(g, g.homeworldRevivalReturn);
else validateHomeworldVictoryReturn(g);
validateHomeworldArrival(g, frame, tag);
} catch {
return false;
}
const record = frame.ambassadors!.at(-1);
if (
!record ||
record.completed ||
record.event !== entry.event ||
record.entrant !== entry.entrant ||
record.destination !== location(entry.territory, entry.sector)
)
return false;
return record.parent === undefined
? entry.guildAdvisorOrigin === undefined
: entry.guildAdvisorOrigin?.event === record.parent;
}