Support immediate payments in group travel deals
Verify and publish checkpoint container / container (push) Successful in 10m49s

This commit is contained in:
Quintine committed 2026-10-29 17:41:58 +11:00
1 parent 3987c5c16b
commit 6c1530382d
10 files changed
+207 -24

No files matched your search

+1 -1
View File
@@ -42974,7 +42974,7 @@ function applyActionWithInitiator(state: Game, id: string, action: Action, initi
const single = (keys === 'target,terms,type' || keys === 'payment,target,terms,type' ||
keys === 'target,terms,travel,type' || keys === 'payment,target,terms,travel,type') && typeof action.target === 'string';
const multiple = (keys === 'targets,terms,type' || keys === 'payment,targets,terms,type' ||
keys === 'targets,terms,travel,type') && Array.isArray(action.targets) &&
keys === 'targets,terms,travel,type' || keys === 'payment,targets,terms,travel,type') && Array.isArray(action.targets) &&
action.targets.every(target => typeof target === 'string');
const hasPayment = Object.hasOwn(action, 'payment');
requireRule((single || multiple) && typeof action.terms === 'string' &&
+4 -3
View File
@@ -190,9 +190,9 @@ export function validatePublicDeals(value: unknown, players: readonly PublicDeal
requireDeal(travel.dueTurn === undefined || travel.dueTurn >= (deal.turn as number),
'Choose a travel turn no earlier than the offer turn.');
requireDeal(!Object.hasOwn(deal, 'paymentStatus') && (multi
? !!travel.actor && travel.actor !== deal.from && parties.includes(travel.actor) && !payment
? !!travel.actor && travel.actor !== deal.from && parties.includes(travel.actor) && (!payment || payment.kind === 'immediateBribe')
: !Object.hasOwn(travel, 'actor') && (!payment || payment.kind === 'immediateBribe')),
'Choose an invited traveler; payment is available only as a two-party immediate bribe.');
'Choose an invited traveler and an optional immediate bribe between participants.');
// The actor's final acceptance is checked privately. An unfinished offer
// cannot already contain that vote, even after a decline or withdrawal.
if (multi && deal.status !== 'active' && deal.status !== 'released')
@@ -253,7 +253,8 @@ export function setPublicDealTravel(deal: PublicDeal, value: unknown, players: r
validatePublicDeals([deal], players);
requireDeal(deal.status === 'offered' && !Object.hasOwn(deal, 'travel') &&
!Object.hasOwn(deal, 'paymentStatus') && (deal.participants
? !!deal.acceptVotes && deal.acceptVotes.length === 1 && deal.acceptVotes[0] === deal.from && !deal.payment
? !!deal.acceptVotes && deal.acceptVotes.length === 1 && deal.acceptVotes[0] === deal.from &&
(!deal.payment || deal.payment.kind === 'immediateBribe')
: !Object.hasOwn(deal, 'acceptVotes') && (!deal.payment ||
deal.payment.kind === 'immediateBribe')),
'Only a fresh offer may add a travel term with a supported payment.');
+1 -1
View File
@@ -304,7 +304,7 @@ export const RULE_TOPICS: RuleTopic[] = [
'A deal may include one immediate spice payment between two participants. The last acceptance invokes the normal bribe action: the payer loses the gross amount immediately, Bureaucrat may divert two, and the recipient collects the remaining share at the next Mentat opening. Nothing is reserved before acceptance, and an unavailable payment leaves the offer open.',
'A deal may instead specify one exact payment due this turn or a later turn. After everyone accepts, the payer can use that deal’s Pay button early or by the deadline. Future payments do not reserve current funds; obligations due now must still be respected. Separate deals require separate payments. A compatible Truthtrance bribe answer can be satisfied by the same payment. Mutual release cancels an unpaid term; a paid amount is not refunded.',
'In a supported Basic classic table, two to six people can agree that one invited recipient will make or avoid one reserve shipment or ground move of at least a selected number of physical forces to a named territory in the current or a later turn. In a group offer the other recipients accept first and the named traveler accepts last. A current-turn term is checked on acceptance; a later-turn term is scheduled without reserving present forces or spice. The actual action fulfills a required term; a forbidden action cannot be taken. Compatible travel terms can share one action. A bounded due-turn search protects witnessed completions; when the travel turn closes without a witness, the game provisionally voids that term. Unsupported combinations remain in development.',
'Two-party travel can include an immediate payment in either direction. Final consent and payment are atomic, and current-turn travel must remain feasible after the payer spends. Deferred and multi-party paid travel remain unfinished.',
'Two-party or group travel can include one immediate payment between two participants. All parties accept, including the payer, and the traveler accepts last; only then does the payment settle. Final consent and payment are atomic, and current-turn travel must remain feasible after the payer spends. Deferred and multiple-payment travel remain unfinished.',
'Players must honor legal deal terms; an impossible part is void. The game does not interpret or enforce free-text promises or determine impossibility. Free text alone pays no spice. Deals must not transfer cards, leaders, forces or faction advantages or contradict the rules.',
'Minimal AI follows supported Truthtrance ordinary-payment answers and their legal guides. AI deal negotiation and automatic enforcement of prose remain unfinished.',
],