Combine current facts with native Traitor decisions

This commit is contained in:
Quintine committed 2026-10-26 18:52:06 +11:00
1 parent 812f77e348
commit 13398aa76e
22 files changed
+1512 -17

No files matched your search

+22 -6
View File
@@ -2,13 +2,29 @@
import type { Action, GameView } from '@/game/engine';
import { Button } from './ui/button';
export function TraitorDecisionAnswers({ game, act, busy }: { game: GameView; act: (action: Action) => void; busy: boolean }) {
if (game.truthtrance?.stage !== 'answer' || game.truthtrance.question?.kind !== 'traitorCall' ||
game.truthtrance.question.target !== game.me) return null;
export function TraitorDecisionAnswers(props: { game: GameView; act: (action: Action) => void; busy: boolean }) {
const { game, act } = props, window = game.truthtrance, question = window?.question, battle = game.battle;
if (window?.stage !== 'answer' || (question?.kind !== 'traitorCall' && question?.kind !== 'mixedTraitorCall') ||
question.target !== game.me || !battle?.revealed || question.battle !== battle.event || question.territory !== battle.territory) return null;
const mixed = question.kind === 'mixedTraitorCall';
const answers = mixed ? game.truthMixedTraitorAnswers : game.truthTraitorAnswers;
const actor = game.me, turn = game.turn, event = battle.event, territory = battle.territory;
const source = window.queue[0], sourceSignature = JSON.stringify(source), signature = JSON.stringify(question);
const canAnswer = (answer: 'yes' | 'no' | 'unknown') => !props.busy && props.game === game && props.act === act &&
game.me === actor && game.turn === turn && game.truthtrance === window && window.stage === 'answer' &&
window.queue[0] === source && JSON.stringify(source) === sourceSignature &&
window.question === question && question.target === actor && JSON.stringify(question) === signature &&
game.battle === battle && battle.revealed && battle.event === event && battle.territory === territory &&
question.battle === event && question.territory === territory && battle.traitorVoters.includes(actor) &&
!battle.traitorSubmitted.includes(actor) &&
(mixed ? game.truthMixedTraitorAnswers : game.truthTraitorAnswers) === answers && !!answers?.includes(answer);
return <section aria-label="Your Truthtrance Traitor answer">
<p className="notice">Yes binds Reveal for this original Traitor decision; No binds decline. This concerns your declaration, so a later Karama or betrayal response can still prevent its effect.</p>
{(game.truthTraitorAnswers ?? []).map(answer => <Button key={answer} className="game-action min-h-11" disabled={busy}
onClick={() => { if (!busy) act({ type: 'truthAnswer', answer }); }}>Answer {answer === 'yes' ? 'Yes' : 'No'}</Button>)}
{mixed ? <p className="notice">Answer the whole mixed claim. Current facts are snapshotted at the answer; No makes the whole expression false, not each condition separately.
A constant whole answer needs no declaration commitment. A remaining commitment concerns your original Reveal or decline declaration,
so a later Karama or betrayal response can still prevent its effect.</p>
: <p className="notice">Yes binds Reveal for this original Traitor decision; No binds decline. This concerns your declaration, so a later Karama or betrayal response can still prevent its effect.</p>}
{(answers ?? []).map(answer => <Button key={answer} className="game-action min-h-11" disabled={!canAnswer(answer)}
onClick={() => { if (canAnswer(answer)) act({ type: 'truthAnswer', answer }); }}>Answer {answer === 'yes' ? 'Yes' : answer === 'no' ? 'No' : 'I don’t know'}</Button>)}
</section>;
}