Support Sapho ordering for shared arrivals
Verify and publish checkpoint container / container (push) Canceled after 0s

This commit is contained in:
Quintine committed 2026-10-29 05:29:51 +11:00
1 parent b18a767470
commit e457478f7d
18 files changed
+808 -23

No files matched your search

+8 -3
View File
@@ -1,4 +1,5 @@
'use client';
import { SaphoArrivalOrder } from './sapho-arrival-order';
import { RicheseBidPromisePanel } from './richese-bid-promise-panel';
import { EarlyRicheseBidPromises } from './early-richese-bid-promises';
import { TravelPromises } from './travel-promises';
@@ -385,8 +386,8 @@ export function GameTable({
const harkonnenBetrayalOwnsControls = !!g.nexusHarkonnenBetrayalReaction &&
!g.response && !g.decision && !g.truthtrance && !g.phaseOpening &&
!g.automaticContinuationPending && !g.nexusCards?.waiting.length && !g.nexusTraitors?.pending;
const busy = reactionBusy || !!g.victoryContinuation || !!g.nexusFremenRideBetrayal || g.automaticContinuationPending || !!g.semutaReaction || !!g.kullReaction || !!g.richeseBetrayalReaction || !!g.guildBetrayalReaction || !!g.nexusIxianReplacement || ixianBetrayalOwnsControls || harkonnenBetrayalOwnsControls;
const reactionOwnsControls = !!g.nexusFremenRideBetrayal || !!g.kullReaction || !!g.kullCounterEvent || !!g.richeseBetrayalReaction || !!g.guildBetrayalReaction || !!g.nexusIxianReplacement || ixianBetrayalOwnsControls || harkonnenBetrayalOwnsControls;
const busy = reactionBusy || !!g.saphoArrivalOrder || !!g.victoryContinuation || !!g.nexusFremenRideBetrayal || g.automaticContinuationPending || !!g.semutaReaction || !!g.kullReaction || !!g.richeseBetrayalReaction || !!g.guildBetrayalReaction || !!g.nexusIxianReplacement || ixianBetrayalOwnsControls || harkonnenBetrayalOwnsControls;
const reactionOwnsControls = !!g.saphoArrivalOrder || !!g.nexusFremenRideBetrayal || !!g.kullReaction || !!g.kullCounterEvent || !!g.richeseBetrayalReaction || !!g.guildBetrayalReaction || !!g.nexusIxianReplacement || ixianBetrayalOwnsControls || harkonnenBetrayalOwnsControls;
const canSpendKarama = (card: Card, purpose: KullPurpose) =>
!kullPurposeBlock(g, purpose) && canUseAsKaramaRole(g, me, card);
const canActivateKarama = (card: Card) => canSpendKarama(card, kullSpecialPurpose(me.faction));
@@ -1514,15 +1515,19 @@ export function GameTable({
<EcazLoyaltyCard loyalty={g.ecazLoyalty} />
<MoritaniTerrorSupply game={g} />
<MoritaniExtortionNotice game={g} />
{g.saphoArrivalOrder && <SaphoArrivalOrder view={g.saphoArrivalOrder} me={g.me}
busy={transportBusy || !!g.roomControl?.paused || !!g.roomControl?.closed || !!me.autopilot}
name={id => g.players.find(player => player.id === id)?.name ?? id} act={act} />}
{g.arrivalOverlap && (
<section className="notice" aria-label="Ambassador and Terror response order">
<p>
{g.players.find((player) => player.id === g.arrivalOverlap!.entrant)?.name ?? 'The entrant'}
{' '}entered {territory(g.arrivalOverlap.territory).name}. Ecaz Ambassador
and Moritani Terror resolve in this table’s provisional storm order:{' '}
and Moritani Terror use this table’s provisional reaction order:{' '}
{g.arrivalOverlap.first === 'ambassador' ? 'Ecaz, then Moritani' : 'Moritani, then Ecaz'}.
{g.semutaReaction
? ' The current fresh-discard response must finish before the next arrival decision.'
: g.saphoArrivalOrder ? ' The reaction owners are choosing their order.'
: <> {g.arrivalOverlap.active === 'ambassador' ? 'Ecaz' : 'Moritani'} decides now.</>}
{' '}The original entry is not repeated.
</p>