el_diablo/src/level.rs

121 lines
3.8 KiB
Rust

use rand::prelude::SliceRandom;
use rand::Rng;
use rand::rngs::ThreadRng;
pub const LEVEL_WIDTH: usize = 50;
pub const LEVEL_HEIGHT: usize = 25;
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum LevelElement {
Wall,
Floor,
StairDown,
StairUp,
}
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum RoomType {
Start,
End,
StairUp,
StairDown,
BasicRoom,
EmptyRoom,
}
#[derive(Copy, Clone, Debug, PartialEq)]
pub struct Level {
pub(crate) structure: [[LevelElement; LEVEL_HEIGHT]; LEVEL_WIDTH],
pub(crate) start_x: usize,
pub(crate) start_y: usize,
}
impl Level {
const ROOM_WIDTH: usize = 7;
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::Wall; LEVEL_HEIGHT]; LEVEL_WIDTH];
Level {
structure: s,
start_x: 1,
start_y: 1
}
}
pub fn generate(&mut self, level: usize) {
let mut rooms: Vec<RoomType> = 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..=3 => { 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)
}
RoomType::Start => {}
RoomType::End => {}
};
}
}
pub fn get_element(&self, x: i16, y: i16) -> Option<LevelElement> {
if x < 0 || y < 0 {
return None;
}
if x >= LEVEL_WIDTH as i16 || y >= LEVEL_HEIGHT as i16 {
return None;
}
Some(self.structure[x as usize][y as usize])
}
}
#[test]
fn test_get_element() {
let l = Level::new();
assert_eq!(l.get_element(0, 0).unwrap(), LevelElement::Wall);
assert_eq!(l.get_element(4, 4).unwrap(), LevelElement::StairDown);
assert_eq!(l.get_element(49, 24).unwrap(), LevelElement::Wall);
assert_eq!(l.get_element(50, 25), None);
}