From 5509abf1e52fc78c6916b941e9e3a3323ee4bea6 Mon Sep 17 00:00:00 2001 From: Quintine <15965533+Quintine@users.noreply.github.com> Date: Fri, 16 Oct 2026 10:11:15 +1100 Subject: [PATCH] Add current concealed No-Field Truthtrance facts --- components/mixed-shipment-fields.tsx | 13 +- components/truthtrance-no-field-value.tsx | 17 ++ docs/CURRENT_STATUS.md | 23 ++ docs/IMPLEMENTATION_STATUS.md | 39 ++++ docs/RICHESE_NO_FIELD_RULES.md | 51 ++++ docs/RULE_DECISIONS.md | 1 + docs/TRUTHTRANCE_FORCE_FACTS.md | 16 ++ game/reference.ts | 26 ++- game/truthtrance-no-field-value.ts | 45 ++++ game/truthtrance.ts | 11 +- tests/fixture-truthtrance-no-field.ts | 175 ++++++++++++++ tests/truthtrance-no-field-engine.test.ts | 269 ++++++++++++++++++++++ tests/truthtrance-no-field-value.test.ts | 123 ++++++++++ 13 files changed, 797 insertions(+), 12 deletions(-) create mode 100644 components/truthtrance-no-field-value.tsx create mode 100644 game/truthtrance-no-field-value.ts create mode 100644 tests/fixture-truthtrance-no-field.ts create mode 100644 tests/truthtrance-no-field-engine.test.ts create mode 100644 tests/truthtrance-no-field-value.test.ts diff --git a/components/mixed-shipment-fields.tsx b/components/mixed-shipment-fields.tsx index 5796c798..c5c39820 100644 --- a/components/mixed-shipment-fields.tsx +++ b/components/mixed-shipment-fields.tsx @@ -13,6 +13,8 @@ import { CardCountFields } from './truthtrance-card-count'; import { KnowledgeFactFields } from './truthtrance-knowledge'; import { ForceCountFields, forceCountInputError } from './truthtrance-force-count'; import { ShipmentClauseFields, invalidShipmentClause } from './shipment-claim-fields'; +import { NoFieldValueFields } from './truthtrance-no-field-value'; +import { parseNoFieldValueFact } from '@/game/truthtrance-no-field-value'; export function invalidTruthFact(fact: TruthFact, game: GameView, target: string): boolean { if (fact.kind === 'and' || fact.kind === 'or') { @@ -21,6 +23,10 @@ export function invalidTruthFact(fact: TruthFact, game: GameView, target: string if (fact.kind === 'spice' || fact.kind === 'handCount' || fact.kind === 'handInventory') { return !Number.isSafeInteger(fact.value) || fact.value < 0; } + if (fact.kind === 'noFieldValue') { + try { parseNoFieldValueFact(fact); return false; } + catch { return true; } + } if (isKnowledgeFact(fact)) return !!knowledgeFactInputError(fact); if (fact.kind === 'forceCount') { return !!forceCountInputError(fact, game, game.players.find(player => player.id === target)!); @@ -47,6 +53,7 @@ export function TruthFactFields({ value: fact, game, target, onChange }: { stormForecast: { kind: 'stormForecast', compare: 'gte', value: 1 }, spice: { kind: 'spice', compare: 'gte', value: 6 }, forceCount: { kind: 'forceCount', zone: { kind: 'reserves' }, counter: 'total', compare: 'gte', value: 6 }, + noFieldValue: { kind: 'noFieldValue', value: 3 }, }; return <> {fact.kind === 'hand' ? : fact.kind === 'handCount' || fact.kind === 'handInventory' ? - : fact.kind === 'forceCount' ? - player.id === target)!} onChange={onChange} /> : + : fact.kind === 'noFieldValue' ? + : fact.kind === 'forceCount' ? + player.id === target)!} onChange={onChange} /> : fact.kind === 'prediction' || fact.kind === 'stormDial' || fact.kind === 'stormForecast' ? : fact.kind === 'spice' ? <>