Addressed some review.

This commit is contained in:
Sam 2021-11-30 23:12:02 -05:00
parent 64c8321626
commit 8221336587
52 changed files with 619 additions and 607 deletions

2
Cargo.lock generated
View File

@ -6191,7 +6191,6 @@ name = "veloren-common"
version = "0.10.0" version = "0.10.0"
dependencies = [ dependencies = [
"approx 0.4.0", "approx 0.4.0",
"bincode",
"bitflags", "bitflags",
"chrono", "chrono",
"chrono-tz", "chrono-tz",
@ -6216,6 +6215,7 @@ dependencies = [
"ron 0.7.0", "ron 0.7.0",
"roots", "roots",
"serde", "serde",
"serde_json",
"serde_repr", "serde_repr",
"sha2", "sha2",
"slab", "slab",

View File

@ -1,83 +1,83 @@
({ ({
General(HealthIncrease): Some(10), General(HealthIncrease): 10,
General(EnergyIncrease): Some(5), General(EnergyIncrease): 5,
Sword(TsDamage): Some(3), Sword(TsDamage): 3,
Sword(TsRegen): Some(2), Sword(TsRegen): 2,
Sword(TsSpeed): Some(3), Sword(TsSpeed): 3,
Sword(DCost): Some(2), Sword(DCost): 2,
Sword(DDrain): Some(2), Sword(DDrain): 2,
Sword(DDamage): Some(2), Sword(DDamage): 2,
Sword(DScaling): Some(3), Sword(DScaling): 3,
Sword(SDamage): Some(2), Sword(SDamage): 2,
Sword(SSpeed): Some(2), Sword(SSpeed): 2,
Sword(SCost): Some(2), Sword(SCost): 2,
Sword(SSpins): Some(2), Sword(SSpins): 2,
Axe(DsDamage): Some(3), Axe(DsDamage): 3,
Axe(DsRegen): Some(2), Axe(DsRegen): 2,
Axe(DsSpeed): Some(3), Axe(DsSpeed): 3,
Axe(SDamage): Some(3), Axe(SDamage): 3,
Axe(SSpeed): Some(2), Axe(SSpeed): 2,
Axe(SCost): Some(2), Axe(SCost): 2,
Axe(LDamage): Some(2), Axe(LDamage): 2,
Axe(LKnockback): Some(2), Axe(LKnockback): 2,
Axe(LCost): Some(2), Axe(LCost): 2,
Axe(LDistance): Some(2), Axe(LDistance): 2,
Hammer(SsKnockback): Some(2), Hammer(SsKnockback): 2,
Hammer(SsDamage): Some(3), Hammer(SsDamage): 3,
Hammer(SsRegen): Some(2), Hammer(SsRegen): 2,
Hammer(SsSpeed): Some(3), Hammer(SsSpeed): 3,
Hammer(CDamage): Some(3), Hammer(CDamage): 3,
Hammer(CKnockback): Some(3), Hammer(CKnockback): 3,
Hammer(CDrain): Some(2), Hammer(CDrain): 2,
Hammer(CSpeed): Some(2), Hammer(CSpeed): 2,
Hammer(LDamage): Some(2), Hammer(LDamage): 2,
Hammer(LCost): Some(2), Hammer(LCost): 2,
Hammer(LDistance): Some(2), Hammer(LDistance): 2,
Hammer(LKnockback): Some(2), Hammer(LKnockback): 2,
Hammer(LRange): Some(2), Hammer(LRange): 2,
Bow(ProjSpeed): Some(2), Bow(ProjSpeed): 2,
Bow(CDamage): Some(3), Bow(CDamage): 3,
Bow(CRegen): Some(2), Bow(CRegen): 2,
Bow(CKnockback): Some(2), Bow(CKnockback): 2,
Bow(CSpeed): Some(2), Bow(CSpeed): 2,
Bow(CMove): Some(2), Bow(CMove): 2,
Bow(RDamage): Some(3), Bow(RDamage): 3,
Bow(RCost): Some(2), Bow(RCost): 2,
Bow(RSpeed): Some(2), Bow(RSpeed): 2,
Bow(SDamage): Some(2), Bow(SDamage): 2,
Bow(SCost): Some(2), Bow(SCost): 2,
Bow(SArrows): Some(2), Bow(SArrows): 2,
Bow(SSpread): Some(2), Bow(SSpread): 2,
Staff(BDamage): Some(3), Staff(BDamage): 3,
Staff(BRegen): Some(2), Staff(BRegen): 2,
Staff(BRadius): Some(3), Staff(BRadius): 3,
Staff(FRange): Some(2), Staff(FRange): 2,
Staff(FDamage): Some(3), Staff(FDamage): 3,
Staff(FDrain): Some(2), Staff(FDrain): 2,
Staff(FVelocity): Some(2), Staff(FVelocity): 2,
Staff(SDamage): Some(2), Staff(SDamage): 2,
Staff(SKnockback): Some(2), Staff(SKnockback): 2,
Staff(SRange): Some(2), Staff(SRange): 2,
Staff(SCost): Some(2), Staff(SCost): 2,
Sceptre(LDamage): Some(3), Sceptre(LDamage): 3,
Sceptre(LRange): Some(2), Sceptre(LRange): 2,
Sceptre(LLifesteal): Some(3), Sceptre(LLifesteal): 3,
Sceptre(LRegen): Some(2), Sceptre(LRegen): 2,
Sceptre(HHeal): Some(3), Sceptre(HHeal): 3,
Sceptre(HRange): Some(2), Sceptre(HRange): 2,
Sceptre(HDuration): Some(2), Sceptre(HDuration): 2,
Sceptre(HCost): Some(2), Sceptre(HCost): 2,
Sceptre(AStrength): Some(2), Sceptre(AStrength): 2,
Sceptre(ADuration): Some(2), Sceptre(ADuration): 2,
Sceptre(ARange): Some(2), Sceptre(ARange): 2,
Sceptre(ACost): Some(2), Sceptre(ACost): 2,
Roll(Cost): Some(2), Roll(Cost): 2,
Roll(Strength): Some(2), Roll(Strength): 2,
Roll(Duration): Some(2), Roll(Duration): 2,
Climb(Cost): Some(2), Climb(Cost): 2,
Climb(Speed): Some(2), Climb(Speed): 2,
Swim(Speed): Some(2), Swim(Speed): 2,
Pick(Speed): Some(3), Pick(Speed): 3,
Pick(OreGain): Some(3), Pick(OreGain): 3,
Pick(GemGain): Some(3), Pick(GemGain): 3,
}) })

View File

@ -1,27 +1,27 @@
({ ({
Sword(SDamage): {Sword(UnlockSpin): None}, Sword(SDamage): {Sword(UnlockSpin): 1},
Sword(SSpeed): {Sword(UnlockSpin): None}, Sword(SSpeed): {Sword(UnlockSpin): 1},
Sword(SCost): {Sword(UnlockSpin): None}, Sword(SCost): {Sword(UnlockSpin): 1},
Sword(SSpins): {Sword(UnlockSpin): None}, Sword(SSpins): {Sword(UnlockSpin): 1},
Axe(LDamage): {Axe(UnlockLeap): None}, Axe(LDamage): {Axe(UnlockLeap): 1},
Axe(LKnockback): {Axe(UnlockLeap): None}, Axe(LKnockback): {Axe(UnlockLeap): 1},
Axe(LCost): {Axe(UnlockLeap): None}, Axe(LCost): {Axe(UnlockLeap): 1},
Axe(LDistance): {Axe(UnlockLeap): None}, Axe(LDistance): {Axe(UnlockLeap): 1},
Hammer(LDamage): {Hammer(UnlockLeap): None}, Hammer(LDamage): {Hammer(UnlockLeap): 1},
Hammer(LCost): {Hammer(UnlockLeap): None}, Hammer(LCost): {Hammer(UnlockLeap): 1},
Hammer(LDistance): {Hammer(UnlockLeap): None}, Hammer(LDistance): {Hammer(UnlockLeap): 1},
Hammer(LKnockback): {Hammer(UnlockLeap): None}, Hammer(LKnockback): {Hammer(UnlockLeap): 1},
Hammer(LRange): {Hammer(UnlockLeap): None}, Hammer(LRange): {Hammer(UnlockLeap): 1},
Bow(SDamage): {Bow(UnlockShotgun): None}, Bow(SDamage): {Bow(UnlockShotgun): 1},
Bow(SCost): {Bow(UnlockShotgun): None}, Bow(SCost): {Bow(UnlockShotgun): 1},
Bow(SArrows): {Bow(UnlockShotgun): None}, Bow(SArrows): {Bow(UnlockShotgun): 1},
Bow(SSpread): {Bow(UnlockShotgun): None}, Bow(SSpread): {Bow(UnlockShotgun): 1},
Staff(SDamage): {Staff(UnlockShockwave): None}, Staff(SDamage): {Staff(UnlockShockwave): 1},
Staff(SKnockback): {Staff(UnlockShockwave): None}, Staff(SKnockback): {Staff(UnlockShockwave): 1},
Staff(SRange): {Staff(UnlockShockwave): None}, Staff(SRange): {Staff(UnlockShockwave): 1},
Staff(SCost): {Staff(UnlockShockwave): None}, Staff(SCost): {Staff(UnlockShockwave): 1},
Sceptre(AStrength): {Sceptre(UnlockAura): None}, Sceptre(AStrength): {Sceptre(UnlockAura): 1},
Sceptre(ADuration): {Sceptre(UnlockAura): None}, Sceptre(ADuration): {Sceptre(UnlockAura): 1},
Sceptre(ARange): {Sceptre(UnlockAura): None}, Sceptre(ARange): {Sceptre(UnlockAura): 1},
Sceptre(ACost): {Sceptre(UnlockAura): None}, Sceptre(ACost): {Sceptre(UnlockAura): 1},
}) })

View File

@ -26,7 +26,7 @@
Sword(DDamage), Sword(DDamage),
Sword(DScaling), Sword(DScaling),
Sword(DSpeed), Sword(DSpeed),
Sword(DInfinite), Sword(DChargeThrough),
Sword(UnlockSpin), Sword(UnlockSpin),
Sword(SDamage), Sword(SDamage),
Sword(SSpeed), Sword(SSpeed),

View File

@ -2,9 +2,9 @@
Group(Weapon(Axe)), Group(Weapon(Axe)),
// DoubleStrike // DoubleStrike
Skill((Axe(DsDamage), Some(1))), Skill((Axe(DsDamage), 1)),
// Spin // Spin
Skill((Axe(SInfinite), None)), Skill((Axe(SInfinite), 1)),
Skill((Axe(SDamage), Some(1))), Skill((Axe(SDamage), 1)),
]) ])

View File

@ -2,13 +2,13 @@
Group(Weapon(Bow)), Group(Weapon(Bow)),
// Projectile Speed // Projectile Speed
Skill((Bow(ProjSpeed), Some(1))), Skill((Bow(ProjSpeed), 1)),
// Charged // Charged
Skill((Bow(CDamage), Some(1))), Skill((Bow(CDamage), 1)),
Skill((Bow(CKnockback), Some(1))), Skill((Bow(CKnockback), 1)),
// Repeater // Repeater
Skill((Bow(RDamage), Some(1))), Skill((Bow(RDamage), 1)),
]) ])

View File

@ -1,4 +1,4 @@
([ ([
Skill((General(HealthIncrease), Some(2))), Skill((General(HealthIncrease), 2)),
Skill((General(EnergyIncrease), Some(1))), Skill((General(EnergyIncrease), 1)),
]) ])

View File

@ -2,11 +2,11 @@
Group(Weapon(Hammer)), Group(Weapon(Hammer)),
// Single Strike, as single as you are // Single Strike, as single as you are
Skill((Hammer(SsKnockback), Some(1))), Skill((Hammer(SsKnockback), 1)),
Skill((Hammer(SsDamage), Some(1))), Skill((Hammer(SsDamage), 1)),
// Charged // Charged
Skill((Hammer(CDamage), Some(1))), Skill((Hammer(CDamage), 1)),
Skill((Hammer(CKnockback), Some(1))), Skill((Hammer(CKnockback), 1)),
]) ])

View File

@ -2,11 +2,11 @@
Group(Weapon(Sceptre)), Group(Weapon(Sceptre)),
// Beam // Beam
Skill((Sceptre(LDamage), Some(1))), Skill((Sceptre(LDamage), 1)),
Skill((Sceptre(LRange), Some(1))), Skill((Sceptre(LRange), 1)),
// Heal // Heal
Skill((Sceptre(HHeal), Some(1))), Skill((Sceptre(HHeal), 1)),
Skill((Sceptre(HDuration), Some(1))), Skill((Sceptre(HDuration), 1)),
]) ])

View File

@ -2,11 +2,11 @@
Group(Weapon(Staff)), Group(Weapon(Staff)),
// Fireball // Fireball
Skill((Staff(BDamage), Some(2))), Skill((Staff(BDamage), 2)),
Skill((Staff(BRegen), Some(2))), Skill((Staff(BRegen), 2)),
Skill((Staff(BRadius), Some(1))), Skill((Staff(BRadius), 1)),
// Flamethrower // Flamethrower
Skill((Staff(FRange), Some(1))), Skill((Staff(FRange), 1)),
]) ])

View File

