Integrate native Banker payments and Tleilaxu Ixian Nexus replacement
This commit is contained in:
1 parent
d72f3a2172
commit
b83d75d9d3
17 files changed
+912
-46
No files matched your search
+43
-18
@@ -7747,8 +7747,9 @@ function bankerIncomeContext(g: Game): BankerIncomeContext {
|
||||
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.players.every(p => FACTIONS.some(f => f.id === p.faction && f.expansion === 'base')) &&
|
||||
g.expansions.length === 0 && !g.nexusCards && !g.homeworlds && !g.techTokens &&
|
||||
((!g.expansions.length && g.players.every(p => FACTIONS.some(f => f.id === p.faction && f.expansion === 'base'))) ||
|
||||
basicExpansionLeaderSkillsProfile(g)) &&
|
||||
!g.nexusCards && !g.homeworlds && !g.techTokens &&
|
||||
!g.strongholdCards && !g.discoveryEnabled && !g.discoveries && !g.discoveryStash &&
|
||||
!g.greatMaker && !g.ecazTreachery && !g.semutaPreview && !g.mentatQuestionPreview &&
|
||||
!g.moritaniAssassinatePreview && !g.moritaniAssassinate && !g.advancedPreview &&
|
||||
@@ -7765,7 +7766,7 @@ function spiceBankerIncomeIntegrity(g: Game): void {
|
||||
return;
|
||||
}
|
||||
requireRule(g.spiceBankerIncomePreview === true && bankerIncomeProfile(g) && !!g.leaderSkills && !!g.spiceBankerIncome,
|
||||
'The saved Spice Banker income profile lost its classic physical setup.');
|
||||
'The saved Spice Banker income profile lost its supported physical setup.');
|
||||
bankerIncomeRule(() => validateBankerIncomeState(g.spiceBankerIncome!, bankerIncomeContext(g)));
|
||||
const continuation = g.pendingTreacheryDiscard?.continuation;
|
||||
const responses = [g, g.pendingExchange, g.pendingNullentropy?.resume, g.pendingRicheseGift?.resume,
|
||||
@@ -7776,7 +7777,9 @@ function spiceBankerIncomeIntegrity(g: Game): void {
|
||||
for (const carrier of [g.currentAuctionSale, ...responses]) {
|
||||
const payment = carrier?.spiceBankerIncomePayment;
|
||||
if (!payment) {
|
||||
requireRule(!carrier || ('winner' in carrier ? carrier.free || carrier.origin !== 'normal' : carrier.kind !== 'guildIncome'),
|
||||
requireRule(!carrier || ('winner' in carrier ? carrier.free || carrier.origin !== 'normal' :
|
||||
carrier.kind !== 'guildIncome' &&
|
||||
!(carrier.kind === 'revivalIncome' && carrier.recipient !== carrier.owner && (carrier.amount ?? 0) > 1)),
|
||||
'The original paid transaction lost its native bank invoice.');
|
||||
continue;
|
||||
}
|
||||
@@ -7791,10 +7794,20 @@ function spiceBankerIncomeIntegrity(g: Game): void {
|
||||
payment.legs.reduce((sum, leg) => sum + leg.amount, 0) === carrier.amount &&
|
||||
payment.legs.every(leg => leg.payer === carrier.winner || leg.payer === getPlayer(g, carrier.winner).ally),
|
||||
'The deferred bank invoice no longer matches its original normal auction.');
|
||||
else if (carrier)
|
||||
requireRule(carrier.kind === 'guildIncome' && payment.kind === 'shipment' &&
|
||||
else if (carrier?.kind === 'guildIncome')
|
||||
requireRule(payment.kind === 'shipment' &&
|
||||
payment.legs.filter(leg => leg.recipient === 'player').reduce((sum, leg) => sum + leg.amount, 0) === carrier.amount,
|
||||
'The deferred bank invoice no longer matches its original Guild income.');
|
||||
else if (carrier) {
|
||||
const paid = payment.legs[0];
|
||||
requireRule(carrier.kind === 'revivalIncome' && payment.phase === 4 &&
|
||||
(payment.kind === 'force-revival' || payment.kind === 'leader-revival' ||
|
||||
payment.kind === 'kh-revival' || payment.kind === 'emperor-extra-revival') &&
|
||||
getPlayer(g, carrier.owner).faction === 'tleilaxu' && carrier.recipient !== carrier.owner &&
|
||||
payment.legs.length === 1 && paid.payer === carrier.recipient && paid.recipient === 'player' &&
|
||||
(carrier.amount === paid.amount || carrier.amount === paid.amount + 1),
|
||||
'The deferred bank invoice no longer matches its original paid revival.');
|
||||
}
|
||||
}
|
||||
}
|
||||
function bankerIncomePayment(g: Game, kind: BankerIncomeAuthority['kind'],
|
||||
@@ -8694,13 +8707,15 @@ function decideIxianNexusBetrayal(g: Game,id: string,action: Action): void {
|
||||
if (use) log(g,`${getPlayer(g,id).name} spent Ixian Nexus Betrayal to prevent the original native ${frame.source.kind} attempt.`);
|
||||
finishIxianNativeAttempt(g,frame.continuation,use);
|
||||
}
|
||||
/** Fresh local classic profile only; no public start or existing-game retrofit. */
|
||||
/** Fresh classic or Basic native Tleilaxu profile; no public start or retrofit. */
|
||||
export function initializeIxianNexusReplacementGameForAudit(state: Game): Game {
|
||||
requireRule(!state.nexusIxianReplacementPreview && !state.pendingNexusIxianReplacement &&
|
||||
state.nexusIxianReplacementHistory === undefined && state.nexusIxianReplacementCursor === undefined &&
|
||||
ixianNexusReplacementModeSupported(state),
|
||||
'Ixian Nexus replacement needs a fresh classic lobby with only base Treachery and Nexus cards.');
|
||||
'Ixian Nexus replacement needs a fresh classic/base or Basic Tleilaxu/Ix lobby with Nexus alone.');
|
||||
const g = initializeNexusGameForAudit(state);
|
||||
// Ix supplies Treachery here, not the optional Sandtrout Spice card.
|
||||
if (g.expansions.length) g.spiceDeck = shuffle(spiceDeck());
|
||||
g.nexusIxianReplacementPreview = true;
|
||||
g.pendingNexusIxianReplacement = null;
|
||||
g.nexusIxianReplacementHistory = [];
|
||||
@@ -8708,9 +8723,12 @@ export function initializeIxianNexusReplacementGameForAudit(state: Game): Game {
|
||||
return g;
|
||||
}
|
||||
function ixianNexusReplacementModeSupported(g: Game): boolean {
|
||||
return !!g.nexusCards && g.expansions.length === 0 && g.players.length >= 2 && g.players.length <= 6 &&
|
||||
return !!g.nexusCards && g.players.length >= 2 && g.players.length <= 6 &&
|
||||
new Set(g.players.map(p => p.faction)).size === g.players.length &&
|
||||
g.players.every(p => CLASSIC_FACTIONS[p.faction] === true) &&
|
||||
((!g.expansions.length && g.players.every(p => CLASSIC_FACTIONS[p.faction] === true)) ||
|
||||
(!g.advanced && g.expansions.length === 1 && g.expansions[0] === 'ix' &&
|
||||
g.players.some(p => p.faction === 'tleilaxu') &&
|
||||
g.players.every(p => p.faction === 'tleilaxu' || CLASSIC_FACTIONS[p.faction] === true))) &&
|
||||
!g.homeworlds && !g.leaderSkills && !g.discoveryEnabled && !g.discoveries &&
|
||||
!g.techTokens && !g.strongholdCards && !g.ecazTreachery && !g.mobileStronghold && !g.sandtrout &&
|
||||
!g.kullPreview && !g.nexusKullPreview && !g.semutaPreview && !g.richeseBetrayalPreview &&
|
||||
@@ -9256,17 +9274,18 @@ export function initializeLeaderSkillsGameForAudit(state: Game): Game {
|
||||
return initializeSetupGameForAudit(g, false, false, false, false, true,
|
||||
g.expansions.length === 1 && g.expansions[0] === 'choam', basicExpansionLeaderSkillsProfile(g));
|
||||
}
|
||||
/** Fresh private all-fourteen-card classic setup; no public action enables income. */
|
||||
/** Fresh all-fourteen-card classic or Basic 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 lobby, base Treachery and Leader Skills alone.');
|
||||
requireFreshSetup(state);
|
||||
'Spice Banker income requires a fresh classic or supported Basic native lobby with Leader Skills alone.');
|
||||
requireFreshSetup(state, state.expansions.length > 0);
|
||||
const g = structuredClone(state);
|
||||
g.leaderSkills = createLeaderSkills(random);
|
||||
g.spiceBankerIncomePreview = true;
|
||||
g.spiceBankerIncome = bankerIncomeRule(() => createBankerIncomeState(bankerIncomeContext(g)));
|
||||
return initializeSetupGameForAudit(g, false, false, false, false, true);
|
||||
return initializeSetupGameForAudit(g, false, false, false, false, true,
|
||||
g.expansions.length === 1 && g.expansions[0] === 'choam', g.expansions.length > 0);
|
||||
}
|
||||
/** Gated development setup for the independent three-card Ecaz variant. */
|
||||
export function initializeEcazTreacheryGameForAudit(state: Game): Game {
|
||||
@@ -21997,11 +22016,13 @@ function finishRevival(
|
||||
amount: revival.amount!, elite: revival.elite ?? 0, free: revival.free,
|
||||
})
|
||||
: null;
|
||||
payer.spice -= revival.cost;
|
||||
if (g.spiceBankerIncomePreview && !byFaction(g, 'tleilaxu')) awardBankerIncome(g, bankerIncomePayment(g,
|
||||
const incomePayment = g.spiceBankerIncomePreview && revival.cost > 0 ? bankerIncomePayment(g,
|
||||
revival.emperorExtra ? 'emperor-extra-revival' : revival.kind === 'forces' ? 'force-revival' :
|
||||
revival.kind === 'kwisatz' ? 'kh-revival' : 'leader-revival',
|
||||
[{payer: payer.id, amount: revival.cost, recipient: 'bank'}]));
|
||||
[{payer: payer.id, amount: revival.cost,
|
||||
recipient: quote.nextResponse?.kind === 'revivalIncome' && quote.nextResponse.owner !== payer.id ? 'player' : 'bank'}]) : undefined;
|
||||
payer.spice -= revival.cost;
|
||||
if (incomePayment?.legs[0]?.recipient === 'bank') awardBankerIncome(g, incomePayment);
|
||||
if (revival.kind === 'forces') {
|
||||
const n = revival.amount!,
|
||||
elite = revival.elite ?? 0;
|
||||
@@ -22074,8 +22095,11 @@ function finishRevival(
|
||||
}
|
||||
if (quote.nextResponse) {
|
||||
g.response = quote.nextResponse;
|
||||
if (quote.nextResponse.kind === 'revivalIncome')
|
||||
if (quote.nextResponse.kind === 'revivalIncome') {
|
||||
Object.assign(g.response, stampBureaucratPayment(g,'revival',payer.id,quote.nextResponse.owner,revival.cost));
|
||||
// The bank-paid free-revival award is not part of this payer's invoice.
|
||||
if (incomePayment?.legs[0]?.recipient === 'player') g.response.spiceBankerIncomePayment = incomePayment;
|
||||
}
|
||||
}
|
||||
}
|
||||
function beginRevival(g: Game, revival: PendingRevival) {
|
||||
@@ -22961,6 +22985,7 @@ function finishResponse(g: Game, canceled: boolean,bureaucratDiversion?:number)
|
||||
if (g.pendingRevival) finishRevival(g);
|
||||
} else if (response.kind === 'revivalIncome') {
|
||||
if (!canceled) getPlayer(g, response.owner).spice += response.amount! - (bureaucratDiversion ?? 0);
|
||||
awardBankerIncome(g, response.spiceBankerIncomePayment, canceled);
|
||||
if (g.pendingChoamMarketGhola && g.pendingChoamMarketGhola.event === response.intent)
|
||||
g.pendingChoamMarketGhola.stage = 'complete';
|
||||
} else if (response.kind === 'faceDancerReplacement') {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { baseDeck, type Card } from './cards';
|
||||
import { treacheryDeck, type Card } from './cards';
|
||||
|
||||
export class IxianReplacementError extends Error {}
|
||||
|
||||
@@ -52,7 +52,7 @@ export type IxianReplacementReceipt = {
|
||||
};
|
||||
|
||||
const canonical: Readonly<Record<string, Card>> =
|
||||
Object.fromEntries(baseDeck().map(card => [card.id, card]));
|
||||
Object.fromEntries(treacheryDeck(['ix']).map(card => [card.id, card]));
|
||||
const genesis = 'ixian-replacement:0';
|
||||
const plain = (value: unknown): value is Record<string, unknown> =>
|
||||
value !== null && typeof value === 'object' && !Array.isArray(value) &&
|
||||
|
||||
+9
-9
@@ -4247,7 +4247,7 @@ export const RULE_TOPICS: RuleTopic[] = [
|
||||
summary: 'In the fresh local ixian-replacement preview, an unallied holder with Ixians absent may spend the physical Ixian Nexus to discard exactly the card just bought in a normal auction and draw the next Treachery deck card privately.',
|
||||
searchText: 'Ixian Nexus Secret Ally purchased card replacement normal auction Karama full hand empty deck same card',
|
||||
steps: [
|
||||
'This is a fresh local development profile, not a public Nexus start or an upgrade to saved games. It admits two to six unique classic-faction seats in Basic or Advanced with the base Treachery deck and Nexus alone. Native Ixians, expansion factions/decks, Leader Skills, Homeworlds, Semuta, Discoveries, Ecaz variants and other optional overlays stay outside the boundary.',
|
||||
'This fresh local profile admits two-to-six unique classic-faction seats in Basic or Advanced with base Treachery, or additionally Basic Tleilaxu plus classic opponents with the original Ix47 deck and Ixians absent. Nexus alone; optional Sandtrout is omitted only in the fresh native variant. Advanced Tleilaxu, other native expansions, Leader Skills, Homeworlds, Semuta, Discoveries, Ecaz variants and other overlays remain guarded. No public start or saved-game upgrade.',
|
||||
'Nexus has no starting deal. A draw requires a qualifying closing Nexus with an alliance. A two-seat profile can continue its base game but cannot naturally create an unallied Secret Ally holder; actual replacement needs at least three seats, or four for two simultaneous unallied recipients.',
|
||||
'The photographed publisher face grants an independent Secret Ally operation when Ixians are absent. Remain unallied and hold the actual singleton Ixian Nexus. Native Ixian allied replacement is a different cancelable advantage and is not removed or used as a fallback. The adopted unofficial Advanced rulebook supplies relevant core rules, not this absent Nexus face or a new Nexus ruling.',
|
||||
'Wait for a genuine normal-auction purchase, paid with spice or through an actual printed Karama purchase, including direct printed acquisition before a positive bid. Native Bene Gesserit Worthless/Truthtrance substitutions continue unchanged without this bounded offer; that producer limit is not a ruling that they are not purchases. A Harkonnen buyer and cache, Black Market or special-purchase origins are guarded pending bonus priority and independent Nexus cache-scope rulings. A Harkonnen rival remains allowed. Gifts, bonus draws, Technology swaps and old hand cards are not eligible purchases.',
|
||||
@@ -4266,7 +4266,7 @@ export const RULE_TOPICS: RuleTopic[] = [
|
||||
{ area: 'Player controls', status: 'Partial', detail: 'Neutral Purchased card choice separates buyer-only purchased-card inspection and legal Use/Pass from public waiting; own-held Nexus inspection grants no rival entitlement. Broader presentation acceptance remains open.', evidence: ['components/nexus-ixian-replacement.tsx', 'components/game-table.tsx'] },
|
||||
{ area: 'AI', status: 'Partial', detail: 'All four minimal legal policies consume only their own projected event and eligibility while the underlying auction waits. Full strategy and difficulty calibration remain unfinished.', evidence: ['game/bots.ts'] },
|
||||
{ area: 'Documentation', status: 'Partial', detail: 'Photographed face, exact physical target, full-hand/empty-deck rules, original settlement once, privacy convention and unresolved cache/Harkonnen/priority boundaries are recorded without PDF Nexus authority or full-family claims.', evidence: ['docs/NEXUS_IXIAN_REPLACEMENT_RULES.md', 'docs/NEXUS_CARD_RULES.md', 'docs/RULE_DECISIONS.md'] },
|
||||
{ area: 'Verification', status: 'Partial', detail: 'Genuine paid/printed Karama acquisition, exact target/custody, full-hand and a captured native depleted pool cover same-card redraw, unsold-row exclusion, original ledger once, privacy, replay and four legal bots. Authenticated SQLite covers restart, races and durable rejection. Actual backed-up CLI/phone Use, Keep, takeback and refresh preserve original seats and stock. Wider modes and deployment remain open.', evidence: ['tests/nexus-ixian-replacement.test.ts', 'tests/nexus-ixian-replacement-engine.test.ts', 'tests/fixtures/nexus-ixian-native-depleted.json', 'tests/fixture-nexus-ixian-replacement.ts', 'tests/nexus-ixian-replacement-controls.test.tsx', 'tests/bot-nexus-ixian-replacement.test.ts', 'tests/nexus-ixian-replacement-recovery.test.ts', 'tests/prototype-room.test.ts', 'docs/NEXUS_IXIAN_REPLACEMENT_RULES.md'] },
|
||||
{ area: 'Verification', status: 'Partial', detail: 'Original base acquisition/full-hand/depleted-pool/native ledger and private/SQLite/phone evidence remains historical. Native Basic Tleilaxu/Ix47: four meaningful regressions, shared affected110 and final native/guide26, twelve actual card/policy programs, original CLI and390px Thumper-to-Amal/spent-Nexus/buyer3/Emperor10-to12 before phase4 opening. No new assurance campaign; full families/modules and deployment remain open.', evidence: ['tests/nexus-ixian-replacement.test.ts', 'tests/nexus-ixian-replacement-engine.test.ts', 'tests/fixtures/nexus-ixian-native-depleted.json', 'tests/fixture-nexus-ixian-replacement.ts', 'tests/fixture-native-ixian-replacement.ts', 'tests/native-ixian-replacement.test.ts', 'tests/nexus-ixian-replacement-controls.test.tsx', 'tests/bot-nexus-ixian-replacement.test.ts', 'tests/nexus-ixian-replacement-recovery.test.ts', 'tests/prototype-room.test.ts', 'docs/NEXUS_IXIAN_REPLACEMENT_RULES.md'] },
|
||||
],
|
||||
},
|
||||
{
|
||||
@@ -4501,10 +4501,10 @@ 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 requires unique two-to-six classic factions, Basic or Advanced, the base Treachery Deck and all fourteen Leader Skills alone. No public start, old-game retrofit, expansion deck, Nexus, Homeworld, Discovery, Tech Token or other overlay is enabled.',
|
||||
'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.',
|
||||
'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 native-counter settlement, not a quoted fee or guessed wallet change. Paid auctions, funded shipments, paid revival and eligible resolved battle support retain their original money, card, force and phase continuation once. Canceled Emperor or Guild income can leave a real bank payment; a stopped shipment cannot.',
|
||||
'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.',
|
||||
'Actual payer contribution legs stay distinct. Two different players paying two each do not become one player paying four. Banker’s separate one-to-three battle payment does not combine with two support to manufacture a qualifying payment. These split-source conventions are explicit conservative local compositions, not a publisher split-payment example.',
|
||||
'A new grant requires an actual available living native trainer. A captive grants no normal income. Hidden unselected skills do not supply their normal band; in the trainer’s own battle, its actual selected surviving leader supplies the appropriate eligibility after reveal/resolution, not private pre-reveal timing.',
|
||||
'One physical Banker card has one use per turn and phase. Repeated payments, refresh, death, return or same-phase reassignment cannot reset that use; the next phase or turn permits a new grant.',
|
||||
@@ -4516,11 +4516,11 @@ 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 the fresh classic skill profile.', evidence: ['game/engine.ts', 'game/spice-banker-income.ts'] },
|
||||
{ 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: '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'] },
|
||||
{ area: 'Verification', status: 'Partial', detail: 'Types/lint, 6,487 offline tests and 140 focused cases pass. Eighteen native source-to-Mentat cases, four legal-budget policies, two preserved six-seat CLI/phone rooms and two independent no-finding reviews cover this bounded profile. Local HTTP 49/55 remains limited by six 503 failures; no deployed/full-module claim.', evidence: ['tests/fixture-spice-banker-income.ts', 'tests/spice-banker-income.test.ts', 'tests/spice-banker-income-runtime.test.ts', 'tests/spice-banker-income-recovery.test.ts', 'tests/prototype-room.test.ts'] },
|
||||
{ area: 'Verification', status: 'Partial', detail: 'Original classic checkpoint: types/lint,6,487 offline and140 focused cases, eighteen source programs and two six-seat CLI/phone rooms. Native integration: affected110, final native/guide26, twelve Banker cases plus four legal post-income policies, native original CLI and390px deferred10-to-Mentat11. Tleilaxu paid/free/self/canceled3-or4 boundaries are exercised. Comprehensive assurance follows all rules; no deployed/full-module claim.', evidence: ['tests/fixture-spice-banker-income.ts', 'tests/spice-banker-income.test.ts', 'tests/spice-banker-income-runtime.test.ts', 'tests/fixture-native-banker-income.ts', 'tests/native-banker-income.test.ts', 'tests/spice-banker-income-recovery.test.ts', 'tests/prototype-room.test.ts'] },
|
||||
],
|
||||
},
|
||||
{
|
||||
@@ -4544,17 +4544,17 @@ 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 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 or supported Basic native banker-income profile; ordinary/default and combined 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.',
|
||||
'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 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 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.',
|
||||
...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'],
|
||||
checklist: [
|
||||
{ area:'Implementation',status:'Partial',detail:'Exact fourteen-card custody, source-ordered setup, public capture, concealment, death and own revival connect five role bonuses, Planetologist movement/Special substitution and Suk Graduate casualty rescue. Rihani inspection/exchange and lower Mentat/Bureaucrat/Sandmaster effects are connected. Smuggler normal reserve shipping, the owned Richese No-Field companion, unmodified battle collection and optional Sandmaster ground-route and native Fremen worm-ride collection are connected. A separately opted-in Mentat preview connects private pre-plan questions and historical observations while ordinary activation awaits the uniform-response decision. Spice Banker lower spending and native Diplomat base Shield/Snooper copying are connected; skilled Diplomat retreat now transfers undialed normal/elite forces before losing casualties in supported battles. Normal Banker income connects only in the separate fresh classic banker-income profile; other remaining bands and combined modules remain missing. Bureaucrat redirects supported third-party auction, shipment and bribe payments with exact saved once-per-phase use.',evidence:['game/leader-skill-cards.ts','game/leader-skills.ts','game/leader-skill-combat.ts','game/suk-graduate.ts','game/rihani-decipherer.ts','game/mentat-question.ts','game/bureaucrat-payment.ts','game/leader-skill-battle-board.ts','game/smuggler-shipment.ts','game/smuggler-no-field.ts','game/smuggler-battle.ts','game/spice-banker.ts','game/spice-banker-income.ts','game/sandmaster-movement.ts','game/sandmaster-worm.ts','game/diplomat-defense.ts','game/diplomat-retreat.ts','game/engine.ts'] },
|
||||
{ area:'Implementation',status:'Partial',detail:'Exact fourteen-card custody, source-ordered setup, public capture, concealment, death and own revival connect five role bonuses, Planetologist movement/Special substitution and Suk Graduate casualty rescue. Rihani inspection/exchange and lower Mentat/Bureaucrat/Sandmaster effects are connected. Smuggler normal reserve shipping, the owned Richese No-Field companion, unmodified battle collection and optional Sandmaster ground-route and native Fremen worm-ride collection are connected. A separately opted-in Mentat preview connects private pre-plan questions and historical observations while ordinary activation awaits the uniform-response decision. Spice Banker lower spending and native Diplomat base Shield/Snooper copying are connected; skilled Diplomat retreat now transfers undialed normal/elite forces before losing casualties in supported battles. Normal Banker income connects only in the separate fresh classic or supported Basic native banker-income profile; other remaining bands and combined modules remain missing. Bureaucrat redirects supported third-party auction, shipment and bribe payments with exact saved once-per-phase use.',evidence:['game/leader-skill-cards.ts','game/leader-skills.ts','game/leader-skill-combat.ts','game/suk-graduate.ts','game/rihani-decipherer.ts','game/mentat-question.ts','game/bureaucrat-payment.ts','game/leader-skill-battle-board.ts','game/smuggler-shipment.ts','game/smuggler-no-field.ts','game/smuggler-battle.ts','game/spice-banker.ts','game/spice-banker-income.ts','game/sandmaster-movement.ts','game/sandmaster-worm.ts','game/diplomat-defense.ts','game/diplomat-retreat.ts','game/engine.ts'] },
|
||||
{ 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'] },
|
||||
|
||||
Reference in new issue
Block a user