Added sword skill tree

This commit is contained in:
Sam 2020-12-06 21:35:29 -06:00
parent 0e84ba18c2
commit cc60ca58be
29 changed files with 317 additions and 42 deletions

View File

@ -28,8 +28,8 @@ ComboMelee(
initial_energy_gain: 25,
max_energy_gain: 175,
energy_increase: 30,
speed_increase: 0.075,
max_speed_increase: 1.6,
speed_increase: 0.1,
max_speed_increase: 0.6,
scales_from_combo: 2,
is_interruptible: false,
)

View File

@ -14,8 +14,8 @@ ComboMelee(
initial_energy_gain: 50,
max_energy_gain: 150,
energy_increase: 50,
speed_increase: 0.05,
max_speed_increase: 1.4,
speed_increase: 0.1,
max_speed_increase: 0.4,
scales_from_combo: 2,
is_interruptible: false,
)

View File

@ -41,7 +41,7 @@ ComboMelee(
max_energy_gain: 200,
energy_increase: 25,
speed_increase: 0.1,
max_speed_increase: 1.8,
max_speed_increase: 0.8,
scales_from_combo: 2,
is_interruptible: true,
)

View File

@ -17,7 +17,7 @@ ComboMelee(
max_energy_gain: 0,
energy_increase: 0,
speed_increase: 0.0,
max_speed_increase: 1.0,
max_speed_increase: 0.0,
scales_from_combo: 0,
is_interruptible: false,
)

View File

@ -41,7 +41,7 @@ ComboMelee(
max_energy_gain: 0,
energy_increase: 0,
speed_increase: 0.0,
max_speed_increase: 1.0,
max_speed_increase: 0.0,
scales_from_combo: 0,
is_interruptible: false,
)

View File

@ -41,7 +41,7 @@ ComboMelee(
max_energy_gain: 0,
energy_increase: 0,
speed_increase: 0.0,
max_speed_increase: 1.0,
max_speed_increase: 0.0,
scales_from_combo: 0,
is_interruptible: false,
)

View File

@ -53,7 +53,7 @@ ComboMelee(
max_energy_gain: 0,
energy_increase: 0,
speed_increase: 0.0,
max_speed_increase: 1.0,
max_speed_increase: 0.0,
scales_from_combo: 0,
is_interruptible: false,
)

View File

@ -17,7 +17,7 @@ ComboMelee(
max_energy_gain: 0,
energy_increase: 0,
speed_increase: 0.0,
max_speed_increase: 1.0,
max_speed_increase: 0.0,
scales_from_combo: 0,
is_interruptible: false,
)

View File

@ -41,7 +41,7 @@ ComboMelee(
max_energy_gain: 0,
energy_increase: 0,
speed_increase: 0.0,
max_speed_increase: 1.0,
max_speed_increase: 0.0,
scales_from_combo: 0,
is_interruptible: false,
)

View File

@ -17,7 +17,7 @@ ComboMelee(
max_energy_gain: 0,
energy_increase: 0,
speed_increase: 0.0,
max_speed_increase: 1.0,
max_speed_increase: 0.0,
scales_from_combo: 0,
is_interruptible: false,
)

View File

@ -41,7 +41,7 @@ ComboMelee(
max_energy_gain: 0,
energy_increase: 0,
speed_increase: 0.0,
max_speed_increase: 1.0,
max_speed_increase: 0.0,
scales_from_combo: 0,
is_interruptible: false,
)

View File

@ -29,7 +29,7 @@ ComboMelee(
max_energy_gain: 0,
energy_increase: 0,
speed_increase: 0.0,
max_speed_increase: 1.0,
max_speed_increase: 0.0,
scales_from_combo: 0,
is_interruptible: false,
)

View File

@ -29,7 +29,7 @@ ComboMelee(
max_energy_gain: 0,
energy_increase: 0,
speed_increase: 0.0,
max_speed_increase: 1.0,
max_speed_increase: 0.0,
scales_from_combo: 0,
is_interruptible: false,
)

View File

@ -41,7 +41,7 @@ ComboMelee(
max_energy_gain: 0,
energy_increase: 0,
speed_increase: 0.0,
max_speed_increase: 1.0,
max_speed_increase: 0.0,
scales_from_combo: 0,
is_interruptible: false,
)

View File

@ -17,7 +17,7 @@ ComboMelee(
max_energy_gain: 0,
energy_increase: 0,
speed_increase: 0.0,
max_speed_increase: 1.0,
max_speed_increase: 0.0,
scales_from_combo: 0,
is_interruptible: false,
)

