use std::sync::Arc; use hashbrown::HashMap; use crate::static_data::Statistic; use crate::StringKey; /// A nature is an attribute on a Pokemon that modifies the effective base stats on a Pokemon. They /// can have an increased statistic and a decreased statistic, or be neutral. #[derive(Debug)] pub struct Nature { /// The stat that should receive the increased modifier. increase_stat: Statistic, /// The stat that should receive the decreased modifier. decrease_stat: Statistic, /// The amount by which the increased stat is multiplied. increase_modifier: f32, /// The amount by which the decreased stat is multiplied. decrease_modifier: f32, } impl Nature { /// Instantiates a new statistic. pub fn new( increase_stat: Statistic, decrease_stat: Statistic, increase_modifier: f32, decrease_modifier: f32, ) -> Self { Self { increase_stat, decrease_stat, increase_modifier, decrease_modifier, } } /// The stat that should receive the increased modifier. pub fn increased_stat(&self) -> Statistic { self.increase_stat } /// The stat that should receive the decreased modifier. pub fn decreased_stat(&self) -> Statistic { self.decrease_stat } /// Calculates the modifier for a given stat. If it's the increased stat, returns the increased /// modifier, if it's the decreased stat, returns the decreased modifier. Otherwise returns 1.0 pub fn get_stat_modifier(&self, stat: Statistic) -> f32 { if stat == self.increase_stat && stat != self.decrease_stat { self.increase_modifier } else if stat == self.decrease_stat && stat != self.increase_stat { self.decrease_modifier } else { 1.0 } } } /// A library of all natures that can be used, stored by their names. #[derive(Debug)] pub struct NatureLibrary { /// The underlying data structure. map: HashMap>, } impl NatureLibrary { /// Creates a new nature library with a given capacity. pub fn new(capacity: usize) -> Self { NatureLibrary { map: HashMap::with_capacity(capacity), } } /// Adds a new nature with name to the library. pub fn load_nature(&mut self, name: StringKey, nature: Nature) { self.map.insert(name, Arc::new(nature)); } /// Gets a nature by name. pub fn get_nature(&self, key: &StringKey) -> Option<&Arc> { self.map.get(key) } /// Finds a nature name by nature. pub fn get_nature_name(&self, nature: &Arc) -> StringKey { for kv in &self.map { // As natures can't be copied, and should always be the same reference as the value // in the map, we just compare by reference. if Arc::ptr_eq(kv.1, nature) { return kv.0.clone(); } } panic!("No name was found for the given nature. This should never happen."); } } #[cfg(test)] pub mod tests { use crate::static_data::natures::{Nature, NatureLibrary}; use crate::static_data::statistics::Statistic; pub fn build() -> NatureLibrary { let mut lib = NatureLibrary::new(2); lib.load_nature( "test_nature".into(), Nature::new(Statistic::HP, Statistic::Attack, 1.1, 0.9), ); lib } #[test] fn create_nature_library_insert_and_retrieve() { let mut lib = NatureLibrary::new(2); lib.load_nature("foo".into(), Nature::new(Statistic::HP, Statistic::Attack, 1.1, 0.9)); lib.load_nature( "bar".into(), Nature::new(Statistic::Attack, Statistic::Defense, 1.1, 0.9), ); let n1 = lib.get_nature(&"foo".into()).expect("Nature was not found"); assert_eq!(n1.increase_stat, Statistic::HP); assert_eq!(n1.decrease_stat, Statistic::Attack); assert_eq!(n1.increase_modifier, 1.1); assert_eq!(n1.decrease_modifier, 0.9); } #[test] fn create_nature_library_insert_and_get_name() { let mut lib = NatureLibrary::new(2); lib.load_nature("foo".into(), Nature::new(Statistic::HP, Statistic::Attack, 1.1, 0.9)); lib.load_nature( "bar".into(), Nature::new(Statistic::Attack, Statistic::Defense, 1.1, 0.9), ); let n1 = lib.get_nature(&"foo".into()).expect("Nature was not found"); let name = lib.get_nature_name(n1); assert_eq!(name, "foo".into()); let n2 = lib.get_nature(&"bar".into()).expect("Nature was not found"); let name2 = lib.get_nature_name(n2); assert_eq!(name2, "bar".into()); } }