From 0bad704719a9c38e6996b17f9ca7127e98b733be Mon Sep 17 00:00:00 2001 From: Joshua Barretto Date: Wed, 29 Jul 2020 20:58:14 +0100 Subject: [PATCH] Made agents flee --- common/src/comp/agent.rs | 34 ++++++++++++++++++++++++++++++++-- common/src/path.rs | 15 ++++++++++++--- common/src/sys/agent.rs | 34 +++++++++++++++++++++++++++++++++- 3 files changed, 77 insertions(+), 6 deletions(-) diff --git a/common/src/comp/agent.rs b/common/src/comp/agent.rs index 41eb83a1cd..8edc90221b 100644 --- a/common/src/comp/agent.rs +++ b/common/src/comp/agent.rs @@ -1,4 +1,5 @@ -use crate::{path::Chaser, sync::Uid}; +use crate::{path::Chaser, sync::Uid, comp::Body}; +use serde::{Deserialize, Serialize}; use specs::{Component, Entity as EcsEntity}; use specs_idvs::IdvStorage; use vek::*; @@ -54,6 +55,33 @@ impl Component for Alignment { type Storage = IdvStorage; } +#[derive(Clone, Debug, Default)] +pub struct Psyche { + pub aggro: f32, // 0.0 = always flees, 1.0 = always attacks +} + +impl<'a> From<&'a Body> for Psyche { + fn from(body: &'a Body) -> Self { + Self { + aggro: match body { + Body::Humanoid(_) => 0.8, + Body::QuadrupedSmall(_) => 0.35, + Body::QuadrupedMedium(_) => 0.5, + Body::QuadrupedLow(_) => 0.65, + Body::BirdMedium(_) => 1.0, + Body::BirdSmall(_) => 0.2, + Body::FishMedium(_) => 0.15, + Body::FishSmall(_) => 0.0, + Body::BipedLarge(_) => 1.0, + Body::Object(_) => 0.0, + Body::Golem(_) => 1.0, + Body::Critter(_) => 0.1, + Body::Dragon(_) => 1.0, + }, + } + } +} + #[derive(Clone, Debug, Default)] pub struct Agent { pub patrol_origin: Option>, @@ -61,6 +89,7 @@ pub struct Agent { /// Does the agent talk when e.g. hit by the player // TODO move speech patterns into a Behavior component pub can_speak: bool, + pub psyche: Psyche, } impl Agent { @@ -69,11 +98,12 @@ impl Agent { self } - pub fn new(origin: Vec3, can_speak: bool) -> Self { + pub fn new(origin: Vec3, can_speak: bool, body: &Body) -> Self { let patrol_origin = Some(origin); Agent { patrol_origin, can_speak, + psyche: Psyche::from(body), ..Default::default() } } diff --git a/common/src/path.rs b/common/src/path.rs index d6c10bed98..2fbf1e1887 100644 --- a/common/src/path.rs +++ b/common/src/path.rs @@ -402,7 +402,7 @@ fn walkable(vol: &V, pos: Vec3) -> bool where V: BaseVol + ReadVol, { - vol.get(pos - Vec3::new(0, 0, 1)) + (vol.get(pos - Vec3::new(0, 0, 1)) .map(|b| b.is_solid() && b.get_height() == 1.0) .unwrap_or(false) && vol @@ -412,7 +412,15 @@ where && vol .get(pos + Vec3::new(0, 0, 1)) .map(|b| !b.is_solid()) + .unwrap_or(true)) + || (vol + .get(pos + Vec3::new(0, 0, 0)) + .map(|b| b.is_fluid()) .unwrap_or(true) + && vol + .get(pos + Vec3::new(0, 0, 1)) + .map(|b| b.is_fluid()) + .unwrap_or(true)) } #[allow(clippy::float_cmp)] // TODO: Pending review in #587 @@ -449,7 +457,7 @@ where let heuristic = |pos: &Vec3| (pos.distance_squared(end) as f32).sqrt(); let neighbors = |pos: &Vec3| { let pos = *pos; - const DIRS: [Vec3; 17] = [ + const DIRS: [Vec3; 18] = [ Vec3::new(0, 1, 0), // Forward Vec3::new(0, 1, 1), // Forward upward Vec3::new(0, 1, 2), // Forward Upwardx2 @@ -466,7 +474,8 @@ where Vec3::new(-1, 0, 1), // Left upward Vec3::new(-1, 0, 2), // Left Upwardx2 Vec3::new(-1, 0, -1), // Left downward - Vec3::new(0, 0, -1), // Downwards + Vec3::new(0, 0, -1), // Downwards (water) + Vec3::new(0, 0, 1), // Upwards (water) ]; // let walkable = [ diff --git a/common/src/sys/agent.rs b/common/src/sys/agent.rs index e2cb88b750..8dc66fae2b 100644 --- a/common/src/sys/agent.rs +++ b/common/src/sys/agent.rs @@ -240,6 +240,7 @@ impl<'a> System<'a> for Sys { bearing.xy().try_normalized().unwrap_or(Vec2::zero()) * speed.min(0.2 + (dist - AVG_FOLLOW_DIST) / 8.0); inputs.jump.set_state(bearing.z > 1.5); + inputs.swim.set_state(bearing.z > 0.5); } } else { do_idle = true; @@ -297,7 +298,37 @@ impl<'a> System<'a> for Sys { } let dist_sqrd = pos.0.distance_squared(tgt_pos.0); - if dist_sqrd < (MIN_ATTACK_DIST * scale).powf(2.0) { + + let damage = stats + .get(entity) + .map(|s| s.health.current() as f32 / s.health.maximum() as f32) + .unwrap_or(0.5); + + // Flee + if 1.0 - agent.psyche.aggro > damage { + if let Some((bearing, speed)) = chaser.chase( + &*terrain, + pos.0, + vel.0, + // Away from the target (ironically) + tgt_pos.0 + (pos.0 - tgt_pos.0) + .try_normalized() + .unwrap_or_else(Vec3::unit_y) * 32.0, + TraversalConfig { + node_tolerance, + slow_factor, + on_ground: physics_state.on_ground, + min_tgt_dist: 1.25, + }, + ) { + inputs.move_dir = Vec2::from(bearing) + .try_normalized() + .unwrap_or(Vec2::zero()) + * speed; + inputs.jump.set_state(bearing.z > 1.5); + inputs.swim.set_state(bearing.z > 0.5); + } + } else if dist_sqrd < (MIN_ATTACK_DIST * scale).powf(2.0) { // Close-range attack inputs.move_dir = Vec2::from(tgt_pos.0 - pos.0) .try_normalized() @@ -360,6 +391,7 @@ impl<'a> System<'a> for Sys { .unwrap_or(Vec2::zero()) * speed; inputs.jump.set_state(bearing.z > 1.5); + inputs.swim.set_state(bearing.z > 0.5); } if dist_sqrd < 16.0f32.powf(2.0)