@ -1,14 +1,14 @@
([ ([
Group(Weapon(Sword)), Group(Weapon(Sword)),
Skill((Sword(InterruptingAttacks), None)), Skill((Sword(InterruptingAttacks), 1)),
// TripleStrike // TripleStrike
Skill((Sword(TsCombo), None)), Skill((Sword(TsCombo), 1)),
Skill((Sword(TsDamage), Some(1))), Skill((Sword(TsDamage), 1)),
Skill((Sword(TsRegen), Some(1))), Skill((Sword(TsRegen), 1)),
// Dash // Dash
Skill((Sword(DCost), Some(1))), Skill((Sword(DCost), 1)),
]) ])

View File

@ -2,13 +2,13 @@
Group(Weapon(Axe)), Group(Weapon(Axe)),
// DoubleStrike // DoubleStrike
Skill((Axe(DsCombo), None)), Skill((Axe(DsCombo), 1)),
Skill((Axe(DsDamage), Some(1))), Skill((Axe(DsDamage), 1)),
Skill((Axe(DsRegen), Some(1))), Skill((Axe(DsRegen), 1)),
// Spin // Spin
Skill((Axe(SInfinite), None)), Skill((Axe(SInfinite), 1)),
Skill((Axe(SHelicopter), None)), Skill((Axe(SHelicopter), 1)),
Skill((Axe(SDamage), Some(1))), Skill((Axe(SDamage), 1)),
Skill((Axe(SSpeed), Some(1))), Skill((Axe(SSpeed), 1)),
]) ])

View File

@ -2,16 +2,16 @@
Group(Weapon(Bow)), Group(Weapon(Bow)),
// Projectile Speed // Projectile Speed
Skill((Bow(ProjSpeed), Some(1))), Skill((Bow(ProjSpeed), 1)),
// Charged // Charged
Skill((Bow(CDamage), Some(1))), Skill((Bow(CDamage), 1)),
Skill((Bow(CKnockback), Some(1))), Skill((Bow(CKnockback), 1)),
Skill((Bow(CSpeed), Some(1))), Skill((Bow(CSpeed), 1)),
Skill((Bow(CRegen), Some(1))), Skill((Bow(CRegen), 1)),
// Repeater // Repeater
Skill((Bow(RDamage), Some(1))), Skill((Bow(RDamage), 1)),
Skill((Bow(RCost), Some(1))), Skill((Bow(RCost), 1)),
]) ])

View File

@ -1,4 +1,4 @@
([ ([
Skill((General(HealthIncrease), Some(4))), Skill((General(HealthIncrease), 4)),
Skill((General(EnergyIncrease), Some(2))), Skill((General(EnergyIncrease), 2)),
]) ])

View File

@ -2,15 +2,15 @@
Group(Weapon(Hammer)), Group(Weapon(Hammer)),
// Single Strike, as single as you are // Single Strike, as single as you are
Skill((Hammer(SsKnockback), Some(1))), Skill((Hammer(SsKnockback), 1)),
Skill((Hammer(SsDamage), Some(2))), Skill((Hammer(SsDamage), 2)),
Skill((Hammer(SsRegen), Some(1))), Skill((Hammer(SsRegen), 1)),
Skill((Hammer(SsSpeed), Some(1))), Skill((Hammer(SsSpeed), 1)),
// Charged // Charged
Skill((Hammer(CDamage), Some(1))), Skill((Hammer(CDamage), 1)),
Skill((Hammer(CKnockback), Some(1))), Skill((Hammer(CKnockback), 1)),
Skill((Hammer(CDrain), Some(1))), Skill((Hammer(CDrain), 1)),
Skill((Hammer(CSpeed), Some(1))), Skill((Hammer(CSpeed), 1)),
]) ])

View File

@ -2,15 +2,15 @@
Group(Weapon(Sceptre)), Group(Weapon(Sceptre)),
// Beam // Beam
Skill((Sceptre(LDamage), Some(1))), Skill((Sceptre(LDamage), 1)),
Skill((Sceptre(LRange), Some(1))), Skill((Sceptre(LRange), 1)),
Skill((Sceptre(LLifesteal), Some(1))), Skill((Sceptre(LLifesteal), 1)),
Skill((Sceptre(LRegen), Some(1))), Skill((Sceptre(LRegen), 1)),
// Heal // Heal
Skill((Sceptre(HHeal), Some(1))), Skill((Sceptre(HHeal), 1)),
Skill((Sceptre(HDuration), Some(1))), Skill((Sceptre(HDuration), 1)),
Skill((Sceptre(HRange), Some(1))), Skill((Sceptre(HRange), 1)),
Skill((Sceptre(HCost), Some(1))), Skill((Sceptre(HCost), 1)),
]) ])

View File

@ -2,12 +2,12 @@
Group(Weapon(Staff)), Group(Weapon(Staff)),
// Fireball // Fireball
Skill((Staff(BDamage), Some(2))), Skill((Staff(BDamage), 2)),
Skill((Staff(BRegen), Some(2))), Skill((Staff(BRegen), 2)),
Skill((Staff(BRadius), Some(1))), Skill((Staff(BRadius), 1)),
// Flamethrower // Flamethrower
Skill((Staff(FRange), Some(2))), Skill((Staff(FRange), 2)),
Skill((Staff(FDamage), Some(2))), Skill((Staff(FDamage), 2)),
]) ])

View File

@ -1,17 +1,17 @@
([ ([
Group(Weapon(Sword)), Group(Weapon(Sword)),
Skill((Sword(InterruptingAttacks), None)), Skill((Sword(InterruptingAttacks), 1)),
// TripleStrike // TripleStrike
Skill((Sword(TsCombo), None)), Skill((Sword(TsCombo), 1)),
Skill((Sword(TsDamage), Some(1))), Skill((Sword(TsDamage), 1)),
Skill((Sword(TsRegen), Some(1))), Skill((Sword(TsRegen), 1)),
Skill((Sword(TsSpeed), Some(1))), Skill((Sword(TsSpeed), 1)),
// Dash // Dash
Skill((Sword(DCost), Some(1))), Skill((Sword(DCost), 1)),
Skill((Sword(DDrain), Some(1))), Skill((Sword(DDrain), 1)),
Skill((Sword(DDamage), Some(1))), Skill((Sword(DDamage), 1)),
]) ])

View File

@ -2,19 +2,19 @@
Group(Weapon(Axe)), Group(Weapon(Axe)),
// DoubleStrike // DoubleStrike
Skill((Axe(DsCombo), None)), Skill((Axe(DsCombo), 1)),
Skill((Axe(DsDamage), Some(1))), Skill((Axe(DsDamage), 1)),
Skill((Axe(DsRegen), Some(1))), Skill((Axe(DsRegen), 1)),
Skill((Axe(DsSpeed), Some(1))), Skill((Axe(DsSpeed), 1)),
// Spin // Spin
Skill((Axe(SInfinite), None)), Skill((Axe(SInfinite), 1)),
Skill((Axe(SHelicopter), None)), Skill((Axe(SHelicopter), 1)),
Skill((Axe(SDamage), Some(1))), Skill((Axe(SDamage), 1)),
Skill((Axe(SSpeed), Some(1))), Skill((Axe(SSpeed), 1)),
Skill((Axe(SCost), Some(1))), Skill((Axe(SCost), 1)),
// Leap // Leap
Skill((Axe(UnlockLeap), None)), Skill((Axe(UnlockLeap), 1)),
Skill((Axe(LDamage), Some(1))), Skill((Axe(LDamage), 1)),
]) ])

View File

@ -2,22 +2,22 @@
Group(Weapon(Bow)), Group(Weapon(Bow)),
// Projectile Speed // Projectile Speed
Skill((Bow(ProjSpeed), Some(2))), Skill((Bow(ProjSpeed), 2)),
// Charged // Charged
Skill((Bow(CDamage), Some(1))), Skill((Bow(CDamage), 1)),
Skill((Bow(CKnockback), Some(1))), Skill((Bow(CKnockback), 1)),
Skill((Bow(CSpeed), Some(1))), Skill((Bow(CSpeed), 1)),
Skill((Bow(CRegen), Some(1))), Skill((Bow(CRegen), 1)),
Skill((Bow(CMove), Some(1))), Skill((Bow(CMove), 1)),
// Repeater // Repeater
Skill((Bow(RDamage), Some(1))), Skill((Bow(RDamage), 1)),
Skill((Bow(RCost), Some(1))), Skill((Bow(RCost), 1)),
Skill((Bow(RSpeed), Some(1))), Skill((Bow(RSpeed), 1)),
// Shotgun // Shotgun
Skill((Bow(UnlockShotgun), None)), Skill((Bow(UnlockShotgun), 1)),
Skill((Bow(SDamage), Some(1))), Skill((Bow(SDamage), 1)),
Skill((Bow(SCost), Some(1))), Skill((Bow(SCost), 1)),
]) ])

View File

@ -1,4 +1,4 @@
([ ([
Skill((General(HealthIncrease), Some(6))), Skill((General(HealthIncrease), 6)),
Skill((General(EnergyIncrease), Some(3))), Skill((General(EnergyIncrease), 3)),
]) ])

View File

@ -2,20 +2,20 @@
Group(Weapon(Hammer)), Group(Weapon(Hammer)),
// Single Strike, as single as you are // Single Strike, as single as you are
Skill((Hammer(SsKnockback), Some(2))), Skill((Hammer(SsKnockback), 2)),
Skill((Hammer(SsDamage), Some(2))), Skill((Hammer(SsDamage), 2)),
Skill((Hammer(SsRegen), Some(1))), Skill((Hammer(SsRegen), 1)),
Skill((Hammer(SsSpeed), Some(1))), Skill((Hammer(SsSpeed), 1)),
// Charged // Charged
Skill((Hammer(CDamage), Some(2))), Skill((Hammer(CDamage), 2)),
Skill((Hammer(CKnockback), Some(1))), Skill((Hammer(CKnockback), 1)),
Skill((Hammer(CDrain), Some(1))), Skill((Hammer(CDrain), 1)),
Skill((Hammer(CSpeed), Some(1))), Skill((Hammer(CSpeed), 1)),
// Leap // Leap
Skill((Hammer(UnlockLeap), None)), Skill((Hammer(UnlockLeap), 1)),
Skill((Hammer(LDamage), Some(1))), Skill((Hammer(LDamage), 1)),
Skill((Hammer(LCost), Some(1))), Skill((Hammer(LCost), 1)),
Skill((Hammer(LDistance), Some(1))), Skill((Hammer(LDistance), 1)),
]) ])

View File

@ -2,18 +2,18 @@
Group(Weapon(Sceptre)), Group(Weapon(Sceptre)),
// Beam // Beam
Skill((Sceptre(LDamage), Some(2))), Skill((Sceptre(LDamage), 2)),
Skill((Sceptre(LRange), Some(2))), Skill((Sceptre(LRange), 2)),
Skill((Sceptre(LLifesteal), Some(1))), Skill((Sceptre(LLifesteal), 1)),
Skill((Sceptre(LRegen), Some(1))), Skill((Sceptre(LRegen), 1)),
// Heal // Heal
Skill((Sceptre(HHeal), Some(2))), Skill((Sceptre(HHeal), 2)),
Skill((Sceptre(HDuration), Some(1))), Skill((Sceptre(HDuration), 1)),
Skill((Sceptre(HRange), Some(1))), Skill((Sceptre(HRange), 1)),
Skill((Sceptre(HCost), Some(1))), Skill((Sceptre(HCost), 1)),
// Ward // Ward
Skill((Sceptre(UnlockAura), None)), Skill((Sceptre(UnlockAura), 1)),
Skill((Sceptre(AStrength), Some(1))), Skill((Sceptre(AStrength), 1)),
Skill((Sceptre(ADuration), Some(1))), Skill((Sceptre(ADuration), 1)),
]) ])

View File

@ -2,14 +2,14 @@
Group(Weapon(Staff)), Group(Weapon(Staff)),
// Fireball // Fireball
Skill((Staff(BDamage), Some(2))), Skill((Staff(BDamage), 2)),
Skill((Staff(BRegen), Some(2))), Skill((Staff(BRegen), 2)),
Skill((Staff(BRadius), Some(2))), Skill((Staff(BRadius), 2)),
// Flamethrower // Flamethrower
Skill((Staff(FRange), Some(2))), Skill((Staff(FRange), 2)),
Skill((Staff(FDamage), Some(3))), Skill((Staff(FDamage), 3)),
Skill((Staff(FDrain), Some(2))), Skill((Staff(FDrain), 2)),
Skill((Staff(FVelocity), Some(1))), Skill((Staff(FVelocity), 1)),
]) ])

View File

@ -1,23 +1,23 @@
([ ([
Group(Weapon(Sword)), Group(Weapon(Sword)),
Skill((Sword(InterruptingAttacks), None)), Skill((Sword(InterruptingAttacks), 1)),
// TripleStrike // TripleStrike
Skill((Sword(TsCombo), None)), Skill((Sword(TsCombo), 1)),
Skill((Sword(TsDamage), Some(2))), Skill((Sword(TsDamage), 2)),
Skill((Sword(TsRegen), Some(2))), Skill((Sword(TsRegen), 2)),
Skill((Sword(TsSpeed), Some(1))), Skill((Sword(TsSpeed), 1)),
// Dash // Dash
Skill((Sword(DCost), Some(2))), Skill((Sword(DCost), 2)),
Skill((Sword(DDrain), Some(2))), Skill((Sword(DDrain), 2)),
Skill((Sword(DDamage), Some(1))), Skill((Sword(DDamage), 1)),
Skill((Sword(DScaling), Some(1))), Skill((Sword(DScaling), 1)),
Skill((Sword(DSpeed), None)), Skill((Sword(DSpeed), 1)),
// Spin of death // Spin of death
Skill((Sword(UnlockSpin), None)), Skill((Sword(UnlockSpin), 1)),
Skill((Sword(SDamage), Some(1))), Skill((Sword(SDamage), 1)),
Skill((Sword(SSpeed), Some(1))), Skill((Sword(SSpeed), 1)),
]) ])

