mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Cleaving stance AI
This commit is contained in:
parent
5358016ba0
commit
df9ef691fd
@ -13,7 +13,7 @@ LeapMelee(
|
|||||||
),
|
),
|
||||||
range: 4.5,
|
range: 4.5,
|
||||||
angle: 30.0,
|
angle: 30.0,
|
||||||
multi_target: true,
|
multi_target: Some(Normal),
|
||||||
),
|
),
|
||||||
forward_leap_strength: 20.0,
|
forward_leap_strength: 20.0,
|
||||||
vertical_leap_strength: 8.0,
|
vertical_leap_strength: 8.0,
|
||||||
|
@ -11,7 +11,7 @@ SpinMelee(
|
|||||||
),
|
),
|
||||||
range: 3.5,
|
range: 3.5,
|
||||||
angle: 360.0,
|
angle: 360.0,
|
||||||
multi_target: true,
|
multi_target: Some(Normal),
|
||||||
),
|
),
|
||||||
energy_cost: 10.0,
|
energy_cost: 10.0,
|
||||||
is_infinite: true,
|
is_infinite: true,
|
||||||
|
@ -13,7 +13,7 @@ LeapMelee(
|
|||||||
),
|
),
|
||||||
range: 4.5,
|
range: 4.5,
|
||||||
angle: 180.0,
|
angle: 180.0,
|
||||||
multi_target: true,
|
multi_target: Some(Normal),
|
||||||
),
|
),
|
||||||
forward_leap_strength: 40.0,
|
forward_leap_strength: 40.0,
|
||||||
vertical_leap_strength: 7.5,
|
vertical_leap_strength: 7.5,
|
||||||
|
@ -12,7 +12,7 @@ BasicMelee(
|
|||||||
),
|
),
|
||||||
range: 4.0,
|
range: 4.0,
|
||||||
angle: 45.0,
|
angle: 45.0,
|
||||||
multi_target: true,
|
multi_target: Some(Normal),
|
||||||
),
|
),
|
||||||
ori_modifier: 1.0,
|
ori_modifier: 1.0,
|
||||||
)
|
)
|
||||||
|
@ -12,7 +12,7 @@ BasicMelee(
|
|||||||
),
|
),
|
||||||
range: 4.0,
|
range: 4.0,
|
||||||
angle: 60.0,
|
angle: 60.0,
|
||||||
multi_target: true,
|
multi_target: Some(Normal),
|
||||||
),
|
),
|
||||||
ori_modifier: 1.0,
|
ori_modifier: 1.0,
|
||||||
)
|
)
|
||||||
|
@ -10,7 +10,7 @@ SpinMelee(
|
|||||||
),
|
),
|
||||||
range: 16.0,
|
range: 16.0,
|
||||||
angle: 360.0,
|
angle: 360.0,
|
||||||
multi_target: true,
|
multi_target: Some(Normal),
|
||||||
),
|
),
|
||||||
energy_cost: 0.0,
|
energy_cost: 0.0,
|
||||||
is_infinite: true,
|
is_infinite: true,
|
||||||
|
@ -21,7 +21,7 @@ DashMelee(
|
|||||||
strength: DamageFraction(0.3),
|
strength: DamageFraction(0.3),
|
||||||
chance: 0.25,
|
chance: 0.25,
|
||||||
))),
|
))),
|
||||||
multi_target: true,
|
multi_target: Some(Normal),
|
||||||
),
|
),
|
||||||
energy_drain: 0,
|
energy_drain: 0,
|
||||||
forward_speed: 5.0,
|
forward_speed: 5.0,
|
||||||
|
@ -16,7 +16,7 @@ ChargedMelee(
|
|||||||
)),
|
)),
|
||||||
range: 5.0,
|
range: 5.0,
|
||||||
angle: 45.0,
|
angle: 45.0,
|
||||||
multi_target: true,
|
multi_target: Some(Normal),
|
||||||
),
|
),
|
||||||
charge_duration: 4.5,
|
charge_duration: 4.5,
|
||||||
swing_duration: 0.1,
|
swing_duration: 0.1,
|
||||||
|
@ -18,7 +18,7 @@ BasicMelee(
|
|||||||
strength: Value(0.5),
|
strength: Value(0.5),
|
||||||
chance: 1.0,
|
chance: 1.0,
|
||||||
))),
|
))),
|
||||||
multi_target: true,
|
multi_target: Some(Normal),
|
||||||
),
|
),
|
||||||
ori_modifier: 1.0,
|
ori_modifier: 1.0,
|
||||||
)
|
)
|
||||||
|
@ -16,7 +16,7 @@ ChargedMelee(
|
|||||||
)),
|
)),
|
||||||
range: 6.0,
|
range: 6.0,
|
||||||
angle: 90.0,
|
angle: 90.0,
|
||||||
multi_target: true,
|
multi_target: Some(Normal),
|
||||||
),
|
),
|
||||||
charge_duration: 3.2,
|
charge_duration: 3.2,
|
||||||
swing_duration: 0.7,
|
swing_duration: 0.7,
|
||||||
|
@ -13,7 +13,7 @@ LeapMelee(
|
|||||||
),
|
),
|
||||||
range: 6.75,
|
range: 6.75,
|
||||||
angle: 180.0,
|
angle: 180.0,
|
||||||
multi_target: true,
|
multi_target: Some(Normal),
|
||||||
),
|
),
|
||||||
forward_leap_strength: 45.0,
|
forward_leap_strength: 45.0,
|
||||||
vertical_leap_strength: 10.0,
|
vertical_leap_strength: 10.0,
|
||||||
|
@ -13,7 +13,7 @@ LeapMelee(
|
|||||||
),
|
),
|
||||||
range: 4.5,
|
range: 4.5,
|
||||||
angle: 180.0,
|
angle: 180.0,
|
||||||
multi_target: true,
|
multi_target: Some(Normal),
|
||||||
),
|
),
|
||||||
forward_leap_strength: 20.0,
|
forward_leap_strength: 20.0,
|
||||||
vertical_leap_strength: 5.0,
|
vertical_leap_strength: 5.0,
|
||||||
|
@ -11,7 +11,7 @@ SpinMelee(
|
|||||||
),
|
),
|
||||||
range: 7.5,
|
range: 7.5,
|
||||||
angle: 360.0,
|
angle: 360.0,
|
||||||
multi_target: true,
|
multi_target: Some(Normal),
|
||||||
),
|
),
|
||||||
energy_cost: 0,
|
energy_cost: 0,
|
||||||
is_infinite: false,
|
is_infinite: false,
|
||||||
|
@ -12,7 +12,7 @@ BasicMelee(
|
|||||||
),
|
),
|
||||||
range: 5.0,
|
range: 5.0,
|
||||||
angle: 60.0,
|
angle: 60.0,
|
||||||
multi_target: true,
|
multi_target: Some(Normal),
|
||||||
),
|
),
|
||||||
ori_modifier: 1.0,
|
ori_modifier: 1.0,
|
||||||
)
|
)
|
||||||
|
@ -15,7 +15,7 @@ DashMelee(
|
|||||||
)),
|
)),
|
||||||
range: 5.0,
|
range: 5.0,
|
||||||
angle: 90.0,
|
angle: 90.0,
|
||||||
multi_target: true,
|
multi_target: Some(Normal),
|
||||||
),
|
),
|
||||||
energy_drain: 0,
|
energy_drain: 0,
|
||||||
forward_speed: 10.0,
|
forward_speed: 10.0,
|
||||||
|
@ -11,7 +11,7 @@ SpinMelee(
|
|||||||
),
|
),
|
||||||
range: 3.5,
|
range: 3.5,
|
||||||
angle: 360.0,
|
angle: 360.0,
|
||||||
multi_target: true,
|
multi_target: Some(Normal),
|
||||||
),
|
),
|
||||||
energy_cost: 0,
|
energy_cost: 0,
|
||||||
is_infinite: true,
|
is_infinite: true,
|
||||||
|
@ -12,7 +12,7 @@ BasicMelee(
|
|||||||
),
|
),
|
||||||
range: 4.0,
|
range: 4.0,
|
||||||
angle: 20.0,
|
angle: 20.0,
|
||||||
multi_target: true,
|
multi_target: Some(Normal),
|
||||||
),
|
),
|
||||||
ori_modifier: 1.0,
|
ori_modifier: 1.0,
|
||||||
)
|
)
|
||||||
|
@ -16,7 +16,7 @@ ChargedMelee(
|
|||||||
)),
|
)),
|
||||||
range: 3.5,
|
range: 3.5,
|
||||||
angle: 30.0,
|
angle: 30.0,
|
||||||
multi_target: true,
|
multi_target: Some(Normal),
|
||||||
),
|
),
|
||||||
charge_duration: 1.0,
|
charge_duration: 1.0,
|
||||||
swing_duration: 0.12,
|
swing_duration: 0.12,
|
||||||
|
@ -13,7 +13,7 @@ LeapMelee(
|
|||||||
),
|
),
|
||||||
range: 4.5,
|
range: 4.5,
|
||||||
angle: 360.0,
|
angle: 360.0,
|
||||||
multi_target: true,
|
multi_target: Some(Normal),
|
||||||
),
|
),
|
||||||
forward_leap_strength: 20.0,
|
forward_leap_strength: 20.0,
|
||||||
vertical_leap_strength: 8.0,
|
vertical_leap_strength: 8.0,
|
||||||
|
@ -6,11 +6,11 @@ ComboMelee2(
|
|||||||
damage: 6,
|
damage: 6,
|
||||||
poise: 0,
|
poise: 0,
|
||||||
knockback: 0,
|
knockback: 0,
|
||||||
energy_regen: 3,
|
energy_regen: 7,
|
||||||
),
|
),
|
||||||
range: 3.0,
|
range: 3.0,
|
||||||
angle: 45.0,
|
angle: 45.0,
|
||||||
multi_target: true,
|
multi_target: Some(Normal),
|
||||||
),
|
),
|
||||||
buildup_duration: 0.3,
|
buildup_duration: 0.3,
|
||||||
swing_duration: 0.1,
|
swing_duration: 0.1,
|
||||||
@ -29,11 +29,11 @@ ComboMelee2(
|
|||||||
damage: 8,
|
damage: 8,
|
||||||
poise: 0,
|
poise: 0,
|
||||||
knockback: 0,
|
knockback: 0,
|
||||||
energy_regen: 5,
|
energy_regen: 8,
|
||||||
),
|
),
|
||||||
range: 3.0,
|
range: 3.0,
|
||||||
angle: 45.0,
|
angle: 45.0,
|
||||||
multi_target: true,
|
multi_target: Some(Normal),
|
||||||
),
|
),
|
||||||
buildup_duration: 0.3,
|
buildup_duration: 0.3,
|
||||||
swing_duration: 0.15,
|
swing_duration: 0.15,
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
DiveMelee(
|
DiveMelee(
|
||||||
energy_cost: 20,
|
energy_cost: 20,
|
||||||
vertical_speed: 15,
|
vertical_speed: 10,
|
||||||
movement_duration: 5,
|
movement_duration: 5,
|
||||||
swing_duration: 0.1,
|
swing_duration: 0.1,
|
||||||
recover_duration: 0.3,
|
recover_duration: 0.3,
|
||||||
@ -19,7 +19,7 @@ DiveMelee(
|
|||||||
)),
|
)),
|
||||||
range: 6.0,
|
range: 6.0,
|
||||||
angle: 15.0,
|
angle: 15.0,
|
||||||
multi_target: true,
|
multi_target: Some(Normal),
|
||||||
),
|
),
|
||||||
meta: (
|
meta: (
|
||||||
kind: Some(Sword(Cleaving)),
|
kind: Some(Sword(Cleaving)),
|
||||||
|
@ -12,7 +12,7 @@ FinisherMelee(
|
|||||||
),
|
),
|
||||||
range: 3.0,
|
range: 3.0,
|
||||||
angle: 15.0,
|
angle: 15.0,
|
||||||
damage_effect: Some(ResetMelee),
|
multi_target: Some(Scaling(0.5)),
|
||||||
),
|
),
|
||||||
scaling: Some((
|
scaling: Some((
|
||||||
target: Buff,
|
target: Buff,
|
||||||
|
@ -10,7 +10,7 @@ ComboMelee2(
|
|||||||
),
|
),
|
||||||
range: 6.0,
|
range: 6.0,
|
||||||
angle: 360.0,
|
angle: 360.0,
|
||||||
multi_target: true,
|
multi_target: Some(Normal),
|
||||||
),
|
),
|
||||||
buildup_duration: 0.1,
|
buildup_duration: 0.1,
|
||||||
swing_duration: 0.3,
|
swing_duration: 0.3,
|
||||||
|
@ -10,7 +10,7 @@ ComboMelee2(
|
|||||||
),
|
),
|
||||||
range: 8.0,
|
range: 8.0,
|
||||||
angle: 10.0,
|
angle: 10.0,
|
||||||
multi_target: true,
|
multi_target: Some(Normal),
|
||||||
),
|
),
|
||||||
buildup_duration: 0.3,
|
buildup_duration: 0.3,
|
||||||
swing_duration: 0.1,
|
swing_duration: 0.1,
|
||||||
|
@ -430,18 +430,6 @@ impl Attack {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
CombatEffect::ResetMelee => {
|
|
||||||
if let Some(attacker_entity) = attacker.map(|a| a.entity) {
|
|
||||||
if target
|
|
||||||
.health
|
|
||||||
.map_or(false, |h| accumulated_damage > h.current())
|
|
||||||
{
|
|
||||||
emit(ServerEvent::ResetMelee {
|
|
||||||
entity: attacker_entity,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
CombatEffect::BuildupsVulnerable => {
|
CombatEffect::BuildupsVulnerable => {
|
||||||
if target.char_state.map_or(false, |cs| {
|
if target.char_state.map_or(false, |cs| {
|
||||||
matches!(cs.stage_section(), Some(StageSection::Buildup))
|
matches!(cs.stage_section(), Some(StageSection::Buildup))
|
||||||
@ -604,18 +592,6 @@ impl Attack {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
CombatEffect::ResetMelee => {
|
|
||||||
if let Some(attacker_entity) = attacker.map(|a| a.entity) {
|
|
||||||
if target
|
|
||||||
.health
|
|
||||||
.map_or(false, |h| accumulated_damage > h.current())
|
|
||||||
{
|
|
||||||
emit(ServerEvent::ResetMelee {
|
|
||||||
entity: attacker_entity,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
// Only has an effect when attached to a damage
|
// Only has an effect when attached to a damage
|
||||||
CombatEffect::BuildupsVulnerable => {},
|
CombatEffect::BuildupsVulnerable => {},
|
||||||
}
|
}
|
||||||
@ -749,8 +725,6 @@ pub enum CombatEffect {
|
|||||||
Lifesteal(f32),
|
Lifesteal(f32),
|
||||||
Poise(f32),
|
Poise(f32),
|
||||||
Combo(i32),
|
Combo(i32),
|
||||||
// If the attack kills the target, reset the melee attack
|
|
||||||
ResetMelee,
|
|
||||||
// If the attack hits the target while they are in the buildup portion of a character state,
|
// If the attack hits the target while they are in the buildup portion of a character state,
|
||||||
// deal double damage Only has an effect when attached to a damage, otherwise does nothing
|
// deal double damage Only has an effect when attached to a damage, otherwise does nothing
|
||||||
// if only attached to the attack TODO: Maybe try to make it do something if tied to
|
// if only attached to the attack TODO: Maybe try to make it do something if tied to
|
||||||
|
@ -732,7 +732,7 @@ impl Default for CharacterAbility {
|
|||||||
scaled: None,
|
scaled: None,
|
||||||
range: 3.5,
|
range: 3.5,
|
||||||
angle: 15.0,
|
angle: 15.0,
|
||||||
multi_target: false,
|
multi_target: None,
|
||||||
damage_effect: None,
|
damage_effect: None,
|
||||||
},
|
},
|
||||||
ori_modifier: 1.0,
|
ori_modifier: 1.0,
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
use crate::DamageSource;
|
|
||||||
#[cfg(not(target_arch = "wasm32"))]
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
use crate::{comp, consts::HP_PER_LEVEL};
|
use crate::{comp, consts::HP_PER_LEVEL};
|
||||||
|
use crate::{uid::Uid, DamageSource};
|
||||||
use hashbrown::HashMap;
|
use hashbrown::HashMap;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::convert::TryFrom;
|
use std::convert::TryFrom;
|
||||||
@ -193,6 +193,12 @@ impl Health {
|
|||||||
.map(|(damage_contrib, (damage, _))| (damage_contrib, damage))
|
.map(|(damage_contrib, (damage, _))| (damage_contrib, damage))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn recent_damagers(&self) -> impl Iterator<Item = (Uid, Time)> + '_ {
|
||||||
|
self.damage_contributors
|
||||||
|
.iter()
|
||||||
|
.map(|(contrib, (_, time))| (contrib.uid(), *time))
|
||||||
|
}
|
||||||
|
|
||||||
pub fn should_die(&self) -> bool { self.current == 0 }
|
pub fn should_die(&self) -> bool { self.current == 0 }
|
||||||
|
|
||||||
pub fn kill(&mut self) { self.current = 0; }
|
pub fn kill(&mut self) { self.current = 0; }
|
||||||
|
@ -20,10 +20,16 @@ pub struct Melee {
|
|||||||
pub max_angle: f32,
|
pub max_angle: f32,
|
||||||
pub applied: bool,
|
pub applied: bool,
|
||||||
pub hit_count: u32,
|
pub hit_count: u32,
|
||||||
pub multi_target: bool,
|
pub multi_target: Option<MultiTarget>,
|
||||||
pub break_block: Option<(Vec3<i32>, Option<ToolKind>)>,
|
pub break_block: Option<(Vec3<i32>, Option<ToolKind>)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||||
|
pub enum MultiTarget {
|
||||||
|
Normal,
|
||||||
|
Scaling(f32),
|
||||||
|
}
|
||||||
|
|
||||||
impl Melee {
|
impl Melee {
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn with_block_breaking(
|
pub fn with_block_breaking(
|
||||||
@ -47,8 +53,7 @@ pub struct MeleeConstructor {
|
|||||||
pub scaled: Option<MeleeConstructorKind>,
|
pub scaled: Option<MeleeConstructorKind>,
|
||||||
pub range: f32,
|
pub range: f32,
|
||||||
pub angle: f32,
|
pub angle: f32,
|
||||||
#[serde(default)]
|
pub multi_target: Option<MultiTarget>,
|
||||||
pub multi_target: bool,
|
|
||||||
pub damage_effect: Option<CombatEffect>,
|
pub damage_effect: Option<CombatEffect>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -226,9 +226,6 @@ pub enum ServerEvent {
|
|||||||
entity: EcsEntity,
|
entity: EcsEntity,
|
||||||
update: comp::MapMarkerChange,
|
update: comp::MapMarkerChange,
|
||||||
},
|
},
|
||||||
ResetMelee {
|
|
||||||
entity: EcsEntity,
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct EventBus<E> {
|
pub struct EventBus<E> {
|
||||||
|
@ -2,7 +2,7 @@ use crate::{
|
|||||||
combat::{Attack, AttackDamage, AttackEffect, CombatBuff, CombatEffect, CombatRequirement},
|
combat::{Attack, AttackDamage, AttackEffect, CombatBuff, CombatEffect, CombatRequirement},
|
||||||
comp::{
|
comp::{
|
||||||
character_state::OutputEvents,
|
character_state::OutputEvents,
|
||||||
tool::{Stats, ToolKind},
|
tool::{Stats, ToolKind}, melee::MultiTarget,
|
||||||
CharacterState, Melee, StateUpdate,
|
CharacterState, Melee, StateUpdate,
|
||||||
},
|
},
|
||||||
states::{
|
states::{
|
||||||
@ -279,7 +279,7 @@ impl CharacterBehavior for Data {
|
|||||||
hit_count: 0,
|
hit_count: 0,
|
||||||
// TODO: Evaluate if we want to leave this true. State will be removed at
|
// TODO: Evaluate if we want to leave this true. State will be removed at
|
||||||
// some point anyways and this does preserve behavior
|
// some point anyways and this does preserve behavior
|
||||||
multi_target: true,
|
multi_target: Some(MultiTarget::Normal),
|
||||||
break_block: data
|
break_block: data
|
||||||
.inputs
|
.inputs
|
||||||
.break_block_pos
|
.break_block_pos
|
||||||
|
@ -278,7 +278,7 @@ fn create_test_melee(static_data: StaticData) -> Melee {
|
|||||||
scaled: None,
|
scaled: None,
|
||||||
range: static_data.melee_constructor.range,
|
range: static_data.melee_constructor.range,
|
||||||
angle: static_data.melee_constructor.angle,
|
angle: static_data.melee_constructor.angle,
|
||||||
multi_target: false,
|
multi_target: None,
|
||||||
damage_effect: None,
|
damage_effect: None,
|
||||||
};
|
};
|
||||||
melee.create_melee((0.0, 0.0), 0.0)
|
melee.create_melee((0.0, 0.0), 0.0)
|
||||||
|
@ -74,6 +74,8 @@ impl CharacterBehavior for Data {
|
|||||||
let crit_data = get_crit_data(data, self.static_data.ability_info);
|
let crit_data = get_crit_data(data, self.static_data.ability_info);
|
||||||
let buff_strength = get_buff_strength(data, self.static_data.ability_info);
|
let buff_strength = get_buff_strength(data, self.static_data.ability_info);
|
||||||
let scaling = self.max_vertical_speed / self.static_data.vertical_speed;
|
let scaling = self.max_vertical_speed / self.static_data.vertical_speed;
|
||||||
|
// TODO: Remove when server authoritative physics
|
||||||
|
let scaling = scaling.max(2.0);
|
||||||
|
|
||||||
data.updater.insert(
|
data.updater.insert(
|
||||||
data.entity,
|
data.entity,
|
||||||
|
@ -2,6 +2,7 @@ use common::{
|
|||||||
combat::{self, AttackOptions, AttackSource, AttackerInfo, TargetInfo},
|
combat::{self, AttackOptions, AttackSource, AttackerInfo, TargetInfo},
|
||||||
comp::{
|
comp::{
|
||||||
agent::{Sound, SoundKind},
|
agent::{Sound, SoundKind},
|
||||||
|
melee::MultiTarget,
|
||||||
Alignment, Body, CharacterState, Combo, Energy, Group, Health, Inventory, Melee, Ori,
|
Alignment, Body, CharacterState, Combo, Energy, Group, Health, Inventory, Melee, Ori,
|
||||||
Player, Pos, Scale, Stats,
|
Player, Pos, Scale, Stats,
|
||||||
},
|
},
|
||||||
@ -116,7 +117,7 @@ impl<'a> System<'a> for Sys {
|
|||||||
{
|
{
|
||||||
// Unless the melee attack can hit multiple targets, stop the attack if it has
|
// Unless the melee attack can hit multiple targets, stop the attack if it has
|
||||||
// already hit 1 target
|
// already hit 1 target
|
||||||
if !melee_attack.multi_target && melee_attack.hit_count > 0 {
|
if melee_attack.multi_target.is_none() && melee_attack.hit_count > 0 {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -197,12 +198,19 @@ impl<'a> System<'a> for Sys {
|
|||||||
target_group,
|
target_group,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let strength =
|
||||||
|
if let Some(MultiTarget::Scaling(scaling)) = melee_attack.multi_target {
|
||||||
|
1.0 + melee_attack.hit_count as f32 * scaling
|
||||||
|
} else {
|
||||||
|
1.0
|
||||||
|
};
|
||||||
|
|
||||||
let is_applied = melee_attack.attack.apply_attack(
|
let is_applied = melee_attack.attack.apply_attack(
|
||||||
attacker_info,
|
attacker_info,
|
||||||
target_info,
|
target_info,
|
||||||
dir,
|
dir,
|
||||||
attack_options,
|
attack_options,
|
||||||
1.0,
|
strength,
|
||||||
AttackSource::Melee,
|
AttackSource::Melee,
|
||||||
*read_data.time,
|
*read_data.time,
|
||||||
|e| server_emitter.emit(e),
|
|e| server_emitter.emit(e),
|
||||||
|
@ -18,6 +18,7 @@ use common::{
|
|||||||
vol::ReadVol,
|
vol::ReadVol,
|
||||||
};
|
};
|
||||||
use rand::Rng;
|
use rand::Rng;
|
||||||
|
use specs::saveload::MarkerAllocator;
|
||||||
use std::{f32::consts::PI, time::Duration};
|
use std::{f32::consts::PI, time::Duration};
|
||||||
use vek::*;
|
use vek::*;
|
||||||
|
|
||||||
@ -474,16 +475,31 @@ impl<'a> AgentData<'a> {
|
|||||||
.map_or(false, |buffs| !buffs.contains(self.buff))
|
.map_or(false, |buffs| !buffs.contains(self.buff))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
struct DiveMeleeData {
|
||||||
|
range: f32,
|
||||||
|
angle: f32,
|
||||||
|
energy: f32,
|
||||||
|
}
|
||||||
|
impl DiveMeleeData {
|
||||||
|
fn npc_should_use_hack(&self, agent_data: &AgentData, tgt_data: &TargetData) -> bool {
|
||||||
|
let dist_sqrd_2d = agent_data.pos.0.xy().distance_squared(tgt_data.pos.0.xy());
|
||||||
|
agent_data.energy.current() > self.energy
|
||||||
|
&& agent_data.physics_state.on_ground.is_some()
|
||||||
|
&& agent_data.pos.0.z >= tgt_data.pos.0.z
|
||||||
|
&& dist_sqrd_2d > (self.range / 2.0).powi(2)
|
||||||
|
&& dist_sqrd_2d < (self.range + 5.0).powi(2)
|
||||||
|
}
|
||||||
|
}
|
||||||
use ability::SwordStance;
|
use ability::SwordStance;
|
||||||
let stance = |stance| match stance {
|
let stance = |stance| match stance {
|
||||||
1 => SwordStance::Offensive,
|
1 => SwordStance::Offensive,
|
||||||
2 => SwordStance::Defensive,
|
2 => SwordStance::Defensive,
|
||||||
3 => SwordStance::Mobility,
|
3 => SwordStance::Mobility,
|
||||||
4 => SwordStance::Crippling,
|
4 => SwordStance::Crippling,
|
||||||
5 => SwordStance::Cleaving,
|
5 => SwordStance::Parrying,
|
||||||
6 => SwordStance::Parrying,
|
6 => SwordStance::Heavy,
|
||||||
7 => SwordStance::Heavy,
|
7 => SwordStance::Reaching,
|
||||||
8 => SwordStance::Reaching,
|
8 => SwordStance::Cleaving,
|
||||||
_ => SwordStance::Balanced,
|
_ => SwordStance::Balanced,
|
||||||
};
|
};
|
||||||
if !agent.action_state.initialized {
|
if !agent.action_state.initialized {
|
||||||
@ -495,8 +511,12 @@ impl<'a> AgentData<'a> {
|
|||||||
.skill_set
|
.skill_set
|
||||||
.has_skill(Skill::Sword(SwordSkill::CripplingFinisher))
|
.has_skill(Skill::Sword(SwordSkill::CripplingFinisher))
|
||||||
{
|
{
|
||||||
|
// Hack to make cleaving stance come up less often because agents cannot use it
|
||||||
|
// effectively due to only considering a single target
|
||||||
|
// Remove when agents properly consider multiple targets
|
||||||
|
// 4 + rng.gen_range(0..13) / 3
|
||||||
// rng.gen_range(4..9)
|
// rng.gen_range(4..9)
|
||||||
4
|
5
|
||||||
} else if self
|
} else if self
|
||||||
.skill_set
|
.skill_set
|
||||||
.has_skill(Skill::Sword(SwordSkill::OffensiveFinisher))
|
.has_skill(Skill::Sword(SwordSkill::OffensiveFinisher))
|
||||||
@ -569,8 +589,8 @@ impl<'a> AgentData<'a> {
|
|||||||
set_sword_ability(2, 10);
|
set_sword_ability(2, 10);
|
||||||
// Cleaving dive
|
// Cleaving dive
|
||||||
set_sword_ability(3, 11);
|
set_sword_ability(3, 11);
|
||||||
// Offensive finisher
|
// Offensive advance
|
||||||
set_sword_ability(4, 2);
|
set_sword_ability(4, 3);
|
||||||
},
|
},
|
||||||
SwordStance::Parrying => {
|
SwordStance::Parrying => {
|
||||||
// Parrying combo
|
// Parrying combo
|
||||||
@ -1021,8 +1041,6 @@ impl<'a> AgentData<'a> {
|
|||||||
if self.energy.current() < DESIRED_ENERGY {
|
if self.energy.current() < DESIRED_ENERGY {
|
||||||
fallback_tactics(agent, controller);
|
fallback_tactics(agent, controller);
|
||||||
} else if !in_stance(SwordStance::Crippling) {
|
} else if !in_stance(SwordStance::Crippling) {
|
||||||
// controller.push_basic_input(InputKind::Jump);
|
|
||||||
// agent.action_state.initialized = false;
|
|
||||||
controller.push_basic_input(InputKind::Ability(0));
|
controller.push_basic_input(InputKind::Ability(0));
|
||||||
} else if CRIPPLING_FINISHER.could_use(attack_data, self)
|
} else if CRIPPLING_FINISHER.could_use(attack_data, self)
|
||||||
&& CRIPPLING_FINISHER.use_desirable(tgt_data, self)
|
&& CRIPPLING_FINISHER.use_desirable(tgt_data, self)
|
||||||
@ -1080,7 +1098,121 @@ impl<'a> AgentData<'a> {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
SwordStance::Cleaving => {
|
SwordStance::Cleaving => {
|
||||||
fallback_tactics(agent, controller);
|
// TODO: Rewrite cleaving stance tactics when agents can consider multiple
|
||||||
|
// targets at once. Remove hack to make cleaving AI appear less frequently above
|
||||||
|
// when doing so.
|
||||||
|
const CLEAVING_COMBO: ComboMeleeData = ComboMeleeData {
|
||||||
|
min_range: 0.0,
|
||||||
|
max_range: 2.5,
|
||||||
|
angle: 35.0,
|
||||||
|
energy: 10.0,
|
||||||
|
};
|
||||||
|
const CLEAVING_FINISHER: FinisherMeleeData = FinisherMeleeData {
|
||||||
|
range: 2.0,
|
||||||
|
angle: 10.0,
|
||||||
|
energy: 40.0,
|
||||||
|
combo: 10,
|
||||||
|
};
|
||||||
|
const CLEAVING_SPIN: ComboMeleeData = ComboMeleeData {
|
||||||
|
min_range: 0.0,
|
||||||
|
max_range: 5.0,
|
||||||
|
angle: 360.0,
|
||||||
|
energy: 15.0,
|
||||||
|
};
|
||||||
|
const CLEAVING_DIVE: DiveMeleeData = DiveMeleeData {
|
||||||
|
range: 5.0,
|
||||||
|
angle: 10.0,
|
||||||
|
energy: 20.0,
|
||||||
|
};
|
||||||
|
const DESIRED_ENERGY: f32 = 50.0;
|
||||||
|
|
||||||
|
// TODO: Remove when agents actually have multiple targets
|
||||||
|
// Hacky check for multiple nearby melee range targets
|
||||||
|
let are_nearby_targets = || {
|
||||||
|
if let Some(health) = self.health {
|
||||||
|
health
|
||||||
|
.recent_damagers()
|
||||||
|
.filter(|(_, time)| read_data.time.0 - time.0 < 5.0)
|
||||||
|
.filter_map(|(uid, _)| {
|
||||||
|
read_data.uid_allocator.retrieve_entity_internal(uid.0)
|
||||||
|
})
|
||||||
|
.filter(|e| {
|
||||||
|
read_data.positions.get(*e).map_or(false, |pos| {
|
||||||
|
pos.0.distance_squared(self.pos.0) < 10_f32.powi(2)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.count()
|
||||||
|
> 1
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if matches!(self.char_state, CharacterState::Roll(_)) {
|
||||||
|
agent.action_state.condition = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if agent.action_state.condition {
|
||||||
|
if self.physics_state.on_ground.is_some() {
|
||||||
|
controller.push_basic_input(InputKind::Jump);
|
||||||
|
} else {
|
||||||
|
controller.push_basic_input(InputKind::Ability(3));
|
||||||
|
}
|
||||||
|
agent.action_state.timer += read_data.dt.0;
|
||||||
|
if agent.action_state.timer > 2.0 {
|
||||||
|
agent.action_state.timer = 0.0;
|
||||||
|
agent.action_state.condition = false;
|
||||||
|
}
|
||||||
|
advance(agent, controller, CLEAVING_DIVE.range, CLEAVING_DIVE.angle);
|
||||||
|
} else if self.energy.current() < DESIRED_ENERGY {
|
||||||
|
fallback_tactics(agent, controller);
|
||||||
|
} else if !in_stance(SwordStance::Cleaving) {
|
||||||
|
controller.push_basic_input(InputKind::Ability(0));
|
||||||
|
} else if CLEAVING_FINISHER.could_use(attack_data, self)
|
||||||
|
&& CLEAVING_FINISHER.use_desirable(tgt_data, self)
|
||||||
|
{
|
||||||
|
controller.push_basic_input(InputKind::Ability(1));
|
||||||
|
advance(
|
||||||
|
agent,
|
||||||
|
controller,
|
||||||
|
CLEAVING_FINISHER.range,
|
||||||
|
CLEAVING_FINISHER.angle,
|
||||||
|
);
|
||||||
|
} else if CLEAVING_SPIN.could_use(attack_data, self) && are_nearby_targets() {
|
||||||
|
controller.push_basic_input(InputKind::Ability(2));
|
||||||
|
advance(
|
||||||
|
agent,
|
||||||
|
controller,
|
||||||
|
CLEAVING_SPIN.max_range,
|
||||||
|
CLEAVING_SPIN.angle,
|
||||||
|
);
|
||||||
|
} else if CLEAVING_DIVE.npc_should_use_hack(self, tgt_data) {
|
||||||
|
controller.push_basic_input(InputKind::Roll);
|
||||||
|
advance(agent, controller, CLEAVING_DIVE.range, CLEAVING_DIVE.angle);
|
||||||
|
} else if CLEAVING_COMBO.could_use(attack_data, self) {
|
||||||
|
controller.push_basic_input(InputKind::Primary);
|
||||||
|
advance(
|
||||||
|
agent,
|
||||||
|
controller,
|
||||||
|
CLEAVING_COMBO.max_range,
|
||||||
|
CLEAVING_COMBO.angle,
|
||||||
|
);
|
||||||
|
} else if OFFENSIVE_ADVANCE.could_use(attack_data, self) {
|
||||||
|
controller.push_basic_input(InputKind::Ability(4));
|
||||||
|
advance(
|
||||||
|
agent,
|
||||||
|
controller,
|
||||||
|
OFFENSIVE_ADVANCE.max_range,
|
||||||
|
OFFENSIVE_ADVANCE.angle,
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
advance(
|
||||||
|
agent,
|
||||||
|
controller,
|
||||||
|
CLEAVING_COMBO.max_range,
|
||||||
|
CLEAVING_COMBO.angle,
|
||||||
|
);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
SwordStance::Parrying => {
|
SwordStance::Parrying => {
|
||||||
fallback_tactics(agent, controller);
|
fallback_tactics(agent, controller);
|
||||||
|
@ -1417,12 +1417,3 @@ pub fn handle_update_map_marker(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn handle_reset_melee(server: &Server, entity: EcsEntity) {
|
|
||||||
let ecs = &server.state.ecs();
|
|
||||||
|
|
||||||
if let Some(mut melee) = ecs.write_storage::<comp::Melee>().get_mut(entity) {
|
|
||||||
melee.applied = false;
|
|
||||||
melee.hit_count = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -13,8 +13,7 @@ use entity_manipulation::{
|
|||||||
handle_aura, handle_bonk, handle_buff, handle_change_ability, handle_combo_change,
|
handle_aura, handle_bonk, handle_buff, handle_change_ability, handle_combo_change,
|
||||||
handle_delete, handle_destroy, handle_energy_change, handle_entity_attacked_hook,
|
handle_delete, handle_destroy, handle_energy_change, handle_entity_attacked_hook,
|
||||||
handle_explosion, handle_health_change, handle_knockback, handle_land_on_ground,
|
handle_explosion, handle_health_change, handle_knockback, handle_land_on_ground,
|
||||||
handle_parry_hook, handle_poise, handle_reset_melee, handle_respawn, handle_teleport_to,
|
handle_parry_hook, handle_poise, handle_respawn, handle_teleport_to, handle_update_map_marker,
|
||||||
handle_update_map_marker,
|
|
||||||
};
|
};
|
||||||
use group_manip::handle_group;
|
use group_manip::handle_group;
|
||||||
use information::handle_site_info;
|
use information::handle_site_info;
|
||||||
@ -287,7 +286,6 @@ impl Server {
|
|||||||
ServerEvent::UpdateMapMarker { entity, update } => {
|
ServerEvent::UpdateMapMarker { entity, update } => {
|
||||||
handle_update_map_marker(self, entity, update)
|
handle_update_map_marker(self, entity, update)
|
||||||
},
|
},
|
||||||
ServerEvent::ResetMelee { entity } => handle_reset_melee(self, entity),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -86,7 +86,7 @@ fn maps_basic_melee() {
|
|||||||
range: 3.5,
|
range: 3.5,
|
||||||
angle: 15.0,
|
angle: 15.0,
|
||||||
damage_effect: None,
|
damage_effect: None,
|
||||||
multi_target: false,
|
multi_target: None,
|
||||||
},
|
},
|
||||||
ori_modifier: 1.0,
|
ori_modifier: 1.0,
|
||||||
ability_info: empty_ability_info(),
|
ability_info: empty_ability_info(),
|
||||||
|
Loading…
Reference in New Issue
Block a user