diff --git a/common/src/comp/buff.rs b/common/src/comp/buff.rs index c0472798a3..15bdbdecac 100644 --- a/common/src/comp/buff.rs +++ b/common/src/comp/buff.rs @@ -152,9 +152,9 @@ pub enum BuffEffect { /// Gradually changes an entities max health over time MaxHealthChangeOverTime { rate: f32, - accumulated: f32, kind: ModifierKind, target_fraction: f32, + achieved_fraction: Option, }, /// Modifies move speed of target MovementSpeed(f32), @@ -247,9 +247,9 @@ impl Buff { vec![ BuffEffect::MaxHealthChangeOverTime { rate: -10.0, - accumulated: 0.0, kind: ModifierKind::Additive, target_fraction: 1.0 - data.strength, + achieved_fraction: None, }, BuffEffect::HealthChangeOverTime { rate: -10.0, diff --git a/common/systems/src/buff.rs b/common/systems/src/buff.rs index 75bb317541..3edb60eb8b 100644 --- a/common/systems/src/buff.rs +++ b/common/systems/src/buff.rs @@ -226,7 +226,8 @@ impl<'a> System<'a> for Sys { }, BuffEffect::MaxHealthModifier { value, kind } => match kind { ModifierKind::Additive => { - stat.max_health_modifier += *value / (health.base_max() as f32); + stat.max_health_modifier *= + 1.0 + *value / (health.base_max() as f32); }, ModifierKind::Fractional => { stat.max_health_modifier *= *value; @@ -245,31 +246,57 @@ impl<'a> System<'a> for Sys { }, BuffEffect::MaxHealthChangeOverTime { rate, - accumulated, kind, target_fraction, + achieved_fraction, } => { - *accumulated += *rate * dt; - let current_fraction = health.maximum() as f32 - / (health.base_max() as f32 * stat.max_health_modifier); - let progress = (1.0 - current_fraction) / (1.0 - *target_fraction); - if progress > 1.0 { - stat.max_health_modifier *= *target_fraction; - } else if accumulated.abs() > rate.abs() { - match kind { + // Current fraction uses information from last tick, which is + // necessary as buffs from this tick are not guaranteed to have + // finished applying + let current_fraction = + health.maximum() as f32 / health.base_max() as f32; + + // If achieved_fraction not initialized, initialize it to health + // fraction + if achieved_fraction.is_none() { + *achieved_fraction = Some(current_fraction) + } + + if let Some(achieved_fraction) = achieved_fraction { + // Percentage change that should be applied to max_health + let health_tick = match kind { ModifierKind::Additive => { - stat.max_health_modifier = stat.max_health_modifier - * current_fraction - + *accumulated / health.maximum() as f32; + // `rate * dt` is amount of health, dividing by base max + // creates fraction + *rate * dt / health.base_max() as f32 }, ModifierKind::Fractional => { - stat.max_health_modifier *= - current_fraction * (1.0 - *accumulated); + // `rate * dt` is the fraction + *rate * dt }, + }; + + let potential_fraction = *achieved_fraction + health_tick; + + // Potential progress towards target fraction + let progress = + (1.0 - potential_fraction) / (1.0 - *target_fraction); + + // Change achieved_fraction depending on what other buffs have + // occurred + if progress > 1.0 { + // If potential fraction already beyond target fraction, + // simply multiply max_health_modifier by the target + // fraction, and set achieved fraction to target_fraction + *achieved_fraction = *target_fraction; + } else { + // Else have not achieved target yet, update + // achieved_fraction + *achieved_fraction = potential_fraction; } - *accumulated = 0.0; - } else { - stat.max_health_modifier *= current_fraction; + + // Apply achieved_fraction to max_health_modifier + stat.max_health_modifier *= *achieved_fraction; } }, BuffEffect::MovementSpeed(speed) => {