Addressed second round of feedback.

This commit is contained in:
Sam 2020-09-12 20:33:46 -05:00
parent b06ab250cc
commit fe70b7fbce
12 changed files with 169 additions and 145 deletions

View File

@ -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",
],

View File

@ -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,

View File

@ -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,
}],

View File

@ -66,7 +66,7 @@ impl LoadoutBuilder {
}
/// Builds loadout of creature when spawned
pub fn build_loadout(body: Body, alignment: Alignment, mut main_tool: Option<Item>) -> Self {
pub fn build_loadout(body: Body, alignment: Alignment, mut main_tool: Option<Item>, 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 {

View File

@ -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;
},
}
}

View File

@ -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;
},
}
}

View File

@ -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,

View File

@ -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;

View File

@ -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))

View File

@ -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::<f32>();
}

View File

@ -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
)
);

View File

@ -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,
//! ),