Merge branch 'sam/fix-health-buffs' into 'master'

Fix interaction of max health and max health over time buffs causing infinite health scaling.

See merge request veloren/veloren!2557
This commit is contained in:
Samuel Keiffer 2021-07-05 03:46:45 +00:00
commit 1020fbe86a
2 changed files with 53 additions and 20 deletions

View File

@ -152,9 +152,9 @@ pub enum BuffEffect {
/// Gradually changes an entities max health over time /// Gradually changes an entities max health over time
MaxHealthChangeOverTime { MaxHealthChangeOverTime {
rate: f32, rate: f32,
accumulated: f32,
kind: ModifierKind, kind: ModifierKind,
target_fraction: f32, target_fraction: f32,
achieved_fraction: Option<f32>,
}, },
/// Modifies move speed of target /// Modifies move speed of target
MovementSpeed(f32), MovementSpeed(f32),
@ -247,9 +247,9 @@ impl Buff {
vec![ vec![
BuffEffect::MaxHealthChangeOverTime { BuffEffect::MaxHealthChangeOverTime {
rate: -10.0, rate: -10.0,
accumulated: 0.0,
kind: ModifierKind::Additive, kind: ModifierKind::Additive,
target_fraction: 1.0 - data.strength, target_fraction: 1.0 - data.strength,
achieved_fraction: None,
}, },
BuffEffect::HealthChangeOverTime { BuffEffect::HealthChangeOverTime {
rate: -10.0, rate: -10.0,

View File

@ -226,7 +226,8 @@ impl<'a> System<'a> for Sys {
}, },
BuffEffect::MaxHealthModifier { value, kind } => match kind { BuffEffect::MaxHealthModifier { value, kind } => match kind {
ModifierKind::Additive => { 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 => { ModifierKind::Fractional => {
stat.max_health_modifier *= *value; stat.max_health_modifier *= *value;
@ -245,31 +246,63 @@ impl<'a> System<'a> for Sys {
}, },
BuffEffect::MaxHealthChangeOverTime { BuffEffect::MaxHealthChangeOverTime {
rate, rate,
accumulated,
kind, kind,
target_fraction, target_fraction,
achieved_fraction,
} => { } => {
*accumulated += *rate * dt; // Current fraction uses information from last tick, which is
let current_fraction = health.maximum() as f32 // necessary as buffs from this tick are not guaranteed to have
/ (health.base_max() as f32 * stat.max_health_modifier); // finished applying
let progress = (1.0 - current_fraction) / (1.0 - *target_fraction); let current_fraction =
if progress > 1.0 { health.maximum() as f32 / health.base_max() as f32;
stat.max_health_modifier *= *target_fraction;
} else if accumulated.abs() > rate.abs() { // If achieved_fraction not initialized, initialize it to health
match kind { // 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 => { ModifierKind::Additive => {
stat.max_health_modifier = stat.max_health_modifier // `rate * dt` is amount of health, dividing by base max
* current_fraction // creates fraction
+ *accumulated / health.maximum() as f32; *rate * dt / health.base_max() as f32
}, },
ModifierKind::Fractional => { ModifierKind::Fractional => {
stat.max_health_modifier *= // `rate * dt` is the fraction
current_fraction * (1.0 - *accumulated); *rate * dt
}, },
} };
*accumulated = 0.0;
let potential_fraction = *achieved_fraction + health_tick;
// Potential progress towards target fraction, if
// target_fraction ~ 1.0 then set progress to 1.0 to avoid
// divide by zero
let progress = if (1.0 - *target_fraction).abs() > f32::EPSILON
{
(1.0 - potential_fraction) / (1.0 - *target_fraction)
} else { } else {
stat.max_health_modifier *= current_fraction; 1.0
};
// 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;
}
// Apply achieved_fraction to max_health_modifier
stat.max_health_modifier *= *achieved_fraction;
} }
}, },
BuffEffect::MovementSpeed(speed) => { BuffEffect::MovementSpeed(speed) => {