use crate::app_interface::list::ImmutableList; use crate::app_interface::{ImmutableStatisticSet, StringKey}; use alloc::rc::Rc; use alloc::vec::Vec; use core::any::Any; #[repr(u8)] #[derive(Eq, PartialEq, Debug)] pub enum Gender { Male = 0, Female = 1, Genderless = 2, } pub trait FormTrait { fn name(&self) -> StringKey; fn height(&self) -> f32; fn weight(&self) -> f32; fn base_experience(&self) -> u32; fn base_stats(&self) -> ImmutableStatisticSet; fn abilities(&self) -> ImmutableList>; fn hidden_abilities(&self) -> ImmutableList>; fn types(&self) -> &Vec; fn has_flag(&self, flag: &str) -> bool; fn as_any(&self) -> &dyn Any; } pub trait SpeciesTrait { /// The national dex identifier of the Pokemon. fn id(&self) -> u16; /// The name of the Pokemon species. fn name(&self) -> StringKey; /// The chance between 0.0 and 1.0 that a Pokemon is female. fn gender_rate(&self) -> f32; /// How much experience is required for a level. 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. fn capture_rate(&self) -> u8; fn get_form(&self, form_name: &str) -> Option
; fn has_flag(&self, flag: &str) -> bool; fn as_any(&self) -> &dyn Any; } pub type Form = Rc; pub type Species = Rc; #[cfg(not(feature = "mock_data"))] mod implementation { use super::*; use crate::app_interface::list::ImmutableListWasm; use crate::app_interface::{get_hash, ImmutableStatisticSetImpl}; use crate::handling::cached_value::CachedValue; use crate::handling::extern_ref::{ExternRef, ExternalReferenceType, VecExternRef}; use crate::handling::ffi_array::FFIArray; use crate::handling::Cacheable; use crate::{cached_value, cached_value_getters}; use spin::RwLock; 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 FormImpl { inner: Rc, } impl FormImpl { 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!({ Rc::new(form_get_base_stats(reference).get_value().unwrap()) }), abilities: cached_value!({ Rc::new( crate::app_interface::list::StringKeyImmutableList::from_ref( form_get_abilities(reference), ), ) }), hidden_abilities: cached_value!({ Rc::new( crate::app_interface::list::StringKeyImmutableList::from_ref( form_get_hidden_abilities(reference), ), ) }), }), }) } pub(crate) fn reference(&self) -> ExternRef { self.inner.reference } } impl FormTrait for FormImpl { cached_value_getters! { fn name(&self) -> StringKey; fn height(&self) -> f32; fn weight(&self) -> f32; fn base_experience(&self) -> u32; fn base_stats(&self) -> ImmutableStatisticSet; fn abilities(&self) -> ImmutableList>; fn hidden_abilities(&self) -> ImmutableList>; } fn types(&self) -> &Vec { self.inner.types.value_ref() } fn has_flag(&self, flag: &str) -> bool { let hash = get_hash(flag); unsafe { form_has_flag_by_hash(self.inner.reference, hash) } } fn as_any(&self) -> &dyn Any { self } } pub struct SpeciesInner { reference: ExternRef, id: CachedValue, name: CachedValue, gender_rate: CachedValue, growth_rate: CachedValue, capture_rate: CachedValue, forms: RwLock>>, } #[derive(Clone)] pub struct SpeciesImpl { inner: Rc, } impl SpeciesImpl { 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 } } impl SpeciesTrait for SpeciesImpl { cached_value_getters! { /// The national dex identifier of the Pokemon. fn id(&self) -> u16; /// The name of the Pokemon species. fn name(&self) -> StringKey; /// The chance between 0.0 and 1.0 that a Pokemon is female. fn gender_rate(&self) -> f32; /// How much experience is required for a level. 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. fn capture_rate(&self) -> u8; } 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(); let value: Option = if let Some(value) = value { Some(Rc::new(value)) } else { None }; self.inner.forms.write().insert(hash, value.clone()); value } } } fn has_flag(&self, flag: &str) -> bool { let hash = get_hash(flag); unsafe { species_has_flag_by_hash(self.inner.reference, hash) } } fn as_any(&self) -> &dyn Any { self } } impl ExternalReferenceType for FormImpl { fn from_extern_value(reference: ExternRef) -> Self { Self::new(reference) } } impl ExternalReferenceType for SpeciesImpl { fn from_extern_value(reference: ExternRef) -> Self { Self::new(reference) } } crate::handling::cacheable::cacheable!(FormImpl); crate::handling::cacheable::cacheable!(SpeciesImpl); extern "wasm" { 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; } } #[cfg(not(feature = "mock_data"))] pub use implementation::*;