Support printed Kull during market Ghola
Verify and publish checkpoint container / container (push) Successful in 11m25s

This commit is contained in:
Quintine committed 2026-10-29 08:37:50 +11:00
1 parent 79fc12c1c1
commit bcca08cac5
10 files changed
+232 -25

No files matched your search

+28 -6
View File
@@ -551,7 +551,7 @@ import {
import { transferDistrans } from './distrans';
import { distransAuctionBlock } from './distrans-timing';
import { SEMUTA_DRUG_ID, committedSemutaCandidates, resolveSemutaDrug, type FreshDiscardBatch, type SemutaContext } from './semuta-drug';
import { semutaMarketGholaSupported } from './semuta-market-ghola';
import { semutaMarketGholaProfile, semutaMarketGholaSupported } from './semuta-market-ghola';
import {
prepareRicheseGift,
transferRicheseGift,
@@ -6618,6 +6618,16 @@ function semutaKaramaRoleCost(g: Game, owner: string, card: Card): boolean {
return card.effect === 'karama' || (card.effect === 'truthtrance' &&
canUseAsKaramaRole(g, getPlayer(g, owner), card));
}
/** Match only the native income belonging to this already committed Ghola. */
function semutaMarketGholaIncome(g: Game, response: ResponseWindow): boolean {
const pending = g.pendingChoamMarketGhola;
if (!semutaMarketGholaProfile(g) || !bareBasicSemutaProfile(g) ||
!pending || pending.stage !== 'income' || response.kind !== 'revivalIncome' ||
response.source !== undefined || response.intent !== pending.event ||
response.recipient !== pending.player || response.amount !== 1 ||
!g.players.some(p => p.id === response.owner && p.faction === 'tleilaxu')) return false;
return choamMarketGholaError({...g, response}) === null;
}
/** Original paid income sources; cancellation never reverses the completed transaction. */
function semutaIncomeKaramaResponse(g: Game, response: ResponseWindow): boolean {
if (g.battle || g.pendingShipment || g.pendingGuildTransport ||
@@ -6629,7 +6639,8 @@ function semutaIncomeKaramaResponse(g: Game, response: ResponseWindow): boolean
if (response.kind === 'revivalIncome') {
// Ordinary returns and Ghola have already committed. Only their income
// remains; other producers retain their own unfinished parent contracts.
if (response.source !== undefined || g.pendingRevival || g.pendingChoamMarketGhola ||
if (response.source !== undefined || g.pendingRevival ||
(g.pendingChoamMarketGhola && !semutaMarketGholaIncome(g, response)) ||
(g.homeworldRevivalReturn && g.homeworldRevivalReturn.stage !== 'complete') ||
g.pendingHomeworldShipment || g.pendingSpiritualAdvisor ||
g.pendingArrivalOverlap || g.pendingArrivalReaction?.length ||
@@ -7029,6 +7040,7 @@ function kullSemutaParentSupported(g: Game, frame?: NonNullable<Game['pendingKul
let revivalSupported = false;
let guildSupported = false;
let saleSupported = false;
let marketSupported = false;
if (nativeResponse && frame && use?.kind === 'cancel') {
// Success has just installed this very Kull restriction. Validate the
// suspended source as it stood before that restriction, without changing
@@ -7040,6 +7052,12 @@ function kullSemutaParentSupported(g: Game, frame?: NonNullable<Game['pendingKul
revivalSupported = !!g.pendingRevival && semutaRevivalKaramaResponse(source, use.response, frame.owner);
guildSupported = (!!g.pendingShipment || !!g.pendingGuildTransport) &&
semutaGuildShipmentKaramaResponse(source, use.response);
if (g.pendingChoamMarketGhola && semutaMarketGholaIncome(source, use.response)) {
validateKaramaUse(source, getPlayer(source, frame.owner), use);
marketSupported = true;
} else if (!g.pendingChoamMarketGhola && g.choamMarket && use.response.kind === 'choamSale') {
marketSupported = semutaMarketGrantKaramaResponse(source, use.response, frame.owner);
}
const paidSale = frame.auctionReceipt === true && !!g.currentAuctionSale && (g.currentAuctionSale.origin === 'normal'
? !!g.auction && !g.richeseAuction
: g.currentAuctionSale.origin === 'cache' && !!g.richeseAuction &&
@@ -7072,8 +7090,8 @@ function kullSemutaParentSupported(g: Game, frame?: NonNullable<Game['pendingKul
!g.pendingHomeworldShipment && !g.pendingTerrorEntry &&
!g.pendingEcazPlacement && !g.pendingMoritaniPlacement &&
!g.pendingArrivalOverlap && !g.pendingArrivalReaction?.length && !g.pendingExchange &&
!g.pendingRichesePurchaseIncome && !g.pendingChoamMarketGhola && (!g.currentAuctionSale || saleSupported) &&
!g.choamMarket && (!g.richeseAuction || saleSupported) && !g.pendingFremenMove && !g.pendingIxMove &&
!g.pendingRichesePurchaseIncome && (!g.pendingChoamMarketGhola || marketSupported) && (!g.currentAuctionSale || saleSupported) &&
(!g.choamMarket || marketSupported) && (!g.richeseAuction || saleSupported) && !g.pendingFremenMove && !g.pendingIxMove &&
!g.pendingMobileMove && !g.pendingChoamMove && !g.ornithopter && !g.ecologicalStorm &&
!g.summonedWorm && !g.wormRides.length;
}
@@ -9618,6 +9636,10 @@ function semutaOfferSupported(
const marketGholaDiscard = continuation.kind === 'ordinaryCardDiscard' && continuation.effect === 'ghola' &&
g.semutaPreview === true && bareBasicSemutaProfile(g) && ordinaryDiscardIncomeMatches(g, continuation) &&
semutaMarketGholaSupported(g, continuation, entries);
const marketGholaIncomeDiscard = continuation.kind === 'karamaIncomeDiscard' &&
g.semutaPreview === true && bareBasicSemutaProfile(g) && !g.nexusKullPreview &&
(!g.pendingTreacheryDiscard || !!g.pendingTreacheryDiscard.reaction) &&
semutaMarketGholaIncome(g, continuation.use.response);
const richeseDiscard = richeseGiftDiscard || continuation.kind === 'karamaRicheseAuctionDiscard';
const auctionAdvantageDiscard = continuation.kind === 'karamaAuctionAdvantageDiscard';
const terminalDiscard = continuation.kind === 'karamaTerminalDiscard';
@@ -10050,13 +10072,13 @@ function semutaOfferSupported(
(richeseGiftDiscard || !g.pendingRicheseGift) &&
(richeseGiftDiscard || (continuation.kind === 'karamaIncomeDiscard' &&
continuation.use.response.kind === 'richesePurchaseIncome') || !g.pendingRichesePurchaseIncome) &&
(richeseGiftDiscard || saleCostDiscard || marketGholaDiscard || (continuation.kind === 'choamSaleDiscard'
(richeseGiftDiscard || saleCostDiscard || marketGholaDiscard || marketGholaIncomeDiscard || (continuation.kind === 'choamSaleDiscard'
? !!g.choamMarket && !g.choamMarket.sale &&
!g.choamMarket.trade && !g.biddingEnd && !g.currentAuctionSale
: continuation.kind === 'kaitainDiscard'
? g.biddingEnd?.event === continuation.event && biddingEndError(g) === null
: !g.choamMarket)) &&
(richeseGiftDiscard || marketGholaDiscard || !g.pendingChoamMarketGhola);
(richeseGiftDiscard || marketGholaDiscard || marketGholaIncomeDiscard || !g.pendingChoamMarketGhola);
}
function semutaContext(g: Game, owner: Player): SemutaContext {
const pending = g.pendingTreacheryDiscard!;