use std::ops::RangeInclusive; use crate::position::{HasPosition, Position}; use macros::CreateMonsters; use rand::Rng; use ratatui::prelude::Color; pub trait Monster: HasPosition { fn get_name(&self) -> &str; fn is_dead(&self) -> bool; fn get_representation(&self) -> (&str, Color); fn decrease_life(&mut self, by: usize); // fn get_immutable_position(&self) -> &Position; fn get_experience_gain(&self) -> usize; fn get_ticks_between_steps(&self) -> u128; #[cfg(test)] fn get_life(&self) -> usize; fn damage(&self) -> usize; } #[derive(CreateMonsters, PartialEq, Eq, Hash, Clone, Copy)] pub enum MonsterTypes { Rat, Orc, Snake, Skeleton, Spider, } macro_rules! create_monster { ($t:ident $(, $k:ident : $v:expr)*$(,)?) => ( impl $t { pub fn new_with_position(position: Position) -> Self { Self { position, $($k: $v,)* } } } ) } create_monster!( Rat, name:"rat".to_string(), life: 2, symbol: String::from("r"), color: Color::White, 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(), life: 4, symbol: String::from("O"), color: Color::Gray, experience_gain: 10, ticks_between_steps: 10, damage_range: 2..=3, ); create_monster!( Snake, name: "snake".to_string(), life: 3, symbol: String::from("s"), color: Color::White, experience_gain: 10, ticks_between_steps: 20, damage_range: 1..=4, ); create_monster!( Skeleton, name: "skeleton".to_string(), life: 3, symbol: String::from("S"), color: Color::Gray, experience_gain: 20, ticks_between_steps: 10, damage_range: 1..=5, ); pub fn create_monster_by_type(monster_type: &MonsterTypes, position: Position) -> Box { 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)), MonsterTypes::Spider => Box::new(Spider::new_with_position(position)), } } #[test] fn monsters_can_move() { let mut m = Rat::new_with_position(Position::new(0, 0, 0)); assert_eq!(m.get_position(), &Position::new(0, 0, 0)); m.get_position().change(1, 2); assert_eq!(m.get_position(), &Position::new(0, 1, 2)); m.get_position().change(2, 1); assert_eq!(m.get_position(), &Position::new(0, 3, 3)); m.get_position().set(1, 2, 3); m.get_position().change(2, 1); assert_eq!(m.get_position(), &Position::new(1, 4, 4)); } #[test] fn monsters_can_die() { let mut m = Rat::new_with_position(Position::new(0, 0, 0)); assert_eq!(m.get_life(), 2); assert_eq!(m.is_dead(), false); m.decrease_life(1); assert_eq!(m.get_life(), 1); m.decrease_life(2); assert_eq!(m.get_life(), 0); assert_eq!(m.is_dead(), true); }