Flee if attacked even if attacker is not close.

This commit is contained in:
holychowders 2022-10-28 21:31:49 +00:00 committed by Marcel
parent dda62b998d
commit 3d4ad29d1d
4 changed files with 35 additions and 12 deletions

View File

@ -68,6 +68,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Fixed npcs using `/say` instead of `/tell` - Fixed npcs using `/say` instead of `/tell`
- Camera jittering in third person has been significantly reduced - Camera jittering in third person has been significantly reduced
- Many water shader issues have been fixed - Many water shader issues have been fixed
- Flee if attacked even if attacker is not close.
## [0.13.0] - 2022-07-23 ## [0.13.0] - 2022-07-23

View File

@ -14,7 +14,7 @@ use std::{collections::VecDeque, fmt};
use strum::{EnumIter, IntoEnumIterator}; use strum::{EnumIter, IntoEnumIterator};
use vek::*; use vek::*;
use super::dialogue::Subject; use super::{dialogue::Subject, Pos};
pub const DEFAULT_INTERACTION_TIME: f32 = 3.0; pub const DEFAULT_INTERACTION_TIME: f32 = 3.0;
pub const TRADE_INTERACTION_TIME: f32 = 300.0; pub const TRADE_INTERACTION_TIME: f32 = 300.0;
@ -531,6 +531,10 @@ pub struct Agent {
pub sounds_heard: Vec<Sound>, pub sounds_heard: Vec<Sound>,
pub awareness: f32, pub awareness: f32,
pub position_pid_controller: Option<PidController<fn(Vec3<f32>, Vec3<f32>) -> f32, 16>>, pub position_pid_controller: Option<PidController<fn(Vec3<f32>, Vec3<f32>) -> f32, 16>>,
/// Position from which to flee. Intended to be the agent's position plus a
/// random position offset, to be used when a random flee direction is
/// required and reset each time the flee timer is reset.
pub flee_from_pos: Option<Pos>,
} }
/// State persistence object for the behavior tree /// State persistence object for the behavior tree
@ -563,6 +567,7 @@ impl Agent {
sounds_heard: Vec::new(), sounds_heard: Vec::new(),
awareness: 0.0, awareness: 0.0,
position_pid_controller: None, position_pid_controller: None,
flee_from_pos: None,
} }
} }

View File

@ -6,7 +6,9 @@ pub const MAX_PATH_DIST: f32 = 170.0;
pub const PARTIAL_PATH_DIST: f32 = 50.0; pub const PARTIAL_PATH_DIST: f32 = 50.0;
pub const SEPARATION_DIST: f32 = 10.0; pub const SEPARATION_DIST: f32 = 10.0;
pub const SEPARATION_BIAS: f32 = 0.8; pub const SEPARATION_BIAS: f32 = 0.8;
pub const MAX_FLEE_DIST: f32 = 20.0; /// The distance within which agents will flee directly away if attacked from
/// distance or if attacker detected.
pub const NORMAL_FLEE_DIR_DIST: f32 = 20.0;
pub const AVG_FOLLOW_DIST: f32 = 6.0; pub const AVG_FOLLOW_DIST: f32 = 6.0;
pub const RETARGETING_THRESHOLD_SECONDS: f64 = 10.0; pub const RETARGETING_THRESHOLD_SECONDS: f64 = 10.0;
pub const HEALING_ITEM_THRESHOLD: f32 = 0.5; pub const HEALING_ITEM_THRESHOLD: f32 = 0.5;

View File

