diff --git a/src/level.rs b/src/level.rs index b5853e0..7a64739 100644 --- a/src/level.rs +++ b/src/level.rs @@ -1,3 +1,7 @@ +use rand::prelude::SliceRandom; +use rand::Rng; +use rand::rngs::ThreadRng; + pub const LEVEL_WIDTH: usize = 50; pub const LEVEL_HEIGHT: usize = 25; @@ -9,38 +13,84 @@ pub enum LevelElement { StairUp, } +#[derive(Copy, Clone, Debug, PartialEq)] +pub enum RoomType { + StairUp, + StairDown, + BasicRoom, + EmptyRoom, +} + #[derive(Copy, Clone, Debug, PartialEq)] pub struct Level { structure: [[LevelElement; LEVEL_HEIGHT]; LEVEL_WIDTH], } impl Level { - const ROOM_HEIGHT: usize = 6; const ROOM_WIDTH: usize = 7; - fn draw_room(row: usize, col: usize, s: &mut [[LevelElement; LEVEL_HEIGHT]; LEVEL_WIDTH]) { - for r in 0..Level::ROOM_HEIGHT { - for c in 0..Level::ROOM_WIDTH { - if c == Level::ROOM_WIDTH - 1 || r == Level::ROOM_HEIGHT - 1 { - s[col * Level::ROOM_WIDTH + c][row * Level::ROOM_HEIGHT + r] = LevelElement::Wall; - } + const ROOM_HEIGHT: usize = 6; + const ROOMS_VERTICAL: usize = 7; + const ROOMS_HORIZONTAL: usize = 4; + + fn draw_room(&mut self, rng: &mut ThreadRng, row: usize, col: usize) { + let width = rng.gen_range(3..6); + let offset_x = rng.gen_range(0..(Level::ROOM_WIDTH - width)); + let height = rng.gen_range(3..5); + let offset_y = rng.gen_range(0..(Level::ROOM_HEIGHT - height)); + + for r in offset_y..offset_y + height { + for c in offset_x..offset_x + width { + self.structure[1 + col * Level::ROOM_WIDTH + c][1 + row * Level::ROOM_HEIGHT + r] = LevelElement::Floor; } } } + fn draw_stair(&mut self, element: LevelElement, row: usize, col: usize) { + for r in 0..Level::ROOM_HEIGHT - 1 { + for c in 0..Level::ROOM_WIDTH - 1 { + self.structure[1 + col * Level::ROOM_WIDTH + c][1 + row * Level::ROOM_HEIGHT + r] = LevelElement::Floor; + } + } + self.structure[1 + col * Level::ROOM_WIDTH + 2][1 + row * Level::ROOM_HEIGHT + 2] = element; + } pub fn new() -> Level { - let mut s = [[LevelElement::Floor; LEVEL_HEIGHT]; LEVEL_WIDTH]; - Level::draw_room(0, 0, &mut s); - Level::draw_room(1, 1, &mut s); - for i in 0..LEVEL_WIDTH { - s[i][0] = LevelElement::Wall; - } - for i in 0..LEVEL_HEIGHT { - s[0][i] = LevelElement::Wall; - } - + let mut s = [[LevelElement::Wall; LEVEL_HEIGHT]; LEVEL_WIDTH]; Level { structure: s } } + pub fn generate(&mut self, level: usize) { + let mut rooms: Vec = Vec::with_capacity(Level::ROOMS_HORIZONTAL * Level::ROOMS_VERTICAL); + if level > 0 { + rooms.push(RoomType::StairUp); + } + if level < 24 { + rooms.push(RoomType::StairDown); + } + let mut rng = rand::thread_rng(); + for _ in rooms.len()..Level::ROOMS_HORIZONTAL * Level::ROOMS_VERTICAL { + match rng.gen_range(1..=6) { + 1 => { rooms.push(RoomType::EmptyRoom) } + _ => { rooms.push(RoomType::BasicRoom) } + } + } + rooms.shuffle(&mut rng); + for (idx, room) in rooms.iter().enumerate() { + let row = idx / Level::ROOMS_VERTICAL; + let col = idx % Level::ROOMS_VERTICAL; + match room { + RoomType::EmptyRoom => {} + RoomType::StairUp => { + self.draw_stair(LevelElement::StairUp, row, col) + } + RoomType::StairDown => { + self.draw_stair(LevelElement::StairDown, row, col) + } + RoomType::BasicRoom => { + self.draw_room(&mut rng, row, col) + } + }; + } + } pub fn get_element(&self, x: i16, y: i16) -> Option { if x < 0 || y < 0 { return None; diff --git a/src/main.rs b/src/main.rs index 85e9915..e2281ef 100644 --- a/src/main.rs +++ b/src/main.rs @@ -12,7 +12,7 @@ use ratatui::prelude::*; use ratatui::widgets::Block; use crate::game::Game; -use crate::level::Level; +use crate::level::{Level, LevelElement}; use crate::level_widget::LevelWidget; use crate::player::Player; @@ -23,11 +23,24 @@ mod position; mod level_widget; fn main() -> Result<()> { + let mut levels: [Level; 25] = [Level::new(); 25]; + for l in 0..25 { + levels[l].generate(l); + } let mut g = Game { player: Player::new("Teddy Tester", 10), - levels: [Level::new(); 25], + levels, }; + // place player on first upper left floor + for i in 0..level::LEVEL_HEIGHT { + let t = (i as usize).try_into().unwrap(); + if g.levels[0].get_element(t, t) == Some(LevelElement::Floor) { + g.player.change_position((i - 1) as i8, (i - 1) as i8); + break; + } + } + stdout().execute(EnterAlternateScreen)?; enable_raw_mode()?; let mut terminal = Terminal::new(CrosstermBackend::new(stdout()))?;