mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Intercept
This commit is contained in:
parent
e24ebc381b
commit
e858b84427
@ -225,13 +225,13 @@
|
||||
((), (Hammer(HeavyWhorl), "common.abilities.hammer.heavy_whorl")),
|
||||
],
|
||||
),
|
||||
// Contextualized(
|
||||
// pseudo_id: "common.abilities.hammer.intercept",
|
||||
// abilities: [
|
||||
// ((dual_wielding_same_kind: true), (Hammer(Intercept), "common.abilities.hammer.dual_intercept")),
|
||||
// ((), (Hammer(Intercept), "common.abilities.hammer.intercept")),
|
||||
// ],
|
||||
// ),
|
||||
Contextualized(
|
||||
pseudo_id: "common.abilities.hammer.intercept",
|
||||
abilities: [
|
||||
((dual_wielding_same_kind: true), (Hammer(Intercept), "common.abilities.hammer.dual_intercept")),
|
||||
((), (Hammer(Intercept), "common.abilities.hammer.intercept")),
|
||||
],
|
||||
),
|
||||
// Simple(Hammer(PileDriver), "common.abilities.hammer.pile_driver"),
|
||||
// Simple(Hammer(LungPummel), "common.abilities.hammer.lung_pummel"),
|
||||
// Simple(Hammer(HelmCrusher), "common.abilities.hammer.helm_crusher"),
|
||||
|
@ -24,5 +24,5 @@ DashMelee(
|
||||
swing_duration: 0.1,
|
||||
recover_duration: 0.9,
|
||||
ori_modifier: 0.3,
|
||||
charge_through: false,
|
||||
auto_charge: false,
|
||||
)
|
||||
|
@ -24,5 +24,5 @@ DashMelee(
|
||||
swing_duration: 0.25,
|
||||
recover_duration: 0.8,
|
||||
ori_modifier: 0.1,
|
||||
charge_through: false,
|
||||
auto_charge: false,
|
||||
)
|
||||
|
@ -24,5 +24,5 @@ DashMelee(
|
||||
swing_duration: 0.3,
|
||||
recover_duration: 2.0,
|
||||
ori_modifier: 0.1,
|
||||
charge_through: false,
|
||||
auto_charge: false,
|
||||
)
|
||||
|
@ -24,5 +24,5 @@ DashMelee(
|
||||
swing_duration: 0.1,
|
||||
recover_duration: 1.4,
|
||||
ori_modifier: 0.3,
|
||||
charge_through: false,
|
||||
auto_charge: false,
|
||||
)
|
||||
|
@ -30,5 +30,5 @@ DashMelee(
|
||||
swing_duration: 0.1,
|
||||
recover_duration: 0.9,
|
||||
ori_modifier: 0.3,
|
||||
charge_through: false,
|
||||
auto_charge: false,
|
||||
)
|
||||
|
@ -24,5 +24,5 @@ DashMelee(
|
||||
swing_duration: 0.1,
|
||||
recover_duration: 2.0,
|
||||
ori_modifier: 0.1,
|
||||
charge_through: true,
|
||||
auto_charge: false,
|
||||
)
|
||||
|
@ -25,5 +25,5 @@ DashMelee(
|
||||
swing_duration: 0.1,
|
||||
recover_duration: 0.8,
|
||||
ori_modifier: 0.1,
|
||||
charge_through: false,
|
||||
auto_charge: false,
|
||||
)
|
||||
|
@ -24,5 +24,5 @@ DashMelee(
|
||||
swing_duration: 0.35,
|
||||
recover_duration: 2.0,
|
||||
ori_modifier: 0.1,
|
||||
charge_through: true,
|
||||
auto_charge: false,
|
||||
)
|
||||
|
@ -25,5 +25,5 @@ DashMelee(
|
||||
swing_duration: 0.1,
|
||||
recover_duration: 1.2,
|
||||
ori_modifier: 0.1,
|
||||
charge_through: false,
|
||||
auto_charge: false,
|
||||
)
|
||||
|
@ -31,5 +31,5 @@ DashMelee(
|
||||
swing_duration: 0.1,
|
||||
recover_duration: 3.4,
|
||||
ori_modifier: 0.1,
|
||||
charge_through: false,
|
||||
auto_charge: false,
|
||||
)
|
||||
|
@ -24,5 +24,5 @@ DashMelee(
|
||||
swing_duration: 0.35,
|
||||
recover_duration: 2.4,
|
||||
ori_modifier: 0.3,
|
||||
charge_through: false,
|
||||
auto_charge: false,
|
||||
)
|
||||
|
@ -24,5 +24,5 @@ DashMelee(
|
||||
swing_duration: 0.35,
|
||||
recover_duration: 2.0,
|
||||
ori_modifier: 0.1,
|
||||
charge_through: false,
|
||||
auto_charge: false,
|
||||
)
|
||||
|
@ -24,5 +24,5 @@ DashMelee(
|
||||
swing_duration: 0.35,
|
||||
recover_duration: 2.0,
|
||||
ori_modifier: 0.1,
|
||||
charge_through: false,
|
||||
auto_charge: false,
|
||||
)
|
||||
|
@ -24,5 +24,5 @@ DashMelee(
|
||||
swing_duration: 0.4,
|
||||
recover_duration: 1.2,
|
||||
ori_modifier: 0.3,
|
||||
charge_through: false,
|
||||
auto_charge: false,
|
||||
)
|
||||
|
@ -24,5 +24,5 @@ DashMelee(
|
||||
swing_duration: 0.65,
|
||||
recover_duration: 2.0,
|
||||
ori_modifier: 0.1,
|
||||
charge_through: false,
|
||||
auto_charge: false,
|
||||
)
|
||||
|
@ -24,5 +24,5 @@ DashMelee(
|
||||
swing_duration: 0.1,
|
||||
recover_duration: 2.2,
|
||||
ori_modifier: 0.3,
|
||||
charge_through: false,
|
||||
auto_charge: false,
|
||||
)
|
||||
|
@ -24,5 +24,5 @@ DashMelee(
|
||||
swing_duration: 0.1,
|
||||
recover_duration: 0.9,
|
||||
ori_modifier: 0.3,
|
||||
charge_through: false,
|
||||
auto_charge: false,
|
||||
)
|
||||
|
@ -24,5 +24,5 @@ DashMelee(
|
||||
swing_duration: 0.3,
|
||||
recover_duration: 0.7,
|
||||
ori_modifier: 0.1,
|
||||
charge_through: false,
|
||||
auto_charge: false,
|
||||
)
|
||||
|
@ -25,5 +25,5 @@ DashMelee(
|
||||
swing_duration: 0.1,
|
||||
recover_duration: 1.0,
|
||||
ori_modifier: 0.3,
|
||||
charge_through: false,
|
||||
auto_charge: false,
|
||||
)
|
||||
|
32
assets/common/abilities/hammer/dual_intercept.ron
Normal file
32
assets/common/abilities/hammer/dual_intercept.ron
Normal file
@ -0,0 +1,32 @@
|
||||
DashMelee(
|
||||
energy_cost: 15,
|
||||
energy_drain: 0,
|
||||
forward_speed: 2.5,
|
||||
buildup_duration: 0.1,
|
||||
charge_duration: 1.5,
|
||||
swing_duration: 0.1,
|
||||
recover_duration: 0.3,
|
||||
melee_constructor: (
|
||||
kind: Bash(
|
||||
damage: 6,
|
||||
poise: 10,
|
||||
knockback: 6,
|
||||
energy_regen: 0,
|
||||
),
|
||||
scaled: Some((
|
||||
kind: Bash(
|
||||
damage: 9,
|
||||
poise: 15,
|
||||
knockback: 9,
|
||||
energy_regen: 0,
|
||||
))),
|
||||
range: 4.0,
|
||||
angle: 30.0,
|
||||
multi_target: Some(Normal),
|
||||
),
|
||||
ori_modifier: 0.1,
|
||||
auto_charge: true,
|
||||
meta: (
|
||||
contextual_stats: Some((context: PoiseResilience(60.0), field: EffectPower)),
|
||||
),
|
||||
)
|
31
assets/common/abilities/hammer/intercept.ron
Normal file
31
assets/common/abilities/hammer/intercept.ron
Normal file
@ -0,0 +1,31 @@
|
||||
DashMelee(
|
||||
energy_cost: 15,
|
||||
energy_drain: 0,
|
||||
forward_speed: 2.5,
|
||||
buildup_duration: 0.1,
|
||||
charge_duration: 1.5,
|
||||
swing_duration: 0.1,
|
||||
recover_duration: 0.3,
|
||||
melee_constructor: (
|
||||
kind: Bash(
|
||||
damage: 8,
|
||||
poise: 12,
|
||||
knockback: 8,
|
||||
energy_regen: 0,
|
||||
),
|
||||
scaled: Some((
|
||||
kind: Bash(
|
||||
damage: 12,
|
||||
poise: 18,
|
||||
knockback: 12,
|
||||
energy_regen: 0,
|
||||
))),
|
||||
range: 4.0,
|
||||
angle: 30.0,
|
||||
),
|
||||
ori_modifier: 0.1,
|
||||
auto_charge: true,
|
||||
meta: (
|
||||
contextual_stats: Some((context: PoiseResilience(30.0), field: EffectPower)),
|
||||
),
|
||||
)
|
@ -24,5 +24,5 @@ DashMelee(
|
||||
swing_duration: 0.1,
|
||||
recover_duration: 0.8,
|
||||
ori_modifier: 0.3,
|
||||
charge_through: false,
|
||||
auto_charge: false,
|
||||
)
|
||||
|
@ -24,5 +24,5 @@ DashMelee(
|
||||
swing_duration: 0.1,
|
||||
recover_duration: 0.9,
|
||||
ori_modifier: 0.3,
|
||||
charge_through: false,
|
||||
auto_charge: false,
|
||||
)
|
||||
|
BIN
assets/voxygen/element/skills/hammer/intercept.png
(Stored with Git LFS)
Normal file
BIN
assets/voxygen/element/skills/hammer/intercept.png
(Stored with Git LFS)
Normal file
Binary file not shown.
@ -398,3 +398,9 @@ common-abilities-hammer-heavy_whorl = Heavy Whorl
|
||||
common-abilities-hammer-dual_heavy_whorl = Heavy Whorl
|
||||
.desc =
|
||||
You strike all foes surrounding you with your hammers.
|
||||
common-abilities-hammer-intercept = Intercept
|
||||
.desc =
|
||||
Charge forward with your hammer throwing your weight behind your strike.
|
||||
common-abilities-hammer-dual_intercept = Intercept
|
||||
.desc =
|
||||
Charge forward with your hammers throwing your weight behind your strike.
|
||||
|
@ -1603,6 +1603,32 @@ pub fn compute_protection(
|
||||
})
|
||||
}
|
||||
|
||||
/// Computes the total resilience provided from armor. Is used to determine the
|
||||
/// reduction applied to poise damage received by an entity. None indicates that
|
||||
/// the armor equipped makes the entity invulnerable to poise damage.
|
||||
pub fn compute_poise_resilience(
|
||||
inventory: Option<&Inventory>,
|
||||
msm: &MaterialStatManifest,
|
||||
) -> Option<f32> {
|
||||
inventory.map_or(Some(0.0), |inv| {
|
||||
inv.equipped_items()
|
||||
.filter_map(|item| {
|
||||
if let ItemKind::Armor(armor) = &*item.kind() {
|
||||
armor
|
||||
.stats(msm, item.stats_durability_multiplier())
|
||||
.poise_resilience
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.map(|protection| match protection {
|
||||
Protection::Normal(protection) => Some(protection),
|
||||
Protection::Invincible => None,
|
||||
})
|
||||
.sum::<Option<f32>>()
|
||||
})
|
||||
}
|
||||
|
||||
/// Used to compute the precision multiplier achieved by flanking a target
|
||||
pub fn precision_mult_from_flank(attack_dir: Vec3<f32>, target_ori: Option<&Ori>) -> Option<f32> {
|
||||
let angle = target_ori.map(|t_ori| t_ori.look_dir().angle_between(attack_dir));
|
||||
|
@ -805,7 +805,7 @@ pub enum CharacterAbility {
|
||||
recover_duration: f32,
|
||||
melee_constructor: MeleeConstructor,
|
||||
ori_modifier: f32,
|
||||
charge_through: bool,
|
||||
auto_charge: bool,
|
||||
#[serde(default)]
|
||||
meta: AbilityMeta,
|
||||
},
|
||||
@ -1331,7 +1331,7 @@ impl CharacterAbility {
|
||||
ref mut recover_duration,
|
||||
ref mut melee_constructor,
|
||||
ori_modifier: _,
|
||||
charge_through: _,
|
||||
auto_charge: _,
|
||||
meta: _,
|
||||
} => {
|
||||
*buildup_duration /= stats.speed;
|
||||
@ -2271,13 +2271,13 @@ impl From<(&CharacterAbility, AbilityInfo, &JoinData<'_>)> for CharacterState {
|
||||
recover_duration,
|
||||
melee_constructor,
|
||||
ori_modifier,
|
||||
charge_through,
|
||||
auto_charge,
|
||||
meta: _,
|
||||
} => CharacterState::DashMelee(dash_melee::Data {
|
||||
static_data: dash_melee::StaticData {
|
||||
energy_drain: *energy_drain,
|
||||
forward_speed: *forward_speed,
|
||||
charge_through: *charge_through,
|
||||
auto_charge: *auto_charge,
|
||||
buildup_duration: Duration::from_secs_f32(*buildup_duration),
|
||||
charge_duration: Duration::from_secs_f32(*charge_duration),
|
||||
swing_duration: Duration::from_secs_f32(*swing_duration),
|
||||
@ -2288,9 +2288,7 @@ impl From<(&CharacterAbility, AbilityInfo, &JoinData<'_>)> for CharacterState {
|
||||
},
|
||||
auto_charge: false,
|
||||
timer: Duration::default(),
|
||||
charge_end_timer: Duration::from_secs_f32(*charge_duration),
|
||||
stage_section: StageSection::Buildup,
|
||||
exhausted: false,
|
||||
}),
|
||||
CharacterAbility::BasicBlock {
|
||||
buildup_duration,
|
||||
@ -2924,6 +2922,44 @@ pub struct AbilityMeta {
|
||||
pub init_event: Option<AbilityInitEvent>,
|
||||
#[serde(default)]
|
||||
pub requirements: AbilityRequirements,
|
||||
/// Adjusts stats of ability when activated based on context.
|
||||
// If we ever add more, I guess change to a vec? Or maybe just an array if we want to keep
|
||||
// AbilityMeta small?
|
||||
pub contextual_stats: Option<StatAdj>,
|
||||
}
|
||||
|
||||
impl StatAdj {
|
||||
pub fn equivalent_stats(&self, data: &JoinData) -> Stats {
|
||||
let mut stats = Stats::one();
|
||||
let add = match self.context {
|
||||
StatContext::PoiseResilience(base) => {
|
||||
let poise_res = combat::compute_poise_resilience(data.inventory, data.msm);
|
||||
poise_res.unwrap_or(0.0) / base
|
||||
},
|
||||
};
|
||||
match self.field {
|
||||
StatField::EffectPower => {
|
||||
stats.effect_power += add;
|
||||
},
|
||||
}
|
||||
stats
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub struct StatAdj {
|
||||
pub context: StatContext,
|
||||
pub field: StatField,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub enum StatContext {
|
||||
PoiseResilience(f32),
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub enum StatField {
|
||||
EffectPower,
|
||||
}
|
||||
|
||||
// TODO: Later move over things like energy and combo into here
|
||||
|
@ -133,8 +133,7 @@ impl MeleeConstructor {
|
||||
CombatEffect::Knockback(Knockback {
|
||||
strength: knockback,
|
||||
direction: KnockbackDir::Away,
|
||||
})
|
||||
.adjusted_by_stats(tool_stats),
|
||||
}),
|
||||
)
|
||||
.with_requirement(CombatRequirement::AnyDamage);
|
||||
|
||||
@ -183,8 +182,7 @@ impl MeleeConstructor {
|
||||
CombatEffect::Knockback(Knockback {
|
||||
strength: knockback,
|
||||
direction: KnockbackDir::Away,
|
||||
})
|
||||
.adjusted_by_stats(tool_stats),
|
||||
}),
|
||||
)
|
||||
.with_requirement(CombatRequirement::AnyDamage);
|
||||
|
||||
@ -225,8 +223,7 @@ impl MeleeConstructor {
|
||||
CombatEffect::Knockback(Knockback {
|
||||
strength: knockback,
|
||||
direction: KnockbackDir::Away,
|
||||
})
|
||||
.adjusted_by_stats(tool_stats),
|
||||
}),
|
||||
)
|
||||
.with_requirement(CombatRequirement::AnyDamage);
|
||||
|
||||
@ -272,8 +269,7 @@ impl MeleeConstructor {
|
||||
CombatEffect::Knockback(Knockback {
|
||||
strength: pull,
|
||||
direction: KnockbackDir::Towards,
|
||||
})
|
||||
.adjusted_by_stats(tool_stats),
|
||||
}),
|
||||
)
|
||||
.with_requirement(CombatRequirement::AnyDamage);
|
||||
|
||||
@ -310,8 +306,7 @@ impl MeleeConstructor {
|
||||
CombatEffect::Knockback(Knockback {
|
||||
strength: pull,
|
||||
direction: KnockbackDir::Towards,
|
||||
})
|
||||
.adjusted_by_stats(tool_stats),
|
||||
}),
|
||||
)
|
||||
.with_requirement(CombatRequirement::AnyDamage);
|
||||
|
||||
@ -347,8 +342,7 @@ impl MeleeConstructor {
|
||||
CombatEffect::Knockback(Knockback {
|
||||
strength: knockback,
|
||||
direction: KnockbackDir::Away,
|
||||
})
|
||||
.adjusted_by_stats(tool_stats),
|
||||
}),
|
||||
)
|
||||
.with_requirement(CombatRequirement::AnyDamage);
|
||||
|
||||
@ -581,52 +575,59 @@ impl MeleeConstructorKind {
|
||||
Slash {
|
||||
ref mut damage,
|
||||
ref mut poise,
|
||||
knockback: _,
|
||||
ref mut knockback,
|
||||
energy_regen: _,
|
||||
} => {
|
||||
*damage *= stats.power;
|
||||
*poise *= stats.effect_power;
|
||||
*knockback *= stats.effect_power;
|
||||
},
|
||||
Stab {
|
||||
ref mut damage,
|
||||
ref mut poise,
|
||||
knockback: _,
|
||||
ref mut knockback,
|
||||
energy_regen: _,
|
||||
} => {
|
||||
*damage *= stats.power;
|
||||
*poise *= stats.effect_power;
|
||||
*knockback *= stats.effect_power;
|
||||
},
|
||||
Bash {
|
||||
ref mut damage,
|
||||
ref mut poise,
|
||||
knockback: _,
|
||||
ref mut knockback,
|
||||
energy_regen: _,
|
||||
} => {
|
||||
*damage *= stats.power;
|
||||
*poise *= stats.effect_power;
|
||||
*knockback *= stats.effect_power;
|
||||
},
|
||||
Hook {
|
||||
ref mut damage,
|
||||
ref mut poise,
|
||||
pull: _,
|
||||
ref mut pull,
|
||||
} => {
|
||||
*damage *= stats.power;
|
||||
*poise *= stats.effect_power;
|
||||
*pull *= stats.effect_power;
|
||||
},
|
||||
NecroticVortex {
|
||||
ref mut damage,
|
||||
pull: _,
|
||||
lifesteal: _,
|
||||
ref mut pull,
|
||||
ref mut lifesteal,
|
||||
} => {
|
||||
*damage *= stats.power;
|
||||
*pull *= stats.effect_power;
|
||||
*lifesteal *= stats.effect_power;
|
||||
},
|
||||
SonicWave {
|
||||
ref mut damage,
|
||||
ref mut poise,
|
||||
knockback: _,
|
||||
ref mut knockback,
|
||||
} => {
|
||||
*damage *= stats.power;
|
||||
*poise *= stats.effect_power;
|
||||
*knockback *= stats.effect_power;
|
||||
},
|
||||
}
|
||||
self
|
||||
|
@ -1,10 +1,8 @@
|
||||
use crate::{
|
||||
combat::{DamageContributor, DamageSource},
|
||||
combat::{compute_poise_resilience, DamageContributor, DamageSource},
|
||||
comp::{
|
||||
self,
|
||||
ability::Capability,
|
||||
inventory::item::{armor::Protection, ItemKind, MaterialStatManifest},
|
||||
CharacterState, Inventory, Stats,
|
||||
self, ability::Capability, inventory::item::MaterialStatManifest, CharacterState,
|
||||
Inventory, Stats,
|
||||
},
|
||||
resources::Time,
|
||||
states,
|
||||
@ -262,23 +260,7 @@ impl Poise {
|
||||
char_state: Option<&CharacterState>,
|
||||
stats: Option<&Stats>,
|
||||
) -> f32 {
|
||||
let protection = inventory.map_or(Some(0.0), |inv| {
|
||||
inv.equipped_items()
|
||||
.filter_map(|item| {
|
||||
if let ItemKind::Armor(armor) = &*item.kind() {
|
||||
armor
|
||||
.stats(msm, item.stats_durability_multiplier())
|
||||
.poise_resilience
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.map(|protection| match protection {
|
||||
Protection::Normal(protection) => Some(protection),
|
||||
Protection::Invincible => None,
|
||||
})
|
||||
.sum::<Option<f32>>()
|
||||
});
|
||||
let protection = compute_poise_resilience(inventory, msm);
|
||||
let from_inventory = match protection {
|
||||
Some(dr) => dr / (60.0 + dr.abs()),
|
||||
None => 1.0,
|
||||
|
@ -1,9 +1,6 @@
|
||||
use crate::{
|
||||
combat,
|
||||
comp::{
|
||||
character_state::OutputEvents, item::tool, CharacterState, Melee, MeleeConstructor,
|
||||
MeleeConstructorKind, StateUpdate,
|
||||
},
|
||||
comp::{character_state::OutputEvents, CharacterState, MeleeConstructor, StateUpdate},
|
||||
states::{
|
||||
behavior::{CharacterBehavior, JoinData},
|
||||
utils::*,
|
||||
@ -19,8 +16,6 @@ pub struct StaticData {
|
||||
pub energy_drain: f32,
|
||||
/// How quickly dasher moves forward
|
||||
pub forward_speed: f32,
|
||||
/// Whether the state can charge through enemies and do a second hit
|
||||
pub charge_through: bool,
|
||||
/// How long until state should deal damage
|
||||
pub buildup_duration: Duration,
|
||||
/// How long the state charges for until it reaches max damage
|
||||
@ -33,6 +28,8 @@ pub struct StaticData {
|
||||
pub melee_constructor: MeleeConstructor,
|
||||
/// How fast can you turn during charge
|
||||
pub ori_modifier: f32,
|
||||
/// Controls whether charge should always go until end or enemy hit
|
||||
pub auto_charge: bool,
|
||||
/// What key is used to press ability
|
||||
pub ability_info: AbilityInfo,
|
||||
}
|
||||
@ -49,10 +46,6 @@ pub struct Data {
|
||||
pub timer: Duration,
|
||||
/// What section the character stage is in
|
||||
pub stage_section: StageSection,
|
||||
/// Whether the state should attempt attacking again
|
||||
pub exhausted: bool,
|
||||
/// Time that charge should end (used for charge through)
|
||||
pub charge_end_timer: Duration,
|
||||
}
|
||||
|
||||
impl CharacterBehavior for Data {
|
||||
@ -82,7 +75,8 @@ impl CharacterBehavior for Data {
|
||||
} else {
|
||||
// Transitions to charge section of stage
|
||||
update.character = CharacterState::DashMelee(Data {
|
||||
auto_charge: !input_is_pressed(data, self.static_data.ability_info.input),
|
||||
auto_charge: !input_is_pressed(data, self.static_data.ability_info.input)
|
||||
|| self.static_data.auto_charge,
|
||||
timer: Duration::default(),
|
||||
stage_section: StageSection::Charge,
|
||||
..*self
|
||||
@ -90,9 +84,9 @@ impl CharacterBehavior for Data {
|
||||
}
|
||||
},
|
||||
StageSection::Charge => {
|
||||
if self.timer < self.charge_end_timer
|
||||
if self.timer < self.static_data.charge_duration
|
||||
&& (input_is_pressed(data, self.static_data.ability_info.input)
|
||||
|| (self.auto_charge && self.timer < self.static_data.charge_duration))
|
||||
|| self.auto_charge)
|
||||
&& update.energy.current() >= 0.0
|
||||
{
|
||||
// Forward movement
|
||||
@ -109,27 +103,9 @@ impl CharacterBehavior for Data {
|
||||
),
|
||||
);
|
||||
|
||||
// This logic basically just decides if a charge should end,
|
||||
// and prevents the character state spamming attacks
|
||||
// while checking if it has hit something.
|
||||
if !self.exhausted {
|
||||
// If charge through, use actual melee strike, otherwise just use a test
|
||||
// strike to "probe" to see when to end charge
|
||||
let melee = if self.static_data.charge_through {
|
||||
create_melee(charge_frac)
|
||||
} else {
|
||||
create_test_melee(self.static_data)
|
||||
};
|
||||
|
||||
// Hit attempt
|
||||
data.updater.insert(data.entity, melee);
|
||||
|
||||
update.character = CharacterState::DashMelee(Data {
|
||||
timer: tick_attack_or_default(data, self.timer, None),
|
||||
exhausted: true,
|
||||
..*self
|
||||
})
|
||||
} else if let Some(melee) = data.melee_attack {
|
||||
// Determines if charge ends by continually refreshing melee component until it
|
||||
// detects a hit, at which point the charge ends
|
||||
if let Some(melee) = data.melee_attack {
|
||||
if !melee.applied {
|
||||
// If melee attack has not applied, just tick duration
|
||||
update.character = CharacterState::DashMelee(Data {
|
||||
@ -137,31 +113,10 @@ impl CharacterBehavior for Data {
|
||||
..*self
|
||||
});
|
||||
} else if melee.hit_count == 0 {
|
||||
// If melee attack has applied, but not hit anything, remove exhausted
|
||||
// so it can attack again
|
||||
// If melee attack has applied, but not hit anything, reset melee attack
|
||||
data.updater.insert(data.entity, create_melee(charge_frac));
|
||||
update.character = CharacterState::DashMelee(Data {
|
||||
timer: tick_attack_or_default(data, self.timer, None),
|
||||
exhausted: false,
|
||||
..*self
|
||||
});
|
||||
} else if self.static_data.charge_through {
|
||||
// If can charge through, set charge_end_timer to stop after a little
|
||||
// more time
|
||||
let charge_end_timer =
|
||||
if self.charge_end_timer != self.static_data.charge_duration {
|
||||
self.charge_end_timer
|
||||
} else {
|
||||
self.timer
|
||||
.checked_add(Duration::from_secs_f32(
|
||||
0.2 * self.static_data.melee_constructor.range
|
||||
/ self.static_data.forward_speed,
|
||||
))
|
||||
.unwrap_or(self.static_data.charge_duration)
|
||||
.min(self.static_data.charge_duration)
|
||||
};
|
||||
update.character = CharacterState::DashMelee(Data {
|
||||
timer: tick_attack_or_default(data, self.timer, None),
|
||||
charge_end_timer,
|
||||
..*self
|
||||
});
|
||||
} else {
|
||||
@ -169,16 +124,15 @@ impl CharacterBehavior for Data {
|
||||
update.character = CharacterState::DashMelee(Data {
|
||||
timer: Duration::default(),
|
||||
stage_section: StageSection::Action,
|
||||
exhausted: false,
|
||||
charge_end_timer: self.timer,
|
||||
..*self
|
||||
});
|
||||
}
|
||||
} else {
|
||||
// If melee attack has not applied, just tick duration
|
||||
// If no melee attack, add it and tick duration
|
||||
data.updater.insert(data.entity, create_melee(charge_frac));
|
||||
|
||||
update.character = CharacterState::DashMelee(Data {
|
||||
timer: tick_attack_or_default(data, self.timer, None),
|
||||
exhausted: false,
|
||||
..*self
|
||||
});
|
||||
}
|
||||
@ -192,39 +146,12 @@ impl CharacterBehavior for Data {
|
||||
update.character = CharacterState::DashMelee(Data {
|
||||
timer: Duration::default(),
|
||||
stage_section: StageSection::Action,
|
||||
exhausted: false,
|
||||
charge_end_timer: self.timer,
|
||||
..*self
|
||||
});
|
||||
}
|
||||
},
|
||||
StageSection::Action => {
|
||||
if !self.exhausted {
|
||||
// If can charge through and not exhausted, do one more melee attack
|
||||
// If not charge through, actual melee attack happens now
|
||||
|
||||
// Assumes charge got to charge_end_timer for damage calculations
|
||||
let charge_frac = (self.charge_end_timer.as_secs_f32()
|
||||
/ self.static_data.charge_duration.as_secs_f32())
|
||||
.min(1.0);
|
||||
|
||||
let precision_mult = combat::compute_precision_mult(data.inventory, data.msm);
|
||||
let tool_stats = get_tool_stats(data, self.static_data.ability_info);
|
||||
|
||||
data.updater.insert(
|
||||
data.entity,
|
||||
self.static_data
|
||||
.melee_constructor
|
||||
.handle_scaling(charge_frac)
|
||||
.create_melee(precision_mult, tool_stats),
|
||||
);
|
||||
|
||||
update.character = CharacterState::DashMelee(Data {
|
||||
timer: tick_attack_or_default(data, self.timer, None),
|
||||
exhausted: true,
|
||||
..*self
|
||||
})
|
||||
} else if self.timer < self.static_data.swing_duration {
|
||||
if self.timer < self.static_data.swing_duration {
|
||||
// Swings
|
||||
update.character = CharacterState::DashMelee(Data {
|
||||
timer: tick_attack_or_default(data, self.timer, None),
|
||||
@ -263,22 +190,3 @@ impl CharacterBehavior for Data {
|
||||
update
|
||||
}
|
||||
}
|
||||
|
||||
fn create_test_melee(static_data: StaticData) -> Melee {
|
||||
let melee = MeleeConstructor {
|
||||
kind: MeleeConstructorKind::Slash {
|
||||
damage: 0.0,
|
||||
poise: 0.0,
|
||||
knockback: 0.0,
|
||||
energy_regen: 0.0,
|
||||
},
|
||||
scaled: None,
|
||||
range: static_data.melee_constructor.range,
|
||||
angle: static_data.melee_constructor.angle,
|
||||
multi_target: None,
|
||||
damage_effect: None,
|
||||
simultaneous_hits: 1,
|
||||
custom_combo: None,
|
||||
};
|
||||
melee.create_melee(0.0, tool::Stats::one())
|
||||
}
|
||||
|
@ -1300,6 +1300,12 @@ fn handle_ability(
|
||||
&context,
|
||||
)
|
||||
})
|
||||
.map(|(mut a, f, s)| {
|
||||
if let Some(contextual_stats) = a.ability_meta().contextual_stats {
|
||||
a = a.adjusted_by_stats(contextual_stats.equivalent_stats(data))
|
||||
}
|
||||
(a, f, s)
|
||||
})
|
||||
.filter(|(ability, _, _)| ability.requirements_paid(data, update))
|
||||
{
|
||||
update.character = CharacterState::from((
|
||||
|
@ -1,21 +1,12 @@
|
||||
use super::{
|
||||
super::{vek::*, Animation},
|
||||
CharacterSkeleton, SkeletonAttr,
|
||||
};
|
||||
use common::{
|
||||
comp::item::Hands,
|
||||
states::utils::{AbilityInfo, StageSection},
|
||||
dual_wield_start, hammer_start, twist_back, twist_forward, CharacterSkeleton, SkeletonAttr,
|
||||
};
|
||||
use common::states::utils::StageSection;
|
||||
|
||||
pub struct DashAnimation;
|
||||
|
||||
type DashAnimationDependency<'a> = (
|
||||
(Option<Hands>, Option<Hands>),
|
||||
Option<&'a str>,
|
||||
f32,
|
||||
Option<StageSection>,
|
||||
Option<AbilityInfo>,
|
||||
);
|
||||
type DashAnimationDependency<'a> = (Option<&'a str>, StageSection);
|
||||
impl Animation for DashAnimation {
|
||||
type Dependency<'a> = DashAnimationDependency<'a>;
|
||||
type Skeleton = CharacterSkeleton;
|
||||
@ -27,20 +18,68 @@ impl Animation for DashAnimation {
|
||||
#[allow(clippy::single_match)] // TODO: Pending review in #587
|
||||
fn update_skeleton_inner(
|
||||
skeleton: &Self::Skeleton,
|
||||
(_hands, _ability_id, _global_time, _stage_section, _ability_info): Self::Dependency<'_>,
|
||||
_anim_time: f32,
|
||||
(ability_id, stage_section): Self::Dependency<'_>,
|
||||
anim_time: f32,
|
||||
rate: &mut f32,
|
||||
_s_a: &SkeletonAttr,
|
||||
s_a: &SkeletonAttr,
|
||||
) -> Self::Skeleton {
|
||||
*rate = 1.0;
|
||||
let mut next = (*skeleton).clone();
|
||||
|
||||
next.main.position = Vec3::new(0.0, 0.0, 0.0);
|
||||
next.main.orientation = Quaternion::rotation_z(0.0);
|
||||
next.main_weapon_trail = true;
|
||||
next.second.position = Vec3::new(0.0, 0.0, 0.0);
|
||||
next.second.orientation = Quaternion::rotation_z(0.0);
|
||||
next.off_weapon_trail = true;
|
||||
if matches!(stage_section, StageSection::Action | StageSection::Charge) {
|
||||
next.main_weapon_trail = true;
|
||||
next.off_weapon_trail = true;
|
||||
}
|
||||
|
||||
match ability_id {
|
||||
Some("common.abilities.hammer.intercept") => {
|
||||
hammer_start(&mut next, s_a);
|
||||
let (move1, _move2, move3, move4) = match stage_section {
|
||||
StageSection::Buildup => (anim_time, 0.0, 0.0, 0.0),
|
||||
StageSection::Charge => (1.0, anim_time, 0.0, 0.0),
|
||||
StageSection::Action => (1.0, 0.0, anim_time, 0.0),
|
||||
StageSection::Recover => (1.0, 0.0, 1.0, anim_time),
|
||||
_ => (0.0, 0.0, 0.0, 0.0),
|
||||
};
|
||||
let pullback = 1.0 - move4;
|
||||
let move1 = move1 * pullback;
|
||||
let move3 = move3 * pullback;
|
||||
|
||||
twist_back(&mut next, move1, 1.6, 0.7, 0.3, 1.1);
|
||||
next.control.orientation.rotate_x(move1 * 1.8);
|
||||
|
||||
twist_forward(&mut next, move3, 2.4, 0.9, 0.5, 1.4);
|
||||
next.control.orientation.rotate_z(move3 * -2.7);
|
||||
next.control.orientation.rotate_x(move3 * 2.0);
|
||||
next.control.position += Vec3::new(5.0, 0.0, 11.0) * move3;
|
||||
},
|
||||
Some("common.abilities.hammer.dual_intercept") => {
|
||||
dual_wield_start(&mut next);
|
||||
let (move1, _move2, move3, move4) = match stage_section {
|
||||
StageSection::Buildup => (anim_time, 0.0, 0.0, 0.0),
|
||||
StageSection::Charge => (1.0, anim_time, 0.0, 0.0),
|
||||
StageSection::Action => (1.0, 0.0, anim_time, 0.0),
|
||||
StageSection::Recover => (1.0, 0.0, 1.0, anim_time),
|
||||
_ => (0.0, 0.0, 0.0, 0.0),
|
||||
};
|
||||
let pullback = 1.0 - move4;
|
||||
let move1 = move1 * pullback;
|
||||
let move3 = move3 * pullback;
|
||||
|
||||
next.control_l.orientation.rotate_x(move1 * -1.4);
|
||||
next.control_l.orientation.rotate_z(move1 * 0.8);
|
||||
next.control_r.orientation.rotate_x(move1 * -1.4);
|
||||
next.control_r.orientation.rotate_z(move1 * -0.8);
|
||||
next.control.position += Vec3::new(0.0, 0.0, -6.0) * move1;
|
||||
|
||||
next.control_l.orientation.rotate_z(move3 * -2.6);
|
||||
next.control_l.orientation.rotate_x(move3 * 4.0);
|
||||
next.control_r.orientation.rotate_z(move3 * 2.6);
|
||||
next.control_r.orientation.rotate_x(move3 * 4.0);
|
||||
next.control.position += Vec3::new(0.0, 0.0, 20.0) * move3;
|
||||
},
|
||||
_ => {},
|
||||
}
|
||||
|
||||
next
|
||||
}
|
||||
|
@ -46,15 +46,13 @@ fn charged_melee_grid(ui: &mut Ui, data: &charged_melee::Data) {
|
||||
|
||||
fn dash_melee_grid(ui: &mut Ui, data: &dash_melee::Data) {
|
||||
Grid::new("selected_entity_dash_melee_grid")
|
||||
.spacing([40.0, 4.0])
|
||||
.max_col_width(100.0)
|
||||
.striped(true)
|
||||
.show(ui, |ui| #[rustfmt::skip] {
|
||||
.spacing([40.0, 4.0])
|
||||
.max_col_width(100.0)
|
||||
.striped(true)
|
||||
.show(ui, |ui| #[rustfmt::skip] {
|
||||
two_col_row(ui, "Auto Charge", if data.auto_charge { "True" } else { "False " });
|
||||
two_col_row(ui, "Timer", format!("{}ms", data.timer.as_millis()));
|
||||
two_col_row(ui, "Stage Section", data.stage_section.to_string());
|
||||
two_col_row(ui, "Exhausted", if data.exhausted { "True" } else { "False " });
|
||||
two_col_row(ui, "Charge End Timer", format!("{}ms", data.charge_end_timer.as_millis()));
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -321,6 +321,7 @@ image_ids! {
|
||||
hammer_tremor: "voxygen.element.skills.hammer.tremor",
|
||||
hammer_vigorous_bash: "voxygen.element.skills.hammer.vigorous_bash",
|
||||
hammer_heavy_whorl: "voxygen.element.skills.hammer.heavy_whorl",
|
||||
hammer_intercept: "voxygen.element.skills.hammer.intercept",
|
||||
// Skilltree Icons
|
||||
health_plus_skill: "voxygen.element.skills.skilltree.health_plus",
|
||||
energy_plus_skill: "voxygen.element.skills.skilltree.energy_plus",
|
||||
|
@ -629,6 +629,8 @@ pub fn ability_image(imgs: &img_ids::Imgs, ability_id: &str) -> image::Id {
|
||||
"common.abilities.hammer.vigorous_bash" => imgs.hammer_vigorous_bash,
|
||||
"common.abilities.hammer.heavy_whorl" => imgs.hammer_heavy_whorl,
|
||||
"common.abilities.hammer.dual_heavy_whorl" => imgs.hammer_heavy_whorl,
|
||||
"common.abilities.hammer.intercept" => imgs.hammer_intercept,
|
||||
"common.abilities.hammer.dual_intercept" => imgs.hammer_intercept,
|
||||
// Bow
|
||||
"common.abilities.bow.charged" => imgs.bow_m1,
|
||||
"common.abilities.bow.repeater" => imgs.bow_m2,
|
||||
|
@ -1611,9 +1611,7 @@ impl FigureMgr {
|
||||
StageSection::Buildup => {
|
||||
stage_time / s.static_data.buildup_duration.as_secs_f32()
|
||||
},
|
||||
StageSection::Charge => {
|
||||
stage_time / s.static_data.charge_duration.as_secs_f32()
|
||||
},
|
||||
StageSection::Charge => stage_time,
|
||||
StageSection::Action => {
|
||||
stage_time / s.static_data.swing_duration.as_secs_f32()
|
||||
},
|
||||
@ -1624,13 +1622,7 @@ impl FigureMgr {
|
||||
};
|
||||
anim::character::DashAnimation::update_skeleton(
|
||||
&target_base,
|
||||
(
|
||||
hands,
|
||||
ability_id,
|
||||
time,
|
||||
Some(s.stage_section),
|
||||
Some(s.static_data.ability_info),
|
||||
),
|
||||
(ability_id, s.stage_section),
|
||||
stage_progress,
|
||||
&mut state_animation_rate,
|
||||
skeleton_attr,
|
||||
|
Loading…
Reference in New Issue
Block a user