use std::sync::{Arc, LazyLock}; use hashbrown::{HashMap, HashSet}; use parking_lot::lock_api::RwLockReadGuard; use parking_lot::{RawRwLock, RwLock}; use crate::static_data::Form; use crate::static_data::Gender; use crate::StringKey; use crate::{Random, ValueIdentifiable, ValueIdentifier}; /// The data belonging to a Pokemon with certain characteristics. #[derive(Debug)] pub struct Species { /// A unique identifier so we know what value this is. identifier: ValueIdentifier, /// The national dex identifier of the Pokemon. id: u16, /// The name of the Pokemon. name: StringKey, /// The chance between 0.0 and 1.0 that a Pokemon is female. gender_rate: f32, /// How much experience is required for a level. growth_rate: StringKey, /// How hard it is to capture a Pokemon. 255 means this will be always caught, 0 means this is /// uncatchable. capture_rate: u8, /// The forms that belong to this Pokemon. forms: RwLock>>, /// The arbitrary flags that can be set on a Pokemon for script use. flags: HashSet, } /// A cached String Key to get the default form. static DEFAULT_KEY: LazyLock = LazyLock::new(|| StringKey::new("default")); /// Gets the StringKey for "default". Initialises it if it does not exist. fn get_default_key() -> StringKey { DEFAULT_KEY.clone() } impl Species { /// Creates a new species. pub fn new( id: u16, name: &StringKey, gender_rate: f32, growth_rate: &StringKey, capture_rate: u8, default_form: Arc
, flags: HashSet, ) -> Species { let mut forms = HashMap::with_capacity(1); forms.insert_unique_unchecked(get_default_key(), default_form); Species { identifier: Default::default(), id, name: name.clone(), gender_rate, growth_rate: growth_rate.clone(), capture_rate, forms: RwLock::new(forms), flags, } } /// The national dex identifier of the Pokemon. pub fn id(&self) -> u16 { self.id } /// The name of the Pokemon. pub fn name(&self) -> &StringKey { &self.name } /// The chance between 0.0 and 1.0 that a Pokemon is female. pub fn gender_rate(&self) -> f32 { self.gender_rate } /// How much experience is required for a level. pub fn growth_rate(&self) -> &StringKey { &self.growth_rate } /// How hard it is to capture a Pokemon. 255 means this will be always caught, 0 means this is /// uncatchable. pub fn capture_rate(&self) -> u8 { self.capture_rate } /// The forms that belong to this Pokemon. pub fn forms(&self) -> RwLockReadGuard<'_, RawRwLock, HashMap>> { self.forms.read() } /// The arbitrary flags that can be set on a Pokemon for script use. pub fn flags(&self) -> &HashSet { &self.flags } /// Adds a new form to the species. pub fn add_form(&self, id: StringKey, form: Arc) { self.forms.write().insert(id, form); } /// Gets a form by name. pub fn get_form(&self, id: &StringKey) -> Option> { self.forms.read().get(id).cloned() } /// Gets the form the Pokemon will have by default, if no other form is specified. pub fn get_default_form(&self) -> Arc { self.forms.read().get(&get_default_key()).unwrap().clone() } /// Gets a random gender. pub fn get_random_gender(&self, rand: &mut Random) -> Gender { if self.gender_rate < 0.0 { Gender::Genderless } else if rand.get_float() >= self.gender_rate { Gender::Female } else { Gender::Male } } /// Check whether the Pokemon has a specific flag set. pub fn has_flag(&self, key: &StringKey) -> bool { self.flags.contains(key) } } impl ValueIdentifiable for Species { fn value_identifier(&self) -> ValueIdentifier { self.identifier } }