Support Sapho ordering during Advanced Revival
This commit is contained in:
1 parent
011b6aa096
commit
82370d906f
15 files changed
+1092
-28
No files matched your search
@@ -15,6 +15,10 @@ function unavailableReason(game: GameView) {
|
||||
if (game.truthtrance || game.response || game.phaseOpening ||
|
||||
(game.decision && !(game.phase === 8 && game.decision.kind === 'moritaniExtortion')))
|
||||
return 'Finish the current interaction before changing turn order.';
|
||||
if (game.phase === 4)
|
||||
return !game.advanced || !game.revivalOrder
|
||||
? 'Revival order changes require an ordered Advanced Revival phase. Basic and an already-opened unstamped phase keep their existing timing.'
|
||||
: 'Choose first or last only among remaining unstarted Revival turns. A player who has started finishes their Revival choices unchanged. Completed turns stay finished; already-held positions and committed cards are unavailable.';
|
||||
if (game.phase === 8 && game.extortion?.pending)
|
||||
return 'Only an unanswered non-Moritani player can change their Extortion choice position. Earlier declines stay finished. Already-held first/last positions and committed cards are unavailable; you may still decline payment when your choice arrives.';
|
||||
if (game.phase === 3) {
|
||||
@@ -59,7 +63,7 @@ export function SaphoOrderButton({
|
||||
}}
|
||||
>
|
||||
{option.scope === 'battleAggressor' ? 'Become aggressor and discard Juice of Sapho' :
|
||||
`${bidding ? 'Bid' : option.scope === 'battleOrder' ? 'Choose battles' : option.scope === 'extortion' ? 'Take your Extortion choice' : 'Take your movement turn'} ${option.mode} and discard Juice of Sapho`}
|
||||
`${bidding ? 'Bid' : option.scope === 'battleOrder' ? 'Choose battles' : option.scope === 'extortion' ? 'Take your Extortion choice' : option.scope === 'revival' ? 'Take your Revival turn' : 'Take your movement turn'} ${option.mode} and discard Juice of Sapho`}
|
||||
</Button>
|
||||
);
|
||||
}
|
||||
@@ -79,7 +83,9 @@ export function JuiceOfSapho({
|
||||
(c) => richeseCardDefinition(c)?.card.effect === 'juiceOfSapho',
|
||||
);
|
||||
if (!card) return null;
|
||||
const options = game.saphoOptions ?? [];
|
||||
const options = (game.saphoOptions ?? []).filter(option => option.scope !== 'revival' ||
|
||||
(game.advanced && game.phase === 4 && game.revivalOrder?.remaining.includes(game.me) &&
|
||||
!game.revivalOrder.completed.includes(game.me)));
|
||||
return (
|
||||
<details className="my-4 min-w-0">
|
||||
<summary className="min-h-11 cursor-pointer py-3">
|
||||
@@ -98,7 +104,8 @@ export function JuiceOfSapho({
|
||||
const battle = option.scope === 'battleOrder';
|
||||
const aggressor = option.scope === 'battleAggressor';
|
||||
const extortion = option.scope === 'extortion';
|
||||
const afterCurrent = option.scope === 'movement' && option.afterCurrent;
|
||||
const revival = option.scope === 'revival';
|
||||
const afterCurrent = (option.scope === 'movement' || revival) && option.afterCurrent;
|
||||
const currentPlayer = afterCurrent
|
||||
? game.players.find(player => player.id === afterCurrent)?.name ?? 'The active player'
|
||||
: null;
|
||||
@@ -107,7 +114,15 @@ export function JuiceOfSapho({
|
||||
key={`${option.scope}-${option.event}-${option.mode}`}
|
||||
className="flex min-w-0 flex-col gap-2"
|
||||
>
|
||||
{currentPlayer && (
|
||||
{currentPlayer && (revival ? (
|
||||
<p aria-label="Provisional queued Revival order">
|
||||
Provisional queued Revival order: {currentPlayer} finishes
|
||||
the current Revival turn unchanged. Your {option.mode}
|
||||
{' '}position applies among later unstarted Revival turns.
|
||||
Completed turns, returned pieces, payments and revival
|
||||
allowances stay unchanged.
|
||||
</p>
|
||||
) : (
|
||||
<p>
|
||||
Provisional queued movement order: {currentPlayer} finishes
|
||||
the current combined shipment and movement turn unchanged.
|
||||
@@ -118,7 +133,7 @@ export function JuiceOfSapho({
|
||||
? ' The Advanced Guild keeps its native timing choice at the next boundary. A last position still follows the Guild.'
|
||||
: ''}
|
||||
</p>
|
||||
)}
|
||||
))}
|
||||
<p>
|
||||
{aggressor
|
||||
? 'Become this battle’s aggressor. You win ordinary ties; a Habbanya Stronghold advantage still takes precedence. The participants, committed plans and later battle choices stay unchanged.'
|
||||
@@ -130,6 +145,8 @@ export function JuiceOfSapho({
|
||||
? `Bid ${option.mode} in the current Once Around lot. Each eligible player still has only one bidding opportunity.`
|
||||
: battle
|
||||
? `Choose your remaining battles ${option.mode}. Completed battles stay resolved. This changes who chooses next, not the aggressor or tie advantage of a battle. Other players may still choose battles against you before your turn.`
|
||||
: revival
|
||||
? `Take the ${option.mode} remaining Revival turn. Completed Revival turns stay finished. This changes the remaining order without granting another revival, resetting allowances or returning completed players to the queue.`
|
||||
: `Take the ${option.mode} remaining combined shipment and movement turn. Completed turns stay completed${option.mode === 'last' ? ', and the Guild cannot move behind you' : game.advanced && game.players.some(player => player.faction === 'guild' && player.id !== game.me) ? '. Provisional first priority: the Guild retains its next legal timing choice and may take its turn before yours; a Karama-locked privilege stays locked' : ''}.`}
|
||||
</p>
|
||||
<SaphoOrderButton card={card.id} option={option} act={act} busy={busy} />
|
||||
|
||||
@@ -10,7 +10,7 @@ type Props = { game: GameView; act: (action: Action) => void; busy: boolean };
|
||||
export function revivalTurnOrderBlock(game: GameView): string | null {
|
||||
const order = game.revivalOrder;
|
||||
if (!game.advanced || !order) return null;
|
||||
if (order.version !== 1 || order.turn !== game.turn || game.status !== 'playing' || game.phase !== 4)
|
||||
if ((order.version !== 1 && order.version !== 2) || order.turn !== game.turn || game.status !== 'playing' || game.phase !== 4)
|
||||
return 'This Revival turn is no longer current.';
|
||||
if (!game.players.some(player => player.id === game.me) || !order.original.includes(game.me))
|
||||
return 'This seat has no Revival turn in the current order.';
|
||||
@@ -62,8 +62,9 @@ export function RevivalTurn({ game, act, busy }: Props) {
|
||||
<p>Completed Revival turns: {order.completed.map(name).join(', ') || 'None yet'}.</p>
|
||||
<p className="fine" aria-label="Provisional Revival grouping">
|
||||
Provisional grouping: finish your force, leader and Kwisatz Haderach revival
|
||||
choices together before ending your turn. Revival turns follow the printed
|
||||
storm order for forces. Tleilaxu can still answer another player’s requests.
|
||||
choices together before ending your turn. Revival turns begin in the printed
|
||||
storm order for forces. Juice of Sapho may change the remaining order;
|
||||
completed Revival turns stay finished. Tleilaxu can still answer another player’s requests.
|
||||
</p>
|
||||
{blocked && <output className="fine block">{blocked}</output>}
|
||||
<FinishRevivalTurn game={game} act={act} busy={busy} />
|
||||
|
||||
Reference in new issue
Block a user