diff --git a/README.md b/README.md index da7bb8b9..4a251f46 100644 --- a/README.md +++ b/README.md @@ -79,7 +79,9 @@ persists through refresh. See [Ecaz Loyalty](docs/ECAZ_LOYALTY.md). The local Leader Skills prototype also supports Basic Moritani with base opponents and the full fourteen-card deck. See [entry, connected interactions -and remaining boundaries](docs/MORITANI_LEADER_SKILLS.md). +and remaining boundaries](docs/MORITANI_LEADER_SKILLS.md). Basic Tleilaxu also +supports the full deck, native Rihani exchanges and saved revival choices; see +[its integration boundary](docs/TLEILAXU_LEADER_SKILLS.md). Above the board, **Treachery draw pile** and **Spice draw pile** show live card counts separately from hands, auction cards and discards. See diff --git a/components/rihani-decipherer.tsx b/components/rihani-decipherer.tsx index 322b066b..d1eaa798 100644 --- a/components/rihani-decipherer.tsx +++ b/components/rihani-decipherer.tsx @@ -13,13 +13,14 @@ function identity(game: GameView, id: string): LeaderDisplayIdentity | null { const leader = game.allLeaders.find((l) => l.id === id); return leader ? { id: leader.id, name: leader.name, factionName: faction(leader.faction).name, strength: leaderStrengthLabel(leader) } : null; } -function Card({ game, id }: { game: GameView; id: string }) { +function Card({ game, id, faceDancer = false }: { game: GameView; id: string; faceDancer?: boolean }) { const card = identity(game, id); - return card ?
{card.name}
:

Card identity unavailable.

; + return card ?
{card.name}
:

Card identity unavailable.

; } export function RihaniHistory({ game }: { game: GameView }) { const history = game.rihani?.history; + const faceDancer = game.players.find(p => p.id === game.me)?.faction === 'tleilaxu'; if (!history?.length) return null; return
Your private Rihani inspections @@ -27,7 +28,7 @@ export function RihaniHistory({ game }: { game: GameView }) { {[...history].reverse().map((r) =>

Turn {r.turn}

{r.peeked.length > 0 && <>

Normal inspection — returned to the shuffled deck

{r.peeked.map((id) => )}} - {r.drawn.length > 0 && <>

Separate skilled draw

{r.drawn.map((id) => )}} + {r.drawn.length > 0 && <>

Separate skilled draw

{r.drawn.map((id) => )}} {r.kept &&

Kept {identity(game, r.kept)?.name}; revealed and returned {identity(game, r.given!)?.name}.

}
)}
; @@ -38,24 +39,27 @@ export function RihaniChoice({ game, act, busy }: { game: GameView; act: (action const pending = game.rihani?.pending; if (!pending || pending.owner !== game.me) return null; const blocked = busy || !!game.truthtrance; + const faceDancer = game.players.find(p => p.id === game.me)?.faction === 'tleilaxu'; + const cardName = faceDancer ? 'Face Dancer' : 'Traitor'; + const oldCard = faceDancer ? 'unrevealed' : 'unused'; if (pending.stage === 'offer') return
-

You may draw two Traitor Cards. Once drawn, you must keep one new card by publicly revealing and returning one unused card you already hold.

+

You may draw two {cardName} Cards. Once drawn, you must keep one new card by publicly revealing and returning one {oldCard} card you already hold.

The other drawn card returns secretly. Your normal inspection, when available, has already returned its cards to the shuffled deck.

- +
; - return
-

Keep one newly drawn card and reveal one unused card from your old hand. The revealed card and the other new card return to the shuffled deck.

-
Keep one new Traitor — private + return
+

Keep one newly drawn card and reveal one {oldCard} card from your old hand. The revealed card and the other new card return to the shuffled deck.

+
Keep one new {cardName} — private {pending.drawn?.map((id) =>
- +
)}
-
Reveal and return one unused old Traitor — public +
Reveal and return one {oldCard} old {cardName} — public {pending.eligible?.map((id) =>
- +
)}