'use client'; import { useState } from 'react'; import type { Action, GameView } from '@/game/engine'; import { faction } from '@/game/catalog'; import { leaderStrengthLabel } from '@/game/cards'; import { CHEAP_HERO_TRAITOR } from '@/game/traitors'; import { nexusTraitorDrawAction, nexusTraitorReturnAction, } from '@/game/nexus-traitor-options'; import { LeaderInspector, type LeaderDisplayIdentity, } from './leader-inspector'; import { Button } from './ui/button'; type Props = { game: GameView; act: (action: Action) => void; busy: boolean }; function identityFor(game: GameView, id: string): LeaderDisplayIdentity | null { if (id === CHEAP_HERO_TRAITOR) return { name: 'Cheap Hero / Heroine', factionName: 'Any faction', strength: 0, cheapHero: true, }; const leader = game.allLeaders.find((leader) => leader.id === id); return leader ? { id: leader.id, name: leader.name, factionName: faction(leader.faction).name, strength: leaderStrengthLabel(leader), } : null; } export function NexusTraitors({ game, act, busy }: Props) { const state = game.nexusTraitors; if (!state) return null; if (state.pending) { // Branch on the public owner before touching private choice identities. if (state.pending.owner !== game.me) return (

Waiting for{' '} {game.players.find((player) => player.id === state.pending!.owner) ?.name ?? 'the card holder'}{' '} to return {state.pending.count}{' '} {state.pending.count === 1 ? 'card' : 'cards'} privately.

); return ( ); } const offer = state.offer; if (!offer) return null; const action = nexusTraitorDrawAction(game, offer.event, offer.mode); const dancers = game.players.find((player) => player.id === game.me)?.faction === 'tleilaxu'; const label = dancers ? 'Face Dancer' : 'Traitor'; return (

Harkonnen Nexus ·{' '} {offer.mode === 'cunning' ? 'Cunning' : offer.mode === 'secretAlly' ? 'Secret Ally' : 'Betrayal'}

{offer.blocked ? (

{offer.blocked}

) : offer.mode === 'betrayal' ? (

The traitor cancellation response is not available yet.

) : ( <>

Draw {offer.draw} {label} {offer.draw === 1 ? 'card' : 'cards'}, then choose {offer.draw} from your hand to shuffle back. Newly drawn cards may be returned.

This uses your Harkonnen Nexus card. Your selections remain private.

)}
); } function ReturnCards({ game, act, busy }: Props) { const pending = game.nexusTraitors!.pending!; const [selected, setSelected] = useState([]); const dancers = game.players.find((player) => player.id === game.me)?.faction === 'tleilaxu'; const label = dancers ? 'Face Dancer' : 'Traitor'; const action = nexusTraitorReturnAction(game, pending.event, selected); const blocked = busy || !!game.truthtrance; return (

Return {pending.count} {label} {pending.count === 1 ? 'card' : 'cards'}

Choose exactly {pending.count} to shuffle into the Traitor Deck. Your other cards stay in your hand.

The previous game action is paused until this return finishes.

{dancers && (

Previously revealed Face Dancers are not available for this return.

)}
{pending.choices.map((choice) => { const identity = identityFor(game, choice.id); if (!identity) return (

This card’s identity is unavailable. Refresh before choosing it.

); const checked = selected.includes(choice.id); return (
{choice.blocked &&

{choice.blocked}

}
); })}

{selected.length} of {pending.count} selected.

{game.truthtrance && (

Finish Truthtrance before returning these cards.

)}
); }