Wolf attacks and ai.

initial wolf dash testing

tool.rs

Wolf attack AI
This commit is contained in:
jshipsey 2020-11-10 22:18:45 -05:00 committed by Sam
parent 7774599a19
commit ae06016e9a
8 changed files with 256 additions and 136 deletions

View File

@ -0,0 +1,17 @@
DashMelee(
energy_cost: 0,
base_damage: 30,
max_damage: 40,
base_knockback: 8.0,
max_knockback: 15.0,
range: 2.0,
angle: 45.0,
energy_drain: 0,
forward_speed: 1.5,
buildup_duration: 1200,
charge_duration: 300,
swing_duration: 100,
recover_duration: 500,
infinite_charge: true,
is_interruptible: true,
)

View File

@ -0,0 +1,13 @@
ItemDef(
name: "Generic Quad Med",
description: "testing123",
kind: Tool(
(
kind: Unique(GenericQuadMed),
stats: (
equip_time_millis: 10,
power: 1.00),
)
),
quality: Low,
)

View File

@ -172,4 +172,5 @@ impl Asset for AbilityMap {
pub enum UniqueKind {
StoneGolemFist,
BeastClaws,
GenericQuadMed,
}

View File

@ -1,7 +1,7 @@
use crate::comp::{
biped_large, golem,
item::{tool::AbilityMap, Item, ItemKind},
Body, CharacterAbility, ItemConfig, Loadout,
quadruped_medium, Body, CharacterAbility, ItemConfig, Loadout,
};
use rand::Rng;
@ -103,6 +103,14 @@ impl LoadoutBuilder {
},
_ => {},
},
Body::QuadrupedMedium(quadruped_medium) => match quadruped_medium.species {
quadruped_medium::Species::Wolf => {
main_tool = Some(Item::new_from_asset_expect(
"common.items.npc_weapons.unique.genericquadmed",
));
},
_ => {},
},
Body::BipedLarge(biped_large) => match (biped_large.species, biped_large.body_type)
{
(biped_large::Species::Occultsaurok, _) => {

View File

@ -28,6 +28,7 @@ use specs::{
saveload::{Marker, MarkerAllocator},
Entities, Join, Read, ReadExpect, ReadStorage, System, Write, WriteStorage,
};
use std::f32::consts::PI;
use vek::*;
/// This system will allow NPCs to modify their controller
@ -332,6 +333,7 @@ impl<'a> System<'a> for Sys {
Bow,
Staff,
StoneGolemBoss,
Wolf,
}
let tactic = match loadout.active_item.as_ref().and_then(|ic| {
@ -349,6 +351,7 @@ impl<'a> System<'a> for Sys {
Some(ToolKind::Unique(UniqueKind::StoneGolemFist)) => {
Tactic::StoneGolemBoss
},
Some(ToolKind::Unique(UniqueKind::GenericQuadMed)) => Tactic::Wolf,
_ => Tactic::Melee,
};
@ -439,73 +442,114 @@ impl<'a> System<'a> for Sys {
}
} else if (tactic == Tactic::Staff
&& dist_sqrd < (5.0 * MIN_ATTACK_DIST * scale).powf(2.0))
|| (tactic == Tactic::Wolf
&& dist_sqrd < (3.0 * MIN_ATTACK_DIST * scale).powf(2.0))
|| dist_sqrd < (MIN_ATTACK_DIST * scale).powf(2.0)
{
// Close-range attack
inputs.move_dir = (tgt_pos.0 - pos.0)
.xy()
.try_normalized()
.unwrap_or(Vec2::unit_y())
* 0.1;
controller.actions.push(ControlAction::Wield);
match tactic {
Tactic::Melee | Tactic::StoneGolemBoss => {
inputs.primary.set_state(true)
Tactic::Wolf => {
// Run away from target to get clear
controller.actions.push(ControlAction::Unwield);
inputs.move_dir = (pos.0 - tgt_pos.0)
.xy()
.try_normalized()
.unwrap_or(Vec2::unit_y());
},
Tactic::Hammer => {
if *powerup > 4.0 {
inputs.secondary.set_state(false);
*powerup = 0.0;
} else if *powerup > 2.0 {
inputs.secondary.set_state(true);
*powerup += dt.0;
} else if energy.current() > 700 {
inputs.ability3.set_state(true);
*powerup += dt.0;
} else {
inputs.primary.set_state(true);
*powerup += dt.0;
_ => {
// Close-range attack
inputs.move_dir = (tgt_pos.0 - pos.0)
.xy()
.try_normalized()
.unwrap_or(Vec2::unit_y())
* 0.1;
match tactic {
Tactic::Hammer => {
if *powerup > 4.0 {
inputs.secondary.set_state(false);
*powerup = 0.0;
} else if *powerup > 2.0 {
inputs.secondary.set_state(true);
*powerup += dt.0;
} else if energy.current() > 700 {
inputs.ability3.set_state(true);
*powerup += dt.0;
} else {
inputs.primary.set_state(true);
*powerup += dt.0;
}
},
Tactic::Staff => {
// Kind of arbitrary values, but feel right in game
if energy.current() > 800
&& thread_rng().gen::<f32>() > 0.8
{
inputs.ability3.set_state(true)
} else if energy.current() > 10 {
inputs.secondary.set_state(true)
} else {
inputs.primary.set_state(true)
}
},
Tactic::Sword => {
if *powerup < 2.0 && energy.current() > 500 {
inputs.ability3.set_state(true);
*powerup += dt.0;
} else if *powerup > 2.0 {
*powerup = 0.0;
} else {
inputs.primary.set_state(true);
*powerup += dt.0;
}
},
Tactic::Axe => {
if *powerup > 6.0 {
inputs.secondary.set_state(false);
*powerup = 0.0;
} else if *powerup > 4.0 && energy.current() > 10 {
inputs.secondary.set_state(true);
*powerup += dt.0;
} else {
inputs.primary.set_state(true);
*powerup += dt.0;
}
},
Tactic::Bow => inputs.roll.set_state(true),
_ => inputs.primary.set_state(true),
}
},
Tactic::Staff => {
// Kind of arbitrary values, but feel right in game
if energy.current() > 800 && thread_rng().gen_bool(0.2) {
inputs.ability3.set_state(true)
} else if energy.current() > 10 {
inputs.secondary.set_state(true)
} else {
inputs.primary.set_state(true)
}
},
Tactic::Sword => {
if *powerup < 2.0 && energy.current() > 500 {
inputs.ability3.set_state(true);
*powerup += dt.0;
} else if *powerup > 2.0 {
*powerup = 0.0;
} else {
inputs.primary.set_state(true);
*powerup += dt.0;
}
},
Tactic::Axe => {
if *powerup > 6.0 {
inputs.secondary.set_state(false);
*powerup = 0.0;
} else if *powerup > 4.0 && energy.current() > 100 {
inputs.secondary.set_state(true);
*powerup += dt.0;
} else if energy.current() > 800
&& thread_rng().gen_bool(0.5)
{
inputs.ability3.set_state(true);
*powerup += dt.0;
} else {
inputs.primary.set_state(true);
*powerup += dt.0;
}
},
Tactic::Bow => inputs.roll.set_state(true),
}
} else if matches!(tactic, Tactic::Wolf)
&& dist_sqrd < (4.0 * MIN_ATTACK_DIST * scale).powf(2.0)
&& dist_sqrd > (3.0 * MIN_ATTACK_DIST * scale).powf(2.0)
{
if *powerup < 2.0 {
controller.actions.push(ControlAction::Unwield);
inputs.move_dir = (tgt_pos.0 - pos.0)
.xy()
.rotated_z(0.45 * PI)
.try_normalized()
.unwrap_or(Vec2::unit_y());
*powerup += dt.0;
} else if *powerup < 2.5 {
controller.actions.push(ControlAction::Wield);
inputs.primary.set_state(true);
*powerup += dt.0;
} else if *powerup < 4.5 {
controller.actions.push(ControlAction::Unwield);
inputs.move_dir = (tgt_pos.0 - pos.0)
.xy()
.rotated_z(-0.45 * PI)
.try_normalized()
.unwrap_or(Vec2::unit_y());
*powerup += dt.0;
} else if *powerup < 5.0 {
controller.actions.push(ControlAction::Wield);
inputs.primary.set_state(true);
*powerup += dt.0;
} else {
*powerup = 0.0;
}
} else if dist_sqrd < MAX_CHASE_DIST.powf(2.0)
|| (dist_sqrd < SIGHT_DIST.powf(2.0)

View File

@ -2,12 +2,13 @@ use super::{
super::{vek::*, Animation},
QuadrupedMediumSkeleton, SkeletonAttr,
};
use common::{comp::item::ToolKind, states::utils::StageSection};
use std::f32::consts::PI;
pub struct AlphaAnimation;
impl Animation for AlphaAnimation {
type Dependency = (f32, f64);
type Dependency = (f32, f64, Option<StageSection>);
type Skeleton = QuadrupedMediumSkeleton;
#[cfg(feature = "use-dyn-lib")]
@ -16,81 +17,103 @@ impl Animation for AlphaAnimation {
#[cfg_attr(feature = "be-dyn-lib", export_name = "quadruped_medium_alpha")]
fn update_skeleton_inner(
skeleton: &Self::Skeleton,
(velocity, _global_time): Self::Dependency,
(velocity, _global_time, stage_section): Self::Dependency,
anim_time: f64,
_rate: &mut f32,
s_a: &SkeletonAttr,
) -> Self::Skeleton {
let mut next = (*skeleton).clone();
let speed = (Vec2::<f32>::from(velocity).magnitude()).min(24.0);
let short = (((1.0)
/ (0.1 + 0.9 * ((anim_time as f32 * 4.0 + PI * 2.5).sin()).powf(2.0 as f32)))
.sqrt())
* ((anim_time as f32 * 4.0 + PI * 2.5).sin());
let quick = (((1.0)
/ (0.001 + 0.9999 * ((anim_time as f32 * 4.0 + PI * 0.5).sin()).powf(2.0 as f32)))
.sqrt())
* ((anim_time as f32 * 4.0 + PI * 0.5).sin());
next.head.position = Vec3::new(0.0, s_a.head.0, s_a.head.1);
next.head.orientation =
Quaternion::rotation_y(short * -0.2) * Quaternion::rotation_x(0.1 + short * 0.2);
next.neck.position = Vec3::new(0.0, s_a.neck.0, s_a.neck.1);
next.jaw.position = Vec3::new(0.0, s_a.jaw.0, s_a.jaw.1);
next.jaw.orientation = Quaternion::rotation_x(-0.3 + quick * 0.4);
next.tail.position = Vec3::new(0.0, s_a.tail.0, s_a.tail.1);
next.torso_front.position = Vec3::new(
0.0,
s_a.torso_front.0 + short * 2.8,
s_a.torso_front.1 + short * 1.0,
) * s_a.scaler
/ 11.0;
next.torso_front.orientation = Quaternion::rotation_y(short * -0.1);
next.torso_back.position = Vec3::new(0.0, s_a.torso_back.0, s_a.torso_back.1);
next.torso_back.orientation = Quaternion::rotation_y(short * -0.1);
next.ears.position = Vec3::new(0.0, s_a.ears.0, s_a.ears.1);
if velocity < 1.0 {
next.leg_fl.position = Vec3::new(-s_a.leg_f.0, s_a.leg_f.1, s_a.leg_f.2);
next.leg_fl.orientation =
Quaternion::rotation_x(short * -0.1) * Quaternion::rotation_y(short * 0.15);
next.leg_fr.position = Vec3::new(s_a.leg_f.0, s_a.leg_f.1, s_a.leg_f.2);
next.leg_fr.orientation =
Quaternion::rotation_x(short * 0.3) * Quaternion::rotation_y(short * -0.2);
next.leg_bl.position = Vec3::new(-s_a.leg_b.0, s_a.leg_b.1, s_a.leg_b.2 + 1.0);
next.leg_bl.orientation =
Quaternion::rotation_x(-0.1 + short * -0.2) * Quaternion::rotation_y(short * 0.2);
next.leg_br.position = Vec3::new(s_a.leg_b.0, s_a.leg_b.1, s_a.leg_b.2 + 1.0);
next.leg_br.orientation = Quaternion::rotation_x(-0.1 + short * -0.2)
* Quaternion::rotation_y(0.1 + short * 0.2);
next.foot_fl.position =
Vec3::new(-s_a.feet_f.0, s_a.feet_f.1, s_a.feet_f.2 + short * -0.2);
next.foot_fl.orientation = Quaternion::rotation_x(short * -0.05);
next.foot_fr.position = Vec3::new(s_a.feet_f.0, s_a.feet_f.1, s_a.feet_f.2);
next.foot_fr.orientation =
Quaternion::rotation_x(short * -0.4) * Quaternion::rotation_y(short * 0.15);
next.foot_bl.position =
Vec3::new(-s_a.feet_b.0, s_a.feet_b.1, s_a.feet_b.2 + short * -0.8);
next.foot_bl.orientation =
Quaternion::rotation_x(-0.2 + short * 0.2) * Quaternion::rotation_y(short * 0.15);
next.foot_br.position = Vec3::new(s_a.feet_b.0, s_a.feet_b.1, s_a.feet_b.2);
next.foot_br.orientation =
Quaternion::rotation_x(-0.2 + short * 0.2) * Quaternion::rotation_y(short * 0.15);
} else {
let (movement1, movement2, movement3) = match stage_section {
Some(StageSection::Buildup) => ((anim_time as f32).powf(0.25), 0.0, 0.0),
Some(StageSection::Swing) => (1.0, anim_time as f32, 0.0),
Some(StageSection::Recover) => (0.0, 1.0, (anim_time as f32).powf(4.0)),
_ => (0.0, 0.0, 0.0),
};
if let Some(stage_section) = stage_section {
match stage_section {
StageSection::Buildup | StageSection::Recover | StageSection::Swing => {
let twitch1 = (movement1 * 20.0).sin();
let twitch2 = (movement3 * 5.0).sin();
let twitchmovement = twitch1 + twitch2;
next.head.position = Vec3::new(0.0, s_a.head.0, s_a.head.1);
next.head.orientation =
Quaternion::rotation_x(
(movement1 * 0.4 + movement2 * 0.4) * (1.0 - movement3),
) * Quaternion::rotation_y(twitchmovement * 0.2 * (1.0 - movement3));
next.neck.position = Vec3::new(0.0, s_a.neck.0, s_a.neck.1);
next.neck.orientation =
Quaternion::rotation_x(movement1 * -0.7 * (1.0 - movement3))
* Quaternion::rotation_y(twitchmovement * 0.1);
next.jaw.position = Vec3::new(0.0, s_a.jaw.0, s_a.jaw.1);
next.jaw.orientation = Quaternion::rotation_x(twitchmovement * 0.1);
next.jaw.scale = Vec3::one() * 1.02;
next.tail.position = Vec3::new(0.0, s_a.tail.0, s_a.tail.1);
next.tail.orientation = Quaternion::rotation_z(twitchmovement * 1.0);
next.torso_front.position =
Vec3::new(0.0, s_a.torso_front.0, s_a.torso_front.1) * s_a.scaler / 11.0;
next.torso_front.orientation =
Quaternion::rotation_x(movement1 * 0.2 * (1.0 - movement3))
* Quaternion::rotation_y(twitchmovement * -0.1);
next.torso_back.position = Vec3::new(0.0, s_a.torso_back.0, s_a.torso_back.1);
next.torso_back.orientation =
Quaternion::rotation_x(movement1 * -0.3 * (1.0 - movement3))
* Quaternion::rotation_y(twitchmovement * 0.1);
next.ears.position = Vec3::new(0.0, s_a.ears.0, s_a.ears.1);
next.ears.orientation =
Quaternion::rotation_x(twitchmovement * 0.1 * (1.0 - movement3));
if speed < 0.5 {
next.leg_fl.position = Vec3::new(-s_a.leg_f.0, s_a.leg_f.1, s_a.leg_f.2);
next.leg_fl.orientation =
Quaternion::rotation_x(movement1 * 0.6 * (1.0 - movement3))
* Quaternion::rotation_y(twitchmovement * 0.1);
next.leg_fr.position = Vec3::new(s_a.leg_f.0, s_a.leg_f.1, s_a.leg_f.2);
next.leg_fr.orientation =
Quaternion::rotation_x(movement1 * 0.6 * (1.0 - movement3))
* Quaternion::rotation_y(twitchmovement * 0.1);
next.leg_bl.position = Vec3::new(-s_a.leg_b.0, s_a.leg_b.1, s_a.leg_b.2);
next.leg_bl.orientation =
Quaternion::rotation_x(movement1 * 0.5 * (1.0 - movement3));
next.leg_br.position = Vec3::new(s_a.leg_b.0, s_a.leg_b.1, s_a.leg_b.2);
next.leg_br.orientation =
Quaternion::rotation_x(movement1 * 0.5 * (1.0 - movement3));
next.foot_fl.position =
Vec3::new(-s_a.feet_f.0, s_a.feet_f.1, s_a.feet_f.2);
next.foot_fl.orientation =
Quaternion::rotation_x(movement1 * -0.5 * (1.0 - movement3));
next.foot_fr.position = Vec3::new(s_a.feet_f.0, s_a.feet_f.1, s_a.feet_f.2);
next.foot_fr.orientation =
Quaternion::rotation_x(movement1 * -0.5 * (1.0 - movement3));
next.foot_bl.position =
Vec3::new(-s_a.feet_b.0, s_a.feet_b.1, s_a.feet_b.2);
next.foot_bl.orientation =
Quaternion::rotation_x(movement1 * -1.0 * (1.0 - movement3));
next.foot_br.position = Vec3::new(s_a.feet_b.0, s_a.feet_b.1, s_a.feet_b.2);
next.foot_br.orientation =
Quaternion::rotation_x(movement1 * -1.0 * (1.0 - movement3));
};
},
StageSection::Charge => {
next.jaw.orientation = Quaternion::rotation_x(-1.0);
},
_ => {},
}
}
next
}
}

View File

@ -22,7 +22,7 @@ impl Animation for RunAnimation {
s_a: &SkeletonAttr,
) -> Self::Skeleton {
let mut next = (*skeleton).clone();
let speed = Vec2::<f32>::from(velocity).magnitude();
let speed = (Vec2::<f32>::from(velocity).magnitude()).min(24.0);
*rate = 1.0;
//let increasefreqtest = (((1.0/speed)*3.0).round()).min(5.0);
let lab = 0.72; //0.72
@ -141,7 +141,7 @@ impl Animation for RunAnimation {
) * s_a.scaler
/ 11.0;
next.torso_front.orientation = Quaternion::rotation_x(
(amplitude * (short * -0.13).max(-0.2)) * s_a.spring
((amplitude * (short * -0.13).max(-0.2)) * s_a.spring).min(0.1)
+ x_tilt * (canceler * 6.0).min(1.0),
) * Quaternion::rotation_y(tilt * 0.8)
* Quaternion::rotation_z(tilt * -1.5);

View File

@ -1528,11 +1528,25 @@ impl FigureMgr {
),
};
let target_bones = match &character {
CharacterState::BasicMelee(_) => {
CharacterState::DashMelee(s) => {
let stage_time = s.timer.as_secs_f64();
let stage_progress = match s.stage_section {
StageSection::Buildup => {
stage_time / s.static_data.buildup_duration.as_secs_f64()
},
StageSection::Charge => stage_time,
StageSection::Swing => {
stage_time / s.static_data.swing_duration.as_secs_f64()
},
StageSection::Recover => {
stage_time / s.static_data.recover_duration.as_secs_f64()
},
_ => 0.0,
};
anim::quadruped_medium::AlphaAnimation::update_skeleton(
&target_base,
(vel.0.magnitude(), time),
state.state_time,
(vel.0.magnitude(), time, Some(s.stage_section)),
stage_progress,
&mut state_animation_rate,
skeleton_attr,
)