use macros to create monsters

This commit is contained in:
2024-10-25 07:21:34 +02:00
parent 8267ad083f
commit e490011b4e
6 changed files with 221 additions and 99 deletions

View File

@@ -12,7 +12,7 @@ use rand::Rng;
use crate::artifacts::{Artifact, Chest, Potion};
use crate::level::{Level, StructureElement};
use crate::monster::{create_monster_by_type, Monster, Orc, Rat, Snake};
use crate::monster::{create_monster_by_type, Monster, MonsterTypes, Orc, Rat, Snake};
use crate::position::Position;
pub const ROOMS_VERTICAL: usize = 7;
@@ -268,11 +268,12 @@ impl LevelGenerator {
let t = [
// level 0
HashMap::from([("Rat", 1..=100)]),
HashMap::from([(MonsterTypes::Rat, 1..=100)]),
// level 1
// HashMap::from([("Rat", 1..=50), ("Snake", 51..=100)]),
// // level 2
// HashMap::from([("Rat", 1..=40)]),
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() {
for (mtype, range) in &t[level] {

View File

@@ -1,10 +1,10 @@
use std::ops::RangeInclusive;
use crate::position::{HasPosition, Position};
use macros::CreateMonsters;
use rand::Rng;
use ratatui::prelude::Color;
use crate::position::{HasPosition, Position};
pub trait Monster: HasPosition {
fn get_name(&self) -> &str;
fn is_dead(&self) -> bool;
@@ -18,99 +18,77 @@ pub trait Monster: HasPosition {
fn damage(&self) -> usize;
}
#[derive(CreateMonsters, PartialEq, Eq, Hash)]
pub enum MonsterTypes {
Rat,
Orc,
Snake,
Skeleton,
}
macro_rules! create_monster {
($($t:ident),+ $(,)?) => ($(
pub struct $t {
name: String,
life: usize,
position: Position,
symbol: String,
color: Color,
experience_gain: usize,
ticks_between_steps: u128,
damage_range: RangeInclusive<usize>,
}
impl Monster for $t {
fn get_name(&self) -> &str { &self.name }
fn is_dead(&self) -> bool { self.life <= 0 }
fn get_experience_gain(&self) -> usize { self.experience_gain }
fn get_representation(&self) -> (&str, Color) { (&self.symbol, self.color) }
fn decrease_life(&mut self, by: usize) {
self.life = self.life.saturating_sub(by);
}
fn get_ticks_between_steps(&self) -> u128 { self.ticks_between_steps }
fn damage(&self) -> usize { rand::thread_rng().gen_range(self.damage_range.clone()) }
#[cfg(test)]
fn get_life(&self) -> usize { self.life }
}
impl HasPosition for $t {
fn get_position(&mut self) -> &mut Position {
&mut self.position
}
fn get_immutable_position(&self) -> &Position {
&self.position
($t:ident $(, $k:ident : $v:expr)*$(,)?) => (
impl $t {
pub fn new_with_position(position: Position) -> Self {
Self {
position,
$($k: $v,)*
}
}
}
)+)
)
}
impl Rat {
pub fn new_with_position(position: Position) -> Self {
Self {
name: "rat".to_string(),
life: 2,
position,
symbol: String::from("R"),
color: Color::Black,
experience_gain: 5,
ticks_between_steps: 5,
damage_range: 1..=2,
}
}
}
create_monster!(Rat);
create_monster!(
Rat,
name:"rat".to_string(),
life: 2,
symbol: String::from("R"),
color: Color::Black,
experience_gain: 5,
ticks_between_steps: 5,
damage_range: 1..=2,
);
impl Orc {
pub fn new_with_position(position: Position) -> Self {
Self {
name: "orc".to_string(),
life: 4,
position,
symbol: String::from("O"),
color: Color::DarkGray,
experience_gain: 10,
ticks_between_steps: 10,
damage_range: 2..=3,
}
}
}
create_monster!(Orc);
create_monster!(
Orc,
name: "orc".to_string(),
life: 4,
symbol: String::from("O"),
color: Color::DarkGray,
experience_gain: 10,
ticks_between_steps: 10,
damage_range: 2..=3,
);
impl Snake {
pub fn new_with_position(position: Position) -> Self {
Self {
name: "snake".to_string(),
life: 3,
position,
symbol: String::from("S"),
color: Color::DarkGray,
experience_gain: 10,
ticks_between_steps: 20,
damage_range: 1..=4,
}
}
}
create_monster!(Snake);
create_monster!(
Snake,
name: "snake".to_string(),
life: 3,
symbol: String::from("s"),
color: Color::Black,
experience_gain: 10,
ticks_between_steps: 20,
damage_range: 1..=4,
);
pub fn create_monster_by_type(mtype: &str, position: Position) -> Box<dyn Monster> {
match mtype {
"Rat" => Box::new(Rat::new_with_position(position)),
"Orc" => Box::new(Orc::new_with_position(position)),
"Snake" => Box::new(Snake::new_with_position(position)),
&_ => {
panic!("Unknown species: {}", mtype)
}
create_monster!(
Skeleton,
name: "skeleton".to_string(),
life: 3,
symbol: String::from("S"),
color: Color::DarkGray,
experience_gain: 20,
ticks_between_steps: 10,
damage_range: 1..=5,
);
pub fn create_monster_by_type(monster_type: &MonsterTypes, position: Position) -> Box<dyn Monster> {
match monster_type {
MonsterTypes::Rat => Box::new(Rat::new_with_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)),
}
}