use super::errors::GridError; use crate::prelude::*; /// Component representing a single tile on the grid. #[derive(Component)] pub struct Tile { pub x: u32, pub y: u32, } /// Visual marker component for the crop on a tile. #[derive(Component)] pub struct CropVisual; /// Visual marker component for the water on a tile. #[derive(Component)] pub struct WaterVisual; /// The logical state of a tile. #[derive(Component, Default, Serialize, Deserialize, Clone, Debug, PartialEq, Eq)] pub enum TileState { #[default] Unclaimed, Empty, Occupied { seed: ItemType, watered: bool, growth_stage: u32, #[serde(default)] withered: bool, #[serde(default)] dry_counter: u8, }, } impl TileState { pub fn is_blocking(&self) -> bool { match self { TileState::Occupied { .. } => true, _ => false, } } } /// Resource containing grid dimensions and tile entities. #[derive(Resource)] pub struct Grid { pub width: u32, pub height: u32, pub tiles: Vec>, } impl Grid { /// Returns the entity of the tile at the given position. pub fn get_tile(&self, pos: (u32, u32)) -> Result { if pos.0 >= self.width || pos.1 >= self.height { return Err(GridError::OutOfBounds { x: pos.0 as i32, y: pos.1 as i32, }); } Ok(self.tiles[pos.0 as usize][pos.1 as usize]) } /// Modifies the state of a tile using a mapping function. pub fn map_tile_state( &self, pos: (u32, u32), mapper: F, mut tile_query: Query<&mut TileState>, ) -> Result<(), GridError> where F: FnOnce(&TileState) -> TileState, { let tile_entity = self.get_tile(pos)?; let mut tile_state = tile_query .get_mut(tile_entity) .map_err(|_| GridError::UnknownError)?; *tile_state = mapper(&*tile_state); Ok(()) } /// Counts the number of tiles that are not unclaimed. pub fn count_claimed_tiles(&self, tile_query: &Query<&TileState>) -> u32 { self.tiles .iter() .flatten() .filter(|&entity| { if let Ok(state) = tile_query.get(*entity) { !matches!(state, TileState::Unclaimed) } else { false } }) .count() as u32 } }