Offer Emperor gifts before allied auction payment
Verify and publish checkpoint container / container (push) Canceled after 0s
Verify and publish checkpoint container / container (push) Canceled after 0s
This commit is contained in:
1 parent
93b0146de9
commit
6cec4ed78b
11 files changed
+528
-2
No files matched your search
@@ -0,0 +1,35 @@
|
||||
'use client';
|
||||
|
||||
import { useId, useState } from 'react';
|
||||
import type { Action, GameView } from '@/game/engine';
|
||||
|
||||
/** The server exposes the current optional opportunity only to its Emperor. */
|
||||
export function EmperorAuctionGift({ game, act, busy }: {
|
||||
game: GameView;
|
||||
act: (action: Action) => void;
|
||||
busy: boolean;
|
||||
}) {
|
||||
const id = useId();
|
||||
const [raw, setRaw] = useState('1');
|
||||
const offer = game.emperorAuctionGift;
|
||||
if (!offer) return null;
|
||||
const amount = /^[1-9]\d*$/.test(raw) ? Number(raw) : NaN;
|
||||
const canShare = !busy && Number.isSafeInteger(amount) && amount >= 1 && amount <= offer.maximum;
|
||||
const recipient = game.players.find(player => player.id === offer.recipient)?.name ?? 'your ally';
|
||||
|
||||
return <section className="notice min-w-0 space-y-3 break-words" aria-label="Emperor auction gift">
|
||||
<h3>Share spice with {recipient}</h3>
|
||||
<p className="fine">The winning bid and its committed ally payment split remain unchanged. Your ally chooses how to pay after the gift’s Karama response.</p>
|
||||
<label htmlFor={`${id}-amount`}>Spice to share</label>
|
||||
<input id={`${id}-amount`} type="number" inputMode="numeric" min={1} max={offer.maximum}
|
||||
step={1} value={raw} disabled={busy || offer.maximum < 1} onChange={event => setRaw(event.target.value)} />
|
||||
<button type="button" className="game-action" disabled={!canShare}
|
||||
onClick={() => { if (canShare) act({type:'emperorGift', amount}); }}>
|
||||
Share spice
|
||||
</button>
|
||||
<button type="button" className="game-action" disabled={busy}
|
||||
onClick={() => { if (!busy) act({type:'emperorAuctionGiftContinue', event:offer.event}); }}>
|
||||
Continue to payment
|
||||
</button>
|
||||
</section>;
|
||||
}
|
||||
@@ -291,6 +291,7 @@ import { RosterAlliance } from './roster-alliance';
|
||||
import { CoalitionFunding, coalitionFundingContributions, type CoalitionFundingContribution } from './coalition-funding';
|
||||
import { CoalitionEmperorAid } from './coalition-emperor-aid';
|
||||
import { EmperorTimingGift } from './emperor-timing-gift';
|
||||
import { EmperorAuctionGift } from './emperor-auction-gift';
|
||||
import { NexusEmperorPayment } from './nexus-emperor-payment';
|
||||
import { NexusEmperorSellerPurchase } from './nexus-emperor-seller-purchase';
|
||||
import { NexusEmperorAmbassadorPurchase } from './nexus-emperor-ambassador-purchase';
|
||||
@@ -3221,6 +3222,7 @@ export function GameTable({
|
||||
: 'Spoils of battle'}
|
||||
</h2>
|
||||
<EmperorTimingGift game={g} act={act} busy={busy} />
|
||||
<EmperorAuctionGift game={g} act={act} busy={busy} />
|
||||
{g.decision.kind === 'capturedLeader' &&
|
||||
(g.decision.controller ?? g.decision.owner) === me.id && (
|
||||
<p className="notice">
|
||||
@@ -3258,7 +3260,9 @@ export function GameTable({
|
||||
. No storm casualties have been applied.
|
||||
</p>
|
||||
)}
|
||||
{g.decision.player !== me.id ? (
|
||||
{g.emperorAuctionGiftPending ? (
|
||||
<p className="muted">Waiting for the Emperor to finish the allied gift opportunity.</p>
|
||||
) : g.decision.player !== me.id ? (
|
||||
<p className="muted">
|
||||
Waiting for{' '}
|
||||
{g.players.find((p) => p.id === g.decision?.player)?.name} to
|
||||
|
||||
Reference in new issue
Block a user