From cf573a42bd2f10dbb434c4f50dbe5141d8b3103f Mon Sep 17 00:00:00 2001 From: Sam Date: Thu, 3 Sep 2020 20:54:59 -0500 Subject: [PATCH 01/28] Initial implementation of combo melee attack. --- assets/voxygen/audio/sfx.ron | 12 +- common/src/comp/ability.rs | 52 +++--- common/src/comp/character_state.rs | 8 +- common/src/comp/inventory/item/tool.rs | 93 ++++++++++- common/src/states/combo_melee.rs | 170 +++++++++++++++++++ common/src/states/mod.rs | 2 +- common/src/states/triple_strike.rs | 220 ------------------------- common/src/sys/character_behavior.rs | 4 +- common/src/sys/stats.rs | 2 +- voxygen/src/audio/sfx/mod.rs | 2 +- voxygen/src/scene/figure/mod.rs | 9 +- 11 files changed, 300 insertions(+), 274 deletions(-) create mode 100644 common/src/states/combo_melee.rs delete mode 100644 common/src/states/triple_strike.rs diff --git a/assets/voxygen/audio/sfx.ron b/assets/voxygen/audio/sfx.ron index ff697a90b4..a44789e880 100644 --- a/assets/voxygen/audio/sfx.ron +++ b/assets/voxygen/audio/sfx.ron @@ -94,19 +94,19 @@ ], threshold: 0.5, ), - Attack(TripleStrike(First), Sword): ( + Attack(ComboMelee(First), Sword): ( files: [ "voxygen.audio.sfx.abilities.swing_sword", ], threshold: 0.7, ), - Attack(TripleStrike(Second), Sword): ( + Attack(ComboMelee(Second), Sword): ( files: [ "voxygen.audio.sfx.abilities.separated_second_swing", ], threshold: 0.7, ), - Attack(TripleStrike(Third), Sword): ( + Attack(ComboMelee(Third), Sword): ( files: [ "voxygen.audio.sfx.abilities.separated_third_swing", ], @@ -174,19 +174,19 @@ ], threshold: 0.5, ), - Attack(TripleStrike(First), Axe): ( + Attack(ComboMelee(First), Axe): ( files: [ "voxygen.audio.sfx.abilities.swing", ], threshold: 0.7, ), - Attack(TripleStrike(Second), Axe): ( + Attack(ComboMelee(Second), Axe): ( files: [ "voxygen.audio.sfx.abilities.swing", ], threshold: 0.7, ), - Attack(TripleStrike(Third), Axe): ( + Attack(ComboMelee(Third), Axe): ( files: [ "voxygen.audio.sfx.abilities.swing", ], diff --git a/common/src/comp/ability.rs b/common/src/comp/ability.rs index 4c328be14d..7e241908f3 100644 --- a/common/src/comp/ability.rs +++ b/common/src/comp/ability.rs @@ -1,10 +1,9 @@ use crate::{ comp::{ - ability::Stage, item::{armor::Protection, Item, ItemKind}, Body, CharacterState, EnergySource, Gravity, LightEmitter, Projectile, StateUpdate, }, - states::{triple_strike::*, *}, + states::*, sys::character_behavior::JoinData, }; use arraygen::Arraygen; @@ -21,7 +20,7 @@ pub enum CharacterAbilityType { ChargedRanged, DashMelee, BasicBlock, - TripleStrike(Stage), + ComboMelee, LeapMelee, SpinMelee, GroundShockwave, @@ -36,7 +35,7 @@ impl From<&CharacterState> for CharacterAbilityType { CharacterState::DashMelee(_) => Self::DashMelee, CharacterState::BasicBlock => Self::BasicBlock, CharacterState::LeapMelee(_) => Self::LeapMelee, - CharacterState::TripleStrike(data) => Self::TripleStrike(data.stage), + CharacterState::ComboMelee(_) => Self::ComboMelee, CharacterState::SpinMelee(_) => Self::SpinMelee, CharacterState::ChargedRanged(_) => Self::ChargedRanged, CharacterState::GroundShockwave(_) => Self::ChargedRanged, @@ -79,9 +78,12 @@ pub enum CharacterAbility { }, BasicBlock, Roll, - TripleStrike { - base_damage: u32, - needs_timing: bool, + ComboMelee { + stage_data: Vec, + initial_energy_gain: u32, + max_energy_gain: u32, + energy_increase: u32, + combo_duration: Duration, }, LeapMelee { energy_cost: u32, @@ -130,11 +132,6 @@ impl CharacterAbility { /// applicable. pub fn requirements_paid(&self, data: &JoinData, update: &mut StateUpdate) -> bool { match self { - CharacterAbility::TripleStrike { .. } => { - data.physics.on_ground - && data.body.is_humanoid() - && data.inputs.look_dir.xy().magnitude_squared() > 0.01 - }, CharacterAbility::Roll => { data.physics.on_ground && data.body.is_humanoid() @@ -328,20 +325,23 @@ impl From<&CharacterAbility> for CharacterState { remaining_duration: Duration::from_millis(500), was_wielded: false, // false by default. utils might set it to true }), - CharacterAbility::TripleStrike { - base_damage, - needs_timing, - } => CharacterState::TripleStrike(triple_strike::Data { - base_damage: *base_damage, - stage: triple_strike::Stage::First, - stage_exhausted: false, - stage_time_active: Duration::default(), - initialized: false, - transition_style: if *needs_timing { - TransitionStyle::Timed(TimingState::NotPressed) - } else { - TransitionStyle::Hold(HoldingState::Holding) - }, + CharacterAbility::ComboMelee { + stage_data, + initial_energy_gain, + max_energy_gain, + energy_increase, + combo_duration, + } => CharacterState::ComboMelee(combo_melee::Data { + stage: 1, + num_stages: stage_data.len() as u32, + combo: 0, + stage_data: stage_data.clone(), + exhausted: false, + initial_energy_gain: *initial_energy_gain, + max_energy_gain: *max_energy_gain, + energy_increase: *energy_increase, + combo_duration: *combo_duration, + timer: Duration::default(), }), CharacterAbility::LeapMelee { energy_cost: _, diff --git a/common/src/comp/character_state.rs b/common/src/comp/character_state.rs index e262c86905..d6da8e4938 100644 --- a/common/src/comp/character_state.rs +++ b/common/src/comp/character_state.rs @@ -62,7 +62,7 @@ pub enum CharacterState { DashMelee(dash_melee::Data), /// A three-stage attack where each attack pushes player forward /// and successive attacks increase in damage, while player holds button. - TripleStrike(triple_strike::Data), + ComboMelee(combo_melee::Data), /// A leap followed by a small aoe ground attack LeapMelee(leap_melee::Data), /// Spin around, dealing damage to enemies surrounding you @@ -80,7 +80,7 @@ impl CharacterState { | CharacterState::BasicMelee(_) | CharacterState::BasicRanged(_) | CharacterState::DashMelee(_) - | CharacterState::TripleStrike(_) + | CharacterState::ComboMelee(_) | CharacterState::BasicBlock | CharacterState::LeapMelee(_) | CharacterState::SpinMelee(_) @@ -94,7 +94,7 @@ impl CharacterState { CharacterState::BasicMelee(_) | CharacterState::BasicRanged(_) | CharacterState::DashMelee(_) - | CharacterState::TripleStrike(_) + | CharacterState::ComboMelee(_) | CharacterState::LeapMelee(_) | CharacterState::SpinMelee(_) | CharacterState::ChargedRanged(_) @@ -107,7 +107,7 @@ impl CharacterState { CharacterState::BasicMelee(_) | CharacterState::BasicRanged(_) | CharacterState::DashMelee(_) - | CharacterState::TripleStrike(_) + | CharacterState::ComboMelee(_) | CharacterState::BasicBlock | CharacterState::LeapMelee(_) | CharacterState::ChargedRanged(_) diff --git a/common/src/comp/inventory/item/tool.rs b/common/src/comp/inventory/item/tool.rs index 58cb8aae6a..260acbb3a3 100644 --- a/common/src/comp/inventory/item/tool.rs +++ b/common/src/comp/inventory/item/tool.rs @@ -1,8 +1,11 @@ // Note: If you changes here "break" old character saves you can change the // version in voxygen\src\meta.rs in order to reset save files to being empty -use crate::comp::{ - body::object, projectile, Body, CharacterAbility, Gravity, LightEmitter, Projectile, +use crate::{ + comp::{ + body::object, projectile, Body, CharacterAbility, Gravity, LightEmitter, Projectile, + }, + states::combo_melee, }; use serde::{Deserialize, Serialize}; use std::time::Duration; @@ -116,9 +119,46 @@ impl Tool { match &self.kind { Sword(_) => vec![ - TripleStrike { - base_damage: (60.0 * self.base_power()) as u32, - needs_timing: false, + ComboMelee { + stage_data: vec![ + combo_melee::Stage { + stage: 1, + base_damage: 30, + max_damage: 50, + damage_increase: 10, + knockback: 5.0, + range: 3.5, + angle: 45.0, + base_buildup_duration: Duration::from_millis(150), + base_recover_duration: Duration::from_millis(100), + }, + combo_melee::Stage { + stage: 2, + base_damage: 50, + max_damage: 80, + damage_increase: 15, + knockback: 5.0, + range: 3.5, + angle: 45.0, + base_buildup_duration: Duration::from_millis(150), + base_recover_duration: Duration::from_millis(100), + }, + combo_melee::Stage { + stage: 3, + base_damage: 70, + max_damage: 110, + damage_increase: 20, + knockback: 5.0, + range: 3.5, + angle: 45.0, + base_buildup_duration: Duration::from_millis(150), + base_recover_duration: Duration::from_millis(100), + }, + ], + initial_energy_gain: 0, + max_energy_gain: 100, + energy_increase: 20, + combo_duration: Duration::from_millis(250), }, DashMelee { energy_cost: 700, @@ -128,9 +168,46 @@ impl Tool { }, ], Axe(_) => vec![ - TripleStrike { - base_damage: (80.0 * self.base_power()) as u32, - needs_timing: true, + ComboMelee { + stage_data: vec![ + combo_melee::Stage { + stage: 1, + base_damage: 30, + max_damage: 50, + damage_increase: 10, + knockback: 5.0, + range: 3.5, + angle: 45.0, + base_buildup_duration: Duration::from_millis(150), + base_recover_duration: Duration::from_millis(100), + }, + combo_melee::Stage { + stage: 2, + base_damage: 50, + max_damage: 80, + damage_increase: 15, + knockback: 5.0, + range: 3.5, + angle: 45.0, + base_buildup_duration: Duration::from_millis(150), + base_recover_duration: Duration::from_millis(100), + }, + combo_melee::Stage { + stage: 3, + base_damage: 70, + max_damage: 110, + damage_increase: 20, + knockback: 5.0, + range: 3.5, + angle: 45.0, + base_buildup_duration: Duration::from_millis(150), + base_recover_duration: Duration::from_millis(100), + }, + ], + initial_energy_gain: 0, + max_energy_gain: 100, + energy_increase: 20, + combo_duration: Duration::from_millis(250), }, SpinMelee { energy_cost: 100, diff --git a/common/src/states/combo_melee.rs b/common/src/states/combo_melee.rs new file mode 100644 index 0000000000..fb8789f8cb --- /dev/null +++ b/common/src/states/combo_melee.rs @@ -0,0 +1,170 @@ +use crate::{ + comp::{Attacking, CharacterState, EnergySource, StateUpdate}, + states::utils::*, + sys::character_behavior::{CharacterBehavior, JoinData}, +}; +use serde::{Deserialize, Serialize}; +use std::time::Duration; + +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +pub struct Stage { + /// Specifies which stage the combo attack is in + pub stage: u32, + /// Initial damage of stage + pub base_damage: u32, + /// Max damage of stage + pub max_damage: u32, + /// Damage scaling per combo + pub damage_increase: u32, + /// Knockback of stage + pub knockback: f32, + /// Range of attack + pub range: f32, + /// Angle of attack + pub angle: f32, + /// Initial buildup duration of stage (how long until state can deal damage) + pub base_buildup_duration: Duration, + /// Initial recover duration of stage (how long until character exits state) + pub base_recover_duration: Duration, +} + +/// A sequence of attacks that can incrementally become faster and more damaging. +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +pub struct Data { + /// Indicates what stage the combo is in + pub stage: u32, + /// Indicates number of stages in combo + pub num_stages: u32, + /// Number of consecutive strikes + pub combo: u32, + /// Data for first stage + pub stage_data: Vec, + /// Whether state can deal more damage + pub exhausted: bool, + /// Initial energy gain per strike + pub initial_energy_gain: u32, + /// Max energy gain per strike + pub max_energy_gain: u32, + /// Energy gain increase per combo + pub energy_increase: u32, + /// Duration for the next stage to be activated + pub combo_duration: Duration, + /// Timer for each stage + pub timer: Duration, +} + +impl CharacterBehavior for Data { + fn behavior(&self, data: &JoinData) -> StateUpdate { + let mut update = StateUpdate::from(data); + + handle_orientation(data, &mut update, 5.0); + handle_move(data, &mut update, 0.8); + + let stage_index = (self.stage - 1) as usize; + + if !self.exhausted && self.timer < self.stage_data[stage_index].base_buildup_duration { + // Build up + update.character = CharacterState::ComboMelee(Data { + stage: self.stage, + num_stages: self.num_stages, + combo: self.combo, + stage_data: self.stage_data.clone(), + exhausted: self.exhausted, + initial_energy_gain: self.initial_energy_gain, + max_energy_gain: self.max_energy_gain, + energy_increase: self.energy_increase, + combo_duration: self.combo_duration, + timer: self + .timer + .checked_add(Duration::from_secs_f32(data.dt.0)) + .unwrap_or_default(), + }); + } else if !self.exhausted { + // Hit attempt + data.updater.insert(data.entity, Attacking { + base_healthchange: -((self.stage_data[stage_index].max_damage.min(self.stage_data[stage_index].base_damage + self.combo / self.num_stages * self.stage_data[stage_index].damage_increase)) as i32), + range: self.stage_data[stage_index].range, + max_angle: self.stage_data[stage_index].angle.to_radians(), + applied: false, + hit_count: 0, + knockback: self.stage_data[stage_index].knockback, + }); + + update.character = CharacterState::ComboMelee(Data { + stage: self.stage, + num_stages: self.num_stages, + combo: self.combo, + stage_data: self.stage_data.clone(), + exhausted: true, + initial_energy_gain: self.initial_energy_gain, + max_energy_gain: self.max_energy_gain, + energy_increase: self.energy_increase, + combo_duration: self.combo_duration, + timer: Duration::default(), + }); + } else if self.timer < self.stage_data[stage_index].base_recover_duration { + update.character = CharacterState::ComboMelee(Data { + stage: self.stage, + num_stages: self.num_stages, + combo: self.combo, + stage_data: self.stage_data.clone(), + exhausted: self.exhausted, + initial_energy_gain: self.initial_energy_gain, + max_energy_gain: self.max_energy_gain, + energy_increase: self.energy_increase, + combo_duration: self.combo_duration, + timer: self + .timer + .checked_add(Duration::from_secs_f32(data.dt.0)) + .unwrap_or_default(), + }); + } else if self.timer < self.combo_duration + self.stage_data[stage_index].base_recover_duration { + if data.inputs.primary.is_pressed() { + update.character = CharacterState::ComboMelee(Data { + stage: (self.stage % self.num_stages) + 1, + num_stages: self.num_stages, + combo: self.combo + 1, + stage_data: self.stage_data.clone(), + exhausted: false, + initial_energy_gain: self.initial_energy_gain, + max_energy_gain: self.max_energy_gain, + energy_increase: self.energy_increase, + combo_duration: self.combo_duration, + timer: Duration::default(), + }); + } else { + update.character = CharacterState::ComboMelee(Data { + stage: self.stage, + num_stages: self.num_stages, + combo: self.combo, + stage_data: self.stage_data.clone(), + exhausted: self.exhausted, + initial_energy_gain: self.initial_energy_gain, + max_energy_gain: self.max_energy_gain, + energy_increase: self.energy_increase, + combo_duration: self.combo_duration, + timer: self + .timer + .checked_add(Duration::from_secs_f32(data.dt.0)) + .unwrap_or_default(), + }); + } + } else { + // Done + update.character = CharacterState::Wielding; + // Make sure attack component is removed + data.updater.remove::(data.entity); + } + + // Grant energy on successful hit + if let Some(attack) = data.attacking { + if attack.applied && attack.hit_count > 0 { + let energy = self.max_energy_gain.min(self.initial_energy_gain + self.combo * self.energy_increase) as i32; + data.updater.remove::(data.entity); + update.energy.change_by(energy, EnergySource::HitEnemy); + } + } + + update + } +} diff --git a/common/src/states/mod.rs b/common/src/states/mod.rs index 435d35683c..c2d04deca1 100644 --- a/common/src/states/mod.rs +++ b/common/src/states/mod.rs @@ -16,6 +16,6 @@ pub mod roll; pub mod sit; pub mod sneak; pub mod spin_melee; -pub mod triple_strike; +pub mod combo_melee; pub mod utils; pub mod wielding; diff --git a/common/src/states/triple_strike.rs b/common/src/states/triple_strike.rs deleted file mode 100644 index 127e83abfd..0000000000 --- a/common/src/states/triple_strike.rs +++ /dev/null @@ -1,220 +0,0 @@ -use crate::{ - comp::{Attacking, CharacterState, EnergySource, StateUpdate}, - states::utils::*, - sys::character_behavior::{CharacterBehavior, JoinData}, -}; -use serde::{Deserialize, Serialize}; -use std::time::Duration; -use vek::vec::Vec3; -use HoldingState::*; -use TimingState::*; -use TransitionStyle::*; - -// In millis -const STAGE_DURATION: u64 = 700; -const TIMING_DELAY: u64 = 350; -const INITIAL_ACCEL: f32 = 90.0; -const BASE_SPEED: f32 = 25.0; - -#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize, Eq, Hash)] -pub enum Stage { - First, - Second, - Third, -} - -#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize, Eq, Hash)] -pub enum TimingState { - NotPressed, - PressedEarly, - Success, -} - -#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize, Eq, Hash)] -pub enum HoldingState { - Holding, - Released, -} - -#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize, Eq, Hash)] -pub enum TransitionStyle { - /// Player must time a button press properly to transition - Timed(TimingState), - /// Player must hold button for whole move - Hold(HoldingState), -} - -/// ### A sequence of 3 incrementally increasing attacks. -/// -/// While holding down the `primary` button, perform a series of 3 attacks, -/// each one pushes the player forward as the character steps into the swings. -/// The player can let go of the left mouse button at any time -/// and stop their attacks by interrupting the attack animation. -#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize, Eq, Hash)] -pub struct Data { - /// The tool this state will read to handle damage, etc. - pub base_damage: u32, - /// What stage (of 3) the attack is in - pub stage: Stage, - /// How long current stage has been active - pub stage_time_active: Duration, - /// Whether current stage has exhausted its attack - pub stage_exhausted: bool, - /// Whether state has performed initialization logic - pub initialized: bool, - /// What this instance's current transition stat is - pub transition_style: TransitionStyle, -} - -impl CharacterBehavior for Data { - fn behavior(&self, data: &JoinData) -> StateUpdate { - let mut update = StateUpdate::from(data); - - handle_move(data, &mut update, 0.3); - - #[allow(clippy::or_fun_call)] // TODO: Pending review in #587 - let stage_time_active = self - .stage_time_active - .checked_add(Duration::from_secs_f32(data.dt.0)) - .unwrap_or(Duration::default()); - - if !self.initialized { - update.vel.0 = Vec3::zero(); - if let Some(dir) = data.inputs.look_dir.try_normalized() { - update.ori.0 = dir.into(); - } - } - let initialized = true; - - // Update transition - let transition_style = match self.transition_style { - Timed(state) => match state { - NotPressed => { - if data.inputs.primary.is_just_pressed() { - if stage_time_active > Duration::from_millis(TIMING_DELAY) { - Timed(Success) - } else { - Timed(PressedEarly) - } - } else { - self.transition_style - } - }, - _ => self.transition_style, - }, - Hold(_) => { - if !data.inputs.primary.is_pressed() { - Hold(Released) - } else { - self.transition_style - } - }, - }; - - // Handling movement - if stage_time_active < Duration::from_millis(STAGE_DURATION / 3) { - let adjusted_accel = match (self.stage, data.physics.touch_entities.is_empty()) { - (Stage::First, true) => INITIAL_ACCEL, - (Stage::Second, true) => INITIAL_ACCEL * 0.75, - (Stage::Third, true) => INITIAL_ACCEL * 0.75, - (_, _) => 0.0, - }; - - // Move player forward while in first third of each stage - if update.vel.0.magnitude_squared() < BASE_SPEED.powf(2.0) { - update.vel.0 += data.dt.0 * (adjusted_accel * Vec3::from(data.ori.0.xy())); - let mag2 = update.vel.0.magnitude_squared(); - if mag2 > BASE_SPEED.powf(2.0) { - update.vel.0 = update.vel.0.normalized() * BASE_SPEED; - } - }; - } else { - handle_orientation(data, &mut update, 50.0); - } - - // Handling attacking - update.character = if stage_time_active > Duration::from_millis(STAGE_DURATION / 2) - && !self.stage_exhausted - { - let dmg = match self.stage { - Stage::First => self.base_damage / 2, - Stage::Second => self.base_damage, - Stage::Third => (self.base_damage as f32 * 1.5) as u32, - }; - - update.vel.0 = Vec3::new(data.inputs.move_dir.x, data.inputs.move_dir.y, 0.0) * 5.0; - - // Try to deal damage in second half of stage - data.updater.insert(data.entity, Attacking { - base_healthchange: -(dmg as i32), - range: 3.5, - max_angle: 45_f32.to_radians(), - applied: false, - hit_count: 0, - knockback: 10.0, - }); - - CharacterState::TripleStrike(Data { - base_damage: self.base_damage, - stage: self.stage, - stage_time_active, - stage_exhausted: true, - initialized, - transition_style, - }) - } else if stage_time_active > Duration::from_millis(STAGE_DURATION) { - let next_stage = - // Determine whether stage can transition based on TransitionStyle - if let Hold(Holding) | Timed(Success) = transition_style { - // Determine what stage to transition to - match self.stage { - Stage::First => Some(Stage::Second), - Stage::Second => Some(Stage::Third), - Stage::Third => None, - } - } - // Player messed up inputs, don't transition - else { None }; - - update.vel.0 = Vec3::new(data.inputs.move_dir.x, data.inputs.move_dir.y, 0.0) * 5.0; - - if let Some(stage) = next_stage { - CharacterState::TripleStrike(Data { - base_damage: self.base_damage, - stage, - stage_time_active: Duration::default(), - stage_exhausted: false, - initialized, - transition_style: match transition_style { - Hold(_) => Hold(Holding), - Timed(_) => Timed(NotPressed), - }, - }) - } else { - // Make sure attack component is removed - data.updater.remove::(data.entity); - // Done - CharacterState::Wielding - } - } else { - CharacterState::TripleStrike(Data { - base_damage: self.base_damage, - stage: self.stage, - stage_time_active, - stage_exhausted: self.stage_exhausted, - initialized, - transition_style, - }) - }; - - // Grant energy on successful hit - if let Some(attack) = data.attacking { - if attack.applied && attack.hit_count > 0 { - data.updater.remove::(data.entity); - update.energy.change_by(50, EnergySource::HitEnemy); - } - } - - update - } -} diff --git a/common/src/sys/character_behavior.rs b/common/src/sys/character_behavior.rs index 2c4b38186d..7f608b01db 100644 --- a/common/src/sys/character_behavior.rs +++ b/common/src/sys/character_behavior.rs @@ -250,7 +250,7 @@ impl<'a> System<'a> for Sys { CharacterState::Roll(data) => data.handle_event(&j, action), CharacterState::Wielding => states::wielding::Data.handle_event(&j, action), CharacterState::Equipping(data) => data.handle_event(&j, action), - CharacterState::TripleStrike(data) => data.handle_event(&j, action), + CharacterState::ComboMelee(data) => data.handle_event(&j, action), CharacterState::BasicMelee(data) => data.handle_event(&j, action), CharacterState::BasicRanged(data) => data.handle_event(&j, action), CharacterState::Boost(data) => data.handle_event(&j, action), @@ -279,7 +279,7 @@ impl<'a> System<'a> for Sys { CharacterState::Roll(data) => data.behavior(&j), CharacterState::Wielding => states::wielding::Data.behavior(&j), CharacterState::Equipping(data) => data.behavior(&j), - CharacterState::TripleStrike(data) => data.behavior(&j), + CharacterState::ComboMelee(data) => data.behavior(&j), CharacterState::BasicMelee(data) => data.behavior(&j), CharacterState::BasicRanged(data) => data.behavior(&j), CharacterState::Boost(data) => data.behavior(&j), diff --git a/common/src/sys/stats.rs b/common/src/sys/stats.rs index e7b26d9436..2252c0de72 100644 --- a/common/src/sys/stats.rs +++ b/common/src/sys/stats.rs @@ -110,7 +110,7 @@ impl<'a> System<'a> for Sys { | CharacterState::DashMelee { .. } | CharacterState::LeapMelee { .. } | CharacterState::SpinMelee { .. } - | CharacterState::TripleStrike { .. } + | CharacterState::ComboMelee { .. } | CharacterState::BasicRanged { .. } | CharacterState::ChargedRanged { .. } | CharacterState::GroundShockwave { .. } => { diff --git a/voxygen/src/audio/sfx/mod.rs b/voxygen/src/audio/sfx/mod.rs index 9e0fe94c06..3c238bfa02 100644 --- a/voxygen/src/audio/sfx/mod.rs +++ b/voxygen/src/audio/sfx/mod.rs @@ -71,7 +71,7 @@ //! ], //! threshold: 1.2, //! ), -//! // A multi-stage attack ability which depends on the weapon +//! // A multi-stage attack ability which depends on the weapon (To do: update example) //! Attack(TripleStrike(First), Sword): ( //! files: [ //! "voxygen.audio.sfx.weapon.sword_03", diff --git a/voxygen/src/scene/figure/mod.rs b/voxygen/src/scene/figure/mod.rs index 93793d9819..ece2054e7a 100644 --- a/voxygen/src/scene/figure/mod.rs +++ b/voxygen/src/scene/figure/mod.rs @@ -30,7 +30,6 @@ use common::{ }, span, state::{DeltaTime, State}, - states::triple_strike, terrain::TerrainChunk, vol::RectRasterableVol, }; @@ -912,8 +911,8 @@ impl FigureMgr { skeleton_attr, ) }, - CharacterState::TripleStrike(s) => match s.stage { - triple_strike::Stage::First => { + CharacterState::ComboMelee(s) => match s.stage { + 1 => { anim::character::AlphaAnimation::update_skeleton( &target_base, (active_tool_kind, second_tool_kind, vel.0.magnitude(), time), @@ -922,7 +921,7 @@ impl FigureMgr { skeleton_attr, ) }, - triple_strike::Stage::Second => { + 2 => { anim::character::SpinAnimation::update_skeleton( &target_base, (active_tool_kind, second_tool_kind, time), @@ -931,7 +930,7 @@ impl FigureMgr { skeleton_attr, ) }, - triple_strike::Stage::Third => { + _ => { anim::character::BetaAnimation::update_skeleton( &target_base, (active_tool_kind, second_tool_kind, vel.0.magnitude(), time), From aab56ea63629f655e648b92fe15a74d0aa025f45 Mon Sep 17 00:00:00 2001 From: Sam Date: Thu, 3 Sep 2020 21:29:58 -0500 Subject: [PATCH 02/28] Animation time for combo melee now resets between stages. --- common/src/comp/inventory/item/tool.rs | 4 +-- common/src/states/combo_melee.rs | 18 ++++++++--- common/src/states/mod.rs | 2 +- voxygen/src/scene/figure/mod.rs | 44 ++++++++++++++++---------- 4 files changed, 44 insertions(+), 24 deletions(-) diff --git a/common/src/comp/inventory/item/tool.rs b/common/src/comp/inventory/item/tool.rs index 260acbb3a3..1cdc6716fa 100644 --- a/common/src/comp/inventory/item/tool.rs +++ b/common/src/comp/inventory/item/tool.rs @@ -2,9 +2,7 @@ // version in voxygen\src\meta.rs in order to reset save files to being empty use crate::{ - comp::{ - body::object, projectile, Body, CharacterAbility, Gravity, LightEmitter, Projectile, - }, + comp::{body::object, projectile, Body, CharacterAbility, Gravity, LightEmitter, Projectile}, states::combo_melee, }; use serde::{Deserialize, Serialize}; diff --git a/common/src/states/combo_melee.rs b/common/src/states/combo_melee.rs index fb8789f8cb..25b2d86342 100644 --- a/common/src/states/combo_melee.rs +++ b/common/src/states/combo_melee.rs @@ -28,7 +28,8 @@ pub struct Stage { pub base_recover_duration: Duration, } -/// A sequence of attacks that can incrementally become faster and more damaging. +/// A sequence of attacks that can incrementally become faster and more +/// damaging. #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] pub struct Data { /// Indicates what stage the combo is in @@ -82,7 +83,11 @@ impl CharacterBehavior for Data { } else if !self.exhausted { // Hit attempt data.updater.insert(data.entity, Attacking { - base_healthchange: -((self.stage_data[stage_index].max_damage.min(self.stage_data[stage_index].base_damage + self.combo / self.num_stages * self.stage_data[stage_index].damage_increase)) as i32), + base_healthchange: -((self.stage_data[stage_index].max_damage.min( + self.stage_data[stage_index].base_damage + + self.combo / self.num_stages + * self.stage_data[stage_index].damage_increase, + )) as i32), range: self.stage_data[stage_index].range, max_angle: self.stage_data[stage_index].angle.to_radians(), applied: false, @@ -118,7 +123,9 @@ impl CharacterBehavior for Data { .checked_add(Duration::from_secs_f32(data.dt.0)) .unwrap_or_default(), }); - } else if self.timer < self.combo_duration + self.stage_data[stage_index].base_recover_duration { + } else if self.timer + < self.combo_duration + self.stage_data[stage_index].base_recover_duration + { if data.inputs.primary.is_pressed() { update.character = CharacterState::ComboMelee(Data { stage: (self.stage % self.num_stages) + 1, @@ -159,7 +166,10 @@ impl CharacterBehavior for Data { // Grant energy on successful hit if let Some(attack) = data.attacking { if attack.applied && attack.hit_count > 0 { - let energy = self.max_energy_gain.min(self.initial_energy_gain + self.combo * self.energy_increase) as i32; + let energy = self + .max_energy_gain + .min(self.initial_energy_gain + self.combo * self.energy_increase) + as i32; data.updater.remove::(data.entity); update.energy.change_by(energy, EnergySource::HitEnemy); } diff --git a/common/src/states/mod.rs b/common/src/states/mod.rs index c2d04deca1..c16c888aa9 100644 --- a/common/src/states/mod.rs +++ b/common/src/states/mod.rs @@ -4,6 +4,7 @@ pub mod basic_ranged; pub mod boost; pub mod charged_ranged; pub mod climb; +pub mod combo_melee; pub mod dance; pub mod dash_melee; pub mod equipping; @@ -16,6 +17,5 @@ pub mod roll; pub mod sit; pub mod sneak; pub mod spin_melee; -pub mod combo_melee; pub mod utils; pub mod wielding; diff --git a/voxygen/src/scene/figure/mod.rs b/voxygen/src/scene/figure/mod.rs index ece2054e7a..7c268fca19 100644 --- a/voxygen/src/scene/figure/mod.rs +++ b/voxygen/src/scene/figure/mod.rs @@ -911,34 +911,46 @@ impl FigureMgr { skeleton_attr, ) }, - CharacterState::ComboMelee(s) => match s.stage { - 1 => { - anim::character::AlphaAnimation::update_skeleton( + CharacterState::ComboMelee(s) => { + let stage_index = (s.stage - 1) as usize; + let stage_time = if !s.exhausted { + s.timer.as_secs_f64() + } else { + s.timer.as_secs_f64() + + s.stage_data[stage_index] + .base_buildup_duration + .as_secs_f64() + }; + let stage_progress = stage_time + / (s.stage_data[stage_index] + .base_buildup_duration + .as_secs_f64() + + s.stage_data[stage_index] + .base_recover_duration + .as_secs_f64()); + match s.stage { + 1 => anim::character::AlphaAnimation::update_skeleton( &target_base, (active_tool_kind, second_tool_kind, vel.0.magnitude(), time), - state.state_time, + stage_progress, &mut state_animation_rate, skeleton_attr, - ) - }, - 2 => { - anim::character::SpinAnimation::update_skeleton( + ), + 2 => anim::character::SpinAnimation::update_skeleton( &target_base, (active_tool_kind, second_tool_kind, time), - state.state_time, + stage_progress, &mut state_animation_rate, skeleton_attr, - ) - }, - _ => { - anim::character::BetaAnimation::update_skeleton( + ), + _ => anim::character::BetaAnimation::update_skeleton( &target_base, (active_tool_kind, second_tool_kind, vel.0.magnitude(), time), - state.state_time, + stage_progress, &mut state_animation_rate, skeleton_attr, - ) - }, + ), + } }, CharacterState::BasicBlock { .. } => { anim::character::BlockIdleAnimation::update_skeleton( From 440e45f2bccd3c6a4fc2f842676b8eb4489b8209 Mon Sep 17 00:00:00 2001 From: Sam Date: Sun, 6 Sep 2020 11:01:15 -0500 Subject: [PATCH 03/28] Did stuff to support addition of keyframes for combo melee animation. --- common/src/comp/ability.rs | 4 ++- common/src/states/combo_melee.rs | 53 ++++++++++++++++++++++++-------- voxygen/src/scene/figure/mod.rs | 28 +++++++++-------- 3 files changed, 58 insertions(+), 27 deletions(-) diff --git a/common/src/comp/ability.rs b/common/src/comp/ability.rs index 7e241908f3..1730c34d13 100644 --- a/common/src/comp/ability.rs +++ b/common/src/comp/ability.rs @@ -336,12 +336,14 @@ impl From<&CharacterAbility> for CharacterState { num_stages: stage_data.len() as u32, combo: 0, stage_data: stage_data.clone(), - exhausted: false, initial_energy_gain: *initial_energy_gain, max_energy_gain: *max_energy_gain, energy_increase: *energy_increase, combo_duration: *combo_duration, timer: Duration::default(), + in_buildup: true, + in_recover: false, + in_combo: false, }), CharacterAbility::LeapMelee { energy_cost: _, diff --git a/common/src/states/combo_melee.rs b/common/src/states/combo_melee.rs index 25b2d86342..3f4470c9f7 100644 --- a/common/src/states/combo_melee.rs +++ b/common/src/states/combo_melee.rs @@ -40,8 +40,6 @@ pub struct Data { pub combo: u32, /// Data for first stage pub stage_data: Vec, - /// Whether state can deal more damage - pub exhausted: bool, /// Initial energy gain per strike pub initial_energy_gain: u32, /// Max energy gain per strike @@ -52,6 +50,12 @@ pub struct Data { pub combo_duration: Duration, /// Timer for each stage pub timer: Duration, + /// Checks if state is in buildup duration + pub in_buildup: bool, + /// Checks if state is in recover duration + pub in_recover: bool, + /// Checks if state is in combo duration + pub in_combo: bool, } impl CharacterBehavior for Data { @@ -63,14 +67,13 @@ impl CharacterBehavior for Data { let stage_index = (self.stage - 1) as usize; - if !self.exhausted && self.timer < self.stage_data[stage_index].base_buildup_duration { + if self.in_buildup && self.timer < self.stage_data[stage_index].base_buildup_duration { // Build up update.character = CharacterState::ComboMelee(Data { stage: self.stage, num_stages: self.num_stages, combo: self.combo, stage_data: self.stage_data.clone(), - exhausted: self.exhausted, initial_energy_gain: self.initial_energy_gain, max_energy_gain: self.max_energy_gain, energy_increase: self.energy_increase, @@ -79,8 +82,11 @@ impl CharacterBehavior for Data { .timer .checked_add(Duration::from_secs_f32(data.dt.0)) .unwrap_or_default(), + in_buildup: self.in_buildup, + in_recover: self.in_recover, + in_combo: self.in_combo, }); - } else if !self.exhausted { + } else if self.in_buildup { // Hit attempt data.updater.insert(data.entity, Attacking { base_healthchange: -((self.stage_data[stage_index].max_damage.min( @@ -100,20 +106,21 @@ impl CharacterBehavior for Data { num_stages: self.num_stages, combo: self.combo, stage_data: self.stage_data.clone(), - exhausted: true, initial_energy_gain: self.initial_energy_gain, max_energy_gain: self.max_energy_gain, energy_increase: self.energy_increase, combo_duration: self.combo_duration, timer: Duration::default(), + in_buildup: false, + in_recover: true, + in_combo: self.in_combo, }); - } else if self.timer < self.stage_data[stage_index].base_recover_duration { + } else if self.in_recover && self.timer < self.stage_data[stage_index].base_recover_duration { update.character = CharacterState::ComboMelee(Data { stage: self.stage, num_stages: self.num_stages, combo: self.combo, stage_data: self.stage_data.clone(), - exhausted: self.exhausted, initial_energy_gain: self.initial_energy_gain, max_energy_gain: self.max_energy_gain, energy_increase: self.energy_increase, @@ -122,22 +129,40 @@ impl CharacterBehavior for Data { .timer .checked_add(Duration::from_secs_f32(data.dt.0)) .unwrap_or_default(), + in_buildup: self.in_buildup, + in_recover: self.in_recover, + in_combo: self.in_combo, }); - } else if self.timer - < self.combo_duration + self.stage_data[stage_index].base_recover_duration - { + } else if self.in_recover { + update.character = CharacterState::ComboMelee(Data { + stage: self.stage, + num_stages: self.num_stages, + combo: self.combo, + stage_data: self.stage_data.clone(), + initial_energy_gain: self.initial_energy_gain, + max_energy_gain: self.max_energy_gain, + energy_increase: self.energy_increase, + combo_duration: self.combo_duration, + timer: Duration::default(), + in_buildup: self.in_buildup, + in_recover: false, + in_combo: true, + }); + } else if self.in_combo && self.timer < self.combo_duration { if data.inputs.primary.is_pressed() { update.character = CharacterState::ComboMelee(Data { stage: (self.stage % self.num_stages) + 1, num_stages: self.num_stages, combo: self.combo + 1, stage_data: self.stage_data.clone(), - exhausted: false, initial_energy_gain: self.initial_energy_gain, max_energy_gain: self.max_energy_gain, energy_increase: self.energy_increase, combo_duration: self.combo_duration, timer: Duration::default(), + in_buildup: true, + in_recover: self.in_recover, + in_combo: false, }); } else { update.character = CharacterState::ComboMelee(Data { @@ -145,7 +170,6 @@ impl CharacterBehavior for Data { num_stages: self.num_stages, combo: self.combo, stage_data: self.stage_data.clone(), - exhausted: self.exhausted, initial_energy_gain: self.initial_energy_gain, max_energy_gain: self.max_energy_gain, energy_increase: self.energy_increase, @@ -154,6 +178,9 @@ impl CharacterBehavior for Data { .timer .checked_add(Duration::from_secs_f32(data.dt.0)) .unwrap_or_default(), + in_buildup: self.in_buildup, + in_recover: self.in_recover, + in_combo: self.in_combo, }); } } else { diff --git a/voxygen/src/scene/figure/mod.rs b/voxygen/src/scene/figure/mod.rs index 7c268fca19..de09039499 100644 --- a/voxygen/src/scene/figure/mod.rs +++ b/voxygen/src/scene/figure/mod.rs @@ -913,21 +913,23 @@ impl FigureMgr { }, CharacterState::ComboMelee(s) => { let stage_index = (s.stage - 1) as usize; - let stage_time = if !s.exhausted { - s.timer.as_secs_f64() + let stage_time = s.timer.as_secs_f64(); + let swing_frac = 0.5; // What percentage of buildup is swing animation + let in_swing: bool; + let stage_progress = if s.in_buildup { + let buildup_progress = stage_time / s.stage_data[stage_index].base_buildup_duration.as_secs_f64(); + if buildup_progress < swing_frac { + in_swing = false; + buildup_progress / (1.0 - swing_frac) + } else { + in_swing = true; + (buildup_progress - (1.0 - swing_frac)) / swing_frac + } + } else if s.in_recover { + stage_time / s.stage_data[stage_index].base_recover_duration.as_secs_f64() } else { - s.timer.as_secs_f64() - + s.stage_data[stage_index] - .base_buildup_duration - .as_secs_f64() + stage_time / s.combo_duration.as_secs_f64() }; - let stage_progress = stage_time - / (s.stage_data[stage_index] - .base_buildup_duration - .as_secs_f64() - + s.stage_data[stage_index] - .base_recover_duration - .as_secs_f64()); match s.stage { 1 => anim::character::AlphaAnimation::update_skeleton( &target_base, From 0ba5740265b4eb5e8439686fdfb719d1eaf3e813 Mon Sep 17 00:00:00 2001 From: Sam Date: Sun, 6 Sep 2020 16:46:53 -0500 Subject: [PATCH 04/28] Added enum for stage section instead of using 4 bools. --- common/src/comp/ability.rs | 4 +-- common/src/states/combo_melee.rs | 51 ++++++++++++++------------------ voxygen/src/scene/figure/mod.rs | 33 ++++++++++++--------- 3 files changed, 42 insertions(+), 46 deletions(-) diff --git a/common/src/comp/ability.rs b/common/src/comp/ability.rs index 1730c34d13..096092a8fb 100644 --- a/common/src/comp/ability.rs +++ b/common/src/comp/ability.rs @@ -341,9 +341,7 @@ impl From<&CharacterAbility> for CharacterState { energy_increase: *energy_increase, combo_duration: *combo_duration, timer: Duration::default(), - in_buildup: true, - in_recover: false, - in_combo: false, + stage_section: combo_melee::StageSection::Buildup, }), CharacterAbility::LeapMelee { energy_cost: _, diff --git a/common/src/states/combo_melee.rs b/common/src/states/combo_melee.rs index 3f4470c9f7..c1ad13d963 100644 --- a/common/src/states/combo_melee.rs +++ b/common/src/states/combo_melee.rs @@ -28,6 +28,15 @@ pub struct Stage { pub base_recover_duration: Duration, } +/// Determines whether state is in buildup, swing, recover, or combo +#[derive(Clone, Copy, Debug, Eq, PartialEq, Serialize, Deserialize)] +pub enum StageSection { + Buildup, + Swing, + Recover, + Combo, +} + /// A sequence of attacks that can incrementally become faster and more /// damaging. #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] @@ -50,12 +59,8 @@ pub struct Data { pub combo_duration: Duration, /// Timer for each stage pub timer: Duration, - /// Checks if state is in buildup duration - pub in_buildup: bool, - /// Checks if state is in recover duration - pub in_recover: bool, - /// Checks if state is in combo duration - pub in_combo: bool, + /// Checks what section a stage is in + pub stage_section: StageSection, } impl CharacterBehavior for Data { @@ -67,7 +72,7 @@ impl CharacterBehavior for Data { let stage_index = (self.stage - 1) as usize; - if self.in_buildup && self.timer < self.stage_data[stage_index].base_buildup_duration { + if self.stage_section == StageSection::Buildup && self.timer < self.stage_data[stage_index].base_buildup_duration { // Build up update.character = CharacterState::ComboMelee(Data { stage: self.stage, @@ -82,11 +87,9 @@ impl CharacterBehavior for Data { .timer .checked_add(Duration::from_secs_f32(data.dt.0)) .unwrap_or_default(), - in_buildup: self.in_buildup, - in_recover: self.in_recover, - in_combo: self.in_combo, + stage_section: self.stage_section, }); - } else if self.in_buildup { + } else if self.stage_section == StageSection::Buildup { // Hit attempt data.updater.insert(data.entity, Attacking { base_healthchange: -((self.stage_data[stage_index].max_damage.min( @@ -111,11 +114,9 @@ impl CharacterBehavior for Data { energy_increase: self.energy_increase, combo_duration: self.combo_duration, timer: Duration::default(), - in_buildup: false, - in_recover: true, - in_combo: self.in_combo, + stage_section: StageSection::Recover, }); - } else if self.in_recover && self.timer < self.stage_data[stage_index].base_recover_duration { + } else if self.stage_section == StageSection::Recover && self.timer < self.stage_data[stage_index].base_recover_duration { update.character = CharacterState::ComboMelee(Data { stage: self.stage, num_stages: self.num_stages, @@ -129,11 +130,9 @@ impl CharacterBehavior for Data { .timer .checked_add(Duration::from_secs_f32(data.dt.0)) .unwrap_or_default(), - in_buildup: self.in_buildup, - in_recover: self.in_recover, - in_combo: self.in_combo, + stage_section: self.stage_section, }); - } else if self.in_recover { + } else if self.stage_section == StageSection::Recover { update.character = CharacterState::ComboMelee(Data { stage: self.stage, num_stages: self.num_stages, @@ -144,11 +143,9 @@ impl CharacterBehavior for Data { energy_increase: self.energy_increase, combo_duration: self.combo_duration, timer: Duration::default(), - in_buildup: self.in_buildup, - in_recover: false, - in_combo: true, + stage_section: StageSection::Combo, }); - } else if self.in_combo && self.timer < self.combo_duration { + } else if self.stage_section == StageSection::Combo && self.timer < self.combo_duration { if data.inputs.primary.is_pressed() { update.character = CharacterState::ComboMelee(Data { stage: (self.stage % self.num_stages) + 1, @@ -160,9 +157,7 @@ impl CharacterBehavior for Data { energy_increase: self.energy_increase, combo_duration: self.combo_duration, timer: Duration::default(), - in_buildup: true, - in_recover: self.in_recover, - in_combo: false, + stage_section: StageSection::Buildup, }); } else { update.character = CharacterState::ComboMelee(Data { @@ -178,9 +173,7 @@ impl CharacterBehavior for Data { .timer .checked_add(Duration::from_secs_f32(data.dt.0)) .unwrap_or_default(), - in_buildup: self.in_buildup, - in_recover: self.in_recover, - in_combo: self.in_combo, + stage_section: self.stage_section, }); } } else { diff --git a/voxygen/src/scene/figure/mod.rs b/voxygen/src/scene/figure/mod.rs index de09039499..31d78283b5 100644 --- a/voxygen/src/scene/figure/mod.rs +++ b/voxygen/src/scene/figure/mod.rs @@ -30,6 +30,7 @@ use common::{ }, span, state::{DeltaTime, State}, + states::combo_melee::StageSection, terrain::TerrainChunk, vol::RectRasterableVol, }; @@ -915,20 +916,24 @@ impl FigureMgr { let stage_index = (s.stage - 1) as usize; let stage_time = s.timer.as_secs_f64(); let swing_frac = 0.5; // What percentage of buildup is swing animation - let in_swing: bool; - let stage_progress = if s.in_buildup { - let buildup_progress = stage_time / s.stage_data[stage_index].base_buildup_duration.as_secs_f64(); - if buildup_progress < swing_frac { - in_swing = false; - buildup_progress / (1.0 - swing_frac) - } else { - in_swing = true; - (buildup_progress - (1.0 - swing_frac)) / swing_frac - } - } else if s.in_recover { - stage_time / s.stage_data[stage_index].base_recover_duration.as_secs_f64() - } else { - stage_time / s.combo_duration.as_secs_f64() + let mut stage_section = s.stage_section; + let stage_progress = match s.stage_section { + StageSection::Buildup => { + let buildup_progress = stage_time / s.stage_data[stage_index].base_buildup_duration.as_secs_f64(); + if buildup_progress < swing_frac { + buildup_progress / (1.0 - swing_frac) + } else { + stage_section = StageSection::Swing; + (buildup_progress - (1.0 - swing_frac)) / swing_frac + } + }, + StageSection::Recover => { + stage_time / s.stage_data[stage_index].base_recover_duration.as_secs_f64() + }, + StageSection::Combo => { + stage_time / s.combo_duration.as_secs_f64() + }, + _ => 0.0, }; match s.stage { 1 => anim::character::AlphaAnimation::update_skeleton( From 2451a64b9791ea221d9dc10dd7e7791af6b6c4e9 Mon Sep 17 00:00:00 2001 From: jshipsey Date: Mon, 7 Sep 2020 01:14:39 -0400 Subject: [PATCH 05/28] stage 2 animation --- common/src/comp/inventory/item/tool.rs | 14 +- common/src/states/combo_melee.rs | 10 +- voxygen/src/anim/Cargo.toml | 2 +- voxygen/src/anim/src/character/alpha.rs | 5 +- voxygen/src/anim/src/character/spin.rs | 168 +++++++++++++++++------- voxygen/src/anim/src/character/wield.rs | 6 +- voxygen/src/scene/figure/mod.rs | 18 ++- 7 files changed, 156 insertions(+), 67 deletions(-) diff --git a/common/src/comp/inventory/item/tool.rs b/common/src/comp/inventory/item/tool.rs index 1cdc6716fa..f53f396ccc 100644 --- a/common/src/comp/inventory/item/tool.rs +++ b/common/src/comp/inventory/item/tool.rs @@ -127,8 +127,8 @@ impl Tool { knockback: 5.0, range: 3.5, angle: 45.0, - base_buildup_duration: Duration::from_millis(150), - base_recover_duration: Duration::from_millis(100), + base_buildup_duration: Duration::from_millis(10), + base_recover_duration: Duration::from_millis(10), }, combo_melee::Stage { stage: 2, @@ -138,8 +138,8 @@ impl Tool { knockback: 5.0, range: 3.5, angle: 45.0, - base_buildup_duration: Duration::from_millis(150), - base_recover_duration: Duration::from_millis(100), + base_buildup_duration: Duration::from_millis(1000), + base_recover_duration: Duration::from_millis(400), }, combo_melee::Stage { stage: 3, @@ -149,14 +149,14 @@ impl Tool { knockback: 5.0, range: 3.5, angle: 45.0, - base_buildup_duration: Duration::from_millis(150), - base_recover_duration: Duration::from_millis(100), + base_buildup_duration: Duration::from_millis(10), + base_recover_duration: Duration::from_millis(10), }, ], initial_energy_gain: 0, max_energy_gain: 100, energy_increase: 20, - combo_duration: Duration::from_millis(250), + combo_duration: Duration::from_millis(10), }, DashMelee { energy_cost: 700, diff --git a/common/src/states/combo_melee.rs b/common/src/states/combo_melee.rs index c1ad13d963..712c35cbfb 100644 --- a/common/src/states/combo_melee.rs +++ b/common/src/states/combo_melee.rs @@ -72,7 +72,9 @@ impl CharacterBehavior for Data { let stage_index = (self.stage - 1) as usize; - if self.stage_section == StageSection::Buildup && self.timer < self.stage_data[stage_index].base_buildup_duration { + if self.stage_section == StageSection::Buildup + && self.timer < self.stage_data[stage_index].base_buildup_duration + { // Build up update.character = CharacterState::ComboMelee(Data { stage: self.stage, @@ -116,7 +118,9 @@ impl CharacterBehavior for Data { timer: Duration::default(), stage_section: StageSection::Recover, }); - } else if self.stage_section == StageSection::Recover && self.timer < self.stage_data[stage_index].base_recover_duration { + } else if self.stage_section == StageSection::Recover + && self.timer < self.stage_data[stage_index].base_recover_duration + { update.character = CharacterState::ComboMelee(Data { stage: self.stage, num_stages: self.num_stages, @@ -173,7 +177,7 @@ impl CharacterBehavior for Data { .timer .checked_add(Duration::from_secs_f32(data.dt.0)) .unwrap_or_default(), - stage_section: self.stage_section, + stage_section: self.stage_section, }); } } else { diff --git a/voxygen/src/anim/Cargo.toml b/voxygen/src/anim/Cargo.toml index 75bb0ecbe3..10869c6cc3 100644 --- a/voxygen/src/anim/Cargo.toml +++ b/voxygen/src/anim/Cargo.toml @@ -8,7 +8,7 @@ version = "0.7.0" name = "voxygen_anim" # Uncomment to use animation hot reloading # Note: this breaks `cargo test` -# crate-type = ["lib", "cdylib"] +crate-type = ["lib", "cdylib"] [features] be-dyn-lib = [] diff --git a/voxygen/src/anim/src/character/alpha.rs b/voxygen/src/anim/src/character/alpha.rs index f9cd1a33c5..71a23f05ed 100644 --- a/voxygen/src/anim/src/character/alpha.rs +++ b/voxygen/src/anim/src/character/alpha.rs @@ -2,7 +2,10 @@ use super::{ super::{vek::*, Animation}, CharacterSkeleton, SkeletonAttr, }; -use common::comp::item::{Hands, ToolKind}; +use common::{ + comp::item::{Hands, ToolKind}, + states::combo_melee::StageSection, +}; use std::f32::consts::PI; pub struct AlphaAnimation; diff --git a/voxygen/src/anim/src/character/spin.rs b/voxygen/src/anim/src/character/spin.rs index 8896e71bae..596906cdb3 100644 --- a/voxygen/src/anim/src/character/spin.rs +++ b/voxygen/src/anim/src/character/spin.rs @@ -2,7 +2,10 @@ use super::{ super::{vek::*, Animation}, CharacterSkeleton, SkeletonAttr, }; -use common::comp::item::{Hands, ToolKind}; +use common::{ + comp::item::{Hands, ToolKind}, + states::combo_melee::StageSection, +}; use std::f32::consts::PI; pub struct Input { @@ -11,7 +14,7 @@ pub struct Input { pub struct SpinAnimation; impl Animation for SpinAnimation { - type Dependency = (Option, Option, f64); + type Dependency = (Option, Option, f64, StageSection); type Skeleton = CharacterSkeleton; #[cfg(feature = "use-dyn-lib")] @@ -20,7 +23,7 @@ impl Animation for SpinAnimation { #[cfg_attr(feature = "be-dyn-lib", export_name = "character_spin")] fn update_skeleton_inner( skeleton: &Self::Skeleton, - (active_tool_kind, second_tool_kind, _global_time): Self::Dependency, + (active_tool_kind, second_tool_kind, _global_time, stage_section): Self::Dependency, anim_time: f64, rate: &mut f32, skeleton_attr: &SkeletonAttr, @@ -40,9 +43,83 @@ impl Animation for SpinAnimation { let spin = (anim_time as f32 * 2.8 * lab as f32).sin(); let spinhalf = (anim_time as f32 * 1.4 * lab as f32).sin(); - if let Some( - ToolKind::Axe(_) | ToolKind::Hammer(_) | ToolKind::Sword(_) | ToolKind::Dagger(_), - ) = active_tool_kind + let build = (anim_time as f32 * 8.0).sin(); + let recover = (anim_time as f32 * 8.0).sin(); + + let movement = anim_time as f32 * 1.0; + let test = (anim_time as f32 * 8.0).sin(); + let test2 = (anim_time as f32 * 1.0).sin(); + + if let Some(ToolKind::Sword(_)) = active_tool_kind { + next.l_hand.position = Vec3::new(-0.75, -1.0, 2.5); + next.l_hand.orientation = Quaternion::rotation_x(1.47) * Quaternion::rotation_y(-0.2); + next.l_hand.scale = Vec3::one() * 1.04; + next.r_hand.position = Vec3::new(0.75, -1.5, -0.5); + next.r_hand.orientation = Quaternion::rotation_x(1.47) * Quaternion::rotation_y(0.3); + next.r_hand.scale = Vec3::one() * 1.05; + next.main.position = Vec3::new(0.0, 0.0, 2.0); + next.main.orientation = Quaternion::rotation_x(-0.1) + * Quaternion::rotation_y(0.0) + * Quaternion::rotation_z(0.0); + + match stage_section { + StageSection::Buildup => { + //println!("{:.3} build", anim_time); + next.control.position = Vec3::new(5.0, 11.0 + build * 0.6, 2.0 + build * 0.6); + next.control.orientation = Quaternion::rotation_x(-1.57) + * Quaternion::rotation_y(2.8) + * Quaternion::rotation_z(1.0); + next.chest.orientation = Quaternion::rotation_y(movement * -0.1) + * Quaternion::rotation_z(build * 0.05 + movement * -0.6); + next.belt.orientation = Quaternion::rotation_x(movement * 0.1); + + next.shorts.orientation = Quaternion::rotation_x(movement * 0.1); + + next.head.orientation = Quaternion::rotation_y(movement * 0.1) + * Quaternion::rotation_z(movement * 0.4); + }, + StageSection::Swing => { + //println!("{:.3} swing", anim_time); + next.control.position = Vec3::new( + 7.0 + movement * -8.0, + 11.0 + test * 3.0, + 2.0 + test * 3.5 + movement * 3.0, + ); + next.control.orientation = + Quaternion::rotation_x(-1.57 + movement * -0.6 + test * -0.25) + * Quaternion::rotation_y(2.8 + movement * -2.0) + * Quaternion::rotation_z(1.0 + movement * 1.0); + next.head.orientation = Quaternion::rotation_z(-test * 0.8); + next.chest.orientation = Quaternion::rotation_x(test * 0.15) + * Quaternion::rotation_y(movement * 0.3) + * Quaternion::rotation_z(movement * 1.5); + next.belt.orientation = Quaternion::rotation_z(test2 * 0.5); + next.shorts.orientation = Quaternion::rotation_z(test2 * 1.5); + next.torso.orientation = Quaternion::rotation_z(test2 * 7.2); + }, + StageSection::Recover => { + //println!("{:.3} recover", anim_time); + next.control.position = Vec3::new( + -8.0, + 11.0 - recover * 0.8 + movement * -10.0, + 6.0 - recover * 0.4 + movement * -4.0, + ); + next.control.orientation = Quaternion::rotation_x(-1.57) + * Quaternion::rotation_y(0.0) + * Quaternion::rotation_z(1.0); + next.chest.orientation = Quaternion::rotation_y(movement * -0.1) + * Quaternion::rotation_z(movement * 0.4); + next.head.orientation = Quaternion::rotation_y(movement * 0.1) + * Quaternion::rotation_z(movement * -0.1); + }, + StageSection::Combo => { + //println!("{:.3} combo", anim_time); + }, + } + } + // println!("{:?}", stage_progress), + + if let Some(ToolKind::Axe(_) | ToolKind::Hammer(_) | ToolKind::Dagger(_)) = active_tool_kind { //INTENTION: SWORD next.l_hand.position = Vec3::new(-0.75, -1.0, -2.5); @@ -88,46 +165,47 @@ impl Animation for SpinAnimation { * Quaternion::rotation_x(0.0) * Quaternion::rotation_y(0.0); next.torso.scale = Vec3::one() / 11.0 * skeleton_attr.scaler; + + next.l_foot.position = + Vec3::new(-skeleton_attr.foot.0, foot * 1.0, skeleton_attr.foot.2); + next.l_foot.orientation = Quaternion::rotation_x(foot * -1.2); + next.l_foot.scale = Vec3::one(); + + next.r_foot.position = + Vec3::new(skeleton_attr.foot.0, foot * -1.0, skeleton_attr.foot.2); + next.r_foot.orientation = Quaternion::rotation_x(foot * 1.2); + next.r_foot.scale = Vec3::one(); + + next.l_shoulder.position = Vec3::new(-5.0, 0.0, 4.7); + next.l_shoulder.orientation = Quaternion::rotation_x(0.0); + next.l_shoulder.scale = Vec3::one() * 1.1; + + next.r_shoulder.position = Vec3::new(5.0, 0.0, 4.7); + next.r_shoulder.orientation = Quaternion::rotation_x(0.0); + next.r_shoulder.scale = Vec3::one() * 1.1; + + next.glider.position = Vec3::new(0.0, 5.0, 0.0); + next.glider.orientation = Quaternion::rotation_y(0.0); + next.glider.scale = Vec3::one() * 0.0; + + next.lantern.position = Vec3::new( + skeleton_attr.lantern.0, + skeleton_attr.lantern.1, + skeleton_attr.lantern.2, + ); + next.lantern.orientation = + Quaternion::rotation_x(spin * -0.7 + 0.4) * Quaternion::rotation_y(spin * 0.4); + next.lantern.scale = Vec3::one() * 0.65; + next.hold.scale = Vec3::one() * 0.0; + + next.l_control.position = Vec3::new(0.0, 0.0, 0.0); + next.l_control.orientation = Quaternion::rotation_x(0.0); + next.l_control.scale = Vec3::one(); + + next.r_control.position = Vec3::new(0.0, 0.0, 0.0); + next.r_control.orientation = Quaternion::rotation_x(0.0); + next.r_control.scale = Vec3::one(); } - - next.l_foot.position = Vec3::new(-skeleton_attr.foot.0, foot * 1.0, skeleton_attr.foot.2); - next.l_foot.orientation = Quaternion::rotation_x(foot * -1.2); - next.l_foot.scale = Vec3::one(); - - next.r_foot.position = Vec3::new(skeleton_attr.foot.0, foot * -1.0, skeleton_attr.foot.2); - next.r_foot.orientation = Quaternion::rotation_x(foot * 1.2); - next.r_foot.scale = Vec3::one(); - - next.l_shoulder.position = Vec3::new(-5.0, 0.0, 4.7); - next.l_shoulder.orientation = Quaternion::rotation_x(0.0); - next.l_shoulder.scale = Vec3::one() * 1.1; - - next.r_shoulder.position = Vec3::new(5.0, 0.0, 4.7); - next.r_shoulder.orientation = Quaternion::rotation_x(0.0); - next.r_shoulder.scale = Vec3::one() * 1.1; - - next.glider.position = Vec3::new(0.0, 5.0, 0.0); - next.glider.orientation = Quaternion::rotation_y(0.0); - next.glider.scale = Vec3::one() * 0.0; - - next.lantern.position = Vec3::new( - skeleton_attr.lantern.0, - skeleton_attr.lantern.1, - skeleton_attr.lantern.2, - ); - next.lantern.orientation = - Quaternion::rotation_x(spin * -0.7 + 0.4) * Quaternion::rotation_y(spin * 0.4); - next.lantern.scale = Vec3::one() * 0.65; - next.hold.scale = Vec3::one() * 0.0; - - next.l_control.position = Vec3::new(0.0, 0.0, 0.0); - next.l_control.orientation = Quaternion::rotation_x(0.0); - next.l_control.scale = Vec3::one(); - - next.r_control.position = Vec3::new(0.0, 0.0, 0.0); - next.r_control.orientation = Quaternion::rotation_x(0.0); - next.r_control.scale = Vec3::one(); - next.second.scale = match ( active_tool_kind.map(|tk| tk.hands()), second_tool_kind.map(|tk| tk.hands()), diff --git a/voxygen/src/anim/src/character/wield.rs b/voxygen/src/anim/src/character/wield.rs index 8ba6f64531..ad3761e3ad 100644 --- a/voxygen/src/anim/src/character/wield.rs +++ b/voxygen/src/anim/src/character/wield.rs @@ -111,18 +111,18 @@ impl Animation for WieldAnimation { match active_tool_kind { //TODO: Inventory Some(ToolKind::Sword(_)) => { - next.l_hand.position = Vec3::new(-0.75, -1.0, -2.5); + next.l_hand.position = Vec3::new(-0.75, -1.0, 2.5); next.l_hand.orientation = Quaternion::rotation_x(1.47) * Quaternion::rotation_y(-0.2); next.l_hand.scale = Vec3::one() * 1.04; - next.r_hand.position = Vec3::new(0.75, -1.5, -5.5); + next.r_hand.position = Vec3::new(0.75, -1.5, -0.5); next.r_hand.orientation = Quaternion::rotation_x(1.47) * Quaternion::rotation_y(0.3); next.r_hand.scale = Vec3::one() * 1.05; next.main.position = Vec3::new(0.0, 0.0, -3.0); next.main.orientation = Quaternion::rotation_x(-0.1); - next.control.position = Vec3::new(-7.0, 6.0, 6.0); + next.control.position = Vec3::new(-7.0, 7.0, 2.0); next.control.orientation = Quaternion::rotation_x(u_slow * 0.15) * Quaternion::rotation_z(u_slowalt * 0.08); next.control.scale = Vec3::one(); diff --git a/voxygen/src/scene/figure/mod.rs b/voxygen/src/scene/figure/mod.rs index 31d78283b5..f210717cd1 100644 --- a/voxygen/src/scene/figure/mod.rs +++ b/voxygen/src/scene/figure/mod.rs @@ -915,11 +915,14 @@ impl FigureMgr { CharacterState::ComboMelee(s) => { let stage_index = (s.stage - 1) as usize; let stage_time = s.timer.as_secs_f64(); - let swing_frac = 0.5; // What percentage of buildup is swing animation + let swing_frac = 0.6; // What percentage of buildup is swing animation let mut stage_section = s.stage_section; let stage_progress = match s.stage_section { StageSection::Buildup => { - let buildup_progress = stage_time / s.stage_data[stage_index].base_buildup_duration.as_secs_f64(); + let buildup_progress = stage_time + / s.stage_data[stage_index] + .base_buildup_duration + .as_secs_f64(); if buildup_progress < swing_frac { buildup_progress / (1.0 - swing_frac) } else { @@ -928,11 +931,12 @@ impl FigureMgr { } }, StageSection::Recover => { - stage_time / s.stage_data[stage_index].base_recover_duration.as_secs_f64() - }, - StageSection::Combo => { - stage_time / s.combo_duration.as_secs_f64() + stage_time + / s.stage_data[stage_index] + .base_recover_duration + .as_secs_f64() }, + StageSection::Combo => stage_time / s.combo_duration.as_secs_f64(), _ => 0.0, }; match s.stage { @@ -945,7 +949,7 @@ impl FigureMgr { ), 2 => anim::character::SpinAnimation::update_skeleton( &target_base, - (active_tool_kind, second_tool_kind, time), + (active_tool_kind, second_tool_kind, time, stage_section), stage_progress, &mut state_animation_rate, skeleton_attr, From 2ba9d1e54f87a0d5e722badc377b3f387ae29e71 Mon Sep 17 00:00:00 2001 From: Sam Date: Mon, 7 Sep 2020 11:58:52 -0500 Subject: [PATCH 06/28] Added support for different swings in the combo melee having differnt fractions of time buildup duration is split. --- common/src/comp/inventory/item/tool.rs | 6 + common/src/states/combo_melee.rs | 2 + voxygen/src/anim/src/character/alpha.rs | 116 +++++------ voxygen/src/anim/src/character/beta.rs | 260 +++++++++++++++++++----- voxygen/src/anim/src/character/spin.rs | 106 +++++----- voxygen/src/scene/figure/mod.rs | 19 +- 6 files changed, 338 insertions(+), 171 deletions(-) diff --git a/common/src/comp/inventory/item/tool.rs b/common/src/comp/inventory/item/tool.rs index f53f396ccc..084f8bd33c 100644 --- a/common/src/comp/inventory/item/tool.rs +++ b/common/src/comp/inventory/item/tool.rs @@ -129,6 +129,7 @@ impl Tool { angle: 45.0, base_buildup_duration: Duration::from_millis(10), base_recover_duration: Duration::from_millis(10), + swing_frac: 0.5, }, combo_melee::Stage { stage: 2, @@ -140,6 +141,7 @@ impl Tool { angle: 45.0, base_buildup_duration: Duration::from_millis(1000), base_recover_duration: Duration::from_millis(400), + swing_frac: 0.6, }, combo_melee::Stage { stage: 3, @@ -151,6 +153,7 @@ impl Tool { angle: 45.0, base_buildup_duration: Duration::from_millis(10), base_recover_duration: Duration::from_millis(10), + swing_frac: 0.5, }, ], initial_energy_gain: 0, @@ -178,6 +181,7 @@ impl Tool { angle: 45.0, base_buildup_duration: Duration::from_millis(150), base_recover_duration: Duration::from_millis(100), + swing_frac: 0.5, }, combo_melee::Stage { stage: 2, @@ -189,6 +193,7 @@ impl Tool { angle: 45.0, base_buildup_duration: Duration::from_millis(150), base_recover_duration: Duration::from_millis(100), + swing_frac: 0.6, }, combo_melee::Stage { stage: 3, @@ -200,6 +205,7 @@ impl Tool { angle: 45.0, base_buildup_duration: Duration::from_millis(150), base_recover_duration: Duration::from_millis(100), + swing_frac: 0.5, }, ], initial_energy_gain: 0, diff --git a/common/src/states/combo_melee.rs b/common/src/states/combo_melee.rs index 712c35cbfb..65294dc975 100644 --- a/common/src/states/combo_melee.rs +++ b/common/src/states/combo_melee.rs @@ -26,6 +26,8 @@ pub struct Stage { pub base_buildup_duration: Duration, /// Initial recover duration of stage (how long until character exits state) pub base_recover_duration: Duration, + /// Determines what portion of the buildup duration is a swing. Used for animation purposes. + pub swing_frac: f64, } /// Determines whether state is in buildup, swing, recover, or combo diff --git a/voxygen/src/anim/src/character/alpha.rs b/voxygen/src/anim/src/character/alpha.rs index 71a23f05ed..27b8b49801 100644 --- a/voxygen/src/anim/src/character/alpha.rs +++ b/voxygen/src/anim/src/character/alpha.rs @@ -11,7 +11,7 @@ use std::f32::consts::PI; pub struct AlphaAnimation; impl Animation for AlphaAnimation { - type Dependency = (Option, Option, f32, f64); + type Dependency = (Option, Option, f32, f64, Option); type Skeleton = CharacterSkeleton; #[cfg(feature = "use-dyn-lib")] @@ -21,7 +21,7 @@ impl Animation for AlphaAnimation { #[allow(clippy::approx_constant)] // TODO: Pending review in #587 fn update_skeleton_inner( skeleton: &Self::Skeleton, - (active_tool_kind, second_tool_kind, velocity, _global_time): Self::Dependency, + (active_tool_kind, second_tool_kind, velocity, _global_time, stage_section): Self::Dependency, anim_time: f64, rate: &mut f32, skeleton_attr: &SkeletonAttr, @@ -67,70 +67,72 @@ impl Animation for AlphaAnimation { match active_tool_kind { //TODO: Inventory Some(ToolKind::Sword(_)) => { - next.head.position = - Vec3::new(0.0, -2.0 + skeleton_attr.head.0, skeleton_attr.head.1); - next.head.orientation = Quaternion::rotation_z(slow * -0.25) - * Quaternion::rotation_x(0.0 + slow * 0.15) - * Quaternion::rotation_y(slow * -0.15); - next.head.scale = Vec3::one() * skeleton_attr.head_scale; + if let Some(stage_section) = stage_section { + next.head.position = + Vec3::new(0.0, -2.0 + skeleton_attr.head.0, skeleton_attr.head.1); + next.head.orientation = Quaternion::rotation_z(slow * -0.25) + * Quaternion::rotation_x(0.0 + slow * 0.15) + * Quaternion::rotation_y(slow * -0.15); + next.head.scale = Vec3::one() * skeleton_attr.head_scale; - next.chest.position = Vec3::new(0.0, skeleton_attr.chest.0, skeleton_attr.chest.1); - next.chest.orientation = Quaternion::rotation_z(slow * 0.4) - * Quaternion::rotation_x(0.0 + slow * -0.2) - * Quaternion::rotation_y(slow * 0.2); - next.chest.scale = Vec3::one(); + next.chest.position = Vec3::new(0.0, skeleton_attr.chest.0, skeleton_attr.chest.1); + next.chest.orientation = Quaternion::rotation_z(slow * 0.4) + * Quaternion::rotation_x(0.0 + slow * -0.2) + * Quaternion::rotation_y(slow * 0.2); + next.chest.scale = Vec3::one(); - next.belt.position = Vec3::new(0.0, skeleton_attr.belt.0, skeleton_attr.belt.1); - next.belt.orientation = next.chest.orientation * -0.3; + next.belt.position = Vec3::new(0.0, skeleton_attr.belt.0, skeleton_attr.belt.1); + next.belt.orientation = next.chest.orientation * -0.3; - next.shorts.position = - Vec3::new(0.0, skeleton_attr.shorts.0, skeleton_attr.shorts.1); - next.shorts.orientation = next.chest.orientation * -0.45; + next.shorts.position = + Vec3::new(0.0, skeleton_attr.shorts.0, skeleton_attr.shorts.1); + next.shorts.orientation = next.chest.orientation * -0.45; - next.l_hand.position = Vec3::new(-0.75, -1.0, -2.5); - next.l_hand.orientation = Quaternion::rotation_x(1.27); - next.l_hand.scale = Vec3::one() * 1.05; - next.r_hand.position = Vec3::new(0.75, -1.5, -5.5); - next.r_hand.orientation = Quaternion::rotation_x(1.27); - next.r_hand.scale = Vec3::one() * 1.05; - next.main.position = Vec3::new(0.0, 0.0, 0.0); - next.main.orientation = Quaternion::rotation_x(-0.3) - * Quaternion::rotation_y(0.0) - * Quaternion::rotation_z(0.0); + next.l_hand.position = Vec3::new(-0.75, -1.0, -2.5); + next.l_hand.orientation = Quaternion::rotation_x(1.27); + next.l_hand.scale = Vec3::one() * 1.05; + next.r_hand.position = Vec3::new(0.75, -1.5, -5.5); + next.r_hand.orientation = Quaternion::rotation_x(1.27); + next.r_hand.scale = Vec3::one() * 1.05; + next.main.position = Vec3::new(0.0, 0.0, 0.0); + next.main.orientation = Quaternion::rotation_x(-0.3) + * Quaternion::rotation_y(0.0) + * Quaternion::rotation_z(0.0); - next.control.position = Vec3::new(-10.0 + push * 5.0, 6.0 + push * 5.0, 2.0); - next.control.orientation = Quaternion::rotation_x(-1.4 + slow * 0.4) - * Quaternion::rotation_y(slow * -1.3) - * Quaternion::rotation_z(1.4 + slow * -0.5); - next.control.scale = Vec3::one(); + next.control.position = Vec3::new(-10.0 + push * 5.0, 6.0 + push * 5.0, 2.0); + next.control.orientation = Quaternion::rotation_x(-1.4 + slow * 0.4) + * Quaternion::rotation_y(slow * -1.3) + * Quaternion::rotation_z(1.4 + slow * -0.5); + next.control.scale = Vec3::one(); - next.l_foot.position = Vec3::new( - -skeleton_attr.foot.0, - slow * -3.0 + quick * 3.0 - 4.0, - skeleton_attr.foot.2, - ); - next.l_foot.orientation = Quaternion::rotation_x(slow * 0.6) - * Quaternion::rotation_y((slow * -0.2).max(0.0)); - next.l_foot.scale = Vec3::one(); + next.l_foot.position = Vec3::new( + -skeleton_attr.foot.0, + slow * -3.0 + quick * 3.0 - 4.0, + skeleton_attr.foot.2, + ); + next.l_foot.orientation = Quaternion::rotation_x(slow * 0.6) + * Quaternion::rotation_y((slow * -0.2).max(0.0)); + next.l_foot.scale = Vec3::one(); - next.r_foot.position = Vec3::new( - skeleton_attr.foot.0, - slow * 3.0 + quick * -3.0 + 5.0, - skeleton_attr.foot.2, - ); - next.r_foot.orientation = Quaternion::rotation_x(slow * -0.6) - * Quaternion::rotation_y((slow * 0.2).min(0.0)); - next.r_foot.scale = Vec3::one(); + next.r_foot.position = Vec3::new( + skeleton_attr.foot.0, + slow * 3.0 + quick * -3.0 + 5.0, + skeleton_attr.foot.2, + ); + next.r_foot.orientation = Quaternion::rotation_x(slow * -0.6) + * Quaternion::rotation_y((slow * 0.2).min(0.0)); + next.r_foot.scale = Vec3::one(); - next.lantern.orientation = - Quaternion::rotation_x(slow * -0.7 + 0.4) * Quaternion::rotation_y(slow * 0.4); - next.hold.scale = Vec3::one() * 0.0; + next.lantern.orientation = + Quaternion::rotation_x(slow * -0.7 + 0.4) * Quaternion::rotation_y(slow * 0.4); + next.hold.scale = Vec3::one() * 0.0; - next.torso.position = Vec3::new(0.0, 0.0, 0.1) * skeleton_attr.scaler; - next.torso.orientation = Quaternion::rotation_z(0.0) - * Quaternion::rotation_x(0.0) - * Quaternion::rotation_y(0.0); - next.torso.scale = Vec3::one() / 11.0 * skeleton_attr.scaler; + next.torso.position = Vec3::new(0.0, 0.0, 0.1) * skeleton_attr.scaler; + next.torso.orientation = Quaternion::rotation_z(0.0) + * Quaternion::rotation_x(0.0) + * Quaternion::rotation_y(0.0); + next.torso.scale = Vec3::one() / 11.0 * skeleton_attr.scaler; + } }, Some(ToolKind::Dagger(_)) => { next.head.position = diff --git a/voxygen/src/anim/src/character/beta.rs b/voxygen/src/anim/src/character/beta.rs index 739d4ca406..3172abb3cb 100644 --- a/voxygen/src/anim/src/character/beta.rs +++ b/voxygen/src/anim/src/character/beta.rs @@ -2,12 +2,15 @@ use super::{ super::{vek::*, Animation}, CharacterSkeleton, SkeletonAttr, }; -use common::comp::item::{Hands, ToolKind}; +use common::{ + comp::item::{Hands, ToolKind}, + states::combo_melee::StageSection, +}; pub struct BetaAnimation; impl Animation for BetaAnimation { - type Dependency = (Option, Option, f32, f64); + type Dependency = (Option, Option, f32, f64, Option); type Skeleton = CharacterSkeleton; #[cfg(feature = "use-dyn-lib")] @@ -16,7 +19,7 @@ impl Animation for BetaAnimation { #[cfg_attr(feature = "be-dyn-lib", export_name = "character_beta")] fn update_skeleton_inner( skeleton: &Self::Skeleton, - (active_tool_kind, second_tool_kind, _velocity, _global_time): Self::Dependency, + (active_tool_kind, second_tool_kind, _velocity, _global_time, stage_section): Self::Dependency, anim_time: f64, rate: &mut f32, skeleton_attr: &SkeletonAttr, @@ -43,62 +46,215 @@ impl Animation for BetaAnimation { .sqrt()) * ((anim_time as f32 * lab as f32 * 14.0).sin()); - if let Some( - ToolKind::Axe(_) | ToolKind::Hammer(_) | ToolKind::Sword(_) | ToolKind::Dagger(_), - ) = active_tool_kind - { - //INTENTION: SWORD - next.head.position = Vec3::new(0.0, -2.0 + skeleton_attr.head.0, skeleton_attr.head.1); - next.head.orientation = Quaternion::rotation_z(slow * -0.18) - * Quaternion::rotation_x(-0.1 + slow * -0.28) - * Quaternion::rotation_y(0.2 + slow * 0.18); - next.head.scale = Vec3::one() * skeleton_attr.head_scale; + match active_tool_kind { + Some(ToolKind::Sword(_)) => { + if let Some(stage_section) = stage_section { + next.head.position = Vec3::new(0.0, -2.0 + skeleton_attr.head.0, skeleton_attr.head.1); + next.head.orientation = Quaternion::rotation_z(slow * -0.18) + * Quaternion::rotation_x(-0.1 + slow * -0.28) + * Quaternion::rotation_y(0.2 + slow * 0.18); + next.head.scale = Vec3::one() * skeleton_attr.head_scale; - next.chest.position = Vec3::new(0.0 + foot * 2.0, 0.0, 7.0); - next.chest.orientation = Quaternion::rotation_z(slow * 0.2) - * Quaternion::rotation_x(slow * 0.2) - * Quaternion::rotation_y(slow * -0.1); + next.chest.position = Vec3::new(0.0 + foot * 2.0, 0.0, 7.0); + next.chest.orientation = Quaternion::rotation_z(slow * 0.2) + * Quaternion::rotation_x(slow * 0.2) + * Quaternion::rotation_y(slow * -0.1); - next.belt.position = Vec3::new(0.0, 0.0, -2.0); - next.belt.orientation = Quaternion::rotation_z(slow * 0.1) - * Quaternion::rotation_x(slow * 0.1) - * Quaternion::rotation_y(slow * -0.04); + next.belt.position = Vec3::new(0.0, 0.0, -2.0); + next.belt.orientation = Quaternion::rotation_z(slow * 0.1) + * Quaternion::rotation_x(slow * 0.1) + * Quaternion::rotation_y(slow * -0.04); - next.shorts.position = Vec3::new(0.0, 0.0, -5.0); - next.shorts.orientation = Quaternion::rotation_z(slow * 0.1) - * Quaternion::rotation_x(slow * 0.1) - * Quaternion::rotation_y(slow * -0.05); + next.shorts.position = Vec3::new(0.0, 0.0, -5.0); + next.shorts.orientation = Quaternion::rotation_z(slow * 0.1) + * Quaternion::rotation_x(slow * 0.1) + * Quaternion::rotation_y(slow * -0.05); - next.l_hand.position = Vec3::new(-0.75, -1.0, -2.5); - next.l_hand.orientation = Quaternion::rotation_x(1.27); - next.l_hand.scale = Vec3::one() * 1.04; - next.r_hand.position = Vec3::new(0.75, -1.5, -5.5); - next.r_hand.orientation = Quaternion::rotation_x(1.27); - next.r_hand.scale = Vec3::one() * 1.05; - next.main.position = Vec3::new(0.0, 6.0, -1.0); - next.main.orientation = Quaternion::rotation_x(-0.3); + next.l_hand.position = Vec3::new(-0.75, -1.0, -2.5); + next.l_hand.orientation = Quaternion::rotation_x(1.27); + next.l_hand.scale = Vec3::one() * 1.04; + next.r_hand.position = Vec3::new(0.75, -1.5, -5.5); + next.r_hand.orientation = Quaternion::rotation_x(1.27); + next.r_hand.scale = Vec3::one() * 1.05; + next.main.position = Vec3::new(0.0, 6.0, -1.0); + next.main.orientation = Quaternion::rotation_x(-0.3); - next.control.position = Vec3::new(-8.0 + slow * 1.5, 1.5 + slow * 1.0, 0.0); - next.control.orientation = Quaternion::rotation_x(-1.4) - * Quaternion::rotation_y(slow * 2.0 + 0.7) - * Quaternion::rotation_z(1.7 - slow * 0.4 + fast * 0.6); - next.control.scale = Vec3::one(); - next.l_foot.position = Vec3::new( - -skeleton_attr.foot.0, - footquick * -9.5, - skeleton_attr.foot.2, - ); - next.l_foot.orientation = - Quaternion::rotation_x(footquick * 0.3) * Quaternion::rotation_y(footquick * -0.6); + next.control.position = Vec3::new(-8.0 + slow * 1.5, 1.5 + slow * 1.0, 0.0); + next.control.orientation = Quaternion::rotation_x(-1.4) + * Quaternion::rotation_y(slow * 2.0 + 0.7) + * Quaternion::rotation_z(1.7 - slow * 0.4 + fast * 0.6); + next.control.scale = Vec3::one(); + next.l_foot.position = Vec3::new( + -skeleton_attr.foot.0, + footquick * -9.5, + skeleton_attr.foot.2, + ); + next.l_foot.orientation = + Quaternion::rotation_x(footquick * 0.3) * Quaternion::rotation_y(footquick * -0.6); - next.r_foot.position = - Vec3::new(skeleton_attr.foot.0, footquick * 9.5, skeleton_attr.foot.2); - next.r_foot.orientation = - Quaternion::rotation_x(footquick * -0.3) * Quaternion::rotation_y(footquick * 0.2); - next.torso.position = Vec3::new(0.0, 0.0, 0.1) * skeleton_attr.scaler; - next.torso.scale = Vec3::one() / 11.0 * skeleton_attr.scaler; + next.r_foot.position = + Vec3::new(skeleton_attr.foot.0, footquick * 9.5, skeleton_attr.foot.2); + next.r_foot.orientation = + Quaternion::rotation_x(footquick * -0.3) * Quaternion::rotation_y(footquick * 0.2); + next.torso.position = Vec3::new(0.0, 0.0, 0.1) * skeleton_attr.scaler; + next.torso.scale = Vec3::one() / 11.0 * skeleton_attr.scaler; + } + }, + Some(ToolKind::Hammer(_)) => { + next.head.position = Vec3::new(0.0, -2.0 + skeleton_attr.head.0, skeleton_attr.head.1); + next.head.orientation = Quaternion::rotation_z(slow * -0.18) + * Quaternion::rotation_x(-0.1 + slow * -0.28) + * Quaternion::rotation_y(0.2 + slow * 0.18); + next.head.scale = Vec3::one() * skeleton_attr.head_scale; + + next.chest.position = Vec3::new(0.0 + foot * 2.0, 0.0, 7.0); + next.chest.orientation = Quaternion::rotation_z(slow * 0.2) + * Quaternion::rotation_x(slow * 0.2) + * Quaternion::rotation_y(slow * -0.1); + + next.belt.position = Vec3::new(0.0, 0.0, -2.0); + next.belt.orientation = Quaternion::rotation_z(slow * 0.1) + * Quaternion::rotation_x(slow * 0.1) + * Quaternion::rotation_y(slow * -0.04); + + next.shorts.position = Vec3::new(0.0, 0.0, -5.0); + next.shorts.orientation = Quaternion::rotation_z(slow * 0.1) + * Quaternion::rotation_x(slow * 0.1) + * Quaternion::rotation_y(slow * -0.05); + + next.l_hand.position = Vec3::new(-0.75, -1.0, -2.5); + next.l_hand.orientation = Quaternion::rotation_x(1.27); + next.l_hand.scale = Vec3::one() * 1.04; + next.r_hand.position = Vec3::new(0.75, -1.5, -5.5); + next.r_hand.orientation = Quaternion::rotation_x(1.27); + next.r_hand.scale = Vec3::one() * 1.05; + next.main.position = Vec3::new(0.0, 6.0, -1.0); + next.main.orientation = Quaternion::rotation_x(-0.3); + + next.control.position = Vec3::new(-8.0 + slow * 1.5, 1.5 + slow * 1.0, 0.0); + next.control.orientation = Quaternion::rotation_x(-1.4) + * Quaternion::rotation_y(slow * 2.0 + 0.7) + * Quaternion::rotation_z(1.7 - slow * 0.4 + fast * 0.6); + next.control.scale = Vec3::one(); + next.l_foot.position = Vec3::new( + -skeleton_attr.foot.0, + footquick * -9.5, + skeleton_attr.foot.2, + ); + next.l_foot.orientation = + Quaternion::rotation_x(footquick * 0.3) * Quaternion::rotation_y(footquick * -0.6); + + next.r_foot.position = + Vec3::new(skeleton_attr.foot.0, footquick * 9.5, skeleton_attr.foot.2); + next.r_foot.orientation = + Quaternion::rotation_x(footquick * -0.3) * Quaternion::rotation_y(footquick * 0.2); + next.torso.position = Vec3::new(0.0, 0.0, 0.1) * skeleton_attr.scaler; + next.torso.scale = Vec3::one() / 11.0 * skeleton_attr.scaler; + }, + Some(ToolKind::Axe(_)) => { + next.head.position = Vec3::new(0.0, -2.0 + skeleton_attr.head.0, skeleton_attr.head.1); + next.head.orientation = Quaternion::rotation_z(slow * -0.18) + * Quaternion::rotation_x(-0.1 + slow * -0.28) + * Quaternion::rotation_y(0.2 + slow * 0.18); + next.head.scale = Vec3::one() * skeleton_attr.head_scale; + + next.chest.position = Vec3::new(0.0 + foot * 2.0, 0.0, 7.0); + next.chest.orientation = Quaternion::rotation_z(slow * 0.2) + * Quaternion::rotation_x(slow * 0.2) + * Quaternion::rotation_y(slow * -0.1); + + next.belt.position = Vec3::new(0.0, 0.0, -2.0); + next.belt.orientation = Quaternion::rotation_z(slow * 0.1) + * Quaternion::rotation_x(slow * 0.1) + * Quaternion::rotation_y(slow * -0.04); + + next.shorts.position = Vec3::new(0.0, 0.0, -5.0); + next.shorts.orientation = Quaternion::rotation_z(slow * 0.1) + * Quaternion::rotation_x(slow * 0.1) + * Quaternion::rotation_y(slow * -0.05); + + next.l_hand.position = Vec3::new(-0.75, -1.0, -2.5); + next.l_hand.orientation = Quaternion::rotation_x(1.27); + next.l_hand.scale = Vec3::one() * 1.04; + next.r_hand.position = Vec3::new(0.75, -1.5, -5.5); + next.r_hand.orientation = Quaternion::rotation_x(1.27); + next.r_hand.scale = Vec3::one() * 1.05; + next.main.position = Vec3::new(0.0, 6.0, -1.0); + next.main.orientation = Quaternion::rotation_x(-0.3); + + next.control.position = Vec3::new(-8.0 + slow * 1.5, 1.5 + slow * 1.0, 0.0); + next.control.orientation = Quaternion::rotation_x(-1.4) + * Quaternion::rotation_y(slow * 2.0 + 0.7) + * Quaternion::rotation_z(1.7 - slow * 0.4 + fast * 0.6); + next.control.scale = Vec3::one(); + next.l_foot.position = Vec3::new( + -skeleton_attr.foot.0, + footquick * -9.5, + skeleton_attr.foot.2, + ); + next.l_foot.orientation = + Quaternion::rotation_x(footquick * 0.3) * Quaternion::rotation_y(footquick * -0.6); + + next.r_foot.position = + Vec3::new(skeleton_attr.foot.0, footquick * 9.5, skeleton_attr.foot.2); + next.r_foot.orientation = + Quaternion::rotation_x(footquick * -0.3) * Quaternion::rotation_y(footquick * 0.2); + next.torso.position = Vec3::new(0.0, 0.0, 0.1) * skeleton_attr.scaler; + next.torso.scale = Vec3::one() / 11.0 * skeleton_attr.scaler; + }, + _ => { + next.head.position = Vec3::new(0.0, -2.0 + skeleton_attr.head.0, skeleton_attr.head.1); + next.head.orientation = Quaternion::rotation_z(slow * -0.18) + * Quaternion::rotation_x(-0.1 + slow * -0.28) + * Quaternion::rotation_y(0.2 + slow * 0.18); + next.head.scale = Vec3::one() * skeleton_attr.head_scale; + + next.chest.position = Vec3::new(0.0 + foot * 2.0, 0.0, 7.0); + next.chest.orientation = Quaternion::rotation_z(slow * 0.2) + * Quaternion::rotation_x(slow * 0.2) + * Quaternion::rotation_y(slow * -0.1); + + next.belt.position = Vec3::new(0.0, 0.0, -2.0); + next.belt.orientation = Quaternion::rotation_z(slow * 0.1) + * Quaternion::rotation_x(slow * 0.1) + * Quaternion::rotation_y(slow * -0.04); + + next.shorts.position = Vec3::new(0.0, 0.0, -5.0); + next.shorts.orientation = Quaternion::rotation_z(slow * 0.1) + * Quaternion::rotation_x(slow * 0.1) + * Quaternion::rotation_y(slow * -0.05); + + next.l_hand.position = Vec3::new(-0.75, -1.0, -2.5); + next.l_hand.orientation = Quaternion::rotation_x(1.27); + next.l_hand.scale = Vec3::one() * 1.04; + next.r_hand.position = Vec3::new(0.75, -1.5, -5.5); + next.r_hand.orientation = Quaternion::rotation_x(1.27); + next.r_hand.scale = Vec3::one() * 1.05; + next.main.position = Vec3::new(0.0, 6.0, -1.0); + next.main.orientation = Quaternion::rotation_x(-0.3); + + next.control.position = Vec3::new(-8.0 + slow * 1.5, 1.5 + slow * 1.0, 0.0); + next.control.orientation = Quaternion::rotation_x(-1.4) + * Quaternion::rotation_y(slow * 2.0 + 0.7) + * Quaternion::rotation_z(1.7 - slow * 0.4 + fast * 0.6); + next.control.scale = Vec3::one(); + next.l_foot.position = Vec3::new( + -skeleton_attr.foot.0, + footquick * -9.5, + skeleton_attr.foot.2, + ); + next.l_foot.orientation = + Quaternion::rotation_x(footquick * 0.3) * Quaternion::rotation_y(footquick * -0.6); + + next.r_foot.position = + Vec3::new(skeleton_attr.foot.0, footquick * 9.5, skeleton_attr.foot.2); + next.r_foot.orientation = + Quaternion::rotation_x(footquick * -0.3) * Quaternion::rotation_y(footquick * 0.2); + next.torso.position = Vec3::new(0.0, 0.0, 0.1) * skeleton_attr.scaler; + next.torso.scale = Vec3::one() / 11.0 * skeleton_attr.scaler; + }, } - + next.l_shoulder.position = Vec3::new( -skeleton_attr.shoulder.0, skeleton_attr.shoulder.1, diff --git a/voxygen/src/anim/src/character/spin.rs b/voxygen/src/anim/src/character/spin.rs index 596906cdb3..c0206607d6 100644 --- a/voxygen/src/anim/src/character/spin.rs +++ b/voxygen/src/anim/src/character/spin.rs @@ -14,7 +14,7 @@ pub struct Input { pub struct SpinAnimation; impl Animation for SpinAnimation { - type Dependency = (Option, Option, f64, StageSection); + type Dependency = (Option, Option, f64, Option); type Skeleton = CharacterSkeleton; #[cfg(feature = "use-dyn-lib")] @@ -62,59 +62,61 @@ impl Animation for SpinAnimation { * Quaternion::rotation_y(0.0) * Quaternion::rotation_z(0.0); - match stage_section { - StageSection::Buildup => { - //println!("{:.3} build", anim_time); - next.control.position = Vec3::new(5.0, 11.0 + build * 0.6, 2.0 + build * 0.6); - next.control.orientation = Quaternion::rotation_x(-1.57) - * Quaternion::rotation_y(2.8) - * Quaternion::rotation_z(1.0); - next.chest.orientation = Quaternion::rotation_y(movement * -0.1) - * Quaternion::rotation_z(build * 0.05 + movement * -0.6); - next.belt.orientation = Quaternion::rotation_x(movement * 0.1); + if let Some(stage_section) = stage_section { + match stage_section { + StageSection::Buildup => { + //println!("{:.3} build", anim_time); + next.control.position = Vec3::new(5.0, 11.0 + build * 0.6, 2.0 + build * 0.6); + next.control.orientation = Quaternion::rotation_x(-1.57) + * Quaternion::rotation_y(2.8) + * Quaternion::rotation_z(1.0); + next.chest.orientation = Quaternion::rotation_y(movement * -0.1) + * Quaternion::rotation_z(build * 0.05 + movement * -0.6); + next.belt.orientation = Quaternion::rotation_x(movement * 0.1); - next.shorts.orientation = Quaternion::rotation_x(movement * 0.1); + next.shorts.orientation = Quaternion::rotation_x(movement * 0.1); - next.head.orientation = Quaternion::rotation_y(movement * 0.1) - * Quaternion::rotation_z(movement * 0.4); - }, - StageSection::Swing => { - //println!("{:.3} swing", anim_time); - next.control.position = Vec3::new( - 7.0 + movement * -8.0, - 11.0 + test * 3.0, - 2.0 + test * 3.5 + movement * 3.0, - ); - next.control.orientation = - Quaternion::rotation_x(-1.57 + movement * -0.6 + test * -0.25) - * Quaternion::rotation_y(2.8 + movement * -2.0) - * Quaternion::rotation_z(1.0 + movement * 1.0); - next.head.orientation = Quaternion::rotation_z(-test * 0.8); - next.chest.orientation = Quaternion::rotation_x(test * 0.15) - * Quaternion::rotation_y(movement * 0.3) - * Quaternion::rotation_z(movement * 1.5); - next.belt.orientation = Quaternion::rotation_z(test2 * 0.5); - next.shorts.orientation = Quaternion::rotation_z(test2 * 1.5); - next.torso.orientation = Quaternion::rotation_z(test2 * 7.2); - }, - StageSection::Recover => { - //println!("{:.3} recover", anim_time); - next.control.position = Vec3::new( - -8.0, - 11.0 - recover * 0.8 + movement * -10.0, - 6.0 - recover * 0.4 + movement * -4.0, - ); - next.control.orientation = Quaternion::rotation_x(-1.57) - * Quaternion::rotation_y(0.0) - * Quaternion::rotation_z(1.0); - next.chest.orientation = Quaternion::rotation_y(movement * -0.1) - * Quaternion::rotation_z(movement * 0.4); - next.head.orientation = Quaternion::rotation_y(movement * 0.1) - * Quaternion::rotation_z(movement * -0.1); - }, - StageSection::Combo => { - //println!("{:.3} combo", anim_time); - }, + next.head.orientation = Quaternion::rotation_y(movement * 0.1) + * Quaternion::rotation_z(movement * 0.4); + }, + StageSection::Swing => { + //println!("{:.3} swing", anim_time); + next.control.position = Vec3::new( + 7.0 + movement * -8.0, + 11.0 + test * 3.0, + 2.0 + test * 3.5 + movement * 3.0, + ); + next.control.orientation = + Quaternion::rotation_x(-1.57 + movement * -0.6 + test * -0.25) + * Quaternion::rotation_y(2.8 + movement * -2.0) + * Quaternion::rotation_z(1.0 + movement * 1.0); + next.head.orientation = Quaternion::rotation_z(-test * 0.8); + next.chest.orientation = Quaternion::rotation_x(test * 0.15) + * Quaternion::rotation_y(movement * 0.3) + * Quaternion::rotation_z(movement * 1.5); + next.belt.orientation = Quaternion::rotation_z(test2 * 0.5); + next.shorts.orientation = Quaternion::rotation_z(test2 * 1.5); + next.torso.orientation = Quaternion::rotation_z(test2 * 7.2); + }, + StageSection::Recover => { + //println!("{:.3} recover", anim_time); + next.control.position = Vec3::new( + -8.0, + 11.0 - recover * 0.8 + movement * -10.0, + 6.0 - recover * 0.4 + movement * -4.0, + ); + next.control.orientation = Quaternion::rotation_x(-1.57) + * Quaternion::rotation_y(0.0) + * Quaternion::rotation_z(1.0); + next.chest.orientation = Quaternion::rotation_y(movement * -0.1) + * Quaternion::rotation_z(movement * 0.4); + next.head.orientation = Quaternion::rotation_y(movement * 0.1) + * Quaternion::rotation_z(movement * -0.1); + }, + StageSection::Combo => { + //println!("{:.3} combo", anim_time); + }, + } } } // println!("{:?}", stage_progress), diff --git a/voxygen/src/scene/figure/mod.rs b/voxygen/src/scene/figure/mod.rs index f210717cd1..8152c4db22 100644 --- a/voxygen/src/scene/figure/mod.rs +++ b/voxygen/src/scene/figure/mod.rs @@ -809,7 +809,7 @@ impl FigureMgr { CharacterState::BasicMelee(_) => { anim::character::AlphaAnimation::update_skeleton( &target_base, - (active_tool_kind, second_tool_kind, vel.0.magnitude(), time), + (active_tool_kind, second_tool_kind, vel.0.magnitude(), time, None), state.state_time, &mut state_animation_rate, skeleton_attr, @@ -879,7 +879,7 @@ impl FigureMgr { CharacterState::Boost(_) => { anim::character::AlphaAnimation::update_skeleton( &target_base, - (active_tool_kind, second_tool_kind, vel.0.magnitude(), time), + (active_tool_kind, second_tool_kind, vel.0.magnitude(), time, None), state.state_time, &mut state_animation_rate, skeleton_attr, @@ -915,19 +915,18 @@ impl FigureMgr { CharacterState::ComboMelee(s) => { let stage_index = (s.stage - 1) as usize; let stage_time = s.timer.as_secs_f64(); - let swing_frac = 0.6; // What percentage of buildup is swing animation - let mut stage_section = s.stage_section; + let mut stage_section = Some(s.stage_section); let stage_progress = match s.stage_section { StageSection::Buildup => { let buildup_progress = stage_time / s.stage_data[stage_index] .base_buildup_duration .as_secs_f64(); - if buildup_progress < swing_frac { - buildup_progress / (1.0 - swing_frac) + if buildup_progress < s.stage_data[stage_index].swing_frac { + buildup_progress / (1.0 - s.stage_data[stage_index].swing_frac) } else { - stage_section = StageSection::Swing; - (buildup_progress - (1.0 - swing_frac)) / swing_frac + stage_section = Some(StageSection::Swing); + (buildup_progress - (1.0 - s.stage_data[stage_index].swing_frac)) / s.stage_data[stage_index].swing_frac } }, StageSection::Recover => { @@ -942,7 +941,7 @@ impl FigureMgr { match s.stage { 1 => anim::character::AlphaAnimation::update_skeleton( &target_base, - (active_tool_kind, second_tool_kind, vel.0.magnitude(), time), + (active_tool_kind, second_tool_kind, vel.0.magnitude(), time, stage_section), stage_progress, &mut state_animation_rate, skeleton_attr, @@ -956,7 +955,7 @@ impl FigureMgr { ), _ => anim::character::BetaAnimation::update_skeleton( &target_base, - (active_tool_kind, second_tool_kind, vel.0.magnitude(), time), + (active_tool_kind, second_tool_kind, vel.0.magnitude(), time, stage_section), stage_progress, &mut state_animation_rate, skeleton_attr, From 847bddbd89681b4f7a10a9dfda51d7404cce92b9 Mon Sep 17 00:00:00 2001 From: Sam Date: Mon, 7 Sep 2020 12:30:52 -0500 Subject: [PATCH 07/28] Removed swing_frac, added a swing duration instead to allow for more utility in character state. Moved location of stage_section enum to wielding so it could more easily be used by other character states. --- common/src/comp/ability.rs | 2 +- common/src/comp/inventory/item/tool.rs | 14 ++++---- common/src/states/combo_melee.rs | 46 ++++++++++++++++++------- common/src/states/wielding.rs | 12 +++++++ voxygen/src/anim/src/character/alpha.rs | 2 +- voxygen/src/anim/src/character/beta.rs | 2 +- voxygen/src/anim/src/character/spin.rs | 2 +- voxygen/src/scene/figure/mod.rs | 26 +++++++------- 8 files changed, 69 insertions(+), 37 deletions(-) diff --git a/common/src/comp/ability.rs b/common/src/comp/ability.rs index 096092a8fb..35842f23d9 100644 --- a/common/src/comp/ability.rs +++ b/common/src/comp/ability.rs @@ -341,7 +341,7 @@ impl From<&CharacterAbility> for CharacterState { energy_increase: *energy_increase, combo_duration: *combo_duration, timer: Duration::default(), - stage_section: combo_melee::StageSection::Buildup, + stage_section: wielding::StageSection::Buildup, }), CharacterAbility::LeapMelee { energy_cost: _, diff --git a/common/src/comp/inventory/item/tool.rs b/common/src/comp/inventory/item/tool.rs index 084f8bd33c..183d8f6b39 100644 --- a/common/src/comp/inventory/item/tool.rs +++ b/common/src/comp/inventory/item/tool.rs @@ -128,8 +128,8 @@ impl Tool { range: 3.5, angle: 45.0, base_buildup_duration: Duration::from_millis(10), + base_swing_duration: Duration::from_millis(10), base_recover_duration: Duration::from_millis(10), - swing_frac: 0.5, }, combo_melee::Stage { stage: 2, @@ -139,9 +139,9 @@ impl Tool { knockback: 5.0, range: 3.5, angle: 45.0, - base_buildup_duration: Duration::from_millis(1000), + base_buildup_duration: Duration::from_millis(400), + base_swing_duration: Duration::from_millis(600), base_recover_duration: Duration::from_millis(400), - swing_frac: 0.6, }, combo_melee::Stage { stage: 3, @@ -152,8 +152,8 @@ impl Tool { range: 3.5, angle: 45.0, base_buildup_duration: Duration::from_millis(10), + base_swing_duration: Duration::from_millis(10), base_recover_duration: Duration::from_millis(10), - swing_frac: 0.5, }, ], initial_energy_gain: 0, @@ -180,8 +180,8 @@ impl Tool { range: 3.5, angle: 45.0, base_buildup_duration: Duration::from_millis(150), + base_swing_duration: Duration::from_millis(100), base_recover_duration: Duration::from_millis(100), - swing_frac: 0.5, }, combo_melee::Stage { stage: 2, @@ -192,8 +192,8 @@ impl Tool { range: 3.5, angle: 45.0, base_buildup_duration: Duration::from_millis(150), + base_swing_duration: Duration::from_millis(100), base_recover_duration: Duration::from_millis(100), - swing_frac: 0.6, }, combo_melee::Stage { stage: 3, @@ -204,8 +204,8 @@ impl Tool { range: 3.5, angle: 45.0, base_buildup_duration: Duration::from_millis(150), + base_swing_duration: Duration::from_millis(100), base_recover_duration: Duration::from_millis(100), - swing_frac: 0.5, }, ], initial_energy_gain: 0, diff --git a/common/src/states/combo_melee.rs b/common/src/states/combo_melee.rs index 65294dc975..3694a20555 100644 --- a/common/src/states/combo_melee.rs +++ b/common/src/states/combo_melee.rs @@ -1,6 +1,6 @@ use crate::{ comp::{Attacking, CharacterState, EnergySource, StateUpdate}, - states::utils::*, + states::{utils::*, wielding::StageSection}, sys::character_behavior::{CharacterBehavior, JoinData}, }; use serde::{Deserialize, Serialize}; @@ -24,19 +24,10 @@ pub struct Stage { pub angle: f32, /// Initial buildup duration of stage (how long until state can deal damage) pub base_buildup_duration: Duration, + /// Duration of stage spent in swing (controls animation stuff, and can also be used to handle movement separately to buildup) + pub base_swing_duration: Duration, /// Initial recover duration of stage (how long until character exits state) pub base_recover_duration: Duration, - /// Determines what portion of the buildup duration is a swing. Used for animation purposes. - pub swing_frac: f64, -} - -/// Determines whether state is in buildup, swing, recover, or combo -#[derive(Clone, Copy, Debug, Eq, PartialEq, Serialize, Deserialize)] -pub enum StageSection { - Buildup, - Swing, - Recover, - Combo, } /// A sequence of attacks that can incrementally become faster and more @@ -94,6 +85,37 @@ impl CharacterBehavior for Data { stage_section: self.stage_section, }); } else if self.stage_section == StageSection::Buildup { + update.character = CharacterState::ComboMelee(Data { + stage: self.stage, + num_stages: self.num_stages, + combo: self.combo, + stage_data: self.stage_data.clone(), + initial_energy_gain: self.initial_energy_gain, + max_energy_gain: self.max_energy_gain, + energy_increase: self.energy_increase, + combo_duration: self.combo_duration, + timer: Duration::default(), + stage_section: StageSection::Swing, + }); + } else if self.stage_section == StageSection::Swing + && self.timer < self.stage_data[stage_index].base_swing_duration + { + update.character = CharacterState::ComboMelee(Data { + stage: self.stage, + num_stages: self.num_stages, + combo: self.combo, + stage_data: self.stage_data.clone(), + initial_energy_gain: self.initial_energy_gain, + max_energy_gain: self.max_energy_gain, + energy_increase: self.energy_increase, + combo_duration: self.combo_duration, + timer: self + .timer + .checked_add(Duration::from_secs_f32(data.dt.0)) + .unwrap_or_default(), + stage_section: self.stage_section, + }); + } else if self.stage_section == StageSection::Swing { // Hit attempt data.updater.insert(data.entity, Attacking { base_healthchange: -((self.stage_data[stage_index].max_damage.min( diff --git a/common/src/states/wielding.rs b/common/src/states/wielding.rs index f64ae9c77f..9f340f8d09 100644 --- a/common/src/states/wielding.rs +++ b/common/src/states/wielding.rs @@ -3,6 +3,7 @@ use crate::{ comp::{CharacterState, StateUpdate}, sys::character_behavior::{CharacterBehavior, JoinData}, }; +use serde::{Deserialize, Serialize}; pub struct Data; @@ -57,3 +58,14 @@ impl CharacterBehavior for Data { update } } + + + +/// Determines what portion a state is in. Used in all attacks (eventually). Is used to control aspects of animation code, as well as logic within the character states. +#[derive(Clone, Copy, Debug, Eq, PartialEq, Serialize, Deserialize)] +pub enum StageSection { + Buildup, + Swing, + Recover, + Combo, +} \ No newline at end of file diff --git a/voxygen/src/anim/src/character/alpha.rs b/voxygen/src/anim/src/character/alpha.rs index 27b8b49801..618f052c75 100644 --- a/voxygen/src/anim/src/character/alpha.rs +++ b/voxygen/src/anim/src/character/alpha.rs @@ -4,7 +4,7 @@ use super::{ }; use common::{ comp::item::{Hands, ToolKind}, - states::combo_melee::StageSection, + states::wielding::StageSection, }; use std::f32::consts::PI; diff --git a/voxygen/src/anim/src/character/beta.rs b/voxygen/src/anim/src/character/beta.rs index 3172abb3cb..ed24a9e663 100644 --- a/voxygen/src/anim/src/character/beta.rs +++ b/voxygen/src/anim/src/character/beta.rs @@ -4,7 +4,7 @@ use super::{ }; use common::{ comp::item::{Hands, ToolKind}, - states::combo_melee::StageSection, + states::wielding::StageSection, }; pub struct BetaAnimation; diff --git a/voxygen/src/anim/src/character/spin.rs b/voxygen/src/anim/src/character/spin.rs index c0206607d6..e31da53f28 100644 --- a/voxygen/src/anim/src/character/spin.rs +++ b/voxygen/src/anim/src/character/spin.rs @@ -4,7 +4,7 @@ use super::{ }; use common::{ comp::item::{Hands, ToolKind}, - states::combo_melee::StageSection, + states::wielding::StageSection, }; use std::f32::consts::PI; diff --git a/voxygen/src/scene/figure/mod.rs b/voxygen/src/scene/figure/mod.rs index 8152c4db22..64d74196f2 100644 --- a/voxygen/src/scene/figure/mod.rs +++ b/voxygen/src/scene/figure/mod.rs @@ -30,7 +30,7 @@ use common::{ }, span, state::{DeltaTime, State}, - states::combo_melee::StageSection, + states::wielding::StageSection, terrain::TerrainChunk, vol::RectRasterableVol, }; @@ -915,19 +915,18 @@ impl FigureMgr { CharacterState::ComboMelee(s) => { let stage_index = (s.stage - 1) as usize; let stage_time = s.timer.as_secs_f64(); - let mut stage_section = Some(s.stage_section); let stage_progress = match s.stage_section { StageSection::Buildup => { - let buildup_progress = stage_time + stage_time / s.stage_data[stage_index] .base_buildup_duration - .as_secs_f64(); - if buildup_progress < s.stage_data[stage_index].swing_frac { - buildup_progress / (1.0 - s.stage_data[stage_index].swing_frac) - } else { - stage_section = Some(StageSection::Swing); - (buildup_progress - (1.0 - s.stage_data[stage_index].swing_frac)) / s.stage_data[stage_index].swing_frac - } + .as_secs_f64() + }, + StageSection::Swing => { + stage_time + / s.stage_data[stage_index] + .base_swing_duration + .as_secs_f64() }, StageSection::Recover => { stage_time @@ -936,26 +935,25 @@ impl FigureMgr { .as_secs_f64() }, StageSection::Combo => stage_time / s.combo_duration.as_secs_f64(), - _ => 0.0, }; match s.stage { 1 => anim::character::AlphaAnimation::update_skeleton( &target_base, - (active_tool_kind, second_tool_kind, vel.0.magnitude(), time, stage_section), + (active_tool_kind, second_tool_kind, vel.0.magnitude(), time, Some(s.stage_section)), stage_progress, &mut state_animation_rate, skeleton_attr, ), 2 => anim::character::SpinAnimation::update_skeleton( &target_base, - (active_tool_kind, second_tool_kind, time, stage_section), + (active_tool_kind, second_tool_kind, time, Some(s.stage_section)), stage_progress, &mut state_animation_rate, skeleton_attr, ), _ => anim::character::BetaAnimation::update_skeleton( &target_base, - (active_tool_kind, second_tool_kind, vel.0.magnitude(), time, stage_section), + (active_tool_kind, second_tool_kind, vel.0.magnitude(), time, Some(s.stage_section)), stage_progress, &mut state_animation_rate, skeleton_attr, From a18c23025e10ef6e57784adb46c7e45abb5b8f86 Mon Sep 17 00:00:00 2001 From: jshipsey Date: Mon, 7 Sep 2020 20:16:55 -0400 Subject: [PATCH 08/28] stage 2 and 3 anim --- common/src/comp/inventory/item/tool.rs | 12 +- common/src/states/combo_melee.rs | 3 +- common/src/states/wielding.rs | 8 +- voxygen/src/anim/src/character/alpha.rs | 141 ++++++++--------- voxygen/src/anim/src/character/beta.rs | 191 ++++++++++-------------- voxygen/src/anim/src/character/spin.rs | 25 ++-- voxygen/src/scene/figure/mod.rs | 39 ++++- 7 files changed, 210 insertions(+), 209 deletions(-) diff --git a/common/src/comp/inventory/item/tool.rs b/common/src/comp/inventory/item/tool.rs index 183d8f6b39..a1df693acd 100644 --- a/common/src/comp/inventory/item/tool.rs +++ b/common/src/comp/inventory/item/tool.rs @@ -127,9 +127,9 @@ impl Tool { knockback: 5.0, range: 3.5, angle: 45.0, - base_buildup_duration: Duration::from_millis(10), - base_swing_duration: Duration::from_millis(10), - base_recover_duration: Duration::from_millis(10), + base_buildup_duration: Duration::from_millis(500), + base_swing_duration: Duration::from_millis(200), + base_recover_duration: Duration::from_millis(400), }, combo_melee::Stage { stage: 2, @@ -151,9 +151,9 @@ impl Tool { knockback: 5.0, range: 3.5, angle: 45.0, - base_buildup_duration: Duration::from_millis(10), - base_swing_duration: Duration::from_millis(10), - base_recover_duration: Duration::from_millis(10), + base_buildup_duration: Duration::from_millis(500), + base_swing_duration: Duration::from_millis(200), + base_recover_duration: Duration::from_millis(300), }, ], initial_energy_gain: 0, diff --git a/common/src/states/combo_melee.rs b/common/src/states/combo_melee.rs index 3694a20555..b452706d50 100644 --- a/common/src/states/combo_melee.rs +++ b/common/src/states/combo_melee.rs @@ -24,7 +24,8 @@ pub struct Stage { pub angle: f32, /// Initial buildup duration of stage (how long until state can deal damage) pub base_buildup_duration: Duration, - /// Duration of stage spent in swing (controls animation stuff, and can also be used to handle movement separately to buildup) + /// Duration of stage spent in swing (controls animation stuff, and can also + /// be used to handle movement separately to buildup) pub base_swing_duration: Duration, /// Initial recover duration of stage (how long until character exits state) pub base_recover_duration: Duration, diff --git a/common/src/states/wielding.rs b/common/src/states/wielding.rs index 9f340f8d09..a91aa8ce07 100644 --- a/common/src/states/wielding.rs +++ b/common/src/states/wielding.rs @@ -59,13 +59,13 @@ impl CharacterBehavior for Data { } } - - -/// Determines what portion a state is in. Used in all attacks (eventually). Is used to control aspects of animation code, as well as logic within the character states. +/// Determines what portion a state is in. Used in all attacks (eventually). Is +/// used to control aspects of animation code, as well as logic within the +/// character states. #[derive(Clone, Copy, Debug, Eq, PartialEq, Serialize, Deserialize)] pub enum StageSection { Buildup, Swing, Recover, Combo, -} \ No newline at end of file +} diff --git a/voxygen/src/anim/src/character/alpha.rs b/voxygen/src/anim/src/character/alpha.rs index 618f052c75..0751aab175 100644 --- a/voxygen/src/anim/src/character/alpha.rs +++ b/voxygen/src/anim/src/character/alpha.rs @@ -11,7 +11,13 @@ use std::f32::consts::PI; pub struct AlphaAnimation; impl Animation for AlphaAnimation { - type Dependency = (Option, Option, f32, f64, Option); + type Dependency = ( + Option, + Option, + f32, + f64, + Option, + ); type Skeleton = CharacterSkeleton; #[cfg(feature = "use-dyn-lib")] @@ -64,76 +70,73 @@ impl Animation for AlphaAnimation { .sqrt()) * ((anim_time as f32 * lab as f32 * 4.0).sin()); + let movement = anim_time as f32 * 1.0; + let test = (anim_time as f32 * 1.75).sin(); + + if let Some(ToolKind::Sword(_)) = active_tool_kind { + next.l_hand.position = Vec3::new(-0.75, -1.0, 2.5); + next.l_hand.orientation = Quaternion::rotation_x(1.47) * Quaternion::rotation_y(-0.2); + next.l_hand.scale = Vec3::one() * 1.04; + next.r_hand.position = Vec3::new(0.75, -1.5, -0.5); + next.r_hand.orientation = Quaternion::rotation_x(1.47) * Quaternion::rotation_y(0.3); + next.r_hand.scale = Vec3::one() * 1.05; + next.main.position = Vec3::new(0.0, 0.0, 2.0); + next.main.orientation = Quaternion::rotation_x(-0.1) + * Quaternion::rotation_y(0.0) + * Quaternion::rotation_z(0.0); + + if let Some(stage_section) = stage_section { + match stage_section { + StageSection::Buildup => { + //println!("{:.3} build", anim_time); + next.control.position = + Vec3::new(-7.0, 7.0 + movement * -4.0, 2.0 + movement * 1.0); + next.control.orientation = Quaternion::rotation_x(movement * -0.5) + * Quaternion::rotation_y(movement * -1.0) + * Quaternion::rotation_z(movement * -1.2); + + next.chest.orientation = Quaternion::rotation_z(movement * 1.5); + next.head.orientation = Quaternion::rotation_z(movement * -0.9); + }, + StageSection::Swing => { + //println!("{:.3} swing", anim_time); + next.control.position = Vec3::new(-7.0, 3.0 + movement * 8.0, 3.0); + next.control.orientation = + Quaternion::rotation_x(-0.5 + movement * -1.0 * 0.0) + * Quaternion::rotation_y(-1.0 + movement * -0.6) + * Quaternion::rotation_z(-1.2 + movement * 1.3); + + next.chest.orientation = Quaternion::rotation_z(1.5 + test * -3.0); + next.head.orientation = Quaternion::rotation_z(-0.9 + test * 2.5); + //next.head.orientation = Quaternion::rotation_z(-test + // * 0.8); next.chest. + // orientation = Quaternion::rotation_x(test * 0.15) + //* Quaternion::rotation_y(movement * 0.3) + //* Quaternion::rotation_z(movement * 1.5); + //next.belt.orientation = Quaternion::rotation_z(test2 + // * 0.5); next.shorts. + // orientation = Quaternion::rotation_z(test2 * 1.5); + // next.torso.orientation = Quaternion::rotation_z(test2 + // * 7.2); + }, + StageSection::Recover | StageSection::Combo => { + //println!("{:.3} recover", anim_time); + next.control.position = Vec3::new(-7.0, 7.0, 2.0); + next.control.orientation = Quaternion::rotation_x(0.0) + * Quaternion::rotation_y(-1.57 + movement * 1.0) + * Quaternion::rotation_z(0.0); + next.control.scale = Vec3::one(); + next.chest.orientation = Quaternion::rotation_y(0.0) + * Quaternion::rotation_z(-1.57 + movement * 0.5); + next.head.orientation = + Quaternion::rotation_y(0.0) * Quaternion::rotation_z(1.57); + }, + } + } + } + match active_tool_kind { //TODO: Inventory - Some(ToolKind::Sword(_)) => { - if let Some(stage_section) = stage_section { - next.head.position = - Vec3::new(0.0, -2.0 + skeleton_attr.head.0, skeleton_attr.head.1); - next.head.orientation = Quaternion::rotation_z(slow * -0.25) - * Quaternion::rotation_x(0.0 + slow * 0.15) - * Quaternion::rotation_y(slow * -0.15); - next.head.scale = Vec3::one() * skeleton_attr.head_scale; - - next.chest.position = Vec3::new(0.0, skeleton_attr.chest.0, skeleton_attr.chest.1); - next.chest.orientation = Quaternion::rotation_z(slow * 0.4) - * Quaternion::rotation_x(0.0 + slow * -0.2) - * Quaternion::rotation_y(slow * 0.2); - next.chest.scale = Vec3::one(); - - next.belt.position = Vec3::new(0.0, skeleton_attr.belt.0, skeleton_attr.belt.1); - next.belt.orientation = next.chest.orientation * -0.3; - - next.shorts.position = - Vec3::new(0.0, skeleton_attr.shorts.0, skeleton_attr.shorts.1); - next.shorts.orientation = next.chest.orientation * -0.45; - - next.l_hand.position = Vec3::new(-0.75, -1.0, -2.5); - next.l_hand.orientation = Quaternion::rotation_x(1.27); - next.l_hand.scale = Vec3::one() * 1.05; - next.r_hand.position = Vec3::new(0.75, -1.5, -5.5); - next.r_hand.orientation = Quaternion::rotation_x(1.27); - next.r_hand.scale = Vec3::one() * 1.05; - next.main.position = Vec3::new(0.0, 0.0, 0.0); - next.main.orientation = Quaternion::rotation_x(-0.3) - * Quaternion::rotation_y(0.0) - * Quaternion::rotation_z(0.0); - - next.control.position = Vec3::new(-10.0 + push * 5.0, 6.0 + push * 5.0, 2.0); - next.control.orientation = Quaternion::rotation_x(-1.4 + slow * 0.4) - * Quaternion::rotation_y(slow * -1.3) - * Quaternion::rotation_z(1.4 + slow * -0.5); - next.control.scale = Vec3::one(); - - next.l_foot.position = Vec3::new( - -skeleton_attr.foot.0, - slow * -3.0 + quick * 3.0 - 4.0, - skeleton_attr.foot.2, - ); - next.l_foot.orientation = Quaternion::rotation_x(slow * 0.6) - * Quaternion::rotation_y((slow * -0.2).max(0.0)); - next.l_foot.scale = Vec3::one(); - - next.r_foot.position = Vec3::new( - skeleton_attr.foot.0, - slow * 3.0 + quick * -3.0 + 5.0, - skeleton_attr.foot.2, - ); - next.r_foot.orientation = Quaternion::rotation_x(slow * -0.6) - * Quaternion::rotation_y((slow * 0.2).min(0.0)); - next.r_foot.scale = Vec3::one(); - - next.lantern.orientation = - Quaternion::rotation_x(slow * -0.7 + 0.4) * Quaternion::rotation_y(slow * 0.4); - next.hold.scale = Vec3::one() * 0.0; - - next.torso.position = Vec3::new(0.0, 0.0, 0.1) * skeleton_attr.scaler; - next.torso.orientation = Quaternion::rotation_z(0.0) - * Quaternion::rotation_x(0.0) - * Quaternion::rotation_y(0.0); - next.torso.scale = Vec3::one() / 11.0 * skeleton_attr.scaler; - } - }, Some(ToolKind::Dagger(_)) => { next.head.position = Vec3::new(0.0, -2.0 + skeleton_attr.head.0, skeleton_attr.head.1); diff --git a/voxygen/src/anim/src/character/beta.rs b/voxygen/src/anim/src/character/beta.rs index ed24a9e663..3beb8b289a 100644 --- a/voxygen/src/anim/src/character/beta.rs +++ b/voxygen/src/anim/src/character/beta.rs @@ -10,7 +10,13 @@ use common::{ pub struct BetaAnimation; impl Animation for BetaAnimation { - type Dependency = (Option, Option, f32, f64, Option); + type Dependency = ( + Option, + Option, + f32, + f64, + Option, + ); type Skeleton = CharacterSkeleton; #[cfg(feature = "use-dyn-lib")] @@ -46,62 +52,70 @@ impl Animation for BetaAnimation { .sqrt()) * ((anim_time as f32 * lab as f32 * 14.0).sin()); - match active_tool_kind { - Some(ToolKind::Sword(_)) => { - if let Some(stage_section) = stage_section { - next.head.position = Vec3::new(0.0, -2.0 + skeleton_attr.head.0, skeleton_attr.head.1); - next.head.orientation = Quaternion::rotation_z(slow * -0.18) - * Quaternion::rotation_x(-0.1 + slow * -0.28) - * Quaternion::rotation_y(0.2 + slow * 0.18); - next.head.scale = Vec3::one() * skeleton_attr.head_scale; + let recover = (anim_time as f32 * 8.0).sin(); - next.chest.position = Vec3::new(0.0 + foot * 2.0, 0.0, 7.0); - next.chest.orientation = Quaternion::rotation_z(slow * 0.2) - * Quaternion::rotation_x(slow * 0.2) - * Quaternion::rotation_y(slow * -0.1); + let movement = anim_time as f32 * 1.0; + let test = (anim_time as f32 * 2.5).sin(); - next.belt.position = Vec3::new(0.0, 0.0, -2.0); - next.belt.orientation = Quaternion::rotation_z(slow * 0.1) - * Quaternion::rotation_x(slow * 0.1) - * Quaternion::rotation_y(slow * -0.04); + if let Some(ToolKind::Sword(_)) = active_tool_kind { + next.l_hand.position = Vec3::new(-0.75, -1.0, 2.5); + next.l_hand.orientation = Quaternion::rotation_x(1.47) * Quaternion::rotation_y(-0.2); + next.l_hand.scale = Vec3::one() * 1.04; + next.r_hand.position = Vec3::new(0.75, -1.5, -0.5); + next.r_hand.orientation = Quaternion::rotation_x(1.47) * Quaternion::rotation_y(0.3); + next.r_hand.scale = Vec3::one() * 1.05; + next.main.position = Vec3::new(0.0, 0.0, 2.0); + next.main.orientation = Quaternion::rotation_x(-0.1) + * Quaternion::rotation_y(0.0) + * Quaternion::rotation_z(0.0); - next.shorts.position = Vec3::new(0.0, 0.0, -5.0); - next.shorts.orientation = Quaternion::rotation_z(slow * 0.1) - * Quaternion::rotation_x(slow * 0.1) - * Quaternion::rotation_y(slow * -0.05); - - next.l_hand.position = Vec3::new(-0.75, -1.0, -2.5); - next.l_hand.orientation = Quaternion::rotation_x(1.27); - next.l_hand.scale = Vec3::one() * 1.04; - next.r_hand.position = Vec3::new(0.75, -1.5, -5.5); - next.r_hand.orientation = Quaternion::rotation_x(1.27); - next.r_hand.scale = Vec3::one() * 1.05; - next.main.position = Vec3::new(0.0, 6.0, -1.0); - next.main.orientation = Quaternion::rotation_x(-0.3); - - next.control.position = Vec3::new(-8.0 + slow * 1.5, 1.5 + slow * 1.0, 0.0); - next.control.orientation = Quaternion::rotation_x(-1.4) - * Quaternion::rotation_y(slow * 2.0 + 0.7) - * Quaternion::rotation_z(1.7 - slow * 0.4 + fast * 0.6); - next.control.scale = Vec3::one(); - next.l_foot.position = Vec3::new( - -skeleton_attr.foot.0, - footquick * -9.5, - skeleton_attr.foot.2, - ); - next.l_foot.orientation = - Quaternion::rotation_x(footquick * 0.3) * Quaternion::rotation_y(footquick * -0.6); - - next.r_foot.position = - Vec3::new(skeleton_attr.foot.0, footquick * 9.5, skeleton_attr.foot.2); - next.r_foot.orientation = - Quaternion::rotation_x(footquick * -0.3) * Quaternion::rotation_y(footquick * 0.2); - next.torso.position = Vec3::new(0.0, 0.0, 0.1) * skeleton_attr.scaler; - next.torso.scale = Vec3::one() / 11.0 * skeleton_attr.scaler; + if let Some(stage_section) = stage_section { + match stage_section { + StageSection::Buildup => { + //println!("{:.3} recover", anim_time); + next.control.position = Vec3::new( + -8.0 + movement * -5.0, + 4.0 - recover * 0.8 + movement * 2.0, + 6.0 - recover * 0.4, + ); + next.control.orientation = Quaternion::rotation_x(-1.57) + * Quaternion::rotation_y(0.0 + movement * 1.5) + * Quaternion::rotation_z(1.0); + next.chest.orientation = Quaternion::rotation_y(-0.1) + * Quaternion::rotation_z(0.4 + movement * 1.5); + next.head.orientation = Quaternion::rotation_y(0.1) + * Quaternion::rotation_z(-0.1 + movement * -1.1); + }, + StageSection::Swing => { + //println!("{:.3} swing", anim_time); + next.control.position = + Vec3::new(-8.0 + test * 30.0, 6.0 + movement * 2.0, 6.0); + next.control.orientation = Quaternion::rotation_x(-1.57) + * Quaternion::rotation_y(1.5 + test * 0.5) + * Quaternion::rotation_z(1.0 + test * 1.0); + next.chest.orientation = Quaternion::rotation_y(-0.1) + * Quaternion::rotation_z(1.9 + test * -0.5); + next.head.orientation = Quaternion::rotation_y(0.1) + * Quaternion::rotation_z(-1.2 + test * -0.5); + }, + StageSection::Recover | StageSection::Combo => { + next.control.position = Vec3::new(10.0 + movement * -5.0, 8.0, 6.0); + next.control.orientation = Quaternion::rotation_x(-1.57) + * Quaternion::rotation_y(2.0) + * Quaternion::rotation_z(2.0); + next.chest.orientation = Quaternion::rotation_y(-0.1) + * Quaternion::rotation_z(1.4 + movement * 1.0); + next.head.orientation = + Quaternion::rotation_y(0.1) * Quaternion::rotation_z(-1.5); + }, } - }, + } + } + + match active_tool_kind { Some(ToolKind::Hammer(_)) => { - next.head.position = Vec3::new(0.0, -2.0 + skeleton_attr.head.0, skeleton_attr.head.1); + next.head.position = + Vec3::new(0.0, -2.0 + skeleton_attr.head.0, skeleton_attr.head.1); next.head.orientation = Quaternion::rotation_z(slow * -0.18) * Quaternion::rotation_x(-0.1 + slow * -0.28) * Quaternion::rotation_y(0.2 + slow * 0.18); @@ -141,18 +155,19 @@ impl Animation for BetaAnimation { footquick * -9.5, skeleton_attr.foot.2, ); - next.l_foot.orientation = - Quaternion::rotation_x(footquick * 0.3) * Quaternion::rotation_y(footquick * -0.6); + next.l_foot.orientation = Quaternion::rotation_x(footquick * 0.3) + * Quaternion::rotation_y(footquick * -0.6); next.r_foot.position = Vec3::new(skeleton_attr.foot.0, footquick * 9.5, skeleton_attr.foot.2); - next.r_foot.orientation = - Quaternion::rotation_x(footquick * -0.3) * Quaternion::rotation_y(footquick * 0.2); + next.r_foot.orientation = Quaternion::rotation_x(footquick * -0.3) + * Quaternion::rotation_y(footquick * 0.2); next.torso.position = Vec3::new(0.0, 0.0, 0.1) * skeleton_attr.scaler; next.torso.scale = Vec3::one() / 11.0 * skeleton_attr.scaler; }, Some(ToolKind::Axe(_)) => { - next.head.position = Vec3::new(0.0, -2.0 + skeleton_attr.head.0, skeleton_attr.head.1); + next.head.position = + Vec3::new(0.0, -2.0 + skeleton_attr.head.0, skeleton_attr.head.1); next.head.orientation = Quaternion::rotation_z(slow * -0.18) * Quaternion::rotation_x(-0.1 + slow * -0.28) * Quaternion::rotation_y(0.2 + slow * 0.18); @@ -192,69 +207,19 @@ impl Animation for BetaAnimation { footquick * -9.5, skeleton_attr.foot.2, ); - next.l_foot.orientation = - Quaternion::rotation_x(footquick * 0.3) * Quaternion::rotation_y(footquick * -0.6); + next.l_foot.orientation = Quaternion::rotation_x(footquick * 0.3) + * Quaternion::rotation_y(footquick * -0.6); next.r_foot.position = Vec3::new(skeleton_attr.foot.0, footquick * 9.5, skeleton_attr.foot.2); - next.r_foot.orientation = - Quaternion::rotation_x(footquick * -0.3) * Quaternion::rotation_y(footquick * 0.2); - next.torso.position = Vec3::new(0.0, 0.0, 0.1) * skeleton_attr.scaler; - next.torso.scale = Vec3::one() / 11.0 * skeleton_attr.scaler; - }, - _ => { - next.head.position = Vec3::new(0.0, -2.0 + skeleton_attr.head.0, skeleton_attr.head.1); - next.head.orientation = Quaternion::rotation_z(slow * -0.18) - * Quaternion::rotation_x(-0.1 + slow * -0.28) - * Quaternion::rotation_y(0.2 + slow * 0.18); - next.head.scale = Vec3::one() * skeleton_attr.head_scale; - - next.chest.position = Vec3::new(0.0 + foot * 2.0, 0.0, 7.0); - next.chest.orientation = Quaternion::rotation_z(slow * 0.2) - * Quaternion::rotation_x(slow * 0.2) - * Quaternion::rotation_y(slow * -0.1); - - next.belt.position = Vec3::new(0.0, 0.0, -2.0); - next.belt.orientation = Quaternion::rotation_z(slow * 0.1) - * Quaternion::rotation_x(slow * 0.1) - * Quaternion::rotation_y(slow * -0.04); - - next.shorts.position = Vec3::new(0.0, 0.0, -5.0); - next.shorts.orientation = Quaternion::rotation_z(slow * 0.1) - * Quaternion::rotation_x(slow * 0.1) - * Quaternion::rotation_y(slow * -0.05); - - next.l_hand.position = Vec3::new(-0.75, -1.0, -2.5); - next.l_hand.orientation = Quaternion::rotation_x(1.27); - next.l_hand.scale = Vec3::one() * 1.04; - next.r_hand.position = Vec3::new(0.75, -1.5, -5.5); - next.r_hand.orientation = Quaternion::rotation_x(1.27); - next.r_hand.scale = Vec3::one() * 1.05; - next.main.position = Vec3::new(0.0, 6.0, -1.0); - next.main.orientation = Quaternion::rotation_x(-0.3); - - next.control.position = Vec3::new(-8.0 + slow * 1.5, 1.5 + slow * 1.0, 0.0); - next.control.orientation = Quaternion::rotation_x(-1.4) - * Quaternion::rotation_y(slow * 2.0 + 0.7) - * Quaternion::rotation_z(1.7 - slow * 0.4 + fast * 0.6); - next.control.scale = Vec3::one(); - next.l_foot.position = Vec3::new( - -skeleton_attr.foot.0, - footquick * -9.5, - skeleton_attr.foot.2, - ); - next.l_foot.orientation = - Quaternion::rotation_x(footquick * 0.3) * Quaternion::rotation_y(footquick * -0.6); - - next.r_foot.position = - Vec3::new(skeleton_attr.foot.0, footquick * 9.5, skeleton_attr.foot.2); - next.r_foot.orientation = - Quaternion::rotation_x(footquick * -0.3) * Quaternion::rotation_y(footquick * 0.2); + next.r_foot.orientation = Quaternion::rotation_x(footquick * -0.3) + * Quaternion::rotation_y(footquick * 0.2); next.torso.position = Vec3::new(0.0, 0.0, 0.1) * skeleton_attr.scaler; next.torso.scale = Vec3::one() / 11.0 * skeleton_attr.scaler; }, + _ => {}, } - + next.l_shoulder.position = Vec3::new( -skeleton_attr.shoulder.0, skeleton_attr.shoulder.1, diff --git a/voxygen/src/anim/src/character/spin.rs b/voxygen/src/anim/src/character/spin.rs index e31da53f28..f3896b4ac2 100644 --- a/voxygen/src/anim/src/character/spin.rs +++ b/voxygen/src/anim/src/character/spin.rs @@ -14,7 +14,12 @@ pub struct Input { pub struct SpinAnimation; impl Animation for SpinAnimation { - type Dependency = (Option, Option, f64, Option); + type Dependency = ( + Option, + Option, + f64, + Option, + ); type Skeleton = CharacterSkeleton; #[cfg(feature = "use-dyn-lib")] @@ -66,18 +71,19 @@ impl Animation for SpinAnimation { match stage_section { StageSection::Buildup => { //println!("{:.3} build", anim_time); - next.control.position = Vec3::new(5.0, 11.0 + build * 0.6, 2.0 + build * 0.6); - next.control.orientation = Quaternion::rotation_x(-1.57) - * Quaternion::rotation_y(2.8) - * Quaternion::rotation_z(1.0); + next.control.position = + Vec3::new(5.0, 11.0 + build * 0.6, 2.0 + build * 0.6); + next.control.orientation = Quaternion::rotation_x(0.0) + * Quaternion::rotation_y(-0.57 + movement * 2.0) + * Quaternion::rotation_z(0.0); next.chest.orientation = Quaternion::rotation_y(movement * -0.1) - * Quaternion::rotation_z(build * 0.05 + movement * -0.6); + * Quaternion::rotation_z(-1.07 + movement * -0.6); next.belt.orientation = Quaternion::rotation_x(movement * 0.1); next.shorts.orientation = Quaternion::rotation_x(movement * 0.1); next.head.orientation = Quaternion::rotation_y(movement * 0.1) - * Quaternion::rotation_z(movement * 0.4); + * Quaternion::rotation_z(1.07 + movement * 0.4); }, StageSection::Swing => { //println!("{:.3} swing", anim_time); @@ -98,7 +104,7 @@ impl Animation for SpinAnimation { next.shorts.orientation = Quaternion::rotation_z(test2 * 1.5); next.torso.orientation = Quaternion::rotation_z(test2 * 7.2); }, - StageSection::Recover => { + StageSection::Recover | StageSection::Combo => { //println!("{:.3} recover", anim_time); next.control.position = Vec3::new( -8.0, @@ -113,9 +119,6 @@ impl Animation for SpinAnimation { next.head.orientation = Quaternion::rotation_y(movement * 0.1) * Quaternion::rotation_z(movement * -0.1); }, - StageSection::Combo => { - //println!("{:.3} combo", anim_time); - }, } } } diff --git a/voxygen/src/scene/figure/mod.rs b/voxygen/src/scene/figure/mod.rs index 64d74196f2..62e08b55ca 100644 --- a/voxygen/src/scene/figure/mod.rs +++ b/voxygen/src/scene/figure/mod.rs @@ -809,7 +809,13 @@ impl FigureMgr { CharacterState::BasicMelee(_) => { anim::character::AlphaAnimation::update_skeleton( &target_base, - (active_tool_kind, second_tool_kind, vel.0.magnitude(), time, None), + ( + active_tool_kind, + second_tool_kind, + vel.0.magnitude(), + time, + None, + ), state.state_time, &mut state_animation_rate, skeleton_attr, @@ -879,7 +885,13 @@ impl FigureMgr { CharacterState::Boost(_) => { anim::character::AlphaAnimation::update_skeleton( &target_base, - (active_tool_kind, second_tool_kind, vel.0.magnitude(), time, None), + ( + active_tool_kind, + second_tool_kind, + vel.0.magnitude(), + time, + None, + ), state.state_time, &mut state_animation_rate, skeleton_attr, @@ -939,21 +951,38 @@ impl FigureMgr { match s.stage { 1 => anim::character::AlphaAnimation::update_skeleton( &target_base, - (active_tool_kind, second_tool_kind, vel.0.magnitude(), time, Some(s.stage_section)), + ( + active_tool_kind, + second_tool_kind, + vel.0.magnitude(), + time, + Some(s.stage_section), + ), stage_progress, &mut state_animation_rate, skeleton_attr, ), 2 => anim::character::SpinAnimation::update_skeleton( &target_base, - (active_tool_kind, second_tool_kind, time, Some(s.stage_section)), + ( + active_tool_kind, + second_tool_kind, + time, + Some(s.stage_section), + ), stage_progress, &mut state_animation_rate, skeleton_attr, ), _ => anim::character::BetaAnimation::update_skeleton( &target_base, - (active_tool_kind, second_tool_kind, vel.0.magnitude(), time, Some(s.stage_section)), + ( + active_tool_kind, + second_tool_kind, + vel.0.magnitude(), + time, + Some(s.stage_section), + ), stage_progress, &mut state_animation_rate, skeleton_attr, From abcd0af1e3c12bf1b53cd093c3dc47cd96ad87d8 Mon Sep 17 00:00:00 2001 From: Sam Date: Tue, 8 Sep 2020 19:28:59 -0500 Subject: [PATCH 09/28] Removed combo duration of combo melee (combo now activated from recover duration). Allowed for forced forward movement in combo melee, and added it to stages 1 and 3). --- common/src/comp/ability.rs | 1 + common/src/comp/inventory/item/tool.rs | 53 ++--------- common/src/states/combo_melee.rs | 124 ++++++++++++++++++------- common/src/states/utils.rs | 14 +++ 4 files changed, 114 insertions(+), 78 deletions(-) diff --git a/common/src/comp/ability.rs b/common/src/comp/ability.rs index 35842f23d9..c5800e24a7 100644 --- a/common/src/comp/ability.rs +++ b/common/src/comp/ability.rs @@ -342,6 +342,7 @@ impl From<&CharacterAbility> for CharacterState { combo_duration: *combo_duration, timer: Duration::default(), stage_section: wielding::StageSection::Buildup, + next_stage: false, }), CharacterAbility::LeapMelee { energy_cost: _, diff --git a/common/src/comp/inventory/item/tool.rs b/common/src/comp/inventory/item/tool.rs index a1df693acd..806b96f1cc 100644 --- a/common/src/comp/inventory/item/tool.rs +++ b/common/src/comp/inventory/item/tool.rs @@ -130,6 +130,7 @@ impl Tool { base_buildup_duration: Duration::from_millis(500), base_swing_duration: Duration::from_millis(200), base_recover_duration: Duration::from_millis(400), + forward_movement: 0.5, }, combo_melee::Stage { stage: 2, @@ -142,6 +143,7 @@ impl Tool { base_buildup_duration: Duration::from_millis(400), base_swing_duration: Duration::from_millis(600), base_recover_duration: Duration::from_millis(400), + forward_movement: 0.0, }, combo_melee::Stage { stage: 3, @@ -154,6 +156,7 @@ impl Tool { base_buildup_duration: Duration::from_millis(500), base_swing_duration: Duration::from_millis(200), base_recover_duration: Duration::from_millis(300), + forward_movement: 1.2, }, ], initial_energy_gain: 0, @@ -169,49 +172,13 @@ impl Tool { }, ], Axe(_) => vec![ - ComboMelee { - stage_data: vec![ - combo_melee::Stage { - stage: 1, - base_damage: 30, - max_damage: 50, - damage_increase: 10, - knockback: 5.0, - range: 3.5, - angle: 45.0, - base_buildup_duration: Duration::from_millis(150), - base_swing_duration: Duration::from_millis(100), - base_recover_duration: Duration::from_millis(100), - }, - combo_melee::Stage { - stage: 2, - base_damage: 50, - max_damage: 80, - damage_increase: 15, - knockback: 5.0, - range: 3.5, - angle: 45.0, - base_buildup_duration: Duration::from_millis(150), - base_swing_duration: Duration::from_millis(100), - base_recover_duration: Duration::from_millis(100), - }, - combo_melee::Stage { - stage: 3, - base_damage: 70, - max_damage: 110, - damage_increase: 20, - knockback: 5.0, - range: 3.5, - angle: 45.0, - base_buildup_duration: Duration::from_millis(150), - base_swing_duration: Duration::from_millis(100), - base_recover_duration: Duration::from_millis(100), - }, - ], - initial_energy_gain: 0, - max_energy_gain: 100, - energy_increase: 20, - combo_duration: Duration::from_millis(250), + BasicMelee { + energy_cost: 0, + buildup_duration: Duration::from_millis(700), + recover_duration: Duration::from_millis(300), + base_healthchange: (-120.0 * self.base_power()) as i32, + range: 3.5, + max_angle: 20.0, }, SpinMelee { energy_cost: 100, diff --git a/common/src/states/combo_melee.rs b/common/src/states/combo_melee.rs index b452706d50..3d2d89e8fd 100644 --- a/common/src/states/combo_melee.rs +++ b/common/src/states/combo_melee.rs @@ -29,6 +29,8 @@ pub struct Stage { pub base_swing_duration: Duration, /// Initial recover duration of stage (how long until character exits state) pub base_recover_duration: Duration, + /// How much forward movement there is in the swing portion of the stage + pub forward_movement: f32, } /// A sequence of attacks that can incrementally become faster and more @@ -55,14 +57,16 @@ pub struct Data { pub timer: Duration, /// Checks what section a stage is in pub stage_section: StageSection, + /// Whether the state should go onto the next stage + pub next_stage: bool, } impl CharacterBehavior for Data { fn behavior(&self, data: &JoinData) -> StateUpdate { let mut update = StateUpdate::from(data); - handle_orientation(data, &mut update, 5.0); - handle_move(data, &mut update, 0.8); + handle_orientation(data, &mut update, 1.0); + handle_move(data, &mut update, 0.1); let stage_index = (self.stage - 1) as usize; @@ -84,8 +88,10 @@ impl CharacterBehavior for Data { .checked_add(Duration::from_secs_f32(data.dt.0)) .unwrap_or_default(), stage_section: self.stage_section, + next_stage: self.next_stage, }); } else if self.stage_section == StageSection::Buildup { + // Transitions to swing section of stage update.character = CharacterState::ComboMelee(Data { stage: self.stage, num_stages: self.num_stages, @@ -97,10 +103,15 @@ impl CharacterBehavior for Data { combo_duration: self.combo_duration, timer: Duration::default(), stage_section: StageSection::Swing, + next_stage: self.next_stage, }); } else if self.stage_section == StageSection::Swing && self.timer < self.stage_data[stage_index].base_swing_duration { + // Forward movement + forward_move(data, &mut update, 0.1, self.stage_data[stage_index].forward_movement * 3.0); + + // Swings update.character = CharacterState::ComboMelee(Data { stage: self.stage, num_stages: self.num_stages, @@ -115,6 +126,7 @@ impl CharacterBehavior for Data { .checked_add(Duration::from_secs_f32(data.dt.0)) .unwrap_or_default(), stage_section: self.stage_section, + next_stage: self.next_stage, }); } else if self.stage_section == StageSection::Swing { // Hit attempt @@ -131,6 +143,7 @@ impl CharacterBehavior for Data { knockback: self.stage_data[stage_index].knockback, }); + // Transitions to recover section of stage update.character = CharacterState::ComboMelee(Data { stage: self.stage, num_stages: self.num_stages, @@ -142,51 +155,29 @@ impl CharacterBehavior for Data { combo_duration: self.combo_duration, timer: Duration::default(), stage_section: StageSection::Recover, + next_stage: self.next_stage, }); } else if self.stage_section == StageSection::Recover && self.timer < self.stage_data[stage_index].base_recover_duration { - update.character = CharacterState::ComboMelee(Data { - stage: self.stage, - num_stages: self.num_stages, - combo: self.combo, - stage_data: self.stage_data.clone(), - initial_energy_gain: self.initial_energy_gain, - max_energy_gain: self.max_energy_gain, - energy_increase: self.energy_increase, - combo_duration: self.combo_duration, - timer: self - .timer - .checked_add(Duration::from_secs_f32(data.dt.0)) - .unwrap_or_default(), - stage_section: self.stage_section, - }); - } else if self.stage_section == StageSection::Recover { - update.character = CharacterState::ComboMelee(Data { - stage: self.stage, - num_stages: self.num_stages, - combo: self.combo, - stage_data: self.stage_data.clone(), - initial_energy_gain: self.initial_energy_gain, - max_energy_gain: self.max_energy_gain, - energy_increase: self.energy_increase, - combo_duration: self.combo_duration, - timer: Duration::default(), - stage_section: StageSection::Combo, - }); - } else if self.stage_section == StageSection::Combo && self.timer < self.combo_duration { + // Recovers if data.inputs.primary.is_pressed() { + // Checks if state will transition to next stage after recover update.character = CharacterState::ComboMelee(Data { - stage: (self.stage % self.num_stages) + 1, + stage: self.stage, num_stages: self.num_stages, - combo: self.combo + 1, + combo: self.combo, stage_data: self.stage_data.clone(), initial_energy_gain: self.initial_energy_gain, max_energy_gain: self.max_energy_gain, energy_increase: self.energy_increase, combo_duration: self.combo_duration, - timer: Duration::default(), - stage_section: StageSection::Buildup, + timer: self + .timer + .checked_add(Duration::from_secs_f32(data.dt.0)) + .unwrap_or_default(), + stage_section: self.stage_section, + next_stage: true, }); } else { update.character = CharacterState::ComboMelee(Data { @@ -203,8 +194,71 @@ impl CharacterBehavior for Data { .checked_add(Duration::from_secs_f32(data.dt.0)) .unwrap_or_default(), stage_section: self.stage_section, + next_stage: self.next_stage, }); } + } /*else if self.stage_section == StageSection::Recover { + update.character = CharacterState::ComboMelee(Data { + stage: self.stage, + num_stages: self.num_stages, + combo: self.combo, + stage_data: self.stage_data.clone(), + initial_energy_gain: self.initial_energy_gain, + max_energy_gain: self.max_energy_gain, + energy_increase: self.energy_increase, + combo_duration: self.combo_duration, + timer: Duration::default(), + stage_section: StageSection::Combo, + next_stage: self.next_stage, + }); + } else if self.stage_section == StageSection::Combo && self.timer < self.combo_duration { + if data.inputs.primary.is_pressed() { + update.character = CharacterState::ComboMelee(Data { + stage: (self.stage % self.num_stages) + 1, + num_stages: self.num_stages, + combo: self.combo + 1, + stage_data: self.stage_data.clone(), + initial_energy_gain: self.initial_energy_gain, + max_energy_gain: self.max_energy_gain, + energy_increase: self.energy_increase, + combo_duration: self.combo_duration, + timer: Duration::default(), + stage_section: StageSection::Buildup, + next_stage: self.next_stage, + }); + } else { + update.character = CharacterState::ComboMelee(Data { + stage: self.stage, + num_stages: self.num_stages, + combo: self.combo, + stage_data: self.stage_data.clone(), + initial_energy_gain: self.initial_energy_gain, + max_energy_gain: self.max_energy_gain, + energy_increase: self.energy_increase, + combo_duration: self.combo_duration, + timer: self + .timer + .checked_add(Duration::from_secs_f32(data.dt.0)) + .unwrap_or_default(), + stage_section: self.stage_section, + next_stage: self.next_stage, + }); + } + }*/ else if self.next_stage { + // Transitions to buildup section of next stage + update.character = CharacterState::ComboMelee(Data { + stage: (self.stage % self.num_stages) + 1, + num_stages: self.num_stages, + combo: self.combo + 1, + stage_data: self.stage_data.clone(), + initial_energy_gain: self.initial_energy_gain, + max_energy_gain: self.max_energy_gain, + energy_increase: self.energy_increase, + combo_duration: self.combo_duration, + timer: Duration::default(), + stage_section: StageSection::Buildup, + next_stage: false, + }); } else { // Done update.character = CharacterState::Wielding; diff --git a/common/src/states/utils.rs b/common/src/states/utils.rs index 1b50424c2e..106394ac80 100644 --- a/common/src/states/utils.rs +++ b/common/src/states/utils.rs @@ -89,6 +89,20 @@ fn basic_move(data: &JoinData, update: &mut StateUpdate, efficiency: f32) { handle_orientation(data, update, data.body.base_ori_rate()); } +/// Similar to basic_move function, but with forced forward movement +pub fn forward_move(data: &JoinData, update: &mut StateUpdate, efficiency: f32, forward: f32) { + let accel = if data.physics.on_ground { + data.body.base_accel() + } else { + BASE_HUMANOID_AIR_ACCEL + }; + + update.vel.0 = + update.vel.0 + Vec2::broadcast(data.dt.0) * data.inputs.move_dir * accel * efficiency + (*update.ori.0).xy() * forward; + + handle_orientation(data, update, data.body.base_ori_rate()); +} + pub fn handle_orientation(data: &JoinData, update: &mut StateUpdate, rate: f32) { // Set direction based on move direction let ori_dir = if update.character.is_attack() | update.character.is_block() { From 04af75bf8dad19c8aea982dc0538d1aba7958489 Mon Sep 17 00:00:00 2001 From: Sam Date: Wed, 9 Sep 2020 21:58:28 -0500 Subject: [PATCH 10/28] Initial implementation of new dash melee. --- common/src/comp/ability.rs | 51 ++++- common/src/comp/inventory/item/tool.rs | 61 +++--- common/src/states/combo_melee.rs | 62 +----- common/src/states/dash_melee.rs | 262 +++++++++++++++++++----- common/src/states/utils.rs | 20 +- common/src/states/wielding.rs | 12 -- voxygen/src/anim/src/character/alpha.rs | 5 +- voxygen/src/anim/src/character/beta.rs | 5 +- voxygen/src/anim/src/character/spin.rs | 5 +- voxygen/src/scene/figure/mod.rs | 4 +- 10 files changed, 318 insertions(+), 169 deletions(-) diff --git a/common/src/comp/ability.rs b/common/src/comp/ability.rs index c5800e24a7..ed270b65af 100644 --- a/common/src/comp/ability.rs +++ b/common/src/comp/ability.rs @@ -3,7 +3,7 @@ use crate::{ item::{armor::Protection, Item, ItemKind}, Body, CharacterState, EnergySource, Gravity, LightEmitter, Projectile, StateUpdate, }, - states::*, + states::{utils::StageSection, *}, sys::character_behavior::JoinData, }; use arraygen::Arraygen; @@ -72,9 +72,19 @@ pub enum CharacterAbility { }, DashMelee { energy_cost: u32, - buildup_duration: Duration, - recover_duration: Duration, base_damage: u32, + max_damage: u32, + base_knockback: f32, + max_knockback: f32, + range: f32, + angle: f32, + energy_drain: u32, + forward_speed: f32, + buildup_duration: Duration, + charge_duration: Duration, + infinite_charge: bool, + swing_duration: Duration, + recover_duration: Duration, }, BasicBlock, Roll, @@ -310,15 +320,36 @@ impl From<&CharacterAbility> for CharacterState { }), CharacterAbility::DashMelee { energy_cost: _, - buildup_duration, - recover_duration, base_damage, + max_damage, + base_knockback, + max_knockback, + range, + angle, + energy_drain, + forward_speed, + buildup_duration, + charge_duration, + infinite_charge, + swing_duration, + recover_duration, } => CharacterState::DashMelee(dash_melee::Data { - initialize: true, - exhausted: false, - buildup_duration: *buildup_duration, - recover_duration: *recover_duration, base_damage: *base_damage, + max_damage: *max_damage, + base_knockback: *base_knockback, + max_knockback: *max_knockback, + range: *range, + angle: *angle, + energy_drain: *energy_drain, + forward_speed: *forward_speed, + buildup_duration: *buildup_duration, + charge_duration: *charge_duration, + charge_duration_attained: Duration::default(), + infinite_charge: *infinite_charge, + swing_duration: *swing_duration, + recover_duration: *recover_duration, + timer: Duration::default(), + stage_section: StageSection::Buildup, }), CharacterAbility::BasicBlock => CharacterState::BasicBlock, CharacterAbility::Roll => CharacterState::Roll(roll::Data { @@ -341,7 +372,7 @@ impl From<&CharacterAbility> for CharacterState { energy_increase: *energy_increase, combo_duration: *combo_duration, timer: Duration::default(), - stage_section: wielding::StageSection::Buildup, + stage_section: StageSection::Buildup, next_stage: false, }), CharacterAbility::LeapMelee { diff --git a/common/src/comp/inventory/item/tool.rs b/common/src/comp/inventory/item/tool.rs index 806b96f1cc..11b7730375 100644 --- a/common/src/comp/inventory/item/tool.rs +++ b/common/src/comp/inventory/item/tool.rs @@ -121,9 +121,9 @@ impl Tool { stage_data: vec![ combo_melee::Stage { stage: 1, - base_damage: 30, - max_damage: 50, - damage_increase: 10, + base_damage: (30.0 * self.base_power()) as u32, + max_damage: (50.0 * self.base_power()) as u32, + damage_increase: (10.0 * self.base_power()) as u32, knockback: 5.0, range: 3.5, angle: 45.0, @@ -134,9 +134,9 @@ impl Tool { }, combo_melee::Stage { stage: 2, - base_damage: 50, - max_damage: 80, - damage_increase: 15, + base_damage: (50.0 * self.base_power()) as u32, + max_damage: (80.0 * self.base_power()) as u32, + damage_increase: (15.0 * self.base_power()) as u32, knockback: 5.0, range: 3.5, angle: 45.0, @@ -147,9 +147,9 @@ impl Tool { }, combo_melee::Stage { stage: 3, - base_damage: 70, - max_damage: 110, - damage_increase: 20, + base_damage: (70.0 * self.base_power()) as u32, + max_damage: (110.0 * self.base_power()) as u32, + damage_increase: (20.0 * self.base_power()) as u32, knockback: 5.0, range: 3.5, angle: 45.0, @@ -165,10 +165,20 @@ impl Tool { combo_duration: Duration::from_millis(10), }, DashMelee { - energy_cost: 700, - buildup_duration: Duration::from_millis(500), - recover_duration: Duration::from_millis(500), - base_damage: (120.0 * self.base_power()) as u32, + energy_cost: 100, + base_damage: (60.0 * self.base_power()) as u32, + max_damage: (180.0 * self.base_power()) as u32, + base_knockback: 5.0, + max_knockback: 10.0, + range: 5.0, + angle: 45.0, + energy_drain: 100, + forward_speed: 2.5, + buildup_duration: Duration::from_millis(250), + charge_duration: Duration::from_millis(2000), + infinite_charge: true, + swing_duration: Duration::from_millis(100), + recover_duration: Duration::from_millis(300), }, ], Axe(_) => vec![ @@ -254,23 +264,14 @@ impl Tool { max_projectile_speed: 500.0, }, ], - Dagger(_) => vec![ - BasicMelee { - energy_cost: 0, - buildup_duration: Duration::from_millis(100), - recover_duration: Duration::from_millis(400), - base_healthchange: (-50.0 * self.base_power()) as i32, - knockback: 0.0, - range: 3.5, - max_angle: 20.0, - }, - DashMelee { - energy_cost: 700, - buildup_duration: Duration::from_millis(500), - recover_duration: Duration::from_millis(500), - base_damage: (100.0 * self.base_power()) as u32, - }, - ], + Dagger(_) => vec![BasicMelee { + energy_cost: 0, + buildup_duration: Duration::from_millis(100), + recover_duration: Duration::from_millis(400), + base_healthchange: (-50.0 * self.base_power()) as i32, + range: 3.5, + max_angle: 20.0, + }], Staff(kind) => { if kind == "Sceptre" { vec![ diff --git a/common/src/states/combo_melee.rs b/common/src/states/combo_melee.rs index 3d2d89e8fd..b90853f779 100644 --- a/common/src/states/combo_melee.rs +++ b/common/src/states/combo_melee.rs @@ -1,6 +1,6 @@ use crate::{ comp::{Attacking, CharacterState, EnergySource, StateUpdate}, - states::{utils::*, wielding::StageSection}, + states::utils::{StageSection, *}, sys::character_behavior::{CharacterBehavior, JoinData}, }; use serde::{Deserialize, Serialize}; @@ -109,8 +109,13 @@ impl CharacterBehavior for Data { && self.timer < self.stage_data[stage_index].base_swing_duration { // Forward movement - forward_move(data, &mut update, 0.1, self.stage_data[stage_index].forward_movement * 3.0); - + forward_move( + data, + &mut update, + 0.1, + self.stage_data[stage_index].forward_movement, + ); + // Swings update.character = CharacterState::ComboMelee(Data { stage: self.stage, @@ -197,54 +202,7 @@ impl CharacterBehavior for Data { next_stage: self.next_stage, }); } - } /*else if self.stage_section == StageSection::Recover { - update.character = CharacterState::ComboMelee(Data { - stage: self.stage, - num_stages: self.num_stages, - combo: self.combo, - stage_data: self.stage_data.clone(), - initial_energy_gain: self.initial_energy_gain, - max_energy_gain: self.max_energy_gain, - energy_increase: self.energy_increase, - combo_duration: self.combo_duration, - timer: Duration::default(), - stage_section: StageSection::Combo, - next_stage: self.next_stage, - }); - } else if self.stage_section == StageSection::Combo && self.timer < self.combo_duration { - if data.inputs.primary.is_pressed() { - update.character = CharacterState::ComboMelee(Data { - stage: (self.stage % self.num_stages) + 1, - num_stages: self.num_stages, - combo: self.combo + 1, - stage_data: self.stage_data.clone(), - initial_energy_gain: self.initial_energy_gain, - max_energy_gain: self.max_energy_gain, - energy_increase: self.energy_increase, - combo_duration: self.combo_duration, - timer: Duration::default(), - stage_section: StageSection::Buildup, - next_stage: self.next_stage, - }); - } else { - update.character = CharacterState::ComboMelee(Data { - stage: self.stage, - num_stages: self.num_stages, - combo: self.combo, - stage_data: self.stage_data.clone(), - initial_energy_gain: self.initial_energy_gain, - max_energy_gain: self.max_energy_gain, - energy_increase: self.energy_increase, - combo_duration: self.combo_duration, - timer: self - .timer - .checked_add(Duration::from_secs_f32(data.dt.0)) - .unwrap_or_default(), - stage_section: self.stage_section, - next_stage: self.next_stage, - }); - } - }*/ else if self.next_stage { + } else if self.next_stage { // Transitions to buildup section of next stage update.character = CharacterState::ComboMelee(Data { stage: (self.stage % self.num_stages) + 1, @@ -258,7 +216,7 @@ impl CharacterBehavior for Data { timer: Duration::default(), stage_section: StageSection::Buildup, next_stage: false, - }); + }); } else { // Done update.character = CharacterState::Wielding; diff --git a/common/src/states/dash_melee.rs b/common/src/states/dash_melee.rs index 239d1fb2c1..5b9d3a061f 100644 --- a/common/src/states/dash_melee.rs +++ b/common/src/states/dash_melee.rs @@ -1,88 +1,242 @@ use crate::{ - comp::{Attacking, CharacterState, StateUpdate}, - states::utils::*, + comp::{Attacking, CharacterState, EnergySource, StateUpdate}, + states::utils::{StageSection, *}, sys::character_behavior::*, }; use serde::{Deserialize, Serialize}; use std::time::Duration; -use vek::Vec3; -const DASH_SPEED: f32 = 19.0; - -#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize, Eq, Hash)] +#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)] pub struct Data { + /// How much damage the attack initially does + pub base_damage: u32, + /// How much damage the attack does at max charge distance + pub max_damage: u32, + /// How much the attack knocks the target back initially + pub base_knockback: f32, + /// How much knockback happens at max charge distance + pub max_knockback: f32, + /// Range of the attack + pub range: f32, + /// Angle of the attack + pub angle: f32, + /// Rate of energy drain + pub energy_drain: u32, + /// How quickly dasher moves forward + pub forward_speed: f32, /// How long until state should deal damage pub buildup_duration: Duration, + /// How long the state charges for until it reaches max damage + pub charge_duration: Duration, + /// How high timer got while in charge potion + pub charge_duration_attained: Duration, + /// Whether state keeps charging after reaching max charge duration + pub infinite_charge: bool, + /// How long the state swings for + pub swing_duration: Duration, /// How long the state has until exiting pub recover_duration: Duration, - /// Base damage - pub base_damage: u32, - /// Whether the attack can deal more damage - pub exhausted: bool, - pub initialize: bool, + /// Timer for each stage + pub timer: Duration, + /// What section the character stage is in + pub stage_section: StageSection, } impl CharacterBehavior for Data { fn behavior(&self, data: &JoinData) -> StateUpdate { let mut update = StateUpdate::from(data); - if self.initialize { - update.vel.0 = *data.inputs.look_dir * 20.0; - if let Some(dir) = Vec3::from(data.inputs.look_dir.xy()).try_normalized() { - update.ori.0 = dir.into(); - } - } - - if self.buildup_duration != Duration::default() && data.physics.touch_entities.is_empty() { - // Build up (this will move you forward) - update.vel.0 = Vec3::new(0.0, 0.0, update.vel.0.z) - + (update.vel.0 * Vec3::new(1.0, 1.0, 0.0) - + 1.5 * data.inputs.move_dir.try_normalized().unwrap_or_default()) - .try_normalized() - .unwrap_or_default() - * DASH_SPEED; + handle_orientation(data, &mut update, 1.0); + handle_move(data, &mut update, 0.1); + if self.stage_section == StageSection::Buildup && self.timer < self.buildup_duration { + // Build up update.character = CharacterState::DashMelee(Data { - buildup_duration: self - .buildup_duration - .checked_sub(Duration::from_secs_f32(data.dt.0)) - .unwrap_or_default(), - recover_duration: self.recover_duration, base_damage: self.base_damage, - exhausted: false, - initialize: false, + max_damage: self.max_damage, + base_knockback: self.base_knockback, + max_knockback: self.max_knockback, + range: self.range, + angle: self.angle, + energy_drain: self.energy_drain, + forward_speed: self.forward_speed, + buildup_duration: self.buildup_duration, + charge_duration: self.charge_duration, + charge_duration_attained: self.charge_duration_attained, + infinite_charge: self.infinite_charge, + swing_duration: self.swing_duration, + recover_duration: self.recover_duration, + timer: self + .timer + .checked_add(Duration::from_secs_f32(data.dt.0)) + .unwrap_or_default(), + stage_section: self.stage_section, + }) + } else if self.stage_section == StageSection::Buildup { + // Transitions to charge section of stage + update.character = CharacterState::DashMelee(Data { + base_damage: self.base_damage, + max_damage: self.max_damage, + base_knockback: self.base_knockback, + max_knockback: self.max_knockback, + range: self.range, + angle: self.angle, + energy_drain: self.energy_drain, + forward_speed: self.forward_speed, + buildup_duration: self.buildup_duration, + charge_duration: self.charge_duration, + charge_duration_attained: self.charge_duration_attained, + infinite_charge: self.infinite_charge, + swing_duration: self.swing_duration, + recover_duration: self.recover_duration, + timer: Duration::default(), + stage_section: StageSection::Charge, + }) + } else if self.stage_section == StageSection::Charge /*&& data.physics.touch_entities.is_empty()*/ && ((self.timer < self.charge_duration && !self.infinite_charge) || (data.inputs.secondary.is_pressed() && self.infinite_charge)) && update.energy.current() > 0 + { + // Forward movement + forward_move(data, &mut update, 0.1, self.forward_speed); + + // Charges + update.character = CharacterState::DashMelee(Data { + base_damage: self.base_damage, + max_damage: self.max_damage, + base_knockback: self.base_knockback, + max_knockback: self.max_knockback, + range: self.range, + angle: self.angle, + energy_drain: self.energy_drain, + forward_speed: self.forward_speed, + buildup_duration: self.buildup_duration, + charge_duration: self.charge_duration, + charge_duration_attained: self.charge_duration_attained, + infinite_charge: self.infinite_charge, + swing_duration: self.swing_duration, + recover_duration: self.recover_duration, + timer: self + .timer + .checked_add(Duration::from_secs_f32(data.dt.0)) + .unwrap_or_default(), + stage_section: self.stage_section, }); - } else if !self.exhausted { + + // Consumes energy if there's enough left and charge has not stopped + update.energy.change_by( + -(self.energy_drain as f32 * data.dt.0) as i32, + EnergySource::Ability, + ); + } else if self.stage_section == StageSection::Charge { + // Transitions to swing section of stage + update.character = CharacterState::DashMelee(Data { + base_damage: self.base_damage, + max_damage: self.max_damage, + base_knockback: self.base_knockback, + max_knockback: self.max_knockback, + range: self.range, + angle: self.angle, + energy_drain: self.energy_drain, + forward_speed: self.forward_speed, + buildup_duration: self.buildup_duration, + charge_duration: self.charge_duration, + charge_duration_attained: self.charge_duration_attained, + infinite_charge: self.infinite_charge, + swing_duration: self.swing_duration, + recover_duration: self.recover_duration, + timer: Duration::default(), + stage_section: StageSection::Swing, + }) + } else if self.stage_section == StageSection::Swing && self.timer < self.swing_duration { + // Swings + let charge_attained = if self.timer > self.charge_duration_attained { + if self.timer > self.charge_duration_attained { + self.charge_duration + } else { + self.timer + } + } else { + self.charge_duration_attained + }; + update.character = CharacterState::DashMelee(Data { + base_damage: self.base_damage, + max_damage: self.max_damage, + base_knockback: self.base_knockback, + max_knockback: self.max_knockback, + range: self.range, + angle: self.angle, + energy_drain: self.energy_drain, + forward_speed: self.forward_speed, + buildup_duration: self.buildup_duration, + charge_duration: self.charge_duration, + charge_duration_attained: charge_attained, + infinite_charge: self.infinite_charge, + swing_duration: self.swing_duration, + recover_duration: self.recover_duration, + timer: self + .timer + .checked_add(Duration::from_secs_f32(data.dt.0)) + .unwrap_or_default(), + stage_section: self.stage_section, + }) + } else if self.stage_section == StageSection::Swing { // Hit attempt + let charge_frac = + (self.charge_duration_attained.as_secs_f32() / self.charge_duration.as_secs_f32()).min(1.0); + let damage = (self.max_damage as f32 - self.base_damage as f32) * charge_frac + + self.base_damage as f32; + let knockback = + (self.max_knockback - self.base_knockback) * charge_frac + self.base_knockback; data.updater.insert(data.entity, Attacking { - base_healthchange: -(self.base_damage as i32), - range: 3.5, - max_angle: 45_f32.to_radians(), + base_healthchange: -damage as i32, + range: self.range, + max_angle: self.angle.to_radians(), applied: false, hit_count: 0, - knockback: 0.0, + knockback, }); + // Transitions to recover section of stage update.character = CharacterState::DashMelee(Data { - buildup_duration: Duration::default(), - recover_duration: self.recover_duration, base_damage: self.base_damage, - exhausted: true, - initialize: false, - }); - } else if self.recover_duration != Duration::default() { - // Recovery - handle_move(data, &mut update, 0.7); - update.character = CharacterState::DashMelee(Data { + max_damage: self.max_damage, + base_knockback: self.base_knockback, + max_knockback: self.max_knockback, + range: self.range, + angle: self.angle, + energy_drain: self.energy_drain, + forward_speed: self.forward_speed, buildup_duration: self.buildup_duration, - recover_duration: self - .recover_duration - .checked_sub(Duration::from_secs_f32(data.dt.0)) - .unwrap_or_default(), + charge_duration: self.charge_duration, + charge_duration_attained: self.charge_duration_attained, + infinite_charge: self.infinite_charge, + swing_duration: self.swing_duration, + recover_duration: self.recover_duration, + timer: Duration::default(), + stage_section: StageSection::Recover, + }) + } else if self.stage_section == StageSection::Recover && self.timer < self.recover_duration + { + // Recover + update.character = CharacterState::DashMelee(Data { base_damage: self.base_damage, - exhausted: true, - initialize: false, - }); + max_damage: self.max_damage, + base_knockback: self.base_knockback, + max_knockback: self.max_knockback, + range: self.range, + angle: self.angle, + energy_drain: self.energy_drain, + forward_speed: self.forward_speed, + buildup_duration: self.buildup_duration, + charge_duration: self.charge_duration, + charge_duration_attained: self.charge_duration_attained, + infinite_charge: self.infinite_charge, + swing_duration: self.swing_duration, + recover_duration: self.recover_duration, + timer: self + .timer + .checked_add(Duration::from_secs_f32(data.dt.0)) + .unwrap_or_default(), + stage_section: self.stage_section, + }) } else { // Done update.character = CharacterState::Wielding; diff --git a/common/src/states/utils.rs b/common/src/states/utils.rs index 106394ac80..c671b051f9 100644 --- a/common/src/states/utils.rs +++ b/common/src/states/utils.rs @@ -8,6 +8,7 @@ use crate::{ sys::{character_behavior::JoinData, phys::GRAVITY}, util::Dir, }; +use serde::{Deserialize, Serialize}; use vek::*; pub const MOVEMENT_THRESHOLD_VEL: f32 = 3.0; @@ -97,10 +98,12 @@ pub fn forward_move(data: &JoinData, update: &mut StateUpdate, efficiency: f32, BASE_HUMANOID_AIR_ACCEL }; - update.vel.0 = - update.vel.0 + Vec2::broadcast(data.dt.0) * data.inputs.move_dir * accel * efficiency + (*update.ori.0).xy() * forward; + update.vel.0 = update.vel.0 + + Vec2::broadcast(data.dt.0) + * accel + * (data.inputs.move_dir * efficiency + (*update.ori.0).xy() * forward); - handle_orientation(data, update, data.body.base_ori_rate()); + handle_orientation(data, update, data.body.base_ori_rate() * efficiency); } pub fn handle_orientation(data: &JoinData, update: &mut StateUpdate, rate: f32) { @@ -344,3 +347,14 @@ pub fn unwrap_tool_data<'a>(data: &'a JoinData) -> Option<&'a Tool> { None } } + +/// Determines what portion a state is in. Used in all attacks (eventually). Is +/// used to control aspects of animation code, as well as logic within the +/// character states. +#[derive(Clone, Copy, Debug, Eq, PartialEq, Serialize, Deserialize)] +pub enum StageSection { + Buildup, + Swing, + Recover, + Charge, +} diff --git a/common/src/states/wielding.rs b/common/src/states/wielding.rs index a91aa8ce07..f64ae9c77f 100644 --- a/common/src/states/wielding.rs +++ b/common/src/states/wielding.rs @@ -3,7 +3,6 @@ use crate::{ comp::{CharacterState, StateUpdate}, sys::character_behavior::{CharacterBehavior, JoinData}, }; -use serde::{Deserialize, Serialize}; pub struct Data; @@ -58,14 +57,3 @@ impl CharacterBehavior for Data { update } } - -/// Determines what portion a state is in. Used in all attacks (eventually). Is -/// used to control aspects of animation code, as well as logic within the -/// character states. -#[derive(Clone, Copy, Debug, Eq, PartialEq, Serialize, Deserialize)] -pub enum StageSection { - Buildup, - Swing, - Recover, - Combo, -} diff --git a/voxygen/src/anim/src/character/alpha.rs b/voxygen/src/anim/src/character/alpha.rs index 0751aab175..17dece4690 100644 --- a/voxygen/src/anim/src/character/alpha.rs +++ b/voxygen/src/anim/src/character/alpha.rs @@ -4,7 +4,7 @@ use super::{ }; use common::{ comp::item::{Hands, ToolKind}, - states::wielding::StageSection, + states::utils::StageSection, }; use std::f32::consts::PI; @@ -119,7 +119,7 @@ impl Animation for AlphaAnimation { // next.torso.orientation = Quaternion::rotation_z(test2 // * 7.2); }, - StageSection::Recover | StageSection::Combo => { + StageSection::Recover => { //println!("{:.3} recover", anim_time); next.control.position = Vec3::new(-7.0, 7.0, 2.0); next.control.orientation = Quaternion::rotation_x(0.0) @@ -131,6 +131,7 @@ impl Animation for AlphaAnimation { next.head.orientation = Quaternion::rotation_y(0.0) * Quaternion::rotation_z(1.57); }, + _ => {}, } } } diff --git a/voxygen/src/anim/src/character/beta.rs b/voxygen/src/anim/src/character/beta.rs index 3beb8b289a..ab8562c292 100644 --- a/voxygen/src/anim/src/character/beta.rs +++ b/voxygen/src/anim/src/character/beta.rs @@ -4,7 +4,7 @@ use super::{ }; use common::{ comp::item::{Hands, ToolKind}, - states::wielding::StageSection, + states::utils::StageSection, }; pub struct BetaAnimation; @@ -98,7 +98,7 @@ impl Animation for BetaAnimation { next.head.orientation = Quaternion::rotation_y(0.1) * Quaternion::rotation_z(-1.2 + test * -0.5); }, - StageSection::Recover | StageSection::Combo => { + StageSection::Recover => { next.control.position = Vec3::new(10.0 + movement * -5.0, 8.0, 6.0); next.control.orientation = Quaternion::rotation_x(-1.57) * Quaternion::rotation_y(2.0) @@ -108,6 +108,7 @@ impl Animation for BetaAnimation { next.head.orientation = Quaternion::rotation_y(0.1) * Quaternion::rotation_z(-1.5); }, + _ => {}, } } } diff --git a/voxygen/src/anim/src/character/spin.rs b/voxygen/src/anim/src/character/spin.rs index f3896b4ac2..290df1b49d 100644 --- a/voxygen/src/anim/src/character/spin.rs +++ b/voxygen/src/anim/src/character/spin.rs @@ -4,7 +4,7 @@ use super::{ }; use common::{ comp::item::{Hands, ToolKind}, - states::wielding::StageSection, + states::utils::StageSection, }; use std::f32::consts::PI; @@ -104,7 +104,7 @@ impl Animation for SpinAnimation { next.shorts.orientation = Quaternion::rotation_z(test2 * 1.5); next.torso.orientation = Quaternion::rotation_z(test2 * 7.2); }, - StageSection::Recover | StageSection::Combo => { + StageSection::Recover => { //println!("{:.3} recover", anim_time); next.control.position = Vec3::new( -8.0, @@ -119,6 +119,7 @@ impl Animation for SpinAnimation { next.head.orientation = Quaternion::rotation_y(movement * 0.1) * Quaternion::rotation_z(movement * -0.1); }, + _ => {}, } } } diff --git a/voxygen/src/scene/figure/mod.rs b/voxygen/src/scene/figure/mod.rs index 62e08b55ca..1264b7b390 100644 --- a/voxygen/src/scene/figure/mod.rs +++ b/voxygen/src/scene/figure/mod.rs @@ -30,7 +30,7 @@ use common::{ }, span, state::{DeltaTime, State}, - states::wielding::StageSection, + states::utils::StageSection, terrain::TerrainChunk, vol::RectRasterableVol, }; @@ -946,7 +946,7 @@ impl FigureMgr { .base_recover_duration .as_secs_f64() }, - StageSection::Combo => stage_time / s.combo_duration.as_secs_f64(), + _ => 0.0, }; match s.stage { 1 => anim::character::AlphaAnimation::update_skeleton( From 744843d03ffbffe7d55b4753de8562fc7aa0e3c9 Mon Sep 17 00:00:00 2001 From: Sam Date: Thu, 10 Sep 2020 21:17:33 -0500 Subject: [PATCH 11/28] Dash now stops when colliding with entity --- common/src/states/dash_melee.rs | 26 ++++++++++++++------------ common/src/sys/phys.rs | 7 +++++++ 2 files changed, 21 insertions(+), 12 deletions(-) diff --git a/common/src/states/dash_melee.rs b/common/src/states/dash_melee.rs index 5b9d3a061f..da01ff0b29 100644 --- a/common/src/states/dash_melee.rs +++ b/common/src/states/dash_melee.rs @@ -92,11 +92,22 @@ impl CharacterBehavior for Data { timer: Duration::default(), stage_section: StageSection::Charge, }) - } else if self.stage_section == StageSection::Charge /*&& data.physics.touch_entities.is_empty()*/ && ((self.timer < self.charge_duration && !self.infinite_charge) || (data.inputs.secondary.is_pressed() && self.infinite_charge)) && update.energy.current() > 0 + } else if self.stage_section == StageSection::Charge && data.physics.touch_entities.is_empty() && ((self.timer < self.charge_duration && !self.infinite_charge) || (data.inputs.secondary.is_pressed() && self.infinite_charge)) && update.energy.current() > 0 { // Forward movement forward_move(data, &mut update, 0.1, self.forward_speed); + // Checks how much a charge has built up + let charge_attained = if self.timer > self.charge_duration_attained { + if self.timer > self.charge_duration_attained { + self.charge_duration + } else { + self.timer + } + } else { + self.charge_duration_attained + }; + // Charges update.character = CharacterState::DashMelee(Data { base_damage: self.base_damage, @@ -109,7 +120,7 @@ impl CharacterBehavior for Data { forward_speed: self.forward_speed, buildup_duration: self.buildup_duration, charge_duration: self.charge_duration, - charge_duration_attained: self.charge_duration_attained, + charge_duration_attained: charge_attained, infinite_charge: self.infinite_charge, swing_duration: self.swing_duration, recover_duration: self.recover_duration, @@ -147,15 +158,6 @@ impl CharacterBehavior for Data { }) } else if self.stage_section == StageSection::Swing && self.timer < self.swing_duration { // Swings - let charge_attained = if self.timer > self.charge_duration_attained { - if self.timer > self.charge_duration_attained { - self.charge_duration - } else { - self.timer - } - } else { - self.charge_duration_attained - }; update.character = CharacterState::DashMelee(Data { base_damage: self.base_damage, max_damage: self.max_damage, @@ -167,7 +169,7 @@ impl CharacterBehavior for Data { forward_speed: self.forward_speed, buildup_duration: self.buildup_duration, charge_duration: self.charge_duration, - charge_duration_attained: charge_attained, + charge_duration_attained: self.charge_duration_attained, infinite_charge: self.infinite_charge, swing_duration: self.swing_duration, recover_duration: self.recover_duration, diff --git a/common/src/sys/phys.rs b/common/src/sys/phys.rs index bc46d5d611..1eb296c24a 100644 --- a/common/src/sys/phys.rs +++ b/common/src/sys/phys.rs @@ -156,6 +156,9 @@ impl<'a> System<'a> for Sys { let z_limits = collider.map(|c| c.get_z_limits()).unwrap_or((-0.5, 0.5)); let mass = mass.map(|m| m.0).unwrap_or(scale); + // Resets touch_entities in physics + physics.touch_entities.clear(); + // Group to ignore collisions with let ignore_group = projectile .filter(|p| p.ignore_group) @@ -189,6 +192,10 @@ impl<'a> System<'a> for Sys { if entity == entity_other || (ignore_group.is_some() && ignore_group == group_b) { continue; } + + if entity_other == entity { + continue; + } let scale_other = scale_other.map(|s| s.0).unwrap_or(1.0); let radius_other = collider_other.map(|c| c.get_radius()).unwrap_or(0.5); From b79235b89059501799734abede3ae48256fdb4a5 Mon Sep 17 00:00:00 2001 From: Sam Date: Fri, 11 Sep 2020 08:59:45 -0500 Subject: [PATCH 12/28] Dash melee now works as desired. --- common/src/comp/ability.rs | 30 +-- common/src/comp/inventory/item/tool.rs | 13 +- common/src/states/dash_melee.rs | 273 +++++++++++-------------- common/src/sys/phys.rs | 2 +- 4 files changed, 137 insertions(+), 181 deletions(-) diff --git a/common/src/comp/ability.rs b/common/src/comp/ability.rs index ed270b65af..8ee9f02fed 100644 --- a/common/src/comp/ability.rs +++ b/common/src/comp/ability.rs @@ -334,22 +334,24 @@ impl From<&CharacterAbility> for CharacterState { swing_duration, recover_duration, } => CharacterState::DashMelee(dash_melee::Data { - base_damage: *base_damage, - max_damage: *max_damage, - base_knockback: *base_knockback, - max_knockback: *max_knockback, - range: *range, - angle: *angle, - energy_drain: *energy_drain, - forward_speed: *forward_speed, - buildup_duration: *buildup_duration, - charge_duration: *charge_duration, - charge_duration_attained: Duration::default(), - infinite_charge: *infinite_charge, - swing_duration: *swing_duration, - recover_duration: *recover_duration, + static_data: dash_melee::StaticData { + base_damage: *base_damage, + max_damage: *max_damage, + base_knockback: *base_knockback, + max_knockback: *max_knockback, + range: *range, + angle: *angle, + energy_drain: *energy_drain, + forward_speed: *forward_speed, + infinite_charge: *infinite_charge, + buildup_duration: *buildup_duration, + charge_duration: *charge_duration, + recover_duration: *recover_duration, + }, + end_charge: false, timer: Duration::default(), stage_section: StageSection::Buildup, + exhausted: false, }), CharacterAbility::BasicBlock => CharacterState::BasicBlock, CharacterAbility::Roll => CharacterState::Roll(roll::Data { diff --git a/common/src/comp/inventory/item/tool.rs b/common/src/comp/inventory/item/tool.rs index 11b7730375..a891d0ae12 100644 --- a/common/src/comp/inventory/item/tool.rs +++ b/common/src/comp/inventory/item/tool.rs @@ -165,20 +165,19 @@ impl Tool { combo_duration: Duration::from_millis(10), }, DashMelee { - energy_cost: 100, + energy_cost: 200, base_damage: (60.0 * self.base_power()) as u32, max_damage: (180.0 * self.base_power()) as u32, base_knockback: 5.0, max_knockback: 10.0, range: 5.0, angle: 45.0, - energy_drain: 100, - forward_speed: 2.5, - buildup_duration: Duration::from_millis(250), - charge_duration: Duration::from_millis(2000), + energy_drain: 500, + forward_speed: 4.0, + buildup_duration: Duration::from_millis(200), + charge_duration: Duration::from_millis(400), infinite_charge: true, - swing_duration: Duration::from_millis(100), - recover_duration: Duration::from_millis(300), + recover_duration: Duration::from_millis(750), }, ], Axe(_) => vec![ diff --git a/common/src/states/dash_melee.rs b/common/src/states/dash_melee.rs index da01ff0b29..5f26f25f5c 100644 --- a/common/src/states/dash_melee.rs +++ b/common/src/states/dash_melee.rs @@ -6,8 +6,9 @@ use crate::{ use serde::{Deserialize, Serialize}; use std::time::Duration; +/// Separated out to condense update portions of character state #[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)] -pub struct Data { +pub struct StaticData { /// How much damage the attack initially does pub base_damage: u32, /// How much damage the attack does at max charge distance @@ -24,22 +25,28 @@ pub struct Data { pub energy_drain: u32, /// How quickly dasher moves forward pub forward_speed: f32, + /// Whether state keeps charging after reaching max charge duration + pub infinite_charge: bool, /// How long until state should deal damage pub buildup_duration: Duration, /// How long the state charges for until it reaches max damage pub charge_duration: Duration, - /// How high timer got while in charge potion - pub charge_duration_attained: Duration, - /// Whether state keeps charging after reaching max charge duration - pub infinite_charge: bool, - /// How long the state swings for - pub swing_duration: Duration, /// How long the state has until exiting pub recover_duration: Duration, +} + +#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)] +pub struct Data { + /// Struct containing data that does not change over the course of the character state + pub static_data: StaticData, + /// Whether the charge should end + pub end_charge: bool, /// Timer for each stage pub timer: Duration, /// What section the character stage is in pub stage_section: StageSection, + /// Whether the state should attempt attacking again + pub exhausted: bool, } impl CharacterBehavior for Data { @@ -49,195 +56,143 @@ impl CharacterBehavior for Data { handle_orientation(data, &mut update, 1.0); handle_move(data, &mut update, 0.1); - if self.stage_section == StageSection::Buildup && self.timer < self.buildup_duration { + if self.stage_section == StageSection::Buildup && self.timer < self.static_data.buildup_duration { // Build up update.character = CharacterState::DashMelee(Data { - base_damage: self.base_damage, - max_damage: self.max_damage, - base_knockback: self.base_knockback, - max_knockback: self.max_knockback, - range: self.range, - angle: self.angle, - energy_drain: self.energy_drain, - forward_speed: self.forward_speed, - buildup_duration: self.buildup_duration, - charge_duration: self.charge_duration, - charge_duration_attained: self.charge_duration_attained, - infinite_charge: self.infinite_charge, - swing_duration: self.swing_duration, - recover_duration: self.recover_duration, + static_data: self.static_data, + end_charge: self.end_charge, timer: self .timer .checked_add(Duration::from_secs_f32(data.dt.0)) .unwrap_or_default(), stage_section: self.stage_section, + exhausted: self.exhausted, }) } else if self.stage_section == StageSection::Buildup { // Transitions to charge section of stage update.character = CharacterState::DashMelee(Data { - base_damage: self.base_damage, - max_damage: self.max_damage, - base_knockback: self.base_knockback, - max_knockback: self.max_knockback, - range: self.range, - angle: self.angle, - energy_drain: self.energy_drain, - forward_speed: self.forward_speed, - buildup_duration: self.buildup_duration, - charge_duration: self.charge_duration, - charge_duration_attained: self.charge_duration_attained, - infinite_charge: self.infinite_charge, - swing_duration: self.swing_duration, - recover_duration: self.recover_duration, + static_data: self.static_data, + end_charge: self.end_charge, timer: Duration::default(), stage_section: StageSection::Charge, + exhausted: self.exhausted, }) - } else if self.stage_section == StageSection::Charge && data.physics.touch_entities.is_empty() && ((self.timer < self.charge_duration && !self.infinite_charge) || (data.inputs.secondary.is_pressed() && self.infinite_charge)) && update.energy.current() > 0 + } else if self.stage_section == StageSection::Charge + && ((self.timer < self.static_data.charge_duration && !self.static_data.infinite_charge) + || (data.inputs.secondary.is_pressed() && self.static_data.infinite_charge)) + && update.energy.current() > 0 + && !self.end_charge { // Forward movement - forward_move(data, &mut update, 0.1, self.forward_speed); + forward_move(data, &mut update, 0.1, self.static_data.forward_speed); - // Checks how much a charge has built up - let charge_attained = if self.timer > self.charge_duration_attained { - if self.timer > self.charge_duration_attained { - self.charge_duration - } else { - self.timer - } + // Hit attempt + if !self.exhausted { + let charge_frac = (self.timer.as_secs_f32() + / self.static_data.charge_duration.as_secs_f32()) + .min(1.0); + let damage = (self.static_data.max_damage as f32 - self.static_data.base_damage as f32) * charge_frac + + self.static_data.base_damage as f32; + let knockback = + (self.static_data.max_knockback - self.static_data.base_knockback) * charge_frac + self.static_data.base_knockback; + data.updater.insert(data.entity, Attacking { + base_healthchange: -damage as i32, + range: self.static_data.range, + max_angle: self.static_data.angle.to_radians(), + applied: false, + hit_count: 0, + knockback, + }); + } + + // 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 { + update.character = CharacterState::DashMelee(Data { + static_data: self.static_data, + end_charge: self.end_charge, + timer: self + .timer + .checked_add(Duration::from_secs_f32(data.dt.0)) + .unwrap_or_default(), + stage_section: StageSection::Charge, + exhausted: true, + }) } else { - self.charge_duration_attained - }; - - // Charges - update.character = CharacterState::DashMelee(Data { - base_damage: self.base_damage, - max_damage: self.max_damage, - base_knockback: self.base_knockback, - max_knockback: self.max_knockback, - range: self.range, - angle: self.angle, - energy_drain: self.energy_drain, - forward_speed: self.forward_speed, - buildup_duration: self.buildup_duration, - charge_duration: self.charge_duration, - charge_duration_attained: charge_attained, - infinite_charge: self.infinite_charge, - swing_duration: self.swing_duration, - recover_duration: self.recover_duration, - timer: self - .timer - .checked_add(Duration::from_secs_f32(data.dt.0)) - .unwrap_or_default(), - stage_section: self.stage_section, - }); + if let Some(attack) = data.attacking { + if attack.applied && attack.hit_count > 0 { + update.character = CharacterState::DashMelee(Data { + static_data: self.static_data, + end_charge: !self.static_data.infinite_charge, + timer: self + .timer + .checked_add(Duration::from_secs_f32(data.dt.0)) + .unwrap_or_default(), + stage_section: StageSection::Charge, + exhausted: false, + }) + } else if attack.applied { + update.character = CharacterState::DashMelee(Data { + static_data: self.static_data, + end_charge: self.end_charge, + timer: self + .timer + .checked_add(Duration::from_secs_f32(data.dt.0)) + .unwrap_or_default(), + stage_section: StageSection::Charge, + exhausted: false, + }) + } else { + update.character = CharacterState::DashMelee(Data { + static_data: self.static_data, + end_charge: !self.static_data.infinite_charge, + timer: self + .timer + .checked_add(Duration::from_secs_f32(data.dt.0)) + .unwrap_or_default(), + stage_section: StageSection::Charge, + exhausted: self.exhausted, + }) + } + } else { + update.character = CharacterState::DashMelee(Data { + static_data: self.static_data, + end_charge: !self.static_data.infinite_charge, + timer: self + .timer + .checked_add(Duration::from_secs_f32(data.dt.0)) + .unwrap_or_default(), + stage_section: StageSection::Charge, + exhausted: self.exhausted, + }) + } + } // Consumes energy if there's enough left and charge has not stopped update.energy.change_by( - -(self.energy_drain as f32 * data.dt.0) as i32, + -(self.static_data.energy_drain as f32 * data.dt.0) as i32, EnergySource::Ability, ); } else if self.stage_section == StageSection::Charge { // Transitions to swing section of stage update.character = CharacterState::DashMelee(Data { - base_damage: self.base_damage, - max_damage: self.max_damage, - base_knockback: self.base_knockback, - max_knockback: self.max_knockback, - range: self.range, - angle: self.angle, - energy_drain: self.energy_drain, - forward_speed: self.forward_speed, - buildup_duration: self.buildup_duration, - charge_duration: self.charge_duration, - charge_duration_attained: self.charge_duration_attained, - infinite_charge: self.infinite_charge, - swing_duration: self.swing_duration, - recover_duration: self.recover_duration, - timer: Duration::default(), - stage_section: StageSection::Swing, - }) - } else if self.stage_section == StageSection::Swing && self.timer < self.swing_duration { - // Swings - update.character = CharacterState::DashMelee(Data { - base_damage: self.base_damage, - max_damage: self.max_damage, - base_knockback: self.base_knockback, - max_knockback: self.max_knockback, - range: self.range, - angle: self.angle, - energy_drain: self.energy_drain, - forward_speed: self.forward_speed, - buildup_duration: self.buildup_duration, - charge_duration: self.charge_duration, - charge_duration_attained: self.charge_duration_attained, - infinite_charge: self.infinite_charge, - swing_duration: self.swing_duration, - recover_duration: self.recover_duration, - timer: self - .timer - .checked_add(Duration::from_secs_f32(data.dt.0)) - .unwrap_or_default(), - stage_section: self.stage_section, - }) - } else if self.stage_section == StageSection::Swing { - // Hit attempt - let charge_frac = - (self.charge_duration_attained.as_secs_f32() / self.charge_duration.as_secs_f32()).min(1.0); - let damage = (self.max_damage as f32 - self.base_damage as f32) * charge_frac - + self.base_damage as f32; - let knockback = - (self.max_knockback - self.base_knockback) * charge_frac + self.base_knockback; - data.updater.insert(data.entity, Attacking { - base_healthchange: -damage as i32, - range: self.range, - max_angle: self.angle.to_radians(), - applied: false, - hit_count: 0, - knockback, - }); - - // Transitions to recover section of stage - update.character = CharacterState::DashMelee(Data { - base_damage: self.base_damage, - max_damage: self.max_damage, - base_knockback: self.base_knockback, - max_knockback: self.max_knockback, - range: self.range, - angle: self.angle, - energy_drain: self.energy_drain, - forward_speed: self.forward_speed, - buildup_duration: self.buildup_duration, - charge_duration: self.charge_duration, - charge_duration_attained: self.charge_duration_attained, - infinite_charge: self.infinite_charge, - swing_duration: self.swing_duration, - recover_duration: self.recover_duration, + static_data: self.static_data, + end_charge: self.end_charge, timer: Duration::default(), stage_section: StageSection::Recover, + exhausted: self.exhausted, }) - } else if self.stage_section == StageSection::Recover && self.timer < self.recover_duration + } else if self.stage_section == StageSection::Recover && self.timer < self.static_data.recover_duration { // Recover update.character = CharacterState::DashMelee(Data { - base_damage: self.base_damage, - max_damage: self.max_damage, - base_knockback: self.base_knockback, - max_knockback: self.max_knockback, - range: self.range, - angle: self.angle, - energy_drain: self.energy_drain, - forward_speed: self.forward_speed, - buildup_duration: self.buildup_duration, - charge_duration: self.charge_duration, - charge_duration_attained: self.charge_duration_attained, - infinite_charge: self.infinite_charge, - swing_duration: self.swing_duration, - recover_duration: self.recover_duration, + static_data: self.static_data, + end_charge: self.end_charge, timer: self .timer .checked_add(Duration::from_secs_f32(data.dt.0)) .unwrap_or_default(), stage_section: self.stage_section, + exhausted: self.exhausted, }) } else { // Done diff --git a/common/src/sys/phys.rs b/common/src/sys/phys.rs index 1eb296c24a..214124291f 100644 --- a/common/src/sys/phys.rs +++ b/common/src/sys/phys.rs @@ -192,7 +192,7 @@ impl<'a> System<'a> for Sys { if entity == entity_other || (ignore_group.is_some() && ignore_group == group_b) { continue; } - + if entity_other == entity { continue; } From e54483d789a5cfdec6e550deabab05c954b40b4c Mon Sep 17 00:00:00 2001 From: Sam Date: Fri, 11 Sep 2020 13:29:42 -0500 Subject: [PATCH 13/28] Shifted hit attempt to before swing duration, instead of after. --- common/src/comp/ability.rs | 2 -- common/src/states/combo_melee.rs | 28 ++++++++++++++-------------- 2 files changed, 14 insertions(+), 16 deletions(-) diff --git a/common/src/comp/ability.rs b/common/src/comp/ability.rs index 8ee9f02fed..80dedb7a5d 100644 --- a/common/src/comp/ability.rs +++ b/common/src/comp/ability.rs @@ -83,7 +83,6 @@ pub enum CharacterAbility { buildup_duration: Duration, charge_duration: Duration, infinite_charge: bool, - swing_duration: Duration, recover_duration: Duration, }, BasicBlock, @@ -331,7 +330,6 @@ impl From<&CharacterAbility> for CharacterState { buildup_duration, charge_duration, infinite_charge, - swing_duration, recover_duration, } => CharacterState::DashMelee(dash_melee::Data { static_data: dash_melee::StaticData { diff --git a/common/src/states/combo_melee.rs b/common/src/states/combo_melee.rs index b90853f779..47a0055aa7 100644 --- a/common/src/states/combo_melee.rs +++ b/common/src/states/combo_melee.rs @@ -105,6 +105,20 @@ impl CharacterBehavior for Data { stage_section: StageSection::Swing, next_stage: self.next_stage, }); + + // Hit attempt + data.updater.insert(data.entity, Attacking { + base_healthchange: -((self.stage_data[stage_index].max_damage.min( + self.stage_data[stage_index].base_damage + + self.combo / self.num_stages + * self.stage_data[stage_index].damage_increase, + )) as i32), + range: self.stage_data[stage_index].range, + max_angle: self.stage_data[stage_index].angle.to_radians(), + applied: false, + hit_count: 0, + knockback: self.stage_data[stage_index].knockback, + }); } else if self.stage_section == StageSection::Swing && self.timer < self.stage_data[stage_index].base_swing_duration { @@ -134,20 +148,6 @@ impl CharacterBehavior for Data { next_stage: self.next_stage, }); } else if self.stage_section == StageSection::Swing { - // Hit attempt - data.updater.insert(data.entity, Attacking { - base_healthchange: -((self.stage_data[stage_index].max_damage.min( - self.stage_data[stage_index].base_damage - + self.combo / self.num_stages - * self.stage_data[stage_index].damage_increase, - )) as i32), - range: self.stage_data[stage_index].range, - max_angle: self.stage_data[stage_index].angle.to_radians(), - applied: false, - hit_count: 0, - knockback: self.stage_data[stage_index].knockback, - }); - // Transitions to recover section of stage update.character = CharacterState::ComboMelee(Data { stage: self.stage, From 2aac008b9047cde65521ab278dfb58a5e8af7cfd Mon Sep 17 00:00:00 2001 From: Sam Date: Fri, 11 Sep 2020 14:24:55 -0500 Subject: [PATCH 14/28] Attack speed now scales with combo in combo melee. --- common/src/comp/ability.rs | 9 ++++--- common/src/comp/inventory/item/tool.rs | 27 ++++++++++---------- common/src/states/combo_melee.rs | 35 ++++++++++++++++---------- 3 files changed, 42 insertions(+), 29 deletions(-) diff --git a/common/src/comp/ability.rs b/common/src/comp/ability.rs index 80dedb7a5d..9c364f54e3 100644 --- a/common/src/comp/ability.rs +++ b/common/src/comp/ability.rs @@ -92,7 +92,8 @@ pub enum CharacterAbility { initial_energy_gain: u32, max_energy_gain: u32, energy_increase: u32, - combo_duration: Duration, + speed_increase: f32, + max_speed_increase: f32, }, LeapMelee { energy_cost: u32, @@ -361,7 +362,8 @@ impl From<&CharacterAbility> for CharacterState { initial_energy_gain, max_energy_gain, energy_increase, - combo_duration, + speed_increase, + max_speed_increase, } => CharacterState::ComboMelee(combo_melee::Data { stage: 1, num_stages: stage_data.len() as u32, @@ -370,10 +372,11 @@ impl From<&CharacterAbility> for CharacterState { initial_energy_gain: *initial_energy_gain, max_energy_gain: *max_energy_gain, energy_increase: *energy_increase, - combo_duration: *combo_duration, timer: Duration::default(), stage_section: StageSection::Buildup, next_stage: false, + speed_increase: *speed_increase, + max_speed_increase: *max_speed_increase, }), CharacterAbility::LeapMelee { energy_cost: _, diff --git a/common/src/comp/inventory/item/tool.rs b/common/src/comp/inventory/item/tool.rs index a891d0ae12..3de56f68b6 100644 --- a/common/src/comp/inventory/item/tool.rs +++ b/common/src/comp/inventory/item/tool.rs @@ -121,12 +121,12 @@ impl Tool { stage_data: vec![ combo_melee::Stage { stage: 1, - base_damage: (30.0 * self.base_power()) as u32, - max_damage: (50.0 * self.base_power()) as u32, + base_damage: (100.0 * self.base_power()) as u32, + max_damage: (120.0 * self.base_power()) as u32, damage_increase: (10.0 * self.base_power()) as u32, knockback: 5.0, - range: 3.5, - angle: 45.0, + range: 4.0, + angle: 30.0, base_buildup_duration: Duration::from_millis(500), base_swing_duration: Duration::from_millis(200), base_recover_duration: Duration::from_millis(400), @@ -134,12 +134,12 @@ impl Tool { }, combo_melee::Stage { stage: 2, - base_damage: (50.0 * self.base_power()) as u32, - max_damage: (80.0 * self.base_power()) as u32, + base_damage: (80.0 * self.base_power()) as u32, + max_damage: (110.0 * self.base_power()) as u32, damage_increase: (15.0 * self.base_power()) as u32, knockback: 5.0, range: 3.5, - angle: 45.0, + angle: 180.0, base_buildup_duration: Duration::from_millis(400), base_swing_duration: Duration::from_millis(600), base_recover_duration: Duration::from_millis(400), @@ -147,12 +147,12 @@ impl Tool { }, combo_melee::Stage { stage: 3, - base_damage: (70.0 * self.base_power()) as u32, - max_damage: (110.0 * self.base_power()) as u32, + base_damage: (130.0 * self.base_power()) as u32, + max_damage: (170.0 * self.base_power()) as u32, damage_increase: (20.0 * self.base_power()) as u32, - knockback: 5.0, - range: 3.5, - angle: 45.0, + knockback: 7.5, + range: 6.0, + angle: 10.0, base_buildup_duration: Duration::from_millis(500), base_swing_duration: Duration::from_millis(200), base_recover_duration: Duration::from_millis(300), @@ -162,7 +162,8 @@ impl Tool { initial_energy_gain: 0, max_energy_gain: 100, energy_increase: 20, - combo_duration: Duration::from_millis(10), + speed_increase: 0.9, + max_speed_increase: 0.8, }, DashMelee { energy_cost: 200, diff --git a/common/src/states/combo_melee.rs b/common/src/states/combo_melee.rs index 47a0055aa7..1028f848b0 100644 --- a/common/src/states/combo_melee.rs +++ b/common/src/states/combo_melee.rs @@ -51,14 +51,16 @@ pub struct Data { pub max_energy_gain: u32, /// Energy gain increase per combo pub energy_increase: u32, - /// Duration for the next stage to be activated - pub combo_duration: Duration, /// Timer for each stage pub timer: Duration, /// Checks what section a stage is in pub stage_section: StageSection, /// Whether the state should go onto the next stage pub next_stage: bool, + /// (100% - speed_increase) is percentage speed increases from current to max when combo increases + pub speed_increase: f32, + /// (100% + max_speed_increase) is the max attack speed + pub max_speed_increase: f32, } impl CharacterBehavior for Data { @@ -82,13 +84,14 @@ impl CharacterBehavior for Data { initial_energy_gain: self.initial_energy_gain, max_energy_gain: self.max_energy_gain, energy_increase: self.energy_increase, - combo_duration: self.combo_duration, timer: self .timer - .checked_add(Duration::from_secs_f32(data.dt.0)) + .checked_add(Duration::from_secs_f32((1.0 + self.max_speed_increase * (1.0 - self.speed_increase.powi((self.combo / self.num_stages) as i32))) * data.dt.0)) .unwrap_or_default(), stage_section: self.stage_section, next_stage: self.next_stage, + speed_increase: self.speed_increase, + max_speed_increase: self.max_speed_increase, }); } else if self.stage_section == StageSection::Buildup { // Transitions to swing section of stage @@ -100,10 +103,11 @@ impl CharacterBehavior for Data { initial_energy_gain: self.initial_energy_gain, max_energy_gain: self.max_energy_gain, energy_increase: self.energy_increase, - combo_duration: self.combo_duration, timer: Duration::default(), stage_section: StageSection::Swing, next_stage: self.next_stage, + speed_increase: self.speed_increase, + max_speed_increase: self.max_speed_increase, }); // Hit attempt @@ -139,13 +143,14 @@ impl CharacterBehavior for Data { initial_energy_gain: self.initial_energy_gain, max_energy_gain: self.max_energy_gain, energy_increase: self.energy_increase, - combo_duration: self.combo_duration, timer: self .timer - .checked_add(Duration::from_secs_f32(data.dt.0)) + .checked_add(Duration::from_secs_f32((1.0 + self.max_speed_increase * (1.0 - self.speed_increase.powi((self.combo / self.num_stages) as i32))) * data.dt.0)) .unwrap_or_default(), stage_section: self.stage_section, next_stage: self.next_stage, + speed_increase: self.speed_increase, + max_speed_increase: self.max_speed_increase, }); } else if self.stage_section == StageSection::Swing { // Transitions to recover section of stage @@ -157,10 +162,11 @@ impl CharacterBehavior for Data { initial_energy_gain: self.initial_energy_gain, max_energy_gain: self.max_energy_gain, energy_increase: self.energy_increase, - combo_duration: self.combo_duration, timer: Duration::default(), stage_section: StageSection::Recover, next_stage: self.next_stage, + speed_increase: self.speed_increase, + max_speed_increase: self.max_speed_increase, }); } else if self.stage_section == StageSection::Recover && self.timer < self.stage_data[stage_index].base_recover_duration @@ -176,13 +182,14 @@ impl CharacterBehavior for Data { initial_energy_gain: self.initial_energy_gain, max_energy_gain: self.max_energy_gain, energy_increase: self.energy_increase, - combo_duration: self.combo_duration, timer: self .timer - .checked_add(Duration::from_secs_f32(data.dt.0)) + .checked_add(Duration::from_secs_f32((1.0 + self.max_speed_increase * (1.0 - self.speed_increase.powi((self.combo / self.num_stages) as i32))) * data.dt.0)) .unwrap_or_default(), stage_section: self.stage_section, next_stage: true, + speed_increase: self.speed_increase, + max_speed_increase: self.max_speed_increase, }); } else { update.character = CharacterState::ComboMelee(Data { @@ -193,13 +200,14 @@ impl CharacterBehavior for Data { initial_energy_gain: self.initial_energy_gain, max_energy_gain: self.max_energy_gain, energy_increase: self.energy_increase, - combo_duration: self.combo_duration, timer: self .timer - .checked_add(Duration::from_secs_f32(data.dt.0)) + .checked_add(Duration::from_secs_f32((1.0 + self.max_speed_increase * (1.0 - self.speed_increase.powi((self.combo / self.num_stages) as i32))) * data.dt.0)) .unwrap_or_default(), stage_section: self.stage_section, next_stage: self.next_stage, + speed_increase: self.speed_increase, + max_speed_increase: self.max_speed_increase, }); } } else if self.next_stage { @@ -212,10 +220,11 @@ impl CharacterBehavior for Data { initial_energy_gain: self.initial_energy_gain, max_energy_gain: self.max_energy_gain, energy_increase: self.energy_increase, - combo_duration: self.combo_duration, timer: Duration::default(), stage_section: StageSection::Buildup, next_stage: false, + speed_increase: self.speed_increase, + max_speed_increase: self.max_speed_increase, }); } else { // Done From 6dede05a0e5f71b538b94c3c08ac5748bdd1eda1 Mon Sep 17 00:00:00 2001 From: Sam Date: Fri, 11 Sep 2020 14:34:00 -0500 Subject: [PATCH 15/28] Combo now only increases when landing a hit. --- common/src/comp/ability.rs | 4 ++-- common/src/comp/inventory/item/tool.rs | 6 +++--- common/src/states/combo_melee.rs | 24 +++++++++++++++++++----- 3 files changed, 24 insertions(+), 10 deletions(-) diff --git a/common/src/comp/ability.rs b/common/src/comp/ability.rs index 9c364f54e3..468330df13 100644 --- a/common/src/comp/ability.rs +++ b/common/src/comp/ability.rs @@ -375,8 +375,8 @@ impl From<&CharacterAbility> for CharacterState { timer: Duration::default(), stage_section: StageSection::Buildup, next_stage: false, - speed_increase: *speed_increase, - max_speed_increase: *max_speed_increase, + speed_increase: 1.0 - *speed_increase, + max_speed_increase: *max_speed_increase - 1.0, }), CharacterAbility::LeapMelee { energy_cost: _, diff --git a/common/src/comp/inventory/item/tool.rs b/common/src/comp/inventory/item/tool.rs index 3de56f68b6..ab3eec1333 100644 --- a/common/src/comp/inventory/item/tool.rs +++ b/common/src/comp/inventory/item/tool.rs @@ -162,8 +162,8 @@ impl Tool { initial_energy_gain: 0, max_energy_gain: 100, energy_increase: 20, - speed_increase: 0.9, - max_speed_increase: 0.8, + speed_increase: 0.05, + max_speed_increase: 1.8, }, DashMelee { energy_cost: 200, @@ -177,8 +177,8 @@ impl Tool { forward_speed: 4.0, buildup_duration: Duration::from_millis(200), charge_duration: Duration::from_millis(400), - infinite_charge: true, recover_duration: Duration::from_millis(750), + infinite_charge: true, }, ], Axe(_) => vec![ diff --git a/common/src/states/combo_melee.rs b/common/src/states/combo_melee.rs index 1028f848b0..e88bfc3121 100644 --- a/common/src/states/combo_melee.rs +++ b/common/src/states/combo_melee.rs @@ -86,7 +86,7 @@ impl CharacterBehavior for Data { energy_increase: self.energy_increase, timer: self .timer - .checked_add(Duration::from_secs_f32((1.0 + self.max_speed_increase * (1.0 - self.speed_increase.powi((self.combo / self.num_stages) as i32))) * data.dt.0)) + .checked_add(Duration::from_secs_f32((1.0 + self.max_speed_increase * (1.0 - self.speed_increase.powi(self.combo as i32))) * data.dt.0)) .unwrap_or_default(), stage_section: self.stage_section, next_stage: self.next_stage, @@ -145,7 +145,7 @@ impl CharacterBehavior for Data { energy_increase: self.energy_increase, timer: self .timer - .checked_add(Duration::from_secs_f32((1.0 + self.max_speed_increase * (1.0 - self.speed_increase.powi((self.combo / self.num_stages) as i32))) * data.dt.0)) + .checked_add(Duration::from_secs_f32((1.0 + self.max_speed_increase * (1.0 - self.speed_increase.powi(self.combo as i32))) * data.dt.0)) .unwrap_or_default(), stage_section: self.stage_section, next_stage: self.next_stage, @@ -184,7 +184,7 @@ impl CharacterBehavior for Data { energy_increase: self.energy_increase, timer: self .timer - .checked_add(Duration::from_secs_f32((1.0 + self.max_speed_increase * (1.0 - self.speed_increase.powi((self.combo / self.num_stages) as i32))) * data.dt.0)) + .checked_add(Duration::from_secs_f32((1.0 + self.max_speed_increase * (1.0 - self.speed_increase.powi(self.combo as i32))) * data.dt.0)) .unwrap_or_default(), stage_section: self.stage_section, next_stage: true, @@ -202,7 +202,7 @@ impl CharacterBehavior for Data { energy_increase: self.energy_increase, timer: self .timer - .checked_add(Duration::from_secs_f32((1.0 + self.max_speed_increase * (1.0 - self.speed_increase.powi((self.combo / self.num_stages) as i32))) * data.dt.0)) + .checked_add(Duration::from_secs_f32((1.0 + self.max_speed_increase * (1.0 - self.speed_increase.powi(self.combo as i32))) * data.dt.0)) .unwrap_or_default(), stage_section: self.stage_section, next_stage: self.next_stage, @@ -215,7 +215,7 @@ impl CharacterBehavior for Data { update.character = CharacterState::ComboMelee(Data { stage: (self.stage % self.num_stages) + 1, num_stages: self.num_stages, - combo: self.combo + 1, + combo: self.combo, stage_data: self.stage_data.clone(), initial_energy_gain: self.initial_energy_gain, max_energy_gain: self.max_energy_gain, @@ -240,6 +240,20 @@ impl CharacterBehavior for Data { .max_energy_gain .min(self.initial_energy_gain + self.combo * self.energy_increase) as i32; + update.character = CharacterState::ComboMelee(Data { + stage: self.stage, + num_stages: self.num_stages, + combo: self.combo + 1, + stage_data: self.stage_data.clone(), + initial_energy_gain: self.initial_energy_gain, + max_energy_gain: self.max_energy_gain, + energy_increase: self.energy_increase, + timer: self.timer, + stage_section: self.stage_section, + next_stage: self.next_stage, + speed_increase: self.speed_increase, + max_speed_increase: self.max_speed_increase, + }); data.updater.remove::(data.entity); update.energy.change_by(energy, EnergySource::HitEnemy); } From c99e4c3c18579653d528c887e3e54e87d160e72e Mon Sep 17 00:00:00 2001 From: Sam Date: Fri, 11 Sep 2020 14:56:04 -0500 Subject: [PATCH 16/28] Added swing duration to dash melee. Added framework for animation to be added. --- common/src/comp/ability.rs | 7 ++++-- common/src/comp/inventory/item/tool.rs | 1 + common/src/states/dash_melee.rs | 23 +++++++++++++++++ voxygen/src/anim/src/character/dash.rs | 26 +++++++++++++++++--- voxygen/src/scene/figure/mod.rs | 34 +++++++++++++++++++++++--- 5 files changed, 83 insertions(+), 8 deletions(-) diff --git a/common/src/comp/ability.rs b/common/src/comp/ability.rs index 468330df13..f56c8671a0 100644 --- a/common/src/comp/ability.rs +++ b/common/src/comp/ability.rs @@ -82,8 +82,9 @@ pub enum CharacterAbility { forward_speed: f32, buildup_duration: Duration, charge_duration: Duration, - infinite_charge: bool, + swing_duration: Duration, recover_duration: Duration, + infinite_charge: bool, }, BasicBlock, Roll, @@ -330,8 +331,9 @@ impl From<&CharacterAbility> for CharacterState { forward_speed, buildup_duration, charge_duration, - infinite_charge, + swing_duration, recover_duration, + infinite_charge, } => CharacterState::DashMelee(dash_melee::Data { static_data: dash_melee::StaticData { base_damage: *base_damage, @@ -345,6 +347,7 @@ impl From<&CharacterAbility> for CharacterState { infinite_charge: *infinite_charge, buildup_duration: *buildup_duration, charge_duration: *charge_duration, + swing_duration: *swing_duration, recover_duration: *recover_duration, }, end_charge: false, diff --git a/common/src/comp/inventory/item/tool.rs b/common/src/comp/inventory/item/tool.rs index ab3eec1333..84054fe2d2 100644 --- a/common/src/comp/inventory/item/tool.rs +++ b/common/src/comp/inventory/item/tool.rs @@ -177,6 +177,7 @@ impl Tool { forward_speed: 4.0, buildup_duration: Duration::from_millis(200), charge_duration: Duration::from_millis(400), + swing_duration: Duration::from_millis(100), recover_duration: Duration::from_millis(750), infinite_charge: true, }, diff --git a/common/src/states/dash_melee.rs b/common/src/states/dash_melee.rs index 5f26f25f5c..2eb462652c 100644 --- a/common/src/states/dash_melee.rs +++ b/common/src/states/dash_melee.rs @@ -31,6 +31,8 @@ pub struct StaticData { pub buildup_duration: Duration, /// How long the state charges for until it reaches max damage pub charge_duration: Duration, + /// Suration of state spent in swing + pub swing_duration: Duration, /// How long the state has until exiting pub recover_duration: Duration, } @@ -174,6 +176,27 @@ impl CharacterBehavior for Data { ); } else if self.stage_section == StageSection::Charge { // Transitions to swing section of stage + update.character = CharacterState::DashMelee(Data { + static_data: self.static_data, + end_charge: self.end_charge, + timer: Duration::default(), + stage_section: StageSection::Swing, + exhausted: self.exhausted, + }) + } else if self.stage_section == StageSection::Swing && self.timer < self.static_data.swing_duration { + // Swings + update.character = CharacterState::DashMelee(Data { + static_data: self.static_data, + end_charge: self.end_charge, + timer: self + .timer + .checked_add(Duration::from_secs_f32(data.dt.0)) + .unwrap_or_default(), + stage_section: self.stage_section, + exhausted: self.exhausted, + }) + } else if self.stage_section == StageSection::Swing { + // Transitions to recover section of stage update.character = CharacterState::DashMelee(Data { static_data: self.static_data, end_charge: self.end_charge, diff --git a/voxygen/src/anim/src/character/dash.rs b/voxygen/src/anim/src/character/dash.rs index 8e1cf865c3..1af9ec84c7 100644 --- a/voxygen/src/anim/src/character/dash.rs +++ b/voxygen/src/anim/src/character/dash.rs @@ -2,7 +2,10 @@ use super::{ super::{vek::*, Animation}, CharacterSkeleton, SkeletonAttr, }; -use common::comp::item::{Hands, ToolKind}; +use common::{ + comp::item::{Hands, ToolKind}, + states::utils::StageSection, +}; pub struct Input { pub attack: bool, @@ -10,7 +13,7 @@ pub struct Input { pub struct DashAnimation; impl Animation for DashAnimation { - type Dependency = (Option, Option, f64); + type Dependency = (Option, Option, f64, Option); type Skeleton = CharacterSkeleton; #[cfg(feature = "use-dyn-lib")] @@ -20,7 +23,7 @@ impl Animation for DashAnimation { #[allow(clippy::single_match)] // TODO: Pending review in #587 fn update_skeleton_inner( skeleton: &Self::Skeleton, - (active_tool_kind, second_tool_kind, _global_time): Self::Dependency, + (active_tool_kind, second_tool_kind, _global_time, stage_section): Self::Dependency, anim_time: f64, rate: &mut f32, skeleton_attr: &SkeletonAttr, @@ -42,6 +45,23 @@ impl Animation for DashAnimation { match active_tool_kind { //TODO: Inventory Some(ToolKind::Sword(_)) => { + if let Some(stage_section) = stage_section { + match stage_section { + StageSection::Buildup => { + + }, + StageSection::Charge => { + + }, + StageSection::Swing => { + + }, + StageSection::Recover => { + + } + } + } + next.head.position = Vec3::new( 0.0, -2.0 + skeleton_attr.head.0, diff --git a/voxygen/src/scene/figure/mod.rs b/voxygen/src/scene/figure/mod.rs index 1264b7b390..fa34a685ed 100644 --- a/voxygen/src/scene/figure/mod.rs +++ b/voxygen/src/scene/figure/mod.rs @@ -897,11 +897,39 @@ impl FigureMgr { skeleton_attr, ) }, - CharacterState::DashMelee(_) => { + 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 + / s.static_data + .charge_duration + .as_secs_f64() + }, + 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::character::DashAnimation::update_skeleton( &target_base, - (active_tool_kind, second_tool_kind, time), - state.state_time, + (active_tool_kind, second_tool_kind, time, Some(s.stage_section)), + stage_progress, &mut state_animation_rate, skeleton_attr, ) From b06ab250cca9e82769720fec3c5ab4c5dce4f229 Mon Sep 17 00:00:00 2001 From: Sam Date: Sat, 12 Sep 2020 11:46:21 -0500 Subject: [PATCH 17/28] Addressed first round of feedback on sword overhaul. --- .../npc_weapons/sword/zweihander_sword_0.ron | 2 +- assets/voxygen/audio/sfx.ron | 20 +-- common/src/comp/ability.rs | 10 +- common/src/comp/inventory/item/tool.rs | 12 +- common/src/states/combo_melee.rs | 55 ++++++-- common/src/states/dash_melee.rs | 119 +++++++++++------- common/src/states/utils.rs | 7 +- server/src/sys/terrain.rs | 27 ++-- voxygen/src/anim/src/character/dash.rs | 25 ++-- voxygen/src/scene/figure/mod.rs | 28 ++--- 10 files changed, 170 insertions(+), 135 deletions(-) diff --git a/assets/common/items/npc_weapons/sword/zweihander_sword_0.ron b/assets/common/items/npc_weapons/sword/zweihander_sword_0.ron index b75c8c515c..7c9a956393 100644 --- a/assets/common/items/npc_weapons/sword/zweihander_sword_0.ron +++ b/assets/common/items/npc_weapons/sword/zweihander_sword_0.ron @@ -6,7 +6,7 @@ ItemDef( kind: Sword("Zweihander0"), stats: ( equip_time_millis: 500, - power: 0.2, + power: 0.75, ), ) ), diff --git a/assets/voxygen/audio/sfx.ron b/assets/voxygen/audio/sfx.ron index a44789e880..9df90f404f 100644 --- a/assets/voxygen/audio/sfx.ron +++ b/assets/voxygen/audio/sfx.ron @@ -94,19 +94,19 @@ ], threshold: 0.5, ), - Attack(ComboMelee(First), Sword): ( + Attack(ComboMelee(1), Sword): ( files: [ "voxygen.audio.sfx.abilities.swing_sword", ], threshold: 0.7, ), - Attack(ComboMelee(Second), Sword): ( + Attack(ComboMelee(2), Sword): ( files: [ "voxygen.audio.sfx.abilities.separated_second_swing", ], threshold: 0.7, ), - Attack(ComboMelee(Third), Sword): ( + Attack(ComboMelee(3), Sword): ( files: [ "voxygen.audio.sfx.abilities.separated_third_swing", ], @@ -174,19 +174,7 @@ ], threshold: 0.5, ), - Attack(ComboMelee(First), Axe): ( - files: [ - "voxygen.audio.sfx.abilities.swing", - ], - threshold: 0.7, - ), - Attack(ComboMelee(Second), Axe): ( - files: [ - "voxygen.audio.sfx.abilities.swing", - ], - threshold: 0.7, - ), - Attack(ComboMelee(Third), Axe): ( + Attack(BasicMelee, Axe): ( files: [ "voxygen.audio.sfx.abilities.swing", ], diff --git a/common/src/comp/ability.rs b/common/src/comp/ability.rs index f56c8671a0..5139e25c51 100644 --- a/common/src/comp/ability.rs +++ b/common/src/comp/ability.rs @@ -20,7 +20,7 @@ pub enum CharacterAbilityType { ChargedRanged, DashMelee, BasicBlock, - ComboMelee, + ComboMelee(u32), LeapMelee, SpinMelee, GroundShockwave, @@ -35,7 +35,7 @@ impl From<&CharacterState> for CharacterAbilityType { CharacterState::DashMelee(_) => Self::DashMelee, CharacterState::BasicBlock => Self::BasicBlock, CharacterState::LeapMelee(_) => Self::LeapMelee, - CharacterState::ComboMelee(_) => Self::ComboMelee, + CharacterState::ComboMelee(data) => Self::ComboMelee(data.stage), CharacterState::SpinMelee(_) => Self::SpinMelee, CharacterState::ChargedRanged(_) => Self::ChargedRanged, CharacterState::GroundShockwave(_) => Self::ChargedRanged, @@ -85,6 +85,7 @@ pub enum CharacterAbility { swing_duration: Duration, recover_duration: Duration, infinite_charge: bool, + is_interruptible: bool, }, BasicBlock, Roll, @@ -95,6 +96,7 @@ pub enum CharacterAbility { energy_increase: u32, speed_increase: f32, max_speed_increase: f32, + is_interruptible: bool, }, LeapMelee { energy_cost: u32, @@ -334,6 +336,7 @@ impl From<&CharacterAbility> for CharacterState { swing_duration, recover_duration, infinite_charge, + is_interruptible, } => CharacterState::DashMelee(dash_melee::Data { static_data: dash_melee::StaticData { base_damage: *base_damage, @@ -349,6 +352,7 @@ impl From<&CharacterAbility> for CharacterState { charge_duration: *charge_duration, swing_duration: *swing_duration, recover_duration: *recover_duration, + is_interruptible: *is_interruptible, }, end_charge: false, timer: Duration::default(), @@ -367,6 +371,7 @@ impl From<&CharacterAbility> for CharacterState { energy_increase, speed_increase, max_speed_increase, + is_interruptible, } => CharacterState::ComboMelee(combo_melee::Data { stage: 1, num_stages: stage_data.len() as u32, @@ -380,6 +385,7 @@ impl From<&CharacterAbility> for CharacterState { next_stage: false, speed_increase: 1.0 - *speed_increase, max_speed_increase: *max_speed_increase - 1.0, + is_interruptible: *is_interruptible, }), CharacterAbility::LeapMelee { energy_cost: _, diff --git a/common/src/comp/inventory/item/tool.rs b/common/src/comp/inventory/item/tool.rs index 84054fe2d2..d8b9bb4bb3 100644 --- a/common/src/comp/inventory/item/tool.rs +++ b/common/src/comp/inventory/item/tool.rs @@ -124,7 +124,7 @@ impl Tool { base_damage: (100.0 * self.base_power()) as u32, max_damage: (120.0 * self.base_power()) as u32, damage_increase: (10.0 * self.base_power()) as u32, - knockback: 5.0, + knockback: 8.0, range: 4.0, angle: 30.0, base_buildup_duration: Duration::from_millis(500), @@ -150,7 +150,7 @@ impl Tool { base_damage: (130.0 * self.base_power()) as u32, max_damage: (170.0 * self.base_power()) as u32, damage_increase: (20.0 * self.base_power()) as u32, - knockback: 7.5, + knockback: 14.0, range: 6.0, angle: 10.0, base_buildup_duration: Duration::from_millis(500), @@ -164,11 +164,12 @@ impl Tool { energy_increase: 20, speed_increase: 0.05, max_speed_increase: 1.8, + is_interruptible: true, }, DashMelee { energy_cost: 200, - base_damage: (60.0 * self.base_power()) as u32, - max_damage: (180.0 * self.base_power()) as u32, + base_damage: (120.0 * self.base_power()) as u32, + max_damage: (260.0 * self.base_power()) as u32, base_knockback: 5.0, max_knockback: 10.0, range: 5.0, @@ -178,8 +179,9 @@ impl Tool { buildup_duration: Duration::from_millis(200), charge_duration: Duration::from_millis(400), swing_duration: Duration::from_millis(100), - recover_duration: Duration::from_millis(750), + recover_duration: Duration::from_millis(500), infinite_charge: true, + is_interruptible: true, }, ], Axe(_) => vec![ diff --git a/common/src/states/combo_melee.rs b/common/src/states/combo_melee.rs index e88bfc3121..b8d5f78d47 100644 --- a/common/src/states/combo_melee.rs +++ b/common/src/states/combo_melee.rs @@ -43,7 +43,7 @@ pub struct Data { pub num_stages: u32, /// Number of consecutive strikes pub combo: u32, - /// Data for first stage + /// Data for each stage pub stage_data: Vec, /// Initial energy gain per strike pub initial_energy_gain: u32, @@ -57,10 +57,13 @@ pub struct Data { pub stage_section: StageSection, /// Whether the state should go onto the next stage pub next_stage: bool, - /// (100% - speed_increase) is percentage speed increases from current to max when combo increases + /// (100% - speed_increase) is percentage speed increases from current to + /// max when combo increases pub speed_increase: f32, /// (100% + max_speed_increase) is the max attack speed pub max_speed_increase: f32, + /// Whether the state can be interrupted by other abilities + pub is_interruptible: bool, } impl CharacterBehavior for Data { @@ -68,10 +71,22 @@ impl CharacterBehavior for Data { let mut update = StateUpdate::from(data); handle_orientation(data, &mut update, 1.0); - handle_move(data, &mut update, 0.1); + handle_move(data, &mut update, 0.3); let stage_index = (self.stage - 1) as usize; + // Allows for other states to interrupt this state + if self.is_interruptible && !data.inputs.primary.is_pressed() { + if data.inputs.roll.is_pressed() { + handle_dodge_input(data, &mut update); + return update; + } + if data.inputs.secondary.is_pressed() { + handle_ability2_input(data, &mut update); + return update; + } + } + if self.stage_section == StageSection::Buildup && self.timer < self.stage_data[stage_index].base_buildup_duration { @@ -86,12 +101,17 @@ impl CharacterBehavior for Data { energy_increase: self.energy_increase, timer: self .timer - .checked_add(Duration::from_secs_f32((1.0 + self.max_speed_increase * (1.0 - self.speed_increase.powi(self.combo as i32))) * data.dt.0)) + .checked_add(Duration::from_secs_f32( + (1.0 + self.max_speed_increase + * (1.0 - self.speed_increase.powi(self.combo as i32))) + * data.dt.0, + )) .unwrap_or_default(), stage_section: self.stage_section, next_stage: self.next_stage, speed_increase: self.speed_increase, max_speed_increase: self.max_speed_increase, + is_interruptible: self.is_interruptible, }); } else if self.stage_section == StageSection::Buildup { // Transitions to swing section of stage @@ -108,6 +128,7 @@ impl CharacterBehavior for Data { next_stage: self.next_stage, speed_increase: self.speed_increase, max_speed_increase: self.max_speed_increase, + is_interruptible: self.is_interruptible, }); // Hit attempt @@ -130,7 +151,7 @@ impl CharacterBehavior for Data { forward_move( data, &mut update, - 0.1, + 0.3, self.stage_data[stage_index].forward_movement, ); @@ -145,12 +166,17 @@ impl CharacterBehavior for Data { energy_increase: self.energy_increase, timer: self .timer - .checked_add(Duration::from_secs_f32((1.0 + self.max_speed_increase * (1.0 - self.speed_increase.powi(self.combo as i32))) * data.dt.0)) + .checked_add(Duration::from_secs_f32( + (1.0 + self.max_speed_increase + * (1.0 - self.speed_increase.powi(self.combo as i32))) + * data.dt.0, + )) .unwrap_or_default(), stage_section: self.stage_section, next_stage: self.next_stage, speed_increase: self.speed_increase, max_speed_increase: self.max_speed_increase, + is_interruptible: self.is_interruptible, }); } else if self.stage_section == StageSection::Swing { // Transitions to recover section of stage @@ -167,6 +193,7 @@ impl CharacterBehavior for Data { next_stage: self.next_stage, speed_increase: self.speed_increase, max_speed_increase: self.max_speed_increase, + is_interruptible: self.is_interruptible, }); } else if self.stage_section == StageSection::Recover && self.timer < self.stage_data[stage_index].base_recover_duration @@ -184,12 +211,17 @@ impl CharacterBehavior for Data { energy_increase: self.energy_increase, timer: self .timer - .checked_add(Duration::from_secs_f32((1.0 + self.max_speed_increase * (1.0 - self.speed_increase.powi(self.combo as i32))) * data.dt.0)) + .checked_add(Duration::from_secs_f32( + (1.0 + self.max_speed_increase + * (1.0 - self.speed_increase.powi(self.combo as i32))) + * data.dt.0, + )) .unwrap_or_default(), stage_section: self.stage_section, next_stage: true, speed_increase: self.speed_increase, max_speed_increase: self.max_speed_increase, + is_interruptible: self.is_interruptible, }); } else { update.character = CharacterState::ComboMelee(Data { @@ -202,12 +234,17 @@ impl CharacterBehavior for Data { energy_increase: self.energy_increase, timer: self .timer - .checked_add(Duration::from_secs_f32((1.0 + self.max_speed_increase * (1.0 - self.speed_increase.powi(self.combo as i32))) * data.dt.0)) + .checked_add(Duration::from_secs_f32( + (1.0 + self.max_speed_increase + * (1.0 - self.speed_increase.powi(self.combo as i32))) + * data.dt.0, + )) .unwrap_or_default(), stage_section: self.stage_section, next_stage: self.next_stage, speed_increase: self.speed_increase, max_speed_increase: self.max_speed_increase, + is_interruptible: self.is_interruptible, }); } } else if self.next_stage { @@ -225,6 +262,7 @@ impl CharacterBehavior for Data { next_stage: false, speed_increase: self.speed_increase, max_speed_increase: self.max_speed_increase, + is_interruptible: self.is_interruptible, }); } else { // Done @@ -253,6 +291,7 @@ impl CharacterBehavior for Data { next_stage: self.next_stage, speed_increase: self.speed_increase, max_speed_increase: self.max_speed_increase, + is_interruptible: self.is_interruptible, }); data.updater.remove::(data.entity); update.energy.change_by(energy, EnergySource::HitEnemy); diff --git a/common/src/states/dash_melee.rs b/common/src/states/dash_melee.rs index 2eb462652c..ac1ad8fd5a 100644 --- a/common/src/states/dash_melee.rs +++ b/common/src/states/dash_melee.rs @@ -5,6 +5,7 @@ use crate::{ }; use serde::{Deserialize, Serialize}; use std::time::Duration; +use vek::Vec3; /// Separated out to condense update portions of character state #[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)] @@ -35,11 +36,14 @@ pub struct StaticData { pub swing_duration: Duration, /// How long the state has until exiting pub recover_duration: Duration, + /// Whether the state can be interrupted by other abilities + pub is_interruptible: bool, } #[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)] pub struct Data { - /// Struct containing data that does not change over the course of the character state + /// Struct containing data that does not change over the course of the + /// character state pub static_data: StaticData, /// Whether the charge should end pub end_charge: bool, @@ -58,7 +62,21 @@ impl CharacterBehavior for Data { handle_orientation(data, &mut update, 1.0); handle_move(data, &mut update, 0.1); - if self.stage_section == StageSection::Buildup && self.timer < self.static_data.buildup_duration { + // Allows for other states to interrupt this state + if self.static_data.is_interruptible && !data.inputs.secondary.is_pressed() { + if data.inputs.roll.is_pressed() { + handle_dodge_input(data, &mut update); + return update; + } + if data.inputs.primary.is_pressed() { + handle_ability1_input(data, &mut update); + return update; + } + } + + if self.stage_section == StageSection::Buildup + && self.timer < self.static_data.buildup_duration + { // Build up update.character = CharacterState::DashMelee(Data { static_data: self.static_data, @@ -80,23 +98,26 @@ impl CharacterBehavior for Data { exhausted: self.exhausted, }) } else if self.stage_section == StageSection::Charge - && ((self.timer < self.static_data.charge_duration && !self.static_data.infinite_charge) - || (data.inputs.secondary.is_pressed() && self.static_data.infinite_charge)) + && (self.timer < self.static_data.charge_duration + || (self.static_data.infinite_charge && data.inputs.secondary.is_pressed())) && update.energy.current() > 0 && !self.end_charge { // Forward movement forward_move(data, &mut update, 0.1, self.static_data.forward_speed); - // Hit attempt - if !self.exhausted { + // Hit attempt (also checks if player is moving) + if !self.exhausted && update.vel.0.distance_squared(Vec3::zero()) > 1.0 { let charge_frac = (self.timer.as_secs_f32() / self.static_data.charge_duration.as_secs_f32()) .min(1.0); - let damage = (self.static_data.max_damage as f32 - self.static_data.base_damage as f32) * charge_frac + let damage = (self.static_data.max_damage as f32 + - self.static_data.base_damage as f32) + * charge_frac + self.static_data.base_damage as f32; - let knockback = - (self.static_data.max_knockback - self.static_data.base_knockback) * charge_frac + self.static_data.base_knockback; + let knockback = (self.static_data.max_knockback - self.static_data.base_knockback) + * charge_frac + + self.static_data.base_knockback; data.updater.insert(data.entity, Attacking { base_healthchange: -damage as i32, range: self.static_data.range, @@ -107,7 +128,8 @@ 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 + // 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 { update.character = CharacterState::DashMelee(Data { static_data: self.static_data, @@ -119,42 +141,29 @@ impl CharacterBehavior for Data { stage_section: StageSection::Charge, exhausted: true, }) - } else { - if let Some(attack) = data.attacking { - if attack.applied && attack.hit_count > 0 { - update.character = CharacterState::DashMelee(Data { - static_data: self.static_data, - end_charge: !self.static_data.infinite_charge, - timer: self - .timer - .checked_add(Duration::from_secs_f32(data.dt.0)) - .unwrap_or_default(), - stage_section: StageSection::Charge, - exhausted: false, - }) - } else if attack.applied { - update.character = CharacterState::DashMelee(Data { - static_data: self.static_data, - end_charge: self.end_charge, - timer: self - .timer - .checked_add(Duration::from_secs_f32(data.dt.0)) - .unwrap_or_default(), - stage_section: StageSection::Charge, - exhausted: false, - }) - } else { - update.character = CharacterState::DashMelee(Data { - static_data: self.static_data, - end_charge: !self.static_data.infinite_charge, - timer: self - .timer - .checked_add(Duration::from_secs_f32(data.dt.0)) - .unwrap_or_default(), - stage_section: StageSection::Charge, - exhausted: self.exhausted, - }) - } + } else if let Some(attack) = data.attacking { + if attack.applied && attack.hit_count > 0 { + update.character = CharacterState::DashMelee(Data { + static_data: self.static_data, + end_charge: !self.static_data.infinite_charge, + timer: self + .timer + .checked_add(Duration::from_secs_f32(data.dt.0)) + .unwrap_or_default(), + stage_section: StageSection::Charge, + exhausted: false, + }) + } else if attack.applied { + update.character = CharacterState::DashMelee(Data { + static_data: self.static_data, + end_charge: self.end_charge, + timer: self + .timer + .checked_add(Duration::from_secs_f32(data.dt.0)) + .unwrap_or_default(), + stage_section: StageSection::Charge, + exhausted: false, + }) } else { update.character = CharacterState::DashMelee(Data { static_data: self.static_data, @@ -167,6 +176,17 @@ impl CharacterBehavior for Data { exhausted: self.exhausted, }) } + } else { + update.character = CharacterState::DashMelee(Data { + static_data: self.static_data, + end_charge: !self.static_data.infinite_charge, + timer: self + .timer + .checked_add(Duration::from_secs_f32(data.dt.0)) + .unwrap_or_default(), + stage_section: StageSection::Charge, + exhausted: self.exhausted, + }) } // Consumes energy if there's enough left and charge has not stopped @@ -183,7 +203,9 @@ impl CharacterBehavior for Data { stage_section: StageSection::Swing, exhausted: self.exhausted, }) - } else if self.stage_section == StageSection::Swing && self.timer < self.static_data.swing_duration { + } else if self.stage_section == StageSection::Swing + && self.timer < self.static_data.swing_duration + { // Swings update.character = CharacterState::DashMelee(Data { static_data: self.static_data, @@ -204,7 +226,8 @@ impl CharacterBehavior for Data { stage_section: StageSection::Recover, exhausted: self.exhausted, }) - } else if self.stage_section == StageSection::Recover && self.timer < self.static_data.recover_duration + } else if self.stage_section == StageSection::Recover + && self.timer < self.static_data.recover_duration { // Recover update.character = CharacterState::DashMelee(Data { diff --git a/common/src/states/utils.rs b/common/src/states/utils.rs index c671b051f9..7e10e4c86b 100644 --- a/common/src/states/utils.rs +++ b/common/src/states/utils.rs @@ -98,10 +98,9 @@ pub fn forward_move(data: &JoinData, update: &mut StateUpdate, efficiency: f32, BASE_HUMANOID_AIR_ACCEL }; - update.vel.0 = update.vel.0 - + Vec2::broadcast(data.dt.0) - * accel - * (data.inputs.move_dir * efficiency + (*update.ori.0).xy() * forward); + update.vel.0 += Vec2::broadcast(data.dt.0) + * accel + * (data.inputs.move_dir * efficiency + (*update.ori.0).xy() * forward); handle_orientation(data, update, data.body.base_ori_rate() * efficiency); } diff --git a/server/src/sys/terrain.rs b/server/src/sys/terrain.rs index 4329b48550..99134bb36f 100644 --- a/server/src/sys/terrain.rs +++ b/server/src/sys/terrain.rs @@ -115,11 +115,17 @@ impl<'a> System<'a> for Sys { let mut body = entity.body; let name = entity.name.unwrap_or_else(|| "Unnamed".to_string()); let alignment = entity.alignment; - let main_tool = entity.main_tool; + let mut main_tool = entity.main_tool; let mut stats = comp::Stats::new(name, body); // let damage = stats.level.level() as i32; TODO: Make NPC base damage // non-linearly depend on their level + if entity.is_giant { + main_tool = Some(comp::Item::new_from_asset_expect( + "common.items.npc_weapons.sword.zweihander_sword_0", + )); + } + let mut loadout = LoadoutBuilder::build_loadout(body, alignment, main_tool).build(); let mut scale = entity.scale; @@ -152,24 +158,7 @@ impl<'a> System<'a> for Sys { ); } loadout = comp::Loadout { - active_item: Some(comp::ItemConfig { - item: comp::Item::new_from_asset_expect( - "common.items.npc_weapons.sword.zweihander_sword_0", - ), - ability1: Some(CharacterAbility::BasicMelee { - energy_cost: 0, - buildup_duration: Duration::from_millis(800), - recover_duration: Duration::from_millis(200), - base_healthchange: -100, - knockback: 0.0, - range: 3.5, - max_angle: 60.0, - }), - ability2: None, - ability3: None, - block_ability: None, - dodge_ability: None, - }), + active_item, second_item: None, shoulder: Some(comp::Item::new_from_asset_expect( "common.items.armor.shoulder.plate_0", diff --git a/voxygen/src/anim/src/character/dash.rs b/voxygen/src/anim/src/character/dash.rs index 1af9ec84c7..60643bfcac 100644 --- a/voxygen/src/anim/src/character/dash.rs +++ b/voxygen/src/anim/src/character/dash.rs @@ -13,7 +13,12 @@ pub struct Input { pub struct DashAnimation; impl Animation for DashAnimation { - type Dependency = (Option, Option, f64, Option); + type Dependency = ( + Option, + Option, + f64, + Option, + ); type Skeleton = CharacterSkeleton; #[cfg(feature = "use-dyn-lib")] @@ -47,21 +52,13 @@ impl Animation for DashAnimation { Some(ToolKind::Sword(_)) => { if let Some(stage_section) = stage_section { match stage_section { - StageSection::Buildup => { - - }, - StageSection::Charge => { - - }, - StageSection::Swing => { - - }, - StageSection::Recover => { - - } + StageSection::Buildup => {}, + StageSection::Charge => {}, + StageSection::Swing => {}, + StageSection::Recover => {}, } } - + next.head.position = Vec3::new( 0.0, -2.0 + skeleton_attr.head.0, diff --git a/voxygen/src/scene/figure/mod.rs b/voxygen/src/scene/figure/mod.rs index fa34a685ed..df5f49062f 100644 --- a/voxygen/src/scene/figure/mod.rs +++ b/voxygen/src/scene/figure/mod.rs @@ -901,34 +901,26 @@ impl FigureMgr { 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() + stage_time / s.static_data.buildup_duration.as_secs_f64() }, StageSection::Charge => { - stage_time - / s.static_data - .charge_duration - .as_secs_f64() + stage_time / s.static_data.charge_duration.as_secs_f64() }, StageSection::Swing => { - stage_time - / s.static_data - .swing_duration - .as_secs_f64() + stage_time / s.static_data.swing_duration.as_secs_f64() }, StageSection::Recover => { - stage_time - / s.static_data - .recover_duration - .as_secs_f64() + stage_time / s.static_data.recover_duration.as_secs_f64() }, - _ => 0.0, }; anim::character::DashAnimation::update_skeleton( &target_base, - (active_tool_kind, second_tool_kind, time, Some(s.stage_section)), + ( + active_tool_kind, + second_tool_kind, + time, + Some(s.stage_section), + ), stage_progress, &mut state_animation_rate, skeleton_attr, From fe70b7fbce393b6f634e2ac91ed4132f518cf297 Mon Sep 17 00:00:00 2001 From: Sam Date: Sat, 12 Sep 2020 20:33:46 -0500 Subject: [PATCH 18/28] Addressed second round of feedback. --- assets/voxygen/audio/sfx.ron | 6 +- common/src/comp/ability.rs | 4 +- common/src/comp/inventory/item/tool.rs | 10 +- common/src/loadout_builder.rs | 146 +++++++++++------- common/src/states/combo_melee.rs | 14 +- common/src/states/dash_melee.rs | 14 +- common/src/states/utils.rs | 2 +- common/src/sys/combat.rs | 3 +- server/src/cmd.rs | 2 +- server/src/sys/terrain.rs | 44 +----- .../audio/sfx/event_mapper/combat/tests.rs | 62 +++++--- voxygen/src/audio/sfx/mod.rs | 7 +- 12 files changed, 169 insertions(+), 145 deletions(-) diff --git a/assets/voxygen/audio/sfx.ron b/assets/voxygen/audio/sfx.ron index 9df90f404f..67cd263bd4 100644 --- a/assets/voxygen/audio/sfx.ron +++ b/assets/voxygen/audio/sfx.ron @@ -94,19 +94,19 @@ ], threshold: 0.5, ), - Attack(ComboMelee(1), Sword): ( + Attack(ComboMelee(Swing, 1), Sword): ( files: [ "voxygen.audio.sfx.abilities.swing_sword", ], threshold: 0.7, ), - Attack(ComboMelee(2), Sword): ( + Attack(ComboMelee(Swing, 2), Sword): ( files: [ "voxygen.audio.sfx.abilities.separated_second_swing", ], threshold: 0.7, ), - Attack(ComboMelee(3), Sword): ( + Attack(ComboMelee(Swing, 3), Sword): ( files: [ "voxygen.audio.sfx.abilities.separated_third_swing", ], diff --git a/common/src/comp/ability.rs b/common/src/comp/ability.rs index 5139e25c51..1d3bcd529a 100644 --- a/common/src/comp/ability.rs +++ b/common/src/comp/ability.rs @@ -20,7 +20,7 @@ pub enum CharacterAbilityType { ChargedRanged, DashMelee, BasicBlock, - ComboMelee(u32), + ComboMelee(StageSection, u32), LeapMelee, SpinMelee, GroundShockwave, @@ -35,7 +35,7 @@ impl From<&CharacterState> for CharacterAbilityType { CharacterState::DashMelee(_) => Self::DashMelee, CharacterState::BasicBlock => Self::BasicBlock, CharacterState::LeapMelee(_) => Self::LeapMelee, - CharacterState::ComboMelee(data) => Self::ComboMelee(data.stage), + CharacterState::ComboMelee(data) => Self::ComboMelee(data.stage_section, data.stage), CharacterState::SpinMelee(_) => Self::SpinMelee, CharacterState::ChargedRanged(_) => Self::ChargedRanged, CharacterState::GroundShockwave(_) => Self::ChargedRanged, diff --git a/common/src/comp/inventory/item/tool.rs b/common/src/comp/inventory/item/tool.rs index d8b9bb4bb3..0baab1e22c 100644 --- a/common/src/comp/inventory/item/tool.rs +++ b/common/src/comp/inventory/item/tool.rs @@ -124,7 +124,7 @@ impl Tool { base_damage: (100.0 * self.base_power()) as u32, max_damage: (120.0 * self.base_power()) as u32, damage_increase: (10.0 * self.base_power()) as u32, - knockback: 8.0, + knockback: 10.0, range: 4.0, angle: 30.0, base_buildup_duration: Duration::from_millis(500), @@ -137,7 +137,7 @@ impl Tool { base_damage: (80.0 * self.base_power()) as u32, max_damage: (110.0 * self.base_power()) as u32, damage_increase: (15.0 * self.base_power()) as u32, - knockback: 5.0, + knockback: 12.0, range: 3.5, angle: 180.0, base_buildup_duration: Duration::from_millis(400), @@ -170,8 +170,8 @@ impl Tool { energy_cost: 200, base_damage: (120.0 * self.base_power()) as u32, max_damage: (260.0 * self.base_power()) as u32, - base_knockback: 5.0, - max_knockback: 10.0, + base_knockback: 10.0, + max_knockback: 20.0, range: 5.0, angle: 45.0, energy_drain: 500, @@ -190,6 +190,7 @@ impl Tool { buildup_duration: Duration::from_millis(700), recover_duration: Duration::from_millis(300), base_healthchange: (-120.0 * self.base_power()) as i32, + knockback: 0.0, range: 3.5, max_angle: 20.0, }, @@ -272,6 +273,7 @@ impl Tool { buildup_duration: Duration::from_millis(100), recover_duration: Duration::from_millis(400), base_healthchange: (-50.0 * self.base_power()) as i32, + knockback: 0.0, range: 3.5, max_angle: 20.0, }], diff --git a/common/src/loadout_builder.rs b/common/src/loadout_builder.rs index 7120b48f8a..978ad61c4e 100644 --- a/common/src/loadout_builder.rs +++ b/common/src/loadout_builder.rs @@ -66,7 +66,7 @@ impl LoadoutBuilder { } /// Builds loadout of creature when spawned - pub fn build_loadout(body: Body, alignment: Alignment, mut main_tool: Option) -> Self { + pub fn build_loadout(body: Body, alignment: Alignment, mut main_tool: Option, is_giant: bool) -> Self { #![allow(clippy::single_match)] // For when this is done to more than just golems. match body { Body::Golem(golem) => match golem.species { @@ -76,6 +76,11 @@ impl LoadoutBuilder { )); }, }, + Body::Humanoid(_) => if is_giant { + main_tool = Some(Item::new_from_asset_expect( + "common.items.npc_weapons.sword.zweihander_sword_0", + )); + }, _ => {}, }; @@ -112,37 +117,27 @@ impl LoadoutBuilder { }; let loadout = match body { - Body::Humanoid(_) => match alignment { - Alignment::Npc => Loadout { + Body::Humanoid(_) => match is_giant { + true => Loadout { active_item, second_item: None, - shoulder: None, + shoulder: Some(Item::new_from_asset_expect( + "common.items.armor.shoulder.plate_0", + )), chest: Some(Item::new_from_asset_expect( - match rand::thread_rng().gen_range(0, 10) { - 0 => "common.items.armor.chest.worker_green_0", - 1 => "common.items.armor.chest.worker_green_1", - 2 => "common.items.armor.chest.worker_red_0", - 3 => "common.items.armor.chest.worker_red_1", - 4 => "common.items.armor.chest.worker_purple_0", - 5 => "common.items.armor.chest.worker_purple_1", - 6 => "common.items.armor.chest.worker_yellow_0", - 7 => "common.items.armor.chest.worker_yellow_1", - 8 => "common.items.armor.chest.worker_orange_0", - _ => "common.items.armor.chest.worker_orange_1", - }, + "common.items.armor.chest.plate_green_0", )), belt: Some(Item::new_from_asset_expect( - "common.items.armor.belt.leather_0", + "common.items.armor.belt.plate_0", + )), + hand: Some(Item::new_from_asset_expect( + "common.items.armor.hand.plate_0", )), - hand: None, pants: Some(Item::new_from_asset_expect( - "common.items.armor.pants.worker_blue_0", + "common.items.armor.pants.plate_green_0", )), foot: Some(Item::new_from_asset_expect( - match rand::thread_rng().gen_range(0, 2) { - 0 => "common.items.armor.foot.leather_0", - _ => "common.items.armor.starter.sandals_0", - }, + "common.items.armor.foot.plate_0", )), back: None, ring: None, @@ -152,38 +147,79 @@ impl LoadoutBuilder { head: None, tabard: None, }, - Alignment::Enemy => Loadout { - active_item, - second_item: None, - shoulder: Some(Item::new_from_asset_expect( - "common.items.armor.shoulder.cultist_shoulder_purple", - )), - chest: Some(Item::new_from_asset_expect( - "common.items.armor.chest.cultist_chest_purple", - )), - belt: Some(Item::new_from_asset_expect( - "common.items.armor.belt.cultist_belt", - )), - hand: Some(Item::new_from_asset_expect( - "common.items.armor.hand.cultist_hands_purple", - )), - pants: Some(Item::new_from_asset_expect( - "common.items.armor.pants.cultist_legs_purple", - )), - foot: Some(Item::new_from_asset_expect( - "common.items.armor.foot.cultist_boots", - )), - back: Some(Item::new_from_asset_expect( - "common.items.armor.back.dungeon_purple-0", - )), - ring: None, - neck: None, - lantern: Some(Item::new_from_asset_expect("common.items.lantern.black_0")), - glider: None, - head: None, - tabard: None, - }, - _ => LoadoutBuilder::animal(body).build(), + false => match alignment { + Alignment::Npc => Loadout { + active_item, + second_item: None, + shoulder: None, + chest: Some(Item::new_from_asset_expect( + match rand::thread_rng().gen_range(0, 10) { + 0 => "common.items.armor.chest.worker_green_0", + 1 => "common.items.armor.chest.worker_green_1", + 2 => "common.items.armor.chest.worker_red_0", + 3 => "common.items.armor.chest.worker_red_1", + 4 => "common.items.armor.chest.worker_purple_0", + 5 => "common.items.armor.chest.worker_purple_1", + 6 => "common.items.armor.chest.worker_yellow_0", + 7 => "common.items.armor.chest.worker_yellow_1", + 8 => "common.items.armor.chest.worker_orange_0", + _ => "common.items.armor.chest.worker_orange_1", + }, + )), + belt: Some(Item::new_from_asset_expect( + "common.items.armor.belt.leather_0", + )), + hand: None, + pants: Some(Item::new_from_asset_expect( + "common.items.armor.pants.worker_blue_0", + )), + foot: Some(Item::new_from_asset_expect( + match rand::thread_rng().gen_range(0, 2) { + 0 => "common.items.armor.foot.leather_0", + _ => "common.items.armor.starter.sandals_0", + }, + )), + back: None, + ring: None, + neck: None, + lantern: None, + glider: None, + head: None, + tabard: None, + }, + Alignment::Enemy => Loadout { + active_item, + second_item: None, + shoulder: Some(Item::new_from_asset_expect( + "common.items.armor.shoulder.cultist_shoulder_purple", + )), + chest: Some(Item::new_from_asset_expect( + "common.items.armor.chest.cultist_chest_purple", + )), + belt: Some(Item::new_from_asset_expect( + "common.items.armor.belt.cultist_belt", + )), + hand: Some(Item::new_from_asset_expect( + "common.items.armor.hand.cultist_hands_purple", + )), + pants: Some(Item::new_from_asset_expect( + "common.items.armor.pants.cultist_legs_purple", + )), + foot: Some(Item::new_from_asset_expect( + "common.items.armor.foot.cultist_boots", + )), + back: Some(Item::new_from_asset_expect( + "common.items.armor.back.dungeon_purple-0", + )), + ring: None, + neck: None, + lantern: Some(Item::new_from_asset_expect("common.items.lantern.black_0")), + glider: None, + head: None, + tabard: None, + }, + _ => LoadoutBuilder::animal(body).build(), + } }, Body::Golem(golem) => match golem.species { golem::Species::StoneGolem => Loadout { diff --git a/common/src/states/combo_melee.rs b/common/src/states/combo_melee.rs index b8d5f78d47..b158df90c8 100644 --- a/common/src/states/combo_melee.rs +++ b/common/src/states/combo_melee.rs @@ -77,13 +77,13 @@ impl CharacterBehavior for Data { // Allows for other states to interrupt this state if self.is_interruptible && !data.inputs.primary.is_pressed() { - if data.inputs.roll.is_pressed() { - handle_dodge_input(data, &mut update); - return update; - } - if data.inputs.secondary.is_pressed() { - handle_ability2_input(data, &mut update); - return update; + handle_dodge_input(data, &mut update); + handle_ability2_input(data, &mut update); + match update.character { + CharacterState::ComboMelee(_) => {}, + _ => { + return update; + }, } } diff --git a/common/src/states/dash_melee.rs b/common/src/states/dash_melee.rs index ac1ad8fd5a..678ff3c6fe 100644 --- a/common/src/states/dash_melee.rs +++ b/common/src/states/dash_melee.rs @@ -64,13 +64,13 @@ impl CharacterBehavior for Data { // Allows for other states to interrupt this state if self.static_data.is_interruptible && !data.inputs.secondary.is_pressed() { - if data.inputs.roll.is_pressed() { - handle_dodge_input(data, &mut update); - return update; - } - if data.inputs.primary.is_pressed() { - handle_ability1_input(data, &mut update); - return update; + handle_dodge_input(data, &mut update); + handle_ability1_input(data, &mut update); + match update.character { + CharacterState::DashMelee(_) => {}, + _ => { + return update; + }, } } diff --git a/common/src/states/utils.rs b/common/src/states/utils.rs index 7e10e4c86b..a7fb142081 100644 --- a/common/src/states/utils.rs +++ b/common/src/states/utils.rs @@ -350,7 +350,7 @@ pub fn unwrap_tool_data<'a>(data: &'a JoinData) -> Option<&'a Tool> { /// Determines what portion a state is in. Used in all attacks (eventually). Is /// used to control aspects of animation code, as well as logic within the /// character states. -#[derive(Clone, Copy, Debug, Eq, PartialEq, Serialize, Deserialize)] +#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)] pub enum StageSection { Buildup, Swing, diff --git a/common/src/sys/combat.rs b/common/src/sys/combat.rs index 7e022f1463..8cfc5c1c28 100644 --- a/common/src/sys/combat.rs +++ b/common/src/sys/combat.rs @@ -153,10 +153,11 @@ impl<'a> System<'a> for Sys { }); } if attack.knockback != 0.0 && damage.healthchange != 0.0 { + let kb_dir = Dir::new((pos_b.0 - pos.0).try_normalized().unwrap_or(*ori.0)); server_emitter.emit(ServerEvent::Knockback { entity: b, impulse: attack.knockback - * *Dir::slerp(ori.0, Dir::new(Vec3::new(0.0, 0.0, 1.0)), 0.5), + * *Dir::slerp(kb_dir, Dir::new(Vec3::new(0.0, 0.0, 1.0)), 0.5), }); } attack.hit_count += 1; diff --git a/server/src/cmd.rs b/server/src/cmd.rs index 0c1ca11eeb..7d793744a3 100644 --- a/server/src/cmd.rs +++ b/server/src/cmd.rs @@ -621,7 +621,7 @@ fn handle_spawn( .create_npc( pos, comp::Stats::new(get_npc_name(id).into(), body), - LoadoutBuilder::build_loadout(body, alignment, None).build(), + LoadoutBuilder::build_loadout(body, alignment, None, false).build(), body, ) .with(comp::Vel(vel)) diff --git a/server/src/sys/terrain.rs b/server/src/sys/terrain.rs index 99134bb36f..f903aa3ebf 100644 --- a/server/src/sys/terrain.rs +++ b/server/src/sys/terrain.rs @@ -1,7 +1,7 @@ use super::SysTimer; use crate::{chunk_generator::ChunkGenerator, client::Client, Tick}; use common::{ - comp::{self, bird_medium, Alignment, CharacterAbility, Player, Pos}, + comp::{self, bird_medium, Alignment, Player, Pos}, event::{EventBus, ServerEvent}, generation::get_npc_name, msg::ServerMsg, @@ -13,7 +13,7 @@ use common::{ }; use rand::Rng; use specs::{Join, Read, ReadStorage, System, Write, WriteExpect, WriteStorage}; -use std::{sync::Arc, time::Duration}; +use std::sync::Arc; use vek::*; /// This system will handle loading generated chunks and unloading @@ -115,18 +115,12 @@ impl<'a> System<'a> for Sys { let mut body = entity.body; let name = entity.name.unwrap_or_else(|| "Unnamed".to_string()); let alignment = entity.alignment; - let mut main_tool = entity.main_tool; + let main_tool = entity.main_tool; let mut stats = comp::Stats::new(name, body); // let damage = stats.level.level() as i32; TODO: Make NPC base damage // non-linearly depend on their level - if entity.is_giant { - main_tool = Some(comp::Item::new_from_asset_expect( - "common.items.npc_weapons.sword.zweihander_sword_0", - )); - } - - let mut loadout = LoadoutBuilder::build_loadout(body, alignment, main_tool).build(); + let loadout = LoadoutBuilder::build_loadout(body, alignment, main_tool, entity.is_giant).build(); let mut scale = entity.scale; @@ -157,36 +151,6 @@ impl<'a> System<'a> for Sys { body, ); } - loadout = comp::Loadout { - active_item, - second_item: None, - shoulder: Some(comp::Item::new_from_asset_expect( - "common.items.armor.shoulder.plate_0", - )), - chest: Some(comp::Item::new_from_asset_expect( - "common.items.armor.chest.plate_green_0", - )), - belt: Some(comp::Item::new_from_asset_expect( - "common.items.armor.belt.plate_0", - )), - hand: Some(comp::Item::new_from_asset_expect( - "common.items.armor.hand.plate_0", - )), - pants: Some(comp::Item::new_from_asset_expect( - "common.items.armor.pants.plate_green_0", - )), - foot: Some(comp::Item::new_from_asset_expect( - "common.items.armor.foot.plate_0", - )), - back: None, - ring: None, - neck: None, - lantern: None, - glider: None, - head: None, - tabard: None, - }; - stats.level.set_level(rand::thread_rng().gen_range(30, 35)); scale = 2.0 + rand::random::(); } diff --git a/voxygen/src/audio/sfx/event_mapper/combat/tests.rs b/voxygen/src/audio/sfx/event_mapper/combat/tests.rs index 457908ef38..86363d6bd1 100644 --- a/voxygen/src/audio/sfx/event_mapper/combat/tests.rs +++ b/voxygen/src/audio/sfx/event_mapper/combat/tests.rs @@ -113,15 +113,26 @@ fn matches_ability_stage() { }); let result = CombatEventMapper::map_event( - &CharacterState::TripleStrike(states::triple_strike::Data { - base_damage: 10, - stage: states::triple_strike::Stage::First, - stage_time_active: Duration::default(), - stage_exhausted: false, - initialized: true, - transition_style: states::triple_strike::TransitionStyle::Hold( - states::triple_strike::HoldingState::Released, - ), + &CharacterState::ComboMelee(states::combo_melee::Data { + stage_data: vec![combo_melee::Stage { + stage: 1, + base_damage: 100, + max_damage: 120, + damage_increase: 10, + knockback: 10.0, + range: 4.0, + angle: 30.0, + base_buildup_duration: Duration::from_millis(500), + base_swing_duration: Duration::from_millis(200), + base_recover_duration: Duration::from_millis(400), + forward_movement: 0.5, + }], + initial_energy_gain: 0, + max_energy_gain: 100, + energy_increase: 20, + speed_increase: 0.05, + max_speed_increase: 1.8, + is_interruptible: true, }), &PreviousEntityState { event: SfxEvent::Idle, @@ -134,7 +145,7 @@ fn matches_ability_stage() { assert_eq!( result, SfxEvent::Attack( - CharacterAbilityType::TripleStrike(states::triple_strike::Stage::First), + CharacterAbilityType::ComboMelee(states::utils::StageSection::Swing, 1), ToolCategory::Sword ) ); @@ -154,15 +165,26 @@ fn ignores_different_ability_stage() { }); let result = CombatEventMapper::map_event( - &CharacterState::TripleStrike(states::triple_strike::Data { - base_damage: 10, - stage: states::triple_strike::Stage::Second, - stage_time_active: Duration::default(), - stage_exhausted: false, - initialized: true, - transition_style: states::triple_strike::TransitionStyle::Hold( - states::triple_strike::HoldingState::Released, - ), + &CharacterState::ComboMelee(states::combo_melee::Data { + stage_data: vec![combo_melee::Stage { + stage: 1, + base_damage: 100, + max_damage: 120, + damage_increase: 10, + knockback: 10.0, + range: 4.0, + angle: 30.0, + base_buildup_duration: Duration::from_millis(500), + base_swing_duration: Duration::from_millis(200), + base_recover_duration: Duration::from_millis(400), + forward_movement: 0.5, + }], + initial_energy_gain: 0, + max_energy_gain: 100, + energy_increase: 20, + speed_increase: 0.05, + max_speed_increase: 1.8, + is_interruptible: true, }), &PreviousEntityState { event: SfxEvent::Idle, @@ -175,7 +197,7 @@ fn ignores_different_ability_stage() { assert_ne!( result, SfxEvent::Attack( - CharacterAbilityType::TripleStrike(states::triple_strike::Stage::First), + CharacterAbilityType::ComboMelee(states::utils::StageSection::Swing, 1), ToolCategory::Sword ) ); diff --git a/voxygen/src/audio/sfx/mod.rs b/voxygen/src/audio/sfx/mod.rs index 3c238bfa02..183577ac98 100644 --- a/voxygen/src/audio/sfx/mod.rs +++ b/voxygen/src/audio/sfx/mod.rs @@ -71,11 +71,10 @@ //! ], //! threshold: 1.2, //! ), -//! // A multi-stage attack ability which depends on the weapon (To do: update example) -//! Attack(TripleStrike(First), Sword): ( +//! // A multi-stage attack ability which depends on the weapon +//! Attack(ComboMelee(Swing, 1), Sword): ( //! files: [ -//! "voxygen.audio.sfx.weapon.sword_03", -//! "voxygen.audio.sfx.weapon.sword_04", +//! "voxygen.audio.sfx.abilities.swing_sword", //! ], //! threshold: 0.5, //! ), From b0d359e29f7aa20832cb301fc6ee40a79cef5fc0 Mon Sep 17 00:00:00 2001 From: jshipsey Date: Wed, 16 Sep 2020 00:10:33 -0400 Subject: [PATCH 19/28] slightly quicker alpha, improved anims --- voxygen/src/anim/src/character/alpha.rs | 13 +++++++++---- voxygen/src/anim/src/character/beta.rs | 2 ++ voxygen/src/anim/src/character/spin.rs | 3 +++ 3 files changed, 14 insertions(+), 4 deletions(-) diff --git a/voxygen/src/anim/src/character/alpha.rs b/voxygen/src/anim/src/character/alpha.rs index 17dece4690..9bfef6bfcb 100644 --- a/voxygen/src/anim/src/character/alpha.rs +++ b/voxygen/src/anim/src/character/alpha.rs @@ -84,6 +84,10 @@ impl Animation for AlphaAnimation { next.main.orientation = Quaternion::rotation_x(-0.1) * Quaternion::rotation_y(0.0) * Quaternion::rotation_z(0.0); + + next.head.position = Vec3::new(0.0, skeleton_attr.head.0+0.0, skeleton_attr.head.1); + + if let Some(stage_section) = stage_section { match stage_section { @@ -100,7 +104,7 @@ impl Animation for AlphaAnimation { }, StageSection::Swing => { //println!("{:.3} swing", anim_time); - next.control.position = Vec3::new(-7.0, 3.0 + movement * 8.0, 3.0); + next.control.position = Vec3::new(-7.0, 3.0 + movement * 16.0, 3.0); next.control.orientation = Quaternion::rotation_x(-0.5 + movement * -1.0 * 0.0) * Quaternion::rotation_y(-1.0 + movement * -0.6) @@ -121,15 +125,16 @@ impl Animation for AlphaAnimation { }, StageSection::Recover => { //println!("{:.3} recover", anim_time); - next.control.position = Vec3::new(-7.0, 7.0, 2.0); - next.control.orientation = Quaternion::rotation_x(0.0) + next.control.position = Vec3::new(-7.0, 15.0, 2.0); + next.control.orientation = Quaternion::rotation_x(-0.5) * Quaternion::rotation_y(-1.57 + movement * 1.0) * Quaternion::rotation_z(0.0); next.control.scale = Vec3::one(); next.chest.orientation = Quaternion::rotation_y(0.0) * Quaternion::rotation_z(-1.57 + movement * 0.5); + next.head.orientation = - Quaternion::rotation_y(0.0) * Quaternion::rotation_z(1.57); + Quaternion::rotation_y(0.0) * Quaternion::rotation_z(1.57+movement*-0.5); }, _ => {}, } diff --git a/voxygen/src/anim/src/character/beta.rs b/voxygen/src/anim/src/character/beta.rs index ab8562c292..212d3fd0d1 100644 --- a/voxygen/src/anim/src/character/beta.rs +++ b/voxygen/src/anim/src/character/beta.rs @@ -69,6 +69,8 @@ impl Animation for BetaAnimation { * Quaternion::rotation_y(0.0) * Quaternion::rotation_z(0.0); + next.head.position = Vec3::new(0.0, skeleton_attr.head.0, skeleton_attr.head.1); + if let Some(stage_section) = stage_section { match stage_section { StageSection::Buildup => { diff --git a/voxygen/src/anim/src/character/spin.rs b/voxygen/src/anim/src/character/spin.rs index 290df1b49d..21789934e9 100644 --- a/voxygen/src/anim/src/character/spin.rs +++ b/voxygen/src/anim/src/character/spin.rs @@ -54,6 +54,9 @@ impl Animation for SpinAnimation { let movement = anim_time as f32 * 1.0; let test = (anim_time as f32 * 8.0).sin(); let test2 = (anim_time as f32 * 1.0).sin(); + + next.head.position = Vec3::new(0.0, skeleton_attr.head.0, skeleton_attr.head.1); + if let Some(ToolKind::Sword(_)) = active_tool_kind { next.l_hand.position = Vec3::new(-0.75, -1.0, 2.5); From a8e834e754750d90942ac729588aa6dcd57a123d Mon Sep 17 00:00:00 2001 From: Sam Date: Wed, 16 Sep 2020 20:31:27 -0500 Subject: [PATCH 20/28] Initial implementation of spin attack for sword. --- common/src/comp/ability.rs | 47 +++-- common/src/comp/inventory/item/tool.rs | 26 ++- common/src/states/spin_melee.rs | 193 +++++++++++--------- voxygen/src/anim/src/character/spinmelee.rs | 132 +++++++------ voxygen/src/hud/hotbar.rs | 2 + voxygen/src/hud/skillbar.rs | 4 + voxygen/src/scene/figure/mod.rs | 27 ++- 7 files changed, 264 insertions(+), 167 deletions(-) diff --git a/common/src/comp/ability.rs b/common/src/comp/ability.rs index 1d3bcd529a..11a47a796d 100644 --- a/common/src/comp/ability.rs +++ b/common/src/comp/ability.rs @@ -106,10 +106,17 @@ pub enum CharacterAbility { base_damage: u32, }, SpinMelee { - energy_cost: u32, buildup_duration: Duration, + swing_duration: Duration, recover_duration: Duration, base_damage: u32, + knockback: f32, + range: f32, + energy_cost: u32, + is_infinite: bool, + is_helicopter: bool, + forward_speed: f32, + num_spins: u32, }, ChargedRanged { energy_cost: u32, @@ -402,24 +409,34 @@ impl From<&CharacterAbility> for CharacterState { base_damage: *base_damage, }), CharacterAbility::SpinMelee { - energy_cost, buildup_duration, + swing_duration, recover_duration, base_damage, + knockback, + range, + energy_cost, + is_infinite, + is_helicopter, + forward_speed, + num_spins, } => CharacterState::SpinMelee(spin_melee::Data { - exhausted: false, - energy_cost: *energy_cost, - buildup_duration: *buildup_duration, - buildup_duration_default: *buildup_duration, - recover_duration: *recover_duration, - recover_duration_default: *recover_duration, - base_damage: *base_damage, - // This isn't needed for it's continuous implementation, but is left in should this - // skill be moved to the skillbar - hits_remaining: 1, - hits_remaining_default: 1, /* Should be the same value as hits_remaining, also - * this value can be removed if ability moved to - * skillbar */ + static_data: spin_melee::StaticData { + buildup_duration: *buildup_duration, + swing_duration: *swing_duration, + recover_duration: *recover_duration, + base_damage: *base_damage, + knockback: *knockback, + range: *range, + energy_cost: *energy_cost, + is_infinite: *is_infinite, + is_helicopter: *is_helicopter, + forward_speed: *forward_speed, + num_spins: *num_spins, + }, + timer: Duration::default(), + spins_remaining: *num_spins - 1, + stage_section: StageSection::Buildup, }), CharacterAbility::ChargedRanged { energy_cost: _, diff --git a/common/src/comp/inventory/item/tool.rs b/common/src/comp/inventory/item/tool.rs index 0baab1e22c..9b481f6b30 100644 --- a/common/src/comp/inventory/item/tool.rs +++ b/common/src/comp/inventory/item/tool.rs @@ -183,6 +183,19 @@ impl Tool { infinite_charge: true, is_interruptible: true, }, + SpinMelee { + buildup_duration: Duration::from_millis(150), + swing_duration: Duration::from_millis(100), + recover_duration: Duration::from_millis(150), + base_damage: (100.0 * self.base_power()) as u32, + knockback: 0.0, + range: 3.5, + energy_cost: 200, + is_infinite: false, + is_helicopter: false, + forward_speed: 1.0, + num_spins: 3, + } ], Axe(_) => vec![ BasicMelee { @@ -195,10 +208,17 @@ impl Tool { max_angle: 20.0, }, SpinMelee { - energy_cost: 100, - buildup_duration: Duration::from_millis(125), - recover_duration: Duration::from_millis(125), + buildup_duration: Duration::from_millis(100), + swing_duration: Duration::from_millis(50), + recover_duration: Duration::from_millis(100), base_damage: (60.0 * self.base_power()) as u32, + knockback: 0.0, + range: 3.5, + energy_cost: 100, + is_infinite: true, + is_helicopter: true, + forward_speed: 0.0, + num_spins: 1, }, ], Hammer(_) => vec![ diff --git a/common/src/states/spin_melee.rs b/common/src/states/spin_melee.rs index 1bb1141fa2..a25d148c87 100644 --- a/common/src/states/spin_melee.rs +++ b/common/src/states/spin_melee.rs @@ -1,131 +1,144 @@ use crate::{ comp::{Attacking, CharacterState, EnergySource, StateUpdate}, + states::utils::{StageSection, *}, sys::character_behavior::*, }; use serde::{Deserialize, Serialize}; use std::time::Duration; use vek::Vec3; -#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize, Eq, Hash)] -pub struct Data { +/// Separated out to condense update portions of character state +#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)] +pub struct StaticData { /// How long until the state attacks pub buildup_duration: Duration, - /// Allows for buildup_duration to be reset to default value - pub buildup_duration_default: Duration, + /// How long the state is in the swing duration + pub swing_duration: Duration, /// How long until state ends pub recover_duration: Duration, - /// Allows for recover_duration to be reset to default value - pub recover_duration_default: Duration, /// Base damage pub base_damage: u32, - /// Whether the attack can deal more damage - pub exhausted: bool, - /// How many hits it can do before ending - pub hits_remaining: u32, - /// Allows for hits_remaining to be reset to default value - pub hits_remaining_default: u32, + /// Knockback + pub knockback: f32, + /// Range + pub range: f32, /// Energy cost per attack pub energy_cost: u32, + /// Whether spin state is infinite + pub is_infinite: bool, + /// Used to maintain classic axe spin physics + pub is_helicopter: bool, + /// Used for forced forward movement + pub forward_speed: f32, + /// Number of spins + pub num_spins: u32, } -const MOVE_SPEED: f32 = 5.0; +#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)] +pub struct Data { + /// Struct containing data that does not change over the course of the + /// character state + pub static_data: StaticData, + /// Timer for each stage + pub timer: Duration, + /// How many spins it can do before ending + pub spins_remaining: u32, + /// What section the character stage is in + pub stage_section: StageSection, +} impl CharacterBehavior for Data { fn behavior(&self, data: &JoinData) -> StateUpdate { let mut update = StateUpdate::from(data); - if self.buildup_duration != Duration::default() { - // Allows for moving + if self.static_data.is_helicopter { update.vel.0 = - Vec3::new(data.inputs.move_dir.x, data.inputs.move_dir.y, 0.0) * MOVE_SPEED; + Vec3::new(data.inputs.move_dir.x, data.inputs.move_dir.y, 0.0) * 5.0; + } else { + handle_orientation(data, &mut update, 1.0); + forward_move(data, &mut update, 0.1, self.static_data.forward_speed); + } + if self.stage_section == StageSection::Buildup + && self.timer < self.static_data.buildup_duration + { + // Build up update.character = CharacterState::SpinMelee(Data { - buildup_duration: self - .buildup_duration - .checked_sub(Duration::from_secs_f32(data.dt.0)) + static_data: self.static_data, + timer: self + .timer + .checked_add(Duration::from_secs_f32(data.dt.0)) .unwrap_or_default(), - buildup_duration_default: self.buildup_duration_default, - recover_duration: self.recover_duration, - recover_duration_default: self.recover_duration_default, - base_damage: self.base_damage, - exhausted: self.exhausted, - hits_remaining: self.hits_remaining, - hits_remaining_default: self.hits_remaining_default, - energy_cost: self.energy_cost, + spins_remaining: self.spins_remaining, + stage_section: self.stage_section, }); - } else if !self.exhausted { - //Hit attempt + } else if self.stage_section == StageSection::Buildup { + // Transitions to swing section of stage + update.character = CharacterState::SpinMelee(Data { + static_data: self.static_data, + timer: Duration::default(), + spins_remaining: self.spins_remaining, + stage_section: StageSection::Swing, + }); + // Hit attempt data.updater.insert(data.entity, Attacking { - base_healthchange: -(self.base_damage as i32), - range: 3.5, - max_angle: 360_f32.to_radians(), + base_healthchange: -(self.static_data.base_damage as i32), + range: self.static_data.range, + max_angle: 180_f32.to_radians(), applied: false, hit_count: 0, - knockback: 0.0, + knockback: self.static_data.knockback, }); - - update.character = CharacterState::SpinMelee(Data { - buildup_duration: self.buildup_duration, - buildup_duration_default: self.buildup_duration_default, - recover_duration: self.recover_duration, - recover_duration_default: self.recover_duration_default, - base_damage: self.base_damage, - exhausted: true, - hits_remaining: self.hits_remaining - 1, - hits_remaining_default: self.hits_remaining_default, - energy_cost: self.energy_cost, - }); - } else if self.recover_duration != Duration::default() { - // Allows for moving - update.vel.0 = - Vec3::new(data.inputs.move_dir.x, data.inputs.move_dir.y, 0.0) * MOVE_SPEED; - - update.character = CharacterState::SpinMelee(Data { - buildup_duration: self.buildup_duration, - buildup_duration_default: self.buildup_duration_default, - recover_duration: self - .recover_duration - .checked_sub(Duration::from_secs_f32(data.dt.0)) - .unwrap_or_default(), - recover_duration_default: self.recover_duration_default, - base_damage: self.base_damage, - exhausted: self.exhausted, - hits_remaining: self.hits_remaining, - hits_remaining_default: self.hits_remaining_default, - energy_cost: self.energy_cost, - }); - } else if self.hits_remaining != 0 { - // Allows for one ability usage to have multiple hits - // This isn't needed for it's continuous implementation, but is left in should - // this skill be moved to the skillbar - update.character = CharacterState::SpinMelee(Data { - buildup_duration: self.buildup_duration_default, - buildup_duration_default: self.buildup_duration_default, - recover_duration: self.recover_duration_default, - recover_duration_default: self.recover_duration_default, - base_damage: self.base_damage, - exhausted: false, - hits_remaining: self.hits_remaining, - hits_remaining_default: self.hits_remaining_default, - energy_cost: self.energy_cost, - }); - } else if update.energy.current() >= self.energy_cost && data.inputs.secondary.is_pressed() + } else if self.stage_section == StageSection::Swing + && self.timer < self.static_data.swing_duration { + // Swings update.character = CharacterState::SpinMelee(Data { - buildup_duration: self.buildup_duration_default, - buildup_duration_default: self.buildup_duration_default, - recover_duration: self.recover_duration_default, - recover_duration_default: self.recover_duration_default, - base_damage: self.base_damage, - exhausted: false, - hits_remaining: self.hits_remaining_default, - hits_remaining_default: self.hits_remaining_default, - energy_cost: self.energy_cost, + static_data: self.static_data, + timer: self + .timer + .checked_add(Duration::from_secs_f32(data.dt.0)) + .unwrap_or_default(), + spins_remaining: self.spins_remaining, + stage_section: self.stage_section, + }); + } else if self.stage_section == StageSection::Swing { + // Transitions to recover section of stage + update.character = CharacterState::SpinMelee(Data { + static_data: self.static_data, + timer: Duration::default(), + spins_remaining: self.spins_remaining, + stage_section: StageSection::Recover, + }) + } else if self.stage_section == StageSection::Recover + && self.timer < self.static_data.recover_duration + { + // Recover + update.character = CharacterState::SpinMelee(Data { + static_data: self.static_data, + timer: self + .timer + .checked_add(Duration::from_secs_f32(data.dt.0)) + .unwrap_or_default(), + spins_remaining: self.spins_remaining, + stage_section: self.stage_section, + }) + } else if update.energy.current() >= self.static_data.energy_cost && (self.spins_remaining != 0 || (self.static_data.is_infinite && data.inputs.secondary.is_pressed())) { + let new_spins_remaining = if self.static_data.is_infinite { + self.spins_remaining + } else { + self.spins_remaining - 1 + }; + update.character = CharacterState::SpinMelee(Data { + static_data: self.static_data, + timer: Duration::default(), + spins_remaining: new_spins_remaining, + stage_section: StageSection::Buildup, }); // Consumes energy if there's enough left and RMB is held down update .energy - .change_by(-(self.energy_cost as i32), EnergySource::Ability); + .change_by(-(self.static_data.energy_cost as i32), EnergySource::Ability); } else { // Done update.character = CharacterState::Wielding; diff --git a/voxygen/src/anim/src/character/spinmelee.rs b/voxygen/src/anim/src/character/spinmelee.rs index b7c06d9fe4..1e350418c6 100644 --- a/voxygen/src/anim/src/character/spinmelee.rs +++ b/voxygen/src/anim/src/character/spinmelee.rs @@ -2,13 +2,22 @@ use super::{ super::{vek::*, Animation}, CharacterSkeleton, SkeletonAttr, }; -use common::comp::item::{Hands, ToolKind}; +use common::{ + comp::item::{Hands, ToolKind}, + states::utils::StageSection, +}; use std::f32::consts::PI; pub struct SpinMeleeAnimation; impl Animation for SpinMeleeAnimation { - type Dependency = (Option, Option, Vec3, f64); + type Dependency = ( + Option, + Option, + Vec3, + f64, + Option, + ); type Skeleton = CharacterSkeleton; #[cfg(feature = "use-dyn-lib")] @@ -18,7 +27,7 @@ impl Animation for SpinMeleeAnimation { #[allow(clippy::approx_constant)] // TODO: Pending review in #587 fn update_skeleton_inner( skeleton: &Self::Skeleton, - (active_tool_kind, second_tool_kind, velocity, _global_time): Self::Dependency, + (active_tool_kind, second_tool_kind, velocity, _global_time, stage_section): Self::Dependency, anim_time: f64, rate: &mut f32, skeleton_attr: &SkeletonAttr, @@ -49,61 +58,74 @@ impl Animation for SpinMeleeAnimation { let slowersmooth = (anim_time as f32 * lab as f32 * 4.0).sin(); let quick = (anim_time as f32 * lab as f32 * 8.0).sin(); - if let Some(ToolKind::Axe(_)) = active_tool_kind { - next.l_hand.position = Vec3::new(-0.5, 0.0, 4.0); - next.l_hand.orientation = Quaternion::rotation_x(PI / 2.0) - * Quaternion::rotation_z(0.0) - * Quaternion::rotation_y(PI); - next.l_hand.scale = Vec3::one() * 1.08; - next.r_hand.position = Vec3::new(0.5, 0.0, -2.5); - next.r_hand.orientation = Quaternion::rotation_x(PI / 2.0) - * Quaternion::rotation_z(0.0) - * Quaternion::rotation_y(0.0); - next.r_hand.scale = Vec3::one() * 1.06; - next.main.position = Vec3::new(-0.0, -2.0, -1.0); - next.main.orientation = Quaternion::rotation_x(0.0) - * Quaternion::rotation_y(0.0) - * Quaternion::rotation_z(0.0); + match active_tool_kind { + Some(ToolKind::Sword(_)) => { + if let Some(stage_section) = stage_section { + match stage_section { + StageSection::Buildup => {}, + StageSection::Swing => {}, + StageSection::Recover => {}, + _ => {}, + } + } + } + Some(ToolKind::Axe(_)) => { + next.l_hand.position = Vec3::new(-0.5, 0.0, 4.0); + next.l_hand.orientation = Quaternion::rotation_x(PI / 2.0) + * Quaternion::rotation_z(0.0) + * Quaternion::rotation_y(PI); + next.l_hand.scale = Vec3::one() * 1.08; + next.r_hand.position = Vec3::new(0.5, 0.0, -2.5); + next.r_hand.orientation = Quaternion::rotation_x(PI / 2.0) + * Quaternion::rotation_z(0.0) + * Quaternion::rotation_y(0.0); + next.r_hand.scale = Vec3::one() * 1.06; + next.main.position = Vec3::new(-0.0, -2.0, -1.0); + next.main.orientation = Quaternion::rotation_x(0.0) + * Quaternion::rotation_y(0.0) + * Quaternion::rotation_z(0.0); - next.control.position = Vec3::new(0.0, 16.0, 3.0); - next.control.orientation = Quaternion::rotation_x(-1.4) - * Quaternion::rotation_y(0.0) - * Quaternion::rotation_z(1.4); - next.control.scale = Vec3::one(); + next.control.position = Vec3::new(0.0, 16.0, 3.0); + next.control.orientation = Quaternion::rotation_x(-1.4) + * Quaternion::rotation_y(0.0) + * Quaternion::rotation_z(1.4); + next.control.scale = Vec3::one(); - next.head.position = Vec3::new(0.0, skeleton_attr.head.0, skeleton_attr.head.1); - next.head.orientation = Quaternion::rotation_z(0.0) - * Quaternion::rotation_x(-0.15) - * Quaternion::rotation_y(0.08); - next.chest.position = Vec3::new( - 0.0, - skeleton_attr.chest.0 - 3.0, - skeleton_attr.chest.1 - 2.0, - ); - next.chest.orientation = Quaternion::rotation_z(0.0) - * Quaternion::rotation_x(-0.1) - * Quaternion::rotation_y(0.3); - next.chest.scale = Vec3::one(); + next.head.position = Vec3::new(0.0, skeleton_attr.head.0, skeleton_attr.head.1); + next.head.orientation = Quaternion::rotation_z(0.0) + * Quaternion::rotation_x(-0.15) + * Quaternion::rotation_y(0.08); + next.chest.position = Vec3::new( + 0.0, + skeleton_attr.chest.0 - 3.0, + skeleton_attr.chest.1 - 2.0, + ); + next.chest.orientation = Quaternion::rotation_z(0.0) + * Quaternion::rotation_x(-0.1) + * Quaternion::rotation_y(0.3); + next.chest.scale = Vec3::one(); - next.belt.position = Vec3::new(0.0, 1.0, -1.0); - next.belt.orientation = Quaternion::rotation_z(0.0) - * Quaternion::rotation_x(0.4) - * Quaternion::rotation_y(0.0); - next.belt.scale = Vec3::one() * 0.98; - next.shorts.position = Vec3::new(0.0, 3.0, -2.5); - next.shorts.orientation = Quaternion::rotation_z(0.0) - * Quaternion::rotation_x(0.7) - * Quaternion::rotation_y(0.0); - next.shorts.scale = Vec3::one(); - next.torso.position = Vec3::new( - -xshift * (anim_time as f32).min(0.6), - -yshift * (anim_time as f32).min(0.6), - 0.0, - ) * skeleton_attr.scaler; - next.torso.orientation = Quaternion::rotation_z(spin * -16.0) - * Quaternion::rotation_x(0.0) - * Quaternion::rotation_y(0.0); - next.torso.scale = Vec3::one() / 11.0 * skeleton_attr.scaler; + next.belt.position = Vec3::new(0.0, 1.0, -1.0); + next.belt.orientation = Quaternion::rotation_z(0.0) + * Quaternion::rotation_x(0.4) + * Quaternion::rotation_y(0.0); + next.belt.scale = Vec3::one() * 0.98; + next.shorts.position = Vec3::new(0.0, 3.0, -2.5); + next.shorts.orientation = Quaternion::rotation_z(0.0) + * Quaternion::rotation_x(0.7) + * Quaternion::rotation_y(0.0); + next.shorts.scale = Vec3::one(); + next.torso.position = Vec3::new( + -xshift * (anim_time as f32).min(0.6), + -yshift * (anim_time as f32).min(0.6), + 0.0, + ) * skeleton_attr.scaler; + next.torso.orientation = Quaternion::rotation_z(spin * -16.0) + * Quaternion::rotation_x(0.0) + * Quaternion::rotation_y(0.0); + next.torso.scale = Vec3::one() / 11.0 * skeleton_attr.scaler; + }, + _ => {}, } if velocity.z.abs() > 0.1 { next.l_foot.position = diff --git a/voxygen/src/hud/hotbar.rs b/voxygen/src/hud/hotbar.rs index 7ca59b2945..37d9cd1b41 100644 --- a/voxygen/src/hud/hotbar.rs +++ b/voxygen/src/hud/hotbar.rs @@ -81,6 +81,8 @@ impl State { kind != "Sceptre" && kind != "SceptreVelorite" } else if let ToolKind::Debug(kind) = &kind.kind { kind == "Boost" + } else if let ToolKind::Sword(_) = &kind.kind { + true } else { false } diff --git a/voxygen/src/hud/skillbar.rs b/voxygen/src/hud/skillbar.rs index cba416f454..215a0fe37c 100644 --- a/voxygen/src/hud/skillbar.rs +++ b/voxygen/src/hud/skillbar.rs @@ -803,6 +803,10 @@ impl<'a> Widget for Skillbar<'a> { "\nWhirls a big fireball into the air. \nExplodes the ground \ and does\na big amount of damage", )), + ToolKind::Sword(_) => Some(( + "Whirlwind", + "\nMove forward while spinning with \n your sword." + )), ToolKind::Debug(kind) => match kind.as_ref() { "Boost" => Some(( "Possessing Arrow", diff --git a/voxygen/src/scene/figure/mod.rs b/voxygen/src/scene/figure/mod.rs index df5f49062f..45b217454d 100644 --- a/voxygen/src/scene/figure/mod.rs +++ b/voxygen/src/scene/figure/mod.rs @@ -25,7 +25,7 @@ use anim::{ }; use common::{ comp::{ - item::ItemKind, Body, CharacterState, Item, Last, LightAnimation, LightEmitter, Loadout, + item::{ItemKind, ToolKind}, Body, CharacterState, Item, Last, LightAnimation, LightEmitter, Loadout, Ori, PhysicsState, Pos, Scale, Stats, Vel, }, span, @@ -935,11 +935,30 @@ impl FigureMgr { skeleton_attr, ) }, - CharacterState::SpinMelee(_) => { + CharacterState::SpinMelee(s) => { + let stage_progress = match active_tool_kind { + Some(ToolKind::Sword(_)) => { + let stage_time = s.timer.as_secs_f64(); + match s.stage_section { + StageSection::Buildup => { + stage_time / s.static_data.buildup_duration.as_secs_f64() + }, + 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, + } + }, + _ => state.state_time + }; + anim::character::SpinMeleeAnimation::update_skeleton( &target_base, - (active_tool_kind, second_tool_kind, vel.0, time), - state.state_time, + (active_tool_kind, second_tool_kind, vel.0, time, Some(s.stage_section),), + stage_progress, &mut state_animation_rate, skeleton_attr, ) From e79cef4824a6178ae168abf93c865dc56d3ec45a Mon Sep 17 00:00:00 2001 From: jshipsey Date: Thu, 17 Sep 2020 00:18:09 -0400 Subject: [PATCH 21/28] dash animation --- common/src/comp/inventory/item/tool.rs | 8 +- common/src/states/spin_melee.rs | 19 +- voxygen/src/anim/src/character/alpha.rs | 8 +- voxygen/src/anim/src/character/beta.rs | 2 +- voxygen/src/anim/src/character/dash.rs | 203 ++++++++++++++------ voxygen/src/anim/src/character/spin.rs | 3 +- voxygen/src/anim/src/character/spinmelee.rs | 2 +- voxygen/src/anim/src/character/stand.rs | 4 +- voxygen/src/hud/skillbar.rs | 2 +- voxygen/src/scene/figure/mod.rs | 21 +- 10 files changed, 181 insertions(+), 91 deletions(-) diff --git a/common/src/comp/inventory/item/tool.rs b/common/src/comp/inventory/item/tool.rs index 9b481f6b30..0f2e0c7daf 100644 --- a/common/src/comp/inventory/item/tool.rs +++ b/common/src/comp/inventory/item/tool.rs @@ -127,8 +127,8 @@ impl Tool { knockback: 10.0, range: 4.0, angle: 30.0, - base_buildup_duration: Duration::from_millis(500), - base_swing_duration: Duration::from_millis(200), + base_buildup_duration: Duration::from_millis(350), + base_swing_duration: Duration::from_millis(100), base_recover_duration: Duration::from_millis(400), forward_movement: 0.5, }, @@ -176,7 +176,7 @@ impl Tool { angle: 45.0, energy_drain: 500, forward_speed: 4.0, - buildup_duration: Duration::from_millis(200), + buildup_duration: Duration::from_millis(250), charge_duration: Duration::from_millis(400), swing_duration: Duration::from_millis(100), recover_duration: Duration::from_millis(500), @@ -195,7 +195,7 @@ impl Tool { is_helicopter: false, forward_speed: 1.0, num_spins: 3, - } + }, ], Axe(_) => vec![ BasicMelee { diff --git a/common/src/states/spin_melee.rs b/common/src/states/spin_melee.rs index a25d148c87..f0a425bf5e 100644 --- a/common/src/states/spin_melee.rs +++ b/common/src/states/spin_melee.rs @@ -52,8 +52,7 @@ impl CharacterBehavior for Data { let mut update = StateUpdate::from(data); if self.static_data.is_helicopter { - update.vel.0 = - Vec3::new(data.inputs.move_dir.x, data.inputs.move_dir.y, 0.0) * 5.0; + update.vel.0 = Vec3::new(data.inputs.move_dir.x, data.inputs.move_dir.y, 0.0) * 5.0; } else { handle_orientation(data, &mut update, 1.0); forward_move(data, &mut update, 0.1, self.static_data.forward_speed); @@ -90,7 +89,7 @@ impl CharacterBehavior for Data { knockback: self.static_data.knockback, }); } else if self.stage_section == StageSection::Swing - && self.timer < self.static_data.swing_duration + && self.timer < self.static_data.swing_duration { // Swings update.character = CharacterState::SpinMelee(Data { @@ -111,7 +110,7 @@ impl CharacterBehavior for Data { stage_section: StageSection::Recover, }) } else if self.stage_section == StageSection::Recover - && self.timer < self.static_data.recover_duration + && self.timer < self.static_data.recover_duration { // Recover update.character = CharacterState::SpinMelee(Data { @@ -123,7 +122,10 @@ impl CharacterBehavior for Data { spins_remaining: self.spins_remaining, stage_section: self.stage_section, }) - } else if update.energy.current() >= self.static_data.energy_cost && (self.spins_remaining != 0 || (self.static_data.is_infinite && data.inputs.secondary.is_pressed())) { + } else if update.energy.current() >= self.static_data.energy_cost + && (self.spins_remaining != 0 + || (self.static_data.is_infinite && data.inputs.secondary.is_pressed())) + { let new_spins_remaining = if self.static_data.is_infinite { self.spins_remaining } else { @@ -136,9 +138,10 @@ impl CharacterBehavior for Data { stage_section: StageSection::Buildup, }); // Consumes energy if there's enough left and RMB is held down - update - .energy - .change_by(-(self.static_data.energy_cost as i32), EnergySource::Ability); + update.energy.change_by( + -(self.static_data.energy_cost as i32), + EnergySource::Ability, + ); } else { // Done update.character = CharacterState::Wielding; diff --git a/voxygen/src/anim/src/character/alpha.rs b/voxygen/src/anim/src/character/alpha.rs index 9bfef6bfcb..3bd7971070 100644 --- a/voxygen/src/anim/src/character/alpha.rs +++ b/voxygen/src/anim/src/character/alpha.rs @@ -84,10 +84,8 @@ impl Animation for AlphaAnimation { next.main.orientation = Quaternion::rotation_x(-0.1) * Quaternion::rotation_y(0.0) * Quaternion::rotation_z(0.0); - - next.head.position = Vec3::new(0.0, skeleton_attr.head.0+0.0, skeleton_attr.head.1); - + next.head.position = Vec3::new(0.0, skeleton_attr.head.0 + 0.0, skeleton_attr.head.1); if let Some(stage_section) = stage_section { match stage_section { @@ -133,8 +131,8 @@ impl Animation for AlphaAnimation { next.chest.orientation = Quaternion::rotation_y(0.0) * Quaternion::rotation_z(-1.57 + movement * 0.5); - next.head.orientation = - Quaternion::rotation_y(0.0) * Quaternion::rotation_z(1.57+movement*-0.5); + next.head.orientation = Quaternion::rotation_y(0.0) + * Quaternion::rotation_z(1.57 + movement * -0.5); }, _ => {}, } diff --git a/voxygen/src/anim/src/character/beta.rs b/voxygen/src/anim/src/character/beta.rs index 212d3fd0d1..3570327a0c 100644 --- a/voxygen/src/anim/src/character/beta.rs +++ b/voxygen/src/anim/src/character/beta.rs @@ -69,7 +69,7 @@ impl Animation for BetaAnimation { * Quaternion::rotation_y(0.0) * Quaternion::rotation_z(0.0); - next.head.position = Vec3::new(0.0, skeleton_attr.head.0, skeleton_attr.head.1); + next.head.position = Vec3::new(0.0, skeleton_attr.head.0, skeleton_attr.head.1); if let Some(stage_section) = stage_section { match stage_section { diff --git a/voxygen/src/anim/src/character/dash.rs b/voxygen/src/anim/src/character/dash.rs index 60643bfcac..9d15e0514c 100644 --- a/voxygen/src/anim/src/character/dash.rs +++ b/voxygen/src/anim/src/character/dash.rs @@ -6,6 +6,7 @@ use common::{ comp::item::{Hands, ToolKind}, states::utils::StageSection, }; +use std::f32::consts::PI; pub struct Input { pub attack: bool, @@ -37,67 +38,150 @@ impl Animation for DashAnimation { let mut next = (*skeleton).clone(); let lab = 1.0; - let foot = (((5.0) - / (1.1 + 3.9 * ((anim_time as f32 * lab as f32 * 25.0).sin()).powf(2.0 as f32))) - .sqrt()) - * ((anim_time as f32 * lab as f32 * 25.0).sin()); - let slow = (((5.0) / (1.1 + 3.9 * ((anim_time as f32 * lab as f32 * 12.4).sin()).powf(2.0 as f32))) .sqrt()) * ((anim_time as f32 * lab as f32 * 12.4).sin()); + let short = (((5.0) + / (1.5 + 3.5 * ((anim_time as f32 * lab as f32 * 5.0).sin()).powf(2.0 as f32))) + .sqrt()) + * ((anim_time as f32 * lab as f32 * 5.0).sin()); + let foothoril = (anim_time as f32 * 5.0 * lab as f32 + PI * 1.45).sin(); + let foothorir = (anim_time as f32 * 5.0 * lab as f32 + PI * (0.45)).sin(); + + let footvertl = (anim_time as f32 * 5.0 * lab as f32).sin(); + let footvertr = (anim_time as f32 * 5.0 * lab as f32 + PI).sin(); + + let footrotl = (((1.0) + / (0.05 + + (0.95) + * ((anim_time as f32 * 5.0 * lab as f32 + PI * 1.4).sin()).powf(2.0 as f32))) + .sqrt()) + * ((anim_time as f32 * 5.0 * lab as f32 + PI * 1.4).sin()); + + let footrotr = (((1.0) + / (0.05 + + (0.95) + * ((anim_time as f32 * 5.0 * lab as f32 + PI * 0.4).sin()).powf(2.0 as f32))) + .sqrt()) + * ((anim_time as f32 * 5.0 * lab as f32 + PI * 0.4).sin()); + + let shortalt = (anim_time as f32 * lab as f32 * 5.0 + PI / 2.0).sin(); + + let movement = (anim_time as f32 * 1.0).min(1.0); + + next.head.position = Vec3::new(0.0, -2.0 + skeleton_attr.head.0, skeleton_attr.head.1); + + next.l_hand.position = Vec3::new(-0.75, -1.0, 2.5); + next.l_hand.orientation = Quaternion::rotation_x(1.47) * Quaternion::rotation_y(-0.2); + next.l_hand.scale = Vec3::one() * 1.04; + next.r_hand.position = Vec3::new(0.75, -1.5, -0.5); + next.r_hand.orientation = Quaternion::rotation_x(1.47) * Quaternion::rotation_y(0.3); + next.r_hand.scale = Vec3::one() * 1.05; + next.main.position = Vec3::new(0.0, 0.0, 2.0); + next.main.orientation = Quaternion::rotation_x(-0.1) + * Quaternion::rotation_y(0.0) + * Quaternion::rotation_z(0.0); + match active_tool_kind { //TODO: Inventory Some(ToolKind::Sword(_)) => { if let Some(stage_section) = stage_section { match stage_section { - StageSection::Buildup => {}, - StageSection::Charge => {}, - StageSection::Swing => {}, - StageSection::Recover => {}, + StageSection::Buildup => { + next.head.orientation = Quaternion::rotation_z(movement * -0.9); + + next.chest.orientation = Quaternion::rotation_z(movement * 1.1); + + next.control.position = Vec3::new(-7.0 + movement * -5.0, 7.0, 2.0); + next.control.orientation = Quaternion::rotation_x(movement * -1.0) + * Quaternion::rotation_y(movement * 1.5) + * Quaternion::rotation_z(0.0); + next.control.scale = Vec3::one(); + next.l_foot.position = Vec3::new( + -skeleton_attr.foot.0, + skeleton_attr.foot.1 + movement * -12.0, + skeleton_attr.foot.2, + ); + next.l_foot.orientation = Quaternion::rotation_x(movement * -1.0); + next.r_foot.position = Vec3::new( + skeleton_attr.foot.0, + skeleton_attr.foot.1, + skeleton_attr.foot.2, + ); + }, + StageSection::Charge => { + next.head.position = Vec3::new( + 0.0, + -2.0 + skeleton_attr.head.0, + skeleton_attr.head.1 + movement * 1.0, + ); + + next.head.orientation = Quaternion::rotation_x(0.0) + * Quaternion::rotation_y(movement * -0.3) + * Quaternion::rotation_z(-0.9 + movement * -0.2 + short * -0.05); + next.chest.position = Vec3::new( + 0.0, + skeleton_attr.chest.0, + skeleton_attr.chest.1 + 2.0 + shortalt * -2.5, + ); + + next.chest.orientation = Quaternion::rotation_x(movement * -0.4) + * Quaternion::rotation_y(movement * -0.2) + * Quaternion::rotation_z(1.1); + + next.control.position = + Vec3::new(-13.0, 7.0 + movement * -2.0, 2.0 + movement * 2.0); + next.control.orientation = + Quaternion::rotation_x(-1.0) * Quaternion::rotation_y(1.5); + next.control.scale = Vec3::one(); + + next.shorts.orientation = Quaternion::rotation_z(short * 0.25); + next.belt.orientation = Quaternion::rotation_z(short * 0.1); + next.l_foot.position = Vec3::new( + 2.0 - skeleton_attr.foot.0, + skeleton_attr.foot.1 + foothoril * -7.5, + 2.0 + skeleton_attr.foot.2 + ((footvertl * -4.0).max(-1.0)), + ); + next.l_foot.orientation = + Quaternion::rotation_x(-0.6 + footrotl * -0.6) + * Quaternion::rotation_z(-0.2); + + next.r_foot.position = Vec3::new( + 2.0 + skeleton_attr.foot.0, + skeleton_attr.foot.1 + foothorir * -7.5, + 2.0 + skeleton_attr.foot.2 + ((footvertr * -4.0).max(-1.0)), + ); + next.r_foot.orientation = + Quaternion::rotation_x(-0.6 + footrotr * -0.6) + * Quaternion::rotation_z(-0.2); + }, + StageSection::Swing => { + next.head.orientation = Quaternion::rotation_y(0.2 + movement * -0.2) + * Quaternion::rotation_z(-1.1 + movement * 1.8); + + next.chest.orientation = Quaternion::rotation_y(-0.2 + movement * 0.3) + * Quaternion::rotation_z(1.1 + movement * -2.2); + + next.control.position = Vec3::new(-13.0 + movement * -2.0, 5.0, 4.0); + next.control.orientation = + Quaternion::rotation_x(-1.0 + movement * -0.5) + * Quaternion::rotation_y(1.5 + movement * -2.5); + next.control.scale = Vec3::one(); + }, + StageSection::Recover => { + next.head.orientation = Quaternion::rotation_z(0.7); + + next.chest.orientation = Quaternion::rotation_z(-1.1); + + next.control.position = Vec3::new(-15.0, 5.0, 2.0); + next.control.orientation = + Quaternion::rotation_x(-1.5) * Quaternion::rotation_y(-1.0); + next.control.scale = Vec3::one(); + }, } } - - next.head.position = Vec3::new( - 0.0, - -2.0 + skeleton_attr.head.0, - -2.0 + skeleton_attr.head.1, - ); - next.head.orientation = Quaternion::rotation_z(0.0) - * Quaternion::rotation_x(0.0) - * Quaternion::rotation_y(0.0); - next.head.scale = Vec3::one() * skeleton_attr.head_scale; - - next.chest.position = Vec3::new(0.0, 0.0, 7.0 + slow * 2.0); - next.chest.orientation = - Quaternion::rotation_x(-0.5) * Quaternion::rotation_z(-0.7); - - next.belt.position = Vec3::new(0.0, 1.0, -1.0); - next.belt.orientation = Quaternion::rotation_x(0.2) * Quaternion::rotation_z(0.2); - - next.shorts.position = Vec3::new(0.0, 3.0, -3.0); - next.shorts.orientation = Quaternion::rotation_x(0.4) * Quaternion::rotation_z(0.3); - - next.l_hand.position = Vec3::new(-0.75, -1.0, -2.5); - next.l_hand.orientation = Quaternion::rotation_x(1.27); - next.l_hand.scale = Vec3::one() * 1.04; - next.r_hand.position = Vec3::new(0.75, -1.5, -5.5); - next.r_hand.orientation = Quaternion::rotation_x(1.27); - next.r_hand.scale = Vec3::one() * 1.05; - next.main.position = Vec3::new(0.0, 6.0, -1.0); - next.main.orientation = Quaternion::rotation_x(-0.3); - next.main.scale = Vec3::one(); - - next.control.position = Vec3::new(-8.0 - slow * 0.5, 3.0 - foot * 0.6, 3.0); - next.control.orientation = - Quaternion::rotation_x(-0.3) * Quaternion::rotation_z(1.1 + slow * 0.2); - next.control.scale = Vec3::one(); - next.l_foot.position = Vec3::new(-1.4, foot * 3.0 + 2.0, skeleton_attr.foot.2); - next.l_foot.orientation = Quaternion::rotation_x(foot * -0.4 - 0.8); - - next.r_foot.position = Vec3::new(5.4, foot * -3.0 - 1.0, skeleton_attr.foot.2); - next.r_foot.orientation = Quaternion::rotation_x(foot * 0.4 - 0.8); }, Some(ToolKind::Dagger(_)) => { next.head.position = Vec3::new( @@ -130,15 +214,15 @@ impl Animation for DashAnimation { next.main.orientation = Quaternion::rotation_x(-0.3); next.main.scale = Vec3::one(); - next.control.position = Vec3::new(-8.0 - slow * 0.5, 3.0 - foot * 0.6, 3.0); + next.control.position = Vec3::new(-8.0 - slow * 0.5, 3.0, 3.0); next.control.orientation = Quaternion::rotation_x(-0.3) * Quaternion::rotation_z(1.1 + slow * 0.2); next.control.scale = Vec3::one(); - next.l_foot.position = Vec3::new(-1.4, foot * 3.0 + 2.0, skeleton_attr.foot.2); - next.l_foot.orientation = Quaternion::rotation_x(foot * -0.4 - 0.8); + next.l_foot.position = Vec3::new(-1.4, 2.0, skeleton_attr.foot.2); + next.l_foot.orientation = Quaternion::rotation_x(-0.8); - next.r_foot.position = Vec3::new(5.4, foot * -3.0 - 1.0, skeleton_attr.foot.2); - next.r_foot.orientation = Quaternion::rotation_x(foot * 0.4 - 0.8); + next.r_foot.position = Vec3::new(5.4, -1.0, skeleton_attr.foot.2); + next.r_foot.orientation = Quaternion::rotation_x(-0.8); }, _ => {}, } @@ -189,11 +273,11 @@ impl Animation for DashAnimation { next.second.orientation = Quaternion::rotation_x(-0.3); next.second.scale = Vec3::one(); - next.l_foot.position = Vec3::new(-1.4, foot * 3.0 + 2.0, skeleton_attr.foot.2); - next.l_foot.orientation = Quaternion::rotation_x(foot * -0.4 - 0.8); + next.l_foot.position = Vec3::new(-1.4, 2.0, skeleton_attr.foot.2); + next.l_foot.orientation = Quaternion::rotation_x(-0.8); - next.r_foot.position = Vec3::new(5.4, foot * -3.0 - 1.0, skeleton_attr.foot.2); - next.r_foot.orientation = Quaternion::rotation_x(foot * 0.4 - 0.8); + next.r_foot.position = Vec3::new(5.4, -1.0, skeleton_attr.foot.2); + next.r_foot.orientation = Quaternion::rotation_x(-0.8); }, _ => {}, } @@ -207,9 +291,6 @@ impl Animation for DashAnimation { Quaternion::rotation_x(slow * -0.7 + 0.4) * Quaternion::rotation_y(slow * 0.4); next.hold.scale = Vec3::one() * 0.0; - next.torso.position = Vec3::new(0.0, 0.0, 0.1) * skeleton_attr.scaler; - next.torso.orientation = - Quaternion::rotation_z(0.0) * Quaternion::rotation_x(0.0) * Quaternion::rotation_y(0.0); next.torso.scale = Vec3::one() / 11.0 * skeleton_attr.scaler; next.l_control.scale = Vec3::one(); diff --git a/voxygen/src/anim/src/character/spin.rs b/voxygen/src/anim/src/character/spin.rs index 21789934e9..ed8d1b5ed1 100644 --- a/voxygen/src/anim/src/character/spin.rs +++ b/voxygen/src/anim/src/character/spin.rs @@ -54,9 +54,8 @@ impl Animation for SpinAnimation { let movement = anim_time as f32 * 1.0; let test = (anim_time as f32 * 8.0).sin(); let test2 = (anim_time as f32 * 1.0).sin(); - - next.head.position = Vec3::new(0.0, skeleton_attr.head.0, skeleton_attr.head.1); + next.head.position = Vec3::new(0.0, skeleton_attr.head.0, skeleton_attr.head.1); if let Some(ToolKind::Sword(_)) = active_tool_kind { next.l_hand.position = Vec3::new(-0.75, -1.0, 2.5); diff --git a/voxygen/src/anim/src/character/spinmelee.rs b/voxygen/src/anim/src/character/spinmelee.rs index 1e350418c6..7de89ae8d9 100644 --- a/voxygen/src/anim/src/character/spinmelee.rs +++ b/voxygen/src/anim/src/character/spinmelee.rs @@ -68,7 +68,7 @@ impl Animation for SpinMeleeAnimation { _ => {}, } } - } + }, Some(ToolKind::Axe(_)) => { next.l_hand.position = Vec3::new(-0.5, 0.0, 4.0); next.l_hand.orientation = Quaternion::rotation_x(PI / 2.0) diff --git a/voxygen/src/anim/src/character/stand.rs b/voxygen/src/anim/src/character/stand.rs index 3362bd4ea2..67225246f2 100644 --- a/voxygen/src/anim/src/character/stand.rs +++ b/voxygen/src/anim/src/character/stand.rs @@ -41,7 +41,7 @@ impl Animation for StandAnimation { ); next.head.position = Vec3::new( 0.0, - -3.0 + skeleton_attr.head.0, + -2.0 + skeleton_attr.head.0, skeleton_attr.head.1 + slow * 0.3 + breathe * -0.05, ); next.head.orientation = Quaternion::rotation_z(head_look.x) @@ -174,7 +174,7 @@ impl Animation for StandAnimation { next.lantern.orientation = Quaternion::rotation_x(0.1) * Quaternion::rotation_y(0.1); next.lantern.scale = Vec3::one() * 0.65; - next.torso.position = Vec3::new(0.0, 0.0, 0.) * skeleton_attr.scaler; + next.torso.position = Vec3::new(0.0, 0.0, 0.0) * skeleton_attr.scaler; next.torso.orientation = Quaternion::rotation_x(0.0); next.torso.scale = Vec3::one() / 11.0 * skeleton_attr.scaler; diff --git a/voxygen/src/hud/skillbar.rs b/voxygen/src/hud/skillbar.rs index 215a0fe37c..9b83cb5e43 100644 --- a/voxygen/src/hud/skillbar.rs +++ b/voxygen/src/hud/skillbar.rs @@ -805,7 +805,7 @@ impl<'a> Widget for Skillbar<'a> { )), ToolKind::Sword(_) => Some(( "Whirlwind", - "\nMove forward while spinning with \n your sword." + "\nMove forward while spinning with \n your sword.", )), ToolKind::Debug(kind) => match kind.as_ref() { "Boost" => Some(( diff --git a/voxygen/src/scene/figure/mod.rs b/voxygen/src/scene/figure/mod.rs index 45b217454d..52228dd073 100644 --- a/voxygen/src/scene/figure/mod.rs +++ b/voxygen/src/scene/figure/mod.rs @@ -25,8 +25,9 @@ use anim::{ }; use common::{ comp::{ - item::{ItemKind, ToolKind}, Body, CharacterState, Item, Last, LightAnimation, LightEmitter, Loadout, - Ori, PhysicsState, Pos, Scale, Stats, Vel, + item::{ItemKind, ToolKind}, + Body, CharacterState, Item, Last, LightAnimation, LightEmitter, Loadout, Ori, PhysicsState, + Pos, Scale, Stats, Vel, }, span, state::{DeltaTime, State}, @@ -941,23 +942,31 @@ impl FigureMgr { let stage_time = s.timer.as_secs_f64(); match s.stage_section { StageSection::Buildup => { - stage_time / s.static_data.buildup_duration.as_secs_f64() + stage_time + / s.static_data.buildup_duration.as_secs_f64() }, StageSection::Swing => { stage_time / s.static_data.swing_duration.as_secs_f64() }, StageSection::Recover => { - stage_time / s.static_data.recover_duration.as_secs_f64() + stage_time + / s.static_data.recover_duration.as_secs_f64() }, _ => 0.0, } }, - _ => state.state_time + _ => state.state_time, }; anim::character::SpinMeleeAnimation::update_skeleton( &target_base, - (active_tool_kind, second_tool_kind, vel.0, time, Some(s.stage_section),), + ( + active_tool_kind, + second_tool_kind, + vel.0, + time, + Some(s.stage_section), + ), stage_progress, &mut state_animation_rate, skeleton_attr, From 133e79ffd512f22057af352414825a5fde9cf05b Mon Sep 17 00:00:00 2001 From: Sam Date: Fri, 18 Sep 2020 14:27:02 -0500 Subject: [PATCH 22/28] Modified how spin melee functions. --- common/src/comp/ability.rs | 1 + common/src/comp/inventory/item/tool.rs | 4 +- common/src/states/spin_melee.rs | 58 ++++++++++++++++---------- 3 files changed, 40 insertions(+), 23 deletions(-) diff --git a/common/src/comp/ability.rs b/common/src/comp/ability.rs index 11a47a796d..074b8c2b1f 100644 --- a/common/src/comp/ability.rs +++ b/common/src/comp/ability.rs @@ -437,6 +437,7 @@ impl From<&CharacterAbility> for CharacterState { timer: Duration::default(), spins_remaining: *num_spins - 1, stage_section: StageSection::Buildup, + exhausted: false, }), CharacterAbility::ChargedRanged { energy_cost: _, diff --git a/common/src/comp/inventory/item/tool.rs b/common/src/comp/inventory/item/tool.rs index 0f2e0c7daf..dc29ff8abb 100644 --- a/common/src/comp/inventory/item/tool.rs +++ b/common/src/comp/inventory/item/tool.rs @@ -185,7 +185,7 @@ impl Tool { }, SpinMelee { buildup_duration: Duration::from_millis(150), - swing_duration: Duration::from_millis(100), + swing_duration: Duration::from_millis(500), recover_duration: Duration::from_millis(150), base_damage: (100.0 * self.base_power()) as u32, knockback: 0.0, @@ -209,7 +209,7 @@ impl Tool { }, SpinMelee { buildup_duration: Duration::from_millis(100), - swing_duration: Duration::from_millis(50), + swing_duration: Duration::from_millis(250), recover_duration: Duration::from_millis(100), base_damage: (60.0 * self.base_power()) as u32, knockback: 0.0, diff --git a/common/src/states/spin_melee.rs b/common/src/states/spin_melee.rs index f0a425bf5e..c8d5e70c84 100644 --- a/common/src/states/spin_melee.rs +++ b/common/src/states/spin_melee.rs @@ -45,6 +45,8 @@ pub struct Data { pub spins_remaining: u32, /// What section the character stage is in pub stage_section: StageSection, + /// Whether the state can deal damage + pub exhausted: bool, } impl CharacterBehavior for Data { @@ -70,6 +72,7 @@ impl CharacterBehavior for Data { .unwrap_or_default(), spins_remaining: self.spins_remaining, stage_section: self.stage_section, + exhausted: self.exhausted }); } else if self.stage_section == StageSection::Buildup { // Transitions to swing section of stage @@ -78,6 +81,15 @@ impl CharacterBehavior for Data { timer: Duration::default(), spins_remaining: self.spins_remaining, stage_section: StageSection::Swing, + exhausted: self.exhausted + }); + } else if !self.exhausted { + update.character = CharacterState::SpinMelee(Data { + static_data: self.static_data, + timer: Duration::default(), + spins_remaining: self.spins_remaining, + stage_section: self.stage_section, + exhausted: true, }); // Hit attempt data.updater.insert(data.entity, Attacking { @@ -100,14 +112,37 @@ impl CharacterBehavior for Data { .unwrap_or_default(), spins_remaining: self.spins_remaining, stage_section: self.stage_section, + exhausted: self.exhausted }); - } else if self.stage_section == StageSection::Swing { + } else if update.energy.current() >= self.static_data.energy_cost + && (self.spins_remaining != 0 + || (self.static_data.is_infinite && data.inputs.secondary.is_pressed())) + { + let new_spins_remaining = if self.static_data.is_infinite { + self.spins_remaining + } else { + self.spins_remaining - 1 + }; + update.character = CharacterState::SpinMelee(Data { + static_data: self.static_data, + timer: Duration::default(), + spins_remaining: new_spins_remaining, + stage_section: self.stage_section, + exhausted: false, + }); + // Consumes energy if there's enough left and RMB is held down + update.energy.change_by( + -(self.static_data.energy_cost as i32), + EnergySource::Ability, + ); + } else if self.stage_section == StageSection::Swing { // Transitions to recover section of stage update.character = CharacterState::SpinMelee(Data { static_data: self.static_data, timer: Duration::default(), spins_remaining: self.spins_remaining, stage_section: StageSection::Recover, + exhausted: self.exhausted }) } else if self.stage_section == StageSection::Recover && self.timer < self.static_data.recover_duration @@ -121,27 +156,8 @@ impl CharacterBehavior for Data { .unwrap_or_default(), spins_remaining: self.spins_remaining, stage_section: self.stage_section, + exhausted: self.exhausted }) - } else if update.energy.current() >= self.static_data.energy_cost - && (self.spins_remaining != 0 - || (self.static_data.is_infinite && data.inputs.secondary.is_pressed())) - { - let new_spins_remaining = if self.static_data.is_infinite { - self.spins_remaining - } else { - self.spins_remaining - 1 - }; - update.character = CharacterState::SpinMelee(Data { - static_data: self.static_data, - timer: Duration::default(), - spins_remaining: new_spins_remaining, - stage_section: StageSection::Buildup, - }); - // Consumes energy if there's enough left and RMB is held down - update.energy.change_by( - -(self.static_data.energy_cost as i32), - EnergySource::Ability, - ); } else { // Done update.character = CharacterState::Wielding; From 8070a38a8914f2365b166d2101fb47603962f35d Mon Sep 17 00:00:00 2001 From: jshipsey Date: Sun, 20 Sep 2020 03:51:18 -0400 Subject: [PATCH 23/28] spin anim --- common/src/comp/inventory/item/tool.rs | 6 +- common/src/states/spin_melee.rs | 3 +- voxygen/src/anim/src/character/spinmelee.rs | 171 +++++++++++++++----- 3 files changed, 132 insertions(+), 48 deletions(-) diff --git a/common/src/comp/inventory/item/tool.rs b/common/src/comp/inventory/item/tool.rs index dc29ff8abb..2cf5bd7408 100644 --- a/common/src/comp/inventory/item/tool.rs +++ b/common/src/comp/inventory/item/tool.rs @@ -184,13 +184,13 @@ impl Tool { is_interruptible: true, }, SpinMelee { - buildup_duration: Duration::from_millis(150), + buildup_duration: Duration::from_millis(1000), swing_duration: Duration::from_millis(500), - recover_duration: Duration::from_millis(150), + recover_duration: Duration::from_millis(100), base_damage: (100.0 * self.base_power()) as u32, knockback: 0.0, range: 3.5, - energy_cost: 200, + energy_cost: 0, is_infinite: false, is_helicopter: false, forward_speed: 1.0, diff --git a/common/src/states/spin_melee.rs b/common/src/states/spin_melee.rs index c8d5e70c84..1b8fa8e302 100644 --- a/common/src/states/spin_melee.rs +++ b/common/src/states/spin_melee.rs @@ -57,7 +57,6 @@ impl CharacterBehavior for Data { update.vel.0 = Vec3::new(data.inputs.move_dir.x, data.inputs.move_dir.y, 0.0) * 5.0; } else { handle_orientation(data, &mut update, 1.0); - forward_move(data, &mut update, 0.1, self.static_data.forward_speed); } if self.stage_section == StageSection::Buildup @@ -103,6 +102,8 @@ impl CharacterBehavior for Data { } else if self.stage_section == StageSection::Swing && self.timer < self.static_data.swing_duration { + forward_move(data, &mut update, 0.1, self.static_data.forward_speed); + // Swings update.character = CharacterState::SpinMelee(Data { static_data: self.static_data, diff --git a/voxygen/src/anim/src/character/spinmelee.rs b/voxygen/src/anim/src/character/spinmelee.rs index 7de89ae8d9..62ed79cc6d 100644 --- a/voxygen/src/anim/src/character/spinmelee.rs +++ b/voxygen/src/anim/src/character/spinmelee.rs @@ -53,6 +53,7 @@ impl Animation for SpinMeleeAnimation { } else { lab as f32 * anim_time as f32 * 0.9 }; + let movement = anim_time as f32 * 1.0; //feet let slowersmooth = (anim_time as f32 * lab as f32 * 4.0).sin(); @@ -60,11 +61,89 @@ impl Animation for SpinMeleeAnimation { match active_tool_kind { Some(ToolKind::Sword(_)) => { + next.l_hand.position = Vec3::new(-0.75, -1.0, 2.5); + next.l_hand.orientation = + Quaternion::rotation_x(1.47) * Quaternion::rotation_y(-0.2); + next.l_hand.scale = Vec3::one() * 1.04; + next.r_hand.position = Vec3::new(0.75, -1.5, -0.5); + next.r_hand.orientation = + Quaternion::rotation_x(1.47) * Quaternion::rotation_y(0.3); + next.r_hand.scale = Vec3::one() * 1.05; + next.main.position = Vec3::new(0.0, 0.0, 2.0); + next.main.orientation = Quaternion::rotation_x(-0.1) + * Quaternion::rotation_y(0.0) + * Quaternion::rotation_z(0.0); + next.head.position = + Vec3::new(0.0, skeleton_attr.head.0 + 0.0, skeleton_attr.head.1); + if let Some(stage_section) = stage_section { match stage_section { - StageSection::Buildup => {}, - StageSection::Swing => {}, - StageSection::Recover => {}, + StageSection::Buildup => { + next.control.position = + Vec3::new(-7.0, 7.0 + movement * -8.0, 2.0 + movement * -6.0); + next.control.orientation = Quaternion::rotation_x(movement * -0.5) + * Quaternion::rotation_y(movement * 0.3) + * Quaternion::rotation_z(movement * -1.5); + next.chest.position = Vec3::new( + 0.0, + skeleton_attr.chest.0 + movement * -1.0, + skeleton_attr.chest.1 + movement * -2.5, + ); + next.chest.orientation = Quaternion::rotation_x(movement * -1.1) + * Quaternion::rotation_z(movement * -0.35); + next.belt.orientation = Quaternion::rotation_z(movement * 0.35); + next.shorts.orientation = Quaternion::rotation_z(movement * 0.5); + next.head.position = Vec3::new( + 0.0, + skeleton_attr.head.0 - 2.0 + movement * -6.0, + skeleton_attr.head.1 + movement * -4.0, + ); + next.head.orientation = Quaternion::rotation_x(movement * 0.9) + * Quaternion::rotation_y(0.0) + * Quaternion::rotation_z(movement * 0.05); + + next.l_foot.position = Vec3::new( + -skeleton_attr.foot.0, + skeleton_attr.foot.1 + movement * 4.0, + skeleton_attr.foot.2, + ); + next.l_foot.orientation = Quaternion::rotation_x(movement * 0.2); + next.r_foot.position = Vec3::new( + skeleton_attr.foot.0, + skeleton_attr.foot.1 + movement * -12.0, + skeleton_attr.foot.2 + movement * 1.0 + quick * 1.0, + ); + next.r_foot.orientation = Quaternion::rotation_x(movement * -1.0) + * Quaternion::rotation_z(movement * -0.8); + }, + StageSection::Swing => { + next.head.position = + Vec3::new(0.0, skeleton_attr.head.0, skeleton_attr.head.1); + + next.control.position = Vec3::new(-7.0, 7.0, 2.0); + next.control.orientation = Quaternion::rotation_x(-PI / 2.0) + * Quaternion::rotation_z(-PI / 2.0); + next.torso.orientation = Quaternion::rotation_z(movement * PI * 2.0); + + next.chest.position = + Vec3::new(0.0, skeleton_attr.chest.0, skeleton_attr.chest.1); + next.chest.orientation = Quaternion::rotation_y(0.3); + next.head.position = + Vec3::new(0.0, skeleton_attr.head.0 - 2.0, skeleton_attr.head.1); + next.head.orientation = Quaternion::rotation_x(-0.15); + next.belt.orientation = Quaternion::rotation_x(0.1); + next.shorts.orientation = Quaternion::rotation_x(0.2); + }, + StageSection::Recover => { + next.head.position = + Vec3::new(0.0, skeleton_attr.head.0 - 2.0, skeleton_attr.head.1); + next.control.position = Vec3::new(-7.0, 7.0, 2.0); + next.control.orientation = + Quaternion::rotation_x(-PI / 2.0 + movement * PI / 2.0) + * Quaternion::rotation_z(-PI / 2.0 + movement * PI / 2.0); + next.head.orientation = Quaternion::rotation_x(-0.15 + movement * 0.15); + next.chest.orientation = Quaternion::rotation_y(0.3 + movement * -0.3) + }, _ => {}, } } @@ -124,51 +203,55 @@ impl Animation for SpinMeleeAnimation { * Quaternion::rotation_x(0.0) * Quaternion::rotation_y(0.0); next.torso.scale = Vec3::one() / 11.0 * skeleton_attr.scaler; + if velocity.z.abs() > 0.1 { + next.l_foot.position = + Vec3::new(-skeleton_attr.foot.0, 8.0, skeleton_attr.foot.2 + 2.0); + next.l_foot.orientation = + Quaternion::rotation_x(1.0) * Quaternion::rotation_z(0.0); + next.l_foot.scale = Vec3::one(); + + next.r_foot.position = + Vec3::new(skeleton_attr.foot.0, 8.0, skeleton_attr.foot.2 + 2.0); + next.r_foot.orientation = Quaternion::rotation_x(1.0); + next.r_foot.scale = Vec3::one(); + } else if speed < 0.5 { + next.l_foot.position = Vec3::new( + -skeleton_attr.foot.0, + 2.0 + quick * -6.0, + skeleton_attr.foot.2, + ); + next.l_foot.orientation = Quaternion::rotation_x(0.5 + slowersmooth * 0.2) + * Quaternion::rotation_z(0.0); + next.l_foot.scale = Vec3::one(); + + next.r_foot.position = + Vec3::new(skeleton_attr.foot.0, 4.0, skeleton_attr.foot.2); + next.r_foot.orientation = Quaternion::rotation_x(0.5 - slowersmooth * 0.2) + * Quaternion::rotation_y(-0.4); + next.r_foot.scale = Vec3::one(); + } else { + next.l_foot.position = Vec3::new( + -skeleton_attr.foot.0, + 2.0 + quick * -6.0, + skeleton_attr.foot.2, + ); + next.l_foot.orientation = Quaternion::rotation_x(0.5 + slowersmooth * 0.2) + * Quaternion::rotation_z(0.0); + next.l_foot.scale = Vec3::one(); + + next.r_foot.position = Vec3::new( + skeleton_attr.foot.0, + 2.0 + quick * 6.0, + skeleton_attr.foot.2, + ); + next.r_foot.orientation = Quaternion::rotation_x(0.5 - slowersmooth * 0.2) + * Quaternion::rotation_z(0.0); + next.r_foot.scale = Vec3::one(); + }; }, _ => {}, } - if velocity.z.abs() > 0.1 { - next.l_foot.position = - Vec3::new(-skeleton_attr.foot.0, 8.0, skeleton_attr.foot.2 + 2.0); - next.l_foot.orientation = Quaternion::rotation_x(1.0) * Quaternion::rotation_z(0.0); - next.l_foot.scale = Vec3::one(); - next.r_foot.position = Vec3::new(skeleton_attr.foot.0, 8.0, skeleton_attr.foot.2 + 2.0); - next.r_foot.orientation = Quaternion::rotation_x(1.0); - next.r_foot.scale = Vec3::one(); - } else if speed < 0.5 { - next.l_foot.position = Vec3::new( - -skeleton_attr.foot.0, - 2.0 + quick * -6.0, - skeleton_attr.foot.2, - ); - next.l_foot.orientation = - Quaternion::rotation_x(0.5 + slowersmooth * 0.2) * Quaternion::rotation_z(0.0); - next.l_foot.scale = Vec3::one(); - - next.r_foot.position = Vec3::new(skeleton_attr.foot.0, 4.0, skeleton_attr.foot.2); - next.r_foot.orientation = - Quaternion::rotation_x(0.5 - slowersmooth * 0.2) * Quaternion::rotation_y(-0.4); - next.r_foot.scale = Vec3::one(); - } else { - next.l_foot.position = Vec3::new( - -skeleton_attr.foot.0, - 2.0 + quick * -6.0, - skeleton_attr.foot.2, - ); - next.l_foot.orientation = - Quaternion::rotation_x(0.5 + slowersmooth * 0.2) * Quaternion::rotation_z(0.0); - next.l_foot.scale = Vec3::one(); - - next.r_foot.position = Vec3::new( - skeleton_attr.foot.0, - 2.0 + quick * 6.0, - skeleton_attr.foot.2, - ); - next.r_foot.orientation = - Quaternion::rotation_x(0.5 - slowersmooth * 0.2) * Quaternion::rotation_z(0.0); - next.r_foot.scale = Vec3::one(); - }; next.lantern.position = Vec3::new( skeleton_attr.lantern.0, skeleton_attr.lantern.1, From b4018e7d42cbaa35fd7fb3f0286da67b46c6c04c Mon Sep 17 00:00:00 2001 From: Sam Date: Sun, 20 Sep 2020 12:23:33 -0500 Subject: [PATCH 24/28] Made 3rd ability interruptible. Final balance tweaks. --- CHANGELOG.md | 1 + common/src/comp/ability.rs | 3 ++ common/src/comp/inventory/item/tool.rs | 12 +++-- common/src/loadout_builder.rs | 19 ++++--- common/src/states/combo_melee.rs | 3 +- common/src/states/dash_melee.rs | 3 +- common/src/states/spin_melee.rs | 72 +++++++++++++++----------- common/src/states/utils.rs | 7 +++ server/src/cmd.rs | 3 +- server/src/sys/terrain.rs | 4 +- voxygen/src/hud/hotbar.rs | 6 +-- 11 files changed, 82 insertions(+), 51 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9918edc9b5..1e9eb6f9a8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -38,6 +38,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Figure meshing no longer blocks the main thread. - Overhauled persistence layer including no longer storing serialized JSON items in the database - Overhauled representation of blocks to permit fluid and sprite coexistence +- Overhauled sword ### Removed diff --git a/common/src/comp/ability.rs b/common/src/comp/ability.rs index 074b8c2b1f..df7e554dee 100644 --- a/common/src/comp/ability.rs +++ b/common/src/comp/ability.rs @@ -115,6 +115,7 @@ pub enum CharacterAbility { energy_cost: u32, is_infinite: bool, is_helicopter: bool, + is_interruptible: bool, forward_speed: f32, num_spins: u32, }, @@ -418,6 +419,7 @@ impl From<&CharacterAbility> for CharacterState { energy_cost, is_infinite, is_helicopter, + is_interruptible, forward_speed, num_spins, } => CharacterState::SpinMelee(spin_melee::Data { @@ -431,6 +433,7 @@ impl From<&CharacterAbility> for CharacterState { energy_cost: *energy_cost, is_infinite: *is_infinite, is_helicopter: *is_helicopter, + is_interruptible: *is_interruptible, forward_speed: *forward_speed, num_spins: *num_spins, }, diff --git a/common/src/comp/inventory/item/tool.rs b/common/src/comp/inventory/item/tool.rs index 2cf5bd7408..00915d8ed5 100644 --- a/common/src/comp/inventory/item/tool.rs +++ b/common/src/comp/inventory/item/tool.rs @@ -184,15 +184,16 @@ impl Tool { is_interruptible: true, }, SpinMelee { - buildup_duration: Duration::from_millis(1000), + buildup_duration: Duration::from_millis(750), swing_duration: Duration::from_millis(500), - recover_duration: Duration::from_millis(100), - base_damage: (100.0 * self.base_power()) as u32, - knockback: 0.0, + recover_duration: Duration::from_millis(500), + base_damage: (140.0 * self.base_power()) as u32, + knockback: 10.0, range: 3.5, - energy_cost: 0, + energy_cost: 200, is_infinite: false, is_helicopter: false, + is_interruptible: true, forward_speed: 1.0, num_spins: 3, }, @@ -217,6 +218,7 @@ impl Tool { energy_cost: 100, is_infinite: true, is_helicopter: true, + is_interruptible: false, forward_speed: 0.0, num_spins: 1, }, diff --git a/common/src/loadout_builder.rs b/common/src/loadout_builder.rs index 978ad61c4e..78807138c4 100644 --- a/common/src/loadout_builder.rs +++ b/common/src/loadout_builder.rs @@ -66,7 +66,12 @@ impl LoadoutBuilder { } /// Builds loadout of creature when spawned - pub fn build_loadout(body: Body, alignment: Alignment, mut main_tool: Option, is_giant: bool) -> Self { + pub fn build_loadout( + body: Body, + alignment: Alignment, + mut main_tool: Option, + is_giant: bool, + ) -> Self { #![allow(clippy::single_match)] // For when this is done to more than just golems. match body { Body::Golem(golem) => match golem.species { @@ -76,10 +81,12 @@ impl LoadoutBuilder { )); }, }, - Body::Humanoid(_) => if is_giant { - main_tool = Some(Item::new_from_asset_expect( - "common.items.npc_weapons.sword.zweihander_sword_0", - )); + Body::Humanoid(_) => { + if is_giant { + main_tool = Some(Item::new_from_asset_expect( + "common.items.npc_weapons.sword.zweihander_sword_0", + )); + } }, _ => {}, }; @@ -219,7 +226,7 @@ impl LoadoutBuilder { tabard: None, }, _ => LoadoutBuilder::animal(body).build(), - } + }, }, Body::Golem(golem) => match golem.species { golem::Species::StoneGolem => Loadout { diff --git a/common/src/states/combo_melee.rs b/common/src/states/combo_melee.rs index b158df90c8..aa7417afbb 100644 --- a/common/src/states/combo_melee.rs +++ b/common/src/states/combo_melee.rs @@ -77,8 +77,7 @@ impl CharacterBehavior for Data { // Allows for other states to interrupt this state if self.is_interruptible && !data.inputs.primary.is_pressed() { - handle_dodge_input(data, &mut update); - handle_ability2_input(data, &mut update); + handle_interrupt(data, &mut update); match update.character { CharacterState::ComboMelee(_) => {}, _ => { diff --git a/common/src/states/dash_melee.rs b/common/src/states/dash_melee.rs index 678ff3c6fe..4e9d8d15ca 100644 --- a/common/src/states/dash_melee.rs +++ b/common/src/states/dash_melee.rs @@ -64,8 +64,7 @@ impl CharacterBehavior for Data { // Allows for other states to interrupt this state if self.static_data.is_interruptible && !data.inputs.secondary.is_pressed() { - handle_dodge_input(data, &mut update); - handle_ability1_input(data, &mut update); + handle_interrupt(data, &mut update); match update.character { CharacterState::DashMelee(_) => {}, _ => { diff --git a/common/src/states/spin_melee.rs b/common/src/states/spin_melee.rs index 1b8fa8e302..8f1b8a8a27 100644 --- a/common/src/states/spin_melee.rs +++ b/common/src/states/spin_melee.rs @@ -28,6 +28,8 @@ pub struct StaticData { pub is_infinite: bool, /// Used to maintain classic axe spin physics pub is_helicopter: bool, + /// Whether the state can be interrupted by other abilities + pub is_interruptible: bool, /// Used for forced forward movement pub forward_speed: f32, /// Number of spins @@ -55,8 +57,17 @@ impl CharacterBehavior for Data { if self.static_data.is_helicopter { update.vel.0 = Vec3::new(data.inputs.move_dir.x, data.inputs.move_dir.y, 0.0) * 5.0; - } else { - handle_orientation(data, &mut update, 1.0); + } + + // Allows for other states to interrupt this state + if self.static_data.is_interruptible && !data.inputs.ability3.is_pressed() { + handle_interrupt(data, &mut update); + match update.character { + CharacterState::SpinMelee(_) => {}, + _ => { + return update; + }, + } } if self.stage_section == StageSection::Buildup @@ -71,7 +82,7 @@ impl CharacterBehavior for Data { .unwrap_or_default(), spins_remaining: self.spins_remaining, stage_section: self.stage_section, - exhausted: self.exhausted + exhausted: self.exhausted, }); } else if self.stage_section == StageSection::Buildup { // Transitions to swing section of stage @@ -80,7 +91,7 @@ impl CharacterBehavior for Data { timer: Duration::default(), spins_remaining: self.spins_remaining, stage_section: StageSection::Swing, - exhausted: self.exhausted + exhausted: self.exhausted, }); } else if !self.exhausted { update.character = CharacterState::SpinMelee(Data { @@ -102,7 +113,10 @@ impl CharacterBehavior for Data { } else if self.stage_section == StageSection::Swing && self.timer < self.static_data.swing_duration { - forward_move(data, &mut update, 0.1, self.static_data.forward_speed); + if !self.static_data.is_helicopter { + forward_move(data, &mut update, 0.1, self.static_data.forward_speed); + handle_orientation(data, &mut update, 1.0); + } // Swings update.character = CharacterState::SpinMelee(Data { @@ -113,37 +127,37 @@ impl CharacterBehavior for Data { .unwrap_or_default(), spins_remaining: self.spins_remaining, stage_section: self.stage_section, - exhausted: self.exhausted + exhausted: self.exhausted, }); } else if update.energy.current() >= self.static_data.energy_cost - && (self.spins_remaining != 0 - || (self.static_data.is_infinite && data.inputs.secondary.is_pressed())) - { - let new_spins_remaining = if self.static_data.is_infinite { - self.spins_remaining - } else { - self.spins_remaining - 1 - }; - update.character = CharacterState::SpinMelee(Data { - static_data: self.static_data, - timer: Duration::default(), - spins_remaining: new_spins_remaining, - stage_section: self.stage_section, - exhausted: false, - }); - // Consumes energy if there's enough left and RMB is held down - update.energy.change_by( - -(self.static_data.energy_cost as i32), - EnergySource::Ability, - ); - } else if self.stage_section == StageSection::Swing { + && (self.spins_remaining != 0 + || (self.static_data.is_infinite && data.inputs.secondary.is_pressed())) + { + let new_spins_remaining = if self.static_data.is_infinite { + self.spins_remaining + } else { + self.spins_remaining - 1 + }; + update.character = CharacterState::SpinMelee(Data { + static_data: self.static_data, + timer: Duration::default(), + spins_remaining: new_spins_remaining, + stage_section: self.stage_section, + exhausted: false, + }); + // Consumes energy if there's enough left and RMB is held down + update.energy.change_by( + -(self.static_data.energy_cost as i32), + EnergySource::Ability, + ); + } else if self.stage_section == StageSection::Swing { // Transitions to recover section of stage update.character = CharacterState::SpinMelee(Data { static_data: self.static_data, timer: Duration::default(), spins_remaining: self.spins_remaining, stage_section: StageSection::Recover, - exhausted: self.exhausted + exhausted: self.exhausted, }) } else if self.stage_section == StageSection::Recover && self.timer < self.static_data.recover_duration @@ -157,7 +171,7 @@ impl CharacterBehavior for Data { .unwrap_or_default(), spins_remaining: self.spins_remaining, stage_section: self.stage_section, - exhausted: self.exhausted + exhausted: self.exhausted, }) } else { // Done diff --git a/common/src/states/utils.rs b/common/src/states/utils.rs index a7fb142081..475a5cf13f 100644 --- a/common/src/states/utils.rs +++ b/common/src/states/utils.rs @@ -347,6 +347,13 @@ pub fn unwrap_tool_data<'a>(data: &'a JoinData) -> Option<&'a Tool> { } } +pub fn handle_interrupt(data: &JoinData, update: &mut StateUpdate) { + handle_ability1_input(data, update); + handle_ability2_input(data, update); + handle_ability3_input(data, update); + handle_dodge_input(data, update); +} + /// Determines what portion a state is in. Used in all attacks (eventually). Is /// used to control aspects of animation code, as well as logic within the /// character states. diff --git a/server/src/cmd.rs b/server/src/cmd.rs index 7d793744a3..1808ba532c 100644 --- a/server/src/cmd.rs +++ b/server/src/cmd.rs @@ -621,7 +621,8 @@ fn handle_spawn( .create_npc( pos, comp::Stats::new(get_npc_name(id).into(), body), - LoadoutBuilder::build_loadout(body, alignment, None, false).build(), + LoadoutBuilder::build_loadout(body, alignment, None, false) + .build(), body, ) .with(comp::Vel(vel)) diff --git a/server/src/sys/terrain.rs b/server/src/sys/terrain.rs index f903aa3ebf..e372a95073 100644 --- a/server/src/sys/terrain.rs +++ b/server/src/sys/terrain.rs @@ -120,7 +120,9 @@ impl<'a> System<'a> for Sys { // let damage = stats.level.level() as i32; TODO: Make NPC base damage // non-linearly depend on their level - let loadout = LoadoutBuilder::build_loadout(body, alignment, main_tool, entity.is_giant).build(); + let loadout = + LoadoutBuilder::build_loadout(body, alignment, main_tool, entity.is_giant) + .build(); let mut scale = entity.scale; diff --git a/voxygen/src/hud/hotbar.rs b/voxygen/src/hud/hotbar.rs index 37d9cd1b41..4817f8e2e7 100644 --- a/voxygen/src/hud/hotbar.rs +++ b/voxygen/src/hud/hotbar.rs @@ -81,11 +81,7 @@ impl State { kind != "Sceptre" && kind != "SceptreVelorite" } else if let ToolKind::Debug(kind) = &kind.kind { kind == "Boost" - } else if let ToolKind::Sword(_) = &kind.kind { - true - } else { - false - } + } else {matches!(&kind.kind, ToolKind::Sword(_))} } else { false } From 1fbcf2be803bd0cc42a47f01b458d4712995f9c1 Mon Sep 17 00:00:00 2001 From: Sam Date: Sun, 20 Sep 2020 12:44:57 -0500 Subject: [PATCH 25/28] Fixed pipeline errors. --- .../src/audio/sfx/event_mapper/combat/tests.rs | 18 +++++++++++++++--- voxygen/src/hud/hotbar.rs | 4 +++- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/voxygen/src/audio/sfx/event_mapper/combat/tests.rs b/voxygen/src/audio/sfx/event_mapper/combat/tests.rs index 86363d6bd1..ba71f492a9 100644 --- a/voxygen/src/audio/sfx/event_mapper/combat/tests.rs +++ b/voxygen/src/audio/sfx/event_mapper/combat/tests.rs @@ -114,7 +114,10 @@ fn matches_ability_stage() { let result = CombatEventMapper::map_event( &CharacterState::ComboMelee(states::combo_melee::Data { - stage_data: vec![combo_melee::Stage { + stage: 1, + num_stages: 1, + combo: 0, + stage_data: vec![states::combo_melee::Stage { stage: 1, base_damage: 100, max_damage: 120, @@ -130,6 +133,9 @@ fn matches_ability_stage() { initial_energy_gain: 0, max_energy_gain: 100, energy_increase: 20, + timer: Duration::default(), + stage_section: states::utils::StageSection::Swing, + next_stage: false, speed_increase: 0.05, max_speed_increase: 1.8, is_interruptible: true, @@ -166,7 +172,10 @@ fn ignores_different_ability_stage() { let result = CombatEventMapper::map_event( &CharacterState::ComboMelee(states::combo_melee::Data { - stage_data: vec![combo_melee::Stage { + stage: 1, + num_stages: 1, + combo: 0, + stage_data: vec![states::combo_melee::Stage { stage: 1, base_damage: 100, max_damage: 120, @@ -182,6 +191,9 @@ fn ignores_different_ability_stage() { initial_energy_gain: 0, max_energy_gain: 100, energy_increase: 20, + timer: Duration::default(), + stage_section: states::utils::StageSection::Swing, + next_stage: false, speed_increase: 0.05, max_speed_increase: 1.8, is_interruptible: true, @@ -197,7 +209,7 @@ fn ignores_different_ability_stage() { assert_ne!( result, SfxEvent::Attack( - CharacterAbilityType::ComboMelee(states::utils::StageSection::Swing, 1), + CharacterAbilityType::ComboMelee(states::utils::StageSection::Swing, 2), ToolCategory::Sword ) ); diff --git a/voxygen/src/hud/hotbar.rs b/voxygen/src/hud/hotbar.rs index 4817f8e2e7..4ddd1fea38 100644 --- a/voxygen/src/hud/hotbar.rs +++ b/voxygen/src/hud/hotbar.rs @@ -81,7 +81,9 @@ impl State { kind != "Sceptre" && kind != "SceptreVelorite" } else if let ToolKind::Debug(kind) = &kind.kind { kind == "Boost" - } else {matches!(&kind.kind, ToolKind::Sword(_))} + } else { + matches!(&kind.kind, ToolKind::Sword(_)) + } } else { false } From 0796337a8cbe0614e23412734d7ec8c4437821a3 Mon Sep 17 00:00:00 2001 From: jshipsey Date: Sun, 20 Sep 2020 17:57:26 -0400 Subject: [PATCH 26/28] resolve minor anim hiccup --- voxygen/src/anim/src/character/beta.rs | 16 ++++++++-------- voxygen/src/anim/src/character/spin.rs | 20 ++++++++++---------- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/voxygen/src/anim/src/character/beta.rs b/voxygen/src/anim/src/character/beta.rs index 3570327a0c..97b1656e21 100644 --- a/voxygen/src/anim/src/character/beta.rs +++ b/voxygen/src/anim/src/character/beta.rs @@ -55,7 +55,7 @@ impl Animation for BetaAnimation { let recover = (anim_time as f32 * 8.0).sin(); let movement = anim_time as f32 * 1.0; - let test = (anim_time as f32 * 2.5).sin(); + let stab = (anim_time as f32 * 2.5).sin(); if let Some(ToolKind::Sword(_)) = active_tool_kind { next.l_hand.position = Vec3::new(-0.75, -1.0, 2.5); @@ -77,8 +77,8 @@ impl Animation for BetaAnimation { //println!("{:.3} recover", anim_time); next.control.position = Vec3::new( -8.0 + movement * -5.0, - 4.0 - recover * 0.8 + movement * 2.0, - 6.0 - recover * 0.4, + 1.0 - recover * 0.8 + movement * 2.0, + 2.0 - recover * 0.4, ); next.control.orientation = Quaternion::rotation_x(-1.57) * Quaternion::rotation_y(0.0 + movement * 1.5) @@ -91,14 +91,14 @@ impl Animation for BetaAnimation { StageSection::Swing => { //println!("{:.3} swing", anim_time); next.control.position = - Vec3::new(-8.0 + test * 30.0, 6.0 + movement * 2.0, 6.0); + Vec3::new(-8.0 + stab * 30.0, 6.0 + movement * 2.0, 6.0); next.control.orientation = Quaternion::rotation_x(-1.57) - * Quaternion::rotation_y(1.5 + test * 0.5) - * Quaternion::rotation_z(1.0 + test * 1.0); + * Quaternion::rotation_y(1.5 + stab * 0.5) + * Quaternion::rotation_z(1.0 + stab * 1.0); next.chest.orientation = Quaternion::rotation_y(-0.1) - * Quaternion::rotation_z(1.9 + test * -0.5); + * Quaternion::rotation_z(1.9 + stab * -0.5); next.head.orientation = Quaternion::rotation_y(0.1) - * Quaternion::rotation_z(-1.2 + test * -0.5); + * Quaternion::rotation_z(-1.2 + stab * -0.5); }, StageSection::Recover => { next.control.position = Vec3::new(10.0 + movement * -5.0, 8.0, 6.0); diff --git a/voxygen/src/anim/src/character/spin.rs b/voxygen/src/anim/src/character/spin.rs index ed8d1b5ed1..af05f26232 100644 --- a/voxygen/src/anim/src/character/spin.rs +++ b/voxygen/src/anim/src/character/spin.rs @@ -52,8 +52,8 @@ impl Animation for SpinAnimation { let recover = (anim_time as f32 * 8.0).sin(); let movement = anim_time as f32 * 1.0; - let test = (anim_time as f32 * 8.0).sin(); - let test2 = (anim_time as f32 * 1.0).sin(); + let stab = (anim_time as f32 * 8.0).sin(); + let rotate = (anim_time as f32 * 1.0).sin(); next.head.position = Vec3::new(0.0, skeleton_attr.head.0, skeleton_attr.head.1); @@ -91,20 +91,20 @@ impl Animation for SpinAnimation { //println!("{:.3} swing", anim_time); next.control.position = Vec3::new( 7.0 + movement * -8.0, - 11.0 + test * 3.0, - 2.0 + test * 3.5 + movement * 3.0, + 11.0 + stab * 3.0, + 2.0 + stab * 3.5 + movement * 3.0, ); next.control.orientation = - Quaternion::rotation_x(-1.57 + movement * -0.6 + test * -0.25) + Quaternion::rotation_x(-1.57 + movement * -0.6 + stab * -0.25) * Quaternion::rotation_y(2.8 + movement * -2.0) * Quaternion::rotation_z(1.0 + movement * 1.0); - next.head.orientation = Quaternion::rotation_z(-test * 0.8); - next.chest.orientation = Quaternion::rotation_x(test * 0.15) + next.head.orientation = Quaternion::rotation_z(-stab * 0.8); + next.chest.orientation = Quaternion::rotation_x(stab * 0.15) * Quaternion::rotation_y(movement * 0.3) * Quaternion::rotation_z(movement * 1.5); - next.belt.orientation = Quaternion::rotation_z(test2 * 0.5); - next.shorts.orientation = Quaternion::rotation_z(test2 * 1.5); - next.torso.orientation = Quaternion::rotation_z(test2 * 7.2); + next.belt.orientation = Quaternion::rotation_z(rotate * 0.5); + next.shorts.orientation = Quaternion::rotation_z(rotate * 1.5); + next.torso.orientation = Quaternion::rotation_z(rotate * 7.2); }, StageSection::Recover => { //println!("{:.3} recover", anim_time); From 8ab0d5e5e07a08221a44f5241e66d08df644d1c2 Mon Sep 17 00:00:00 2001 From: Sam Date: Sun, 20 Sep 2020 21:18:45 -0500 Subject: [PATCH 27/28] Added icon for skillbar ability of sword. --- assets/voxygen/element/icons/sword_whirlwind.png | 3 +++ voxygen/src/hud/img_ids.rs | 1 + voxygen/src/hud/slots.rs | 3 +++ 3 files changed, 7 insertions(+) create mode 100644 assets/voxygen/element/icons/sword_whirlwind.png diff --git a/assets/voxygen/element/icons/sword_whirlwind.png b/assets/voxygen/element/icons/sword_whirlwind.png new file mode 100644 index 0000000000..6b76ae0c1a --- /dev/null +++ b/assets/voxygen/element/icons/sword_whirlwind.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f5f67d60ff7ab065a99e49ee0cf1cda2ddc4d1b1c1370f5cc9ca066dedcbb682 +size 533 diff --git a/voxygen/src/hud/img_ids.rs b/voxygen/src/hud/img_ids.rs index 6548e91f48..29b35d13f6 100644 --- a/voxygen/src/hud/img_ids.rs +++ b/voxygen/src/hud/img_ids.rs @@ -267,6 +267,7 @@ image_ids! { fire_spell_1: "voxygen.element.icons.fire_spell_0", snake_arrow_0: "voxygen.element.icons.snake", heal_0: "voxygen.element.icons.heal_0", + sowrd_whirlwind: "voxygen.element.icons.sword_whirlwind", // Buttons button: "voxygen.element.buttons.button", diff --git a/voxygen/src/hud/slots.rs b/voxygen/src/hud/slots.rs index 534d0f3f50..13113cc5d3 100644 --- a/voxygen/src/hud/slots.rs +++ b/voxygen/src/hud/slots.rs @@ -84,6 +84,7 @@ pub enum HotbarImage { Item(ItemKey), Fireball, SnakeArrow, + SwordWhirlwind, } type HotbarSource<'a> = (&'a hotbar::State, &'a Inventory, &'a Loadout, &'a Energy); @@ -113,6 +114,7 @@ impl<'a> SlotKey, HotbarImageSource<'a>> for HotbarSlot { "Boost" => Some(HotbarImage::SnakeArrow), _ => None, }, + ToolKind::Sword(_) => Some(HotbarImage::SwordWhirlwind), _ => None, }, _ => None, @@ -143,6 +145,7 @@ impl<'a> SlotKey, HotbarImageSource<'a>> for HotbarSlot { HotbarImage::Item(key) => item_imgs.img_id_or_not_found_img(key.clone()), HotbarImage::SnakeArrow => imgs.snake_arrow_0, HotbarImage::Fireball => imgs.fire_spell_1, + HotbarImage::SwordWhirlwind => imgs.sowrd_whirlwind, } } } From 2ff59c9f60f5c8dee15bb9ffbb019f4b56a8fdce Mon Sep 17 00:00:00 2001 From: Sam Date: Mon, 21 Sep 2020 17:38:01 -0500 Subject: [PATCH 28/28] Addressed comments --- common/src/comp/ability.rs | 18 +- common/src/loadout_builder.rs | 177 ++++---- common/src/states/combo_melee.rs | 385 ++++++++---------- common/src/states/dash_melee.rs | 317 +++++++------- common/src/states/spin_melee.rs | 224 +++++----- common/src/sys/phys.rs | 4 - .../audio/sfx/event_mapper/combat/tests.rs | 84 ++-- voxygen/src/hud/img_ids.rs | 2 +- voxygen/src/hud/slots.rs | 2 +- voxygen/src/scene/figure/mod.rs | 6 +- 10 files changed, 608 insertions(+), 611 deletions(-) diff --git a/common/src/comp/ability.rs b/common/src/comp/ability.rs index df7e554dee..7fa360af56 100644 --- a/common/src/comp/ability.rs +++ b/common/src/comp/ability.rs @@ -381,19 +381,21 @@ impl From<&CharacterAbility> for CharacterState { max_speed_increase, is_interruptible, } => CharacterState::ComboMelee(combo_melee::Data { + static_data: combo_melee::StaticData { + num_stages: stage_data.len() as u32, + stage_data: stage_data.clone(), + initial_energy_gain: *initial_energy_gain, + max_energy_gain: *max_energy_gain, + energy_increase: *energy_increase, + speed_increase: 1.0 - *speed_increase, + max_speed_increase: *max_speed_increase - 1.0, + is_interruptible: *is_interruptible, + }, stage: 1, - num_stages: stage_data.len() as u32, combo: 0, - stage_data: stage_data.clone(), - initial_energy_gain: *initial_energy_gain, - max_energy_gain: *max_energy_gain, - energy_increase: *energy_increase, timer: Duration::default(), stage_section: StageSection::Buildup, next_stage: false, - speed_increase: 1.0 - *speed_increase, - max_speed_increase: *max_speed_increase - 1.0, - is_interruptible: *is_interruptible, }), CharacterAbility::LeapMelee { energy_cost: _, diff --git a/common/src/loadout_builder.rs b/common/src/loadout_builder.rs index 78807138c4..775a55c0ce 100644 --- a/common/src/loadout_builder.rs +++ b/common/src/loadout_builder.rs @@ -124,67 +124,28 @@ impl LoadoutBuilder { }; let loadout = match body { - Body::Humanoid(_) => match is_giant { - true => Loadout { - active_item, - second_item: None, - shoulder: Some(Item::new_from_asset_expect( - "common.items.armor.shoulder.plate_0", - )), - chest: Some(Item::new_from_asset_expect( - "common.items.armor.chest.plate_green_0", - )), - belt: Some(Item::new_from_asset_expect( - "common.items.armor.belt.plate_0", - )), - hand: Some(Item::new_from_asset_expect( - "common.items.armor.hand.plate_0", - )), - pants: Some(Item::new_from_asset_expect( - "common.items.armor.pants.plate_green_0", - )), - foot: Some(Item::new_from_asset_expect( - "common.items.armor.foot.plate_0", - )), - back: None, - ring: None, - neck: None, - lantern: None, - glider: None, - head: None, - tabard: None, - }, - false => match alignment { - Alignment::Npc => Loadout { + Body::Humanoid(_) => { + if is_giant { + Loadout { active_item, second_item: None, - shoulder: None, + shoulder: Some(Item::new_from_asset_expect( + "common.items.armor.shoulder.plate_0", + )), chest: Some(Item::new_from_asset_expect( - match rand::thread_rng().gen_range(0, 10) { - 0 => "common.items.armor.chest.worker_green_0", - 1 => "common.items.armor.chest.worker_green_1", - 2 => "common.items.armor.chest.worker_red_0", - 3 => "common.items.armor.chest.worker_red_1", - 4 => "common.items.armor.chest.worker_purple_0", - 5 => "common.items.armor.chest.worker_purple_1", - 6 => "common.items.armor.chest.worker_yellow_0", - 7 => "common.items.armor.chest.worker_yellow_1", - 8 => "common.items.armor.chest.worker_orange_0", - _ => "common.items.armor.chest.worker_orange_1", - }, + "common.items.armor.chest.plate_green_0", )), belt: Some(Item::new_from_asset_expect( - "common.items.armor.belt.leather_0", + "common.items.armor.belt.plate_0", + )), + hand: Some(Item::new_from_asset_expect( + "common.items.armor.hand.plate_0", )), - hand: None, pants: Some(Item::new_from_asset_expect( - "common.items.armor.pants.worker_blue_0", + "common.items.armor.pants.plate_green_0", )), foot: Some(Item::new_from_asset_expect( - match rand::thread_rng().gen_range(0, 2) { - 0 => "common.items.armor.foot.leather_0", - _ => "common.items.armor.starter.sandals_0", - }, + "common.items.armor.foot.plate_0", )), back: None, ring: None, @@ -193,40 +154,84 @@ impl LoadoutBuilder { glider: None, head: None, tabard: None, - }, - Alignment::Enemy => Loadout { - active_item, - second_item: None, - shoulder: Some(Item::new_from_asset_expect( - "common.items.armor.shoulder.cultist_shoulder_purple", - )), - chest: Some(Item::new_from_asset_expect( - "common.items.armor.chest.cultist_chest_purple", - )), - belt: Some(Item::new_from_asset_expect( - "common.items.armor.belt.cultist_belt", - )), - hand: Some(Item::new_from_asset_expect( - "common.items.armor.hand.cultist_hands_purple", - )), - pants: Some(Item::new_from_asset_expect( - "common.items.armor.pants.cultist_legs_purple", - )), - foot: Some(Item::new_from_asset_expect( - "common.items.armor.foot.cultist_boots", - )), - back: Some(Item::new_from_asset_expect( - "common.items.armor.back.dungeon_purple-0", - )), - ring: None, - neck: None, - lantern: Some(Item::new_from_asset_expect("common.items.lantern.black_0")), - glider: None, - head: None, - tabard: None, - }, - _ => LoadoutBuilder::animal(body).build(), - }, + } + } else { + match alignment { + Alignment::Npc => Loadout { + active_item, + second_item: None, + shoulder: None, + chest: Some(Item::new_from_asset_expect( + match rand::thread_rng().gen_range(0, 10) { + 0 => "common.items.armor.chest.worker_green_0", + 1 => "common.items.armor.chest.worker_green_1", + 2 => "common.items.armor.chest.worker_red_0", + 3 => "common.items.armor.chest.worker_red_1", + 4 => "common.items.armor.chest.worker_purple_0", + 5 => "common.items.armor.chest.worker_purple_1", + 6 => "common.items.armor.chest.worker_yellow_0", + 7 => "common.items.armor.chest.worker_yellow_1", + 8 => "common.items.armor.chest.worker_orange_0", + _ => "common.items.armor.chest.worker_orange_1", + }, + )), + belt: Some(Item::new_from_asset_expect( + "common.items.armor.belt.leather_0", + )), + hand: None, + pants: Some(Item::new_from_asset_expect( + "common.items.armor.pants.worker_blue_0", + )), + foot: Some(Item::new_from_asset_expect( + match rand::thread_rng().gen_range(0, 2) { + 0 => "common.items.armor.foot.leather_0", + _ => "common.items.armor.starter.sandals_0", + }, + )), + back: None, + ring: None, + neck: None, + lantern: None, + glider: None, + head: None, + tabard: None, + }, + Alignment::Enemy => Loadout { + active_item, + second_item: None, + shoulder: Some(Item::new_from_asset_expect( + "common.items.armor.shoulder.cultist_shoulder_purple", + )), + chest: Some(Item::new_from_asset_expect( + "common.items.armor.chest.cultist_chest_purple", + )), + belt: Some(Item::new_from_asset_expect( + "common.items.armor.belt.cultist_belt", + )), + hand: Some(Item::new_from_asset_expect( + "common.items.armor.hand.cultist_hands_purple", + )), + pants: Some(Item::new_from_asset_expect( + "common.items.armor.pants.cultist_legs_purple", + )), + foot: Some(Item::new_from_asset_expect( + "common.items.armor.foot.cultist_boots", + )), + back: Some(Item::new_from_asset_expect( + "common.items.armor.back.dungeon_purple-0", + )), + ring: None, + neck: None, + lantern: Some(Item::new_from_asset_expect( + "common.items.lantern.black_0", + )), + glider: None, + head: None, + tabard: None, + }, + _ => LoadoutBuilder::animal(body).build(), + } + } }, Body::Golem(golem) => match golem.species { golem::Species::StoneGolem => Loadout { diff --git a/common/src/states/combo_melee.rs b/common/src/states/combo_melee.rs index aa7417afbb..7de105803f 100644 --- a/common/src/states/combo_melee.rs +++ b/common/src/states/combo_melee.rs @@ -33,16 +33,11 @@ pub struct Stage { pub forward_movement: f32, } -/// A sequence of attacks that can incrementally become faster and more -/// damaging. #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] -pub struct Data { - /// Indicates what stage the combo is in - pub stage: u32, +/// Separated out to condense update portions of character state +pub struct StaticData { /// Indicates number of stages in combo pub num_stages: u32, - /// Number of consecutive strikes - pub combo: u32, /// Data for each stage pub stage_data: Vec, /// Initial energy gain per strike @@ -51,12 +46,6 @@ pub struct Data { pub max_energy_gain: u32, /// Energy gain increase per combo pub energy_increase: u32, - /// Timer for each stage - pub timer: Duration, - /// Checks what section a stage is in - pub stage_section: StageSection, - /// Whether the state should go onto the next stage - pub next_stage: bool, /// (100% - speed_increase) is percentage speed increases from current to /// max when combo increases pub speed_increase: f32, @@ -65,6 +54,24 @@ pub struct Data { /// Whether the state can be interrupted by other abilities pub is_interruptible: bool, } +/// A sequence of attacks that can incrementally become faster and more +/// damaging. +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +pub struct Data { + /// Struct containing data that does not change over the course of the + /// character state + pub static_data: StaticData, + /// Indicates what stage the combo is in + pub stage: u32, + /// Number of consecutive strikes + pub combo: u32, + /// Timer for each stage + pub timer: Duration, + /// Checks what section a stage is in + pub stage_section: StageSection, + /// Whether the state should go onto the next stage + pub next_stage: bool, +} impl CharacterBehavior for Data { fn behavior(&self, data: &JoinData) -> StateUpdate { @@ -76,7 +83,7 @@ impl CharacterBehavior for Data { let stage_index = (self.stage - 1) as usize; // Allows for other states to interrupt this state - if self.is_interruptible && !data.inputs.primary.is_pressed() { + if self.static_data.is_interruptible && !data.inputs.primary.is_pressed() { handle_interrupt(data, &mut update); match update.character { CharacterState::ComboMelee(_) => {}, @@ -86,211 +93,177 @@ impl CharacterBehavior for Data { } } - if self.stage_section == StageSection::Buildup - && self.timer < self.stage_data[stage_index].base_buildup_duration - { - // Build up - update.character = CharacterState::ComboMelee(Data { - stage: self.stage, - num_stages: self.num_stages, - combo: self.combo, - stage_data: self.stage_data.clone(), - initial_energy_gain: self.initial_energy_gain, - max_energy_gain: self.max_energy_gain, - energy_increase: self.energy_increase, - timer: self - .timer - .checked_add(Duration::from_secs_f32( - (1.0 + self.max_speed_increase - * (1.0 - self.speed_increase.powi(self.combo as i32))) - * data.dt.0, - )) - .unwrap_or_default(), - stage_section: self.stage_section, - next_stage: self.next_stage, - speed_increase: self.speed_increase, - max_speed_increase: self.max_speed_increase, - is_interruptible: self.is_interruptible, - }); - } else if self.stage_section == StageSection::Buildup { - // Transitions to swing section of stage - update.character = CharacterState::ComboMelee(Data { - stage: self.stage, - num_stages: self.num_stages, - combo: self.combo, - stage_data: self.stage_data.clone(), - initial_energy_gain: self.initial_energy_gain, - max_energy_gain: self.max_energy_gain, - energy_increase: self.energy_increase, - timer: Duration::default(), - stage_section: StageSection::Swing, - next_stage: self.next_stage, - speed_increase: self.speed_increase, - max_speed_increase: self.max_speed_increase, - is_interruptible: self.is_interruptible, - }); + match self.stage_section { + StageSection::Buildup => { + if self.timer < self.static_data.stage_data[stage_index].base_buildup_duration { + // Build up + update.character = CharacterState::ComboMelee(Data { + static_data: self.static_data.clone(), + stage: self.stage, + combo: self.combo, + timer: self + .timer + .checked_add(Duration::from_secs_f32( + (1.0 + self.static_data.max_speed_increase + * (1.0 + - self.static_data.speed_increase.powi(self.combo as i32))) + * data.dt.0, + )) + .unwrap_or_default(), + stage_section: self.stage_section, + next_stage: self.next_stage, + }); + } else { + // Transitions to swing section of stage + update.character = CharacterState::ComboMelee(Data { + static_data: self.static_data.clone(), + stage: self.stage, + combo: self.combo, + timer: Duration::default(), + stage_section: StageSection::Swing, + next_stage: self.next_stage, + }); - // Hit attempt - data.updater.insert(data.entity, Attacking { - base_healthchange: -((self.stage_data[stage_index].max_damage.min( - self.stage_data[stage_index].base_damage - + self.combo / self.num_stages - * self.stage_data[stage_index].damage_increase, - )) as i32), - range: self.stage_data[stage_index].range, - max_angle: self.stage_data[stage_index].angle.to_radians(), - applied: false, - hit_count: 0, - knockback: self.stage_data[stage_index].knockback, - }); - } else if self.stage_section == StageSection::Swing - && self.timer < self.stage_data[stage_index].base_swing_duration - { - // Forward movement - forward_move( - data, - &mut update, - 0.3, - self.stage_data[stage_index].forward_movement, - ); + // Hit attempt + data.updater.insert(data.entity, Attacking { + base_healthchange: -((self.static_data.stage_data[stage_index] + .max_damage + .min( + self.static_data.stage_data[stage_index].base_damage + + self.combo / self.static_data.num_stages + * self.static_data.stage_data[stage_index].damage_increase, + )) as i32), + range: self.static_data.stage_data[stage_index].range, + max_angle: self.static_data.stage_data[stage_index].angle.to_radians(), + applied: false, + hit_count: 0, + knockback: self.static_data.stage_data[stage_index].knockback, + }); + } + }, + StageSection::Swing => { + if self.timer < self.static_data.stage_data[stage_index].base_swing_duration { + // Forward movement + forward_move( + data, + &mut update, + 0.3, + self.static_data.stage_data[stage_index].forward_movement, + ); - // Swings - update.character = CharacterState::ComboMelee(Data { - stage: self.stage, - num_stages: self.num_stages, - combo: self.combo, - stage_data: self.stage_data.clone(), - initial_energy_gain: self.initial_energy_gain, - max_energy_gain: self.max_energy_gain, - energy_increase: self.energy_increase, - timer: self - .timer - .checked_add(Duration::from_secs_f32( - (1.0 + self.max_speed_increase - * (1.0 - self.speed_increase.powi(self.combo as i32))) - * data.dt.0, - )) - .unwrap_or_default(), - stage_section: self.stage_section, - next_stage: self.next_stage, - speed_increase: self.speed_increase, - max_speed_increase: self.max_speed_increase, - is_interruptible: self.is_interruptible, - }); - } else if self.stage_section == StageSection::Swing { - // Transitions to recover section of stage - update.character = CharacterState::ComboMelee(Data { - stage: self.stage, - num_stages: self.num_stages, - combo: self.combo, - stage_data: self.stage_data.clone(), - initial_energy_gain: self.initial_energy_gain, - max_energy_gain: self.max_energy_gain, - energy_increase: self.energy_increase, - timer: Duration::default(), - stage_section: StageSection::Recover, - next_stage: self.next_stage, - speed_increase: self.speed_increase, - max_speed_increase: self.max_speed_increase, - is_interruptible: self.is_interruptible, - }); - } else if self.stage_section == StageSection::Recover - && self.timer < self.stage_data[stage_index].base_recover_duration - { - // Recovers - if data.inputs.primary.is_pressed() { - // Checks if state will transition to next stage after recover - update.character = CharacterState::ComboMelee(Data { - stage: self.stage, - num_stages: self.num_stages, - combo: self.combo, - stage_data: self.stage_data.clone(), - initial_energy_gain: self.initial_energy_gain, - max_energy_gain: self.max_energy_gain, - energy_increase: self.energy_increase, - timer: self - .timer - .checked_add(Duration::from_secs_f32( - (1.0 + self.max_speed_increase - * (1.0 - self.speed_increase.powi(self.combo as i32))) - * data.dt.0, - )) - .unwrap_or_default(), - stage_section: self.stage_section, - next_stage: true, - speed_increase: self.speed_increase, - max_speed_increase: self.max_speed_increase, - is_interruptible: self.is_interruptible, - }); - } else { - update.character = CharacterState::ComboMelee(Data { - stage: self.stage, - num_stages: self.num_stages, - combo: self.combo, - stage_data: self.stage_data.clone(), - initial_energy_gain: self.initial_energy_gain, - max_energy_gain: self.max_energy_gain, - energy_increase: self.energy_increase, - timer: self - .timer - .checked_add(Duration::from_secs_f32( - (1.0 + self.max_speed_increase - * (1.0 - self.speed_increase.powi(self.combo as i32))) - * data.dt.0, - )) - .unwrap_or_default(), - stage_section: self.stage_section, - next_stage: self.next_stage, - speed_increase: self.speed_increase, - max_speed_increase: self.max_speed_increase, - is_interruptible: self.is_interruptible, - }); - } - } else if self.next_stage { - // Transitions to buildup section of next stage - update.character = CharacterState::ComboMelee(Data { - stage: (self.stage % self.num_stages) + 1, - num_stages: self.num_stages, - combo: self.combo, - stage_data: self.stage_data.clone(), - initial_energy_gain: self.initial_energy_gain, - max_energy_gain: self.max_energy_gain, - energy_increase: self.energy_increase, - timer: Duration::default(), - stage_section: StageSection::Buildup, - next_stage: false, - speed_increase: self.speed_increase, - max_speed_increase: self.max_speed_increase, - is_interruptible: self.is_interruptible, - }); - } else { - // Done - update.character = CharacterState::Wielding; - // Make sure attack component is removed - data.updater.remove::(data.entity); + // Swings + update.character = CharacterState::ComboMelee(Data { + static_data: self.static_data.clone(), + stage: self.stage, + combo: self.combo, + timer: self + .timer + .checked_add(Duration::from_secs_f32( + (1.0 + self.static_data.max_speed_increase + * (1.0 + - self.static_data.speed_increase.powi(self.combo as i32))) + * data.dt.0, + )) + .unwrap_or_default(), + stage_section: self.stage_section, + next_stage: self.next_stage, + }); + } else { + // Transitions to recover section of stage + update.character = CharacterState::ComboMelee(Data { + static_data: self.static_data.clone(), + stage: self.stage, + combo: self.combo, + timer: Duration::default(), + stage_section: StageSection::Recover, + next_stage: self.next_stage, + }); + } + }, + StageSection::Recover => { + if self.timer < self.static_data.stage_data[stage_index].base_recover_duration { + // Recovers + if data.inputs.primary.is_pressed() { + // Checks if state will transition to next stage after recover + update.character = CharacterState::ComboMelee(Data { + static_data: self.static_data.clone(), + stage: self.stage, + combo: self.combo, + timer: self + .timer + .checked_add(Duration::from_secs_f32( + (1.0 + self.static_data.max_speed_increase + * (1.0 + - self + .static_data + .speed_increase + .powi(self.combo as i32))) + * data.dt.0, + )) + .unwrap_or_default(), + stage_section: self.stage_section, + next_stage: true, + }); + } else { + update.character = CharacterState::ComboMelee(Data { + static_data: self.static_data.clone(), + stage: self.stage, + combo: self.combo, + timer: self + .timer + .checked_add(Duration::from_secs_f32( + (1.0 + self.static_data.max_speed_increase + * (1.0 + - self + .static_data + .speed_increase + .powi(self.combo as i32))) + * data.dt.0, + )) + .unwrap_or_default(), + stage_section: self.stage_section, + next_stage: self.next_stage, + }); + } + } else if self.next_stage { + // Transitions to buildup section of next stage + update.character = CharacterState::ComboMelee(Data { + static_data: self.static_data.clone(), + stage: (self.stage % self.static_data.num_stages) + 1, + combo: self.combo, + timer: Duration::default(), + stage_section: StageSection::Buildup, + next_stage: false, + }); + } else { + // Done + update.character = CharacterState::Wielding; + // Make sure attack component is removed + data.updater.remove::(data.entity); + } + }, + _ => { + // If it somehow ends up in an incorrect stage section + update.character = CharacterState::Wielding; + // Make sure attack component is removed + data.updater.remove::(data.entity); + }, } // Grant energy on successful hit if let Some(attack) = data.attacking { if attack.applied && attack.hit_count > 0 { - let energy = self - .max_energy_gain - .min(self.initial_energy_gain + self.combo * self.energy_increase) - as i32; + let energy = self.static_data.max_energy_gain.min( + self.static_data.initial_energy_gain + + self.combo * self.static_data.energy_increase, + ) as i32; update.character = CharacterState::ComboMelee(Data { + static_data: self.static_data.clone(), stage: self.stage, - num_stages: self.num_stages, combo: self.combo + 1, - stage_data: self.stage_data.clone(), - initial_energy_gain: self.initial_energy_gain, - max_energy_gain: self.max_energy_gain, - energy_increase: self.energy_increase, timer: self.timer, stage_section: self.stage_section, next_stage: self.next_stage, - speed_increase: self.speed_increase, - max_speed_increase: self.max_speed_increase, - is_interruptible: self.is_interruptible, }); data.updater.remove::(data.entity); update.energy.change_by(energy, EnergySource::HitEnemy); diff --git a/common/src/states/dash_melee.rs b/common/src/states/dash_melee.rs index 4e9d8d15ca..ce120d68e2 100644 --- a/common/src/states/dash_melee.rs +++ b/common/src/states/dash_melee.rs @@ -73,86 +73,10 @@ impl CharacterBehavior for Data { } } - if self.stage_section == StageSection::Buildup - && self.timer < self.static_data.buildup_duration - { - // Build up - update.character = CharacterState::DashMelee(Data { - static_data: self.static_data, - end_charge: self.end_charge, - timer: self - .timer - .checked_add(Duration::from_secs_f32(data.dt.0)) - .unwrap_or_default(), - stage_section: self.stage_section, - exhausted: self.exhausted, - }) - } else if self.stage_section == StageSection::Buildup { - // Transitions to charge section of stage - update.character = CharacterState::DashMelee(Data { - static_data: self.static_data, - end_charge: self.end_charge, - timer: Duration::default(), - stage_section: StageSection::Charge, - exhausted: self.exhausted, - }) - } else if self.stage_section == StageSection::Charge - && (self.timer < self.static_data.charge_duration - || (self.static_data.infinite_charge && data.inputs.secondary.is_pressed())) - && update.energy.current() > 0 - && !self.end_charge - { - // Forward movement - forward_move(data, &mut update, 0.1, self.static_data.forward_speed); - - // Hit attempt (also checks if player is moving) - if !self.exhausted && update.vel.0.distance_squared(Vec3::zero()) > 1.0 { - let charge_frac = (self.timer.as_secs_f32() - / self.static_data.charge_duration.as_secs_f32()) - .min(1.0); - let damage = (self.static_data.max_damage as f32 - - self.static_data.base_damage as f32) - * charge_frac - + self.static_data.base_damage as f32; - let knockback = (self.static_data.max_knockback - self.static_data.base_knockback) - * charge_frac - + self.static_data.base_knockback; - data.updater.insert(data.entity, Attacking { - base_healthchange: -damage as i32, - range: self.static_data.range, - max_angle: self.static_data.angle.to_radians(), - applied: false, - hit_count: 0, - knockback, - }); - } - - // 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 { - update.character = CharacterState::DashMelee(Data { - static_data: self.static_data, - end_charge: self.end_charge, - timer: self - .timer - .checked_add(Duration::from_secs_f32(data.dt.0)) - .unwrap_or_default(), - stage_section: StageSection::Charge, - exhausted: true, - }) - } else if let Some(attack) = data.attacking { - if attack.applied && attack.hit_count > 0 { - update.character = CharacterState::DashMelee(Data { - static_data: self.static_data, - end_charge: !self.static_data.infinite_charge, - timer: self - .timer - .checked_add(Duration::from_secs_f32(data.dt.0)) - .unwrap_or_default(), - stage_section: StageSection::Charge, - exhausted: false, - }) - } else if attack.applied { + match self.stage_section { + StageSection::Buildup => { + if self.timer < self.static_data.buildup_duration { + // Build up update.character = CharacterState::DashMelee(Data { static_data: self.static_data, end_charge: self.end_charge, @@ -160,90 +84,173 @@ impl CharacterBehavior for Data { .timer .checked_add(Duration::from_secs_f32(data.dt.0)) .unwrap_or_default(), - stage_section: StageSection::Charge, - exhausted: false, - }) + stage_section: self.stage_section, + exhausted: self.exhausted, + }); } else { + // Transitions to charge section of stage update.character = CharacterState::DashMelee(Data { static_data: self.static_data, - end_charge: !self.static_data.infinite_charge, + end_charge: self.end_charge, + timer: Duration::default(), + stage_section: StageSection::Charge, + exhausted: self.exhausted, + }); + } + }, + StageSection::Charge => { + if (self.timer < self.static_data.charge_duration + || (self.static_data.infinite_charge && data.inputs.secondary.is_pressed())) + && update.energy.current() > 0 + && !self.end_charge + { + // Forward movement + forward_move(data, &mut update, 0.1, self.static_data.forward_speed); + + // Hit attempt (also checks if player is moving) + if !self.exhausted && update.vel.0.distance_squared(Vec3::zero()) > 1.0 { + let charge_frac = (self.timer.as_secs_f32() + / self.static_data.charge_duration.as_secs_f32()) + .min(1.0); + let damage = (self.static_data.max_damage as f32 + - self.static_data.base_damage as f32) + * charge_frac + + self.static_data.base_damage as f32; + let knockback = (self.static_data.max_knockback + - self.static_data.base_knockback) + * charge_frac + + self.static_data.base_knockback; + data.updater.insert(data.entity, Attacking { + base_healthchange: -damage as i32, + range: self.static_data.range, + max_angle: self.static_data.angle.to_radians(), + applied: false, + hit_count: 0, + knockback, + }); + } + + // 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 { + update.character = CharacterState::DashMelee(Data { + static_data: self.static_data, + end_charge: self.end_charge, + timer: self + .timer + .checked_add(Duration::from_secs_f32(data.dt.0)) + .unwrap_or_default(), + stage_section: StageSection::Charge, + exhausted: true, + }) + } else if let Some(attack) = data.attacking { + if attack.applied && attack.hit_count > 0 { + update.character = CharacterState::DashMelee(Data { + static_data: self.static_data, + end_charge: !self.static_data.infinite_charge, + timer: self + .timer + .checked_add(Duration::from_secs_f32(data.dt.0)) + .unwrap_or_default(), + stage_section: StageSection::Charge, + exhausted: false, + }) + } else if attack.applied { + update.character = CharacterState::DashMelee(Data { + static_data: self.static_data, + end_charge: self.end_charge, + timer: self + .timer + .checked_add(Duration::from_secs_f32(data.dt.0)) + .unwrap_or_default(), + stage_section: StageSection::Charge, + exhausted: false, + }) + } else { + update.character = CharacterState::DashMelee(Data { + static_data: self.static_data, + end_charge: !self.static_data.infinite_charge, + timer: self + .timer + .checked_add(Duration::from_secs_f32(data.dt.0)) + .unwrap_or_default(), + stage_section: StageSection::Charge, + exhausted: self.exhausted, + }) + } + } else { + update.character = CharacterState::DashMelee(Data { + static_data: self.static_data, + end_charge: !self.static_data.infinite_charge, + timer: self + .timer + .checked_add(Duration::from_secs_f32(data.dt.0)) + .unwrap_or_default(), + stage_section: StageSection::Charge, + exhausted: self.exhausted, + }) + } + + // Consumes energy if there's enough left and charge has not stopped + update.energy.change_by( + -(self.static_data.energy_drain as f32 * data.dt.0) as i32, + EnergySource::Ability, + ); + } else { + // Transitions to swing section of stage + update.character = CharacterState::DashMelee(Data { + static_data: self.static_data, + end_charge: self.end_charge, + timer: Duration::default(), + stage_section: StageSection::Swing, + exhausted: self.exhausted, + }); + } + }, + StageSection::Swing => { + if self.timer < self.static_data.swing_duration { + // Swings + update.character = CharacterState::DashMelee(Data { + static_data: self.static_data, + end_charge: self.end_charge, timer: self .timer .checked_add(Duration::from_secs_f32(data.dt.0)) .unwrap_or_default(), - stage_section: StageSection::Charge, + stage_section: self.stage_section, exhausted: self.exhausted, - }) + }); + } else { + // Transitions to recover section of stage + update.character = CharacterState::DashMelee(Data { + static_data: self.static_data, + end_charge: self.end_charge, + timer: Duration::default(), + stage_section: StageSection::Recover, + exhausted: self.exhausted, + }); } - } else { - update.character = CharacterState::DashMelee(Data { - static_data: self.static_data, - end_charge: !self.static_data.infinite_charge, - timer: self - .timer - .checked_add(Duration::from_secs_f32(data.dt.0)) - .unwrap_or_default(), - stage_section: StageSection::Charge, - exhausted: self.exhausted, - }) - } - - // Consumes energy if there's enough left and charge has not stopped - update.energy.change_by( - -(self.static_data.energy_drain as f32 * data.dt.0) as i32, - EnergySource::Ability, - ); - } else if self.stage_section == StageSection::Charge { - // Transitions to swing section of stage - update.character = CharacterState::DashMelee(Data { - static_data: self.static_data, - end_charge: self.end_charge, - timer: Duration::default(), - stage_section: StageSection::Swing, - exhausted: self.exhausted, - }) - } else if self.stage_section == StageSection::Swing - && self.timer < self.static_data.swing_duration - { - // Swings - update.character = CharacterState::DashMelee(Data { - static_data: self.static_data, - end_charge: self.end_charge, - timer: self - .timer - .checked_add(Duration::from_secs_f32(data.dt.0)) - .unwrap_or_default(), - stage_section: self.stage_section, - exhausted: self.exhausted, - }) - } else if self.stage_section == StageSection::Swing { - // Transitions to recover section of stage - update.character = CharacterState::DashMelee(Data { - static_data: self.static_data, - end_charge: self.end_charge, - timer: Duration::default(), - stage_section: StageSection::Recover, - exhausted: self.exhausted, - }) - } else if self.stage_section == StageSection::Recover - && self.timer < self.static_data.recover_duration - { - // Recover - update.character = CharacterState::DashMelee(Data { - static_data: self.static_data, - end_charge: self.end_charge, - timer: self - .timer - .checked_add(Duration::from_secs_f32(data.dt.0)) - .unwrap_or_default(), - stage_section: self.stage_section, - exhausted: self.exhausted, - }) - } else { - // Done - update.character = CharacterState::Wielding; - // Make sure attack component is removed - data.updater.remove::(data.entity); + }, + StageSection::Recover => { + if self.timer < self.static_data.recover_duration { + // Recover + update.character = CharacterState::DashMelee(Data { + static_data: self.static_data, + end_charge: self.end_charge, + timer: self + .timer + .checked_add(Duration::from_secs_f32(data.dt.0)) + .unwrap_or_default(), + stage_section: self.stage_section, + exhausted: self.exhausted, + }); + } else { + // Done + update.character = CharacterState::Wielding; + // Make sure attack component is removed + data.updater.remove::(data.entity); + } + }, } update diff --git a/common/src/states/spin_melee.rs b/common/src/states/spin_melee.rs index 8f1b8a8a27..dd1064cb44 100644 --- a/common/src/states/spin_melee.rs +++ b/common/src/states/spin_melee.rs @@ -70,114 +70,124 @@ impl CharacterBehavior for Data { } } - if self.stage_section == StageSection::Buildup - && self.timer < self.static_data.buildup_duration - { - // Build up - update.character = CharacterState::SpinMelee(Data { - static_data: self.static_data, - timer: self - .timer - .checked_add(Duration::from_secs_f32(data.dt.0)) - .unwrap_or_default(), - spins_remaining: self.spins_remaining, - stage_section: self.stage_section, - exhausted: self.exhausted, - }); - } else if self.stage_section == StageSection::Buildup { - // Transitions to swing section of stage - update.character = CharacterState::SpinMelee(Data { - static_data: self.static_data, - timer: Duration::default(), - spins_remaining: self.spins_remaining, - stage_section: StageSection::Swing, - exhausted: self.exhausted, - }); - } else if !self.exhausted { - update.character = CharacterState::SpinMelee(Data { - static_data: self.static_data, - timer: Duration::default(), - spins_remaining: self.spins_remaining, - stage_section: self.stage_section, - exhausted: true, - }); - // Hit attempt - data.updater.insert(data.entity, Attacking { - base_healthchange: -(self.static_data.base_damage as i32), - range: self.static_data.range, - max_angle: 180_f32.to_radians(), - applied: false, - hit_count: 0, - knockback: self.static_data.knockback, - }); - } else if self.stage_section == StageSection::Swing - && self.timer < self.static_data.swing_duration - { - if !self.static_data.is_helicopter { - forward_move(data, &mut update, 0.1, self.static_data.forward_speed); - handle_orientation(data, &mut update, 1.0); - } + match self.stage_section { + StageSection::Buildup => { + if self.timer < self.static_data.buildup_duration { + // Build up + update.character = CharacterState::SpinMelee(Data { + static_data: self.static_data, + timer: self + .timer + .checked_add(Duration::from_secs_f32(data.dt.0)) + .unwrap_or_default(), + spins_remaining: self.spins_remaining, + stage_section: self.stage_section, + exhausted: self.exhausted, + }); + } else { + // Transitions to swing section of stage + update.character = CharacterState::SpinMelee(Data { + static_data: self.static_data, + timer: Duration::default(), + spins_remaining: self.spins_remaining, + stage_section: StageSection::Swing, + exhausted: self.exhausted, + }); + } + }, + StageSection::Swing => { + if !self.exhausted { + update.character = CharacterState::SpinMelee(Data { + static_data: self.static_data, + timer: Duration::default(), + spins_remaining: self.spins_remaining, + stage_section: self.stage_section, + exhausted: true, + }); + // Hit attempt + data.updater.insert(data.entity, Attacking { + base_healthchange: -(self.static_data.base_damage as i32), + range: self.static_data.range, + max_angle: 180_f32.to_radians(), + applied: false, + hit_count: 0, + knockback: self.static_data.knockback, + }); + } else if self.timer < self.static_data.swing_duration { + if !self.static_data.is_helicopter { + forward_move(data, &mut update, 0.1, self.static_data.forward_speed); + handle_orientation(data, &mut update, 1.0); + } - // Swings - update.character = CharacterState::SpinMelee(Data { - static_data: self.static_data, - timer: self - .timer - .checked_add(Duration::from_secs_f32(data.dt.0)) - .unwrap_or_default(), - spins_remaining: self.spins_remaining, - stage_section: self.stage_section, - exhausted: self.exhausted, - }); - } else if update.energy.current() >= self.static_data.energy_cost - && (self.spins_remaining != 0 - || (self.static_data.is_infinite && data.inputs.secondary.is_pressed())) - { - let new_spins_remaining = if self.static_data.is_infinite { - self.spins_remaining - } else { - self.spins_remaining - 1 - }; - update.character = CharacterState::SpinMelee(Data { - static_data: self.static_data, - timer: Duration::default(), - spins_remaining: new_spins_remaining, - stage_section: self.stage_section, - exhausted: false, - }); - // Consumes energy if there's enough left and RMB is held down - update.energy.change_by( - -(self.static_data.energy_cost as i32), - EnergySource::Ability, - ); - } else if self.stage_section == StageSection::Swing { - // Transitions to recover section of stage - update.character = CharacterState::SpinMelee(Data { - static_data: self.static_data, - timer: Duration::default(), - spins_remaining: self.spins_remaining, - stage_section: StageSection::Recover, - exhausted: self.exhausted, - }) - } else if self.stage_section == StageSection::Recover - && self.timer < self.static_data.recover_duration - { - // Recover - update.character = CharacterState::SpinMelee(Data { - static_data: self.static_data, - timer: self - .timer - .checked_add(Duration::from_secs_f32(data.dt.0)) - .unwrap_or_default(), - spins_remaining: self.spins_remaining, - stage_section: self.stage_section, - exhausted: self.exhausted, - }) - } else { - // Done - update.character = CharacterState::Wielding; - // Make sure attack component is removed - data.updater.remove::(data.entity); + // Swings + update.character = CharacterState::SpinMelee(Data { + static_data: self.static_data, + timer: self + .timer + .checked_add(Duration::from_secs_f32(data.dt.0)) + .unwrap_or_default(), + spins_remaining: self.spins_remaining, + stage_section: self.stage_section, + exhausted: self.exhausted, + }); + } else if update.energy.current() >= self.static_data.energy_cost + && (self.spins_remaining != 0 + || (self.static_data.is_infinite && data.inputs.secondary.is_pressed())) + { + let new_spins_remaining = if self.static_data.is_infinite { + self.spins_remaining + } else { + self.spins_remaining - 1 + }; + update.character = CharacterState::SpinMelee(Data { + static_data: self.static_data, + timer: Duration::default(), + spins_remaining: new_spins_remaining, + stage_section: self.stage_section, + exhausted: false, + }); + // Consumes energy if there's enough left and RMB is held down + update.energy.change_by( + -(self.static_data.energy_cost as i32), + EnergySource::Ability, + ); + } else { + // Transitions to recover section of stage + update.character = CharacterState::SpinMelee(Data { + static_data: self.static_data, + timer: Duration::default(), + spins_remaining: self.spins_remaining, + stage_section: StageSection::Recover, + exhausted: self.exhausted, + }); + } + }, + StageSection::Recover => { + if self.timer < self.static_data.recover_duration { + // Recover + update.character = CharacterState::SpinMelee(Data { + static_data: self.static_data, + timer: self + .timer + .checked_add(Duration::from_secs_f32(data.dt.0)) + .unwrap_or_default(), + spins_remaining: self.spins_remaining, + stage_section: self.stage_section, + exhausted: self.exhausted, + }); + } else { + // Done + update.character = CharacterState::Wielding; + // Make sure attack component is removed + data.updater.remove::(data.entity); + } + }, + _ => { + // If it somehow ends up in an incorrect stage section + update.character = CharacterState::Wielding; + // Make sure attack component is removed + data.updater.remove::(data.entity); + }, } update diff --git a/common/src/sys/phys.rs b/common/src/sys/phys.rs index 214124291f..c1e11b7a0b 100644 --- a/common/src/sys/phys.rs +++ b/common/src/sys/phys.rs @@ -193,10 +193,6 @@ impl<'a> System<'a> for Sys { continue; } - if entity_other == entity { - continue; - } - let scale_other = scale_other.map(|s| s.0).unwrap_or(1.0); let radius_other = collider_other.map(|c| c.get_radius()).unwrap_or(0.5); let z_limits_other = collider_other diff --git a/voxygen/src/audio/sfx/event_mapper/combat/tests.rs b/voxygen/src/audio/sfx/event_mapper/combat/tests.rs index ba71f492a9..ad03ea0ea5 100644 --- a/voxygen/src/audio/sfx/event_mapper/combat/tests.rs +++ b/voxygen/src/audio/sfx/event_mapper/combat/tests.rs @@ -114,31 +114,33 @@ fn matches_ability_stage() { let result = CombatEventMapper::map_event( &CharacterState::ComboMelee(states::combo_melee::Data { + static_data: states::combo_melee::StaticData { + num_stages: 1, + stage_data: vec![states::combo_melee::Stage { + stage: 1, + base_damage: 100, + max_damage: 120, + damage_increase: 10, + knockback: 10.0, + range: 4.0, + angle: 30.0, + base_buildup_duration: Duration::from_millis(500), + base_swing_duration: Duration::from_millis(200), + base_recover_duration: Duration::from_millis(400), + forward_movement: 0.5, + }], + initial_energy_gain: 0, + max_energy_gain: 100, + energy_increase: 20, + speed_increase: 0.05, + max_speed_increase: 1.8, + is_interruptible: true, + }, stage: 1, - num_stages: 1, combo: 0, - stage_data: vec![states::combo_melee::Stage { - stage: 1, - base_damage: 100, - max_damage: 120, - damage_increase: 10, - knockback: 10.0, - range: 4.0, - angle: 30.0, - base_buildup_duration: Duration::from_millis(500), - base_swing_duration: Duration::from_millis(200), - base_recover_duration: Duration::from_millis(400), - forward_movement: 0.5, - }], - initial_energy_gain: 0, - max_energy_gain: 100, - energy_increase: 20, timer: Duration::default(), stage_section: states::utils::StageSection::Swing, next_stage: false, - speed_increase: 0.05, - max_speed_increase: 1.8, - is_interruptible: true, }), &PreviousEntityState { event: SfxEvent::Idle, @@ -172,31 +174,33 @@ fn ignores_different_ability_stage() { let result = CombatEventMapper::map_event( &CharacterState::ComboMelee(states::combo_melee::Data { + static_data: states::combo_melee::StaticData { + num_stages: 1, + stage_data: vec![states::combo_melee::Stage { + stage: 1, + base_damage: 100, + max_damage: 120, + damage_increase: 10, + knockback: 10.0, + range: 4.0, + angle: 30.0, + base_buildup_duration: Duration::from_millis(500), + base_swing_duration: Duration::from_millis(200), + base_recover_duration: Duration::from_millis(400), + forward_movement: 0.5, + }], + initial_energy_gain: 0, + max_energy_gain: 100, + energy_increase: 20, + speed_increase: 0.05, + max_speed_increase: 1.8, + is_interruptible: true, + }, stage: 1, - num_stages: 1, combo: 0, - stage_data: vec![states::combo_melee::Stage { - stage: 1, - base_damage: 100, - max_damage: 120, - damage_increase: 10, - knockback: 10.0, - range: 4.0, - angle: 30.0, - base_buildup_duration: Duration::from_millis(500), - base_swing_duration: Duration::from_millis(200), - base_recover_duration: Duration::from_millis(400), - forward_movement: 0.5, - }], - initial_energy_gain: 0, - max_energy_gain: 100, - energy_increase: 20, timer: Duration::default(), stage_section: states::utils::StageSection::Swing, next_stage: false, - speed_increase: 0.05, - max_speed_increase: 1.8, - is_interruptible: true, }), &PreviousEntityState { event: SfxEvent::Idle, diff --git a/voxygen/src/hud/img_ids.rs b/voxygen/src/hud/img_ids.rs index 29b35d13f6..0b12a0696b 100644 --- a/voxygen/src/hud/img_ids.rs +++ b/voxygen/src/hud/img_ids.rs @@ -267,7 +267,7 @@ image_ids! { fire_spell_1: "voxygen.element.icons.fire_spell_0", snake_arrow_0: "voxygen.element.icons.snake", heal_0: "voxygen.element.icons.heal_0", - sowrd_whirlwind: "voxygen.element.icons.sword_whirlwind", + sword_whirlwind: "voxygen.element.icons.sword_whirlwind", // Buttons button: "voxygen.element.buttons.button", diff --git a/voxygen/src/hud/slots.rs b/voxygen/src/hud/slots.rs index 13113cc5d3..33b6c6efc4 100644 --- a/voxygen/src/hud/slots.rs +++ b/voxygen/src/hud/slots.rs @@ -145,7 +145,7 @@ impl<'a> SlotKey, HotbarImageSource<'a>> for HotbarSlot { HotbarImage::Item(key) => item_imgs.img_id_or_not_found_img(key.clone()), HotbarImage::SnakeArrow => imgs.snake_arrow_0, HotbarImage::Fireball => imgs.fire_spell_1, - HotbarImage::SwordWhirlwind => imgs.sowrd_whirlwind, + HotbarImage::SwordWhirlwind => imgs.sword_whirlwind, } } } diff --git a/voxygen/src/scene/figure/mod.rs b/voxygen/src/scene/figure/mod.rs index 52228dd073..12ba45ec99 100644 --- a/voxygen/src/scene/figure/mod.rs +++ b/voxygen/src/scene/figure/mod.rs @@ -978,19 +978,19 @@ impl FigureMgr { let stage_progress = match s.stage_section { StageSection::Buildup => { stage_time - / s.stage_data[stage_index] + / s.static_data.stage_data[stage_index] .base_buildup_duration .as_secs_f64() }, StageSection::Swing => { stage_time - / s.stage_data[stage_index] + / s.static_data.stage_data[stage_index] .base_swing_duration .as_secs_f64() }, StageSection::Recover => { stage_time - / s.stage_data[stage_index] + / s.static_data.stage_data[stage_index] .base_recover_duration .as_secs_f64() },