Files
Dune/game/spice-banker.ts
T
Quintine 1380271bb6 Connect Spice Banker sealed battle spending and saved settlement
Prototype one through three own spice as a separate sealed battle commitment. Reserve funds alongside actual force support, add strength only for the surviving skilled leader, and settle once through existing versioned writes. Apply the documented card/core-rule interpretation: payment survives leader death or loss, except for the sole successful traitor caller. Keep printed disc strength and bounty unchanged. Normal income awaits its deferred-custody ruling; combined modules remain gated.

Validation: 54 focused tests; typecheck, lint, 4490 offline tests, production build and 43 HTTP tests passed. Independent rules, privacy, persistence and UI review completed. SQLite tests cover reserved-spice diversion, concurrent settlement, traitor waiver and legacy plans. Browser exercised a three-spice commitment, pending refresh, actual +3 strength and payment, and restored private cards and the next decision. Two genuine four-profile Basic/Advanced samples completed without rejected candidates but did not use Banker spending.

Following another reported outage, the server remained healthy. Preserved all 461 opening rooms and original seat/recovery rows (495 rooms after QA/HTTP). SQLite integrity and foreign keys passed. A fresh online backup captured all 495 rooms, and browser refresh restored the QA seat. No restart or reset was needed.

Verified source tree: 208bf9324ab994b5e59ed50d78998b4dbf8810b3b6799b1a577ef3b84479335f
2026-09-13 20:45:42 +10:00

73 lines
1.9 KiB
TypeScript

import {
usesSurvivingSkilledLeader,
type BattleLeaderSkill,
} from './leader-skill-combat';
export class SpiceBankerError extends Error {}
/** The same development boundary applies to declarations, saved plans, controls and bots. */
export function spiceBankerModeSupported(game: {
expansions: readonly string[];
homeworlds?: unknown;
nexusCards?: unknown;
discoveries?: unknown;
discoveryEnabled?: boolean;
strongholdCards?: unknown;
techTokens?: unknown;
}): boolean {
return (
!game.expansions.length &&
!game.homeworlds &&
!game.nexusCards &&
!game.discoveries &&
!game.discoveryEnabled &&
!game.strongholdCards &&
!game.techTokens
);
}
export function spiceBankerBattleMaximum(
assignments: readonly BattleLeaderSkill[],
leader: string | null | undefined,
ownSpice: number,
ownSupport = 0,
): number {
if (!usesSurvivingSkilledLeader(assignments, 'spice-banker', leader, true))
return 0;
if (
!Number.isSafeInteger(ownSpice) ||
!Number.isSafeInteger(ownSupport) ||
ownSpice < 0 ||
ownSupport < 0
)
return 0;
return Math.max(0, Math.min(3, ownSpice - ownSupport));
}
/** Banker funds are separate from force support and remain behind the shield until settlement. */
export function validateSpiceBankerSpend(
assignments: readonly BattleLeaderSkill[],
leader: string | null | undefined,
amount: unknown,
ownSpice: number,
ownSupport = 0,
): number {
const spend = amount === undefined ? 0 : amount;
if (
typeof spend !== 'number' ||
!Number.isSafeInteger(spend) ||
spend < 0 ||
spend > 3
)
throw new SpiceBankerError(
'Choose zero to decline, or one through three spice for Spice Banker.',
);
if (
spend > spiceBankerBattleMaximum(assignments, leader, ownSpice, ownSupport)
)
throw new SpiceBankerError(
'Spice Banker needs the selected skilled leader and enough own spice after force support.',
);
return spend;
}