diff --git a/common/src/combat.rs b/common/src/combat.rs index 4cf12646af..b070d5a78e 100644 --- a/common/src/combat.rs +++ b/common/src/combat.rs @@ -1224,7 +1224,7 @@ impl Damage { }; let stats_dr = if let Some(stats) = stats { - stats.damage_reduction + stats.damage_reduction.modifier() } else { 0.0 }; diff --git a/common/src/comp/poise.rs b/common/src/comp/poise.rs index d1b96f5c62..9dca59d9a0 100644 --- a/common/src/comp/poise.rs +++ b/common/src/comp/poise.rs @@ -275,7 +275,7 @@ impl Poise { if resistant { 0.5 } else { 0.0 } }; let from_stats = if let Some(stats) = stats { - stats.poise_reduction + stats.poise_reduction.modifier() } else { 0.0 }; diff --git a/common/src/comp/stats.rs b/common/src/comp/stats.rs index a30141c4a8..121c52408e 100644 --- a/common/src/comp/stats.rs +++ b/common/src/comp/stats.rs @@ -28,6 +28,25 @@ impl Default for StatsModifier { } } +#[derive(Debug, Clone, Copy, Deserialize, Serialize)] +pub struct StatsSplit { + pub pos_mod: f32, + pub neg_mod: f32, +} + +impl Default for StatsSplit { + fn default() -> Self { + Self { + pos_mod: 0.0, + neg_mod: 0.0, + } + } +} + +impl StatsSplit { + pub fn modifier(&self) -> f32 { self.pos_mod + self.neg_mod } +} + impl StatsModifier { pub fn compute_maximum(&self, base_value: f32) -> f32 { base_value * self.mult_mod + self.add_mod @@ -53,9 +72,11 @@ impl Error for StatChangeError {} pub struct Stats { pub name: String, pub original_body: Body, - pub damage_reduction: f32, - pub poise_reduction: f32, + pub damage_reduction: StatsSplit, + pub poise_reduction: StatsSplit, pub heal_multiplier: f32, + // Note: This is used to counteract agility as a "potion sickness" right now, and otherwise + // does not impact movement speed pub move_speed_multiplier: f32, pub max_health_modifiers: StatsModifier, pub move_speed_modifier: f32, @@ -87,8 +108,8 @@ impl Stats { Self { name, original_body: body, - damage_reduction: 0.0, - poise_reduction: 0.0, + damage_reduction: StatsSplit::default(), + poise_reduction: StatsSplit::default(), heal_multiplier: 1.0, move_speed_multiplier: 1.0, max_health_modifiers: StatsModifier::default(), diff --git a/common/systems/src/buff.rs b/common/systems/src/buff.rs index 429975738b..9004042d62 100644 --- a/common/systems/src/buff.rs +++ b/common/systems/src/buff.rs @@ -702,7 +702,11 @@ fn execute_effect( }, }, BuffEffect::DamageReduction(dr) => { - stat.damage_reduction = 1.0 - ((1.0 - stat.damage_reduction) * (1.0 - *dr)); + if *dr > 0.0 { + stat.damage_reduction.pos_mod = stat.damage_reduction.pos_mod.max(*dr); + } else { + stat.damage_reduction.neg_mod += dr; + } }, BuffEffect::MaxHealthChangeOverTime { rate, @@ -761,9 +765,12 @@ fn execute_effect( BuffEffect::GroundFriction(gf) => { stat.friction_modifier *= *gf; }, - #[allow(clippy::manual_clamp)] BuffEffect::PoiseReduction(pr) => { - stat.poise_reduction = stat.poise_reduction.max(*pr).min(1.0); + if *pr > 0.0 { + stat.damage_reduction.pos_mod = stat.damage_reduction.pos_mod.max(*pr); + } else { + stat.damage_reduction.neg_mod += pr; + } }, BuffEffect::HealReduction(red) => { stat.heal_multiplier *= 1.0 - *red; diff --git a/voxygen/egui/src/lib.rs b/voxygen/egui/src/lib.rs index dcb039c96c..1de7b2323d 100644 --- a/voxygen/egui/src/lib.rs +++ b/voxygen/egui/src/lib.rs @@ -620,7 +620,7 @@ fn selected_entity_window( .striped(true) .show(ui, |ui| { two_col_row(ui, "Name", stats.name.to_string()); - two_col_row(ui, "Damage Reduction", format!("{:.1}", stats.damage_reduction)); + two_col_row(ui, "Damage Reduction", format!("{:.1}", stats.damage_reduction.modifier())); two_col_row(ui, "Multiplicative Max Health Modifier", format!("{:.1}", stats.max_health_modifiers.mult_mod)); two_col_row(ui, "Move Speed Modifier", format!("{:.1}", stats.move_speed_modifier)); });