From f7bd1176a69dd0e45160df708240710d6c3bb7a3 Mon Sep 17 00:00:00 2001 From: Joshua Barretto Date: Sun, 19 Apr 2020 12:50:25 +0100 Subject: [PATCH] Made agents cleverer --- common/src/comp/agent.rs | 1 + common/src/sys/agent.rs | 80 ++++++++++++++++++++++++++-------------- 2 files changed, 53 insertions(+), 28 deletions(-) diff --git a/common/src/comp/agent.rs b/common/src/comp/agent.rs index e3edda4dbf..be33b4bb49 100644 --- a/common/src/comp/agent.rs +++ b/common/src/comp/agent.rs @@ -25,6 +25,7 @@ impl Alignment { // Never attacks pub fn passive_towards(self, other: Alignment) -> bool { match (self, other) { + (Alignment::Enemy, Alignment::Enemy) => true, (Alignment::Owned(a), Alignment::Owned(b)) if a == b => true, _ => false, } diff --git a/common/src/sys/agent.rs b/common/src/sys/agent.rs index 8e20961915..ea8c63d3de 100644 --- a/common/src/sys/agent.rs +++ b/common/src/sys/agent.rs @@ -1,5 +1,5 @@ use crate::{ - comp::{self, agent::Activity, Agent, Alignment, Controller, MountState, Ori, Scale, Pos, Stats, Loadout, item::{ItemKind, tool::ToolKind}, CharacterState}, + comp::{self, agent::Activity, Agent, Alignment, Controller, ControlAction, MountState, Ori, Scale, Pos, Stats, Loadout, item::{ItemKind, tool::ToolKind}, CharacterState}, path::Chaser, state::{Time, DeltaTime}, sync::UidAllocator, @@ -92,7 +92,8 @@ impl<'a> System<'a> for Sys { const AVG_FOLLOW_DIST: f32 = 6.0; const MAX_FOLLOW_DIST: f32 = 12.0; const MAX_CHASE_DIST: f32 = 24.0; - const SEARCH_DIST: f32 = 30.0; + const LISTEN_DIST: f32 = 16.0; + const SEARCH_DIST: f32 = 48.0; const SIGHT_DIST: f32 = 128.0; const MIN_ATTACK_DIST: f32 = 3.25; @@ -124,7 +125,7 @@ impl<'a> System<'a> for Sys { + Vec3::from(*bearing) .try_normalized() .unwrap_or(Vec3::unit_y()) - * 1.5 + * 5.0 + Vec3::unit_z(), ) .until(|block| block.is_solid()) @@ -142,8 +143,18 @@ impl<'a> System<'a> for Sys { inputs.move_dir = *bearing * 0.65; } + // Put away weapon + if thread_rng().gen::() < 0.005 { + controller.actions.push(ControlAction::Unwield); + } + + // Sit + if thread_rng().gen::() < 0.0035 { + controller.actions.push(ControlAction::Sit); + } + // Sometimes try searching for new targets - if thread_rng().gen::() < 0.1 { + if thread_rng().gen::() < 0.05 { choose_target = true; } }, @@ -177,9 +188,9 @@ impl<'a> System<'a> for Sys { .. } => { enum Tactic { - Melee, // Attack: primary/secondary + Melee, RangedPowerup, - RangedConstant, + Staff, } let tactic = match loadout.active_item @@ -187,7 +198,7 @@ impl<'a> System<'a> for Sys { .and_then(|ic| if let ItemKind::Tool(tool) = &ic.item.kind { Some(&tool.kind) } else { None}) { Some(ToolKind::Bow(_)) => Tactic::RangedPowerup, - Some(ToolKind::Staff(_)) => Tactic::RangedConstant, + Some(ToolKind::Staff(_)) => Tactic::Staff, _ => Tactic::Melee, }; @@ -223,34 +234,40 @@ impl<'a> System<'a> for Sys { if let Tactic::Melee = tactic { inputs.primary.set_state(true); - } else if let Tactic::RangedPowerup = tactic { + } else if let Tactic::Staff = tactic { inputs.primary.set_state(true); } else { - inputs.move_dir = -Vec2::from(tgt_pos.0 - pos.0) - .try_normalized() - .unwrap_or(Vec2::unit_y()); + inputs.roll.set_state(true); } } else if dist_sqrd < MAX_CHASE_DIST.powf(2.0) || (dist_sqrd < SIGHT_DIST.powf(2.0) && !*been_close) { - if let Tactic::RangedPowerup = tactic { - if *powerup > 2.0 { - inputs.primary.set_state(false); - *powerup = 0.0; - } else { - inputs.primary.set_state(true); - *powerup += dt.0; - } - } else if let Tactic::RangedConstant = tactic { - if !character_state.is_wield() { - inputs.primary.set_state(true); + let can_see_tgt = terrain + .ray(pos.0 + Vec3::unit_z(), tgt_pos.0 + Vec3::unit_z()) + .until(|block| !block.is_air()) + .cast() + .0.powf(2.0) >= dist_sqrd; + + if can_see_tgt { + if let Tactic::RangedPowerup = tactic { + if *powerup > 2.0 { + inputs.primary.set_state(false); + *powerup = 0.0; + } else { + inputs.primary.set_state(true); + *powerup += dt.0; + } + } else if let Tactic::Staff = tactic { + if !character_state.is_wield() { + inputs.primary.set_state(true); + } + + inputs.secondary.set_state(true); } - inputs.secondary.set_state(true); - } - - if dist_sqrd < MAX_CHASE_DIST.powf(2.0) { - *been_close = true; + if dist_sqrd < MAX_CHASE_DIST.powf(2.0) { + *been_close = true; + } } // Long-range chase @@ -290,13 +307,20 @@ impl<'a> System<'a> for Sys { let closest_entity = (&entities, &positions, &stats, alignments.maybe()) .join() .filter(|(e, e_pos, e_stats, e_alignment)| { - e_pos.0.distance_squared(pos.0) < SEARCH_DIST.powf(2.0) + ((e_pos.0.distance_squared(pos.0) < SEARCH_DIST.powf(2.0) && (e_pos.0 - pos.0).try_normalized().map(|v| v.dot(*inputs.look_dir) > 0.3).unwrap_or(true)) + || e_pos.0.distance_squared(pos.0) < LISTEN_DIST.powf(2.0)) && *e != entity && !e_stats.is_dead && alignment .and_then(|a| e_alignment.map(|b| a.hostile_towards(*b))) .unwrap_or(false) }) + // Can we even see them? + .filter(|(_, e_pos, _, _)| terrain + .ray(pos.0 + Vec3::unit_z(), e_pos.0 + Vec3::unit_z()) + .until(|block| !block.is_air()) + .cast() + .0 >= e_pos.0.distance(pos.0)) .min_by_key(|(_, e_pos, _, _)| (e_pos.0.distance_squared(pos.0) * 100.0) as i32) .map(|(e, _, _, _)| e);