Files
canopy-game/src/types.ts

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;
};