Connect Semuta in Discovery and Skills games
Verify and publish checkpoint container / container (push) Successful in 11m5s

This commit is contained in:
Quintine committed 2026-10-30 17:56:08 +11:00
1 parent 77eb2392eb
commit 528b152f7d
14 files changed
+481 -15

No files matched your search

+2 -2
View File
@@ -1,5 +1,5 @@
import { FACTIONS } from './catalog';
import { independentDiscoveryProfile, mixedE3NexusRosterProfile, selectedDiscoveryWithoutCardsProfile, selectedNexusWithoutCardsProfile, selectedPhaseModuleRoster, type FactionModuleProfile } from './faction-module-profile';
import { independentDiscoveryProfile, mixedE3NexusRosterProfile, selectedDiscoverySkillsSemutaProfile, selectedDiscoveryWithoutCardsProfile, selectedNexusWithoutCardsProfile, selectedPhaseModuleRoster, type FactionModuleProfile } from './faction-module-profile';
import type { LeaderSkillProfile } from './leader-skill-profile';
/** Public unused-lobby admission only. The original initializer owns physical
@@ -64,7 +64,7 @@ export function discoveryModeSupported(game: FactionModuleProfile): boolean {
* and the separate Ecaz cards. Setup owns physical inventory; this public
* roster contract also remains valid during live Discovery frames. */
export function selectedDiscoveryLeaderSkillsProfile(game: LeaderSkillProfile): boolean {
return selectedDiscoveryWithoutCardsProfile(game);
return selectedDiscoveryWithoutCardsProfile(game) || selectedDiscoverySkillsSemutaProfile(game);
}
/** The original E3 pair can use selected decks with Discovery without Nexus or cards. */
+15 -7
View File
@@ -99,7 +99,7 @@ import { movementShipmentPreparations } from './movement-shipment-preparation';
import { MovementClaimError, liveMovementPromises, movementEventAllowed, movementPromiseModeSupported, movementPromiseTargetAvailable, settleMovementEvent, finishMovementPromises, validMovementClaim, type MovementClaim, type MovementPromise } from './movement-promises';
import { findMovementCompletion, type MovementCompletion } from './movement-promise-search';
import { classicNexusModulesProfile, mixedE1E2NexusProfile, mixedE3NexusProfile, pairedE3NexusProfile, pairedNexusModulesProfile, singleE1E2NexusProfile, standaloneE3NexusProfile } from './nexus-module-profile';
import { independentDiscoveryProfile, independentNexusProfile, nexusCoreProfile, nativeFactionTechProfile, selectedDiscoveryWithoutCardsProfile, selectedFactionStrongholdProfile, selectedIndependentCardsProfile, selectedNexusWithoutCardsProfile, selectedPhaseModuleRoster } from './faction-module-profile';
import { independentDiscoveryProfile, independentNexusProfile, nexusCoreProfile, nativeFactionTechProfile, selectedDiscoverySkillsSemutaProfile, selectedDiscoveryWithoutCardsProfile, selectedFactionStrongholdProfile, selectedIndependentCardsProfile, selectedNexusWithoutCardsProfile, selectedPhaseModuleRoster } from './faction-module-profile';
import { homeworldOccupationLeaderSkillsProfile, homeworldOccupationModulesProfile, homeworldPhaseModulesProfile } from './homeworld-module-profile';
import { RevivalPromiseError, revivalPromiseModeSupported, liveRevivalPromises, recordPromisedRevival,
revivalPromisesSatisfied, validateRevivalPromises, type RevivalClaim, type RevivalPromise } from './revival-promises';
@@ -8091,6 +8091,7 @@ function semutaHomeworldRoster(g: Game): boolean {
* Sapho's neutral simultaneous-Truth ordering in their supported parents. */
function semutaTruthOrderProfile(g: Game): boolean {
if (bareBasicSemutaProfile(g) || semutaHomeworldRoster(g)) return true;
if (selectedDiscoverySkillsSemutaProfile(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) &&
@@ -11163,6 +11164,10 @@ function lobbyModulesSelected(g: Game): boolean {
/** Fresh public Richese + Skills entry, using the already connected Semuta
* continuation. Other family/module compositions retain their own entry. */
function publicSemutaSkillsProfile(g: Game): boolean {
if (g.status === 'lobby' && !g.leaderSkills && !g.homeworlds &&
!g.twoPlayerControllers && !g.shortAllianceVictory && !g.coalitionPreview &&
g.expansions.includes('choam') && !!byFaction(g, 'richese') &&
selectedDiscoveryWithoutCardsProfile(g)) return true;
return g.status === 'lobby' && typeof g.advanced === 'boolean' &&
g.players.length >= 2 && g.players.length <= 6 &&
g.expansions.length === 1 && g.expansions[0] === 'choam' && !!byFaction(g, 'richese') &&
@@ -13638,21 +13643,24 @@ function bareAdvancedEcazSemutaProfile(g: Game): boolean {
export function initializeSemutaGameForAudit(state: Game, skills = false): Game {
const basicNative = bareBasicSemutaProfile(state);
const advancedEcaz = bareAdvancedEcazSemutaProfile(state);
const selectedSkillsDiscovery = skills && state.discoveryEnabled === true && !state.homeworlds &&
selectedDiscoveryWithoutCardsProfile(state);
requireRule(!advancedEcaz || !skills, 'Advanced Ecaz Semuta excludes Leader Skills and other optional modules.');
requireRule(!state.semutaPreview &&
state.expansions.includes('choam') &&
(state.expansions.every(id => id === 'choam' || id === 'ix') || basicNative || advancedEcaz) &&
(state.expansions.every(id => id === 'choam' || id === 'ix') || basicNative || advancedEcaz || selectedSkillsDiscovery) &&
state.players.some(p => p.faction === 'richese'),
'Semuta needs a fresh Richese faction game: bare Basic selected native families, bare Advanced Ecaz/Richese, or CHOAM with optional Ix and supported original modules/skills; separate classic or Advanced Tleilax Homeworld occupation has no other modules. Other overlays remain excluded.');
if (state.discoveryEnabled) requireRule(!basicNative && !skills && !state.homeworlds &&
!state.nexusCards && discoveryModuleProfile(state),
'Semuta Discovery keeps original Richese/CHOAM and optional Ix setup, without Skills, Homeworlds, Nexus or E3 overlays.');
if (state.discoveryEnabled) requireRule(selectedSkillsDiscovery || (!basicNative && !skills && !state.homeworlds &&
!state.nexusCards && discoveryModuleProfile(state)),
'Semuta Discovery requires a supported fresh Richese roster without Homeworlds or Nexus.');
if (state.nexusCards) requireRule(!basicNative && !state.homeworlds &&
!state.discoveryEnabled && !state.discoveries,
'Semuta Nexus retains original E1/E2 rosters without Homeworlds, Discovery or E3.');
if (state.homeworlds) requireRule(!skills && semutaHomeworldRoster(state),
'Semuta Homeworlds require original Richese/CHOAM and classic factions with exact CHOAM, or Advanced Tleilax with exact CHOAM+Ix, and no other modules.');
const g = state.discoveryEnabled ? initializeDiscoveryGameForAudit(state)
const g = selectedSkillsDiscovery ? initializeLeaderSkillsGameForAudit(state)
: state.discoveryEnabled ? initializeDiscoveryGameForAudit(state)
: state.homeworlds ? initializeHomeworldOccupationGameForAudit(state)
: skills ? initializeLeaderSkillsGameForAudit(state)
: state.nexusCards ? state.expansions.length === 1 && !!byFaction(state, 'choam')
@@ -25185,7 +25193,7 @@ function arrivalOverlapModeSupported(g: Game, revivalArrival?: RevivalEntryParen
if (bareBasicNativeArrivalOverlap(g)) return true;
if (bareAdvancedNativeArrivalOverlap(g)) return true;
if (e3DiscoveryOnlyOverlapProfile(g)) return true;
if (g.leaderSkills && selectedDiscoveryWithoutCardsProfile(g) &&
if (g.leaderSkills && (selectedDiscoveryWithoutCardsProfile(g) || selectedDiscoverySkillsSemutaProfile(g)) &&
byFaction(g, 'ecaz') && byFaction(g, 'moritani')) return true;
if (homeworldPhaseModulesProfile(g) && byFaction(g, 'ecaz') && byFaction(g, 'moritani')) return true;
if (revivalArrival && g.homeworlds && byFaction(g, 'ecaz') && byFaction(g, 'moritani')) return true;
+9
View File
@@ -70,6 +70,15 @@ export function selectedDiscoveryWithoutCardsProfile(game: NexusCoreConfiguratio
players.some(player => player.faction === 'ecaz' || player.faction === 'moritani'));
}
/** The original Richese Semuta protocol can join these selected decks once
* Skills and Discovery have both been initialized. Homeworlds retain their
* separately supported Semuta envelope. */
export function selectedDiscoverySkillsSemutaProfile(game: NexusCoreConfiguration): boolean {
return game.semutaPreview === true && !!game.leaderSkills && !game.homeworlds &&
game.expansions.includes('choam') && !!game.players?.some(player => player.faction === 'richese') &&
selectedDiscoveryWithoutCardsProfile({...game, semutaPreview: undefined});
}
/** Original selected decks do not require their native factions or the
* independent three-card variant. Hidden E3/Harkonnen compositions retain
* their existing separately scoped paths. */
+1
View File
@@ -6,6 +6,7 @@ import { classicDiscoveryLeaderSkillsProfile, selectedDiscoveryLeaderSkillsProfi
export type LeaderSkillProfile = {
expansions: readonly string[];
advanced?: boolean;
leaderSkills?: unknown;
players?: readonly { faction: string }[];
homeworlds?: unknown;
nexusCards?: unknown;
+1 -1
View File
@@ -5927,7 +5927,7 @@ export const RULE_TOPICS: RuleTopic[] = [
searchText: 'Hiereg Smuggler Jacurutu Sietch Cistern Ecological Testing Station Shrine Orgiz Processing Station Treachery Card Stash Spice Stash Ornithopter',
steps: [
'The Discovery-only fresh preview supports classics and selected Ixian/Tleilaxu, CHOAM/Richese and Ecaz/Moritani decks in Basic/Advanced2–6, including unused selected decks. It supplies seven extra Spice Cards/eight tokens; optional Tech requires3+ and Strongholds require Advanced. Nexus and independent cards are not required. Existing Advanced Moritani/Harkonnen and deeper interaction restrictions remain; complete-mode acceptance stays separate.',
'Fresh selected-deck Discovery previews can also train Leader Skills without Nexus or independent Ecaz cards, including mixed and unseated families. Advanced Harkonnen with an actual Ecaz or Moritani seat, Semuta and deeper interactions keep their existing limitations.',
'Fresh selected-deck Discovery previews can also train Leader Skills without Nexus or independent Ecaz cards, including mixed and unseated families. With Richese seated, supported Semuta discards can react while those modules are active. Advanced Harkonnen with an actual Ecaz or Moritani seat, other Semuta sources and deeper interactions keep their existing limitations.',
'Fresh Discovery retains original Homeworlds and native reserves in classic and supported E1/E2 or E3 tables, Basic/Advanced2–6, optional Tech3+/Advanced Strongholds. Original Nexus entries additionally admit natives from BOTH Ix+CHOAM families/union47 or BOTH Ecaz+Moritani/ecaz33 with classics, with or without all14 Skills. Maker, actual parent/nested entry, source-local payments/rescue, phase-end industry and original-winner cleanup/Tech remain. Held benefits do not migrate into nested locations. Original capture/roster and unresolved-effect guards remain.',
'The original leader-skills --nexus-cards --discoveries entry composes all14 offered training/all12 Nexus/Discovery7/8 for classics/base33, single or paired one-family E1/E2, natives from BOTH selected Ix+CHOAM families/union47, or standalone OR paired Ecaz/Moritani/ecaz33 with classics. Original Homeworlds may be retained; Tech requires3+ and Strongholds Advanced. Hands/offers, native components and actual Maker/both-pile/alliance-change closing draws remain authoritative. Shared Duke never trains; Advanced paired E3/Moritani excludes Harkonnen. Mixed E3/three-family and pending effects/public starts/save conversion remain separate.',
'Connected native outcomes use original sources: Suboid Cunning and winning trained Suk settle typed fixed casualties before one equal actual Cyborg Tank substitution; original cleanup and mandatory winner Tech precede matching Face Dance, retaining its foreign-Homeworld suppression. Signed Richese two-marker one-invoice physical shipment requires a currently revealed nested site. Ecaz-selected coalition armies and Moritani skill-first assassination remain distinct from shared-Duke training. These programmes do not certify every skill or card band.',