Intercept

This commit is contained in:
Sam 2024-02-21 22:42:55 -05:00
parent e24ebc381b
commit e858b84427
37 changed files with 283 additions and 220 deletions

View File

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

View File

@ -24,5 +24,5 @@ DashMelee(
swing_duration: 0.1,
recover_duration: 0.9,
ori_modifier: 0.3,
charge_through: false,
auto_charge: false,
)

View File

@ -24,5 +24,5 @@ DashMelee(
swing_duration: 0.25,
recover_duration: 0.8,
ori_modifier: 0.1,
charge_through: false,
auto_charge: false,
)

View File

@ -24,5 +24,5 @@ DashMelee(
swing_duration: 0.3,
recover_duration: 2.0,
ori_modifier: 0.1,
charge_through: false,
auto_charge: false,
)

View File

@ -24,5 +24,5 @@ DashMelee(
swing_duration: 0.1,
recover_duration: 1.4,
ori_modifier: 0.3,
charge_through: false,
auto_charge: false,
)

View File

@ -30,5 +30,5 @@ DashMelee(
swing_duration: 0.1,
recover_duration: 0.9,
ori_modifier: 0.3,
charge_through: false,
auto_charge: false,
)

View File

@ -24,5 +24,5 @@ DashMelee(
swing_duration: 0.1,
recover_duration: 2.0,
ori_modifier: 0.1,
charge_through: true,
auto_charge: false,
)

View File

@ -25,5 +25,5 @@ DashMelee(
swing_duration: 0.1,
recover_duration: 0.8,
ori_modifier: 0.1,
charge_through: false,
auto_charge: false,
)

View File

@ -24,5 +24,5 @@ DashMelee(
swing_duration: 0.35,
recover_duration: 2.0,
ori_modifier: 0.1,
charge_through: true,
auto_charge: false,
)

View File

@ -25,5 +25,5 @@ DashMelee(
swing_duration: 0.1,
recover_duration: 1.2,
ori_modifier: 0.1,
charge_through: false,
auto_charge: false,
)

View File

@ -31,5 +31,5 @@ DashMelee(
swing_duration: 0.1,
recover_duration: 3.4,
ori_modifier: 0.1,
charge_through: false,
auto_charge: false,
)

View File

@ -24,5 +24,5 @@ DashMelee(
swing_duration: 0.35,
recover_duration: 2.4,
ori_modifier: 0.3,
charge_through: false,
auto_charge: false,
)

View File

@ -24,5 +24,5 @@ DashMelee(
swing_duration: 0.35,
recover_duration: 2.0,
ori_modifier: 0.1,
charge_through: false,
auto_charge: false,
)

View File

@ -24,5 +24,5 @@ DashMelee(
swing_duration: 0.35,
recover_duration: 2.0,
ori_modifier: 0.1,
charge_through: false,
auto_charge: false,
)

View File

@ -24,5 +24,5 @@ DashMelee(
swing_duration: 0.4,
recover_duration: 1.2,
ori_modifier: 0.3,
charge_through: false,
auto_charge: false,
)

View File

@ -24,5 +24,5 @@ DashMelee(
swing_duration: 0.65,
recover_duration: 2.0,
ori_modifier: 0.1,
charge_through: false,
auto_charge: false,
)

View File

@ -24,5 +24,5 @@ DashMelee(
swing_duration: 0.1,
recover_duration: 2.2,
ori_modifier: 0.3,
charge_through: false,
auto_charge: false,
)

View File

@ -24,5 +24,5 @@ DashMelee(
swing_duration: 0.1,
recover_duration: 0.9,
ori_modifier: 0.3,
charge_through: false,
auto_charge: false,
)

View File

@ -24,5 +24,5 @@ DashMelee(
swing_duration: 0.3,
recover_duration: 0.7,
ori_modifier: 0.1,
charge_through: false,
auto_charge: false,
)

View File

@ -25,5 +25,5 @@ DashMelee(
swing_duration: 0.1,
recover_duration: 1.0,
ori_modifier: 0.3,
charge_through: false,
auto_charge: false,
)

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

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

View File

@ -24,5 +24,5 @@ DashMelee(
swing_duration: 0.1,
recover_duration: 0.8,
ori_modifier: 0.3,
charge_through: false,
auto_charge: false,
)

View File

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

Binary file not shown.

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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()));
});
}

View File

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

View File

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

View File

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