From 003751847250083fdd749a21f47a04f058b1a108 Mon Sep 17 00:00:00 2001 From: Manuel Schmidbauer Date: Sun, 27 Feb 2022 14:30:31 +0100 Subject: [PATCH] Impl #1357: Agent chase abort - Adds util funcs to calculate benefit of continue pursue vs letting target escape - Hooks util funcs into agent's hostile tree --- CHANGELOG.md | 1 + server/src/sys/agent.rs | 27 ++++++++++++++++++++-- server/src/sys/agent/util.rs | 44 +++++++++++++++++++++++++++++++++++- 3 files changed, 69 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c12d5a7fee..1de1daf941 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Waypoints saved between sessions and shared with group members. - New rocks - Weapon trails +- Hostile agent will now abort pursuing their target based on multiple metrics ### Changed diff --git a/server/src/sys/agent.rs b/server/src/sys/agent.rs index d339e87fb7..9f54c7b96f 100644 --- a/server/src/sys/agent.rs +++ b/server/src/sys/agent.rs @@ -15,7 +15,7 @@ use crate::{ data::{AgentData, AttackData, Path, ReadData, Tactic, TargetData}, util::{ aim_projectile, can_see_tgt, get_entity_by_id, is_dead, is_dead_or_invulnerable, - is_invulnerable, try_owner_alignment, + is_invulnerable, stop_pursuing, try_owner_alignment, }, }, }; @@ -613,6 +613,20 @@ impl<'a> AgentData<'a> { if let Some(tgt_pos) = read_data.positions.get(target) { let dist_sqrd = self.pos.0.distance_squared(tgt_pos.0); + let origin_dist_sqrd = match agent.patrol_origin { + Some(pos) => pos.distance_squared(self.pos.0), + None => 1.0, + }; + + let own_health_fraction = match self.health { + Some(val) => val.fraction(), + None => 1.0, + }; + let target_health_fraction = match read_data.healths.get(target) { + Some(val) => val.fraction(), + None => 1.0, + }; + let in_aggro_range = agent .psyche .aggro_dist @@ -645,7 +659,16 @@ impl<'a> AgentData<'a> { self.exclaim_relief_about_enemy_dead(agent, event_emitter); agent.target = None; self.idle(agent, controller, read_data, rng); - } else if is_invulnerable(target, read_data) { + } else if is_invulnerable(target, read_data) + || stop_pursuing( + dist_sqrd, + origin_dist_sqrd, + own_health_fraction, + target_health_fraction, + read_data.time.0 - selected_at, + &agent.psyche, + ) + { agent.target = None; self.idle(agent, controller, read_data, rng); } else { diff --git a/server/src/sys/agent/util.rs b/server/src/sys/agent/util.rs index ac17813ffb..fe999526fe 100644 --- a/server/src/sys/agent/util.rs +++ b/server/src/sys/agent/util.rs @@ -1,6 +1,6 @@ use crate::sys::agent::{AgentData, ReadData}; use common::{ - comp::{buff::BuffKind, Alignment, Pos}, + comp::{agent::Psyche, buff::BuffKind, Alignment, Pos}, consts::GRAVITY, terrain::{Block, TerrainGrid}, util::Dir, @@ -79,3 +79,45 @@ impl<'a> AgentData<'a> { .map_or(false, |b| b.kinds.contains_key(&buff)) } } + +/// Calculates whether the agent should continue chase or let the target escape. +/// +/// Will return true when score of letting target escape is higher then the +/// score of continuing the pursue, false otherwise. +pub fn stop_pursuing( + dist_to_target_sqrd: f32, + dist_to_home_sqrd: f32, + own_health_fraction: f32, + target_health_fraction: f32, + dur_since_last_attacked: f64, + psyche: &Psyche, +) -> bool { + should_let_target_escape( + dist_to_home_sqrd, + dur_since_last_attacked, + own_health_fraction, + ) > should_continue_to_pursue(dist_to_target_sqrd, psyche, target_health_fraction) +} + +/// Scores the benefit of continuing the pursue in value from 0 to infinity. +fn should_continue_to_pursue( + dist_to_target_sqrd: f32, + psyche: &Psyche, + target_health_fraction: f32, +) -> f32 { + let aggression_score = (1.0 / psyche.flee_health.max(0.25)) + * psyche.aggro_dist.unwrap_or(psyche.sight_dist) + * psyche.sight_dist; + + (100.0 * aggression_score) / (dist_to_target_sqrd * target_health_fraction) +} + +/// Scores the benefit of letting the target escape in a value from 0 to +/// infinity. +fn should_let_target_escape( + dist_to_home_sqrd: f32, + dur_since_last_attacked: f64, + own_health_fraction: f32, +) -> f32 { + (dist_to_home_sqrd / own_health_fraction) * dur_since_last_attacked as f32 * 0.005 +}