mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Initial AI for gnarling logger/mugger.
This commit is contained in:
parent
e93e7fd21c
commit
e1f164d099
@ -63,14 +63,15 @@
|
||||
secondary: "common.abilities.hammersimple.doublestrike",
|
||||
abilities: [],
|
||||
),
|
||||
Custom("Axe Simple"): (
|
||||
primary: "common.abilities.axesimple.doublestrike",
|
||||
secondary: "common.abilities.axesimple.doublestrike",
|
||||
// TODO: Later investigate if we want to make this back to a simple axe when more things need a simpler axe ability set
|
||||
Custom("Gnarling Axe"): (
|
||||
primary: "common.abilities.gnarling.axe.chop",
|
||||
secondary: "common.abilities.gnarling.axe.chop",
|
||||
abilities: [],
|
||||
),
|
||||
Custom("Dagger Simple"): (
|
||||
primary: "common.abilities.daggersimple.singlestrike",
|
||||
secondary: "common.abilities.daggersimple.singlestrike",
|
||||
Custom("Gnarling Dagger"): (
|
||||
primary: "common.abilities.gnarling.dagger.stab",
|
||||
secondary: "common.abilities.gnarling.dagger.stab",
|
||||
abilities: [],
|
||||
),
|
||||
Custom("Sword Simple"): (
|
||||
|
@ -1,56 +0,0 @@
|
||||
ComboMelee(
|
||||
stage_data: [
|
||||
(
|
||||
stage: 1,
|
||||
base_damage: 8.0,
|
||||
damage_increase: 1.0,
|
||||
base_poise_damage: 15,
|
||||
poise_damage_increase: 0,
|
||||
knockback: 8.0,
|
||||
range: 3.5,
|
||||
angle: 50.0,
|
||||
base_buildup_duration: 0.4,
|
||||
base_swing_duration: 0.08,
|
||||
hit_timing: 0.5,
|
||||
base_recover_duration: 0.5,
|
||||
forward_movement: 2.5,
|
||||
damage_kind: Slashing,
|
||||
damage_effect: Some(Buff((
|
||||
kind: Bleeding,
|
||||
dur_secs: 10.0,
|
||||
strength: DamageFraction(0.1),
|
||||
chance: 0.1,
|
||||
))),
|
||||
),
|
||||
(
|
||||
stage: 2,
|
||||
base_damage: 10.0,
|
||||
damage_increase: 1.5,
|
||||
base_poise_damage: 20,
|
||||
poise_damage_increase: 0,
|
||||
knockback: 12.0,
|
||||
range: 3.5,
|
||||
angle: 30.0,
|
||||
base_buildup_duration: 0.7,
|
||||
base_swing_duration: 0.1,
|
||||
hit_timing: 0.5,
|
||||
base_recover_duration: 0.7,
|
||||
forward_movement: 2.0,
|
||||
damage_kind: Slashing,
|
||||
damage_effect: Some(Buff((
|
||||
kind: Bleeding,
|
||||
dur_secs: 10.0,
|
||||
strength: DamageFraction(0.1),
|
||||
chance: 0.1,
|
||||
))),
|
||||
),
|
||||
],
|
||||
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.7,
|
||||
)
|
@ -1,34 +0,0 @@
|
||||
ComboMelee(
|
||||
stage_data: [
|
||||
(
|
||||
stage: 1,
|
||||
base_damage: 2.0,
|
||||
damage_increase: 1.0,
|
||||
base_poise_damage: 8,
|
||||
poise_damage_increase: 0,
|
||||
knockback: 8.0,
|
||||
range: 3.5,
|
||||
angle: 50.0,
|
||||
base_buildup_duration: 0.1,
|
||||
base_swing_duration: 0.05,
|
||||
hit_timing: 0.5,
|
||||
base_recover_duration: 0.05,
|
||||
forward_movement: 1.0,
|
||||
damage_kind: Slashing,
|
||||
damage_effect: Some(Buff((
|
||||
kind: Bleeding,
|
||||
dur_secs: 10.0,
|
||||
strength: DamageFraction(0.1),
|
||||
chance: 0.1,
|
||||
))),
|
||||
),
|
||||
],
|
||||
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.7,
|
||||
)
|
18
assets/common/abilities/gnarling/axe/chop.ron
Normal file
18
assets/common/abilities/gnarling/axe/chop.ron
Normal file
@ -0,0 +1,18 @@
|
||||
BasicMelee(
|
||||
energy_cost: 0,
|
||||
buildup_duration: 0.2,
|
||||
swing_duration: 0.05,
|
||||
recover_duration: 0.3,
|
||||
base_damage: 6,
|
||||
base_poise_damage: 5,
|
||||
knockback: ( strength: 0, direction: Away),
|
||||
range: 3,
|
||||
max_angle: 30,
|
||||
damage_effect: Some(Buff((
|
||||
kind: Bleeding,
|
||||
dur_secs: 10,
|
||||
strength: DamageFraction(0.1),
|
||||
chance: 0.1,
|
||||
))),
|
||||
damage_kind: Slashing,
|
||||
)
|
18
assets/common/abilities/gnarling/dagger/stab.ron
Normal file
18
assets/common/abilities/gnarling/dagger/stab.ron
Normal file
@ -0,0 +1,18 @@
|
||||
BasicMelee(
|
||||
energy_cost: 0,
|
||||
buildup_duration: 0.1,
|
||||
swing_duration: 0.05,
|
||||
recover_duration: 0.25,
|
||||
base_damage: 4,
|
||||
base_poise_damage: 0,
|
||||
knockback: ( strength: 0, direction: Away),
|
||||
range: 2,
|
||||
max_angle: 15,
|
||||
damage_effect: Some(Buff((
|
||||
kind: Bleeding,
|
||||
dur_secs: 10,
|
||||
strength: DamageFraction(0.2),
|
||||
chance: 0.3,
|
||||
))),
|
||||
damage_kind: Piercing,
|
||||
)
|
@ -3,10 +3,10 @@
|
||||
body: RandomWith("gnarling"),
|
||||
alignment: Alignment(Enemy),
|
||||
loadout: Extended(
|
||||
hands: TwoHanded(Item("common.items.npc_weapons.biped_small.gnarling.chieftain")),
|
||||
base_asset: Loadout("common.loadout.dungeon.tier-0.gnarling_chieftain"),
|
||||
hands: TwoHanded(Item("common.items.npc_weapons.biped_small.gnarling.chieftain_staff")),
|
||||
base_asset: Loadout("common.loadout.dungeon.gnarling.chieftain"),
|
||||
inventory: [],
|
||||
),
|
||||
loot: LootTable("common.loot_tables.dungeon.tier-0.enemy"),
|
||||
meta: [],
|
||||
)
|
||||
)
|
||||
|
@ -3,10 +3,10 @@
|
||||
body: RandomWith("gnarling"),
|
||||
alignment: Alignment(Enemy),
|
||||
loadout: Extended(
|
||||
hands: TwoHanded(Item("common.items.npc_weapons.biped_small.gnarling.logger")),
|
||||
base_asset: Loadout("common.loadout.dungeon.tier-0.logger"),
|
||||
hands: TwoHanded(Item("common.items.npc_weapons.biped_small.gnarling.axe")),
|
||||
base_asset: Loadout("common.loadout.dungeon.gnarling.logger"),
|
||||
inventory: [],
|
||||
),
|
||||
loot: LootTable("common.loot_tables.dungeon.tier-0.enemy"),
|
||||
meta: [],
|
||||
)
|
||||
)
|
||||
|
@ -3,10 +3,10 @@
|
||||
body: RandomWith("gnarling"),
|
||||
alignment: Alignment(Enemy),
|
||||
loadout: Extended(
|
||||
hands: TwoHanded(Item("common.items.npc_weapons.biped_small.gnarling.mugger")),
|
||||
base_asset: Loadout("common.loadout.dungeon.tier-0.mugger"),
|
||||
hands: TwoHanded(Item("common.items.npc_weapons.biped_small.gnarling.dagger")),
|
||||
base_asset: Loadout("common.loadout.dungeon.gnarling.mugger"),
|
||||
inventory: [],
|
||||
),
|
||||
loot: LootTable("common.loot_tables.dungeon.tier-0.enemy"),
|
||||
meta: [],
|
||||
)
|
||||
)
|
||||
|
@ -3,10 +3,10 @@
|
||||
body: RandomWith("gnarling"),
|
||||
alignment: Alignment(Enemy),
|
||||
loadout: Extended(
|
||||
hands: TwoHanded(Item("common.items.npc_weapons.biped_small.gnarling.stalker")),
|
||||
base_asset: Loadout("common.loadout.dungeon.tier-0.stalker"),
|
||||
hands: TwoHanded(Item("common.items.npc_weapons.biped_small.gnarling.blowgun")),
|
||||
base_asset: Loadout("common.loadout.dungeon.gnarling.stalker"),
|
||||
inventory: [],
|
||||
),
|
||||
loot: LootTable("common.loot_tables.dungeon.tier-0.enemy"),
|
||||
meta: [],
|
||||
)
|
||||
)
|
||||
|
@ -6,10 +6,10 @@ ItemDef(
|
||||
hands: Two,
|
||||
stats: Direct((
|
||||
equip_time_secs: 0.0,
|
||||
power: 0.3,
|
||||
power: 1.0,
|
||||
effect_power: 1.0,
|
||||
speed: 1.0,
|
||||
crit_chance: 0.12037037,
|
||||
crit_chance: 0.1,
|
||||
range: 1.0,
|
||||
energy_efficiency: 1.0,
|
||||
buff_strength: 1.0,
|
||||
@ -17,5 +17,6 @@ ItemDef(
|
||||
)),
|
||||
quality: Low,
|
||||
tags: [],
|
||||
ability_spec: Some(Custom("Axe Simple")),
|
||||
// TODO: Later investigate if we want to make this back to a simple axe when more things need a simpler axe ability set
|
||||
ability_spec: Some(Custom("Gnarling Axe")),
|
||||
)
|
@ -17,5 +17,6 @@ ItemDef(
|
||||
)),
|
||||
quality: Low,
|
||||
tags: [],
|
||||
ability_spec: Some(Custom("Dagger Simple")),
|
||||
// TODO: Later investigate if we want to make this back to a simple dagger when more things need a simpler dagger ability set
|
||||
ability_spec: Some(Custom("Gnarling Dagger")),
|
||||
)
|
@ -1703,7 +1703,7 @@ impl<'a> AgentData<'a> {
|
||||
if let Some(ability_spec) = item.ability_spec() {
|
||||
match ability_spec {
|
||||
AbilitySpec::Custom(spec) => match spec.as_str() {
|
||||
"Axe Simple" | "Oni" | "Sword Simple" => Tactic::Sword,
|
||||
"Oni" | "Sword Simple" => Tactic::Sword,
|
||||
"Staff Simple" => Tactic::Staff,
|
||||
"Bow Simple" => Tactic::Bow,
|
||||
"Stone Golem" => Tactic::StoneGolem,
|
||||
@ -1745,6 +1745,7 @@ impl<'a> AgentData<'a> {
|
||||
"Tidal Totem" => Tactic::RadialTurret,
|
||||
"Yeti" => Tactic::Yeti,
|
||||
"Harvester" => Tactic::Harvester,
|
||||
"Gnarling Dagger" => Tactic::Backstab,
|
||||
_ => Tactic::Melee,
|
||||
},
|
||||
AbilitySpec::Tool(tool_kind) => tool_tactic(*tool_kind),
|
||||
@ -2110,6 +2111,14 @@ 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,
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -19,6 +19,8 @@ use std::{f32::consts::PI, time::Duration};
|
||||
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(
|
||||
&self,
|
||||
agent: &mut Agent,
|
||||
@ -28,7 +30,7 @@ impl<'a> AgentData<'a> {
|
||||
read_data: &ReadData,
|
||||
rng: &mut impl Rng,
|
||||
) {
|
||||
if attack_data.in_min_range() && attack_data.angle < 45.0 {
|
||||
if attack_data.in_min_range() && attack_data.angle < 30.0 {
|
||||
controller.push_basic_input(InputKind::Primary);
|
||||
controller.inputs.move_dir = Vec2::zero();
|
||||
} else if attack_data.dist_sqrd < MAX_PATH_DIST.powi(2) {
|
||||
@ -45,6 +47,62 @@ 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(
|
||||
&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 {
|
||||
controller.push_basic_input(InputKind::Primary);
|
||||
controller.inputs.move_dir = Vec2::zero();
|
||||
}
|
||||
|
||||
// Handle movement of agent
|
||||
let target_ori = agent
|
||||
.target
|
||||
.and_then(|t| read_data.orientations.get(t.target))
|
||||
.map(|ori| ori.look_vec())
|
||||
.unwrap_or_default();
|
||||
let vec_to_target = (tgt_data.pos.0 - self.pos.0).xy();
|
||||
let in_front_of_target = target_ori.dot(self.pos.0 - tgt_data.pos.0) > 0.0;
|
||||
if attack_data.dist_sqrd < MAX_PATH_DIST.powi(2) {
|
||||
// If in front of the target, circle to try and get behind, else just make a
|
||||
// beeline for the back of the agent
|
||||
if in_front_of_target {
|
||||
// Checks both CW and CCW rotation
|
||||
let potential_move_dirs = [
|
||||
vec_to_target
|
||||
.rotated_z(PI / 2.)
|
||||
.try_normalized()
|
||||
.unwrap_or_default(),
|
||||
vec_to_target
|
||||
.rotated_z(-PI / 2.)
|
||||
.try_normalized()
|
||||
.unwrap_or_default(),
|
||||
];
|
||||
// Finds shortest path to get behind
|
||||
if let Some(move_dir) = potential_move_dirs
|
||||
.iter()
|
||||
.find(|move_dir| target_ori.xy().dot(**move_dir) < 0.0)
|
||||
{
|
||||
controller.inputs.move_dir = *move_dir;
|
||||
}
|
||||
} else {
|
||||
controller.inputs.move_dir = vec_to_target.try_normalized().unwrap_or_default();
|
||||
}
|
||||
} else {
|
||||
self.path_toward_target(agent, controller, tgt_data, read_data, false, true, None);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn handle_axe_attack(
|
||||
&self,
|
||||
agent: &mut Agent,
|
||||
|
@ -103,6 +103,7 @@ pub enum Tactic {
|
||||
Yeti,
|
||||
Tornado,
|
||||
Harvester,
|
||||
Backstab,
|
||||
}
|
||||
|
||||
#[derive(SystemData)]
|
||||
|
@ -3182,6 +3182,38 @@ impl FigureMgr {
|
||||
),
|
||||
}
|
||||
},
|
||||
CharacterState::BasicMelee(s) => {
|
||||
let stage_time = s.timer.as_secs_f32();
|
||||
let stage_progress = match s.stage_section {
|
||||
StageSection::Buildup => {
|
||||
stage_time / s.static_data.buildup_duration.as_secs_f32()
|
||||
},
|
||||
StageSection::Action => {
|
||||
stage_time / s.static_data.swing_duration.as_secs_f32()
|
||||
},
|
||||
StageSection::Recover => {
|
||||
stage_time / s.static_data.recover_duration.as_secs_f32()
|
||||
},
|
||||
_ => 0.0,
|
||||
};
|
||||
anim::biped_small::AlphaAnimation::update_skeleton(
|
||||
&target_base,
|
||||
(
|
||||
active_tool_kind,
|
||||
rel_vel,
|
||||
ori * anim::vek::Vec3::<f32>::unit_y(),
|
||||
state.last_ori * anim::vek::Vec3::<f32>::unit_y(),
|
||||
time,
|
||||
rel_avg_vel,
|
||||
state.acc_vel,
|
||||
Some(s.stage_section),
|
||||
state.state_time,
|
||||
),
|
||||
stage_progress,
|
||||
&mut state_animation_rate,
|
||||
skeleton_attr,
|
||||
)
|
||||
},
|
||||
// TODO!
|
||||
_ => target_base,
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user