Align Advanced Ix starting cards with Harkonnen pool
This commit is contained in:
1 parent
e530d267a3
commit
84fdd404c9
14 files changed
+637
-12
No files matched your search
@@ -0,0 +1,61 @@
|
||||
import { FACTIONS } from './catalog';
|
||||
|
||||
export type IxStartingCardGame = {
|
||||
advanced: boolean;
|
||||
players: readonly { id: string; faction: string }[];
|
||||
};
|
||||
export type IxStartingCardDealPlan = {
|
||||
kind: 'advanced-pool' | 'legacy-deck-bonus';
|
||||
seats: { player: string; amount: number }[];
|
||||
deckBonus: string | null;
|
||||
};
|
||||
export class IxStartingCardError extends Error {
|
||||
constructor(message: string) {
|
||||
super(message);
|
||||
this.name = 'IxStartingCardError';
|
||||
}
|
||||
}
|
||||
|
||||
function validateStartingRoster(game: IxStartingCardGame): void {
|
||||
if (!game || typeof game !== 'object' || typeof game.advanced !== 'boolean' ||
|
||||
!Array.isArray(game.players) || game.players.length < 2 || game.players.length > 6)
|
||||
throw new IxStartingCardError('Ixian starting cards require a two-to-six-player native roster and rules mode.');
|
||||
const ids = new Set<string>();
|
||||
const factions = new Set<string>();
|
||||
for (const player of game.players) {
|
||||
if (!player || typeof player !== 'object' || typeof player.id !== 'string' ||
|
||||
!player.id || player.id.trim() !== player.id || ids.has(player.id) ||
|
||||
!FACTIONS.some(faction => faction.id === player.faction) || factions.has(player.faction))
|
||||
throw new IxStartingCardError('Ixian starting cards require distinct registered factions and player identities.');
|
||||
ids.add(player.id);
|
||||
factions.add(player.faction);
|
||||
}
|
||||
if (!factions.has('ixians'))
|
||||
throw new IxStartingCardError('The starting-card pool requires the native Ixian faction.');
|
||||
}
|
||||
|
||||
/** Fresh supplied Advanced p34 includes Harkonnen's second card in Ixians' pool. */
|
||||
export function ixStartingCardPoolSize(game: IxStartingCardGame): number {
|
||||
validateStartingRoster(game);
|
||||
return game.players.length +
|
||||
(game.advanced && game.players.some(player => player.faction === 'harkonnen') ? 1 : 0);
|
||||
}
|
||||
|
||||
/** poolCount is the recorded original pool, including the card Ixians will keep.
|
||||
* Old N-card and historical short pools retain the original deck-bonus suffix.
|
||||
*/
|
||||
export function ixStartingCardDealPlan(game: IxStartingCardGame, poolCount: number): IxStartingCardDealPlan {
|
||||
const maximum = ixStartingCardPoolSize(game);
|
||||
if (!Number.isSafeInteger(poolCount) || poolCount < 1 || poolCount > maximum)
|
||||
throw new IxStartingCardError('The recorded Ixian starting-card pool has an invalid size.');
|
||||
const harkonnen = game.players.find(player => player.faction === 'harkonnen');
|
||||
const advancedPool = game.advanced && !!harkonnen && poolCount === game.players.length + 1;
|
||||
return {
|
||||
kind: advancedPool ? 'advanced-pool' : 'legacy-deck-bonus',
|
||||
seats: game.players.filter(player => player.faction !== 'ixians').map(player => ({
|
||||
player: player.id,
|
||||
amount: advancedPool && player.faction === 'harkonnen' ? 2 : 1,
|
||||
})),
|
||||
deckBonus: advancedPool ? null : harkonnen?.id ?? null,
|
||||
};
|
||||
}
|
||||
Reference in new issue
Block a user