diff --git a/common/src/comp/ability.rs b/common/src/comp/ability.rs index 9210ee6b02..05fadd2ab4 100644 --- a/common/src/comp/ability.rs +++ b/common/src/comp/ability.rs @@ -5,6 +5,7 @@ pub enum AbilityState { BasicAttack, BasicBlock, Roll, + ChargeAttack, } impl Default for AbilityState { fn default() -> Self { Self::BasicAttack } @@ -26,7 +27,7 @@ impl Default for AbilityPool { fn default() -> Self { Self { primary: Some(AbilityState::BasicAttack), - secondary: Some(AbilityState::BasicBlock), + secondary: Some(AbilityState::ChargeAttack), block: None, dodge: Some(AbilityState::Roll), } diff --git a/common/src/comp/character_state.rs b/common/src/comp/character_state.rs index bdabd39759..4726226ec1 100644 --- a/common/src/comp/character_state.rs +++ b/common/src/comp/character_state.rs @@ -42,7 +42,10 @@ pub enum CharacterState { }, /// A basic blocking state BasicBlock {}, - //Charge{}, + ChargeAttack { + /// How long the state has until exiting + remaining_duration: Duration, + }, Roll { /// How long the state has until exiting remaining_duration: Duration, @@ -61,7 +64,7 @@ impl CharacterState { pub fn is_attack(&self) -> bool { match self { - CharacterState::BasicAttack { .. } => true, + CharacterState::BasicAttack { .. } | CharacterState::ChargeAttack { .. } => true, _ => false, } } diff --git a/common/src/states/basic_block.rs b/common/src/states/basic_block.rs index 8c5444b6bf..09f827d432 100644 --- a/common/src/states/basic_block.rs +++ b/common/src/states/basic_block.rs @@ -22,14 +22,7 @@ pub fn behavior(data: &JoinData) -> StateUpdate { handle_move(&data, &mut update); if !data.physics.on_ground || !data.inputs.secondary.is_pressed() { - if let Some(ItemKind::Tool(tool)) = data.stats.equipment.main.as_ref().map(|i| i.kind) { - update.character = CharacterState::Equipping { - tool, - time_left: tool.equip_time(), - }; - } else { - update.character = CharacterState::Idle {}; - }; + attempt_wield(data, &mut update); } update } diff --git a/common/src/states/charge_attack.rs b/common/src/states/charge_attack.rs index 82e229de78..7958885a4e 100644 --- a/common/src/states/charge_attack.rs +++ b/common/src/states/charge_attack.rs @@ -1,13 +1,10 @@ use super::utils::*; use crate::{ - comp::{ - ActionState::Attack, AttackKind::Charge, CharacterEntityData, HealthChange, HealthSource, - ItemKind::Tool, MoveState::Run, StateUpdate, ToolData, - }, + comp::{CharacterState::*, HealthChange, HealthSource, StateUpdate}, event::ServerEvent, sys::character_behavior::JoinData, }; -use std::time::Duration; +use std::{collections::VecDeque, time::Duration}; use vek::Vec3; const CHARGE_SPEED: f32 = 20.0; @@ -18,45 +15,49 @@ pub fn behavior(data: &JoinData) -> StateUpdate { vel: *data.vel, ori: *data.ori, character: *data.character, + energy: *data.energy, + local_events: VecDeque::new(), + server_events: VecDeque::new(), }; - // Move player - 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() - * CHARGE_SPEED; + if let ChargeAttack { remaining_duration } = data.character { + // Move player + 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() + * CHARGE_SPEED; - // Check if hitting another entity - if let Some(uid_b) = data.physics.touch_entity { - // Send Damage event - data.server_bus.emitter().emit(ServerEvent::Damage { - uid: uid_b, - change: HealthChange { - amount: -20, - cause: HealthSource::Attack { by: *data.uid }, - }, - }); + // Check if hitting another entity + if let Some(uid_b) = data.physics.touch_entity { + // Send Damage event + update.server_events.push_front(ServerEvent::Damage { + uid: uid_b, + change: HealthChange { + amount: -20, + cause: HealthSource::Attack { by: *data.uid }, + }, + }); - // Go back to wielding or idling - update.character.action_state = attempt_wield(data.stats); - return update; + // Go back to wielding or idling + attempt_wield(data, &mut update); + return update; + } + + // Check if charge timed out or can't keep moving forward + if *remaining_duration == Duration::default() || update.vel.0.magnitude_squared() < 10.0 { + attempt_wield(data, &mut update); + return update; + } + + // Tick remaining-duration and keep charging + update.character = ChargeAttack { + remaining_duration: remaining_duration + .checked_sub(Duration::from_secs_f32(data.dt.0)) + .unwrap_or_default(), + }; } - // Check if charge timed out or can't keep moving forward - if self.remaining_duration == Duration::default() || update.vel.0.magnitude_squared() < 10.0 { - update.character.action_state = attempt_wield(data.stats); - return update; - } - - // Tick remaining-duration and keep charging - update.character.action_state = Attack(Charge(Some(State { - remaining_duration: self - .remaining_duration - .checked_sub(Duration::from_secs_f32(data.dt.0)) - .unwrap_or_default(), - }))); - update } diff --git a/common/src/states/mod.rs b/common/src/states/mod.rs index 2375e7d586..5f48ad7367 100644 --- a/common/src/states/mod.rs +++ b/common/src/states/mod.rs @@ -1,6 +1,7 @@ // Module declarations pub mod basic_attack; pub mod basic_block; +pub mod charge_attack; pub mod climb; pub mod equipping; pub mod glide; diff --git a/common/src/states/utils.rs b/common/src/states/utils.rs index 0f936efddc..2de02e1454 100644 --- a/common/src/states/utils.rs +++ b/common/src/states/utils.rs @@ -105,19 +105,26 @@ fn swim_move(data: &JoinData, update: &mut StateUpdate) { } } +/// First checks whether `primary` input is pressed, then +/// attempts to go into Equipping state, otherwise Idle pub fn handle_wield(data: &JoinData, update: &mut StateUpdate) { if data.inputs.primary.is_pressed() { - if let Some(Tool(tool)) = data.stats.equipment.main.as_ref().map(|i| i.kind) { - update.character = CharacterState::Equipping { - tool, - time_left: tool.equip_time(), - }; - } else { - update.character = CharacterState::Idle {}; - }; + attempt_wield(data, update); } } +/// If a tool is equipped, goes into Equipping state, otherwise goes to Idle +pub fn attempt_wield(data: &JoinData, update: &mut StateUpdate) { + if let Some(Tool(tool)) = data.stats.equipment.main.as_ref().map(|i| i.kind) { + update.character = CharacterState::Equipping { + tool, + time_left: tool.equip_time(), + }; + } else { + update.character = CharacterState::Idle {}; + }; +} + pub fn handle_sit(data: &JoinData, update: &mut StateUpdate) { if data.inputs.sit.is_pressed() && data.physics.on_ground && data.body.is_humanoid() { update.character = CharacterState::Sit {}; @@ -226,5 +233,8 @@ pub fn character_state_from_ability( AbilityState::Roll { .. } => CharacterState::Roll { remaining_duration: Duration::from_millis(600), }, + AbilityState::ChargeAttack { .. } => CharacterState::ChargeAttack { + remaining_duration: Duration::from_millis(600), + }, } } diff --git a/common/src/states/wielding.rs b/common/src/states/wielding.rs index 1edc0bf78c..43fe8c297d 100644 --- a/common/src/states/wielding.rs +++ b/common/src/states/wielding.rs @@ -2,26 +2,26 @@ use super::utils::*; use crate::{comp::StateUpdate, sys::character_behavior::JoinData}; use std::collections::VecDeque; -pub fn behavior(ecs_data: &JoinData) -> StateUpdate { +pub fn behavior(data: &JoinData) -> StateUpdate { let mut update = StateUpdate { - character: *ecs_data.character, - pos: *ecs_data.pos, - vel: *ecs_data.vel, - ori: *ecs_data.ori, - energy: *ecs_data.energy, + character: *data.character, + pos: *data.pos, + vel: *data.vel, + ori: *data.ori, + energy: *data.energy, local_events: VecDeque::new(), server_events: VecDeque::new(), }; - handle_move(&ecs_data, &mut update); - handle_jump(&ecs_data, &mut update); - handle_sit(&ecs_data, &mut update); - handle_climb(&ecs_data, &mut update); - handle_glide(&ecs_data, &mut update); - handle_unwield(&ecs_data, &mut update); - handle_primary(&ecs_data, &mut update); - handle_secondary(&ecs_data, &mut update); - handle_dodge(&ecs_data, &mut update); + handle_move(&data, &mut update); + handle_jump(&data, &mut update); + handle_sit(&data, &mut update); + handle_climb(&data, &mut update); + handle_glide(&data, &mut update); + handle_unwield(&data, &mut update); + handle_primary(&data, &mut update); + handle_secondary(&data, &mut update); + handle_dodge(&data, &mut update); update } diff --git a/common/src/sys/character_behavior.rs b/common/src/sys/character_behavior.rs index 1179a3c196..89034ace4d 100644 --- a/common/src/sys/character_behavior.rs +++ b/common/src/sys/character_behavior.rs @@ -169,6 +169,7 @@ impl<'a> System<'a> for Sys { CharacterState::Equipping { .. } => states::equipping::behavior(&j), CharacterState::BasicAttack { .. } => states::basic_attack::behavior(&j), CharacterState::BasicBlock { .. } => states::basic_block::behavior(&j), + CharacterState::ChargeAttack { .. } => states::charge_attack::behavior(&j), CharacterState::Sit { .. } => states::sit::behavior(&j), // _ => StateUpdate {