Support early Advanced Charity commitments
Verify and publish checkpoint container / container (push) Successful in 11m25s

This commit is contained in:
Quintine committed 2026-10-29 09:00:38 +11:00
1 parent 68c7434a20
commit ad0abfef98
8 files changed
+294 -14

No files matched your search

+3 -3
View File
@@ -17735,8 +17735,8 @@ function charityPromiseRule<T>(run: () => T): T {
}
}
function charityQuestionWindow(g: Game): boolean {
const timing = !g.advanced && g.phase >= 0 && g.phase <= 2 && !g.charityOrder ||
g.advanced && g.phase === 2 && !!g.charityOrder;
const timing = g.phase >= 0 && g.phase < 2 && !g.charityOrder ||
g.phase === 2 && (g.advanced ? !!g.charityOrder : !g.charityOrder);
return g.status === 'playing' && timing &&
!g.response && !g.decision && !g.phaseOpening && !g.pendingKarama && !g.pendingTreacheryDiscard &&
(g.phase < 2 || !byFaction(g, 'choam') || g.choamCharity?.turn === g.turn);
@@ -17812,7 +17812,7 @@ function reconcileCharityTruth(g: Game,voluntary?: {actor:string;action:Action})
const rows: CharityPromise[] = promises.filter(row => row.player === player && !row.fulfilled && !row.released);
for (const turn of new Set(rows.map(row => row.turn))) {
const open = g.status === 'playing' && g.turn === turn &&
(!g.advanced && g.phase >= 0 && g.phase <= 2 ||
(g.phase >= 0 && g.phase < 2 || !g.advanced && g.phase === 2 ||
g.advanced && g.phase === 2 && !!g.charityOrder?.remaining.includes(player));
const before: CharityPromise[] = promises;
promises = charityPromiseRule(() => reconcileCharityPromises(before,player,turn,
+4 -4
View File
@@ -3974,20 +3974,20 @@ export const RULE_TOPICS: RuleTopic[] = [
category: 'Cards',
coverage: 'Partial',
developmentStage: 'Prototyped',
summary: 'Ask whether another player will claim Charity during a supported Basic or live Advanced Charity opportunity.',
summary: 'Ask whether another player will claim Charity during a supported Basic or Advanced Charity opportunity.',
steps: [
'Yes requires an actual native Charity claim while possible; No forbids it through the original Basic Charity phase or the player’s Advanced ordered turn. An answer in concurrent Basic Charity reopens that player’s Ready; earlier Storm or Spice readiness and the Advanced order stay intact, and an earlier claim does not count.',
'During Charity a private guide can suggest the exact claim or an ordinary bribe that makes the claim eligible. Before Charity, the forecast offers no executable future action. The bribe is paid now and received at Mentat; the claim uses the normal eligibility, payer and inflation rules.',
'A Yes remains binding while a supported claim or payment route exists. A voluntary action cannot abandon it; an external change that removes the supported route releases it. Independent future commitments may require an unknown answer until their joint planning is supported.',
'During live Advanced Charity, an unclaimed player whose turn remains can answer without changing the order. Their private guide appears only on their own turn; No ends when that turn closes. Quiet timing and the forecast remain provisional. Upcoming Advanced Charity, other preparations, pending windows and broader combinations remain unfinished.',
'In quiet Advanced Storm or Spice Blow, an answer can bind the upcoming Charity turn without changing the current readiness. During live Advanced Charity, an unclaimed player whose turn remains can answer without changing the order. Their private guide appears only on their own turn; No ends when that turn closes. Timing and the forecast remain provisional; other preparations, pending windows and broader combinations remain unfinished.',
],
related: ['card-truthtrance', 'charity', 'truthtrance-bribe'],
checklist: [
{ area: 'Implementation', status: 'Partial', detail: 'Native Basic upcoming/current and live Advanced ordered claims, one-payment route, turn-bound Yes/No and event-bound guide are connected; wider forecasts and combined obligations remain open.', evidence: ['game/charity-promises.ts', 'game/truthtrance.ts', 'game/engine.ts'] },
{ area: 'Implementation', status: 'Partial', detail: 'Native Basic and Advanced upcoming/current claims, one-payment route, turn-bound Yes/No and event-bound guide are connected; wider forecasts and combined obligations remain open.', evidence: ['game/charity-promises.ts', 'game/truthtrance.ts', 'game/engine.ts'] },
{ area: 'Player controls', status: 'Partial', detail: 'Question, recipient answers, persistent private guidance and claim/Ready reasons are connected; browser acceptance remains open.', evidence: ['components/truthtrance.tsx', 'components/truth-charity-promise.tsx', 'components/charity-claim.tsx', 'components/game-table.tsx'] },
{ area: 'AI', status: 'Partial', detail: 'Profiles use the private answer and native guided action; strategy and calibration are deferred.', evidence: ['game/bots.ts', 'tests/truth-charity-commitment-runtime.test.ts'] },
{ area: 'Documentation', status: 'Implemented', detail: 'The FAQ source, provisional timing and bounded preparation route are recorded.', evidence: ['docs/TRUTHTRANCE_CHARITY.md', 'docs/RULE_DECISIONS.md'] },
{ area: 'Verification', status: 'Partial', detail: 'Focused native and rendered controls cover the Basic and ordered Advanced prototypes; wider combinations and deployed acceptance remain open.', evidence: ['tests/charity-promises.test.ts', 'tests/truth-charity-commitment-runtime.test.ts', 'tests/truth-charity-commitment-controls.test.tsx', 'tests/truth-charity-early-runtime.test.ts', 'tests/truth-charity-early-controls.test.tsx', 'tests/truth-charity-ordered-runtime.test.ts', 'tests/truth-charity-ordered-controls.test.tsx', 'tests/truth-charity-ordered-bg.test.ts'] },
{ area: 'Verification', status: 'Partial', detail: 'Focused native and rendered controls cover Basic and Advanced upcoming and ordered prototypes; wider combinations and deployed acceptance remain open.', evidence: ['tests/charity-promises.test.ts', 'tests/truth-charity-commitment-runtime.test.ts', 'tests/truth-charity-commitment-controls.test.tsx', 'tests/truth-charity-early-runtime.test.ts', 'tests/truth-charity-early-controls.test.tsx', 'tests/truth-charity-ordered-runtime.test.ts', 'tests/truth-charity-ordered-controls.test.tsx', 'tests/truth-charity-ordered-bg.test.ts', 'tests/truth-charity-advanced-early.test.ts', 'tests/truth-charity-advanced-early-controls.test.tsx'] },
],
},
{
+2 -1
View File
@@ -294,7 +294,8 @@ function parseQuestion(g: Game, asker: string, value: unknown): TruthQuestion {
throw new TruthError('Finish this player’s conditional battle answer before binding another action question.');
if (v.kind === 'charity') {
check(Object.keys(v).sort().join(',') === 'kind,target,turn' && v.turn === g.turn &&
g.status === 'playing' && (!g.advanced && g.phase >= 0 && g.phase <= 2 && !g.charityOrder ||
g.status === 'playing' && (g.phase >= 0 && g.phase < 2 && !g.charityOrder ||
!g.advanced && g.phase === 2 && !g.charityOrder ||
g.advanced && g.phase === 2 && !!g.charityOrder?.remaining.includes(v.target as string)) &&
g.players.find(player => player.id === v.target)?.charityTurn !== g.turn &&
!g.response && !g.decision && !g.phaseOpening && !g.pendingKarama && !g.pendingTreacheryDiscard,