use crate::app_interface::ability::{Ability, AbilityIndex}; use crate::app_interface::{ Battle, BattleSide, ClampedStatisticSet, Form, Gender, Item, LearnedMove, LevelInt, Nature, Species, Statistic, StatisticSet, }; use crate::handling::cached_value::CachedValue; use crate::handling::Cacheable; use crate::{ cached_value, cached_value_getters, wasm_optional_reference_getters, wasm_reference_getters, wasm_value_getters, DynamicLibrary, ExternRef, ExternalReferenceType, Script, TypeIdentifier, }; use alloc::boxed::Box; use alloc::rc::Rc; use cstr_core::{c_char, CString}; struct PokemonInner { reference: ExternRef, library: CachedValue, // We cache the reference to the data, not the values stored inside, which are dynamic. flat_stats: CachedValue>, // We cache the reference to the data, not the values stored inside, which are dynamic. stat_boosts: CachedValue>, // We cache the reference to the data, not the values stored inside, which are dynamic. boosted_stats: CachedValue>, // We cache the reference to the data, not the values stored inside, which are dynamic. individual_values: CachedValue>, // We cache the reference to the data, not the values stored inside, which are dynamic. effort_values: CachedValue>, } #[derive(Clone)] pub struct Pokemon { inner: Rc, } impl Pokemon { #[cfg(not(feature = "mock_data"))] pub(crate) fn new(reference: ExternRef) -> Self { Self::from_ref(reference, &|reference| Self { inner: Rc::new(PokemonInner { reference, library: cached_value!({ pokemon_get_library(reference).get_value().unwrap() }), flat_stats: cached_value!({ pokemon_get_flat_stats(reference).get_value().unwrap() }), stat_boosts: cached_value!({ pokemon_get_stat_boosts(reference).get_value().unwrap() }), boosted_stats: cached_value!({ pokemon_get_boosted_stats(reference).get_value().unwrap() }), individual_values: cached_value!({ pokemon_get_individual_values(reference) .get_value() .unwrap() }), effort_values: cached_value!({ pokemon_get_effort_values(reference).get_value().unwrap() }), }), }) } pub(crate) fn reference(&self) -> ExternRef { self.inner.reference } cached_value_getters! { pub fn library(&self) -> DynamicLibrary; pub fn flat_stats(&self) -> StatisticSet; pub fn stat_boosts(&self) -> ClampedStatisticSet; pub fn boosted_stats(&self) -> StatisticSet; pub fn individual_values(&self) -> ClampedStatisticSet; pub fn effort_values(&self) -> ClampedStatisticSet; } #[cfg(not(feature = "mock_data"))] pub fn has_held_item(&self, name: &str) -> bool { let cstr = CString::new(name).unwrap(); unsafe { pokemon_has_held_item(self.inner.reference, cstr.as_ptr()) } } #[cfg(not(feature = "mock_data"))] pub fn set_held_item(&self, item: &Item) -> Option { unsafe { pokemon_set_held_item(self.inner.reference, item.reference()).get_value() } } #[cfg(not(feature = "mock_data"))] pub fn remove_held_item(&self) -> Option { unsafe { pokemon_remove_held_item(self.inner.reference).get_value() } } #[cfg(not(feature = "mock_data"))] pub fn consume_held_item(&self) -> bool { unsafe { pokemon_consume_held_item(self.inner.reference) } } #[cfg(not(feature = "mock_data"))] pub fn max_health(&self) -> u32 { self.boosted_stats().hp() } #[cfg(not(feature = "mock_data"))] pub fn get_type(&self, index: usize) -> u8 { unsafe { pokemon_get_type(self.inner.reference, index) } } #[cfg(not(feature = "mock_data"))] pub fn has_type(&self, type_identifier: TypeIdentifier) -> bool { unsafe { pokemon_has_type(self.inner.reference, type_identifier.into()) } } #[cfg(not(feature = "mock_data"))] pub fn has_type_by_name(&self, type_name: &str) -> bool { let type_identifier = self .library() .data_library() .type_library() .get_type_from_name(type_name); if let Some(type_identifier) = type_identifier { return self.has_type(type_identifier); } false } #[cfg(not(feature = "mock_data"))] pub fn get_learned_move(&self, index: usize) -> Option { unsafe { pokemon_get_learned_move(self.inner.reference, index).get_value() } } #[cfg(not(feature = "mock_data"))] pub fn change_stat_boost( &self, stat: Statistic, diff_amount: i8, self_inflicted: bool, ) -> bool { unsafe { pokemon_change_stat_boost(self.inner.reference, stat, diff_amount, self_inflicted) } } #[cfg(not(feature = "mock_data"))] pub fn ability_script(&self) -> Option<&Box> { unsafe { pokemon_get_ability_script(self.inner.reference).as_ref() } } #[cfg(not(feature = "mock_data"))] pub fn change_species(&self, species: Species, form: Form) { unsafe { pokemon_change_species(self.inner.reference, species.reference(), form.reference()); } } #[cfg(not(feature = "mock_data"))] pub fn change_form(&self, form: Form) { unsafe { pokemon_change_form(self.inner.reference, form.reference()); } } pub fn is_fainted(&self) -> bool { self.current_health() == 0 } #[cfg(not(feature = "mock_data"))] pub fn damage(&self, damage: u32, source: DamageSource) { unsafe { pokemon_damage(self.inner.reference, damage, source) } } #[cfg(not(feature = "mock_data"))] pub fn heal(&self, amount: u32, allow_revive: bool) -> bool { unsafe { pokemon_heal(self.inner.reference, amount, allow_revive) } } #[cfg(not(feature = "mock_data"))] pub fn battle_side(&self) -> BattleSide { self.battle() .unwrap() .sides() .get(self.battle_side_index() as u32) .unwrap() } } #[cfg(not(feature = "mock_data"))] wasm_reference_getters! { Pokemon, pub fn species(&self) -> Species; pub fn form(&self) -> Form; pub fn active_ability(&self) -> Ability; pub fn nature(&self) -> Nature; } #[cfg(not(feature = "mock_data"))] wasm_optional_reference_getters! { Pokemon, pub fn display_species(&self) -> Option; pub fn display_form(&self) -> Option
; pub fn held_item(&self) -> Option; pub fn battle(&self) -> Option; } #[cfg(not(feature = "mock_data"))] wasm_value_getters! { Pokemon, pub fn level(&self) -> LevelInt; pub fn experience(&self) -> u32; pub fn unique_identifier(&self) -> u32; pub fn gender(&self) -> Gender; pub fn coloring(&self) -> u8; pub fn current_health(&self) -> u32; pub fn weight(&self) -> f32; pub fn height(&self) -> f32; pub fn nickname(&self) -> *const c_char; pub fn real_ability(&self) -> AbilityIndex; pub fn types_length(&self) -> usize; pub fn battle_side_index(&self) -> u8; pub fn battle_index(&self) -> u8; pub fn is_ability_overriden(&self) -> u8; pub fn allowed_experience_gain(&self) -> bool; pub fn is_usable(&self) -> bool; } impl PartialEq for Pokemon { fn eq(&self, other: &Self) -> bool { self.inner.reference == other.inner.reference } } /// A source of damage. This should be as unique as possible. #[derive(Debug, Clone, Copy)] #[repr(u8)] pub enum DamageSource { /// The damage is done by a move. MoveDamage = 0, /// The damage is done by something else. Misc = 1, } crate::handling::cacheable::cacheable!(Pokemon); #[cfg(not(feature = "mock_data"))] impl ExternalReferenceType for Pokemon { fn from_extern_value(reference: ExternRef) -> Self { Self::new(reference) } } #[cfg(not(feature = "mock_data"))] extern "wasm" { fn pokemon_get_library(r: ExternRef) -> ExternRef; fn pokemon_get_flat_stats(r: ExternRef) -> ExternRef>; fn pokemon_get_stat_boosts(r: ExternRef) -> ExternRef>; fn pokemon_get_boosted_stats(r: ExternRef) -> ExternRef>; fn pokemon_get_individual_values(r: ExternRef) -> ExternRef>; fn pokemon_get_effort_values(r: ExternRef) -> ExternRef>; fn pokemon_has_held_item(r: ExternRef, name: *const c_char) -> bool; fn pokemon_set_held_item(r: ExternRef, item: ExternRef) -> ExternRef; fn pokemon_remove_held_item(r: ExternRef) -> ExternRef; fn pokemon_consume_held_item(r: ExternRef) -> bool; fn pokemon_get_type(r: ExternRef, index: usize) -> u8; fn pokemon_has_type(r: ExternRef, identifier: u8) -> bool; fn pokemon_get_learned_move(r: ExternRef, index: usize) -> ExternRef; fn pokemon_change_stat_boost( r: ExternRef, tat: Statistic, diff_amount: i8, self_inflicted: bool, ) -> bool; #[allow(improper_ctypes)] fn pokemon_get_ability_script(r: ExternRef) -> *const Box; fn pokemon_change_species( r: ExternRef, species: ExternRef, form: ExternRef, ); fn pokemon_change_form(r: ExternRef, form: ExternRef); fn pokemon_damage(r: ExternRef, damage: u32, source: DamageSource); fn pokemon_heal(r: ExternRef, amount: u32, allow_revive: bool) -> bool; } #[cfg(feature = "mock_data")] impl Pokemon { pub fn current_health(&self) -> u32 { unimplemented!() } pub fn species(&self) -> Species { unimplemented!() } }