use ratatui::prelude::Color; use crate::position::{HasPosition, Position}; 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; } macro_rules! default_monster { ($($t:ty),+ $(,)?) => ($( 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 } #[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 } } )+) } pub struct Rat { name: String, life: usize, position: Position, symbol: String, color: Color, experience_gain: usize, ticks_between_steps: u128, } 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, } } } default_monster!(Rat); pub struct Orc { name: String, life: usize, position: Position, symbol: String, color: Color, experience_gain: usize, ticks_between_steps: u128, } 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, } } } default_monster!(Orc); #[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); }