Bind current Traitor declarations with Truthtrance
This commit is contained in:
1 parent
724eabf99c
commit
86608f7ea9
20 files changed
+1362
-35
No files matched your search
+21
-1
@@ -55,6 +55,7 @@ export type TruthFact =
|
||||
| { kind: 'spice'; compare: 'eq' | 'gte' | 'lte'; value: number }
|
||||
| { kind: 'and' | 'or'; terms: TruthFact[] };
|
||||
export type TruthQuestion =
|
||||
| { kind: 'traitorCall'; target: string; battle: string; territory: string }
|
||||
| ({ kind: 'movement'; target: string } & MovementClaim)
|
||||
| ({ kind: 'shipment'; target: string } & ShipmentClaim)
|
||||
| { kind: 'mixedShipment'; target: string; mixed: MixedShipmentExpression }
|
||||
@@ -205,6 +206,14 @@ function parseQuestion(g: Game, asker: string, value: unknown): TruthQuestion {
|
||||
g.players.some((p) => p.id === v.target),
|
||||
'Ask one other player.',
|
||||
);
|
||||
if (v.kind === 'traitorCall') {
|
||||
check(Object.keys(v).sort().join(',') === 'battle,kind,target,territory' &&
|
||||
g.status === 'playing' && g.phase === 6 && g.battle?.revealed &&
|
||||
typeof v.battle === 'string' && v.battle === g.battle.event &&
|
||||
v.territory === g.battle.territory && g.battle.traitorCalls[v.target as string] === undefined,
|
||||
'Choose the current revealed battle and a still-unsubmitted Traitor decision.');
|
||||
return { kind: 'traitorCall', target: v.target as string, battle: v.battle, territory: v.territory as string };
|
||||
}
|
||||
if (v.kind === 'movement') {
|
||||
check(Object.keys(v).sort().join(',') === 'kind,minimum,target,territory',
|
||||
'Supply one ground-movement destination, minimum and respondent.');
|
||||
@@ -317,7 +326,7 @@ export function validateSavedTruthtrance(g: Game) {
|
||||
'The saved Truthtrance must retain each committed physical card in its holder’s hand.',
|
||||
);
|
||||
}
|
||||
if (window?.question?.kind === 'fact' || window?.question?.kind === 'movement') {
|
||||
if (window?.question?.kind === 'fact' || window?.question?.kind === 'movement' || window?.question?.kind === 'traitorCall') {
|
||||
check((window.stage === 'answer' || window.stage === 'unknown') && window.queue.length > 0,
|
||||
'The saved fact question must retain its asking player and answer stage.');
|
||||
check(JSON.stringify(parseQuestion(g, window.queue[0].player, window.question)) === JSON.stringify(window.question),
|
||||
@@ -421,6 +430,7 @@ export function truthQuestionText(
|
||||
locationName: (id: string) => string,
|
||||
): string {
|
||||
if (q.kind === 'freeform') return q.text;
|
||||
if (q.kind === 'traitorCall') return `In this revealed battle in ${locationName(q.territory)}, will you declare the opposing leader a Traitor?`;
|
||||
if (q.kind === 'movement') return `Will you ${movementClaimText(q)} before your Shipment and Movement turn ends?`;
|
||||
if (q.kind === 'shipment')
|
||||
return `Will you ${shipmentClaimText(q)} this turn?`;
|
||||
@@ -465,6 +475,8 @@ export function resolveTruthAction(
|
||||
) => void;
|
||||
movementAnswers?: (g: Game, p: Player, claim: MovementClaim) => TruthAnswer[];
|
||||
bindMovement?: (g: Game, p: Player, claim: MovementClaim, answer: boolean, asker: string) => void;
|
||||
traitorAnswers?: (g: Game, p: Player) => TruthAnswer[];
|
||||
bindTraitor?: (g: Game, p: Player, answer: boolean, asker: string) => void;
|
||||
battleAnswers: (g: Game, p: Player, claim: PlanClaim) => TruthAnswer[];
|
||||
bindBattle: (
|
||||
g: Game,
|
||||
@@ -581,6 +593,9 @@ export function resolveTruthAction(
|
||||
'Waiting for the Truthtrance holder to ask a question.',
|
||||
);
|
||||
w.question = parseQuestion(g, p.id, a.question);
|
||||
if (w.question.kind === 'traitorCall')
|
||||
check(effects.traitorAnswers?.(g, g.players.find(other => other.id === w.question!.target)!).length,
|
||||
'Choose an actual unsubmitted native Traitor voter.');
|
||||
w.stage = 'answer';
|
||||
const target = g.players.find(
|
||||
(other) => other.id === w.question!.target,
|
||||
@@ -628,6 +643,11 @@ export function resolveTruthAction(
|
||||
'Choose an answer consistent with legal ground movement and earlier promises.');
|
||||
if (a.answer !== 'unknown') effects.bindMovement(g, p, q, a.answer === 'yes', current.player);
|
||||
}
|
||||
if (q.kind === 'traitorCall') {
|
||||
check(effects.traitorAnswers && effects.bindTraitor && effects.traitorAnswers(g, p).includes(a.answer),
|
||||
'Choose an answer compatible with your current legal Traitor declaration and earlier answers.');
|
||||
if (a.answer !== 'unknown') effects.bindTraitor(g, p, a.answer === 'yes', current.player);
|
||||
}
|
||||
if (q.kind === 'battlePlan') {
|
||||
check(
|
||||
effects.battleAnswers(g, p, q.claim).includes(a.answer),
|
||||
|
||||
Reference in new issue
Block a user