View File

@ -2,22 +2,22 @@
Group(Weapon(Axe)), Group(Weapon(Axe)),
// DoubleStrike // DoubleStrike
Skill((Axe(DsCombo), None)), Skill((Axe(DsCombo), 1)),
Skill((Axe(DsDamage), Some(2))), Skill((Axe(DsDamage), 2)),
Skill((Axe(DsRegen), Some(1))), Skill((Axe(DsRegen), 1)),
Skill((Axe(DsSpeed), Some(2))), Skill((Axe(DsSpeed), 2)),
// Spin // Spin
Skill((Axe(SInfinite), None)), Skill((Axe(SInfinite), 1)),
Skill((Axe(SHelicopter), None)), Skill((Axe(SHelicopter), 1)),
Skill((Axe(SDamage), Some(2))), Skill((Axe(SDamage), 2)),
Skill((Axe(SSpeed), Some(1))), Skill((Axe(SSpeed), 1)),
Skill((Axe(SCost), Some(1))), Skill((Axe(SCost), 1)),
// Leap // Leap
Skill((Axe(UnlockLeap), None)), Skill((Axe(UnlockLeap), 1)),
Skill((Axe(LDamage), Some(1))), Skill((Axe(LDamage), 1)),
Skill((Axe(LKnockback), Some(1))), Skill((Axe(LKnockback), 1)),
Skill((Axe(LCost), Some(1))), Skill((Axe(LCost), 1)),
Skill((Axe(LDistance), Some(1))), Skill((Axe(LDistance), 1)),
]) ])

View File

@ -2,24 +2,24 @@
Group(Weapon(Bow)), Group(Weapon(Bow)),
// Projectile Speed // Projectile Speed
Skill((Bow(ProjSpeed), Some(2))), Skill((Bow(ProjSpeed), 2)),
// Charged // Charged
Skill((Bow(CDamage), Some(2))), Skill((Bow(CDamage), 2)),
Skill((Bow(CKnockback), Some(2))), Skill((Bow(CKnockback), 2)),
Skill((Bow(CSpeed), Some(2))), Skill((Bow(CSpeed), 2)),
Skill((Bow(CRegen), Some(1))), Skill((Bow(CRegen), 1)),
Skill((Bow(CMove), Some(1))), Skill((Bow(CMove), 1)),
// Repeater // Repeater
Skill((Bow(RDamage), Some(2))), Skill((Bow(RDamage), 2)),
Skill((Bow(RCost), Some(1))), Skill((Bow(RCost), 1)),
Skill((Bow(RSpeed), Some(1))), Skill((Bow(RSpeed), 1)),
// Shotgun // Shotgun
Skill((Bow(UnlockShotgun), None)), Skill((Bow(UnlockShotgun), 1)),
Skill((Bow(SDamage), Some(1))), Skill((Bow(SDamage), 1)),
Skill((Bow(SCost), Some(1))), Skill((Bow(SCost), 1)),
Skill((Bow(SArrows), Some(1))), Skill((Bow(SArrows), 1)),
Skill((Bow(SSpread), Some(1))), Skill((Bow(SSpread), 1)),
]) ])

View File

@ -1,4 +1,4 @@
([ ([
Skill((General(HealthIncrease), Some(8))), Skill((General(HealthIncrease), 8)),
Skill((General(EnergyIncrease), Some(4))), Skill((General(EnergyIncrease), 4)),
]) ])

View File

@ -2,22 +2,22 @@
Group(Weapon(Hammer)), Group(Weapon(Hammer)),
// Single Strike, as single as you are // Single Strike, as single as you are
Skill((Hammer(SsKnockback), Some(2))), Skill((Hammer(SsKnockback), 2)),
Skill((Hammer(SsDamage), Some(2))), Skill((Hammer(SsDamage), 2)),
Skill((Hammer(SsRegen), Some(2))), Skill((Hammer(SsRegen), 2)),
Skill((Hammer(SsSpeed), Some(2))), Skill((Hammer(SsSpeed), 2)),
// Charged // Charged
Skill((Hammer(CDamage), Some(2))), Skill((Hammer(CDamage), 2)),
Skill((Hammer(CKnockback), Some(2))), Skill((Hammer(CKnockback), 2)),
Skill((Hammer(CDrain), Some(2))), Skill((Hammer(CDrain), 2)),
Skill((Hammer(CSpeed), Some(2))), Skill((Hammer(CSpeed), 2)),
// Leap // Leap
Skill((Hammer(UnlockLeap), None)), Skill((Hammer(UnlockLeap), 1)),
Skill((Hammer(LDamage), Some(1))), Skill((Hammer(LDamage), 1)),
Skill((Hammer(LCost), Some(1))), Skill((Hammer(LCost), 1)),
Skill((Hammer(LDistance), Some(1))), Skill((Hammer(LDistance), 1)),
Skill((Hammer(LKnockback), Some(1))), Skill((Hammer(LKnockback), 1)),
Skill((Hammer(LRange), Some(1))), Skill((Hammer(LRange), 1)),
]) ])

View File

@ -2,20 +2,20 @@
Group(Weapon(Sceptre)), Group(Weapon(Sceptre)),
// Beam // Beam
Skill((Sceptre(LDamage), Some(2))), Skill((Sceptre(LDamage), 2)),
Skill((Sceptre(LRange), Some(2))), Skill((Sceptre(LRange), 2)),
Skill((Sceptre(LLifesteal), Some(2))), Skill((Sceptre(LLifesteal), 2)),
Skill((Sceptre(LRegen), Some(2))), Skill((Sceptre(LRegen), 2)),
// Heal // Heal
Skill((Sceptre(HHeal), Some(2))), Skill((Sceptre(HHeal), 2)),
Skill((Sceptre(HDuration), Some(2))), Skill((Sceptre(HDuration), 2)),
Skill((Sceptre(HRange), Some(2))), Skill((Sceptre(HRange), 2)),
Skill((Sceptre(HCost), Some(2))), Skill((Sceptre(HCost), 2)),
// Ward // Ward
Skill((Sceptre(UnlockAura), None)), Skill((Sceptre(UnlockAura), 1)),
Skill((Sceptre(AStrength), Some(1))), Skill((Sceptre(AStrength), 1)),
Skill((Sceptre(ADuration), Some(1))), Skill((Sceptre(ADuration), 1)),
Skill((Sceptre(ARange), Some(1))), Skill((Sceptre(ARange), 1)),
Skill((Sceptre(ACost), Some(1))), Skill((Sceptre(ACost), 1)),
]) ])

View File

@ -2,20 +2,20 @@
Group(Weapon(Staff)), Group(Weapon(Staff)),
// Fireball // Fireball
Skill((Staff(BDamage), Some(1))), Skill((Staff(BDamage), 1)),
Skill((Staff(BRegen), Some(2))), Skill((Staff(BRegen), 2)),
Skill((Staff(BRadius), Some(2))), Skill((Staff(BRadius), 2)),
// Flamethrower // Flamethrower
Skill((Staff(FRange), Some(2))), Skill((Staff(FRange), 2)),
Skill((Staff(FDamage), Some(1))), Skill((Staff(FDamage), 1)),
Skill((Staff(FDrain), Some(1))), Skill((Staff(FDrain), 1)),
Skill((Staff(FVelocity), Some(2))), Skill((Staff(FVelocity), 2)),
// Shockwave // Shockwave
Skill((Staff(UnlockShockwave), None)), Skill((Staff(UnlockShockwave), 1)),
Skill((Staff(SDamage), Some(1))), Skill((Staff(SDamage), 1)),
Skill((Staff(SKnockback), Some(1))), Skill((Staff(SKnockback), 1)),
Skill((Staff(SRange), Some(1))), Skill((Staff(SRange), 1)),
Skill((Staff(SCost), Some(1))), Skill((Staff(SCost), 1)),
]) ])

View File

@ -1,26 +1,26 @@
([ ([
Group(Weapon(Sword)), Group(Weapon(Sword)),
Skill((Sword(InterruptingAttacks), None)), Skill((Sword(InterruptingAttacks), 1)),
// TripleStrike // TripleStrike
Skill((Sword(TsCombo), None)), Skill((Sword(TsCombo), 1)),
Skill((Sword(TsDamage), Some(2))), Skill((Sword(TsDamage), 2)),
Skill((Sword(TsRegen), Some(2))), Skill((Sword(TsRegen), 2)),
Skill((Sword(TsSpeed), Some(3))), Skill((Sword(TsSpeed), 3)),
// Dash // Dash
Skill((Sword(DCost), Some(2))), Skill((Sword(DCost), 2)),
Skill((Sword(DDrain), Some(2))), Skill((Sword(DDrain), 2)),
Skill((Sword(DDamage), Some(2))), Skill((Sword(DDamage), 2)),
Skill((Sword(DScaling), Some(2))), Skill((Sword(DScaling), 2)),
Skill((Sword(DSpeed), None)), Skill((Sword(DSpeed), 1)),
Skill((Sword(DInfinite), None)), Skill((Sword(DChargeThrough), 1)),
// Spin of death // Spin of death
Skill((Sword(UnlockSpin), None)), Skill((Sword(UnlockSpin), 1)),
Skill((Sword(SDamage), Some(1))), Skill((Sword(SDamage), 1)),
Skill((Sword(SSpeed), Some(1))), Skill((Sword(SSpeed), 1)),
Skill((Sword(SSpins), Some(1))), Skill((Sword(SSpins), 1)),
Skill((Sword(SCost), Some(1))), Skill((Sword(SCost), 1)),
]) ])

View File

@ -2,22 +2,22 @@
Group(Weapon(Axe)), Group(Weapon(Axe)),
// DoubleStrike // DoubleStrike
Skill((Axe(DsCombo), None)), Skill((Axe(DsCombo), 1)),
Skill((Axe(DsDamage), Some(3))), Skill((Axe(DsDamage), 3)),
Skill((Axe(DsRegen), Some(2))), Skill((Axe(DsRegen), 2)),
Skill((Axe(DsSpeed), Some(3))), Skill((Axe(DsSpeed), 3)),
// Spin // Spin
Skill((Axe(SInfinite), None)), Skill((Axe(SInfinite), 1)),
Skill((Axe(SHelicopter), None)), Skill((Axe(SHelicopter), 1)),
Skill((Axe(SDamage), Some(3))), Skill((Axe(SDamage), 3)),
Skill((Axe(SSpeed), Some(2))), Skill((Axe(SSpeed), 2)),
Skill((Axe(SCost), Some(2))), Skill((Axe(SCost), 2)),
// Leap // Leap
Skill((Axe(UnlockLeap), None)), Skill((Axe(UnlockLeap), 1)),
Skill((Axe(LDamage), Some(2))), Skill((Axe(LDamage), 2)),
Skill((Axe(LKnockback), Some(2))), Skill((Axe(LKnockback), 2)),
Skill((Axe(LCost), Some(2))), Skill((Axe(LCost), 2)),
Skill((Axe(LDistance), Some(2))), Skill((Axe(LDistance), 2)),
]) ])

View File

@ -2,24 +2,24 @@
Group(Weapon(Bow)), Group(Weapon(Bow)),
// Projectile Speed // Projectile Speed
Skill((Bow(ProjSpeed), Some(2))), Skill((Bow(ProjSpeed), 2)),
// Charged // Charged
Skill((Bow(CDamage), Some(3))), Skill((Bow(CDamage), 3)),
Skill((Bow(CKnockback), Some(2))), Skill((Bow(CKnockback), 2)),
Skill((Bow(CSpeed), Some(2))), Skill((Bow(CSpeed), 2)),
Skill((Bow(CRegen), Some(2))), Skill((Bow(CRegen), 2)),
Skill((Bow(CMove), Some(2))), Skill((Bow(CMove), 2)),
// Repeater // Repeater
Skill((Bow(RDamage), Some(3))), Skill((Bow(RDamage), 3)),
Skill((Bow(RCost), Some(2))), Skill((Bow(RCost), 2)),
Skill((Bow(RSpeed), Some(2))), Skill((Bow(RSpeed), 2)),
// Shotgun // Shotgun
Skill((Bow(UnlockShotgun), None)), Skill((Bow(UnlockShotgun), 1)),
Skill((Bow(SDamage), Some(2))), Skill((Bow(SDamage), 2)),
Skill((Bow(SCost), Some(2))), Skill((Bow(SCost), 2)),
Skill((Bow(SArrows), Some(2))), Skill((Bow(SArrows), 2)),
Skill((Bow(SSpread), Some(2))), Skill((Bow(SSpread), 2)),
]) ])

View File

@ -1,4 +1,4 @@
([ ([
Skill((General(HealthIncrease), Some(10))), Skill((General(HealthIncrease), 10)),
Skill((General(EnergyIncrease), Some(5))), Skill((General(EnergyIncrease), 5)),
]) ])

View File

