mirror of
https://gitlab.com/veloren/veloren.git
synced 2025-07-25 04:42:23 +00:00
Addressed review
This commit is contained in:
@ -1,4 +1,8 @@
|
|||||||
use crate::{consts::MAX_PATH_DIST, data::*, util::entities_have_line_of_sight};
|
use crate::{
|
||||||
|
consts::MAX_PATH_DIST,
|
||||||
|
data::*,
|
||||||
|
util::{entities_have_line_of_sight, handle_attack_aggression},
|
||||||
|
};
|
||||||
use common::{
|
use common::{
|
||||||
comp::{
|
comp::{
|
||||||
ability::{ActiveAbilities, AuxiliaryAbility, Stance, SwordStance},
|
ability::{ActiveAbilities, AuxiliaryAbility, Stance, SwordStance},
|
||||||
@ -472,43 +476,6 @@ impl<'a> AgentData<'a> {
|
|||||||
read_data: &ReadData,
|
read_data: &ReadData,
|
||||||
rng: &mut impl Rng,
|
rng: &mut impl Rng,
|
||||||
) {
|
) {
|
||||||
#[derive(Copy, Clone)]
|
|
||||||
enum SwordTactics {
|
|
||||||
Unskilled = 0,
|
|
||||||
Basic = 1,
|
|
||||||
HeavySimple = 2,
|
|
||||||
AgileSimple = 3,
|
|
||||||
DefensiveSimple = 4,
|
|
||||||
CripplingSimple = 5,
|
|
||||||
CleavingSimple = 6,
|
|
||||||
HeavyAdvanced = 7,
|
|
||||||
AgileAdvanced = 8,
|
|
||||||
DefensiveAdvanced = 9,
|
|
||||||
CripplingAdvanced = 10,
|
|
||||||
CleavingAdvanced = 11,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl SwordTactics {
|
|
||||||
fn from_u8(x: u8) -> Self {
|
|
||||||
use SwordTactics::*;
|
|
||||||
match x {
|
|
||||||
0 => Unskilled,
|
|
||||||
1 => Basic,
|
|
||||||
2 => HeavySimple,
|
|
||||||
3 => AgileSimple,
|
|
||||||
4 => DefensiveSimple,
|
|
||||||
5 => CripplingSimple,
|
|
||||||
6 => CleavingSimple,
|
|
||||||
7 => HeavyAdvanced,
|
|
||||||
8 => AgileAdvanced,
|
|
||||||
9 => DefensiveAdvanced,
|
|
||||||
10 => CripplingAdvanced,
|
|
||||||
11 => CleavingAdvanced,
|
|
||||||
_ => Unskilled,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if !agent.action_state.initialized {
|
if !agent.action_state.initialized {
|
||||||
agent.action_state.initialized = true;
|
agent.action_state.initialized = true;
|
||||||
let available_tactics = {
|
let available_tactics = {
|
||||||
@ -735,38 +702,6 @@ impl<'a> AgentData<'a> {
|
|||||||
ActionMode::Reckless as u8;
|
ActionMode::Reckless as u8;
|
||||||
}
|
}
|
||||||
|
|
||||||
enum ActionMode {
|
|
||||||
Reckless = 0,
|
|
||||||
Guarded = 1,
|
|
||||||
Fleeing = 2,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ActionMode {
|
|
||||||
fn from_u8(x: u8) -> Self {
|
|
||||||
match x {
|
|
||||||
0 => ActionMode::Reckless,
|
|
||||||
1 => ActionMode::Guarded,
|
|
||||||
2 => ActionMode::Fleeing,
|
|
||||||
_ => ActionMode::Guarded,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(health) = self.health {
|
|
||||||
agent.action_state.int_counters[IntCounters::ActionMode as usize] =
|
|
||||||
if health.fraction() < 0.1 {
|
|
||||||
agent.action_state.positions[Positions::GuardedCover as usize] = None;
|
|
||||||
ActionMode::Fleeing as u8
|
|
||||||
} else if health.fraction() < 0.9 {
|
|
||||||
agent.action_state.positions[Positions::Flee as usize] = None;
|
|
||||||
ActionMode::Guarded as u8
|
|
||||||
} else {
|
|
||||||
agent.action_state.positions[Positions::GuardedCover as usize] = None;
|
|
||||||
agent.action_state.positions[Positions::Flee as usize] = None;
|
|
||||||
ActionMode::Reckless as u8
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
enum IntCounters {
|
enum IntCounters {
|
||||||
Tactics = 0,
|
Tactics = 0,
|
||||||
ActionMode = 1,
|
ActionMode = 1,
|
||||||
@ -791,215 +726,23 @@ impl<'a> AgentData<'a> {
|
|||||||
Flee = 1,
|
Flee = 1,
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.vel.0.magnitude_squared() < 1_f32.powi(2) {
|
let attempt_attack = handle_attack_aggression(
|
||||||
agent.action_state.timers[Timers::PosTimeOut as usize] += read_data.dt.0;
|
self,
|
||||||
} else {
|
agent,
|
||||||
agent.action_state.timers[Timers::PosTimeOut as usize] = 0.0;
|
controller,
|
||||||
}
|
attack_data,
|
||||||
|
tgt_data,
|
||||||
if agent.action_state.timers[Timers::PosTimeOut as usize] > 2.0 {
|
read_data,
|
||||||
agent.action_state.positions.iter_mut().for_each(|pos| {
|
rng,
|
||||||
*pos = None;
|
Timers::PosTimeOut as usize,
|
||||||
});
|
Timers::GuardedCycle as usize,
|
||||||
agent.action_state.timers[Timers::PosTimeOut as usize] = 0.0;
|
FloatCounters::GuardedTimer as usize,
|
||||||
}
|
IntCounters::ActionMode as usize,
|
||||||
|
Conditions::GuardedDefend as usize,
|
||||||
let attempt_attack = match ActionMode::from_u8(
|
Conditions::RollingBreakThrough as usize,
|
||||||
agent.action_state.int_counters[IntCounters::ActionMode as usize],
|
Positions::GuardedCover as usize,
|
||||||
) {
|
Positions::Flee as usize,
|
||||||
ActionMode::Reckless => true,
|
);
|
||||||
ActionMode::Guarded => {
|
|
||||||
agent.action_state.timers[Timers::GuardedCycle as usize] += read_data.dt.0;
|
|
||||||
if agent.action_state.timers[Timers::GuardedCycle as usize]
|
|
||||||
> agent.action_state.counters[FloatCounters::GuardedTimer as usize]
|
|
||||||
{
|
|
||||||
agent.action_state.timers[Timers::GuardedCycle as usize] = 0.0;
|
|
||||||
agent.action_state.conditions[Conditions::GuardedDefend as usize] ^= true;
|
|
||||||
agent.action_state.counters[FloatCounters::GuardedTimer as usize] =
|
|
||||||
if agent.action_state.conditions[Conditions::GuardedDefend as usize] {
|
|
||||||
rng.gen_range(3.0..6.0)
|
|
||||||
} else {
|
|
||||||
rng.gen_range(6.0..10.0)
|
|
||||||
};
|
|
||||||
}
|
|
||||||
if let Some(pos) = agent.action_state.positions[Positions::GuardedCover as usize] {
|
|
||||||
if pos.distance_squared(self.pos.0) < 3_f32.powi(2) {
|
|
||||||
agent.action_state.positions[Positions::GuardedCover as usize] = None;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if !agent.action_state.conditions[Conditions::GuardedDefend as usize] {
|
|
||||||
agent.action_state.positions[Positions::GuardedCover as usize] = None;
|
|
||||||
true
|
|
||||||
} else {
|
|
||||||
if attack_data.dist_sqrd > 10_f32.powi(2) {
|
|
||||||
// Choose random point to either side when looking at target and move
|
|
||||||
// towards it
|
|
||||||
if let Some(pos) =
|
|
||||||
agent.action_state.positions[Positions::GuardedCover as usize]
|
|
||||||
{
|
|
||||||
if pos.distance_squared(self.pos.0) < 5_f32.powi(2) {
|
|
||||||
agent.action_state.positions[Positions::GuardedCover as usize] =
|
|
||||||
None;
|
|
||||||
}
|
|
||||||
self.path_toward_target(
|
|
||||||
agent,
|
|
||||||
controller,
|
|
||||||
pos,
|
|
||||||
read_data,
|
|
||||||
Path::Separate,
|
|
||||||
None,
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
agent.action_state.positions[Positions::GuardedCover as usize] = {
|
|
||||||
let rand_dir = {
|
|
||||||
let dir = (tgt_data.pos.0 - self.pos.0)
|
|
||||||
.try_normalized()
|
|
||||||
.unwrap_or(Vec3::unit_x())
|
|
||||||
.xy();
|
|
||||||
if rng.gen_bool(0.5) {
|
|
||||||
dir.rotated_z(PI / 2.0 + rng.gen_range(-0.75..0.0))
|
|
||||||
} else {
|
|
||||||
dir.rotated_z(-PI / 2.0 + rng.gen_range(-0.0..0.75))
|
|
||||||
}
|
|
||||||
};
|
|
||||||
let attempted_dist = rng.gen_range(6.0..16.0);
|
|
||||||
let actual_dist = read_data
|
|
||||||
.terrain
|
|
||||||
.ray(
|
|
||||||
self.pos.0 + Vec3::unit_z() * 0.5,
|
|
||||||
self.pos.0
|
|
||||||
+ Vec3::unit_z() * 0.5
|
|
||||||
+ rand_dir * attempted_dist,
|
|
||||||
)
|
|
||||||
.until(Block::is_solid)
|
|
||||||
.cast()
|
|
||||||
.0
|
|
||||||
- 1.0;
|
|
||||||
Some(self.pos.0 + rand_dir * actual_dist)
|
|
||||||
};
|
|
||||||
}
|
|
||||||
} else if let Some(pos) =
|
|
||||||
agent.action_state.positions[Positions::GuardedCover as usize]
|
|
||||||
{
|
|
||||||
self.path_toward_target(
|
|
||||||
agent,
|
|
||||||
controller,
|
|
||||||
pos,
|
|
||||||
read_data,
|
|
||||||
Path::Separate,
|
|
||||||
None,
|
|
||||||
);
|
|
||||||
if agent.action_state.conditions[Conditions::RollingBreakThrough as usize] {
|
|
||||||
controller.push_basic_input(InputKind::Roll);
|
|
||||||
agent.action_state.conditions
|
|
||||||
[Conditions::RollingBreakThrough as usize] = false;
|
|
||||||
}
|
|
||||||
if tgt_data.char_state.map_or(false, |cs| cs.is_melee_attack()) {
|
|
||||||
controller.push_basic_input(InputKind::Block);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
agent.action_state.positions[Positions::GuardedCover as usize] = {
|
|
||||||
let backwards = (self.pos.0 - tgt_data.pos.0)
|
|
||||||
.try_normalized()
|
|
||||||
.unwrap_or(Vec3::unit_x())
|
|
||||||
.xy();
|
|
||||||
let pos = if read_data
|
|
||||||
.terrain
|
|
||||||
.ray(
|
|
||||||
self.pos.0 + Vec3::unit_z() * 0.5,
|
|
||||||
self.pos.0 + Vec3::unit_z() * 0.5 + backwards * 6.0,
|
|
||||||
)
|
|
||||||
.until(Block::is_solid)
|
|
||||||
.cast()
|
|
||||||
.0
|
|
||||||
> 5.0
|
|
||||||
{
|
|
||||||
self.pos.0 + backwards * 5.0
|
|
||||||
} else {
|
|
||||||
agent.action_state.conditions
|
|
||||||
[Conditions::RollingBreakThrough as usize] = true;
|
|
||||||
self.pos.0
|
|
||||||
- backwards
|
|
||||||
* read_data
|
|
||||||
.terrain
|
|
||||||
.ray(
|
|
||||||
self.pos.0 + Vec3::unit_z() * 0.5,
|
|
||||||
self.pos.0 + Vec3::unit_z() * 0.5
|
|
||||||
- backwards * 10.0,
|
|
||||||
)
|
|
||||||
.until(Block::is_solid)
|
|
||||||
.cast()
|
|
||||||
.0
|
|
||||||
- 1.0
|
|
||||||
};
|
|
||||||
Some(pos)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
false
|
|
||||||
}
|
|
||||||
},
|
|
||||||
ActionMode::Fleeing => {
|
|
||||||
if agent.action_state.conditions[Conditions::RollingBreakThrough as usize] {
|
|
||||||
controller.push_basic_input(InputKind::Roll);
|
|
||||||
agent.action_state.conditions[Conditions::RollingBreakThrough as usize] = false;
|
|
||||||
}
|
|
||||||
if let Some(pos) = agent.action_state.positions[Positions::Flee as usize] {
|
|
||||||
if let Some(dir) = Dir::from_unnormalized(pos - self.pos.0) {
|
|
||||||
controller.inputs.look_dir = dir;
|
|
||||||
}
|
|
||||||
if pos.distance_squared(self.pos.0) < 5_f32.powi(2) {
|
|
||||||
agent.action_state.positions[Positions::Flee as usize] = None;
|
|
||||||
}
|
|
||||||
self.path_toward_target(
|
|
||||||
agent,
|
|
||||||
controller,
|
|
||||||
pos,
|
|
||||||
read_data,
|
|
||||||
Path::Separate,
|
|
||||||
None,
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
agent.action_state.positions[Positions::Flee as usize] = {
|
|
||||||
let rand_dir = {
|
|
||||||
let dir = (self.pos.0 - tgt_data.pos.0)
|
|
||||||
.try_normalized()
|
|
||||||
.unwrap_or(Vec3::unit_x())
|
|
||||||
.xy();
|
|
||||||
dir.rotated_z(rng.gen_range(-0.75..0.75))
|
|
||||||
};
|
|
||||||
let attempted_dist = rng.gen_range(16.0..26.0);
|
|
||||||
let actual_dist = read_data
|
|
||||||
.terrain
|
|
||||||
.ray(
|
|
||||||
self.pos.0 + Vec3::unit_z() * 0.5,
|
|
||||||
self.pos.0 + Vec3::unit_z() * 0.5 + rand_dir * attempted_dist,
|
|
||||||
)
|
|
||||||
.until(Block::is_solid)
|
|
||||||
.cast()
|
|
||||||
.0
|
|
||||||
- 1.0;
|
|
||||||
if actual_dist < 10.0 {
|
|
||||||
let dist = read_data
|
|
||||||
.terrain
|
|
||||||
.ray(
|
|
||||||
self.pos.0 + Vec3::unit_z() * 0.5,
|
|
||||||
self.pos.0 + Vec3::unit_z() * 0.5 - rand_dir * attempted_dist,
|
|
||||||
)
|
|
||||||
.until(Block::is_solid)
|
|
||||||
.cast()
|
|
||||||
.0
|
|
||||||
- 1.0;
|
|
||||||
agent.action_state.conditions
|
|
||||||
[Conditions::RollingBreakThrough as usize] = true;
|
|
||||||
Some(self.pos.0 - rand_dir * dist)
|
|
||||||
} else {
|
|
||||||
Some(self.pos.0 + rand_dir * actual_dist)
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
false
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
let attack_failed = if attempt_attack {
|
let attack_failed = if attempt_attack {
|
||||||
let context = AbilityContext::from(self.stance);
|
let context = AbilityContext::from(self.stance);
|
||||||
@ -1040,6 +783,23 @@ impl<'a> AgentData<'a> {
|
|||||||
}),
|
}),
|
||||||
_ => false,
|
_ => false,
|
||||||
};
|
};
|
||||||
|
let continue_current_input = |current_input, next_input: &mut Option<InputKind>| {
|
||||||
|
if matches!(current_input, InputKind::Secondary) {
|
||||||
|
let charging =
|
||||||
|
matches!(self.char_state.stage_section(), Some(StageSection::Charge));
|
||||||
|
let charged = self
|
||||||
|
.char_state
|
||||||
|
.durations()
|
||||||
|
.and_then(|durs| durs.charge)
|
||||||
|
.zip(self.char_state.timer())
|
||||||
|
.map_or(false, |(dur, timer)| timer > dur);
|
||||||
|
if !(charging && charged) {
|
||||||
|
*next_input = Some(InputKind::Secondary);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
*next_input = Some(current_input);
|
||||||
|
}
|
||||||
|
};
|
||||||
match SwordTactics::from_u8(
|
match SwordTactics::from_u8(
|
||||||
agent.action_state.int_counters[IntCounters::Tactics as usize],
|
agent.action_state.int_counters[IntCounters::Tactics as usize],
|
||||||
) {
|
) {
|
||||||
@ -1050,23 +810,7 @@ impl<'a> AgentData<'a> {
|
|||||||
let current_input = self.char_state.ability_info().map(|ai| ai.input);
|
let current_input = self.char_state.ability_info().map(|ai| ai.input);
|
||||||
let mut next_input = None;
|
let mut next_input = None;
|
||||||
if let Some(input) = current_input {
|
if let Some(input) = current_input {
|
||||||
if matches!(input, InputKind::Secondary) {
|
continue_current_input(input, &mut next_input);
|
||||||
let charging = matches!(
|
|
||||||
self.char_state.stage_section(),
|
|
||||||
Some(StageSection::Charge)
|
|
||||||
);
|
|
||||||
let charged = self
|
|
||||||
.char_state
|
|
||||||
.durations()
|
|
||||||
.and_then(|durs| durs.charge)
|
|
||||||
.zip(self.char_state.timer())
|
|
||||||
.map_or(false, |(dur, timer)| timer > dur);
|
|
||||||
if !(charging && charged) {
|
|
||||||
next_input = Some(InputKind::Secondary);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
next_input = Some(input);
|
|
||||||
}
|
|
||||||
} else if rng.gen_bool(0.5) {
|
} else if rng.gen_bool(0.5) {
|
||||||
next_input = Some(InputKind::Primary);
|
next_input = Some(InputKind::Primary);
|
||||||
} else {
|
} else {
|
||||||
@ -1090,23 +834,7 @@ impl<'a> AgentData<'a> {
|
|||||||
let current_input = self.char_state.ability_info().map(|ai| ai.input);
|
let current_input = self.char_state.ability_info().map(|ai| ai.input);
|
||||||
let mut next_input = None;
|
let mut next_input = None;
|
||||||
if let Some(input) = current_input {
|
if let Some(input) = current_input {
|
||||||
if matches!(input, InputKind::Secondary) {
|
continue_current_input(input, &mut next_input);
|
||||||
let charging = matches!(
|
|
||||||
self.char_state.stage_section(),
|
|
||||||
Some(StageSection::Charge)
|
|
||||||
);
|
|
||||||
let charged = self
|
|
||||||
.char_state
|
|
||||||
.durations()
|
|
||||||
.and_then(|durs| durs.charge)
|
|
||||||
.zip(self.char_state.timer())
|
|
||||||
.map_or(false, |(dur, timer)| timer > dur);
|
|
||||||
if !(charging && charged) {
|
|
||||||
next_input = Some(InputKind::Secondary);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
next_input = Some(input);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
let attempt_ability = InputKind::Ability(rng.gen_range(0..5));
|
let attempt_ability = InputKind::Ability(rng.gen_range(0..5));
|
||||||
if could_use_input(attempt_ability, &misc_data) {
|
if could_use_input(attempt_ability, &misc_data) {
|
||||||
@ -1135,23 +863,7 @@ impl<'a> AgentData<'a> {
|
|||||||
let current_input = self.char_state.ability_info().map(|ai| ai.input);
|
let current_input = self.char_state.ability_info().map(|ai| ai.input);
|
||||||
let mut next_input = None;
|
let mut next_input = None;
|
||||||
if let Some(input) = current_input {
|
if let Some(input) = current_input {
|
||||||
if matches!(input, InputKind::Secondary) {
|
continue_current_input(input, &mut next_input);
|
||||||
let charging = matches!(
|
|
||||||
self.char_state.stage_section(),
|
|
||||||
Some(StageSection::Charge)
|
|
||||||
);
|
|
||||||
let charged = self
|
|
||||||
.char_state
|
|
||||||
.durations()
|
|
||||||
.and_then(|durs| durs.charge)
|
|
||||||
.zip(self.char_state.timer())
|
|
||||||
.map_or(false, |(dur, timer)| timer > dur);
|
|
||||||
if !(charging && charged) {
|
|
||||||
next_input = Some(InputKind::Secondary);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
next_input = Some(input);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
let stance_ability = InputKind::Ability(rng.gen_range(3..5));
|
let stance_ability = InputKind::Ability(rng.gen_range(3..5));
|
||||||
let random_ability = InputKind::Ability(rng.gen_range(1..5));
|
let random_ability = InputKind::Ability(rng.gen_range(1..5));
|
||||||
@ -1191,23 +903,7 @@ impl<'a> AgentData<'a> {
|
|||||||
let current_input = self.char_state.ability_info().map(|ai| ai.input);
|
let current_input = self.char_state.ability_info().map(|ai| ai.input);
|
||||||
let mut next_input = None;
|
let mut next_input = None;
|
||||||
if let Some(input) = current_input {
|
if let Some(input) = current_input {
|
||||||
if matches!(input, InputKind::Secondary) {
|
continue_current_input(input, &mut next_input);
|
||||||
let charging = matches!(
|
|
||||||
self.char_state.stage_section(),
|
|
||||||
Some(StageSection::Charge)
|
|
||||||
);
|
|
||||||
let charged = self
|
|
||||||
.char_state
|
|
||||||
.durations()
|
|
||||||
.and_then(|durs| durs.charge)
|
|
||||||
.zip(self.char_state.timer())
|
|
||||||
.map_or(false, |(dur, timer)| timer > dur);
|
|
||||||
if !(charging && charged) {
|
|
||||||
next_input = Some(InputKind::Secondary);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
next_input = Some(input);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
let stance_ability = InputKind::Ability(rng.gen_range(3..5));
|
let stance_ability = InputKind::Ability(rng.gen_range(3..5));
|
||||||
let random_ability = InputKind::Ability(rng.gen_range(1..5));
|
let random_ability = InputKind::Ability(rng.gen_range(1..5));
|
||||||
@ -1247,23 +943,7 @@ impl<'a> AgentData<'a> {
|
|||||||
let current_input = self.char_state.ability_info().map(|ai| ai.input);
|
let current_input = self.char_state.ability_info().map(|ai| ai.input);
|
||||||
let mut next_input = None;
|
let mut next_input = None;
|
||||||
if let Some(input) = current_input {
|
if let Some(input) = current_input {
|
||||||
if matches!(input, InputKind::Secondary) {
|
continue_current_input(input, &mut next_input);
|
||||||
let charging = matches!(
|
|
||||||
self.char_state.stage_section(),
|
|
||||||
Some(StageSection::Charge)
|
|
||||||
);
|
|
||||||
let charged = self
|
|
||||||
.char_state
|
|
||||||
.durations()
|
|
||||||
.and_then(|durs| durs.charge)
|
|
||||||
.zip(self.char_state.timer())
|
|
||||||
.map_or(false, |(dur, timer)| timer > dur);
|
|
||||||
if !(charging && charged) {
|
|
||||||
next_input = Some(InputKind::Secondary);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
next_input = Some(input);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
let stance_ability = InputKind::Ability(rng.gen_range(3..5));
|
let stance_ability = InputKind::Ability(rng.gen_range(3..5));
|
||||||
let random_ability = InputKind::Ability(rng.gen_range(1..5));
|
let random_ability = InputKind::Ability(rng.gen_range(1..5));
|
||||||
@ -1305,23 +985,7 @@ impl<'a> AgentData<'a> {
|
|||||||
let current_input = self.char_state.ability_info().map(|ai| ai.input);
|
let current_input = self.char_state.ability_info().map(|ai| ai.input);
|
||||||
let mut next_input = None;
|
let mut next_input = None;
|
||||||
if let Some(input) = current_input {
|
if let Some(input) = current_input {
|
||||||
if matches!(input, InputKind::Secondary) {
|
continue_current_input(input, &mut next_input);
|
||||||
let charging = matches!(
|
|
||||||
self.char_state.stage_section(),
|
|
||||||
Some(StageSection::Charge)
|
|
||||||
);
|
|
||||||
let charged = self
|
|
||||||
.char_state
|
|
||||||
.durations()
|
|
||||||
.and_then(|durs| durs.charge)
|
|
||||||
.zip(self.char_state.timer())
|
|
||||||
.map_or(false, |(dur, timer)| timer > dur);
|
|
||||||
if !(charging && charged) {
|
|
||||||
next_input = Some(InputKind::Secondary);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
next_input = Some(input);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
let stance_ability = InputKind::Ability(rng.gen_range(3..5));
|
let stance_ability = InputKind::Ability(rng.gen_range(3..5));
|
||||||
let random_ability = InputKind::Ability(rng.gen_range(1..5));
|
let random_ability = InputKind::Ability(rng.gen_range(1..5));
|
||||||
@ -1361,23 +1025,7 @@ impl<'a> AgentData<'a> {
|
|||||||
let current_input = self.char_state.ability_info().map(|ai| ai.input);
|
let current_input = self.char_state.ability_info().map(|ai| ai.input);
|
||||||
let mut next_input = None;
|
let mut next_input = None;
|
||||||
if let Some(input) = current_input {
|
if let Some(input) = current_input {
|
||||||
if matches!(input, InputKind::Secondary) {
|
continue_current_input(input, &mut next_input);
|
||||||
let charging = matches!(
|
|
||||||
self.char_state.stage_section(),
|
|
||||||
Some(StageSection::Charge)
|
|
||||||
);
|
|
||||||
let charged = self
|
|
||||||
.char_state
|
|
||||||
.durations()
|
|
||||||
.and_then(|durs| durs.charge)
|
|
||||||
.zip(self.char_state.timer())
|
|
||||||
.map_or(false, |(dur, timer)| timer > dur);
|
|
||||||
if !(charging && charged) {
|
|
||||||
next_input = Some(InputKind::Secondary);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
next_input = Some(input);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
let stance_ability = InputKind::Ability(rng.gen_range(3..5));
|
let stance_ability = InputKind::Ability(rng.gen_range(3..5));
|
||||||
let random_ability = InputKind::Ability(rng.gen_range(1..5));
|
let random_ability = InputKind::Ability(rng.gen_range(1..5));
|
||||||
@ -1417,23 +1065,7 @@ impl<'a> AgentData<'a> {
|
|||||||
let current_input = self.char_state.ability_info().map(|ai| ai.input);
|
let current_input = self.char_state.ability_info().map(|ai| ai.input);
|
||||||
let mut next_input = None;
|
let mut next_input = None;
|
||||||
if let Some(input) = current_input {
|
if let Some(input) = current_input {
|
||||||
if matches!(input, InputKind::Secondary) {
|
continue_current_input(input, &mut next_input);
|
||||||
let charging = matches!(
|
|
||||||
self.char_state.stage_section(),
|
|
||||||
Some(StageSection::Charge)
|
|
||||||
);
|
|
||||||
let charged = self
|
|
||||||
.char_state
|
|
||||||
.durations()
|
|
||||||
.and_then(|durs| durs.charge)
|
|
||||||
.zip(self.char_state.timer())
|
|
||||||
.map_or(false, |(dur, timer)| timer > dur);
|
|
||||||
if !(charging && charged) {
|
|
||||||
next_input = Some(InputKind::Secondary);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
next_input = Some(input);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
let stance_ability = InputKind::Ability(rng.gen_range(1..3));
|
let stance_ability = InputKind::Ability(rng.gen_range(1..3));
|
||||||
let random_ability = InputKind::Ability(rng.gen_range(1..5));
|
let random_ability = InputKind::Ability(rng.gen_range(1..5));
|
||||||
@ -1473,23 +1105,7 @@ impl<'a> AgentData<'a> {
|
|||||||
let current_input = self.char_state.ability_info().map(|ai| ai.input);
|
let current_input = self.char_state.ability_info().map(|ai| ai.input);
|
||||||
let mut next_input = None;
|
let mut next_input = None;
|
||||||
if let Some(input) = current_input {
|
if let Some(input) = current_input {
|
||||||
if matches!(input, InputKind::Secondary) {
|
continue_current_input(input, &mut next_input);
|
||||||
let charging = matches!(
|
|
||||||
self.char_state.stage_section(),
|
|
||||||
Some(StageSection::Charge)
|
|
||||||
);
|
|
||||||
let charged = self
|
|
||||||
.char_state
|
|
||||||
.durations()
|
|
||||||
.and_then(|durs| durs.charge)
|
|
||||||
.zip(self.char_state.timer())
|
|
||||||
.map_or(false, |(dur, timer)| timer > dur);
|
|
||||||
if !(charging && charged) {
|
|
||||||
next_input = Some(InputKind::Secondary);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
next_input = Some(input);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
let stance_ability = InputKind::Ability(rng.gen_range(1..3));
|
let stance_ability = InputKind::Ability(rng.gen_range(1..3));
|
||||||
let random_ability = InputKind::Ability(rng.gen_range(1..5));
|
let random_ability = InputKind::Ability(rng.gen_range(1..5));
|
||||||
@ -1529,23 +1145,7 @@ impl<'a> AgentData<'a> {
|
|||||||
let current_input = self.char_state.ability_info().map(|ai| ai.input);
|
let current_input = self.char_state.ability_info().map(|ai| ai.input);
|
||||||
let mut next_input = None;
|
let mut next_input = None;
|
||||||
if let Some(input) = current_input {
|
if let Some(input) = current_input {
|
||||||
if matches!(input, InputKind::Secondary) {
|
continue_current_input(input, &mut next_input);
|
||||||
let charging = matches!(
|
|
||||||
self.char_state.stage_section(),
|
|
||||||
Some(StageSection::Charge)
|
|
||||||
);
|
|
||||||
let charged = self
|
|
||||||
.char_state
|
|
||||||
.durations()
|
|
||||||
.and_then(|durs| durs.charge)
|
|
||||||
.zip(self.char_state.timer())
|
|
||||||
.map_or(false, |(dur, timer)| timer > dur);
|
|
||||||
if !(charging && charged) {
|
|
||||||
next_input = Some(InputKind::Secondary);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
next_input = Some(input);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
let stance_ability = InputKind::Ability(rng.gen_range(1..3));
|
let stance_ability = InputKind::Ability(rng.gen_range(1..3));
|
||||||
let random_ability = InputKind::Ability(rng.gen_range(1..4));
|
let random_ability = InputKind::Ability(rng.gen_range(1..4));
|
||||||
@ -1589,23 +1189,7 @@ impl<'a> AgentData<'a> {
|
|||||||
let current_input = self.char_state.ability_info().map(|ai| ai.input);
|
let current_input = self.char_state.ability_info().map(|ai| ai.input);
|
||||||
let mut next_input = None;
|
let mut next_input = None;
|
||||||
if let Some(input) = current_input {
|
if let Some(input) = current_input {
|
||||||
if matches!(input, InputKind::Secondary) {
|
continue_current_input(input, &mut next_input);
|
||||||
let charging = matches!(
|
|
||||||
self.char_state.stage_section(),
|
|
||||||
Some(StageSection::Charge)
|
|
||||||
);
|
|
||||||
let charged = self
|
|
||||||
.char_state
|
|
||||||
.durations()
|
|
||||||
.and_then(|durs| durs.charge)
|
|
||||||
.zip(self.char_state.timer())
|
|
||||||
.map_or(false, |(dur, timer)| timer > dur);
|
|
||||||
if !(charging && charged) {
|
|
||||||
next_input = Some(InputKind::Secondary);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
next_input = Some(input);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
let stance_ability = InputKind::Ability(rng.gen_range(1..3));
|
let stance_ability = InputKind::Ability(rng.gen_range(1..3));
|
||||||
let random_ability = InputKind::Ability(rng.gen_range(1..5));
|
let random_ability = InputKind::Ability(rng.gen_range(1..5));
|
||||||
@ -1645,23 +1229,7 @@ impl<'a> AgentData<'a> {
|
|||||||
let current_input = self.char_state.ability_info().map(|ai| ai.input);
|
let current_input = self.char_state.ability_info().map(|ai| ai.input);
|
||||||
let mut next_input = None;
|
let mut next_input = None;
|
||||||
if let Some(input) = current_input {
|
if let Some(input) = current_input {
|
||||||
if matches!(input, InputKind::Secondary) {
|
continue_current_input(input, &mut next_input);
|
||||||
let charging = matches!(
|
|
||||||
self.char_state.stage_section(),
|
|
||||||
Some(StageSection::Charge)
|
|
||||||
);
|
|
||||||
let charged = self
|
|
||||||
.char_state
|
|
||||||
.durations()
|
|
||||||
.and_then(|durs| durs.charge)
|
|
||||||
.zip(self.char_state.timer())
|
|
||||||
.map_or(false, |(dur, timer)| timer > dur);
|
|
||||||
if !(charging && charged) {
|
|
||||||
next_input = Some(InputKind::Secondary);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
next_input = Some(input);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
let stance_ability = InputKind::Ability(rng.gen_range(1..3));
|
let stance_ability = InputKind::Ability(rng.gen_range(1..3));
|
||||||
let random_ability = InputKind::Ability(rng.gen_range(1..5));
|
let random_ability = InputKind::Ability(rng.gen_range(1..5));
|
||||||
|
@ -89,6 +89,23 @@ impl AttackData {
|
|||||||
pub fn in_min_range(&self) -> bool { self.dist_sqrd < self.min_attack_dist.powi(2) }
|
pub fn in_min_range(&self) -> bool { self.dist_sqrd < self.min_attack_dist.powi(2) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub enum ActionMode {
|
||||||
|
Reckless = 0,
|
||||||
|
Guarded = 1,
|
||||||
|
Fleeing = 2,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ActionMode {
|
||||||
|
pub fn from_u8(x: u8) -> Self {
|
||||||
|
match x {
|
||||||
|
0 => ActionMode::Reckless,
|
||||||
|
1 => ActionMode::Guarded,
|
||||||
|
2 => ActionMode::Fleeing,
|
||||||
|
_ => ActionMode::Guarded,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Eq, PartialEq)]
|
#[derive(Eq, PartialEq)]
|
||||||
// When adding a new variant, first decide if it should instead fall under one
|
// When adding a new variant, first decide if it should instead fall under one
|
||||||
// of the pre-existing tactics
|
// of the pre-existing tactics
|
||||||
@ -151,6 +168,43 @@ pub enum Tactic {
|
|||||||
BorealHammer,
|
BorealHammer,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone)]
|
||||||
|
pub enum SwordTactics {
|
||||||
|
Unskilled = 0,
|
||||||
|
Basic = 1,
|
||||||
|
HeavySimple = 2,
|
||||||
|
AgileSimple = 3,
|
||||||
|
DefensiveSimple = 4,
|
||||||
|
CripplingSimple = 5,
|
||||||
|
CleavingSimple = 6,
|
||||||
|
HeavyAdvanced = 7,
|
||||||
|
AgileAdvanced = 8,
|
||||||
|
DefensiveAdvanced = 9,
|
||||||
|
CripplingAdvanced = 10,
|
||||||
|
CleavingAdvanced = 11,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SwordTactics {
|
||||||
|
pub fn from_u8(x: u8) -> Self {
|
||||||
|
use SwordTactics::*;
|
||||||
|
match x {
|
||||||
|
0 => Unskilled,
|
||||||
|
1 => Basic,
|
||||||
|
2 => HeavySimple,
|
||||||
|
3 => AgileSimple,
|
||||||
|
4 => DefensiveSimple,
|
||||||
|
5 => CripplingSimple,
|
||||||
|
6 => CleavingSimple,
|
||||||
|
7 => HeavyAdvanced,
|
||||||
|
8 => AgileAdvanced,
|
||||||
|
9 => DefensiveAdvanced,
|
||||||
|
10 => CripplingAdvanced,
|
||||||
|
11 => CleavingAdvanced,
|
||||||
|
_ => Unskilled,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(SystemData)]
|
#[derive(SystemData)]
|
||||||
pub struct ReadData<'a> {
|
pub struct ReadData<'a> {
|
||||||
pub entities: Entities<'a>,
|
pub entities: Entities<'a>,
|
||||||
|
@ -1,14 +1,16 @@
|
|||||||
use crate::data::{AgentData, ReadData};
|
use crate::data::{ActionMode, AgentData, AttackData, Path, ReadData, TargetData};
|
||||||
use common::{
|
use common::{
|
||||||
comp::{
|
comp::{
|
||||||
agent::Psyche, buff::BuffKind, inventory::item::ItemTag, item::ItemDesc, Alignment, Body,
|
agent::Psyche, buff::BuffKind, inventory::item::ItemTag, item::ItemDesc, Agent, Alignment,
|
||||||
Pos,
|
Body, Controller, InputKind, Pos,
|
||||||
},
|
},
|
||||||
consts::GRAVITY,
|
consts::GRAVITY,
|
||||||
terrain::Block,
|
terrain::Block,
|
||||||
util::Dir,
|
util::Dir,
|
||||||
vol::ReadVol,
|
vol::ReadVol,
|
||||||
};
|
};
|
||||||
|
use core::f32::consts::PI;
|
||||||
|
use rand::Rng;
|
||||||
use specs::{
|
use specs::{
|
||||||
saveload::{Marker, MarkerAllocator},
|
saveload::{Marker, MarkerAllocator},
|
||||||
Entity as EcsEntity,
|
Entity as EcsEntity,
|
||||||
@ -202,3 +204,243 @@ impl<'a> AgentData<'a> {
|
|||||||
.map_or(false, |b| b.kinds.contains_key(&buff))
|
.map_or(false, |b| b.kinds.contains_key(&buff))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Probably works best for melee (or maybe only for melee considering its
|
||||||
|
// reliance on blocking?)
|
||||||
|
/// Handles whether an agent should attack and how the agent moves around.
|
||||||
|
/// Returns whether the agent should attack (so that individual tactics can
|
||||||
|
/// determine what specific attack to use)
|
||||||
|
pub fn handle_attack_aggression(
|
||||||
|
agent_data: &AgentData,
|
||||||
|
agent: &mut Agent,
|
||||||
|
controller: &mut Controller,
|
||||||
|
attack_data: &AttackData,
|
||||||
|
tgt_data: &TargetData,
|
||||||
|
read_data: &ReadData,
|
||||||
|
rng: &mut impl Rng,
|
||||||
|
timer_pos_timeout_index: usize,
|
||||||
|
timer_guarded_cycle_index: usize,
|
||||||
|
fcounter_guarded_timer_index: usize,
|
||||||
|
icounter_action_mode_index: usize,
|
||||||
|
condition_guarded_defend_index: usize,
|
||||||
|
condition_rolling_breakthrough_index: usize,
|
||||||
|
position_guarded_cover_index: usize,
|
||||||
|
position_flee_index: usize,
|
||||||
|
) -> bool {
|
||||||
|
if let Some(health) = agent_data.health {
|
||||||
|
agent.action_state.int_counters[icounter_action_mode_index] = if health.fraction() < 0.1 {
|
||||||
|
agent.action_state.positions[position_guarded_cover_index] = None;
|
||||||
|
ActionMode::Fleeing as u8
|
||||||
|
} else if health.fraction() < 0.9 {
|
||||||
|
agent.action_state.positions[position_flee_index] = None;
|
||||||
|
ActionMode::Guarded as u8
|
||||||
|
} else {
|
||||||
|
agent.action_state.positions[position_guarded_cover_index] = None;
|
||||||
|
agent.action_state.positions[position_flee_index] = None;
|
||||||
|
ActionMode::Reckless as u8
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// If agent has not moved, assume agent was unable to move and reset attempted
|
||||||
|
// path positions if occurs for too long
|
||||||
|
if agent_data.vel.0.magnitude_squared() < 1_f32.powi(2) {
|
||||||
|
agent.action_state.timers[timer_pos_timeout_index] += read_data.dt.0;
|
||||||
|
} else {
|
||||||
|
agent.action_state.timers[timer_pos_timeout_index] = 0.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if agent.action_state.timers[timer_pos_timeout_index] > 2.0 {
|
||||||
|
agent.action_state.positions[position_guarded_cover_index] = None;
|
||||||
|
agent.action_state.positions[position_flee_index] = None;
|
||||||
|
agent.action_state.timers[timer_pos_timeout_index] = 0.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
match ActionMode::from_u8(agent.action_state.int_counters[icounter_action_mode_index]) {
|
||||||
|
ActionMode::Reckless => true,
|
||||||
|
ActionMode::Guarded => {
|
||||||
|
agent.action_state.timers[timer_guarded_cycle_index] += read_data.dt.0;
|
||||||
|
if agent.action_state.timers[timer_guarded_cycle_index]
|
||||||
|
> agent.action_state.counters[fcounter_guarded_timer_index]
|
||||||
|
{
|
||||||
|
agent.action_state.timers[timer_guarded_cycle_index] = 0.0;
|
||||||
|
agent.action_state.conditions[condition_guarded_defend_index] ^= true;
|
||||||
|
agent.action_state.counters[fcounter_guarded_timer_index] =
|
||||||
|
if agent.action_state.conditions[condition_guarded_defend_index] {
|
||||||
|
rng.gen_range(3.0..6.0)
|
||||||
|
} else {
|
||||||
|
rng.gen_range(6.0..10.0)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
if let Some(pos) = agent.action_state.positions[position_guarded_cover_index] {
|
||||||
|
if pos.distance_squared(agent_data.pos.0) < 3_f32.powi(2) {
|
||||||
|
agent.action_state.positions[position_guarded_cover_index] = None;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !agent.action_state.conditions[condition_guarded_defend_index] {
|
||||||
|
agent.action_state.positions[position_guarded_cover_index] = None;
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
if attack_data.dist_sqrd > 10_f32.powi(2) {
|
||||||
|
// Choose random point to either side when looking at target and move
|
||||||
|
// towards it
|
||||||
|
if let Some(pos) = agent.action_state.positions[position_guarded_cover_index] {
|
||||||
|
if pos.distance_squared(agent_data.pos.0) < 5_f32.powi(2) {
|
||||||
|
agent.action_state.positions[position_guarded_cover_index] = None;
|
||||||
|
}
|
||||||
|
agent_data.path_toward_target(
|
||||||
|
agent,
|
||||||
|
controller,
|
||||||
|
pos,
|
||||||
|
read_data,
|
||||||
|
Path::Separate,
|
||||||
|
None,
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
agent.action_state.positions[position_guarded_cover_index] = {
|
||||||
|
let rand_dir = {
|
||||||
|
let dir = (tgt_data.pos.0 - agent_data.pos.0)
|
||||||
|
.try_normalized()
|
||||||
|
.unwrap_or(Vec3::unit_x())
|
||||||
|
.xy();
|
||||||
|
if rng.gen_bool(0.5) {
|
||||||
|
dir.rotated_z(PI / 2.0 + rng.gen_range(-0.75..0.0))
|
||||||
|
} else {
|
||||||
|
dir.rotated_z(-PI / 2.0 + rng.gen_range(-0.0..0.75))
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let attempted_dist = rng.gen_range(6.0..16.0);
|
||||||
|
let actual_dist = read_data
|
||||||
|
.terrain
|
||||||
|
.ray(
|
||||||
|
agent_data.pos.0 + Vec3::unit_z() * 0.5,
|
||||||
|
agent_data.pos.0
|
||||||
|
+ Vec3::unit_z() * 0.5
|
||||||
|
+ rand_dir * attempted_dist,
|
||||||
|
)
|
||||||
|
.until(Block::is_solid)
|
||||||
|
.cast()
|
||||||
|
.0
|
||||||
|
- 1.0;
|
||||||
|
Some(agent_data.pos.0 + rand_dir * actual_dist)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
} else if let Some(pos) = agent.action_state.positions[position_guarded_cover_index]
|
||||||
|
{
|
||||||
|
agent_data.path_toward_target(
|
||||||
|
agent,
|
||||||
|
controller,
|
||||||
|
pos,
|
||||||
|
read_data,
|
||||||
|
Path::Separate,
|
||||||
|
None,
|
||||||
|
);
|
||||||
|
if agent.action_state.conditions[condition_rolling_breakthrough_index] {
|
||||||
|
controller.push_basic_input(InputKind::Roll);
|
||||||
|
agent.action_state.conditions[condition_rolling_breakthrough_index] = false;
|
||||||
|
}
|
||||||
|
if tgt_data.char_state.map_or(false, |cs| cs.is_melee_attack()) {
|
||||||
|
controller.push_basic_input(InputKind::Block);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
agent.action_state.positions[position_guarded_cover_index] = {
|
||||||
|
let backwards = (agent_data.pos.0 - tgt_data.pos.0)
|
||||||
|
.try_normalized()
|
||||||
|
.unwrap_or(Vec3::unit_x())
|
||||||
|
.xy();
|
||||||
|
let pos = if read_data
|
||||||
|
.terrain
|
||||||
|
.ray(
|
||||||
|
agent_data.pos.0 + Vec3::unit_z() * 0.5,
|
||||||
|
agent_data.pos.0 + Vec3::unit_z() * 0.5 + backwards * 6.0,
|
||||||
|
)
|
||||||
|
.until(Block::is_solid)
|
||||||
|
.cast()
|
||||||
|
.0
|
||||||
|
> 5.0
|
||||||
|
{
|
||||||
|
agent_data.pos.0 + backwards * 5.0
|
||||||
|
} else {
|
||||||
|
agent.action_state.conditions[condition_rolling_breakthrough_index] =
|
||||||
|
true;
|
||||||
|
agent_data.pos.0
|
||||||
|
- backwards
|
||||||
|
* read_data
|
||||||
|
.terrain
|
||||||
|
.ray(
|
||||||
|
agent_data.pos.0 + Vec3::unit_z() * 0.5,
|
||||||
|
agent_data.pos.0 + Vec3::unit_z() * 0.5
|
||||||
|
- backwards * 10.0,
|
||||||
|
)
|
||||||
|
.until(Block::is_solid)
|
||||||
|
.cast()
|
||||||
|
.0
|
||||||
|
- 1.0
|
||||||
|
};
|
||||||
|
Some(pos)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
ActionMode::Fleeing => {
|
||||||
|
if agent.action_state.conditions[condition_rolling_breakthrough_index] {
|
||||||
|
controller.push_basic_input(InputKind::Roll);
|
||||||
|
agent.action_state.conditions[condition_rolling_breakthrough_index] = false;
|
||||||
|
}
|
||||||
|
if let Some(pos) = agent.action_state.positions[position_flee_index] {
|
||||||
|
if let Some(dir) = Dir::from_unnormalized(pos - agent_data.pos.0) {
|
||||||
|
controller.inputs.look_dir = dir;
|
||||||
|
}
|
||||||
|
if pos.distance_squared(agent_data.pos.0) < 5_f32.powi(2) {
|
||||||
|
agent.action_state.positions[position_flee_index] = None;
|
||||||
|
}
|
||||||
|
agent_data.path_toward_target(
|
||||||
|
agent,
|
||||||
|
controller,
|
||||||
|
pos,
|
||||||
|
read_data,
|
||||||
|
Path::Separate,
|
||||||
|
None,
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
agent.action_state.positions[position_flee_index] = {
|
||||||
|
let rand_dir = {
|
||||||
|
let dir = (agent_data.pos.0 - tgt_data.pos.0)
|
||||||
|
.try_normalized()
|
||||||
|
.unwrap_or(Vec3::unit_x())
|
||||||
|
.xy();
|
||||||
|
dir.rotated_z(rng.gen_range(-0.75..0.75))
|
||||||
|
};
|
||||||
|
let attempted_dist = rng.gen_range(16.0..26.0);
|
||||||
|
let actual_dist = read_data
|
||||||
|
.terrain
|
||||||
|
.ray(
|
||||||
|
agent_data.pos.0 + Vec3::unit_z() * 0.5,
|
||||||
|
agent_data.pos.0 + Vec3::unit_z() * 0.5 + rand_dir * attempted_dist,
|
||||||
|
)
|
||||||
|
.until(Block::is_solid)
|
||||||
|
.cast()
|
||||||
|
.0
|
||||||
|
- 1.0;
|
||||||
|
if actual_dist < 10.0 {
|
||||||
|
let dist = read_data
|
||||||
|
.terrain
|
||||||
|
.ray(
|
||||||
|
agent_data.pos.0 + Vec3::unit_z() * 0.5,
|
||||||
|
agent_data.pos.0 + Vec3::unit_z() * 0.5 - rand_dir * attempted_dist,
|
||||||
|
)
|
||||||
|
.until(Block::is_solid)
|
||||||
|
.cast()
|
||||||
|
.0
|
||||||
|
- 1.0;
|
||||||
|
agent.action_state.conditions[condition_rolling_breakthrough_index] = true;
|
||||||
|
Some(agent_data.pos.0 - rand_dir * dist)
|
||||||
|
} else {
|
||||||
|
Some(agent_data.pos.0 + rand_dir * actual_dist)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
false
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Reference in New Issue
Block a user