View File

@ -17,7 +17,7 @@ ComboMelee(
max_energy_gain: 0,
energy_increase: 0,
speed_increase: 0.0,
max_speed_increase: 1.0,
max_speed_increase: 0.0,
scales_from_combo: 0,
is_interruptible: false,
)

View File

@ -41,7 +41,7 @@ ComboMelee(
max_energy_gain: 0,
energy_increase: 0,
speed_increase: 0.0,
max_speed_increase: 1.0,
max_speed_increase: 0.0,
scales_from_combo: 0,
is_interruptible: false,
)

View File

@ -17,7 +17,7 @@ ComboMelee(
max_energy_gain: 0,
energy_increase: 0,
speed_increase: 0.0,
max_speed_increase: 1.0,
max_speed_increase: 0.0,
scales_from_combo: 0,
is_interruptible: false,
)

View File

@ -41,7 +41,7 @@ ComboMelee(
max_energy_gain: 0,
energy_increase: 0,
speed_increase: 0.0,
max_speed_increase: 1.0,
max_speed_increase: 0.0,
scales_from_combo: 0,
is_interruptible: false,
)

View File

@ -1,7 +1,7 @@
({
General(HealthIncrease): Some(10),
Sword(TsDamage): Some(3),
Sword(TsRegen): Some(3),
Sword(TsRegen): Some(2),
Sword(TsSpeed): Some(3),
Sword(DCost): Some(2),
Sword(DDrain): Some(2),

View File

@ -9,4 +9,12 @@
Sword(SSpeed): {Sword(SUnlockSpin): None},
Sword(SCost): {Sword(SUnlockSpin): None},
Sword(SSpins): {Sword(SUnlockSpin): None},
Sword(DDrain): {Sword(DDamage): Some(1)},
Sword(DCost): {Sword(DDamage): Some(1)},
Sword(DSpeed): {Sword(DDamage): Some(1)},
Sword(DInfinite): {Sword(DDamage): Some(1)},
Sword(DScaling): {Sword(DDamage): Some(1)},
Sword(TsDamage): {Sword(TsCombo): None},
Sword(TsRegen): {Sword(TsCombo): None},
Sword(TsSpeed): {Sword(TsCombo): None},
})

View File

