Compose Advanced native Ixian and CHOAM Leader Skills

This commit is contained in:
Quintine committed 2026-10-03 13:06:44 +10:00
1 parent 64c8dfc770
commit 7ee064df14
20 files changed
+723 -71

No files matched your search

+2 -2
View File
@@ -1,4 +1,4 @@
import { basicExpansionLeaderSkillsProfile, noOtherLeaderSkillModules, type LeaderSkillProfile } from './leader-skill-profile';
import { nativeExpansionLeaderSkillsProfile, noOtherLeaderSkillModules, 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') ||
basicExpansionLeaderSkillsProfile(game));
nativeExpansionLeaderSkillsProfile(game));
}
export function bureaucratUsed(
used: readonly BureaucratPaymentUse[],
+7 -7
View File
@@ -1,4 +1,4 @@
import { basicExpansionLeaderSkillsProfile, ordinaryLeaderSkillModeSupported } from './leader-skill-profile';
import { nativeExpansionLeaderSkillsProfile, ordinaryLeaderSkillModeSupported } 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';
@@ -7778,7 +7778,7 @@ function bankerIncomeProfile(g: Game): boolean {
return g.players.length >= 2 && g.players.length <= 6 &&
new Set(g.players.map(p => p.faction)).size === g.players.length &&
((!g.expansions.length && g.players.every(p => FACTIONS.some(f => f.id === p.faction && f.expansion === 'base'))) ||
basicExpansionLeaderSkillsProfile(g)) &&
nativeExpansionLeaderSkillsProfile(g)) &&
!g.nexusCards && !g.homeworlds && !g.techTokens &&
!g.strongholdCards && !g.discoveryEnabled && !g.discoveries && !g.discoveryStash &&
!g.greatMaker && !g.ecazTreachery && !g.semutaPreview && !g.mentatQuestionPreview &&
@@ -9302,13 +9302,13 @@ export function initializeLeaderSkillsGameForAudit(state: Game): Game {
const g = structuredClone(state);
g.leaderSkills = createLeaderSkills(random);
return initializeSetupGameForAudit(g, false, false, false, false, true,
g.expansions.length === 1 && g.expansions[0] === 'choam', basicExpansionLeaderSkillsProfile(g));
g.expansions.length === 1 && g.expansions[0] === 'choam', nativeExpansionLeaderSkillsProfile(g));
}
/** Fresh all-fourteen-card classic or Basic native skills; no public income toggle. */
/** Fresh all-fourteen-card classic or supported native skills; no public income toggle. */
export function initializeSpiceBankerIncomeGameForAudit(state: Game): Game {
requireRule(bankerIncomeProfile(state) && !state.leaderSkills &&
!state.spiceBankerIncomePreview && state.spiceBankerIncome === undefined,
'Spice Banker income requires a fresh classic or supported Basic native lobby with Leader Skills alone.');
'Spice Banker income requires a fresh classic or supported native lobby with Leader Skills alone.');
requireFreshSetup(state, state.expansions.length > 0);
const g = structuredClone(state);
g.leaderSkills = createLeaderSkills(random);
@@ -20277,11 +20277,11 @@ function currentBattleResolutionQuote(g: Game, canceledVoter?: string) {
'Suk Graduate rescue for Advanced Atreides awaits the Kwisatz Haderach loss-count ruling.');
if (quote.sukGraduate) requireRule(
ordinaryLeaderSkillModeSupported(g) &&
(basicExpansionLeaderSkillsProfile(g) || g.players.every((p) => faction(p.faction).expansion === 'base')),
(nativeExpansionLeaderSkillsProfile(g) || g.players.every((p) => faction(p.faction).expansion === 'base')),
'Suk Graduate rescue with expansion factions or other optional modules is still being implemented.');
if (quote.rihani || quote.sandmaster) requireRule(
ordinaryLeaderSkillModeSupported(g) &&
(basicExpansionLeaderSkillsProfile(g) || g.players.every((p) => faction(p.faction).expansion === 'base')),
(nativeExpansionLeaderSkillsProfile(g) || g.players.every((p) => faction(p.faction).expansion === 'base')),
'These Leader Skill victory effects with expansion factions or other optional modules are still being integrated.');
const smuggler = b.smugglerCollection ? nexusRule(() => settleSmugglerBattle(b.smugglerCollection!,
!(b.smugglerCollection!.player === b.attacker ? quote.leaderDeaths.attacker : quote.leaderDeaths.defender), g.spice)) : null;
+47 -1
View File
@@ -12,6 +12,16 @@ export type LeaderSkillProfile = {
strongholdCards?: unknown;
techTokens?: unknown;
ecazTreachery?: unknown;
semutaPreview?: unknown;
moritaniAssassinatePreview?: unknown;
advancedPreview?: unknown;
kullPreview?: unknown;
nexusKullPreview?: unknown;
guildBetrayalPreview?: unknown;
richeseBetrayalPreview?: unknown;
nexusIxianReplacementPreview?: unknown;
nexusIxianBetrayalPreview?: unknown;
nexusHarkonnenBetrayalPreview?: unknown;
};
export function noOtherLeaderSkillModules(game: LeaderSkillProfile): boolean {
@@ -60,8 +70,44 @@ export function basicExpansionLeaderSkillsProfile(game: LeaderSkillProfile): boo
basicIxLeaderSkillsProfile(game) || basicChoamLeaderSkillsProfile(game);
}
/** Source-clear Advanced native factions; optional decks never imply a seated faction. */
export function advancedNativeLeaderSkillsProfile(game: LeaderSkillProfile): boolean {
const players = game.players;
if (game.advanced !== true || !players || players.length < 2 || players.length > 6 ||
game.expansions.length < 1 || game.expansions.length > 2 ||
(game.expansions.length === 2 && game.expansions[0] === game.expansions[1]) ||
!noOtherLeaderSkillModules(game) ||
game.semutaPreview || game.moritaniAssassinatePreview || game.advancedPreview ||
game.kullPreview || game.nexusKullPreview ||
game.guildBetrayalPreview || game.richeseBetrayalPreview ||
game.nexusIxianReplacementPreview || game.nexusIxianBetrayalPreview ||
game.nexusHarkonnenBetrayalPreview) return false;
for (const expansion of game.expansions)
if (expansion !== 'ix' && expansion !== 'choam') return false;
let native = false;
for (let i = 0; i < players.length; i++) {
const player = players[i];
// Six seats at most: check prior seats without allocating per-rule quote sets.
for (let j = 0; j < i; j++) if (players[j].faction === player.faction) return false;
if (player.faction === 'ixians' || player.faction === 'choam') {
if (!game.expansions.includes(player.faction === 'ixians' ? 'ix' : 'choam')) return false;
native = true;
} else {
let classic = false;
for (const faction of FACTIONS)
if (faction.id === player.faction && faction.expansion === 'base') { classic = true; break; }
if (!classic) return false;
}
}
return native;
}
export function nativeExpansionLeaderSkillsProfile(game: LeaderSkillProfile): boolean {
return basicExpansionLeaderSkillsProfile(game) || advancedNativeLeaderSkillsProfile(game);
}
/** Shared by rule quotes, controls and minimal legal bot participation. */
export function ordinaryLeaderSkillModeSupported(game: LeaderSkillProfile): boolean {
return noOtherLeaderSkillModules(game) &&
(!game.expansions.length || basicExpansionLeaderSkillsProfile(game));
(!game.expansions.length || nativeExpansionLeaderSkillsProfile(game));
}
+2 -2
View File
@@ -1,7 +1,7 @@
import { treacheryDeck, type Card } from './cards';
import { richeseCards } from './richese-cards';
import { quoteTupileIntelligenceAnswer } from './tupile-intelligence-answer';
import {basicExpansionLeaderSkillsProfile,noOtherLeaderSkillModules,type LeaderSkillProfile} from './leader-skill-profile';
import {nativeExpansionLeaderSkillsProfile,noOtherLeaderSkillModules,type LeaderSkillProfile} from './leader-skill-profile';
export class MentatQuestionError extends Error {}
export const MENTAT_EMPTY_HAND =
@@ -43,7 +43,7 @@ export function mentatQuestionModeSupported(game: LeaderSkillProfile): boolean {
return noOtherLeaderSkillModules(game) &&
(!game.expansions.length ||
(game.expansions.length === 1 && game.expansions[0] === 'choam') ||
basicExpansionLeaderSkillsProfile(game));
nativeExpansionLeaderSkillsProfile(game));
}
function inventory(expansions: readonly string[]): Card[] {
return [
+3 -3
View File
@@ -1,5 +1,5 @@
import { FACTIONS } from './catalog';
import { basicExpansionLeaderSkillsProfile } from './leader-skill-profile';
import { nativeExpansionLeaderSkillsProfile } from './leader-skill-profile';
import type { Game, GameView } from './engine';
import { splitLocation } from './board';
@@ -66,8 +66,8 @@ export function groundMovementRange(
return planetologistRange(base + (options.choamBonus ?? 0), mode);
}
/** Keep the existing base-roster boundary and add the connected Basic Moritani profile. */
/** Keep the existing classic-roster boundary and add supported native factions. */
export function planetologistMovementModeSupported(game: Game | GameView): boolean {
return game.players.every(player => FACTIONS.some(f => f.id === player.faction && f.expansion === 'base')) ||
basicExpansionLeaderSkillsProfile(game);
nativeExpansionLeaderSkillsProfile(game);
}
+11 -10
View File
@@ -4412,13 +4412,13 @@ export const RULE_TOPICS: RuleTopic[] = [
category: 'Advanced & expansions',
coverage: 'Partial',
developmentStage: 'Prototyped',
summary: 'Basic CHOAM connects ordinary skill actions and private revival choices during a suspended sale.',
summary: 'Native CHOAM connects full-deck skill actions, Basic suspended-sale revival and bounded Advanced support and aftermath.',
steps: [
'This development combination uses Basic CHOAM and base opponents, the full fourteen-skill deck and no other optional modules. Starting cards precede skills and Traitors. Its 35-card Treachery deck includes Poison Tooth and Artillery; neither is a green Special. Auditor belongs to Advanced and cannot receive a skill.',
'Connected movement, shipping, payment and battle skills share their normal controls and legal choices. CHOAM cannot spend a card already committed to a sale or sell a Special already discarded after Planetologist battle use.',
'Ghola may revive an eligible own leader while a declared sale waits. Finish the spent Ghola, optional private replacement draw or decline, and any required assignment before the original sale resumes. The replacement belongs to the actual revived leader.',
'The sale resumes with its original card, price and response passes. Canceling that sale preserves the completed free revival and does not return the spent Ghola.',
'Advanced Auditor, Richese and further combinations retain separate implementation boundaries. Remaining skill effects are unfinished; this prototype does not certify complete expansion rules or AI strength.',
'Fresh Advanced CHOAM and/or Ixians plus classic tables use distinct required family decks and all fourteen skills. Auditor is excluded both at assignment and paid revival; original support income and bank-held allied funding remain distinct. Richese and further optional combinations retain separate boundaries. Remaining skill effects are unfinished; this prototype does not certify complete expansion rules or AI strength.',
],
related: ['leader-skills', 'choam-modules', 'implementation-checklist'],
checklist: [
@@ -4435,9 +4435,9 @@ export const RULE_TOPICS: RuleTopic[] = [
category: 'Advanced & expansions',
coverage: 'Partial',
developmentStage: 'Prototyped',
summary: 'Basic Ixians connect the full skill deck to cyborg movement, the HMS and battle aftermath.',
summary: 'Native Ixians connect the full skill deck to cyborg movement, the HMS and Basic or bounded Advanced battle aftermath.',
steps: [
'The private starting-card choice precedes the full skill deal, Traitors and real first-Storm HMS placement. Basic Ixians can share this development combination with Tleilaxu and base factions; other optional modules and Advanced remain unavailable.',
'The private starting-card choice precedes the full skill deal, Traitors and real first-Storm HMS placement. Basic Ixians retain Tleilaxu and base combinations. Fresh Advanced Ixians and/or CHOAM plus classic tables use distinct required family decks; unrelated optional overlays and foreign gholas remain guarded.',
'Planetologist calculates each gathered origin separately using its selected cyborgs. Canceling native cyborg movement leaves the independent skill range available. Sandmaster routes can enter or leave the HMS through its current pointer.',
'Suk Graduate rescues finish before substitution. Select the original sectors of rescued cyborgs where needed; only cyborgs actually sent to the Tanks can return through substitution. Rihani also finishes before native substitution.',
'Planetologist may substitute the green Thumper, Harvester or Amal in its weapon role. Their normal effects do not execute, and mandatory disposal still follows allowed, declined or canceled substitution.',
@@ -4505,7 +4505,7 @@ export const RULE_TOPICS: RuleTopic[] = [
summary: 'The fresh banker-income preview gains one deferred spice once per phase when another player makes one qualifying payment to the Spice Bank, then collects automatically at native Mentat.',
searchText: 'Spice Banker normal income bank payment four spice phase deferred front shield original owner death capture Mentat',
steps: [
'This separate fresh local profile admits unique two-to-six classic factions in Basic or Advanced with the base deck, or supported Basic Ixian/Tleilaxu/CHOAM/Moritani skill rosters with their single required deck. All fourteen skills and native setup remain. Advanced native rosters, mixed families, Nexus, Homeworld, Discovery, Tech Tokens and other overlays stay guarded; no public start or old-game retrofit.',
'This separate fresh local profile admits unique two-to-six classic factions in Basic or Advanced with the base deck, supported Basic Ixian/Tleilaxu/CHOAM/Moritani skill rosters with their single required deck, or bounded Advanced native Ixians and/or CHOAM plus classic seats with distinct required family decks. All fourteen skills and native setup remain. Foreign gholas, unrelated native families, Nexus, Homeworld, Discovery, Tech Tokens and other overlays stay guarded; no public start or old-game retrofit.',
'The printed normal band is mandatory once per phase: when another player makes a payment of at least four spice to the Spice Bank, gain one spice and place it in front of the shield. It is an additional bank grant, not a reduction of the payer’s payment or another player’s income.',
'Only an actual completed positive bank payment qualifies. A payment to a player, zero/free/waived cost, self-payment, invalid declaration or unfinished possible payment supplies no income. Several smaller payments do not combine to reach four.',
'Use the original actual bank portion after recipient and counter settlement, not a quoted fee or guessed wallet change. Paid auctions, funded shipments, paid revival and eligible resolved battle support keep their native continuation once. Canceled Emperor, Guild or Tleilaxu revival income can leave a real bank payment. Tleilaxu self-revival pays the Bank; other-player revival normally pays Tleilaxu. Its separate free-revival bank award is not payer debit: three paid plus that one reward never becomes four paid to the Bank. A stopped shipment supplies no payment.',
@@ -4520,7 +4520,7 @@ export const RULE_TOPICS: RuleTopic[] = [
],
related: ['leader-skills', 'battle', 'bidding', 'revival', 'implementation-checklist'],
checklist: [
{ area: 'Implementation', status: 'Implemented', detail: 'Actual final bank payer legs, native skill eligibility, one physical-card phase grant and original-owner automatic Mentat collection connect through fresh classic and supported Basic native skill profiles. Tleilaxu self-revival and canceled revival income preserve actual payer cost separately from the free award.', evidence: ['game/engine.ts', 'game/spice-banker-income.ts'] },
{ area: 'Implementation', status: 'Implemented', detail: 'Actual final bank payer legs, native skill eligibility, one physical Banker phase grant and original-owner automatic Mentat collection connect through fresh classic, supported Basic native and bounded Advanced Ixian/CHOAM skill profiles. Tleilaxu self-revival and canceled revival income preserve actual payer cost separately from the free award.', evidence: ['game/engine.ts', 'game/spice-banker-income.ts'] },
{ area: 'Player controls', status: 'Implemented', detail: 'A full-width read-only public front-shield notice explains unavailable spice and automatic collection; genuine original payment and final Collection controls work at 390px through refresh. No new income action or confirmation.', evidence: ['components/spice-banker-income.tsx', 'components/game-table.tsx'] },
{ area: 'AI', status: 'Partial', detail: 'All four minimal legal policies preserve identical available-budget actions with deferred income present or absent. Original wallets exclude front-shield currency; strategy/calibration remain deferred.', evidence: ['game/bots.ts', 'game/spice-banker.ts'] },
{ area: 'Documentation', status: 'Partial', detail: 'Printed gain/threshold/one-payment/phase/collection, original payment separation, provisional earned custody and per-payer split composition are explicit without universal rulings.', evidence: ['docs/LEADER_SKILLS_RULES.md', 'docs/SPICE_BANKER_RUNTIME.md', 'docs/RULE_DECISIONS.md'] },
@@ -4536,6 +4536,7 @@ export const RULE_TOPICS: RuleTopic[] = [
summary: 'Fourteen physical skills, private assignment choices, five battle disciplines, Planetologist movement/battle effects and Suk Graduate rescues, Mentat/Bureaucrat scoring and Bureaucrat payment redirection, Sandmaster victory spice, Rihani exchanges, optional Smuggler shipping and unmodified battle collection, Sandmaster route and worm-ride collection, sealed Spice Banker battle spending and optional Diplomat base-defense copying in development tables. Other effects and combined-module acceptance remain unfinished.',
steps: [
'A development profile also connects Basic Moritani with base opponents and no other optional modules. It keeps the full deck and existing unfinished-effect boundaries; see Moritani with Leader Skills.',
'Fresh Advanced development profiles now compose native Ixians and/or CHOAM with classic opponents, two through six unique seats and their distinct required Ix/CHOAM decks. All fourteen skills and original native starting choices remain. Auditor never receives a skill. Typed cyborg support flows through Suk rescue before native substitution; CHOAM keeps original payer/income and Smuggler-before-Collection order. Existing Basic entries are unchanged; foreign gholas, captured replacement, Advanced Atreides Suk/KH and unrelated overlays remain guarded.',
'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.',
'Warmaster, Master of Assassins, Swordmaster of Ginaz, Killer Medic and Prana-Bindu Adept are connected. They give another leader +1 for the matching physical card role, or the surviving assigned leader +3. These bonuses do not stack to +4. They change battle strength, not the printed disc value or leader bounty.',
@@ -4548,12 +4549,12 @@ export const RULE_TOPICS: RuleTopic[] = [
'A surviving skilled Sandmaster victory automatically adds three board spice to an existing pile in the battle territory, even with no surviving forces. Multiple piles await a placement ruling.',
'Rihani normally inspects two random Traitor Deck cards privately, then reshuffles them. A surviving selected native Rihani also offers a separate optional draw of two. Decide before seeing them: once drawn, keep one new card and publicly reveal and return one unused old card. The other new card returns secretly. A captured Rihani grants only the optional exchange. Your private history records both samples; a card just called to win is already used.',
'Smuggler can include one free accompanying force in an off-planet shipment into an empty territory. Select the entire physical total; three forces cost the ordinary price of two. The checkbox can decline this optional benefit. Guild rounding follows the free force. Richese may instead ship one separate free reserve force beside its owned No-Field into an empty territory; the marker retains its ordinary price and hidden value. Existing forces, including advisors, prevent the bonus; ordinary Fremen on-planet reinforcement has no bonus.',
'Spice Banker can commit one through three own spice with its Battle Plan, separate from force support. Only the surviving selected skilled disc gains that strength. The amount stays private until authorized plan inspection or public reveal. It is paid on win or loss, including leader death, except a sole traitor-call winner spends nothing. Normal deferred income connects only in the separate fresh classic or supported Basic native banker-income profile; ordinary/default and combined starts are unchanged.',
'Spice Banker can commit one through three own spice with its Battle Plan, separate from force support. Only the surviving selected skilled disc gains that strength. The amount stays private until authorized plan inspection or public reveal. It is paid on win or loss, including leader death, except a sole traitor-call winner spends nothing. Normal deferred income connects only in the separate fresh classic, supported Basic native or bounded Advanced Ixian/CHOAM banker-income profile; ordinary/default starts are unchanged.',
'Diplomat may use one committed Worthless card as the opponent’s base Shield or Snooper if you played no defense. After both plans reveal, choose the card or decline before traitor decisions. A native Diplomat may protect its own selected trained leader this way; a captive grants no upper effect. The chosen Worthless must be discarded afterward, even if you win. A surviving trained leader that loses a supported battle may retreat selected undialed physical counters up to its printed/copied disc strength into one empty adjacent non-stronghold territory before ordinary loser losses; modified defenses remain unfinished.',
'Mentat has an explicit private developer preview for naming a specific weapon before posture and faction powers, including supported Basic Ixian/Tleilaxu/CHOAM/Moritani skill starts. The target privately shows the named held card or chooses another held card. Weirding Way is a nameable default weapon; Chemistry is not. The card stays held and need not enter a Battle Plan. Every answer uses the same private response step; ordinary activation awaits the user’s timing-design decision. Empty hands skip without an answer. Private history is an observation, not a later hand guarantee.',
'Mentat has an explicit private developer preview for naming a specific weapon before posture and faction powers, including supported Basic Ixian/Tleilaxu/CHOAM/Moritani and bounded Advanced Ixian/CHOAM skill starts. The target privately shows the named held card or chooses another held card. Weirding Way is a nameable default weapon; Chemistry is not. The card stays held and need not enter a Battle Plan. Every answer uses the same private response step; ordinary activation awaits the user’s timing-design decision. Empty hands skip without an answer. Private history is an observation, not a later hand guarantee.',
'Bureaucrat may redirect two spice from a payment of at least five between two other players, once per phase. The payer still pays in full; the recipient receives two less. Declining keeps the use available for a later payment. Paid bribes qualify when transferred, with the remaining share still unavailable until Mentat Pause. Ordinary auctions, Guild income, Richese sales and actual paid Tleilaxu revival income in the Basic Tleilaxu skill profile have connected payment paths. A separate free-revival award is not part of the paid price and stays with Tleilaxu. Split funding, gifts, other payment families and combined modules remain unfinished.',
'Smuggler records the existing battle-territory spice when plans reveal, capped by the selected leader’s unmodified strength. If that leader survives, it collects automatically even when losing or no forces remain. A captive pays its controller. Pending spice cannot fund the plan. Collection precedes Sandmaster’s addition; a drained pile receives none. Modified strength, multiple positive piles and combined modules remain guarded. Older saved battles keep their original behavior.',
'Other special Sandmaster relocation remains missing. Normal Banker income has a separate fresh classic or supported Basic native source-to-Mentat preview with provisional original-earned-faction custody, not general activation. Diplomat retreat uses a documented conservative outcome-order interpretation in standalone Leader Skills play. Foreign gholas, Face Dancers and combined modules remain unfinished. This development prototype does not enable public module starts.',
'Other special Sandmaster relocation remains missing. Normal Banker income has a separate fresh classic, supported Basic native or bounded Advanced Ixian/CHOAM source-to-Mentat preview with provisional original-earned-faction custody, not general activation. Diplomat retreat uses a documented conservative outcome-order interpretation in standalone Leader Skills play. Foreign gholas, Face Dancers and combined modules remain unfinished. This development prototype does not enable public module starts.',
...LEADER_SKILL_CARDS.map(card => `${card.name}. Normal: ${card.normal.join(' ')} Skilled battle: ${card.battle.join(' ')}`),
],
related: ['spice-banker-income', 'choam-leader-skills', 'ixian-leader-skills', 'tleilaxu-leader-skills', 'moritani-leader-skills', 'setup','choam-modules','implementation-checklist'],
@@ -4562,7 +4563,7 @@ export const RULE_TOPICS: RuleTopic[] = [
{ area:'Player controls',status:'Partial',detail:'Private card/leader selection, readable inspectors, public battle posture and revival draw/decline, Planetologist range/gather controls, Special weapon selection and Suk Graduate physical rescue choices are connected. Rihani has private history and separate keep-new/reveal-old controls; automatic battle effects need no confirmation. Smuggler has explicit ordinary shipping opt-out and No-Field companion opt-in with physical-versus-priced force counts, plus automatic surviving-leader battle collection with reveal-time guidance. Banker exposes separate sealed spending and authorized inspection. Sandmaster exposes explicit legal routes, per-territory collection choices and an optional worm-destination checkbox. Diplomat offers a named committed Worthless choice or decline after public reveal, and a separate surviving-loser destination/normal/elite retreat or decline. Bureaucrat offers redirect or full payment with explicit recipient amounts and deferred bribe custody. Remaining effect controls are missing.',evidence:['components/leader-skills.tsx','components/planetologist-movement.tsx','components/suk-graduate.tsx','components/rihani-decipherer.tsx','components/mentat-question.tsx','components/bureaucrat-payment.tsx','components/leader-skill-battle-guide.tsx','components/smuggler-shipment.tsx','components/spice-banker.tsx','components/sandmaster-movement.tsx','components/sandmaster-worm.tsx','components/diplomat-defense.tsx','components/diplomat-retreat.tsx','components/game-table.tsx'] },
{ area:'AI',status:'Partial',detail:'All four profiles use private offers, legal visibility/revival actions and Planetologist movement/battle candidates and legal Suk Graduate rescues, Rihani exchanges, shared battle scoring, Smuggler reserve/owned No-Field shipments and unmodified collection plans, Sandmaster route and worm collection, funded Banker commitments and optional Diplomat copying from public revealed defenses or choosing legal losing-battle retreat. Bureaucrat uses the public payee alliance to redirect enemy income or preserve allied income. These are legal prototype paths; complete skill strategy and difficulty calibration remain unfinished.',evidence:['game/bots.ts'] },
{ area:'Documentation',status:'Partial',detail:'All fourteen faces and common rules are recorded. Skilled capture follows public physical-card custody; replacement entitlement and other material timing interpretations remain explicit.',evidence:['docs/LEADER_SKILLS_RULES.md','docs/LEADER_SKILLS_CAPTURE.md','docs/LEADER_SKILLS_RUNTIME.md','docs/PLANETOLOGIST_RULES.md','docs/SUK_GRADUATE_RULES.md','docs/LEADER_BATTLE_EFFECTS.md','docs/MENTAT_QUESTION.md','docs/BUREAUCRAT_PAYMENTS.md','docs/SMUGGLER_SHIPMENT.md','docs/SPICE_BANKER_RUNTIME.md','docs/SANDMASTER_WORM.md','docs/DIPLOMAT_DEFENSE.md'] },
{ area:'Verification',status:'Partial',detail:'Focused inventory, scoring, Voice, capture, saved private setup/revival Planetologist movement/cancellation and Suk Graduate casualty/SQLite checks, plus Rihani privacy/concurrent recovery battle-effect regressions and Smuggler shipment and battle collection, losing/captured survival, Sandmaster order, explosion, legacy and concurrent recovery, and Banker funding, death, traitor, privacy and concurrent settlement checks cover this boundary. Diplomat checks cover self-protection, mandatory discard, public-choice privacy, concurrent saved decisions, legacy continuation, losing-battle ordinary/elite retreat and concurrent saved force custody. Bureaucrat checks cover once-per-phase use, private source receipts and resumed payment custody. Sandmaster worm checks cover typed forces, decline, saved arrival reactions, concurrent writes, repeated distinct rides and special-Karama origin. Sample games and browser continuation are recorded separately; full module acceptance remains open.',evidence:['tests/leader-skills-engine.test.ts','tests/leader-skills-capture.test.ts','tests/leader-skills-recovery.test.ts','tests/leader-skills-controls.test.ts','tests/suk-graduate.test.ts','tests/suk-graduate-recovery.test.ts','tests/leader-battle-effects.test.ts','tests/leader-battle-effects-recovery.test.ts','tests/leader-battle-effects-controls.test.tsx','tests/mentat-question.test.ts','tests/mentat-question-bots.test.ts','tests/mentat-question-controls.test.tsx','tests/mentat-question-recovery.test.ts','tests/bureaucrat-payment.test.ts','tests/bureaucrat-payment-controls.test.tsx','tests/bureaucrat-payment-bots.test.ts','tests/bureaucrat-payment-recovery.test.ts','tests/smuggler-battle.test.ts','tests/smuggler-battle-recovery.test.ts','tests/smuggler-shipment.test.ts','tests/smuggler-shipment-controls.test.tsx','tests/smuggler-shipment-recovery.test.ts','tests/smuggler-no-field.test.ts','tests/smuggler-no-field-controls.test.tsx','tests/smuggler-no-field-recovery.test.ts','tests/spice-banker.test.ts','tests/spice-banker-recovery.test.ts','tests/spice-banker-controls.test.tsx','tests/sandmaster-movement.test.ts','tests/sandmaster-movement-recovery.test.ts','tests/sandmaster-movement-controls.test.tsx','tests/sandmaster-worm.test.ts','tests/sandmaster-worm-controls.test.tsx','tests/sandmaster-worm-recovery.test.ts','tests/diplomat-defense.test.ts','tests/diplomat-defense-controls.test.tsx','tests/diplomat-defense-recovery.test.ts','tests/diplomat-retreat-engine.test.ts','tests/diplomat-retreat-controls.test.tsx','tests/diplomat-retreat-recovery.test.ts'] },
{ area:'Verification',status:'Partial',detail:'Existing role, custody, privacy, saved-continuation and physical-effect regressions cover the bounded standalone paths, not full module acceptance. Advanced Ixian/CHOAM composition adds affected122/122, types/lint/build, ten controlled actual native programs and three genuine CLI games (511 accepted actions, no rejection, twelve JSON continuations). Native games contained no battles; controlled programs and390px ARRHUS7Z v20 prove typed support, mixed Suk rescue and original substitution into Collection. Original KFW75TCB v6 retains genuine CLI setup. Comprehensive assurance follows all rules; no full-module or deployed claim.',evidence:['tests/leader-skills-engine.test.ts','tests/leader-skills-capture.test.ts','tests/leader-battle-effects.test.ts','tests/suk-graduate.test.ts','tests/mentat-question.test.ts','tests/bureaucrat-payment.test.ts','tests/smuggler-battle.test.ts','tests/spice-banker.test.ts','tests/advanced-native-skills.test.ts','tests/fixture-advanced-native-skills.ts','docs/LEADER_SKILLS_RUNTIME.md'] },
],
},
{
+2 -2
View File
@@ -1,7 +1,7 @@
import type { Game, GameView } from './engine';
import { splitLocation, validGameLocation } from './board';
import { faction } from './catalog';
import { basicExpansionLeaderSkillsProfile } from './leader-skill-profile';
import { nativeExpansionLeaderSkillsProfile } from './leader-skill-profile';
import { sandmasterLeader, sandmasterModeSupported } from './sandmaster-movement';
export type SandmasterWormCollection = {
@@ -26,7 +26,7 @@ export function sandmasterWormCollection(
const blocked = (reason: string): SandmasterWormCollection =>
({ leader, key: null, before: 0, blocked: reason });
if (!sandmasterModeSupported(game) || game.ecazTreachery ||
!(basicExpansionLeaderSkillsProfile(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.');
if (destination === decision.territory ||
+2 -2
View File
@@ -1,5 +1,5 @@
import { FACTIONS } from './catalog';
import { basicExpansionLeaderSkillsProfile, ordinaryLeaderSkillModeSupported, type LeaderSkillProfile } from './leader-skill-profile';
import { nativeExpansionLeaderSkillsProfile, ordinaryLeaderSkillModeSupported, type LeaderSkillProfile } from './leader-skill-profile';
import type { Card, Leader } from './cards';
import { splitLocation, validGameLocation } from './board';
import { leaderSkillBattleBonus, usesSurvivingSkilledLeader, type BattleLeaderSkill } from './leader-skill-combat';
@@ -11,7 +11,7 @@ export type SmugglerBattleReceipt = {
};
export function smugglerBattleModeSupported(g: LeaderSkillProfile & { players: readonly { faction: string }[] }) {
return ordinaryLeaderSkillModeSupported(g) &&
(basicExpansionLeaderSkillsProfile(g) || g.players.every(p => FACTIONS.some(f => f.id === p.faction && f.expansion === 'base')));
(nativeExpansionLeaderSkillsProfile(g) || g.players.every(p => FACTIONS.some(f => f.id === p.faction && f.expansion === 'base')));
}
export type SmugglerBattlePlan = {
assignments: readonly BattleLeaderSkill[];