From 517c5710d1f46c8b24acfed359cf2b509210924c Mon Sep 17 00:00:00 2001 From: Deukhoofd Date: Wed, 4 Jan 2023 18:39:27 +0100 Subject: [PATCH] More work on mocking and unit testing --- gen_7_scripts/src/moves/acrobatics.rs | 2 +- gen_7_scripts/src/moves/acupressure.rs | 66 +- gen_7_scripts/src/moves/aurora_veil.rs | 4 +- pkmn_lib_interface/Cargo.toml | 2 +- .../src/app_interface/dynamic_data/battle.rs | 285 +++--- .../dynamic_data/battle_random.rs | 72 +- .../app_interface/dynamic_data/battle_side.rs | 18 +- .../dynamic_data/choice_queue.rs | 1 + .../dynamic_data/executing_move.rs | 364 ++++---- .../src/app_interface/dynamic_data/party.rs | 4 +- .../src/app_interface/dynamic_data/pokemon.rs | 818 ++++++++++-------- .../dynamic_data/turn_choices.rs | 5 +- .../dynamic_data/with_volatile.rs | 3 +- .../src/app_interface/static_data/species.rs | 3 +- pkmn_lib_interface/src/handling/script.rs | 3 +- pkmn_lib_interface/src/lib.rs | 7 +- pkmn_lib_interface/src/utils.rs | 5 +- 17 files changed, 948 insertions(+), 714 deletions(-) diff --git a/gen_7_scripts/src/moves/acrobatics.rs b/gen_7_scripts/src/moves/acrobatics.rs index e5ee2a5..74e01e5 100755 --- a/gen_7_scripts/src/moves/acrobatics.rs +++ b/gen_7_scripts/src/moves/acrobatics.rs @@ -44,7 +44,7 @@ impl Script for Acrobatics { mod tests { use super::*; use alloc::rc::Rc; - use pkmn_lib_interface::app_interface::{Item, MockExecutingMove, MockItem, MockPokemon}; + use pkmn_lib_interface::app_interface::{MockExecutingMove, MockItem, MockPokemon}; fn mock_executing_move(has_held_item: bool) -> ExecutingMove { let mut mv = MockExecutingMove::new(); diff --git a/gen_7_scripts/src/moves/acupressure.rs b/gen_7_scripts/src/moves/acupressure.rs index 2e9a0fc..864b0d1 100755 --- a/gen_7_scripts/src/moves/acupressure.rs +++ b/gen_7_scripts/src/moves/acupressure.rs @@ -1,4 +1,3 @@ -use alloc::boxed::Box; use core::any::Any; use core::mem::transmute; use pkmn_lib_interface::app_interface::{ExecutingMove, Pokemon, Statistic}; @@ -39,3 +38,68 @@ impl Script for Acupressure { self } } + +#[cfg(test)] +mod tests { + use super::*; + use alloc::rc::Rc; + use pkmn_lib_interface::app_interface::{ + MockBattle, MockBattleRandom, MockExecutingMove, MockHitData, MockItem, MockPokemon, + }; + + #[test] + fn fails_if_target_is_user() { + let mut user = MockPokemon::new(); + user.expect_equals().return_const(true); + let user = Rc::new(user); + let u = user.clone(); + + let mut mv = MockExecutingMove::new(); + mv.expect_user().returning_st(move || user.clone()); + + let mut hit_data = MockHitData::new(); + hit_data.expect_fail().once(); + let hit_data = Rc::new(hit_data); + mv.expect_get_hit_data() + .returning_st(move |_, _| hit_data.clone()); + + let script = Acupressure::new(); + script.on_secondary_effect(Rc::new(mv), u, 0); + } + + #[test] + fn increases_stat_by_two() { + let mut user = MockPokemon::new(); + user.expect_equals().return_const(false); + user.expect_battle().returning_st(move || { + let mut battle = MockBattle::new(); + battle.expect_random().returning_st(move || { + let mut random = MockBattleRandom::new(); + random.expect_get_between().returning_st(|low, high| { + assert_eq!(1, low); + assert_eq!(6, high); + return 1; + }); + Rc::new(random) + }); + Some(Rc::new(battle)) + }); + user.expect_change_stat_boost() + .once() + .returning(|stat, amount, self_inflicted| { + assert_eq!(Statistic::Attack, stat); + assert_eq!(2, amount); + assert_eq!(false, self_inflicted); + true + }); + + let user = Rc::new(user); + let u = user.clone(); + + let mut mv = MockExecutingMove::new(); + mv.expect_user().returning_st(move || user.clone()); + + let script = Acupressure::new(); + script.on_secondary_effect(Rc::new(mv), u, 0); + } +} diff --git a/gen_7_scripts/src/moves/aurora_veil.rs b/gen_7_scripts/src/moves/aurora_veil.rs index db87ee1..f1dd484 100644 --- a/gen_7_scripts/src/moves/aurora_veil.rs +++ b/gen_7_scripts/src/moves/aurora_veil.rs @@ -30,8 +30,8 @@ impl Script for AuroraVeil { if target.battle().unwrap().has_weather(Hail::get_const_name()) { return mv.get_hit_data(&target, hit).fail(); } - let script = target - .battle_side() + let binding = target.battle_side(); + let script = binding .add_volatile(Box::new(AuroraVeilEffect::new())) .as_any() .downcast_ref::() diff --git a/pkmn_lib_interface/Cargo.toml b/pkmn_lib_interface/Cargo.toml index 301131c..4db7cd6 100755 --- a/pkmn_lib_interface/Cargo.toml +++ b/pkmn_lib_interface/Cargo.toml @@ -14,6 +14,6 @@ spin = { version = "0.9.4", default-features = false, features = ["rwlock"] } paste = { version = "1.0.7" } hashbrown = { version = "0.12.3" } dlmalloc = { version = "0.2.4", features = ["global"] } -mockall = { version = "0.11.2", optional = true } +mockall = { version = "0.11.2", optional = true, features = ["nightly"] } diff --git a/pkmn_lib_interface/src/app_interface/dynamic_data/battle.rs b/pkmn_lib_interface/src/app_interface/dynamic_data/battle.rs index ef89cbe..f0112cf 100755 --- a/pkmn_lib_interface/src/app_interface/dynamic_data/battle.rs +++ b/pkmn_lib_interface/src/app_interface/dynamic_data/battle.rs @@ -1,16 +1,12 @@ -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, wasm_value_getters_extern, - wasm_value_getters_funcs, DynamicLibrary, ExternRef, ExternalReferenceType, ImmutableList, - StringKey, VecExternRef, -}; use alloc::rc::Rc; +use crate::app_interface::list::ImmutableList; +use crate::app_interface::BattleSideImpl; +use crate::app_interface::{ + BattleParty, BattlePartyImpl, BattleRandom, ChoiceQueue, DynamicLibrary, Pokemon, StringKey, +}; + +#[cfg_attr(feature = "mock_data", mockall::automock)] pub trait BattleTrait { fn library(&self) -> DynamicLibrary; fn parties(&self) -> ImmutableList; @@ -31,130 +27,157 @@ pub trait BattleTrait { } pub type Battle = Rc; - -struct BattleInner { - reference: ExternRef, - library: CachedValue, - parties: CachedValue>, - sides: CachedValue>, - random: CachedValue>, - choice_queue: CachedValue>, -} - -#[derive(Clone)] -pub struct BattleImpl { - inner: Rc, -} +#[cfg(feature = "mock_data")] +pub type MockBattle = MockBattleTrait; #[cfg(not(feature = "mock_data"))] -impl BattleImpl { - pub fn new(reference: ExternRef) -> 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!({ - Rc::new(battle_get_random(reference).get_value().unwrap()) +mod implementation { + use super::*; + use crate::app_interface::PokemonImpl; + use crate::app_interface::{ + BattleParty, BattlePartyImpl, BattleRandom, BattleRandomImpl, BattleSide, BattleSideImpl, + ChoiceQueue, ChoiceQueueImpl, Pokemon, + }; + use crate::handling::cached_value::CachedValue; + use crate::handling::Cacheable; + use crate::{ + cached_value, cached_value_getters, wasm_value_getters, wasm_value_getters_extern, + wasm_value_getters_funcs, DynamicLibrary, ExternRef, ExternalReferenceType, ImmutableList, + StringKey, VecExternRef, + }; + + struct BattleInner { + reference: ExternRef, + library: CachedValue, + parties: CachedValue>, + sides: CachedValue>, + random: CachedValue>, + choice_queue: CachedValue>, + } + + #[derive(Clone)] + pub struct BattleImpl { + inner: Rc, + } + + #[cfg(not(feature = "mock_data"))] + impl BattleImpl { + pub fn new(reference: ExternRef) -> 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!({ + Rc::new(battle_get_random(reference).get_value().unwrap()) + }), + choice_queue: cached_value!({ + Rc::new(battle_get_choice_queue(reference).get_value().unwrap()) + }), }), - choice_queue: cached_value!({ - Rc::new(battle_get_choice_queue(reference).get_value().unwrap()) - }), - }), - }) + }) + } + } + + #[cfg(not(feature = "mock_data"))] + impl BattleTrait for BattleImpl { + cached_value_getters! { + fn library(&self) -> DynamicLibrary; + fn parties(&self) -> ImmutableList; + fn sides(&self) -> ImmutableList; + fn random(&self) -> BattleRandom; + fn choice_queue(&self) -> ChoiceQueue; + } + + fn get_pokemon(&self, side: u8, index: u8) -> Option { + unsafe { + let v = battle_get_pokemon(self.inner.reference, side, index).get_value(); + if let Some(v) = v { + Some(Rc::new(v)) + } else { + None + } + } + } + + fn find_party_for_pokemon(&self, pokemon: &Pokemon) -> Option { + 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 + } + } + } + + fn weather_name(&self) -> Option { + unsafe { battle_get_weather_name(self.inner.reference).get_value() } + } + fn has_weather(&self, name: &str) -> bool { + if let Some(weather) = self.weather_name() { + if weather.eq(name) { + return true; + } + } + 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_extern! { + BattleImpl, Battle, + pub fn can_flee(&self) -> bool; + pub fn number_of_sides(&self) -> u8; + pub fn pokemon_per_side(&self) -> u8; + pub fn has_ended(&self) -> bool; + pub fn has_ended_conclusively(&self) -> bool; + pub fn winning_side(&self) -> u8; + pub fn current_turn(&self) -> u32; + } + + crate::handling::cacheable::cacheable!(BattleImpl); + + #[cfg(not(feature = "mock_data"))] + impl ExternalReferenceType for BattleImpl { + fn from_extern_value(reference: ExternRef) -> Self { + Self::new(reference) + } + } + + #[cfg(not(feature = "mock_data"))] + extern "wasm" { + fn battle_get_library(r: ExternRef) -> ExternRef; + fn battle_get_parties(r: ExternRef) -> VecExternRef; + fn battle_get_sides(r: ExternRef) -> VecExternRef; + fn battle_get_random(r: ExternRef) -> ExternRef; + fn battle_get_choice_queue(r: ExternRef) -> ExternRef; + fn battle_get_pokemon( + r: ExternRef, + side: u8, + index: u8, + ) -> ExternRef; + fn battle_find_party_for_pokemon( + r: ExternRef, + mon: ExternRef, + ) -> ExternRef; + + fn battle_get_weather_name(r: ExternRef) -> ExternRef; } } #[cfg(not(feature = "mock_data"))] -impl BattleTrait for BattleImpl { - cached_value_getters! { - fn library(&self) -> DynamicLibrary; - fn parties(&self) -> ImmutableList; - fn sides(&self) -> ImmutableList; - fn random(&self) -> BattleRandom; - fn choice_queue(&self) -> ChoiceQueue; - } - - fn get_pokemon(&self, side: u8, index: u8) -> Option { - unsafe { - let v = battle_get_pokemon(self.inner.reference, side, index).get_value(); - if let Some(v) = v { - Some(Rc::new(v)) - } else { - None - } - } - } - - fn find_party_for_pokemon(&self, pokemon: &Pokemon) -> Option { - 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 - } - } - } - - fn weather_name(&self) -> Option { - unsafe { battle_get_weather_name(self.inner.reference).get_value() } - } - fn has_weather(&self, name: &str) -> bool { - if let Some(weather) = self.weather_name() { - if weather.eq(name) { - return true; - } - } - 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_extern! { - BattleImpl, Battle, - pub fn can_flee(&self) -> bool; - pub fn number_of_sides(&self) -> u8; - pub fn pokemon_per_side(&self) -> u8; - pub fn has_ended(&self) -> bool; - pub fn has_ended_conclusively(&self) -> bool; - pub fn winning_side(&self) -> u8; - pub fn current_turn(&self) -> u32; -} - -crate::handling::cacheable::cacheable!(BattleImpl); - -#[cfg(not(feature = "mock_data"))] -impl ExternalReferenceType for BattleImpl { - fn from_extern_value(reference: ExternRef) -> Self { - Self::new(reference) - } -} - -#[cfg(not(feature = "mock_data"))] -extern "wasm" { - fn battle_get_library(r: ExternRef) -> ExternRef; - fn battle_get_parties(r: ExternRef) -> VecExternRef; - fn battle_get_sides(r: ExternRef) -> VecExternRef; - fn battle_get_random(r: ExternRef) -> ExternRef; - fn battle_get_choice_queue(r: ExternRef) -> ExternRef; - fn battle_get_pokemon(r: ExternRef, side: u8, index: u8) -> ExternRef; - fn battle_find_party_for_pokemon( - r: ExternRef, - mon: ExternRef, - ) -> ExternRef; - - fn battle_get_weather_name(r: ExternRef) -> ExternRef; -} +pub use implementation::*; diff --git a/pkmn_lib_interface/src/app_interface/dynamic_data/battle_random.rs b/pkmn_lib_interface/src/app_interface/dynamic_data/battle_random.rs index d528ad4..37090c9 100755 --- a/pkmn_lib_interface/src/app_interface/dynamic_data/battle_random.rs +++ b/pkmn_lib_interface/src/app_interface/dynamic_data/battle_random.rs @@ -1,6 +1,6 @@ -use crate::{ExternRef, ExternalReferenceType}; use alloc::rc::Rc; +#[cfg_attr(feature = "mock_data", mockall::automock)] pub trait BattleRandomTrait { fn get(&self) -> i32; fn get_max(&self, max: i32) -> i32; @@ -8,39 +8,49 @@ pub trait BattleRandomTrait { } pub type BattleRandom = Rc; - -#[derive(Clone)] -pub struct BattleRandomImpl { - reference: ExternRef, -} +#[cfg(feature = "mock_data")] +pub type MockBattleRandom = MockBattleRandomTrait; #[cfg(not(feature = "mock_data"))] -impl BattleRandomTrait for BattleRandomImpl { - #[cfg(not(feature = "mock_data"))] - fn get(&self) -> i32 { - unsafe { battle_random_get(self.reference) } - } - #[cfg(not(feature = "mock_data"))] - fn get_max(&self, max: i32) -> i32 { - unsafe { battle_random_get_max(self.reference, max) } - } - #[cfg(not(feature = "mock_data"))] - fn get_between(&self, min: i32, max: i32) -> i32 { - unsafe { battle_random_get_between(self.reference, min, max) } - } - // TODO: effect_chance() -} - -impl ExternalReferenceType for BattleRandomImpl { - fn from_extern_value(reference: ExternRef) -> Self { - Self { reference } - } -} +pub use implementation::*; #[cfg(not(feature = "mock_data"))] -extern "wasm" { - fn battle_random_get(r: ExternRef) -> i32; - fn battle_random_get_max(r: ExternRef, max: i32) -> i32; - fn battle_random_get_between(r: ExternRef, min: i32, max: i32) -> i32; +mod implementation { + use super::*; + use crate::{ExternRef, ExternalReferenceType}; + #[derive(Clone)] + pub struct BattleRandomImpl { + reference: ExternRef, + } + + impl BattleRandomTrait for BattleRandomImpl { + #[cfg(not(feature = "mock_data"))] + fn get(&self) -> i32 { + unsafe { battle_random_get(self.reference) } + } + #[cfg(not(feature = "mock_data"))] + fn get_max(&self, max: i32) -> i32 { + unsafe { battle_random_get_max(self.reference, max) } + } + #[cfg(not(feature = "mock_data"))] + fn get_between(&self, min: i32, max: i32) -> i32 { + unsafe { battle_random_get_between(self.reference, min, max) } + } + // TODO: effect_chance() + } + + impl ExternalReferenceType for BattleRandomImpl { + fn from_extern_value(reference: ExternRef) -> Self { + Self { reference } + } + } + + #[cfg(not(feature = "mock_data"))] + extern "wasm" { + fn battle_random_get(r: ExternRef) -> i32; + fn battle_random_get_max(r: ExternRef, max: i32) -> i32; + fn battle_random_get_between(r: ExternRef, min: i32, max: i32) -> i32; + + } } diff --git a/pkmn_lib_interface/src/app_interface/dynamic_data/battle_side.rs b/pkmn_lib_interface/src/app_interface/dynamic_data/battle_side.rs index 4764b29..a0a8b53 100755 --- a/pkmn_lib_interface/src/app_interface/dynamic_data/battle_side.rs +++ b/pkmn_lib_interface/src/app_interface/dynamic_data/battle_side.rs @@ -1,4 +1,6 @@ -use crate::app_interface::{Battle, BattleImpl, Pokemon, PokemonImpl, WithVolatile}; +use crate::app_interface::{Battle, Pokemon, WithVolatile}; +#[cfg(not(feature = "mock_data"))] +use crate::app_interface::{BattleImpl, PokemonImpl}; use crate::handling::cacheable::Cacheable; use crate::handling::cached_value::CachedValue; use crate::{ @@ -20,6 +22,7 @@ pub trait BattleSideTrait: WithVolatile { pub type BattleSide = Rc; +#[cfg(not(feature = "mock_data"))] struct BattleSideInner { reference: ExternRef, side_index: CachedValue, @@ -29,6 +32,7 @@ struct BattleSideInner { #[derive(Clone)] pub struct BattleSideImpl { + #[cfg(not(feature = "mock_data"))] inner: Rc, } @@ -82,13 +86,23 @@ impl WithVolatile for BattleSideImpl { battleside_has_volatile(self.inner.reference, script_name.as_ptr()) } } - fn add_volatile<'a, 'b>(&'a self, script: Box) -> &'b dyn Script { + fn add_volatile(&self, script: Box) -> &dyn Script { unsafe { battleside_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(); + battleside_add_volatile_by_name(self.inner.reference, ptr.as_ptr()) + .val() + .unwrap() + } + } + fn remove_volatile(&self, script: &dyn Script) { unsafe { let name = CString::new(script.get_name()).unwrap(); diff --git a/pkmn_lib_interface/src/app_interface/dynamic_data/choice_queue.rs b/pkmn_lib_interface/src/app_interface/dynamic_data/choice_queue.rs index 393e4e2..ddf2061 100755 --- a/pkmn_lib_interface/src/app_interface/dynamic_data/choice_queue.rs +++ b/pkmn_lib_interface/src/app_interface/dynamic_data/choice_queue.rs @@ -1,3 +1,4 @@ +#[cfg(not(feature = "mock_data"))] use crate::app_interface::PokemonImpl; use crate::{ExternRef, ExternalReferenceType, Pokemon}; use alloc::rc::Rc; diff --git a/pkmn_lib_interface/src/app_interface/dynamic_data/executing_move.rs b/pkmn_lib_interface/src/app_interface/dynamic_data/executing_move.rs index 5fe0dd1..cdf39de 100755 --- a/pkmn_lib_interface/src/app_interface/dynamic_data/executing_move.rs +++ b/pkmn_lib_interface/src/app_interface/dynamic_data/executing_move.rs @@ -1,18 +1,11 @@ -use crate::app_interface::{LearnedMove, MoveData, Pokemon, PokemonImpl}; +#[cfg(not(feature = "mock_data"))] +use crate::app_interface::PokemonImpl; +use crate::app_interface::{LearnedMove, MoveData, Pokemon}; 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, - number_of_hits: CachedValue, - user: CachedValue, - chosen_move: CachedValue, - use_move: CachedValue, -} - #[cfg_attr(feature = "mock_data", mockall::automock)] pub trait ExecutingMoveTrait { fn number_of_hits(&self) -> u8; @@ -25,84 +18,7 @@ pub trait ExecutingMoveTrait { fn get_hit_data(&self, pokemon: &Pokemon, hit: u8) -> HitData; } -pub type ExecutingMove = Rc; -#[cfg(feature = "mock_data")] -pub type MockExecutingMove = MockExecutingMoveTrait; - -#[derive(Clone)] -pub struct ExecutingMoveImpl { - inner: Temporary, -} - -impl ExecutingMoveImpl { - #[cfg(not(feature = "mock_data"))] - pub(crate) fn new(reference: ExternRef) -> Self { - Self { - inner: Temporary::new( - reference.get_internal_index(), - ExecutingMoveInner { - reference, - number_of_hits: cached_value!({ executing_move_get_number_of_hits(reference) }), - user: cached_value!({ - executing_move_get_user(reference).get_value().unwrap() - }), - chosen_move: cached_value!({ - executing_move_get_chosen_move(reference) - .get_value() - .unwrap() - }), - use_move: cached_value!({ - executing_move_get_use_move(reference).get_value().unwrap() - }), - }, - ), - } - } -} - -#[cfg(not(feature = "mock_data"))] -impl ExecutingMoveTrait for ExecutingMoveImpl { - fn number_of_hits(&self) -> u8 { - self.inner.value().number_of_hits.value() - } - fn user(&self) -> Pokemon { - Rc::new(self.inner.value().user.value()) - } - fn chosen_move(&self) -> LearnedMove { - self.inner.value().chosen_move.value() - } - fn use_move(&self) -> MoveData { - self.inner.value().use_move.value() - } - fn move_script(&self) -> Option<&dyn Script> { - unsafe { executing_move_get_script(self.inner.value().reference).as_ref() } - } - fn number_of_targets(&self) -> usize { - unsafe { executing_move_get_number_of_targets(self.inner.value().reference) } - } - fn is_pokemon_target(&self, pokemon: &Pokemon) -> bool { - unsafe { - executing_move_is_pokemon_target( - self.inner.value().reference, - pokemon.reference().into(), - ) - } - } - fn get_hit_data(&self, pokemon: &Pokemon, hit: u8) -> HitData { - unsafe { - Rc::new( - executing_move_get_hit_data( - self.inner.value().reference, - pokemon.reference().into(), - hit, - ) - .get_value() - .unwrap(), - ) - } - } -} - +#[cfg_attr(feature = "mock_data", mockall::automock)] pub trait HitDataTrait { fn is_critical(&self) -> bool; fn base_power(&self) -> u8; @@ -117,96 +33,196 @@ pub trait HitDataTrait { fn fail(&self); } +pub type ExecutingMove = Rc; +#[cfg(feature = "mock_data")] +pub type MockExecutingMove = MockExecutingMoveTrait; + pub type HitData = Rc; - -#[derive(Clone)] -pub struct HitDataImpl { - reference: ExternRef, -} +#[cfg(feature = "mock_data")] +pub type MockHitData = MockHitDataTrait; #[cfg(not(feature = "mock_data"))] -impl HitDataTrait for HitDataImpl { - fn is_critical(&self) -> bool { - unsafe { hit_data_is_critical(self.reference) } - } - fn base_power(&self) -> u8 { - unsafe { hit_data_get_base_power(self.reference) } - } - fn effectiveness(&self) -> f32 { - unsafe { hit_data_get_effectiveness(self.reference) } - } - fn damage(&self) -> u32 { - unsafe { hit_data_get_damage(self.reference) } - } - fn move_type(&self) -> u8 { - unsafe { hit_data_get_move_type(self.reference) } - } - fn has_failed(&self) -> bool { - unsafe { hit_data_is_critical(self.reference) } - } - - fn set_critical(&self, critical: bool) { - unsafe { hit_data_set_critical(self.reference, critical) } - } - fn set_effectiveness(&self, effectiveness: f32) { - unsafe { hit_data_set_effectiveness(self.reference, effectiveness) } - } - fn set_damage(&self, damage: u32) { - unsafe { hit_data_set_damage(self.reference, damage) } - } - fn set_move_type(&self, move_type: u8) { - unsafe { hit_data_set_move_type(self.reference, move_type) } - } - fn fail(&self) { - unsafe { hit_data_fail(self.reference) } - } -} +pub use implementation::*; #[cfg(not(feature = "mock_data"))] -impl ExternalReferenceType for ExecutingMoveImpl { - fn from_extern_value(reference: ExternRef) -> Self { - Self::new(reference) +mod implementation { + use super::*; + + #[derive(Clone)] + pub struct ExecutingMoveImpl { + inner: Temporary, + } + + struct ExecutingMoveInner { + reference: ExternRef, + number_of_hits: CachedValue, + user: CachedValue, + chosen_move: CachedValue, + use_move: CachedValue, + } + + impl ExecutingMoveImpl { + #[cfg(not(feature = "mock_data"))] + pub(crate) fn new(reference: ExternRef) -> Self { + Self { + inner: Temporary::new( + reference.get_internal_index(), + ExecutingMoveInner { + reference, + number_of_hits: cached_value!({ + executing_move_get_number_of_hits(reference) + }), + user: cached_value!({ + executing_move_get_user(reference).get_value().unwrap() + }), + chosen_move: cached_value!({ + executing_move_get_chosen_move(reference) + .get_value() + .unwrap() + }), + use_move: cached_value!({ + executing_move_get_use_move(reference).get_value().unwrap() + }), + }, + ), + } + } + } + + #[cfg(not(feature = "mock_data"))] + impl ExecutingMoveTrait for ExecutingMoveImpl { + fn number_of_hits(&self) -> u8 { + self.inner.value().number_of_hits.value() + } + fn user(&self) -> Pokemon { + Rc::new(self.inner.value().user.value()) + } + fn chosen_move(&self) -> LearnedMove { + self.inner.value().chosen_move.value() + } + fn use_move(&self) -> MoveData { + self.inner.value().use_move.value() + } + fn move_script(&self) -> Option<&dyn Script> { + unsafe { executing_move_get_script(self.inner.value().reference).as_ref() } + } + fn number_of_targets(&self) -> usize { + unsafe { executing_move_get_number_of_targets(self.inner.value().reference) } + } + fn is_pokemon_target(&self, pokemon: &Pokemon) -> bool { + unsafe { + executing_move_is_pokemon_target( + self.inner.value().reference, + pokemon.reference().into(), + ) + } + } + fn get_hit_data(&self, pokemon: &Pokemon, hit: u8) -> HitData { + unsafe { + Rc::new( + executing_move_get_hit_data( + self.inner.value().reference, + pokemon.reference().into(), + hit, + ) + .get_value() + .unwrap(), + ) + } + } + } + + #[derive(Clone)] + pub struct HitDataImpl { + reference: ExternRef, + } + + #[cfg(not(feature = "mock_data"))] + impl HitDataTrait for HitDataImpl { + fn is_critical(&self) -> bool { + unsafe { hit_data_is_critical(self.reference) } + } + fn base_power(&self) -> u8 { + unsafe { hit_data_get_base_power(self.reference) } + } + fn effectiveness(&self) -> f32 { + unsafe { hit_data_get_effectiveness(self.reference) } + } + fn damage(&self) -> u32 { + unsafe { hit_data_get_damage(self.reference) } + } + fn move_type(&self) -> u8 { + unsafe { hit_data_get_move_type(self.reference) } + } + fn has_failed(&self) -> bool { + unsafe { hit_data_is_critical(self.reference) } + } + + fn set_critical(&self, critical: bool) { + unsafe { hit_data_set_critical(self.reference, critical) } + } + fn set_effectiveness(&self, effectiveness: f32) { + unsafe { hit_data_set_effectiveness(self.reference, effectiveness) } + } + fn set_damage(&self, damage: u32) { + unsafe { hit_data_set_damage(self.reference, damage) } + } + fn set_move_type(&self, move_type: u8) { + unsafe { hit_data_set_move_type(self.reference, move_type) } + } + fn fail(&self) { + unsafe { hit_data_fail(self.reference) } + } + } + + #[cfg(not(feature = "mock_data"))] + impl ExternalReferenceType for ExecutingMoveImpl { + fn from_extern_value(reference: ExternRef) -> Self { + Self::new(reference) + } + } + + #[cfg(not(feature = "mock_data"))] + impl ExternalReferenceType for HitDataImpl { + fn from_extern_value(reference: ExternRef) -> Self { + Self { reference } + } + } + + #[cfg(not(feature = "mock_data"))] + extern "wasm" { + fn executing_move_get_number_of_targets(r: ExternRef) -> usize; + fn executing_move_get_number_of_hits(r: ExternRef) -> u8; + fn executing_move_get_user(r: ExternRef) -> ExternRef; + fn executing_move_get_chosen_move( + r: ExternRef, + ) -> ExternRef; + fn executing_move_get_use_move(r: ExternRef) -> ExternRef; + #[allow(improper_ctypes)] + fn executing_move_get_script(r: ExternRef) -> *const dyn Script; + + fn executing_move_is_pokemon_target( + r: ExternRef, + pokemon: ExternRef, + ) -> bool; + fn executing_move_get_hit_data( + r: ExternRef, + target: ExternRef, + hit: u8, + ) -> ExternRef; + + fn hit_data_is_critical(r: ExternRef) -> bool; + fn hit_data_get_base_power(r: ExternRef) -> u8; + fn hit_data_get_effectiveness(r: ExternRef) -> f32; + fn hit_data_get_damage(r: ExternRef) -> u32; + fn hit_data_get_move_type(r: ExternRef) -> u8; + fn hit_data_has_failed(r: ExternRef) -> bool; + + fn hit_data_set_critical(r: ExternRef, critical: bool); + fn hit_data_set_base_power(r: ExternRef, power: u8); + fn hit_data_set_effectiveness(r: ExternRef, effectiveness: f32); + fn hit_data_set_damage(r: ExternRef, damage: u32); + fn hit_data_set_move_type(r: ExternRef, move_type: u8); + fn hit_data_fail(r: ExternRef); } } - -#[cfg(not(feature = "mock_data"))] -impl ExternalReferenceType for HitDataImpl { - fn from_extern_value(reference: ExternRef) -> Self { - Self { reference } - } -} - -#[cfg(not(feature = "mock_data"))] -extern "wasm" { - fn executing_move_get_number_of_targets(r: ExternRef) -> usize; - fn executing_move_get_number_of_hits(r: ExternRef) -> u8; - fn executing_move_get_user(r: ExternRef) -> ExternRef; - fn executing_move_get_chosen_move(r: ExternRef) -> ExternRef; - fn executing_move_get_use_move(r: ExternRef) -> ExternRef; - #[allow(improper_ctypes)] - fn executing_move_get_script(r: ExternRef) -> *const dyn Script; - - fn executing_move_is_pokemon_target( - r: ExternRef, - pokemon: ExternRef, - ) -> bool; - fn executing_move_get_hit_data( - r: ExternRef, - target: ExternRef, - hit: u8, - ) -> ExternRef; - - fn hit_data_is_critical(r: ExternRef) -> bool; - fn hit_data_get_base_power(r: ExternRef) -> u8; - fn hit_data_get_effectiveness(r: ExternRef) -> f32; - fn hit_data_get_damage(r: ExternRef) -> u32; - fn hit_data_get_move_type(r: ExternRef) -> u8; - fn hit_data_has_failed(r: ExternRef) -> bool; - - fn hit_data_set_critical(r: ExternRef, critical: bool); - fn hit_data_set_base_power(r: ExternRef, power: u8); - fn hit_data_set_effectiveness(r: ExternRef, effectiveness: f32); - fn hit_data_set_damage(r: ExternRef, damage: u32); - fn hit_data_set_move_type(r: ExternRef, move_type: u8); - fn hit_data_fail(r: ExternRef); -} diff --git a/pkmn_lib_interface/src/app_interface/dynamic_data/party.rs b/pkmn_lib_interface/src/app_interface/dynamic_data/party.rs index 3619007..1d01beb 100755 --- a/pkmn_lib_interface/src/app_interface/dynamic_data/party.rs +++ b/pkmn_lib_interface/src/app_interface/dynamic_data/party.rs @@ -1,4 +1,6 @@ -use crate::app_interface::{Pokemon, PokemonImpl}; +use crate::app_interface::Pokemon; +#[cfg(not(feature = "mock_data"))] +use crate::app_interface::PokemonImpl; use crate::{ExternRef, ExternalReferenceType}; use alloc::rc::Rc; diff --git a/pkmn_lib_interface/src/app_interface/dynamic_data/pokemon.rs b/pkmn_lib_interface/src/app_interface/dynamic_data/pokemon.rs index 7ac6316..8fe2586 100755 --- a/pkmn_lib_interface/src/app_interface/dynamic_data/pokemon.rs +++ b/pkmn_lib_interface/src/app_interface/dynamic_data/pokemon.rs @@ -1,48 +1,17 @@ -use crate::app_interface::ability::{Ability, AbilityIndex}; use crate::app_interface::{ - 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_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, + AbilityImpl, AbilityIndex, Battle, BattleSide, ClampedStatisticSet, DynamicLibrary, Form, + Gender, Item, LearnedMove, LevelInt, Nature, Species, Statistic, StatisticSet, TypeIdentifier, + WithVolatile, }; +use crate::handling::Script; use alloc::boxed::Box; use alloc::rc::Rc; -use core::any::Any; -use cstr_core::{c_char, CString}; +use cstr_core::c_char; -struct PokemonInner { - reference: ExternRef, - library: CachedValue, - // We cache the reference to the data, not the values stored inside, which are dynamic. - flat_stats: CachedValue>>, - // We cache the reference to the data, not the values stored inside, which are dynamic. - stat_boosts: CachedValue>, - // We cache the reference to the data, not the values stored inside, which are dynamic. - boosted_stats: CachedValue>>, - // We cache the reference to the data, not the values stored inside, which are dynamic. - individual_values: CachedValue>, - // We cache the reference to the data, not the values stored inside, which are dynamic. - effort_values: CachedValue>, -} +#[cfg(not(feature = "mock_data"))] +pub use implementation::*; -pub type Pokemon = Rc; -#[cfg(feature = "mock_data")] -pub type MockPokemon = MockPokemonTrait; - -#[derive(Clone)] -pub struct PokemonImpl { - inner: Rc, -} - -#[cfg_attr(feature = "mock_data", mockall::automock)] -pub trait PokemonTrait { +pub trait PokemonTrait: WithVolatile { fn reference(&self) -> u32; fn species(&self) -> Species; @@ -95,189 +64,437 @@ pub trait PokemonTrait { fn set_weight(&self, weight: f32); fn clear_status(&self); fn battle_side(&self) -> BattleSide; - fn add_volatile(&self, script: Box) -> &dyn Script; - fn add_volatile_by_name(&self, script_name: &str) -> &dyn Script; - fn remove_volatile(&self, script: &dyn Script); - // fn get_volatile(&self, script_name: &str) -> Option<&'static T> - // where - // T: Script + 'static; - fn equals(&self, other: &Pokemon) -> bool; } +pub type Pokemon = Rc; + +/// A source of damage. This should be as unique as possible. +#[derive(Debug, Clone, Copy)] +#[repr(u8)] +pub enum DamageSource { + /// The damage is done by a move. + MoveDamage = 0, + /// The damage is done by something else. + Misc = 1, + /// The damage is done because of struggling. + Struggle = 2, +} + #[cfg(not(feature = "mock_data"))] -impl PokemonTrait for PokemonImpl { - fn reference(&self) -> u32 { - self.reference().get_internal_index() +mod implementation { + use super::*; + use cstr_core::CString; + + use crate::app_interface::{BattleImpl, ItemImpl, StatisticSetImpl}; + use crate::handling::cached_value::CachedValue; + use crate::handling::Cacheable; + use crate::{ + cached_value, cached_value_getters, wasm_optional_reference_getters_extern, + wasm_optional_reference_getters_funcs, wasm_reference_getters_extern, + wasm_reference_getters_funcs, wasm_value_getters_extern, wasm_value_getters_funcs, + DynamicLibrary, ExternRef, ExternalReferenceType, Script, ScriptPtr, TypeIdentifier, + }; + + struct PokemonInner { + reference: ExternRef, + library: CachedValue, + // We cache the reference to the data, not the values stored inside, which are dynamic. + flat_stats: CachedValue>>, + // We cache the reference to the data, not the values stored inside, which are dynamic. + stat_boosts: CachedValue>, + // We cache the reference to the data, not the values stored inside, which are dynamic. + boosted_stats: CachedValue>>, + // We cache the reference to the data, not the values stored inside, which are dynamic. + individual_values: CachedValue>, + // We cache the reference to the data, not the values stored inside, which are dynamic. + effort_values: CachedValue>, } - cached_value_getters! { - fn library(&self) -> DynamicLibrary; - fn flat_stats(&self) -> StatisticSet; - fn stat_boosts(&self) -> ClampedStatisticSet; - fn boosted_stats(&self) -> StatisticSet; - fn individual_values(&self) -> ClampedStatisticSet; - fn effort_values(&self) -> ClampedStatisticSet; + #[derive(Clone)] + pub struct PokemonImpl { + inner: Rc, } - fn battle(&self) -> Option { - unsafe { - let b = pokemon_get_battle(self.reference()).get_value(); - if let Some(b) = b { - Some(Rc::new(b)) - } else { - None + 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; + fn stat_boosts(&self) -> ClampedStatisticSet; + fn boosted_stats(&self) -> StatisticSet; + fn individual_values(&self) -> ClampedStatisticSet; + fn effort_values(&self) -> ClampedStatisticSet; + } + + fn battle(&self) -> Option { + 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 { - 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 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 { + 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 { - unsafe { - let i = pokemon_remove_held_item(self.inner.reference).get_value(); - if let Some(i) = i { - Some(Rc::new(i)) - } else { - None + fn remove_held_item(&self) -> Option { + 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); + fn consume_held_item(&self) -> bool { + unsafe { pokemon_consume_held_item(self.inner.reference) } } - false - } - fn get_learned_move(&self, index: usize) -> Option { - 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 max_health(&self) -> u32 { + self.boosted_stats().hp() } - } - fn ability_script(&self) -> Option<&Box> { - 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 get_type(&self, index: usize) -> u8 { + unsafe { pokemon_get_type(self.inner.reference, index) } } - } - fn change_form(&self, form: Form) { - unsafe { - pokemon_change_form(self.inner.reference, form.reference()); + fn has_type(&self, type_identifier: TypeIdentifier) -> bool { + unsafe { pokemon_has_type(self.inner.reference, type_identifier.into()) } } - } - 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 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 clear_status(&self) { - unsafe { - pokemon_clear_status(self.reference()); + fn get_learned_move(&self, index: usize) -> Option { + unsafe { pokemon_get_learned_move(self.inner.reference, index).get_value() } } - } - 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 { - 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; - fn display_form(&self) -> Option
; - } - - fn held_item(&self) -> Option { - unsafe { - let i = pokemon_get_held_item(self.inner.reference).get_value(); - if let Some(i) = i { - Some(Rc::new(i)) - } else { - None + 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> { + 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 remove_volatile(&self, script: &dyn Script) { - unsafe { - let name = CString::new(script.get_name()).unwrap(); - pokemon_remove_volatile(self.inner.reference, name.as_ptr()); + 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; + fn display_form(&self) -> Option; + } + + fn held_item(&self) -> Option { + unsafe { + let i = pokemon_get_held_item(self.inner.reference).get_value(); + if let Some(i) = i { + Some(Rc::new(i)) + } else { + None + } + } + } + + #[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"))] - wasm_value_getters_funcs! { - Pokemon, + impl WithVolatile for PokemonImpl { + fn has_volatile(&self, script_name: &str) -> bool { + unsafe { + let ptr = CString::new(script_name).unwrap(); + pokemon_has_volatile(self.inner.reference, ptr.as_ptr()) + } + } + + fn add_volatile(&self, script: Box) -> &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() + } + } + + 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()); + } + } + + fn get_volatile_script(&self, script_name: &str) -> Option<&dyn Script> { + unsafe { + let script_name = CString::new(script_name).unwrap(); + pokemon_get_volatile(self.inner.reference, script_name.as_ptr()).val() + } + } + } + + #[cfg(not(feature = "mock_data"))] + impl PokemonImpl { + pub(crate) fn new(reference: ExternRef) -> Self { + Self::from_ref(reference, &|reference| Self { + inner: Rc::new(PokemonInner { + reference, + library: cached_value!({ pokemon_get_library(reference).get_value().unwrap() }), + flat_stats: cached_value!({ + 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!({ + Rc::new(pokemon_get_boosted_stats(reference).get_value().unwrap()) + }), + individual_values: cached_value!({ + pokemon_get_individual_values(reference) + .get_value() + .unwrap() + }), + effort_values: cached_value!({ + pokemon_get_effort_values(reference).get_value().unwrap() + }), + }), + }) + } + + pub(crate) fn reference(&self) -> ExternRef { + self.inner.reference + } + } + + #[cfg(not(feature = "mock_data"))] + wasm_reference_getters_extern! { + PokemonImpl, Pokemon, + pub fn species(&self) -> Species; + pub fn form(&self) -> Form; + pub fn active_ability(&self) -> AbilityImpl; + pub fn nature(&self) -> Nature; + } + + #[cfg(not(feature = "mock_data"))] + wasm_optional_reference_getters_extern! { + PokemonImpl, Pokemon, + pub fn display_species(&self) -> Option; + pub fn display_form(&self) -> Option; + pub fn held_item(&self) -> Option; + pub fn battle(&self) -> Option; + } + + #[cfg(not(feature = "mock_data"))] + wasm_value_getters_extern! { + PokemonImpl, Pokemon, + pub fn level(&self) -> LevelInt; + pub fn experience(&self) -> u32; + pub fn unique_identifier(&self) -> u32; + pub fn gender(&self) -> Gender; + pub fn coloring(&self) -> u8; + pub fn current_health(&self) -> u32; + pub fn weight(&self) -> f32; + pub fn height(&self) -> f32; + pub fn nickname(&self) -> *const c_char; + pub fn real_ability(&self) -> AbilityIndex; + pub fn types_length(&self) -> usize; + pub fn battle_side_index(&self) -> u8; + pub fn battle_index(&self) -> u8; + pub fn is_ability_overriden(&self) -> u8; + pub fn allowed_experience_gain(&self) -> bool; + pub fn is_usable(&self) -> bool; + } + + impl PartialEq for PokemonImpl { + fn eq(&self, other: &Self) -> bool { + self.inner.reference == other.inner.reference + } + } + + crate::handling::cacheable::cacheable!(PokemonImpl); + + #[cfg(not(feature = "mock_data"))] + impl ExternalReferenceType for PokemonImpl { + fn from_extern_value(reference: ExternRef) -> Self { + Self::new(reference) + } + } + + #[cfg(not(feature = "mock_data"))] + extern "wasm" { + fn pokemon_get_library(r: ExternRef) -> ExternRef; + fn pokemon_get_flat_stats(r: ExternRef) -> ExternRef>; + fn pokemon_get_stat_boosts(r: ExternRef) + -> ExternRef>; + fn pokemon_get_boosted_stats(r: ExternRef) + -> ExternRef>; + fn pokemon_get_individual_values( + r: ExternRef, + ) -> ExternRef>; + fn pokemon_get_effort_values( + r: ExternRef, + ) -> ExternRef>; + fn pokemon_has_held_item(r: ExternRef, name: *const c_char) -> bool; + fn pokemon_set_held_item( + r: ExternRef, + item: ExternRef, + ) -> ExternRef; + fn pokemon_remove_held_item(r: ExternRef) -> ExternRef; + fn pokemon_consume_held_item(r: ExternRef) -> bool; + fn pokemon_get_type(r: ExternRef, index: usize) -> u8; + fn pokemon_has_type(r: ExternRef, identifier: u8) -> bool; + fn pokemon_get_learned_move( + r: ExternRef, + index: usize, + ) -> ExternRef; + fn pokemon_change_stat_boost( + r: ExternRef, + tat: Statistic, + diff_amount: i8, + self_inflicted: bool, + ) -> bool; + #[allow(improper_ctypes)] + fn pokemon_get_ability_script(r: ExternRef) -> *const Box; + fn pokemon_change_species( + r: ExternRef, + species: ExternRef, + form: ExternRef, + ); + fn pokemon_change_form(r: ExternRef, form: ExternRef); + fn pokemon_damage(r: ExternRef, damage: u32, source: DamageSource); + fn pokemon_heal(r: ExternRef, amount: u32, allow_revive: bool) -> bool; + fn pokemon_set_weight(r: ExternRef, weight: f32); + fn pokemon_clear_status(r: ExternRef); + + fn pokemon_add_volatile_by_name( + r: ExternRef, + name: *const c_char, + ) -> ScriptPtr; + fn pokemon_add_volatile(r: ExternRef, script: ScriptPtr) -> ScriptPtr; + fn pokemon_has_volatile(r: ExternRef, name: *const c_char) -> bool; + fn pokemon_remove_volatile(r: ExternRef, name: *const c_char); + fn pokemon_get_volatile(r: ExternRef, name: *const c_char) -> ScriptPtr; + } +} + +#[cfg(feature = "mock_data")] +mockall::mock!( + pub Pokemon {} + impl PokemonTrait for Pokemon { + 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; + fn display_form(&self) -> Option; + fn held_item(&self) -> Option; + fn battle(&self) -> Option; fn level(&self) -> LevelInt; fn experience(&self) -> u32; fn unique_identifier(&self) -> u32; @@ -294,172 +511,51 @@ impl PokemonTrait for PokemonImpl { 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()) + fn library(&self) -> DynamicLibrary; + fn flat_stats(&self) -> StatisticSet; + fn stat_boosts(&self) -> ClampedStatisticSet; + fn boosted_stats(&self) -> StatisticSet; + fn individual_values(&self) -> ClampedStatisticSet; + fn effort_values(&self) -> ClampedStatisticSet; + fn has_held_item(&self, name: &str) -> bool; + fn set_held_item(&self, item: &Item) -> Option; + fn remove_held_item(&self) -> Option; + 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; + fn change_stat_boost(&self, stat: Statistic, diff_amount: i8, self_inflicted: bool) -> bool; + fn ability_script<'a>(&'a self) -> Option<&'a Box>; + 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 equals(&self, other: &Pokemon) -> bool; + } +); + +#[cfg(feature = "mock_data")] +impl WithVolatile for MockPokemon { + fn has_volatile(&self, script_name: &str) -> bool { + unimplemented!() + } + fn add_volatile(&self, script: Box) -> &dyn Script { + unimplemented!() + } + fn add_volatile_by_name(&self, script_name: &str) -> &dyn Script { + unimplemented!() + } + fn remove_volatile<'a, 'b>(&'a self, script: &dyn Script) { + unimplemented!() + } + fn get_volatile_script<'a>(&'a self, script_name: &str) -> Option<&'a dyn Script> { + unimplemented!() } } - -#[cfg(not(feature = "mock_data"))] -impl PokemonImpl { - pub(crate) fn new(reference: ExternRef) -> Self { - Self::from_ref(reference, &|reference| Self { - inner: Rc::new(PokemonInner { - reference, - library: cached_value!({ pokemon_get_library(reference).get_value().unwrap() }), - flat_stats: cached_value!({ - 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!({ - Rc::new(pokemon_get_boosted_stats(reference).get_value().unwrap()) - }), - individual_values: cached_value!({ - pokemon_get_individual_values(reference) - .get_value() - .unwrap() - }), - effort_values: cached_value!({ - pokemon_get_effort_values(reference).get_value().unwrap() - }), - }), - }) - } - - pub(crate) fn reference(&self) -> ExternRef { - self.inner.reference - } - - fn get_volatile(&self, script_name: &str) -> Option<&T> - where - T: Script + 'static, - { - unsafe { - let script_name = CString::new(script_name).unwrap(); - let s = pokemon_get_volatile(self.inner.reference, script_name.as_ptr()).val(); - if let Some(s) = s { - Some(s.as_any().downcast_ref().unwrap()) - } else { - None - } - } - } -} - -#[cfg(not(feature = "mock_data"))] -wasm_reference_getters_extern! { - PokemonImpl, Pokemon, - pub fn species(&self) -> Species; - pub fn form(&self) -> Form; - pub fn active_ability(&self) -> AbilityImpl; - pub fn nature(&self) -> Nature; -} - -#[cfg(not(feature = "mock_data"))] -wasm_optional_reference_getters_extern! { - PokemonImpl, Pokemon, - pub fn display_species(&self) -> Option; - pub fn display_form(&self) -> Option; - pub fn held_item(&self) -> Option; - pub fn battle(&self) -> Option; -} - -#[cfg(not(feature = "mock_data"))] -wasm_value_getters_extern! { - PokemonImpl, Pokemon, - pub fn level(&self) -> LevelInt; - pub fn experience(&self) -> u32; - pub fn unique_identifier(&self) -> u32; - pub fn gender(&self) -> Gender; - pub fn coloring(&self) -> u8; - pub fn current_health(&self) -> u32; - pub fn weight(&self) -> f32; - pub fn height(&self) -> f32; - pub fn nickname(&self) -> *const c_char; - pub fn real_ability(&self) -> AbilityIndex; - pub fn types_length(&self) -> usize; - pub fn battle_side_index(&self) -> u8; - pub fn battle_index(&self) -> u8; - pub fn is_ability_overriden(&self) -> u8; - pub fn allowed_experience_gain(&self) -> bool; - pub fn is_usable(&self) -> bool; -} - -impl PartialEq for PokemonImpl { - fn eq(&self, other: &Self) -> bool { - self.inner.reference == other.inner.reference - } -} - -/// A source of damage. This should be as unique as possible. -#[derive(Debug, Clone, Copy)] -#[repr(u8)] -pub enum DamageSource { - /// The damage is done by a move. - MoveDamage = 0, - /// The damage is done by something else. - Misc = 1, - /// The damage is done because of struggling. - Struggle = 2, -} - -crate::handling::cacheable::cacheable!(PokemonImpl); - -#[cfg(not(feature = "mock_data"))] -impl ExternalReferenceType for PokemonImpl { - fn from_extern_value(reference: ExternRef) -> Self { - Self::new(reference) - } -} - -#[cfg(not(feature = "mock_data"))] -extern "wasm" { - fn pokemon_get_library(r: ExternRef) -> ExternRef; - fn pokemon_get_flat_stats(r: ExternRef) -> ExternRef>; - fn pokemon_get_stat_boosts(r: ExternRef) -> ExternRef>; - fn pokemon_get_boosted_stats(r: ExternRef) -> ExternRef>; - fn pokemon_get_individual_values( - r: ExternRef, - ) -> ExternRef>; - fn pokemon_get_effort_values(r: ExternRef) -> ExternRef>; - fn pokemon_has_held_item(r: ExternRef, name: *const c_char) -> bool; - fn pokemon_set_held_item( - r: ExternRef, - item: ExternRef, - ) -> ExternRef; - fn pokemon_remove_held_item(r: ExternRef) -> ExternRef; - fn pokemon_consume_held_item(r: ExternRef) -> bool; - fn pokemon_get_type(r: ExternRef, index: usize) -> u8; - fn pokemon_has_type(r: ExternRef, identifier: u8) -> bool; - fn pokemon_get_learned_move(r: ExternRef, index: usize) -> ExternRef; - fn pokemon_change_stat_boost( - r: ExternRef, - tat: Statistic, - diff_amount: i8, - self_inflicted: bool, - ) -> bool; - #[allow(improper_ctypes)] - fn pokemon_get_ability_script(r: ExternRef) -> *const Box; - fn pokemon_change_species( - r: ExternRef, - species: ExternRef, - form: ExternRef, - ); - fn pokemon_change_form(r: ExternRef, form: ExternRef); - fn pokemon_damage(r: ExternRef, damage: u32, source: DamageSource); - fn pokemon_heal(r: ExternRef, amount: u32, allow_revive: bool) -> bool; - fn pokemon_set_weight(r: ExternRef, weight: f32); - fn pokemon_clear_status(r: ExternRef); - - fn pokemon_add_volatile_by_name(r: ExternRef, name: *const c_char) -> ScriptPtr; - fn pokemon_add_volatile(r: ExternRef, script: ScriptPtr) -> ScriptPtr; - fn pokemon_has_volatile(r: ExternRef, name: *const c_char) -> bool; - fn pokemon_remove_volatile(r: ExternRef, name: *const c_char); - fn pokemon_get_volatile(r: ExternRef, name: *const c_char) -> ScriptPtr; -} diff --git a/pkmn_lib_interface/src/app_interface/dynamic_data/turn_choices.rs b/pkmn_lib_interface/src/app_interface/dynamic_data/turn_choices.rs index 2f11e56..5cfbd60 100755 --- a/pkmn_lib_interface/src/app_interface/dynamic_data/turn_choices.rs +++ b/pkmn_lib_interface/src/app_interface/dynamic_data/turn_choices.rs @@ -1,4 +1,6 @@ -use crate::app_interface::{LearnedMove, Pokemon, PokemonImpl}; +#[cfg(not(feature = "mock_data"))] +use crate::app_interface::PokemonImpl; +use crate::app_interface::{LearnedMove, Pokemon}; use crate::handling::cached_value::CachedValue; use crate::handling::temporary::Temporary; use crate::ExternRef; @@ -14,6 +16,7 @@ pub trait BaseTurnChoiceDataTrait { fn fail(&self); } +#[cfg(not(feature = "mock_data"))] struct BaseTurnChoiceDataImpl { reference: ExternRef, user: CachedValue>, diff --git a/pkmn_lib_interface/src/app_interface/dynamic_data/with_volatile.rs b/pkmn_lib_interface/src/app_interface/dynamic_data/with_volatile.rs index 58e9927..30744e4 100644 --- a/pkmn_lib_interface/src/app_interface/dynamic_data/with_volatile.rs +++ b/pkmn_lib_interface/src/app_interface/dynamic_data/with_volatile.rs @@ -3,7 +3,8 @@ use alloc::boxed::Box; pub trait WithVolatile { fn has_volatile(&self, script_name: &str) -> bool; - fn add_volatile<'a, 'b>(&'a self, script: Box) -> &'b dyn Script; + fn add_volatile(&self, script: Box) -> &dyn Script; + fn add_volatile_by_name(&self, script_name: &str) -> &dyn Script; fn remove_volatile(&self, script: &dyn Script); fn get_volatile_script(&self, script_name: &str) -> Option<&dyn Script>; } diff --git a/pkmn_lib_interface/src/app_interface/static_data/species.rs b/pkmn_lib_interface/src/app_interface/static_data/species.rs index 2bf980b..62985b3 100755 --- a/pkmn_lib_interface/src/app_interface/static_data/species.rs +++ b/pkmn_lib_interface/src/app_interface/static_data/species.rs @@ -10,7 +10,7 @@ use alloc::vec::Vec; use spin::RwLock; #[repr(u8)] -#[derive(Eq, PartialEq)] +#[derive(Eq, PartialEq, Debug)] pub enum Gender { Male = 0, Female = 1, @@ -18,6 +18,7 @@ pub enum Gender { } #[repr(u8)] +#[derive(Eq, PartialEq, Debug)] pub enum Statistic { HP = 0, Attack = 1, diff --git a/pkmn_lib_interface/src/handling/script.rs b/pkmn_lib_interface/src/handling/script.rs index 2c8e362..2ddea9b 100755 --- a/pkmn_lib_interface/src/handling/script.rs +++ b/pkmn_lib_interface/src/handling/script.rs @@ -1,7 +1,6 @@ use crate::app_interface::list::ImmutableList; use crate::app_interface::{ - Battle, BattleImpl, DamageSource, DynamicLibrary, EffectParameter, ExecutingMove, Item, - Pokemon, Statistic, + Battle, DamageSource, DynamicLibrary, EffectParameter, ExecutingMove, Item, Pokemon, Statistic, }; use crate::handling::ScriptCapabilities; use crate::{ExternRef, ExternalReferenceType, ScriptPtr, StringKey, TurnChoice, TypeIdentifier}; diff --git a/pkmn_lib_interface/src/lib.rs b/pkmn_lib_interface/src/lib.rs index c161b9a..6d4c523 100755 --- a/pkmn_lib_interface/src/lib.rs +++ b/pkmn_lib_interface/src/lib.rs @@ -23,10 +23,13 @@ extern crate dlmalloc; static ALLOC: dlmalloc::GlobalDlmalloc = dlmalloc::GlobalDlmalloc {}; use crate::app_interface::list::ImmutableList; +#[cfg(not(feature = "mock_data"))] +use crate::app_interface::{BattleImpl, ExecutingMoveImpl, PokemonImpl}; use crate::app_interface::{ - BattleImpl, DamageSource, DynamicLibrary, EffectParameter, ExecutingMoveImpl, Item, ItemImpl, - Pokemon, PokemonImpl, Statistic, StringKey, TurnChoice, TypeIdentifier, + DamageSource, DynamicLibrary, EffectParameter, Item, ItemImpl, Pokemon, Statistic, StringKey, + TurnChoice, TypeIdentifier, }; + pub(crate) use crate::handling::extern_ref::*; use crate::handling::ffi_array::FFIArray; #[cfg(not(feature = "mock_data"))] diff --git a/pkmn_lib_interface/src/utils.rs b/pkmn_lib_interface/src/utils.rs index 1b2aa49..eddafb5 100755 --- a/pkmn_lib_interface/src/utils.rs +++ b/pkmn_lib_interface/src/utils.rs @@ -1,4 +1,5 @@ use alloc::alloc::alloc; +use alloc::string::String; use core::alloc::Layout; #[cfg(not(feature = "mock_data"))] use core::panic::PanicInfo; @@ -22,9 +23,9 @@ pub fn print_raw(s: &[u8]) { } #[cfg(feature = "mock_data")] -pub fn print_raw(s: CString) { +pub fn print_raw(s: &[u8]) { unsafe { - println!("{}", s.into_string().unwrap()); + println!("{}", String::from_utf8_lossy(s)); } }