mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Gnarling stalker AI
This commit is contained in:
parent
c15fb2b68f
commit
40bb74c42f
@ -74,6 +74,11 @@
|
||||
secondary: "common.abilities.gnarling.dagger.stab",
|
||||
abilities: [],
|
||||
),
|
||||
Custom("Gnarling Blowgun"): (
|
||||
primary: "common.abilities.gnarling.blowgun.dart",
|
||||
secondary: "common.abilities.gnarling.blowgun.dart",
|
||||
abilities: [],
|
||||
),
|
||||
Custom("Sword Simple"): (
|
||||
primary: "common.abilities.swordsimple.doublestrike",
|
||||
secondary: "common.abilities.swordsimple.dash",
|
||||
@ -90,12 +95,6 @@
|
||||
abilities: [
|
||||
],
|
||||
),
|
||||
Tool(Blowgun): (
|
||||
primary: "common.abilities.blowgun.basic",
|
||||
secondary: "common.abilities.blowgun.basic",
|
||||
abilities: [
|
||||
],
|
||||
),
|
||||
Tool(Dagger): (
|
||||
primary: "common.abilities.dagger.tempbasic",
|
||||
secondary: "common.abilities.dagger.tempbasic",
|
||||
|
@ -3,13 +3,13 @@ BasicRanged(
|
||||
buildup_duration: 0.5,
|
||||
recover_duration: 0.3,
|
||||
projectile: Arrow(
|
||||
damage: 3.5,
|
||||
knockback: 5.0,
|
||||
energy_regen: 4.0,
|
||||
damage: 4,
|
||||
knockback: 0,
|
||||
energy_regen: 0,
|
||||
),
|
||||
projectile_body: Object(Arrow),
|
||||
projectile_light: None,
|
||||
projectile_speed: 100.0,
|
||||
projectile_speed: 80.0,
|
||||
num_projectiles: 1,
|
||||
projectile_spread: 0.0,
|
||||
)
|
@ -17,5 +17,5 @@ ItemDef(
|
||||
)),
|
||||
quality: Low,
|
||||
tags: [],
|
||||
ability_spec: None,
|
||||
ability_spec: Some(Custom("Gnarling Blowgun")),
|
||||
)
|
@ -1692,7 +1692,7 @@ impl<'a> AgentData<'a> {
|
||||
ToolKind::Hammer => Tactic::Hammer,
|
||||
ToolKind::Sword | ToolKind::Spear | ToolKind::Blowgun => Tactic::Sword,
|
||||
ToolKind::Axe => Tactic::Axe,
|
||||
_ => Tactic::Melee,
|
||||
_ => Tactic::SimpleMelee,
|
||||
};
|
||||
|
||||
let tactic = self
|
||||
@ -1742,21 +1742,22 @@ impl<'a> AgentData<'a> {
|
||||
"Minotaur" => Tactic::Minotaur,
|
||||
"Clay Golem" => Tactic::ClayGolem,
|
||||
"Tidal Warrior" => Tactic::TidalWarrior,
|
||||
"Tidal Totem" => Tactic::RadialTurret,
|
||||
"Tidal Totem" | "Tornado" => Tactic::RadialTurret,
|
||||
"Yeti" => Tactic::Yeti,
|
||||
"Harvester" => Tactic::Harvester,
|
||||
"Gnarling Dagger" => Tactic::Backstab,
|
||||
_ => Tactic::Melee,
|
||||
"Gnarling Dagger" => Tactic::SimpleBackstab,
|
||||
"Gnarling Blowgun" => Tactic::ElevatedRanged,
|
||||
_ => Tactic::SimpleMelee,
|
||||
},
|
||||
AbilitySpec::Tool(tool_kind) => tool_tactic(*tool_kind),
|
||||
}
|
||||
} else if let ItemKind::Tool(tool) = &item.kind() {
|
||||
tool_tactic(tool.kind)
|
||||
} else {
|
||||
Tactic::Melee
|
||||
Tactic::SimpleMelee
|
||||
}
|
||||
})
|
||||
.unwrap_or(Tactic::Melee);
|
||||
.unwrap_or(Tactic::SimpleMelee);
|
||||
|
||||
// Wield the weapon as running towards the target
|
||||
controller.push_action(ControlAction::Wield);
|
||||
@ -1770,6 +1771,12 @@ impl<'a> AgentData<'a> {
|
||||
.look_vec()
|
||||
.angle_between(tgt_data.pos.0 - self.pos.0)
|
||||
.to_degrees();
|
||||
let angle_xy = self
|
||||
.ori
|
||||
.look_vec()
|
||||
.xy()
|
||||
.angle_between((tgt_data.pos.0 - self.pos.0).xy())
|
||||
.to_degrees();
|
||||
|
||||
let eye_offset = self.body.map_or(0.0, |b| b.eye_height());
|
||||
|
||||
@ -1911,13 +1918,14 @@ impl<'a> AgentData<'a> {
|
||||
min_attack_dist,
|
||||
dist_sqrd,
|
||||
angle,
|
||||
angle_xy,
|
||||
};
|
||||
|
||||
// Match on tactic. Each tactic has different controls
|
||||
// depending on the distance from the agent to the target
|
||||
match tactic {
|
||||
Tactic::Melee => {
|
||||
self.handle_melee_attack(agent, controller, &attack_data, tgt_data, read_data, rng)
|
||||
Tactic::SimpleMelee => {
|
||||
self.handle_simple_melee(agent, controller, &attack_data, tgt_data, read_data, rng)
|
||||
},
|
||||
Tactic::Axe => {
|
||||
self.handle_axe_attack(agent, controller, &attack_data, tgt_data, read_data, rng)
|
||||
@ -2052,7 +2060,6 @@ impl<'a> AgentData<'a> {
|
||||
tgt_data,
|
||||
read_data,
|
||||
),
|
||||
Tactic::Tornado => self.handle_tornado_attack(controller),
|
||||
Tactic::Mindflayer => self.handle_mindflayer_attack(
|
||||
agent,
|
||||
controller,
|
||||
@ -2111,14 +2118,12 @@ impl<'a> AgentData<'a> {
|
||||
Tactic::Harvester => {
|
||||
self.handle_harvester_attack(agent, controller, &attack_data, tgt_data, read_data)
|
||||
},
|
||||
Tactic::Backstab => self.handle_backstab_attack(
|
||||
agent,
|
||||
controller,
|
||||
&attack_data,
|
||||
tgt_data,
|
||||
read_data,
|
||||
rng,
|
||||
),
|
||||
Tactic::SimpleBackstab => {
|
||||
self.handle_simple_backstab(agent, controller, &attack_data, tgt_data, read_data)
|
||||
},
|
||||
Tactic::ElevatedRanged => {
|
||||
self.handle_elevated_ranged(agent, controller, &attack_data, tgt_data, read_data)
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -21,7 +21,7 @@ use vek::*;
|
||||
impl<'a> AgentData<'a> {
|
||||
// Intended for any agent that has one attack, that attack is a melee attack,
|
||||
// and the agent is able to freely walk around
|
||||
pub fn handle_melee_attack(
|
||||
pub fn handle_simple_melee(
|
||||
&self,
|
||||
agent: &mut Agent,
|
||||
controller: &mut Controller,
|
||||
@ -50,14 +50,13 @@ impl<'a> AgentData<'a> {
|
||||
// Intended for any agent that has one attack, that attack is a melee attack,
|
||||
// the agent is able to freely walk around, and the agent is trying to attack
|
||||
// from behind its target
|
||||
pub fn handle_backstab_attack(
|
||||
pub fn handle_simple_backstab(
|
||||
&self,
|
||||
agent: &mut Agent,
|
||||
controller: &mut Controller,
|
||||
attack_data: &AttackData,
|
||||
tgt_data: &TargetData,
|
||||
read_data: &ReadData,
|
||||
rng: &mut impl Rng,
|
||||
) {
|
||||
// Handle attacking of agent
|
||||
if attack_data.in_min_range() && attack_data.angle < 30.0 {
|
||||
@ -111,6 +110,72 @@ impl<'a> AgentData<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn handle_elevated_ranged(
|
||||
&self,
|
||||
agent: &mut Agent,
|
||||
controller: &mut Controller,
|
||||
attack_data: &AttackData,
|
||||
tgt_data: &TargetData,
|
||||
read_data: &ReadData,
|
||||
) {
|
||||
let elevation = self.pos.0.z - tgt_data.pos.0.z;
|
||||
const PREF_DIST: f32 = 30_f32;
|
||||
if attack_data.angle_xy < 30.0
|
||||
&& (elevation > 10.0 || attack_data.dist_sqrd > PREF_DIST.powi(2))
|
||||
&& can_see_tgt(
|
||||
&read_data.terrain,
|
||||
self.pos,
|
||||
tgt_data.pos,
|
||||
attack_data.dist_sqrd,
|
||||
)
|
||||
{
|
||||
controller.push_basic_input(InputKind::Primary);
|
||||
} else if attack_data.dist_sqrd < (PREF_DIST / 2.).powi(2) {
|
||||
// Attempt to move quickly away from target if too close
|
||||
if let Some((bearing, _)) = 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);
|
||||
if !self.char_state.is_attack() {
|
||||
controller.inputs.look_dir = -controller.inputs.look_dir;
|
||||
}
|
||||
}
|
||||
} else if attack_data.dist_sqrd < PREF_DIST.powi(2) {
|
||||
// Attempt to move away from target if too close, while still attacking
|
||||
if let Some((bearing, _)) = 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
|
||||
},
|
||||
) {
|
||||
if can_see_tgt(
|
||||
&read_data.terrain,
|
||||
self.pos,
|
||||
tgt_data.pos,
|
||||
attack_data.dist_sqrd,
|
||||
) {
|
||||
controller.push_basic_input(InputKind::Primary);
|
||||
}
|
||||
controller.inputs.move_dir =
|
||||
-bearing.xy().try_normalized().unwrap_or_else(Vec2::zero);
|
||||
}
|
||||
} else {
|
||||
self.path_toward_target(agent, controller, tgt_data, read_data, false, true, None);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn handle_axe_attack(
|
||||
&self,
|
||||
agent: &mut Agent,
|
||||
@ -1186,10 +1251,6 @@ impl<'a> AgentData<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn handle_tornado_attack(&self, controller: &mut Controller) {
|
||||
controller.push_basic_input(InputKind::Primary);
|
||||
}
|
||||
|
||||
pub fn handle_mindflayer_attack(
|
||||
&self,
|
||||
agent: &mut Agent,
|
||||
|
@ -60,6 +60,7 @@ pub struct AttackData {
|
||||
pub min_attack_dist: f32,
|
||||
pub dist_sqrd: f32,
|
||||
pub angle: f32,
|
||||
pub angle_xy: f32,
|
||||
}
|
||||
|
||||
impl AttackData {
|
||||
@ -67,15 +68,27 @@ impl AttackData {
|
||||
}
|
||||
|
||||
#[derive(Eq, PartialEq)]
|
||||
// When adding a new variant, first decide if it should instead fall under one
|
||||
// of the pre-exisitng tactics
|
||||
pub enum Tactic {
|
||||
Melee,
|
||||
// General tactics
|
||||
SimpleMelee,
|
||||
SimpleBackstab,
|
||||
ElevatedRanged,
|
||||
Turret,
|
||||
FixedTurret,
|
||||
RotatingTurret,
|
||||
RadialTurret,
|
||||
|
||||
// Tool specific tactics
|
||||
Axe,
|
||||
Hammer,
|
||||
Sword,
|
||||
Bow,
|
||||
Staff,
|
||||
Sceptre,
|
||||
StoneGolem,
|
||||
|
||||
// Broad creature tactics
|
||||
CircleCharge { radius: u32, circle_time: u32 },
|
||||
QuadLowRanged,
|
||||
TailSlap,
|
||||
@ -85,11 +98,6 @@ pub enum Tactic {
|
||||
QuadMedJump,
|
||||
QuadMedBasic,
|
||||
Theropod,
|
||||
Turret,
|
||||
FixedTurret,
|
||||
RotatingTurret,
|
||||
RadialTurret,
|
||||
Mindflayer,
|
||||
BirdLargeBreathe,
|
||||
BirdLargeFire,
|
||||
BirdLargeBasic,
|
||||
@ -97,13 +105,15 @@ pub enum Tactic {
|
||||
ArthropodBasic,
|
||||
ArthropodRanged,
|
||||
ArthropodLeap,
|
||||
|
||||
// Specific species tactics
|
||||
Mindflayer,
|
||||
Minotaur,
|
||||
ClayGolem,
|
||||
TidalWarrior,
|
||||
Yeti,
|
||||
Tornado,
|
||||
Harvester,
|
||||
Backstab,
|
||||
StoneGolem,
|
||||
}
|
||||
|
||||
#[derive(SystemData)]
|
||||
|
Loading…
Reference in New Issue
Block a user