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"
dependencies = [
"approx 0.4.0",
"bincode",
"bitflags",
"chrono",
"chrono-tz",
@ -6216,6 +6215,7 @@ dependencies = [
"ron 0.7.0",
"roots",
"serde",
"serde_json",
"serde_repr",
"sha2",
"slab",

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1187,7 +1187,7 @@ impl CharacterAbility {
..
} = 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 speed = modifiers.speed.powi(level.into());
@ -1211,13 +1211,13 @@ impl CharacterAbility {
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());
}
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());
}
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());
}
}
@ -1241,9 +1241,7 @@ impl CharacterAbility {
*is_interruptible = skillset.has_skill(Sword(InterruptingAttacks));
if skillset.has_skill(Sword(TsCombo)) {
let speed_segments = Sword(TsSpeed)
.max_level()
.map_or(1.0, |l| f32::from(l) + 1.0);
let speed_segments = f32::from(Sword(TsSpeed).max_level()) + 1.0;
let speed_level = f32::from(skillset.skill_level_or(Sword(TsSpeed), 0));
*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)
* 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();
},
CharacterAbility::DashMelee {
@ -1274,22 +1272,22 @@ impl CharacterAbility {
} => {
let modifiers = SKILL_MODIFIERS.sword_tree.dash;
*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());
}
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());
}
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());
}
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());
}
if skillset.has_skill(Sword(DSpeed)) {
*forward_speed *= modifiers.forward_speed;
}
*charge_through = skillset.has_skill(Sword(DInfinite));
*charge_through = skillset.has_skill(Sword(DChargeThrough));
},
CharacterAbility::SpinMelee {
ref mut is_interruptible,
@ -1301,13 +1299,13 @@ impl CharacterAbility {
} => {
let modifiers = SKILL_MODIFIERS.sword_tree.spin;
*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());
}
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());
}
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());
}
let spin_level = skillset.skill_level_or(Sword(SSpins), 0);
@ -1334,7 +1332,7 @@ impl CharacterAbility {
if !skillset.has_skill(Axe(DsCombo)) {
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));
*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)
* 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();
},
CharacterAbility::SpinMelee {
@ -1365,13 +1363,13 @@ impl CharacterAbility {
} else {
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());
}
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());
}
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());
}
},
@ -1384,16 +1382,16 @@ impl CharacterAbility {
..
} => {
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());
}
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());
}
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());
}
if let Ok(Some(level)) = skillset.skill_level(Axe(LDistance)) {
if let Ok(level) = skillset.skill_level(Axe(LDistance)) {
let strength = modifiers.leap_strength;
*forward_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;
if let Ok(Some(level)) = skillset.skill_level(Hammer(SsKnockback)) {
if let Ok(level) = skillset.skill_level(Hammer(SsKnockback)) {
*stage_data = (*stage_data)
.iter()
.map(|s| s.modify_strike(modifiers.knockback.powi(level.into())))
.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));
*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");
*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();
},
@ -1449,16 +1447,16 @@ impl CharacterAbility {
} => {
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());
}
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());
}
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());
}
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;
*charge_duration *= charge_time.powi(level.into());
}
@ -1473,21 +1471,21 @@ impl CharacterAbility {
..
} => {
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());
}
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());
}
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());
}
if let Ok(Some(level)) = skillset.skill_level(Hammer(LDistance)) {
if let Ok(level) = skillset.skill_level(Hammer(LDistance)) {
let strength = modifiers.leap_strength;
*forward_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);
}
},
@ -1516,31 +1514,31 @@ impl CharacterAbility {
..
} => {
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());
*initial_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());
*initial_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());
*initial_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());
*initial_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;
*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());
}
},
@ -1552,17 +1550,17 @@ impl CharacterAbility {
..
} => {
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());
}
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());
*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());
}
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());
}
},
@ -1575,20 +1573,20 @@ impl CharacterAbility {
..
} => {
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());
}
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());
*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());
}
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;
}
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());
}
},
@ -1622,19 +1620,19 @@ impl CharacterAbility {
..
} => {
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());
}
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());
*range *= range_mod;
// Duration modified to keep velocity constant
*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());
}
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 duration_mod = 1.0 / (1.0 + velocity_increase);
*beam_duration *= duration_mod;
@ -1648,17 +1646,17 @@ impl CharacterAbility {
..
} => {
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());
}
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());
*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());
}
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());
}
},
@ -1681,19 +1679,19 @@ impl CharacterAbility {
..
} => {
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());
}
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());
*range *= range_mod;
// Duration modified to keep velocity constant
*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());
}
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)
{
*lifesteal *= modifiers.lifesteal.powi(level.into());
@ -1707,18 +1705,18 @@ impl CharacterAbility {
..
} => {
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());
}
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 {
*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());
}
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());
}
},
@ -1730,18 +1728,18 @@ impl CharacterAbility {
..
} => {
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());
}
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 {
*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());
}
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());
}
},

