Offer Semuta after clean completed Ornithopter flight

This commit is contained in:
Quintine committed 2026-09-30 08:33:23 +10:00
1 parent eb4df0b99c
commit b3e4f1babb
9 files changed
+178 -51

No files matched your search

+11 -5
View File
@@ -5741,9 +5741,9 @@ function treacheryDiscardIntegrity(g: Game) {
'The committed Kaitain discard no longer matches its payment and closing opportunity.');
} else throw new RuleError('Unknown saved discard continuation.');
}
/** Bounded public single-card reaction after a completed ordinary effect, paid
* Box search, early-ended Ornithopter, clean Distrans transfer, final definite
* Truthtrance answer or clean Sapho movement reorder. */
/** Bounded public single-card reaction after clean completed effects. A final
* Ornithopter arrival qualifies only without factions that can open a new
* intrusion or territory-entry response from the committed movement. */
function semutaOfferSupported(
g: Game,
continuation: NonNullable<Game['pendingTreacheryDiscard']>['continuation'],
@@ -5753,13 +5753,19 @@ function semutaOfferSupported(
continuation.kind !== 'nullentropyDiscard' &&
continuation.kind !== 'distransDiscard' &&
continuation.kind !== 'saphoMovementDiscard' &&
!(continuation.kind === 'ornithopterDiscard' && continuation.source === 'end') &&
!(continuation.kind === 'ornithopterDiscard' &&
(continuation.source === 'end' ||
(continuation.source === 'move' &&
!g.players.some(p => p.faction === 'beneGesserit' ||
p.faction === 'ecaz' || p.faction === 'moritani') &&
!g.pendingArrivalOverlap))) &&
!(continuation.kind === 'truthtranceDiscard' &&
continuation.consumed.source === undefined &&
continuation.remaining === null && continuation.promise === null)) return false;
if ((continuation.kind === 'distransDiscard' ||
continuation.kind === 'truthtranceDiscard' ||
continuation.kind === 'saphoMovementDiscard') &&
continuation.kind === 'saphoMovementDiscard' ||
(continuation.kind === 'ornithopterDiscard' && continuation.source === 'move')) &&
(g.pendingChoamMove || g.pendingIxMove || g.pendingFremenMove ||
g.ornithopter || g.summonedWorm || g.wormRides.length > 0)) return false;
return g.semutaPreview === true && g.status === 'playing' &&
+4 -4
View File
@@ -1156,7 +1156,7 @@ export const RULE_TOPICS: RuleTopic[] = [
: definition.card.effect === 'portableSnooper'
? 'Choose Portable Snooper as your ordinary poison defense, or use the late-defense panel after reveal before your own traitor decision. It uses ordinary winner retention and cannot stop Poison Tooth.'
: definition.card.effect === 'semutaDrug'
? 'In an explicitly opted-in Richese development game, every seat sees a neutral response after a clean public ordinary-card discard, paid Box search, early-ended Ornithopter flight, private Distrans transfer, final definite Truthtrance answer or completed movement-order Sapho discard. Continue or commit held Semuta with a free hand slot; only the freshly discarded public card transfers. Private gifts and bound answers stay intact; a Sapho claim resumes its saved movement queue once. Competing transactions, auction and battle Sapho, full-hand sequencing and normal Richese starts remain unfinished.'
? 'In an explicitly opted-in Richese development game, every seat sees a neutral response after a clean public ordinary-card discard, paid Box search, retired Ornithopter, private Distrans transfer, final definite Truthtrance answer or movement-order Sapho discard. Continue or commit held Semuta with a free hand slot; only the freshly discarded public card transfers. An early-ended flight advances the queue, while a completed flight resumes its already committed arrival once when no BG, Ecaz or Moritani entry reaction can open. Private gifts and bound answers stay intact. Competing transactions, other arrival compositions, full-hand sequencing and normal Richese starts remain unfinished.'
: 'Reference component only: this Richese card’s game actions are not enabled.',
],
...(definition.card.effect === 'semutaDrug'
@@ -1166,7 +1166,7 @@ export const RULE_TOPICS: RuleTopic[] = [
area: 'Implementation' as const,
status: 'Partial' as const,
detail:
'An explicitly opted-in Richese profile interrupts clean public ordinary-card, paid Box, early-ended Ornithopter, private Distrans, final definite Truthtrance and movement-order Sapho discards with a neutral all-seat offer. Committing held Semuta claims only the other-player discarded card and discards Semuta. Private gifts and answered history remain intact; completed effects, Sapho ordering and movement resume once. Auction/battle Sapho, competing transactions, other typed producers and full-hand exchange remain unfinished.',
'An explicitly opted-in Richese profile interrupts clean public ordinary-card, paid Box, retired Ornithopter, private Distrans, final definite Truthtrance and movement-order Sapho discards with a neutral all-seat offer. Committing held Semuta claims only the other-player discarded card and discards Semuta. Early-ended flights advance the queue; completed flights with no BG/Ecaz/Moritani entry reaction resume their committed arrival. Private gifts and answered history remain intact. Other arrivals, auction/battle Sapho, competing transactions, other typed producers and full-hand exchange remain unfinished.',
},
{
area: 'Player controls' as const,
@@ -1184,13 +1184,13 @@ export const RULE_TOPICS: RuleTopic[] = [
area: 'Documentation' as const,
status: 'Partial' as const,
detail:
'The guide distinguishes bounded public ordinary-card, paid Box, early-ended Ornithopter, clean Distrans, final definite Truthtrance and movement-order Sapho previews, privacy-neutral acknowledgements and conservative free-slot policy from unresolved full-hand sequencing and remaining discard sources.',
'The guide distinguishes bounded public ordinary-card, paid Box, both clean Ornithopter retirement paths, Distrans, final definite Truthtrance and movement-order Sapho previews, privacy-neutral acknowledgements and conservative free-slot policy from unresolved full-hand sequencing and remaining discard sources.',
},
{
area: 'Verification' as const,
status: 'Partial' as const,
detail:
'Genuine setup, physical card custody, neutral hidden-hand parity, saved JSON, authenticated SQLite CAS and legal AI participation cover clean ordinary-card, paid Box, early-ended Ornithopter, private Distrans, final definite Truthtrance and movement-order Sapho reactions. Other discard producers, full games and live deployment remain unverified.',
'Genuine setup, physical card custody, neutral hidden-hand parity, saved JSON, authenticated SQLite CAS and legal AI participation cover clean ordinary-card, paid Box, retired Ornithopter, private Distrans, final definite Truthtrance and movement-order Sapho reactions. BG/Ecaz/Moritani arrival composition, other producers, full games and live deployment remain unverified.',
evidence: [
'tests/semuta-engine.test.ts',
'tests/semuta-recovery.test.ts',