immediate_stats 0.5.0

Game stats that reset every frame, inspired by immediate mode GUI.
Documentation
//! Contains a modifier that can be applied to [`Stat`](crate::Stat).

use std::fmt::{Display, Formatter};
use std::ops::{AddAssign, DivAssign, MulAssign, SubAssign};

/// Modifier values that can be [applied](super::Stat::apply) to a [`Stat`](super::Stat).
#[derive(PartialEq, Debug, Copy, Clone)]
#[cfg_attr(
    feature = "bevy",
    derive(bevy_reflect::Reflect),
    reflect(PartialEq, Debug, Clone)
)]
pub struct Modifier {
    /// Added to the `base` of a [`Stat`](super::Stat) during calculation.
    ///
    /// Can be modified using [`+=`](Modifier::add_assign) and [`-=`](`Modifier::sub_assign`).
    pub bonus: i32,
    /// Multiplies the `base` of a [`Stat`](super::Stat) during calculation.
    ///
    /// Can be modified using [`*=`](`Modifier::mul_assign`) and [`/=`](`Modifier::div_assign`).
    pub multiplier: f32,
}

impl Modifier {
    /// Creates a new modifier from a bonus and a multiplier.
    pub fn new(bonus: i32, multiplier: f32) -> Self {
        Self { bonus, multiplier }
    }

    /// Creates a new modifier from a bonus.
    pub fn from_bonus(bonus: i32) -> Self {
        Self {
            bonus,
            ..Self::default()
        }
    }

    /// Creates a new modifier from a multiplier.
    pub fn from_multiplier(multiplier: f32) -> Self {
        Self {
            multiplier,
            ..Self::default()
        }
    }

    /// Returns a new modifier scaled by a fraction.
    ///
    /// When the scale is zero, the bonus will be zero while the multiplier will be one.
    pub fn scaled(&self, fraction: f32) -> Self {
        Self {
            bonus: (self.bonus as f32 * fraction) as i32,
            multiplier: (1.0 - fraction) * 1.0 + fraction * self.multiplier,
        }
    }
}

impl Default for Modifier {
    fn default() -> Self {
        Self {
            bonus: 0,
            multiplier: 1.0,
        }
    }
}

impl AddAssign<i32> for Modifier {
    /// Adds to the modifier's bonus.
    fn add_assign(&mut self, rhs: i32) {
        self.bonus += rhs;
    }
}

impl SubAssign<i32> for Modifier {
    /// Subtracts from the modifier's bonus.
    fn sub_assign(&mut self, rhs: i32) {
        self.bonus -= rhs;
    }
}

impl MulAssign<f32> for Modifier {
    /// Multiplies the modifier's multiplier.
    fn mul_assign(&mut self, rhs: f32) {
        self.multiplier *= rhs;
    }
}

impl DivAssign<f32> for Modifier {
    /// Divides the modifier's multiplier.
    fn div_assign(&mut self, rhs: f32) {
        self.multiplier /= rhs;
    }
}

impl Display for Modifier {
    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
        if let Some(precision) = f.precision() {
            write!(f, "(+{}) x {:.*}", self.bonus, precision, self.multiplier)
        } else {
            write!(f, "(+{}) x {}", self.bonus, self.multiplier)
        }
    }
}