From 91c628821387cd798665bfd55a3acc6a28372b89 Mon Sep 17 00:00:00 2001 From: Sam Date: Fri, 9 Apr 2021 23:40:20 -0400 Subject: [PATCH 01/11] Melee weapons can now block. --- assets/common/abilities/shield/block.ron | 7 +- common/src/combat.rs | 40 +++++++++- common/src/comp/ability.rs | 52 +++++++++++-- common/src/comp/character_state.rs | 8 +- common/src/comp/controller.rs | 9 ++- common/src/comp/inventory/item/tool.rs | 11 +++ common/src/states/basic_block.rs | 99 ++++++++++++++++++++++-- common/src/states/utils.rs | 18 ++++- common/systems/src/beam.rs | 10 ++- common/systems/src/character_behavior.rs | 6 +- common/systems/src/melee.rs | 5 +- common/systems/src/projectile.rs | 12 ++- common/systems/src/shockwave.rs | 10 ++- common/systems/src/stats.rs | 21 +---- server/src/events/entity_manipulation.rs | 28 +++++-- voxygen/src/session/mod.rs | 9 +++ voxygen/src/settings/control.rs | 1 + voxygen/src/window.rs | 3 + 18 files changed, 289 insertions(+), 60 deletions(-) diff --git a/assets/common/abilities/shield/block.ron b/assets/common/abilities/shield/block.ron index ca0309ede7..ca387d1ae6 100644 --- a/assets/common/abilities/shield/block.ron +++ b/assets/common/abilities/shield/block.ron @@ -1 +1,6 @@ -BasicBlock \ No newline at end of file +BasicBlock( + buildup_duration: 0.1, + recover_duration: 0.1, + max_angle: 90.0, + block_strength: 0.8, +) \ No newline at end of file diff --git a/common/src/combat.rs b/common/src/combat.rs index e2de8da7db..0cbd466021 100644 --- a/common/src/combat.rs +++ b/common/src/combat.rs @@ -12,8 +12,8 @@ use crate::{ }, poise::PoiseChange, skills::SkillGroupKind, - Body, Combo, Energy, EnergyChange, EnergySource, Health, HealthChange, HealthSource, - Inventory, SkillSet, Stats, + Body, CharacterState, Combo, Energy, EnergyChange, EnergySource, Health, HealthChange, HealthSource, + Inventory, Ori, SkillSet, Stats, }, event::ServerEvent, outcome::Outcome, @@ -39,6 +39,15 @@ pub enum GroupTarget { OutOfGroup, } +#[derive(Copy, Clone, Debug, Serialize, Deserialize)] +pub enum AttackSource { + Melee, + Projectile, + Beam, + Shockwave, + Explosion, +} + #[cfg(not(target_arch = "wasm32"))] #[derive(Copy, Clone)] pub struct AttackerInfo<'a> { @@ -55,6 +64,8 @@ pub struct TargetInfo<'a> { pub stats: Option<&'a Stats>, pub health: Option<&'a Health>, pub pos: Vec3, + pub ori: Option<&'a Ori>, + pub char_state: Option<&'a CharacterState>, } #[cfg(not(target_arch = "wasm32"))] @@ -105,6 +116,28 @@ impl Attack { pub fn effects(&self) -> impl Iterator { self.effects.iter() } + pub fn compute_damage_reduction(target: &TargetInfo, source: AttackSource, dir: Dir) -> f32 { + let damage_reduction = Damage::compute_damage_reduction(target.inventory, target.stats); + let block_reduction = match source { + AttackSource::Melee => { + if let (Some(CharacterState::BasicBlock(data)), Some(ori)) = + (target.char_state, target.ori) + { + if ori.look_vec().angle_between(-*dir) < data.static_data.max_angle.to_radians() + { + data.static_data.block_strength + } else { + 0.0 + } + } else { + 0.0 + } + }, + _ => 0.0, + }; + 1.0 - (1.0 - damage_reduction) * (1.0 - block_reduction) + } + #[allow(clippy::too_many_arguments)] pub fn apply_attack( &self, @@ -115,6 +148,7 @@ impl Attack { target_dodging: bool, // Currently just modifies damage, maybe look into modifying strength of other effects? strength_modifier: f32, + attack_source: AttackSource, mut emit: impl FnMut(ServerEvent), mut emit_outcome: impl FnMut(Outcome), ) { @@ -126,7 +160,7 @@ impl Attack { .filter(|d| d.target.map_or(true, |t| t == target_group)) .filter(|d| !(matches!(d.target, Some(GroupTarget::OutOfGroup)) && target_dodging)) { - let damage_reduction = Damage::compute_damage_reduction(target.inventory, target.stats); + let damage_reduction = Attack::compute_damage_reduction(&target, attack_source, dir); let change = damage.damage.calculate_health_change( damage_reduction, attacker.map(|a| a.uid), diff --git a/common/src/comp/ability.rs b/common/src/comp/ability.rs index e29b21021d..143e66d891 100644 --- a/common/src/comp/ability.rs +++ b/common/src/comp/ability.rs @@ -39,7 +39,7 @@ impl From<&CharacterState> for CharacterAbilityType { CharacterState::BasicRanged(_) => Self::BasicRanged, CharacterState::Boost(_) => Self::Boost, CharacterState::DashMelee(data) => Self::DashMelee(data.stage_section), - CharacterState::BasicBlock => Self::BasicBlock, + CharacterState::BasicBlock(_) => Self::BasicBlock, CharacterState::LeapMelee(data) => Self::LeapMelee(data.stage_section), CharacterState::ComboMelee(data) => Self::ComboMelee(data.stage_section, data.stage), CharacterState::SpinMelee(data) => Self::SpinMelee(data.stage_section), @@ -114,7 +114,12 @@ pub enum CharacterAbility { charge_through: bool, is_interruptible: bool, }, - BasicBlock, + BasicBlock { + buildup_duration: f32, + recover_duration: f32, + max_angle: f32, + block_strength: f32, + }, Roll { energy_cost: f32, buildup_duration: f32, @@ -341,6 +346,15 @@ impl CharacterAbility { } } + pub fn default_block() -> CharacterAbility { + CharacterAbility::BasicBlock { + buildup_duration: 0.1, + recover_duration: 0.1, + max_angle: 60.0, + block_strength: 0.5, + } + } + pub fn adjusted_by_stats(mut self, power: f32, poise_strength: f32, speed: f32) -> Self { use CharacterAbility::*; match self { @@ -408,7 +422,15 @@ impl CharacterAbility { *swing_duration /= speed; *recover_duration /= speed; }, - BasicBlock => {}, + BasicBlock { + ref mut buildup_duration, + ref mut recover_duration, + // Block strength explicitly not modified by power, that will be a separate stat + .. + } => { + *buildup_duration /= speed; + *recover_duration /= speed; + }, Roll { ref mut buildup_duration, ref mut movement_duration, @@ -586,7 +608,11 @@ impl CharacterAbility { 0 } }, - BasicBlock | Boost { .. } | ComboMelee { .. } | Blink { .. } | BasicSummon { .. } => 0, + BasicBlock { .. } + | Boost { .. } + | ComboMelee { .. } + | Blink { .. } + | BasicSummon { .. } => 0, } } @@ -1235,7 +1261,23 @@ impl From<(&CharacterAbility, AbilityInfo)> for CharacterState { stage_section: StageSection::Buildup, exhausted: false, }), - CharacterAbility::BasicBlock => CharacterState::BasicBlock, + CharacterAbility::BasicBlock { + buildup_duration, + recover_duration, + max_angle, + block_strength, + } => CharacterState::BasicBlock(basic_block::Data { + static_data: basic_block::StaticData { + buildup_duration: Duration::from_secs_f32(*buildup_duration), + recover_duration: Duration::from_secs_f32(*recover_duration), + max_angle: *max_angle, + block_strength: *block_strength, + ability_info, + }, + timer: Duration::default(), + stage_section: StageSection::Buildup, + parry: false, + }), CharacterAbility::Roll { energy_cost: _, buildup_duration, diff --git a/common/src/comp/character_state.rs b/common/src/comp/character_state.rs index 40414c39ad..6f7a375e65 100644 --- a/common/src/comp/character_state.rs +++ b/common/src/comp/character_state.rs @@ -55,7 +55,7 @@ pub enum CharacterState { /// A stunned state Stunned(stunned::Data), /// A basic blocking state - BasicBlock, + BasicBlock(basic_block::Data), /// Player is busy equipping or unequipping weapons Equipping(equipping::Data), /// Player is holding a weapon and can perform other actions @@ -110,7 +110,7 @@ impl CharacterState { | CharacterState::BasicRanged(_) | CharacterState::DashMelee(_) | CharacterState::ComboMelee(_) - | CharacterState::BasicBlock + | CharacterState::BasicBlock(_) | CharacterState::LeapMelee(_) | CharacterState::SpinMelee(_) | CharacterState::ChargedMelee(_) @@ -153,7 +153,7 @@ impl CharacterState { | CharacterState::BasicRanged(_) | CharacterState::DashMelee(_) | CharacterState::ComboMelee(_) - | CharacterState::BasicBlock + | CharacterState::BasicBlock(_) | CharacterState::LeapMelee(_) | CharacterState::ChargedMelee(_) | CharacterState::ChargedRanged(_) @@ -180,7 +180,7 @@ impl CharacterState { ) } - pub fn is_block(&self) -> bool { matches!(self, CharacterState::BasicBlock) } + pub fn is_block(&self) -> bool { matches!(self, CharacterState::BasicBlock(_)) } pub fn is_dodge(&self) -> bool { matches!(self, CharacterState::Roll(_)) } diff --git a/common/src/comp/controller.rs b/common/src/comp/controller.rs index 62d7f0befd..f937cb7dc7 100644 --- a/common/src/comp/controller.rs +++ b/common/src/comp/controller.rs @@ -149,10 +149,11 @@ impl ControlAction { pub enum InputKind { Primary = 0, Secondary = 1, - Ability(usize) = 2, - Roll = 3, - Jump = 4, - Fly = 5, + Block = 2, + Ability(usize) = 3, + Roll = 4, + Jump = 5, + Fly = 6, } impl InputKind { diff --git a/common/src/comp/inventory/item/tool.rs b/common/src/comp/inventory/item/tool.rs index 9bf489e6e8..cd85d3b4f0 100644 --- a/common/src/comp/inventory/item/tool.rs +++ b/common/src/comp/inventory/item/tool.rs @@ -326,6 +326,17 @@ impl Tool { Default::default() } } + + pub fn can_block(&self) -> bool { + matches!( + self.kind, + ToolKind::Sword + | ToolKind::Axe + | ToolKind::Hammer + | ToolKind::Shield + | ToolKind::Dagger + ) + } } #[derive(Clone, Debug, Serialize, Deserialize)] diff --git a/common/src/states/basic_block.rs b/common/src/states/basic_block.rs index 6db22268cf..bdd5dae164 100644 --- a/common/src/states/basic_block.rs +++ b/common/src/states/basic_block.rs @@ -1,15 +1,38 @@ use super::utils::*; use crate::{ - comp::StateUpdate, + comp::{CharacterState, InputKind, StateUpdate}, states::behavior::{CharacterBehavior, JoinData}, }; use serde::{Deserialize, Serialize}; +use std::time::Duration; -// const BLOCK_ACCEL: f32 = 30.0; -// const BLOCK_SPEED: f32 = 75.0; +/// Separated out to condense update portions of character state +#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)] +pub struct StaticData { + /// How long until state should deal damage + pub buildup_duration: Duration, + /// How long the state has until exiting + pub recover_duration: Duration, + /// Max angle (45.0 will give you a 90.0 angle window) + pub max_angle: f32, + /// What percentage incoming damage is reduced by + pub block_strength: f32, + /// What key is used to press ability + pub ability_info: AbilityInfo, +} -#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize, Eq, Hash)] -pub struct Data; +#[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, + /// What section the character stage is in + pub stage_section: StageSection, + /// Whether the block was cancelled early enough to become a parry + pub parry: bool, +} impl CharacterBehavior for Data { fn behavior(&self, data: &JoinData) -> StateUpdate { @@ -17,6 +40,72 @@ impl CharacterBehavior for Data { handle_move(&data, &mut update, 0.4); + match self.stage_section { + StageSection::Buildup => { + if self.timer < self.static_data.buildup_duration { + // Build up + update.character = CharacterState::BasicBlock(Data { + timer: self + .timer + .checked_add(Duration::from_secs_f32(data.dt.0)) + .unwrap_or_default(), + parry: !input_is_pressed(data, InputKind::Block), + ..*self + }); + } else { + // Transitions to swing section of stage + update.character = CharacterState::BasicBlock(Data { + timer: Duration::default(), + stage_section: StageSection::Swing, + ..*self + }); + } + }, + StageSection::Swing => { + if input_is_pressed(data, InputKind::Block) { + // Block + update.character = CharacterState::BasicBlock(Data { + timer: self + .timer + .checked_add(Duration::from_secs_f32(data.dt.0)) + .unwrap_or_default(), + ..*self + }); + } else { + // Transitions to recover section of stage + update.character = CharacterState::BasicBlock(Data { + timer: Duration::default(), + stage_section: StageSection::Recover, + ..*self + }); + } + }, + StageSection::Recover => { + if self.timer < self.static_data.recover_duration { + // Recovery + update.character = CharacterState::BasicBlock(Data { + timer: self + .timer + .checked_add(Duration::from_secs_f32(data.dt.0)) + .unwrap_or_default(), + ..*self + }); + } else { + // Done + update.character = CharacterState::Wielding; + } + }, + _ => { + // If it somehow ends up in an incorrect stage section + update.character = CharacterState::Wielding; + }, + } + + // At end of state logic so an interrupt isn't overwritten + if !input_is_pressed(data, self.static_data.ability_info.input) { + handle_state_interrupt(data, &mut update, false); + } + update } } diff --git a/common/src/states/utils.rs b/common/src/states/utils.rs index 245169fc3b..d145ed26e4 100644 --- a/common/src/states/utils.rs +++ b/common/src/states/utils.rs @@ -579,7 +579,7 @@ fn handle_ability(data: &JoinData, update: &mut StateUpdate, input: InputKind) { .get(skill_index) .cloned() .and_then(unlocked), - InputKind::Roll | InputKind::Jump | InputKind::Fly => None, + InputKind::Roll | InputKind::Jump | InputKind::Fly | InputKind::Block => None, }) .map(|a| { let tool = unwrap_tool_data(data, equip_slot).map(|t| t.kind); @@ -615,6 +615,7 @@ pub fn handle_input(data: &JoinData, update: &mut StateUpdate, input: InputKind) InputKind::Jump => { handle_jump(data, update, 1.0); }, + InputKind::Block => handle_block_input(data, update), InputKind::Fly => {}, } } @@ -626,6 +627,21 @@ pub fn attempt_input(data: &JoinData, update: &mut StateUpdate) { } } +/// Checks that player can block, then attempts to block +pub fn handle_block_input(data: &JoinData, update: &mut StateUpdate) { + let can_block = + |equip_slot| matches!(unwrap_tool_data(data, equip_slot), Some(tool) if tool.can_block()); + if input_is_pressed(data, InputKind::Block) && can_block(EquipSlot::Mainhand) { + let ability = CharacterAbility::default_block(); + if ability.requirements_paid(data, update) { + update.character = CharacterState::from(( + &ability, + AbilityInfo::from_input(data, false, InputKind::Roll), + )); + } + } +} + /// Checks that player can perform a dodge, then /// attempts to perform their dodge ability pub fn handle_dodge_input(data: &JoinData, update: &mut StateUpdate) { diff --git a/common/systems/src/beam.rs b/common/systems/src/beam.rs index b91ca2c94d..7640195837 100644 --- a/common/systems/src/beam.rs +++ b/common/systems/src/beam.rs @@ -1,8 +1,8 @@ use common::{ - combat::{AttackerInfo, TargetInfo}, + combat::{AttackSource, AttackerInfo, TargetInfo}, comp::{ - Beam, BeamSegment, Body, Combo, Energy, Group, Health, HealthSource, Inventory, Ori, Pos, - Scale, Stats, + Beam, BeamSegment, Body, CharacterState, Combo, Energy, Group, Health, HealthSource, + Inventory, Ori, Pos, Scale, Stats, }, event::{EventBus, ServerEvent}, outcome::Outcome, @@ -40,6 +40,7 @@ pub struct ReadData<'a> { energies: ReadStorage<'a, Energy>, stats: ReadStorage<'a, Stats>, combos: ReadStorage<'a, Combo>, + character_states: ReadStorage<'a, CharacterState>, } /// This system is responsible for handling beams that heal or do damage @@ -188,6 +189,8 @@ impl<'a> System<'a> for Sys { stats: read_data.stats.get(target), health: read_data.healths.get(target), pos: pos.0, + ori: read_data.orientations.get(target), + char_state: read_data.character_states.get(target), }; beam_segment.properties.attack.apply_attack( @@ -197,6 +200,7 @@ impl<'a> System<'a> for Sys { ori.look_dir(), false, 1.0, + AttackSource::Beam, |e| server_events.push(e), |o| outcomes.push(o), ); diff --git a/common/systems/src/character_behavior.rs b/common/systems/src/character_behavior.rs index 251df59873..b2336bffdb 100644 --- a/common/systems/src/character_behavior.rs +++ b/common/systems/src/character_behavior.rs @@ -301,9 +301,7 @@ impl<'a> System<'a> for Sys { CharacterState::Sneak => { states::sneak::Data::handle_event(&states::sneak::Data, &j, action) }, - CharacterState::BasicBlock => { - states::basic_block::Data.handle_event(&j, action) - }, + CharacterState::BasicBlock(data) => data.handle_event(&j, action), 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), @@ -357,7 +355,7 @@ impl<'a> System<'a> for Sys { CharacterState::Sit => states::sit::Data::behavior(&states::sit::Data, &j), CharacterState::Dance => states::dance::Data::behavior(&states::dance::Data, &j), CharacterState::Sneak => states::sneak::Data::behavior(&states::sneak::Data, &j), - CharacterState::BasicBlock => states::basic_block::Data.behavior(&j), + CharacterState::BasicBlock(data) => data.behavior(&j), CharacterState::Roll(data) => data.behavior(&j), CharacterState::Wielding => states::wielding::Data.behavior(&j), CharacterState::Equipping(data) => data.behavior(&j), diff --git a/common/systems/src/melee.rs b/common/systems/src/melee.rs index 0809f0d965..ab1688414c 100644 --- a/common/systems/src/melee.rs +++ b/common/systems/src/melee.rs @@ -1,5 +1,5 @@ use common::{ - combat::{AttackerInfo, TargetInfo}, + combat::{AttackSource, AttackerInfo, TargetInfo}, comp::{ Body, CharacterState, Combo, Energy, Group, Health, Inventory, Melee, Ori, Pos, Scale, Stats, @@ -147,6 +147,8 @@ impl<'a> System<'a> for Sys { stats: read_data.stats.get(target), health: read_data.healths.get(target), pos: pos.0, + ori: read_data.orientations.get(target), + char_state: read_data.char_states.get(target), }; melee_attack.attack.apply_attack( @@ -156,6 +158,7 @@ impl<'a> System<'a> for Sys { dir, is_dodge, 1.0, + AttackSource::Melee, |e| server_emitter.emit(e), |o| outcomes.push(o), ); diff --git a/common/systems/src/projectile.rs b/common/systems/src/projectile.rs index f780f7f967..2a8d10cbdf 100644 --- a/common/systems/src/projectile.rs +++ b/common/systems/src/projectile.rs @@ -1,8 +1,8 @@ use common::{ - combat::{AttackerInfo, TargetInfo}, + combat::{AttackSource, AttackerInfo, TargetInfo}, comp::{ - projectile, Body, Combo, Energy, Group, Health, HealthSource, Inventory, Ori, PhysicsState, - Pos, Projectile, Stats, Vel, + projectile, Body, CharacterState, Combo, Energy, Group, Health, HealthSource, Inventory, + Ori, PhysicsState, Pos, Projectile, Stats, Vel, }, event::{EventBus, ServerEvent}, outcome::Outcome, @@ -36,6 +36,7 @@ pub struct ReadData<'a> { combos: ReadStorage<'a, Combo>, healths: ReadStorage<'a, Health>, bodies: ReadStorage<'a, Body>, + character_states: ReadStorage<'a, CharacterState>, } /// This system is responsible for handling projectile effect triggers @@ -130,6 +131,10 @@ impl<'a> System<'a> for Sys { stats: read_data.stats.get(target), health: read_data.healths.get(target), pos: pos.0, + // TODO: Let someone smarter figure this out + // ori: orientations.get(target), + ori: None, + char_state: read_data.character_states.get(target), }; if let Some(&body) = read_data.bodies.get(entity) { @@ -152,6 +157,7 @@ impl<'a> System<'a> for Sys { ori.look_dir(), false, 1.0, + AttackSource::Projectile, |e| server_emitter.emit(e), |o| outcomes.push(o), ); diff --git a/common/systems/src/shockwave.rs b/common/systems/src/shockwave.rs index fe6ab8ed48..e77eff0f07 100644 --- a/common/systems/src/shockwave.rs +++ b/common/systems/src/shockwave.rs @@ -1,8 +1,8 @@ use common::{ - combat::{AttackerInfo, TargetInfo}, + combat::{AttackSource, AttackerInfo, TargetInfo}, comp::{ - Body, Combo, Energy, Group, Health, HealthSource, Inventory, Ori, PhysicsState, Pos, Scale, - Shockwave, ShockwaveHitEntities, Stats, + Body, CharacterState, Combo, Energy, Group, Health, HealthSource, Inventory, Ori, + PhysicsState, Pos, Scale, Shockwave, ShockwaveHitEntities, Stats, }, event::{EventBus, ServerEvent}, outcome::Outcome, @@ -37,6 +37,7 @@ pub struct ReadData<'a> { energies: ReadStorage<'a, Energy>, stats: ReadStorage<'a, Stats>, combos: ReadStorage<'a, Combo>, + character_states: ReadStorage<'a, CharacterState>, } /// This system is responsible for handling accepted inputs like moving or @@ -193,6 +194,8 @@ impl<'a> System<'a> for Sys { stats: read_data.stats.get(target), health: read_data.healths.get(target), pos: pos.0, + ori: read_data.orientations.get(target), + char_state: read_data.character_states.get(target), }; shockwave.properties.attack.apply_attack( @@ -202,6 +205,7 @@ impl<'a> System<'a> for Sys { dir, false, 1.0, + AttackSource::Shockwave, |e| server_emitter.emit(e), |o| outcomes.push(o), ); diff --git a/common/systems/src/stats.rs b/common/systems/src/stats.rs index c7da3ffd1a..d56129c3f7 100644 --- a/common/systems/src/stats.rs +++ b/common/systems/src/stats.rs @@ -253,26 +253,11 @@ impl<'a> System<'a> for Sys { energy.get_mut_unchecked().regen_rate = 0.0 } }, - // recover small amount of passive energy from blocking, and bonus energy from - // blocking attacks? - CharacterState::BasicBlock => { - let res = { - let energy = energy.get_unchecked(); - energy.current() < energy.maximum() - }; - - if res { - energy.get_mut_unchecked().change_by(EnergyChange { - amount: -3, - source: EnergySource::Regen, - }); - } - }, - // Non-combat abilities that consume energy; - // temporarily stall energy gain, but preserve regen_rate. + // Abilities that temporarily stall energy gain, but preserve regen_rate. CharacterState::Roll { .. } | CharacterState::Climb { .. } - | CharacterState::Stunned { .. } => {}, + | CharacterState::Stunned { .. } + | CharacterState::BasicBlock { .. } => {}, } } diff --git a/server/src/events/entity_manipulation.rs b/server/src/events/entity_manipulation.rs index d046405393..1267d70c15 100644 --- a/server/src/events/entity_manipulation.rs +++ b/server/src/events/entity_manipulation.rs @@ -672,16 +672,31 @@ pub fn handle_explosion(server: &Server, pos: Vec3, explosion: Explosion, o RadiusEffect::Attack(attack) => { let energies = &ecs.read_storage::(); let combos = &ecs.read_storage::(); - for (entity_b, pos_b, health_b, inventory_b_maybe, stats_b_maybe, body_b_maybe) in ( + for ( + entity_b, + pos_b, + health_b, + ( + body_b_maybe, + inventory_b_maybe, + stats_b_maybe, + ori_b_maybe, + char_state_b_maybe, + ), + ) in ( &ecs.entities(), &ecs.read_storage::(), &ecs.read_storage::(), - ecs.read_storage::().maybe(), - ecs.read_storage::().maybe(), - ecs.read_storage::().maybe(), + ( + ecs.read_storage::().maybe(), + ecs.read_storage::().maybe(), + ecs.read_storage::().maybe(), + ecs.read_storage::().maybe(), + ecs.read_storage::().maybe(), + ), ) .join() - .filter(|(_, _, h, _, _, _)| !h.is_dead) + .filter(|(_, _, h, _)| !h.is_dead) { // Check if it is a hit let strength = if let Some(body) = body_b_maybe { @@ -725,6 +740,8 @@ pub fn handle_explosion(server: &Server, pos: Vec3, explosion: Explosion, o stats: stats_b_maybe, health: Some(health_b), pos, + ori: ori_b_maybe, + char_state: char_state_b_maybe, }; let server_eventbus = ecs.read_resource::>(); @@ -736,6 +753,7 @@ pub fn handle_explosion(server: &Server, pos: Vec3, explosion: Explosion, o dir, false, strength, + combat::AttackSource::Explosion, |e| server_eventbus.emit_now(e), |o| outcomes.push(o), ); diff --git a/voxygen/src/session/mod.rs b/voxygen/src/session/mod.rs index fa1b98732c..57f293f0d7 100644 --- a/voxygen/src/session/mod.rs +++ b/voxygen/src/session/mod.rs @@ -418,6 +418,15 @@ impl PlayState for SessionState { ); } }, + GameInput::Block => { + let mut client = self.client.borrow_mut(); + client.handle_input( + InputKind::Block, + state, + select_pos, + target_entity.map(|t| t.0), + ); + }, GameInput::Roll => { let mut client = self.client.borrow_mut(); if can_build { diff --git a/voxygen/src/settings/control.rs b/voxygen/src/settings/control.rs index b70e30ebe2..67b4defb63 100644 --- a/voxygen/src/settings/control.rs +++ b/voxygen/src/settings/control.rs @@ -111,6 +111,7 @@ impl ControlSettings { match game_input { GameInput::Primary => KeyMouse::Mouse(MouseButton::Left), GameInput::Secondary => KeyMouse::Mouse(MouseButton::Right), + GameInput::Block => KeyMouse::Key(VirtualKeyCode::LAlt), GameInput::ToggleCursor => KeyMouse::Key(VirtualKeyCode::Comma), GameInput::Escape => KeyMouse::Key(VirtualKeyCode::Escape), GameInput::Chat => KeyMouse::Key(VirtualKeyCode::Return), diff --git a/voxygen/src/window.rs b/voxygen/src/window.rs index e6c1581402..d75cc87785 100644 --- a/voxygen/src/window.rs +++ b/voxygen/src/window.rs @@ -21,6 +21,7 @@ use winit::monitor::VideoMode; pub enum GameInput { Primary, Secondary, + Block, Slot1, Slot2, Slot3, @@ -85,6 +86,7 @@ impl GameInput { match *self { GameInput::Primary => "gameinput.primary", GameInput::Secondary => "gameinput.secondary", + GameInput::Block => "gameinput.block", GameInput::ToggleCursor => "gameinput.togglecursor", GameInput::MoveForward => "gameinput.moveforward", GameInput::MoveLeft => "gameinput.moveleft", @@ -149,6 +151,7 @@ impl GameInput { [ GameInput::Primary, GameInput::Secondary, + GameInput::Block, GameInput::ToggleCursor, GameInput::MoveForward, GameInput::MoveLeft, From f5ec23df480aab883a5ec96fcb0a2684eb0f547c Mon Sep 17 00:00:00 2001 From: Sam Date: Tue, 13 Apr 2021 01:46:42 -0400 Subject: [PATCH 02/11] Parrying --- assets/common/abilities/shield/block.ron | 1 + common/src/combat.rs | 10 +++++++--- common/src/comp/ability.rs | 15 ++++++++------- common/src/states/basic_block.rs | 8 ++++++-- 4 files changed, 22 insertions(+), 12 deletions(-) diff --git a/assets/common/abilities/shield/block.ron b/assets/common/abilities/shield/block.ron index ca387d1ae6..f586128082 100644 --- a/assets/common/abilities/shield/block.ron +++ b/assets/common/abilities/shield/block.ron @@ -3,4 +3,5 @@ BasicBlock( recover_duration: 0.1, max_angle: 90.0, block_strength: 0.8, + energy_cost: 0.0, ) \ No newline at end of file diff --git a/common/src/combat.rs b/common/src/combat.rs index 0cbd466021..52ed671846 100644 --- a/common/src/combat.rs +++ b/common/src/combat.rs @@ -12,8 +12,8 @@ use crate::{ }, poise::PoiseChange, skills::SkillGroupKind, - Body, CharacterState, Combo, Energy, EnergyChange, EnergySource, Health, HealthChange, HealthSource, - Inventory, Ori, SkillSet, Stats, + Body, CharacterState, Combo, Energy, EnergyChange, EnergySource, Health, HealthChange, + HealthSource, Inventory, Ori, SkillSet, Stats, }, event::ServerEvent, outcome::Outcome, @@ -125,7 +125,11 @@ impl Attack { { if ori.look_vec().angle_between(-*dir) < data.static_data.max_angle.to_radians() { - data.static_data.block_strength + if data.parry { + 1.0 + } else { + data.static_data.block_strength + } } else { 0.0 } diff --git a/common/src/comp/ability.rs b/common/src/comp/ability.rs index 143e66d891..804e4d7563 100644 --- a/common/src/comp/ability.rs +++ b/common/src/comp/ability.rs @@ -119,6 +119,7 @@ pub enum CharacterAbility { recover_duration: f32, max_angle: f32, block_strength: f32, + energy_cost: f32, }, Roll { energy_cost: f32, @@ -310,7 +311,8 @@ impl CharacterAbility { | CharacterAbility::ChargedRanged { energy_cost, .. } | CharacterAbility::ChargedMelee { energy_cost, .. } | CharacterAbility::Shockwave { energy_cost, .. } - | CharacterAbility::BasicAura { energy_cost, .. } => update + | CharacterAbility::BasicAura { energy_cost, .. } + | CharacterAbility::BasicBlock { energy_cost, .. } => update .energy .try_change_by(-(*energy_cost as i32), EnergySource::Ability) .is_ok(), @@ -352,6 +354,7 @@ impl CharacterAbility { recover_duration: 0.1, max_angle: 60.0, block_strength: 0.5, + energy_cost: 50.0, } } @@ -600,7 +603,8 @@ impl CharacterAbility { | ChargedRanged { energy_cost, .. } | Shockwave { energy_cost, .. } | HealingBeam { energy_cost, .. } - | BasicAura { energy_cost, .. } => *energy_cost as u32, + | BasicAura { energy_cost, .. } + | BasicBlock { energy_cost, .. } => *energy_cost as u32, BasicBeam { energy_drain, .. } => { if *energy_drain > f32::EPSILON { 1 @@ -608,11 +612,7 @@ impl CharacterAbility { 0 } }, - BasicBlock { .. } - | Boost { .. } - | ComboMelee { .. } - | Blink { .. } - | BasicSummon { .. } => 0, + Boost { .. } | ComboMelee { .. } | Blink { .. } | BasicSummon { .. } => 0, } } @@ -1266,6 +1266,7 @@ impl From<(&CharacterAbility, AbilityInfo)> for CharacterState { recover_duration, max_angle, block_strength, + energy_cost: _, } => CharacterState::BasicBlock(basic_block::Data { static_data: basic_block::StaticData { buildup_duration: Duration::from_secs_f32(*buildup_duration), diff --git a/common/src/states/basic_block.rs b/common/src/states/basic_block.rs index bdd5dae164..4ecb58802b 100644 --- a/common/src/states/basic_block.rs +++ b/common/src/states/basic_block.rs @@ -49,14 +49,18 @@ impl CharacterBehavior for Data { .timer .checked_add(Duration::from_secs_f32(data.dt.0)) .unwrap_or_default(), - parry: !input_is_pressed(data, InputKind::Block), + parry: self.parry || !input_is_pressed(data, InputKind::Block), ..*self }); } else { // Transitions to swing section of stage update.character = CharacterState::BasicBlock(Data { timer: Duration::default(), - stage_section: StageSection::Swing, + stage_section: if self.parry { + StageSection::Recover + } else { + StageSection::Swing + }, ..*self }); } From fad31bd7ab5bcbc41f9d4c7903ff2ebbda3794cf Mon Sep 17 00:00:00 2001 From: jshipsey Date: Mon, 19 Apr 2021 00:31:10 -0400 Subject: [PATCH 03/11] anim --- voxygen/anim/src/character/alpha.rs | 10 +- voxygen/anim/src/character/block.rs | 222 ++++++++++++++++++++-- voxygen/anim/src/character/chargeswing.rs | 10 +- voxygen/anim/src/character/leapmelee.rs | 6 +- voxygen/anim/src/character/mod.rs | 4 +- voxygen/anim/src/character/staggered.rs | 6 +- voxygen/anim/src/character/stunned.rs | 10 +- voxygen/anim/src/character/wield.rs | 23 +-- voxygen/src/scene/figure/mod.rs | 26 ++- 9 files changed, 264 insertions(+), 53 deletions(-) diff --git a/voxygen/anim/src/character/alpha.rs b/voxygen/anim/src/character/alpha.rs index 0004398591..2ab3349da2 100644 --- a/voxygen/anim/src/character/alpha.rs +++ b/voxygen/anim/src/character/alpha.rs @@ -166,11 +166,13 @@ impl Animation for AlphaAnimation { let moveret2 = move2 * pullback; next.hand_l.position = Vec3::new(s_a.hhl.0, s_a.hhl.1, s_a.hhl.2 + moveret2 * -7.0); - next.hand_l.orientation = - Quaternion::rotation_x(s_a.hhl.3) * Quaternion::rotation_y(s_a.hhl.4); + next.hand_l.orientation = Quaternion::rotation_x(s_a.hhl.3) + * Quaternion::rotation_y(s_a.hhl.4) + * Quaternion::rotation_z(s_a.hhl.5); next.hand_r.position = Vec3::new(s_a.hhr.0, s_a.hhr.1, s_a.hhr.2); - next.hand_r.orientation = - Quaternion::rotation_x(s_a.hhr.3) * Quaternion::rotation_y(s_a.hhr.4); + next.hand_r.orientation = Quaternion::rotation_x(s_a.hhr.3) + * Quaternion::rotation_y(s_a.hhr.4) + * Quaternion::rotation_z(s_a.hhr.5); next.control.position = Vec3::new( s_a.hc.0 + moveret1 * -13.0 + moveret2 * 3.0, diff --git a/voxygen/anim/src/character/block.rs b/voxygen/anim/src/character/block.rs index c4ceb474ca..8b582c6da9 100644 --- a/voxygen/anim/src/character/block.rs +++ b/voxygen/anim/src/character/block.rs @@ -2,12 +2,24 @@ use super::{ super::{vek::*, Animation}, CharacterSkeleton, SkeletonAttr, }; -use common::comp::item::ToolKind; +use common::{ + comp::item::{Hands, ToolKind}, + states::utils::StageSection, +}; +use std::f32::consts::PI; pub struct BlockAnimation; +type BlockAnimationDependency = ( + (Option, Option), + Option, + Option, + Vec3, + f32, + Option, +); impl Animation for BlockAnimation { - type Dependency = (Option, Option, f32); + type Dependency = BlockAnimationDependency; type Skeleton = CharacterSkeleton; #[cfg(feature = "use-dyn-lib")] @@ -16,24 +28,206 @@ impl Animation for BlockAnimation { #[cfg_attr(feature = "be-dyn-lib", export_name = "character_block")] fn update_skeleton_inner( skeleton: &Self::Skeleton, - (_active_tool_kind, _second_tool_kind, _global_time): Self::Dependency, - _anim_time: f32, - _rate: &mut f32, + (hands, active_tool_kind, second_tool_kind,velocity, _global_time, stage_section): Self::Dependency, + anim_time: f32, + rate: &mut f32, s_a: &SkeletonAttr, ) -> Self::Skeleton { + *rate = 1.0; let mut next = (*skeleton).clone(); - next.head.position = Vec3::new(0.0, -1.0 + s_a.head.0, s_a.head.1 + 19.5); - next.head.orientation = Quaternion::rotation_x(-0.25); - - next.hand_l.position = Vec3::new(s_a.hand.0 - 6.0, s_a.hand.1 + 3.5, s_a.hand.2 + 0.0); - next.hand_l.orientation = Quaternion::rotation_x(-0.3); - next.hand_r.position = Vec3::new(s_a.hand.0 - 6.0, s_a.hand.1 + 3.0, s_a.hand.2 - 2.0); - next.hand_r.orientation = Quaternion::rotation_x(-0.3); next.main.position = Vec3::new(0.0, 0.0, 0.0); - next.main.orientation = Quaternion::rotation_x(-0.3); + next.main.orientation = Quaternion::rotation_z(0.0); + next.second.position = Vec3::new(0.0, 0.0, 0.0); + next.second.orientation = Quaternion::rotation_z(0.0); - next.torso.position = Vec3::new(0.0, -0.2, 0.1) * s_a.scaler; + let speed = Vec2::::from(velocity).magnitude(); + + let (movement1base, move2, movement3) = match stage_section { + Some(StageSection::Buildup) => (anim_time.powf(0.25), 0.0, 0.0), + Some(StageSection::Swing) => (1.0, (anim_time * 10.0).sin(), 0.0), + + Some(StageSection::Recover) => (1.0, 1.0, anim_time.powf(4.0)), + _ => (0.0, 0.0, 0.0), + }; + let pullback = 1.0 - movement3; + let move1 = movement1base * pullback; + + if speed > 0.5 { + } else { + next.chest.position = + Vec3::new(0.0, s_a.chest.0, s_a.chest.1 + move1 * -1.0 + move2 * 0.2); + next.chest.orientation = Quaternion::rotation_x(move1 * -0.15); + next.head.orientation = Quaternion::rotation_x(move1 * 0.25); + + next.belt.position = Vec3::new(0.0, s_a.belt.0 + move1 * 0.5, s_a.belt.1 + move1 * 0.5); + next.shorts.position = + Vec3::new(0.0, s_a.shorts.0 + move1 * 1.3, s_a.shorts.1 + move1 * 1.0); + + next.belt.orientation = Quaternion::rotation_x(move1 * 0.15); + next.shorts.orientation = Quaternion::rotation_x(move1 * 0.25); + + next.foot_l.position = Vec3::new(-s_a.foot.0, s_a.foot.1 + move1 * 2.0, s_a.foot.2); + next.foot_l.orientation = Quaternion::rotation_z(move1 * -0.5); + + next.foot_r.position = Vec3::new(s_a.foot.0, s_a.foot.1 + move1 * -2.0, s_a.foot.2); + next.foot_r.orientation = Quaternion::rotation_x(move1 * -0.5); + }; + + match (hands, active_tool_kind, second_tool_kind) { + ((Some(Hands::Two), _), tool, _) | ((None, Some(Hands::Two)), _, tool) => match tool { + Some(ToolKind::Sword) | Some(ToolKind::SwordSimple) => { + next.hand_l.position = Vec3::new(s_a.shl.0, s_a.shl.1, s_a.shl.2); + next.hand_l.orientation = + Quaternion::rotation_x(s_a.shl.3) * Quaternion::rotation_y(s_a.shl.4); + next.hand_r.position = Vec3::new( + s_a.shr.0 + move1 * -2.0, + s_a.shr.1, + s_a.shr.2 + move1 * 20.0, + ); + next.hand_r.orientation = Quaternion::rotation_x(s_a.shr.3) + * Quaternion::rotation_y(s_a.shr.4) + * Quaternion::rotation_z(move1 * 1.5); + + next.control.position = + Vec3::new(s_a.sc.0 + move1 * -3.0, s_a.sc.1, s_a.sc.2 + move1 * 4.0); + next.control.orientation = Quaternion::rotation_x(s_a.sc.3) + * Quaternion::rotation_y(move1 * 1.1) + * Quaternion::rotation_z(move1 * 1.7); + }, + + Some(ToolKind::Axe) => { + next.main.position = Vec3::new(0.0, 0.0, 0.0); + next.main.orientation = Quaternion::rotation_x(0.0); + + next.hand_l.position = Vec3::new(s_a.ahl.0, s_a.ahl.1, s_a.ahl.2); + next.hand_l.orientation = + Quaternion::rotation_x(s_a.ahl.3) * Quaternion::rotation_y(s_a.ahl.4); + next.hand_r.position = Vec3::new(s_a.ahr.0, s_a.ahr.1, s_a.ahr.2); + next.hand_r.orientation = + Quaternion::rotation_x(s_a.ahr.3) * Quaternion::rotation_z(s_a.ahr.5); + + next.control.position = Vec3::new( + s_a.ac.0 + move1 * 13.0, + s_a.ac.1 + move1 * -3.0, + s_a.ac.2 + move1 * 8.0, + ); + next.control.orientation = Quaternion::rotation_x(s_a.ac.3 + move1 * -2.0) + * Quaternion::rotation_y(s_a.ac.4 + move1 * -1.8) + * Quaternion::rotation_z(s_a.ac.5 + move1 * 4.0); + }, + Some(ToolKind::Hammer) | Some(ToolKind::HammerSimple) | Some(ToolKind::Pick) => { + next.hand_l.position = + Vec3::new(s_a.hhl.0, s_a.hhl.1 + move1 * 6.0, s_a.hhl.2 + move1 * 6.0); + next.hand_l.orientation = Quaternion::rotation_x(s_a.hhl.3 + move1 * -0.5) + * Quaternion::rotation_y(s_a.hhl.4 + move1 * 1.5) + * Quaternion::rotation_z(s_a.hhl.5 + move1 * PI); + next.hand_r.position = Vec3::new(s_a.hhr.0, s_a.hhr.1, s_a.hhr.2); + next.hand_r.orientation = Quaternion::rotation_x(s_a.hhr.3) + * Quaternion::rotation_y(s_a.hhr.4) + * Quaternion::rotation_z(s_a.hhr.5); + + next.control.position = Vec3::new( + s_a.hc.0 + move1 * 3.0, + s_a.hc.1 + move1 * 3.0, + s_a.hc.2 + move1 * 10.0, + ); + next.control.orientation = Quaternion::rotation_x(s_a.hc.3) + * Quaternion::rotation_y(s_a.hc.4) + * Quaternion::rotation_z(s_a.hc.5 + move1 * -1.0); + }, + Some(ToolKind::Staff) | Some(ToolKind::Sceptre) => { + next.hand_r.position = Vec3::new(s_a.sthr.0, s_a.sthr.1, s_a.sthr.2); + next.hand_r.orientation = + Quaternion::rotation_x(s_a.sthr.3) * Quaternion::rotation_y(s_a.sthr.4); + + next.control.position = Vec3::new(s_a.stc.0, s_a.stc.1, s_a.stc.2); + + next.hand_l.position = Vec3::new(s_a.sthl.0, s_a.sthl.1, s_a.sthl.2); + next.hand_l.orientation = Quaternion::rotation_x(s_a.sthl.3); + + next.control.orientation = Quaternion::rotation_x(s_a.stc.3) + * Quaternion::rotation_y(s_a.stc.4) + * Quaternion::rotation_z(s_a.stc.5); + }, + Some(ToolKind::Bow) => { + next.main.position = Vec3::new(0.0, 0.0, 0.0); + next.main.orientation = Quaternion::rotation_x(0.0); + next.hand_l.position = Vec3::new(s_a.bhl.0, s_a.bhl.1, s_a.bhl.2); + next.hand_l.orientation = Quaternion::rotation_x(s_a.bhl.3); + next.hand_r.position = Vec3::new(s_a.bhr.0, s_a.bhr.1, s_a.bhr.2); + next.hand_r.orientation = Quaternion::rotation_x(s_a.bhr.3); + + next.hold.position = Vec3::new(0.0, -1.0, -5.2); + next.hold.orientation = Quaternion::rotation_x(-1.57); + next.hold.scale = Vec3::one() * 1.0; + + next.control.position = Vec3::new(s_a.bc.0, s_a.bc.1, s_a.bc.2); + next.control.orientation = Quaternion::rotation_x(0.0) + * Quaternion::rotation_y(s_a.bc.4) + * Quaternion::rotation_z(s_a.bc.5); + }, + Some(ToolKind::Debug) => { + next.hand_l.position = Vec3::new(-7.0, 4.0, 3.0); + next.hand_l.orientation = Quaternion::rotation_x(1.27); + next.main.position = Vec3::new(-5.0, 5.0, 23.0); + next.main.orientation = Quaternion::rotation_x(PI); + }, + Some(ToolKind::Farming) => { + next.hand_l.position = Vec3::new(9.0, 1.0, 1.0); + next.hand_l.orientation = Quaternion::rotation_x(1.57); + next.hand_r.position = Vec3::new(9.0, 1.0, 11.0); + next.hand_r.orientation = Quaternion::rotation_x(1.57); + next.main.position = Vec3::new(7.5, 7.5, 13.2); + next.main.orientation = Quaternion::rotation_y(PI); + + next.control.position = Vec3::new(-11.0, 1.8, 4.0); + next.control.orientation = Quaternion::rotation_x(0.0) + * Quaternion::rotation_y(0.6) + * Quaternion::rotation_z(0.0); + }, + _ => {}, + }, + ((_, _), _, _) => {}, + }; + match hands { + (Some(Hands::One), _) => { + next.control_l.position = Vec3::new(-7.0, 8.0 + move1 * 3.0, 2.0 + move1 * 3.0); + next.control_l.orientation = + Quaternion::rotation_x(-0.3) * Quaternion::rotation_y(move1 * 1.0); + next.hand_l.position = Vec3::new(0.0, -0.5, 0.0); + next.hand_l.orientation = Quaternion::rotation_x(1.57) + }, + (_, _) => {}, + }; + match hands { + (None | Some(Hands::One), Some(Hands::One)) => { + next.control_r.position = Vec3::new(7.0, 8.0 + move1 * 3.0, 2.0 + move1 * 3.0); + next.control_r.orientation = + Quaternion::rotation_x(-0.3) * Quaternion::rotation_y(move1 * -1.0); + next.hand_r.position = Vec3::new(0.0, -0.5, 0.0); + next.hand_r.orientation = Quaternion::rotation_x(1.57) + }, + (_, _) => {}, + }; + match hands { + (None, None) | (None, Some(Hands::One)) => { + next.hand_l.position = Vec3::new(-4.5, 8.0, 5.0); + next.hand_l.orientation = Quaternion::rotation_x(1.9) * Quaternion::rotation_y(-0.5) + }, + (_, _) => {}, + }; + match hands { + (None, None) | (Some(Hands::One), None) => { + next.hand_r.position = Vec3::new(4.5, 8.0, 5.0); + next.hand_r.orientation = Quaternion::rotation_x(1.9) * Quaternion::rotation_y(0.5) + }, + (_, _) => {}, + }; + + if let (None, Some(Hands::Two)) = hands { + next.second = next.main; + } next } diff --git a/voxygen/anim/src/character/chargeswing.rs b/voxygen/anim/src/character/chargeswing.rs index 7a19349913..4be709117e 100644 --- a/voxygen/anim/src/character/chargeswing.rs +++ b/voxygen/anim/src/character/chargeswing.rs @@ -87,11 +87,13 @@ impl Animation for ChargeswingAnimation { Some(ToolKind::Hammer) | Some(ToolKind::HammerSimple) => { next.hand_l.position = Vec3::new(s_a.hhl.0, s_a.hhl.1, s_a.hhl.2 + (move2 * -8.0)); - next.hand_l.orientation = - Quaternion::rotation_x(s_a.hhl.3) * Quaternion::rotation_y(s_a.hhl.4); + next.hand_l.orientation = Quaternion::rotation_x(s_a.hhl.3) + * Quaternion::rotation_y(s_a.hhl.4) + * Quaternion::rotation_z(s_a.hhl.5); next.hand_r.position = Vec3::new(s_a.hhr.0, s_a.hhr.1, s_a.hhr.2); - next.hand_r.orientation = - Quaternion::rotation_x(s_a.hhr.3) * Quaternion::rotation_y(s_a.hhr.4); + next.hand_r.orientation = Quaternion::rotation_x(s_a.hhr.3) + * Quaternion::rotation_y(s_a.hhr.4) + * Quaternion::rotation_z(s_a.hhr.5); next.control.position = Vec3::new( s_a.hc.0 + (move1 * -2.0 + move2 * -8.0), diff --git a/voxygen/anim/src/character/leapmelee.rs b/voxygen/anim/src/character/leapmelee.rs index 272cde65ec..116851439c 100644 --- a/voxygen/anim/src/character/leapmelee.rs +++ b/voxygen/anim/src/character/leapmelee.rs @@ -119,9 +119,11 @@ impl Animation for LeapAnimation { match ability_info.and_then(|a| a.tool) { Some(ToolKind::Hammer) => { next.hand_l.position = Vec3::new(s_a.hhl.0, s_a.hhl.1, s_a.hhl.2); - next.hand_l.orientation = Quaternion::rotation_x(s_a.hhl.3); + next.hand_l.orientation = + Quaternion::rotation_x(s_a.hhl.3) * Quaternion::rotation_z(s_a.hhl.5); next.hand_r.position = Vec3::new(s_a.hhr.0, s_a.hhr.1, s_a.hhr.2); - next.hand_r.orientation = Quaternion::rotation_x(s_a.hhr.3); + next.hand_r.orientation = + Quaternion::rotation_x(s_a.hhr.3) * Quaternion::rotation_z(s_a.hhr.5); next.main.position = Vec3::new(0.0, 0.0, 0.0); next.main.orientation = Quaternion::rotation_y(0.0) * Quaternion::rotation_z(0.0); diff --git a/voxygen/anim/src/character/mod.rs b/voxygen/anim/src/character/mod.rs index 7e01dcde4a..ad446fcff1 100644 --- a/voxygen/anim/src/character/mod.rs +++ b/voxygen/anim/src/character/mod.rs @@ -291,10 +291,10 @@ impl<'a> From<&'a Body> for SkeletonAttr { _ => (-7.0, 7.0, 2.0, -0.1, 0.0, 0.0), }, hhl: match (body.species, body.body_type) { - _ => (-0.5, -1.0, 10.0, 4.71, 0.0, 0.0), + _ => (0.1, 0.0, 11.0, 4.71, 0.0, PI), }, hhr: match (body.species, body.body_type) { - _ => (0.0, 0.0, 0.0, 4.71, 0.0, 0.0), + _ => (0.0, 0.0, 0.0, 4.71, 0.0, PI), }, hc: match (body.species, body.body_type) { _ => (6.0, 7.0, 1.0, -0.3, -1.57, 3.64), diff --git a/voxygen/anim/src/character/staggered.rs b/voxygen/anim/src/character/staggered.rs index 644ab23884..c738a88fc9 100644 --- a/voxygen/anim/src/character/staggered.rs +++ b/voxygen/anim/src/character/staggered.rs @@ -106,10 +106,12 @@ impl Animation for StaggeredAnimation { Some(ToolKind::Hammer | ToolKind::Pick) => { next.hand_l.position = Vec3::new(s_a.hhl.0, s_a.hhl.1, s_a.hhl.2); next.hand_l.orientation = Quaternion::rotation_x(s_a.hhl.3) - * Quaternion::rotation_y(s_a.hhl.4); + * Quaternion::rotation_y(s_a.hhl.4) + * Quaternion::rotation_z(s_a.hhl.5); next.hand_r.position = Vec3::new(s_a.hhr.0, s_a.hhr.1, s_a.hhr.2); next.hand_r.orientation = Quaternion::rotation_x(s_a.hhr.3) - * Quaternion::rotation_y(s_a.hhr.4); + * Quaternion::rotation_y(s_a.hhr.4) + * Quaternion::rotation_z(s_a.hhr.5); next.control.position = Vec3::new(s_a.hc.0, s_a.hc.1, s_a.hc.2); next.control.orientation = Quaternion::rotation_x(s_a.hc.3) diff --git a/voxygen/anim/src/character/stunned.rs b/voxygen/anim/src/character/stunned.rs index c88a001e91..fa12b7a934 100644 --- a/voxygen/anim/src/character/stunned.rs +++ b/voxygen/anim/src/character/stunned.rs @@ -101,11 +101,13 @@ impl Animation for StunnedAnimation { }, Some(ToolKind::Hammer | ToolKind::Pick) => { next.hand_l.position = Vec3::new(s_a.hhl.0, s_a.hhl.1, s_a.hhl.2); - next.hand_l.orientation = - Quaternion::rotation_x(s_a.hhl.3) * Quaternion::rotation_y(s_a.hhl.4); + next.hand_l.orientation = Quaternion::rotation_x(s_a.hhl.3) + * Quaternion::rotation_y(s_a.hhl.4) + * Quaternion::rotation_z(s_a.hhl.5); next.hand_r.position = Vec3::new(s_a.hhr.0, s_a.hhr.1, s_a.hhr.2); - next.hand_r.orientation = - Quaternion::rotation_x(s_a.hhr.3) * Quaternion::rotation_y(s_a.hhr.4); + next.hand_r.orientation = Quaternion::rotation_x(s_a.hhr.3) + * Quaternion::rotation_y(s_a.hhr.4) + * Quaternion::rotation_z(s_a.hhr.5); next.control.position = Vec3::new(s_a.hc.0, s_a.hc.1, s_a.hc.2); next.control.orientation = Quaternion::rotation_x(s_a.hc.3) diff --git a/voxygen/anim/src/character/wield.rs b/voxygen/anim/src/character/wield.rs index 66c91a7d73..cc4751481b 100644 --- a/voxygen/anim/src/character/wield.rs +++ b/voxygen/anim/src/character/wield.rs @@ -166,19 +166,6 @@ impl Animation for WieldAnimation { next.control.orientation = Quaternion::rotation_x(s_a.sc.3 + u_slow * 0.15) * Quaternion::rotation_z(u_slowalt * 0.08); }, - Some(ToolKind::Dagger) => { - next.control.position = Vec3::new(0.0, 0.0, 0.0); - - next.hand_l.position = Vec3::new(0.0, 0.0, 0.0); - next.hand_l.orientation = Quaternion::rotation_x(0.0); - - next.control_l.position = Vec3::new(-7.0, 0.0, 0.0); - - next.hand_r.position = Vec3::new(0.0, 0.0, 0.0); - next.hand_r.orientation = Quaternion::rotation_x(0.0); - - next.control_r.position = Vec3::new(7.0, 0.0, 0.0); - }, Some(ToolKind::Axe) => { next.main.position = Vec3::new(0.0, 0.0, 0.0); next.main.orientation = Quaternion::rotation_x(0.0); @@ -215,11 +202,13 @@ impl Animation for WieldAnimation { }, Some(ToolKind::Hammer) | Some(ToolKind::HammerSimple) | Some(ToolKind::Pick) => { next.hand_l.position = Vec3::new(s_a.hhl.0, s_a.hhl.1, s_a.hhl.2); - next.hand_l.orientation = - Quaternion::rotation_x(s_a.hhl.3) * Quaternion::rotation_y(s_a.hhl.4); + next.hand_l.orientation = Quaternion::rotation_x(s_a.hhl.3) + * Quaternion::rotation_y(s_a.hhl.4) + * Quaternion::rotation_z(s_a.hhl.5); next.hand_r.position = Vec3::new(s_a.hhr.0, s_a.hhr.1, s_a.hhr.2); - next.hand_r.orientation = - Quaternion::rotation_x(s_a.hhr.3) * Quaternion::rotation_y(s_a.hhr.4); + next.hand_r.orientation = Quaternion::rotation_x(s_a.hhr.3) + * Quaternion::rotation_y(s_a.hhr.4) + * Quaternion::rotation_z(s_a.hhr.5); next.control.position = Vec3::new( s_a.hc.0, diff --git a/voxygen/src/scene/figure/mod.rs b/voxygen/src/scene/figure/mod.rs index ff3845c199..07dae79cbe 100644 --- a/voxygen/src/scene/figure/mod.rs +++ b/voxygen/src/scene/figure/mod.rs @@ -1385,11 +1385,29 @@ impl FigureMgr { ), } }, - CharacterState::BasicBlock { .. } => { + CharacterState::BasicBlock(s) => { + let stage_time = s.timer.as_secs_f32(); + let stage_progress = match s.stage_section { + StageSection::Buildup => { + stage_time / s.static_data.buildup_duration.as_secs_f32() + }, + StageSection::Swing => stage_time, + StageSection::Recover => { + stage_time / s.static_data.recover_duration.as_secs_f32() + }, + _ => 0.0, + }; anim::character::BlockAnimation::update_skeleton( - &CharacterSkeleton::new(holding_lantern), - (active_tool_kind, second_tool_kind, time), - state.state_time, + &target_base, + ( + hands, + active_tool_kind, + second_tool_kind, + rel_vel, + time, + Some(s.stage_section), + ), + stage_progress, &mut state_animation_rate, skeleton_attr, ) From 288a6f3a82e2af24602875def21f379930f67278 Mon Sep 17 00:00:00 2001 From: Sam Date: Mon, 19 Apr 2021 01:35:46 -0400 Subject: [PATCH 04/11] Blocking now works if no weapon is equipped in main hand. Added temp sfx for blocking and parrying. Added temp particles for successful parry. Tweaked values of default block ability. --- CHANGELOG.md | 1 + common/src/combat.rs | 17 ++++- common/src/comp/ability.rs | 4 +- common/src/comp/controller.rs | 5 +- common/src/outcome.rs | 7 +- common/src/states/utils.rs | 24 +++++-- common/systems/src/beam.rs | 2 +- common/systems/src/melee.rs | 2 +- common/systems/src/projectile.rs | 92 ++++++++++++------------ common/systems/src/shockwave.rs | 2 +- server/src/events/entity_manipulation.rs | 2 +- voxygen/src/audio/sfx/mod.rs | 10 ++- voxygen/src/scene/particle.rs | 12 ++++ 13 files changed, 114 insertions(+), 66 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7a23e1566f..2c1f1b9c00 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -47,6 +47,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Missing translations can be displayed in English. - New large birds npcs - Day period dependant wildlife spawns +- You can now block and parry with melee weapons ### Changed diff --git a/common/src/combat.rs b/common/src/combat.rs index 52ed671846..031b04d91d 100644 --- a/common/src/combat.rs +++ b/common/src/combat.rs @@ -17,6 +17,7 @@ use crate::{ }, event::ServerEvent, outcome::Outcome, + states::utils::StageSection, uid::Uid, util::Dir, }; @@ -116,7 +117,12 @@ impl Attack { pub fn effects(&self) -> impl Iterator { self.effects.iter() } - pub fn compute_damage_reduction(target: &TargetInfo, source: AttackSource, dir: Dir) -> f32 { + pub fn compute_damage_reduction( + target: &TargetInfo, + source: AttackSource, + dir: Dir, + mut emit_outcome: impl FnMut(Outcome), + ) -> f32 { let damage_reduction = Damage::compute_damage_reduction(target.inventory, target.stats); let block_reduction = match source { AttackSource::Melee => { @@ -125,7 +131,11 @@ impl Attack { { if ori.look_vec().angle_between(-*dir) < data.static_data.max_angle.to_radians() { - if data.parry { + emit_outcome(Outcome::Block { + parry: data.parry, + pos: target.pos, + }); + if data.parry && matches!(data.stage_section, StageSection::Buildup) { 1.0 } else { data.static_data.block_strength @@ -164,7 +174,8 @@ impl Attack { .filter(|d| d.target.map_or(true, |t| t == target_group)) .filter(|d| !(matches!(d.target, Some(GroupTarget::OutOfGroup)) && target_dodging)) { - let damage_reduction = Attack::compute_damage_reduction(&target, attack_source, dir); + let damage_reduction = + Attack::compute_damage_reduction(&target, attack_source, dir, |o| emit_outcome(o)); let change = damage.damage.calculate_health_change( damage_reduction, attacker.map(|a| a.uid), diff --git a/common/src/comp/ability.rs b/common/src/comp/ability.rs index 804e4d7563..36c4f720ea 100644 --- a/common/src/comp/ability.rs +++ b/common/src/comp/ability.rs @@ -350,8 +350,8 @@ impl CharacterAbility { pub fn default_block() -> CharacterAbility { CharacterAbility::BasicBlock { - buildup_duration: 0.1, - recover_duration: 0.1, + buildup_duration: 0.3, + recover_duration: 0.2, max_angle: 60.0, block_strength: 0.5, energy_cost: 50.0, diff --git a/common/src/comp/controller.rs b/common/src/comp/controller.rs index f937cb7dc7..9e13b4e327 100644 --- a/common/src/comp/controller.rs +++ b/common/src/comp/controller.rs @@ -158,7 +158,10 @@ pub enum InputKind { impl InputKind { pub fn is_ability(self) -> bool { - matches!(self, Self::Primary | Self::Secondary | Self::Ability(_)) + matches!( + self, + Self::Primary | Self::Secondary | Self::Ability(_) | Self::Block + ) } } diff --git a/common/src/outcome.rs b/common/src/outcome.rs index ecc1e08b05..2801f3a3c9 100644 --- a/common/src/outcome.rs +++ b/common/src/outcome.rs @@ -59,6 +59,10 @@ pub enum Outcome { Damage { pos: Vec3, }, + Block { + pos: Vec3, + parry: bool, + }, } impl Outcome { @@ -70,7 +74,8 @@ impl Outcome { | Outcome::Beam { pos, .. } | Outcome::SkillPointGain { pos, .. } | Outcome::SummonedCreature { pos, .. } - | Outcome::Damage { pos, .. } => Some(*pos), + | Outcome::Damage { pos, .. } + | Outcome::Block { pos, .. } => Some(*pos), Outcome::BreakBlock { pos, .. } => Some(pos.map(|e| e as f32 + 0.5)), Outcome::ExpChange { .. } | Outcome::ComboChange { .. } => None, } diff --git a/common/src/states/utils.rs b/common/src/states/utils.rs index d145ed26e4..76dd3d1ac7 100644 --- a/common/src/states/utils.rs +++ b/common/src/states/utils.rs @@ -538,21 +538,17 @@ pub fn handle_jump(data: &JoinData, update: &mut StateUpdate, strength: f32) -> } fn handle_ability(data: &JoinData, update: &mut StateUpdate, input: InputKind) { - let hands = |equip_slot| match data.inventory.equipped(equip_slot).map(|i| i.kind()) { - Some(ItemKind::Tool(tool)) => Some(tool.hands), - _ => None, - }; + let hands = get_hands(data); // Mouse1 and Skill1 always use the MainHand slot let always_main_hand = matches!(input, InputKind::Primary | InputKind::Ability(0)); - let no_main_hand = hands(EquipSlot::Mainhand).is_none(); + let no_main_hand = hands.0.is_none(); // skill_index used to select ability for the AbilityKey::Skill2 input let (equip_slot, skill_index) = if no_main_hand { (Some(EquipSlot::Offhand), 1) } else if always_main_hand { (Some(EquipSlot::Mainhand), 0) } else { - let hands = (hands(EquipSlot::Mainhand), hands(EquipSlot::Offhand)); match hands { (Some(Hands::Two), _) => (Some(EquipSlot::Mainhand), 1), (_, Some(Hands::One)) => (Some(EquipSlot::Offhand), 0), @@ -631,7 +627,10 @@ pub fn attempt_input(data: &JoinData, update: &mut StateUpdate) { pub fn handle_block_input(data: &JoinData, update: &mut StateUpdate) { let can_block = |equip_slot| matches!(unwrap_tool_data(data, equip_slot), Some(tool) if tool.can_block()); - if input_is_pressed(data, InputKind::Block) && can_block(EquipSlot::Mainhand) { + let hands = get_hands(data); + if input_is_pressed(data, InputKind::Block) + && (can_block(EquipSlot::Mainhand) || (hands.0.is_none() && can_block(EquipSlot::Offhand))) + { let ability = CharacterAbility::default_block(); if ability.requirements_paid(data, update) { update.character = CharacterState::from(( @@ -678,6 +677,17 @@ pub fn unwrap_tool_data<'a>(data: &'a JoinData, equip_slot: EquipSlot) -> Option } } +pub fn get_hands(data: &JoinData) -> (Option, Option) { + let hand = |slot| { + if let Some(ItemKind::Tool(tool)) = data.inventory.equipped(slot).map(|i| i.kind()) { + Some(tool.hands) + } else { + None + } + }; + (hand(EquipSlot::Mainhand), hand(EquipSlot::Offhand)) +} + pub fn get_crit_data(data: &JoinData, ai: AbilityInfo) -> (f32, f32) { const DEFAULT_CRIT_DATA: (f32, f32) = (0.5, 1.3); use HandInfo::*; diff --git a/common/systems/src/beam.rs b/common/systems/src/beam.rs index 7640195837..594f9ecbe5 100644 --- a/common/systems/src/beam.rs +++ b/common/systems/src/beam.rs @@ -188,7 +188,7 @@ impl<'a> System<'a> for Sys { inventory: read_data.inventories.get(target), stats: read_data.stats.get(target), health: read_data.healths.get(target), - pos: pos.0, + pos: pos_b.0, ori: read_data.orientations.get(target), char_state: read_data.character_states.get(target), }; diff --git a/common/systems/src/melee.rs b/common/systems/src/melee.rs index ab1688414c..998a67986f 100644 --- a/common/systems/src/melee.rs +++ b/common/systems/src/melee.rs @@ -146,7 +146,7 @@ impl<'a> System<'a> for Sys { inventory: read_data.inventories.get(target), stats: read_data.stats.get(target), health: read_data.healths.get(target), - pos: pos.0, + pos: pos_b.0, ori: read_data.orientations.get(target), char_state: read_data.char_states.get(target), }; diff --git a/common/systems/src/projectile.rs b/common/systems/src/projectile.rs index 2a8d10cbdf..b054377cff 100644 --- a/common/systems/src/projectile.rs +++ b/common/systems/src/projectile.rs @@ -111,56 +111,58 @@ impl<'a> System<'a> for Sys { .uid_allocator .retrieve_entity_internal(other.into()) { - let owner_entity = projectile.owner.and_then(|u| { - read_data.uid_allocator.retrieve_entity_internal(u.into()) - }); - - let attacker_info = - owner_entity.zip(projectile.owner).map(|(entity, uid)| { - AttackerInfo { - entity, - uid, - energy: read_data.energies.get(entity), - combo: read_data.combos.get(entity), - } + if let Some(pos) = read_data.positions.get(target) { + let owner_entity = projectile.owner.and_then(|u| { + read_data.uid_allocator.retrieve_entity_internal(u.into()) }); - let target_info = TargetInfo { - entity: target, - inventory: read_data.inventories.get(target), - stats: read_data.stats.get(target), - health: read_data.healths.get(target), - pos: pos.0, - // TODO: Let someone smarter figure this out - // ori: orientations.get(target), - ori: None, - char_state: read_data.character_states.get(target), - }; + let attacker_info = + owner_entity.zip(projectile.owner).map(|(entity, uid)| { + AttackerInfo { + entity, + uid, + energy: read_data.energies.get(entity), + combo: read_data.combos.get(entity), + } + }); - if let Some(&body) = read_data.bodies.get(entity) { - outcomes.push(Outcome::ProjectileHit { + let target_info = TargetInfo { + entity: target, + inventory: read_data.inventories.get(target), + stats: read_data.stats.get(target), + health: read_data.healths.get(target), pos: pos.0, - body, - vel: read_data - .velocities - .get(entity) - .map_or(Vec3::zero(), |v| v.0), - source: projectile.owner, - target: read_data.uids.get(target).copied(), - }); - } + // TODO: Let someone smarter figure this out + // ori: orientations.get(target), + ori: None, + char_state: read_data.character_states.get(target), + }; - attack.apply_attack( - target_group, - attacker_info, - target_info, - ori.look_dir(), - false, - 1.0, - AttackSource::Projectile, - |e| server_emitter.emit(e), - |o| outcomes.push(o), - ); + if let Some(&body) = read_data.bodies.get(entity) { + outcomes.push(Outcome::ProjectileHit { + pos: pos.0, + body, + vel: read_data + .velocities + .get(entity) + .map_or(Vec3::zero(), |v| v.0), + source: projectile.owner, + target: read_data.uids.get(target).copied(), + }); + } + + attack.apply_attack( + target_group, + attacker_info, + target_info, + ori.look_dir(), + false, + 1.0, + AttackSource::Projectile, + |e| server_emitter.emit(e), + |o| outcomes.push(o), + ); + } } }, projectile::Effect::Explode(e) => { diff --git a/common/systems/src/shockwave.rs b/common/systems/src/shockwave.rs index e77eff0f07..3e86f4c98e 100644 --- a/common/systems/src/shockwave.rs +++ b/common/systems/src/shockwave.rs @@ -193,7 +193,7 @@ impl<'a> System<'a> for Sys { inventory: read_data.inventories.get(target), stats: read_data.stats.get(target), health: read_data.healths.get(target), - pos: pos.0, + pos: pos_b.0, ori: read_data.orientations.get(target), char_state: read_data.character_states.get(target), }; diff --git a/server/src/events/entity_manipulation.rs b/server/src/events/entity_manipulation.rs index 1267d70c15..8ab17c7bbd 100644 --- a/server/src/events/entity_manipulation.rs +++ b/server/src/events/entity_manipulation.rs @@ -739,7 +739,7 @@ pub fn handle_explosion(server: &Server, pos: Vec3, explosion: Explosion, o inventory: inventory_b_maybe, stats: stats_b_maybe, health: Some(health_b), - pos, + pos: pos_b.0, ori: ori_b_maybe, char_state: char_state_b_maybe, }; diff --git a/voxygen/src/audio/sfx/mod.rs b/voxygen/src/audio/sfx/mod.rs index 96ea404ba2..1f2072ed4b 100644 --- a/voxygen/src/audio/sfx/mod.rs +++ b/voxygen/src/audio/sfx/mod.rs @@ -407,9 +407,6 @@ impl SfxMgr { let file_ref = "voxygen.audio.sfx.footsteps.stone_step_1"; audio.play_sfx(file_ref, pos.map(|e| e as f32 + 0.5), Some(3.0)); }, - Outcome::ExpChange { .. } - | Outcome::ComboChange { .. } - | Outcome::SummonedCreature { .. } => {}, Outcome::Damage { pos, .. } => { let file_ref = vec![ "voxygen.audio.sfx.character.hit_1", @@ -419,6 +416,13 @@ impl SfxMgr { ][rand::thread_rng().gen_range(1..4)]; audio.play_sfx(file_ref, *pos, None); }, + Outcome::Block { pos, parry: _parry } => { + // TODO: Get audio for blocking and parrying + audio.play_sfx("voxygen.audio.sfx.character.arrow_hit", *pos, Some(2.0)); + }, + Outcome::ExpChange { .. } + | Outcome::ComboChange { .. } + | Outcome::SummonedCreature { .. } => {}, } } diff --git a/voxygen/src/scene/particle.rs b/voxygen/src/scene/particle.rs index b58bbff27f..852cc28325 100644 --- a/voxygen/src/scene/particle.rs +++ b/voxygen/src/scene/particle.rs @@ -203,6 +203,18 @@ impl ParticleMgr { }); } }, + Outcome::Block { pos, parry } => { + if *parry { + self.particles.resize_with(self.particles.len() + 20, || { + Particle::new( + Duration::from_millis(200), + time, + ParticleMode::GunPowderSpark, + *pos + Vec3::unit_z(), + ) + }); + } + }, Outcome::ProjectileShot { .. } | Outcome::Beam { .. } | Outcome::ExpChange { .. } From 9f79c80072d3d5ad872d483e48d7f903b963f218 Mon Sep 17 00:00:00 2001 From: alfy <76448920+alfvy@users.noreply.github.com> Date: Wed, 21 Apr 2021 03:02:33 +0200 Subject: [PATCH 05/11] block and parry sounds added --- assets/voxygen/audio/sfx/character/block_1.ogg | 3 +++ assets/voxygen/audio/sfx/character/block_2.ogg | 3 +++ assets/voxygen/audio/sfx/character/block_3.ogg | 3 +++ assets/voxygen/audio/sfx/character/parry_1.ogg | 3 +++ assets/voxygen/audio/sfx/character/parry_2.ogg | 3 +++ voxygen/src/audio/sfx/mod.rs | 18 ++++++++++++++++-- 6 files changed, 31 insertions(+), 2 deletions(-) create mode 100644 assets/voxygen/audio/sfx/character/block_1.ogg create mode 100644 assets/voxygen/audio/sfx/character/block_2.ogg create mode 100644 assets/voxygen/audio/sfx/character/block_3.ogg create mode 100644 assets/voxygen/audio/sfx/character/parry_1.ogg create mode 100644 assets/voxygen/audio/sfx/character/parry_2.ogg diff --git a/assets/voxygen/audio/sfx/character/block_1.ogg b/assets/voxygen/audio/sfx/character/block_1.ogg new file mode 100644 index 0000000000..3cbe0eefdf --- /dev/null +++ b/assets/voxygen/audio/sfx/character/block_1.ogg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:994a0ba11843516a95430fa3c9bab86327b929bc715e25b481fa092898c78123 +size 23291 diff --git a/assets/voxygen/audio/sfx/character/block_2.ogg b/assets/voxygen/audio/sfx/character/block_2.ogg new file mode 100644 index 0000000000..4b321a5926 --- /dev/null +++ b/assets/voxygen/audio/sfx/character/block_2.ogg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:7aaf995af282f54764a458601cb503e38f7d04bf6d9d153855b4436007365550 +size 24064 diff --git a/assets/voxygen/audio/sfx/character/block_3.ogg b/assets/voxygen/audio/sfx/character/block_3.ogg new file mode 100644 index 0000000000..a5c37ccfc4 --- /dev/null +++ b/assets/voxygen/audio/sfx/character/block_3.ogg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:60e7243b87b29f6e1f1ddce65cc5f3c7c022d86be99be57c4d223872508fdf1c +size 4111 diff --git a/assets/voxygen/audio/sfx/character/parry_1.ogg b/assets/voxygen/audio/sfx/character/parry_1.ogg new file mode 100644 index 0000000000..1b718953c7 --- /dev/null +++ b/assets/voxygen/audio/sfx/character/parry_1.ogg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:dd023532c743e2b91405638efd64926e8b77de65ed5e72b74e0076217fb4c96b +size 4111 diff --git a/assets/voxygen/audio/sfx/character/parry_2.ogg b/assets/voxygen/audio/sfx/character/parry_2.ogg new file mode 100644 index 0000000000..9e2d0dacd0 --- /dev/null +++ b/assets/voxygen/audio/sfx/character/parry_2.ogg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:dfb8f2139b7779fb19e89456f1e2626ff06757a9781aad2376305ef946728af1 +size 4111 diff --git a/voxygen/src/audio/sfx/mod.rs b/voxygen/src/audio/sfx/mod.rs index 1f2072ed4b..c5df2925b2 100644 --- a/voxygen/src/audio/sfx/mod.rs +++ b/voxygen/src/audio/sfx/mod.rs @@ -416,9 +416,23 @@ impl SfxMgr { ][rand::thread_rng().gen_range(1..4)]; audio.play_sfx(file_ref, *pos, None); }, - Outcome::Block { pos, parry: _parry } => { + Outcome::Block { pos, parry } => { // TODO: Get audio for blocking and parrying - audio.play_sfx("voxygen.audio.sfx.character.arrow_hit", *pos, Some(2.0)); + let file_ref_block = vec![ + "voxygen.audio.sfx.character.block_1", + "voxygen.audio.sfx.character.block_2", + "voxygen.audio.sfx.character.block_3", + ][rand::thread_rng().gen_range(1..3)]; + let file_ref_parry = vec![ + "voxygen.audio.sfx.character.parry_1", + "voxygen.audio.sfx.character.parry_2", + ][rand::thread_rng().gen_range(1..2)]; + if *parry { + audio.play_sfx(file_ref_parry, *pos, Some(2.0)); + } + else { + audio.play_sfx(file_ref_block, *pos, Some(2.0)); + } }, Outcome::ExpChange { .. } | Outcome::ComboChange { .. } From 73cb6d19ffb5797d57dceb56d40691db7b2c19a6 Mon Sep 17 00:00:00 2001 From: alfy <76448920+alfvy@users.noreply.github.com> Date: Wed, 21 Apr 2021 18:47:09 +0200 Subject: [PATCH 06/11] Fixed the sounds since they were seemingly empty, as well as a new more organic wind sound --- assets/voxygen/audio/ambient/wind.ogg | 4 ++-- assets/voxygen/audio/sfx/character/block_1.ogg | 4 ++-- assets/voxygen/audio/sfx/character/block_2.ogg | 4 ++-- assets/voxygen/audio/sfx/character/block_3.ogg | 4 ++-- assets/voxygen/audio/sfx/character/parry_1.ogg | 4 ++-- assets/voxygen/audio/sfx/character/parry_2.ogg | 4 ++-- 6 files changed, 12 insertions(+), 12 deletions(-) diff --git a/assets/voxygen/audio/ambient/wind.ogg b/assets/voxygen/audio/ambient/wind.ogg index a351e79110..b8509325e9 100644 --- a/assets/voxygen/audio/ambient/wind.ogg +++ b/assets/voxygen/audio/ambient/wind.ogg @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:70f1ce7d6f20d94e66fa5ad45eb71f35f09312e32741772d6ff04008b1314f99 -size 257478 +oid sha256:4416db6944a76b35c8fb9994c671681970853aa521bbbf86b4f2de25638ec46a +size 351351 diff --git a/assets/voxygen/audio/sfx/character/block_1.ogg b/assets/voxygen/audio/sfx/character/block_1.ogg index 3cbe0eefdf..bc8f726218 100644 --- a/assets/voxygen/audio/sfx/character/block_1.ogg +++ b/assets/voxygen/audio/sfx/character/block_1.ogg @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:994a0ba11843516a95430fa3c9bab86327b929bc715e25b481fa092898c78123 -size 23291 +oid sha256:02b8f554bd7b0a4c86ef4dcf40933edc0f5548a39db9caf40c71f8f659d4e424 +size 20008 diff --git a/assets/voxygen/audio/sfx/character/block_2.ogg b/assets/voxygen/audio/sfx/character/block_2.ogg index 4b321a5926..f24b07d24f 100644 --- a/assets/voxygen/audio/sfx/character/block_2.ogg +++ b/assets/voxygen/audio/sfx/character/block_2.ogg @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:7aaf995af282f54764a458601cb503e38f7d04bf6d9d153855b4436007365550 -size 24064 +oid sha256:8ac1d38cf8aeec45834c57309596fe7d0d16bcc55d06a1a7fcb44e825e2aa563 +size 14764 diff --git a/assets/voxygen/audio/sfx/character/block_3.ogg b/assets/voxygen/audio/sfx/character/block_3.ogg index a5c37ccfc4..163c7f48cf 100644 --- a/assets/voxygen/audio/sfx/character/block_3.ogg +++ b/assets/voxygen/audio/sfx/character/block_3.ogg @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:60e7243b87b29f6e1f1ddce65cc5f3c7c022d86be99be57c4d223872508fdf1c -size 4111 +oid sha256:70f63b6e8dad4dadcc1d42b3045ebe49718302b4850e2cd9432cd500b5a1619b +size 21549 diff --git a/assets/voxygen/audio/sfx/character/parry_1.ogg b/assets/voxygen/audio/sfx/character/parry_1.ogg index 1b718953c7..c30b040265 100644 --- a/assets/voxygen/audio/sfx/character/parry_1.ogg +++ b/assets/voxygen/audio/sfx/character/parry_1.ogg @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:dd023532c743e2b91405638efd64926e8b77de65ed5e72b74e0076217fb4c96b -size 4111 +oid sha256:23f15dcad6a34c473fe623278a31153acc938d65ce2990cc7f69e1cd4e03fb29 +size 23921 diff --git a/assets/voxygen/audio/sfx/character/parry_2.ogg b/assets/voxygen/audio/sfx/character/parry_2.ogg index 9e2d0dacd0..38fd748211 100644 --- a/assets/voxygen/audio/sfx/character/parry_2.ogg +++ b/assets/voxygen/audio/sfx/character/parry_2.ogg @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:dfb8f2139b7779fb19e89456f1e2626ff06757a9781aad2376305ef946728af1 -size 4111 +oid sha256:f2f7cf45b1fd57c4941e7b699dca41ea7d6f85b5f4a122f8b96bf413ebef8896 +size 31716 From b9d6bd2fd2ddcd27c9c7edeb62892660e5b4e92b Mon Sep 17 00:00:00 2001 From: Sam Date: Fri, 23 Apr 2021 15:01:09 -0400 Subject: [PATCH 07/11] Parrying no longer requires releasing the block button, and instead can parry if block happened in buildup. --- assets/common/abilities/sword/spin.ron | 2 +- common/src/combat.rs | 5 +++-- common/src/comp/ability.rs | 1 - common/src/states/basic_block.rs | 9 +-------- voxygen/src/audio/sfx/mod.rs | 3 +-- 5 files changed, 6 insertions(+), 14 deletions(-) diff --git a/assets/common/abilities/sword/spin.ron b/assets/common/abilities/sword/spin.ron index a0cef50ca7..171d2ec2d2 100644 --- a/assets/common/abilities/sword/spin.ron +++ b/assets/common/abilities/sword/spin.ron @@ -1,5 +1,5 @@ SpinMelee( - buildup_duration: 0.6, + buildup_duration: 0.35, swing_duration: 0.4, recover_duration: 0.5, base_damage: 160, diff --git a/common/src/combat.rs b/common/src/combat.rs index 031b04d91d..f761f9d751 100644 --- a/common/src/combat.rs +++ b/common/src/combat.rs @@ -131,11 +131,12 @@ impl Attack { { if ori.look_vec().angle_between(-*dir) < data.static_data.max_angle.to_radians() { + let parry = matches!(data.stage_section, StageSection::Buildup); emit_outcome(Outcome::Block { - parry: data.parry, + parry, pos: target.pos, }); - if data.parry && matches!(data.stage_section, StageSection::Buildup) { + if parry { 1.0 } else { data.static_data.block_strength diff --git a/common/src/comp/ability.rs b/common/src/comp/ability.rs index 36c4f720ea..7e55976bb1 100644 --- a/common/src/comp/ability.rs +++ b/common/src/comp/ability.rs @@ -1277,7 +1277,6 @@ impl From<(&CharacterAbility, AbilityInfo)> for CharacterState { }, timer: Duration::default(), stage_section: StageSection::Buildup, - parry: false, }), CharacterAbility::Roll { energy_cost: _, diff --git a/common/src/states/basic_block.rs b/common/src/states/basic_block.rs index 4ecb58802b..dffe356fe8 100644 --- a/common/src/states/basic_block.rs +++ b/common/src/states/basic_block.rs @@ -30,8 +30,6 @@ pub struct Data { pub timer: Duration, /// What section the character stage is in pub stage_section: StageSection, - /// Whether the block was cancelled early enough to become a parry - pub parry: bool, } impl CharacterBehavior for Data { @@ -49,18 +47,13 @@ impl CharacterBehavior for Data { .timer .checked_add(Duration::from_secs_f32(data.dt.0)) .unwrap_or_default(), - parry: self.parry || !input_is_pressed(data, InputKind::Block), ..*self }); } else { // Transitions to swing section of stage update.character = CharacterState::BasicBlock(Data { timer: Duration::default(), - stage_section: if self.parry { - StageSection::Recover - } else { - StageSection::Swing - }, + stage_section: StageSection::Swing, ..*self }); } diff --git a/voxygen/src/audio/sfx/mod.rs b/voxygen/src/audio/sfx/mod.rs index c5df2925b2..2ada3b1cf1 100644 --- a/voxygen/src/audio/sfx/mod.rs +++ b/voxygen/src/audio/sfx/mod.rs @@ -429,8 +429,7 @@ impl SfxMgr { ][rand::thread_rng().gen_range(1..2)]; if *parry { audio.play_sfx(file_ref_parry, *pos, Some(2.0)); - } - else { + } else { audio.play_sfx(file_ref_block, *pos, Some(2.0)); } }, From d2d8d43410d5beae676fad918c3e790fb356a94f Mon Sep 17 00:00:00 2001 From: Sam Date: Fri, 23 Apr 2021 23:34:31 -0400 Subject: [PATCH 08/11] Addressed testing feedback. Particles better. --- assets/voxygen/shaders/particle-vert.glsl | 2 +- common/src/comp/ability.rs | 4 ++-- voxygen/src/scene/particle.rs | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/assets/voxygen/shaders/particle-vert.glsl b/assets/voxygen/shaders/particle-vert.glsl index a2c8a89ee4..dd3ca7b466 100644 --- a/assets/voxygen/shaders/particle-vert.glsl +++ b/assets/voxygen/shaders/particle-vert.glsl @@ -202,7 +202,7 @@ void main() { attr = Attr( linear_motion( normalize(vec3(rand0, rand1, rand3)) * 0.3, - normalize(vec3(rand4, rand5, rand6)) * 2.0 + grav_vel(earth_gravity) + normalize(vec3(rand4, rand5, rand6)) * 4.0 + grav_vel(earth_gravity) ), vec3(1.0), vec4(3.5, 3 + rand7, 0, 1), diff --git a/common/src/comp/ability.rs b/common/src/comp/ability.rs index 7e55976bb1..aecb1775dd 100644 --- a/common/src/comp/ability.rs +++ b/common/src/comp/ability.rs @@ -350,8 +350,8 @@ impl CharacterAbility { pub fn default_block() -> CharacterAbility { CharacterAbility::BasicBlock { - buildup_duration: 0.3, - recover_duration: 0.2, + buildup_duration: 0.35, + recover_duration: 0.3, max_angle: 60.0, block_strength: 0.5, energy_cost: 50.0, diff --git a/voxygen/src/scene/particle.rs b/voxygen/src/scene/particle.rs index 852cc28325..9fafde5e5f 100644 --- a/voxygen/src/scene/particle.rs +++ b/voxygen/src/scene/particle.rs @@ -205,7 +205,7 @@ impl ParticleMgr { }, Outcome::Block { pos, parry } => { if *parry { - self.particles.resize_with(self.particles.len() + 20, || { + self.particles.resize_with(self.particles.len() + 10, || { Particle::new( Duration::from_millis(200), time, From 372eff2a023e006c8c6345150b0e96a93b6b7a9e Mon Sep 17 00:00:00 2001 From: Sam Date: Sat, 24 Apr 2021 00:11:41 -0400 Subject: [PATCH 09/11] Initial SCT implementation to display blocks. --- common/src/combat.rs | 2 + common/src/outcome.rs | 1 + common/systems/src/beam.rs | 1 + common/systems/src/melee.rs | 4 +- common/systems/src/projectile.rs | 1 + common/systems/src/shockwave.rs | 1 + server/src/events/entity_manipulation.rs | 3 + voxygen/src/audio/sfx/mod.rs | 2 +- voxygen/src/hud/mod.rs | 134 +++++++++++++++++++---- voxygen/src/scene/particle.rs | 2 +- 10 files changed, 125 insertions(+), 26 deletions(-) diff --git a/common/src/combat.rs b/common/src/combat.rs index f761f9d751..b79c837e1e 100644 --- a/common/src/combat.rs +++ b/common/src/combat.rs @@ -61,6 +61,7 @@ pub struct AttackerInfo<'a> { #[cfg(not(target_arch = "wasm32"))] pub struct TargetInfo<'a> { pub entity: EcsEntity, + pub uid: Uid, pub inventory: Option<&'a Inventory>, pub stats: Option<&'a Stats>, pub health: Option<&'a Health>, @@ -135,6 +136,7 @@ impl Attack { emit_outcome(Outcome::Block { parry, pos: target.pos, + uid: target.uid, }); if parry { 1.0 diff --git a/common/src/outcome.rs b/common/src/outcome.rs index 2801f3a3c9..1125094511 100644 --- a/common/src/outcome.rs +++ b/common/src/outcome.rs @@ -62,6 +62,7 @@ pub enum Outcome { Block { pos: Vec3, parry: bool, + uid: Uid, }, } diff --git a/common/systems/src/beam.rs b/common/systems/src/beam.rs index 594f9ecbe5..5c0aa482c7 100644 --- a/common/systems/src/beam.rs +++ b/common/systems/src/beam.rs @@ -185,6 +185,7 @@ impl<'a> System<'a> for Sys { let target_info = TargetInfo { entity: target, + uid: *uid_b, inventory: read_data.inventories.get(target), stats: read_data.stats.get(target), health: read_data.healths.get(target), diff --git a/common/systems/src/melee.rs b/common/systems/src/melee.rs index 998a67986f..abb5aa703d 100644 --- a/common/systems/src/melee.rs +++ b/common/systems/src/melee.rs @@ -87,11 +87,12 @@ impl<'a> System<'a> for Sys { } // Go through all other entities - for (target, pos_b, health_b, body_b) in ( + for (target, pos_b, health_b, body_b, uid_b) in ( &read_data.entities, &read_data.positions, &read_data.healths, &read_data.bodies, + &read_data.uids, ) .join() { @@ -143,6 +144,7 @@ impl<'a> System<'a> for Sys { let target_info = TargetInfo { entity: target, + uid: *uid_b, inventory: read_data.inventories.get(target), stats: read_data.stats.get(target), health: read_data.healths.get(target), diff --git a/common/systems/src/projectile.rs b/common/systems/src/projectile.rs index b054377cff..9d7839b8f4 100644 --- a/common/systems/src/projectile.rs +++ b/common/systems/src/projectile.rs @@ -128,6 +128,7 @@ impl<'a> System<'a> for Sys { let target_info = TargetInfo { entity: target, + uid: other, inventory: read_data.inventories.get(target), stats: read_data.stats.get(target), health: read_data.healths.get(target), diff --git a/common/systems/src/shockwave.rs b/common/systems/src/shockwave.rs index 3e86f4c98e..0c6e1131c8 100644 --- a/common/systems/src/shockwave.rs +++ b/common/systems/src/shockwave.rs @@ -190,6 +190,7 @@ impl<'a> System<'a> for Sys { let target_info = TargetInfo { entity: target, + uid: *uid_b, inventory: read_data.inventories.get(target), stats: read_data.stats.get(target), health: read_data.healths.get(target), diff --git a/server/src/events/entity_manipulation.rs b/server/src/events/entity_manipulation.rs index 8ab17c7bbd..1151f79638 100644 --- a/server/src/events/entity_manipulation.rs +++ b/server/src/events/entity_manipulation.rs @@ -682,6 +682,7 @@ pub fn handle_explosion(server: &Server, pos: Vec3, explosion: Explosion, o stats_b_maybe, ori_b_maybe, char_state_b_maybe, + uid_b, ), ) in ( &ecs.entities(), @@ -693,6 +694,7 @@ pub fn handle_explosion(server: &Server, pos: Vec3, explosion: Explosion, o ecs.read_storage::().maybe(), ecs.read_storage::().maybe(), ecs.read_storage::().maybe(), + &ecs.read_storage::(), ), ) .join() @@ -736,6 +738,7 @@ pub fn handle_explosion(server: &Server, pos: Vec3, explosion: Explosion, o let target_info = combat::TargetInfo { entity: entity_b, + uid: *uid_b, inventory: inventory_b_maybe, stats: stats_b_maybe, health: Some(health_b), diff --git a/voxygen/src/audio/sfx/mod.rs b/voxygen/src/audio/sfx/mod.rs index 2ada3b1cf1..dd955da89d 100644 --- a/voxygen/src/audio/sfx/mod.rs +++ b/voxygen/src/audio/sfx/mod.rs @@ -416,7 +416,7 @@ impl SfxMgr { ][rand::thread_rng().gen_range(1..4)]; audio.play_sfx(file_ref, *pos, None); }, - Outcome::Block { pos, parry } => { + Outcome::Block { pos, parry, .. } => { // TODO: Get audio for blocking and parrying let file_ref_block = vec![ "voxygen.audio.sfx.character.block_1", diff --git a/voxygen/src/hud/mod.rs b/voxygen/src/hud/mod.rs index f96a46586f..3056b4d332 100644 --- a/voxygen/src/hud/mod.rs +++ b/voxygen/src/hud/mod.rs @@ -329,6 +329,11 @@ pub struct ComboFloater { pub timer: f64, } +pub struct BlockFloater { + pub owner: Uid, + pub timer: f32, +} + pub struct DebugInfo { pub tps: f64, pub frame_time: Duration, @@ -739,6 +744,13 @@ impl PromptDialogSettings { } } +pub struct Floaters { + pub exp_floaters: Vec, + pub skill_point_displays: Vec, + pub combo_floaters: VecDeque, + pub block_floaters: Vec, +} + pub struct Hud { ui: Ui, ids: Ids, @@ -765,9 +777,7 @@ pub struct Hud { hotbar: hotbar::State, events: Vec, crosshair_opacity: f32, - exp_floaters: Vec, - skill_point_displays: Vec, - combo_floaters: VecDeque, + floaters: Floaters, } impl Hud { @@ -878,9 +888,12 @@ impl Hud { hotbar: hotbar_state, events: Vec::new(), crosshair_opacity: 0.0, - exp_floaters: Vec::new(), - skill_point_displays: Vec::new(), - combo_floaters: VecDeque::new(), + floaters: Floaters { + exp_floaters: Vec::new(), + skill_point_displays: Vec::new(), + combo_floaters: VecDeque::new(), + block_floaters: Vec::new(), + }, } } @@ -1174,9 +1187,18 @@ impl Hud { } } // EXP Numbers - self.exp_floaters.retain(|f| f.timer > 0_f32); + self.floaters + .exp_floaters + .iter_mut() + .for_each(|f| f.timer -= dt.as_secs_f32()); + self.floaters.exp_floaters.retain(|f| f.timer > 0_f32); if let Some(uid) = uids.get(me) { - for floater in self.exp_floaters.iter_mut().filter(|f| f.owner == *uid) { + for floater in self + .floaters + .exp_floaters + .iter_mut() + .filter(|f| f.owner == *uid) + { let number_speed = 50.0; // Number Speed for Single EXP let player_sct_bg_id = player_sct_bg_id_walker.next( &mut self.ids.player_sct_bgs, @@ -1221,13 +1243,19 @@ impl Hud { ) .set(player_sct_id, ui_widgets); } - floater.timer -= dt.as_secs_f32(); } } // Skill points - self.skill_point_displays.retain(|d| d.timer > 0_f32); + self.floaters + .skill_point_displays + .iter_mut() + .for_each(|f| f.timer -= dt.as_secs_f32()); + self.floaters + .skill_point_displays + .retain(|d| d.timer > 0_f32); if let Some(uid) = uids.get(me) { if let Some(display) = self + .floaters .skill_point_displays .iter_mut() .find(|d| d.owner == *uid) @@ -1311,8 +1339,58 @@ impl Hud { .left_from(self.ids.player_rank_up_txt_1_bg, 5.0) .color(Some(Color::Rgba(1.0, 1.0, 1.0, fade))) .set(self.ids.player_rank_up_icon, ui_widgets); + } + } + // Scrolling Combat Text for Parrying an attack + self.floaters + .block_floaters + .iter_mut() + .for_each(|f| f.timer -= dt.as_secs_f32()); + self.floaters.block_floaters.retain(|f| f.timer > 0_f32); + if let Some(uid) = uids.get(me) { + use inline_tweak::tweak; + for floater in self + .floaters + .block_floaters + .iter_mut() + .filter(|f| f.owner == *uid) + { + let number_speed = 50.0; + let player_sct_bg_id = player_sct_bg_id_walker.next( + &mut self.ids.player_sct_bgs, + &mut ui_widgets.widget_id_generator(), + ); + let player_sct_id = player_sct_id_walker.next( + &mut self.ids.player_scts, + &mut ui_widgets.widget_id_generator(), + ); + let font_size = 30; + let y = floater.timer as f64 * number_speed; // Timer sets the widget offset + // text transparency + let fade = if floater.timer < 0.25 { + floater.timer as f32 / 0.25 + } else { + 1.0 + }; - display.timer -= dt.as_secs_f32(); + Text::new("Blocked") + .font_size(font_size) + .font_id(self.fonts.cyri.conrod_id) + .color(Color::Rgba(0.0, 0.0, 0.0, fade)) + .x_y( + ui_widgets.win_w * (tweak!(0.0)), + ui_widgets.win_h * (tweak!(-0.3)) + y - tweak!(3.0), + ) + .set(player_sct_bg_id, ui_widgets); + Text::new("Blocked") + .font_size(font_size) + .font_id(self.fonts.cyri.conrod_id) + .color(Color::Rgba(tweak!(0.9), tweak!(0.85), tweak!(0.2), fade)) + .x_y( + ui_widgets.win_w * (tweak!(0.0)), + ui_widgets.win_h * (tweak!(-0.3)) + y, + ) + .set(player_sct_id, ui_widgets); } } } @@ -2273,12 +2351,14 @@ impl Hud { let ability_map = ecs.fetch::(); let bodies = ecs.read_storage::(); // Combo floater stuffs - for combo_floater in self.combo_floaters.iter_mut() { - combo_floater.timer -= dt.as_secs_f64(); - } - self.combo_floaters.retain(|f| f.timer > 0_f64); + self.floaters + .combo_floaters + .iter_mut() + .for_each(|f| f.timer -= dt.as_secs_f64()); + self.floaters.combo_floaters.retain(|f| f.timer > 0_f64); let combo = if let Some(uid) = ecs.read_storage::().get(entity) { - self.combo_floaters + self.floaters + .combo_floaters .iter() .find(|c| c.owner == *uid) .copied() @@ -3425,7 +3505,7 @@ impl Hud { pub fn handle_outcome(&mut self, outcome: &Outcome) { match outcome { - Outcome::ExpChange { uid, exp } => self.exp_floaters.push(ExpFloater { + Outcome::ExpChange { uid, exp } => self.floaters.exp_floaters.push(ExpFloater { owner: *uid, exp_change: *exp, timer: 4.0, @@ -3436,17 +3516,25 @@ impl Hud { skill_tree, total_points, .. - } => self.skill_point_displays.push(SkillPointGain { + } => self.floaters.skill_point_displays.push(SkillPointGain { owner: *uid, skill_tree: *skill_tree, total_points: *total_points, timer: 5.0, }), - Outcome::ComboChange { uid, combo } => self.combo_floaters.push_front(ComboFloater { - owner: *uid, - combo: *combo, - timer: comp::combo::COMBO_DECAY_START, - }), + Outcome::ComboChange { uid, combo } => { + self.floaters.combo_floaters.push_front(ComboFloater { + owner: *uid, + combo: *combo, + timer: comp::combo::COMBO_DECAY_START, + }) + }, + Outcome::Block { uid, parry, .. } if *parry => { + self.floaters.block_floaters.push(BlockFloater { + owner: *uid, + timer: 1.0, + }) + }, _ => {}, } } diff --git a/voxygen/src/scene/particle.rs b/voxygen/src/scene/particle.rs index 9fafde5e5f..c9a349d96e 100644 --- a/voxygen/src/scene/particle.rs +++ b/voxygen/src/scene/particle.rs @@ -203,7 +203,7 @@ impl ParticleMgr { }); } }, - Outcome::Block { pos, parry } => { + Outcome::Block { pos, parry, .. } => { if *parry { self.particles.resize_with(self.particles.len() + 10, || { Particle::new( From 2e24fcf165545405e13a3eb5f8b3e3eeadf3f1c0 Mon Sep 17 00:00:00 2001 From: Monty Date: Sun, 25 Apr 2021 00:01:01 +0200 Subject: [PATCH 10/11] Add i18n, change SCT Blocked col and string --- assets/voxygen/i18n/en/gameinput.ron | 3 ++- voxygen/src/hud/mod.rs | 10 +++++----- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/assets/voxygen/i18n/en/gameinput.ron b/assets/voxygen/i18n/en/gameinput.ron index bdec336735..331da4aae6 100644 --- a/assets/voxygen/i18n/en/gameinput.ron +++ b/assets/voxygen/i18n/en/gameinput.ron @@ -4,7 +4,8 @@ ( string_map: { "gameinput.primary": "Basic Attack", - "gameinput.secondary": "Secondary Attack/Block/Aim", + "gameinput.secondary": "Secondary Attack", + "gameinput.block": "Block", "gameinput.slot1": "Hotbar Slot 1", "gameinput.slot2": "Hotbar Slot 2", "gameinput.slot3": "Hotbar Slot 3", diff --git a/voxygen/src/hud/mod.rs b/voxygen/src/hud/mod.rs index 3056b4d332..53b0358a6f 100644 --- a/voxygen/src/hud/mod.rs +++ b/voxygen/src/hud/mod.rs @@ -1373,7 +1373,7 @@ impl Hud { 1.0 }; - Text::new("Blocked") + Text::new(&i18n.get("hud.sct.block")) .font_size(font_size) .font_id(self.fonts.cyri.conrod_id) .color(Color::Rgba(0.0, 0.0, 0.0, fade)) @@ -1382,10 +1382,10 @@ impl Hud { ui_widgets.win_h * (tweak!(-0.3)) + y - tweak!(3.0), ) .set(player_sct_bg_id, ui_widgets); - Text::new("Blocked") + Text::new(&i18n.get("hud.sct.block")) .font_size(font_size) .font_id(self.fonts.cyri.conrod_id) - .color(Color::Rgba(tweak!(0.9), tweak!(0.85), tweak!(0.2), fade)) + .color(Color::Rgba(tweak!(0.69), tweak!(0.82), tweak!(0.88), fade)) .x_y( ui_widgets.win_w * (tweak!(0.0)), ui_widgets.win_h * (tweak!(-0.3)) + y, @@ -3656,8 +3656,8 @@ pub fn get_buff_desc(buff: BuffKind, localized_strings: &Localization) -> &str { pub fn get_buff_time(buff: BuffInfo) -> String { if let Some(dur) = buff.dur { - format!("Remaining: {:.0}s", dur.as_secs_f32()) + format!("{:.0}s", dur.as_secs_f32()) } else { - "Permanent".to_string() + "".to_string() } } From 6848851dc30ed74965f9b5c92238709299d7d6fb Mon Sep 17 00:00:00 2001 From: Sam Date: Sun, 25 Apr 2021 12:09:24 -0400 Subject: [PATCH 11/11] Cleaned up tweaks in ui and allowed sfx choosing to scale to amount of sfx variants provided. --- common/systems/src/projectile.rs | 25 ++++++++++++------------- voxygen/src/audio/sfx/mod.rs | 15 ++++++++------- voxygen/src/hud/mod.rs | 12 ++++-------- 3 files changed, 24 insertions(+), 28 deletions(-) diff --git a/common/systems/src/projectile.rs b/common/systems/src/projectile.rs index 9d7839b8f4..096f0f512d 100644 --- a/common/systems/src/projectile.rs +++ b/common/systems/src/projectile.rs @@ -61,11 +61,11 @@ impl<'a> System<'a> for Sys { let mut server_emitter = read_data.server_bus.emitter(); // Attacks - 'projectile_loop: for (entity, pos, physics, ori, mut projectile) in ( + 'projectile_loop: for (entity, pos, physics, vel, mut projectile) in ( &read_data.entities, &read_data.positions, &read_data.physics_states, - &mut orientations, + &read_data.velocities, &mut projectiles, ) .join() @@ -111,7 +111,10 @@ impl<'a> System<'a> for Sys { .uid_allocator .retrieve_entity_internal(other.into()) { - if let Some(pos) = read_data.positions.get(target) { + if let (Some(pos), Some(dir)) = ( + read_data.positions.get(target), + Dir::from_unnormalized(vel.0), + ) { let owner_entity = projectile.owner.and_then(|u| { read_data.uid_allocator.retrieve_entity_internal(u.into()) }); @@ -133,9 +136,7 @@ impl<'a> System<'a> for Sys { stats: read_data.stats.get(target), health: read_data.healths.get(target), pos: pos.0, - // TODO: Let someone smarter figure this out - // ori: orientations.get(target), - ori: None, + ori: orientations.get(target), char_state: read_data.character_states.get(target), }; @@ -156,7 +157,7 @@ impl<'a> System<'a> for Sys { target_group, attacker_info, target_info, - ori.look_dir(), + dir, false, 1.0, AttackSource::Projectile, @@ -222,12 +223,10 @@ impl<'a> System<'a> for Sys { if projectile_vanished { continue 'projectile_loop; } - } else if let Some(dir) = read_data - .velocities - .get(entity) - .and_then(|vel| Dir::from_unnormalized(vel.0)) - { - *ori = dir.into(); + } else if let Some(ori) = orientations.get_mut(entity) { + if let Some(dir) = Dir::from_unnormalized(vel.0) { + *ori = dir.into(); + } } if projectile.time_left == Duration::default() { diff --git a/voxygen/src/audio/sfx/mod.rs b/voxygen/src/audio/sfx/mod.rs index dd955da89d..fe2d0ceb7c 100644 --- a/voxygen/src/audio/sfx/mod.rs +++ b/voxygen/src/audio/sfx/mod.rs @@ -417,20 +417,21 @@ impl SfxMgr { audio.play_sfx(file_ref, *pos, None); }, Outcome::Block { pos, parry, .. } => { - // TODO: Get audio for blocking and parrying - let file_ref_block = vec![ + let block_sfx = vec![ "voxygen.audio.sfx.character.block_1", "voxygen.audio.sfx.character.block_2", "voxygen.audio.sfx.character.block_3", - ][rand::thread_rng().gen_range(1..3)]; - let file_ref_parry = vec![ + ]; + let parry_sfx = vec![ "voxygen.audio.sfx.character.parry_1", "voxygen.audio.sfx.character.parry_2", - ][rand::thread_rng().gen_range(1..2)]; + ]; if *parry { - audio.play_sfx(file_ref_parry, *pos, Some(2.0)); + let file_ref = parry_sfx[rand::thread_rng().gen_range(1..parry_sfx.len())]; + audio.play_sfx(file_ref, *pos, Some(2.0)); } else { - audio.play_sfx(file_ref_block, *pos, Some(2.0)); + let file_ref = block_sfx[rand::thread_rng().gen_range(1..block_sfx.len())]; + audio.play_sfx(file_ref, *pos, Some(2.0)); } }, Outcome::ExpChange { .. } diff --git a/voxygen/src/hud/mod.rs b/voxygen/src/hud/mod.rs index 53b0358a6f..48ee2b7816 100644 --- a/voxygen/src/hud/mod.rs +++ b/voxygen/src/hud/mod.rs @@ -1348,7 +1348,6 @@ impl Hud { .for_each(|f| f.timer -= dt.as_secs_f32()); self.floaters.block_floaters.retain(|f| f.timer > 0_f32); if let Some(uid) = uids.get(me) { - use inline_tweak::tweak; for floater in self .floaters .block_floaters @@ -1378,18 +1377,15 @@ impl Hud { .font_id(self.fonts.cyri.conrod_id) .color(Color::Rgba(0.0, 0.0, 0.0, fade)) .x_y( - ui_widgets.win_w * (tweak!(0.0)), - ui_widgets.win_h * (tweak!(-0.3)) + y - tweak!(3.0), + ui_widgets.win_w * (0.0), + ui_widgets.win_h * (-0.3) + y - 3.0, ) .set(player_sct_bg_id, ui_widgets); Text::new(&i18n.get("hud.sct.block")) .font_size(font_size) .font_id(self.fonts.cyri.conrod_id) - .color(Color::Rgba(tweak!(0.69), tweak!(0.82), tweak!(0.88), fade)) - .x_y( - ui_widgets.win_w * (tweak!(0.0)), - ui_widgets.win_h * (tweak!(-0.3)) + y, - ) + .color(Color::Rgba(0.69, 0.82, 0.88, fade)) + .x_y(ui_widgets.win_w * 0.0, ui_widgets.win_h * -0.3 + y) .set(player_sct_id, ui_widgets); } }