diff --git a/common/src/comp/character_state.rs b/common/src/comp/character_state.rs index a7cffd1724..c9d5c55b17 100644 --- a/common/src/comp/character_state.rs +++ b/common/src/comp/character_state.rs @@ -27,6 +27,7 @@ pub enum ActionState { Idle, Wield { time_left: Duration }, Attack { time_left: Duration, applied: bool }, + Block { time_left: Duration }, //Carry, } @@ -46,6 +47,14 @@ impl ActionState { false } } + + pub fn is_block(&self) -> bool { + if let Self::Block { .. } = self { + true + } else { + false + } + } } #[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize)] diff --git a/common/src/comp/controller.rs b/common/src/comp/controller.rs index 38f5796193..f64c961977 100644 --- a/common/src/comp/controller.rs +++ b/common/src/comp/controller.rs @@ -7,6 +7,7 @@ pub struct Controller { pub move_dir: Vec2, pub jump: bool, pub attack: bool, + pub block: bool, pub roll: bool, pub glide: bool, pub respawn: bool, diff --git a/common/src/sys/animation.rs b/common/src/sys/animation.rs index 4affc39fb2..6b30123ac1 100644 --- a/common/src/sys/animation.rs +++ b/common/src/sys/animation.rs @@ -41,6 +41,7 @@ impl<'a> System<'a> for Sys { (false, Jump, Wield { .. }) => Animation::Cjump, (_, Glide, Idle) => Animation::Gliding, (_, _, Attack { .. }) => Animation::Attack, + (_, _, Block { .. }) => Animation::Gliding, // Impossible animation (Caused by missing animations or syncing delays) _ => Animation::Gliding, }; diff --git a/common/src/sys/combat.rs b/common/src/sys/combat.rs index 6181854063..9e83b6faa0 100644 --- a/common/src/sys/combat.rs +++ b/common/src/sys/combat.rs @@ -35,22 +35,23 @@ impl<'a> System<'a> for Sys { ): Self::SystemData, ) { // Attacks - for (entity, uid, pos, ori, mut character) in ( - &entities, - &uids, - &positions, - &orientations, - &mut character_states, - ) - .join() - { + for (entity, uid, pos, ori) in (&entities, &uids, &positions, &orientations).join() { let mut todo_end = false; // Go through all other entities - if let Attack { time_left, applied } = &mut character.action { + if let Some(Attack { time_left, applied }) = + &mut character_states.get(entity).map(|c| c.action) + { if !*applied { - for (b, pos_b, mut vel_b, stat_b) in - (&entities, &positions, &mut velocities, &mut stats).join() + for (b, pos_b, ori_b, character_b, mut vel_b, stat_b) in ( + &entities, + &positions, + &orientations, + &character_states, + &mut velocities, + &mut stats, + ) + .join() { // Check if it is a hit if entity != b @@ -58,33 +59,51 @@ impl<'a> System<'a> for Sys { && pos.0.distance_squared(pos_b.0) < 50.0 && ori.0.angle_between(pos_b.0 - pos.0).to_degrees() < 90.0 { + let dmg = if character_b.action.is_block() + && ori_b.0.angle_between(pos.0 - pos_b.0).to_degrees() < 90.0 + { + 1 + } else { + 10 + }; + // Deal damage stat_b .health - .change_by(-10, HealthSource::Attack { by: *uid }); // TODO: variable damage and weapon + .change_by(-dmg, HealthSource::Attack { by: *uid }); // TODO: variable damage and weapon vel_b.0 += (pos_b.0 - pos.0).normalized() * 2.0; vel_b.0.z = 2.0; let _ = force_updates.insert(b, ForceUpdate); } } - *applied = true; } - if *time_left == Duration::default() { - todo_end = true; - } else { - *time_left = time_left - .checked_sub(Duration::from_secs_f32(dt.0)) - .unwrap_or_default(); + if let Some(Attack { time_left, applied }) = + &mut character_states.get_mut(entity).map(|c| &mut c.action) + { + // Only attack once + *applied = true; + + if *time_left == Duration::default() { + todo_end = true; + } else { + *time_left = time_left + .checked_sub(Duration::from_secs_f32(dt.0)) + .unwrap_or_default(); + } } } if todo_end { - character.action = Wield { - time_left: Duration::default(), - }; + if let Some(character) = &mut character_states.get_mut(entity) { + character.action = Wield { + time_left: Duration::default(), + }; + } } - if let Wield { time_left } = &mut character.action { + if let Some(Wield { time_left }) = + &mut character_states.get_mut(entity).map(|c| &mut c.action) + { if *time_left != Duration::default() { *time_left = time_left .checked_sub(Duration::from_secs_f32(dt.0)) diff --git a/common/src/sys/controller.rs b/common/src/sys/controller.rs index b28cff5b0f..d74281e1da 100644 --- a/common/src/sys/controller.rs +++ b/common/src/sys/controller.rs @@ -109,6 +109,19 @@ impl<'a> System<'a> for Sys { } } + // Block + if controller.block + && (character.movement == Stand || character.movement == Run) + && (character.action == Idle || character.action.is_wield()) + { + character.action = Block { + time_left: Duration::from_secs(5), + }; + } else if !controller.block && character.action.is_block() { + dbg!(); + character.action = Idle; + } + // Roll if controller.roll && (character.action == Idle || character.action.is_wield()) diff --git a/voxygen/src/session.rs b/voxygen/src/session.rs index 4bbc3814da..3b750fdbeb 100644 --- a/voxygen/src/session.rs +++ b/voxygen/src/session.rs @@ -160,32 +160,29 @@ impl PlayState for SessionState { } } - Event::InputUpdate(GameInput::SecondAttack, state) => { - if state { - let mut client = self.client.borrow_mut(); - if client + Event::InputUpdate(GameInput::Block, state) => { + let mut client = self.client.borrow_mut(); + if state + && client .state() .read_storage::() .get(client.entity()) .is_some() - { - let (cam_dir, cam_pos) = - get_cam_data(&self.scene.camera(), &client); + { + let (cam_dir, cam_pos) = get_cam_data(&self.scene.camera(), &client); - let (d, b) = { - let terrain = client.state().terrain(); - let ray = - terrain.ray(cam_pos, cam_pos + cam_dir * 100.0).cast(); - (ray.0, if let Ok(Some(_)) = ray.1 { true } else { false }) - }; + let (d, b) = { + let terrain = client.state().terrain(); + let ray = terrain.ray(cam_pos, cam_pos + cam_dir * 100.0).cast(); + (ray.0, if let Ok(Some(_)) = ray.1 { true } else { false }) + }; - if b { - let pos = (cam_pos + cam_dir * d).map(|e| e.floor() as i32); - client.remove_block(pos); - } - } else { - // TODO: Handle secondary attack + if b { + let pos = (cam_pos + cam_dir * d).map(|e| e.floor() as i32); + client.remove_block(pos); } + } else { + self.controller.block = state; } } Event::InputUpdate(GameInput::Roll, state) => { diff --git a/voxygen/src/settings.rs b/voxygen/src/settings.rs index 3e4e4f23e3..853a6cac08 100644 --- a/voxygen/src/settings.rs +++ b/voxygen/src/settings.rs @@ -37,7 +37,7 @@ pub struct ControlSettings { pub screenshot: KeyMouse, pub toggle_ingame_ui: KeyMouse, pub attack: KeyMouse, - pub second_attack: KeyMouse, + pub block: KeyMouse, pub roll: KeyMouse, pub interact: KeyMouse, } @@ -69,7 +69,7 @@ impl Default for ControlSettings { screenshot: KeyMouse::Key(VirtualKeyCode::F4), toggle_ingame_ui: KeyMouse::Key(VirtualKeyCode::F6), attack: KeyMouse::Mouse(MouseButton::Left), - second_attack: KeyMouse::Mouse(MouseButton::Right), + block: KeyMouse::Mouse(MouseButton::Right), roll: KeyMouse::Mouse(MouseButton::Middle), interact: KeyMouse::Key(VirtualKeyCode::E), } diff --git a/voxygen/src/window.rs b/voxygen/src/window.rs index 4ebd0e2088..2e9b9534ec 100644 --- a/voxygen/src/window.rs +++ b/voxygen/src/window.rs @@ -35,7 +35,7 @@ pub enum GameInput { Screenshot, ToggleIngameUi, Attack, - SecondAttack, + Block, Roll, Respawn, Interact, @@ -142,7 +142,7 @@ impl Window { GameInput::ToggleIngameUi, ); key_map.insert(settings.controls.attack, GameInput::Attack); - key_map.insert(settings.controls.second_attack, GameInput::SecondAttack); + key_map.insert(settings.controls.block, GameInput::Block); key_map.insert(settings.controls.roll, GameInput::Roll); key_map.insert(settings.controls.interact, GameInput::Interact);