Extract constants and make monsters variable per level
This commit is contained in:
parent
e490011b4e
commit
b833b43c7c
|
@ -0,0 +1,58 @@
|
||||||
|
use std::{collections::HashMap, ops::RangeInclusive};
|
||||||
|
|
||||||
|
use crate::monster::MonsterTypes;
|
||||||
|
|
||||||
|
/// the number of rooms in vertical direction
|
||||||
|
pub const ROOMS_VERTICAL: usize = 7;
|
||||||
|
/// the number of rooms in horizontal direction
|
||||||
|
pub const ROOMS_HORIZONTAL: usize = 7;
|
||||||
|
|
||||||
|
/// the width of a room in the grid of rooms (number of characters)
|
||||||
|
pub const ROOM_WIDTH: usize = 9;
|
||||||
|
/// the height of a room in the grid of rooms (number of characters)
|
||||||
|
pub const ROOM_HEIGHT: usize = 6;
|
||||||
|
|
||||||
|
/// How many levels does the dungeon have?
|
||||||
|
pub const LEVELS: usize = 3;
|
||||||
|
|
||||||
|
/// length of a game frame in ms
|
||||||
|
pub const FRAME_LENGTH: u64 = 100;
|
||||||
|
|
||||||
|
/// define the minimum width of a terminal to run the game, must be at least the level width plus some space for stats and messages
|
||||||
|
pub const MIN_WIDTH: u16 = 120;
|
||||||
|
/// define the minimum height of a terminal to run the game, this must be at least the level height!
|
||||||
|
pub const MIN_HEIGHT: u16 = LEVEL_HEIGHT as u16;
|
||||||
|
|
||||||
|
/// the calculated width of a level
|
||||||
|
pub const LEVEL_WIDTH: usize = 1 + ROOMS_VERTICAL * ROOM_WIDTH;
|
||||||
|
/// the calculated height of a level
|
||||||
|
pub const LEVEL_HEIGHT: usize = 1 + ROOMS_HORIZONTAL * ROOM_HEIGHT;
|
||||||
|
|
||||||
|
pub fn get_monsters_per_level() -> Vec<HashMap<MonsterTypes, std::ops::RangeInclusive<u8>>> {
|
||||||
|
let tmp = vec![
|
||||||
|
// level 1
|
||||||
|
vec![(MonsterTypes::Rat, 50), (MonsterTypes::Spider, 50)],
|
||||||
|
// level 2
|
||||||
|
vec![(MonsterTypes::Rat, 50), (MonsterTypes::Snake, 50)],
|
||||||
|
// level 3
|
||||||
|
vec![(MonsterTypes::Orc, 33), (MonsterTypes::Skeleton, 33), (MonsterTypes::Snake, 33)],
|
||||||
|
];
|
||||||
|
if tmp.len() != LEVELS {
|
||||||
|
panic!("Only {} monster sets defined for {} levels!", tmp.len(), LEVELS);
|
||||||
|
}
|
||||||
|
let mut result: Vec<HashMap<MonsterTypes, std::ops::RangeInclusive<u8>>> = vec![];
|
||||||
|
for (idx, level) in tmp.iter().enumerate() {
|
||||||
|
let mut sum = 0;
|
||||||
|
let mut map: HashMap<MonsterTypes, RangeInclusive<u8>> = HashMap::new();
|
||||||
|
for monster in level {
|
||||||
|
map.insert(monster.0, RangeInclusive::new(sum+1, sum+monster.1));
|
||||||
|
sum += monster.1;
|
||||||
|
|
||||||
|
}
|
||||||
|
if sum != 100 {
|
||||||
|
panic!("all percentages must add to 100 (was {}) per level, error in level {}!", sum, idx+1);
|
||||||
|
}
|
||||||
|
result.push(map);
|
||||||
|
}
|
||||||
|
result
|
||||||
|
}
|
|
@ -1,11 +1,9 @@
|
||||||
|
use crate::constants::LEVELS;
|
||||||
use crate::level::{Level, StructureElement};
|
use crate::level::{Level, StructureElement};
|
||||||
use crate::level_generator::LevelGenerator;
|
use crate::level_generator::LevelGenerator;
|
||||||
use crate::player::Player;
|
use crate::player::Player;
|
||||||
use crate::position::{HasPosition, Position};
|
use crate::position::{HasPosition, Position};
|
||||||
|
|
||||||
/// How many levels does the dungeon have?
|
|
||||||
pub const LEVELS: usize = 2;
|
|
||||||
|
|
||||||
#[derive(PartialEq)]
|
#[derive(PartialEq)]
|
||||||
/// represents a state of a game
|
/// represents a state of a game
|
||||||
pub enum GameState {
|
pub enum GameState {
|
||||||
|
|
|
@ -6,10 +6,8 @@ use rand::Rng;
|
||||||
use crate::artifacts::Artifact;
|
use crate::artifacts::Artifact;
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
use crate::artifacts::{Chest, Potion};
|
use crate::artifacts::{Chest, Potion};
|
||||||
use crate::level_generator::ROOMS_HORIZONTAL;
|
use crate::constants::LEVEL_HEIGHT;
|
||||||
use crate::level_generator::ROOMS_VERTICAL;
|
use crate::constants::LEVEL_WIDTH;
|
||||||
use crate::level_generator::ROOM_HEIGHT;
|
|
||||||
use crate::level_generator::ROOM_WIDTH;
|
|
||||||
use crate::monster::Monster;
|
use crate::monster::Monster;
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
use crate::monster::{Orc, Rat};
|
use crate::monster::{Orc, Rat};
|
||||||
|
@ -17,9 +15,6 @@ use crate::player::Player;
|
||||||
use crate::position::HasPosition;
|
use crate::position::HasPosition;
|
||||||
use crate::position::Position;
|
use crate::position::Position;
|
||||||
|
|
||||||
pub const LEVEL_WIDTH: usize = 1 + ROOMS_VERTICAL * ROOM_WIDTH;
|
|
||||||
pub const LEVEL_HEIGHT: usize = 1 + ROOMS_HORIZONTAL * ROOM_HEIGHT;
|
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, PartialEq)]
|
#[derive(Copy, Clone, Debug, PartialEq)]
|
||||||
pub enum StructureElement {
|
pub enum StructureElement {
|
||||||
Start,
|
Start,
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
use std::cmp::{max, min};
|
use std::cmp::{max, min};
|
||||||
use std::collections::HashMap;
|
|
||||||
use std::ops::Range;
|
use std::ops::Range;
|
||||||
|
|
||||||
use petgraph::algo::min_spanning_tree;
|
use petgraph::algo::min_spanning_tree;
|
||||||
|
@ -11,16 +10,13 @@ use rand::rngs::ThreadRng;
|
||||||
use rand::Rng;
|
use rand::Rng;
|
||||||
|
|
||||||
use crate::artifacts::{Artifact, Chest, Potion};
|
use crate::artifacts::{Artifact, Chest, Potion};
|
||||||
|
use crate::constants::{
|
||||||
|
get_monsters_per_level, ROOMS_HORIZONTAL, ROOMS_VERTICAL, ROOM_HEIGHT, ROOM_WIDTH,
|
||||||
|
};
|
||||||
use crate::level::{Level, StructureElement};
|
use crate::level::{Level, StructureElement};
|
||||||
use crate::monster::{create_monster_by_type, Monster, MonsterTypes, Orc, Rat, Snake};
|
use crate::monster::{create_monster_by_type, Monster, Orc, Rat, Snake};
|
||||||
use crate::position::Position;
|
use crate::position::Position;
|
||||||
|
|
||||||
pub const ROOMS_VERTICAL: usize = 7;
|
|
||||||
pub const ROOMS_HORIZONTAL: usize = 7;
|
|
||||||
|
|
||||||
pub const ROOM_WIDTH: usize = 9;
|
|
||||||
pub const ROOM_HEIGHT: usize = 6;
|
|
||||||
|
|
||||||
#[derive(PartialEq, Copy, Clone)]
|
#[derive(PartialEq, Copy, Clone)]
|
||||||
enum RoomType {
|
enum RoomType {
|
||||||
Start,
|
Start,
|
||||||
|
@ -266,15 +262,7 @@ impl LevelGenerator {
|
||||||
let level = position.get_level();
|
let level = position.get_level();
|
||||||
let value = rng.gen_range(1..=100);
|
let value = rng.gen_range(1..=100);
|
||||||
|
|
||||||
let t = [
|
let t = get_monsters_per_level();
|
||||||
// level 0
|
|
||||||
HashMap::from([(MonsterTypes::Rat, 1..=100)]),
|
|
||||||
// level 1
|
|
||||||
HashMap::from([(MonsterTypes::Rat, 1..=50), (MonsterTypes::Snake, 51..=100)]),
|
|
||||||
// level 2
|
|
||||||
HashMap::from([(MonsterTypes::Orc, 1..=100)]),
|
|
||||||
HashMap::from([(MonsterTypes::Skeleton, 1..=100)]),
|
|
||||||
];
|
|
||||||
if level < t.len() {
|
if level < t.len() {
|
||||||
for (mtype, range) in &t[level] {
|
for (mtype, range) in &t[level] {
|
||||||
if range.contains(&value) {
|
if range.contains(&value) {
|
||||||
|
|
24
src/main.rs
24
src/main.rs
|
@ -2,6 +2,12 @@ use std::io::stdout;
|
||||||
use std::io::Result;
|
use std::io::Result;
|
||||||
use std::time::Instant;
|
use std::time::Instant;
|
||||||
|
|
||||||
|
use constants::FRAME_LENGTH;
|
||||||
|
use constants::LEVELS;
|
||||||
|
use constants::LEVEL_HEIGHT;
|
||||||
|
use constants::LEVEL_WIDTH;
|
||||||
|
use constants::MIN_HEIGHT;
|
||||||
|
use constants::MIN_WIDTH;
|
||||||
use crossterm::{
|
use crossterm::{
|
||||||
event::{self, KeyCode, KeyEventKind},
|
event::{self, KeyCode, KeyEventKind},
|
||||||
terminal::{disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen},
|
terminal::{disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen},
|
||||||
|
@ -22,6 +28,7 @@ use crate::player::Player;
|
||||||
use crate::position::HasPosition;
|
use crate::position::HasPosition;
|
||||||
|
|
||||||
mod artifacts;
|
mod artifacts;
|
||||||
|
mod constants;
|
||||||
mod game;
|
mod game;
|
||||||
mod level;
|
mod level;
|
||||||
mod level_generator;
|
mod level_generator;
|
||||||
|
@ -30,12 +37,6 @@ mod monster;
|
||||||
mod player;
|
mod player;
|
||||||
mod position;
|
mod position;
|
||||||
|
|
||||||
/// length of a game frame in ms
|
|
||||||
pub const FRAME_LENGTH: u64 = 100;
|
|
||||||
|
|
||||||
pub const MIN_WIDTH: u16 = 120;
|
|
||||||
pub const MIN_HEIGHT: u16 = 30;
|
|
||||||
|
|
||||||
//
|
//
|
||||||
fn main() -> Result<()> {
|
fn main() -> Result<()> {
|
||||||
let mut game = Game::new(Player::new(realname().as_str(), 30));
|
let mut game = Game::new(Player::new(realname().as_str(), 30));
|
||||||
|
@ -79,15 +80,15 @@ fn main() -> Result<()> {
|
||||||
area.width = MIN_WIDTH;
|
area.width = MIN_WIDTH;
|
||||||
}
|
}
|
||||||
if area.height > MIN_HEIGHT {
|
if area.height > MIN_HEIGHT {
|
||||||
area.y = (area.height - level::LEVEL_HEIGHT as u16) / 2;
|
area.y = (area.height - LEVEL_HEIGHT as u16) / 2;
|
||||||
area.height = level::LEVEL_HEIGHT as u16;
|
area.height = LEVEL_HEIGHT as u16;
|
||||||
}
|
}
|
||||||
|
|
||||||
let map_area = Rect {
|
let map_area = Rect {
|
||||||
x: area.x,
|
x: area.x,
|
||||||
y: area.y,
|
y: area.y,
|
||||||
width: level::LEVEL_WIDTH as u16,
|
width: LEVEL_WIDTH as u16,
|
||||||
height: level::LEVEL_HEIGHT as u16,
|
height: LEVEL_HEIGHT as u16,
|
||||||
};
|
};
|
||||||
frame.render_stateful_widget(LevelWidget {}, map_area, &mut game);
|
frame.render_stateful_widget(LevelWidget {}, map_area, &mut game);
|
||||||
|
|
||||||
|
@ -109,12 +110,13 @@ fn main() -> Result<()> {
|
||||||
.style(Style::default().bg(Color::Blue));
|
.style(Style::default().bg(Color::Blue));
|
||||||
frame.render_widget(
|
frame.render_widget(
|
||||||
Paragraph::new(format!(
|
Paragraph::new(format!(
|
||||||
"Health: {}/{}\nExp: {}\nGold: {}\nLevel: {}\nInventory: {}/{}",
|
"Health: {} of {}\nExp: {}\nGold: {}\nLevel: {} of {}\nInventory used: {} of {}",
|
||||||
game.get_player().get_life(),
|
game.get_player().get_life(),
|
||||||
game.get_player().get_max_life(),
|
game.get_player().get_max_life(),
|
||||||
game.get_player().get_experience(),
|
game.get_player().get_experience(),
|
||||||
game.get_player().get_gold(),
|
game.get_player().get_gold(),
|
||||||
game.get_player().get_immutable_position().get_level() + 1,
|
game.get_player().get_immutable_position().get_level() + 1,
|
||||||
|
LEVELS,
|
||||||
game.get_player().inventory_size().0,
|
game.get_player().inventory_size().0,
|
||||||
game.get_player().inventory_size().1,
|
game.get_player().inventory_size().1,
|
||||||
))
|
))
|
||||||
|
|
|
@ -18,12 +18,13 @@ pub trait Monster: HasPosition {
|
||||||
fn damage(&self) -> usize;
|
fn damage(&self) -> usize;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(CreateMonsters, PartialEq, Eq, Hash)]
|
#[derive(CreateMonsters, PartialEq, Eq, Hash, Clone, Copy)]
|
||||||
pub enum MonsterTypes {
|
pub enum MonsterTypes {
|
||||||
Rat,
|
Rat,
|
||||||
Orc,
|
Orc,
|
||||||
Snake,
|
Snake,
|
||||||
Skeleton,
|
Skeleton,
|
||||||
|
Spider,
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! create_monster {
|
macro_rules! create_monster {
|
||||||
|
@ -43,13 +44,24 @@ create_monster!(
|
||||||
Rat,
|
Rat,
|
||||||
name:"rat".to_string(),
|
name:"rat".to_string(),
|
||||||
life: 2,
|
life: 2,
|
||||||
symbol: String::from("R"),
|
symbol: String::from("r"),
|
||||||
color: Color::Black,
|
color: Color::Black,
|
||||||
experience_gain: 5,
|
experience_gain: 5,
|
||||||
ticks_between_steps: 5,
|
ticks_between_steps: 5,
|
||||||
damage_range: 1..=2,
|
damage_range: 1..=2,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
create_monster!(
|
||||||
|
Spider,
|
||||||
|
name:"spider".to_string(),
|
||||||
|
life: 3,
|
||||||
|
symbol: String::from("s"),
|
||||||
|
color: Color::Blue,
|
||||||
|
experience_gain: 7,
|
||||||
|
ticks_between_steps: 7,
|
||||||
|
damage_range: 2..=3,
|
||||||
|
);
|
||||||
|
|
||||||
create_monster!(
|
create_monster!(
|
||||||
Orc,
|
Orc,
|
||||||
name: "orc".to_string(),
|
name: "orc".to_string(),
|
||||||
|
@ -89,6 +101,7 @@ pub fn create_monster_by_type(monster_type: &MonsterTypes, position: Position) -
|
||||||
MonsterTypes::Orc => Box::new(Orc::new_with_position(position)),
|
MonsterTypes::Orc => Box::new(Orc::new_with_position(position)),
|
||||||
MonsterTypes::Snake => Box::new(Snake::new_with_position(position)),
|
MonsterTypes::Snake => Box::new(Snake::new_with_position(position)),
|
||||||
MonsterTypes::Skeleton => Box::new(Skeleton::new_with_position(position)),
|
MonsterTypes::Skeleton => Box::new(Skeleton::new_with_position(position)),
|
||||||
|
MonsterTypes::Spider => Box::new(Spider::new_with_position(position)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue