'use client'; import { TERRITORIES } from '@/game/board'; import type { GameView } from '@/game/engine'; import type { MixedActionExpression } from '@/game/mixed-action-question'; import { parseTurnActionLeaf, TURN_ACTION_MAX_DEPTH, TURN_ACTION_MAX_LEAVES, type TurnActionLeaf } from '@/game/turn-action-promises'; import { MixedActionFields, mixedActionInputError, type MixedActionConfig } from './mixed-action-fields'; import { Input } from './ui/input'; type TurnActionExpression = MixedActionExpression; const recipients = (game: GameView, target: string) => { const player = game.players.find(player => player.id === target); return player ? game.players.filter(recipient => recipient.id !== target && recipient.id !== player.ally) : []; }; const config: MixedActionConfig = { prefix: 'turn-action', legend: 'Future payments, shipment and ground movements, with optional current facts', actionLabel: 'payment, shipment or ground-movement condition', actionTiming: 'Future ordinary payment, reserve shipment or ground move ยท this turn', actionHelp: <>Ordinary payment conditions sum future real bribes to the same recipient after the answer this turn. Earlier payments, gifts and ally aid do not count. The sender pays immediately; the recipient collects at the next Mentat opening. Payments made during Mentat Pause wait until next turn's Mentat opening; collection never counts twice. Shipment conditions concern the single future original reserve shipment after the answer. Ground-movement conditions use the maximum physical forces in one actual future move to that destination; smaller moves never add together. Shipment and movement close at your own Movement turn end, while payment conditions last until the actual turn ends. AND requires every condition; OR keeps legal alternatives. No makes the whole expression false, not every condition separately. Original costs, timing, cards, preparation and action rights still apply; this claim grants no extra action., fallbackError: 'Choose a future ordinary payment, reserve shipment or ground-movement condition, with optional current facts.', maxLeaves: TURN_ACTION_MAX_LEAVES, maxDepth: TURN_ACTION_MAX_DEPTH, requireFact: false, newAction: () => ({ kind: 'ship', territory: 'carthag', minimum: 1 }), parseAction: (input, game, target) => { const action = parseTurnActionLeaf(input); if (action.kind === 'payment' && !recipients(game, target).some(recipient => recipient.id === action.recipient)) throw new Error('Choose a public non-allied recipient for the future ordinary payment.'); return action; }, renderAction: ({ value, id, game, target, disabled, onChange }) => { const choices = recipients(game, target); return <> {value.kind === 'payment' ? <> : <> } 20} onChange={event => onChange({ ...value, minimum: event.currentTarget.valueAsNumber })} /> ; }, }; /** Public schema choices only; the native engine owns eligibility and funding. */ export function turnActionInputError(value: unknown, game: GameView, target: string): string | null { return mixedActionInputError(value, game, target, config); } export function TurnActionFields(props: { value: TurnActionExpression; game: GameView; target: string; disabled: boolean; onChange: (expression: TurnActionExpression) => void; }) { return MixedActionFields({ ...props, config }); }