use crate::app_interface::get_hash; use crate::handling::cached_value::CachedValue; use crate::handling::Cacheable; use crate::{ cached_value, cached_value_getters, ExternRef, ExternalReferenceType, FFIArray, ImmutableList, StringKey, VecExternRef, }; use alloc::rc::Rc; use alloc::vec::Vec; use spin::RwLock; #[repr(u8)] pub enum Gender { Male = 0, Female = 1, Genderless = 2, } #[repr(u8)] pub enum Statistic { HP = 0, Attack = 1, Defense = 2, SpecialAttack = 3, SpecialDefense = 4, Speed = 5, } pub struct ImmutableStatisticSetInner { reference: ExternRef, /// The health point stat value. hp: CachedValue, /// The physical attack stat value. attack: CachedValue, /// The physical defense stat value. defense: CachedValue, /// The special attack stat value. special_attack: CachedValue, /// The special defense stat value. special_defense: CachedValue, /// The speed stat value. speed: CachedValue, } #[derive(Clone)] pub struct ImmutableStatisticSet { inner: Rc, } impl ImmutableStatisticSet { #[cfg(not(feature = "mock_data"))] pub(crate) fn new(reference: ExternRef) -> Self { Self::from_ref(reference, &|reference| Self { inner: Rc::new(ImmutableStatisticSetInner { reference, hp: cached_value!({ static_statistics_set_get_hp(reference) }), attack: cached_value!({ static_statistics_set_get_attack(reference) }), defense: cached_value!({ static_statistics_set_get_defense(reference) }), special_attack: cached_value!({ static_statistics_set_get_special_attack(reference) }), special_defense: cached_value!({ static_statistics_set_get_special_defense(reference) }), speed: cached_value!({ static_statistics_set_get_speed(reference) }), }), }) } pub fn hp(&self) -> u16 { self.inner.hp.value() } pub fn attack(&self) -> u16 { self.inner.attack.value() } pub fn defense(&self) -> u16 { self.inner.defense.value() } pub fn special_attack(&self) -> u16 { self.inner.special_attack.value() } pub fn special_defense(&self) -> u16 { self.inner.special_defense.value() } pub fn speed(&self) -> u16 { self.inner.speed.value() } } struct FormInner { reference: ExternRef
, name: CachedValue, height: CachedValue, weight: CachedValue, types: CachedValue>, base_experience: CachedValue, base_stats: CachedValue, abilities: CachedValue>, hidden_abilities: CachedValue>, // moves: CachedValue, } #[derive(Clone)] pub struct Form { inner: Rc, } impl Form { #[cfg(not(feature = "mock_data"))] pub(crate) fn new(reference: ExternRef) -> Self { Self::from_ref(reference, &|reference| Self { inner: Rc::new(FormInner { reference, name: cached_value!({ form_get_name(reference).get_value().unwrap() }), height: cached_value!({ form_get_height(reference) }), weight: cached_value!({ form_get_weight(reference) }), types: cached_value!({ let raw = form_get_types(reference); Vec::from_raw_parts(raw.ptr(), raw.len(), raw.len()) }), base_experience: cached_value!({ form_get_base_experience(reference) }), base_stats: cached_value!({ form_get_base_stats(reference).get_value().unwrap() }), abilities: cached_value!({ form_get_abilities(reference).get_immutable_list() }), hidden_abilities: cached_value!({ form_get_hidden_abilities(reference).get_immutable_list() }), }), }) } pub(crate) fn reference(&self) -> ExternRef { self.inner.reference } cached_value_getters! { pub fn name(&self) -> StringKey; pub fn height(&self) -> f32; pub fn weight(&self) -> f32; pub fn base_experience(&self) -> u32; pub fn base_stats(&self) -> ImmutableStatisticSet; pub fn abilities(&self) -> ImmutableList; pub fn hidden_abilities(&self) -> ImmutableList; } pub fn types(&self) -> &Vec { self.inner.types.value_ref() } #[cfg(not(feature = "mock_data"))] pub fn has_flag(&self, flag: &str) -> bool { let hash = get_hash(flag); unsafe { form_has_flag_by_hash(self.inner.reference, hash) } } } pub struct SpeciesInner { reference: ExternRef, id: CachedValue, name: CachedValue, gender_rate: CachedValue, growth_rate: CachedValue, capture_rate: CachedValue, forms: RwLock>>, } #[derive(Clone)] pub struct Species { inner: Rc, } impl Species { #[cfg(not(feature = "mock_data"))] pub(crate) fn new(reference: ExternRef) -> Self { Self { inner: Rc::new(SpeciesInner { reference, id: cached_value!({ species_get_id(reference) }), name: cached_value!({ species_get_name(reference).get_value().unwrap() }), gender_rate: cached_value!({ species_get_gender_rate(reference) }), growth_rate: cached_value!({ species_get_growth_rate(reference).get_value().unwrap() }), capture_rate: cached_value!({ species_get_capture_rate(reference) }), forms: Default::default(), }), } } pub(crate) fn reference(&self) -> ExternRef { self.inner.reference } cached_value_getters! { /// The national dex identifier of the Pokemon. pub fn id(&self) -> u16; /// The name of the Pokemon species. pub fn name(&self) -> StringKey; /// The chance between 0.0 and 1.0 that a Pokemon is female. pub fn gender_rate(&self) -> f32; /// How much experience is required for a level. pub fn growth_rate(&self) -> StringKey; /// 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; } #[cfg(not(feature = "mock_data"))] pub fn get_form(&self, form_name: &str) -> Option { let hash = get_hash(form_name); unsafe { if let Some(v) = self.inner.forms.read().get(&hash) { v.clone() } else { let r = species_get_form_by_hash(self.inner.reference, hash); let value = r.get_value(); self.inner.forms.write().insert(hash, value.clone()); value } } } #[cfg(not(feature = "mock_data"))] pub fn has_flag(&self, flag: &str) -> bool { let hash = get_hash(flag); unsafe { species_has_flag_by_hash(self.inner.reference, hash) } } } #[cfg(not(feature = "mock_data"))] impl ExternalReferenceType for ImmutableStatisticSet { fn from_extern_value(reference: ExternRef) -> Self { Self::new(reference) } } #[cfg(not(feature = "mock_data"))] impl ExternalReferenceType for Form { fn from_extern_value(reference: ExternRef) -> Self { Self::new(reference) } } #[cfg(not(feature = "mock_data"))] impl ExternalReferenceType for Species { fn from_extern_value(reference: ExternRef) -> Self { Self::new(reference) } } crate::handling::cacheable::cacheable!(ImmutableStatisticSet); crate::handling::cacheable::cacheable!(Form); crate::handling::cacheable::cacheable!(Species); #[cfg(not(feature = "mock_data"))] extern "wasm" { fn static_statistics_set_get_hp(r: ExternRef) -> u16; fn static_statistics_set_get_attack(r: ExternRef) -> u16; fn static_statistics_set_get_defense(r: ExternRef) -> u16; fn static_statistics_set_get_special_attack(r: ExternRef) -> u16; fn static_statistics_set_get_special_defense(r: ExternRef) -> u16; fn static_statistics_set_get_speed(r: ExternRef) -> u16; fn form_get_name(r: ExternRef) -> ExternRef; fn form_get_height(r: ExternRef) -> f32; fn form_get_weight(r: ExternRef) -> f32; fn form_get_types(r: ExternRef) -> FFIArray; fn form_get_base_experience(r: ExternRef) -> u32; fn form_get_base_stats(r: ExternRef) -> ExternRef; fn form_get_abilities(r: ExternRef) -> VecExternRef; fn form_get_hidden_abilities(r: ExternRef) -> VecExternRef; fn form_has_flag_by_hash(r: ExternRef, hash: u32) -> bool; fn species_get_id(r: ExternRef) -> u16; fn species_get_name(r: ExternRef) -> ExternRef; fn species_get_gender_rate(r: ExternRef) -> f32; fn species_get_growth_rate(r: ExternRef) -> ExternRef; fn species_get_capture_rate(r: ExternRef) -> u8; fn species_get_form_by_hash(r: ExternRef, hash: u32) -> ExternRef; fn species_has_flag_by_hash(r: ExternRef, flag_hash: u32) -> bool; }