From 38432cc88044e083217b839718143cf700431973 Mon Sep 17 00:00:00 2001 From: Knightress Paladin Date: Sat, 17 Jul 2021 23:55:22 -0700 Subject: [PATCH] Restructured logic for staff AI --- .../common/entity/dungeon/tier-5/warlock.ron | 2 + .../common/skillset/dungeon/tier-5/staff.ron | 21 ++++++ .../skillset/dungeon/tier-5/warlock.ron | 5 ++ server/src/sys/agent.rs | 72 +++++++++++-------- 4 files changed, 72 insertions(+), 28 deletions(-) create mode 100644 assets/common/skillset/dungeon/tier-5/staff.ron create mode 100644 assets/common/skillset/dungeon/tier-5/warlock.ron diff --git a/assets/common/entity/dungeon/tier-5/warlock.ron b/assets/common/entity/dungeon/tier-5/warlock.ron index 0ee439d4df..6caba2a001 100644 --- a/assets/common/entity/dungeon/tier-5/warlock.ron +++ b/assets/common/entity/dungeon/tier-5/warlock.ron @@ -11,4 +11,6 @@ EntityConfig ( ])), meta: [], + loadout_asset: None, + skillset_asset: Some("common.skillset.dungeon.tier-5.warlock"), ) diff --git a/assets/common/skillset/dungeon/tier-5/staff.ron b/assets/common/skillset/dungeon/tier-5/staff.ron new file mode 100644 index 0000000000..59d5e9ae24 --- /dev/null +++ b/assets/common/skillset/dungeon/tier-5/staff.ron @@ -0,0 +1,21 @@ +([ + Group(Weapon(Staff)), + + // Fireball + Skill((Staff(BDamage), Some(1))), + Skill((Staff(BRegen), Some(1))), + Skill((Staff(BRadius), Some(1))), + + // Flamethrower + Skill((Staff(FDamage), Some(1))), + Skill((Staff(FRange), Some(1))), + Skill((Staff(FDrain), Some(1))), + Skill((Staff(FVelocity), Some(1))), + + // Shockwave + Skill((Staff(UnlockShockwave), None)), + Skill((Staff(SDamage), Some(1))), + Skill((Staff(SKnockback), Some(1))), + Skill((Staff(SRange), Some(1))), + Skill((Staff(SCost), Some(1))), +]) diff --git a/assets/common/skillset/dungeon/tier-5/warlock.ron b/assets/common/skillset/dungeon/tier-5/warlock.ron new file mode 100644 index 0000000000..a8944845e0 --- /dev/null +++ b/assets/common/skillset/dungeon/tier-5/warlock.ron @@ -0,0 +1,5 @@ +([ + // Gather all warlock skills + Tree("common.skillset.dungeon.tier-5.bow"), + Tree("common.skillset.dungeon.tier-5.staff"), +]) diff --git a/server/src/sys/agent.rs b/server/src/sys/agent.rs index a0ac28315e..fedd4597b0 100644 --- a/server/src/sys/agent.rs +++ b/server/src/sys/agent.rs @@ -2443,40 +2443,37 @@ impl<'a> AgentData<'a> { tgt_data: &TargetData, read_data: &ReadData, ) { - if self.body.map(|b| b.is_humanoid()).unwrap_or(false) && attack_data.in_min_range() { + //TODO: minimum energy values for skills and rolls are hard coded from + // approximate guesses + if self.body.map(|b| b.is_humanoid()).unwrap_or(false) + && attack_data.in_min_range() + && self.energy.current() > 100 + { + // if a humanoid, have enough stamina, and in melee range, emergency roll controller .actions .push(ControlAction::basic_input(InputKind::Roll)); - } else if attack_data.dist_sqrd < (5.0 * attack_data.min_attack_dist).powi(2) - && attack_data.angle < 15.0 + } else if !matches!(self.char_state, CharacterState::Shockwave(c) if !matches!(c.stage_section, StageSection::Recover)) { - if agent.action_state.timer < 1.5 { - 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); - agent.action_state.timer += read_data.dt.0; - } else if agent.action_state.timer < 3.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); - agent.action_state.timer += read_data.dt.0; - } else { - agent.action_state.timer = 0.0; - } + // only try to use another ability if not already in recover and not casting + // shockwave + let target_approaching_speed = -agent + .target + .as_ref() + .map(|t| t.target) + .and_then(|e| read_data.velocities.get(e)) + .map_or(0.0, |v| v.0.dot(self.ori.look_vec())); if self .skill_set .has_skill(Skill::Staff(StaffSkill::UnlockShockwave)) - && self.energy.current() > 800 - && thread_rng().gen::() > 0.8 + && target_approaching_speed > 20.0 + && self.energy.current() > 200 { + // if enemy is closing distance quickly, use shockwave to knock back controller .actions .push(ControlAction::basic_input(InputKind::Ability(0))); - } else if self.energy.current() > 10 { + } else if self.energy.current() > 100 && attack_data.dist_sqrd < 280.0 { controller .actions .push(ControlAction::basic_input(InputKind::Secondary)); @@ -2485,7 +2482,26 @@ impl<'a> AgentData<'a> { .actions .push(ControlAction::basic_input(InputKind::Primary)); } + } + // Logic to move. Intentionally kept separate from ability logic so duplicated + // work is less necessary. + if attack_data.dist_sqrd < (2.0 * attack_data.min_attack_dist).powi(2) { + // Attempt to move away from target if too close + if let Some((bearing, speed)) = agent.chaser.chase( + &*read_data.terrain, + self.pos.0, + self.vel.0, + tgt_data.pos.0, + TraversalConfig { + min_tgt_dist: 1.25, + ..self.traversal_config + }, + ) { + controller.inputs.move_dir = + -bearing.xy().try_normalized().unwrap_or_else(Vec2::zero) * speed; + } } else if attack_data.dist_sqrd < MAX_PATH_DIST.powi(2) { + // Else attempt to circle target if neither too close nor too far if let Some((bearing, speed)) = agent.chaser.chase( &*read_data.terrain, self.pos.0, @@ -2501,7 +2517,7 @@ impl<'a> AgentData<'a> { self.pos, tgt_data.pos, attack_data.dist_sqrd, - ) && attack_data.angle < 15.0 + ) && attack_data.angle < 45.0 { controller.inputs.move_dir = bearing .xy() @@ -2509,25 +2525,25 @@ impl<'a> AgentData<'a> { .try_normalized() .unwrap_or_else(Vec2::zero) * speed; - controller - .actions - .push(ControlAction::basic_input(InputKind::Primary)); } else { + // Unless cannot see target, then move towards them controller.inputs.move_dir = bearing.xy().try_normalized().unwrap_or_else(Vec2::zero) * speed; self.jump_if(controller, bearing.z > 1.5); controller.inputs.move_z = bearing.z; } } + // Sometimes try to roll if self.body.map(|b| b.is_humanoid()).unwrap_or(false) && attack_data.dist_sqrd < 16.0f32.powi(2) - && thread_rng().gen::() < 0.02 + && thread_rng().gen::() < 0.01 { controller .actions .push(ControlAction::basic_input(InputKind::Roll)); } } else { + // If too far, move towards target self.path_toward_target(agent, controller, tgt_data, read_data, false, false, None); } }