View File

@ -5,7 +5,6 @@ use crate::{
skills::{GeneralSkill, Skill},
},
};
use bincode;
use hashbrown::HashMap;
use lazy_static::lazy_static;
use serde::{Deserialize, Serialize};
@ -17,6 +16,9 @@ use tracing::{trace, warn};
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)]
pub struct SkillTreeMap(HashMap<SkillGroupKind, BTreeSet<Skill>>);
@ -32,7 +34,7 @@ pub struct SkillGroupDef {
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct SkillLevelMap(HashMap<Skill, Option<u16>>);
pub struct SkillLevelMap(HashMap<Skill, u16>);
impl Asset for SkillLevelMap {
type Loader = assets::RonLoader;
@ -41,7 +43,7 @@ impl Asset for SkillLevelMap {
}
#[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 {
type Loader = assets::RonLoader;
@ -63,14 +65,11 @@ lazy_static! {
total_skill_point_cost: skills
.iter()
.map(|skill| {
if let Some(max_level) = skill.max_level() {
let max_level = skill.max_level();
(1..=max_level)
.into_iter()
.map(|level| skill.skill_cost(Some(level)))
.sum()
} else {
skill.skill_cost(None)
}
.map(|level| skill.skill_cost(level))
.sum::<u16>()
})
.sum()
})
@ -85,13 +84,13 @@ lazy_static! {
map.iter().flat_map(|(sgk, skills)| skills.into_iter().map(move |s| (*s, *sgk))).collect()
};
// 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(
"common.skill_trees.skill_max_levels",
).0
};
// 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(
"common.skill_trees.skill_prerequisites",
).0
@ -103,9 +102,9 @@ lazy_static! {
let mut hashes = HashMap::new();
for (skill_group_kind, skills) in map.iter() {
let mut hasher = Sha256::new();
let bincode_input: Vec<_> = skills.iter().map(|skill| (*skill, skill.max_level())).collect();
let hash_input = bincode::serialize(&bincode_input).unwrap_or_default();
hasher.update(hash_input);
let json_input: Vec<_> = skills.iter().map(|skill| (*skill, skill.max_level())).collect();
let hash_input = serde_json::to_string(&json_input).unwrap_or_default();
hasher.update(hash_input.as_bytes());
let hash_result = hasher.finalize();
hashes.insert(*skill_group_kind, hash_result.iter().copied().collect());
}
@ -121,6 +120,8 @@ pub enum SkillGroupKind {
impl SkillGroupKind {
/// 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 {
const EXP_INCREMENT: f32 = 10.0;
const STARTING_EXP: f32 = 70.0;
@ -186,9 +187,21 @@ impl SkillGroup {
pub fn earn_skill_point(&mut self) -> Result<(), SpRewardError> {
let sp_cost = self.skill_group_kind.skill_point_cost(self.earned_sp);
if self.available_experience() >= sp_cost {
self.spent_exp = self.spent_exp.saturating_add(sp_cost);
self.available_sp = self.available_sp.saturating_add(1);
self.earned_sp = self.earned_sp.saturating_add(1);
let new_spent_exp = self
.spent_exp
.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(())
} else {
Err(SpRewardError::InsufficientExp)
@ -202,7 +215,7 @@ impl SkillGroup {
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
pub struct SkillSet {
skill_groups: Vec<SkillGroup>,
skills: HashMap<Skill, Option<u16>>,
skills: HashMap<Skill, u16>,
pub modify_health: bool,
pub modify_energy: bool,
}
@ -229,12 +242,12 @@ impl Default for SkillSet {
}
impl SkillSet {
pub fn initial_skills() -> HashMap<Skill, Option<u16>> {
pub fn initial_skills() -> HashMap<Skill, u16> {
let mut skills = HashMap::new();
skills.insert(Skill::UnlockGroup(SkillGroupKind::General), None);
skills.insert(Skill::UnlockGroup(SkillGroupKind::General), 1);
skills.insert(
Skill::UnlockGroup(SkillGroupKind::Weapon(ToolKind::Pick)),
None,
1,
);
skills
}
@ -310,10 +323,15 @@ impl 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> {
// 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
.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
@ -347,13 +365,13 @@ impl SkillSet {
skill_group_kind: SkillGroupKind,
number_of_skill_points: u16,
) {
if let Some(mut skill_group) = self.skill_group_mut(skill_group_kind) {
skill_group.available_sp = skill_group
.available_sp
.saturating_add(number_of_skill_points);
skill_group.earned_sp = skill_group.earned_sp.saturating_add(number_of_skill_points);
} else {
warn!("Tried to add skill points to a skill group that player does not have");
for _ in 0..number_of_skill_points {
let exp_needed = self.skill_point_cost(skill_group_kind);
self.add_experience(skill_group_kind, exp_needed);
if self.earn_skill_point(skill_group_kind).is_err() {
warn!("Failed to add skill point");
break;
}
}
}
@ -397,11 +415,7 @@ impl SkillSet {
/// Checks if player has sufficient skill points to purchase a skill
pub fn sufficient_skill_points(&self, skill: Skill) -> bool {
if let Some(skill_group_kind) = skill.skill_group_kind() {
if let Some(skill_group) = self
.skill_groups
.iter()
.find(|x| x.skill_group_kind == skill_group_kind)
{
if let Some(skill_group) = self.skill_group(skill_group_kind) {
let needed_sp = self.skill_cost(skill);
skill_group.available_sp >= needed_sp
} else {
@ -413,13 +427,13 @@ impl SkillSet {
}
/// 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 already has skill, and that skill has levels, level + 1
level.map(|l| l + 1)
// If already has skill, then level + 1
level + 1
} else {
// Else if the skill has levels, 1
skill.max_level().map(|_| 1)
// Otherwise the next level is the first level
1
}
}
@ -431,11 +445,13 @@ impl SkillSet {
let prerequisites_met = self.prerequisites_met(skill);
// Check that skill is not yet at 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 prerequisites_met {
if skill_group.available_sp >= skill.skill_cost(next_level) {
skill_group.available_sp -= skill.skill_cost(next_level);
if let Some(new_available_sp) = skill_group
.available_sp
.checked_sub(skill.skill_cost(next_level))
{
skill_group.available_sp = new_available_sp;
skill_group.ordered_skills.push(skill);
match skill {
Skill::UnlockGroup(group) => {
@ -452,9 +468,7 @@ impl SkillSet {
self.skills.insert(skill, next_level);
Ok(())
} else {
trace!(
"Tried to unlock skill for skill group with insufficient SP"
);
trace!("Tried to unlock skill for skill group with insufficient SP");
Err(SkillUnlockError::InsufficientSP)
}
} else {
@ -465,10 +479,6 @@ impl SkillSet {
trace!("Tried to unlock skill for a skill group that player does not have");
Err(SkillUnlockError::UnavailableSkillGroup)
}
} else {
trace!("Tried to unlock skill for a skill group that player does not have");
Err(SkillUnlockError::UnavailableSkillGroup)
}
} else {
trace!("Tried to unlock skill the player already has");
Err(SkillUnlockError::SkillAlreadyUnlocked)
@ -486,6 +496,7 @@ impl SkillSet {
pub fn has_available_sp(&self) -> bool {
self.skill_groups.iter().any(|sg| {
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()
})
}
@ -503,7 +514,7 @@ impl SkillSet {
pub fn has_skill(&self, skill: Skill) -> bool { self.skills.contains_key(&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() {
Ok(level)
} else {
@ -513,7 +524,7 @@ 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) {
if let Ok(level) = self.skill_level(skill) {
level
} else {
default
@ -521,6 +532,7 @@ impl SkillSet {
}
}
#[derive(Debug)]
pub enum SkillError {
MissingSkill,
}
@ -537,4 +549,5 @@ pub enum SkillUnlockError {
pub enum SpRewardError {
InsufficientExp,
UnavailableSkillGroup,
Overflow,
}

View File

@ -22,7 +22,6 @@ pub enum Skill {
Climb(ClimbSkill),
Swim(SwimSkill),
Pick(MiningSkill),
// TODO: Don't do this, maybe Sharp has idea?
UnlockGroup(SkillGroupKind),
}
@ -41,7 +40,7 @@ pub enum SwordSkill {
DDamage,
DScaling,
DSpeed,
DInfinite, // Represents charge through, not migrated because laziness
DChargeThrough,
// Spin upgrades
UnlockSpin,
SDamage,
@ -187,23 +186,30 @@ pub enum MiningSkill {
impl Skill {
/// Returns a vec of prerequisite skills (it should only be necessary to
/// 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
.get(self)
.into_iter()
.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
pub fn skill_cost(&self, level: Option<u16>) -> u16 {
pub fn skill_cost(&self, level: u16) -> u16 {
// TODO: Better balance the costs later
level.unwrap_or(1)
level
}
/// Returns the maximum level a skill can reach, returns None if the skill
/// 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
/// definitions.

View File

@ -23,19 +23,19 @@ impl assets::Asset for SkillSetTree {
#[derive(Debug, Deserialize, Clone)]
enum SkillNode {
Tree(String),
Skill((Skill, Option<u16>)),
Skill((Skill, u16)),
Group(SkillGroupKind),
}
#[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();
skills_from_nodes(&nodes.0)
}
#[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();
for node in nodes {
match node {
@ -46,7 +46,7 @@ fn skills_from_nodes(nodes: &[SkillNode]) -> Vec<(Skill, Option<u16>)> {
skills.push(*req);
},
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
/// 2) If added skill already applied
/// 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() {
skill_group
} else {
@ -114,7 +114,7 @@ impl SkillSetBuilder {
);
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));
if let Err(err) = skill_set.unlock_skill(skill) {
let err_msg = format!("Failed to add skill: {:?}. Error: {:?}", skill, err);
@ -137,7 +137,7 @@ impl SkillSetBuilder {
}
#[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) {
applied_level == level
} else {

View File

@ -34,10 +34,10 @@ impl Data {
pub fn create_adjusted_by_skills(join_data: &JoinData) -> Self {
let modifiers = SKILL_MODIFIERS.general_tree.climb;
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());
}
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

View File

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

View File

@ -530,6 +530,8 @@ fn convert_skill_groups_from_database(
spent_exp: 0,
available_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(),
};
@ -559,16 +561,17 @@ pub fn convert_skill_groups_to_database(
entity_id: CharacterId,
skill_groups: Vec<skillset::SkillGroup>,
) -> Vec<SkillGroup> {
let skill_group_hashes = &skillset::SKILL_GROUP_HASHES;
skill_groups
.into_iter()
.map(|sg| SkillGroup {
entity_id,
skill_group_kind: json_models::skill_group_to_db_string(sg.skill_group_kind),
earned_exp: sg.earned_exp as i32,
spent_exp: sg.spent_exp as i32,
earned_exp: i64::from(sg.earned_exp),
spent_exp: i64::from(sg.spent_exp),
// If fails to convert, just forces a respec on next login
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)
.cloned()
.unwrap_or_default(),

View File

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

View File

@ -221,7 +221,6 @@ impl StateExt for State {
body,
skill_set
.skill_level(Skill::General(GeneralSkill::EnergyIncrease))
.unwrap_or(None)
.unwrap_or(0),
))
.with(stats)
@ -508,11 +507,9 @@ impl StateExt for State {
let (health_level, energy_level) = (
skill_set
.skill_level(Skill::General(GeneralSkill::HealthIncrease))
.unwrap_or(None)
.unwrap_or(0),
skill_set
.skill_level(Skill::General(GeneralSkill::EnergyIncrease))
.unwrap_or(None)
.unwrap_or(0),
);
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,
},
SkillIcon::Unlockable {
skill: Skill::Sword(DInfinite),
skill: Skill::Sword(DChargeThrough),
image: self.imgs.physical_distance_skill,
position: MidTopWithMarginOn(state.skills_top_r[5], 3.0),
id: state.skill_sword_dash_5,
@ -1996,11 +1996,8 @@ impl<'a> Diary<'a> {
diary_tooltip: &Tooltip,
) {
let label = if self.skill_set.prerequisites_met(skill) {
let current = self
.skill_set
.skill_level(skill)
.map_or(0, |l| l.unwrap_or(1));
let max = skill.max_level().unwrap_or(1);
let current = self.skill_set.skill_level(skill).unwrap_or(0);
let max = skill.max_level();
format!("{}/{}", current, max)
} else {
"".to_owned()
@ -2195,7 +2192,7 @@ fn sword_skill_strings(skill: SwordSkill, i18n: &Localization) -> (&str, Cow<str
"hud.skill.sw_dash_speed",
modifiers.dash.forward_speed,
),
SwordSkill::DInfinite => localize(
SwordSkill::DChargeThrough => localize(
i18n,
"hud.skill.sw_dash_charge_through_title",
"hud.skill.sw_dash_charge_through",