Enable Semuta in public Homeworld games
Verify and publish checkpoint container / container (push) Successful in 11m13s

This commit is contained in:
Quintine committed 2026-10-29 09:36:52 +11:00
1 parent 98ead3a4b5
commit 49f9ebdea0
11 files changed
+526 -6

No files matched your search

+19 -3
View File
@@ -8019,6 +8019,17 @@ function semutaHomeworldRoster(g: Game): boolean {
!g.discoveryEnabled && !g.discoveries && !g.discoveryStash &&
!g.greatMaker && !g.ecazTreachery;
}
/** Existing bare and fresh public CHOAM-only Semuta profiles may retain
* Sapho's neutral simultaneous-Truth ordering in their supported parents. */
function semutaTruthOrderProfile(g: Game): boolean {
if (bareBasicSemutaProfile(g) || semutaHomeworldRoster(g)) return true;
return g.semutaPreview === true && g.expansions.length === 1 && g.expansions[0] === 'choam' &&
!!byFaction(g, 'richese') && g.players.every(p => p.faction === 'richese' ||
p.faction === 'choam' || CLASSIC_FACTIONS[p.faction] === true) &&
!g.homeworlds && !g.nexusCards && !g.ecazTreachery && !g.kullPreview && !g.nexusKullPreview &&
(g.discoveryEnabled === true && !!g.discoveries && !g.leaderSkills && discoveryModeSupported(g) ||
!!g.leaderSkills && !g.discoveryEnabled && ordinaryLeaderSkillModeSupported(g));
}
type TupileDiscardContinuation = Extract<
NonNullable<Game['pendingTreacheryDiscard']>['continuation'],
{ kind: 'tupileCleanupDiscard' }
@@ -9815,6 +9826,7 @@ function semutaOfferSupported(
continuation.kind !== 'saphoRevivalDiscard' &&
continuation.kind !== 'saphoCharityDiscard' &&
continuation.kind !== 'saphoExtortionDiscard' &&
!(continuation.kind === 'saphoTruthOrderDiscard' && semutaHomeworldRoster(g)) &&
continuation.kind !== 'battleResolved' &&
continuation.kind !== 'winnerMandatoryDiscard' &&
continuation.kind !== 'battleCleanup' &&
@@ -10086,7 +10098,7 @@ function semutaOfferSupported(
(richeseGiftDiscard || combatDiscard || alliedTraitorDiscard || occupyDiscard || continuation.kind === 'saphoAggressorDiscard' ||
(continuation.kind === 'saphoTruthOrderDiscard' && !!continuation.battleEvent &&
g.phase === 6 && g.battle?.event === continuation.battleEvent && !g.battle.revealed && !g.battle.preparation &&
bareBasicSemutaProfile(g)) ||
semutaTruthOrderProfile(g)) ||
bgDiscard ||
continuation.kind === 'specialKaramaDiscard' ||
continuation.kind === 'residualPoisonDiscard' ||
@@ -11118,8 +11130,12 @@ function startModules(state: Game): Game {
}
if (g.discoveryEnabled) return publicSemutaDiscoveryProfile(g)
? initializeSemutaGameForAudit(g) : initializeDiscoveryGameForAudit(g);
if (g.homeworlds)
if (g.homeworlds) {
if (g.status === 'lobby' && !g.twoPlayerControllers && !g.shortAllianceVictory &&
!g.coalitionPreview && semutaHomeworldRoster(g))
return initializeSemutaGameForAudit(g);
return g.expansions.length ? initializeHomeworldOccupationGameForAudit(g) : initializeHomeworldGameForAudit(g);
}
if (g.strongholdCards) return initializeStrongholdFactionsGameForAudit(g);
const advancedOrdinarySemuta = bareAdvancedClassicSemutaProfile(g);
const initialized = initializeFactionExpansionsGame(g, bareBasicSemutaProfile(g));
@@ -29342,7 +29358,7 @@ function saphoTruthOrderSemutaSupported(g: Game,p: Player,card: string,mode: 'fi
}
function saphoTruthOrderChoices(g: Game,p: Player): {card:string;mode:'first'|'last'}[] {
const w = g.truthtrance;
if (w?.stage !== 'order' || !w.order || (g.semutaPreview && !bareBasicSemutaProfile(g)) ||
if (w?.stage !== 'order' || !w.order || (g.semutaPreview && !semutaTruthOrderProfile(g)) ||
printedRolePlayBlock(g,p.id,'juiceOfSapho')) return [];
const card = p.hand.find(row => row.id === 'richese-juice-of-sapho' && row.effect === 'juiceOfSapho');
if (!card || !richeseCardDefinition(card) || p.hand.filter(row => row.id === card.id).length !== 1 ||