use crate::defines::LevelInt; use crate::VecExt; use anyhow::Result; use anyhow_ext::ensure; /// A growth rate defines how much experience is required per level. pub trait GrowthRate { /// Calculate the level something with this growth rate would have at a certain experience. fn calculate_level(&self, experience: u32) -> LevelInt; /// Calculate the experience something with this growth rate would have at a certain level. fn calculate_experience(&self, level: LevelInt) -> Result; } /// An implementation of the growth rate that uses a lookup table for experience. pub struct LookupGrowthRate { /// The lookup Vec. experience: Vec, } impl LookupGrowthRate { /// Instantiates a new lookup growth rate. The experience vec should be the amount of experience /// required per level, with the first element being the experience required for level 1 (generally 0). pub fn new(experience: Vec) -> LookupGrowthRate { LookupGrowthRate { experience } } } impl GrowthRate for LookupGrowthRate { fn calculate_level(&self, experience: u32) -> LevelInt { for (i, v) in self.experience.iter().enumerate() { if *v > experience { return i as LevelInt; } } self.experience.len() as LevelInt } fn calculate_experience(&self, level: LevelInt) -> Result { ensure!(level > 0, "Level must be greater than 0, but was {}", level); if level >= self.experience.len() as LevelInt { match self.experience.last() { Some(v) => Ok(*v), None => anyhow::bail!("No experience values found"), } } else { Ok(*self.experience.get_res((level - 1) as usize)?) } } } #[cfg(test)] #[allow(clippy::indexing_slicing)] pub(crate) mod tests { use super::*; mockall::mock! { #[derive(Debug)] pub GrowthRate {} impl GrowthRate for GrowthRate { fn calculate_level(&self, experience: u32) -> LevelInt; fn calculate_experience(&self, level: LevelInt) -> Result; } } }