mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Bat AI
This commit is contained in:
parent
586d0f6dd8
commit
6bacb487f3
@ -121,6 +121,11 @@
|
||||
(None, "common.abilities.custom.woodgolem.shockwave")
|
||||
],
|
||||
),
|
||||
Custom("Simple Flying Melee"): (
|
||||
primary: "common.abilities.custom.simpleflyingmelee.singlestrike",
|
||||
secondary: "common.abilities.custom.simpleflyingmelee.singlestrike",
|
||||
abilities: [],
|
||||
),
|
||||
Custom("Sword Simple"): (
|
||||
primary: "common.abilities.swordsimple.doublestrike",
|
||||
secondary: "common.abilities.swordsimple.dash",
|
||||
|
@ -0,0 +1,28 @@
|
||||
ComboMelee(
|
||||
stage_data: [
|
||||
(
|
||||
stage: 1,
|
||||
base_damage: 4.0,
|
||||
damage_increase: 0,
|
||||
base_poise_damage: 0,
|
||||
poise_damage_increase: 0,
|
||||
knockback: 0.0,
|
||||
range: 2.5,
|
||||
angle: 150.0,
|
||||
base_buildup_duration: 0.1,
|
||||
base_swing_duration: 0.07,
|
||||
hit_timing: 0.5,
|
||||
base_recover_duration: 0.2,
|
||||
forward_movement: 0.0,
|
||||
damage_kind: Piercing,
|
||||
),
|
||||
],
|
||||
initial_energy_gain: 0,
|
||||
max_energy_gain: 0,
|
||||
energy_increase: 0,
|
||||
speed_increase: 0.0,
|
||||
max_speed_increase: 0.0,
|
||||
scales_from_combo: 0,
|
||||
is_interruptible: false,
|
||||
ori_modifier: 0.6,
|
||||
)
|
21
assets/common/items/npc_weapons/unique/simpleflyingbasic.ron
Normal file
21
assets/common/items/npc_weapons/unique/simpleflyingbasic.ron
Normal file
@ -0,0 +1,21 @@
|
||||
ItemDef(
|
||||
name: "Simple Flying Melee",
|
||||
description: "I believe I can fly!!!!!",
|
||||
kind: Tool((
|
||||
kind: Natural,
|
||||
hands: Two,
|
||||
stats: (
|
||||
equip_time_secs: 0.01,
|
||||
power: 1.0,
|
||||
effect_power: 1.0,
|
||||
speed: 1.0,
|
||||
crit_chance: 0.0625,
|
||||
range: 1.0,
|
||||
energy_efficiency: 1.0,
|
||||
buff_strength: 1.0,
|
||||
),
|
||||
)),
|
||||
quality: Low,
|
||||
tags: [],
|
||||
ability_spec: Some(Custom("Simple Flying Melee")),
|
||||
)
|
@ -289,6 +289,7 @@ impl<'a> From<&'a Body> for Psyche {
|
||||
bird_medium::Species::Peacock => 0.4,
|
||||
bird_medium::Species::Eagle => 0.3,
|
||||
bird_medium::Species::Parrot => 0.8,
|
||||
bird_medium::Species::Bat => 0.0,
|
||||
_ => 0.5,
|
||||
},
|
||||
Body::BirdLarge(_) => 0.1,
|
||||
|
@ -27,7 +27,7 @@ use specs::{Component, DerefFlaggedStorage};
|
||||
use strum::Display;
|
||||
use vek::*;
|
||||
|
||||
use super::{BuffKind, Collider, Density, Mass};
|
||||
use super::{BuffKind, Collider, Density, Mass, Scale};
|
||||
|
||||
make_case_elim!(
|
||||
body,
|
||||
@ -231,6 +231,17 @@ impl Body {
|
||||
)
|
||||
}
|
||||
|
||||
pub fn scale(&self) -> Scale {
|
||||
let s = match self {
|
||||
Body::BirdMedium(bird_medium) => match bird_medium.species {
|
||||
bird_medium::Species::Bat => 0.5,
|
||||
_ => 1.0,
|
||||
},
|
||||
_ => 1.0,
|
||||
};
|
||||
Scale(s)
|
||||
}
|
||||
|
||||
/// Average density of the body
|
||||
// Units are based on kg/m³
|
||||
pub fn density(&self) -> Density {
|
||||
|
@ -1,7 +1,7 @@
|
||||
use crate::{
|
||||
assets::{self, AssetExt},
|
||||
comp::{
|
||||
arthropod, biped_large, biped_small, bird_large, golem,
|
||||
arthropod, biped_large, biped_small, bird_large, bird_medium, golem,
|
||||
inventory::{
|
||||
loadout::Loadout,
|
||||
slot::{ArmorSlot, EquipSlot},
|
||||
@ -778,6 +778,12 @@ fn default_main_tool(body: &Body) -> Item {
|
||||
"common.items.npc_weapons.unique.birdlargebasic",
|
||||
)),
|
||||
},
|
||||
Body::BirdMedium(bird_medium) => match bird_medium.species {
|
||||
bird_medium::Species::Bat => Some(Item::new_from_asset_expect(
|
||||
"common.items.npc_weapons.unique.simpleflyingbasic",
|
||||
)),
|
||||
_ => None,
|
||||
},
|
||||
_ => None,
|
||||
};
|
||||
|
||||
|
@ -322,6 +322,44 @@ impl<'a> AgentData<'a> {
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Bats should fly
|
||||
// Use a proportional controller as the bouncing effect mimics bat flight
|
||||
if self.traversal_config.can_fly
|
||||
&& self
|
||||
.inventory
|
||||
.equipped(EquipSlot::ActiveMainhand)
|
||||
.as_ref()
|
||||
.map_or(false, |item| {
|
||||
item.ability_spec().map_or(false, |a_s| match &*a_s {
|
||||
AbilitySpec::Custom(spec) => match spec.as_str() {
|
||||
"Simple Flying Melee" => true,
|
||||
_ => false,
|
||||
},
|
||||
_ => false,
|
||||
})
|
||||
})
|
||||
{
|
||||
// Bats don't like the ground, so make sure they are always flying
|
||||
controller.push_basic_input(InputKind::Fly);
|
||||
if read_data
|
||||
.terrain
|
||||
.ray(self.pos.0, self.pos.0 - (Vec3::unit_z() * 5.0))
|
||||
.until(Block::is_solid)
|
||||
.cast()
|
||||
.1
|
||||
.map_or(true, |b| b.is_some())
|
||||
{
|
||||
// Fly up
|
||||
controller.inputs.move_z = 1.0;
|
||||
// If on the ground, jump
|
||||
if self.physics_state.on_ground.is_some() {
|
||||
controller.push_basic_input(InputKind::Jump);
|
||||
}
|
||||
} else {
|
||||
// Fly down
|
||||
controller.inputs.move_z = -1.0;
|
||||
}
|
||||
}
|
||||
agent.bearing += Vec2::new(rng.gen::<f32>() - 0.5, rng.gen::<f32>() - 0.5) * 0.1
|
||||
- agent.bearing * 0.003
|
||||
- agent.patrol_origin.map_or(Vec2::zero(), |patrol_origin| {
|
||||
@ -768,6 +806,7 @@ impl<'a> AgentData<'a> {
|
||||
AbilitySpec::Custom(spec) => match spec.as_str() {
|
||||
"Oni" | "Sword Simple" => Tactic::Sword,
|
||||
"Staff Simple" => Tactic::Staff,
|
||||
"Simple Flying Melee" => Tactic::SimpleFlyingMelee,
|
||||
"Bow Simple" => Tactic::Bow,
|
||||
"Stone Golem" => Tactic::StoneGolem,
|
||||
"Quad Med Quick" => Tactic::CircleCharge {
|
||||
@ -1000,6 +1039,14 @@ impl<'a> AgentData<'a> {
|
||||
// Match on tactic. Each tactic has different controls depending on the distance
|
||||
// from the agent to the target.
|
||||
match tactic {
|
||||
Tactic::SimpleFlyingMelee => self.handle_simple_flying_melee(
|
||||
agent,
|
||||
controller,
|
||||
&attack_data,
|
||||
tgt_data,
|
||||
read_data,
|
||||
rng,
|
||||
),
|
||||
Tactic::SimpleMelee => {
|
||||
self.handle_simple_melee(agent, controller, &attack_data, tgt_data, read_data, rng)
|
||||
},
|
||||
|
@ -53,6 +53,64 @@ 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 fly around
|
||||
pub fn handle_simple_flying_melee(
|
||||
&self,
|
||||
agent: &mut Agent,
|
||||
controller: &mut Controller,
|
||||
attack_data: &AttackData,
|
||||
tgt_data: &TargetData,
|
||||
read_data: &ReadData,
|
||||
rng: &mut impl Rng,
|
||||
) {
|
||||
// Fly to target
|
||||
let dir_to_target = ((tgt_data.pos.0 + Vec3::unit_z() * 1.5) - self.pos.0)
|
||||
.try_normalized()
|
||||
.unwrap_or_else(Vec3::zero);
|
||||
let speed = 1.0;
|
||||
controller.inputs.move_dir = dir_to_target.xy() * speed;
|
||||
|
||||
// Always fly! If the floor can't touch you, it can't hurt you...
|
||||
controller.push_basic_input(InputKind::Fly);
|
||||
// Flee from the ground! The internet told me it was lava!
|
||||
// If on the ground, jump with every last ounce of energy, holding onto all that
|
||||
// is dear in life and straining for the wide open skies.
|
||||
if self.physics_state.on_ground.is_some() {
|
||||
controller.push_basic_input(InputKind::Jump);
|
||||
} else {
|
||||
// Only fly down if close enough to target in the xy plane
|
||||
// Otherwise fly towards the target bouncing around a 5 block altitude
|
||||
let mut maintain_altitude = |altitude| {
|
||||
if read_data
|
||||
.terrain
|
||||
.ray(self.pos.0, self.pos.0 - (Vec3::unit_z() * altitude))
|
||||
.until(Block::is_solid)
|
||||
.cast()
|
||||
.1
|
||||
.map_or(true, |b| b.is_some())
|
||||
{
|
||||
// Fly up
|
||||
controller.inputs.move_z = 1.0;
|
||||
} else {
|
||||
// Fly down
|
||||
controller.inputs.move_z = -1.0;
|
||||
}
|
||||
};
|
||||
if (tgt_data.pos.0 - self.pos.0).xy().magnitude_squared() > (5.0_f32).powi(2) {
|
||||
// If above 5 blocks, fly down
|
||||
maintain_altitude(5.0);
|
||||
} else {
|
||||
maintain_altitude(2.0);
|
||||
|
||||
// Attack if in range
|
||||
if attack_data.dist_sqrd < 3.5_f32.powi(2) && attack_data.angle < 150.0 {
|
||||
controller.push_basic_input(InputKind::Primary);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 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
|
||||
|
@ -74,6 +74,7 @@ impl AttackData {
|
||||
pub enum Tactic {
|
||||
// General tactics
|
||||
SimpleMelee,
|
||||
SimpleFlyingMelee,
|
||||
SimpleBackstab,
|
||||
ElevatedRanged,
|
||||
Turret,
|
||||
|
@ -1212,6 +1212,7 @@ fn handle_spawn(
|
||||
body,
|
||||
)
|
||||
.with(comp::Vel(vel))
|
||||
.with(body.scale())
|
||||
.with(alignment);
|
||||
|
||||
if ai {
|
||||
|
Loading…
Reference in New Issue
Block a user