From efe531f6ce719ee07ac1678449d827d44d7facd6 Mon Sep 17 00:00:00 2001 From: Joachim Lusiardi Date: Wed, 10 Jan 2024 16:40:46 +0100 Subject: [PATCH] movement depends on monster class now --- src/level.rs | 8 +------- src/monster.rs | 39 +++++++++++++++++++++++++++++++++++++++ src/position.rs | 24 +++++++++++++++++++++++- 3 files changed, 63 insertions(+), 8 deletions(-) diff --git a/src/level.rs b/src/level.rs index 80c80f6..6ddc42b 100644 --- a/src/level.rs +++ b/src/level.rs @@ -129,13 +129,7 @@ impl Level { } loop { // calculate the direction the monster will try to walk - let (dx, dy) = match self.rng.gen_range(0..5) { - 1 => { (1, 0) } - 2 => { (-1, 0) } - 3 => { (0, 1) } - 4 => { (0, -1) } - _ => { (0, 0) } - }; + let (dx, dy) = self.monsters[index].get_next_move(&self, player.get_immutable_position()); if self.can_monster_move(self.monsters[index].as_ref(), dx, dy) { let (new_x, new_y) = self.monsters[index].get_position().change(dx, dy); if player.get_immutable_position().get_x() == new_x && player.get_immutable_position().get_y() == new_y { diff --git a/src/monster.rs b/src/monster.rs index 331ff5b..0313186 100644 --- a/src/monster.rs +++ b/src/monster.rs @@ -1,7 +1,10 @@ use ratatui::prelude::Color; use crate::dungeon_slayer::MonsterStats; +use crate::level::Level; use crate::position::{HasPosition, Position}; +use rand::Rng; + pub trait Monster: HasPosition { fn get_name(&self) -> &str; @@ -13,6 +16,7 @@ pub trait Monster: HasPosition { fn get_ticks_between_steps(&self) -> u128; fn get_defense(&self) -> u8; fn get_hit(&self) -> u8; + fn get_next_move(&self, level: &Level, player_pos: &Position) -> (i16, i16); #[cfg(test)] fn get_life(&self) -> usize; } @@ -30,6 +34,9 @@ macro_rules! default_monster { fn get_ticks_between_steps(&self) -> u128 { self.ticks_between_steps } fn get_defense(&self) -> u8 { self.monster_stats.defense } fn get_hit(&self) -> u8 { self.monster_stats.hit } + fn get_next_move(&self, level: &Level, player_pos: &Position) -> (i16, i16) { + self.calc_move(level, player_pos) + } #[cfg(test)] fn get_life(&self) -> usize { self.life } } @@ -90,6 +97,20 @@ impl crate::monster::LowerDaemon { monster_stats, } } + + fn calc_move(&self, level: &Level, player_pos: &Position) -> (i16, i16) { + let d = self.position.distance(player_pos); + if d == 1 { + return self.position.get_direction(player_pos); + } + match rand::thread_rng().gen_range(0..5) { + 1 => { (1, 0) } + 2 => { (-1, 0) } + 3 => { (0, 1) } + 4 => { (0, -1) } + _ => { (0, 0) } + } + } } default_monster!(LowerDaemon); @@ -139,6 +160,15 @@ impl Rat { monster_stats, } } + fn calc_move(&self, level: &Level, player_pos: &Position) -> (i16, i16) { + match rand::thread_rng().gen_range(0..5) { + 1 => { (1, 0) } + 2 => { (-1, 0) } + 3 => { (0, 1) } + 4 => { (0, -1) } + _ => { (0, 0) } + } + } } default_monster!(Rat); @@ -188,6 +218,15 @@ impl Orc { monster_stats, } } + fn calc_move(&self, level: &Level, player_pos: &Position) -> (i16, i16) { + match rand::thread_rng().gen_range(0..5) { + 1 => { (1, 0) } + 2 => { (-1, 0) } + 3 => { (0, 1) } + 4 => { (0, -1) } + _ => { (0, 0) } + } + } } default_monster!(Orc); diff --git a/src/position.rs b/src/position.rs index 67ea8e1..1038f35 100644 --- a/src/position.rs +++ b/src/position.rs @@ -1,4 +1,4 @@ -use std::cmp::max; +use std::cmp::{max, min}; /// describes an character (PC or NPC) in the dungeon that has a position. pub trait HasPosition { @@ -43,6 +43,28 @@ impl Position { } pub fn get_y(&self) -> usize { self.y } + + /// calculate the distance to the other position using the manhattan metric + pub fn distance(&self, other: &Self) -> usize { + self.x.abs_diff(other.x) + self.y.abs_diff(other.y) + } + + /// get the direction (step size 1) towards the other position + pub fn get_direction(&self, other: &Self) -> (i16, i16) { + ( + max(min(other.x as i16 - self.x as i16, 1), -1), + max(min(other.y as i16 - self.y as i16, 1), -1) + ) + } +} + +#[test] +fn test_get_direction() { + let p1 = Position::new(0, 10, 10); + let p2 = Position::new(0, 8, 8); + assert_eq!(p1.get_direction(&p2), (-1, -1)); + let p2 = Position::new(0, 11, 10); + assert_eq!(p1.get_direction(&p2), (1, 0)); } #[test]