work on level generator
This commit is contained in:
parent
7f288dbcd1
commit
c6492c28c2
|
@ -73,7 +73,8 @@ pub fn get_room_type_per_level() -> Vec<HashMap<RoomType, std::ops::RangeInclusi
|
||||||
let tmp = [
|
let tmp = [
|
||||||
// level 1
|
// level 1
|
||||||
vec![
|
vec![
|
||||||
(RoomType::EmptyRoom, 75),
|
(RoomType::EmptyRoom, 50),
|
||||||
|
(RoomType::ArtifactRoom, 25),
|
||||||
(RoomType::MonsterRoom, 5),
|
(RoomType::MonsterRoom, 5),
|
||||||
(RoomType::BasicRoom, 20),
|
(RoomType::BasicRoom, 20),
|
||||||
],
|
],
|
||||||
|
|
|
@ -57,6 +57,7 @@ impl Level {
|
||||||
return (None, None, None);
|
return (None, None, None);
|
||||||
}
|
}
|
||||||
if !self.discovered[x][y] {
|
if !self.discovered[x][y] {
|
||||||
|
#[cfg(test)]
|
||||||
return (Some(StructureElement::Unknown), None, None);
|
return (Some(StructureElement::Unknown), None, None);
|
||||||
}
|
}
|
||||||
let search_pos = &Position::new(self.level, x, y);
|
let search_pos = &Position::new(self.level, x, y);
|
||||||
|
|
|
@ -2,15 +2,19 @@ use petgraph::algo::min_spanning_tree;
|
||||||
use petgraph::data::*;
|
use petgraph::data::*;
|
||||||
use petgraph::graph::Graph;
|
use petgraph::graph::Graph;
|
||||||
use petgraph::graph::UnGraph;
|
use petgraph::graph::UnGraph;
|
||||||
use std::cmp::max;
|
|
||||||
use std::cmp::min;
|
|
||||||
use std::ops::Range;
|
|
||||||
|
|
||||||
use rand::Rng;
|
use rand::Rng;
|
||||||
use rand::{rngs::ThreadRng, seq::SliceRandom};
|
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_HEIGHT;
|
||||||
use crate::constants::ROOM_WIDTH;
|
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::room::Connection;
|
||||||
use crate::{
|
use crate::{
|
||||||
constants::{
|
constants::{
|
||||||
|
@ -23,6 +27,7 @@ use crate::{
|
||||||
pub struct LevelGenerator {
|
pub struct LevelGenerator {
|
||||||
level: usize,
|
level: usize,
|
||||||
rooms: [[Room; ROOMS_VERTICAL]; ROOMS_HORIZONAL],
|
rooms: [[Room; ROOMS_VERTICAL]; ROOMS_HORIZONAL],
|
||||||
|
rng: ThreadRng,
|
||||||
}
|
}
|
||||||
enum Direction {
|
enum Direction {
|
||||||
Horizontal,
|
Horizontal,
|
||||||
|
@ -103,7 +108,7 @@ impl LevelGenerator {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// debug print a text view of the dungeon
|
||||||
println!(" 0 1 2 3 4 5 6 7");
|
println!(" 0 1 2 3 4 5 6 7");
|
||||||
for r in 0..ROOMS_VERTICAL {
|
for r in 0..ROOMS_VERTICAL {
|
||||||
print!("{} ", r);
|
print!("{} ", r);
|
||||||
|
@ -174,20 +179,20 @@ impl LevelGenerator {
|
||||||
|
|
||||||
if src_node_col == tgt_node_col {
|
if src_node_col == tgt_node_col {
|
||||||
// println!("Down");
|
// println!("Down");
|
||||||
let start_col = src_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 start_row = src_node_row * ROOM_HEIGHT + ROOM_HEIGHT;
|
||||||
let end_col = tgt_node_col * ROOM_WIDTH+ROOM_WIDTH/2;
|
let end_col = tgt_node_col * ROOM_WIDTH + ROOM_WIDTH / 2;
|
||||||
let end_row = tgt_node_row * ROOM_HEIGHT;
|
let end_row = tgt_node_row * ROOM_HEIGHT;
|
||||||
rooms[src_node_col][src_node_row].connection_down = Some(Connection {
|
rooms[src_node_col][src_node_row].connection_down = Some(Connection {
|
||||||
start_pos: (start_col, start_row),
|
start_pos: (start_col, start_row),
|
||||||
end_pos: (end_col, end_row),
|
end_pos: (end_col, end_row),
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
// println!("Right");
|
// println!("Right");
|
||||||
let start_col = src_node_col * ROOM_WIDTH+ROOM_WIDTH;
|
let start_col = src_node_col * ROOM_WIDTH + ROOM_WIDTH;
|
||||||
let start_row = src_node_row * ROOM_HEIGHT+ROOM_HEIGHT/2;
|
let start_row = src_node_row * ROOM_HEIGHT + ROOM_HEIGHT / 2;
|
||||||
let end_col = tgt_node_col * ROOM_WIDTH;
|
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 {
|
rooms[src_node_col][src_node_row].connection_right = Some(Connection {
|
||||||
start_pos: (start_col, start_row),
|
start_pos: (start_col, start_row),
|
||||||
end_pos: (end_col, end_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 {
|
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 structure = [[StructureElement::Wall; LEVEL_HEIGHT]; LEVEL_WIDTH];
|
||||||
let mut start_pos = (0, 0);
|
let mut start_pos = (0, 0);
|
||||||
let mut end_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 col in 0..ROOMS_HORIZONAL {
|
||||||
for row in 0..ROOMS_VERTICAL {
|
for row in 0..ROOMS_VERTICAL {
|
||||||
let position = self.rooms[col][row].render(&mut structure, col, row);
|
let room = self.rooms[col][row];
|
||||||
if self.rooms[col][row].kind == RoomType::Start
|
let position = room.render(&mut structure, col, row);
|
||||||
|| self.rooms[col][row].kind == RoomType::StairUp
|
match room.kind {
|
||||||
{
|
RoomType::Start => {start_pos=position},
|
||||||
start_pos = position;
|
RoomType::End => {end_pos=position},
|
||||||
}
|
RoomType::StairUp => {start_pos=position},
|
||||||
if self.rooms[col][row].kind == RoomType::End
|
RoomType::StairDown => {end_pos=position},
|
||||||
|| self.rooms[col][row].kind == RoomType::StairDown
|
RoomType::BasicRoom => {},
|
||||||
{
|
RoomType::ArtifactRoom => {
|
||||||
end_pos = position;
|
match self.rng.gen_range(1..=100) {
|
||||||
|
1..=50 => {
|
||||||
|
artifacts
|
||||||
|
.push(Box::new(Chest::new(Position::new(self.level, position.0, position.1))));
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
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,
|
level: self.level,
|
||||||
structure,
|
structure,
|
||||||
discovered: [[false; LEVEL_HEIGHT]; LEVEL_WIDTH],
|
discovered: [[false; LEVEL_HEIGHT]; LEVEL_WIDTH],
|
||||||
monsters: vec![],
|
monsters,
|
||||||
artifacts: vec![],
|
artifacts,
|
||||||
start: start_pos,
|
start: start_pos,
|
||||||
end: end_pos,
|
end: end_pos,
|
||||||
rng: rand::thread_rng(),
|
rng: rand::thread_rng(),
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use ratatui::buffer::Buffer;
|
use ratatui::buffer::Buffer;
|
||||||
use ratatui::layout::Rect;
|
use ratatui::layout::Rect;
|
||||||
use ratatui::style::Color;
|
use ratatui::style::{Color, Modifier, Style};
|
||||||
use ratatui::widgets::{StatefulWidget, Widget};
|
use ratatui::widgets::{StatefulWidget, Widget};
|
||||||
|
|
||||||
use crate::game::Game;
|
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) {
|
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);
|
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 {
|
impl StatefulWidget for LevelWidget {
|
||||||
|
@ -46,7 +49,7 @@ impl StatefulWidget for LevelWidget {
|
||||||
}
|
}
|
||||||
StructureElement::Wall => {
|
StructureElement::Wall => {
|
||||||
// TODO add fancy walls with https://en.wikipedia.org/wiki/Box-drawing_characters
|
// 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 => {
|
StructureElement::Floor => {
|
||||||
self.set_cell(buf, x, y, " ", FG_BROWN, Color::Gray);
|
self.set_cell(buf, x, y, " ", FG_BROWN, Color::Gray);
|
||||||
|
@ -68,7 +71,7 @@ impl StatefulWidget for LevelWidget {
|
||||||
}
|
}
|
||||||
(_, _, Some(t)) => {
|
(_, _, Some(t)) => {
|
||||||
let (s, c) = t.get_representation();
|
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) => {}
|
(None, None, None) => {}
|
||||||
};
|
};
|
||||||
|
|
12
src/room.rs
12
src/room.rs
|
@ -119,25 +119,19 @@ impl Room {
|
||||||
match self.kind {
|
match self.kind {
|
||||||
RoomType::Start => {
|
RoomType::Start => {
|
||||||
tgt[left + self.special.0][top + self.special.1] = StructureElement::Start;
|
tgt[left + self.special.0][top + self.special.1] = StructureElement::Start;
|
||||||
(left + self.special.0, top + self.special.1)
|
|
||||||
}
|
}
|
||||||
RoomType::End => {
|
RoomType::End => {
|
||||||
tgt[left + self.special.0][top + self.special.1] = StructureElement::End;
|
tgt[left + self.special.0][top + self.special.1] = StructureElement::End;
|
||||||
(left + self.special.0, top + self.special.1)
|
|
||||||
}
|
}
|
||||||
RoomType::StairUp => {
|
RoomType::StairUp => {
|
||||||
tgt[left + self.special.0][top + self.special.1] = StructureElement::StairUp;
|
tgt[left + self.special.0][top + self.special.1] = StructureElement::StairUp;
|
||||||
(left + self.special.0, top + self.special.1)
|
|
||||||
}
|
}
|
||||||
RoomType::StairDown => {
|
RoomType::StairDown => {
|
||||||
tgt[left + self.special.0][top + self.special.1] = StructureElement::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),
|
(left + self.special.0, top + self.special.1)
|
||||||
RoomType::EmptyRoom => (0, 0),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue