//! The `dungon` crate contains the core functionality for //! interacting with a `Dungeon` and its components. pub mod astar; pub mod bsp; pub mod entity; pub mod map; pub mod msg; pub mod player_input; pub mod pos; use rand::{ SeedableRng, TryRngCore, rngs::{OsRng, SmallRng}, }; use crate::{ entity::{Entity, Player}, map::{Floor, Tile}, msg::Message, player_input::PlayerInput, pos::FPos, }; /// Lets the caller know what has /// changed in the game state this /// tick #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum UpdateResult { /// Default, entities have moved EntityMovement, /// We have moved to the next floor NextFloor, /// Message on screen updated. /// Contains if a char was added. MessageUpdated(bool), } /// The `Dungeon` type represents the game state of the /// dungeon crawler. #[derive(Debug, Clone)] pub struct Dungeon { pub floor: Floor, pub player: Player, pub enemies: Vec, pub msg: Message, seed: u64, rng: SmallRng, } impl Dungeon { /// Creates a new `Dungeon` with a provided seed. /// /// # Examples /// /// ```no_run /// use dungeon::Dungeon; /// /// let seed = 234690523482u64; /// let dungeon = Dungeon::new(seed); /// ``` #[must_use] pub fn new(seed: u64) -> Self { let mut rng = SmallRng::seed_from_u64(seed); let floor = bsp::generate(&mut rng); let player = Player::new(floor.player_start()); let enemies = vec![]; let msg = Message::empty(); let mut dungeon = Self { floor, player, enemies, msg, seed, rng, }; dungeon.spawn_enimies(); dungeon } /// Creates a new `Dungeon` with a random seed /// /// # Examples /// /// ```no_run /// use dungeon::Dungeon; /// /// let dungeon = Dungeon::random(); /// ``` #[must_use] pub fn random() -> Self { let seed = OsRng.try_next_u64().unwrap_or_default(); Self::new(seed) } /// Returns the current position of the camera (viewer) #[must_use] pub const fn camera(&self) -> FPos { self.player.entity.fpos } /// Returns the seed used to generate the map #[must_use] pub const fn seed(&self) -> u64 { self.seed } /// Returns the random number gen for the `Floor` #[must_use] pub const fn rng(&mut self) -> &mut SmallRng { &mut self.rng } pub fn update(&mut self, player_input: PlayerInput, delta_time: f32) -> UpdateResult { if self.msg.visible() { let changed = self.msg.update(player_input); UpdateResult::MessageUpdated(changed) } else { self.update_entities(player_input, delta_time); if self.floor.get(self.player.entity.pos) == Tile::Stairs { // we are moving to a new floor self.floor = bsp::generate(&mut self.rng); self.player.entity.teleport(self.floor.player_start()); self.spawn_enimies(); return UpdateResult::NextFloor; } UpdateResult::EntityMovement } } fn spawn_enimies(&mut self) { // TODO: better entity spawning let zombie = Entity::zombie(self.floor.random_walkable_pos(&mut self.rng)); self.enemies.clear(); self.enemies.push(zombie); } }