diff --git a/server/src/sys/agent.rs b/server/src/sys/agent.rs index 2fcd8e0279..d5de5115dc 100644 --- a/server/src/sys/agent.rs +++ b/server/src/sys/agent.rs @@ -12,7 +12,7 @@ use crate::{ IDLE_HEALING_ITEM_THRESHOLD, MAX_FLEE_DIST, MAX_FOLLOW_DIST, PARTIAL_PATH_DIST, RETARGETING_THRESHOLD_SECONDS, SEPARATION_BIAS, SEPARATION_DIST, }, - data::{AgentData, AttackData, ReadData, Tactic, TargetData}, + 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, @@ -2270,55 +2270,57 @@ impl<'a> AgentData<'a> { controller: &mut Controller, tgt_data: &TargetData, read_data: &ReadData, - full_path: bool, - separate: bool, + path: Path, speed_multiplier: Option, ) -> bool { - let pathing_pos = if separate { - let mut sep_vec: Vec3 = Vec3::::zero(); + let pathing_pos = match path { + Path::Full => { + let mut sep_vec: Vec3 = Vec3::::zero(); - for entity in read_data - .cached_spatial_grid - .0 - .in_circle_aabr(self.pos.0.xy(), SEPARATION_DIST) - { - if let (Some(alignment), Some(other_alignment)) = - (self.alignment, read_data.alignments.get(entity)) + for entity in read_data + .cached_spatial_grid + .0 + .in_circle_aabr(self.pos.0.xy(), SEPARATION_DIST) { - if Alignment::passive_towards(*alignment, *other_alignment) { - if let (Some(pos), Some(body), Some(other_body)) = ( - read_data.positions.get(entity), - self.body, - read_data.bodies.get(entity), - ) { - if self.pos.0.xy().distance(pos.0.xy()) - < body.spacing_radius() + other_body.spacing_radius() - { - sep_vec += (self.pos.0.xy() - pos.0.xy()) - .try_normalized() - .unwrap_or_else(Vec2::zero) - * (((body.spacing_radius() + other_body.spacing_radius()) - - self.pos.0.xy().distance(pos.0.xy())) - / (body.spacing_radius() + other_body.spacing_radius())); + if let (Some(alignment), Some(other_alignment)) = + (self.alignment, read_data.alignments.get(entity)) + { + if Alignment::passive_towards(*alignment, *other_alignment) { + if let (Some(pos), Some(body), Some(other_body)) = ( + read_data.positions.get(entity), + self.body, + read_data.bodies.get(entity), + ) { + if self.pos.0.xy().distance(pos.0.xy()) + < body.spacing_radius() + other_body.spacing_radius() + { + sep_vec += (self.pos.0.xy() - pos.0.xy()) + .try_normalized() + .unwrap_or_else(Vec2::zero) + * (((body.spacing_radius() + other_body.spacing_radius()) + - self.pos.0.xy().distance(pos.0.xy())) + / (body.spacing_radius() + + other_body.spacing_radius())); + } } } } } - } - self.pos.0 - + PARTIAL_PATH_DIST - * (sep_vec * SEPARATION_BIAS - + (tgt_data.pos.0 - self.pos.0) * (1.0 - SEPARATION_BIAS)) - .try_normalized() - .unwrap_or_else(Vec3::zero) - } else if full_path { - tgt_data.pos.0 - } else { - self.pos.0 - + PARTIAL_PATH_DIST - * (tgt_data.pos.0 - self.pos.0) - .try_normalized() - .unwrap_or_else(Vec3::zero) + self.pos.0 + + PARTIAL_PATH_DIST + * (sep_vec * SEPARATION_BIAS + + (tgt_data.pos.0 - self.pos.0) * (1.0 - SEPARATION_BIAS)) + .try_normalized() + .unwrap_or_else(Vec3::zero) + }, + Path::Separate => tgt_data.pos.0, + Path::Partial => { + self.pos.0 + + PARTIAL_PATH_DIST + * (tgt_data.pos.0 - self.pos.0) + .try_normalized() + .unwrap_or_else(Vec3::zero) + }, }; let speed_multiplier = speed_multiplier.unwrap_or(1.0).min(1.0); if let Some((bearing, speed)) = agent.chaser.chase( diff --git a/server/src/sys/agent/attack.rs b/server/src/sys/agent/attack.rs index b82651f943..7e392ba0df 100644 --- a/server/src/sys/agent/attack.rs +++ b/server/src/sys/agent/attack.rs @@ -1,5 +1,6 @@ use crate::sys::agent::{ - consts::MAX_PATH_DIST, util::can_see_tgt, AgentData, AttackData, ReadData, TargetData, + consts::MAX_PATH_DIST, data::Path, util::can_see_tgt, AgentData, AttackData, ReadData, + TargetData, }; use common::{ comp::{ @@ -34,7 +35,7 @@ impl<'a> AgentData<'a> { controller.push_basic_input(InputKind::Primary); controller.inputs.move_dir = Vec2::zero(); } else if attack_data.dist_sqrd < MAX_PATH_DIST.powi(2) { - self.path_toward_target(agent, controller, tgt_data, read_data, true, true, None); + self.path_toward_target(agent, controller, tgt_data, read_data, Path::Full, None); if self.body.map(|b| b.is_humanoid()).unwrap_or(false) && attack_data.dist_sqrd < 16.0f32.powi(2) @@ -43,7 +44,7 @@ impl<'a> AgentData<'a> { controller.push_basic_input(InputKind::Roll); } } else { - self.path_toward_target(agent, controller, tgt_data, read_data, false, true, None); + self.path_toward_target(agent, controller, tgt_data, read_data, Path::Full, None); } } @@ -106,7 +107,7 @@ impl<'a> AgentData<'a> { .unwrap_or_default(); } } else { - self.path_toward_target(agent, controller, tgt_data, read_data, false, true, None); + self.path_toward_target(agent, controller, tgt_data, read_data, Path::Full, None); } } @@ -186,7 +187,7 @@ impl<'a> AgentData<'a> { -bearing.xy().try_normalized().unwrap_or_else(Vec2::zero); } } else { - self.path_toward_target(agent, controller, tgt_data, read_data, false, true, None); + self.path_toward_target(agent, controller, tgt_data, read_data, Path::Full, None); } } @@ -222,7 +223,7 @@ impl<'a> AgentData<'a> { agent.action_state.timer += read_data.dt.0; } } else if attack_data.dist_sqrd < MAX_PATH_DIST.powi(2) { - self.path_toward_target(agent, controller, tgt_data, read_data, true, false, None); + self.path_toward_target(agent, controller, tgt_data, read_data, Path::Separate, None); if attack_data.dist_sqrd < 32.0f32.powi(2) && has_leap() && has_energy(50.0) @@ -242,7 +243,7 @@ impl<'a> AgentData<'a> { controller.push_basic_input(InputKind::Roll); } } else { - self.path_toward_target(agent, controller, tgt_data, read_data, false, false, None); + self.path_toward_target(agent, controller, tgt_data, read_data, Path::Partial, None); } } @@ -282,7 +283,7 @@ impl<'a> AgentData<'a> { agent.action_state.timer += read_data.dt.0; } } else if attack_data.dist_sqrd < MAX_PATH_DIST.powi(2) { - self.path_toward_target(agent, controller, tgt_data, read_data, true, false, None); + self.path_toward_target(agent, controller, tgt_data, read_data, Path::Separate, None); if attack_data.dist_sqrd < 32.0f32.powi(2) && has_leap() && has_energy(50.0) @@ -302,7 +303,7 @@ impl<'a> AgentData<'a> { controller.push_basic_input(InputKind::Roll); } } else { - self.path_toward_target(agent, controller, tgt_data, read_data, false, false, None); + self.path_toward_target(agent, controller, tgt_data, read_data, Path::Partial, None); } } @@ -332,7 +333,7 @@ impl<'a> AgentData<'a> { agent.action_state.timer += read_data.dt.0; } } else if attack_data.dist_sqrd < MAX_PATH_DIST.powi(2) { - if self.path_toward_target(agent, controller, tgt_data, read_data, true, false, None) + if self.path_toward_target(agent, controller, tgt_data, read_data, Path::Separate, None) && can_see_tgt( &*read_data.terrain, self.pos, @@ -354,7 +355,7 @@ impl<'a> AgentData<'a> { controller.push_basic_input(InputKind::Roll); } } else { - self.path_toward_target(agent, controller, tgt_data, read_data, false, false, None); + self.path_toward_target(agent, controller, tgt_data, read_data, Path::Partial, None); } } @@ -421,7 +422,14 @@ impl<'a> AgentData<'a> { // (other 2 attacks have interrupt handled above) unless in recover controller.push_basic_input(InputKind::Roll); } else { - self.path_toward_target(agent, controller, tgt_data, read_data, true, false, None); + self.path_toward_target( + agent, + controller, + tgt_data, + read_data, + Path::Separate, + None, + ); if attack_data.angle < 15.0 { controller.push_basic_input(InputKind::Primary); } @@ -502,7 +510,7 @@ impl<'a> AgentData<'a> { } } else { // If too far, move towards target - self.path_toward_target(agent, controller, tgt_data, read_data, false, false, None); + self.path_toward_target(agent, controller, tgt_data, read_data, Path::Partial, None); } } @@ -634,7 +642,7 @@ impl<'a> AgentData<'a> { } } else { // If too far, move towards target - self.path_toward_target(agent, controller, tgt_data, read_data, false, false, None); + self.path_toward_target(agent, controller, tgt_data, read_data, Path::Partial, None); } } @@ -765,7 +773,7 @@ impl<'a> AgentData<'a> { } } else { // If too far, move towards target - self.path_toward_target(agent, controller, tgt_data, read_data, false, false, None); + self.path_toward_target(agent, controller, tgt_data, read_data, Path::Partial, None); } } @@ -785,7 +793,7 @@ impl<'a> AgentData<'a> { if self.vel.0.is_approx_zero() { controller.push_basic_input(InputKind::Ability(0)); } - if self.path_toward_target(agent, controller, tgt_data, read_data, true, false, None) + if self.path_toward_target(agent, controller, tgt_data, read_data, Path::Separate, None) && can_see_tgt( &*read_data.terrain, self.pos, @@ -802,7 +810,7 @@ impl<'a> AgentData<'a> { } } } else { - self.path_toward_target(agent, controller, tgt_data, read_data, false, false, None); + self.path_toward_target(agent, controller, tgt_data, read_data, Path::Partial, None); } } @@ -886,9 +894,9 @@ impl<'a> AgentData<'a> { // activating charge once circle timer expires is handled above } else if attack_data.dist_sqrd < MAX_PATH_DIST.powi(2) { // if too far away from target, move towards them - self.path_toward_target(agent, controller, tgt_data, read_data, true, false, None); + self.path_toward_target(agent, controller, tgt_data, read_data, Path::Separate, None); } else { - self.path_toward_target(agent, controller, tgt_data, read_data, false, false, None); + self.path_toward_target(agent, controller, tgt_data, read_data, Path::Partial, None); } } @@ -959,7 +967,7 @@ impl<'a> AgentData<'a> { agent.target = None; } } else { - self.path_toward_target(agent, controller, tgt_data, read_data, false, false, None); + self.path_toward_target(agent, controller, tgt_data, read_data, Path::Partial, None); } } @@ -990,9 +998,9 @@ impl<'a> AgentData<'a> { .unwrap_or_else(Vec2::unit_y) * 0.1; } else if attack_data.dist_sqrd < MAX_PATH_DIST.powi(2) { - self.path_toward_target(agent, controller, tgt_data, read_data, true, false, None); + self.path_toward_target(agent, controller, tgt_data, read_data, Path::Separate, None); } else { - self.path_toward_target(agent, controller, tgt_data, read_data, false, false, None); + self.path_toward_target(agent, controller, tgt_data, read_data, Path::Partial, None); } } @@ -1020,9 +1028,9 @@ impl<'a> AgentData<'a> { .try_normalized() .unwrap_or_else(Vec2::unit_y); } else if attack_data.dist_sqrd < MAX_PATH_DIST.powi(2) { - self.path_toward_target(agent, controller, tgt_data, read_data, true, false, None); + self.path_toward_target(agent, controller, tgt_data, read_data, Path::Separate, None); } else { - self.path_toward_target(agent, controller, tgt_data, read_data, false, false, None); + self.path_toward_target(agent, controller, tgt_data, read_data, Path::Partial, None); } } @@ -1048,9 +1056,9 @@ impl<'a> AgentData<'a> { agent.action_state.timer += read_data.dt.0; } } else if attack_data.dist_sqrd < MAX_PATH_DIST.powi(2) { - self.path_toward_target(agent, controller, tgt_data, read_data, true, false, None); + self.path_toward_target(agent, controller, tgt_data, read_data, Path::Separate, None); } else { - self.path_toward_target(agent, controller, tgt_data, read_data, false, false, None); + self.path_toward_target(agent, controller, tgt_data, read_data, Path::Partial, None); } } @@ -1072,7 +1080,7 @@ impl<'a> AgentData<'a> { { controller.push_basic_input(InputKind::Ability(0)); } else if attack_data.dist_sqrd < MAX_PATH_DIST.powi(2) { - if self.path_toward_target(agent, controller, tgt_data, read_data, true, false, None) + if self.path_toward_target(agent, controller, tgt_data, read_data, Path::Separate, None) && attack_data.angle < 15.0 && can_see_tgt( &*read_data.terrain, @@ -1084,7 +1092,7 @@ impl<'a> AgentData<'a> { controller.push_basic_input(InputKind::Primary); } } else { - self.path_toward_target(agent, controller, tgt_data, read_data, false, false, None); + self.path_toward_target(agent, controller, tgt_data, read_data, Path::Partial, None); } } @@ -1108,9 +1116,9 @@ impl<'a> AgentData<'a> { agent.action_state.timer = 0.0; } } else if attack_data.dist_sqrd < MAX_PATH_DIST.powi(2) { - self.path_toward_target(agent, controller, tgt_data, read_data, true, false, None); + self.path_toward_target(agent, controller, tgt_data, read_data, Path::Separate, None); } else { - self.path_toward_target(agent, controller, tgt_data, read_data, false, false, None); + self.path_toward_target(agent, controller, tgt_data, read_data, Path::Partial, None); } } @@ -1153,9 +1161,9 @@ impl<'a> AgentData<'a> { agent.action_state.timer = 0.0; } } else if attack_data.dist_sqrd < MAX_PATH_DIST.powi(2) { - self.path_toward_target(agent, controller, tgt_data, read_data, true, false, None); + self.path_toward_target(agent, controller, tgt_data, read_data, Path::Separate, None); } else { - self.path_toward_target(agent, controller, tgt_data, read_data, false, false, None); + self.path_toward_target(agent, controller, tgt_data, read_data, Path::Partial, None); } } @@ -1171,9 +1179,9 @@ impl<'a> AgentData<'a> { controller.inputs.move_dir = Vec2::zero(); controller.push_basic_input(InputKind::Primary); } else if attack_data.dist_sqrd < MAX_PATH_DIST.powi(2) { - self.path_toward_target(agent, controller, tgt_data, read_data, true, false, None); + self.path_toward_target(agent, controller, tgt_data, read_data, Path::Separate, None); } else { - self.path_toward_target(agent, controller, tgt_data, read_data, false, false, None); + self.path_toward_target(agent, controller, tgt_data, read_data, Path::Partial, None); } } @@ -1310,7 +1318,14 @@ impl<'a> AgentData<'a> { controller.push_basic_input(InputKind::Secondary); } } else { - self.path_toward_target(agent, controller, tgt_data, read_data, true, false, None); + self.path_toward_target( + agent, + controller, + tgt_data, + read_data, + Path::Separate, + None, + ); } } else if attack_data.dist_sqrd < MAX_PATH_DIST.powi(2) { // If too far from target, throw a random number of necrotic spheres at them and @@ -1341,9 +1356,9 @@ impl<'a> AgentData<'a> { select_pos: None, }); } - self.path_toward_target(agent, controller, tgt_data, read_data, true, false, None); + self.path_toward_target(agent, controller, tgt_data, read_data, Path::Separate, None); } else { - self.path_toward_target(agent, controller, tgt_data, read_data, false, false, None); + self.path_toward_target(agent, controller, tgt_data, read_data, Path::Partial, None); } } @@ -1444,7 +1459,7 @@ impl<'a> AgentData<'a> { // If further than 2.5 blocks and random chance else if attack_data.dist_sqrd > (2.5 * attack_data.min_attack_dist).powi(2) { // Walk to target - self.path_toward_target(agent, controller, tgt_data, read_data, true, false, None); + self.path_toward_target(agent, controller, tgt_data, read_data, Path::Separate, None); } // If energy higher than 600 and random chance else if self.energy.current() > 60.0 && rng.gen_bool(0.4) { @@ -1455,7 +1470,7 @@ impl<'a> AgentData<'a> { controller.push_basic_input(InputKind::Secondary); } else { // Target is behind us. Turn around and chase target - self.path_toward_target(agent, controller, tgt_data, read_data, true, false, None); + self.path_toward_target(agent, controller, tgt_data, read_data, Path::Separate, None); } } @@ -1536,7 +1551,7 @@ impl<'a> AgentData<'a> { controller.push_basic_input(InputKind::Fly); controller.inputs.move_z = 1.0; } else if attack_data.dist_sqrd > (3.0 * attack_data.min_attack_dist).powi(2) { - self.path_toward_target(agent, controller, tgt_data, read_data, true, false, None); + self.path_toward_target(agent, controller, tgt_data, read_data, Path::Separate, None); } else if self.energy.current() > 60.0 && agent.action_state.timer < 3.0 && attack_data.angle < 15.0 @@ -1549,8 +1564,7 @@ impl<'a> AgentData<'a> { controller, tgt_data, read_data, - true, - false, + Path::Separate, Some(0.5), ); agent.action_state.timer += read_data.dt.0; @@ -1565,7 +1579,7 @@ impl<'a> AgentData<'a> { // Reset timer agent.action_state.timer = 0.0; // Target is behind us or the timer needs to be reset. Chase target - self.path_toward_target(agent, controller, tgt_data, read_data, true, false, None); + self.path_toward_target(agent, controller, tgt_data, read_data, Path::Separate, None); } } @@ -1624,7 +1638,7 @@ impl<'a> AgentData<'a> { agent.action_state.condition = true; } // Make bird move towards target - self.path_toward_target(agent, controller, tgt_data, read_data, true, false, None); + self.path_toward_target(agent, controller, tgt_data, read_data, Path::Separate, None); } pub fn handle_arthropod_basic_attack( @@ -1652,7 +1666,7 @@ impl<'a> AgentData<'a> { controller.inputs.move_dir = Vec2::zero(); controller.push_basic_input(InputKind::Primary); } else { - self.path_toward_target(agent, controller, tgt_data, read_data, false, false, None); + self.path_toward_target(agent, controller, tgt_data, read_data, Path::Partial, None); } } @@ -1734,7 +1748,7 @@ impl<'a> AgentData<'a> { agent.target = None; } } else { - self.path_toward_target(agent, controller, tgt_data, read_data, false, false, None); + self.path_toward_target(agent, controller, tgt_data, read_data, Path::Partial, None); } } @@ -1769,7 +1783,7 @@ impl<'a> AgentData<'a> { { controller.push_basic_input(InputKind::Ability(0)); } else { - self.path_toward_target(agent, controller, tgt_data, read_data, false, false, None); + self.path_toward_target(agent, controller, tgt_data, read_data, Path::Partial, None); } } @@ -1797,7 +1811,7 @@ impl<'a> AgentData<'a> { controller.inputs.move_dir = Vec2::zero(); controller.push_basic_input(InputKind::Primary); } else { - self.path_toward_target(agent, controller, tgt_data, read_data, false, false, None); + self.path_toward_target(agent, controller, tgt_data, read_data, Path::Partial, None); } } @@ -1853,7 +1867,7 @@ impl<'a> AgentData<'a> { } } // Make minotaur move towards target - self.path_toward_target(agent, controller, tgt_data, read_data, true, false, None); + self.path_toward_target(agent, controller, tgt_data, read_data, Path::Separate, None); } pub fn handle_clay_golem_attack( @@ -1929,7 +1943,7 @@ impl<'a> AgentData<'a> { } } // Make clay golem move towards target - self.path_toward_target(agent, controller, tgt_data, read_data, true, false, None); + self.path_toward_target(agent, controller, tgt_data, read_data, Path::Separate, None); } pub fn handle_tidal_warrior_attack( @@ -1999,7 +2013,7 @@ impl<'a> AgentData<'a> { } } // Always attempt to path towards target - self.path_toward_target(agent, controller, tgt_data, read_data, false, false, None); + self.path_toward_target(agent, controller, tgt_data, read_data, Path::Partial, None); } pub fn handle_yeti_attack( @@ -2046,7 +2060,7 @@ impl<'a> AgentData<'a> { } // Always attempt to path towards target - self.path_toward_target(agent, controller, tgt_data, read_data, false, false, None); + self.path_toward_target(agent, controller, tgt_data, read_data, Path::Partial, None); } pub fn handle_harvester_attack( @@ -2108,7 +2122,7 @@ impl<'a> AgentData<'a> { controller.push_basic_input(InputKind::Ability(1)); } // Always attempt to path towards target - self.path_toward_target(agent, controller, tgt_data, read_data, false, false, None); + self.path_toward_target(agent, controller, tgt_data, read_data, Path::Partial, None); } pub fn handle_deadwood( @@ -2148,7 +2162,7 @@ impl<'a> AgentData<'a> { } } else { // Otherwise too far, move towards target - self.path_toward_target(agent, controller, tgt_data, read_data, false, false, None); + self.path_toward_target(agent, controller, tgt_data, read_data, Path::Partial, None); } } @@ -2191,7 +2205,14 @@ impl<'a> AgentData<'a> { ) { // If in pathing range and can see target, move towards them - self.path_toward_target(agent, controller, tgt_data, read_data, false, false, None); + self.path_toward_target( + agent, + controller, + tgt_data, + read_data, + Path::Partial, + None, + ); } else { // Otherwise, go back to sleep agent.action_state.condition = false; @@ -2250,7 +2271,7 @@ impl<'a> AgentData<'a> { } } // And always try to path towards target - self.path_toward_target(agent, controller, tgt_data, read_data, false, false, None); + self.path_toward_target(agent, controller, tgt_data, read_data, Path::Partial, None); } } @@ -2329,6 +2350,6 @@ impl<'a> AgentData<'a> { agent.action_state.counter += read_data.dt.0 * 3.3; } - self.path_toward_target(agent, controller, tgt_data, read_data, false, true, None); + self.path_toward_target(agent, controller, tgt_data, read_data, Path::Full, None); } } diff --git a/server/src/sys/agent/data.rs b/server/src/sys/agent/data.rs index 8e016a5f0d..68cd90d083 100644 --- a/server/src/sys/agent/data.rs +++ b/server/src/sys/agent/data.rs @@ -154,3 +154,9 @@ pub struct ReadData<'a> { pub combos: ReadStorage<'a, Combo>, pub active_abilities: ReadStorage<'a, ActiveAbilities>, } + +pub enum Path { + Full, + Separate, + Partial, +}