work on level generator

This commit is contained in:
Joachim Lusiardi 2024-10-30 08:56:45 +01:00
parent 7f288dbcd1
commit c6492c28c2
5 changed files with 79 additions and 37 deletions

View File

@ -73,7 +73,8 @@ pub fn get_room_type_per_level() -> Vec<HashMap<RoomType, std::ops::RangeInclusi
let tmp = [
// level 1
vec![
(RoomType::EmptyRoom, 75),
(RoomType::EmptyRoom, 50),
(RoomType::ArtifactRoom, 25),
(RoomType::MonsterRoom, 5),
(RoomType::BasicRoom, 20),
],

View File

@ -57,6 +57,7 @@ impl Level {
return (None, None, None);
}
if !self.discovered[x][y] {
#[cfg(test)]
return (Some(StructureElement::Unknown), None, None);
}
let search_pos = &Position::new(self.level, x, y);

View File

@ -2,15 +2,19 @@ use petgraph::algo::min_spanning_tree;
use petgraph::data::*;
use petgraph::graph::Graph;
use petgraph::graph::UnGraph;
use std::cmp::max;
use std::cmp::min;
use std::ops::Range;
use rand::Rng;
use rand::{rngs::ThreadRng, seq::SliceRandom};
use crate::artifacts::Artifact;
use crate::artifacts::Chest;
use crate::artifacts::Potion;
use crate::constants::get_monsters_per_level;
use crate::constants::ROOM_HEIGHT;
use crate::constants::ROOM_WIDTH;
use crate::monster::create_monster_by_type;
use crate::monster::Monster;
use crate::position::Position;
use crate::room::Connection;
use crate::{
constants::{
@ -23,6 +27,7 @@ use crate::{
pub struct LevelGenerator {
level: usize,
rooms: [[Room; ROOMS_VERTICAL]; ROOMS_HORIZONAL],
rng: ThreadRng,
}
enum Direction {
Horizontal,
@ -103,7 +108,7 @@ impl LevelGenerator {
}
}
// debug print a text view of the dungeon
println!(" 0 1 2 3 4 5 6 7");
for r in 0..ROOMS_VERTICAL {
print!("{} ", r);
@ -174,9 +179,9 @@ impl LevelGenerator {
if src_node_col == tgt_node_col {
// println!("Down");
let start_col = src_node_col * ROOM_WIDTH+ROOM_WIDTH/2;
let start_row = src_node_row * ROOM_HEIGHT+ROOM_HEIGHT;
let end_col = tgt_node_col * ROOM_WIDTH+ROOM_WIDTH/2;
let start_col = src_node_col * ROOM_WIDTH + ROOM_WIDTH / 2;
let start_row = src_node_row * ROOM_HEIGHT + ROOM_HEIGHT;
let end_col = tgt_node_col * ROOM_WIDTH + ROOM_WIDTH / 2;
let end_row = tgt_node_row * ROOM_HEIGHT;
rooms[src_node_col][src_node_row].connection_down = Some(Connection {
start_pos: (start_col, start_row),
@ -184,10 +189,10 @@ impl LevelGenerator {
});
} else {
// println!("Right");
let start_col = src_node_col * ROOM_WIDTH+ROOM_WIDTH;
let start_row = src_node_row * ROOM_HEIGHT+ROOM_HEIGHT/2;
let start_col = src_node_col * ROOM_WIDTH + ROOM_WIDTH;
let start_row = src_node_row * ROOM_HEIGHT + ROOM_HEIGHT / 2;
let end_col = tgt_node_col * ROOM_WIDTH;
let end_row = tgt_node_row * ROOM_HEIGHT+ROOM_HEIGHT/2;
let end_row = tgt_node_row * ROOM_HEIGHT + ROOM_HEIGHT / 2;
rooms[src_node_col][src_node_row].connection_right = Some(Connection {
start_pos: (start_col, start_row),
end_pos: (end_col, end_row),
@ -195,7 +200,26 @@ impl LevelGenerator {
}
}
LevelGenerator { level, rooms }
LevelGenerator {
level,
rooms,
rng,
}
}
fn select_monster(position: Position, rng: &mut ThreadRng) -> Box<dyn Monster> {
let level = position.get_level();
let value = rng.gen_range(1..=100);
let t = get_monsters_per_level();
if level < t.len() {
for (mtype, range) in &t[level] {
if range.contains(&value) {
return create_monster_by_type(mtype, position);
}
}
}
panic!("no monster selectable!");
}
fn select_room_type(level: usize, rng: &mut ThreadRng) -> RoomType {
@ -216,18 +240,37 @@ impl LevelGenerator {
let mut structure = [[StructureElement::Wall; LEVEL_HEIGHT]; LEVEL_WIDTH];
let mut start_pos = (0, 0);
let mut end_pos = (0, 0);
let mut monsters: Vec<Box<dyn Monster>> = Vec::with_capacity(10);
let mut artifacts: Vec<Box<dyn Artifact>> = Vec::with_capacity(10);
for col in 0..ROOMS_HORIZONAL {
for row in 0..ROOMS_VERTICAL {
let position = self.rooms[col][row].render(&mut structure, col, row);
if self.rooms[col][row].kind == RoomType::Start
|| self.rooms[col][row].kind == RoomType::StairUp
{
start_pos = position;
let room = self.rooms[col][row];
let position = room.render(&mut structure, col, row);
match room.kind {
RoomType::Start => {start_pos=position},
RoomType::End => {end_pos=position},
RoomType::StairUp => {start_pos=position},
RoomType::StairDown => {end_pos=position},
RoomType::BasicRoom => {},
RoomType::ArtifactRoom => {
match self.rng.gen_range(1..=100) {
1..=50 => {
artifacts
.push(Box::new(Chest::new(Position::new(self.level, position.0, position.1))));
}
if self.rooms[col][row].kind == RoomType::End
|| self.rooms[col][row].kind == RoomType::StairDown
{
end_pos = position;
_ => {
artifacts
.push(Box::new(Potion::new(Position::new(self.level, position.0, position.1))));
}
};
},
RoomType::MonsterRoom => {
monsters.push(LevelGenerator::select_monster(
Position::new(self.level, position.0, position.1),
&mut self.rng,
));
},
RoomType::EmptyRoom => {},
}
}
}
@ -247,8 +290,8 @@ impl LevelGenerator {
level: self.level,
structure,
discovered: [[false; LEVEL_HEIGHT]; LEVEL_WIDTH],
monsters: vec![],
artifacts: vec![],
monsters,
artifacts,
start: start_pos,
end: end_pos,
rng: rand::thread_rng(),

View File

@ -1,6 +1,6 @@
use ratatui::buffer::Buffer;
use ratatui::layout::Rect;
use ratatui::style::Color;
use ratatui::style::{Color, Modifier, Style};
use ratatui::widgets::{StatefulWidget, Widget};
use crate::game::Game;
@ -15,6 +15,9 @@ impl LevelWidget {
fn set_cell(&self, buf: &mut Buffer, x: u16, y: u16, symbol: &str, fg: Color, bg: Color) {
buf[(x, y)].set_symbol(symbol).set_bg(bg).set_fg(fg);
}
fn set_bold_cell(&self, buf: &mut Buffer, x: u16, y: u16, symbol: &str, fg: Color, bg: Color) {
buf[(x, y)].set_symbol(symbol).set_bg(bg).set_fg(fg).set_style(Style::new().add_modifier(Modifier::BOLD));
}
}
impl StatefulWidget for LevelWidget {
@ -46,7 +49,7 @@ impl StatefulWidget for LevelWidget {
}
StructureElement::Wall => {
// TODO add fancy walls with https://en.wikipedia.org/wiki/Box-drawing_characters
self.set_cell(buf, x, y, "#", FG_BROWN, Color::Gray);
self.set_cell(buf, x, y, "#", FG_BROWN, FG_BROWN);
}
StructureElement::Floor => {
self.set_cell(buf, x, y, " ", FG_BROWN, Color::Gray);
@ -68,7 +71,7 @@ impl StatefulWidget for LevelWidget {
}
(_, _, Some(t)) => {
let (s, c) = t.get_representation();
self.set_cell(buf, x, y, s, c, Color::Gray);
self.set_bold_cell(buf, x, y, s, c, Color::Gray);
}
(None, None, None) => {}
};

View File

@ -119,26 +119,20 @@ impl Room {
match self.kind {
RoomType::Start => {
tgt[left + self.special.0][top + self.special.1] = StructureElement::Start;
(left + self.special.0, top + self.special.1)
}
RoomType::End => {
tgt[left + self.special.0][top + self.special.1] = StructureElement::End;
(left + self.special.0, top + self.special.1)
}
RoomType::StairUp => {
tgt[left + self.special.0][top + self.special.1] = StructureElement::StairUp;
(left + self.special.0, top + self.special.1)
}
RoomType::StairDown => {
tgt[left + self.special.0][top + self.special.1] = StructureElement::StairDown;
}
_ => {}
};
(left + self.special.0, top + self.special.1)
}
RoomType::BasicRoom => (0, 0),
RoomType::ArtifactRoom => (0, 0),
RoomType::MonsterRoom => (0, 0),
RoomType::EmptyRoom => (0, 0),
}
}
}
#[test]