diff --git a/common/src/comp/ability.rs b/common/src/comp/ability.rs index 3e93926b3a..e631e197ad 100644 --- a/common/src/comp/ability.rs +++ b/common/src/comp/ability.rs @@ -36,6 +36,9 @@ pub enum CharacterAbility { recover_duration: Duration, base_damage: u32, }, + TripleStrike { + base_damage: u32, + }, } impl CharacterAbility { @@ -146,6 +149,14 @@ impl From<&CharacterAbility> for CharacterState { stage_time_active: Duration::default(), base_damage: *base_damage, }), + CharacterAbility::TripleStrike { base_damage } => { + CharacterState::TripleStrike(triple_strike::Data { + base_damage: *base_damage, + stage: 0, + stage_exhausted: false, + stage_time_active: Duration::default(), + }) + }, } } } diff --git a/common/src/comp/character_state.rs b/common/src/comp/character_state.rs index 480f937afa..7d0fb6cc9b 100644 --- a/common/src/comp/character_state.rs +++ b/common/src/comp/character_state.rs @@ -64,6 +64,13 @@ impl CharacterState { } } + pub fn can_swap(&self) -> bool { + match self { + CharacterState::Wielding => true, + _ => false, + } + } + pub fn is_attack(&self) -> bool { match self { CharacterState::BasicMelee(_) diff --git a/common/src/comp/inventory/item.rs b/common/src/comp/inventory/item.rs index 00c35348e3..4963218807 100644 --- a/common/src/comp/inventory/item.rs +++ b/common/src/comp/inventory/item.rs @@ -69,11 +69,12 @@ impl ToolData { match self.kind { Sword(_) => vec![ - BasicMelee { - buildup_duration: Duration::from_millis(100), - recover_duration: Duration::from_millis(500), - base_damage: 6, - }, + // BasicMelee { + // buildup_duration: Duration::from_millis(100), + // recover_duration: Duration::from_millis(500), + // base_damage: 6, + // }, + CharacterAbility::TripleStrike { base_damage: 7 }, DashMelee { buildup_duration: Duration::from_millis(500), recover_duration: Duration::from_millis(500), diff --git a/common/src/states/triple_strike.rs b/common/src/states/triple_strike.rs index 2fe224f265..4dddbd629f 100644 --- a/common/src/states/triple_strike.rs +++ b/common/src/states/triple_strike.rs @@ -1,13 +1,16 @@ use crate::{ - comp::{StateUpdate, ToolData}, + comp::{Attacking, CharacterState, EnergySource, StateUpdate}, states::utils::*, sys::character_behavior::{CharacterBehavior, JoinData}, }; use std::{collections::VecDeque, time::Duration}; +use vek::vec::Vec2; // In millis const STAGE_DURATION: u64 = 600; +const BASE_ACCEL: f32 = 200.0; +const BASE_SPEED: f32 = 250.0; /// ### A sequence of 3 incrementally increasing attacks. /// /// While holding down the `primary` button, perform a series of 3 attacks, @@ -17,13 +20,13 @@ const STAGE_DURATION: u64 = 600; #[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize, Eq, Hash)] pub struct Data { /// The tool this state will read to handle damage, etc. - pub tool: ToolData, + pub base_damage: u32, /// `int` denoting what stage (of 3) the attack is in. pub stage: i8, /// How long current stage has been active pub stage_time_active: Duration, /// Whether current stage has exhausted its attack - stage_exhausted: bool, + pub stage_exhausted: bool, } impl CharacterBehavior for Data { @@ -38,7 +41,6 @@ impl CharacterBehavior for Data { server_events: VecDeque::new(), }; - let new_stage_exhausted = self.stage_exhausted; let new_stage_time_active = self .stage_time_active .checked_add(Duration::from_secs_f32(data.dt.0)) @@ -46,19 +48,83 @@ impl CharacterBehavior for Data { // If player stops holding input, if !data.inputs.primary.is_pressed() { - attempt_wield(data, &mut update); + // Done + update.character = CharacterState::Wielding; + // Make sure attack component is removed + data.updater.remove::(data.entity); return update; } if self.stage < 3 { if new_stage_time_active < Duration::from_millis(STAGE_DURATION / 3) { // Move player forward while in first third of each stage - handle_move(data, &mut update); + // Move player according to move_dir + if update.vel.0.magnitude_squared() < BASE_SPEED.powf(2.0) { + update.vel.0 = + update.vel.0 + Vec2::broadcast(data.dt.0) * data.ori.0 * BASE_ACCEL; + let mag2 = update.vel.0.magnitude_squared(); + if mag2 > BASE_SPEED.powf(2.0) { + update.vel.0 = update.vel.0.normalized() * BASE_SPEED; + } + }; + + update.character = CharacterState::TripleStrike(Data { + base_damage: self.base_damage, + stage: self.stage, + stage_time_active: new_stage_time_active, + stage_exhausted: false, + }); } else if new_stage_time_active > Duration::from_millis(STAGE_DURATION / 2) - && !new_stage_exhausted + && !self.stage_exhausted { + // Allow player to influence orientation a little + handle_move(data, &mut update); + // Try to deal damage in second half of stage - // TODO: deal damage + data.updater.insert(data.entity, Attacking { + base_damage: self.base_damage * (self.stage as u32 + 1), + max_angle: 180_f32.to_radians(), + applied: false, + hit_count: 0, + }); + + update.character = CharacterState::TripleStrike(Data { + base_damage: self.base_damage, + stage: self.stage, + stage_time_active: new_stage_time_active, + stage_exhausted: true, + }); + } else if new_stage_time_active > Duration::from_millis(STAGE_DURATION) { + // Allow player to influence orientation a little + handle_move(data, &mut update); + + update.character = CharacterState::TripleStrike(Data { + base_damage: self.base_damage, + stage: self.stage + 1, + stage_time_active: Duration::default(), + stage_exhausted: false, + }); + } else { + update.character = CharacterState::TripleStrike(Data { + base_damage: self.base_damage, + stage: self.stage, + stage_time_active: new_stage_time_active, + stage_exhausted: self.stage_exhausted, + }); + } + } 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 { + data.updater.remove::(data.entity); + update.energy.change_by(100, EnergySource::HitEnemy); + 4 } } diff --git a/voxygen/src/scene/figure/mod.rs b/voxygen/src/scene/figure/mod.rs index da537888b8..aca487e7c2 100644 --- a/voxygen/src/scene/figure/mod.rs +++ b/voxygen/src/scene/figure/mod.rs @@ -504,6 +504,22 @@ impl FigureMgr { skeleton_attr, ) }, + CharacterState::TripleStrike(s) => match s.stage { + 0 | 2 => anim::character::AttackAnimation::update_skeleton( + &target_base, + (active_tool_kind, time), + state.state_time, + &mut state_animation_rate, + skeleton_attr, + ), + _ => anim::character::ChargeAnimation::update_skeleton( + &target_base, + (active_tool_kind, time), + state.state_time, + &mut state_animation_rate, + skeleton_attr, + ), + }, CharacterState::TimedCombo(s) => match s.stage { 0 | 2 => anim::character::AttackAnimation::update_skeleton( &target_base,