diff --git a/immediate_stats/src/stat.rs b/immediate_stats/src/stat.rs index 4a0e54b..f064a24 100644 --- a/immediate_stats/src/stat.rs +++ b/immediate_stats/src/stat.rs @@ -1,6 +1,9 @@ use crate::StatContainer; +use crate::stat::modifier::Modifier; use std::ops::{AddAssign, DivAssign, MulAssign, SubAssign}; +mod modifier; + /// A stat that [resets] to a base value every iteration. /// /// Temporary bonuses can be applied using [`+=`](add), [`-=`](sub), [`*=`](mul), and [`/=`](div). @@ -52,6 +55,21 @@ impl Stat { self.multiplier = multiplier; self } + + /// Sets the bonus and multiplier to the [`Modifier`] values. + pub fn with_modifier(mut self, modifier: Modifier) -> Self { + self.bonus = modifier.bonus; + self.multiplier = modifier.multiplier; + self + } + + /// Applies the [`Modifier`] values to the bonus and multiplier. + /// + /// This adds the bonuses, and multiplies the multipliers. + pub fn apply(&mut self, modifier: Modifier) { + self.bonus += modifier.bonus; + self.multiplier *= modifier.multiplier; + } } impl StatContainer for Stat { @@ -198,4 +216,26 @@ mod tests { fn total_no_multiplier() { assert_eq!(Stat::new(2).with_bonus(1).total(), 3); } + + #[test] + fn total_with_modifier() { + assert_eq!(Stat::new(5).with_modifier(Modifier::new(1, 0.5)).total(), 3); + } + + #[test] + fn apply() { + let mut stat = Stat::new(10); + + stat.apply(Modifier::new(2, 2.0)); + stat.apply(Modifier::new(3, 4.0)); + + assert_eq!( + stat, + Stat { + base: 10, + bonus: 5, + multiplier: 8.0, + } + ) + } } diff --git a/immediate_stats/src/stat/modifier.rs b/immediate_stats/src/stat/modifier.rs new file mode 100644 index 0000000..e7a15bc --- /dev/null +++ b/immediate_stats/src/stat/modifier.rs @@ -0,0 +1,107 @@ +use std::ops::{AddAssign, DivAssign, MulAssign, SubAssign}; + +/// Modifier values that can be applied to a [`super::Stat`]. +#[derive(PartialEq, Debug, Copy, Clone)] +#[cfg_attr(feature = "bevy", derive(bevy_reflect::Reflect))] +pub struct Modifier { + /// Added to `base` of a [`super::Stat`] during calculation. + pub bonus: i32, + /// Multiplies the `base` of a [`super::Stat`] during calculation. + pub multiplier: f32, +} + +impl Modifier { + pub fn new(bonus: i32, multiplier: f32) -> Self { + Self { bonus, multiplier } + } +} + +impl Default for Modifier { + fn default() -> Self { + Self { + bonus: 0, + multiplier: 1.0, + } + } +} + +impl AddAssign for Modifier { + fn add_assign(&mut self, rhs: i32) { + self.bonus += rhs; + } +} + +impl SubAssign for Modifier { + fn sub_assign(&mut self, rhs: i32) { + self.bonus -= rhs; + } +} + +impl MulAssign for Modifier { + fn mul_assign(&mut self, rhs: f32) { + self.multiplier *= rhs; + } +} + +impl DivAssign for Modifier { + fn div_assign(&mut self, rhs: f32) { + self.multiplier /= rhs; + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn add() { + let mut modifier = Modifier::default(); + modifier += 5; + assert_eq!( + modifier, + Modifier { + bonus: 5, + multiplier: 1.0, + } + ); + } + + #[test] + fn subtract() { + let mut modifier = Modifier::default(); + modifier -= 5; + assert_eq!( + modifier, + Modifier { + bonus: -5, + multiplier: 1.0, + } + ); + } + + #[test] + fn multiply() { + let mut modifier = Modifier::default(); + modifier *= 2.0; + assert_eq!( + modifier, + Modifier { + bonus: 0, + multiplier: 2.0, + } + ); + } + + #[test] + fn divide() { + let mut modifier = Modifier::default(); + modifier /= 2.0; + assert_eq!( + modifier, + Modifier { + bonus: 0, + multiplier: 0.5, + } + ); + } +}