Compose classic Nexus Skills with original Tech and Strongholds

This commit is contained in:
Quintine committed 2026-10-04 23:59:58 +11:00
1 parent 03aedc14d7
commit 449e27b415
17 files changed
+1764 -23

No files matched your search

+2 -2
View File
@@ -1,4 +1,4 @@
import { classicTechLeaderSkillsProfile, nativeExpansionLeaderSkillsProfile, nativeTechLeaderSkillsProfile, noOtherLeaderSkillModules, strongholdLeaderSkillsProfile, type LeaderSkillProfile } from './leader-skill-profile';
import { classicNexusLeaderSkillsProfile, classicTechLeaderSkillsProfile, nativeExpansionLeaderSkillsProfile, nativeTechLeaderSkillsProfile, noOtherLeaderSkillModules, strongholdLeaderSkillsProfile, type LeaderSkillProfile } from './leader-skill-profile';
export type BureaucratPaymentKind = 'auction' | 'shipment' | 'bribe' | 'revival';
export type BureaucratPaymentSource = {
event: string;
@@ -38,7 +38,7 @@ export function bureaucratPaymentModeSupported(game: LeaderSkillProfile): boolea
return (noOtherLeaderSkillModules(game) &&
(!game.expansions.length ||
(game.expansions.length === 1 && game.expansions[0] === 'choam') ||
nativeExpansionLeaderSkillsProfile(game))) || classicTechLeaderSkillsProfile(game) || nativeTechLeaderSkillsProfile(game) || strongholdLeaderSkillsProfile(game);
nativeExpansionLeaderSkillsProfile(game))) || classicTechLeaderSkillsProfile(game) || nativeTechLeaderSkillsProfile(game) || strongholdLeaderSkillsProfile(game) || classicNexusLeaderSkillsProfile(game);
}
export function bureaucratUsed(
used: readonly BureaucratPaymentUse[],
+10 -5
View File
@@ -8118,11 +8118,14 @@ function actBureaucratPayment(g: Game,action:Action) {
else if (pending.continuation.kind === 'auction') commitAuctionContinuation(g,pending.continuation.quote,redirected);
else getPlayer(g,pending.source.payee).bribes += pending.source.amount-redirected;
}
function leaderSkillRevivalBlocked(g: Game, owner: string): boolean {
return !!g.leaderSkills?.assignments.some(
(a) => a.owner === owner && leaderSkillController(g, a) !== owner,
);
}
function requireLeaderSkillRevival(g: Game, owner: string) {
requireRule(
!g.leaderSkills?.assignments.some(
(a) => a.owner === owner && leaderSkillController(g, a) !== owner,
),
!leaderSkillRevivalBlocked(g, owner),
'Reviving another leader while your Leader Skill is captured awaits the replacement-skill ruling.',
);
}
@@ -9439,7 +9442,8 @@ function initializeSetupGameForAudit(state: Game, homeworlds: boolean, nexus = f
const skillStronghold = leaderSkills && strongholdLeaderSkillsProfile(g);
const skillTech = leaderSkills && (classicTechLeaderSkillsProfile(g) || nativeTechLeaderSkillsProfile(g) || skillStronghold);
const nativeTech = factions && !leaderSkills && nativeFactionTechProfile(g);
const nexusModules = nexus && (classicNexusModulesProfile(g) || pairedNexusModulesProfile(g));
const nexusModules = nexus && (classicNexusModulesProfile(g) || pairedNexusModulesProfile(g) ||
(leaderSkills && classicNexusLeaderSkillsProfile(g)));
requireRule(!g.techTokens || ((skillTech || nativeTech || nexusModules) &&
JSON.stringify(g.techTokens) === JSON.stringify(createTechTokens())),
'Tech Tokens require a fresh supported three-through-six-seat lobby with unused tokens.');
@@ -18965,6 +18969,7 @@ function normalizeBattle(g: Game) {
/** Ghola follows current control for ordinary leaders, but Duke's printed
* revival right belongs exclusively to Ecaz, regardless of temporary custody. */
function gholaLeaders(g: Game, p: Player) {
if (leaderSkillRevivalBlocked(g, p.id)) return [];
const native = controlledLeaders(g, p).filter(
(l) => l.id !== DUKE_VIDAL_ID && l.dead && !l.capturedBy,
);
@@ -31385,7 +31390,7 @@ export function viewGame(state: Game, id: string) {
g.decision?.kind === 'revivalStop'
? homeworldRevivalKaramaBlock(g, g.decision.recipient)
: null,
leaders: leaderRevivals.leaders,
leaders: leaderSkillRevivalBlocked(g, id) ? [] : leaderRevivals.leaders,
kwisatz: leaderRevivals.kwisatz,
cycleBlock: leaderRevivals.cycleBlock,
dukeBlocked: leaderRevivals.dukeBlocked,
+6 -4
View File
@@ -33,11 +33,13 @@ export function noOtherLeaderSkillModules(game: LeaderSkillProfile): boolean {
!game.discoveryEnabled && !game.strongholdCards && !game.techTokens && !game.ecazTreachery;
}
function nexusLeaderSkillModulesSupported(game: LeaderSkillProfile): boolean {
function nexusLeaderSkillModulesSupported(game: LeaderSkillProfile, tokenCards = false): boolean {
return !!game.nexusCards && typeof game.advanced === 'boolean' &&
!!game.players && game.players.length >= 2 && game.players.length <= 6 &&
!game.homeworlds && !game.discoveries && !game.discoveryEnabled &&
!game.discoveryStash && !game.greatMaker && !game.strongholdCards && !game.techTokens &&
!game.discoveryStash && !game.greatMaker &&
(!game.techTokens || (tokenCards && game.players.length >= 3)) &&
(!game.strongholdCards || (tokenCards && game.advanced === true)) &&
!game.ecazTreachery && !game.semutaPreview && !game.moritaniAssassinatePreview &&
!game.advancedPreview && !game.kullPreview && !game.nexusKullPreview &&
!game.guildBetrayalPreview && !game.richeseBetrayalPreview &&
@@ -46,9 +48,9 @@ function nexusLeaderSkillModulesSupported(game: LeaderSkillProfile): boolean {
!game.spiceBankerIncomePreview;
}
/** Fresh classic Nexus/Skills only; other module and native compositions stay separate. */
/** Fresh classic Nexus/Skills, with original Tech and Advanced Strongholds; native overlays stay separate. */
export function classicNexusLeaderSkillsProfile(game: LeaderSkillProfile): boolean {
if (game.expansions.length || !nexusLeaderSkillModulesSupported(game)) return false;
if (game.expansions.length || !nexusLeaderSkillModulesSupported(game, true)) return false;
const players = game.players!;
for (let i = 0; i < players.length; i++) {
for (let j = 0; j < i; j++) if (players[j].faction === players[i].faction) return false;
+2 -1
View File
@@ -71,7 +71,8 @@ export function emperorNexusModeSupported(g: Game): boolean {
!g.discoveries &&
!g.discoveryStash &&
!g.greatMaker &&
((!g.techTokens && !g.strongholdCards) || classicNexusModulesProfile(g))
((!g.techTokens && !g.strongholdCards) || classicNexusModulesProfile(g) ||
(!!g.leaderSkills && classicNexusLeaderSkillsProfile(g)))
);
}
/** A fixed three-counter grant preserves the separate Advanced elite cap. */
+3 -3
View File
@@ -4367,7 +4367,7 @@ export const RULE_TOPICS: RuleTopic[] = [
'Use Cunning for your own faction, Betrayal when another player controls the printed faction, and Secret Ally when that faction is absent. Used cards go to the separate Nexus discard pile. Each printed effect has its own timing.',
'Fresh local classic Nexus tables may preserve original Tech Tokens in Basic/Advanced three-through-six-seat lobbies and/or Stronghold Cards in Advanced two-through-six-seat lobbies; selecting both requires three or more. Original base33/all12 setup, closing Nexus deals, first-Storm Tech and actual end-Mentat Stronghold custody remain. Skills, Homeworlds in this composition, native expansions, unrelated previews, public starts and saved-game conversion stay separate.',
'The same fresh local Nexus entry also composes Tech and/or Advanced Strongholds with paired Ixians + Tleilaxu OR CHOAM + Richese and classic opponents, one original family deck and no Skills. Tech needs three through six seats; Strongholds needs two through six Advanced seats. Real closing draws, native typed forces, physical Face Dancers and No-Fields, original payments/rewards and held effects remain. Mixed families, E3, Homeworlds, unrelated previews, public starts and unresolved rulings are not opened.',
'The separate fresh local leader-skills --nexus-cards entry combines classic base33/all14 Skills/all12 Nexus in Basic or Advanced, two through six seats, without other overlays or public starts. Original starting hands and skill offers are continued, not redealt. Actual closing Nexus draws remain required. Extra/ordinary free-three returns, bank purchase and committed Traitor Deck exchanges preserve skill custody. Native Emperor Cunning composes ordinary skill posture, bonuses and Suk rescue without changing physical starred inventory or repeating support.',
'The separate fresh local leader-skills --nexus-cards entry combines classic base33/all14 Skills/all12 Nexus in Basic or Advanced, two through six seats. Selected original Tech Tokens require three or more seats; Stronghold Cards require Advanced. Original starting hands/offers, closing draws, first-Storm Tech and end-Mentat held custody remain. Extra/ordinary free-three returns earn original phase-end Axlotl without changing skill custody. Emperor Cunning composes skill posture, support and Suk rescue; Arrakeen reduces payer cost, not committed support or rescue eligibility. Winner cleanup precedes mandatory Tech reward. Other overlays and public starts remain guarded.',
'The same fresh skill/Nexus entry also supports paired Ixians + Tleilaxu OR CHOAM + Richese with classics and one original family deck/all14/all12, Basic/Advanced two through six seats, without other overlays. Full Suboid Cunning composes typed skill rescue before equal actual Cyborg Tank substitution. Face Dance follows original skill/card/reward settlement, kills the matching trainer and returns its skill once without another bounty; partial Tleilaxu Cunning preserves ordinary Mentat rights. Original Richese pair and CHOAM printed fuel use their distinct physical operations. Mixed families, E3, companion/mixed-plan, native free-return accounting and other pending rulings stay separate.',
'Atreides Cunning adds a second, different opposing plan element after the first native answer. Both remain binding. Use it in your own battle before sealing your plan; Karama may cancel the extra attempt while preserving the first disclosure.',
'With Atreides absent, Secret Ally inspects one opposing element in your battle. A sealed plan supplies only that selected answer automatically. Otherwise the opponent chooses an answer that permits a legal plan. Other players receive no private answer.',
@@ -4419,7 +4419,7 @@ export const RULE_TOPICS: RuleTopic[] = [
{ area: 'Player controls', status: 'Partial', detail: 'Private lifecycle, inspections, exchanges, Tleilaxu refresh, Ixian activation, advisor selection, temporary Sardaukar and CHOAM effects, Moritani Betrayal, Ecaz Betrayal and owner-only Secret Ally inquiry, native Duke Cunning, Richese shipment and bounded auction Betrayal, Emperor purchase and Fremen Cunning controls are connected. Remaining effect controls are unfinished.', evidence: ['components/nexus-cards.tsx', 'components/nexus-traitors.tsx', 'components/nexus-tleilaxu.tsx', 'components/nexus-suboids.tsx', 'components/nexus-advisors.tsx', 'components/nexus-sardaukar.tsx', 'components/choam-power-cost.tsx', 'components/moritani-terror.tsx', 'components/nexus-moritani-betrayal.tsx', 'components/nexus-ecaz-betrayal.tsx', 'components/nexus-ecaz-inquiry.tsx', 'components/nexus-ecaz-duke.tsx', 'components/nexus-richese-betrayal.tsx', 'components/game-table.tsx'] },
{ area: 'AI', status: 'Partial', detail: 'All four profiles choose legal actions through private offers, including Moritani/Ecaz Betrayal, Ecaz Secret Ally inquiry and native Duke Cunning, Fremen Cunning, Emperor purchase and bounded Richese auction Betrayal. Complete module strategy and calibration remain unfinished.', evidence: ['game/nexus-card-options.ts', 'game/nexus-traitor-options.ts', 'game/nexus-tleilaxu-options.ts', 'game/nexus-suboid-options.ts', 'game/nexus-advisor-options.ts', 'game/nexus-sardaukar-options.ts', 'game/choam-power-options.ts', 'game/nexus-moritani-options.ts', 'game/nexus-moritani-betrayal-options.ts', 'game/nexus-ecaz-betrayal-options.ts', 'game/nexus-ecaz-inquiry-options.ts', 'game/nexus-ecaz-duke-options.ts', 'game/nexus-richese-options.ts', 'game/bot-nexus-richese-betrayal.ts', 'game/nexus-guild-cunning-options.ts', 'game/bots.ts'] },
{ area: 'Documentation', status: 'Partial', detail: 'Common rules, twelve printed faces and bounded runtime contracts retain explicit unresolved Ecaz Duke capture/Tanks/Ghola and inquiry audience/scope, Fremen nested Cunning, Great Maker, combined modules, fresh advisors, storm and borrowed Voice. Richese auction Betrayal has a separate cost/prepayment/privacy contract and excluded-producer boundaries. Guild Betrayal separately records full funded payment, own pre-funding, donor escrow once, the printed full-Junction override, four native adapters and neutral privacy; ordinary occupation/rounding and general response-priority questions remain unresolved.', evidence: ['docs/NEXUS_CARD_RULES.md', 'docs/NEXUS_ATREIDES_RULES.md', 'docs/NEXUS_HARKONNEN_RULES.md', 'docs/NEXUS_TLEILAXU_RULES.md', 'docs/NEXUS_IXIAN_CUNNING_RULES.md', 'docs/NEXUS_CUNNING_RUNTIME.md', 'docs/NEXUS_BENE_GESSERIT_RULES.md', 'docs/NEXUS_ADVISOR_RUNTIME.md', 'docs/NEXUS_EMPEROR_RULES.md', 'docs/NEXUS_SARDAUKAR_RUNTIME.md', 'docs/NEXUS_FREMEN_RULES.md', 'docs/NEXUS_ECAZ_RULES.md', 'docs/NEXUS_CHOAM_RULES.md', 'docs/NEXUS_CHOAM_RUNTIME.md', 'docs/NEXUS_MORITANI_RULES.md', 'docs/NEXUS_MORITANI_RUNTIME.md', 'docs/NEXUS_RICHESE_RUNTIME.md', 'docs/NEXUS_RICHESE_RULES.md', 'docs/NEXUS_GUILD_CUNNING_RUNTIME.md', 'docs/NEXUS_GUILD_RULES.md'] },
{ area: 'Verification', status: 'Partial', detail: 'Physical custody, commitments, controls, legal bots, Basic/Advanced and in-memory SQLite recovery regressions include native Ecaz Duke override and private Secret Ally inquiry. A read-only local browser fixture showed the owner-only Duke choice and no rival offer; no room was written. Bounded Richese auction Betrayal additionally has local CLI/runtime, authenticated SQLite and refreshed phone Use/Pass evidence in owned disposable rooms. New Guild Betrayal verification is separately Planned pending frozen direct evidence; these earlier results do not certify it. Fresh classic and paired E1/E2 Tech/Stronghold compositions have bounded runtime cases, genuine games and original CLI/phone evidence. Classic all14 Skills additionally has actual free-return/purchase/exchange and Cunning/Suk lifecycle programs, original phone controls and genuine2..6-seat games. Full module games, exceptional Duke custody, combined interactions and deployed acceptance remain separate.', evidence: ['tests/nexus-cards.test.ts', 'tests/nexus-card-engine.test.ts', 'tests/nexus-fremen-cunning.test.ts', 'tests/nexus-fremen-cunning-recovery.test.ts', 'tests/nexus-fremen-cunning-summon.test.ts', 'tests/nexus-fremen-cunning-summon-recovery.test.ts', 'tests/nexus-ecaz-betrayal-quotes.test.ts', 'tests/nexus-ecaz-betrayal.test.ts', 'tests/nexus-ecaz-betrayal-recovery.test.ts', 'tests/nexus-ecaz-inquiry.test.ts', 'tests/nexus-ecaz-duke-quote.test.ts', 'tests/nexus-ecaz-duke-engine.test.ts', 'tests/nexus-ecaz-duke-controls.test.ts', 'tests/nexus-ecaz-duke-recovery.test.ts', 'tests/nexus-traitor-recovery.test.ts', 'tests/nexus-face-dancer-engine.test.ts', 'tests/nexus-suboids-engine.test.ts', 'tests/normal-free-support.test.ts', 'tests/nexus-suboid-controls.test.ts', 'tests/nexus-advisor-controls.test.ts', 'tests/nexus-advisor-bots.test.ts', 'tests/nexus-sardaukar-controls.test.ts', 'tests/nexus-sardaukar-bots.test.ts', 'tests/nexus-choam-controls.test.ts', 'tests/nexus-choam-bots.test.ts', 'tests/nexus-moritani-controls.test.ts', 'tests/nexus-moritani-bots.test.ts', 'tests/nexus-moritani-betrayal.test.ts', 'tests/nexus-richese-controls.test.ts', 'tests/nexus-richese-bots.test.ts', 'tests/nexus-richese-betrayal-engine.test.ts', 'tests/nexus-richese-betrayal-recovery.test.ts', 'tests/nexus-guild-cunning-controls.test.ts', 'tests/nexus-guild-cunning-bots.test.ts', 'tests/nexus-module-payments-runtime.test.ts', 'tests/nexus-module-battles-runtime.test.ts', 'tests/paired-ix-nexus-modules-runtime.test.ts', 'tests/paired-choam-nexus-modules-runtime.test.ts', 'tests/classic-nexus-skills-payments-runtime.test.ts', 'tests/classic-nexus-skills-battles-runtime.test.ts'] },
{ area: 'Verification', status: 'Partial', detail: 'Physical custody, commitments, controls, legal bots, Basic/Advanced and in-memory SQLite recovery regressions include native Ecaz Duke override and private Secret Ally inquiry. A read-only local browser fixture showed the owner-only Duke choice and no rival offer; no room was written. Bounded Richese auction Betrayal additionally has local CLI/runtime, authenticated SQLite and refreshed phone Use/Pass evidence in owned disposable rooms. New Guild Betrayal verification is separately Planned pending frozen direct evidence; these earlier results do not certify it. Fresh classic and paired E1/E2 Tech/Stronghold compositions have bounded runtime cases, genuine games and original CLI/phone evidence. Classic all14 Skills additionally has actual free-return/purchase/exchange and Cunning/Suk lifecycle programs, original phone controls and genuine2..6-seat games. Full module games, exceptional Duke custody, combined interactions and deployed acceptance remain separate.', evidence: ['tests/nexus-cards.test.ts', 'tests/nexus-card-engine.test.ts', 'tests/nexus-fremen-cunning.test.ts', 'tests/nexus-fremen-cunning-recovery.test.ts', 'tests/nexus-fremen-cunning-summon.test.ts', 'tests/nexus-fremen-cunning-summon-recovery.test.ts', 'tests/nexus-ecaz-betrayal-quotes.test.ts', 'tests/nexus-ecaz-betrayal.test.ts', 'tests/nexus-ecaz-betrayal-recovery.test.ts', 'tests/nexus-ecaz-inquiry.test.ts', 'tests/nexus-ecaz-duke-quote.test.ts', 'tests/nexus-ecaz-duke-engine.test.ts', 'tests/nexus-ecaz-duke-controls.test.ts', 'tests/nexus-ecaz-duke-recovery.test.ts', 'tests/nexus-traitor-recovery.test.ts', 'tests/nexus-face-dancer-engine.test.ts', 'tests/nexus-suboids-engine.test.ts', 'tests/normal-free-support.test.ts', 'tests/nexus-suboid-controls.test.ts', 'tests/nexus-advisor-controls.test.ts', 'tests/nexus-advisor-bots.test.ts', 'tests/nexus-sardaukar-controls.test.ts', 'tests/nexus-sardaukar-bots.test.ts', 'tests/nexus-choam-controls.test.ts', 'tests/nexus-choam-bots.test.ts', 'tests/nexus-moritani-controls.test.ts', 'tests/nexus-moritani-bots.test.ts', 'tests/nexus-moritani-betrayal.test.ts', 'tests/nexus-richese-controls.test.ts', 'tests/nexus-richese-bots.test.ts', 'tests/nexus-richese-betrayal-engine.test.ts', 'tests/nexus-richese-betrayal-recovery.test.ts', 'tests/nexus-guild-cunning-controls.test.ts', 'tests/nexus-guild-cunning-bots.test.ts', 'tests/nexus-module-payments-runtime.test.ts', 'tests/nexus-module-battles-runtime.test.ts', 'tests/paired-ix-nexus-modules-runtime.test.ts', 'tests/paired-choam-nexus-modules-runtime.test.ts', 'tests/classic-nexus-skills-payments-runtime.test.ts', 'tests/classic-nexus-skills-battles-runtime.test.ts', 'tests/nexus-skills-modules-payments-runtime.test.ts', 'tests/nexus-skills-modules-battles-runtime.test.ts'] },
],
},
{
@@ -4606,7 +4606,7 @@ export const RULE_TOPICS: RuleTopic[] = [
'Fresh Advanced profiles compose native Ixians, Tleilaxu, CHOAM and/or Richese with classic opponents and distinct required family decks. All fourteen skills and native starts remain. Auditor stays unskilled; cyborg casualties, original CHOAM support and Richese capped marker revelation remain physical. Foreign revival creates no new skill. Native Ixian Technology on Richese lots, own mixed No-Field, captured replacement, Advanced Atreides Suk/KH and unrelated overlays retain their guards.',
'Fresh three-through-six-seat Basic/Advanced development tables may compose all fourteen Skills with original Tech Tokens: classic factions, supported E1/E2 native families, or standalone Ecaz/Moritani with the exact ecaz deck and original roster exclusions. Starting cards/cache, skill/Traitor choices and printed/first-Storm assignment stay genuine. Existing leader-skills/banker-income entry preserves unused selected tokens; mixed E3 families, other overlays, public activation and saved-game conversion remain separate.',
'Fresh Advanced classic or supported native two-through-six-seat skill tables may retain six original Stronghold Cards, with Tech at three or more seats. Original end-Mentat/local held effects remain. Arrakeen changes actual payer cost, not rescue or Banker eligibility; native CHOAM income retains bank support. Physical defenses, normal disciplines, holder ties and original dial/Worthless earnings remain. Standalone Ecaz Duke and Moritani assassination compose original rules; mixed E3, allied Occupy skills, copied Diplomat defenses, active skill/Stone and other guards stay separate.',
'Fresh classic Leader Skills may explicitly add Nexus alone through the local leader-skills --nexus-cards entry, Basic/Advanced two through six players. Starting hands can already be dealt before skill choice; saved offers remain authoritative. Original closing Nexus draws, free-return ledgers, bank purchase and Traitor Deck declarations stay distinct from physical training. Native expansions, Tech/Strongholds/Homeworlds, Banker/Mentat previews, borrowed Smuggler shipment arithmetic and other unresolved interactions remain separate.',
'Fresh classic Leader Skills may explicitly add Nexus through local leader-skills --nexus-cards, Basic/Advanced two through six players, retaining selected original Tech at three or more seats and/or Advanced Strongholds. Saved hands/offers remain authoritative; actual closing draws remain required. Free-return ledgers, bank purchase and Traitor Deck declarations stay distinct from training. Original phase-end industry, held payer support/physical defenses, physical Suk rescue and subsequent mandatory winner Tech rewards retain their own timing. Homeworlds, native factions with these combined components, Banker/Mentat previews, borrowed Smuggler arithmetic and unresolved interactions remain separate.',
'The original paired Ixian/Tleilaxu or CHOAM/Richese native skill roster may also add Nexus alone through that explicit fresh local entry, with classics and one original family deck, Basic/Advanced two through six players. Full unsupported Suboids retain Cyborg support and skill posture. Suk physical rescue finishes before equal substitution of only actual Cyborg Tank losses; Face Dance then returns a killed trainer skill once without another bounty. Richese Cunning preserves its signed two-marker/one-invoice operation; ordinary skill marker proofs and companion exclusions remain separate. CHOAM Special fuel is discarded before an ordinary Planetologist move, without a second card effect or created combat Special.',
'With this optional module, starting Treachery Cards are dealt after prediction and before skill assignment. Every faction privately receives two skills, keeps one, returns the other to the shuffled deck, and assigns its chosen card to an eligible leader. Skill and leader become public before traitor selection.',
'Before Battle Plans, leave the skilled leader face up to keep its normal effect, or move it behind the shield for possible use. A face-up leader cannot be selected for the plan. Concealing it while choosing another leader gives neither effect. A leader that must be used because no alternative remains moves behind the shield automatically.',