Files
Dune/components/ix-technology.tsx
T

141 lines
5.3 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
'use client';
import { useState } from 'react';
import { Button } from '@/components/ui/button';
import { HelpTip } from './help-tip';
import { CardInspector } from './card-inspector';
import type { Action, GameView } from '@/game/engine';
import { ixStartingCardDealPlan } from '@/game/ixian-starting-cards';
export function IxTechnology({
game: g,
act,
busy,
}: {
game: GameView;
act: (a: Action) => void;
busy: boolean;
}) {
const kind = g.decision?.kind;
const me = g.players.find((p) => p.id === g.me)!;
const [position, setPosition] = useState('bottom');
if (
g.decision?.player !== g.me ||
!['ixSetup', 'ixAuction', 'ixTechnology', 'ixAllyCard'].includes(kind ?? '')
) return null;
if (kind === 'ixAuction' && g.ixTechnology?.blocked)
return <output className="notice block">{g.ixTechnology.blocked}</output>;
const cards =
kind === 'ixSetup'
? g.ixTechnology?.setup
: kind === 'ixAuction'
? g.ixTechnology?.pool
: me.hand;
let startingExplanation = 'Choose your starting card from the recorded pool. The remaining cards are shuffled and dealt privately.';
if (kind === 'ixSetup' && cards?.length) {
try {
const plan = ixStartingCardDealPlan(g, cards.length);
startingExplanation = plan.kind === 'advanced-pool'
? 'Choose your starting card from the full Advanced pool, including Harkonnen’s extra card. The remainder is shuffled: two cards go to Harkonnen and one to every other faction. No extra card is drawn from the deck.'
: plan.deckBonus
? `${g.advanced ? 'This recorded draft keeps the earlier starting procedure. ' : ''}Choose your starting card. The remaining cards are shuffled and dealt privately, one to each other faction; Harkonnen then draws its extra card from the deck.`
: 'Choose your starting card. The remaining cards are shuffled and dealt privately, one to each other faction.';
} catch {
// A transient/incomplete view keeps the generic prompt; the server owns
// the saved draft, recipient quantities and final physical deal.
}
}
if (kind === 'ixAllyCard')
return (
<>
<p>
You purchased{' '}
<strong>
{g.ixPurchased?.name ?? 'a card that is no longer in your hand'}
</strong>
. Your Ixian alliance lets you keep it or discard it for the top card
of the deck. The replacement stays private.{' '}
<HelpTip topic="ixTechnology" />
</p>
{g.ixPurchased && <CardInspector card={g.ixPurchased} />}
<Button
className="game-action"
disabled={busy}
onClick={() => act({ type: 'decision', accept: false })}
>
Keep purchase
</Button>
<Button
variant="outline"
disabled={busy || !g.ixPurchased}
onClick={() => act({ type: 'decision', accept: true })}
>
Request replacement
</Button>
</>
);
return (
<>
<p>
{kind === 'ixSetup'
? startingExplanation
: kind === 'ixAuction'
? 'Privately choose one card from the original Ixian pool to return to the deck. The remaining pool will be shuffled for auction. This choice does not transfer unrelated Ixian Technology.'
: 'Exchange one card from your hand for the upcoming card, before Atreides looks. You commit your offered card before learning what you receive. This advantage can be attempted once this round.'}{' '}
<HelpTip topic="ixTechnology" />
</p>
{kind === 'ixAuction' && (
<label>
Return chosen card to
<select
value={position}
onChange={(e) => setPosition(e.target.value)}
>
<option value="bottom">Bottom of deck</option>
<option value="top">Top of deck</option>
</select>
</label>
)}
<div className="card-choices grid min-w-0 gap-3">
{cards?.map((c) => (
<article
key={c.id}
className="flex min-w-0 flex-col gap-3 rounded-lg border border-[#454b3c] bg-[#1d221b] p-3"
>
<h3 className="m-0 break-words text-base font-semibold text-[#efd9a8]">
{c.name}
</h3>
<CardInspector card={c} />
<Button
variant="outline"
className="game-action min-h-11"
aria-label={`${kind === 'ixAuction' ? 'Return card' : kind === 'ixSetup' ? 'Choose starting card' : 'Offer this card'}: ${c.name}`}
disabled={busy}
onClick={() =>
act({
type: 'decision',
card: c.id,
...(kind === 'ixAuction' ? { position } : {}),
})
}
>
{kind === 'ixAuction'
? 'Return card'
: kind === 'ixSetup'
? 'Choose starting card'
: 'Offer this card'}
</Button>
</article>
))}
</div>
{kind === 'ixTechnology' && (
<Button
variant="outline"
disabled={busy}
onClick={() => act({ type: 'decision', decline: true })}
>
Save technology for a later card
</Button>
)}
</>
);
}