Connect physical Jacurutu allocation and cumulative station choices
This commit is contained in:
1 parent
373badd560
commit
554f2bf9e9
22 files changed
+1943
-129
No files matched your search
@@ -96,7 +96,7 @@ export function DiscoveryPanel({ game, act, busy }: Props) {
|
||||
</div>
|
||||
<p className="fine">Inspection and reveal are optional. Next-turn free entry, sole-occupant Cistern income and later-turn Ornithopter movement are available in the development prototype. Jacurutu income, Testing Station storm choices and Shrine card conversion are prototyped. {game.advanced
|
||||
? 'A sole Orgiz occupant takes one spice for each territory where one rival collected board spice.'
|
||||
: 'Basic keeps the provisional one-spice transfer per positive board deposit collected by one rival.'} Contested Orgiz, different or shared collectors, mixed-force Jacurutu rewards and contested Cistern/Testing Station benefits remain pending; uncertain transfers do not block ordinary Collection.</p>
|
||||
: 'Basic keeps the provisional one-spice transfer per positive board deposit collected by one rival.'} Mixed physical Jacurutu dials now use a defeated-player choice before settlement. Testing Station occupants each choose once in original storm order, cumulatively. These ordering/allocation interpretations are provisional. Contested Cistern/Orgiz and different or shared collectors remain pending; uncertain transfers do not block ordinary Collection.</p>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -20,11 +20,11 @@ export function DiscoveryStormDecision({
|
||||
return (
|
||||
<section aria-label="Ecological Testing Station" className="space-y-3">
|
||||
<p>
|
||||
Your forces occupy Ecological Testing Station. The storm will move{' '}
|
||||
{offer.base} sectors. You may decrease or increase this by one, or keep
|
||||
the ordinary movement.
|
||||
Your forces occupy Ecological Testing Station. The storm currently
|
||||
moves {offer.base} sectors. You may decrease or increase this by one, or
|
||||
keep the current movement.
|
||||
</p>
|
||||
<p className="fine">This choice cannot change Weather Control.</p>
|
||||
<p className="fine">Prototype ordering: each occupying faction chooses once in storm order; adjustments are cumulative. This choice cannot change Weather Control.</p>
|
||||
<div className="flex flex-wrap gap-2">
|
||||
{offer.options.map((option) => {
|
||||
const action = actions.find(
|
||||
|
||||
@@ -34,6 +34,7 @@ import { GreatMakerDecision } from './great-maker';
|
||||
import { DiscoveryPanel, DiscoveryDiscardDecision } from './discoveries';
|
||||
import { DiscoveryEntryDecision } from './discovery-entry';
|
||||
import { DiscoveryStormDecision } from './discovery-storm';
|
||||
import { JacurutuDial } from './jacurutu-dial';
|
||||
import { NexusChoamTrade, NexusChoamInspectionDecision, NexusChoamInspectionInsight } from './nexus-choam-trade';
|
||||
import { NexusChoamBetrayal } from './nexus-choam-betrayal';
|
||||
import { NexusMoritaniBetrayal } from './nexus-moritani-betrayal';
|
||||
@@ -2616,6 +2617,8 @@ export function GameTable({
|
||||
? 'Choose Smuggler collection sectors'
|
||||
: g.decision.kind === 'sandmasterVictorySpice'
|
||||
? 'Choose Sandmaster victory spice sector'
|
||||
: g.decision.kind === 'jacurutuDial'
|
||||
? 'Identify your Jacurutu physical dial'
|
||||
: g.decision.kind === 'harassWithdraw'
|
||||
? 'Choose undialed forces to return'
|
||||
: g.decision.kind === 'diplomatRetreat'
|
||||
@@ -3072,6 +3075,9 @@ export function GameTable({
|
||||
<SmugglerBattleCollection key={g.decision.event} offer={g.decision} act={act} busy={busy} />
|
||||
) : g.decision.kind === 'sandmasterVictorySpice' ? (
|
||||
<SandmasterVictorySpice offer={g.decision} act={act} busy={busy} />
|
||||
) : g.decision.kind === 'jacurutuDial' && g.jacurutuDial ? (
|
||||
<JacurutuDial offer={g.jacurutuDial}
|
||||
onChoose={allocation => act({type:'decision',event:g.jacurutuDial!.event,allocation})} busy={busy} />
|
||||
) : g.decision.kind === 'harassWithdraw' ? (
|
||||
<>
|
||||
<HarassWithdrawChoice key={g.decision.event} game={g} act={act} busy={busy} />
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
'use client';
|
||||
|
||||
import {
|
||||
JACURUTU_BATTLE_INCOME_RULE,
|
||||
type JacurutuDialChoice,
|
||||
type JacurutuDialOffer,
|
||||
} from '@/game/discovery-battle';
|
||||
import { Button } from './ui/button';
|
||||
|
||||
/** Concrete physical reading of one legal allocation of the revealed dial. */
|
||||
export function jacurutuDialChoiceLabel(choice: JacurutuDialChoice): string {
|
||||
const { normal, elite, paidNormal, paidElite } = choice.dialed;
|
||||
const counters = [
|
||||
`${normal} ordinary counter${normal === 1 ? '' : 's'} (${paidNormal} paid)`,
|
||||
`${elite} elite counter${elite === 1 ? '' : 's'} (${paidElite} paid)`,
|
||||
].join(' · ');
|
||||
return `${counters} — ${
|
||||
choice.amount === 0
|
||||
? 'no spice from the bank'
|
||||
: `${choice.amount} spice from the bank`
|
||||
}`;
|
||||
}
|
||||
|
||||
/**
|
||||
* The defeated player's own allocation of their revealed dial. Only the legal
|
||||
* physical readings reported for this battle are offered; the numeric wheel
|
||||
* value alone never decides the counters.
|
||||
*/
|
||||
export function JacurutuDial({
|
||||
offer,
|
||||
onChoose,
|
||||
busy,
|
||||
}: {
|
||||
offer: JacurutuDialOffer;
|
||||
onChoose: (allocation: number) => void;
|
||||
busy: boolean;
|
||||
}) {
|
||||
if (!offer.choices.length) return null;
|
||||
return (
|
||||
<section
|
||||
className="flex flex-col gap-3"
|
||||
aria-label="Jacurutu Sietch dial allocation"
|
||||
>
|
||||
<p>
|
||||
You lost this battle in Jacurutu Sietch. Choose which counters your
|
||||
revealed dial actually committed; the winner collects one bank spice
|
||||
for each opposing undialed force sent to the Tanks.
|
||||
</p>
|
||||
<p className="fine">{JACURUTU_BATTLE_INCOME_RULE}</p>
|
||||
<p className="fine">Prototype interpretation: the defeated player identifies the physical dial allocation before battle settlement.</p>
|
||||
<div className="flex flex-wrap gap-2">
|
||||
{offer.choices.map((choice, allocation) => (
|
||||
<Button
|
||||
key={`${choice.dialed.normal}:${choice.dialed.elite}:${choice.dialed.paidNormal}:${choice.dialed.paidElite}`}
|
||||
className="game-action min-h-11 whitespace-normal"
|
||||
variant={choice.amount === 0 ? 'outline' : 'default'}
|
||||
disabled={busy}
|
||||
onClick={() => !busy && onChoose(allocation)}
|
||||
>
|
||||
{jacurutuDialChoiceLabel(choice)}
|
||||
</Button>
|
||||
))}
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
Reference in new issue
Block a user