249 lines
5.1 KiB
TypeScript
249 lines
5.1 KiB
TypeScript
export type PlayerId = number;
|
|
export type NodeKey = `${number}:${number}`;
|
|
|
|
export type PlayerPalette = {
|
|
name: string;
|
|
primary: string;
|
|
glow: string;
|
|
};
|
|
|
|
export type Position = {
|
|
row: number;
|
|
column: number;
|
|
};
|
|
|
|
export type SetupState = {
|
|
playerCount: number;
|
|
playerNames: string[];
|
|
columns: number;
|
|
rows: number;
|
|
startingNodesPerPlayer: number;
|
|
sunbeamChance: number;
|
|
diseaseChance: number;
|
|
seedInputs: string[];
|
|
paletteOrder: number[];
|
|
initiativeMode: "fixed" | "bid";
|
|
biddingOrderRule: "rotating" | "lowest_growth_income";
|
|
weatherDraftEnabled: boolean;
|
|
weatherDraftCount: number;
|
|
winCondition: "rounds" | "top_leaves";
|
|
maxRounds: number;
|
|
topLeafTarget: number;
|
|
};
|
|
|
|
export type Player = {
|
|
id: PlayerId;
|
|
name: string;
|
|
color: string;
|
|
glow: string;
|
|
totalScore: number;
|
|
roundScore: number;
|
|
growthPoints: number;
|
|
bankedPoints: number;
|
|
bonusPoints: number;
|
|
lifetimeGrowthIncome: number;
|
|
passed: boolean;
|
|
};
|
|
|
|
export type GameConfig = {
|
|
columns: number;
|
|
rows: number;
|
|
playerCount: number;
|
|
startingNodesPerPlayer: number;
|
|
playerPaletteOrder: number[];
|
|
initiativeMode: SetupState["initiativeMode"];
|
|
biddingOrderRule: SetupState["biddingOrderRule"];
|
|
weatherDraftEnabled: boolean;
|
|
weatherDraftCount: number;
|
|
winCondition: SetupState["winCondition"];
|
|
maxRounds: number;
|
|
topLeafTarget: number;
|
|
};
|
|
|
|
export type NodeState = {
|
|
ownerId: PlayerId;
|
|
};
|
|
|
|
export type Edge = {
|
|
from: Position;
|
|
to: Position;
|
|
ownerId: PlayerId;
|
|
};
|
|
|
|
export type GrowDirection = "vertical" | "left" | "right";
|
|
|
|
export type GrowTarget = Position & {
|
|
cost: number;
|
|
direction: GrowDirection;
|
|
};
|
|
|
|
export type ShiftMove = {
|
|
type: "shift";
|
|
cost: number;
|
|
direction: "left" | "right";
|
|
movedNodes: Array<{
|
|
fromKey: NodeKey;
|
|
toKey: NodeKey;
|
|
row: number;
|
|
fromColumn: number;
|
|
toColumn: number;
|
|
}>;
|
|
movedEdges: Array<{
|
|
before: Edge;
|
|
after: Edge;
|
|
}>;
|
|
undoKeys: NodeKey[];
|
|
selectKey: NodeKey;
|
|
};
|
|
|
|
export type GrowMove = {
|
|
type: "grow";
|
|
from: Position;
|
|
to: Position;
|
|
cost: number;
|
|
targetKey: NodeKey;
|
|
undoKeys: NodeKey[];
|
|
selectKey: NodeKey;
|
|
};
|
|
|
|
export type TurnMove = GrowMove | ShiftMove;
|
|
|
|
export type ColumnEnergy = {
|
|
column: number;
|
|
terminalRow: number;
|
|
intercepted: boolean;
|
|
ownerId: PlayerId | null;
|
|
playersPresent: PlayerId[];
|
|
hitNode: Position | null;
|
|
rootKey: NodeKey | null;
|
|
branchNodes: Position[];
|
|
branchEdges: Array<{ from: Position; to: Position }>;
|
|
};
|
|
|
|
export type RootBurst = {
|
|
key: NodeKey;
|
|
playerId: PlayerId;
|
|
count: number;
|
|
};
|
|
|
|
export type EnergySimulation = {
|
|
scores: number[];
|
|
columns: ColumnEnergy[];
|
|
rootBursts: RootBurst[];
|
|
};
|
|
|
|
export type RoundAnimationTrace = {
|
|
playerId: PlayerId;
|
|
verticalCells: Position[];
|
|
ray: { x: number; y: number };
|
|
rootKey: NodeKey | null;
|
|
branchNodes: Position[];
|
|
};
|
|
|
|
export type RoundAnimation = {
|
|
phase: "sunlight" | "branches" | "bonus" | "events";
|
|
columns: ColumnEnergy[];
|
|
traces: RoundAnimationTrace[];
|
|
rootBursts: RootBurst[];
|
|
sunbeamPlayerId: PlayerId | null;
|
|
bonusTrace: RoundAnimationTrace | null;
|
|
bonusBurst: RootBurst | null;
|
|
diseaseKeys: NodeKey[];
|
|
};
|
|
|
|
export type ColumnResult = {
|
|
column: number;
|
|
ownerId: PlayerId | null;
|
|
topRow: number | null;
|
|
tied: boolean;
|
|
};
|
|
|
|
export type RoundSummary = {
|
|
scores: number[];
|
|
columnResults: ColumnResult[];
|
|
event: string | null;
|
|
};
|
|
|
|
export type ScoreSnapshot = {
|
|
projectedIncome: number;
|
|
growthPoints: number;
|
|
bankedPoints: number;
|
|
lifetimeGrowthIncome: number;
|
|
};
|
|
|
|
export type ColumnLeader = {
|
|
ownerId: PlayerId | null;
|
|
row: number | null;
|
|
tied: boolean;
|
|
};
|
|
|
|
export type RandomEffects = {
|
|
sunbeamChance: number;
|
|
diseaseChance: number;
|
|
};
|
|
|
|
export type GamePhase = "initiative" | "turn" | "round_end" | "game_over";
|
|
|
|
export type WeatherCardId =
|
|
| "leaf_surge"
|
|
| "branching_season"
|
|
| "storehouse"
|
|
| "sun_ladder"
|
|
| "west_light"
|
|
| "east_light"
|
|
| "high_noon"
|
|
| "edge_bloom"
|
|
| "wide_reach"
|
|
| "tall_reward"
|
|
| "stalemate"
|
|
| "split_light";
|
|
|
|
export type WeatherCardDefinition = {
|
|
id: WeatherCardId;
|
|
title: string;
|
|
description: string;
|
|
};
|
|
|
|
export type WeatherOfferPair = {
|
|
id: string;
|
|
options: [WeatherCardId, WeatherCardId];
|
|
};
|
|
|
|
export type InitiativeDraftState = {
|
|
biddingOrder: PlayerId[];
|
|
biddingIndex: number;
|
|
seatAssignments: Array<PlayerId | null>;
|
|
seatBonuses: number[];
|
|
};
|
|
|
|
export type WeatherDraftState = {
|
|
playerOrder: PlayerId[];
|
|
draftIndex: number;
|
|
offers: WeatherOfferPair[];
|
|
drafted: WeatherCardId[];
|
|
banned: WeatherCardId[];
|
|
};
|
|
|
|
export type GameState = {
|
|
config: GameConfig;
|
|
players: Player[];
|
|
nodes: Map<NodeKey, NodeState>;
|
|
edges: Edge[];
|
|
round: number;
|
|
activePlayerId: PlayerId;
|
|
turnOrder: PlayerId[];
|
|
phase: GamePhase | "weather";
|
|
turnMoves: TurnMove[];
|
|
selectedSource: NodeKey | null;
|
|
availableTargets: GrowTarget[];
|
|
animation: RoundAnimation | null;
|
|
initiativeAnchorPlayerId: PlayerId;
|
|
initiativeDraft: InitiativeDraftState | null;
|
|
weatherDraft: WeatherDraftState | null;
|
|
activeRoundEffects: WeatherCardId[];
|
|
randomEffects: RandomEffects;
|
|
gameOver: boolean;
|
|
history: string[];
|
|
roundSummary: RoundSummary | null;
|
|
};
|