Files
Dune/game/kull-default-profile.ts
T
Quintine 16f10beecf
Verify and publish checkpoint container / container (push) Canceled after 0s
Enable Basic Kull preview with Tech Tokens
2026-10-29 05:10:06 +11:00

73 lines
4.4 KiB
TypeScript

/** Public lobby facts only. This controls fresh Basic setup and never examines
* a player's cards, spice or any hidden Karama/counter eligibility. */
export type KullDefaultProfile = {
status: string;
advanced: boolean;
expansions: readonly string[];
players: readonly { faction: string }[];
lobbyOptions?: { leaderSkills?: unknown; ecazTreachery?: unknown } | null;
/** Same public selections on a projected lobby view. */
lobbyModules?: { leaderSkills?: unknown; ecazTreachery?: unknown; nexusCards?: unknown; discoveries?: unknown } | null;
leaderSkills?: unknown;
ecazTreachery?: unknown;
nexusCards?: unknown;
discoveryEnabled?: unknown;
discoveries?: unknown;
discoveryStash?: unknown;
greatMaker?: unknown;
homeworlds?: unknown;
techTokens?: unknown;
strongholdCards?: unknown;
};
export type KullDefaultEligibility = { eligible: boolean; reason: string | null };
const classic = new Set(['atreides', 'beneGesserit', 'emperor', 'fremen', 'guild', 'harkonnen']);
const ix = new Set(['ixians', 'tleilaxu']);
const choam = new Set(['choam', 'richese']);
const ecaz = new Set(['ecaz', 'moritani']);
const blocked = (reason: string): KullDefaultEligibility => ({ eligible: false, reason });
/** Narrow Basic Tech composition: native CHOAM and classic factions only. */
export function basicKullTechRoster(game: Pick<KullDefaultProfile, 'advanced' | 'expansions' | 'players' | 'techTokens'>): boolean {
return game.advanced === false && !!game.techTokens && Array.isArray(game.expansions) &&
game.expansions.length === 2 && game.expansions.includes('ix') && game.expansions.includes('choam') &&
Array.isArray(game.players) && game.players.length >= 3 && game.players.length <= 6 &&
game.players.some(player => player?.faction === 'choam') &&
game.players.every(player => !!player && (player.faction === 'choam' || classic.has(player.faction))) &&
new Set(game.players.map(player => player.faction)).size === game.players.length;
}
/** Public profile eligibility is independent of the host's explicit opt-out.
* A lone CHOAM seat can see the choice while waiting for others; the native
* start still checks readiness, minimum seats and all fresh private inventory.
* This quote cannot authorize a start or inspect pending/private game state. */
export function kullDefaultProfile(game: KullDefaultProfile): KullDefaultEligibility {
if (game.status !== 'lobby') return blocked('Automatic Kull applies only to a fresh lobby.');
if (game.advanced !== false) return blocked('Automatic Kull currently supports Basic rules only.');
if (!Array.isArray(game.expansions) ||
!(game.expansions.length === 2 || game.expansions.length === 3 && game.expansions.includes('ecaz')) ||
!game.expansions.includes('choam') || !game.expansions.includes('ix') ||
new Set(game.expansions).size !== game.expansions.length)
return blocked('Automatic Kull currently needs the CHOAM and Ix decks, with Ecaz optional.');
if (!Array.isArray(game.players) || game.players.length < 1 || game.players.length > 6 ||
!game.players.some(player => player?.faction === 'choam') ||
!game.players.every(player => !!player && typeof player.faction === 'string' &&
(classic.has(player.faction) || ix.has(player.faction) && game.expansions.includes('ix') ||
choam.has(player.faction) && game.expansions.includes('choam') ||
ecaz.has(player.faction) && game.expansions.includes('ecaz'))) ||
new Set(game.players.map(player => player.faction)).size !== game.players.length)
return blocked('Automatic Kull needs one to six distinct factions, including CHOAM, with their selected decks.');
const options = game.lobbyOptions, projected = game.lobbyModules;
if (options?.leaderSkills || projected?.leaderSkills ||
projected?.nexusCards || projected?.discoveries || game.leaderSkills || game.ecazTreachery || game.nexusCards ||
game.discoveryEnabled || game.discoveries || game.discoveryStash || game.greatMaker ||
game.homeworlds || game.strongholdCards ||
(game.techTokens && (!basicKullTechRoster(game) || options?.ecazTreachery || projected?.ecazTreachery)))
return blocked('Automatic Kull supports independent Ecaz Treachery Cards, or Tech Tokens with three to six CHOAM/classic factions and the Ix and CHOAM decks.');
return { eligible: true, reason: null };
}
export function kullDefaultEligible(game: KullDefaultProfile): boolean {
return kullDefaultProfile(game).eligible;
}