@ -5,17 +5,18 @@ use common::{
AgentEvent, Target, TimerAction, DEFAULT_INTERACTION_TIME, TRADE_INTERACTION_TIME, AgentEvent, Target, TimerAction, DEFAULT_INTERACTION_TIME, TRADE_INTERACTION_TIME,
}, },
Agent, Alignment, BehaviorCapability, BehaviorState, Body, BuffKind, ControlAction, Agent, Alignment, BehaviorCapability, BehaviorState, Body, BuffKind, ControlAction,
ControlEvent, Controller, InputKind, InventoryEvent, UtteranceKind, ControlEvent, Controller, InputKind, InventoryEvent, Pos, UtteranceKind,
}, },
event::{Emitter, ServerEvent}, event::{Emitter, ServerEvent},
path::TraversalConfig, path::TraversalConfig,
}; };
use rand::{prelude::ThreadRng, Rng}; use rand::{prelude::ThreadRng, thread_rng, Rng};
use server_agent::consts::NORMAL_FLEE_DIR_DIST;
use specs::{ use specs::{
saveload::{Marker, MarkerAllocator}, saveload::{Marker, MarkerAllocator},
Entity as EcsEntity, Entity as EcsEntity,
}; };
use vek::Vec2; use vek::{Vec2, Vec3};
use self::interaction::{ use self::interaction::{
handle_inbox_cancel_interactions, handle_inbox_finished_trade, handle_inbox_talk, handle_inbox_cancel_interactions, handle_inbox_finished_trade, handle_inbox_talk,
@ -25,8 +26,8 @@ use self::interaction::{
use super::{ use super::{
consts::{ consts::{
DAMAGE_MEMORY_DURATION, FLEE_DURATION, HEALING_ITEM_THRESHOLD, MAX_FLEE_DIST, DAMAGE_MEMORY_DURATION, FLEE_DURATION, HEALING_ITEM_THRESHOLD, MAX_FOLLOW_DIST,
MAX_FOLLOW_DIST, NPC_PICKUP_RANGE, RETARGETING_THRESHOLD_SECONDS, NPC_PICKUP_RANGE, RETARGETING_THRESHOLD_SECONDS,
}, },
data::{AgentData, ReadData, TargetData}, data::{AgentData, ReadData, TargetData},
util::{get_entity_by_id, is_dead, is_dead_or_invulnerable, is_invulnerable, stop_pursuing}, util::{get_entity_by_id, is_dead, is_dead_or_invulnerable, is_invulnerable, stop_pursuing},
@ -560,10 +561,10 @@ fn do_combat(bdata: &mut BehaviorData) -> bool {
let aggro_on = *aggro_on; let aggro_on = *aggro_on;
if agent_data.below_flee_health(agent) { if agent_data.below_flee_health(agent) {
let has_opportunity_to_flee = agent.action_state.timers let flee_timer_done = agent.action_state.timers
[ActionStateBehaviorTreeTimers::TimerBehaviorTree as usize] [ActionStateBehaviorTreeTimers::TimerBehaviorTree as usize]
< FLEE_DURATION; > FLEE_DURATION;
let within_flee_distance = dist_sqrd < MAX_FLEE_DIST.powi(2); let within_normal_flee_dir_dist = dist_sqrd < NORMAL_FLEE_DIR_DIST.powi(2);
// FIXME: Using action state timer to see if allowed to speak is a hack. // FIXME: Using action state timer to see if allowed to speak is a hack.
if agent.action_state.timers if agent.action_state.timers
@ -573,8 +574,21 @@ fn do_combat(bdata: &mut BehaviorData) -> bool {
agent_data.cry_out(agent, event_emitter, read_data); agent_data.cry_out(agent, event_emitter, read_data);
agent.action_state.timers agent.action_state.timers
[ActionStateBehaviorTreeTimers::TimerBehaviorTree as usize] = 0.01; [ActionStateBehaviorTreeTimers::TimerBehaviorTree as usize] = 0.01;
} else if within_flee_distance && has_opportunity_to_flee { agent.flee_from_pos = {
agent_data.flee(agent, controller, tgt_pos, &read_data.terrain); let random = || thread_rng().gen_range(-1.0..1.0);
Some(Pos(
agent_data.pos.0 + Vec3::new(random(), random(), random())
))
};
} else if !flee_timer_done {
if within_normal_flee_dir_dist {
agent_data.flee(agent, controller, tgt_pos, &read_data.terrain);
} else if let Some(random_pos) = agent.flee_from_pos {
agent_data.flee(agent, controller, &random_pos, &read_data.terrain);
} else {
agent_data.flee(agent, controller, tgt_pos, &read_data.terrain);
}
agent.action_state.timers agent.action_state.timers
[ActionStateBehaviorTreeTimers::TimerBehaviorTree as usize] += [ActionStateBehaviorTreeTimers::TimerBehaviorTree as usize] +=
read_data.dt.0; read_data.dt.0;
@ -582,6 +596,7 @@ fn do_combat(bdata: &mut BehaviorData) -> bool {
agent.action_state.timers agent.action_state.timers
[ActionStateBehaviorTreeTimers::TimerBehaviorTree as usize] = 0.0; [ActionStateBehaviorTreeTimers::TimerBehaviorTree as usize] = 0.0;
agent.target = None; agent.target = None;
agent.flee_from_pos = None;
agent_data.idle(agent, controller, read_data, rng); agent_data.idle(agent, controller, read_data, rng);
} }
} else if is_dead(target, read_data) { } else if is_dead(target, read_data) {