Files
Dune/components/ix-substitution.tsx
T
2026-09-08 07:37:52 +10:00

85 lines
2.6 KiB
TypeScript

'use client';
import { useState } from 'react';
import type { Action, GameView } from '@/game/engine';
import { splitLocation } from '@/game/board';
import { Button } from './ui/button';
import { Input } from './ui/input';
export function IxSubstitution({
game: g,
act,
busy,
}: {
game: GameView;
act: (action: Action) => void;
busy: boolean;
}) {
const [sources, setSources] = useState<Record<string, number>>({});
const [recover, setRecover] = useState<Record<string, number>>({});
if (g.decision?.kind !== 'ixSubstitution') return null;
const d = g.decision;
const me = g.players.find((p) => p.id === g.me)!;
const available = Object.entries(me.forces)
.filter(([key]) => splitLocation(key).territory === d.territory)
.map(
([key, count]) => [key, count - (me.elites?.forces[key] ?? 0)] as const,
)
.filter(([, count]) => count > 0);
const total = (value: Record<string, number>) =>
Object.values(value).reduce((a, b) => a + b, 0);
return (
<>
<p>
Exchange surviving suboids, one for one, to retain cyborgs lost in this
battle. Retained cyborgs return to their casualty sectors. Opponents may
cancel this substitution with Karama.
</p>
<h3>Suboids to sacrifice</h3>
{available.map(([key, max]) => (
<label key={key}>
Sector {splitLocation(key).sector} · {max} suboids available
<Input
type="number"
min={0}
max={max}
value={sources[key] ?? 0}
onChange={(e) =>
setSources({ ...sources, [key]: Number(e.target.value) })
}
/>
</label>
))}
<h3>Cyborgs to retain</h3>
{Object.entries(d.losses).map(([key, max]) => (
<label key={key}>
Sector {splitLocation(key).sector} · {max} cyborgs lost
<Input
type="number"
min={0}
max={max}
value={recover[key] ?? 0}
onChange={(e) =>
setRecover({ ...recover, [key]: Number(e.target.value) })
}
/>
</label>
))}
<p>
{total(sources)} suboids for {total(recover)} cyborgs
</p>
<Button
disabled={busy || !total(sources) || total(sources) !== total(recover)}
onClick={() => act({ type: 'decision', sources, recover })}
>
Confirm substitution
</Button>
<Button
variant="outline"
disabled={busy}
onClick={() => act({ type: 'decision', decline: true })}
>
Keep these casualties
</Button>
</>
);
}