Initial AI for gnarling logger/mugger.

This commit is contained in:
Sam 2022-01-19 20:15:50 -05:00
parent e93e7fd21c
commit e1f164d099
19 changed files with 163 additions and 114 deletions

View File

@ -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"): (

View File

@ -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,
)

View File

@ -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,
)

View 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,
)

View 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,
)

View File

@ -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: [],
)
)

View File

@ -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: [],
)
)

View File

@ -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: [],
)
)

View File

@ -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: [],
)
)

View File

@ -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")),
)

View File

@ -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")),
)

View File

@ -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,
),
}
}

View File

@ -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,

View File

@ -103,6 +103,7 @@ pub enum Tactic {
Yeti,
Tornado,
Harvester,
Backstab,
}
#[derive(SystemData)]

View File

@ -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,
};