use serde::{Deserialize, Serialize}; use std::fmt; pub const TICK_RATE_HZ: u16 = 120; pub const SAMPLE_RATE_HZ: u16 = 40; pub const PHYSICS_DT: f32 = 1.0 / TICK_RATE_HZ as f32; pub const FEET_TO_METERS: f32 = 0.3048; pub const STONES_PER_TEAM: u8 = 8; pub const ENDS: u8 = 10; // World coordinates in meters, y along sheet toward house. pub const SHEET_WIDTH: f32 = 5.0; pub const SHEET_LENGTH: f32 = 45.0; pub const HOUSE_CENTER: (f32, f32) = (0.0, 38.5); pub const HOUSE_RADIUS: f32 = 6.0 * FEET_TO_METERS; // 12 ft diameter → 6 ft radius pub const HOG_LINE_Y: f32 = 21.0; pub const BACK_LINE_Y: f32 = 42.0; pub const HACK_Y: f32 = 2.0; // Stone physical properties pub const STONE_RADIUS: f32 = 0.15; pub const STONE_MASS: f32 = 20.0; pub const STONE_FRICTION: f32 = 0.015; pub const STONE_RESTITUTION: f32 = 0.05; pub const MIN_SPEED: f32 = 3.0; pub const MAX_SPEED: f32 = 6.45; #[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Hash, Default)] #[serde(rename_all = "snake_case")] pub enum Team { #[default] Red, Yellow, } impl Team { pub fn other(self) -> Self { match self { Team::Red => Team::Yellow, Team::Yellow => Team::Red, } } } impl fmt::Display for Team { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { Team::Red => write!(f, "red"), Team::Yellow => write!(f, "yellow"), } } } #[derive(Debug, Clone, Serialize, Deserialize)] #[serde(tag = "type", rename_all = "snake_case")] pub enum ClientMessage { Throw { team: Team, broom_x: f32, broom_y: f32, weight: u8, #[serde(default = "default_curl")] curl: i8, #[serde(default = "default_friction")] friction: f32, }, } fn default_curl() -> i8 { 1 } fn default_friction() -> f32 { 1.0 } #[derive(Debug, Clone, Serialize, Deserialize)] #[serde(tag = "type", rename_all = "snake_case")] pub enum ServerMessage { Joined { room: String }, Waiting { message: String }, GameState { end: u8, scores: [i32; 2], // red, yellow hammer: Team, turn_team: Team, stones: Vec, phase: Phase, }, Trajectory { paths: Vec, }, EndScored { end: u8, points: i32, scoring_team: Option }, GameOver { scores: [i32; 2], winner: Option, }, Error { message: String }, } #[derive(Debug, Clone, Default, Serialize, Deserialize, PartialEq, Eq)] #[serde(rename_all = "snake_case")] pub enum Phase { #[default] Waiting, Playing, Simulating, Scoring, EndComplete, GameComplete, } #[derive(Debug, Clone, Serialize, Deserialize)] pub struct StoneTrajectory { pub stone_id: u32, pub path: Vec<(f32, f32, f32)>, } #[derive(Debug, Clone, Serialize, Deserialize)] pub struct StoneState { pub id: u32, pub team: Team, pub x: f32, pub y: f32, pub rotation: f32, pub active: bool, }