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_generator::LevelGenerator;
|
||||
use crate::player::Player;
|
||||
use crate::position::{HasPosition, Position};
|
||||
|
||||
/// How many levels does the dungeon have?
|
||||
pub const LEVELS: usize = 2;
|
||||
|
||||
#[derive(PartialEq)]
|
||||
/// represents a state of a game
|
||||
pub enum GameState {
|
||||
|
|
|
@ -6,10 +6,8 @@ use rand::Rng;
|
|||
use crate::artifacts::Artifact;
|
||||
#[cfg(test)]
|
||||
use crate::artifacts::{Chest, Potion};
|
||||
use crate::level_generator::ROOMS_HORIZONTAL;
|
||||
use crate::level_generator::ROOMS_VERTICAL;
|
||||
use crate::level_generator::ROOM_HEIGHT;
|
||||
use crate::level_generator::ROOM_WIDTH;
|
||||
use crate::constants::LEVEL_HEIGHT;
|
||||
use crate::constants::LEVEL_WIDTH;
|
||||
use crate::monster::Monster;
|
||||
#[cfg(test)]
|
||||
use crate::monster::{Orc, Rat};
|
||||
|
@ -17,9 +15,6 @@ use crate::player::Player;
|
|||
use crate::position::HasPosition;
|
||||
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)]
|
||||
pub enum StructureElement {
|
||||
Start,
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
use std::cmp::{max, min};
|
||||
use std::collections::HashMap;
|
||||
use std::ops::Range;
|
||||
|
||||
use petgraph::algo::min_spanning_tree;
|
||||
|
@ -11,16 +10,13 @@ use rand::rngs::ThreadRng;
|
|||
use rand::Rng;
|
||||
|
||||
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::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;
|
||||
|
||||
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)]
|
||||
enum RoomType {
|
||||
Start,
|
||||
|
@ -266,15 +262,7 @@ impl LevelGenerator {
|
|||
let level = position.get_level();
|
||||
let value = rng.gen_range(1..=100);
|
||||
|
||||
let t = [
|
||||
// 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)]),
|
||||
];
|
||||
let t = get_monsters_per_level();
|
||||
if level < t.len() {
|
||||
for (mtype, range) in &t[level] {
|
||||
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::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::{
|
||||
event::{self, KeyCode, KeyEventKind},
|
||||
terminal::{disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen},
|
||||
|
@ -22,6 +28,7 @@ use crate::player::Player;
|
|||
use crate::position::HasPosition;
|
||||
|
||||
mod artifacts;
|
||||
mod constants;
|
||||
mod game;
|
||||
mod level;
|
||||
mod level_generator;
|
||||
|
@ -30,12 +37,6 @@ mod monster;
|
|||
mod player;
|
||||
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<()> {
|
||||
let mut game = Game::new(Player::new(realname().as_str(), 30));
|
||||
|
@ -79,15 +80,15 @@ fn main() -> Result<()> {
|
|||
area.width = MIN_WIDTH;
|
||||
}
|
||||
if area.height > MIN_HEIGHT {
|
||||
area.y = (area.height - level::LEVEL_HEIGHT as u16) / 2;
|
||||
area.height = level::LEVEL_HEIGHT as u16;
|
||||
area.y = (area.height - LEVEL_HEIGHT as u16) / 2;
|
||||
area.height = LEVEL_HEIGHT as u16;
|
||||
}
|
||||
|
||||
let map_area = Rect {
|
||||
x: area.x,
|
||||
y: area.y,
|
||||
width: level::LEVEL_WIDTH as u16,
|
||||
height: level::LEVEL_HEIGHT as u16,
|
||||
width: LEVEL_WIDTH as u16,
|
||||
height: LEVEL_HEIGHT as u16,
|
||||
};
|
||||
frame.render_stateful_widget(LevelWidget {}, map_area, &mut game);
|
||||
|
||||
|
@ -109,12 +110,13 @@ fn main() -> Result<()> {
|
|||
.style(Style::default().bg(Color::Blue));
|
||||
frame.render_widget(
|
||||
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_max_life(),
|
||||
game.get_player().get_experience(),
|
||||
game.get_player().get_gold(),
|
||||
game.get_player().get_immutable_position().get_level() + 1,
|
||||
LEVELS,
|
||||
game.get_player().inventory_size().0,
|
||||
game.get_player().inventory_size().1,
|
||||
))
|
||||
|
|
|
@ -18,12 +18,13 @@ pub trait Monster: HasPosition {
|
|||
fn damage(&self) -> usize;
|
||||
}
|
||||
|
||||
#[derive(CreateMonsters, PartialEq, Eq, Hash)]
|
||||
#[derive(CreateMonsters, PartialEq, Eq, Hash, Clone, Copy)]
|
||||
pub enum MonsterTypes {
|
||||
Rat,
|
||||
Orc,
|
||||
Snake,
|
||||
Skeleton,
|
||||
Spider,
|
||||
}
|
||||
|
||||
macro_rules! create_monster {
|
||||
|
@ -43,13 +44,24 @@ create_monster!(
|
|||
Rat,
|
||||
name:"rat".to_string(),
|
||||
life: 2,
|
||||
symbol: String::from("R"),
|
||||
symbol: String::from("r"),
|
||||
color: Color::Black,
|
||||
experience_gain: 5,
|
||||
ticks_between_steps: 5,
|
||||
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!(
|
||||
Orc,
|
||||
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::Snake => Box::new(Snake::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