Support Semuta after Box searches during bidding
This commit is contained in:
1 parent
7dfdf8d593
commit
6bf165a6aa
8 files changed
+312
-2
No files matched your search
+25
-2
@@ -1647,6 +1647,8 @@ export type Game = {
|
||||
finalDiscardSignature: string;
|
||||
resume: NonNullable<Game['pendingNullentropy']>['resume'];
|
||||
parentSignature: string;
|
||||
/** New Basic bidding reactions bind the existing lot and funding. */
|
||||
auctionBinding?: { kind: 'ordinary' | 'richese'; signature: string };
|
||||
}
|
||||
| {
|
||||
kind: 'ordinaryCardDiscard';
|
||||
@@ -5115,6 +5117,7 @@ function finishNullentropy(
|
||||
`${owner.name} recovered one private card with Nullentropy Box, shuffled the remaining discard pile, and placed the used Box on top. The bank was paid when the search began.`,
|
||||
{ faction: owner.faction, name: 'Nullentropy Box' },
|
||||
);
|
||||
const auctionBinding = nullentropyAuctionBinding(g);
|
||||
stageTreacheryDiscard(
|
||||
g,
|
||||
'nullentropyBox',
|
||||
@@ -5129,6 +5132,7 @@ function finishNullentropy(
|
||||
finalDiscardSignature: JSON.stringify(g.discard),
|
||||
resume: pending.resume,
|
||||
parentSignature: nullentropyParentSignature(g, pending.resume, event),
|
||||
...(auctionBinding ? {auctionBinding} : {}),
|
||||
},
|
||||
);
|
||||
}
|
||||
@@ -6157,6 +6161,18 @@ function nullentropyParentSignature(
|
||||
);
|
||||
return JSON.stringify({ searchEvent, resume, parents });
|
||||
}
|
||||
/** Clock state is deliberately excluded: it pauses and resumes while decisions
|
||||
* are pending. The lot and committed resources themselves remain unchanged. */
|
||||
function nullentropyAuctionBinding(g: Game): {kind:'ordinary'|'richese';signature:string} | undefined {
|
||||
if (!g.semutaPreview || !bareBasicSemutaProfile(g) || g.phase !== 3 || g.currentAuctionSale || g.ixAuction)
|
||||
return undefined;
|
||||
const kind = g.auction && !g.richeseAuction ? 'ordinary' : supportedRicheseTruthLot(g) ? 'richese' : undefined;
|
||||
if (!kind) return undefined;
|
||||
return {kind, signature: JSON.stringify({turn:g.turn,phase:g.phase,active:g.active,order:g.order,
|
||||
auction:g.auction,richeseAuction:g.richeseAuction,richeseBidding:g.richeseBidding,
|
||||
richeseFunding:g.richeseFunding,aid:g.aid,
|
||||
players:g.players.map(p => ({id:p.id,spice:p.spice,ally:p.ally}))})};
|
||||
}
|
||||
type OrdinaryDiscardContinuation = Extract<
|
||||
NonNullable<Game['pendingTreacheryDiscard']>['continuation'],
|
||||
{ kind: 'ordinaryCardDiscard' }
|
||||
@@ -7929,6 +7945,10 @@ function treacheryDiscardIntegrity(g: Game) {
|
||||
nullentropyParentSignature(g, c.resume, c.searchEvent),
|
||||
'The completed Box search does not match its suspended controls and obligations.',
|
||||
);
|
||||
if (c.auctionBinding) requireRule(
|
||||
JSON.stringify(c.auctionBinding) === JSON.stringify(nullentropyAuctionBinding(g)),
|
||||
'The completed Box search no longer matches its original auction and funding.',
|
||||
);
|
||||
suspendedControlsIntegrity(g, c.resume);
|
||||
} else if (continuation?.kind === 'ordinaryCardDiscard') {
|
||||
const c = continuation,
|
||||
@@ -9222,10 +9242,13 @@ function semutaOfferSupported(
|
||||
// native Distrans still cannot produce a transfer after that bid starts.
|
||||
const ordinaryAuctionDiscard = g.phase === 3 && !!g.auction && !g.richeseAuction && !g.currentAuctionSale &&
|
||||
(continuation.kind === 'truthtranceDiscard' || continuation.kind === 'distransDiscard' ||
|
||||
continuation.kind === 'saphoTruthOrderDiscard');
|
||||
continuation.kind === 'saphoTruthOrderDiscard' ||
|
||||
continuation.kind === 'nullentropyDiscard' && continuation.auctionBinding?.kind === 'ordinary');
|
||||
const richeseTruthDiscard = supportedRicheseTruthLot(g) &&
|
||||
(continuation.kind === 'truthtranceDiscard' || continuation.kind === 'saphoTruthOrderDiscard') &&
|
||||
!!continuation.richeseLotEvent && continuation.richeseLotEvent === g.richeseAuction?.event;
|
||||
const richeseBoxDiscard = supportedRicheseTruthLot(g) && continuation.kind === 'nullentropyDiscard' &&
|
||||
continuation.auctionBinding?.kind === 'richese';
|
||||
if (continuation.kind === 'truthtranceDiscard' &&
|
||||
['bribe', 'bribeExpression', 'mixedBribe'].includes(continuation.record.question.kind) &&
|
||||
(!continuation.bribeBinding || !bareBasicSemutaProfile(g) || !!g.kullPreview)) return false;
|
||||
@@ -9562,7 +9585,7 @@ function semutaOfferSupported(
|
||||
(advisorDiscard || auctionCostDiscard || bonusDiscard || auctionAdvantageDiscard || richeseGiftDiscard || bgDiscard || continuation.kind === 'specialKaramaDiscard' || continuation.kind === 'saphoAuctionDiscard' ||
|
||||
continuation.kind === 'ixAllyCard' ||
|
||||
(continuation.kind === 'karamaIncomeDiscard' &&
|
||||
continuation.use.response.kind === 'emperorIncome') || richeseTruthDiscard || !g.richeseAuction) &&
|
||||
continuation.use.response.kind === 'emperorIncome') || richeseTruthDiscard || richeseBoxDiscard || !g.richeseAuction) &&
|
||||
(richeseGiftDiscard || combatDiscard || alliedTraitorDiscard || occupyDiscard || continuation.kind === 'saphoAggressorDiscard' ||
|
||||
bgDiscard ||
|
||||
continuation.kind === 'specialKaramaDiscard' ||
|
||||
|
||||
Reference in new issue
Block a user