mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Merge branch 'juliancoffee/skill_boost_rework' into 'master'
ECS & Diary info synchronization See merge request veloren/veloren!2771
This commit is contained in:
commit
970d57f905
File diff suppressed because it is too large
Load Diff
@ -16,7 +16,7 @@ pub mod theropod;
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
assets::{self, Asset},
|
assets::{self, Asset},
|
||||||
consts::{HUMAN_DENSITY, WATER_DENSITY},
|
consts::{HUMANOID_HP_PER_LEVEL, HUMAN_DENSITY, WATER_DENSITY},
|
||||||
make_case_elim,
|
make_case_elim,
|
||||||
npc::NpcKind,
|
npc::NpcKind,
|
||||||
};
|
};
|
||||||
@ -563,7 +563,7 @@ impl Body {
|
|||||||
#[allow(unreachable_patterns)]
|
#[allow(unreachable_patterns)]
|
||||||
pub fn base_health_increase(&self) -> u32 {
|
pub fn base_health_increase(&self) -> u32 {
|
||||||
match self {
|
match self {
|
||||||
Body::Humanoid(_) => 50,
|
Body::Humanoid(_) => HUMANOID_HP_PER_LEVEL,
|
||||||
Body::QuadrupedSmall(quadruped_small) => match quadruped_small.species {
|
Body::QuadrupedSmall(quadruped_small) => match quadruped_small.species {
|
||||||
quadruped_small::Species::Boar => 20,
|
quadruped_small::Species::Boar => 20,
|
||||||
quadruped_small::Species::Batfox => 10,
|
quadruped_small::Species::Batfox => 10,
|
||||||
|
@ -1,9 +1,8 @@
|
|||||||
use crate::comp::Body;
|
use crate::{comp::Body, consts::ENERGY_PER_LEVEL};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use specs::{Component, DerefFlaggedStorage};
|
use specs::{Component, DerefFlaggedStorage};
|
||||||
use specs_idvs::IdvStorage;
|
use specs_idvs::IdvStorage;
|
||||||
|
|
||||||
pub const ENERGY_PER_LEVEL: u32 = 50;
|
|
||||||
#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize)]
|
#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize)]
|
||||||
pub struct Energy {
|
pub struct Energy {
|
||||||
current: u32,
|
current: u32,
|
||||||
|
@ -14,19 +14,25 @@ use std::{
|
|||||||
|
|
||||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
||||||
pub enum ToolKind {
|
pub enum ToolKind {
|
||||||
|
// weapons
|
||||||
Sword,
|
Sword,
|
||||||
Axe,
|
Axe,
|
||||||
Hammer,
|
Hammer,
|
||||||
Bow,
|
Bow,
|
||||||
Dagger,
|
|
||||||
Staff,
|
Staff,
|
||||||
Sceptre,
|
Sceptre,
|
||||||
|
// future weapons
|
||||||
|
Dagger,
|
||||||
Shield,
|
Shield,
|
||||||
Spear,
|
Spear,
|
||||||
Natural, // Intended for invisible weapons (e.g. a creature using its claws or biting)
|
// tools
|
||||||
Debug,
|
Debug,
|
||||||
Farming,
|
Farming,
|
||||||
Pick,
|
Pick,
|
||||||
|
// npcs
|
||||||
|
/// Intended for invisible weapons (e.g. a creature using its claws or
|
||||||
|
/// biting)
|
||||||
|
Natural,
|
||||||
/// This is an placeholder item, it is used by non-humanoid npcs to attack
|
/// This is an placeholder item, it is used by non-humanoid npcs to attack
|
||||||
Empty,
|
Empty,
|
||||||
}
|
}
|
||||||
|
@ -367,6 +367,7 @@ impl ProjectileConstructor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: split this to three methods per stat
|
||||||
pub fn modified_projectile(mut self, power: f32, regen: f32, range: f32) -> Self {
|
pub fn modified_projectile(mut self, power: f32, regen: f32, range: f32) -> Self {
|
||||||
use ProjectileConstructor::*;
|
use ProjectileConstructor::*;
|
||||||
match self {
|
match self {
|
||||||
|
@ -1,10 +1,6 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
assets::{self, Asset, AssetExt},
|
assets::{self, Asset, AssetExt},
|
||||||
comp::{
|
comp::item::tool::ToolKind,
|
||||||
self,
|
|
||||||
body::{humanoid, Body},
|
|
||||||
item::tool::ToolKind,
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
use hashbrown::{HashMap, HashSet};
|
use hashbrown::{HashMap, HashSet};
|
||||||
use lazy_static::lazy_static;
|
use lazy_static::lazy_static;
|
||||||
@ -47,9 +43,10 @@ impl Asset for SkillPrerequisitesMap {
|
|||||||
}
|
}
|
||||||
|
|
||||||
lazy_static! {
|
lazy_static! {
|
||||||
// Determines the skills that comprise each skill group - this data is used to determine
|
// Determines the skills that comprise each skill group.
|
||||||
// which of a player's skill groups a particular skill should be added to when a skill unlock
|
//
|
||||||
// is requested.
|
// This data is used to determine which of a player's skill groups a
|
||||||
|
// particular skill should be added to when a skill unlock is requested.
|
||||||
pub static ref SKILL_GROUP_DEFS: HashMap<SkillGroupKind, SkillGroupDef> = {
|
pub static ref SKILL_GROUP_DEFS: HashMap<SkillGroupKind, SkillGroupDef> = {
|
||||||
let map = SkillTreeMap::load_expect_cloned(
|
let map = SkillTreeMap::load_expect_cloned(
|
||||||
"common.skill_trees.skills_skill-groups_manifest",
|
"common.skill_trees.skills_skill-groups_manifest",
|
||||||
@ -98,6 +95,8 @@ lazy_static! {
|
|||||||
/// kind of active ability, or a passive effect etc. Obviously because this is
|
/// kind of active ability, or a passive effect etc. Obviously because this is
|
||||||
/// an enum it doesn't describe what the skill actually -does-, this will be
|
/// an enum it doesn't describe what the skill actually -does-, this will be
|
||||||
/// handled by dedicated ECS systems.
|
/// handled by dedicated ECS systems.
|
||||||
|
// NOTE: if skill does use some constant, add it to corresponding
|
||||||
|
// SkillTree Modifiers below.
|
||||||
#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, Serialize, Deserialize)]
|
#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, Serialize, Deserialize)]
|
||||||
pub enum Skill {
|
pub enum Skill {
|
||||||
General(GeneralSkill),
|
General(GeneralSkill),
|
||||||
@ -114,127 +113,382 @@ pub enum Skill {
|
|||||||
Pick(MiningSkill),
|
Pick(MiningSkill),
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Enum which returned as result from `boost` function
|
/// Tree of modifiers that represent how stats are
|
||||||
/// `Number` can represent values from -inf to +inf,
|
/// changed per each skill level.
|
||||||
/// but it should generaly be in range -50..50
|
|
||||||
///
|
///
|
||||||
/// Number(-25) says that some value
|
/// It's used as bridge between ECS systems
|
||||||
/// will be reduced by 25% (for example energy consumption)
|
/// and voxygen Diary for skill descriptions and helps to sync them.
|
||||||
///
|
///
|
||||||
/// Number(15) says that some value
|
/// NOTE: Just adding constant does nothing, you need to use it in both
|
||||||
/// will be increased by 15% (for example damage)
|
/// ECS systems and Diary.
|
||||||
#[derive(Debug, Clone, Copy)]
|
// TODO: make it lazy_static and move to .ron?
|
||||||
pub enum BoostValue {
|
pub const SKILL_MODIFIERS: SkillTreeModifiers = SkillTreeModifiers::get();
|
||||||
Number(i16),
|
|
||||||
NonDescriptive,
|
pub struct SkillTreeModifiers {
|
||||||
|
pub sword_tree: SwordTreeModifiers,
|
||||||
|
pub axe_tree: AxeTreeModifiers,
|
||||||
|
pub hammer_tree: HammerTreeModifiers,
|
||||||
|
pub bow_tree: BowTreeModifiers,
|
||||||
|
pub staff_tree: StaffTreeModifiers,
|
||||||
|
pub sceptre_tree: SceptreTreeModifiers,
|
||||||
|
pub mining_tree: MiningTreeModifiers,
|
||||||
|
pub general_tree: GeneralTreeModifiers,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BoostValue {
|
impl SkillTreeModifiers {
|
||||||
pub fn as_mult_maybe(self) -> Option<f32> {
|
const fn get() -> Self {
|
||||||
match self {
|
Self {
|
||||||
Self::Number(x) => Some(1.0 + x as f32 * 0.01),
|
sword_tree: SwordTreeModifiers::get(),
|
||||||
Self::NonDescriptive => None,
|
axe_tree: AxeTreeModifiers::get(),
|
||||||
}
|
hammer_tree: HammerTreeModifiers::get(),
|
||||||
}
|
bow_tree: BowTreeModifiers::get(),
|
||||||
|
staff_tree: StaffTreeModifiers::get(),
|
||||||
pub fn as_i16_maybe(self) -> Option<i16> {
|
sceptre_tree: SceptreTreeModifiers::get(),
|
||||||
match self {
|
mining_tree: MiningTreeModifiers::get(),
|
||||||
Self::Number(x) => Some(x),
|
general_tree: GeneralTreeModifiers::get(),
|
||||||
Self::NonDescriptive => None,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<i16> for BoostValue {
|
pub struct SwordTreeModifiers {
|
||||||
fn from(number: i16) -> Self { BoostValue::Number(number) }
|
pub dash: SwordDashModifiers,
|
||||||
|
pub spin: SwordSpinModifiers,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn adjust_with_level(skillset: &SkillSet, skill: Skill, effect: impl FnOnce(f32, u16)) {
|
pub struct SwordDashModifiers {
|
||||||
// NOTE: We are unwrapping before checking skill level,
|
pub energy_cost: f32,
|
||||||
// because if it falls we want know it even if we don't have this level
|
pub energy_drain: f32,
|
||||||
let multiplier = match skill.boost().as_mult_maybe() {
|
pub base_damage: f32,
|
||||||
Some(m) => m,
|
pub scaled_damage: f32,
|
||||||
None => return invalid_skill_boost(skill),
|
pub forward_speed: f32,
|
||||||
};
|
|
||||||
if let Ok(Some(level)) = skillset.skill_level(skill) {
|
|
||||||
effect(multiplier, level);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn adjust_counter_with_level(skillset: &SkillSet, skill: Skill, effect: impl FnOnce(i16, i16)) {
|
pub struct SwordSpinModifiers {
|
||||||
// NOTE: We are unwrapping before checking skill level,
|
pub base_damage: f32,
|
||||||
// because if it falls we want know it even if we don't have this level
|
pub swing_duration: f32,
|
||||||
let counter = match skill.boost().as_i16_maybe() {
|
pub energy_cost: f32,
|
||||||
Some(c) => c,
|
pub num: u32,
|
||||||
None => return invalid_skill_boost(skill),
|
|
||||||
};
|
|
||||||
if let Ok(Some(level)) = skillset.skill_level(skill) {
|
|
||||||
effect(counter, level as i16);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_if_has(skillset: &SkillSet, skill: Skill, effect: impl FnOnce(f32)) {
|
impl SwordTreeModifiers {
|
||||||
// NOTE: We are unwrapping before checking skill level,
|
const fn get() -> Self {
|
||||||
// because if it falls we want know it even if we don't have this level
|
Self {
|
||||||
let multiplier = match skill.boost().as_mult_maybe() {
|
dash: SwordDashModifiers {
|
||||||
Some(c) => c,
|
energy_cost: 0.75,
|
||||||
None => return invalid_skill_boost(skill),
|
energy_drain: 0.75,
|
||||||
};
|
base_damage: 1.2,
|
||||||
if skillset.has_skill(skill) {
|
scaled_damage: 1.2,
|
||||||
effect(multiplier);
|
forward_speed: 1.15,
|
||||||
}
|
},
|
||||||
}
|
spin: SwordSpinModifiers {
|
||||||
|
base_damage: 1.4,
|
||||||
#[track_caller]
|
swing_duration: 0.8,
|
||||||
pub fn invalid_skill_boost(skill: Skill) {
|
energy_cost: 0.75,
|
||||||
let err_msg = format!(
|
num: 1,
|
||||||
r#"
|
},
|
||||||
|
|
||||||
{:?} produced unexpected BoostValue: {:?}
|
|
||||||
|
|
||||||
Clearly that shouldn't happen and tests should catch this.
|
|
||||||
|
|
||||||
If they didn't, probably because we've added new skills/weapons.
|
|
||||||
In this case, please find `test_adjusting_skills`,
|
|
||||||
fix tests and fix corresponding `impl Boost` for this skill.
|
|
||||||
|
|
||||||
"#,
|
|
||||||
skill,
|
|
||||||
skill.boost()
|
|
||||||
);
|
|
||||||
common_base::dev_panic!(err_msg);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns value which corresponds to the boost given by this skill
|
|
||||||
pub trait Boost {
|
|
||||||
fn boost(self) -> BoostValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Boost for Skill {
|
|
||||||
fn boost(self) -> BoostValue {
|
|
||||||
match self {
|
|
||||||
// General tree boosts
|
|
||||||
Skill::General(s) => s.boost(),
|
|
||||||
// Weapon tree boosts
|
|
||||||
Skill::Sword(s) => s.boost(),
|
|
||||||
Skill::Axe(s) => s.boost(),
|
|
||||||
Skill::Hammer(s) => s.boost(),
|
|
||||||
Skill::Bow(s) => s.boost(),
|
|
||||||
Skill::Staff(s) => s.boost(),
|
|
||||||
Skill::Sceptre(s) => s.boost(),
|
|
||||||
|
|
||||||
// Movement tree boosts
|
|
||||||
Skill::Roll(s) => s.boost(),
|
|
||||||
Skill::Climb(s) => s.boost(),
|
|
||||||
Skill::Swim(s) => s.boost(),
|
|
||||||
// Non-combat tree boosts
|
|
||||||
Skill::Pick(s) => s.boost(),
|
|
||||||
// Unlock Group has more complex semantic
|
|
||||||
Skill::UnlockGroup(_) => BoostValue::NonDescriptive,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct AxeTreeModifiers {
|
||||||
|
pub spin: AxeSpinModifiers,
|
||||||
|
pub leap: AxeLeapModifiers,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct AxeSpinModifiers {
|
||||||
|
pub base_damage: f32,
|
||||||
|
pub swing_duration: f32,
|
||||||
|
pub energy_cost: f32,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct AxeLeapModifiers {
|
||||||
|
pub base_damage: f32,
|
||||||
|
pub knockback: f32,
|
||||||
|
pub energy_cost: f32,
|
||||||
|
// TODO: split to forward and vertical?
|
||||||
|
pub leap_strength: f32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AxeTreeModifiers {
|
||||||
|
const fn get() -> Self {
|
||||||
|
Self {
|
||||||
|
spin: AxeSpinModifiers {
|
||||||
|
base_damage: 1.3,
|
||||||
|
swing_duration: 0.8,
|
||||||
|
energy_cost: 0.75,
|
||||||
|
},
|
||||||
|
leap: AxeLeapModifiers {
|
||||||
|
base_damage: 1.35,
|
||||||
|
knockback: 1.4,
|
||||||
|
energy_cost: 0.75,
|
||||||
|
leap_strength: 1.2,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct HammerTreeModifiers {
|
||||||
|
pub single_strike: HammerStrikeModifiers,
|
||||||
|
pub charged: HammerChargedModifers,
|
||||||
|
pub leap: HammerLeapModifiers,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct HammerStrikeModifiers {
|
||||||
|
pub knockback: f32,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct HammerChargedModifers {
|
||||||
|
pub scaled_damage: f32,
|
||||||
|
pub scaled_knockback: f32,
|
||||||
|
pub energy_drain: f32,
|
||||||
|
pub charge_rate: f32,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct HammerLeapModifiers {
|
||||||
|
pub base_damage: f32,
|
||||||
|
pub knockback: f32,
|
||||||
|
pub energy_cost: f32,
|
||||||
|
pub leap_strength: f32,
|
||||||
|
pub range: f32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl HammerTreeModifiers {
|
||||||
|
const fn get() -> Self {
|
||||||
|
Self {
|
||||||
|
single_strike: HammerStrikeModifiers { knockback: 1.5 },
|
||||||
|
charged: HammerChargedModifers {
|
||||||
|
scaled_damage: 1.25,
|
||||||
|
scaled_knockback: 1.5,
|
||||||
|
energy_drain: 0.75,
|
||||||
|
charge_rate: 1.25,
|
||||||
|
},
|
||||||
|
leap: HammerLeapModifiers {
|
||||||
|
base_damage: 1.4,
|
||||||
|
knockback: 1.5,
|
||||||
|
energy_cost: 0.75,
|
||||||
|
leap_strength: 1.25,
|
||||||
|
range: 1.0,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct BowTreeModifiers {
|
||||||
|
pub universal: BowUniversalModifiers,
|
||||||
|
pub charged: BowChargedModifiers,
|
||||||
|
pub repeater: BowRepeaterModifiers,
|
||||||
|
pub shotgun: BowShotgunModifiers,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct BowUniversalModifiers {
|
||||||
|
// TODO: split per abilities?
|
||||||
|
pub projectile_speed: f32,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct BowChargedModifiers {
|
||||||
|
pub damage_scaling: f32,
|
||||||
|
pub regen_scaling: f32,
|
||||||
|
pub knockback_scaling: f32,
|
||||||
|
pub charge_rate: f32,
|
||||||
|
pub move_speed: f32,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct BowRepeaterModifiers {
|
||||||
|
pub power: f32,
|
||||||
|
pub energy_cost: f32,
|
||||||
|
pub max_speed: f32,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct BowShotgunModifiers {
|
||||||
|
pub power: f32,
|
||||||
|
pub energy_cost: f32,
|
||||||
|
pub num_projectiles: u32,
|
||||||
|
pub spread: f32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BowTreeModifiers {
|
||||||
|
const fn get() -> Self {
|
||||||
|
Self {
|
||||||
|
universal: BowUniversalModifiers {
|
||||||
|
projectile_speed: 1.2,
|
||||||
|
},
|
||||||
|
charged: BowChargedModifiers {
|
||||||
|
damage_scaling: 1.2,
|
||||||
|
regen_scaling: 1.2,
|
||||||
|
knockback_scaling: 1.2,
|
||||||
|
charge_rate: 1.1,
|
||||||
|
move_speed: 1.1,
|
||||||
|
},
|
||||||
|
repeater: BowRepeaterModifiers {
|
||||||
|
power: 1.2,
|
||||||
|
energy_cost: 0.8,
|
||||||
|
max_speed: 1.2,
|
||||||
|
},
|
||||||
|
shotgun: BowShotgunModifiers {
|
||||||
|
power: 1.2,
|
||||||
|
energy_cost: 1.2,
|
||||||
|
num_projectiles: 1,
|
||||||
|
spread: 0.8,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct StaffTreeModifiers {
|
||||||
|
pub fireball: StaffFireballModifiers,
|
||||||
|
pub flamethrower: StaffFlamethrowerModifiers,
|
||||||
|
pub shockwave: StaffShockwaveModifiers,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct StaffFireballModifiers {
|
||||||
|
pub power: f32,
|
||||||
|
pub regen: f32,
|
||||||
|
pub range: f32,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct StaffFlamethrowerModifiers {
|
||||||
|
pub damage: f32,
|
||||||
|
pub range: f32,
|
||||||
|
pub energy_drain: f32,
|
||||||
|
pub velocity: f32,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct StaffShockwaveModifiers {
|
||||||
|
pub damage: f32,
|
||||||
|
pub knockback: f32,
|
||||||
|
pub duration: f32,
|
||||||
|
pub energy_cost: f32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl StaffTreeModifiers {
|
||||||
|
const fn get() -> Self {
|
||||||
|
Self {
|
||||||
|
fireball: StaffFireballModifiers {
|
||||||
|
power: 1.2,
|
||||||
|
regen: 1.2,
|
||||||
|
range: 1.15,
|
||||||
|
},
|
||||||
|
flamethrower: StaffFlamethrowerModifiers {
|
||||||
|
damage: 1.3,
|
||||||
|
range: 1.25,
|
||||||
|
energy_drain: 0.8,
|
||||||
|
velocity: 1.25,
|
||||||
|
},
|
||||||
|
shockwave: StaffShockwaveModifiers {
|
||||||
|
damage: 1.3,
|
||||||
|
knockback: 1.3,
|
||||||
|
duration: 1.2,
|
||||||
|
energy_cost: 0.8,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct SceptreTreeModifiers {
|
||||||
|
pub beam: SceptreBeamModifiers,
|
||||||
|
pub healing_aura: SceptreHealingAuraModifiers,
|
||||||
|
pub warding_aura: SceptreWardingAuraModifiers,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct SceptreBeamModifiers {
|
||||||
|
pub damage: f32,
|
||||||
|
pub range: f32,
|
||||||
|
pub energy_regen: f32,
|
||||||
|
pub lifesteal: f32,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct SceptreHealingAuraModifiers {
|
||||||
|
pub strength: f32,
|
||||||
|
pub duration: f32,
|
||||||
|
pub range: f32,
|
||||||
|
pub energy_cost: f32,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct SceptreWardingAuraModifiers {
|
||||||
|
pub strength: f32,
|
||||||
|
pub duration: f32,
|
||||||
|
pub range: f32,
|
||||||
|
pub energy_cost: f32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SceptreTreeModifiers {
|
||||||
|
const fn get() -> Self {
|
||||||
|
Self {
|
||||||
|
beam: SceptreBeamModifiers {
|
||||||
|
damage: 1.2,
|
||||||
|
range: 1.2,
|
||||||
|
energy_regen: 1.2,
|
||||||
|
lifesteal: 1.15,
|
||||||
|
},
|
||||||
|
healing_aura: SceptreHealingAuraModifiers {
|
||||||
|
strength: 1.15,
|
||||||
|
duration: 1.2,
|
||||||
|
range: 1.25,
|
||||||
|
energy_cost: 0.85,
|
||||||
|
},
|
||||||
|
warding_aura: SceptreWardingAuraModifiers {
|
||||||
|
strength: 1.15,
|
||||||
|
duration: 1.2,
|
||||||
|
range: 1.25,
|
||||||
|
energy_cost: 0.85,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct MiningTreeModifiers {
|
||||||
|
pub speed: f32,
|
||||||
|
pub gem_gain: f32,
|
||||||
|
pub ore_gain: f32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MiningTreeModifiers {
|
||||||
|
const fn get() -> Self {
|
||||||
|
Self {
|
||||||
|
speed: 1.1,
|
||||||
|
gem_gain: 0.05,
|
||||||
|
ore_gain: 0.05,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct GeneralTreeModifiers {
|
||||||
|
pub roll: RollTreeModifiers,
|
||||||
|
pub swim: SwimTreeModifiers,
|
||||||
|
pub climb: ClimbTreeModifiers,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct RollTreeModifiers {
|
||||||
|
pub energy_cost: f32,
|
||||||
|
pub strength: f32,
|
||||||
|
pub duration: f32,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct SwimTreeModifiers {
|
||||||
|
pub speed: f32,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct ClimbTreeModifiers {
|
||||||
|
pub energy_cost: f32,
|
||||||
|
pub speed: f32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl GeneralTreeModifiers {
|
||||||
|
const fn get() -> Self {
|
||||||
|
Self {
|
||||||
|
roll: RollTreeModifiers {
|
||||||
|
energy_cost: 0.9,
|
||||||
|
strength: 1.1,
|
||||||
|
duration: 1.1,
|
||||||
|
},
|
||||||
|
swim: SwimTreeModifiers { speed: 1.25 },
|
||||||
|
climb: ClimbTreeModifiers {
|
||||||
|
energy_cost: 0.8,
|
||||||
|
speed: 1.2,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
pub enum SkillError {
|
pub enum SkillError {
|
||||||
MissingSkill,
|
MissingSkill,
|
||||||
}
|
}
|
||||||
@ -263,32 +517,6 @@ pub enum SwordSkill {
|
|||||||
SSpins,
|
SSpins,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Boost for SwordSkill {
|
|
||||||
fn boost(self) -> BoostValue {
|
|
||||||
match self {
|
|
||||||
// Dash
|
|
||||||
Self::DDamage => 20.into(),
|
|
||||||
Self::DCost => (-25_i16).into(),
|
|
||||||
Self::DDrain => (-25_i16).into(),
|
|
||||||
Self::DScaling => 20.into(),
|
|
||||||
Self::DSpeed => 15.into(),
|
|
||||||
// Spin
|
|
||||||
Self::SDamage => 40.into(),
|
|
||||||
Self::SSpeed => (-20_i16).into(),
|
|
||||||
Self::SCost => (-25_i16).into(),
|
|
||||||
// Non-descriptive values
|
|
||||||
Self::InterruptingAttacks
|
|
||||||
| Self::TsCombo
|
|
||||||
| Self::TsDamage
|
|
||||||
| Self::TsRegen
|
|
||||||
| Self::TsSpeed
|
|
||||||
| Self::DInfinite
|
|
||||||
| Self::UnlockSpin
|
|
||||||
| Self::SSpins => BoostValue::NonDescriptive,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, Serialize, Deserialize)]
|
#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, Serialize, Deserialize)]
|
||||||
pub enum AxeSkill {
|
pub enum AxeSkill {
|
||||||
// Double strike upgrades
|
// Double strike upgrades
|
||||||
@ -310,30 +538,6 @@ pub enum AxeSkill {
|
|||||||
LDistance,
|
LDistance,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Boost for AxeSkill {
|
|
||||||
fn boost(self) -> BoostValue {
|
|
||||||
match self {
|
|
||||||
// Spin upgrades
|
|
||||||
Self::SDamage => 30.into(),
|
|
||||||
Self::SSpeed => (-20_i16).into(),
|
|
||||||
Self::SCost => (-25_i16).into(),
|
|
||||||
// Leap upgrades
|
|
||||||
Self::LDamage => 35.into(),
|
|
||||||
Self::LKnockback => 40.into(),
|
|
||||||
Self::LCost => (-25_i16).into(),
|
|
||||||
Self::LDistance => 20.into(),
|
|
||||||
// Non-descriptive boosts
|
|
||||||
Self::UnlockLeap
|
|
||||||
| Self::DsCombo
|
|
||||||
| Self::DsDamage
|
|
||||||
| Self::DsSpeed
|
|
||||||
| Self::DsRegen
|
|
||||||
| Self::SInfinite
|
|
||||||
| Self::SHelicopter => BoostValue::NonDescriptive,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, Serialize, Deserialize)]
|
#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, Serialize, Deserialize)]
|
||||||
pub enum HammerSkill {
|
pub enum HammerSkill {
|
||||||
// Single strike upgrades
|
// Single strike upgrades
|
||||||
@ -355,30 +559,6 @@ pub enum HammerSkill {
|
|||||||
LRange,
|
LRange,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Boost for HammerSkill {
|
|
||||||
fn boost(self) -> BoostValue {
|
|
||||||
match self {
|
|
||||||
// Single strike upgrades
|
|
||||||
Self::SsKnockback => 50.into(),
|
|
||||||
// Charged melee upgrades
|
|
||||||
Self::CDamage => 25.into(),
|
|
||||||
Self::CKnockback => 50.into(),
|
|
||||||
Self::CDrain => (-25_i16).into(),
|
|
||||||
Self::CSpeed => 25.into(),
|
|
||||||
// Leap upgrades
|
|
||||||
Self::LDamage => 40.into(),
|
|
||||||
Self::LKnockback => 50.into(),
|
|
||||||
Self::LCost => (-25_i16).into(),
|
|
||||||
Self::LDistance => 25.into(),
|
|
||||||
Self::LRange => 1.into(),
|
|
||||||
// Non-descriptive values
|
|
||||||
Self::UnlockLeap | Self::SsDamage | Self::SsSpeed | Self::SsRegen => {
|
|
||||||
BoostValue::NonDescriptive
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, Serialize, Deserialize)]
|
#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, Serialize, Deserialize)]
|
||||||
pub enum BowSkill {
|
pub enum BowSkill {
|
||||||
// Passives
|
// Passives
|
||||||
@ -401,32 +581,6 @@ pub enum BowSkill {
|
|||||||
SSpread,
|
SSpread,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Boost for BowSkill {
|
|
||||||
fn boost(self) -> BoostValue {
|
|
||||||
match self {
|
|
||||||
// Passive
|
|
||||||
Self::ProjSpeed => 20.into(),
|
|
||||||
// Charged upgrades
|
|
||||||
Self::CDamage => 20.into(),
|
|
||||||
Self::CRegen => 20.into(),
|
|
||||||
Self::CKnockback => 20.into(),
|
|
||||||
Self::CSpeed => 10.into(),
|
|
||||||
Self::CMove => 10.into(),
|
|
||||||
// Repeater upgrades
|
|
||||||
Self::RDamage => 20.into(),
|
|
||||||
Self::RCost => (-20_i16).into(),
|
|
||||||
Self::RSpeed => 20.into(),
|
|
||||||
// Shotgun upgrades
|
|
||||||
Self::SDamage => 20.into(),
|
|
||||||
Self::SCost => (-20_i16).into(),
|
|
||||||
Self::SArrows => 1.into(),
|
|
||||||
Self::SSpread => (-20_i16).into(),
|
|
||||||
// Non-descriptive values
|
|
||||||
Self::UnlockShotgun => BoostValue::NonDescriptive,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, Serialize, Deserialize)]
|
#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, Serialize, Deserialize)]
|
||||||
pub enum StaffSkill {
|
pub enum StaffSkill {
|
||||||
// Basic ranged upgrades
|
// Basic ranged upgrades
|
||||||
@ -446,29 +600,6 @@ pub enum StaffSkill {
|
|||||||
SCost,
|
SCost,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Boost for StaffSkill {
|
|
||||||
fn boost(self) -> BoostValue {
|
|
||||||
match self {
|
|
||||||
// Fireball upgrades
|
|
||||||
Self::BDamage => 20.into(),
|
|
||||||
Self::BRegen => 20.into(),
|
|
||||||
Self::BRadius => 15.into(),
|
|
||||||
// Flamethrower upgrades
|
|
||||||
Self::FDamage => 30.into(),
|
|
||||||
Self::FRange => 25.into(),
|
|
||||||
Self::FDrain => (-20_i16).into(),
|
|
||||||
Self::FVelocity => 25.into(),
|
|
||||||
// Shockwave upgrades
|
|
||||||
Self::SDamage => 30.into(),
|
|
||||||
Self::SKnockback => 30.into(),
|
|
||||||
Self::SRange => 20.into(),
|
|
||||||
Self::SCost => (-20_i16).into(),
|
|
||||||
// Non-descriptive values
|
|
||||||
Self::UnlockShockwave => BoostValue::NonDescriptive,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, Serialize, Deserialize)]
|
#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, Serialize, Deserialize)]
|
||||||
pub enum SceptreSkill {
|
pub enum SceptreSkill {
|
||||||
// Lifesteal beam upgrades
|
// Lifesteal beam upgrades
|
||||||
@ -476,7 +607,7 @@ pub enum SceptreSkill {
|
|||||||
LRange,
|
LRange,
|
||||||
LLifesteal,
|
LLifesteal,
|
||||||
LRegen,
|
LRegen,
|
||||||
// Healing beam upgrades
|
// Healing aura upgrades
|
||||||
HHeal,
|
HHeal,
|
||||||
HRange,
|
HRange,
|
||||||
HDuration,
|
HDuration,
|
||||||
@ -489,53 +620,12 @@ pub enum SceptreSkill {
|
|||||||
ACost,
|
ACost,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Boost for SceptreSkill {
|
|
||||||
fn boost(self) -> BoostValue {
|
|
||||||
match self {
|
|
||||||
// Lifesteal beam upgrades
|
|
||||||
Self::LDamage => 20.into(),
|
|
||||||
Self::LRange => 20.into(),
|
|
||||||
Self::LRegen => 20.into(),
|
|
||||||
Self::LLifesteal => 15.into(),
|
|
||||||
// Healing beam upgrades
|
|
||||||
Self::HHeal => 20.into(),
|
|
||||||
Self::HRange => 20.into(),
|
|
||||||
Self::HDuration => 20.into(),
|
|
||||||
Self::HCost => (-20_i16).into(),
|
|
||||||
// Warding aura upgrades
|
|
||||||
Self::AStrength => 15.into(),
|
|
||||||
Self::ADuration => 20.into(),
|
|
||||||
Self::ARange => 25.into(),
|
|
||||||
Self::ACost => (-15_i16).into(),
|
|
||||||
Self::UnlockAura => BoostValue::NonDescriptive,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, Serialize, Deserialize)]
|
#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, Serialize, Deserialize)]
|
||||||
pub enum GeneralSkill {
|
pub enum GeneralSkill {
|
||||||
HealthIncrease,
|
HealthIncrease,
|
||||||
EnergyIncrease,
|
EnergyIncrease,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Boost for GeneralSkill {
|
|
||||||
fn boost(self) -> BoostValue {
|
|
||||||
// NOTE: These should be used only for UI.
|
|
||||||
// Source of truth are corresponding systems
|
|
||||||
match self {
|
|
||||||
Self::HealthIncrease => {
|
|
||||||
let health_increase =
|
|
||||||
(Body::Humanoid(humanoid::Body::random()).base_health_increase() / 10) as i16;
|
|
||||||
health_increase.into()
|
|
||||||
},
|
|
||||||
Self::EnergyIncrease => {
|
|
||||||
let energy_increase = (comp::energy::ENERGY_PER_LEVEL / 10) as i16;
|
|
||||||
energy_increase.into()
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, Serialize, Deserialize)]
|
#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, Serialize, Deserialize)]
|
||||||
pub enum RollSkill {
|
pub enum RollSkill {
|
||||||
Cost,
|
Cost,
|
||||||
@ -543,44 +633,17 @@ pub enum RollSkill {
|
|||||||
Duration,
|
Duration,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Boost for RollSkill {
|
|
||||||
fn boost(self) -> BoostValue {
|
|
||||||
match self {
|
|
||||||
Self::Cost => (-10_i16).into(),
|
|
||||||
Self::Strength => 10.into(),
|
|
||||||
Self::Duration => 10.into(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, Serialize, Deserialize)]
|
#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, Serialize, Deserialize)]
|
||||||
pub enum ClimbSkill {
|
pub enum ClimbSkill {
|
||||||
Cost,
|
Cost,
|
||||||
Speed,
|
Speed,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Boost for ClimbSkill {
|
|
||||||
fn boost(self) -> BoostValue {
|
|
||||||
match self {
|
|
||||||
Self::Cost => (-20_i16).into(),
|
|
||||||
Self::Speed => 20.into(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, Serialize, Deserialize)]
|
#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, Serialize, Deserialize)]
|
||||||
pub enum SwimSkill {
|
pub enum SwimSkill {
|
||||||
Speed,
|
Speed,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Boost for SwimSkill {
|
|
||||||
fn boost(self) -> BoostValue {
|
|
||||||
match self {
|
|
||||||
Self::Speed => 25.into(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, Serialize, Deserialize)]
|
#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, Serialize, Deserialize)]
|
||||||
pub enum MiningSkill {
|
pub enum MiningSkill {
|
||||||
Speed,
|
Speed,
|
||||||
@ -588,16 +651,6 @@ pub enum MiningSkill {
|
|||||||
GemGain,
|
GemGain,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Boost for MiningSkill {
|
|
||||||
fn boost(self) -> BoostValue {
|
|
||||||
match self {
|
|
||||||
Self::Speed => 10.into(),
|
|
||||||
Self::OreGain => 5.into(),
|
|
||||||
Self::GemGain => 5.into(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, Serialize, Deserialize)]
|
#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, Serialize, Deserialize)]
|
||||||
pub enum SkillGroupKind {
|
pub enum SkillGroupKind {
|
||||||
General,
|
General,
|
||||||
@ -956,6 +1009,15 @@ impl SkillSet {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the level of the skill or passed value as default
|
||||||
|
pub fn skill_level_or(&self, skill: Skill, default: u16) -> u16 {
|
||||||
|
if let Ok(Some(level)) = self.skill_level(skill) {
|
||||||
|
level
|
||||||
|
} else {
|
||||||
|
default
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Checks the next level of a skill
|
/// Checks the next level of a skill
|
||||||
fn next_skill_level(&self, skill: Skill) -> Option<u16> {
|
fn next_skill_level(&self, skill: Skill) -> Option<u16> {
|
||||||
if let Ok(level) = self.skill_level(skill) {
|
if let Ok(level) = self.skill_level(skill) {
|
||||||
|
@ -26,3 +26,7 @@ pub const MIN_RECOMMENDED_RAYON_THREADS: usize = 2;
|
|||||||
pub const MIN_RECOMMENDED_TOKIO_THREADS: usize = 2;
|
pub const MIN_RECOMMENDED_TOKIO_THREADS: usize = 2;
|
||||||
|
|
||||||
pub const SOUND_TRAVEL_DIST_PER_VOLUME: f32 = 3.0;
|
pub const SOUND_TRAVEL_DIST_PER_VOLUME: f32 = 3.0;
|
||||||
|
|
||||||
|
// Stat increase per level (multiplied by 10 compared to what you'll see in UI)
|
||||||
|
pub const ENERGY_PER_LEVEL: u32 = 50;
|
||||||
|
pub const HUMANOID_HP_PER_LEVEL: u32 = 50;
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
comp::{
|
comp::{
|
||||||
skills::{ClimbSkill::*, Skill},
|
skills::{ClimbSkill::*, Skill, SKILL_MODIFIERS},
|
||||||
CharacterState, Climb, EnergySource, InputKind, Ori, StateUpdate,
|
CharacterState, Climb, EnergySource, InputKind, Ori, StateUpdate,
|
||||||
},
|
},
|
||||||
consts::GRAVITY,
|
consts::GRAVITY,
|
||||||
@ -30,12 +30,13 @@ pub struct Data {
|
|||||||
|
|
||||||
impl Data {
|
impl Data {
|
||||||
pub fn create_adjusted_by_skills(join_data: &JoinData) -> Self {
|
pub fn create_adjusted_by_skills(join_data: &JoinData) -> Self {
|
||||||
|
let modifiers = SKILL_MODIFIERS.general_tree.climb;
|
||||||
let mut data = Data::default();
|
let mut data = Data::default();
|
||||||
if let Ok(Some(level)) = join_data.skill_set.skill_level(Skill::Climb(Cost)) {
|
if let Ok(Some(level)) = join_data.skill_set.skill_level(Skill::Climb(Cost)) {
|
||||||
data.static_data.energy_cost *= 0.8_f32.powi(level.into());
|
data.static_data.energy_cost *= modifiers.energy_cost.powi(level.into());
|
||||||
}
|
}
|
||||||
if let Ok(Some(level)) = join_data.skill_set.skill_level(Skill::Climb(Speed)) {
|
if let Ok(Some(level)) = join_data.skill_set.skill_level(Skill::Climb(Speed)) {
|
||||||
data.static_data.movement_speed *= 1.2_f32.powi(level.into());
|
data.static_data.movement_speed *= modifiers.speed.powi(level.into());
|
||||||
}
|
}
|
||||||
data
|
data
|
||||||
}
|
}
|
||||||
|
@ -98,6 +98,7 @@ impl Stage<f32> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: name it as using knockback
|
||||||
pub fn modify_strike(mut self, knockback_mult: f32) -> Self {
|
pub fn modify_strike(mut self, knockback_mult: f32) -> Self {
|
||||||
self.knockback *= knockback_mult;
|
self.knockback *= knockback_mult;
|
||||||
self
|
self
|
||||||
|
@ -6,7 +6,7 @@ use crate::{
|
|||||||
inventory::slot::{EquipSlot, Slot},
|
inventory::slot::{EquipSlot, Slot},
|
||||||
item::{Hands, ItemKind, Tool, ToolKind},
|
item::{Hands, ItemKind, Tool, ToolKind},
|
||||||
quadruped_low, quadruped_medium, quadruped_small,
|
quadruped_low, quadruped_medium, quadruped_small,
|
||||||
skills::{Skill, SwimSkill},
|
skills::{Skill, SwimSkill, SKILL_MODIFIERS},
|
||||||
theropod, Body, CharacterAbility, CharacterState, Density, InputAttr, InputKind,
|
theropod, Body, CharacterAbility, CharacterState, Density, InputAttr, InputKind,
|
||||||
InventoryAction, StateUpdate,
|
InventoryAction, StateUpdate,
|
||||||
},
|
},
|
||||||
@ -391,7 +391,8 @@ fn swim_move(
|
|||||||
let mut water_accel = force / data.mass.0;
|
let mut water_accel = force / data.mass.0;
|
||||||
|
|
||||||
if let Ok(Some(level)) = data.skill_set.skill_level(Skill::Swim(SwimSkill::Speed)) {
|
if let Ok(Some(level)) = data.skill_set.skill_level(Skill::Swim(SwimSkill::Speed)) {
|
||||||
water_accel *= 1.25_f32.powi(level.into());
|
let modifiers = SKILL_MODIFIERS.general_tree.swim;
|
||||||
|
water_accel *= modifiers.speed.powi(level.into());
|
||||||
}
|
}
|
||||||
|
|
||||||
let dir = if data.body.can_strafe() {
|
let dir = if data.body.can_strafe() {
|
||||||
|
@ -349,29 +349,32 @@ pub fn handle_mine_block(
|
|||||||
xp_pools: HashSet::from_iter(vec![SkillGroupKind::Weapon(tool)]),
|
xp_pools: HashSet::from_iter(vec![SkillGroupKind::Weapon(tool)]),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
use common::comp::skills::{MiningSkill, Skill};
|
use common::comp::skills::{MiningSkill, Skill, SKILL_MODIFIERS};
|
||||||
use rand::Rng;
|
use rand::Rng;
|
||||||
let mut rng = rand::thread_rng();
|
let mut rng = rand::thread_rng();
|
||||||
if item.item_definition_id().contains("mineral.ore.")
|
|
||||||
&& rng.gen_bool(
|
let need_double_ore = |rng: &mut rand::rngs::ThreadRng| {
|
||||||
0.05 * skillset
|
let chance_mod = f64::from(SKILL_MODIFIERS.mining_tree.ore_gain);
|
||||||
.skill_level(Skill::Pick(MiningSkill::OreGain))
|
let skill_level =
|
||||||
.ok()
|
skillset.skill_level_or(Skill::Pick(MiningSkill::OreGain), 0);
|
||||||
.flatten()
|
|
||||||
.unwrap_or(0) as f64,
|
rng.gen_bool(chance_mod * f64::from(skill_level))
|
||||||
)
|
};
|
||||||
{
|
let need_double_gem = |rng: &mut rand::rngs::ThreadRng| {
|
||||||
let _ = item.increase_amount(1);
|
let chance_mod = f64::from(SKILL_MODIFIERS.mining_tree.gem_gain);
|
||||||
}
|
let skill_level =
|
||||||
if item.item_definition_id().contains("mineral.gem.")
|
skillset.skill_level_or(Skill::Pick(MiningSkill::GemGain), 0);
|
||||||
&& rng.gen_bool(
|
|
||||||
0.05 * skillset
|
rng.gen_bool(chance_mod * f64::from(skill_level))
|
||||||
.skill_level(Skill::Pick(MiningSkill::GemGain))
|
};
|
||||||
.ok()
|
|
||||||
.flatten()
|
let double_gain = (item.item_definition_id().contains("mineral.ore.")
|
||||||
.unwrap_or(0) as f64,
|
&& need_double_ore(&mut rng))
|
||||||
)
|
|| (item.item_definition_id().contains("mineral.gem.")
|
||||||
{
|
&& need_double_gem(&mut rng));
|
||||||
|
|
||||||
|
if double_gain {
|
||||||
|
// Ignore non-stackable errors
|
||||||
let _ = item.increase_amount(1);
|
let _ = item.increase_amount(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -325,10 +325,19 @@ widget_ids! {
|
|||||||
// TODO: extend as you need it
|
// TODO: extend as you need it
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
pub enum PositionSpecifier {
|
pub enum PositionSpecifier {
|
||||||
MidBottomWithMarginOn(widget::Id, f64),
|
// Place the widget near other widget with the given margins
|
||||||
|
TopLeftWithMarginsOn(widget::Id, f64, f64),
|
||||||
TopRightWithMarginsOn(widget::Id, f64, f64),
|
TopRightWithMarginsOn(widget::Id, f64, f64),
|
||||||
BottomRightWithMarginsOn(widget::Id, f64, f64),
|
MidBottomWithMarginOn(widget::Id, f64),
|
||||||
BottomLeftWithMarginsOn(widget::Id, f64, f64),
|
BottomLeftWithMarginsOn(widget::Id, f64, f64),
|
||||||
|
BottomRightWithMarginsOn(widget::Id, f64, f64),
|
||||||
|
// Place the widget near other widget with given margin
|
||||||
|
MidTopWithMarginOn(widget::Id, f64),
|
||||||
|
// Place the widget near other widget at given distance
|
||||||
|
MiddleOf(widget::Id),
|
||||||
|
UpFrom(widget::Id, f64),
|
||||||
|
DownFrom(widget::Id, f64),
|
||||||
|
LeftFrom(widget::Id, f64),
|
||||||
RightFrom(widget::Id, f64),
|
RightFrom(widget::Id, f64),
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -385,18 +394,31 @@ pub trait Position {
|
|||||||
impl<W: Positionable> Position for W {
|
impl<W: Positionable> Position for W {
|
||||||
fn position(self, request: PositionSpecifier) -> Self {
|
fn position(self, request: PositionSpecifier) -> Self {
|
||||||
match request {
|
match request {
|
||||||
PositionSpecifier::MidBottomWithMarginOn(other, margin) => {
|
// Place the widget near other widget with the given margins
|
||||||
self.mid_bottom_with_margin_on(other, margin)
|
PositionSpecifier::TopLeftWithMarginsOn(other, top, right) => {
|
||||||
|
self.top_left_with_margins_on(other, top, right)
|
||||||
},
|
},
|
||||||
PositionSpecifier::TopRightWithMarginsOn(other, top, right) => {
|
PositionSpecifier::TopRightWithMarginsOn(other, top, right) => {
|
||||||
self.top_right_with_margins_on(other, top, right)
|
self.top_right_with_margins_on(other, top, right)
|
||||||
},
|
},
|
||||||
|
PositionSpecifier::MidBottomWithMarginOn(other, margin) => {
|
||||||
|
self.mid_bottom_with_margin_on(other, margin)
|
||||||
|
},
|
||||||
PositionSpecifier::BottomRightWithMarginsOn(other, bottom, right) => {
|
PositionSpecifier::BottomRightWithMarginsOn(other, bottom, right) => {
|
||||||
self.bottom_right_with_margins_on(other, bottom, right)
|
self.bottom_right_with_margins_on(other, bottom, right)
|
||||||
},
|
},
|
||||||
PositionSpecifier::BottomLeftWithMarginsOn(other, bottom, left) => {
|
PositionSpecifier::BottomLeftWithMarginsOn(other, bottom, left) => {
|
||||||
self.bottom_left_with_margins_on(other, bottom, left)
|
self.bottom_left_with_margins_on(other, bottom, left)
|
||||||
},
|
},
|
||||||
|
// Place the widget near other widget with given margin
|
||||||
|
PositionSpecifier::MidTopWithMarginOn(other, margin) => {
|
||||||
|
self.mid_top_with_margin_on(other, margin)
|
||||||
|
},
|
||||||
|
// Place the widget near other widget at given distance
|
||||||
|
PositionSpecifier::MiddleOf(other) => self.middle_of(other),
|
||||||
|
PositionSpecifier::UpFrom(other, offset) => self.up_from(other, offset),
|
||||||
|
PositionSpecifier::DownFrom(other, offset) => self.down_from(other, offset),
|
||||||
|
PositionSpecifier::LeftFrom(other, offset) => self.left_from(other, offset),
|
||||||
PositionSpecifier::RightFrom(other, offset) => self.right_from(other, offset),
|
PositionSpecifier::RightFrom(other, offset) => self.right_from(other, offset),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -4116,3 +4138,17 @@ pub fn angle_of_attack_text(
|
|||||||
"Angle of Attack: Not moving".to_owned()
|
"Angle of Attack: Not moving".to_owned()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Converts multiplier to percentage.
|
||||||
|
/// NOTE: floats are not the most precise type.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
/// ```
|
||||||
|
/// use veloren_voxygen::hud::multiplier_to_percentage;
|
||||||
|
///
|
||||||
|
/// let positive = multiplier_to_percentage(1.05);
|
||||||
|
/// assert!((positive - 5.0).abs() < 0.0001);
|
||||||
|
/// let negative = multiplier_to_percentage(0.85);
|
||||||
|
/// assert!((negative - (-15.0)).abs() < 0.0001);
|
||||||
|
/// ```
|
||||||
|
pub fn multiplier_to_percentage(value: f32) -> f32 { value * 100.0 - 100.0 }
|
||||||
|
Loading…
Reference in New Issue
Block a user