From fe70b7fbce393b6f634e2ac91ed4132f518cf297 Mon Sep 17 00:00:00 2001 From: Sam Date: Sat, 12 Sep 2020 20:33:46 -0500 Subject: [PATCH] Addressed second round of feedback. --- assets/voxygen/audio/sfx.ron | 6 +- common/src/comp/ability.rs | 4 +- common/src/comp/inventory/item/tool.rs | 10 +- common/src/loadout_builder.rs | 146 +++++++++++------- common/src/states/combo_melee.rs | 14 +- common/src/states/dash_melee.rs | 14 +- common/src/states/utils.rs | 2 +- common/src/sys/combat.rs | 3 +- server/src/cmd.rs | 2 +- server/src/sys/terrain.rs | 44 +----- .../audio/sfx/event_mapper/combat/tests.rs | 62 +++++--- voxygen/src/audio/sfx/mod.rs | 7 +- 12 files changed, 169 insertions(+), 145 deletions(-) diff --git a/assets/voxygen/audio/sfx.ron b/assets/voxygen/audio/sfx.ron index 9df90f404f..67cd263bd4 100644 --- a/assets/voxygen/audio/sfx.ron +++ b/assets/voxygen/audio/sfx.ron @@ -94,19 +94,19 @@ ], threshold: 0.5, ), - Attack(ComboMelee(1), Sword): ( + Attack(ComboMelee(Swing, 1), Sword): ( files: [ "voxygen.audio.sfx.abilities.swing_sword", ], threshold: 0.7, ), - Attack(ComboMelee(2), Sword): ( + Attack(ComboMelee(Swing, 2), Sword): ( files: [ "voxygen.audio.sfx.abilities.separated_second_swing", ], threshold: 0.7, ), - Attack(ComboMelee(3), Sword): ( + Attack(ComboMelee(Swing, 3), Sword): ( files: [ "voxygen.audio.sfx.abilities.separated_third_swing", ], diff --git a/common/src/comp/ability.rs b/common/src/comp/ability.rs index 5139e25c51..1d3bcd529a 100644 --- a/common/src/comp/ability.rs +++ b/common/src/comp/ability.rs @@ -20,7 +20,7 @@ pub enum CharacterAbilityType { ChargedRanged, DashMelee, BasicBlock, - ComboMelee(u32), + ComboMelee(StageSection, u32), LeapMelee, SpinMelee, GroundShockwave, @@ -35,7 +35,7 @@ impl From<&CharacterState> for CharacterAbilityType { CharacterState::DashMelee(_) => Self::DashMelee, CharacterState::BasicBlock => Self::BasicBlock, CharacterState::LeapMelee(_) => Self::LeapMelee, - CharacterState::ComboMelee(data) => Self::ComboMelee(data.stage), + CharacterState::ComboMelee(data) => Self::ComboMelee(data.stage_section, data.stage), CharacterState::SpinMelee(_) => Self::SpinMelee, CharacterState::ChargedRanged(_) => Self::ChargedRanged, CharacterState::GroundShockwave(_) => Self::ChargedRanged, diff --git a/common/src/comp/inventory/item/tool.rs b/common/src/comp/inventory/item/tool.rs index d8b9bb4bb3..0baab1e22c 100644 --- a/common/src/comp/inventory/item/tool.rs +++ b/common/src/comp/inventory/item/tool.rs @@ -124,7 +124,7 @@ impl Tool { base_damage: (100.0 * self.base_power()) as u32, max_damage: (120.0 * self.base_power()) as u32, damage_increase: (10.0 * self.base_power()) as u32, - knockback: 8.0, + knockback: 10.0, range: 4.0, angle: 30.0, base_buildup_duration: Duration::from_millis(500), @@ -137,7 +137,7 @@ impl Tool { base_damage: (80.0 * self.base_power()) as u32, max_damage: (110.0 * self.base_power()) as u32, damage_increase: (15.0 * self.base_power()) as u32, - knockback: 5.0, + knockback: 12.0, range: 3.5, angle: 180.0, base_buildup_duration: Duration::from_millis(400), @@ -170,8 +170,8 @@ impl Tool { energy_cost: 200, base_damage: (120.0 * self.base_power()) as u32, max_damage: (260.0 * self.base_power()) as u32, - base_knockback: 5.0, - max_knockback: 10.0, + base_knockback: 10.0, + max_knockback: 20.0, range: 5.0, angle: 45.0, energy_drain: 500, @@ -190,6 +190,7 @@ impl Tool { buildup_duration: Duration::from_millis(700), recover_duration: Duration::from_millis(300), base_healthchange: (-120.0 * self.base_power()) as i32, + knockback: 0.0, range: 3.5, max_angle: 20.0, }, @@ -272,6 +273,7 @@ impl Tool { buildup_duration: Duration::from_millis(100), recover_duration: Duration::from_millis(400), base_healthchange: (-50.0 * self.base_power()) as i32, + knockback: 0.0, range: 3.5, max_angle: 20.0, }], diff --git a/common/src/loadout_builder.rs b/common/src/loadout_builder.rs index 7120b48f8a..978ad61c4e 100644 --- a/common/src/loadout_builder.rs +++ b/common/src/loadout_builder.rs @@ -66,7 +66,7 @@ impl LoadoutBuilder { } /// Builds loadout of creature when spawned - pub fn build_loadout(body: Body, alignment: Alignment, mut main_tool: Option) -> Self { + pub fn build_loadout(body: Body, alignment: Alignment, mut main_tool: Option, is_giant: bool) -> Self { #![allow(clippy::single_match)] // For when this is done to more than just golems. match body { Body::Golem(golem) => match golem.species { @@ -76,6 +76,11 @@ impl LoadoutBuilder { )); }, }, + Body::Humanoid(_) => if is_giant { + main_tool = Some(Item::new_from_asset_expect( + "common.items.npc_weapons.sword.zweihander_sword_0", + )); + }, _ => {}, }; @@ -112,37 +117,27 @@ impl LoadoutBuilder { }; let loadout = match body { - Body::Humanoid(_) => match alignment { - Alignment::Npc => Loadout { + Body::Humanoid(_) => match is_giant { + true => Loadout { active_item, second_item: None, - shoulder: None, + shoulder: Some(Item::new_from_asset_expect( + "common.items.armor.shoulder.plate_0", + )), chest: Some(Item::new_from_asset_expect( - match rand::thread_rng().gen_range(0, 10) { - 0 => "common.items.armor.chest.worker_green_0", - 1 => "common.items.armor.chest.worker_green_1", - 2 => "common.items.armor.chest.worker_red_0", - 3 => "common.items.armor.chest.worker_red_1", - 4 => "common.items.armor.chest.worker_purple_0", - 5 => "common.items.armor.chest.worker_purple_1", - 6 => "common.items.armor.chest.worker_yellow_0", - 7 => "common.items.armor.chest.worker_yellow_1", - 8 => "common.items.armor.chest.worker_orange_0", - _ => "common.items.armor.chest.worker_orange_1", - }, + "common.items.armor.chest.plate_green_0", )), belt: Some(Item::new_from_asset_expect( - "common.items.armor.belt.leather_0", + "common.items.armor.belt.plate_0", + )), + hand: Some(Item::new_from_asset_expect( + "common.items.armor.hand.plate_0", )), - hand: None, pants: Some(Item::new_from_asset_expect( - "common.items.armor.pants.worker_blue_0", + "common.items.armor.pants.plate_green_0", )), foot: Some(Item::new_from_asset_expect( - match rand::thread_rng().gen_range(0, 2) { - 0 => "common.items.armor.foot.leather_0", - _ => "common.items.armor.starter.sandals_0", - }, + "common.items.armor.foot.plate_0", )), back: None, ring: None, @@ -152,38 +147,79 @@ impl LoadoutBuilder { head: None, tabard: None, }, - Alignment::Enemy => Loadout { - active_item, - second_item: None, - shoulder: Some(Item::new_from_asset_expect( - "common.items.armor.shoulder.cultist_shoulder_purple", - )), - chest: Some(Item::new_from_asset_expect( - "common.items.armor.chest.cultist_chest_purple", - )), - belt: Some(Item::new_from_asset_expect( - "common.items.armor.belt.cultist_belt", - )), - hand: Some(Item::new_from_asset_expect( - "common.items.armor.hand.cultist_hands_purple", - )), - pants: Some(Item::new_from_asset_expect( - "common.items.armor.pants.cultist_legs_purple", - )), - foot: Some(Item::new_from_asset_expect( - "common.items.armor.foot.cultist_boots", - )), - back: Some(Item::new_from_asset_expect( - "common.items.armor.back.dungeon_purple-0", - )), - ring: None, - neck: None, - lantern: Some(Item::new_from_asset_expect("common.items.lantern.black_0")), - glider: None, - head: None, - tabard: None, - }, - _ => LoadoutBuilder::animal(body).build(), + false => match alignment { + Alignment::Npc => Loadout { + active_item, + second_item: None, + shoulder: None, + chest: Some(Item::new_from_asset_expect( + match rand::thread_rng().gen_range(0, 10) { + 0 => "common.items.armor.chest.worker_green_0", + 1 => "common.items.armor.chest.worker_green_1", + 2 => "common.items.armor.chest.worker_red_0", + 3 => "common.items.armor.chest.worker_red_1", + 4 => "common.items.armor.chest.worker_purple_0", + 5 => "common.items.armor.chest.worker_purple_1", + 6 => "common.items.armor.chest.worker_yellow_0", + 7 => "common.items.armor.chest.worker_yellow_1", + 8 => "common.items.armor.chest.worker_orange_0", + _ => "common.items.armor.chest.worker_orange_1", + }, + )), + belt: Some(Item::new_from_asset_expect( + "common.items.armor.belt.leather_0", + )), + hand: None, + pants: Some(Item::new_from_asset_expect( + "common.items.armor.pants.worker_blue_0", + )), + foot: Some(Item::new_from_asset_expect( + match rand::thread_rng().gen_range(0, 2) { + 0 => "common.items.armor.foot.leather_0", + _ => "common.items.armor.starter.sandals_0", + }, + )), + back: None, + ring: None, + neck: None, + lantern: None, + glider: None, + head: None, + tabard: None, + }, + Alignment::Enemy => Loadout { + active_item, + second_item: None, + shoulder: Some(Item::new_from_asset_expect( + "common.items.armor.shoulder.cultist_shoulder_purple", + )), + chest: Some(Item::new_from_asset_expect( + "common.items.armor.chest.cultist_chest_purple", + )), + belt: Some(Item::new_from_asset_expect( + "common.items.armor.belt.cultist_belt", + )), + hand: Some(Item::new_from_asset_expect( + "common.items.armor.hand.cultist_hands_purple", + )), + pants: Some(Item::new_from_asset_expect( + "common.items.armor.pants.cultist_legs_purple", + )), + foot: Some(Item::new_from_asset_expect( + "common.items.armor.foot.cultist_boots", + )), + back: Some(Item::new_from_asset_expect( + "common.items.armor.back.dungeon_purple-0", + )), + ring: None, + neck: None, + lantern: Some(Item::new_from_asset_expect("common.items.lantern.black_0")), + glider: None, + head: None, + tabard: None, + }, + _ => LoadoutBuilder::animal(body).build(), + } }, Body::Golem(golem) => match golem.species { golem::Species::StoneGolem => Loadout { diff --git a/common/src/states/combo_melee.rs b/common/src/states/combo_melee.rs index b8d5f78d47..b158df90c8 100644 --- a/common/src/states/combo_melee.rs +++ b/common/src/states/combo_melee.rs @@ -77,13 +77,13 @@ impl CharacterBehavior for Data { // Allows for other states to interrupt this state if self.is_interruptible && !data.inputs.primary.is_pressed() { - if data.inputs.roll.is_pressed() { - handle_dodge_input(data, &mut update); - return update; - } - if data.inputs.secondary.is_pressed() { - handle_ability2_input(data, &mut update); - return update; + handle_dodge_input(data, &mut update); + handle_ability2_input(data, &mut update); + match update.character { + CharacterState::ComboMelee(_) => {}, + _ => { + return update; + }, } } diff --git a/common/src/states/dash_melee.rs b/common/src/states/dash_melee.rs index ac1ad8fd5a..678ff3c6fe 100644 --- a/common/src/states/dash_melee.rs +++ b/common/src/states/dash_melee.rs @@ -64,13 +64,13 @@ impl CharacterBehavior for Data { // Allows for other states to interrupt this state if self.static_data.is_interruptible && !data.inputs.secondary.is_pressed() { - if data.inputs.roll.is_pressed() { - handle_dodge_input(data, &mut update); - return update; - } - if data.inputs.primary.is_pressed() { - handle_ability1_input(data, &mut update); - return update; + handle_dodge_input(data, &mut update); + handle_ability1_input(data, &mut update); + match update.character { + CharacterState::DashMelee(_) => {}, + _ => { + return update; + }, } } diff --git a/common/src/states/utils.rs b/common/src/states/utils.rs index 7e10e4c86b..a7fb142081 100644 --- a/common/src/states/utils.rs +++ b/common/src/states/utils.rs @@ -350,7 +350,7 @@ pub fn unwrap_tool_data<'a>(data: &'a JoinData) -> Option<&'a Tool> { /// Determines what portion a state is in. Used in all attacks (eventually). Is /// used to control aspects of animation code, as well as logic within the /// character states. -#[derive(Clone, Copy, Debug, Eq, PartialEq, Serialize, Deserialize)] +#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)] pub enum StageSection { Buildup, Swing, diff --git a/common/src/sys/combat.rs b/common/src/sys/combat.rs index 7e022f1463..8cfc5c1c28 100644 --- a/common/src/sys/combat.rs +++ b/common/src/sys/combat.rs @@ -153,10 +153,11 @@ impl<'a> System<'a> for Sys { }); } if attack.knockback != 0.0 && damage.healthchange != 0.0 { + let kb_dir = Dir::new((pos_b.0 - pos.0).try_normalized().unwrap_or(*ori.0)); server_emitter.emit(ServerEvent::Knockback { entity: b, impulse: attack.knockback - * *Dir::slerp(ori.0, Dir::new(Vec3::new(0.0, 0.0, 1.0)), 0.5), + * *Dir::slerp(kb_dir, Dir::new(Vec3::new(0.0, 0.0, 1.0)), 0.5), }); } attack.hit_count += 1; diff --git a/server/src/cmd.rs b/server/src/cmd.rs index 0c1ca11eeb..7d793744a3 100644 --- a/server/src/cmd.rs +++ b/server/src/cmd.rs @@ -621,7 +621,7 @@ fn handle_spawn( .create_npc( pos, comp::Stats::new(get_npc_name(id).into(), body), - LoadoutBuilder::build_loadout(body, alignment, None).build(), + LoadoutBuilder::build_loadout(body, alignment, None, false).build(), body, ) .with(comp::Vel(vel)) diff --git a/server/src/sys/terrain.rs b/server/src/sys/terrain.rs index 99134bb36f..f903aa3ebf 100644 --- a/server/src/sys/terrain.rs +++ b/server/src/sys/terrain.rs @@ -1,7 +1,7 @@ use super::SysTimer; use crate::{chunk_generator::ChunkGenerator, client::Client, Tick}; use common::{ - comp::{self, bird_medium, Alignment, CharacterAbility, Player, Pos}, + comp::{self, bird_medium, Alignment, Player, Pos}, event::{EventBus, ServerEvent}, generation::get_npc_name, msg::ServerMsg, @@ -13,7 +13,7 @@ use common::{ }; use rand::Rng; use specs::{Join, Read, ReadStorage, System, Write, WriteExpect, WriteStorage}; -use std::{sync::Arc, time::Duration}; +use std::sync::Arc; use vek::*; /// This system will handle loading generated chunks and unloading @@ -115,18 +115,12 @@ impl<'a> System<'a> for Sys { let mut body = entity.body; let name = entity.name.unwrap_or_else(|| "Unnamed".to_string()); let alignment = entity.alignment; - let mut main_tool = entity.main_tool; + let main_tool = entity.main_tool; let mut stats = comp::Stats::new(name, body); // let damage = stats.level.level() as i32; TODO: Make NPC base damage // non-linearly depend on their level - if entity.is_giant { - main_tool = Some(comp::Item::new_from_asset_expect( - "common.items.npc_weapons.sword.zweihander_sword_0", - )); - } - - let mut loadout = LoadoutBuilder::build_loadout(body, alignment, main_tool).build(); + let loadout = LoadoutBuilder::build_loadout(body, alignment, main_tool, entity.is_giant).build(); let mut scale = entity.scale; @@ -157,36 +151,6 @@ impl<'a> System<'a> for Sys { body, ); } - loadout = comp::Loadout { - active_item, - second_item: None, - shoulder: Some(comp::Item::new_from_asset_expect( - "common.items.armor.shoulder.plate_0", - )), - chest: Some(comp::Item::new_from_asset_expect( - "common.items.armor.chest.plate_green_0", - )), - belt: Some(comp::Item::new_from_asset_expect( - "common.items.armor.belt.plate_0", - )), - hand: Some(comp::Item::new_from_asset_expect( - "common.items.armor.hand.plate_0", - )), - pants: Some(comp::Item::new_from_asset_expect( - "common.items.armor.pants.plate_green_0", - )), - foot: Some(comp::Item::new_from_asset_expect( - "common.items.armor.foot.plate_0", - )), - back: None, - ring: None, - neck: None, - lantern: None, - glider: None, - head: None, - tabard: None, - }; - stats.level.set_level(rand::thread_rng().gen_range(30, 35)); scale = 2.0 + rand::random::(); } diff --git a/voxygen/src/audio/sfx/event_mapper/combat/tests.rs b/voxygen/src/audio/sfx/event_mapper/combat/tests.rs index 457908ef38..86363d6bd1 100644 --- a/voxygen/src/audio/sfx/event_mapper/combat/tests.rs +++ b/voxygen/src/audio/sfx/event_mapper/combat/tests.rs @@ -113,15 +113,26 @@ fn matches_ability_stage() { }); let result = CombatEventMapper::map_event( - &CharacterState::TripleStrike(states::triple_strike::Data { - base_damage: 10, - stage: states::triple_strike::Stage::First, - stage_time_active: Duration::default(), - stage_exhausted: false, - initialized: true, - transition_style: states::triple_strike::TransitionStyle::Hold( - states::triple_strike::HoldingState::Released, - ), + &CharacterState::ComboMelee(states::combo_melee::Data { + stage_data: vec![combo_melee::Stage { + stage: 1, + base_damage: 100, + max_damage: 120, + damage_increase: 10, + knockback: 10.0, + range: 4.0, + angle: 30.0, + base_buildup_duration: Duration::from_millis(500), + base_swing_duration: Duration::from_millis(200), + base_recover_duration: Duration::from_millis(400), + forward_movement: 0.5, + }], + initial_energy_gain: 0, + max_energy_gain: 100, + energy_increase: 20, + speed_increase: 0.05, + max_speed_increase: 1.8, + is_interruptible: true, }), &PreviousEntityState { event: SfxEvent::Idle, @@ -134,7 +145,7 @@ fn matches_ability_stage() { assert_eq!( result, SfxEvent::Attack( - CharacterAbilityType::TripleStrike(states::triple_strike::Stage::First), + CharacterAbilityType::ComboMelee(states::utils::StageSection::Swing, 1), ToolCategory::Sword ) ); @@ -154,15 +165,26 @@ fn ignores_different_ability_stage() { }); let result = CombatEventMapper::map_event( - &CharacterState::TripleStrike(states::triple_strike::Data { - base_damage: 10, - stage: states::triple_strike::Stage::Second, - stage_time_active: Duration::default(), - stage_exhausted: false, - initialized: true, - transition_style: states::triple_strike::TransitionStyle::Hold( - states::triple_strike::HoldingState::Released, - ), + &CharacterState::ComboMelee(states::combo_melee::Data { + stage_data: vec![combo_melee::Stage { + stage: 1, + base_damage: 100, + max_damage: 120, + damage_increase: 10, + knockback: 10.0, + range: 4.0, + angle: 30.0, + base_buildup_duration: Duration::from_millis(500), + base_swing_duration: Duration::from_millis(200), + base_recover_duration: Duration::from_millis(400), + forward_movement: 0.5, + }], + initial_energy_gain: 0, + max_energy_gain: 100, + energy_increase: 20, + speed_increase: 0.05, + max_speed_increase: 1.8, + is_interruptible: true, }), &PreviousEntityState { event: SfxEvent::Idle, @@ -175,7 +197,7 @@ fn ignores_different_ability_stage() { assert_ne!( result, SfxEvent::Attack( - CharacterAbilityType::TripleStrike(states::triple_strike::Stage::First), + CharacterAbilityType::ComboMelee(states::utils::StageSection::Swing, 1), ToolCategory::Sword ) ); diff --git a/voxygen/src/audio/sfx/mod.rs b/voxygen/src/audio/sfx/mod.rs index 3c238bfa02..183577ac98 100644 --- a/voxygen/src/audio/sfx/mod.rs +++ b/voxygen/src/audio/sfx/mod.rs @@ -71,11 +71,10 @@ //! ], //! threshold: 1.2, //! ), -//! // A multi-stage attack ability which depends on the weapon (To do: update example) -//! Attack(TripleStrike(First), Sword): ( +//! // A multi-stage attack ability which depends on the weapon +//! Attack(ComboMelee(Swing, 1), Sword): ( //! files: [ -//! "voxygen.audio.sfx.weapon.sword_03", -//! "voxygen.audio.sfx.weapon.sword_04", +//! "voxygen.audio.sfx.abilities.swing_sword", //! ], //! threshold: 0.5, //! ),