@ -2,22 +2,22 @@
Group(Weapon(Hammer)), Group(Weapon(Hammer)),
// Single Strike, as single as you are // Single Strike, as single as you are
Skill((Hammer(SsKnockback), Some(2))), Skill((Hammer(SsKnockback), 2)),
Skill((Hammer(SsDamage), Some(3))), Skill((Hammer(SsDamage), 3)),
Skill((Hammer(SsRegen), Some(2))), Skill((Hammer(SsRegen), 2)),
Skill((Hammer(SsSpeed), Some(3))), Skill((Hammer(SsSpeed), 3)),
// Charged // Charged
Skill((Hammer(CDamage), Some(3))), Skill((Hammer(CDamage), 3)),
Skill((Hammer(CKnockback), Some(3))), Skill((Hammer(CKnockback), 3)),
Skill((Hammer(CDrain), Some(2))), Skill((Hammer(CDrain), 2)),
Skill((Hammer(CSpeed), Some(2))), Skill((Hammer(CSpeed), 2)),
// Leap // Leap
Skill((Hammer(UnlockLeap), None)), Skill((Hammer(UnlockLeap), 1)),
Skill((Hammer(LDamage), Some(2))), Skill((Hammer(LDamage), 2)),
Skill((Hammer(LCost), Some(2))), Skill((Hammer(LCost), 2)),
Skill((Hammer(LDistance), Some(2))), Skill((Hammer(LDistance), 2)),
Skill((Hammer(LKnockback), Some(2))), Skill((Hammer(LKnockback), 2)),
Skill((Hammer(LRange), Some(2))), Skill((Hammer(LRange), 2)),
]) ])

View File

@ -2,20 +2,20 @@
Group(Weapon(Sceptre)), Group(Weapon(Sceptre)),
// Beam // Beam
Skill((Sceptre(LDamage), Some(3))), Skill((Sceptre(LDamage), 3)),
Skill((Sceptre(LRange), Some(2))), Skill((Sceptre(LRange), 2)),
Skill((Sceptre(LLifesteal), Some(3))), Skill((Sceptre(LLifesteal), 3)),
Skill((Sceptre(LRegen), Some(2))), Skill((Sceptre(LRegen), 2)),
// Heal // Heal
Skill((Sceptre(HHeal), Some(3))), Skill((Sceptre(HHeal), 3)),
Skill((Sceptre(HDuration), Some(2))), Skill((Sceptre(HDuration), 2)),
Skill((Sceptre(HRange), Some(2))), Skill((Sceptre(HRange), 2)),
Skill((Sceptre(HCost), Some(2))), Skill((Sceptre(HCost), 2)),
// Ward // Ward
Skill((Sceptre(UnlockAura), None)), Skill((Sceptre(UnlockAura), 1)),
Skill((Sceptre(AStrength), Some(2))), Skill((Sceptre(AStrength), 2)),
Skill((Sceptre(ADuration), Some(2))), Skill((Sceptre(ADuration), 2)),
Skill((Sceptre(ARange), Some(2))), Skill((Sceptre(ARange), 2)),
Skill((Sceptre(ACost), Some(2))), Skill((Sceptre(ACost), 2)),
]) ])

View File

@ -2,20 +2,20 @@
Group(Weapon(Staff)), Group(Weapon(Staff)),
// Fireball // Fireball
Skill((Staff(BDamage), Some(3))), Skill((Staff(BDamage), 3)),
Skill((Staff(BRegen), Some(2))), Skill((Staff(BRegen), 2)),
Skill((Staff(BRadius), Some(3))), Skill((Staff(BRadius), 3)),
// Flamethrower // Flamethrower
Skill((Staff(FRange), Some(2))), Skill((Staff(FRange), 2)),
Skill((Staff(FDamage), Some(3))), Skill((Staff(FDamage), 3)),
Skill((Staff(FDrain), Some(2))), Skill((Staff(FDrain), 2)),
Skill((Staff(FVelocity), Some(2))), Skill((Staff(FVelocity), 2)),
// Shockwave // Shockwave
Skill((Staff(UnlockShockwave), None)), Skill((Staff(UnlockShockwave), 1)),
Skill((Staff(SDamage), Some(2))), Skill((Staff(SDamage), 2)),
Skill((Staff(SKnockback), Some(2))), Skill((Staff(SKnockback), 2)),
Skill((Staff(SRange), Some(2))), Skill((Staff(SRange), 2)),
Skill((Staff(SCost), Some(2))), Skill((Staff(SCost), 2)),
]) ])

View File

@ -1,26 +1,26 @@
([ ([
Group(Weapon(Sword)), Group(Weapon(Sword)),
Skill((Sword(InterruptingAttacks), None)), Skill((Sword(InterruptingAttacks), 1)),
// TripleStrike // TripleStrike
Skill((Sword(TsCombo), None)), Skill((Sword(TsCombo), 1)),
Skill((Sword(TsDamage), Some(3))), Skill((Sword(TsDamage), 3)),
Skill((Sword(TsRegen), Some(2))), Skill((Sword(TsRegen), 2)),
Skill((Sword(TsSpeed), Some(3))), Skill((Sword(TsSpeed), 3)),
// Dash // Dash
Skill((Sword(DCost), Some(2))), Skill((Sword(DCost), 2)),
Skill((Sword(DDrain), Some(2))), Skill((Sword(DDrain), 2)),
Skill((Sword(DDamage), Some(2))), Skill((Sword(DDamage), 2)),
Skill((Sword(DScaling), Some(3))), Skill((Sword(DScaling), 3)),
Skill((Sword(DSpeed), None)), Skill((Sword(DSpeed), 1)),
Skill((Sword(DInfinite), None)), Skill((Sword(DChargeThrough), 1)),
// Spin of death // Spin of death
Skill((Sword(UnlockSpin), None)), Skill((Sword(UnlockSpin), 1)),
Skill((Sword(SDamage), Some(2))), Skill((Sword(SDamage), 2)),
Skill((Sword(SSpeed), Some(2))), Skill((Sword(SSpeed), 2)),
Skill((Sword(SSpins), Some(2))), Skill((Sword(SSpins), 2)),
Skill((Sword(SCost), Some(2))), Skill((Sword(SCost), 2)),
]) ])

View File

@ -27,7 +27,7 @@
(Sword(DDamage), 2), (Sword(DDamage), 2),
(Sword(DScaling), 3), (Sword(DScaling), 3),
(Sword(DSpeed), 1), (Sword(DSpeed), 1),
(Sword(DInfinite), 1), (Sword(DChargeThrough), 1),
(Sword(UnlockSpin), 1), (Sword(UnlockSpin), 1),
(Sword(SDamage), 2), (Sword(SDamage), 2),
@ -157,7 +157,7 @@
(Sword(DDamage), 2), (Sword(DDamage), 2),
(Sword(DScaling), 2), (Sword(DScaling), 2),
(Sword(DSpeed), 1), (Sword(DSpeed), 1),
(Sword(DInfinite), 1), (Sword(DChargeThrough), 1),
(Sword(UnlockSpin), 1), (Sword(UnlockSpin), 1),
(Sword(SDamage), 1), (Sword(SDamage), 1),

View File

@ -30,7 +30,7 @@ vek = { version = "=0.14.1", features = ["serde"] }
chrono = "0.4" chrono = "0.4"
chrono-tz = "0.6" chrono-tz = "0.6"
sha2 = "0.9.8" sha2 = "0.9.8"
bincode = "1.3.1" serde_json = "1.0.50"
# Strum # Strum
strum = { version = "0.23", features = ["derive"] } strum = { version = "0.23", features = ["derive"] }

View File

