Compose native Ix and CHOAM Skills with independent Treachery Cards

This commit is contained in:
Quintine committed 2026-10-17 19:29:37 +11:00
1 parent 7182502b16
commit 2ad947af54
17 files changed
+1376 -22

No files matched your search

+2 -2
View File
@@ -1,4 +1,4 @@
import { homeworldLeaderSkillsProfile, classicIndependentLeaderSkillsProfile, classicNexusLeaderSkillsProfile, classicTechLeaderSkillsProfile, guildBetrayalNexusLeaderSkillsProfile, mixedE1E2NexusLeaderSkillsProfile, mixedE3NexusLeaderSkillsProfile, nativeDiscoveryLeaderSkillsProfile, nativeExpansionLeaderSkillsProfile, nativeTechLeaderSkillsProfile, noOtherLeaderSkillModules, pairedE3NexusLeaderSkillsProfile, pairedNexusLeaderSkillsProfile, standaloneE3NexusLeaderSkillsProfile, strongholdLeaderSkillsProfile, type LeaderSkillProfile } from './leader-skill-profile';
import { homeworldLeaderSkillsProfile, independentTreacheryLeaderSkillsProfile, classicNexusLeaderSkillsProfile, classicTechLeaderSkillsProfile, guildBetrayalNexusLeaderSkillsProfile, mixedE1E2NexusLeaderSkillsProfile, mixedE3NexusLeaderSkillsProfile, nativeDiscoveryLeaderSkillsProfile, nativeExpansionLeaderSkillsProfile, nativeTechLeaderSkillsProfile, noOtherLeaderSkillModules, pairedE3NexusLeaderSkillsProfile, pairedNexusLeaderSkillsProfile, standaloneE3NexusLeaderSkillsProfile, strongholdLeaderSkillsProfile, type LeaderSkillProfile } from './leader-skill-profile';
import { classicDiscoveryLeaderSkillsProfile } from './discovery-module-profile';
export type BureaucratPaymentKind = 'auction' | 'shipment' | 'bribe' | 'revival';
export type BureaucratPaymentSource = {
@@ -40,7 +40,7 @@ export function bureaucratPaymentSignature(value: object): string {
return JSON.stringify({ ...value, signature: undefined });
}
export function bureaucratPaymentModeSupported(game: LeaderSkillProfile): boolean {
return classicIndependentLeaderSkillsProfile(game) || (!game.homeworlds && game.expansions.length === 1 &&
return independentTreacheryLeaderSkillsProfile(game) || (!game.homeworlds && game.expansions.length === 1 &&
(game.expansions[0] === 'choam' || game.expansions[0] === 'ix') &&
pairedNexusLeaderSkillsProfile(game)) ||
mixedE3NexusLeaderSkillsProfile(game) || mixedE1E2NexusLeaderSkillsProfile(game) || pairedE3NexusLeaderSkillsProfile(game) ||
+4 -4
View File
@@ -1,7 +1,7 @@
import { classicNexusModulesProfile, mixedE1E2NexusProfile, mixedE3NexusProfile, pairedE3NexusProfile, pairedNexusModulesProfile, singleE1E2NexusProfile, standaloneE3NexusProfile } from './nexus-module-profile';
import { nativeFactionTechProfile } from './faction-module-profile';
import { classicDiscoveryLeaderSkillsProfile, classicDiscoveryNexusProfile, homeworldDiscoveryProfile, discoveryModeSupported, discoveryModuleProfile, mixedE1E2DiscoveryNexusProfile, mixedE3DiscoveryNexusProfile, pairedDiscoveryNexusProfile, pairedE3DiscoveryNexusProfile, singleE1E2DiscoveryNexusProfile, standaloneE3DiscoveryNexusProfile } from './discovery-module-profile';
import { advancedMoritaniLeaderSkillsProfile, advancedNativeLeaderSkillsProfile, homeworldLeaderSkillsProfile, classicIndependentLeaderSkillsProfile, classicNexusLeaderSkillsProfile, classicTechLeaderSkillsProfile, guildBetrayalNexusLeaderSkillsProfile, mixedE1E2NexusLeaderSkillsProfile, mixedE3NexusLeaderSkillsProfile, nativeDiscoveryLeaderSkillsProfile, nativeEcazLeaderSkillsProfile, nativeExpansionLeaderSkillsProfile, nativeTechLeaderSkillsProfile, ordinaryLeaderSkillModeSupported, pairedE3NexusLeaderSkillsProfile, pairedNexusLeaderSkillsProfile, singleE1E2NexusLeaderSkillsProfile, standaloneE3NexusLeaderSkillsProfile, strongholdLeaderSkillsProfile } from './leader-skill-profile';
import { advancedMoritaniLeaderSkillsProfile, advancedNativeLeaderSkillsProfile, homeworldLeaderSkillsProfile, independentTreacheryLeaderSkillsProfile, classicNexusLeaderSkillsProfile, classicTechLeaderSkillsProfile, guildBetrayalNexusLeaderSkillsProfile, mixedE1E2NexusLeaderSkillsProfile, mixedE3NexusLeaderSkillsProfile, nativeDiscoveryLeaderSkillsProfile, nativeEcazLeaderSkillsProfile, nativeExpansionLeaderSkillsProfile, nativeTechLeaderSkillsProfile, ordinaryLeaderSkillModeSupported, pairedE3NexusLeaderSkillsProfile, pairedNexusLeaderSkillsProfile, singleE1E2NexusLeaderSkillsProfile, standaloneE3NexusLeaderSkillsProfile, strongholdLeaderSkillsProfile } from './leader-skill-profile';
import { bribeTimingBlock, maximumBribe, type BribeOptions } from './bribe-options';
import { quoteSpicePlacement, stormExposesTerritory, stormSectorAfter, wormConsumesForces } from './disaster-rules';
import { isStormCardDistance, type StormCardComponent } from './storm-cards';
@@ -10701,9 +10701,9 @@ export function initializeDiscoveryGameForAudit(state: Game): Game {
export function initializeLeaderSkillsGameForAudit(state: Game): Game {
requireRule(!state.leaderSkills, 'Leader Skills cannot redeal existing skill cards.');
const homeworlds = homeworldLeaderSkillsProfile(state);
const independent = classicIndependentLeaderSkillsProfile(state);
const independent = independentTreacheryLeaderSkillsProfile(state);
if (state.ecazTreachery) {
requireRule(independent, 'Independent Treachery with Leader Skills requires a fresh classic lobby without other modules.');
requireRule(independent, 'Independent Treachery with Leader Skills requires a fresh classic or selected Ix/CHOAM lobby without other modules.');
requireFreshBaseRuntime(state);
requireFreshFactionInventory(state);
}
@@ -13829,7 +13829,7 @@ function recruitsModeSupported(g: Game) {
return (
(!g.homeworlds || ecazHomeworldProfile(g)) &&
!g.nexusCards &&
(!g.leaderSkills || classicIndependentLeaderSkillsProfile(g)) &&
(!g.leaderSkills || independentTreacheryLeaderSkillsProfile(g)) &&
(!g.techTokens || modules) &&
(!g.strongholdCards || modules) &&
!g.discoveryEnabled
+16 -8
View File
@@ -455,7 +455,8 @@ export function advancedNativeLeaderSkillsProfile(game: LeaderSkillProfile): boo
}
export function nativeExpansionLeaderSkillsProfile(game: LeaderSkillProfile): boolean {
return mixedE3NexusLeaderSkillsProfile(game) || mixedE1E2NexusLeaderSkillsProfile(game) || pairedE3NexusLeaderSkillsProfile(game) ||
return (game.expansions.length > 0 && independentTreacheryLeaderSkillsProfile(game)) ||
mixedE3NexusLeaderSkillsProfile(game) || mixedE1E2NexusLeaderSkillsProfile(game) || pairedE3NexusLeaderSkillsProfile(game) ||
basicExpansionLeaderSkillsProfile(game) || advancedNativeLeaderSkillsProfile(game) ||
advancedMoritaniLeaderSkillsProfile(game) || nativeEcazLeaderSkillsProfile(game);
}
@@ -507,9 +508,9 @@ export function homeworldLeaderSkillsProfile(game: LeaderSkillProfile): boolean
return true;
}
/** Independent utility cards with original classic all14 setup, without other modules. */
export function classicIndependentLeaderSkillsProfile(game: LeaderSkillProfile): boolean {
if (game.ecazTreachery !== true || game.expansions.length ||
/** Independent utility cards with original classic or selected E1/E2 all14 setup. */
export function independentTreacheryLeaderSkillsProfile(game: LeaderSkillProfile): boolean {
if (game.ecazTreachery !== true || game.expansions.length > 2 ||
typeof game.advanced !== 'boolean' || !game.players ||
game.players.length < 2 || game.players.length > 6 ||
game.homeworlds || game.nexusCards || game.discoveries || game.discoveryEnabled ||
@@ -518,20 +519,27 @@ export function classicIndependentLeaderSkillsProfile(game: LeaderSkillProfile):
game.kullPreview || game.nexusKullPreview || game.guildBetrayalPreview ||
game.richeseBetrayalPreview || game.nexusIxianReplacementPreview ||
game.nexusIxianBetrayalPreview || game.nexusHarkonnenBetrayalPreview) return false;
for (let i = 0; i < game.expansions.length; i++) {
if (game.expansions[i] !== 'ix' && game.expansions[i] !== 'choam') return false;
for (let j = 0; j < i; j++) if (game.expansions[j] === game.expansions[i]) 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;
let classic = false;
let selected = false;
for (const faction of FACTIONS)
if (faction.id === players[i].faction) { classic = faction.expansion === 'base'; break; }
if (!classic) return false;
if (faction.id === players[i].faction) {
selected = faction.expansion === 'base' || game.expansions.includes(faction.expansion);
break;
}
if (!selected) return false;
}
return true;
}
/** Shared by rule quotes, controls and minimal legal bot participation. */
export function ordinaryLeaderSkillModeSupported(game: LeaderSkillProfile): boolean {
return classicIndependentLeaderSkillsProfile(game) || (noOtherLeaderSkillModules(game) &&
return independentTreacheryLeaderSkillsProfile(game) || (noOtherLeaderSkillModules(game) &&
(!game.expansions.length || nativeExpansionLeaderSkillsProfile(game) ||
(game.expansions.length === 1 && game.expansions[0] === 'choam'))) ||
classicTechLeaderSkillsProfile(game) || nativeTechLeaderSkillsProfile(game) ||
+4
View File
@@ -4931,6 +4931,7 @@ export const RULE_TOPICS: RuleTopic[] = [
'Explicit guild-betrayal --leader-skills retains the original classic native-Guild Nexus profile without Homeworlds, Tech, Strongholds, Discovery, Semuta or other overlays. All14 training remains native. Ordinary skill quotes now admit the composition, restoring actual Mentat private questions before posture and Sandmaster ground collection rather than only enabling Bureaucrat. Native card custody, paid forces, original Betrayal Use/Pass and movement/plan continuation stay unchanged. Other combinations and complete-mode acceptance remain separate.',
'Basic Moritani retains base opponents including Harkonnen. Its separate bounded Advanced classic/non-Harkonnen roster now composes the original assassination preview and all fourteen skills: winner Suk rescue and Rihani choice finish first, then an eligible different trained disc may be assassinated with its exact card return and printed bounty. No casualties repeat; original set-aside and one private Mentat replacement remain. See Moritani with Leader Skills for the exact scope.',
'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. Supplied Advanced p34 excludes Richese auctions from Ixian Technology; own mixed No-Field, captured replacement, Advanced Atreides Suk/KH and unrelated overlays retain their guards.',
'The independent Recruits, Reinforcements and Harass & Withdraw cards may be selected with all fourteen Skills in fresh classic or selected Ix/CHOAM native/base Basic/Advanced games, without other modules. Original36/38/50 ordinary decks, any separate Richese cache, native setup, free-revival exceptions and paid Cyborg prices stay. Native typed fee/withdrawal/Suk outcomes and ordinary Smuggler, Planetologist and Sandmaster capabilities use one shared admission; the card variant does not silently remove those skills. Other faction/module combinations retain their explicit 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/Arrakis coalition and Moritani assassination compose original rules; mixed E3, exceptional copied defenses, active skill/Stone and other guards stay 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. --discoveries additionally composes original Discovery7/8 in this classic profile. Saved hands/offers remain authoritative; the actual end-Spice closing draw follows Maker votes/typed rides, both Advanced piles and settled alliance. 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, Banker/Mentat previews, borrowed Smuggler arithmetic and unresolved interactions remain separate.',
@@ -4984,6 +4985,7 @@ export const RULE_TOPICS: RuleTopic[] = [
'Clean classic2–6 Basic/Advanced Homeworlds compose through the fresh independent36-card setup. Double current native free rates including low-population bonuses, within the seven-force total. Provisionally recheck population and recorded free use on each separate request: low Fremen may take7 together, but1 crossing high leaves5 further free and cannot buy a seventh without Tleilaxu. Original typed destinations and special-force limits stay. Other overlays/rosters, public activation and whole-mode acceptance remain unfinished.',
'Classic or selected Ix/CHOAM native/base rosters, including Homeworlds, may retain original unused Tech Tokens3–6 and/or Stronghold Cards2–6 Advanced. Setup, first-Storm Tech and actual end-Mentat custody remain original. Recruits changes current native free rates, not the once-per-phase Axlotl trigger/delayed payout. Harass returns are not free Revival.',
'Selected Ix/CHOAM native/base Basic/Advanced Worlds use original38/50 independent-card setup with optional original phase modules. Current native bonuses, typed deposits and accepted paid/free classifications stay. Ix keeps its multiple-Cyborg allowance; Tleilaxu and CHOAM remain unlimited rather than being reduced to seven. Other card/overlay/public-start gates remain.',
'Fresh classic or selected Ix/CHOAM games may combine these three cards with all fourteen Leader Skills, without other modules. The current native free allowance is still doubled after prior recorded use. An Ix revival keeps its paid Cyborg surcharge and any Tleilaxu recipient; native CHOAM/Tleilaxu limits are not reduced to seven. No separate skill or native revival ledger is invented.',
],
related: ['revival', 'homeworlds', 'ecaz-modules', 'expansion-faction-games', 'implementation-checklist'],
checklist: [
@@ -5010,6 +5012,7 @@ export const RULE_TOPICS: RuleTopic[] = [
'Classic and selected Ix/CHOAM Basic/Advanced Worlds retain exact native normal-first sources, sealed when ambiguous; unique sources may derive. Own-World fees cannot also fund dial/casualties; original face/support stays, including explosion thresholds. Original phase modules preserve their own prerequisites and earned custody. Native-only World Traitors, typed Tanks and fee-before-Harass stay provisional composition, not a new card FAQ.',
'One canonical physical-name registry now includes the independent cards for current facts and named battle conditions. Naming Reinforcements in a weapon slot does not make it a weapon category. Native questions use actual combat-location labels. Source-aware legal completion, private full-plan/read-only review and the fill button retain exact native sources.',
'Selected Ix/CHOAM Worlds retain original38/50 setup and native stock, optionally with original Tech3+ and Advanced Strongholds2+. Cyborg substitution and Face Dance use their actual physical pools, never a duplicate fee origin. Native Richese must retain three World reserves AFTER its own projected No-Field reveal before R seals; rejection moves no counter or marker. Original phase rewards and earned held-card support stay; admitted Stone compositions retain their separate guards.',
'With supported native Ix/CHOAM all-fourteen Skills, the same physical fee and score rules apply. Trained Suk may rescue the actual committed battle casualties, never the three reserve counters spent on this card. A native Richese marker must still leave the full fee after its own materialization; future Harass returns cannot fund a refused seal.',
],
related: ['battle-cards', 'battle', 'homeworlds', 'card-recruits', 'card-harass-withdraw', 'card-truthtrance', 'implementation-checklist'],
checklist: [
@@ -5038,6 +5041,7 @@ export const RULE_TOPICS: RuleTopic[] = [
'With an own concealed No-Field, this prototype provisionally uses the original materialization-first order. Before sealing, privately forecast its actual ordinary counters at the original marker sector; do not move them early. Both plans seal before native revelation, then any return allocation uses actual counters. Marker0 remains legal with a leader/cards, reserve shortage caps materialization, and withdrawal does not return/reset the token. Opposing successful Traitor cancels Harass, not that native reveal.',
'Classic and selected Ix/CHOAM Basic/Advanced Worlds may choose the independent cards before original setup. Harass works on Arrakis or a foreign World, never an own World. Return actual undialed board/visitor types through native custody: normal/special to the original primary World except Advanced Emperor normal to Kaitain and Sardaukar to Salusa. Original commitment stays across thresholds; native-only World Traitors/Face Dancers, late defense/explosion and disposal stay.',
'Classic or selected Ix/CHOAM native/base rosters, including Homeworlds, compose original Tech3+ and/or Advanced Strongholds2+. An earned held Stronghold affects only its original eligible plan/actual support; +2 R adds no supported counters. Harass deposits are not off-planet shipment/free Revival. Original winner card cleanup/Tech reward and native queues retain their order.',
'Supported native Ix/CHOAM all-fourteen Skills keep the same typed undialed complement and original selected-trainer effects. Ix may return both Suboids and Cyborgs, then resolve trained rescue only on the remaining committed casualties. A capped Richese marker may legally play Harass when Reinforcements is unfunded; unambiguous single-sector returns stay automatic.',
],
related: ['battle-cards', 'battle', 'card-recruits', 'homeworlds', 'ecaz-modules', 'implementation-checklist'],
checklist: [
+1 -1
View File
@@ -19,7 +19,7 @@ export function sandmasterWormCollection(
game.players.find(p => p.id === player)?.faction !== 'fremen') return null;
const blocked = (reason: string): SandmasterDestinationCollection =>
({ leader, key: null, before: 0, piles: [], blocked: reason });
if (!sandmasterModeSupported(game) || game.ecazTreachery ||
if (!sandmasterModeSupported(game) ||
!(nativeExpansionLeaderSkillsProfile(game) ||
game.players.every(p => faction(p.faction).expansion === 'base')))
return blocked('Sandmaster worm collection with other optional modules is still being integrated.');