use serde::{Deserialize, Serialize}; #[cfg(feature = "spacetime-types")] use spacetimedb::SpacetimeType; pub const PUZZLE_CLEAR_PLAY_ID: &str = "puzzle-clear"; pub const PUZZLE_CLEAR_PUBLIC_WORK_CODE_PREFIX: &str = "PC-"; pub const PUZZLE_CLEAR_SESSION_ID_PREFIX: &str = "puzzle-clear-session-"; pub const PUZZLE_CLEAR_PROFILE_ID_PREFIX: &str = "puzzle-clear-profile-"; pub const PUZZLE_CLEAR_WORK_ID_PREFIX: &str = "puzzle-clear-work-"; pub const PUZZLE_CLEAR_RUN_ID_PREFIX: &str = "puzzle-clear-run-"; pub const PUZZLE_CLEAR_LEVEL_DURATION_SECONDS: u32 = 600; #[cfg_attr(feature = "spacetime-types", derive(SpacetimeType))] #[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)] pub enum PuzzleClearShapeKind { OneByTwo, OneByThree, TwoByTwo, TwoByThree, } #[cfg_attr(feature = "spacetime-types", derive(SpacetimeType))] #[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)] pub enum PuzzleClearOrientation { Horizontal, Vertical, } #[cfg_attr(feature = "spacetime-types", derive(SpacetimeType))] #[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)] pub enum PuzzleClearRunStatus { Playing, LevelFailed, LevelCleared, Finished, } #[cfg_attr(feature = "spacetime-types", derive(SpacetimeType))] #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] pub struct PuzzleClearLevelConfig { pub level_index: u32, pub board_size: u32, pub target_clears: u32, pub duration_seconds: u32, pub unlocked_shapes: Vec, } #[cfg_attr(feature = "spacetime-types", derive(SpacetimeType))] #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] pub struct PuzzleClearShapeQuota { pub shape: PuzzleClearShapeKind, pub count: u32, } #[cfg_attr(feature = "spacetime-types", derive(SpacetimeType))] #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] pub struct PuzzleClearPatternGroup { pub group_id: String, pub shape: PuzzleClearShapeKind, pub width: u32, pub height: u32, pub atlas_x: u32, pub atlas_y: u32, pub atlas_width: u32, pub atlas_height: u32, } #[cfg_attr(feature = "spacetime-types", derive(SpacetimeType))] #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] pub struct PuzzleClearCard { pub card_id: String, pub group_id: String, pub shape: PuzzleClearShapeKind, pub orientation: PuzzleClearOrientation, pub part_x: u32, pub part_y: u32, pub image_src: String, pub image_object_key: String, pub asset_object_id: String, pub source_atlas_cell: String, } #[cfg_attr(feature = "spacetime-types", derive(SpacetimeType))] #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] pub struct PuzzleClearCell { pub row: u32, pub col: u32, pub card: Option, pub locked_group_id: Option, } #[cfg_attr(feature = "spacetime-types", derive(SpacetimeType))] #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] pub struct PuzzleClearBoard { pub rows: u32, pub cols: u32, pub cells: Vec, } #[cfg_attr(feature = "spacetime-types", derive(SpacetimeType))] #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] pub struct PuzzleClearDeck { pub ready_columns: Vec>, } #[cfg_attr(feature = "spacetime-types", derive(SpacetimeType))] #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] pub struct PuzzleClearMove { pub from_row: u32, pub from_col: u32, pub to_row: u32, pub to_col: u32, } #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] pub struct PuzzleClearElimination { pub group_id: String, pub positions: Vec<(u32, u32)>, } #[cfg_attr(feature = "spacetime-types", derive(SpacetimeType))] #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] pub struct PuzzleClearRunSnapshot { pub run_id: String, pub owner_user_id: String, pub profile_id: String, pub status: PuzzleClearRunStatus, pub level_index: u32, pub clears_done: u32, pub board: PuzzleClearBoard, pub deck: PuzzleClearDeck, pub started_at_ms: u64, pub level_started_at_ms: u64, pub finished_at_ms: Option, } impl PuzzleClearShapeKind { pub fn as_str(self) -> &'static str { match self { Self::OneByTwo => "1x2", Self::OneByThree => "1x3", Self::TwoByTwo => "2x2", Self::TwoByThree => "2x3", } } pub fn base_dimensions(self) -> (u32, u32) { match self { Self::OneByTwo => (2, 1), Self::OneByThree => (3, 1), Self::TwoByTwo => (2, 2), Self::TwoByThree => (3, 2), } } pub fn dimensions(self, orientation: PuzzleClearOrientation) -> (u32, u32) { let (width, height) = self.base_dimensions(); if matches!(orientation, PuzzleClearOrientation::Vertical) && matches!( self, PuzzleClearShapeKind::OneByTwo | PuzzleClearShapeKind::OneByThree | PuzzleClearShapeKind::TwoByThree ) { (height, width) } else { (width, height) } } } impl PuzzleClearOrientation { pub fn as_str(self) -> &'static str { match self { Self::Horizontal => "horizontal", Self::Vertical => "vertical", } } } impl PuzzleClearRunStatus { pub fn as_str(self) -> &'static str { match self { Self::Playing => "playing", Self::LevelFailed => "level_failed", Self::LevelCleared => "level_cleared", Self::Finished => "finished", } } }