mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Ran Cargo fmt
This commit is contained in:
parent
cd5ae96424
commit
1922d69154
@ -21,20 +21,22 @@ pub const TRADE_INTERACTION_TIME: f32 = 300.0;
|
|||||||
const AWARENESS_DECREMENT_CONSTANT: f32 = 2.1;
|
const AWARENESS_DECREMENT_CONSTANT: f32 = 2.1;
|
||||||
const SECONDS_BEFORE_FORGET_SOUNDS: f64 = 180.0;
|
const SECONDS_BEFORE_FORGET_SOUNDS: f64 = 180.0;
|
||||||
|
|
||||||
//intentionally very few concurrent action state variables are allowed. This is to keep the
|
//intentionally very few concurrent action state variables are allowed. This is
|
||||||
//complexity of our AI from getting too large, too quickly. Originally I was
|
// to keep the complexity of our AI from getting too large, too quickly.
|
||||||
//going to provide 30 of these, but if we decide later that this is too many
|
// Originally I was going to provide 30 of these, but if we decide later that
|
||||||
//and somebody is already using 30 in one of their AI, it will be difficult
|
// this is too many and somebody is already using 30 in one of their AI, it will
|
||||||
//to go back.
|
// be difficult to go back.
|
||||||
|
|
||||||
/// The number of timers that a single Action node can track concurrently
|
/// The number of timers that a single Action node can track concurrently
|
||||||
/// Define constants within a given action node to index between them.
|
/// Define constants within a given action node to index between them.
|
||||||
const ACTIONSTATE_NUMBER_OF_CONCURRENT_TIMERS: usize = 5;
|
const ACTIONSTATE_NUMBER_OF_CONCURRENT_TIMERS: usize = 5;
|
||||||
/// The number of float counters that a single Action node can track concurrently
|
/// The number of float counters that a single Action node can track
|
||||||
/// Define constants within a given action node to index between them.
|
/// concurrently Define constants within a given action node to index between
|
||||||
|
/// them.
|
||||||
const ACTIONSTATE_NUMBER_OF_CONCURRENT_COUNTERS: usize = 5;
|
const ACTIONSTATE_NUMBER_OF_CONCURRENT_COUNTERS: usize = 5;
|
||||||
/// The number of integer counters that a single Action node can track concurrently
|
/// The number of integer counters that a single Action node can track
|
||||||
/// Define constants within a given action node to index between them.
|
/// concurrently Define constants within a given action node to index between
|
||||||
|
/// them.
|
||||||
const ACTIONSTATE_NUMBER_OF_CONCURRENT_INT_COUNTERS: usize = 5;
|
const ACTIONSTATE_NUMBER_OF_CONCURRENT_INT_COUNTERS: usize = 5;
|
||||||
/// The number of booleans that a single Action node can track concurrently
|
/// The number of booleans that a single Action node can track concurrently
|
||||||
/// Define constants within a given action node to index between them.
|
/// Define constants within a given action node to index between them.
|
||||||
@ -531,8 +533,9 @@ pub struct Agent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// State persistence object for the behavior tree
|
/// State persistence object for the behavior tree
|
||||||
/// Allows for state to be stored between subsequent, sequential calls of a single action node.
|
/// Allows for state to be stored between subsequent, sequential calls of a
|
||||||
/// If the executed action node changes between ticks, then the state should be considered lost.
|
/// single action node. If the executed action node changes between ticks, then
|
||||||
|
/// the state should be considered lost.
|
||||||
#[derive(Clone, Debug, Default)]
|
#[derive(Clone, Debug, Default)]
|
||||||
pub struct ActionState {
|
pub struct ActionState {
|
||||||
pub timers: [f32; ACTIONSTATE_NUMBER_OF_CONCURRENT_TIMERS],
|
pub timers: [f32; ACTIONSTATE_NUMBER_OF_CONCURRENT_TIMERS],
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
consts::{
|
consts::{
|
||||||
AVG_FOLLOW_DIST, DEFAULT_ATTACK_RANGE, IDLE_HEALING_ITEM_THRESHOLD, PARTIAL_PATH_DIST,
|
AVG_FOLLOW_DIST, DEFAULT_ATTACK_RANGE, IDLE_HEALING_ITEM_THRESHOLD, PARTIAL_PATH_DIST,
|
||||||
@ -44,9 +43,6 @@ use vek::*;
|
|||||||
#[cfg(feature = "use-dyn-lib")]
|
#[cfg(feature = "use-dyn-lib")]
|
||||||
use {crate::LIB, std::ffi::CStr};
|
use {crate::LIB, std::ffi::CStr};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
impl<'a> AgentData<'a> {
|
impl<'a> AgentData<'a> {
|
||||||
////////////////////////////////////////
|
////////////////////////////////////////
|
||||||
// Action Nodes
|
// Action Nodes
|
||||||
|
@ -213,8 +213,7 @@ impl<'a> AgentData<'a> {
|
|||||||
read_data: &ReadData,
|
read_data: &ReadData,
|
||||||
rng: &mut impl Rng,
|
rng: &mut impl Rng,
|
||||||
) {
|
) {
|
||||||
enum ActionStateTimers
|
enum ActionStateTimers {
|
||||||
{
|
|
||||||
TimerHandleAxeAttack = 0,
|
TimerHandleAxeAttack = 0,
|
||||||
}
|
}
|
||||||
let has_leap = || self.skill_set.has_skill(Skill::Axe(AxeSkill::UnlockLeap));
|
let has_leap = || self.skill_set.has_skill(Skill::Axe(AxeSkill::UnlockLeap));
|
||||||
@ -228,15 +227,21 @@ impl<'a> AgentData<'a> {
|
|||||||
if agent.action_state.timers[ActionStateTimers::TimerHandleAxeAttack as usize] > 5.0 {
|
if agent.action_state.timers[ActionStateTimers::TimerHandleAxeAttack as usize] > 5.0 {
|
||||||
controller.push_cancel_input(InputKind::Secondary);
|
controller.push_cancel_input(InputKind::Secondary);
|
||||||
agent.action_state.timers[ActionStateTimers::TimerHandleAxeAttack as usize] = 0.0;
|
agent.action_state.timers[ActionStateTimers::TimerHandleAxeAttack as usize] = 0.0;
|
||||||
} else if agent.action_state.timers[ActionStateTimers::TimerHandleAxeAttack as usize] > 2.5 && has_energy(10.0) {
|
} else if agent.action_state.timers[ActionStateTimers::TimerHandleAxeAttack as usize]
|
||||||
|
> 2.5
|
||||||
|
&& has_energy(10.0)
|
||||||
|
{
|
||||||
controller.push_basic_input(InputKind::Secondary);
|
controller.push_basic_input(InputKind::Secondary);
|
||||||
agent.action_state.timers[ActionStateTimers::TimerHandleAxeAttack as usize] += read_data.dt.0;
|
agent.action_state.timers[ActionStateTimers::TimerHandleAxeAttack as usize] +=
|
||||||
|
read_data.dt.0;
|
||||||
} else if has_leap() && has_energy(45.0) && rng.gen_bool(0.5) {
|
} else if has_leap() && has_energy(45.0) && rng.gen_bool(0.5) {
|
||||||
controller.push_basic_input(InputKind::Ability(0));
|
controller.push_basic_input(InputKind::Ability(0));
|
||||||
agent.action_state.timers[ActionStateTimers::TimerHandleAxeAttack as usize] += read_data.dt.0;
|
agent.action_state.timers[ActionStateTimers::TimerHandleAxeAttack as usize] +=
|
||||||
|
read_data.dt.0;
|
||||||
} else {
|
} else {
|
||||||
controller.push_basic_input(InputKind::Primary);
|
controller.push_basic_input(InputKind::Primary);
|
||||||
agent.action_state.timers[ActionStateTimers::TimerHandleAxeAttack as usize] += read_data.dt.0;
|
agent.action_state.timers[ActionStateTimers::TimerHandleAxeAttack as usize] +=
|
||||||
|
read_data.dt.0;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
self.path_toward_target(
|
self.path_toward_target(
|
||||||
@ -279,8 +284,7 @@ impl<'a> AgentData<'a> {
|
|||||||
read_data: &ReadData,
|
read_data: &ReadData,
|
||||||
rng: &mut impl Rng,
|
rng: &mut impl Rng,
|
||||||
) {
|
) {
|
||||||
enum ActionStateTimers
|
enum ActionStateTimers {
|
||||||
{
|
|
||||||
TimerHandleHammerAttack = 0,
|
TimerHandleHammerAttack = 0,
|
||||||
}
|
}
|
||||||
let has_leap = || {
|
let has_leap = || {
|
||||||
@ -296,18 +300,25 @@ impl<'a> AgentData<'a> {
|
|||||||
|
|
||||||
if attack_data.in_min_range() && attack_data.angle < 45.0 {
|
if attack_data.in_min_range() && attack_data.angle < 45.0 {
|
||||||
controller.inputs.move_dir = Vec2::zero();
|
controller.inputs.move_dir = Vec2::zero();
|
||||||
if agent.action_state.timers[ActionStateTimers::TimerHandleHammerAttack as usize] > 4.0 {
|
if agent.action_state.timers[ActionStateTimers::TimerHandleHammerAttack as usize] > 4.0
|
||||||
|
{
|
||||||
controller.push_cancel_input(InputKind::Secondary);
|
controller.push_cancel_input(InputKind::Secondary);
|
||||||
agent.action_state.timers[ActionStateTimers::TimerHandleHammerAttack as usize] = 0.0;
|
agent.action_state.timers[ActionStateTimers::TimerHandleHammerAttack as usize] =
|
||||||
} else if agent.action_state.timers[ActionStateTimers::TimerHandleHammerAttack as usize] > 3.0 {
|
0.0;
|
||||||
|
} else if agent.action_state.timers[ActionStateTimers::TimerHandleHammerAttack as usize]
|
||||||
|
> 3.0
|
||||||
|
{
|
||||||
controller.push_basic_input(InputKind::Secondary);
|
controller.push_basic_input(InputKind::Secondary);
|
||||||
agent.action_state.timers[ActionStateTimers::TimerHandleHammerAttack as usize] += read_data.dt.0;
|
agent.action_state.timers[ActionStateTimers::TimerHandleHammerAttack as usize] +=
|
||||||
|
read_data.dt.0;
|
||||||
} else if has_leap() && has_energy(50.0) && rng.gen_bool(0.9) {
|
} else if has_leap() && has_energy(50.0) && rng.gen_bool(0.9) {
|
||||||
use_leap(controller);
|
use_leap(controller);
|
||||||
agent.action_state.timers[ActionStateTimers::TimerHandleHammerAttack as usize] += read_data.dt.0;
|
agent.action_state.timers[ActionStateTimers::TimerHandleHammerAttack as usize] +=
|
||||||
|
read_data.dt.0;
|
||||||
} else {
|
} else {
|
||||||
controller.push_basic_input(InputKind::Primary);
|
controller.push_basic_input(InputKind::Primary);
|
||||||
agent.action_state.timers[ActionStateTimers::TimerHandleHammerAttack as usize] += read_data.dt.0;
|
agent.action_state.timers[ActionStateTimers::TimerHandleHammerAttack as usize] +=
|
||||||
|
read_data.dt.0;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
self.path_toward_target(
|
self.path_toward_target(
|
||||||
@ -358,16 +369,21 @@ impl<'a> AgentData<'a> {
|
|||||||
if self
|
if self
|
||||||
.skill_set
|
.skill_set
|
||||||
.has_skill(Skill::Sword(SwordSkill::UnlockSpin))
|
.has_skill(Skill::Sword(SwordSkill::UnlockSpin))
|
||||||
&& agent.action_state.timers[ActionStateTimers::TimerHandleSwordAttack as usize] < 2.0
|
&& agent.action_state.timers[ActionStateTimers::TimerHandleSwordAttack as usize]
|
||||||
|
< 2.0
|
||||||
&& self.energy.current() > 60.0
|
&& self.energy.current() > 60.0
|
||||||
{
|
{
|
||||||
controller.push_basic_input(InputKind::Ability(0));
|
controller.push_basic_input(InputKind::Ability(0));
|
||||||
agent.action_state.timers[ActionStateTimers::TimerHandleSwordAttack as usize] += read_data.dt.0;
|
agent.action_state.timers[ActionStateTimers::TimerHandleSwordAttack as usize] +=
|
||||||
} else if agent.action_state.timers[ActionStateTimers::TimerHandleSwordAttack as usize] > 2.0 {
|
read_data.dt.0;
|
||||||
|
} else if agent.action_state.timers[ActionStateTimers::TimerHandleSwordAttack as usize]
|
||||||
|
> 2.0
|
||||||
|
{
|
||||||
agent.action_state.timers[ActionStateTimers::TimerHandleSwordAttack as usize] = 0.0;
|
agent.action_state.timers[ActionStateTimers::TimerHandleSwordAttack as usize] = 0.0;
|
||||||
} else {
|
} else {
|
||||||
controller.push_basic_input(InputKind::Primary);
|
controller.push_basic_input(InputKind::Primary);
|
||||||
agent.action_state.timers[ActionStateTimers::TimerHandleSwordAttack as usize] += read_data.dt.0;
|
agent.action_state.timers[ActionStateTimers::TimerHandleSwordAttack as usize] +=
|
||||||
|
read_data.dt.0;
|
||||||
}
|
}
|
||||||
} else if attack_data.dist_sqrd < MAX_PATH_DIST.powi(2) {
|
} else if attack_data.dist_sqrd < MAX_PATH_DIST.powi(2) {
|
||||||
if self.path_toward_target(
|
if self.path_toward_target(
|
||||||
@ -384,11 +400,16 @@ impl<'a> AgentData<'a> {
|
|||||||
tgt_data.body,
|
tgt_data.body,
|
||||||
read_data,
|
read_data,
|
||||||
) {
|
) {
|
||||||
if agent.action_state.timers[ActionStateTimers::TimerHandleSwordAttack as usize] > 4.0 && attack_data.angle < 45.0 {
|
if agent.action_state.timers[ActionStateTimers::TimerHandleSwordAttack as usize]
|
||||||
|
> 4.0
|
||||||
|
&& attack_data.angle < 45.0
|
||||||
|
{
|
||||||
controller.push_basic_input(InputKind::Secondary);
|
controller.push_basic_input(InputKind::Secondary);
|
||||||
agent.action_state.timers[ActionStateTimers::TimerHandleSwordAttack as usize] = 0.0;
|
agent.action_state.timers[ActionStateTimers::TimerHandleSwordAttack as usize] =
|
||||||
|
0.0;
|
||||||
} else {
|
} else {
|
||||||
agent.action_state.timers[ActionStateTimers::TimerHandleSwordAttack as usize] += read_data.dt.0;
|
agent.action_state.timers
|
||||||
|
[ActionStateTimers::TimerHandleSwordAttack as usize] += read_data.dt.0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if self.body.map(|b| b.is_humanoid()).unwrap_or(false)
|
if self.body.map(|b| b.is_humanoid()).unwrap_or(false)
|
||||||
@ -594,8 +615,10 @@ impl<'a> AgentData<'a> {
|
|||||||
// emergency roll
|
// emergency roll
|
||||||
controller.push_basic_input(InputKind::Roll);
|
controller.push_basic_input(InputKind::Roll);
|
||||||
} else if matches!(self.char_state, CharacterState::Shockwave(_)) {
|
} else if matches!(self.char_state, CharacterState::Shockwave(_)) {
|
||||||
agent.action_state.conditions[ActionStateConditions::ConditionStaffCanShockwave as usize] = false;
|
agent.action_state.conditions
|
||||||
} else if agent.action_state.conditions[ActionStateConditions::ConditionStaffCanShockwave as usize]
|
[ActionStateConditions::ConditionStaffCanShockwave as usize] = false;
|
||||||
|
} else if agent.action_state.conditions
|
||||||
|
[ActionStateConditions::ConditionStaffCanShockwave as usize]
|
||||||
&& matches!(self.char_state, CharacterState::Wielding(_))
|
&& matches!(self.char_state, CharacterState::Wielding(_))
|
||||||
{
|
{
|
||||||
controller.push_basic_input(InputKind::Ability(0));
|
controller.push_basic_input(InputKind::Ability(0));
|
||||||
@ -618,7 +641,8 @@ impl<'a> AgentData<'a> {
|
|||||||
if matches!(self.char_state, CharacterState::Wielding(_)) {
|
if matches!(self.char_state, CharacterState::Wielding(_)) {
|
||||||
controller.push_basic_input(InputKind::Ability(0));
|
controller.push_basic_input(InputKind::Ability(0));
|
||||||
} else {
|
} else {
|
||||||
agent.action_state.conditions[ActionStateConditions::ConditionStaffCanShockwave as usize] = true;
|
agent.action_state.conditions
|
||||||
|
[ActionStateConditions::ConditionStaffCanShockwave as usize] = true;
|
||||||
}
|
}
|
||||||
} else if self.energy.current()
|
} else if self.energy.current()
|
||||||
> shockwave_cost + CharacterAbility::default_roll().get_energy_cost()
|
> shockwave_cost + CharacterAbility::default_roll().get_energy_cost()
|
||||||
@ -868,11 +892,16 @@ impl<'a> AgentData<'a> {
|
|||||||
read_data,
|
read_data,
|
||||||
) && attack_data.angle < 90.0
|
) && attack_data.angle < 90.0
|
||||||
{
|
{
|
||||||
if agent.action_state.timers[ActionStateTimers::TimerHandleStoneGolemAttack as usize] > 5.0 {
|
if agent.action_state.timers
|
||||||
|
[ActionStateTimers::TimerHandleStoneGolemAttack as usize]
|
||||||
|
> 5.0
|
||||||
|
{
|
||||||
controller.push_basic_input(InputKind::Secondary);
|
controller.push_basic_input(InputKind::Secondary);
|
||||||
agent.action_state.timers[ActionStateTimers::TimerHandleStoneGolemAttack as usize] = 0.0;
|
agent.action_state.timers
|
||||||
|
[ActionStateTimers::TimerHandleStoneGolemAttack as usize] = 0.0;
|
||||||
} else {
|
} else {
|
||||||
agent.action_state.timers[ActionStateTimers::TimerHandleStoneGolemAttack as usize] += read_data.dt.0;
|
agent.action_state.timers
|
||||||
|
[ActionStateTimers::TimerHandleStoneGolemAttack as usize] += read_data.dt.0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -907,15 +936,23 @@ impl<'a> AgentData<'a> {
|
|||||||
CounterIHandleCircleChargeAttack = 0,
|
CounterIHandleCircleChargeAttack = 0,
|
||||||
}
|
}
|
||||||
|
|
||||||
if agent.action_state.counters[ActionStateCountersF::CounterFHandleCircleChargeAttack as usize] >= circle_time as f32 {
|
if agent.action_state.counters
|
||||||
|
[ActionStateCountersF::CounterFHandleCircleChargeAttack as usize]
|
||||||
|
>= circle_time as f32
|
||||||
|
{
|
||||||
// if circle charge is in progress and time hasn't expired, continue charging
|
// if circle charge is in progress and time hasn't expired, continue charging
|
||||||
controller.push_basic_input(InputKind::Secondary);
|
controller.push_basic_input(InputKind::Secondary);
|
||||||
}
|
}
|
||||||
if attack_data.in_min_range() {
|
if attack_data.in_min_range() {
|
||||||
if agent.action_state.counters[ActionStateCountersF::CounterFHandleCircleChargeAttack as usize] > 0.0 {
|
if agent.action_state.counters
|
||||||
|
[ActionStateCountersF::CounterFHandleCircleChargeAttack as usize]
|
||||||
|
> 0.0
|
||||||
|
{
|
||||||
// set timer and rotation counter to zero if in minimum range
|
// set timer and rotation counter to zero if in minimum range
|
||||||
agent.action_state.counters[ActionStateCountersF::CounterFHandleCircleChargeAttack as usize] = 0.0;
|
agent.action_state.counters
|
||||||
agent.action_state.int_counters[ActionStateCountersI::CounterIHandleCircleChargeAttack as usize] = 0;
|
[ActionStateCountersF::CounterFHandleCircleChargeAttack as usize] = 0.0;
|
||||||
|
agent.action_state.int_counters
|
||||||
|
[ActionStateCountersI::CounterIHandleCircleChargeAttack as usize] = 0;
|
||||||
} else {
|
} else {
|
||||||
// melee attack
|
// melee attack
|
||||||
controller.push_basic_input(InputKind::Primary);
|
controller.push_basic_input(InputKind::Primary);
|
||||||
@ -923,13 +960,23 @@ impl<'a> AgentData<'a> {
|
|||||||
}
|
}
|
||||||
} else if attack_data.dist_sqrd < (radius as f32 + attack_data.min_attack_dist).powi(2) {
|
} else if attack_data.dist_sqrd < (radius as f32 + attack_data.min_attack_dist).powi(2) {
|
||||||
// if in range to charge, circle, then charge
|
// if in range to charge, circle, then charge
|
||||||
if agent.action_state.int_counters[ActionStateCountersI::CounterIHandleCircleChargeAttack as usize] == 0 {
|
if agent.action_state.int_counters
|
||||||
|
[ActionStateCountersI::CounterIHandleCircleChargeAttack as usize]
|
||||||
|
== 0
|
||||||
|
{
|
||||||
// if you haven't chosen a direction to go in, choose now
|
// if you haven't chosen a direction to go in, choose now
|
||||||
agent.action_state.int_counters[ActionStateCountersI::CounterIHandleCircleChargeAttack as usize] = 1 + rng.gen_bool(0.5) as u8;
|
agent.action_state.int_counters
|
||||||
|
[ActionStateCountersI::CounterIHandleCircleChargeAttack as usize] =
|
||||||
|
1 + rng.gen_bool(0.5) as u8;
|
||||||
}
|
}
|
||||||
if agent.action_state.counters[ActionStateCountersF::CounterFHandleCircleChargeAttack as usize] < circle_time as f32 {
|
if agent.action_state.counters
|
||||||
|
[ActionStateCountersF::CounterFHandleCircleChargeAttack as usize]
|
||||||
|
< circle_time as f32
|
||||||
|
{
|
||||||
// circle if circle timer not ready
|
// circle if circle timer not ready
|
||||||
let move_dir = match agent.action_state.int_counters[ActionStateCountersI::CounterIHandleCircleChargeAttack as usize] {
|
let move_dir = match agent.action_state.int_counters
|
||||||
|
[ActionStateCountersI::CounterIHandleCircleChargeAttack as usize]
|
||||||
|
{
|
||||||
1 =>
|
1 =>
|
||||||
// circle left if counter is 1
|
// circle left if counter is 1
|
||||||
{
|
{
|
||||||
@ -966,11 +1013,15 @@ impl<'a> AgentData<'a> {
|
|||||||
.map_or(true, |b| b.is_some());
|
.map_or(true, |b| b.is_some());
|
||||||
if obstacle {
|
if obstacle {
|
||||||
// if obstacle detected, stop circling
|
// if obstacle detected, stop circling
|
||||||
agent.action_state.counters[ActionStateCountersF::CounterFHandleCircleChargeAttack as usize] = circle_time as f32;
|
agent.action_state.counters
|
||||||
|
[ActionStateCountersF::CounterFHandleCircleChargeAttack as usize] =
|
||||||
|
circle_time as f32;
|
||||||
}
|
}
|
||||||
controller.inputs.move_dir = move_dir;
|
controller.inputs.move_dir = move_dir;
|
||||||
// use counter as timer since timer may be modified in other parts of the code
|
// use counter as timer since timer may be modified in other parts of the code
|
||||||
agent.action_state.counters[ActionStateCountersF::CounterFHandleCircleChargeAttack as usize] += read_data.dt.0;
|
agent.action_state.counters
|
||||||
|
[ActionStateCountersF::CounterFHandleCircleChargeAttack as usize] +=
|
||||||
|
read_data.dt.0;
|
||||||
}
|
}
|
||||||
// activating charge once circle timer expires is handled above
|
// activating charge once circle timer expires is handled above
|
||||||
} else {
|
} else {
|
||||||
@ -1024,16 +1075,25 @@ impl<'a> AgentData<'a> {
|
|||||||
read_data,
|
read_data,
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
if agent.action_state.timers[ActionStateTimers::TimerHandleQuadLowRanged as usize] > 5.0 {
|
if agent.action_state.timers
|
||||||
agent.action_state.timers[ActionStateTimers::TimerHandleQuadLowRanged as usize] = 0.0;
|
[ActionStateTimers::TimerHandleQuadLowRanged as usize]
|
||||||
} else if agent.action_state.timers[ActionStateTimers::TimerHandleQuadLowRanged as usize] > 2.5 {
|
> 5.0
|
||||||
|
{
|
||||||
|
agent.action_state.timers
|
||||||
|
[ActionStateTimers::TimerHandleQuadLowRanged as usize] = 0.0;
|
||||||
|
} else if agent.action_state.timers
|
||||||
|
[ActionStateTimers::TimerHandleQuadLowRanged as usize]
|
||||||
|
> 2.5
|
||||||
|
{
|
||||||
controller.inputs.move_dir = (tgt_data.pos.0 - self.pos.0)
|
controller.inputs.move_dir = (tgt_data.pos.0 - self.pos.0)
|
||||||
.xy()
|
.xy()
|
||||||
.rotated_z(1.75 * PI)
|
.rotated_z(1.75 * PI)
|
||||||
.try_normalized()
|
.try_normalized()
|
||||||
.unwrap_or_else(Vec2::zero)
|
.unwrap_or_else(Vec2::zero)
|
||||||
* speed;
|
* speed;
|
||||||
agent.action_state.timers[ActionStateTimers::TimerHandleQuadLowRanged as usize] += read_data.dt.0;
|
agent.action_state.timers
|
||||||
|
[ActionStateTimers::TimerHandleQuadLowRanged as usize] +=
|
||||||
|
read_data.dt.0;
|
||||||
} else {
|
} else {
|
||||||
controller.inputs.move_dir = (tgt_data.pos.0 - self.pos.0)
|
controller.inputs.move_dir = (tgt_data.pos.0 - self.pos.0)
|
||||||
.xy()
|
.xy()
|
||||||
@ -1041,7 +1101,9 @@ impl<'a> AgentData<'a> {
|
|||||||
.try_normalized()
|
.try_normalized()
|
||||||
.unwrap_or_else(Vec2::zero)
|
.unwrap_or_else(Vec2::zero)
|
||||||
* speed;
|
* speed;
|
||||||
agent.action_state.timers[ActionStateTimers::TimerHandleQuadLowRanged as usize] += read_data.dt.0;
|
agent.action_state.timers
|
||||||
|
[ActionStateTimers::TimerHandleQuadLowRanged as usize] +=
|
||||||
|
read_data.dt.0;
|
||||||
}
|
}
|
||||||
controller.push_basic_input(InputKind::Secondary);
|
controller.push_basic_input(InputKind::Secondary);
|
||||||
self.jump_if(bearing.z > 1.5, controller);
|
self.jump_if(bearing.z > 1.5, controller);
|
||||||
@ -1087,10 +1149,12 @@ impl<'a> AgentData<'a> {
|
|||||||
agent.action_state.timers[ActionStateTimers::TimerTailSlap as usize] = 0.0;
|
agent.action_state.timers[ActionStateTimers::TimerTailSlap as usize] = 0.0;
|
||||||
} else if agent.action_state.timers[ActionStateTimers::TimerTailSlap as usize] > 1.0 {
|
} else if agent.action_state.timers[ActionStateTimers::TimerTailSlap as usize] > 1.0 {
|
||||||
controller.push_basic_input(InputKind::Primary);
|
controller.push_basic_input(InputKind::Primary);
|
||||||
agent.action_state.timers[ActionStateTimers::TimerTailSlap as usize] += read_data.dt.0;
|
agent.action_state.timers[ActionStateTimers::TimerTailSlap as usize] +=
|
||||||
|
read_data.dt.0;
|
||||||
} else {
|
} else {
|
||||||
controller.push_basic_input(InputKind::Secondary);
|
controller.push_basic_input(InputKind::Secondary);
|
||||||
agent.action_state.timers[ActionStateTimers::TimerTailSlap as usize] += read_data.dt.0;
|
agent.action_state.timers[ActionStateTimers::TimerTailSlap as usize] +=
|
||||||
|
read_data.dt.0;
|
||||||
}
|
}
|
||||||
controller.inputs.move_dir = (tgt_data.pos.0 - self.pos.0)
|
controller.inputs.move_dir = (tgt_data.pos.0 - self.pos.0)
|
||||||
.xy()
|
.xy()
|
||||||
@ -1180,12 +1244,15 @@ impl<'a> AgentData<'a> {
|
|||||||
controller.inputs.move_dir = Vec2::zero();
|
controller.inputs.move_dir = Vec2::zero();
|
||||||
if agent.action_state.timers[ActionStateTimers::TimerQuadLowBasic as usize] > 5.0 {
|
if agent.action_state.timers[ActionStateTimers::TimerQuadLowBasic as usize] > 5.0 {
|
||||||
agent.action_state.timers[ActionStateTimers::TimerQuadLowBasic as usize] = 0.0;
|
agent.action_state.timers[ActionStateTimers::TimerQuadLowBasic as usize] = 0.0;
|
||||||
} else if agent.action_state.timers[ActionStateTimers::TimerQuadLowBasic as usize] > 2.0 {
|
} else if agent.action_state.timers[ActionStateTimers::TimerQuadLowBasic as usize] > 2.0
|
||||||
|
{
|
||||||
controller.push_basic_input(InputKind::Secondary);
|
controller.push_basic_input(InputKind::Secondary);
|
||||||
agent.action_state.timers[ActionStateTimers::TimerQuadLowBasic as usize] += read_data.dt.0;
|
agent.action_state.timers[ActionStateTimers::TimerQuadLowBasic as usize] +=
|
||||||
|
read_data.dt.0;
|
||||||
} else {
|
} else {
|
||||||
controller.push_basic_input(InputKind::Primary);
|
controller.push_basic_input(InputKind::Primary);
|
||||||
agent.action_state.timers[ActionStateTimers::TimerQuadLowBasic as usize] += read_data.dt.0;
|
agent.action_state.timers[ActionStateTimers::TimerQuadLowBasic as usize] +=
|
||||||
|
read_data.dt.0;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
let path = if attack_data.dist_sqrd < MAX_PATH_DIST.powi(2) {
|
let path = if attack_data.dist_sqrd < MAX_PATH_DIST.powi(2) {
|
||||||
@ -1261,10 +1328,13 @@ impl<'a> AgentData<'a> {
|
|||||||
controller.inputs.move_dir = Vec2::zero();
|
controller.inputs.move_dir = Vec2::zero();
|
||||||
if agent.action_state.timers[ActionStateTimers::TimerQuadMedBasic as usize] < 2.0 {
|
if agent.action_state.timers[ActionStateTimers::TimerQuadMedBasic as usize] < 2.0 {
|
||||||
controller.push_basic_input(InputKind::Secondary);
|
controller.push_basic_input(InputKind::Secondary);
|
||||||
agent.action_state.timers[ActionStateTimers::TimerQuadMedBasic as usize] += read_data.dt.0;
|
agent.action_state.timers[ActionStateTimers::TimerQuadMedBasic as usize] +=
|
||||||
} else if agent.action_state.timers[ActionStateTimers::TimerQuadMedBasic as usize] < 3.0 {
|
read_data.dt.0;
|
||||||
|
} else if agent.action_state.timers[ActionStateTimers::TimerQuadMedBasic as usize] < 3.0
|
||||||
|
{
|
||||||
controller.push_basic_input(InputKind::Primary);
|
controller.push_basic_input(InputKind::Primary);
|
||||||
agent.action_state.timers[ActionStateTimers::TimerQuadMedBasic as usize] += read_data.dt.0;
|
agent.action_state.timers[ActionStateTimers::TimerQuadMedBasic as usize] +=
|
||||||
|
read_data.dt.0;
|
||||||
} else {
|
} else {
|
||||||
agent.action_state.timers[ActionStateTimers::TimerQuadMedBasic as usize] = 0.0;
|
agent.action_state.timers[ActionStateTimers::TimerQuadMedBasic as usize] = 0.0;
|
||||||
}
|
}
|
||||||
@ -1297,8 +1367,7 @@ impl<'a> AgentData<'a> {
|
|||||||
tgt_data: &TargetData,
|
tgt_data: &TargetData,
|
||||||
read_data: &ReadData,
|
read_data: &ReadData,
|
||||||
) {
|
) {
|
||||||
enum ActionStateTimers
|
enum ActionStateTimers {
|
||||||
{
|
|
||||||
TimerQuadLowBeam = 0,
|
TimerQuadLowBeam = 0,
|
||||||
}
|
}
|
||||||
if attack_data.angle < 90.0
|
if attack_data.angle < 90.0
|
||||||
@ -1316,18 +1385,25 @@ impl<'a> AgentData<'a> {
|
|||||||
.try_normalized()
|
.try_normalized()
|
||||||
.unwrap_or_else(Vec2::unit_y);
|
.unwrap_or_else(Vec2::unit_y);
|
||||||
controller.push_basic_input(InputKind::Primary);
|
controller.push_basic_input(InputKind::Primary);
|
||||||
agent.action_state.timers[ActionStateTimers::TimerQuadLowBeam as usize] += read_data.dt.0;
|
agent.action_state.timers[ActionStateTimers::TimerQuadLowBeam as usize] +=
|
||||||
} else if agent.action_state.timers[ActionStateTimers::TimerQuadLowBeam as usize] < 4.0 && attack_data.angle < 15.0 {
|
read_data.dt.0;
|
||||||
|
} else if agent.action_state.timers[ActionStateTimers::TimerQuadLowBeam as usize] < 4.0
|
||||||
|
&& attack_data.angle < 15.0
|
||||||
|
{
|
||||||
controller.inputs.move_dir = (tgt_data.pos.0 - self.pos.0)
|
controller.inputs.move_dir = (tgt_data.pos.0 - self.pos.0)
|
||||||
.xy()
|
.xy()
|
||||||
.rotated_z(-0.47 * PI)
|
.rotated_z(-0.47 * PI)
|
||||||
.try_normalized()
|
.try_normalized()
|
||||||
.unwrap_or_else(Vec2::unit_y);
|
.unwrap_or_else(Vec2::unit_y);
|
||||||
controller.push_basic_input(InputKind::Primary);
|
controller.push_basic_input(InputKind::Primary);
|
||||||
agent.action_state.timers[ActionStateTimers::TimerQuadLowBeam as usize] += read_data.dt.0;
|
agent.action_state.timers[ActionStateTimers::TimerQuadLowBeam as usize] +=
|
||||||
} else if agent.action_state.timers[ActionStateTimers::TimerQuadLowBeam as usize] < 6.0 && attack_data.angle < 15.0 {
|
read_data.dt.0;
|
||||||
|
} else if agent.action_state.timers[ActionStateTimers::TimerQuadLowBeam as usize] < 6.0
|
||||||
|
&& attack_data.angle < 15.0
|
||||||
|
{
|
||||||
controller.push_basic_input(InputKind::Ability(0));
|
controller.push_basic_input(InputKind::Ability(0));
|
||||||
agent.action_state.timers[ActionStateTimers::TimerQuadLowBeam as usize] += read_data.dt.0;
|
agent.action_state.timers[ActionStateTimers::TimerQuadLowBeam as usize] +=
|
||||||
|
read_data.dt.0;
|
||||||
} else {
|
} else {
|
||||||
agent.action_state.timers[ActionStateTimers::TimerQuadLowBeam as usize] = 0.0;
|
agent.action_state.timers[ActionStateTimers::TimerQuadLowBeam as usize] = 0.0;
|
||||||
}
|
}
|
||||||
@ -1366,15 +1442,19 @@ impl<'a> AgentData<'a> {
|
|||||||
|
|
||||||
const ORGAN_AURA_DURATION: f32 = 34.75;
|
const ORGAN_AURA_DURATION: f32 = 34.75;
|
||||||
if attack_data.dist_sqrd < (7.0 * attack_data.min_attack_dist).powi(2) {
|
if attack_data.dist_sqrd < (7.0 * attack_data.min_attack_dist).powi(2) {
|
||||||
if agent.action_state.timers[ActionStateTimers::TimerOrganAura as usize] > ORGAN_AURA_DURATION {
|
if agent.action_state.timers[ActionStateTimers::TimerOrganAura as usize]
|
||||||
|
> ORGAN_AURA_DURATION
|
||||||
|
{
|
||||||
agent.action_state.timers[ActionStateTimers::TimerOrganAura as usize] = 0.0;
|
agent.action_state.timers[ActionStateTimers::TimerOrganAura as usize] = 0.0;
|
||||||
} else if agent.action_state.timers[ActionStateTimers::TimerOrganAura as usize] < 1.0 {
|
} else if agent.action_state.timers[ActionStateTimers::TimerOrganAura as usize] < 1.0 {
|
||||||
controller
|
controller
|
||||||
.actions
|
.actions
|
||||||
.push(ControlAction::basic_input(InputKind::Primary));
|
.push(ControlAction::basic_input(InputKind::Primary));
|
||||||
agent.action_state.timers[ActionStateTimers::TimerOrganAura as usize] += read_data.dt.0;
|
agent.action_state.timers[ActionStateTimers::TimerOrganAura as usize] +=
|
||||||
|
read_data.dt.0;
|
||||||
} else {
|
} else {
|
||||||
agent.action_state.timers[ActionStateTimers::TimerOrganAura as usize] += read_data.dt.0;
|
agent.action_state.timers[ActionStateTimers::TimerOrganAura as usize] +=
|
||||||
|
read_data.dt.0;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
agent.target = None;
|
agent.target = None;
|
||||||
@ -1495,24 +1575,29 @@ impl<'a> AgentData<'a> {
|
|||||||
ConditionCounterInit = 0,
|
ConditionCounterInit = 0,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const MINDFLAYER_ATTACK_DIST: f32 = 16.0;
|
const MINDFLAYER_ATTACK_DIST: f32 = 16.0;
|
||||||
const MINION_SUMMON_THRESHOLD: f32 = 0.20;
|
const MINION_SUMMON_THRESHOLD: f32 = 0.20;
|
||||||
let health_fraction = self.health.map_or(0.5, |h| h.fraction());
|
let health_fraction = self.health.map_or(0.5, |h| h.fraction());
|
||||||
// Sets counter at start of combat, using `condition` to keep track of whether
|
// Sets counter at start of combat, using `condition` to keep track of whether
|
||||||
// it was already initialized
|
// it was already initialized
|
||||||
if !agent.action_state.conditions[ActionStateConditions::ConditionCounterInit as usize] {
|
if !agent.action_state.conditions[ActionStateConditions::ConditionCounterInit as usize] {
|
||||||
agent.action_state.counters[ActionStateFCounters::FCounterHealthThreshold as usize] = 1.0 - MINION_SUMMON_THRESHOLD;
|
agent.action_state.counters[ActionStateFCounters::FCounterHealthThreshold as usize] =
|
||||||
agent.action_state.conditions[ActionStateConditions::ConditionCounterInit as usize] = true;
|
1.0 - MINION_SUMMON_THRESHOLD;
|
||||||
|
agent.action_state.conditions[ActionStateConditions::ConditionCounterInit as usize] =
|
||||||
|
true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if agent.action_state.counters[ActionStateFCounters::FCounterHealthThreshold as usize] > health_fraction {
|
if agent.action_state.counters[ActionStateFCounters::FCounterHealthThreshold as usize]
|
||||||
|
> health_fraction
|
||||||
|
{
|
||||||
// Summon minions at particular thresholds of health
|
// Summon minions at particular thresholds of health
|
||||||
controller.push_basic_input(InputKind::Ability(2));
|
controller.push_basic_input(InputKind::Ability(2));
|
||||||
|
|
||||||
if matches!(self.char_state, CharacterState::BasicSummon(c) if matches!(c.stage_section, StageSection::Recover))
|
if matches!(self.char_state, CharacterState::BasicSummon(c) if matches!(c.stage_section, StageSection::Recover))
|
||||||
{
|
{
|
||||||
agent.action_state.counters[ActionStateFCounters::FCounterHealthThreshold as usize] -= MINION_SUMMON_THRESHOLD;
|
agent.action_state.counters
|
||||||
|
[ActionStateFCounters::FCounterHealthThreshold as usize] -=
|
||||||
|
MINION_SUMMON_THRESHOLD;
|
||||||
}
|
}
|
||||||
} else if attack_data.dist_sqrd < MINDFLAYER_ATTACK_DIST.powi(2) {
|
} else if attack_data.dist_sqrd < MINDFLAYER_ATTACK_DIST.powi(2) {
|
||||||
if entities_have_line_of_sight(
|
if entities_have_line_of_sight(
|
||||||
@ -1552,7 +1637,8 @@ impl<'a> AgentData<'a> {
|
|||||||
} else if attack_data.dist_sqrd < MAX_PATH_DIST.powi(2) {
|
} 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
|
// If too far from target, throw a random number of necrotic spheres at them and
|
||||||
// then blink to them.
|
// then blink to them.
|
||||||
let num_fireballs = &mut agent.action_state.int_counters[ActionStateICounters::ICounterNumFireballs as usize];
|
let num_fireballs = &mut agent.action_state.int_counters
|
||||||
|
[ActionStateICounters::ICounterNumFireballs as usize];
|
||||||
if *num_fireballs == 0 {
|
if *num_fireballs == 0 {
|
||||||
controller.push_action(ControlAction::StartInput {
|
controller.push_action(ControlAction::StartInput {
|
||||||
input: InputKind::Ability(0),
|
input: InputKind::Ability(0),
|
||||||
@ -1830,14 +1916,16 @@ impl<'a> AgentData<'a> {
|
|||||||
Path::Separate,
|
Path::Separate,
|
||||||
Some(0.5),
|
Some(0.5),
|
||||||
);
|
);
|
||||||
agent.action_state.timers[ActionStateTimers::TimerBirdLargeBreathe as usize] += read_data.dt.0;
|
agent.action_state.timers[ActionStateTimers::TimerBirdLargeBreathe as usize] +=
|
||||||
|
read_data.dt.0;
|
||||||
} else if agent.action_state.timers[ActionStateTimers::TimerBirdLargeBreathe as usize] < 6.0
|
} else if agent.action_state.timers[ActionStateTimers::TimerBirdLargeBreathe as usize] < 6.0
|
||||||
&& attack_data.angle < 90.0
|
&& attack_data.angle < 90.0
|
||||||
&& attack_data.in_min_range()
|
&& attack_data.in_min_range()
|
||||||
{
|
{
|
||||||
// Triple strike
|
// Triple strike
|
||||||
controller.push_basic_input(InputKind::Secondary);
|
controller.push_basic_input(InputKind::Secondary);
|
||||||
agent.action_state.timers[ActionStateTimers::TimerBirdLargeBreathe as usize] += read_data.dt.0;
|
agent.action_state.timers[ActionStateTimers::TimerBirdLargeBreathe as usize] +=
|
||||||
|
read_data.dt.0;
|
||||||
} else {
|
} else {
|
||||||
// Reset timer
|
// Reset timer
|
||||||
agent.action_state.timers[ActionStateTimers::TimerBirdLargeBreathe as usize] = 0.0;
|
agent.action_state.timers[ActionStateTimers::TimerBirdLargeBreathe as usize] = 0.0;
|
||||||
@ -1866,14 +1954,16 @@ impl<'a> AgentData<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
enum ActionStateConditions {
|
enum ActionStateConditions {
|
||||||
ConditionBirdLargeBasic = 0, //FIXME: Not sure what this represents. This name should be reflective of the condition...
|
ConditionBirdLargeBasic = 0, /* FIXME: Not sure what this represents. This name
|
||||||
|
* should be reflective of the condition... */
|
||||||
}
|
}
|
||||||
|
|
||||||
const BIRD_ATTACK_RANGE: f32 = 4.0;
|
const BIRD_ATTACK_RANGE: f32 = 4.0;
|
||||||
const BIRD_CHARGE_DISTANCE: f32 = 15.0;
|
const BIRD_CHARGE_DISTANCE: f32 = 15.0;
|
||||||
let bird_attack_distance = self.body.map_or(0.0, |b| b.max_radius()) + BIRD_ATTACK_RANGE;
|
let bird_attack_distance = self.body.map_or(0.0, |b| b.max_radius()) + BIRD_ATTACK_RANGE;
|
||||||
// Increase action timer
|
// Increase action timer
|
||||||
agent.action_state.timers[ActionStateTimers::TimerBirdLargeBasic as usize] += read_data.dt.0;
|
agent.action_state.timers[ActionStateTimers::TimerBirdLargeBasic as usize] +=
|
||||||
|
read_data.dt.0;
|
||||||
// If higher than 2 blocks
|
// If higher than 2 blocks
|
||||||
if !read_data
|
if !read_data
|
||||||
.terrain
|
.terrain
|
||||||
@ -1913,7 +2003,8 @@ impl<'a> AgentData<'a> {
|
|||||||
} else if attack_data.dist_sqrd < bird_attack_distance.powi(2) {
|
} else if attack_data.dist_sqrd < bird_attack_distance.powi(2) {
|
||||||
// Combo melee target
|
// Combo melee target
|
||||||
controller.push_basic_input(InputKind::Primary);
|
controller.push_basic_input(InputKind::Primary);
|
||||||
agent.action_state.conditions[ActionStateConditions::ConditionBirdLargeBasic as usize] = true;
|
agent.action_state.conditions
|
||||||
|
[ActionStateConditions::ConditionBirdLargeBasic as usize] = true;
|
||||||
}
|
}
|
||||||
// Make bird move towards target
|
// Make bird move towards target
|
||||||
self.path_toward_target(
|
self.path_toward_target(
|
||||||
@ -1934,12 +2025,12 @@ impl<'a> AgentData<'a> {
|
|||||||
tgt_data: &TargetData,
|
tgt_data: &TargetData,
|
||||||
read_data: &ReadData,
|
read_data: &ReadData,
|
||||||
) {
|
) {
|
||||||
enum ActionStateTimers
|
enum ActionStateTimers {
|
||||||
{
|
|
||||||
TimerArthropodRanged = 0,
|
TimerArthropodRanged = 0,
|
||||||
}
|
}
|
||||||
|
|
||||||
agent.action_state.timers[ActionStateTimers::TimerArthropodRanged as usize] += read_data.dt.0;
|
agent.action_state.timers[ActionStateTimers::TimerArthropodRanged as usize] +=
|
||||||
|
read_data.dt.0;
|
||||||
if agent.action_state.timers[ActionStateTimers::TimerArthropodRanged as usize] > 6.0
|
if agent.action_state.timers[ActionStateTimers::TimerArthropodRanged as usize] > 6.0
|
||||||
&& attack_data.dist_sqrd < (1.5 * attack_data.min_attack_dist).powi(2)
|
&& attack_data.dist_sqrd < (1.5 * attack_data.min_attack_dist).powi(2)
|
||||||
{
|
{
|
||||||
@ -1981,16 +2072,23 @@ impl<'a> AgentData<'a> {
|
|||||||
read_data,
|
read_data,
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
if agent.action_state.timers[ActionStateTimers::TimerArthropodRanged as usize] > 5.0 {
|
if agent.action_state.timers[ActionStateTimers::TimerArthropodRanged as usize]
|
||||||
agent.action_state.timers[ActionStateTimers::TimerArthropodRanged as usize] = 0.0;
|
> 5.0
|
||||||
} else if agent.action_state.timers[ActionStateTimers::TimerArthropodRanged as usize] > 2.5 {
|
{
|
||||||
|
agent.action_state.timers
|
||||||
|
[ActionStateTimers::TimerArthropodRanged as usize] = 0.0;
|
||||||
|
} else if agent.action_state.timers
|
||||||
|
[ActionStateTimers::TimerArthropodRanged as usize]
|
||||||
|
> 2.5
|
||||||
|
{
|
||||||
controller.inputs.move_dir = (tgt_data.pos.0 - self.pos.0)
|
controller.inputs.move_dir = (tgt_data.pos.0 - self.pos.0)
|
||||||
.xy()
|
.xy()
|
||||||
.rotated_z(1.75 * PI)
|
.rotated_z(1.75 * PI)
|
||||||
.try_normalized()
|
.try_normalized()
|
||||||
.unwrap_or_else(Vec2::zero)
|
.unwrap_or_else(Vec2::zero)
|
||||||
* speed;
|
* speed;
|
||||||
agent.action_state.timers[ActionStateTimers::TimerArthropodRanged as usize] += read_data.dt.0;
|
agent.action_state.timers
|
||||||
|
[ActionStateTimers::TimerArthropodRanged as usize] += read_data.dt.0;
|
||||||
} else {
|
} else {
|
||||||
controller.inputs.move_dir = (tgt_data.pos.0 - self.pos.0)
|
controller.inputs.move_dir = (tgt_data.pos.0 - self.pos.0)
|
||||||
.xy()
|
.xy()
|
||||||
@ -1998,7 +2096,8 @@ impl<'a> AgentData<'a> {
|
|||||||
.try_normalized()
|
.try_normalized()
|
||||||
.unwrap_or_else(Vec2::zero)
|
.unwrap_or_else(Vec2::zero)
|
||||||
* speed;
|
* speed;
|
||||||
agent.action_state.timers[ActionStateTimers::TimerArthropodRanged as usize] += read_data.dt.0;
|
agent.action_state.timers
|
||||||
|
[ActionStateTimers::TimerArthropodRanged as usize] += read_data.dt.0;
|
||||||
}
|
}
|
||||||
controller.push_basic_input(InputKind::Ability(0));
|
controller.push_basic_input(InputKind::Ability(0));
|
||||||
self.jump_if(bearing.z > 1.5, controller);
|
self.jump_if(bearing.z > 1.5, controller);
|
||||||
@ -2037,7 +2136,8 @@ impl<'a> AgentData<'a> {
|
|||||||
TimersArthropodAmbush = 0,
|
TimersArthropodAmbush = 0,
|
||||||
}
|
}
|
||||||
|
|
||||||
agent.action_state.timers[ActionStateTimers::TimersArthropodAmbush as usize] += read_data.dt.0;
|
agent.action_state.timers[ActionStateTimers::TimersArthropodAmbush as usize] +=
|
||||||
|
read_data.dt.0;
|
||||||
if agent.action_state.timers[ActionStateTimers::TimersArthropodAmbush as usize] > 12.0
|
if agent.action_state.timers[ActionStateTimers::TimersArthropodAmbush as usize] > 12.0
|
||||||
&& attack_data.dist_sqrd < (1.5 * attack_data.min_attack_dist).powi(2)
|
&& attack_data.dist_sqrd < (1.5 * attack_data.min_attack_dist).powi(2)
|
||||||
{
|
{
|
||||||
@ -2084,7 +2184,8 @@ impl<'a> AgentData<'a> {
|
|||||||
enum ActionStateTimers {
|
enum ActionStateTimers {
|
||||||
TimersArthropodMelee = 0,
|
TimersArthropodMelee = 0,
|
||||||
}
|
}
|
||||||
agent.action_state.timers[ActionStateTimers::TimersArthropodMelee as usize] += read_data.dt.0;
|
agent.action_state.timers[ActionStateTimers::TimersArthropodMelee as usize] +=
|
||||||
|
read_data.dt.0;
|
||||||
if matches!(self.char_state, CharacterState::DashMelee(c) if !matches!(c.stage_section, StageSection::Recover))
|
if matches!(self.char_state, CharacterState::DashMelee(c) if !matches!(c.stage_section, StageSection::Recover))
|
||||||
{
|
{
|
||||||
// If already charging, keep charging if not in recover
|
// If already charging, keep charging if not in recover
|
||||||
@ -2135,17 +2236,22 @@ impl<'a> AgentData<'a> {
|
|||||||
self.body.map_or(0.0, |b| b.max_radius()) + MINOTAUR_ATTACK_RANGE;
|
self.body.map_or(0.0, |b| b.max_radius()) + MINOTAUR_ATTACK_RANGE;
|
||||||
let health_fraction = self.health.map_or(1.0, |h| h.fraction());
|
let health_fraction = self.health.map_or(1.0, |h| h.fraction());
|
||||||
// Sets action counter at start of combat
|
// Sets action counter at start of combat
|
||||||
if agent.action_state.counters[ActionStateFCounters::FCounterMinotaurAttack as usize] < MINOTAUR_FRENZY_THRESHOLD
|
if agent.action_state.counters[ActionStateFCounters::FCounterMinotaurAttack as usize]
|
||||||
|
< MINOTAUR_FRENZY_THRESHOLD
|
||||||
&& health_fraction > MINOTAUR_FRENZY_THRESHOLD
|
&& health_fraction > MINOTAUR_FRENZY_THRESHOLD
|
||||||
{
|
{
|
||||||
agent.action_state.counters[ActionStateFCounters::FCounterMinotaurAttack as usize] = MINOTAUR_FRENZY_THRESHOLD;
|
agent.action_state.counters[ActionStateFCounters::FCounterMinotaurAttack as usize] =
|
||||||
|
MINOTAUR_FRENZY_THRESHOLD;
|
||||||
}
|
}
|
||||||
if health_fraction < agent.action_state.counters[ActionStateFCounters::FCounterMinotaurAttack as usize] {
|
if health_fraction
|
||||||
|
< agent.action_state.counters[ActionStateFCounters::FCounterMinotaurAttack as usize]
|
||||||
|
{
|
||||||
// Makes minotaur buff itself with frenzy
|
// Makes minotaur buff itself with frenzy
|
||||||
controller.push_basic_input(InputKind::Ability(1));
|
controller.push_basic_input(InputKind::Ability(1));
|
||||||
if matches!(self.char_state, CharacterState::SelfBuff(c) if matches!(c.stage_section, StageSection::Recover))
|
if matches!(self.char_state, CharacterState::SelfBuff(c) if matches!(c.stage_section, StageSection::Recover))
|
||||||
{
|
{
|
||||||
agent.action_state.counters[ActionStateFCounters::FCounterMinotaurAttack as usize] = 0.0;
|
agent.action_state.counters
|
||||||
|
[ActionStateFCounters::FCounterMinotaurAttack as usize] = 0.0;
|
||||||
}
|
}
|
||||||
} else if matches!(self.char_state, CharacterState::DashMelee(c) if !matches!(c.stage_section, StageSection::Recover))
|
} else if matches!(self.char_state, CharacterState::DashMelee(c) if !matches!(c.stage_section, StageSection::Recover))
|
||||||
{
|
{
|
||||||
@ -2161,14 +2267,19 @@ impl<'a> AgentData<'a> {
|
|||||||
controller.push_basic_input(InputKind::Ability(0));
|
controller.push_basic_input(InputKind::Ability(0));
|
||||||
}
|
}
|
||||||
} else if attack_data.dist_sqrd < minotaur_attack_distance.powi(2) {
|
} else if attack_data.dist_sqrd < minotaur_attack_distance.powi(2) {
|
||||||
if agent.action_state.conditions[ActionStateConditions::ConditionJustCrippledOrCleaved as usize] && !self.char_state.is_attack() {
|
if agent.action_state.conditions
|
||||||
|
[ActionStateConditions::ConditionJustCrippledOrCleaved as usize]
|
||||||
|
&& !self.char_state.is_attack()
|
||||||
|
{
|
||||||
// Cripple target if not just used cripple
|
// Cripple target if not just used cripple
|
||||||
controller.push_basic_input(InputKind::Secondary);
|
controller.push_basic_input(InputKind::Secondary);
|
||||||
agent.action_state.conditions[ActionStateConditions::ConditionJustCrippledOrCleaved as usize] = false;
|
agent.action_state.conditions
|
||||||
|
[ActionStateConditions::ConditionJustCrippledOrCleaved as usize] = false;
|
||||||
} else if !self.char_state.is_attack() {
|
} else if !self.char_state.is_attack() {
|
||||||
// Cleave target if not just used cleave
|
// Cleave target if not just used cleave
|
||||||
controller.push_basic_input(InputKind::Primary);
|
controller.push_basic_input(InputKind::Primary);
|
||||||
agent.action_state.conditions[ActionStateConditions::ConditionJustCrippledOrCleaved as usize] = true;
|
agent.action_state.conditions
|
||||||
|
[ActionStateConditions::ConditionJustCrippledOrCleaved as usize] = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Make minotaur move towards target
|
// Make minotaur move towards target
|
||||||
@ -2215,16 +2326,20 @@ impl<'a> AgentData<'a> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
if attack_data.dist_sqrd < golem_melee_range.powi(2) {
|
if attack_data.dist_sqrd < golem_melee_range.powi(2) {
|
||||||
if agent.action_state.counters[ActionStateFCounters::FCounterGlayGolemAttack as usize] < 7.5 {
|
if agent.action_state.counters[ActionStateFCounters::FCounterGlayGolemAttack as usize]
|
||||||
|
< 7.5
|
||||||
|
{
|
||||||
// If target is close, whack them
|
// If target is close, whack them
|
||||||
controller.push_basic_input(InputKind::Primary);
|
controller.push_basic_input(InputKind::Primary);
|
||||||
agent.action_state.counters[ActionStateFCounters::FCounterGlayGolemAttack as usize] += read_data.dt.0;
|
agent.action_state.counters
|
||||||
|
[ActionStateFCounters::FCounterGlayGolemAttack as usize] += read_data.dt.0;
|
||||||
} else {
|
} else {
|
||||||
// If whacked for too long, nuke them
|
// If whacked for too long, nuke them
|
||||||
controller.push_basic_input(InputKind::Ability(1));
|
controller.push_basic_input(InputKind::Ability(1));
|
||||||
if matches!(self.char_state, CharacterState::BasicRanged(c) if matches!(c.stage_section, StageSection::Recover))
|
if matches!(self.char_state, CharacterState::BasicRanged(c) if matches!(c.stage_section, StageSection::Recover))
|
||||||
{
|
{
|
||||||
agent.action_state.counters[ActionStateFCounters::FCounterGlayGolemAttack as usize] = 0.0;
|
agent.action_state.counters
|
||||||
|
[ActionStateFCounters::FCounterGlayGolemAttack as usize] = 0.0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if attack_data.dist_sqrd < GOLEM_LASER_RANGE.powi(2) {
|
} else if attack_data.dist_sqrd < GOLEM_LASER_RANGE.powi(2) {
|
||||||
@ -2274,13 +2389,11 @@ impl<'a> AgentData<'a> {
|
|||||||
const BUBBLE_RANGE: f32 = 20.0;
|
const BUBBLE_RANGE: f32 = 20.0;
|
||||||
const MINION_SUMMON_THRESHOLD: f32 = 0.20;
|
const MINION_SUMMON_THRESHOLD: f32 = 0.20;
|
||||||
|
|
||||||
enum ActionStateConditions
|
enum ActionStateConditions {
|
||||||
{
|
|
||||||
ConditionCounterInitialized = 0,
|
ConditionCounterInitialized = 0,
|
||||||
}
|
}
|
||||||
|
|
||||||
enum ActionStateFCounters
|
enum ActionStateFCounters {
|
||||||
{
|
|
||||||
FCounterMinionSummonThreshold = 0,
|
FCounterMinionSummonThreshold = 0,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2291,18 +2404,27 @@ impl<'a> AgentData<'a> {
|
|||||||
|
|
||||||
// Sets counter at start of combat, using `condition` to keep track of whether
|
// Sets counter at start of combat, using `condition` to keep track of whether
|
||||||
// it was already initialized
|
// it was already initialized
|
||||||
if !agent.action_state.conditions[ActionStateConditions::ConditionCounterInitialized as usize] {
|
if !agent.action_state.conditions
|
||||||
agent.action_state.counters[ActionStateFCounters::FCounterMinionSummonThreshold as usize] = 1.0 - MINION_SUMMON_THRESHOLD;
|
[ActionStateConditions::ConditionCounterInitialized as usize]
|
||||||
agent.action_state.conditions[ActionStateConditions::ConditionCounterInitialized as usize] = true;
|
{
|
||||||
|
agent.action_state.counters
|
||||||
|
[ActionStateFCounters::FCounterMinionSummonThreshold as usize] =
|
||||||
|
1.0 - MINION_SUMMON_THRESHOLD;
|
||||||
|
agent.action_state.conditions
|
||||||
|
[ActionStateConditions::ConditionCounterInitialized as usize] = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if agent.action_state.counters[ActionStateFCounters::FCounterMinionSummonThreshold as usize] > health_fraction {
|
if agent.action_state.counters[ActionStateFCounters::FCounterMinionSummonThreshold as usize]
|
||||||
|
> health_fraction
|
||||||
|
{
|
||||||
// Summon minions at particular thresholds of health
|
// Summon minions at particular thresholds of health
|
||||||
controller.push_basic_input(InputKind::Ability(1));
|
controller.push_basic_input(InputKind::Ability(1));
|
||||||
|
|
||||||
if matches!(self.char_state, CharacterState::BasicSummon(c) if matches!(c.stage_section, StageSection::Recover))
|
if matches!(self.char_state, CharacterState::BasicSummon(c) if matches!(c.stage_section, StageSection::Recover))
|
||||||
{
|
{
|
||||||
agent.action_state.counters[ActionStateFCounters::FCounterMinionSummonThreshold as usize] -= MINION_SUMMON_THRESHOLD;
|
agent.action_state.counters
|
||||||
|
[ActionStateFCounters::FCounterMinionSummonThreshold as usize] -=
|
||||||
|
MINION_SUMMON_THRESHOLD;
|
||||||
}
|
}
|
||||||
} else if attack_data.dist_sqrd < SCUTTLE_RANGE.powi(2) {
|
} else if attack_data.dist_sqrd < SCUTTLE_RANGE.powi(2) {
|
||||||
if matches!(self.char_state, CharacterState::DashMelee(c) if !matches!(c.stage_section, StageSection::Recover))
|
if matches!(self.char_state, CharacterState::DashMelee(c) if !matches!(c.stage_section, StageSection::Recover))
|
||||||
@ -2353,25 +2475,28 @@ impl<'a> AgentData<'a> {
|
|||||||
const ICE_BREATH_TIMER: f32 = 10.0;
|
const ICE_BREATH_TIMER: f32 = 10.0;
|
||||||
const SNOWBALL_MAX_RANGE: f32 = 50.0;
|
const SNOWBALL_MAX_RANGE: f32 = 50.0;
|
||||||
|
|
||||||
enum ActionStateFCounters
|
enum ActionStateFCounters {
|
||||||
{
|
|
||||||
FCounterYetiAttack = 0,
|
FCounterYetiAttack = 0,
|
||||||
}
|
}
|
||||||
|
|
||||||
agent.action_state.counters[ActionStateFCounters::FCounterYetiAttack as usize] += read_data.dt.0;
|
agent.action_state.counters[ActionStateFCounters::FCounterYetiAttack as usize] +=
|
||||||
|
read_data.dt.0;
|
||||||
|
|
||||||
if attack_data.dist_sqrd < ICE_BREATH_RANGE.powi(2) {
|
if attack_data.dist_sqrd < ICE_BREATH_RANGE.powi(2) {
|
||||||
if matches!(self.char_state, CharacterState::BasicBeam(c) if c.timer < Duration::from_secs(2))
|
if matches!(self.char_state, CharacterState::BasicBeam(c) if c.timer < Duration::from_secs(2))
|
||||||
{
|
{
|
||||||
// Keep using ice breath for 2 second
|
// Keep using ice breath for 2 second
|
||||||
controller.push_basic_input(InputKind::Ability(0));
|
controller.push_basic_input(InputKind::Ability(0));
|
||||||
} else if agent.action_state.counters[ActionStateFCounters::FCounterYetiAttack as usize] > ICE_BREATH_TIMER {
|
} else if agent.action_state.counters[ActionStateFCounters::FCounterYetiAttack as usize]
|
||||||
|
> ICE_BREATH_TIMER
|
||||||
|
{
|
||||||
// Use ice breath if timer has gone for long enough
|
// Use ice breath if timer has gone for long enough
|
||||||
controller.push_basic_input(InputKind::Ability(0));
|
controller.push_basic_input(InputKind::Ability(0));
|
||||||
|
|
||||||
if matches!(self.char_state, CharacterState::BasicBeam(_)) {
|
if matches!(self.char_state, CharacterState::BasicBeam(_)) {
|
||||||
// Resets action counter when using beam
|
// Resets action counter when using beam
|
||||||
agent.action_state.counters[ActionStateFCounters::FCounterYetiAttack as usize] = 0.0;
|
agent.action_state.counters
|
||||||
|
[ActionStateFCounters::FCounterYetiAttack as usize] = 0.0;
|
||||||
}
|
}
|
||||||
} else if attack_data.in_min_range() {
|
} else if attack_data.in_min_range() {
|
||||||
// Basic attack if on top of them
|
// Basic attack if on top of them
|
||||||
@ -2420,13 +2545,17 @@ impl<'a> AgentData<'a> {
|
|||||||
entities_have_line_of_sight(self.pos, self.body, tgt_data.pos, tgt_data.body, read_data)
|
entities_have_line_of_sight(self.pos, self.body, tgt_data.pos, tgt_data.body, read_data)
|
||||||
};
|
};
|
||||||
|
|
||||||
if health_fraction < VINE_CREATION_THRESHOLD && !agent.action_state.conditions[ActionStateConditions::ConditionHasSummonedVines as usize] {
|
if health_fraction < VINE_CREATION_THRESHOLD
|
||||||
|
&& !agent.action_state.conditions
|
||||||
|
[ActionStateConditions::ConditionHasSummonedVines as usize]
|
||||||
|
{
|
||||||
// Summon vines when reach threshold of health
|
// Summon vines when reach threshold of health
|
||||||
controller.push_basic_input(InputKind::Ability(0));
|
controller.push_basic_input(InputKind::Ability(0));
|
||||||
|
|
||||||
if matches!(self.char_state, CharacterState::SpriteSummon(c) if matches!(c.stage_section, StageSection::Recover))
|
if matches!(self.char_state, CharacterState::SpriteSummon(c) if matches!(c.stage_section, StageSection::Recover))
|
||||||
{
|
{
|
||||||
agent.action_state.conditions[ActionStateConditions::ConditionHasSummonedVines as usize] = true;
|
agent.action_state.conditions
|
||||||
|
[ActionStateConditions::ConditionHasSummonedVines as usize] = true;
|
||||||
}
|
}
|
||||||
} else if attack_data.dist_sqrd < FIRE_BREATH_RANGE.powi(2) {
|
} else if attack_data.dist_sqrd < FIRE_BREATH_RANGE.powi(2) {
|
||||||
if matches!(self.char_state, CharacterState::BasicBeam(c) if c.timer < Duration::from_secs(5))
|
if matches!(self.char_state, CharacterState::BasicBeam(c) if c.timer < Duration::from_secs(5))
|
||||||
@ -2474,26 +2603,33 @@ impl<'a> AgentData<'a> {
|
|||||||
ConditionCounterInitialized = 0,
|
ConditionCounterInitialized = 0,
|
||||||
}
|
}
|
||||||
|
|
||||||
enum ActionStateFCounters
|
enum ActionStateFCounters {
|
||||||
{
|
|
||||||
FCounterHealthThreshold = 0,
|
FCounterHealthThreshold = 0,
|
||||||
}
|
}
|
||||||
|
|
||||||
let health_fraction = self.health.map_or(0.5, |h| h.fraction());
|
let health_fraction = self.health.map_or(0.5, |h| h.fraction());
|
||||||
// Sets counter at start of combat, using `condition` to keep track of whether
|
// Sets counter at start of combat, using `condition` to keep track of whether
|
||||||
// it was already intitialized
|
// it was already intitialized
|
||||||
if !agent.action_state.conditions[ActionStateConditions::ConditionCounterInitialized as usize] {
|
if !agent.action_state.conditions
|
||||||
agent.action_state.counters[ActionStateFCounters::FCounterHealthThreshold as usize] = 1.0 - MINION_SUMMON_THRESHOLD;
|
[ActionStateConditions::ConditionCounterInitialized as usize]
|
||||||
agent.action_state.conditions[ActionStateConditions::ConditionCounterInitialized as usize] = true;
|
{
|
||||||
|
agent.action_state.counters[ActionStateFCounters::FCounterHealthThreshold as usize] =
|
||||||
|
1.0 - MINION_SUMMON_THRESHOLD;
|
||||||
|
agent.action_state.conditions
|
||||||
|
[ActionStateConditions::ConditionCounterInitialized as usize] = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if agent.action_state.counters[ActionStateFCounters::FCounterHealthThreshold as usize] > health_fraction {
|
if agent.action_state.counters[ActionStateFCounters::FCounterHealthThreshold as usize]
|
||||||
|
> health_fraction
|
||||||
|
{
|
||||||
// Summon minions at particular thresholds of health
|
// Summon minions at particular thresholds of health
|
||||||
controller.push_basic_input(InputKind::Ability(1));
|
controller.push_basic_input(InputKind::Ability(1));
|
||||||
|
|
||||||
if matches!(self.char_state, CharacterState::BasicSummon(c) if matches!(c.stage_section, StageSection::Recover))
|
if matches!(self.char_state, CharacterState::BasicSummon(c) if matches!(c.stage_section, StageSection::Recover))
|
||||||
{
|
{
|
||||||
agent.action_state.counters[ActionStateFCounters::FCounterHealthThreshold as usize] -= MINION_SUMMON_THRESHOLD;
|
agent.action_state.counters
|
||||||
|
[ActionStateFCounters::FCounterHealthThreshold as usize] -=
|
||||||
|
MINION_SUMMON_THRESHOLD;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Logic to use abilities
|
// Logic to use abilities
|
||||||
@ -2632,14 +2768,10 @@ impl<'a> AgentData<'a> {
|
|||||||
tgt_data: &TargetData,
|
tgt_data: &TargetData,
|
||||||
read_data: &ReadData,
|
read_data: &ReadData,
|
||||||
) {
|
) {
|
||||||
enum ActionStateTimers
|
enum ActionStateTimers {
|
||||||
{
|
|
||||||
TimerDagon = 0,
|
TimerDagon = 0,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if agent.action_state.timers[ActionStateTimers::TimerDagon as usize] > 2.5 {
|
if agent.action_state.timers[ActionStateTimers::TimerDagon as usize] > 2.5 {
|
||||||
agent.action_state.timers[ActionStateTimers::TimerDagon as usize] = 0.0;
|
agent.action_state.timers[ActionStateTimers::TimerDagon as usize] = 0.0;
|
||||||
}
|
}
|
||||||
@ -2742,30 +2874,31 @@ impl<'a> AgentData<'a> {
|
|||||||
) {
|
) {
|
||||||
const SCREAM_RANGE: f32 = 10.0;
|
const SCREAM_RANGE: f32 = 10.0;
|
||||||
|
|
||||||
enum ActionStateFCounters
|
enum ActionStateFCounters {
|
||||||
{
|
|
||||||
FCounterHealthThreshold = 0,
|
FCounterHealthThreshold = 0,
|
||||||
}
|
}
|
||||||
|
|
||||||
enum ActionStateConditions
|
enum ActionStateConditions {
|
||||||
{
|
|
||||||
ConditionHasScreamed = 0,
|
ConditionHasScreamed = 0,
|
||||||
}
|
}
|
||||||
|
|
||||||
if !agent.action_state.initialized {
|
if !agent.action_state.initialized {
|
||||||
agent.action_state.counters[ActionStateFCounters::FCounterHealthThreshold as usize] = self.health.map_or(0.0, |h| h.maximum());
|
agent.action_state.counters[ActionStateFCounters::FCounterHealthThreshold as usize] =
|
||||||
|
self.health.map_or(0.0, |h| h.maximum());
|
||||||
agent.action_state.initialized = true;
|
agent.action_state.initialized = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if !agent.action_state.conditions[ActionStateConditions::ConditionHasScreamed as usize] {
|
if !agent.action_state.conditions[ActionStateConditions::ConditionHasScreamed as usize] {
|
||||||
// If mandragora is still "sleeping" and hasn't screamed yet, do nothing until
|
// If mandragora is still "sleeping" and hasn't screamed yet, do nothing until
|
||||||
// target in range or until it's taken damage
|
// target in range or until it's taken damage
|
||||||
if self
|
if self.health.map_or(false, |h| {
|
||||||
.health
|
h.current()
|
||||||
.map_or(false, |h| h.current() < agent.action_state.counters[ActionStateFCounters::FCounterHealthThreshold as usize])
|
< agent.action_state.counters
|
||||||
|| attack_data.dist_sqrd < SCREAM_RANGE.powi(2)
|
[ActionStateFCounters::FCounterHealthThreshold as usize]
|
||||||
|
}) || attack_data.dist_sqrd < SCREAM_RANGE.powi(2)
|
||||||
{
|
{
|
||||||
agent.action_state.conditions[ActionStateConditions::ConditionHasScreamed as usize] = true;
|
agent.action_state.conditions
|
||||||
|
[ActionStateConditions::ConditionHasScreamed as usize] = true;
|
||||||
controller.push_basic_input(InputKind::Secondary);
|
controller.push_basic_input(InputKind::Secondary);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -2792,8 +2925,11 @@ impl<'a> AgentData<'a> {
|
|||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
// Otherwise, go back to sleep
|
// Otherwise, go back to sleep
|
||||||
agent.action_state.conditions[ActionStateConditions::ConditionHasScreamed as usize] = false;
|
agent.action_state.conditions
|
||||||
agent.action_state.counters[ActionStateFCounters::FCounterHealthThreshold as usize] = self.health.map_or(0.0, |h| h.maximum());
|
[ActionStateConditions::ConditionHasScreamed as usize] = false;
|
||||||
|
agent.action_state.counters
|
||||||
|
[ActionStateFCounters::FCounterHealthThreshold as usize] =
|
||||||
|
self.health.map_or(0.0, |h| h.maximum());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2810,8 +2946,7 @@ impl<'a> AgentData<'a> {
|
|||||||
const SHOCKWAVE_WAIT_TIME: f32 = 7.5;
|
const SHOCKWAVE_WAIT_TIME: f32 = 7.5;
|
||||||
const SPIN_WAIT_TIME: f32 = 3.0;
|
const SPIN_WAIT_TIME: f32 = 3.0;
|
||||||
|
|
||||||
enum ActionStateTimers
|
enum ActionStateTimers {
|
||||||
{
|
|
||||||
TimerSpinWait = 0,
|
TimerSpinWait = 0,
|
||||||
TimerShockwaveWait,
|
TimerShockwaveWait,
|
||||||
}
|
}
|
||||||
@ -2824,7 +2959,8 @@ impl<'a> AgentData<'a> {
|
|||||||
|
|
||||||
if attack_data.in_min_range() {
|
if attack_data.in_min_range() {
|
||||||
// If in minimum range
|
// If in minimum range
|
||||||
if agent.action_state.timers[ActionStateTimers::TimerSpinWait as usize] > SPIN_WAIT_TIME {
|
if agent.action_state.timers[ActionStateTimers::TimerSpinWait as usize] > SPIN_WAIT_TIME
|
||||||
|
{
|
||||||
// If it's been too long since able to hit target, spin
|
// If it's been too long since able to hit target, spin
|
||||||
controller.push_basic_input(InputKind::Secondary);
|
controller.push_basic_input(InputKind::Secondary);
|
||||||
} else if attack_data.angle < 30.0 {
|
} else if attack_data.angle < 30.0 {
|
||||||
@ -2832,7 +2968,8 @@ impl<'a> AgentData<'a> {
|
|||||||
controller.push_basic_input(InputKind::Primary);
|
controller.push_basic_input(InputKind::Primary);
|
||||||
} else {
|
} else {
|
||||||
// Else increment spin timer
|
// Else increment spin timer
|
||||||
agent.action_state.timers[ActionStateTimers::TimerSpinWait as usize] += read_data.dt.0;
|
agent.action_state.timers[ActionStateTimers::TimerSpinWait as usize] +=
|
||||||
|
read_data.dt.0;
|
||||||
// If not in angle, apply slight movement so golem orients itself correctly
|
// If not in angle, apply slight movement so golem orients itself correctly
|
||||||
controller.inputs.move_dir = (tgt_data.pos.0 - self.pos.0)
|
controller.inputs.move_dir = (tgt_data.pos.0 - self.pos.0)
|
||||||
.xy()
|
.xy()
|
||||||
@ -2844,13 +2981,16 @@ impl<'a> AgentData<'a> {
|
|||||||
// Else if too far for melee
|
// Else if too far for melee
|
||||||
if attack_data.dist_sqrd < SHOCKWAVE_RANGE.powi(2) && attack_data.angle < 45.0 {
|
if attack_data.dist_sqrd < SHOCKWAVE_RANGE.powi(2) && attack_data.angle < 45.0 {
|
||||||
// Shockwave if close enough and haven't shockwaved too recently
|
// Shockwave if close enough and haven't shockwaved too recently
|
||||||
if agent.action_state.timers[ActionStateTimers::TimerSpinWait as usize] > SHOCKWAVE_WAIT_TIME {
|
if agent.action_state.timers[ActionStateTimers::TimerSpinWait as usize]
|
||||||
|
> SHOCKWAVE_WAIT_TIME
|
||||||
|
{
|
||||||
controller.push_basic_input(InputKind::Ability(0));
|
controller.push_basic_input(InputKind::Ability(0));
|
||||||
}
|
}
|
||||||
if matches!(self.char_state, CharacterState::Shockwave(_)) {
|
if matches!(self.char_state, CharacterState::Shockwave(_)) {
|
||||||
agent.action_state.timers[ActionStateTimers::TimerShockwaveWait as usize] = 0.0;
|
agent.action_state.timers[ActionStateTimers::TimerShockwaveWait as usize] = 0.0;
|
||||||
} else {
|
} else {
|
||||||
agent.action_state.timers[ActionStateTimers::TimerShockwaveWait as usize] += read_data.dt.0;
|
agent.action_state.timers[ActionStateTimers::TimerShockwaveWait as usize] +=
|
||||||
|
read_data.dt.0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// And always try to path towards target
|
// And always try to path towards target
|
||||||
@ -2884,7 +3024,9 @@ impl<'a> AgentData<'a> {
|
|||||||
// Handle timers
|
// Handle timers
|
||||||
agent.action_state.timers[ActionStateTimers::TimerSummonTotem as usize] += read_data.dt.0;
|
agent.action_state.timers[ActionStateTimers::TimerSummonTotem as usize] += read_data.dt.0;
|
||||||
match self.char_state {
|
match self.char_state {
|
||||||
CharacterState::BasicSummon(_) => agent.action_state.timers[ActionStateTimers::TimerSummonTotem as usize] = 0.0,
|
CharacterState::BasicSummon(_) => {
|
||||||
|
agent.action_state.timers[ActionStateTimers::TimerSummonTotem as usize] = 0.0
|
||||||
|
},
|
||||||
CharacterState::Shockwave(_) | CharacterState::BasicRanged(_) => {
|
CharacterState::Shockwave(_) | CharacterState::BasicRanged(_) => {
|
||||||
agent.action_state.counters[ActionStateTimers::TimerShockwave as usize] = 0.0
|
agent.action_state.counters[ActionStateTimers::TimerShockwave as usize] = 0.0
|
||||||
},
|
},
|
||||||
@ -2898,7 +3040,9 @@ impl<'a> AgentData<'a> {
|
|||||||
{
|
{
|
||||||
agent.action_state.initialized = true;
|
agent.action_state.initialized = true;
|
||||||
}
|
}
|
||||||
} else if agent.action_state.timers[ActionStateTimers::TimerSummonTotem as usize] > TOTEM_TIMER {
|
} else if agent.action_state.timers[ActionStateTimers::TimerSummonTotem as usize]
|
||||||
|
> TOTEM_TIMER
|
||||||
|
{
|
||||||
// If time to summon a totem, do it
|
// If time to summon a totem, do it
|
||||||
let input = rng.gen_range(1..=3);
|
let input = rng.gen_range(1..=3);
|
||||||
let buff_kind = match input {
|
let buff_kind = match input {
|
||||||
@ -2916,7 +3060,9 @@ impl<'a> AgentData<'a> {
|
|||||||
} else {
|
} else {
|
||||||
controller.push_basic_input(InputKind::Ability(input));
|
controller.push_basic_input(InputKind::Ability(input));
|
||||||
}
|
}
|
||||||
} else if agent.action_state.counters[ActionStateTimers::TimerShockwave as usize] > HEAVY_ATTACK_WAIT_TIME {
|
} else if agent.action_state.counters[ActionStateTimers::TimerShockwave as usize]
|
||||||
|
> HEAVY_ATTACK_WAIT_TIME
|
||||||
|
{
|
||||||
// Else if time for a heavy attack
|
// Else if time for a heavy attack
|
||||||
if attack_data.in_min_range() {
|
if attack_data.in_min_range() {
|
||||||
// If in range, shockwave
|
// If in range, shockwave
|
||||||
@ -2935,14 +3081,17 @@ impl<'a> AgentData<'a> {
|
|||||||
// Else if not time to use anything fancy, if in range and angle, strike them
|
// Else if not time to use anything fancy, if in range and angle, strike them
|
||||||
if attack_data.angle < 20.0 {
|
if attack_data.angle < 20.0 {
|
||||||
controller.push_basic_input(InputKind::Primary);
|
controller.push_basic_input(InputKind::Primary);
|
||||||
agent.action_state.counters[ActionStateTimers::TimerShockwave as usize] += read_data.dt.0;
|
agent.action_state.counters[ActionStateTimers::TimerShockwave as usize] +=
|
||||||
|
read_data.dt.0;
|
||||||
} else {
|
} else {
|
||||||
// If not in angle, charge heavy attack faster
|
// If not in angle, charge heavy attack faster
|
||||||
agent.action_state.counters[ActionStateTimers::TimerShockwave as usize] += read_data.dt.0 * 5.0;
|
agent.action_state.counters[ActionStateTimers::TimerShockwave as usize] +=
|
||||||
|
read_data.dt.0 * 5.0;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// If not in range, charge heavy attack faster
|
// If not in range, charge heavy attack faster
|
||||||
agent.action_state.counters[ActionStateTimers::TimerShockwave as usize] += read_data.dt.0 * 3.3;
|
agent.action_state.counters[ActionStateTimers::TimerShockwave as usize] +=
|
||||||
|
read_data.dt.0 * 3.3;
|
||||||
}
|
}
|
||||||
|
|
||||||
self.path_toward_target(
|
self.path_toward_target(
|
||||||
|
@ -59,15 +59,17 @@ pub struct BehaviorTree {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Enumeration of the timers used by the behavior tree.
|
/// Enumeration of the timers used by the behavior tree.
|
||||||
// FIXME: We shouldnt have a global timer enumeration for the whole behavior tree.
|
// FIXME: We shouldnt have a global timer enumeration for the whole behavior
|
||||||
// It isnt entirely clear where a lot of the agents in some of the bdata objects in
|
// tree. It isnt entirely clear where a lot of the agents in some of the bdata
|
||||||
// behavior tree functions come from, so it's hard to granularly define these timers per action
|
// objects in behavior tree functions come from, so it's hard to granularly
|
||||||
// node. As such, the behavior tree currently has one global enumeration for mapping timers
|
// define these timers per action node. As such, the behavior tree currently has
|
||||||
// in all functions, regardless as to use case or action node currently executed -- even if the
|
// one global enumeration for mapping timers in all functions, regardless as to
|
||||||
// agent might be different between calls. This doesn't break anything as each agent has its own
|
// use case or action node currently executed -- even if the agent might be
|
||||||
// instance of timers, but it is much less clear than I would like.
|
// different between calls. This doesn't break anything as each agent has its
|
||||||
|
// own instance of timers, but it is much less clear than I would like.
|
||||||
//
|
//
|
||||||
// This may require some refactoring to fix, and I don't feel confident doing so.
|
// This may require some refactoring to fix, and I don't feel confident doing
|
||||||
|
// so.
|
||||||
enum ActionStateBehaviorTreeTimers {
|
enum ActionStateBehaviorTreeTimers {
|
||||||
TimerBehaviorTree = 0,
|
TimerBehaviorTree = 0,
|
||||||
}
|
}
|
||||||
@ -488,13 +490,13 @@ fn handle_timed_events(bdata: &mut BehaviorData) -> bool {
|
|||||||
|
|
||||||
/// Try to heal self if our damage went below a certain threshold
|
/// Try to heal self if our damage went below a certain threshold
|
||||||
fn heal_self_if_hurt(bdata: &mut BehaviorData) -> bool {
|
fn heal_self_if_hurt(bdata: &mut BehaviorData) -> bool {
|
||||||
|
|
||||||
if bdata.agent_data.damage < HEALING_ITEM_THRESHOLD
|
if bdata.agent_data.damage < HEALING_ITEM_THRESHOLD
|
||||||
&& bdata
|
&& bdata
|
||||||
.agent_data
|
.agent_data
|
||||||
.heal_self(bdata.agent, bdata.controller, false)
|
.heal_self(bdata.agent, bdata.controller, false)
|
||||||
{
|
{
|
||||||
bdata.agent.action_state.timers[ActionStateBehaviorTreeTimers::TimerBehaviorTree as usize] = 0.01;
|
bdata.agent.action_state.timers
|
||||||
|
[ActionStateBehaviorTreeTimers::TimerBehaviorTree as usize] = 0.01;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
false
|
false
|
||||||
@ -558,18 +560,27 @@ 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[ActionStateBehaviorTreeTimers::TimerBehaviorTree as usize] < FLEE_DURATION;
|
let has_opportunity_to_flee = agent.action_state.timers
|
||||||
|
[ActionStateBehaviorTreeTimers::TimerBehaviorTree as usize]
|
||||||
|
< FLEE_DURATION;
|
||||||
let within_flee_distance = dist_sqrd < MAX_FLEE_DIST.powi(2);
|
let within_flee_distance = dist_sqrd < MAX_FLEE_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[ActionStateBehaviorTreeTimers::TimerBehaviorTree as usize] == 0.0 {
|
if agent.action_state.timers
|
||||||
|
[ActionStateBehaviorTreeTimers::TimerBehaviorTree as usize]
|
||||||
|
== 0.0
|
||||||
|
{
|
||||||
agent_data.cry_out(agent, event_emitter, read_data);
|
agent_data.cry_out(agent, event_emitter, read_data);
|
||||||
agent.action_state.timers[ActionStateBehaviorTreeTimers::TimerBehaviorTree as usize] = 0.01;
|
agent.action_state.timers
|
||||||
|
[ActionStateBehaviorTreeTimers::TimerBehaviorTree as usize] = 0.01;
|
||||||
} else if within_flee_distance && has_opportunity_to_flee {
|
} else if within_flee_distance && has_opportunity_to_flee {
|
||||||
agent_data.flee(agent, controller, tgt_pos, &read_data.terrain);
|
agent_data.flee(agent, controller, tgt_pos, &read_data.terrain);
|
||||||
agent.action_state.timers[ActionStateBehaviorTreeTimers::TimerBehaviorTree as usize] += read_data.dt.0;
|
agent.action_state.timers
|
||||||
|
[ActionStateBehaviorTreeTimers::TimerBehaviorTree as usize] +=
|
||||||
|
read_data.dt.0;
|
||||||
} else {
|
} else {
|
||||||
agent.action_state.timers[ActionStateBehaviorTreeTimers::TimerBehaviorTree as usize] = 0.0;
|
agent.action_state.timers
|
||||||
|
[ActionStateBehaviorTreeTimers::TimerBehaviorTree as usize] = 0.0;
|
||||||
agent.target = None;
|
agent.target = None;
|
||||||
agent_data.idle(agent, controller, read_data, rng);
|
agent_data.idle(agent, controller, read_data, rng);
|
||||||
}
|
}
|
||||||
|
@ -26,7 +26,6 @@ enum ActionStateInteractionTimers {
|
|||||||
TimerInteraction = 0,
|
TimerInteraction = 0,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// Interact if incoming messages
|
/// Interact if incoming messages
|
||||||
pub fn process_inbox_sound_and_hurt(bdata: &mut BehaviorData) -> bool {
|
pub fn process_inbox_sound_and_hurt(bdata: &mut BehaviorData) -> bool {
|
||||||
if !bdata.agent.inbox.is_empty() {
|
if !bdata.agent.inbox.is_empty() {
|
||||||
@ -49,7 +48,8 @@ pub fn process_inbox_sound_and_hurt(bdata: &mut BehaviorData) -> bool {
|
|||||||
Some(_) | None => {},
|
Some(_) | None => {},
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
bdata.agent.action_state.timers[ActionStateInteractionTimers::TimerInteraction as usize] = 0.1;
|
bdata.agent.action_state.timers
|
||||||
|
[ActionStateInteractionTimers::TimerInteraction as usize] = 0.1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
false
|
false
|
||||||
@ -68,7 +68,8 @@ pub fn process_inbox_interaction(bdata: &mut BehaviorData) -> bool {
|
|||||||
|
|
||||||
/// Increment agent's action_state timer
|
/// Increment agent's action_state timer
|
||||||
pub fn increment_timer_deltatime(bdata: &mut BehaviorData) -> bool {
|
pub fn increment_timer_deltatime(bdata: &mut BehaviorData) -> bool {
|
||||||
bdata.agent.action_state.timers[ActionStateInteractionTimers::TimerInteraction as usize] += bdata.read_data.dt.0;
|
bdata.agent.action_state.timers[ActionStateInteractionTimers::TimerInteraction as usize] +=
|
||||||
|
bdata.read_data.dt.0;
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user