A lot of work on mocking to set up unit testing
This commit is contained in:
		| @@ -1,74 +1,108 @@ | ||||
| use crate::app_interface::{BattleParty, BattleRandom, BattleSide, ChoiceQueue, Pokemon}; | ||||
| use crate::app_interface::{ | ||||
|     BattleParty, BattlePartyImpl, BattleRandom, BattleRandomImpl, BattleSide, BattleSideImpl, | ||||
|     ChoiceQueue, ChoiceQueueImpl, Pokemon, PokemonImpl, | ||||
| }; | ||||
| use crate::handling::cached_value::CachedValue; | ||||
| use crate::handling::Cacheable; | ||||
| use crate::{ | ||||
|     cached_value, cached_value_getters, wasm_value_getters, DynamicLibrary, ExternRef, | ||||
|     ExternalReferenceType, ImmutableList, StringKey, VecExternRef, | ||||
|     cached_value, cached_value_getters, wasm_value_getters, wasm_value_getters_extern, | ||||
|     wasm_value_getters_funcs, DynamicLibrary, ExternRef, ExternalReferenceType, ImmutableList, | ||||
|     StringKey, VecExternRef, | ||||
| }; | ||||
| use alloc::rc::Rc; | ||||
|  | ||||
| pub trait BattleTrait { | ||||
|     fn library(&self) -> DynamicLibrary; | ||||
|     fn parties(&self) -> ImmutableList<BattlePartyImpl>; | ||||
|     fn sides(&self) -> ImmutableList<BattleSideImpl>; | ||||
|     fn random(&self) -> BattleRandom; | ||||
|     fn choice_queue(&self) -> ChoiceQueue; | ||||
|     fn get_pokemon(&self, side: u8, index: u8) -> Option<Pokemon>; | ||||
|     fn find_party_for_pokemon(&self, pokemon: &Pokemon) -> Option<BattleParty>; | ||||
|     fn weather_name(&self) -> Option<StringKey>; | ||||
|     fn has_weather(&self, name: &str) -> bool; | ||||
|     fn can_flee(&self) -> bool; | ||||
|     fn number_of_sides(&self) -> u8; | ||||
|     fn pokemon_per_side(&self) -> u8; | ||||
|     fn has_ended(&self) -> bool; | ||||
|     fn has_ended_conclusively(&self) -> bool; | ||||
|     fn winning_side(&self) -> u8; | ||||
|     fn current_turn(&self) -> u32; | ||||
| } | ||||
|  | ||||
| pub type Battle = Rc<dyn BattleTrait>; | ||||
|  | ||||
| struct BattleInner { | ||||
|     reference: ExternRef<Battle>, | ||||
|     reference: ExternRef<BattleImpl>, | ||||
|     library: CachedValue<DynamicLibrary>, | ||||
|     parties: CachedValue<ImmutableList<BattleParty>>, | ||||
|     sides: CachedValue<ImmutableList<BattleSide>>, | ||||
|     random: CachedValue<BattleRandom>, | ||||
|     choice_queue: CachedValue<ChoiceQueue>, | ||||
|     parties: CachedValue<ImmutableList<BattlePartyImpl>>, | ||||
|     sides: CachedValue<ImmutableList<BattleSideImpl>>, | ||||
|     random: CachedValue<Rc<BattleRandomImpl>>, | ||||
|     choice_queue: CachedValue<Rc<ChoiceQueueImpl>>, | ||||
| } | ||||
|  | ||||
| #[derive(Clone)] | ||||
| pub struct Battle { | ||||
| pub struct BattleImpl { | ||||
|     inner: Rc<BattleInner>, | ||||
| } | ||||
|  | ||||
| impl Battle { | ||||
|     #[cfg(not(feature = "mock_data"))] | ||||
|     pub fn new(reference: ExternRef<Battle>) -> Self { | ||||
| #[cfg(not(feature = "mock_data"))] | ||||
| impl BattleImpl { | ||||
|     pub fn new(reference: ExternRef<BattleImpl>) -> Self { | ||||
|         Self::from_ref(reference, &|reference| Self { | ||||
|             inner: Rc::new(BattleInner { | ||||
|                 reference, | ||||
|                 library: cached_value!({ battle_get_library(reference).get_value().unwrap() }), | ||||
|                 parties: cached_value!({ battle_get_parties(reference).get_immutable_list() }), | ||||
|                 sides: cached_value!({ battle_get_sides(reference).get_immutable_list() }), | ||||
|                 random: cached_value!({ battle_get_random(reference).get_value().unwrap() }), | ||||
|                 random: cached_value!({ | ||||
|                     Rc::new(battle_get_random(reference).get_value().unwrap()) | ||||
|                 }), | ||||
|                 choice_queue: cached_value!({ | ||||
|                     battle_get_choice_queue(reference).get_value().unwrap() | ||||
|                     Rc::new(battle_get_choice_queue(reference).get_value().unwrap()) | ||||
|                 }), | ||||
|             }), | ||||
|         }) | ||||
|     } | ||||
| } | ||||
|  | ||||
| #[cfg(not(feature = "mock_data"))] | ||||
| impl BattleTrait for BattleImpl { | ||||
|     cached_value_getters! { | ||||
|         pub fn library(&self) -> DynamicLibrary; | ||||
|         pub fn parties(&self) -> ImmutableList<BattleParty>; | ||||
|         pub fn sides(&self) -> ImmutableList<BattleSide>; | ||||
|         pub fn random(&self) -> BattleRandom; | ||||
|         pub fn choice_queue(&self) -> ChoiceQueue; | ||||
|         fn library(&self) -> DynamicLibrary; | ||||
|         fn parties(&self) -> ImmutableList<BattlePartyImpl>; | ||||
|         fn sides(&self) -> ImmutableList<BattleSideImpl>; | ||||
|         fn random(&self) -> BattleRandom; | ||||
|         fn choice_queue(&self) -> ChoiceQueue; | ||||
|     } | ||||
|  | ||||
|     #[cfg(not(feature = "mock_data"))] | ||||
|     pub fn get_pokemon(&self, side: u8, index: u8) -> Option<Pokemon> { | ||||
|         unsafe { battle_get_pokemon(self.inner.reference, side, index).get_value() } | ||||
|     } | ||||
|  | ||||
|     #[cfg(not(feature = "mock_data"))] | ||||
|     pub fn find_party_for_pokemon(&self, pokemon: &Pokemon) -> Option<BattleParty> { | ||||
|     fn get_pokemon(&self, side: u8, index: u8) -> Option<Pokemon> { | ||||
|         unsafe { | ||||
|             battle_find_party_for_pokemon(self.inner.reference, pokemon.reference()).get_value() | ||||
|             let v = battle_get_pokemon(self.inner.reference, side, index).get_value(); | ||||
|             if let Some(v) = v { | ||||
|                 Some(Rc::new(v)) | ||||
|             } else { | ||||
|                 None | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     #[cfg(feature = "mock_data")] | ||||
|     pub fn weather_name(&self) -> Option<StringKey> { | ||||
|         None | ||||
|     fn find_party_for_pokemon(&self, pokemon: &Pokemon) -> Option<BattleParty> { | ||||
|         unsafe { | ||||
|             let b = battle_find_party_for_pokemon(self.inner.reference, pokemon.reference().into()) | ||||
|                 .get_value(); | ||||
|             if let Some(b) = b { | ||||
|                 Some(Rc::new(b)) | ||||
|             } else { | ||||
|                 None | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     #[cfg(not(feature = "mock_data"))] | ||||
|     pub fn weather_name(&self) -> Option<StringKey> { | ||||
|     fn weather_name(&self) -> Option<StringKey> { | ||||
|         unsafe { battle_get_weather_name(self.inner.reference).get_value() } | ||||
|     } | ||||
|  | ||||
|     pub fn has_weather(&self, name: &str) -> bool { | ||||
|     fn has_weather(&self, name: &str) -> bool { | ||||
|         if let Some(weather) = self.weather_name() { | ||||
|             if weather.eq(name) { | ||||
|                 return true; | ||||
| @@ -76,10 +110,21 @@ impl Battle { | ||||
|         } | ||||
|         false | ||||
|     } | ||||
|  | ||||
|     wasm_value_getters_funcs! { | ||||
|         Battle, | ||||
|         fn can_flee(&self) -> bool; | ||||
|         fn number_of_sides(&self) -> u8; | ||||
|         fn pokemon_per_side(&self) -> u8; | ||||
|         fn has_ended(&self) -> bool; | ||||
|         fn has_ended_conclusively(&self) -> bool; | ||||
|         fn winning_side(&self) -> u8; | ||||
|         fn current_turn(&self) -> u32; | ||||
|     } | ||||
| } | ||||
|  | ||||
| wasm_value_getters! { | ||||
|     Battle, | ||||
| wasm_value_getters_extern! { | ||||
|     BattleImpl, Battle, | ||||
|     pub fn can_flee(&self) -> bool; | ||||
|     pub fn number_of_sides(&self) -> u8; | ||||
|     pub fn pokemon_per_side(&self) -> u8; | ||||
| @@ -89,10 +134,10 @@ wasm_value_getters! { | ||||
|     pub fn current_turn(&self) -> u32; | ||||
| } | ||||
|  | ||||
| crate::handling::cacheable::cacheable!(Battle); | ||||
| crate::handling::cacheable::cacheable!(BattleImpl); | ||||
|  | ||||
| #[cfg(not(feature = "mock_data"))] | ||||
| impl ExternalReferenceType for Battle { | ||||
| impl ExternalReferenceType for BattleImpl { | ||||
|     fn from_extern_value(reference: ExternRef<Self>) -> Self { | ||||
|         Self::new(reference) | ||||
|     } | ||||
| @@ -100,16 +145,16 @@ impl ExternalReferenceType for Battle { | ||||
|  | ||||
| #[cfg(not(feature = "mock_data"))] | ||||
| extern "wasm" { | ||||
|     fn battle_get_library(r: ExternRef<Battle>) -> ExternRef<DynamicLibrary>; | ||||
|     fn battle_get_parties(r: ExternRef<Battle>) -> VecExternRef<BattleParty>; | ||||
|     fn battle_get_sides(r: ExternRef<Battle>) -> VecExternRef<BattleSide>; | ||||
|     fn battle_get_random(r: ExternRef<Battle>) -> ExternRef<BattleRandom>; | ||||
|     fn battle_get_choice_queue(r: ExternRef<Battle>) -> ExternRef<ChoiceQueue>; | ||||
|     fn battle_get_pokemon(r: ExternRef<Battle>, side: u8, index: u8) -> ExternRef<Pokemon>; | ||||
|     fn battle_get_library(r: ExternRef<BattleImpl>) -> ExternRef<DynamicLibrary>; | ||||
|     fn battle_get_parties(r: ExternRef<BattleImpl>) -> VecExternRef<BattlePartyImpl>; | ||||
|     fn battle_get_sides(r: ExternRef<BattleImpl>) -> VecExternRef<BattleSideImpl>; | ||||
|     fn battle_get_random(r: ExternRef<BattleImpl>) -> ExternRef<BattleRandomImpl>; | ||||
|     fn battle_get_choice_queue(r: ExternRef<BattleImpl>) -> ExternRef<ChoiceQueueImpl>; | ||||
|     fn battle_get_pokemon(r: ExternRef<BattleImpl>, side: u8, index: u8) -> ExternRef<PokemonImpl>; | ||||
|     fn battle_find_party_for_pokemon( | ||||
|         r: ExternRef<Battle>, | ||||
|         mon: ExternRef<Pokemon>, | ||||
|     ) -> ExternRef<BattleParty>; | ||||
|         r: ExternRef<BattleImpl>, | ||||
|         mon: ExternRef<PokemonImpl>, | ||||
|     ) -> ExternRef<BattlePartyImpl>; | ||||
|  | ||||
|     fn battle_get_weather_name(r: ExternRef<Battle>) -> ExternRef<StringKey>; | ||||
|     fn battle_get_weather_name(r: ExternRef<BattleImpl>) -> ExternRef<StringKey>; | ||||
| } | ||||
|   | ||||
| @@ -1,39 +1,50 @@ | ||||
| use crate::app_interface::Party; | ||||
| use crate::app_interface::{Party, PartyImpl}; | ||||
| use crate::handling::cached_value::CachedValue; | ||||
| use crate::handling::Cacheable; | ||||
| use crate::{cached_value, cached_value_getters, ExternRef, ExternalReferenceType}; | ||||
| use alloc::rc::Rc; | ||||
|  | ||||
| pub trait BattlePartyTrait { | ||||
|     fn party(&self) -> Party; | ||||
| } | ||||
|  | ||||
| pub type BattleParty = Rc<dyn BattlePartyTrait>; | ||||
|  | ||||
| struct BattlePartyInner { | ||||
|     reference: ExternRef<BattleParty>, | ||||
|     party: CachedValue<Party>, | ||||
|     reference: ExternRef<BattlePartyImpl>, | ||||
|     party: CachedValue<Rc<PartyImpl>>, | ||||
| } | ||||
|  | ||||
| #[derive(Clone)] | ||||
| pub struct BattleParty { | ||||
| pub struct BattlePartyImpl { | ||||
|     inner: Rc<BattlePartyInner>, | ||||
| } | ||||
|  | ||||
| impl BattleParty { | ||||
|     #[cfg(not(feature = "mock_data"))] | ||||
|     pub fn new(reference: ExternRef<BattleParty>) -> Self { | ||||
| #[cfg(not(feature = "mock_data"))] | ||||
| impl BattlePartyImpl { | ||||
|     pub fn new(reference: ExternRef<BattlePartyImpl>) -> Self { | ||||
|         Self::from_ref(reference, &|reference| Self { | ||||
|             inner: Rc::new(BattlePartyInner { | ||||
|                 reference, | ||||
|                 party: cached_value!({ battle_party_get_party(reference).get_value().unwrap() }), | ||||
|                 party: cached_value!({ | ||||
|                     Rc::new(battle_party_get_party(reference).get_value().unwrap()) | ||||
|                 }), | ||||
|             }), | ||||
|         }) | ||||
|     } | ||||
| } | ||||
|  | ||||
| #[cfg(not(feature = "mock_data"))] | ||||
| impl BattlePartyTrait for BattlePartyImpl { | ||||
|     cached_value_getters! { | ||||
|         pub fn party(&self) -> Party; | ||||
|         fn party(&self) -> Party; | ||||
|     } | ||||
| } | ||||
|  | ||||
| crate::handling::cacheable::cacheable!(BattleParty); | ||||
| crate::handling::cacheable::cacheable!(BattlePartyImpl); | ||||
|  | ||||
| #[cfg(not(feature = "mock_data"))] | ||||
| impl ExternalReferenceType for BattleParty { | ||||
| impl ExternalReferenceType for BattlePartyImpl { | ||||
|     fn from_extern_value(reference: ExternRef<Self>) -> Self { | ||||
|         Self::new(reference) | ||||
|     } | ||||
| @@ -41,5 +52,5 @@ impl ExternalReferenceType for BattleParty { | ||||
|  | ||||
| #[cfg(not(feature = "mock_data"))] | ||||
| extern "wasm" { | ||||
|     fn battle_party_get_party(r: ExternRef<BattleParty>) -> ExternRef<Party>; | ||||
|     fn battle_party_get_party(r: ExternRef<BattlePartyImpl>) -> ExternRef<PartyImpl>; | ||||
| } | ||||
|   | ||||
| @@ -1,27 +1,37 @@ | ||||
| use crate::{ExternRef, ExternalReferenceType}; | ||||
| use alloc::rc::Rc; | ||||
|  | ||||
| pub trait BattleRandomTrait { | ||||
|     fn get(&self) -> i32; | ||||
|     fn get_max(&self, max: i32) -> i32; | ||||
|     fn get_between(&self, min: i32, max: i32) -> i32; | ||||
| } | ||||
|  | ||||
| pub type BattleRandom = Rc<dyn BattleRandomTrait>; | ||||
|  | ||||
| #[derive(Clone)] | ||||
| pub struct BattleRandom { | ||||
| pub struct BattleRandomImpl { | ||||
|     reference: ExternRef<Self>, | ||||
| } | ||||
|  | ||||
| impl BattleRandom { | ||||
| #[cfg(not(feature = "mock_data"))] | ||||
| impl BattleRandomTrait for BattleRandomImpl { | ||||
|     #[cfg(not(feature = "mock_data"))] | ||||
|     pub fn get(&self) -> i32 { | ||||
|     fn get(&self) -> i32 { | ||||
|         unsafe { battle_random_get(self.reference) } | ||||
|     } | ||||
|     #[cfg(not(feature = "mock_data"))] | ||||
|     pub fn get_max(&self, max: i32) -> i32 { | ||||
|     fn get_max(&self, max: i32) -> i32 { | ||||
|         unsafe { battle_random_get_max(self.reference, max) } | ||||
|     } | ||||
|     #[cfg(not(feature = "mock_data"))] | ||||
|     pub fn get_between(&self, min: i32, max: i32) -> i32 { | ||||
|     fn get_between(&self, min: i32, max: i32) -> i32 { | ||||
|         unsafe { battle_random_get_between(self.reference, min, max) } | ||||
|     } | ||||
|     // TODO: effect_chance() | ||||
| } | ||||
|  | ||||
| impl ExternalReferenceType for BattleRandom { | ||||
| impl ExternalReferenceType for BattleRandomImpl { | ||||
|     fn from_extern_value(reference: ExternRef<Self>) -> Self { | ||||
|         Self { reference } | ||||
|     } | ||||
| @@ -29,8 +39,8 @@ impl ExternalReferenceType for BattleRandom { | ||||
|  | ||||
| #[cfg(not(feature = "mock_data"))] | ||||
| extern "wasm" { | ||||
|     fn battle_random_get(r: ExternRef<BattleRandom>) -> i32; | ||||
|     fn battle_random_get_max(r: ExternRef<BattleRandom>, max: i32) -> i32; | ||||
|     fn battle_random_get_between(r: ExternRef<BattleRandom>, min: i32, max: i32) -> i32; | ||||
|     fn battle_random_get(r: ExternRef<BattleRandomImpl>) -> i32; | ||||
|     fn battle_random_get_max(r: ExternRef<BattleRandomImpl>, max: i32) -> i32; | ||||
|     fn battle_random_get_between(r: ExternRef<BattleRandomImpl>, min: i32, max: i32) -> i32; | ||||
|  | ||||
| } | ||||
|   | ||||
| @@ -1,102 +1,117 @@ | ||||
| use crate::app_interface::{Battle, Pokemon}; | ||||
| use crate::app_interface::{Battle, BattleImpl, Pokemon, PokemonImpl, WithVolatile}; | ||||
| use crate::handling::cacheable::Cacheable; | ||||
| use crate::handling::cached_value::CachedValue; | ||||
| use crate::{ | ||||
|     cached_value, cached_value_getters, wasm_value_getters, ExternRef, ExternalReferenceType, | ||||
|     Script, ScriptPtr, | ||||
|     cached_value, cached_value_getters, wasm_value_getters, wasm_value_getters_extern, | ||||
|     wasm_value_getters_funcs, ExternRef, ExternalReferenceType, Script, ScriptPtr, | ||||
| }; | ||||
| use alloc::boxed::Box; | ||||
| use alloc::rc::Rc; | ||||
| use cstr_core::{c_char, CString}; | ||||
|  | ||||
| pub trait BattleSideTrait: WithVolatile { | ||||
|     fn side_index(&self) -> u8; | ||||
|     fn pokemon_per_side(&self) -> u8; | ||||
|     fn battle(&self) -> Battle; | ||||
|     fn get_pokemon(&self, index: usize) -> Option<Pokemon>; | ||||
|     fn has_fled_battle(&self) -> bool; | ||||
|     fn is_defeated(&self) -> bool; | ||||
| } | ||||
|  | ||||
| pub type BattleSide = Rc<dyn BattleSideTrait>; | ||||
|  | ||||
| struct BattleSideInner { | ||||
|     reference: ExternRef<BattleSide>, | ||||
|     reference: ExternRef<BattleSideImpl>, | ||||
|     side_index: CachedValue<u8>, | ||||
|     pokemon_per_side: CachedValue<u8>, | ||||
|     battle: CachedValue<Battle>, | ||||
|     battle: CachedValue<Rc<BattleImpl>>, | ||||
| } | ||||
|  | ||||
| #[derive(Clone)] | ||||
| pub struct BattleSide { | ||||
| pub struct BattleSideImpl { | ||||
|     inner: Rc<BattleSideInner>, | ||||
| } | ||||
|  | ||||
| impl BattleSide { | ||||
|     #[cfg(not(feature = "mock_data"))] | ||||
| #[cfg(not(feature = "mock_data"))] | ||||
| impl BattleSideImpl { | ||||
|     pub fn new(reference: ExternRef<Self>) -> Self { | ||||
|         Self::from_ref(reference, &|reference| Self { | ||||
|             inner: Rc::new(BattleSideInner { | ||||
|                 reference, | ||||
|                 side_index: cached_value!({ battleside_get_side_index(reference) }), | ||||
|                 pokemon_per_side: cached_value!({ battleside_get_pokemon_per_side(reference) }), | ||||
|                 battle: cached_value!({ battleside_get_battle(reference).get_value().unwrap() }), | ||||
|                 battle: cached_value!({ | ||||
|                     Rc::new(battleside_get_battle(reference).get_value().unwrap()) | ||||
|                 }), | ||||
|             }), | ||||
|         }) | ||||
|     } | ||||
| } | ||||
|  | ||||
| #[cfg(not(feature = "mock_data"))] | ||||
| impl BattleSideTrait for BattleSideImpl { | ||||
|     cached_value_getters! { | ||||
|         pub fn side_index(&self) -> u8; | ||||
|         pub fn pokemon_per_side(&self) -> u8; | ||||
|         pub fn battle(&self) -> Battle; | ||||
|         fn side_index(&self) -> u8; | ||||
|         fn pokemon_per_side(&self) -> u8; | ||||
|         fn battle(&self) -> Battle; | ||||
|     } | ||||
|  | ||||
|     #[cfg(not(feature = "mock_data"))] | ||||
|     pub fn get_pokemon(&self, index: usize) -> Option<Pokemon> { | ||||
|         unsafe { battleside_get_pokemon(self.inner.reference, index).get_value() } | ||||
|     fn get_pokemon(&self, index: usize) -> Option<Pokemon> { | ||||
|         unsafe { | ||||
|             let p = battleside_get_pokemon(self.inner.reference, index).get_value(); | ||||
|             if let Some(p) = p { | ||||
|                 Some(Rc::new(p)) | ||||
|             } else { | ||||
|                 None | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     #[cfg(not(feature = "mock_data"))] | ||||
|     pub fn has_volatile(&self, script_name: &str) -> bool { | ||||
|     wasm_value_getters_funcs! { | ||||
|         BattleSide, | ||||
|         fn has_fled_battle(&self) -> bool; | ||||
|         fn is_defeated(&self) -> bool; | ||||
|     } | ||||
| } | ||||
|  | ||||
| #[cfg(not(feature = "mock_data"))] | ||||
| impl WithVolatile for BattleSideImpl { | ||||
|     fn has_volatile(&self, script_name: &str) -> bool { | ||||
|         unsafe { | ||||
|             let script_name = CString::new(script_name).unwrap(); | ||||
|             battleside_has_volatile(self.inner.reference, script_name.as_ptr()) | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     #[cfg(not(feature = "mock_data"))] | ||||
|     pub fn add_volatile<'a, 'b>(&'a self, script: Box<dyn Script>) -> &'b dyn Script { | ||||
|     fn add_volatile<'a, 'b>(&'a self, script: Box<dyn Script>) -> &'b dyn Script { | ||||
|         unsafe { | ||||
|             battleside_add_volatile(self.inner.reference, ScriptPtr::new(script)) | ||||
|                 .val() | ||||
|                 .unwrap() | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     #[cfg(not(feature = "mock_data"))] | ||||
|     pub fn remove_volatile(&self, script: &dyn Script) { | ||||
|     fn remove_volatile(&self, script: &dyn Script) { | ||||
|         unsafe { | ||||
|             let name = CString::new(script.get_name()).unwrap(); | ||||
|             battleside_remove_volatile(self.inner.reference, name.as_ptr()); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     #[cfg(not(feature = "mock_data"))] | ||||
|     pub fn get_volatile<T>(&self, script_name: &str) -> Option<&T> | ||||
|     where | ||||
|         T: Script + 'static, | ||||
|     { | ||||
|         unsafe { | ||||
|             let script_name = CString::new(script_name).unwrap(); | ||||
|             let s = battleside_get_volatile(self.inner.reference, script_name.as_ptr()).val(); | ||||
|             if let Some(s) = s { | ||||
|                 Some(s.as_any().downcast_ref().unwrap()) | ||||
|             } else { | ||||
|                 None | ||||
|             } | ||||
|         } | ||||
|     fn get_volatile_script(&self, script_name: &str) -> Option<&dyn Script> { | ||||
|         let script_name = CString::new(script_name).unwrap(); | ||||
|         unsafe { battleside_get_volatile(self.inner.reference, script_name.as_ptr()).val() } | ||||
|     } | ||||
| } | ||||
|  | ||||
| wasm_value_getters! { | ||||
|     BattleSide, | ||||
| wasm_value_getters_extern! { | ||||
|     BattleSideImpl, BattleSide, | ||||
|     pub fn has_fled_battle(&self) -> bool; | ||||
|     pub fn is_defeated(&self) -> bool; | ||||
| } | ||||
|  | ||||
| crate::handling::cacheable::cacheable!(BattleSide); | ||||
| crate::handling::cacheable::cacheable!(BattleSideImpl); | ||||
|  | ||||
| #[cfg(not(feature = "mock_data"))] | ||||
| impl ExternalReferenceType for BattleSide { | ||||
| impl ExternalReferenceType for BattleSideImpl { | ||||
|     fn from_extern_value(reference: ExternRef<Self>) -> Self { | ||||
|         Self::new(reference) | ||||
|     } | ||||
| @@ -104,14 +119,18 @@ impl ExternalReferenceType for BattleSide { | ||||
|  | ||||
| #[cfg(not(feature = "mock_data"))] | ||||
| extern "wasm" { | ||||
|     fn battleside_get_side_index(r: ExternRef<BattleSide>) -> u8; | ||||
|     fn battleside_get_pokemon_per_side(r: ExternRef<BattleSide>) -> u8; | ||||
|     fn battleside_get_battle(r: ExternRef<BattleSide>) -> ExternRef<Battle>; | ||||
|     fn battleside_get_pokemon(r: ExternRef<BattleSide>, index: usize) -> ExternRef<Pokemon>; | ||||
|     fn battleside_get_side_index(r: ExternRef<BattleSideImpl>) -> u8; | ||||
|     fn battleside_get_pokemon_per_side(r: ExternRef<BattleSideImpl>) -> u8; | ||||
|     fn battleside_get_battle(r: ExternRef<BattleSideImpl>) -> ExternRef<BattleImpl>; | ||||
|     fn battleside_get_pokemon(r: ExternRef<BattleSideImpl>, index: usize) | ||||
|         -> ExternRef<PokemonImpl>; | ||||
|  | ||||
|     fn battleside_add_volatile_by_name(r: ExternRef<BattleSide>, name: *const c_char) -> ScriptPtr; | ||||
|     fn battleside_add_volatile(r: ExternRef<BattleSide>, script: ScriptPtr) -> ScriptPtr; | ||||
|     fn battleside_has_volatile(r: ExternRef<BattleSide>, name: *const c_char) -> bool; | ||||
|     fn battleside_remove_volatile(r: ExternRef<BattleSide>, name: *const c_char); | ||||
|     fn battleside_get_volatile(r: ExternRef<BattleSide>, name: *const c_char) -> ScriptPtr; | ||||
|     fn battleside_add_volatile_by_name( | ||||
|         r: ExternRef<BattleSideImpl>, | ||||
|         name: *const c_char, | ||||
|     ) -> ScriptPtr; | ||||
|     fn battleside_add_volatile(r: ExternRef<BattleSideImpl>, script: ScriptPtr) -> ScriptPtr; | ||||
|     fn battleside_has_volatile(r: ExternRef<BattleSideImpl>, name: *const c_char) -> bool; | ||||
|     fn battleside_remove_volatile(r: ExternRef<BattleSideImpl>, name: *const c_char); | ||||
|     fn battleside_get_volatile(r: ExternRef<BattleSideImpl>, name: *const c_char) -> ScriptPtr; | ||||
| } | ||||
|   | ||||
| @@ -1,23 +1,34 @@ | ||||
| use crate::app_interface::PokemonImpl; | ||||
| use crate::{ExternRef, ExternalReferenceType, Pokemon}; | ||||
| use alloc::rc::Rc; | ||||
|  | ||||
| #[derive(Clone)] | ||||
| pub struct ChoiceQueue { | ||||
|     reference: ExternRef<ChoiceQueue>, | ||||
| pub trait ChoiceQueueTrait { | ||||
|     fn move_pokemon_choice_next(&self, pokemon: &Pokemon) -> bool; | ||||
| } | ||||
|  | ||||
| impl ChoiceQueue { | ||||
|     #[cfg(not(feature = "mock_data"))] | ||||
|     pub fn new(reference: ExternRef<ChoiceQueue>) -> Self { | ||||
|         Self { reference } | ||||
|     } | ||||
| pub type ChoiceQueue = Rc<dyn ChoiceQueueTrait>; | ||||
|  | ||||
|     pub fn move_pokemon_choice_next(&self, pokemon: &Pokemon) -> bool { | ||||
|         unsafe { choice_queue_move_pokemon_choice_next(self.reference, pokemon.reference()) } | ||||
| #[derive(Clone)] | ||||
| pub struct ChoiceQueueImpl { | ||||
|     reference: ExternRef<ChoiceQueueImpl>, | ||||
| } | ||||
|  | ||||
| #[cfg(not(feature = "mock_data"))] | ||||
| impl ChoiceQueueImpl { | ||||
|     pub fn new(reference: ExternRef<ChoiceQueueImpl>) -> Self { | ||||
|         Self { reference } | ||||
|     } | ||||
| } | ||||
|  | ||||
| #[cfg(not(feature = "mock_data"))] | ||||
| impl ExternalReferenceType for ChoiceQueue { | ||||
| impl ChoiceQueueTrait for ChoiceQueueImpl { | ||||
|     fn move_pokemon_choice_next(&self, pokemon: &Pokemon) -> bool { | ||||
|         unsafe { choice_queue_move_pokemon_choice_next(self.reference, pokemon.reference().into()) } | ||||
|     } | ||||
| } | ||||
|  | ||||
| #[cfg(not(feature = "mock_data"))] | ||||
| impl ExternalReferenceType for ChoiceQueueImpl { | ||||
|     fn from_extern_value(reference: ExternRef<Self>) -> Self { | ||||
|         Self::new(reference) | ||||
|     } | ||||
| @@ -26,7 +37,7 @@ impl ExternalReferenceType for ChoiceQueue { | ||||
| #[cfg(not(feature = "mock_data"))] | ||||
| extern "wasm" { | ||||
|     fn choice_queue_move_pokemon_choice_next( | ||||
|         r: ExternRef<ChoiceQueue>, | ||||
|         pokemon: ExternRef<Pokemon>, | ||||
|         r: ExternRef<ChoiceQueueImpl>, | ||||
|         pokemon: ExternRef<PokemonImpl>, | ||||
|     ) -> bool; | ||||
| } | ||||
|   | ||||
| @@ -1,23 +1,42 @@ | ||||
| use crate::app_interface::{LearnedMove, MoveData, Pokemon}; | ||||
| use crate::app_interface::{LearnedMove, MoveData, Pokemon, PokemonImpl}; | ||||
| use crate::handling::cached_value::CachedValue; | ||||
| use crate::handling::temporary::Temporary; | ||||
| use crate::{cached_value, ExternRef, ExternalReferenceType, Script}; | ||||
| use alloc::boxed::Box; | ||||
| use alloc::rc::Rc; | ||||
|  | ||||
| struct ExecutingMoveInner { | ||||
|     reference: ExternRef<ExecutingMove>, | ||||
|     reference: ExternRef<ExecutingMoveImpl>, | ||||
|     number_of_hits: CachedValue<u8>, | ||||
|     user: CachedValue<Pokemon>, | ||||
|     user: CachedValue<PokemonImpl>, | ||||
|     chosen_move: CachedValue<LearnedMove>, | ||||
|     use_move: CachedValue<MoveData>, | ||||
| } | ||||
|  | ||||
| #[cfg_attr(feature = "mock_data", mockall::automock)] | ||||
| pub trait ExecutingMoveTrait { | ||||
|     fn number_of_hits(&self) -> u8; | ||||
|     fn user(&self) -> Pokemon; | ||||
|     fn chosen_move(&self) -> LearnedMove; | ||||
|     fn use_move(&self) -> MoveData; | ||||
|     fn move_script<'a>(&'a self) -> Option<&'a dyn Script>; | ||||
|     fn number_of_targets(&self) -> usize; | ||||
|     fn is_pokemon_target(&self, pokemon: &Pokemon) -> bool; | ||||
|     fn get_hit_data(&self, pokemon: &Pokemon, hit: u8) -> HitData; | ||||
| } | ||||
|  | ||||
| pub type ExecutingMove = Rc<dyn ExecutingMoveTrait>; | ||||
| #[cfg(feature = "mock_data")] | ||||
| pub type MockExecutingMove = MockExecutingMoveTrait; | ||||
|  | ||||
| #[derive(Clone)] | ||||
| pub struct ExecutingMove { | ||||
| pub struct ExecutingMoveImpl { | ||||
|     inner: Temporary<ExecutingMoveInner>, | ||||
| } | ||||
|  | ||||
| impl ExecutingMove { | ||||
|     pub(crate) fn new(reference: ExternRef<ExecutingMove>) -> Self { | ||||
| impl ExecutingMoveImpl { | ||||
|     #[cfg(not(feature = "mock_data"))] | ||||
|     pub(crate) fn new(reference: ExternRef<Self>) -> Self { | ||||
|         Self { | ||||
|             inner: Temporary::new( | ||||
|                 reference.get_internal_index(), | ||||
| @@ -39,88 +58,119 @@ impl ExecutingMove { | ||||
|             ), | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
|     pub fn number_of_hits(&self) -> u8 { | ||||
| #[cfg(not(feature = "mock_data"))] | ||||
| impl ExecutingMoveTrait for ExecutingMoveImpl { | ||||
|     fn number_of_hits(&self) -> u8 { | ||||
|         self.inner.value().number_of_hits.value() | ||||
|     } | ||||
|     pub fn user(&self) -> Pokemon { | ||||
|         self.inner.value().user.value() | ||||
|     fn user(&self) -> Pokemon { | ||||
|         Rc::new(self.inner.value().user.value()) | ||||
|     } | ||||
|     pub fn chosen_move(&self) -> LearnedMove { | ||||
|     fn chosen_move(&self) -> LearnedMove { | ||||
|         self.inner.value().chosen_move.value() | ||||
|     } | ||||
|     pub fn use_move(&self) -> MoveData { | ||||
|     fn use_move(&self) -> MoveData { | ||||
|         self.inner.value().use_move.value() | ||||
|     } | ||||
|     pub fn move_script(&self) -> Option<&dyn Script> { | ||||
|     fn move_script(&self) -> Option<&dyn Script> { | ||||
|         unsafe { executing_move_get_script(self.inner.value().reference).as_ref() } | ||||
|     } | ||||
|     pub fn number_of_targets(&self) -> usize { | ||||
|     fn number_of_targets(&self) -> usize { | ||||
|         unsafe { executing_move_get_number_of_targets(self.inner.value().reference) } | ||||
|     } | ||||
|     pub fn is_pokemon_target(&self, pokemon: &Pokemon) -> bool { | ||||
|     fn is_pokemon_target(&self, pokemon: &Pokemon) -> bool { | ||||
|         unsafe { | ||||
|             executing_move_is_pokemon_target(self.inner.value().reference, pokemon.reference()) | ||||
|             executing_move_is_pokemon_target( | ||||
|                 self.inner.value().reference, | ||||
|                 pokemon.reference().into(), | ||||
|             ) | ||||
|         } | ||||
|     } | ||||
|     pub fn get_hit_data(&self, pokemon: &Pokemon, hit: u8) -> HitData { | ||||
|     fn get_hit_data(&self, pokemon: &Pokemon, hit: u8) -> HitData { | ||||
|         unsafe { | ||||
|             executing_move_get_hit_data(self.inner.value().reference, pokemon.reference(), hit) | ||||
|             Rc::new( | ||||
|                 executing_move_get_hit_data( | ||||
|                     self.inner.value().reference, | ||||
|                     pokemon.reference().into(), | ||||
|                     hit, | ||||
|                 ) | ||||
|                 .get_value() | ||||
|                 .unwrap() | ||||
|                 .unwrap(), | ||||
|             ) | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| pub trait HitDataTrait { | ||||
|     fn is_critical(&self) -> bool; | ||||
|     fn base_power(&self) -> u8; | ||||
|     fn effectiveness(&self) -> f32; | ||||
|     fn damage(&self) -> u32; | ||||
|     fn move_type(&self) -> u8; | ||||
|     fn has_failed(&self) -> bool; | ||||
|     fn set_critical(&self, critical: bool); | ||||
|     fn set_effectiveness(&self, effectiveness: f32); | ||||
|     fn set_damage(&self, damage: u32); | ||||
|     fn set_move_type(&self, move_type: u8); | ||||
|     fn fail(&self); | ||||
| } | ||||
|  | ||||
| pub type HitData = Rc<dyn HitDataTrait>; | ||||
|  | ||||
| #[derive(Clone)] | ||||
| pub struct HitData { | ||||
|     reference: ExternRef<HitData>, | ||||
| pub struct HitDataImpl { | ||||
|     reference: ExternRef<HitDataImpl>, | ||||
| } | ||||
|  | ||||
| impl HitData { | ||||
|     pub fn is_critical(&self) -> bool { | ||||
| #[cfg(not(feature = "mock_data"))] | ||||
| impl HitDataTrait for HitDataImpl { | ||||
|     fn is_critical(&self) -> bool { | ||||
|         unsafe { hit_data_is_critical(self.reference) } | ||||
|     } | ||||
|     pub fn base_power(&self) -> u8 { | ||||
|     fn base_power(&self) -> u8 { | ||||
|         unsafe { hit_data_get_base_power(self.reference) } | ||||
|     } | ||||
|     pub fn effectiveness(&self) -> f32 { | ||||
|     fn effectiveness(&self) -> f32 { | ||||
|         unsafe { hit_data_get_effectiveness(self.reference) } | ||||
|     } | ||||
|     pub fn damage(&self) -> u32 { | ||||
|     fn damage(&self) -> u32 { | ||||
|         unsafe { hit_data_get_damage(self.reference) } | ||||
|     } | ||||
|     pub fn move_type(&self) -> u8 { | ||||
|     fn move_type(&self) -> u8 { | ||||
|         unsafe { hit_data_get_move_type(self.reference) } | ||||
|     } | ||||
|     pub fn has_failed(&self) -> bool { | ||||
|     fn has_failed(&self) -> bool { | ||||
|         unsafe { hit_data_is_critical(self.reference) } | ||||
|     } | ||||
|  | ||||
|     pub fn set_critical(&self, critical: bool) { | ||||
|     fn set_critical(&self, critical: bool) { | ||||
|         unsafe { hit_data_set_critical(self.reference, critical) } | ||||
|     } | ||||
|     pub fn set_effectiveness(&self, effectiveness: f32) { | ||||
|     fn set_effectiveness(&self, effectiveness: f32) { | ||||
|         unsafe { hit_data_set_effectiveness(self.reference, effectiveness) } | ||||
|     } | ||||
|     pub fn set_damage(&self, damage: u32) { | ||||
|     fn set_damage(&self, damage: u32) { | ||||
|         unsafe { hit_data_set_damage(self.reference, damage) } | ||||
|     } | ||||
|     pub fn set_move_type(&self, move_type: u8) { | ||||
|     fn set_move_type(&self, move_type: u8) { | ||||
|         unsafe { hit_data_set_move_type(self.reference, move_type) } | ||||
|     } | ||||
|     pub fn fail(&self) { | ||||
|     fn fail(&self) { | ||||
|         unsafe { hit_data_fail(self.reference) } | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl ExternalReferenceType for ExecutingMove { | ||||
| #[cfg(not(feature = "mock_data"))] | ||||
| impl ExternalReferenceType for ExecutingMoveImpl { | ||||
|     fn from_extern_value(reference: ExternRef<Self>) -> Self { | ||||
|         Self::new(reference) | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl ExternalReferenceType for HitData { | ||||
| #[cfg(not(feature = "mock_data"))] | ||||
| impl ExternalReferenceType for HitDataImpl { | ||||
|     fn from_extern_value(reference: ExternRef<Self>) -> Self { | ||||
|         Self { reference } | ||||
|     } | ||||
| @@ -128,35 +178,35 @@ impl ExternalReferenceType for HitData { | ||||
|  | ||||
| #[cfg(not(feature = "mock_data"))] | ||||
| extern "wasm" { | ||||
|     fn executing_move_get_number_of_targets(r: ExternRef<ExecutingMove>) -> usize; | ||||
|     fn executing_move_get_number_of_hits(r: ExternRef<ExecutingMove>) -> u8; | ||||
|     fn executing_move_get_user(r: ExternRef<ExecutingMove>) -> ExternRef<Pokemon>; | ||||
|     fn executing_move_get_chosen_move(r: ExternRef<ExecutingMove>) -> ExternRef<LearnedMove>; | ||||
|     fn executing_move_get_use_move(r: ExternRef<ExecutingMove>) -> ExternRef<MoveData>; | ||||
|     fn executing_move_get_number_of_targets(r: ExternRef<ExecutingMoveImpl>) -> usize; | ||||
|     fn executing_move_get_number_of_hits(r: ExternRef<ExecutingMoveImpl>) -> u8; | ||||
|     fn executing_move_get_user(r: ExternRef<ExecutingMoveImpl>) -> ExternRef<PokemonImpl>; | ||||
|     fn executing_move_get_chosen_move(r: ExternRef<ExecutingMoveImpl>) -> ExternRef<LearnedMove>; | ||||
|     fn executing_move_get_use_move(r: ExternRef<ExecutingMoveImpl>) -> ExternRef<MoveData>; | ||||
|     #[allow(improper_ctypes)] | ||||
|     fn executing_move_get_script(r: ExternRef<ExecutingMove>) -> *const dyn Script; | ||||
|     fn executing_move_get_script(r: ExternRef<ExecutingMoveImpl>) -> *const dyn Script; | ||||
|  | ||||
|     fn executing_move_is_pokemon_target( | ||||
|         r: ExternRef<ExecutingMove>, | ||||
|         pokemon: ExternRef<Pokemon>, | ||||
|         r: ExternRef<ExecutingMoveImpl>, | ||||
|         pokemon: ExternRef<PokemonImpl>, | ||||
|     ) -> bool; | ||||
|     fn executing_move_get_hit_data( | ||||
|         r: ExternRef<ExecutingMove>, | ||||
|         target: ExternRef<Pokemon>, | ||||
|         r: ExternRef<ExecutingMoveImpl>, | ||||
|         target: ExternRef<PokemonImpl>, | ||||
|         hit: u8, | ||||
|     ) -> ExternRef<HitData>; | ||||
|     ) -> ExternRef<HitDataImpl>; | ||||
|  | ||||
|     fn hit_data_is_critical(r: ExternRef<HitData>) -> bool; | ||||
|     fn hit_data_get_base_power(r: ExternRef<HitData>) -> u8; | ||||
|     fn hit_data_get_effectiveness(r: ExternRef<HitData>) -> f32; | ||||
|     fn hit_data_get_damage(r: ExternRef<HitData>) -> u32; | ||||
|     fn hit_data_get_move_type(r: ExternRef<HitData>) -> u8; | ||||
|     fn hit_data_has_failed(r: ExternRef<HitData>) -> bool; | ||||
|     fn hit_data_is_critical(r: ExternRef<HitDataImpl>) -> bool; | ||||
|     fn hit_data_get_base_power(r: ExternRef<HitDataImpl>) -> u8; | ||||
|     fn hit_data_get_effectiveness(r: ExternRef<HitDataImpl>) -> f32; | ||||
|     fn hit_data_get_damage(r: ExternRef<HitDataImpl>) -> u32; | ||||
|     fn hit_data_get_move_type(r: ExternRef<HitDataImpl>) -> u8; | ||||
|     fn hit_data_has_failed(r: ExternRef<HitDataImpl>) -> bool; | ||||
|  | ||||
|     fn hit_data_set_critical(r: ExternRef<HitData>, critical: bool); | ||||
|     fn hit_data_set_base_power(r: ExternRef<HitData>, power: u8); | ||||
|     fn hit_data_set_effectiveness(r: ExternRef<HitData>, effectiveness: f32); | ||||
|     fn hit_data_set_damage(r: ExternRef<HitData>, damage: u32); | ||||
|     fn hit_data_set_move_type(r: ExternRef<HitData>, move_type: u8); | ||||
|     fn hit_data_fail(r: ExternRef<HitData>); | ||||
|     fn hit_data_set_critical(r: ExternRef<HitDataImpl>, critical: bool); | ||||
|     fn hit_data_set_base_power(r: ExternRef<HitDataImpl>, power: u8); | ||||
|     fn hit_data_set_effectiveness(r: ExternRef<HitDataImpl>, effectiveness: f32); | ||||
|     fn hit_data_set_damage(r: ExternRef<HitDataImpl>, damage: u32); | ||||
|     fn hit_data_set_move_type(r: ExternRef<HitDataImpl>, move_type: u8); | ||||
|     fn hit_data_fail(r: ExternRef<HitDataImpl>); | ||||
| } | ||||
|   | ||||
| @@ -10,6 +10,7 @@ mod party; | ||||
| mod pokemon; | ||||
| mod statistic_set; | ||||
| mod turn_choices; | ||||
| mod with_volatile; | ||||
|  | ||||
| pub use battle::*; | ||||
| pub use battle_party::*; | ||||
| @@ -23,3 +24,4 @@ pub use party::*; | ||||
| pub use pokemon::*; | ||||
| pub use statistic_set::*; | ||||
| pub use turn_choices::*; | ||||
| pub use with_volatile::*; | ||||
|   | ||||
| @@ -1,27 +1,46 @@ | ||||
| use crate::app_interface::Pokemon; | ||||
| use crate::app_interface::{Pokemon, PokemonImpl}; | ||||
| use crate::{ExternRef, ExternalReferenceType}; | ||||
| use alloc::rc::Rc; | ||||
|  | ||||
| #[derive(Clone)] | ||||
| pub struct Party { | ||||
|     reference: ExternRef<Party>, | ||||
| pub trait PartyTrait { | ||||
|     fn get_pokemon(&self, index: usize) -> Option<Pokemon>; | ||||
|     fn length(&self) -> usize; | ||||
| } | ||||
|  | ||||
| impl Party { | ||||
|     pub fn new(reference: ExternRef<Party>) -> Self { | ||||
| pub type Party = Rc<dyn PartyTrait>; | ||||
|  | ||||
| #[derive(Clone)] | ||||
| pub struct PartyImpl { | ||||
|     reference: ExternRef<Self>, | ||||
| } | ||||
|  | ||||
| #[cfg(not(feature = "mock_data"))] | ||||
| impl PartyImpl { | ||||
|     pub fn new(reference: ExternRef<PartyImpl>) -> Self { | ||||
|         Self { reference } | ||||
|     } | ||||
| } | ||||
|  | ||||
|     #[cfg(not(feature = "mock_data"))] | ||||
|     pub fn get_pokemon(&self, index: usize) -> Option<Pokemon> { | ||||
|         unsafe { party_get_pokemon(self.reference, index).get_value() } | ||||
| #[cfg(not(feature = "mock_data"))] | ||||
| impl PartyTrait for PartyImpl { | ||||
|     fn get_pokemon(&self, index: usize) -> Option<Pokemon> { | ||||
|         unsafe { | ||||
|             let v = party_get_pokemon(self.reference, index).get_value(); | ||||
|             if let Some(v) = v { | ||||
|                 Some(Rc::new(v)) | ||||
|             } else { | ||||
|                 None | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     pub fn length(&self) -> usize { | ||||
|     fn length(&self) -> usize { | ||||
|         unsafe { party_get_length(self.reference) } | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl ExternalReferenceType for Party { | ||||
| #[cfg(not(feature = "mock_data"))] | ||||
| impl ExternalReferenceType for PartyImpl { | ||||
|     fn from_extern_value(reference: ExternRef<Self>) -> Self { | ||||
|         Self::new(reference) | ||||
|     } | ||||
| @@ -29,6 +48,6 @@ impl ExternalReferenceType for Party { | ||||
|  | ||||
| #[cfg(not(feature = "mock_data"))] | ||||
| extern "wasm" { | ||||
|     fn party_get_pokemon(r: ExternRef<Party>, index: usize) -> ExternRef<Pokemon>; | ||||
|     fn party_get_length(r: ExternRef<Party>) -> usize; | ||||
|     fn party_get_pokemon(r: ExternRef<PartyImpl>, index: usize) -> ExternRef<PokemonImpl>; | ||||
|     fn party_get_length(r: ExternRef<PartyImpl>) -> usize; | ||||
| } | ||||
|   | ||||
| @@ -1,54 +1,324 @@ | ||||
| use crate::app_interface::ability::{Ability, AbilityIndex}; | ||||
| use crate::app_interface::{ | ||||
|     Battle, BattleSide, ClampedStatisticSet, Form, Gender, Item, LearnedMove, LevelInt, Nature, | ||||
|     Species, Statistic, StatisticSet, | ||||
|     AbilityImpl, Battle, BattleImpl, BattleSide, ClampedStatisticSet, Form, Gender, Item, ItemImpl, | ||||
|     LearnedMove, LevelInt, Nature, Species, Statistic, StatisticSet, StatisticSetImpl, | ||||
| }; | ||||
| 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, ScriptPtr, | ||||
|     TypeIdentifier, | ||||
|     cached_value, cached_value_getters, wasm_optional_reference_getters, | ||||
|     wasm_optional_reference_getters_extern, wasm_optional_reference_getters_funcs, | ||||
|     wasm_reference_getters, wasm_reference_getters_extern, wasm_reference_getters_funcs, | ||||
|     wasm_value_getters, wasm_value_getters_extern, wasm_value_getters_funcs, DynamicLibrary, | ||||
|     ExternRef, ExternalReferenceType, Script, ScriptPtr, TypeIdentifier, | ||||
| }; | ||||
| use alloc::boxed::Box; | ||||
| use alloc::rc::Rc; | ||||
| use core::any::Any; | ||||
| use cstr_core::{c_char, CString}; | ||||
|  | ||||
| struct PokemonInner { | ||||
|     reference: ExternRef<Pokemon>, | ||||
|     reference: ExternRef<PokemonImpl>, | ||||
|     library: CachedValue<DynamicLibrary>, | ||||
|     // We cache the reference to the data, not the values stored inside, which are dynamic. | ||||
|     flat_stats: CachedValue<StatisticSet<u32>>, | ||||
|     flat_stats: CachedValue<Rc<StatisticSetImpl<u32>>>, | ||||
|     // We cache the reference to the data, not the values stored inside, which are dynamic. | ||||
|     stat_boosts: CachedValue<ClampedStatisticSet<i8>>, | ||||
|     // We cache the reference to the data, not the values stored inside, which are dynamic. | ||||
|     boosted_stats: CachedValue<StatisticSet<u32>>, | ||||
|     boosted_stats: CachedValue<Rc<StatisticSetImpl<u32>>>, | ||||
|     // We cache the reference to the data, not the values stored inside, which are dynamic. | ||||
|     individual_values: CachedValue<ClampedStatisticSet<u8>>, | ||||
|     // We cache the reference to the data, not the values stored inside, which are dynamic. | ||||
|     effort_values: CachedValue<ClampedStatisticSet<u8>>, | ||||
| } | ||||
|  | ||||
| pub type Pokemon = Rc<dyn PokemonTrait>; | ||||
| #[cfg(feature = "mock_data")] | ||||
| pub type MockPokemon = MockPokemonTrait; | ||||
|  | ||||
| #[derive(Clone)] | ||||
| pub struct Pokemon { | ||||
| pub struct PokemonImpl { | ||||
|     inner: Rc<PokemonInner>, | ||||
| } | ||||
|  | ||||
| impl Pokemon { | ||||
| #[cfg_attr(feature = "mock_data", mockall::automock)] | ||||
| pub trait PokemonTrait { | ||||
|     fn reference(&self) -> u32; | ||||
|  | ||||
|     fn species(&self) -> Species; | ||||
|     fn form(&self) -> Form; | ||||
|     fn active_ability(&self) -> AbilityImpl; | ||||
|     fn nature(&self) -> Nature; | ||||
|     fn display_species(&self) -> Option<Species>; | ||||
|     fn display_form(&self) -> Option<Form>; | ||||
|     fn held_item(&self) -> Option<Item>; | ||||
|     fn battle(&self) -> Option<Battle>; | ||||
|     fn level(&self) -> LevelInt; | ||||
|     fn experience(&self) -> u32; | ||||
|     fn unique_identifier(&self) -> u32; | ||||
|     fn gender(&self) -> Gender; | ||||
|     fn coloring(&self) -> u8; | ||||
|     fn current_health(&self) -> u32; | ||||
|     fn weight(&self) -> f32; | ||||
|     fn height(&self) -> f32; | ||||
|     fn nickname(&self) -> *const c_char; | ||||
|     fn real_ability(&self) -> AbilityIndex; | ||||
|     fn types_length(&self) -> usize; | ||||
|     fn battle_side_index(&self) -> u8; | ||||
|     fn battle_index(&self) -> u8; | ||||
|     fn is_ability_overriden(&self) -> u8; | ||||
|     fn allowed_experience_gain(&self) -> bool; | ||||
|     fn is_usable(&self) -> bool; | ||||
|  | ||||
|     fn library(&self) -> DynamicLibrary; | ||||
|     fn flat_stats(&self) -> StatisticSet<u32>; | ||||
|     fn stat_boosts(&self) -> ClampedStatisticSet<i8>; | ||||
|     fn boosted_stats(&self) -> StatisticSet<u32>; | ||||
|     fn individual_values(&self) -> ClampedStatisticSet<u8>; | ||||
|     fn effort_values(&self) -> ClampedStatisticSet<u8>; | ||||
|     fn has_held_item(&self, name: &str) -> bool; | ||||
|     fn set_held_item(&self, item: &Item) -> Option<Item>; | ||||
|     fn remove_held_item(&self) -> Option<Item>; | ||||
|     fn consume_held_item(&self) -> bool; | ||||
|     fn max_health(&self) -> u32; | ||||
|     fn get_type(&self, index: usize) -> u8; | ||||
|     fn has_type(&self, type_identifier: TypeIdentifier) -> bool; | ||||
|     fn has_type_by_name(&self, type_name: &str) -> bool; | ||||
|     fn get_learned_move(&self, index: usize) -> Option<LearnedMove>; | ||||
|     fn change_stat_boost(&self, stat: Statistic, diff_amount: i8, self_inflicted: bool) -> bool; | ||||
|     fn ability_script<'a>(&'a self) -> Option<&'a Box<dyn Script>>; | ||||
|     fn change_species(&self, species: Species, form: Form); | ||||
|     fn change_form(&self, form: Form); | ||||
|     fn is_fainted(&self) -> bool; | ||||
|     fn damage(&self, damage: u32, source: DamageSource); | ||||
|     fn heal(&self, amount: u32, allow_revive: bool) -> bool; | ||||
|     fn set_weight(&self, weight: f32); | ||||
|     fn clear_status(&self); | ||||
|     fn battle_side(&self) -> BattleSide; | ||||
|     fn add_volatile(&self, script: Box<dyn Script>) -> &dyn Script; | ||||
|     fn add_volatile_by_name(&self, script_name: &str) -> &dyn Script; | ||||
|     fn remove_volatile(&self, script: &dyn Script); | ||||
|     // fn get_volatile<T: Script>(&self, script_name: &str) -> Option<&'static T> | ||||
|     // where | ||||
|     //     T: Script + 'static; | ||||
|  | ||||
|     fn equals(&self, other: &Pokemon) -> bool; | ||||
| } | ||||
|  | ||||
| #[cfg(not(feature = "mock_data"))] | ||||
| impl PokemonTrait for PokemonImpl { | ||||
|     fn reference(&self) -> u32 { | ||||
|         self.reference().get_internal_index() | ||||
|     } | ||||
|  | ||||
|     cached_value_getters! { | ||||
|         fn library(&self) -> DynamicLibrary; | ||||
|         fn flat_stats(&self) -> StatisticSet<u32>; | ||||
|         fn stat_boosts(&self) -> ClampedStatisticSet<i8>; | ||||
|         fn boosted_stats(&self) -> StatisticSet<u32>; | ||||
|         fn individual_values(&self) -> ClampedStatisticSet<u8>; | ||||
|         fn effort_values(&self) -> ClampedStatisticSet<u8>; | ||||
|     } | ||||
|  | ||||
|     fn battle(&self) -> Option<Battle> { | ||||
|         unsafe { | ||||
|             let b = pokemon_get_battle(self.reference()).get_value(); | ||||
|             if let Some(b) = b { | ||||
|                 Some(Rc::new(b)) | ||||
|             } else { | ||||
|                 None | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|     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()) } | ||||
|     } | ||||
|     fn set_held_item(&self, item: &Item) -> Option<Item> { | ||||
|         unsafe { | ||||
|             let i = | ||||
|                 pokemon_set_held_item(self.inner.reference, item.reference().into()).get_value(); | ||||
|             if let Some(i) = i { | ||||
|                 Some(Rc::new(i)) | ||||
|             } else { | ||||
|                 None | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|     fn remove_held_item(&self) -> Option<Item> { | ||||
|         unsafe { | ||||
|             let i = pokemon_remove_held_item(self.inner.reference).get_value(); | ||||
|             if let Some(i) = i { | ||||
|                 Some(Rc::new(i)) | ||||
|             } else { | ||||
|                 None | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|     fn consume_held_item(&self) -> bool { | ||||
|         unsafe { pokemon_consume_held_item(self.inner.reference) } | ||||
|     } | ||||
|     fn max_health(&self) -> u32 { | ||||
|         self.boosted_stats().hp() | ||||
|     } | ||||
|     fn get_type(&self, index: usize) -> u8 { | ||||
|         unsafe { pokemon_get_type(self.inner.reference, index) } | ||||
|     } | ||||
|     fn has_type(&self, type_identifier: TypeIdentifier) -> bool { | ||||
|         unsafe { pokemon_has_type(self.inner.reference, type_identifier.into()) } | ||||
|     } | ||||
|     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 | ||||
|     } | ||||
|     fn get_learned_move(&self, index: usize) -> Option<LearnedMove> { | ||||
|         unsafe { pokemon_get_learned_move(self.inner.reference, index).get_value() } | ||||
|     } | ||||
|     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) | ||||
|         } | ||||
|     } | ||||
|     fn ability_script(&self) -> Option<&Box<dyn Script>> { | ||||
|         unsafe { pokemon_get_ability_script(self.inner.reference).as_ref() } | ||||
|     } | ||||
|     fn change_species(&self, species: Species, form: Form) { | ||||
|         unsafe { | ||||
|             pokemon_change_species(self.inner.reference, species.reference(), form.reference()); | ||||
|         } | ||||
|     } | ||||
|     fn change_form(&self, form: Form) { | ||||
|         unsafe { | ||||
|             pokemon_change_form(self.inner.reference, form.reference()); | ||||
|         } | ||||
|     } | ||||
|     fn is_fainted(&self) -> bool { | ||||
|         self.current_health() == 0 | ||||
|     } | ||||
|     fn damage(&self, damage: u32, source: DamageSource) { | ||||
|         unsafe { pokemon_damage(self.inner.reference, damage, source) } | ||||
|     } | ||||
|     fn heal(&self, amount: u32, allow_revive: bool) -> bool { | ||||
|         unsafe { pokemon_heal(self.inner.reference, amount, allow_revive) } | ||||
|     } | ||||
|     fn set_weight(&self, weight: f32) { | ||||
|         unsafe { | ||||
|             pokemon_set_weight(self.reference(), weight); | ||||
|         } | ||||
|     } | ||||
|     fn clear_status(&self) { | ||||
|         unsafe { | ||||
|             pokemon_clear_status(self.reference()); | ||||
|         } | ||||
|     } | ||||
|     fn battle_side(&self) -> BattleSide { | ||||
|         Rc::new( | ||||
|             self.battle() | ||||
|                 .unwrap() | ||||
|                 .sides() | ||||
|                 .get(self.battle_side_index() as u32) | ||||
|                 .unwrap(), | ||||
|         ) | ||||
|     } | ||||
|     fn add_volatile(&self, script: Box<dyn Script>) -> &dyn Script { | ||||
|         unsafe { | ||||
|             pokemon_add_volatile(self.inner.reference, ScriptPtr::new(script)) | ||||
|                 .val() | ||||
|                 .unwrap() | ||||
|         } | ||||
|     } | ||||
|     fn add_volatile_by_name(&self, script_name: &str) -> &dyn Script { | ||||
|         unsafe { | ||||
|             let ptr = CString::new(script_name).unwrap(); | ||||
|             pokemon_add_volatile_by_name(self.inner.reference, ptr.as_ptr()) | ||||
|                 .val() | ||||
|                 .unwrap() | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     wasm_reference_getters_funcs! { | ||||
|         Pokemon, | ||||
|         fn species(&self) -> Species; | ||||
|         fn form(&self) -> Form; | ||||
|         fn active_ability(&self) -> AbilityImpl; | ||||
|         fn nature(&self) -> Nature; | ||||
|     } | ||||
|  | ||||
|     wasm_optional_reference_getters_funcs! { | ||||
|         Pokemon, | ||||
|         fn display_species(&self) -> Option<Species>; | ||||
|         fn display_form(&self) -> Option<Form>; | ||||
|     } | ||||
|  | ||||
|     fn held_item(&self) -> Option<Item> { | ||||
|         unsafe { | ||||
|             let i = pokemon_get_held_item(self.inner.reference).get_value(); | ||||
|             if let Some(i) = i { | ||||
|                 Some(Rc::new(i)) | ||||
|             } else { | ||||
|                 None | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     fn remove_volatile(&self, script: &dyn Script) { | ||||
|         unsafe { | ||||
|             let name = CString::new(script.get_name()).unwrap(); | ||||
|             pokemon_remove_volatile(self.inner.reference, name.as_ptr()); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     #[cfg(not(feature = "mock_data"))] | ||||
|     wasm_value_getters_funcs! { | ||||
|         Pokemon, | ||||
|         fn level(&self) -> LevelInt; | ||||
|         fn experience(&self) -> u32; | ||||
|         fn unique_identifier(&self) -> u32; | ||||
|         fn gender(&self) -> Gender; | ||||
|         fn coloring(&self) -> u8; | ||||
|         fn current_health(&self) -> u32; | ||||
|         fn weight(&self) -> f32; | ||||
|         fn height(&self) -> f32; | ||||
|         fn nickname(&self) -> *const c_char; | ||||
|         fn real_ability(&self) -> AbilityIndex; | ||||
|         fn types_length(&self) -> usize; | ||||
|         fn battle_side_index(&self) -> u8; | ||||
|         fn battle_index(&self) -> u8; | ||||
|         fn is_ability_overriden(&self) -> u8; | ||||
|         fn allowed_experience_gain(&self) -> bool; | ||||
|         fn is_usable(&self) -> bool; | ||||
|     } | ||||
|  | ||||
|     fn equals(&self, other: &Pokemon) -> bool { | ||||
|         self.inner | ||||
|             .reference | ||||
|             .get_internal_index() | ||||
|             .eq(&other.reference()) | ||||
|     } | ||||
| } | ||||
|  | ||||
| #[cfg(not(feature = "mock_data"))] | ||||
| impl PokemonImpl { | ||||
|     pub(crate) fn new(reference: ExternRef<Self>) -> 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() | ||||
|                     Rc::new(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() | ||||
|                     Rc::new(pokemon_get_boosted_stats(reference).get_value().unwrap()) | ||||
|                 }), | ||||
|                 individual_values: cached_value!({ | ||||
|                     pokemon_get_individual_values(reference) | ||||
| @@ -66,163 +336,7 @@ impl Pokemon { | ||||
|         self.inner.reference | ||||
|     } | ||||
|  | ||||
|     cached_value_getters! { | ||||
|         pub fn library(&self) -> DynamicLibrary; | ||||
|         pub fn flat_stats(&self) -> StatisticSet<u32>; | ||||
|         pub fn stat_boosts(&self) -> ClampedStatisticSet<i8>; | ||||
|         pub fn boosted_stats(&self) -> StatisticSet<u32>; | ||||
|         pub fn individual_values(&self) -> ClampedStatisticSet<u8>; | ||||
|         pub fn effort_values(&self) -> ClampedStatisticSet<u8>; | ||||
|     } | ||||
|  | ||||
|     #[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<Item> { | ||||
|         unsafe { pokemon_set_held_item(self.inner.reference, item.reference()).get_value() } | ||||
|     } | ||||
|  | ||||
|     #[cfg(not(feature = "mock_data"))] | ||||
|     pub fn remove_held_item(&self) -> Option<Item> { | ||||
|         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<LearnedMove> { | ||||
|         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<dyn Script>> { | ||||
|         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 set_weight(&self, weight: f32) { | ||||
|         unsafe { | ||||
|             pokemon_set_weight(self.reference(), weight); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     #[cfg(not(feature = "mock_data"))] | ||||
|     pub fn clear_status(&self) { | ||||
|         unsafe { | ||||
|             pokemon_clear_status(self.reference()); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     #[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"))] | ||||
|     pub fn add_volatile(&self, script: Box<dyn Script>) -> &dyn Script { | ||||
|         unsafe { | ||||
|             pokemon_add_volatile(self.inner.reference, ScriptPtr::new(script)) | ||||
|                 .val() | ||||
|                 .unwrap() | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     #[cfg(not(feature = "mock_data"))] | ||||
|     pub fn add_volatile_by_name(&self, script_name: &str) -> &dyn Script { | ||||
|         unsafe { | ||||
|             let ptr = CString::new(script_name).unwrap(); | ||||
|             pokemon_add_volatile_by_name(self.inner.reference, ptr.as_ptr()) | ||||
|                 .val() | ||||
|                 .unwrap() | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     #[cfg(not(feature = "mock_data"))] | ||||
|     pub fn remove_volatile(&self, script: &dyn Script) { | ||||
|         unsafe { | ||||
|             let name = CString::new(script.get_name()).unwrap(); | ||||
|             pokemon_remove_volatile(self.inner.reference, name.as_ptr()); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     #[cfg(not(feature = "mock_data"))] | ||||
|     pub fn get_volatile<T>(&self, script_name: &str) -> Option<&T> | ||||
|     fn get_volatile<T>(&self, script_name: &str) -> Option<&T> | ||||
|     where | ||||
|         T: Script + 'static, | ||||
|     { | ||||
| @@ -239,26 +353,26 @@ impl Pokemon { | ||||
| } | ||||
|  | ||||
| #[cfg(not(feature = "mock_data"))] | ||||
| wasm_reference_getters! { | ||||
|     Pokemon, | ||||
| wasm_reference_getters_extern! { | ||||
|     PokemonImpl, Pokemon, | ||||
|     pub fn species(&self) -> Species; | ||||
|     pub fn form(&self) -> Form; | ||||
|     pub fn active_ability(&self) -> Ability; | ||||
|     pub fn active_ability(&self) -> AbilityImpl; | ||||
|     pub fn nature(&self) -> Nature; | ||||
| } | ||||
|  | ||||
| #[cfg(not(feature = "mock_data"))] | ||||
| wasm_optional_reference_getters! { | ||||
|     Pokemon, | ||||
| wasm_optional_reference_getters_extern! { | ||||
|     PokemonImpl, Pokemon, | ||||
|     pub fn display_species(&self) -> Option<Species>; | ||||
|     pub fn display_form(&self) -> Option<Form>; | ||||
|     pub fn held_item(&self) -> Option<Item>; | ||||
|     pub fn battle(&self) -> Option<Battle>; | ||||
|     pub fn held_item(&self) -> Option<ItemImpl>; | ||||
|     pub fn battle(&self) -> Option<BattleImpl>; | ||||
| } | ||||
|  | ||||
| #[cfg(not(feature = "mock_data"))] | ||||
| wasm_value_getters! { | ||||
|     Pokemon, | ||||
| wasm_value_getters_extern! { | ||||
|     PokemonImpl, Pokemon, | ||||
|     pub fn level(&self) -> LevelInt; | ||||
|     pub fn experience(&self) -> u32; | ||||
|     pub fn unique_identifier(&self) -> u32; | ||||
| @@ -277,7 +391,7 @@ wasm_value_getters! { | ||||
|     pub fn is_usable(&self) -> bool; | ||||
| } | ||||
|  | ||||
| impl PartialEq for Pokemon { | ||||
| impl PartialEq for PokemonImpl { | ||||
|     fn eq(&self, other: &Self) -> bool { | ||||
|         self.inner.reference == other.inner.reference | ||||
|     } | ||||
| @@ -295,10 +409,10 @@ pub enum DamageSource { | ||||
|     Struggle = 2, | ||||
| } | ||||
|  | ||||
| crate::handling::cacheable::cacheable!(Pokemon); | ||||
| crate::handling::cacheable::cacheable!(PokemonImpl); | ||||
|  | ||||
| #[cfg(not(feature = "mock_data"))] | ||||
| impl ExternalReferenceType for Pokemon { | ||||
| impl ExternalReferenceType for PokemonImpl { | ||||
|     fn from_extern_value(reference: ExternRef<Self>) -> Self { | ||||
|         Self::new(reference) | ||||
|     } | ||||
| @@ -306,51 +420,46 @@ impl ExternalReferenceType for Pokemon { | ||||
|  | ||||
| #[cfg(not(feature = "mock_data"))] | ||||
| extern "wasm" { | ||||
|     fn pokemon_get_library(r: ExternRef<Pokemon>) -> ExternRef<DynamicLibrary>; | ||||
|     fn pokemon_get_flat_stats(r: ExternRef<Pokemon>) -> ExternRef<StatisticSet<u32>>; | ||||
|     fn pokemon_get_stat_boosts(r: ExternRef<Pokemon>) -> ExternRef<ClampedStatisticSet<i8>>; | ||||
|     fn pokemon_get_boosted_stats(r: ExternRef<Pokemon>) -> ExternRef<StatisticSet<u32>>; | ||||
|     fn pokemon_get_individual_values(r: ExternRef<Pokemon>) -> ExternRef<ClampedStatisticSet<u8>>; | ||||
|     fn pokemon_get_effort_values(r: ExternRef<Pokemon>) -> ExternRef<ClampedStatisticSet<u8>>; | ||||
|     fn pokemon_has_held_item(r: ExternRef<Pokemon>, name: *const c_char) -> bool; | ||||
|     fn pokemon_set_held_item(r: ExternRef<Pokemon>, item: ExternRef<Item>) -> ExternRef<Item>; | ||||
|     fn pokemon_remove_held_item(r: ExternRef<Pokemon>) -> ExternRef<Item>; | ||||
|     fn pokemon_consume_held_item(r: ExternRef<Pokemon>) -> bool; | ||||
|     fn pokemon_get_type(r: ExternRef<Pokemon>, index: usize) -> u8; | ||||
|     fn pokemon_has_type(r: ExternRef<Pokemon>, identifier: u8) -> bool; | ||||
|     fn pokemon_get_learned_move(r: ExternRef<Pokemon>, index: usize) -> ExternRef<LearnedMove>; | ||||
|     fn pokemon_get_library(r: ExternRef<PokemonImpl>) -> ExternRef<DynamicLibrary>; | ||||
|     fn pokemon_get_flat_stats(r: ExternRef<PokemonImpl>) -> ExternRef<StatisticSetImpl<u32>>; | ||||
|     fn pokemon_get_stat_boosts(r: ExternRef<PokemonImpl>) -> ExternRef<ClampedStatisticSet<i8>>; | ||||
|     fn pokemon_get_boosted_stats(r: ExternRef<PokemonImpl>) -> ExternRef<StatisticSetImpl<u32>>; | ||||
|     fn pokemon_get_individual_values( | ||||
|         r: ExternRef<PokemonImpl>, | ||||
|     ) -> ExternRef<ClampedStatisticSet<u8>>; | ||||
|     fn pokemon_get_effort_values(r: ExternRef<PokemonImpl>) -> ExternRef<ClampedStatisticSet<u8>>; | ||||
|     fn pokemon_has_held_item(r: ExternRef<PokemonImpl>, name: *const c_char) -> bool; | ||||
|     fn pokemon_set_held_item( | ||||
|         r: ExternRef<PokemonImpl>, | ||||
|         item: ExternRef<ItemImpl>, | ||||
|     ) -> ExternRef<ItemImpl>; | ||||
|     fn pokemon_remove_held_item(r: ExternRef<PokemonImpl>) -> ExternRef<ItemImpl>; | ||||
|     fn pokemon_consume_held_item(r: ExternRef<PokemonImpl>) -> bool; | ||||
|     fn pokemon_get_type(r: ExternRef<PokemonImpl>, index: usize) -> u8; | ||||
|     fn pokemon_has_type(r: ExternRef<PokemonImpl>, identifier: u8) -> bool; | ||||
|     fn pokemon_get_learned_move(r: ExternRef<PokemonImpl>, index: usize) -> ExternRef<LearnedMove>; | ||||
|     fn pokemon_change_stat_boost( | ||||
|         r: ExternRef<Pokemon>, | ||||
|         r: ExternRef<PokemonImpl>, | ||||
|         tat: Statistic, | ||||
|         diff_amount: i8, | ||||
|         self_inflicted: bool, | ||||
|     ) -> bool; | ||||
|     #[allow(improper_ctypes)] | ||||
|     fn pokemon_get_ability_script(r: ExternRef<Pokemon>) -> *const Box<dyn Script>; | ||||
|     fn pokemon_get_ability_script(r: ExternRef<PokemonImpl>) -> *const Box<dyn Script>; | ||||
|     fn pokemon_change_species( | ||||
|         r: ExternRef<Pokemon>, | ||||
|         r: ExternRef<PokemonImpl>, | ||||
|         species: ExternRef<Species>, | ||||
|         form: ExternRef<Form>, | ||||
|     ); | ||||
|     fn pokemon_change_form(r: ExternRef<Pokemon>, form: ExternRef<Form>); | ||||
|     fn pokemon_damage(r: ExternRef<Pokemon>, damage: u32, source: DamageSource); | ||||
|     fn pokemon_heal(r: ExternRef<Pokemon>, amount: u32, allow_revive: bool) -> bool; | ||||
|     fn pokemon_set_weight(r: ExternRef<Pokemon>, weight: f32); | ||||
|     fn pokemon_clear_status(r: ExternRef<Pokemon>); | ||||
|     fn pokemon_change_form(r: ExternRef<PokemonImpl>, form: ExternRef<Form>); | ||||
|     fn pokemon_damage(r: ExternRef<PokemonImpl>, damage: u32, source: DamageSource); | ||||
|     fn pokemon_heal(r: ExternRef<PokemonImpl>, amount: u32, allow_revive: bool) -> bool; | ||||
|     fn pokemon_set_weight(r: ExternRef<PokemonImpl>, weight: f32); | ||||
|     fn pokemon_clear_status(r: ExternRef<PokemonImpl>); | ||||
|  | ||||
|     fn pokemon_add_volatile_by_name(r: ExternRef<Pokemon>, name: *const c_char) -> ScriptPtr; | ||||
|     fn pokemon_add_volatile(r: ExternRef<Pokemon>, script: ScriptPtr) -> ScriptPtr; | ||||
|     fn pokemon_has_volatile(r: ExternRef<Pokemon>, name: *const c_char) -> bool; | ||||
|     fn pokemon_remove_volatile(r: ExternRef<Pokemon>, name: *const c_char); | ||||
|     fn pokemon_get_volatile(r: ExternRef<Pokemon>, name: *const c_char) -> ScriptPtr; | ||||
| } | ||||
|  | ||||
| #[cfg(feature = "mock_data")] | ||||
| impl Pokemon { | ||||
|     pub fn current_health(&self) -> u32 { | ||||
|         unimplemented!() | ||||
|     } | ||||
|     pub fn species(&self) -> Species { | ||||
|         unimplemented!() | ||||
|     } | ||||
|     fn pokemon_add_volatile_by_name(r: ExternRef<PokemonImpl>, name: *const c_char) -> ScriptPtr; | ||||
|     fn pokemon_add_volatile(r: ExternRef<PokemonImpl>, script: ScriptPtr) -> ScriptPtr; | ||||
|     fn pokemon_has_volatile(r: ExternRef<PokemonImpl>, name: *const c_char) -> bool; | ||||
|     fn pokemon_remove_volatile(r: ExternRef<PokemonImpl>, name: *const c_char); | ||||
|     fn pokemon_get_volatile(r: ExternRef<PokemonImpl>, name: *const c_char) -> ScriptPtr; | ||||
| } | ||||
|   | ||||
| @@ -1,20 +1,57 @@ | ||||
| use crate::app_interface::Statistic; | ||||
| use crate::{ExternRef, ExternalReferenceType}; | ||||
| use alloc::rc::Rc; | ||||
| use core::convert::{TryFrom, TryInto}; | ||||
| use core::fmt::Debug; | ||||
| use core::marker::PhantomData; | ||||
|  | ||||
| #[derive(Clone)] | ||||
| pub struct StatisticSet<T> | ||||
| pub trait StatisticSetTrait<T> | ||||
| where | ||||
|     T: TryFrom<i64>, | ||||
|     T: TryInto<i64>, | ||||
|     <T as TryFrom<i64>>::Error: Debug, | ||||
|     <T as TryInto<i64>>::Error: Debug, | ||||
| { | ||||
|     fn hp(&self) -> T { | ||||
|         self.get_stat(Statistic::Attack) | ||||
|     } | ||||
|     fn attack(&self) -> T { | ||||
|         self.get_stat(Statistic::Attack) | ||||
|     } | ||||
|     fn defense(&self) -> T { | ||||
|         self.get_stat(Statistic::Defense) | ||||
|     } | ||||
|     fn special_attack(&self) -> T { | ||||
|         self.get_stat(Statistic::SpecialAttack) | ||||
|     } | ||||
|     fn special_defense(&self) -> T { | ||||
|         self.get_stat(Statistic::SpecialDefense) | ||||
|     } | ||||
|     fn speed(&self) -> T { | ||||
|         self.get_stat(Statistic::Speed) | ||||
|     } | ||||
|     fn get_stat(&self, stat: Statistic) -> T; | ||||
|     fn set_stat(&self, stat: Statistic, value: T); | ||||
|     fn increase_stat(&self, stat: Statistic, value: T); | ||||
|     fn decrease_stat(&self, stat: Statistic, value: T); | ||||
| } | ||||
|  | ||||
| pub type StatisticSet<T> = Rc<dyn StatisticSetTrait<T>>; | ||||
|  | ||||
| #[derive(Clone)] | ||||
| pub struct StatisticSetImpl<T> | ||||
| where | ||||
|     T: TryFrom<i64>, | ||||
|     T: TryInto<i64>, | ||||
|     <T as TryFrom<i64>>::Error: Debug, | ||||
|     <T as TryInto<i64>>::Error: Debug, | ||||
| { | ||||
|     reference: ExternRef<Self>, | ||||
|     _p: PhantomData<T>, | ||||
| } | ||||
|  | ||||
| impl<T> StatisticSet<T> | ||||
| #[cfg(not(feature = "mock_data"))] | ||||
| impl<T> StatisticSetImpl<T> | ||||
| where | ||||
|     T: TryFrom<i64>, | ||||
|     T: TryInto<i64>, | ||||
| @@ -27,61 +64,40 @@ where | ||||
|             _p: Default::default(), | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
|     #[cfg(not(feature = "mock_data"))] | ||||
|     pub fn hp(&self) -> T { | ||||
|         self.get_stat(Statistic::HP) | ||||
|     } | ||||
|     #[cfg(not(feature = "mock_data"))] | ||||
|     pub fn attack(&self) -> T { | ||||
|         self.get_stat(Statistic::Attack) | ||||
|     } | ||||
|     #[cfg(not(feature = "mock_data"))] | ||||
|     pub fn defense(&self) -> T { | ||||
|         self.get_stat(Statistic::Defense) | ||||
|     } | ||||
|     #[cfg(not(feature = "mock_data"))] | ||||
|     pub fn special_attack(&self) -> T { | ||||
|         self.get_stat(Statistic::SpecialAttack) | ||||
|     } | ||||
|     #[cfg(not(feature = "mock_data"))] | ||||
|     pub fn special_defense(&self) -> T { | ||||
|         self.get_stat(Statistic::SpecialDefense) | ||||
|     } | ||||
|     #[cfg(not(feature = "mock_data"))] | ||||
|     pub fn speed(&self) -> T { | ||||
|         self.get_stat(Statistic::Speed) | ||||
|     } | ||||
|  | ||||
|     #[cfg(not(feature = "mock_data"))] | ||||
|     pub fn get_stat(&self, stat: Statistic) -> T { | ||||
| #[cfg(not(feature = "mock_data"))] | ||||
| impl<T> StatisticSetTrait<T> for StatisticSetImpl<T> | ||||
| where | ||||
|     T: TryFrom<i64>, | ||||
|     T: TryInto<i64>, | ||||
|     <T as TryFrom<i64>>::Error: Debug, | ||||
|     <T as TryInto<i64>>::Error: Debug, | ||||
| { | ||||
|     fn get_stat(&self, stat: Statistic) -> T { | ||||
|         unsafe { | ||||
|             statistic_set_get(self.reference.cast(), stat) | ||||
|                 .try_into() | ||||
|                 .unwrap() | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     #[cfg(not(feature = "mock_data"))] | ||||
|     pub fn set_stat(&self, stat: Statistic, value: T) { | ||||
|     fn set_stat(&self, stat: Statistic, value: T) { | ||||
|         unsafe { statistic_set_set(self.reference.cast(), stat, value.try_into().unwrap()) } | ||||
|     } | ||||
|  | ||||
|     #[cfg(not(feature = "mock_data"))] | ||||
|     pub fn increase_stat(&self, stat: Statistic, value: T) { | ||||
|     fn increase_stat(&self, stat: Statistic, value: T) { | ||||
|         unsafe { | ||||
|             statistic_set_increase_stat(self.reference.cast(), stat, value.try_into().unwrap()) | ||||
|         } | ||||
|     } | ||||
|     #[cfg(not(feature = "mock_data"))] | ||||
|     pub fn decrease_stat(&self, stat: Statistic, value: T) { | ||||
|     fn decrease_stat(&self, stat: Statistic, value: T) { | ||||
|         unsafe { | ||||
|             statistic_set_decrease_stat(self.reference.cast(), stat, value.try_into().unwrap()) | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl<T> ExternalReferenceType for StatisticSet<T> | ||||
| #[cfg(not(feature = "mock_data"))] | ||||
| impl<T> ExternalReferenceType for StatisticSetImpl<T> | ||||
| where | ||||
|     T: TryFrom<i64>, | ||||
|     T: TryInto<i64>, | ||||
| @@ -89,7 +105,7 @@ where | ||||
|     <T as TryInto<i64>>::Error: Debug, | ||||
| { | ||||
|     fn from_extern_value(reference: ExternRef<Self>) -> Self { | ||||
|         StatisticSet::<T>::new(reference) | ||||
|         StatisticSetImpl::<T>::new(reference) | ||||
|     } | ||||
| } | ||||
|  | ||||
| @@ -98,6 +114,8 @@ pub struct ClampedStatisticSet<T> | ||||
| where | ||||
|     T: TryFrom<i64>, | ||||
|     T: TryInto<i64>, | ||||
|     <T as TryFrom<i64>>::Error: Debug, | ||||
|     <T as TryInto<i64>>::Error: Debug, | ||||
| { | ||||
|     reference: ExternRef<Self>, | ||||
|     _p: PhantomData<T>, | ||||
| @@ -192,10 +210,18 @@ where | ||||
|  | ||||
| #[cfg(not(feature = "mock_data"))] | ||||
| extern "wasm" { | ||||
|     fn statistic_set_get(r: ExternRef<StatisticSet<i64>>, stat: Statistic) -> i64; | ||||
|     fn statistic_set_set(r: ExternRef<StatisticSet<i64>>, stat: Statistic, value: i64); | ||||
|     fn statistic_set_increase_stat(r: ExternRef<StatisticSet<i64>>, stat: Statistic, value: i64); | ||||
|     fn statistic_set_decrease_stat(r: ExternRef<StatisticSet<i64>>, stat: Statistic, value: i64); | ||||
|     fn statistic_set_get(r: ExternRef<StatisticSetImpl<i64>>, stat: Statistic) -> i64; | ||||
|     fn statistic_set_set(r: ExternRef<StatisticSetImpl<i64>>, stat: Statistic, value: i64); | ||||
|     fn statistic_set_increase_stat( | ||||
|         r: ExternRef<StatisticSetImpl<i64>>, | ||||
|         stat: Statistic, | ||||
|         value: i64, | ||||
|     ); | ||||
|     fn statistic_set_decrease_stat( | ||||
|         r: ExternRef<StatisticSetImpl<i64>>, | ||||
|         stat: Statistic, | ||||
|         value: i64, | ||||
|     ); | ||||
|  | ||||
|     fn clamped_statistic_set_get(r: ExternRef<ClampedStatisticSet<i64>>, stat: Statistic) -> i64; | ||||
|     fn clamped_statistic_set_set( | ||||
|   | ||||
| @@ -1,17 +1,46 @@ | ||||
| use crate::app_interface::{LearnedMove, Pokemon}; | ||||
| use crate::app_interface::{LearnedMove, Pokemon, PokemonImpl}; | ||||
| use crate::handling::cached_value::CachedValue; | ||||
| use crate::handling::temporary::Temporary; | ||||
| use crate::ExternRef; | ||||
| #[cfg(not(feature = "mock_data"))] | ||||
| use crate::{cached_value, ExternalReferenceType, Script}; | ||||
| #[cfg(not(feature = "mock_data"))] | ||||
| use alloc::boxed::Box; | ||||
| use alloc::rc::Rc; | ||||
|  | ||||
| struct BaseTurnChoiceData { | ||||
|     reference: ExternRef<TurnChoice>, | ||||
|     user: CachedValue<Pokemon>, | ||||
| pub trait BaseTurnChoiceDataTrait { | ||||
|     fn reference(&self) -> u32; | ||||
|     fn user(&self) -> Pokemon; | ||||
|     fn speed(&self) -> u32; | ||||
|     fn has_failed(&self) -> bool; | ||||
|     fn fail(&self); | ||||
| } | ||||
|  | ||||
| struct BaseTurnChoiceDataImpl { | ||||
|     reference: ExternRef<TurnChoice>, | ||||
|     user: CachedValue<Rc<PokemonImpl>>, | ||||
| } | ||||
|  | ||||
| #[cfg(not(feature = "mock_data"))] | ||||
| impl BaseTurnChoiceDataTrait for BaseTurnChoiceDataImpl { | ||||
|     fn reference(&self) -> u32 { | ||||
|         self.reference.get_internal_index() | ||||
|     } | ||||
|  | ||||
|     fn user(&self) -> Pokemon { | ||||
|         self.user.value() | ||||
|     } | ||||
|     fn speed(&self) -> u32 { | ||||
|         unsafe { turn_choice_get_speed(self.reference) } | ||||
|     } | ||||
|     fn has_failed(&self) -> bool { | ||||
|         unsafe { turn_choice_has_failed(self.reference) } | ||||
|     } | ||||
|     fn fail(&self) { | ||||
|         unsafe { turn_choice_fail(self.reference) } | ||||
|     } | ||||
| } | ||||
|  | ||||
| pub type BaseTurnChoiceData = Rc<dyn BaseTurnChoiceDataTrait>; | ||||
|  | ||||
| struct MoveTurnChoiceDataInner { | ||||
|     base: BaseTurnChoiceData, | ||||
|     used_move: CachedValue<LearnedMove>, | ||||
| @@ -19,13 +48,22 @@ struct MoveTurnChoiceDataInner { | ||||
|     target_index: CachedValue<u8>, | ||||
| } | ||||
|  | ||||
| pub trait MoveTurnChoiceDataTrait { | ||||
|     fn base(&self) -> BaseTurnChoiceData; | ||||
|     fn used_move(&self) -> LearnedMove; | ||||
|     fn target_side(&self) -> u8; | ||||
|     fn target_index(&self) -> u8; | ||||
|     fn priority(&self) -> i8; | ||||
|     fn move_script(&self) -> Option<&Box<dyn Script>>; | ||||
| } | ||||
|  | ||||
| #[derive(Clone)] | ||||
| pub struct MoveTurnChoiceData { | ||||
| pub struct MoveTurnChoiceDataImpl { | ||||
|     inner: Temporary<MoveTurnChoiceDataInner>, | ||||
| } | ||||
|  | ||||
| pub enum TurnChoice { | ||||
|     Move(MoveTurnChoiceData), | ||||
|     Move(Box<dyn MoveTurnChoiceDataTrait>), | ||||
|     Item(), | ||||
|     Switch(), | ||||
|     Flee, | ||||
| @@ -33,9 +71,9 @@ pub enum TurnChoice { | ||||
| } | ||||
|  | ||||
| impl TurnChoice { | ||||
|     fn base(&self) -> &BaseTurnChoiceData { | ||||
|     fn base(&self) -> BaseTurnChoiceData { | ||||
|         match self { | ||||
|             TurnChoice::Move(d) => &d.inner.value_ref().base, | ||||
|             TurnChoice::Move(m) => m.base(), | ||||
|             TurnChoice::Item() => unimplemented!(), | ||||
|             TurnChoice::Switch() => unimplemented!(), | ||||
|             TurnChoice::Flee => unimplemented!(), | ||||
| @@ -44,43 +82,39 @@ impl TurnChoice { | ||||
|     } | ||||
|  | ||||
|     pub fn user(&self) -> Pokemon { | ||||
|         self.base().user.value() | ||||
|         self.base().user() | ||||
|     } | ||||
|  | ||||
|     #[cfg(not(feature = "mock_data"))] | ||||
|     pub fn speed(&self) -> u32 { | ||||
|         unsafe { turn_choice_get_speed(self.base().reference) } | ||||
|         self.base().speed() | ||||
|     } | ||||
|  | ||||
|     #[cfg(not(feature = "mock_data"))] | ||||
|     pub fn has_failed(&self) -> bool { | ||||
|         unsafe { turn_choice_has_failed(self.base().reference) } | ||||
|         self.base().has_failed() | ||||
|     } | ||||
|  | ||||
|     #[cfg(not(feature = "mock_data"))] | ||||
|     pub fn fail(&self) { | ||||
|         unsafe { turn_choice_fail(self.base().reference) } | ||||
|         self.base().fail() | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl MoveTurnChoiceData { | ||||
|     pub fn used_move(&self) -> LearnedMove { | ||||
|         self.inner.value().used_move.value() | ||||
|     } | ||||
|     pub fn target_side(&self) -> u8 { | ||||
|         self.inner.value().target_side.value() | ||||
|     } | ||||
|     pub fn target_index(&self) -> u8 { | ||||
|         self.inner.value().target_index.value() | ||||
|     } | ||||
|     #[cfg(not(feature = "mock_data"))] | ||||
|     pub fn priority(&self) -> i8 { | ||||
|         unsafe { turn_choice_move_priority(self.inner.value().base.reference.cast()) } | ||||
| #[cfg(not(feature = "mock_data"))] | ||||
| impl MoveTurnChoiceDataTrait for MoveTurnChoiceDataImpl { | ||||
|     fn base(&self) -> BaseTurnChoiceData { | ||||
|         self.inner.value().base.clone() | ||||
|     } | ||||
|  | ||||
|     #[cfg(not(feature = "mock_data"))] | ||||
|     pub fn move_script(&self) -> Option<&Box<dyn Script>> { | ||||
|         unsafe { turn_choice_move_script(self.inner.value().base.reference.cast()).as_ref() } | ||||
|     fn used_move(&self) -> LearnedMove { | ||||
|         self.inner.value().used_move.value() | ||||
|     } | ||||
|     fn target_side(&self) -> u8 { | ||||
|         self.inner.value().target_side.value() | ||||
|     } | ||||
|     fn target_index(&self) -> u8 { | ||||
|         self.inner.value().target_index.value() | ||||
|     } | ||||
|     fn priority(&self) -> i8 { | ||||
|         unsafe { turn_choice_move_priority(self.base().reference().into()) } | ||||
|     } | ||||
|     fn move_script(&self) -> Option<&Box<dyn Script>> { | ||||
|         unsafe { turn_choice_move_script(self.base().reference().into()).as_ref() } | ||||
|     } | ||||
| } | ||||
|  | ||||
| @@ -89,12 +123,12 @@ impl ExternalReferenceType for TurnChoice { | ||||
|     fn from_extern_value(reference: ExternRef<Self>) -> Self { | ||||
|         let kind = unsafe { turn_choice_get_kind(reference) }; | ||||
|         match kind { | ||||
|             0 => TurnChoice::Move(MoveTurnChoiceData { | ||||
|             0 => TurnChoice::Move(Box::new(MoveTurnChoiceDataImpl { | ||||
|                 inner: Temporary::new( | ||||
|                     reference.get_internal_index(), | ||||
|                     MoveTurnChoiceDataInner::from_reference(reference.cast()), | ||||
|                 ), | ||||
|             }), | ||||
|             })), | ||||
|             _ => panic!("Unknown turn choice type"), | ||||
|         } | ||||
|     } | ||||
| @@ -102,14 +136,14 @@ impl ExternalReferenceType for TurnChoice { | ||||
|  | ||||
| #[cfg(not(feature = "mock_data"))] | ||||
| impl MoveTurnChoiceDataInner { | ||||
|     fn from_reference(reference: ExternRef<MoveTurnChoiceData>) -> Self { | ||||
|     fn from_reference(reference: ExternRef<MoveTurnChoiceDataImpl>) -> Self { | ||||
|         Self { | ||||
|             base: BaseTurnChoiceData { | ||||
|             base: Rc::new(BaseTurnChoiceDataImpl { | ||||
|                 reference: reference.cast(), | ||||
|                 user: cached_value!({ | ||||
|                     turn_choice_get_user(reference.cast()).get_value().unwrap() | ||||
|                     Rc::new(turn_choice_get_user(reference.cast()).get_value().unwrap()) | ||||
|                 }), | ||||
|             }, | ||||
|             }), | ||||
|             used_move: cached_value!({ | ||||
|                 turn_choice_move_used_move(reference.cast()) | ||||
|                     .get_value() | ||||
| @@ -124,15 +158,15 @@ impl MoveTurnChoiceDataInner { | ||||
| #[cfg(not(feature = "mock_data"))] | ||||
| extern "wasm" { | ||||
|     fn turn_choice_get_kind(r: ExternRef<TurnChoice>) -> u8; | ||||
|     fn turn_choice_get_user(r: ExternRef<TurnChoice>) -> ExternRef<Pokemon>; | ||||
|     fn turn_choice_get_user(r: ExternRef<TurnChoice>) -> ExternRef<PokemonImpl>; | ||||
|     fn turn_choice_get_speed(r: ExternRef<TurnChoice>) -> u32; | ||||
|     fn turn_choice_has_failed(r: ExternRef<TurnChoice>) -> bool; | ||||
|     fn turn_choice_fail(r: ExternRef<TurnChoice>); | ||||
|  | ||||
|     fn turn_choice_move_used_move(r: ExternRef<MoveTurnChoiceData>) -> ExternRef<LearnedMove>; | ||||
|     fn turn_choice_move_target_side(r: ExternRef<MoveTurnChoiceData>) -> u8; | ||||
|     fn turn_choice_move_target_index(r: ExternRef<MoveTurnChoiceData>) -> u8; | ||||
|     fn turn_choice_move_priority(r: ExternRef<MoveTurnChoiceData>) -> i8; | ||||
|     fn turn_choice_move_used_move(r: ExternRef<MoveTurnChoiceDataImpl>) -> ExternRef<LearnedMove>; | ||||
|     fn turn_choice_move_target_side(r: ExternRef<MoveTurnChoiceDataImpl>) -> u8; | ||||
|     fn turn_choice_move_target_index(r: ExternRef<MoveTurnChoiceDataImpl>) -> u8; | ||||
|     fn turn_choice_move_priority(r: ExternRef<MoveTurnChoiceDataImpl>) -> i8; | ||||
|     #[allow(improper_ctypes)] | ||||
|     fn turn_choice_move_script(r: ExternRef<MoveTurnChoiceData>) -> *const Box<dyn Script>; | ||||
|     fn turn_choice_move_script(r: ExternRef<MoveTurnChoiceDataImpl>) -> *const Box<dyn Script>; | ||||
| } | ||||
|   | ||||
| @@ -0,0 +1,21 @@ | ||||
| use crate::handling::Script; | ||||
| use alloc::boxed::Box; | ||||
|  | ||||
| pub trait WithVolatile { | ||||
|     fn has_volatile(&self, script_name: &str) -> bool; | ||||
|     fn add_volatile<'a, 'b>(&'a self, script: Box<dyn Script>) -> &'b dyn Script; | ||||
|     fn remove_volatile(&self, script: &dyn Script); | ||||
|     fn get_volatile_script(&self, script_name: &str) -> Option<&dyn Script>; | ||||
| } | ||||
|  | ||||
| pub fn get_volatile_as<'a, T>(v: &'a dyn WithVolatile, script_name: &str) -> Option<&'a T> | ||||
| where | ||||
|     T: Script + 'static, | ||||
| { | ||||
|     let s = v.get_volatile_script(script_name); | ||||
|     if let Some(s) = s { | ||||
|         Some(s.as_any().downcast_ref::<T>().unwrap()) | ||||
|     } else { | ||||
|         None | ||||
|     } | ||||
| } | ||||
| @@ -7,18 +7,24 @@ use crate::{ | ||||
| use alloc::rc::Rc; | ||||
|  | ||||
| struct AbilityInner { | ||||
|     reference: ExternRef<Ability>, | ||||
|     reference: ExternRef<AbilityImpl>, | ||||
|     name: CachedValue<StringKey>, | ||||
|     effect: CachedValue<StringKey>, | ||||
|     parameters: CachedValue<ImmutableList<EffectParameter>>, | ||||
| } | ||||
|  | ||||
| #[cfg_attr(test, mockall::automock)] | ||||
| pub trait Ability { | ||||
|     fn name(&self) -> StringKey; | ||||
|     fn effect(&self) -> StringKey; | ||||
| } | ||||
|  | ||||
| #[derive(Clone)] | ||||
| pub struct Ability { | ||||
| pub struct AbilityImpl { | ||||
|     inner: Rc<AbilityInner>, | ||||
| } | ||||
|  | ||||
| impl Ability { | ||||
| impl AbilityImpl { | ||||
|     #[cfg(not(feature = "mock_data"))] | ||||
|     pub fn new(reference: ExternRef<Self>) -> Self { | ||||
|         Self::from_ref(reference, &|reference| Self { | ||||
| @@ -32,21 +38,23 @@ impl Ability { | ||||
|             }), | ||||
|         }) | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl Ability for AbilityImpl { | ||||
|     cached_value_getters! { | ||||
|         pub fn name(&self) -> StringKey; | ||||
|         pub fn effect(&self) -> StringKey; | ||||
|         fn name(&self) -> StringKey; | ||||
|         fn effect(&self) -> StringKey; | ||||
|     } | ||||
| } | ||||
|  | ||||
| #[cfg(not(feature = "mock_data"))] | ||||
| impl ExternalReferenceType for Ability { | ||||
| impl ExternalReferenceType for AbilityImpl { | ||||
|     fn from_extern_value(reference: ExternRef<Self>) -> Self { | ||||
|         Self::new(reference) | ||||
|     } | ||||
| } | ||||
|  | ||||
| crate::handling::cacheable::cacheable!(Ability); | ||||
| crate::handling::cacheable::cacheable!(AbilityImpl); | ||||
|  | ||||
| #[derive(Copy, Clone, Debug, Eq, PartialEq)] | ||||
| #[repr(C)] | ||||
| @@ -57,7 +65,7 @@ pub struct AbilityIndex { | ||||
|  | ||||
| #[cfg(not(feature = "mock_data"))] | ||||
| extern "wasm" { | ||||
|     fn ability_get_name(r: ExternRef<Ability>) -> ExternRef<StringKey>; | ||||
|     fn ability_get_effect(r: ExternRef<Ability>) -> ExternRef<StringKey>; | ||||
|     fn ability_get_parameters(r: ExternRef<Ability>) -> VecExternRef<EffectParameter>; | ||||
|     fn ability_get_name(r: ExternRef<AbilityImpl>) -> ExternRef<StringKey>; | ||||
|     fn ability_get_effect(r: ExternRef<AbilityImpl>) -> ExternRef<StringKey>; | ||||
|     fn ability_get_parameters(r: ExternRef<AbilityImpl>) -> VecExternRef<EffectParameter>; | ||||
| } | ||||
|   | ||||
| @@ -1,11 +1,11 @@ | ||||
| use crate::app_interface::{DataLibrary, Item}; | ||||
| use crate::app_interface::{DataLibrary, Item, ItemImpl}; | ||||
| use crate::{ExternRef, ExternalReferenceType, StringKey}; | ||||
| use alloc::rc::Rc; | ||||
| use spin::rwlock::RwLock; | ||||
|  | ||||
| struct ItemLibraryInner { | ||||
|     ptr: ExternRef<ItemLibrary>, | ||||
|     cache: RwLock<hashbrown::HashMap<u32, Item>>, | ||||
|     cache: RwLock<hashbrown::HashMap<u32, ItemImpl>>, | ||||
| } | ||||
|  | ||||
| #[derive(Clone)] | ||||
| @@ -25,8 +25,8 @@ impl ItemLibrary { | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl DataLibrary<Item> for ItemLibrary { | ||||
|     fn get_cache(&self) -> &spin::rwlock::RwLock<hashbrown::HashMap<u32, Item>> { | ||||
| impl DataLibrary<ItemImpl> for ItemLibrary { | ||||
|     fn get_cache(&self) -> &spin::rwlock::RwLock<hashbrown::HashMap<u32, ItemImpl>> { | ||||
|         &self.inner.cache | ||||
|     } | ||||
|  | ||||
| @@ -35,12 +35,12 @@ impl DataLibrary<Item> for ItemLibrary { | ||||
|     } | ||||
|  | ||||
|     #[cfg(not(feature = "mock_data"))] | ||||
|     fn _get_ref_by_name(ptr: ExternRef<Self>, name: ExternRef<StringKey>) -> ExternRef<Item> { | ||||
|     fn _get_ref_by_name(ptr: ExternRef<Self>, name: ExternRef<StringKey>) -> ExternRef<ItemImpl> { | ||||
|         unsafe { item_library_get_item(ptr, name) } | ||||
|     } | ||||
|  | ||||
|     #[cfg(not(feature = "mock_data"))] | ||||
|     fn _get_ref_by_hash(ptr: ExternRef<Self>, hash: u32) -> ExternRef<Item> { | ||||
|     fn _get_ref_by_hash(ptr: ExternRef<Self>, hash: u32) -> ExternRef<ItemImpl> { | ||||
|         unsafe { item_library_get_item_by_hash(ptr, hash) } | ||||
|     } | ||||
| } | ||||
| @@ -59,8 +59,9 @@ extern "wasm" { | ||||
|     fn item_library_get_item( | ||||
|         ptr: ExternRef<ItemLibrary>, | ||||
|         name: ExternRef<StringKey>, | ||||
|     ) -> ExternRef<Item>; | ||||
|     fn item_library_get_item_by_hash(ptr: ExternRef<ItemLibrary>, hash: u32) -> ExternRef<Item>; | ||||
|     ) -> ExternRef<ItemImpl>; | ||||
|     fn item_library_get_item_by_hash(ptr: ExternRef<ItemLibrary>, hash: u32) | ||||
|         -> ExternRef<ItemImpl>; | ||||
| } | ||||
|  | ||||
| #[cfg(feature = "mock_data")] | ||||
|   | ||||
| @@ -41,8 +41,26 @@ pub enum BattleItemCategory { | ||||
|     MiscBattleItem, | ||||
| } | ||||
|  | ||||
| #[cfg_attr(feature = "mock_data", mockall::automock)] | ||||
| pub trait ItemTrait { | ||||
|     fn reference(&self) -> u32; | ||||
|     /// The name of the item. | ||||
|     fn name(&self) -> StringKey; | ||||
|     /// Which bag slot items are stored in. | ||||
|     fn category(&self) -> ItemCategory; | ||||
|     /// How the item is categorized when in battle. | ||||
|     fn battle_category(&self) -> BattleItemCategory; | ||||
|     /// The buying value of the item. | ||||
|     fn price(&self) -> i32; | ||||
|     fn has_flag(&self, flag: &StringKey) -> bool; | ||||
| } | ||||
|  | ||||
| pub type Item = Rc<dyn ItemTrait>; | ||||
| #[cfg(feature = "mock_data")] | ||||
| pub type MockItem = MockItemTrait; | ||||
|  | ||||
| struct ItemInner { | ||||
|     reference: ExternRef<Item>, | ||||
|     reference: ExternRef<ItemImpl>, | ||||
|     name: CachedValue<StringKey>, | ||||
|     category: CachedValue<ItemCategory>, | ||||
|     battle_category: CachedValue<BattleItemCategory>, | ||||
| @@ -51,12 +69,12 @@ struct ItemInner { | ||||
|  | ||||
| /// An item is an object which the player can pick up, keep in their Bag, and use in some manner | ||||
| #[derive(Clone)] | ||||
| pub struct Item { | ||||
| pub struct ItemImpl { | ||||
|     inner: Rc<ItemInner>, | ||||
| } | ||||
|  | ||||
| impl Item { | ||||
|     #[cfg(not(feature = "mock_data"))] | ||||
| #[cfg(not(feature = "mock_data"))] | ||||
| impl ItemImpl { | ||||
|     pub(crate) fn new(reference: ExternRef<Self>) -> Self { | ||||
|         Self::from_ref(reference, &|reference| Self { | ||||
|             inner: Rc::new(ItemInner { | ||||
| @@ -69,69 +87,47 @@ impl Item { | ||||
|         }) | ||||
|     } | ||||
|  | ||||
|     #[cfg(not(feature = "mock_data"))] | ||||
|     pub(crate) fn reference(&self) -> ExternRef<Self> { | ||||
|         self.inner.reference | ||||
|     } | ||||
| } | ||||
|  | ||||
| #[cfg(not(feature = "mock_data"))] | ||||
| impl ItemTrait for ItemImpl { | ||||
|     fn reference(&self) -> u32 { | ||||
|         self.inner.reference.get_internal_index() | ||||
|     } | ||||
|  | ||||
|     cached_value_getters! { | ||||
|         /// The name of the item. | ||||
|         pub fn name(&self) -> StringKey; | ||||
|         fn name(&self) -> StringKey; | ||||
|         /// Which bag slot items are stored in. | ||||
|         pub fn category(&self) -> ItemCategory; | ||||
|         fn category(&self) -> ItemCategory; | ||||
|         /// How the item is categorized when in battle. | ||||
|         pub fn battle_category(&self) -> BattleItemCategory; | ||||
|         fn battle_category(&self) -> BattleItemCategory; | ||||
|         /// The buying value of the item. | ||||
|         pub fn price(&self) -> i32; | ||||
|         fn price(&self) -> i32; | ||||
|     } | ||||
|  | ||||
|     #[cfg(not(feature = "mock_data"))] | ||||
|     pub fn has_flag(&self, flag: &StringKey) -> bool { | ||||
|     fn has_flag(&self, flag: &StringKey) -> bool { | ||||
|         unsafe { item_has_flag(self.inner.reference, flag.ptr()) } | ||||
|     } | ||||
| } | ||||
|  | ||||
| crate::handling::cacheable::cacheable!(Item); | ||||
| crate::handling::cacheable::cacheable!(ItemImpl); | ||||
|  | ||||
| #[cfg(not(feature = "mock_data"))] | ||||
| impl ExternalReferenceType for Item { | ||||
| impl ExternalReferenceType for ItemImpl { | ||||
|     fn from_extern_value(reference: ExternRef<Self>) -> Self { | ||||
|         Item::new(reference) | ||||
|         ItemImpl::new(reference) | ||||
|     } | ||||
| } | ||||
|  | ||||
| #[cfg(not(feature = "mock_data"))] | ||||
| extern "wasm" { | ||||
|     fn item_get_name(ptr: ExternRef<Item>) -> ExternRef<StringKey>; | ||||
|     fn item_get_category(ptr: ExternRef<Item>) -> ItemCategory; | ||||
|     fn item_get_battle_category(ptr: ExternRef<Item>) -> BattleItemCategory; | ||||
|     fn item_get_price(ptr: ExternRef<Item>) -> i32; | ||||
|     fn item_has_flag(ptr: ExternRef<Item>, flag: ExternRef<StringKey>) -> bool; | ||||
| } | ||||
|  | ||||
| #[cfg(feature = "mock_data")] | ||||
| mod test { | ||||
|     use super::Item; | ||||
|     use super::ItemInner; | ||||
|     use crate::app_interface::{BattleItemCategory, ItemCategory}; | ||||
|     use crate::{cached_value, ExternRef, StringKey}; | ||||
|     use alloc::rc::Rc; | ||||
|  | ||||
|     impl Item { | ||||
|         pub fn mock() -> Self { | ||||
|             Self { | ||||
|                 inner: Rc::new(ItemInner { | ||||
|                     reference: ExternRef::mock(), | ||||
|                     name: StringKey::new("test").into(), | ||||
|                     category: ItemCategory::MiscItem.into(), | ||||
|                     battle_category: BattleItemCategory::None.into(), | ||||
|                     price: 0.into(), | ||||
|                 }), | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         pub fn has_flag(&self) -> bool { | ||||
|             unimplemented!() | ||||
|         } | ||||
|     } | ||||
|     fn item_get_name(ptr: ExternRef<ItemImpl>) -> ExternRef<StringKey>; | ||||
|     fn item_get_category(ptr: ExternRef<ItemImpl>) -> ItemCategory; | ||||
|     fn item_get_battle_category(ptr: ExternRef<ItemImpl>) -> BattleItemCategory; | ||||
|     fn item_get_price(ptr: ExternRef<ItemImpl>) -> i32; | ||||
|     fn item_has_flag(ptr: ExternRef<ItemImpl>, flag: ExternRef<StringKey>) -> bool; | ||||
| } | ||||
|   | ||||
| @@ -6,6 +6,7 @@ pub mod move_data; | ||||
| mod nature; | ||||
| pub mod species; | ||||
|  | ||||
| pub use ability::*; | ||||
| pub use data_libraries::*; | ||||
| pub use effect_parameter::EffectParameter; | ||||
| pub use item::*; | ||||
|   | ||||
| @@ -166,7 +166,7 @@ mod test { | ||||
|  | ||||
|     impl StringKey { | ||||
|         pub fn new(s: &str) -> Self { | ||||
|             let hash = get_hash(s.as_bytes()); | ||||
|             let hash = get_hash(s); | ||||
|             Self { | ||||
|                 data: Rc::new(StringKeyInner { | ||||
|                     ptr: ExternRef::mock(), | ||||
|   | ||||
		Reference in New Issue
	
	Block a user