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 SECONDS_BEFORE_FORGET_SOUNDS: f64 = 180.0;
|
||||
|
||||
//intentionally very few concurrent action state variables are allowed. This is to keep the
|
||||
//complexity of our AI from getting too large, too quickly. Originally I was
|
||||
//going to provide 30 of these, but if we decide later that this is too many
|
||||
//and somebody is already using 30 in one of their AI, it will be difficult
|
||||
//to go back.
|
||||
//intentionally very few concurrent action state variables are allowed. This is
|
||||
// to keep the complexity of our AI from getting too large, too quickly.
|
||||
// Originally I was going to provide 30 of these, but if we decide later that
|
||||
// this is too many and somebody is already using 30 in one of their AI, it will
|
||||
// be difficult to go back.
|
||||
|
||||
/// The number of timers that a single Action node can track concurrently
|
||||
/// Define constants within a given action node to index between them.
|
||||
const ACTIONSTATE_NUMBER_OF_CONCURRENT_TIMERS: usize = 5;
|
||||
/// The number of float counters that a single Action node can track concurrently
|
||||
/// Define constants within a given action node to index between them.
|
||||
/// The number of float counters that a single Action node can track
|
||||
/// concurrently Define constants within a given action node to index between
|
||||
/// them.
|
||||
const ACTIONSTATE_NUMBER_OF_CONCURRENT_COUNTERS: usize = 5;
|
||||
/// The number of integer counters that a single Action node can track concurrently
|
||||
/// Define constants within a given action node to index between them.
|
||||
/// The number of integer counters that a single Action node can track
|
||||
/// concurrently Define constants within a given action node to index between
|
||||
/// them.
|
||||
const ACTIONSTATE_NUMBER_OF_CONCURRENT_INT_COUNTERS: usize = 5;
|
||||
/// The number of booleans that a single Action node can track concurrently
|
||||
/// 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
|
||||
/// Allows for state to be stored between subsequent, sequential calls of a single action node.
|
||||
/// If the executed action node changes between ticks, then the state should be considered lost.
|
||||
/// Allows for state to be stored between subsequent, sequential calls of a
|
||||
/// single action node. If the executed action node changes between ticks, then
|
||||
/// the state should be considered lost.
|
||||
#[derive(Clone, Debug, Default)]
|
||||
pub struct ActionState {
|
||||
pub timers: [f32; ACTIONSTATE_NUMBER_OF_CONCURRENT_TIMERS],
|
||||
|
@ -1,4 +1,3 @@
|
||||
|
||||
use crate::{
|
||||
consts::{
|
||||
AVG_FOLLOW_DIST, DEFAULT_ATTACK_RANGE, IDLE_HEALING_ITEM_THRESHOLD, PARTIAL_PATH_DIST,
|
||||
@ -44,9 +43,6 @@ use vek::*;
|
||||
#[cfg(feature = "use-dyn-lib")]
|
||||
use {crate::LIB, std::ffi::CStr};
|
||||
|
||||
|
||||
|
||||
|
||||
impl<'a> AgentData<'a> {
|
||||
////////////////////////////////////////
|
||||
// Action Nodes
|
||||
|
@ -213,8 +213,7 @@ impl<'a> AgentData<'a> {
|
||||
read_data: &ReadData,
|
||||
rng: &mut impl Rng,
|
||||
) {
|
||||
enum ActionStateTimers
|
||||
{
|
||||
enum ActionStateTimers {
|
||||
TimerHandleAxeAttack = 0,
|
||||
}
|
||||
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 {
|
||||
controller.push_cancel_input(InputKind::Secondary);
|
||||
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);
|
||||
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) {
|
||||
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 {
|
||||
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 {
|
||||
self.path_toward_target(
|
||||
@ -279,8 +284,7 @@ impl<'a> AgentData<'a> {
|
||||
read_data: &ReadData,
|
||||
rng: &mut impl Rng,
|
||||
) {
|
||||
enum ActionStateTimers
|
||||
{
|
||||
enum ActionStateTimers {
|
||||
TimerHandleHammerAttack = 0,
|
||||
}
|
||||
let has_leap = || {
|
||||
@ -296,18 +300,25 @@ impl<'a> AgentData<'a> {
|
||||
|
||||
if attack_data.in_min_range() && attack_data.angle < 45.0 {
|
||||
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);
|
||||
agent.action_state.timers[ActionStateTimers::TimerHandleHammerAttack as usize] = 0.0;
|
||||
} else if agent.action_state.timers[ActionStateTimers::TimerHandleHammerAttack as usize] > 3.0 {
|
||||
agent.action_state.timers[ActionStateTimers::TimerHandleHammerAttack as usize] =
|
||||
0.0;
|
||||
} else if agent.action_state.timers[ActionStateTimers::TimerHandleHammerAttack as usize]
|
||||
> 3.0
|
||||
{
|
||||
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) {
|
||||
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 {
|
||||
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 {
|
||||
self.path_toward_target(
|
||||
@ -358,16 +369,21 @@ impl<'a> AgentData<'a> {
|
||||
if self
|
||||
.skill_set
|
||||
.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
|
||||
{
|
||||
controller.push_basic_input(InputKind::Ability(0));
|
||||
agent.action_state.timers[ActionStateTimers::TimerHandleSwordAttack as usize] += read_data.dt.0;
|
||||
} else if agent.action_state.timers[ActionStateTimers::TimerHandleSwordAttack as usize] > 2.0 {
|
||||
agent.action_state.timers[ActionStateTimers::TimerHandleSwordAttack as usize] +=
|
||||
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;
|
||||
} else {
|
||||
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) {
|
||||
if self.path_toward_target(
|
||||
@ -384,11 +400,16 @@ impl<'a> AgentData<'a> {
|
||||
tgt_data.body,
|
||||
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);
|
||||
agent.action_state.timers[ActionStateTimers::TimerHandleSwordAttack as usize] = 0.0;
|
||||
agent.action_state.timers[ActionStateTimers::TimerHandleSwordAttack as usize] =
|
||||
0.0;
|
||||
} 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)
|
||||
@ -594,8 +615,10 @@ impl<'a> AgentData<'a> {
|
||||
// emergency roll
|
||||
controller.push_basic_input(InputKind::Roll);
|
||||
} else if matches!(self.char_state, CharacterState::Shockwave(_)) {
|
||||
agent.action_state.conditions[ActionStateConditions::ConditionStaffCanShockwave as usize] = false;
|
||||
} else if agent.action_state.conditions[ActionStateConditions::ConditionStaffCanShockwave as usize]
|
||||
agent.action_state.conditions
|
||||
[ActionStateConditions::ConditionStaffCanShockwave as usize] = false;
|
||||
} else if agent.action_state.conditions
|
||||
[ActionStateConditions::ConditionStaffCanShockwave as usize]
|
||||
&& matches!(self.char_state, CharacterState::Wielding(_))
|
||||
{
|
||||
controller.push_basic_input(InputKind::Ability(0));
|
||||
@ -618,7 +641,8 @@ impl<'a> AgentData<'a> {
|
||||
if matches!(self.char_state, CharacterState::Wielding(_)) {
|
||||
controller.push_basic_input(InputKind::Ability(0));
|
||||
} else {
|
||||
agent.action_state.conditions[ActionStateConditions::ConditionStaffCanShockwave as usize] = true;
|
||||
agent.action_state.conditions
|
||||
[ActionStateConditions::ConditionStaffCanShockwave as usize] = true;
|
||||
}
|
||||
} else if self.energy.current()
|
||||
> shockwave_cost + CharacterAbility::default_roll().get_energy_cost()
|
||||
@ -868,11 +892,16 @@ impl<'a> AgentData<'a> {
|
||||
read_data,
|
||||
) && 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);
|
||||
agent.action_state.timers[ActionStateTimers::TimerHandleStoneGolemAttack as usize] = 0.0;
|
||||
agent.action_state.timers
|
||||
[ActionStateTimers::TimerHandleStoneGolemAttack as usize] = 0.0;
|
||||
} 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 {
|
||||
@ -907,15 +936,23 @@ impl<'a> AgentData<'a> {
|
||||
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
|
||||
controller.push_basic_input(InputKind::Secondary);
|
||||
}
|
||||
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
|
||||
agent.action_state.counters[ActionStateCountersF::CounterFHandleCircleChargeAttack as usize] = 0.0;
|
||||
agent.action_state.int_counters[ActionStateCountersI::CounterIHandleCircleChargeAttack as usize] = 0;
|
||||
agent.action_state.counters
|
||||
[ActionStateCountersF::CounterFHandleCircleChargeAttack as usize] = 0.0;
|
||||
agent.action_state.int_counters
|
||||
[ActionStateCountersI::CounterIHandleCircleChargeAttack as usize] = 0;
|
||||
} else {
|
||||
// melee attack
|
||||
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) {
|
||||
// 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
|
||||
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
|
||||
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 =>
|
||||
// circle left if counter is 1
|
||||
{
|
||||
@ -966,11 +1013,15 @@ impl<'a> AgentData<'a> {
|
||||
.map_or(true, |b| b.is_some());
|
||||
if obstacle {
|
||||
// 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;
|
||||
// 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
|
||||
} else {
|
||||
@ -1024,16 +1075,25 @@ impl<'a> AgentData<'a> {
|
||||
read_data,
|
||||
)
|
||||
{
|
||||
if agent.action_state.timers[ActionStateTimers::TimerHandleQuadLowRanged as usize] > 5.0 {
|
||||
agent.action_state.timers[ActionStateTimers::TimerHandleQuadLowRanged as usize] = 0.0;
|
||||
} else if agent.action_state.timers[ActionStateTimers::TimerHandleQuadLowRanged as usize] > 2.5 {
|
||||
if agent.action_state.timers
|
||||
[ActionStateTimers::TimerHandleQuadLowRanged as usize]
|
||||
> 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)
|
||||
.xy()
|
||||
.rotated_z(1.75 * PI)
|
||||
.try_normalized()
|
||||
.unwrap_or_else(Vec2::zero)
|
||||
* 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 {
|
||||
controller.inputs.move_dir = (tgt_data.pos.0 - self.pos.0)
|
||||
.xy()
|
||||
@ -1041,7 +1101,9 @@ impl<'a> AgentData<'a> {
|
||||
.try_normalized()
|
||||
.unwrap_or_else(Vec2::zero)
|
||||
* 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);
|
||||
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;
|
||||
} else if agent.action_state.timers[ActionStateTimers::TimerTailSlap as usize] > 1.0 {
|
||||
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 {
|
||||
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)
|
||||
.xy()
|
||||
@ -1180,12 +1244,15 @@ impl<'a> AgentData<'a> {
|
||||
controller.inputs.move_dir = Vec2::zero();
|
||||
if agent.action_state.timers[ActionStateTimers::TimerQuadLowBasic as usize] > 5.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);
|
||||
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 {
|
||||
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 {
|
||||
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();
|
||||
if agent.action_state.timers[ActionStateTimers::TimerQuadMedBasic as usize] < 2.0 {
|
||||
controller.push_basic_input(InputKind::Secondary);
|
||||
agent.action_state.timers[ActionStateTimers::TimerQuadMedBasic as usize] += read_data.dt.0;
|
||||
} else if agent.action_state.timers[ActionStateTimers::TimerQuadMedBasic as usize] < 3.0 {
|
||||
agent.action_state.timers[ActionStateTimers::TimerQuadMedBasic as usize] +=
|
||||
read_data.dt.0;
|
||||
} else if agent.action_state.timers[ActionStateTimers::TimerQuadMedBasic as usize] < 3.0
|
||||
{
|
||||
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 {
|
||||
agent.action_state.timers[ActionStateTimers::TimerQuadMedBasic as usize] = 0.0;
|
||||
}
|
||||
@ -1297,8 +1367,7 @@ impl<'a> AgentData<'a> {
|
||||
tgt_data: &TargetData,
|
||||
read_data: &ReadData,
|
||||
) {
|
||||
enum ActionStateTimers
|
||||
{
|
||||
enum ActionStateTimers {
|
||||
TimerQuadLowBeam = 0,
|
||||
}
|
||||
if attack_data.angle < 90.0
|
||||
@ -1316,18 +1385,25 @@ impl<'a> AgentData<'a> {
|
||||
.try_normalized()
|
||||
.unwrap_or_else(Vec2::unit_y);
|
||||
controller.push_basic_input(InputKind::Primary);
|
||||
agent.action_state.timers[ActionStateTimers::TimerQuadLowBeam as usize] += read_data.dt.0;
|
||||
} else if agent.action_state.timers[ActionStateTimers::TimerQuadLowBeam as usize] < 4.0 && attack_data.angle < 15.0 {
|
||||
agent.action_state.timers[ActionStateTimers::TimerQuadLowBeam as usize] +=
|
||||
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)
|
||||
.xy()
|
||||
.rotated_z(-0.47 * PI)
|
||||
.try_normalized()
|
||||
.unwrap_or_else(Vec2::unit_y);
|
||||
controller.push_basic_input(InputKind::Primary);
|
||||
agent.action_state.timers[ActionStateTimers::TimerQuadLowBeam as usize] += read_data.dt.0;
|
||||
} else if agent.action_state.timers[ActionStateTimers::TimerQuadLowBeam as usize] < 6.0 && attack_data.angle < 15.0 {
|
||||
agent.action_state.timers[ActionStateTimers::TimerQuadLowBeam as usize] +=
|
||||
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));
|
||||
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 {
|
||||
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;
|
||||
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;
|
||||
} else if agent.action_state.timers[ActionStateTimers::TimerOrganAura as usize] < 1.0 {
|
||||
controller
|
||||
.actions
|
||||
.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 {
|
||||
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 {
|
||||
agent.target = None;
|
||||
@ -1495,24 +1575,29 @@ impl<'a> AgentData<'a> {
|
||||
ConditionCounterInit = 0,
|
||||
}
|
||||
|
||||
|
||||
const MINDFLAYER_ATTACK_DIST: f32 = 16.0;
|
||||
const MINION_SUMMON_THRESHOLD: f32 = 0.20;
|
||||
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
|
||||
// it was already initialized
|
||||
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.conditions[ActionStateConditions::ConditionCounterInit as usize] = true;
|
||||
agent.action_state.counters[ActionStateFCounters::FCounterHealthThreshold as usize] =
|
||||
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
|
||||
controller.push_basic_input(InputKind::Ability(2));
|
||||
|
||||
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) {
|
||||
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) {
|
||||
// If too far from target, throw a random number of necrotic spheres at them and
|
||||
// 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 {
|
||||
controller.push_action(ControlAction::StartInput {
|
||||
input: InputKind::Ability(0),
|
||||
@ -1830,14 +1916,16 @@ impl<'a> AgentData<'a> {
|
||||
Path::Separate,
|
||||
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
|
||||
&& attack_data.angle < 90.0
|
||||
&& attack_data.in_min_range()
|
||||
{
|
||||
// Triple strike
|
||||
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 {
|
||||
// Reset timer
|
||||
agent.action_state.timers[ActionStateTimers::TimerBirdLargeBreathe as usize] = 0.0;
|
||||
@ -1866,14 +1954,16 @@ impl<'a> AgentData<'a> {
|
||||
}
|
||||
|
||||
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_CHARGE_DISTANCE: f32 = 15.0;
|
||||
let bird_attack_distance = self.body.map_or(0.0, |b| b.max_radius()) + BIRD_ATTACK_RANGE;
|
||||
// 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 !read_data
|
||||
.terrain
|
||||
@ -1913,7 +2003,8 @@ impl<'a> AgentData<'a> {
|
||||
} else if attack_data.dist_sqrd < bird_attack_distance.powi(2) {
|
||||
// Combo melee target
|
||||
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
|
||||
self.path_toward_target(
|
||||
@ -1934,12 +2025,12 @@ impl<'a> AgentData<'a> {
|
||||
tgt_data: &TargetData,
|
||||
read_data: &ReadData,
|
||||
) {
|
||||
enum ActionStateTimers
|
||||
{
|
||||
enum ActionStateTimers {
|
||||
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
|
||||
&& attack_data.dist_sqrd < (1.5 * attack_data.min_attack_dist).powi(2)
|
||||
{
|
||||
@ -1981,16 +2072,23 @@ impl<'a> AgentData<'a> {
|
||||
read_data,
|
||||
)
|
||||
{
|
||||
if agent.action_state.timers[ActionStateTimers::TimerArthropodRanged as usize] > 5.0 {
|
||||
agent.action_state.timers[ActionStateTimers::TimerArthropodRanged as usize] = 0.0;
|
||||
} else if agent.action_state.timers[ActionStateTimers::TimerArthropodRanged as usize] > 2.5 {
|
||||
if agent.action_state.timers[ActionStateTimers::TimerArthropodRanged as usize]
|
||||
> 5.0
|
||||
{
|
||||
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)
|
||||
.xy()
|
||||
.rotated_z(1.75 * PI)
|
||||
.try_normalized()
|
||||
.unwrap_or_else(Vec2::zero)
|
||||
* 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 {
|
||||
controller.inputs.move_dir = (tgt_data.pos.0 - self.pos.0)
|
||||
.xy()
|
||||
@ -1998,7 +2096,8 @@ impl<'a> AgentData<'a> {
|
||||
.try_normalized()
|
||||
.unwrap_or_else(Vec2::zero)
|
||||
* 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));
|
||||
self.jump_if(bearing.z > 1.5, controller);
|
||||
@ -2037,7 +2136,8 @@ impl<'a> AgentData<'a> {
|
||||
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
|
||||
&& attack_data.dist_sqrd < (1.5 * attack_data.min_attack_dist).powi(2)
|
||||
{
|
||||
@ -2084,7 +2184,8 @@ impl<'a> AgentData<'a> {
|
||||
enum ActionStateTimers {
|
||||
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 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;
|
||||
let health_fraction = self.health.map_or(1.0, |h| h.fraction());
|
||||
// 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
|
||||
{
|
||||
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
|
||||
controller.push_basic_input(InputKind::Ability(1));
|
||||
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))
|
||||
{
|
||||
@ -2161,14 +2267,19 @@ impl<'a> AgentData<'a> {
|
||||
controller.push_basic_input(InputKind::Ability(0));
|
||||
}
|
||||
} 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
|
||||
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() {
|
||||
// Cleave target if not just used cleave
|
||||
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
|
||||
@ -2215,16 +2326,20 @@ impl<'a> AgentData<'a> {
|
||||
};
|
||||
|
||||
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
|
||||
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 {
|
||||
// If whacked for too long, nuke them
|
||||
controller.push_basic_input(InputKind::Ability(1));
|
||||
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) {
|
||||
@ -2274,13 +2389,11 @@ impl<'a> AgentData<'a> {
|
||||
const BUBBLE_RANGE: f32 = 20.0;
|
||||
const MINION_SUMMON_THRESHOLD: f32 = 0.20;
|
||||
|
||||
enum ActionStateConditions
|
||||
{
|
||||
enum ActionStateConditions {
|
||||
ConditionCounterInitialized = 0,
|
||||
}
|
||||
|
||||
enum ActionStateFCounters
|
||||
{
|
||||
enum ActionStateFCounters {
|
||||
FCounterMinionSummonThreshold = 0,
|
||||
}
|
||||
|
||||
@ -2291,18 +2404,27 @@ impl<'a> AgentData<'a> {
|
||||
|
||||
// Sets counter at start of combat, using `condition` to keep track of whether
|
||||
// it was already initialized
|
||||
if !agent.action_state.conditions[ActionStateConditions::ConditionCounterInitialized as usize] {
|
||||
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.conditions
|
||||
[ActionStateConditions::ConditionCounterInitialized as usize]
|
||||
{
|
||||
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
|
||||
controller.push_basic_input(InputKind::Ability(1));
|
||||
|
||||
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) {
|
||||
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 SNOWBALL_MAX_RANGE: f32 = 50.0;
|
||||
|
||||
enum ActionStateFCounters
|
||||
{
|
||||
enum ActionStateFCounters {
|
||||
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 matches!(self.char_state, CharacterState::BasicBeam(c) if c.timer < Duration::from_secs(2))
|
||||
{
|
||||
// Keep using ice breath for 2 second
|
||||
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
|
||||
controller.push_basic_input(InputKind::Ability(0));
|
||||
|
||||
if matches!(self.char_state, CharacterState::BasicBeam(_)) {
|
||||
// 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() {
|
||||
// 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)
|
||||
};
|
||||
|
||||
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
|
||||
controller.push_basic_input(InputKind::Ability(0));
|
||||
|
||||
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) {
|
||||
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,
|
||||
}
|
||||
|
||||
enum ActionStateFCounters
|
||||
{
|
||||
enum ActionStateFCounters {
|
||||
FCounterHealthThreshold = 0,
|
||||
}
|
||||
|
||||
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
|
||||
// it was already intitialized
|
||||
if !agent.action_state.conditions[ActionStateConditions::ConditionCounterInitialized as usize] {
|
||||
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.conditions
|
||||
[ActionStateConditions::ConditionCounterInitialized as usize]
|
||||
{
|
||||
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
|
||||
controller.push_basic_input(InputKind::Ability(1));
|
||||
|
||||
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
|
||||
@ -2632,14 +2768,10 @@ impl<'a> AgentData<'a> {
|
||||
tgt_data: &TargetData,
|
||||
read_data: &ReadData,
|
||||
) {
|
||||
enum ActionStateTimers
|
||||
{
|
||||
enum ActionStateTimers {
|
||||
TimerDagon = 0,
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
if agent.action_state.timers[ActionStateTimers::TimerDagon as usize] > 2.5 {
|
||||
agent.action_state.timers[ActionStateTimers::TimerDagon as usize] = 0.0;
|
||||
}
|
||||
@ -2742,30 +2874,31 @@ impl<'a> AgentData<'a> {
|
||||
) {
|
||||
const SCREAM_RANGE: f32 = 10.0;
|
||||
|
||||
enum ActionStateFCounters
|
||||
{
|
||||
enum ActionStateFCounters {
|
||||
FCounterHealthThreshold = 0,
|
||||
}
|
||||
|
||||
enum ActionStateConditions
|
||||
{
|
||||
enum ActionStateConditions {
|
||||
ConditionHasScreamed = 0,
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
if !agent.action_state.conditions[ActionStateConditions::ConditionHasScreamed as usize] {
|
||||
// If mandragora is still "sleeping" and hasn't screamed yet, do nothing until
|
||||
// target in range or until it's taken damage
|
||||
if self
|
||||
.health
|
||||
.map_or(false, |h| h.current() < agent.action_state.counters[ActionStateFCounters::FCounterHealthThreshold as usize])
|
||||
|| attack_data.dist_sqrd < SCREAM_RANGE.powi(2)
|
||||
if self.health.map_or(false, |h| {
|
||||
h.current()
|
||||
< agent.action_state.counters
|
||||
[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);
|
||||
}
|
||||
} else {
|
||||
@ -2792,8 +2925,11 @@ impl<'a> AgentData<'a> {
|
||||
);
|
||||
} else {
|
||||
// Otherwise, go back to sleep
|
||||
agent.action_state.conditions[ActionStateConditions::ConditionHasScreamed as usize] = false;
|
||||
agent.action_state.counters[ActionStateFCounters::FCounterHealthThreshold as usize] = self.health.map_or(0.0, |h| h.maximum());
|
||||
agent.action_state.conditions
|
||||
[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 SPIN_WAIT_TIME: f32 = 3.0;
|
||||
|
||||
enum ActionStateTimers
|
||||
{
|
||||
enum ActionStateTimers {
|
||||
TimerSpinWait = 0,
|
||||
TimerShockwaveWait,
|
||||
}
|
||||
@ -2824,7 +2959,8 @@ impl<'a> AgentData<'a> {
|
||||
|
||||
if attack_data.in_min_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
|
||||
controller.push_basic_input(InputKind::Secondary);
|
||||
} else if attack_data.angle < 30.0 {
|
||||
@ -2832,7 +2968,8 @@ impl<'a> AgentData<'a> {
|
||||
controller.push_basic_input(InputKind::Primary);
|
||||
} else {
|
||||
// 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
|
||||
controller.inputs.move_dir = (tgt_data.pos.0 - self.pos.0)
|
||||
.xy()
|
||||
@ -2844,13 +2981,16 @@ impl<'a> AgentData<'a> {
|
||||
// Else if too far for melee
|
||||
if attack_data.dist_sqrd < SHOCKWAVE_RANGE.powi(2) && attack_data.angle < 45.0 {
|
||||
// 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));
|
||||
}
|
||||
if matches!(self.char_state, CharacterState::Shockwave(_)) {
|
||||
agent.action_state.timers[ActionStateTimers::TimerShockwaveWait as usize] = 0.0;
|
||||
} 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
|
||||
@ -2884,7 +3024,9 @@ impl<'a> AgentData<'a> {
|
||||
// Handle timers
|
||||
agent.action_state.timers[ActionStateTimers::TimerSummonTotem as usize] += read_data.dt.0;
|
||||
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(_) => {
|
||||
agent.action_state.counters[ActionStateTimers::TimerShockwave as usize] = 0.0
|
||||
},
|
||||
@ -2898,7 +3040,9 @@ impl<'a> AgentData<'a> {
|
||||
{
|
||||
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
|
||||
let input = rng.gen_range(1..=3);
|
||||
let buff_kind = match input {
|
||||
@ -2916,7 +3060,9 @@ impl<'a> AgentData<'a> {
|
||||
} else {
|
||||
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
|
||||
if attack_data.in_min_range() {
|
||||
// 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
|
||||
if attack_data.angle < 20.0 {
|
||||
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 {
|
||||
// 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 {
|
||||
// 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(
|
||||
|
@ -59,15 +59,17 @@ pub struct BehaviorTree {
|
||||
}
|
||||
|
||||
/// Enumeration of the timers used by the behavior tree.
|
||||
// FIXME: We shouldnt have a global timer enumeration for the whole behavior tree.
|
||||
// It isnt entirely clear where a lot of the agents in some of the bdata objects in
|
||||
// behavior tree functions come from, so it's hard to granularly define these timers per action
|
||||
// node. As such, the behavior tree currently has one global enumeration for mapping timers
|
||||
// in all functions, regardless as to use case or action node currently executed -- even if the
|
||||
// agent might be 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.
|
||||
// FIXME: We shouldnt have a global timer enumeration for the whole behavior
|
||||
// tree. It isnt entirely clear where a lot of the agents in some of the bdata
|
||||
// objects in behavior tree functions come from, so it's hard to granularly
|
||||
// define these timers per action node. As such, the behavior tree currently has
|
||||
// one global enumeration for mapping timers in all functions, regardless as to
|
||||
// use case or action node currently executed -- even if the agent might be
|
||||
// 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 {
|
||||
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
|
||||
fn heal_self_if_hurt(bdata: &mut BehaviorData) -> bool {
|
||||
|
||||
if bdata.agent_data.damage < HEALING_ITEM_THRESHOLD
|
||||
&& bdata
|
||||
.agent_data
|
||||
.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;
|
||||
}
|
||||
false
|
||||
@ -558,18 +560,27 @@ fn do_combat(bdata: &mut BehaviorData) -> bool {
|
||||
let aggro_on = *aggro_on;
|
||||
|
||||
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);
|
||||
|
||||
// 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.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 {
|
||||
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 {
|
||||
agent.action_state.timers[ActionStateBehaviorTreeTimers::TimerBehaviorTree as usize] = 0.0;
|
||||
agent.action_state.timers
|
||||
[ActionStateBehaviorTreeTimers::TimerBehaviorTree as usize] = 0.0;
|
||||
agent.target = None;
|
||||
agent_data.idle(agent, controller, read_data, rng);
|
||||
}
|
||||
|
@ -26,7 +26,6 @@ enum ActionStateInteractionTimers {
|
||||
TimerInteraction = 0,
|
||||
}
|
||||
|
||||
|
||||
/// Interact if incoming messages
|
||||
pub fn process_inbox_sound_and_hurt(bdata: &mut BehaviorData) -> bool {
|
||||
if !bdata.agent.inbox.is_empty() {
|
||||
@ -49,7 +48,8 @@ pub fn process_inbox_sound_and_hurt(bdata: &mut BehaviorData) -> bool {
|
||||
Some(_) | None => {},
|
||||
}
|
||||
} else {
|
||||
bdata.agent.action_state.timers[ActionStateInteractionTimers::TimerInteraction as usize] = 0.1;
|
||||
bdata.agent.action_state.timers
|
||||
[ActionStateInteractionTimers::TimerInteraction as usize] = 0.1;
|
||||
}
|
||||
}
|
||||
false
|
||||
@ -68,7 +68,8 @@ pub fn process_inbox_interaction(bdata: &mut BehaviorData) -> bool {
|
||||
|
||||
/// Increment agent's action_state timer
|
||||
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
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user