@ -1187,7 +1187,7 @@ impl CharacterAbility {
.. ..
} = self } = self
{ {
if let Ok(Some(level)) = skillset.skill_level(Skill::Pick(Speed)) { if let Ok(level) = skillset.skill_level(Skill::Pick(Speed)) {
let modifiers = SKILL_MODIFIERS.mining_tree; let modifiers = SKILL_MODIFIERS.mining_tree;
let speed = modifiers.speed.powi(level.into()); let speed = modifiers.speed.powi(level.into());
@ -1211,13 +1211,13 @@ impl CharacterAbility {
let modifiers = SKILL_MODIFIERS.general_tree.roll; let modifiers = SKILL_MODIFIERS.general_tree.roll;
if let Ok(Some(level)) = skillset.skill_level(Skill::Roll(Cost)) { if let Ok(level) = skillset.skill_level(Skill::Roll(Cost)) {
*energy_cost *= modifiers.energy_cost.powi(level.into()); *energy_cost *= modifiers.energy_cost.powi(level.into());
} }
if let Ok(Some(level)) = skillset.skill_level(Skill::Roll(Strength)) { if let Ok(level) = skillset.skill_level(Skill::Roll(Strength)) {
*roll_strength *= modifiers.strength.powi(level.into()); *roll_strength *= modifiers.strength.powi(level.into());
} }
if let Ok(Some(level)) = skillset.skill_level(Skill::Roll(Duration)) { if let Ok(level) = skillset.skill_level(Skill::Roll(Duration)) {
*movement_duration *= modifiers.duration.powi(level.into()); *movement_duration *= modifiers.duration.powi(level.into());
} }
} }
@ -1241,9 +1241,7 @@ impl CharacterAbility {
*is_interruptible = skillset.has_skill(Sword(InterruptingAttacks)); *is_interruptible = skillset.has_skill(Sword(InterruptingAttacks));
if skillset.has_skill(Sword(TsCombo)) { if skillset.has_skill(Sword(TsCombo)) {
let speed_segments = Sword(TsSpeed) let speed_segments = f32::from(Sword(TsSpeed).max_level()) + 1.0;
.max_level()
.map_or(1.0, |l| f32::from(l) + 1.0);
let speed_level = f32::from(skillset.skill_level_or(Sword(TsSpeed), 0)); let speed_level = f32::from(skillset.skill_level_or(Sword(TsSpeed), 0));
*speed_increase = (speed_level + 1.0) / speed_segments; *speed_increase = (speed_level + 1.0) / speed_segments;
*max_speed_increase = (speed_level + 1.0) / speed_segments; *max_speed_increase = (speed_level + 1.0) / speed_segments;
@ -1259,7 +1257,7 @@ impl CharacterAbility {
*max_energy_gain *= f32::from((energy_level + 1) * stages - 1) *max_energy_gain *= f32::from((energy_level + 1) * stages - 1)
* f32::from(stages - 1) * f32::from(stages - 1)
/ f32::from(Sword(TsRegen).max_level().unwrap() + 1); / f32::from(Sword(TsRegen).max_level() + 1);
*scales_from_combo = skillset.skill_level_or(Sword(TsDamage), 0).into(); *scales_from_combo = skillset.skill_level_or(Sword(TsDamage), 0).into();
}, },
CharacterAbility::DashMelee { CharacterAbility::DashMelee {
@ -1274,22 +1272,22 @@ impl CharacterAbility {
} => { } => {
let modifiers = SKILL_MODIFIERS.sword_tree.dash; let modifiers = SKILL_MODIFIERS.sword_tree.dash;
*is_interruptible = skillset.has_skill(Sword(InterruptingAttacks)); *is_interruptible = skillset.has_skill(Sword(InterruptingAttacks));
if let Ok(Some(level)) = skillset.skill_level(Sword(DCost)) { if let Ok(level) = skillset.skill_level(Sword(DCost)) {
*energy_cost *= modifiers.energy_cost.powi(level.into()); *energy_cost *= modifiers.energy_cost.powi(level.into());
} }
if let Ok(Some(level)) = skillset.skill_level(Sword(DDrain)) { if let Ok(level) = skillset.skill_level(Sword(DDrain)) {
*energy_drain *= modifiers.energy_drain.powi(level.into()); *energy_drain *= modifiers.energy_drain.powi(level.into());
} }
if let Ok(Some(level)) = skillset.skill_level(Sword(DDamage)) { if let Ok(level) = skillset.skill_level(Sword(DDamage)) {
*base_damage *= modifiers.base_damage.powi(level.into()); *base_damage *= modifiers.base_damage.powi(level.into());
} }
if let Ok(Some(level)) = skillset.skill_level(Sword(DScaling)) { if let Ok(level) = skillset.skill_level(Sword(DScaling)) {
*scaled_damage *= modifiers.scaled_damage.powi(level.into()); *scaled_damage *= modifiers.scaled_damage.powi(level.into());
} }
if skillset.has_skill(Sword(DSpeed)) { if skillset.has_skill(Sword(DSpeed)) {
*forward_speed *= modifiers.forward_speed; *forward_speed *= modifiers.forward_speed;
} }
*charge_through = skillset.has_skill(Sword(DInfinite)); *charge_through = skillset.has_skill(Sword(DChargeThrough));
}, },
CharacterAbility::SpinMelee { CharacterAbility::SpinMelee {
ref mut is_interruptible, ref mut is_interruptible,
@ -1301,13 +1299,13 @@ impl CharacterAbility {
} => { } => {
let modifiers = SKILL_MODIFIERS.sword_tree.spin; let modifiers = SKILL_MODIFIERS.sword_tree.spin;
*is_interruptible = skillset.has_skill(Sword(InterruptingAttacks)); *is_interruptible = skillset.has_skill(Sword(InterruptingAttacks));
if let Ok(Some(level)) = skillset.skill_level(Sword(SDamage)) { if let Ok(level) = skillset.skill_level(Sword(SDamage)) {
*base_damage *= modifiers.base_damage.powi(level.into()); *base_damage *= modifiers.base_damage.powi(level.into());
} }
if let Ok(Some(level)) = skillset.skill_level(Sword(SSpeed)) { if let Ok(level) = skillset.skill_level(Sword(SSpeed)) {
*swing_duration *= modifiers.swing_duration.powi(level.into()); *swing_duration *= modifiers.swing_duration.powi(level.into());
} }
if let Ok(Some(level)) = skillset.skill_level(Sword(SCost)) { if let Ok(level) = skillset.skill_level(Sword(SCost)) {
*energy_cost *= modifiers.energy_cost.powi(level.into()); *energy_cost *= modifiers.energy_cost.powi(level.into());
} }
let spin_level = skillset.skill_level_or(Sword(SSpins), 0); let spin_level = skillset.skill_level_or(Sword(SSpins), 0);
@ -1334,7 +1332,7 @@ impl CharacterAbility {
if !skillset.has_skill(Axe(DsCombo)) { if !skillset.has_skill(Axe(DsCombo)) {
stage_data.pop(); stage_data.pop();
} }
let speed_segments = f32::from(Axe(DsSpeed).max_level().unwrap_or(1)); let speed_segments = f32::from(Axe(DsSpeed).max_level());
let speed_level = f32::from(skillset.skill_level_or(Axe(DsSpeed), 0)); let speed_level = f32::from(skillset.skill_level_or(Axe(DsSpeed), 0));
*speed_increase *= speed_level / speed_segments; *speed_increase *= speed_level / speed_segments;
*max_speed_increase *= speed_level / speed_segments; *max_speed_increase *= speed_level / speed_segments;
@ -1346,7 +1344,7 @@ impl CharacterAbility {
*max_energy_gain *= f32::from((energy_level + 1) * stages - 1).max(1.0) *max_energy_gain *= f32::from((energy_level + 1) * stages - 1).max(1.0)
* f32::from(stages - 1).max(1.0) * f32::from(stages - 1).max(1.0)
/ f32::from(Axe(DsRegen).max_level().unwrap() + 1); / f32::from(Axe(DsRegen).max_level() + 1);
*scales_from_combo = skillset.skill_level_or(Axe(DsDamage), 0).into(); *scales_from_combo = skillset.skill_level_or(Axe(DsDamage), 0).into();
}, },
CharacterAbility::SpinMelee { CharacterAbility::SpinMelee {
@ -1365,13 +1363,13 @@ impl CharacterAbility {
} else { } else {
spin_melee::MovementBehavior::ForwardGround spin_melee::MovementBehavior::ForwardGround
}; };
if let Ok(Some(level)) = skillset.skill_level(Axe(SDamage)) { if let Ok(level) = skillset.skill_level(Axe(SDamage)) {
*base_damage *= modifiers.base_damage.powi(level.into()); *base_damage *= modifiers.base_damage.powi(level.into());
} }
if let Ok(Some(level)) = skillset.skill_level(Axe(SSpeed)) { if let Ok(level) = skillset.skill_level(Axe(SSpeed)) {
*swing_duration *= modifiers.swing_duration.powi(level.into()); *swing_duration *= modifiers.swing_duration.powi(level.into());
} }
if let Ok(Some(level)) = skillset.skill_level(Axe(SCost)) { if let Ok(level) = skillset.skill_level(Axe(SCost)) {
*energy_cost *= modifiers.energy_cost.powi(level.into()); *energy_cost *= modifiers.energy_cost.powi(level.into());
} }
}, },
@ -1384,16 +1382,16 @@ impl CharacterAbility {
.. ..
} => { } => {
let modifiers = SKILL_MODIFIERS.axe_tree.leap; let modifiers = SKILL_MODIFIERS.axe_tree.leap;
if let Ok(Some(level)) = skillset.skill_level(Axe(LDamage)) { if let Ok(level) = skillset.skill_level(Axe(LDamage)) {
*base_damage *= modifiers.base_damage.powi(level.into()); *base_damage *= modifiers.base_damage.powi(level.into());
} }
if let Ok(Some(level)) = skillset.skill_level(Axe(LKnockback)) { if let Ok(level) = skillset.skill_level(Axe(LKnockback)) {
*knockback *= modifiers.knockback.powi(level.into()); *knockback *= modifiers.knockback.powi(level.into());
} }
if let Ok(Some(level)) = skillset.skill_level(Axe(LCost)) { if let Ok(level) = skillset.skill_level(Axe(LCost)) {
*energy_cost *= modifiers.energy_cost.powi(level.into()); *energy_cost *= modifiers.energy_cost.powi(level.into());
} }
if let Ok(Some(level)) = skillset.skill_level(Axe(LDistance)) { if let Ok(level) = skillset.skill_level(Axe(LDistance)) {
let strength = modifiers.leap_strength; let strength = modifiers.leap_strength;
*forward_leap_strength *= strength.powi(level.into()); *forward_leap_strength *= strength.powi(level.into());
*vertical_leap_strength *= strength.powi(level.into()); *vertical_leap_strength *= strength.powi(level.into());
@ -1419,13 +1417,13 @@ impl CharacterAbility {
} => { } => {
let modifiers = SKILL_MODIFIERS.hammer_tree.single_strike; let modifiers = SKILL_MODIFIERS.hammer_tree.single_strike;
if let Ok(Some(level)) = skillset.skill_level(Hammer(SsKnockback)) { if let Ok(level) = skillset.skill_level(Hammer(SsKnockback)) {
*stage_data = (*stage_data) *stage_data = (*stage_data)
.iter() .iter()
.map(|s| s.modify_strike(modifiers.knockback.powi(level.into()))) .map(|s| s.modify_strike(modifiers.knockback.powi(level.into())))
.collect::<Vec<_>>(); .collect::<Vec<_>>();
} }
let speed_segments = f32::from(Hammer(SsSpeed).max_level().unwrap_or(1)); let speed_segments = f32::from(Hammer(SsSpeed).max_level());
let speed_level = f32::from(skillset.skill_level_or(Hammer(SsSpeed), 0)); let speed_level = f32::from(skillset.skill_level_or(Hammer(SsSpeed), 0));
*speed_increase *= speed_level / speed_segments; *speed_increase *= speed_level / speed_segments;
*max_speed_increase *= speed_level / speed_segments; *max_speed_increase *= speed_level / speed_segments;
@ -1436,7 +1434,7 @@ impl CharacterAbility {
.expect("number of stages can't be more than u16"); .expect("number of stages can't be more than u16");
*max_energy_gain *= f32::from((energy_level + 1) * stages) *max_energy_gain *= f32::from((energy_level + 1) * stages)
/ f32::from((Hammer(SsRegen).max_level().unwrap() + 1) * stages); / f32::from((Hammer(SsRegen).max_level() + 1) * stages);
*scales_from_combo = skillset.skill_level_or(Hammer(SsDamage), 0).into(); *scales_from_combo = skillset.skill_level_or(Hammer(SsDamage), 0).into();
}, },
@ -1449,16 +1447,16 @@ impl CharacterAbility {
} => { } => {
let modifiers = SKILL_MODIFIERS.hammer_tree.charged; let modifiers = SKILL_MODIFIERS.hammer_tree.charged;
if let Ok(Some(level)) = skillset.skill_level(Hammer(CDamage)) { if let Ok(level) = skillset.skill_level(Hammer(CDamage)) {
*scaled_damage *= modifiers.scaled_damage.powi(level.into()); *scaled_damage *= modifiers.scaled_damage.powi(level.into());
} }
if let Ok(Some(level)) = skillset.skill_level(Hammer(CKnockback)) { if let Ok(level) = skillset.skill_level(Hammer(CKnockback)) {
*scaled_knockback *= modifiers.scaled_knockback.powi(level.into()); *scaled_knockback *= modifiers.scaled_knockback.powi(level.into());
} }
if let Ok(Some(level)) = skillset.skill_level(Hammer(CDrain)) { if let Ok(level) = skillset.skill_level(Hammer(CDrain)) {
*energy_drain *= modifiers.energy_drain.powi(level.into()); *energy_drain *= modifiers.energy_drain.powi(level.into());
} }
if let Ok(Some(level)) = skillset.skill_level(Hammer(CSpeed)) { if let Ok(level) = skillset.skill_level(Hammer(CSpeed)) {
let charge_time = 1.0 / modifiers.charge_rate; let charge_time = 1.0 / modifiers.charge_rate;
*charge_duration *= charge_time.powi(level.into()); *charge_duration *= charge_time.powi(level.into());
} }
@ -1473,21 +1471,21 @@ impl CharacterAbility {
.. ..
} => { } => {
let modifiers = SKILL_MODIFIERS.hammer_tree.leap; let modifiers = SKILL_MODIFIERS.hammer_tree.leap;
if let Ok(Some(level)) = skillset.skill_level(Hammer(LDamage)) { if let Ok(level) = skillset.skill_level(Hammer(LDamage)) {
*base_damage *= modifiers.base_damage.powi(level.into()); *base_damage *= modifiers.base_damage.powi(level.into());
} }
if let Ok(Some(level)) = skillset.skill_level(Hammer(LKnockback)) { if let Ok(level) = skillset.skill_level(Hammer(LKnockback)) {
*knockback *= modifiers.knockback.powi(level.into()); *knockback *= modifiers.knockback.powi(level.into());
} }
if let Ok(Some(level)) = skillset.skill_level(Hammer(LCost)) { if let Ok(level) = skillset.skill_level(Hammer(LCost)) {
*energy_cost *= modifiers.energy_cost.powi(level.into()); *energy_cost *= modifiers.energy_cost.powi(level.into());
} }
if let Ok(Some(level)) = skillset.skill_level(Hammer(LDistance)) { if let Ok(level) = skillset.skill_level(Hammer(LDistance)) {
let strength = modifiers.leap_strength; let strength = modifiers.leap_strength;
*forward_leap_strength *= strength.powi(level.into()); *forward_leap_strength *= strength.powi(level.into());
*vertical_leap_strength *= strength.powi(level.into()); *vertical_leap_strength *= strength.powi(level.into());
} }
if let Ok(Some(level)) = skillset.skill_level(Hammer(LRange)) { if let Ok(level) = skillset.skill_level(Hammer(LRange)) {
*range += modifiers.range * f32::from(level); *range += modifiers.range * f32::from(level);
} }
}, },
@ -1516,31 +1514,31 @@ impl CharacterAbility {
.. ..
} => { } => {
let modifiers = SKILL_MODIFIERS.bow_tree.charged; let modifiers = SKILL_MODIFIERS.bow_tree.charged;
if let Ok(Some(level)) = skillset.skill_level(Bow(ProjSpeed)) { if let Ok(level) = skillset.skill_level(Bow(ProjSpeed)) {
let projectile_speed_scaling = projectile_speed_modifier.powi(level.into()); let projectile_speed_scaling = projectile_speed_modifier.powi(level.into());
*initial_projectile_speed *= projectile_speed_scaling; *initial_projectile_speed *= projectile_speed_scaling;
*scaled_projectile_speed *= projectile_speed_scaling; *scaled_projectile_speed *= projectile_speed_scaling;
} }
if let Ok(Some(level)) = skillset.skill_level(Bow(CDamage)) { if let Ok(level) = skillset.skill_level(Bow(CDamage)) {
let damage_scaling = modifiers.damage_scaling.powi(level.into()); let damage_scaling = modifiers.damage_scaling.powi(level.into());
*initial_damage *= damage_scaling; *initial_damage *= damage_scaling;
*scaled_damage *= damage_scaling; *scaled_damage *= damage_scaling;
} }
if let Ok(Some(level)) = skillset.skill_level(Bow(CRegen)) { if let Ok(level) = skillset.skill_level(Bow(CRegen)) {
let regen_scaling = modifiers.regen_scaling.powi(level.into()); let regen_scaling = modifiers.regen_scaling.powi(level.into());
*initial_regen *= regen_scaling; *initial_regen *= regen_scaling;
*scaled_regen *= regen_scaling; *scaled_regen *= regen_scaling;
} }
if let Ok(Some(level)) = skillset.skill_level(Bow(CKnockback)) { if let Ok(level) = skillset.skill_level(Bow(CKnockback)) {
let knockback_scaling = modifiers.knockback_scaling.powi(level.into()); let knockback_scaling = modifiers.knockback_scaling.powi(level.into());
*initial_knockback *= knockback_scaling; *initial_knockback *= knockback_scaling;
*scaled_knockback *= knockback_scaling; *scaled_knockback *= knockback_scaling;
} }
if let Ok(Some(level)) = skillset.skill_level(Bow(CSpeed)) { if let Ok(level) = skillset.skill_level(Bow(CSpeed)) {
let charge_time = 1.0 / modifiers.charge_rate; let charge_time = 1.0 / modifiers.charge_rate;
*charge_duration *= charge_time.powi(level.into()); *charge_duration *= charge_time.powi(level.into());
} }
if let Ok(Some(level)) = skillset.skill_level(Bow(CMove)) { if let Ok(level) = skillset.skill_level(Bow(CMove)) {
*move_speed *= modifiers.move_speed.powi(level.into()); *move_speed *= modifiers.move_speed.powi(level.into());
} }
}, },
@ -1552,17 +1550,17 @@ impl CharacterAbility {
.. ..
} => { } => {
let modifiers = SKILL_MODIFIERS.bow_tree.repeater; let modifiers = SKILL_MODIFIERS.bow_tree.repeater;
if let Ok(Some(level)) = skillset.skill_level(Bow(ProjSpeed)) { if let Ok(level) = skillset.skill_level(Bow(ProjSpeed)) {
*projectile_speed *= projectile_speed_modifier.powi(level.into()); *projectile_speed *= projectile_speed_modifier.powi(level.into());
} }
if let Ok(Some(level)) = skillset.skill_level(Bow(RDamage)) { if let Ok(level) = skillset.skill_level(Bow(RDamage)) {
let power = modifiers.power.powi(level.into()); let power = modifiers.power.powi(level.into());
*projectile = projectile.modified_projectile(power, 1_f32, 1_f32); *projectile = projectile.modified_projectile(power, 1_f32, 1_f32);
} }
if let Ok(Some(level)) = skillset.skill_level(Bow(RCost)) { if let Ok(level) = skillset.skill_level(Bow(RCost)) {
*energy_cost *= modifiers.energy_cost.powi(level.into()); *energy_cost *= modifiers.energy_cost.powi(level.into());
} }
if let Ok(Some(level)) = skillset.skill_level(Bow(RSpeed)) { if let Ok(level) = skillset.skill_level(Bow(RSpeed)) {
*max_speed *= modifiers.max_speed.powi(level.into()); *max_speed *= modifiers.max_speed.powi(level.into());
} }
}, },
@ -1575,20 +1573,20 @@ impl CharacterAbility {
.. ..
} => { } => {
let modifiers = SKILL_MODIFIERS.bow_tree.shotgun; let modifiers = SKILL_MODIFIERS.bow_tree.shotgun;
if let Ok(Some(level)) = skillset.skill_level(Bow(ProjSpeed)) { if let Ok(level) = skillset.skill_level(Bow(ProjSpeed)) {
*projectile_speed *= projectile_speed_modifier.powi(level.into()); *projectile_speed *= projectile_speed_modifier.powi(level.into());
} }
if let Ok(Some(level)) = skillset.skill_level(Bow(SDamage)) { if let Ok(level) = skillset.skill_level(Bow(SDamage)) {
let power = modifiers.power.powi(level.into()); let power = modifiers.power.powi(level.into());
*projectile = projectile.modified_projectile(power, 1_f32, 1_f32); *projectile = projectile.modified_projectile(power, 1_f32, 1_f32);
} }
if let Ok(Some(level)) = skillset.skill_level(Bow(SCost)) { if let Ok(level) = skillset.skill_level(Bow(SCost)) {
*energy_cost *= modifiers.energy_cost.powi(level.into()); *energy_cost *= modifiers.energy_cost.powi(level.into());
} }
if let Ok(Some(level)) = skillset.skill_level(Bow(SArrows)) { if let Ok(level) = skillset.skill_level(Bow(SArrows)) {
*num_projectiles += u32::from(level) * modifiers.num_projectiles; *num_projectiles += u32::from(level) * modifiers.num_projectiles;
} }
if let Ok(Some(level)) = skillset.skill_level(Bow(SSpread)) { if let Ok(level) = skillset.skill_level(Bow(SSpread)) {
*projectile_spread *= modifiers.spread.powi(level.into()); *projectile_spread *= modifiers.spread.powi(level.into());
} }
}, },
@ -1622,19 +1620,19 @@ impl CharacterAbility {
.. ..
} => { } => {
let modifiers = SKILL_MODIFIERS.staff_tree.flamethrower; let modifiers = SKILL_MODIFIERS.staff_tree.flamethrower;
if let Ok(Some(level)) = skillset.skill_level(Staff(FDamage)) { if let Ok(level) = skillset.skill_level(Staff(FDamage)) {
*damage *= modifiers.damage.powi(level.into()); *damage *= modifiers.damage.powi(level.into());
} }
if let Ok(Some(level)) = skillset.skill_level(Staff(FRange)) { if let Ok(level) = skillset.skill_level(Staff(FRange)) {
let range_mod = modifiers.range.powi(level.into()); let range_mod = modifiers.range.powi(level.into());
*range *= range_mod; *range *= range_mod;
// Duration modified to keep velocity constant // Duration modified to keep velocity constant
*beam_duration *= range_mod; *beam_duration *= range_mod;
} }
if let Ok(Some(level)) = skillset.skill_level(Staff(FDrain)) { if let Ok(level) = skillset.skill_level(Staff(FDrain)) {
*energy_drain *= modifiers.energy_drain.powi(level.into()); *energy_drain *= modifiers.energy_drain.powi(level.into());
} }
if let Ok(Some(level)) = skillset.skill_level(Staff(FVelocity)) { if let Ok(level) = skillset.skill_level(Staff(FVelocity)) {
let velocity_increase = modifiers.velocity.powi(level.into()); let velocity_increase = modifiers.velocity.powi(level.into());
let duration_mod = 1.0 / (1.0 + velocity_increase); let duration_mod = 1.0 / (1.0 + velocity_increase);
*beam_duration *= duration_mod; *beam_duration *= duration_mod;
@ -1648,17 +1646,17 @@ impl CharacterAbility {
.. ..
} => { } => {
let modifiers = SKILL_MODIFIERS.staff_tree.shockwave; let modifiers = SKILL_MODIFIERS.staff_tree.shockwave;
if let Ok(Some(level)) = skillset.skill_level(Staff(SDamage)) { if let Ok(level) = skillset.skill_level(Staff(SDamage)) {
*damage *= modifiers.damage.powi(level.into()); *damage *= modifiers.damage.powi(level.into());
} }
if let Ok(Some(level)) = skillset.skill_level(Staff(SKnockback)) { if let Ok(level) = skillset.skill_level(Staff(SKnockback)) {
let knockback_mod = modifiers.knockback.powi(level.into()); let knockback_mod = modifiers.knockback.powi(level.into());
*knockback = knockback.modify_strength(knockback_mod); *knockback = knockback.modify_strength(knockback_mod);
} }
if let Ok(Some(level)) = skillset.skill_level(Staff(SRange)) { if let Ok(level) = skillset.skill_level(Staff(SRange)) {
*shockwave_duration *= modifiers.duration.powi(level.into()); *shockwave_duration *= modifiers.duration.powi(level.into());
} }
if let Ok(Some(level)) = skillset.skill_level(Staff(SCost)) { if let Ok(level) = skillset.skill_level(Staff(SCost)) {
*energy_cost *= modifiers.energy_cost.powi(level.into()); *energy_cost *= modifiers.energy_cost.powi(level.into());
} }
}, },
@ -1681,19 +1679,19 @@ impl CharacterAbility {
.. ..
} => { } => {
let modifiers = SKILL_MODIFIERS.sceptre_tree.beam; let modifiers = SKILL_MODIFIERS.sceptre_tree.beam;
if let Ok(Some(level)) = skillset.skill_level(Sceptre(LDamage)) { if let Ok(level) = skillset.skill_level(Sceptre(LDamage)) {
*damage *= modifiers.damage.powi(level.into()); *damage *= modifiers.damage.powi(level.into());
} }
if let Ok(Some(level)) = skillset.skill_level(Sceptre(LRange)) { if let Ok(level) = skillset.skill_level(Sceptre(LRange)) {
let range_mod = modifiers.range.powi(level.into()); let range_mod = modifiers.range.powi(level.into());
*range *= range_mod; *range *= range_mod;
// Duration modified to keep velocity constant // Duration modified to keep velocity constant
*beam_duration *= range_mod; *beam_duration *= range_mod;
} }
if let Ok(Some(level)) = skillset.skill_level(Sceptre(LRegen)) { if let Ok(level) = skillset.skill_level(Sceptre(LRegen)) {
*energy_regen *= modifiers.energy_regen.powi(level.into()); *energy_regen *= modifiers.energy_regen.powi(level.into());
} }
if let (Ok(Some(level)), Some(CombatEffect::Lifesteal(ref mut lifesteal))) = if let (Ok(level), Some(CombatEffect::Lifesteal(ref mut lifesteal))) =
(skillset.skill_level(Sceptre(LLifesteal)), damage_effect) (skillset.skill_level(Sceptre(LLifesteal)), damage_effect)
{ {
*lifesteal *= modifiers.lifesteal.powi(level.into()); *lifesteal *= modifiers.lifesteal.powi(level.into());
@ -1707,18 +1705,18 @@ impl CharacterAbility {
.. ..
} => { } => {
let modifiers = SKILL_MODIFIERS.sceptre_tree.healing_aura; let modifiers = SKILL_MODIFIERS.sceptre_tree.healing_aura;
if let Ok(Some(level)) = skillset.skill_level(Sceptre(HHeal)) { if let Ok(level) = skillset.skill_level(Sceptre(HHeal)) {
aura.strength *= modifiers.strength.powi(level.into()); aura.strength *= modifiers.strength.powi(level.into());
} }
if let Ok(Some(level)) = skillset.skill_level(Sceptre(HDuration)) { if let Ok(level) = skillset.skill_level(Sceptre(HDuration)) {
if let Some(ref mut duration) = aura.duration { if let Some(ref mut duration) = aura.duration {
*duration *= modifiers.duration.powi(level.into()); *duration *= modifiers.duration.powi(level.into());
} }
} }
if let Ok(Some(level)) = skillset.skill_level(Sceptre(HRange)) { if let Ok(level) = skillset.skill_level(Sceptre(HRange)) {
*range *= modifiers.range.powi(level.into()); *range *= modifiers.range.powi(level.into());
} }
if let Ok(Some(level)) = skillset.skill_level(Sceptre(HCost)) { if let Ok(level) = skillset.skill_level(Sceptre(HCost)) {
*energy_cost *= modifiers.energy_cost.powi(level.into()); *energy_cost *= modifiers.energy_cost.powi(level.into());
} }
}, },
@ -1730,18 +1728,18 @@ impl CharacterAbility {
.. ..
} => { } => {
let modifiers = SKILL_MODIFIERS.sceptre_tree.warding_aura; let modifiers = SKILL_MODIFIERS.sceptre_tree.warding_aura;
if let Ok(Some(level)) = skillset.skill_level(Sceptre(AStrength)) { if let Ok(level) = skillset.skill_level(Sceptre(AStrength)) {
aura.strength *= modifiers.strength.powi(level.into()); aura.strength *= modifiers.strength.powi(level.into());
} }
if let Ok(Some(level)) = skillset.skill_level(Sceptre(ADuration)) { if let Ok(level) = skillset.skill_level(Sceptre(ADuration)) {
if let Some(ref mut duration) = aura.duration { if let Some(ref mut duration) = aura.duration {
*duration *= modifiers.duration.powi(level.into()); *duration *= modifiers.duration.powi(level.into());
} }
} }
if let Ok(Some(level)) = skillset.skill_level(Sceptre(ARange)) { if let Ok(level) = skillset.skill_level(Sceptre(ARange)) {
*range *= modifiers.range.powi(level.into()); *range *= modifiers.range.powi(level.into());
} }
if let Ok(Some(level)) = skillset.skill_level(Sceptre(ACost)) { if let Ok(level) = skillset.skill_level(Sceptre(ACost)) {
*energy_cost *= modifiers.energy_cost.powi(level.into()); *energy_cost *= modifiers.energy_cost.powi(level.into());
} }
}, },

View File

@ -5,7 +5,6 @@ use crate::{
skills::{GeneralSkill, Skill}, skills::{GeneralSkill, Skill},
}, },
}; };
use bincode;
use hashbrown::HashMap; use hashbrown::HashMap;
use lazy_static::lazy_static; use lazy_static::lazy_static;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
@ -17,6 +16,9 @@ use tracing::{trace, warn};
pub mod skills; pub mod skills;
/// BTreeSet is used here to ensure that skills are ordered. This is important
/// to ensure that the hash created from it is consistent so that we don't
/// needlessly force a respec when loading skills from persistence.
#[derive(Clone, Debug, Serialize, Deserialize)] #[derive(Clone, Debug, Serialize, Deserialize)]
pub struct SkillTreeMap(HashMap<SkillGroupKind, BTreeSet<Skill>>); pub struct SkillTreeMap(HashMap<SkillGroupKind, BTreeSet<Skill>>);
@ -32,7 +34,7 @@ pub struct SkillGroupDef {
} }
#[derive(Clone, Debug, Serialize, Deserialize)] #[derive(Clone, Debug, Serialize, Deserialize)]
pub struct SkillLevelMap(HashMap<Skill, Option<u16>>); pub struct SkillLevelMap(HashMap<Skill, u16>);
impl Asset for SkillLevelMap { impl Asset for SkillLevelMap {
type Loader = assets::RonLoader; type Loader = assets::RonLoader;
@ -41,7 +43,7 @@ impl Asset for SkillLevelMap {
} }
#[derive(Clone, Debug, Serialize, Deserialize)] #[derive(Clone, Debug, Serialize, Deserialize)]
pub struct SkillPrerequisitesMap(HashMap<Skill, HashMap<Skill, Option<u16>>>); pub struct SkillPrerequisitesMap(HashMap<Skill, HashMap<Skill, u16>>);
impl Asset for SkillPrerequisitesMap { impl Asset for SkillPrerequisitesMap {
type Loader = assets::RonLoader; type Loader = assets::RonLoader;
@ -63,14 +65,11 @@ lazy_static! {
total_skill_point_cost: skills total_skill_point_cost: skills
.iter() .iter()
.map(|skill| { .map(|skill| {
if let Some(max_level) = skill.max_level() { let max_level = skill.max_level();
(1..=max_level) (1..=max_level)
.into_iter() .into_iter()
.map(|level| skill.skill_cost(Some(level))) .map(|level| skill.skill_cost(level))
.sum() .sum::<u16>()
} else {
skill.skill_cost(None)
}
}) })
.sum() .sum()
}) })
@ -85,13 +84,13 @@ lazy_static! {
map.iter().flat_map(|(sgk, skills)| skills.into_iter().map(move |s| (*s, *sgk))).collect() map.iter().flat_map(|(sgk, skills)| skills.into_iter().map(move |s| (*s, *sgk))).collect()
}; };
// Loads the maximum level that a skill can obtain // Loads the maximum level that a skill can obtain
pub static ref SKILL_MAX_LEVEL: HashMap<Skill, Option<u16>> = { pub static ref SKILL_MAX_LEVEL: HashMap<Skill, u16> = {
SkillLevelMap::load_expect_cloned( SkillLevelMap::load_expect_cloned(
"common.skill_trees.skill_max_levels", "common.skill_trees.skill_max_levels",
).0 ).0
}; };
// Loads the prerequisite skills for a particular skill // Loads the prerequisite skills for a particular skill
pub static ref SKILL_PREREQUISITES: HashMap<Skill, HashMap<Skill, Option<u16>>> = { pub static ref SKILL_PREREQUISITES: HashMap<Skill, HashMap<Skill, u16>> = {
SkillPrerequisitesMap::load_expect_cloned( SkillPrerequisitesMap::load_expect_cloned(
"common.skill_trees.skill_prerequisites", "common.skill_trees.skill_prerequisites",
).0 ).0
@ -103,9 +102,9 @@ lazy_static! {
let mut hashes = HashMap::new(); let mut hashes = HashMap::new();
for (skill_group_kind, skills) in map.iter() { for (skill_group_kind, skills) in map.iter() {
let mut hasher = Sha256::new(); let mut hasher = Sha256::new();
let bincode_input: Vec<_> = skills.iter().map(|skill| (*skill, skill.max_level())).collect(); let json_input: Vec<_> = skills.iter().map(|skill| (*skill, skill.max_level())).collect();
let hash_input = bincode::serialize(&bincode_input).unwrap_or_default(); let hash_input = serde_json::to_string(&json_input).unwrap_or_default();
hasher.update(hash_input); hasher.update(hash_input.as_bytes());
let hash_result = hasher.finalize(); let hash_result = hasher.finalize();
hashes.insert(*skill_group_kind, hash_result.iter().copied().collect()); hashes.insert(*skill_group_kind, hash_result.iter().copied().collect());
} }
@ -121,6 +120,8 @@ pub enum SkillGroupKind {
impl SkillGroupKind { impl SkillGroupKind {
/// Gets the cost in experience of earning a skill point /// Gets the cost in experience of earning a skill point
/// Changing this is forward compatible with persistence and will
/// automatically force a respec for skill group kinds that are affected.
pub fn skill_point_cost(self, level: u16) -> u32 { pub fn skill_point_cost(self, level: u16) -> u32 {
const EXP_INCREMENT: f32 = 10.0; const EXP_INCREMENT: f32 = 10.0;
const STARTING_EXP: f32 = 70.0; const STARTING_EXP: f32 = 70.0;
@ -186,9 +187,21 @@ impl SkillGroup {
pub fn earn_skill_point(&mut self) -> Result<(), SpRewardError> { pub fn earn_skill_point(&mut self) -> Result<(), SpRewardError> {
let sp_cost = self.skill_group_kind.skill_point_cost(self.earned_sp); let sp_cost = self.skill_group_kind.skill_point_cost(self.earned_sp);
if self.available_experience() >= sp_cost { if self.available_experience() >= sp_cost {
self.spent_exp = self.spent_exp.saturating_add(sp_cost); let new_spent_exp = self
self.available_sp = self.available_sp.saturating_add(1); .spent_exp
self.earned_sp = self.earned_sp.saturating_add(1); .checked_add(sp_cost)
.ok_or(SpRewardError::Overflow)?;
let new_earned_sp = self
.earned_sp
.checked_add(1)
.ok_or(SpRewardError::Overflow)?;
let new_available_sp = self
.available_sp
.checked_add(1)
.ok_or(SpRewardError::Overflow)?;
self.spent_exp = new_spent_exp;
self.earned_sp = new_earned_sp;
self.available_sp = new_available_sp;
Ok(()) Ok(())
} else { } else {
Err(SpRewardError::InsufficientExp) Err(SpRewardError::InsufficientExp)
@ -202,7 +215,7 @@ impl SkillGroup {
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] #[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
pub struct SkillSet { pub struct SkillSet {
skill_groups: Vec<SkillGroup>, skill_groups: Vec<SkillGroup>,
skills: HashMap<Skill, Option<u16>>, skills: HashMap<Skill, u16>,
pub modify_health: bool, pub modify_health: bool,
pub modify_energy: bool, pub modify_energy: bool,
} }
@ -229,12 +242,12 @@ impl Default for SkillSet {
} }
impl SkillSet { impl SkillSet {
pub fn initial_skills() -> HashMap<Skill, Option<u16>> { pub fn initial_skills() -> HashMap<Skill, u16> {
let mut skills = HashMap::new(); let mut skills = HashMap::new();
skills.insert(Skill::UnlockGroup(SkillGroupKind::General), None); skills.insert(Skill::UnlockGroup(SkillGroupKind::General), 1);
skills.insert( skills.insert(
Skill::UnlockGroup(SkillGroupKind::Weapon(ToolKind::Pick)), Skill::UnlockGroup(SkillGroupKind::Weapon(ToolKind::Pick)),
None, 1,
); );
skills skills
} }
@ -310,10 +323,15 @@ impl SkillSet {
} }
/// Returns a mutable reference to a particular skill group in a skillset /// Returns a mutable reference to a particular skill group in a skillset
/// Requires that skillset contains skill that unlocks the skill group
fn skill_group_mut(&mut self, skill_group: SkillGroupKind) -> Option<&mut SkillGroup> { fn skill_group_mut(&mut self, skill_group: SkillGroupKind) -> Option<&mut SkillGroup> {
// In order to mutate skill group, we check that the prerequisite skill has been
// acquired, as this is one of the requirements for us to consider the skill
// group accessible.
let skill_group_accessible = self.skill_group_accessible(skill_group);
self.skill_groups self.skill_groups
.iter_mut() .iter_mut()
.find(|s_g| s_g.skill_group_kind == skill_group) .find(|s_g| s_g.skill_group_kind == skill_group && skill_group_accessible)
} }
/// Adds experience to the skill group within an entity's skill set /// Adds experience to the skill group within an entity's skill set
@ -347,13 +365,13 @@ impl SkillSet {
skill_group_kind: SkillGroupKind, skill_group_kind: SkillGroupKind,
number_of_skill_points: u16, number_of_skill_points: u16,
) { ) {
if let Some(mut skill_group) = self.skill_group_mut(skill_group_kind) { for _ in 0..number_of_skill_points {
skill_group.available_sp = skill_group let exp_needed = self.skill_point_cost(skill_group_kind);
.available_sp self.add_experience(skill_group_kind, exp_needed);
.saturating_add(number_of_skill_points); if self.earn_skill_point(skill_group_kind).is_err() {
skill_group.earned_sp = skill_group.earned_sp.saturating_add(number_of_skill_points); warn!("Failed to add skill point");
} else { break;
warn!("Tried to add skill points to a skill group that player does not have"); }
} }
} }
@ -397,11 +415,7 @@ impl SkillSet {
/// Checks if player has sufficient skill points to purchase a skill /// Checks if player has sufficient skill points to purchase a skill
pub fn sufficient_skill_points(&self, skill: Skill) -> bool { pub fn sufficient_skill_points(&self, skill: Skill) -> bool {
if let Some(skill_group_kind) = skill.skill_group_kind() { if let Some(skill_group_kind) = skill.skill_group_kind() {
if let Some(skill_group) = self if let Some(skill_group) = self.skill_group(skill_group_kind) {
.skill_groups
.iter()
.find(|x| x.skill_group_kind == skill_group_kind)
{
let needed_sp = self.skill_cost(skill); let needed_sp = self.skill_cost(skill);
skill_group.available_sp >= needed_sp skill_group.available_sp >= needed_sp
} else { } else {
@ -413,13 +427,13 @@ impl SkillSet {
} }
/// 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) -> u16 {
if let Ok(level) = self.skill_level(skill) { if let Ok(level) = self.skill_level(skill) {
// If already has skill, and that skill has levels, level + 1 // If already has skill, then level + 1
level.map(|l| l + 1) level + 1
} else { } else {
// Else if the skill has levels, 1 // Otherwise the next level is the first level
skill.max_level().map(|_| 1) 1
} }
} }
@ -431,11 +445,13 @@ impl SkillSet {
let prerequisites_met = self.prerequisites_met(skill); let prerequisites_met = self.prerequisites_met(skill);
// Check that skill is not yet at max level // Check that skill is not yet at max level
if !matches!(self.skills.get(&skill), Some(level) if *level == skill.max_level()) { if !matches!(self.skills.get(&skill), Some(level) if *level == skill.max_level()) {
if self.has_skill(Skill::UnlockGroup(skill_group_kind)) {
if let Some(mut skill_group) = self.skill_group_mut(skill_group_kind) { if let Some(mut skill_group) = self.skill_group_mut(skill_group_kind) {
if prerequisites_met { if prerequisites_met {
if skill_group.available_sp >= skill.skill_cost(next_level) { if let Some(new_available_sp) = skill_group
skill_group.available_sp -= skill.skill_cost(next_level); .available_sp
.checked_sub(skill.skill_cost(next_level))
{
skill_group.available_sp = new_available_sp;
skill_group.ordered_skills.push(skill); skill_group.ordered_skills.push(skill);
match skill { match skill {
Skill::UnlockGroup(group) => { Skill::UnlockGroup(group) => {
@ -452,9 +468,7 @@ impl SkillSet {
self.skills.insert(skill, next_level); self.skills.insert(skill, next_level);
Ok(()) Ok(())
} else { } else {
trace!( trace!("Tried to unlock skill for skill group with insufficient SP");
"Tried to unlock skill for skill group with insufficient SP"
);
Err(SkillUnlockError::InsufficientSP) Err(SkillUnlockError::InsufficientSP)
} }
} else { } else {
@ -465,10 +479,6 @@ impl SkillSet {
trace!("Tried to unlock skill for a skill group that player does not have"); trace!("Tried to unlock skill for a skill group that player does not have");
Err(SkillUnlockError::UnavailableSkillGroup) Err(SkillUnlockError::UnavailableSkillGroup)
} }
} else {
trace!("Tried to unlock skill for a skill group that player does not have");
Err(SkillUnlockError::UnavailableSkillGroup)
}
} else { } else {
trace!("Tried to unlock skill the player already has"); trace!("Tried to unlock skill the player already has");
Err(SkillUnlockError::SkillAlreadyUnlocked) Err(SkillUnlockError::SkillAlreadyUnlocked)
@ -486,6 +496,7 @@ impl SkillSet {
pub fn has_available_sp(&self) -> bool { pub fn has_available_sp(&self) -> bool {
self.skill_groups.iter().any(|sg| { self.skill_groups.iter().any(|sg| {
sg.available_sp > 0 sg.available_sp > 0
// Subtraction in bounds because of the invariant that available_sp <= earned_sp
&& (sg.earned_sp - sg.available_sp) < sg.skill_group_kind.total_skill_point_cost() && (sg.earned_sp - sg.available_sp) < sg.skill_group_kind.total_skill_point_cost()
}) })
} }
@ -503,7 +514,7 @@ impl SkillSet {
pub fn has_skill(&self, skill: Skill) -> bool { self.skills.contains_key(&skill) } pub fn has_skill(&self, skill: Skill) -> bool { self.skills.contains_key(&skill) }
/// Returns the level of the skill /// Returns the level of the skill
pub fn skill_level(&self, skill: Skill) -> Result<Option<u16>, SkillError> { pub fn skill_level(&self, skill: Skill) -> Result<u16, SkillError> {
if let Some(level) = self.skills.get(&skill).copied() { if let Some(level) = self.skills.get(&skill).copied() {
Ok(level) Ok(level)
} else { } else {
@ -513,7 +524,7 @@ impl SkillSet {
/// Returns the level of the skill or passed value as default /// Returns the level of the skill or passed value as default
pub fn skill_level_or(&self, skill: Skill, default: u16) -> u16 { pub fn skill_level_or(&self, skill: Skill, default: u16) -> u16 {
if let Ok(Some(level)) = self.skill_level(skill) { if let Ok(level) = self.skill_level(skill) {
level level
} else { } else {
default default
@ -521,6 +532,7 @@ impl SkillSet {
} }
} }
#[derive(Debug)]
pub enum SkillError { pub enum SkillError {
MissingSkill, MissingSkill,
} }
@ -537,4 +549,5 @@ pub enum SkillUnlockError {
pub enum SpRewardError { pub enum SpRewardError {
InsufficientExp, InsufficientExp,
UnavailableSkillGroup, UnavailableSkillGroup,
Overflow,
} }

View File

@ -22,7 +22,6 @@ pub enum Skill {
Climb(ClimbSkill), Climb(ClimbSkill),
Swim(SwimSkill), Swim(SwimSkill),
Pick(MiningSkill), Pick(MiningSkill),
// TODO: Don't do this, maybe Sharp has idea?
UnlockGroup(SkillGroupKind), UnlockGroup(SkillGroupKind),
} }
@ -41,7 +40,7 @@ pub enum SwordSkill {
DDamage, DDamage,
DScaling, DScaling,
DSpeed, DSpeed,
DInfinite, // Represents charge through, not migrated because laziness DChargeThrough,
// Spin upgrades // Spin upgrades
UnlockSpin, UnlockSpin,
SDamage, SDamage,
@ -187,23 +186,30 @@ pub enum MiningSkill {
impl Skill { impl Skill {
/// Returns a vec of prerequisite skills (it should only be necessary to /// Returns a vec of prerequisite skills (it should only be necessary to
/// note direct prerequisites) /// note direct prerequisites)
pub fn prerequisite_skills(&self) -> impl Iterator<Item = (Skill, Option<u16>)> { /// Automatically filters itself from the skills returned
pub fn prerequisite_skills(&self) -> impl Iterator<Item = (Skill, u16)> + '_ {
SKILL_PREREQUISITES SKILL_PREREQUISITES
.get(self) .get(self)
.into_iter() .into_iter()
.flatten() .flatten()
.map(|(skill, level)| (*skill, *level)) .filter_map(move |(skill, level)| {
if self == skill {
None
} else {
Some((*skill, *level))
}
})
} }
/// Returns the cost in skill points of unlocking a particular skill /// Returns the cost in skill points of unlocking a particular skill
pub fn skill_cost(&self, level: Option<u16>) -> u16 { pub fn skill_cost(&self, level: u16) -> u16 {
// TODO: Better balance the costs later // TODO: Better balance the costs later
level.unwrap_or(1) level
} }
/// Returns the maximum level a skill can reach, returns None if the skill /// Returns the maximum level a skill can reach, returns None if the skill
/// doesn't level /// doesn't level
pub fn max_level(&self) -> Option<u16> { SKILL_MAX_LEVEL.get(self).copied().flatten() } pub fn max_level(&self) -> u16 { SKILL_MAX_LEVEL.get(self).copied().unwrap_or(1) }
/// Returns the skill group type for a skill from the static skill group /// Returns the skill group type for a skill from the static skill group
/// definitions. /// definitions.

View File

@ -23,19 +23,19 @@ impl assets::Asset for SkillSetTree {
#[derive(Debug, Deserialize, Clone)] #[derive(Debug, Deserialize, Clone)]
enum SkillNode { enum SkillNode {
Tree(String), Tree(String),
Skill((Skill, Option<u16>)), Skill((Skill, u16)),
Group(SkillGroupKind), Group(SkillGroupKind),
} }
#[must_use] #[must_use]
fn skills_from_asset_expect(asset_specifier: &str) -> Vec<(Skill, Option<u16>)> { fn skills_from_asset_expect(asset_specifier: &str) -> Vec<(Skill, u16)> {
let nodes = SkillSetTree::load_expect(asset_specifier).read(); let nodes = SkillSetTree::load_expect(asset_specifier).read();
skills_from_nodes(&nodes.0) skills_from_nodes(&nodes.0)
} }
#[must_use] #[must_use]
fn skills_from_nodes(nodes: &[SkillNode]) -> Vec<(Skill, Option<u16>)> { fn skills_from_nodes(nodes: &[SkillNode]) -> Vec<(Skill, u16)> {
let mut skills = Vec::new(); let mut skills = Vec::new();
for node in nodes { for node in nodes {
match node { match node {
@ -46,7 +46,7 @@ fn skills_from_nodes(nodes: &[SkillNode]) -> Vec<(Skill, Option<u16>)> {
skills.push(*req); skills.push(*req);
}, },
SkillNode::Group(group) => { SkillNode::Group(group) => {
skills.push((Skill::UnlockGroup(*group), None)); skills.push((Skill::UnlockGroup(*group), 1));
}, },
} }
} }
@ -95,7 +95,7 @@ impl SkillSetBuilder {
/// 1) If added skill doesn't have any group /// 1) If added skill doesn't have any group
/// 2) If added skill already applied /// 2) If added skill already applied
/// 3) If added skill wasn't applied at the end /// 3) If added skill wasn't applied at the end
pub fn with_skill(mut self, skill: Skill, level: Option<u16>) -> Self { pub fn with_skill(mut self, skill: Skill, level: u16) -> Self {
let group = if let Some(skill_group) = skill.skill_group_kind() { let group = if let Some(skill_group) = skill.skill_group_kind() {
skill_group skill_group
} else { } else {
@ -114,7 +114,7 @@ impl SkillSetBuilder {
); );
common_base::dev_panic!(err, or return self); common_base::dev_panic!(err, or return self);
} }
for _ in 0..level.unwrap_or(1) { for _ in 0..level {
skill_set.add_skill_points(group, skill_set.skill_cost(skill)); skill_set.add_skill_points(group, skill_set.skill_cost(skill));
if let Err(err) = skill_set.unlock_skill(skill) { if let Err(err) = skill_set.unlock_skill(skill) {
let err_msg = format!("Failed to add skill: {:?}. Error: {:?}", skill, err); let err_msg = format!("Failed to add skill: {:?}. Error: {:?}", skill, err);
@ -137,7 +137,7 @@ impl SkillSetBuilder {
} }
#[must_use] #[must_use]
fn skill_is_applied(skill_set: &SkillSet, skill: Skill, level: Option<u16>) -> bool { fn skill_is_applied(skill_set: &SkillSet, skill: Skill, level: u16) -> bool {
if let Ok(applied_level) = skill_set.skill_level(skill) { if let Ok(applied_level) = skill_set.skill_level(skill) {
applied_level == level applied_level == level
} else { } else {

View File

@ -34,10 +34,10 @@ 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 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(level) = join_data.skill_set.skill_level(Skill::Climb(Cost)) {
data.static_data.energy_cost *= modifiers.energy_cost.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(level) = join_data.skill_set.skill_level(Skill::Climb(Speed)) {
data.static_data.movement_speed *= modifiers.speed.powi(level.into()); data.static_data.movement_speed *= modifiers.speed.powi(level.into());
} }
data data

View File

@ -437,7 +437,7 @@ fn swim_move(
let force = efficiency * force; let force = efficiency * force;
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(level) = data.skill_set.skill_level(Skill::Swim(SwimSkill::Speed)) {
let modifiers = SKILL_MODIFIERS.general_tree.swim; let modifiers = SKILL_MODIFIERS.general_tree.swim;
water_accel *= modifiers.speed.powi(level.into()); water_accel *= modifiers.speed.powi(level.into());
} }

View File

@ -140,17 +140,17 @@ impl<'a> System<'a> for Sys {
if !skills_to_level.is_empty() { if !skills_to_level.is_empty() {
for skill_group in skills_to_level { for skill_group in skills_to_level {
if skill_set.earn_skill_point(skill_group).is_err() { match skill_set.earn_skill_point(skill_group) {
warn!( Ok(_) => outcomes.push(Outcome::SkillPointGain {
"Attempted to add skill point to group which is inelgible to earn one"
);
}
outcomes.push(Outcome::SkillPointGain {
uid: *uid, uid: *uid,
skill_tree: skill_group, skill_tree: skill_group,
total_points: skill_set.earned_sp(skill_group), total_points: skill_set.earned_sp(skill_group),
pos: pos.0, pos: pos.0,
}); }),
Err(_) => warn!(
"Attempted to add skill point to group which is inelgible to earn one"
),
}
} }
} }
} }
@ -167,7 +167,6 @@ impl<'a> System<'a> for Sys {
if skill_set.modify_health { if skill_set.modify_health {
let health_level = skill_set let health_level = skill_set
.skill_level(Skill::General(GeneralSkill::HealthIncrease)) .skill_level(Skill::General(GeneralSkill::HealthIncrease))
.unwrap_or(None)
.unwrap_or(0); .unwrap_or(0);
health.update_max_hp(*body, health_level); health.update_max_hp(*body, health_level);
skill_set.modify_health = false; skill_set.modify_health = false;
@ -175,7 +174,6 @@ impl<'a> System<'a> for Sys {
if skill_set.modify_energy { if skill_set.modify_energy {
let energy_level = skill_set let energy_level = skill_set
.skill_level(Skill::General(GeneralSkill::EnergyIncrease)) .skill_level(Skill::General(GeneralSkill::EnergyIncrease))
.unwrap_or(None)
.unwrap_or(0); .unwrap_or(0);
energy.update_max_energy(*body, energy_level); energy.update_max_energy(*body, energy_level);
skill_set.modify_energy = false; skill_set.modify_energy = false;

View File

@ -530,6 +530,8 @@ fn convert_skill_groups_from_database(
spent_exp: 0, spent_exp: 0,
available_sp: 0, available_sp: 0,
earned_sp: 0, earned_sp: 0,
// Ordered skills empty here as skills get inserted later as they are unlocked, so long
// as there is not a respec.
ordered_skills: Vec::new(), ordered_skills: Vec::new(),
}; };
@ -559,16 +561,17 @@ pub fn convert_skill_groups_to_database(
entity_id: CharacterId, entity_id: CharacterId,
skill_groups: Vec<skillset::SkillGroup>, skill_groups: Vec<skillset::SkillGroup>,
) -> Vec<SkillGroup> { ) -> Vec<SkillGroup> {
let skill_group_hashes = &skillset::SKILL_GROUP_HASHES;
skill_groups skill_groups
.into_iter() .into_iter()
.map(|sg| SkillGroup { .map(|sg| SkillGroup {
entity_id, entity_id,
skill_group_kind: json_models::skill_group_to_db_string(sg.skill_group_kind), skill_group_kind: json_models::skill_group_to_db_string(sg.skill_group_kind),
earned_exp: sg.earned_exp as i32, earned_exp: i64::from(sg.earned_exp),
spent_exp: sg.spent_exp as i32, spent_exp: i64::from(sg.spent_exp),
// If fails to convert, just forces a respec on next login // If fails to convert, just forces a respec on next login
skills: serde_json::to_string(&sg.ordered_skills).unwrap_or_else(|_| "".to_string()), skills: serde_json::to_string(&sg.ordered_skills).unwrap_or_else(|_| "".to_string()),
hash_val: skillset::SKILL_GROUP_HASHES hash_val: skill_group_hashes
.get(&sg.skill_group_kind) .get(&sg.skill_group_kind)
.cloned() .cloned()
.unwrap_or_default(), .unwrap_or_default(),

View File

@ -23,8 +23,8 @@ pub struct Body {
pub struct SkillGroup { pub struct SkillGroup {
pub entity_id: i64, pub entity_id: i64,
pub skill_group_kind: String, pub skill_group_kind: String,
pub earned_exp: i32, pub earned_exp: i64,
pub spent_exp: i32, pub spent_exp: i64,
pub skills: String, pub skills: String,
pub hash_val: Vec<u8>, pub hash_val: Vec<u8>,
} }

View File

@ -221,7 +221,6 @@ impl StateExt for State {
body, body,
skill_set skill_set
.skill_level(Skill::General(GeneralSkill::EnergyIncrease)) .skill_level(Skill::General(GeneralSkill::EnergyIncrease))
.unwrap_or(None)
.unwrap_or(0), .unwrap_or(0),
)) ))
.with(stats) .with(stats)
@ -508,11 +507,9 @@ impl StateExt for State {
let (health_level, energy_level) = ( let (health_level, energy_level) = (
skill_set skill_set
.skill_level(Skill::General(GeneralSkill::HealthIncrease)) .skill_level(Skill::General(GeneralSkill::HealthIncrease))
.unwrap_or(None)
.unwrap_or(0), .unwrap_or(0),
skill_set skill_set
.skill_level(Skill::General(GeneralSkill::EnergyIncrease)) .skill_level(Skill::General(GeneralSkill::EnergyIncrease))
.unwrap_or(None)
.unwrap_or(0), .unwrap_or(0),
); );
self.write_component_ignore_entity_dead(entity, comp::Health::new(body, health_level)); self.write_component_ignore_entity_dead(entity, comp::Health::new(body, health_level));

View File

@ -903,7 +903,7 @@ impl<'a> Diary<'a> {
id: state.skill_sword_dash_4, id: state.skill_sword_dash_4,
}, },
SkillIcon::Unlockable { SkillIcon::Unlockable {
skill: Skill::Sword(DInfinite), skill: Skill::Sword(DChargeThrough),
image: self.imgs.physical_distance_skill, image: self.imgs.physical_distance_skill,
position: MidTopWithMarginOn(state.skills_top_r[5], 3.0), position: MidTopWithMarginOn(state.skills_top_r[5], 3.0),
id: state.skill_sword_dash_5, id: state.skill_sword_dash_5,
@ -1996,11 +1996,8 @@ impl<'a> Diary<'a> {
diary_tooltip: &Tooltip, diary_tooltip: &Tooltip,
) { ) {
let label = if self.skill_set.prerequisites_met(skill) { let label = if self.skill_set.prerequisites_met(skill) {
let current = self let current = self.skill_set.skill_level(skill).unwrap_or(0);
.skill_set let max = skill.max_level();
.skill_level(skill)
.map_or(0, |l| l.unwrap_or(1));
let max = skill.max_level().unwrap_or(1);
format!("{}/{}", current, max) format!("{}/{}", current, max)
} else { } else {
"".to_owned() "".to_owned()
@ -2195,7 +2192,7 @@ fn sword_skill_strings(skill: SwordSkill, i18n: &Localization) -> (&str, Cow<str
"hud.skill.sw_dash_speed", "hud.skill.sw_dash_speed",
modifiers.dash.forward_speed, modifiers.dash.forward_speed,
), ),
SwordSkill::DInfinite => localize( SwordSkill::DChargeThrough => localize(
i18n, i18n,
"hud.skill.sw_dash_charge_through_title", "hud.skill.sw_dash_charge_through_title",
"hud.skill.sw_dash_charge_through", "hud.skill.sw_dash_charge_through",