Support mixed Discovery decks with Leader Skills
Verify and publish checkpoint container / container (push) Canceled after 0s
Verify and publish checkpoint container / container (push) Canceled after 0s
This commit is contained in:
1 parent
7c1f4b4e09
commit
77eb2392eb
15 files changed
+420
-11
No files matched your search
@@ -1,5 +1,5 @@
|
||||
import { FACTIONS } from './catalog';
|
||||
import { independentDiscoveryProfile, mixedE3NexusRosterProfile, selectedNexusWithoutCardsProfile, selectedPhaseModuleRoster, type FactionModuleProfile } from './faction-module-profile';
|
||||
import { independentDiscoveryProfile, mixedE3NexusRosterProfile, 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
|
||||
@@ -17,6 +17,7 @@ export function homeworldDiscoveryProfile(game: FactionModuleProfile): boolean {
|
||||
/** The same roster/module contract during play; live Discovery frames are expected. */
|
||||
export function discoveryModeSupported(game: FactionModuleProfile): boolean {
|
||||
if (independentDiscoveryProfile(game)) return true;
|
||||
if (game.leaderSkills && selectedDiscoveryLeaderSkillsProfile(game)) return true;
|
||||
if (game.nexusCards) return (game.discoveryEnabled === true && selectedNexusWithoutCardsProfile(game)) || standaloneE3DiscoveryNexusProfile(game) || singleE1E2DiscoveryNexusProfile(game) ||
|
||||
mixedE3DiscoveryNexusProfile(game) || mixedE1E2DiscoveryNexusProfile(game) || pairedE3DiscoveryNexusProfile(game);
|
||||
if (typeof game.advanced !== 'boolean' || game.discoveryEnabled !== true ||
|
||||
@@ -59,6 +60,13 @@ export function discoveryModeSupported(game: FactionModuleProfile): boolean {
|
||||
return !(game.advanced && moritani && harkonnen);
|
||||
}
|
||||
|
||||
/** Original selected decks with Discovery and Skills are independent of Nexus
|
||||
* 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);
|
||||
}
|
||||
|
||||
/** The original E3 pair can use selected decks with Discovery without Nexus or cards. */
|
||||
export function e3DiscoveryOnlyOverlapProfile(game: FactionModuleProfile): boolean {
|
||||
return !game.nexusCards && !game.ecazTreachery && !game.leaderSkills &&
|
||||
|
||||
+3
-1
@@ -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, selectedFactionStrongholdProfile, selectedIndependentCardsProfile, selectedNexusWithoutCardsProfile, selectedPhaseModuleRoster } from './faction-module-profile';
|
||||
import { independentDiscoveryProfile, independentNexusProfile, nexusCoreProfile, nativeFactionTechProfile, 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';
|
||||
@@ -25185,6 +25185,8 @@ 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) &&
|
||||
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;
|
||||
if (bareBasicSemutaProfile(g) && byFaction(g, 'ecaz') && byFaction(g, 'moritani')) return true;
|
||||
|
||||
@@ -59,6 +59,17 @@ export function independentDiscoveryNexusProfile(game: NexusCoreConfiguration):
|
||||
return !!game.nexusCards && independentDiscoveryProfile(game);
|
||||
}
|
||||
|
||||
/** Selected Discovery decks and registered native seats remain independent of
|
||||
* Nexus and Ecaz's separate three cards, including before Skills are dealt. */
|
||||
export function selectedDiscoveryWithoutCardsProfile(game: NexusCoreConfiguration): boolean {
|
||||
const players = game.players;
|
||||
if (game.discoveryEnabled !== true || !game.expansions.length || !players ||
|
||||
game.nexusCards || game.ecazTreachery || game.semutaPreview ||
|
||||
!nexusCoreRosterProfile(game, true, true)) return false;
|
||||
return !(game.advanced && players.some(player => player.faction === 'harkonnen') &&
|
||||
players.some(player => player.faction === 'ecaz' || player.faction === 'moritani'));
|
||||
}
|
||||
|
||||
/** 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,6 +1,6 @@
|
||||
import { FACTIONS } from './catalog';
|
||||
import { independentDiscoveryProfile, independentNexusProfile, classicNexusCoreProfile, nexusCoreProfile, mixedE3NexusRosterProfile, selectedNexusWithoutCardsProfile } from './faction-module-profile';
|
||||
import { classicDiscoveryLeaderSkillsProfile } from './discovery-module-profile';
|
||||
import { classicDiscoveryLeaderSkillsProfile, selectedDiscoveryLeaderSkillsProfile } from './discovery-module-profile';
|
||||
|
||||
/** Public configuration only; never gate a skill on a hidden card or random deal. */
|
||||
export type LeaderSkillProfile = {
|
||||
@@ -305,7 +305,7 @@ export function classicTechLeaderSkillsProfile(game: LeaderSkillProfile): boolea
|
||||
export function strongholdLeaderSkillsProfile(game: LeaderSkillProfile): boolean {
|
||||
if (!game.strongholdCards || game.advanced !== true) return false;
|
||||
if (independentTreacheryLeaderSkillsProfile(game)) return true;
|
||||
if (game.expansions.length) return selectedNexusLeaderSkillsProfile(game) || selectedDeckLeaderSkillsProfile(game) ||
|
||||
if (game.expansions.length) return selectedDiscoveryLeaderSkillsProfile(game) || selectedNexusLeaderSkillsProfile(game) || selectedDeckLeaderSkillsProfile(game) ||
|
||||
advancedMoritaniLeaderSkillsProfile(game) || nativeEcazLeaderSkillsProfile(game);
|
||||
const players = game.players;
|
||||
if (!players || players.length < (game.techTokens ? 3 : 2) || players.length > 6 ||
|
||||
@@ -328,7 +328,7 @@ export function strongholdLeaderSkillsProfile(game: LeaderSkillProfile): boolean
|
||||
/** Bounded integration of the ordinary Moritani roster, not Advanced assassination. */
|
||||
export function basicMoritaniLeaderSkillsProfile(game: LeaderSkillProfile): boolean {
|
||||
if (game.advanced === false && game.players?.some(player => player.faction === 'moritani') &&
|
||||
(selectedNexusLeaderSkillsProfile(game) || selectedDeckLeaderSkillsProfile(game))) return true;
|
||||
(selectedDiscoveryLeaderSkillsProfile(game) || selectedNexusLeaderSkillsProfile(game) || selectedDeckLeaderSkillsProfile(game))) return true;
|
||||
return game.advanced === false && game.expansions.length === 1 &&
|
||||
game.expansions[0] === 'ecaz' && e3LeaderSkillModulesSupported(game) &&
|
||||
!!game.players?.some(player => player.faction === 'moritani') &&
|
||||
@@ -339,7 +339,7 @@ export function basicMoritaniLeaderSkillsProfile(game: LeaderSkillProfile): bool
|
||||
/** Existing bounded Advanced assassination roster, composed with native skills. */
|
||||
export function advancedMoritaniLeaderSkillsProfile(game: LeaderSkillProfile): boolean {
|
||||
if (game.advanced === true && game.players?.some(player => player.faction === 'moritani') &&
|
||||
(selectedNexusLeaderSkillsProfile(game) || selectedDeckLeaderSkillsProfile(game))) return true;
|
||||
(selectedDiscoveryLeaderSkillsProfile(game) || selectedNexusLeaderSkillsProfile(game) || selectedDeckLeaderSkillsProfile(game))) return true;
|
||||
const players = game.players;
|
||||
if (game.advanced !== true || game.expansions.length !== 1 ||
|
||||
game.expansions[0] !== 'ecaz' || !players || players.length < 2 || players.length > 6 ||
|
||||
@@ -366,7 +366,7 @@ export function advancedMoritaniLeaderSkillsProfile(game: LeaderSkillProfile): b
|
||||
/** Ecaz's five native discs; the separate temporarily controlled Duke is not an assignment disc. */
|
||||
export function nativeEcazLeaderSkillsProfile(game: LeaderSkillProfile): boolean {
|
||||
if (game.players?.some(player => player.faction === 'ecaz') &&
|
||||
(selectedNexusLeaderSkillsProfile(game) || selectedDeckLeaderSkillsProfile(game))) return true;
|
||||
(selectedDiscoveryLeaderSkillsProfile(game) || selectedNexusLeaderSkillsProfile(game) || selectedDeckLeaderSkillsProfile(game))) return true;
|
||||
const players = game.players;
|
||||
if (typeof game.advanced !== 'boolean' || game.expansions.length !== 1 ||
|
||||
game.expansions[0] !== 'ecaz' || !players || players.length < 2 || players.length > 6 ||
|
||||
@@ -442,7 +442,7 @@ export function selectedDeckLeaderSkillsProfile(game: LeaderSkillProfile): boole
|
||||
|
||||
export function nativeExpansionLeaderSkillsProfile(game: LeaderSkillProfile): boolean {
|
||||
return (game.expansions.length > 0 && independentTreacheryLeaderSkillsProfile(game)) ||
|
||||
selectedNexusLeaderSkillsProfile(game) || mixedE3NexusLeaderSkillsProfile(game) || mixedE1E2NexusLeaderSkillsProfile(game) || pairedE3NexusLeaderSkillsProfile(game) ||
|
||||
selectedDiscoveryLeaderSkillsProfile(game) || selectedNexusLeaderSkillsProfile(game) || mixedE3NexusLeaderSkillsProfile(game) || mixedE1E2NexusLeaderSkillsProfile(game) || pairedE3NexusLeaderSkillsProfile(game) ||
|
||||
basicMoritaniLeaderSkillsProfile(game) || selectedDeckLeaderSkillsProfile(game) ||
|
||||
advancedMoritaniLeaderSkillsProfile(game) || nativeEcazLeaderSkillsProfile(game);
|
||||
}
|
||||
|
||||
@@ -5927,6 +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 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.',
|
||||
|
||||
Reference in new issue
Block a user