@ -957,6 +957,86 @@ impl Client {
SkillGroupType::Weapon(Sword),
)));
},
"@unlock sword interrupt" => {
self.send_msg(ClientGeneral::UnlockSkill(Skill::Sword(
SwordSkill::InterruptingAttacks,
)));
},
"@unlock sword combo" => {
self.send_msg(ClientGeneral::UnlockSkill(Skill::Sword(
SwordSkill::TsCombo,
)));
},
"@unlock sword combo damage" => {
self.send_msg(ClientGeneral::UnlockSkill(Skill::Sword(
SwordSkill::TsDamage,
)));
},
"@unlock sword combo regen" => {
self.send_msg(ClientGeneral::UnlockSkill(Skill::Sword(
SwordSkill::TsRegen,
)));
},
"@unlock sword combo speed" => {
self.send_msg(ClientGeneral::UnlockSkill(Skill::Sword(
SwordSkill::TsSpeed,
)));
},
"@unlock sword dash cost" => {
self.send_msg(ClientGeneral::UnlockSkill(Skill::Sword(
SwordSkill::DCost,
)));
},
"@unlock sword dash drain" => {
self.send_msg(ClientGeneral::UnlockSkill(Skill::Sword(
SwordSkill::DDrain,
)));
},
"@unlock sword dash damage" => {
self.send_msg(ClientGeneral::UnlockSkill(Skill::Sword(
SwordSkill::DDamage,
)));
},
"@unlock sword dash scaling" => {
self.send_msg(ClientGeneral::UnlockSkill(Skill::Sword(
SwordSkill::DScaling,
)));
},
"@unlock sword dash speed" => {
self.send_msg(ClientGeneral::UnlockSkill(Skill::Sword(
SwordSkill::DSpeed,
)));
},
"@unlock sword dash infinite" => {
self.send_msg(ClientGeneral::UnlockSkill(Skill::Sword(
SwordSkill::DInfinite,
)));
},
"@unlock sword spin unlock" => {
self.send_msg(ClientGeneral::UnlockSkill(Skill::Sword(
SwordSkill::SUnlockSpin,
)));
},
"@unlock sword spin damage" => {
self.send_msg(ClientGeneral::UnlockSkill(Skill::Sword(
SwordSkill::SDamage,
)));
},
"@unlock sword spin speed" => {
self.send_msg(ClientGeneral::UnlockSkill(Skill::Sword(
SwordSkill::SSpeed,
)));
},
"@unlock sword spin cost" => {
self.send_msg(ClientGeneral::UnlockSkill(Skill::Sword(
SwordSkill::SCost,
)));
},
"@unlock sword spin num" => {
self.send_msg(ClientGeneral::UnlockSkill(Skill::Sword(
SwordSkill::SSpins,
)));
},
"@unlock axe" => {
self.send_msg(ClientGeneral::UnlockSkill(Skill::UnlockGroup(
SkillGroupType::Weapon(Axe),

View File

@ -65,9 +65,10 @@ impl Damage {
DamageSource::Melee => {
// Critical hit
let mut critdamage = 0.0;
/* Disabled so I can actually test stuff
if rand::random() {
critdamage = damage * 0.3;
}
}*/
// Armor
damage *= 1.0 - damage_reduction;

View File

@ -1,8 +1,9 @@
use crate::{
assets::{self, Asset},
comp::{
inventory::item::tool::ToolKind,
projectile::ProjectileConstructor,
Body, CharacterState, EnergySource, Gravity, LightEmitter, StateUpdate,
skills, Body, CharacterState, EnergySource, Gravity, LightEmitter, StateUpdate,
},
states::{
behavior::JoinData,
@ -11,6 +12,7 @@ use crate::{
},
Knockback,
};
use hashbrown::HashMap;
use serde::{Deserialize, Serialize};
use std::time::Duration;
use vek::Vec3;
@ -493,6 +495,131 @@ impl CharacterAbility {
_ => 0,
}
}
pub fn adjusted_by_skills(
mut self,
skills: &HashMap<skills::Skill, skills::Level>,
tool: Option<ToolKind>,
) -> Self {
use skills::Skill::*;
use CharacterAbility::*;
if let Some(tool) = tool {
match tool {
ToolKind::Sword => {
use skills::SwordSkill::*;
match self {
ComboMelee {
ref mut is_interruptible,
ref mut speed_increase,
ref mut max_speed_increase,
ref mut stage_data,
ref mut max_energy_gain,
ref mut scales_from_combo,
..
} => {
*is_interruptible = skills.contains_key(&Sword(InterruptingAttacks));
let speed_segments =
Sword(TsSpeed).get_max_level().map_or(1, |l| l + 1) as f32;
let speed_level = if skills.contains_key(&Sword(TsCombo)) {
skills
.get(&Sword(TsSpeed))
.copied()
.flatten()
.map_or(1, |l| l + 1) as f32
} else {
0.0
};
{
*speed_increase *= speed_level / speed_segments;
*max_speed_increase *= speed_level / speed_segments;
}
let energy_level = if let Some(level) =
skills.get(&Sword(TsRegen)).copied().flatten()
{
level
} else {
0
};
{
*max_energy_gain = (*max_energy_gain as f32
* ((energy_level + 1) * stage_data.len() as u16 - 1) as f32
/ ((Sword(TsRegen).get_max_level().unwrap() + 1)
* stage_data.len() as u16
- 1) as f32)
as u32;
}
*scales_from_combo = skills
.get(&Sword(TsDamage))
.copied()
.flatten()
.unwrap_or(0)
.into();
},
DashMelee {
ref mut is_interruptible,
ref mut energy_cost,
ref mut energy_drain,
ref mut base_damage,
ref mut scaled_damage,
ref mut forward_speed,
ref mut infinite_charge,
..
} => {
*is_interruptible = skills.contains_key(&Sword(InterruptingAttacks));
if let Some(level) = skills.get(&Sword(DCost)).copied().flatten() {
*energy_cost =
(*energy_cost as f32 * 0.75_f32.powi(level.into())) as u32;
}
if let Some(level) = skills.get(&Sword(DDrain)).copied().flatten() {
*energy_drain =
(*energy_drain as f32 * 0.75_f32.powi(level.into())) as u32;
}
if let Some(level) = skills.get(&Sword(DDamage)).copied().flatten() {
*base_damage =
(*base_damage as f32 * 1.2_f32.powi(level.into())) as u32;
}
if let Some(level) = skills.get(&Sword(DScaling)).copied().flatten() {
*scaled_damage =
(*scaled_damage as f32 * 1.2_f32.powi(level.into())) as u32;
}
if skills.contains_key(&Sword(DSpeed)) {
*forward_speed *= 1.5;
}
*infinite_charge = skills.contains_key(&Sword(DInfinite));
},
SpinMelee {
ref mut is_interruptible,
ref mut base_damage,
ref mut swing_duration,
ref mut energy_cost,
ref mut num_spins,
..
} => {
*is_interruptible = skills.contains_key(&Sword(InterruptingAttacks));
if let Some(level) = skills.get(&Sword(SDamage)).copied().flatten() {
*base_damage =
(*base_damage as f32 * 1.4_f32.powi(level.into())) as u32;
}
if let Some(level) = skills.get(&Sword(SSpeed)).copied().flatten() {
*swing_duration =
(*swing_duration as f32 * 0.8_f32.powi(level.into())) as u64;
}
if let Some(level) = skills.get(&Sword(SCost)).copied().flatten() {
*energy_cost =
(*energy_cost as f32 * 0.75_f32.powi(level.into())) as u32;
}
*num_spins = skills.get(&Sword(SSpins)).copied().flatten().unwrap_or(0)
as u32
+ 1;
},
_ => {},
}
},
_ => {},
}
}
self
}
}
impl From<(&CharacterAbility, AbilityKey)> for CharacterState {
@ -636,7 +763,7 @@ impl From<(&CharacterAbility, AbilityKey)> for CharacterState {
max_energy_gain: *max_energy_gain,
energy_increase: *energy_increase,
speed_increase: 1.0 - *speed_increase,
max_speed_increase: *max_speed_increase - 1.0,
max_speed_increase: *max_speed_increase,
scales_from_combo: *scales_from_combo,
is_interruptible: *is_interruptible,
ability_key: key,

View File

@ -1,7 +1,7 @@
use crate::{
comp::{
Attacking, Beam, Body, CharacterState, ControlAction, Controller, ControllerInputs, Energy,
Health, Inventory, Ori, PhysicsState, Pos, StateUpdate, Vel,
Health, Inventory, Ori, PhysicsState, Pos, StateUpdate, Stats, Vel,
},
resources::DeltaTime,
uid::Uid,
@ -57,6 +57,7 @@ pub struct JoinData<'a> {
pub physics: &'a PhysicsState,
pub attacking: Option<&'a Attacking>,
pub updater: &'a LazyUpdate,
pub stats: &'a Stats,
}
type RestrictedMut<'a, C> = PairedStorage<
@ -83,6 +84,7 @@ pub type JoinTuple<'a> = (
&'a PhysicsState,
Option<&'a Attacking>,
Option<&'a Beam>,
&'a Stats,
);
impl<'a> JoinData<'a> {
@ -102,6 +104,7 @@ impl<'a> JoinData<'a> {
body: j.10,
physics: j.11,
attacking: j.12,
stats: j.14,
updater,
dt,
}

View File

@ -74,9 +74,10 @@ pub struct StaticData {
/// Energy gain increase per combo
pub energy_increase: u32,
/// (100% - speed_increase) is percentage speed increases from current to
/// max when combo increases
/// max per combo increase
pub speed_increase: f32,
/// (100% + max_speed_increase) is the max attack speed
/// This value is the highest percentage speed can increase from the base
/// speed
pub max_speed_increase: f32,
/// Number of times damage scales with combo
pub scales_from_combo: u32,

View File

@ -1,8 +1,10 @@
use crate::{
comp::{
inventory::slot::EquipSlot,
item::{Hands, ItemKind, Tool},
quadruped_low, quadruped_medium, theropod, Body, CharacterState, StateUpdate,
item::{Hands, ItemKind, Tool, ToolKind},
quadruped_low, quadruped_medium,
skills::{Skill, SwordSkill},
theropod, Body, CharacterState, StateUpdate,
},
consts::{FRIC_GROUND, GRAVITY},
event::LocalEvent,
@ -386,10 +388,19 @@ pub fn handle_ability1_input(data: &JoinData, update: &mut StateUpdate) {
if let Some(ability) = data
.inventory
.equipped(EquipSlot::Mainhand)
.and_then(|i| i.item_config_expect().ability1.as_ref())
.and_then(|i| {
i.item_config_expect().ability1.as_ref().map(|a| {
let tool = match i.kind() {
ItemKind::Tool(tool) => Some(tool.kind),
_ => None,
};
a.clone()
.adjusted_by_skills(&data.stats.skill_set.skills, tool)
})
})
.filter(|ability| ability.requirements_paid(data, update))
{
update.character = (ability, AbilityKey::Mouse1).into();
update.character = (&ability, AbilityKey::Mouse1).into();
}
}
}
@ -422,20 +433,38 @@ pub fn handle_ability2_input(data: &JoinData, update: &mut StateUpdate) {
if let Some(ability) = data
.inventory
.equipped(EquipSlot::Mainhand)
.and_then(|i| i.item_config_expect().ability2.as_ref())
.and_then(|i| {
i.item_config_expect().ability2.as_ref().map(|a| {
let tool = match i.kind() {
ItemKind::Tool(tool) => Some(tool.kind),
_ => None,
};
a.clone()
.adjusted_by_skills(&data.stats.skill_set.skills, tool)
})
})
.filter(|ability| ability.requirements_paid(data, update))
{
update.character = (ability, AbilityKey::Mouse2).into();
update.character = (&ability, AbilityKey::Mouse2).into();
}
},
(_, Some(Hands::OneHand)) => {
if let Some(ability) = data
.inventory
.equipped(EquipSlot::Offhand)
.and_then(|i| i.item_config_expect().ability2.as_ref())
.and_then(|i| {
i.item_config_expect().ability2.as_ref().map(|a| {
let tool = match i.kind() {
ItemKind::Tool(tool) => Some(tool.kind),
_ => None,
};
a.clone()
.adjusted_by_skills(&data.stats.skill_set.skills, tool)
})
})
.filter(|ability| ability.requirements_paid(data, update))
{
update.character = (ability, AbilityKey::Mouse2).into();
update.character = (&ability, AbilityKey::Mouse2).into();
}
},
(_, _) => {},
@ -448,10 +477,33 @@ pub fn handle_ability3_input(data: &JoinData, update: &mut StateUpdate) {
if let Some(ability) = data
.inventory
.equipped(EquipSlot::Mainhand)
.and_then(|i| i.item_config_expect().ability3.as_ref())
.and_then(|i| {
let tool = match i.kind() {
ItemKind::Tool(tool) => Some(tool.kind),
_ => None,
};
i.item_config_expect().ability3
.as_ref()
.and_then(|s| match tool {
Some(ToolKind::Sword)
if !&data
.stats
.skill_set
.skills
.contains_key(&Skill::Sword(SwordSkill::SUnlockSpin)) =>
{
None
},
_ => Some(s),
})
.map(|a| {
a.clone()
.adjusted_by_skills(&data.stats.skill_set.skills, tool)
})
})
.filter(|ability| ability.requirements_paid(data, update))
{
update.character = (ability, AbilityKey::Skill1).into();
update.character = (&ability, AbilityKey::Skill1).into();
}
}
}

View File

@ -3,8 +3,8 @@ use specs::{Entities, Join, LazyUpdate, Read, ReadExpect, ReadStorage, System, W
use common::{
comp::{
inventory::slot::{EquipSlot, Slot},
Attacking, Beam, Body, CharacterState, Controller, Energy, Health, Inventory, Mounting,
Ori, PhysicsState, Pos, StateUpdate, Vel,
Attacking, Beam, Body, CharacterState, Controller, Energy, Health, Inventory, Mounting, Ori,
PhysicsState, Pos, StateUpdate, Stats, Vel,
},
event::{EventBus, LocalEvent, ServerEvent},
metrics::SysMetrics,
@ -71,6 +71,7 @@ impl<'a> System<'a> for Sys {
ReadStorage<'a, Beam>,
ReadStorage<'a, Uid>,
ReadStorage<'a, Mounting>,
ReadStorage<'a, Stats>,
);
#[allow(clippy::while_let_on_iterator)] // TODO: Pending review in #587
@ -98,6 +99,7 @@ impl<'a> System<'a> for Sys {
beam_storage,
uids,
mountings,
stats,
): Self::SystemData,
) {
let start_time = std::time::Instant::now();
@ -120,6 +122,7 @@ impl<'a> System<'a> for Sys {
&physics_states,
attacking_storage.maybe(),
beam_storage.maybe(),
&stats,
)
.join()
{

View File

@ -126,7 +126,7 @@ fn matches_ability_stage() {
max_energy_gain: 100,
energy_increase: 20,
speed_increase: 0.05,
max_speed_increase: 1.8,
max_speed_increase: 0.8,
scales_from_combo: 2,
is_interruptible: true,
ability_key: states::utils::AbilityKey::Mouse1,
@ -183,7 +183,7 @@ fn ignores_different_ability_stage() {
max_energy_gain: 100,
energy_increase: 20,
speed_increase: 0.05,
max_speed_increase: 1.8,
max_speed_increase: 0.8,
scales_from_combo: 2,
is_interruptible: true,
ability_key: states::utils::AbilityKey::Mouse1,