From a1e13af793fe8210a95da354a3decc7172e10472 Mon Sep 17 00:00:00 2001 From: Deukhoofd Date: Wed, 4 Jan 2023 17:24:13 +0100 Subject: [PATCH] A lot of work on mocking to set up unit testing --- gen_7_scripts/Cargo.toml | 1 + gen_7_scripts/src/lib.rs | 1 + gen_7_scripts/src/moves/acrobatics.rs | 54 ++ gen_7_scripts/src/moves/acupressure.rs | 3 +- gen_7_scripts/src/moves/after_you.rs | 1 + gen_7_scripts/src/moves/assist.rs | 2 +- gen_7_scripts/src/moves/assurance.rs | 17 +- gen_7_scripts/src/moves/aurora_veil.rs | 7 +- .../src/moves/change_all_target_stats.rs | 10 +- .../src/moves/change_target_stats.rs | 2 +- gen_7_scripts/src/moves/cure_party_status.rs | 2 +- pkmn_lib_interface/Cargo.toml | 5 +- .../src/app_interface/dynamic_data/battle.rs | 141 +++-- .../dynamic_data/battle_party.rs | 35 +- .../dynamic_data/battle_random.rs | 28 +- .../app_interface/dynamic_data/battle_side.rs | 119 ++-- .../dynamic_data/choice_queue.rs | 37 +- .../dynamic_data/executing_move.rs | 164 ++++-- .../src/app_interface/dynamic_data/mod.rs | 2 + .../src/app_interface/dynamic_data/party.rs | 45 +- .../src/app_interface/dynamic_data/pokemon.rs | 543 +++++++++++------- .../dynamic_data/statistic_set.rs | 114 ++-- .../dynamic_data/turn_choices.rs | 130 +++-- .../dynamic_data/with_volatile.rs | 21 + .../src/app_interface/static_data/ability.rs | 28 +- .../data_libraries/item_library.rs | 17 +- .../src/app_interface/static_data/item.rs | 88 ++- .../src/app_interface/static_data/mod.rs | 1 + .../src/app_interface/string_key.rs | 2 +- pkmn_lib_interface/src/handling/extern_ref.rs | 43 +- pkmn_lib_interface/src/handling/mod.rs | 126 ++++ pkmn_lib_interface/src/handling/script.rs | 14 +- pkmn_lib_interface/src/lib.rs | 236 ++++---- 33 files changed, 1320 insertions(+), 719 deletions(-) create mode 100644 pkmn_lib_interface/src/app_interface/dynamic_data/with_volatile.rs diff --git a/gen_7_scripts/Cargo.toml b/gen_7_scripts/Cargo.toml index d1609a4..0f48b47 100755 --- a/gen_7_scripts/Cargo.toml +++ b/gen_7_scripts/Cargo.toml @@ -14,3 +14,4 @@ atomic_float = "0.1.0" [dev-dependencies] pkmn_lib_interface = { path = "../pkmn_lib_interface", features = ["mock_data"] } +mockall = "0.11.2" \ No newline at end of file diff --git a/gen_7_scripts/src/lib.rs b/gen_7_scripts/src/lib.rs index a1d52d6..63d844a 100755 --- a/gen_7_scripts/src/lib.rs +++ b/gen_7_scripts/src/lib.rs @@ -1,6 +1,7 @@ #![feature(inline_const)] #![feature(inline_const_pat)] #![feature(wasm_abi)] +#![feature(trait_upcasting)] #![cfg_attr(not(test), no_std)] #![allow(incomplete_features)] diff --git a/gen_7_scripts/src/moves/acrobatics.rs b/gen_7_scripts/src/moves/acrobatics.rs index 7d75b29..e5ee2a5 100755 --- a/gen_7_scripts/src/moves/acrobatics.rs +++ b/gen_7_scripts/src/moves/acrobatics.rs @@ -1,4 +1,5 @@ use crate::script; +use alloc::boxed::Box; use core::any::Any; use pkmn_lib_interface::app_interface::{ExecutingMove, Pokemon}; use pkmn_lib_interface::handling::{Script, ScriptCapabilities}; @@ -38,3 +39,56 @@ impl Script for Acrobatics { self } } + +#[cfg(test)] +mod tests { + use super::*; + use alloc::rc::Rc; + use pkmn_lib_interface::app_interface::{Item, MockExecutingMove, MockItem, MockPokemon}; + + fn mock_executing_move(has_held_item: bool) -> ExecutingMove { + let mut mv = MockExecutingMove::new(); + mv.expect_user().returning(move || { + let mut user = MockPokemon::new(); + user.expect_held_item().returning(move || { + if has_held_item { + Some(Rc::new(MockItem::new())) + } else { + None + } + }); + Rc::new(user) + }); + Rc::new(mv) + } + + #[test] + fn without_held_item_doubles_power() { + let mv = mock_executing_move(false); + + let script = Acrobatics::new(); + let mut base_power = 50u8; + script.change_base_power(mv, Rc::new(MockPokemon::new()), 0, &mut base_power); + assert_eq!(100, base_power); + } + + #[test] + fn without_held_item_does_not_overflow() { + let mv = mock_executing_move(false); + + let script = Acrobatics::new(); + let mut base_power = 200u8; + script.change_base_power(mv, Rc::new(MockPokemon::new()), 0, &mut base_power); + assert_eq!(255, base_power); + } + + #[test] + fn with_held_item_does_nothing() { + let mv = mock_executing_move(true); + + let script = Acrobatics::new(); + let mut base_power = 50u8; + script.change_base_power(mv, Rc::new(MockPokemon::new()), 0, &mut base_power); + assert_eq!(50, base_power); + } +} diff --git a/gen_7_scripts/src/moves/acupressure.rs b/gen_7_scripts/src/moves/acupressure.rs index 1dd9d05..2e9a0fc 100755 --- a/gen_7_scripts/src/moves/acupressure.rs +++ b/gen_7_scripts/src/moves/acupressure.rs @@ -1,3 +1,4 @@ +use alloc::boxed::Box; use core::any::Any; use core::mem::transmute; use pkmn_lib_interface::app_interface::{ExecutingMove, Pokemon, Statistic}; @@ -25,7 +26,7 @@ impl Script for Acupressure { } fn on_secondary_effect(&self, mv: ExecutingMove, target: Pokemon, hit: u8) { - if target == mv.user() { + if target.equals(&mv.user()) { mv.get_hit_data(&target, hit).fail(); return; } diff --git a/gen_7_scripts/src/moves/after_you.rs b/gen_7_scripts/src/moves/after_you.rs index f41c48b..2e925c0 100755 --- a/gen_7_scripts/src/moves/after_you.rs +++ b/gen_7_scripts/src/moves/after_you.rs @@ -1,3 +1,4 @@ +use alloc::boxed::Box; use core::any::Any; use pkmn_lib_interface::app_interface::{ExecutingMove, Pokemon}; use pkmn_lib_interface::handling::{Script, ScriptCapabilities}; diff --git a/gen_7_scripts/src/moves/assist.rs b/gen_7_scripts/src/moves/assist.rs index caa911f..5c8ea4c 100755 --- a/gen_7_scripts/src/moves/assist.rs +++ b/gen_7_scripts/src/moves/assist.rs @@ -14,7 +14,7 @@ impl Assist { let mon = party.get_pokemon(mon_index); if let Some(mon) = mon { // Ignore moves from the user - if mon == *user { + if mon.equals(user) { continue; } // Iterate over all moves. We make the assumption of 4 moves. diff --git a/gen_7_scripts/src/moves/assurance.rs b/gen_7_scripts/src/moves/assurance.rs index 6b7633c..3b8b990 100755 --- a/gen_7_scripts/src/moves/assurance.rs +++ b/gen_7_scripts/src/moves/assurance.rs @@ -3,7 +3,8 @@ use alloc::boxed::Box; use core::any::Any; use core::sync::atomic::{AtomicBool, Ordering}; use pkmn_lib_interface::app_interface::{ - BattleSide, DamageSource, DataLibrary, ExecutingMove, Pokemon, TurnChoice, + BattleSide, BattleSideImpl, DamageSource, DataLibrary, ExecutingMove, Pokemon, TurnChoice, + WithVolatile, }; use pkmn_lib_interface::handling::{Script, ScriptCapabilities}; @@ -25,9 +26,10 @@ impl Script for Assurance { ] } + #[cfg(not(test))] fn on_before_turn(&self, choice: TurnChoice) { if let TurnChoice::Move(data) = &choice { - let side: BattleSide = choice + let side: BattleSideImpl = choice .user() .battle() .unwrap() @@ -48,10 +50,10 @@ impl Script for Assurance { _hit: u8, base_power: &mut u8, ) { - if let Some(s) = target - .battle_side() - .get_volatile::(AssuranceData::get_const_name()) - { + if let Some(s) = pkmn_lib_interface::app_interface::get_volatile_as::( + target.battle_side().as_ref(), + AssuranceData::get_const_name(), + ) { if s.has_hit.load(Ordering::Relaxed) { *base_power *= 2; } @@ -86,8 +88,9 @@ impl Script for AssuranceData { &[ScriptCapabilities::OnEndTurn, ScriptCapabilities::OnDamage] } + #[cfg(not(test))] fn on_end_turn(&self) { - let side: BattleSide = self.get_owner().unwrap(); + let side: BattleSideImpl = self.get_owner().unwrap(); side.remove_volatile(self); } diff --git a/gen_7_scripts/src/moves/aurora_veil.rs b/gen_7_scripts/src/moves/aurora_veil.rs index a36b943..db87ee1 100644 --- a/gen_7_scripts/src/moves/aurora_veil.rs +++ b/gen_7_scripts/src/moves/aurora_veil.rs @@ -5,7 +5,9 @@ use crate::weather::hail::Hail; use alloc::boxed::Box; use core::any::Any; use core::sync::atomic::{AtomicU32, Ordering}; -use pkmn_lib_interface::app_interface::{BattleSide, ExecutingMove, MoveCategory, Pokemon}; +use pkmn_lib_interface::app_interface::{ + BattleSide, BattleSideImpl, ExecutingMove, MoveCategory, Pokemon, WithVolatile, +}; use pkmn_lib_interface::handling::ScriptCapabilities::OnEndTurn; use pkmn_lib_interface::handling::{Script, ScriptCapabilities}; @@ -63,6 +65,7 @@ impl Script for AuroraVeilEffect { &[ScriptCapabilities::ChangeIncomingDamage, OnEndTurn] } + #[cfg(not(test))] fn change_incoming_damage( &self, mv: ExecutingMove, @@ -73,7 +76,7 @@ impl Script for AuroraVeilEffect { if mv.get_hit_data(&target, hit).is_critical() { return; } - let side: BattleSide = self.get_owner().unwrap(); + let side: BattleSideImpl = self.get_owner().unwrap(); if side.has_volatile(ReflectEffect::get_const_name()) && mv.use_move().category() == MoveCategory::Physical { diff --git a/gen_7_scripts/src/moves/change_all_target_stats.rs b/gen_7_scripts/src/moves/change_all_target_stats.rs index 0b39a19..9212d08 100644 --- a/gen_7_scripts/src/moves/change_all_target_stats.rs +++ b/gen_7_scripts/src/moves/change_all_target_stats.rs @@ -45,11 +45,11 @@ impl Script for ChangeAllTargetStats { fn on_secondary_effect(&self, mv: ExecutingMove, target: Pokemon, _hit: u8) { let user = mv.user(); let amount = self.amount.load(Ordering::SeqCst); - target.change_stat_boost(Statistic::Attack, amount, user == target); - target.change_stat_boost(Statistic::Defense, amount, user == target); - target.change_stat_boost(Statistic::SpecialAttack, amount, user == target); - target.change_stat_boost(Statistic::SpecialDefense, amount, user == target); - target.change_stat_boost(Statistic::Speed, amount, user == target); + target.change_stat_boost(Statistic::Attack, amount, user.equals(&target)); + target.change_stat_boost(Statistic::Defense, amount, user.equals(&target)); + target.change_stat_boost(Statistic::SpecialAttack, amount, user.equals(&target)); + target.change_stat_boost(Statistic::SpecialDefense, amount, user.equals(&target)); + target.change_stat_boost(Statistic::Speed, amount, user.equals(&target)); } fn as_any(&self) -> &dyn Any { diff --git a/gen_7_scripts/src/moves/change_target_stats.rs b/gen_7_scripts/src/moves/change_target_stats.rs index a101cd3..970341e 100644 --- a/gen_7_scripts/src/moves/change_target_stats.rs +++ b/gen_7_scripts/src/moves/change_target_stats.rs @@ -54,7 +54,7 @@ macro_rules! change_stat_effect { target.change_stat_boost( Statistic::$stat, self.amount.load(Ordering::SeqCst), - mv.user() == target, + mv.user().equals(&target), ); } diff --git a/gen_7_scripts/src/moves/cure_party_status.rs b/gen_7_scripts/src/moves/cure_party_status.rs index dec69f1..55bec92 100644 --- a/gen_7_scripts/src/moves/cure_party_status.rs +++ b/gen_7_scripts/src/moves/cure_party_status.rs @@ -27,7 +27,7 @@ impl Script for CurePartyStatus { for index in 0..p.length() { let mon = p.get_pokemon(index); if let Some(mon) = mon { - if mon != user { + if !mon.equals(&user) { mon.clear_status(); } } diff --git a/pkmn_lib_interface/Cargo.toml b/pkmn_lib_interface/Cargo.toml index 8f58f2f..301131c 100755 --- a/pkmn_lib_interface/Cargo.toml +++ b/pkmn_lib_interface/Cargo.toml @@ -5,7 +5,7 @@ authors = ["Deukhoofd "] edition = "2021" [features] -mock_data = [] +mock_data = ["mockall"] [dependencies] cstr_core = { version = "0.2.6", features = ["nightly"]} @@ -14,7 +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"] } - -[dev-dependencies] +mockall = { version = "0.11.2", optional = true } 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 f01bca3..ef89cbe 100755 --- a/pkmn_lib_interface/src/app_interface/dynamic_data/battle.rs +++ b/pkmn_lib_interface/src/app_interface/dynamic_data/battle.rs @@ -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; + fn sides(&self) -> ImmutableList; + fn random(&self) -> BattleRandom; + fn choice_queue(&self) -> ChoiceQueue; + fn get_pokemon(&self, side: u8, index: u8) -> Option; + fn find_party_for_pokemon(&self, pokemon: &Pokemon) -> Option; + fn weather_name(&self) -> Option; + 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; + struct BattleInner { - reference: ExternRef, + reference: ExternRef, library: CachedValue, - parties: CachedValue>, - sides: CachedValue>, - random: CachedValue, - choice_queue: CachedValue, + parties: CachedValue>, + sides: CachedValue>, + random: CachedValue>, + choice_queue: CachedValue>, } #[derive(Clone)] -pub struct Battle { +pub struct BattleImpl { inner: Rc, } -impl Battle { - #[cfg(not(feature = "mock_data"))] - pub fn new(reference: ExternRef) -> Self { +#[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!({ 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; - pub fn sides(&self) -> ImmutableList; - pub fn random(&self) -> BattleRandom; - pub fn choice_queue(&self) -> ChoiceQueue; + fn library(&self) -> DynamicLibrary; + fn parties(&self) -> ImmutableList; + fn sides(&self) -> ImmutableList; + fn random(&self) -> BattleRandom; + fn choice_queue(&self) -> ChoiceQueue; } - #[cfg(not(feature = "mock_data"))] - pub fn get_pokemon(&self, side: u8, index: u8) -> Option { - 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 { + fn get_pokemon(&self, side: u8, index: u8) -> Option { 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 { - 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 + } + } } - #[cfg(not(feature = "mock_data"))] - pub fn weather_name(&self) -> Option { + fn weather_name(&self) -> Option { 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::new(reference) } @@ -100,16 +145,16 @@ impl ExternalReferenceType for Battle { #[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_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; + r: ExternRef, + mon: ExternRef, + ) -> ExternRef; - fn battle_get_weather_name(r: ExternRef) -> ExternRef; + fn battle_get_weather_name(r: ExternRef) -> ExternRef; } diff --git a/pkmn_lib_interface/src/app_interface/dynamic_data/battle_party.rs b/pkmn_lib_interface/src/app_interface/dynamic_data/battle_party.rs index 87dc1e3..addfe30 100755 --- a/pkmn_lib_interface/src/app_interface/dynamic_data/battle_party.rs +++ b/pkmn_lib_interface/src/app_interface/dynamic_data/battle_party.rs @@ -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; + struct BattlePartyInner { - reference: ExternRef, - party: CachedValue, + reference: ExternRef, + party: CachedValue>, } #[derive(Clone)] -pub struct BattleParty { +pub struct BattlePartyImpl { inner: Rc, } -impl BattleParty { - #[cfg(not(feature = "mock_data"))] - pub fn new(reference: ExternRef) -> Self { +#[cfg(not(feature = "mock_data"))] +impl BattlePartyImpl { + pub fn new(reference: ExternRef) -> 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::new(reference) } @@ -41,5 +52,5 @@ impl ExternalReferenceType for BattleParty { #[cfg(not(feature = "mock_data"))] extern "wasm" { - fn battle_party_get_party(r: ExternRef) -> ExternRef; + fn battle_party_get_party(r: ExternRef) -> ExternRef; } 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 9de7142..d528ad4 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,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; #[derive(Clone)] -pub struct BattleRandom { +pub struct BattleRandomImpl { reference: ExternRef, } -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 { reference } } @@ -29,8 +39,8 @@ impl ExternalReferenceType for BattleRandom { #[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; + 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 2c268d4..4764b29 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,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; + fn has_fled_battle(&self) -> bool; + fn is_defeated(&self) -> bool; +} + +pub type BattleSide = Rc; + struct BattleSideInner { - reference: ExternRef, + reference: ExternRef, side_index: CachedValue, pokemon_per_side: CachedValue, - battle: CachedValue, + battle: CachedValue>, } #[derive(Clone)] -pub struct BattleSide { +pub struct BattleSideImpl { inner: Rc, } -impl BattleSide { - #[cfg(not(feature = "mock_data"))] +#[cfg(not(feature = "mock_data"))] +impl BattleSideImpl { pub fn new(reference: ExternRef) -> 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 { - unsafe { battleside_get_pokemon(self.inner.reference, index).get_value() } + fn get_pokemon(&self, index: usize) -> Option { + 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) -> &'b dyn Script { + fn add_volatile<'a, 'b>(&'a self, script: Box) -> &'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(&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::new(reference) } @@ -104,14 +119,18 @@ impl ExternalReferenceType for BattleSide { #[cfg(not(feature = "mock_data"))] extern "wasm" { - fn battleside_get_side_index(r: ExternRef) -> u8; - fn battleside_get_pokemon_per_side(r: ExternRef) -> u8; - fn battleside_get_battle(r: ExternRef) -> ExternRef; - fn battleside_get_pokemon(r: ExternRef, index: usize) -> ExternRef; + fn battleside_get_side_index(r: ExternRef) -> u8; + fn battleside_get_pokemon_per_side(r: ExternRef) -> u8; + fn battleside_get_battle(r: ExternRef) -> ExternRef; + fn battleside_get_pokemon(r: ExternRef, index: usize) + -> ExternRef; - fn battleside_add_volatile_by_name(r: ExternRef, name: *const c_char) -> ScriptPtr; - fn battleside_add_volatile(r: ExternRef, script: ScriptPtr) -> ScriptPtr; - fn battleside_has_volatile(r: ExternRef, name: *const c_char) -> bool; - fn battleside_remove_volatile(r: ExternRef, name: *const c_char); - fn battleside_get_volatile(r: ExternRef, name: *const c_char) -> ScriptPtr; + fn battleside_add_volatile_by_name( + r: ExternRef, + name: *const c_char, + ) -> ScriptPtr; + fn battleside_add_volatile(r: ExternRef, script: ScriptPtr) -> ScriptPtr; + fn battleside_has_volatile(r: ExternRef, name: *const c_char) -> bool; + fn battleside_remove_volatile(r: ExternRef, name: *const c_char); + fn battleside_get_volatile(r: ExternRef, name: *const c_char) -> ScriptPtr; } 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 05c3109..393e4e2 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,23 +1,34 @@ +use crate::app_interface::PokemonImpl; use crate::{ExternRef, ExternalReferenceType, Pokemon}; +use alloc::rc::Rc; -#[derive(Clone)] -pub struct ChoiceQueue { - reference: ExternRef, +pub trait ChoiceQueueTrait { + fn move_pokemon_choice_next(&self, pokemon: &Pokemon) -> bool; } -impl ChoiceQueue { - #[cfg(not(feature = "mock_data"))] - pub fn new(reference: ExternRef) -> Self { - Self { reference } - } +pub type ChoiceQueue = Rc; - 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, +} + +#[cfg(not(feature = "mock_data"))] +impl ChoiceQueueImpl { + pub fn new(reference: ExternRef) -> 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::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, - pokemon: ExternRef, + r: ExternRef, + pokemon: ExternRef, ) -> bool; } 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 b52047e..5fe0dd1 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,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, + reference: ExternRef, number_of_hits: CachedValue, - user: 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; + 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; +#[cfg(feature = "mock_data")] +pub type MockExecutingMove = MockExecutingMoveTrait; + #[derive(Clone)] -pub struct ExecutingMove { +pub struct ExecutingMoveImpl { inner: Temporary, } -impl ExecutingMove { - pub(crate) fn new(reference: ExternRef) -> Self { +impl ExecutingMoveImpl { + #[cfg(not(feature = "mock_data"))] + pub(crate) fn new(reference: ExternRef) -> 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; + #[derive(Clone)] -pub struct HitData { - reference: ExternRef, +pub struct HitDataImpl { + reference: ExternRef, } -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::new(reference) } } -impl ExternalReferenceType for HitData { +#[cfg(not(feature = "mock_data"))] +impl ExternalReferenceType for HitDataImpl { fn from_extern_value(reference: ExternRef) -> 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) -> 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; + 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_get_script(r: ExternRef) -> *const dyn Script; fn executing_move_is_pokemon_target( - r: ExternRef, - pokemon: ExternRef, + r: ExternRef, + pokemon: ExternRef, ) -> bool; fn executing_move_get_hit_data( - r: ExternRef, - target: ExternRef, + r: ExternRef, + target: ExternRef, hit: u8, - ) -> ExternRef; + ) -> 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_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); + 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/mod.rs b/pkmn_lib_interface/src/app_interface/dynamic_data/mod.rs index 8ca783b..e7209da 100755 --- a/pkmn_lib_interface/src/app_interface/dynamic_data/mod.rs +++ b/pkmn_lib_interface/src/app_interface/dynamic_data/mod.rs @@ -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::*; 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 9c9d4f9..3619007 100755 --- a/pkmn_lib_interface/src/app_interface/dynamic_data/party.rs +++ b/pkmn_lib_interface/src/app_interface/dynamic_data/party.rs @@ -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, +pub trait PartyTrait { + fn get_pokemon(&self, index: usize) -> Option; + fn length(&self) -> usize; } -impl Party { - pub fn new(reference: ExternRef) -> Self { +pub type Party = Rc; + +#[derive(Clone)] +pub struct PartyImpl { + reference: ExternRef, +} + +#[cfg(not(feature = "mock_data"))] +impl PartyImpl { + pub fn new(reference: ExternRef) -> Self { Self { reference } } +} - #[cfg(not(feature = "mock_data"))] - pub fn get_pokemon(&self, index: usize) -> Option { - 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 { + 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::new(reference) } @@ -29,6 +48,6 @@ impl ExternalReferenceType for Party { #[cfg(not(feature = "mock_data"))] extern "wasm" { - fn party_get_pokemon(r: ExternRef, index: usize) -> ExternRef; - fn party_get_length(r: ExternRef) -> usize; + fn party_get_pokemon(r: ExternRef, index: usize) -> ExternRef; + fn party_get_length(r: ExternRef) -> usize; } 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 6b5dae4..7ac6316 100755 --- a/pkmn_lib_interface/src/app_interface/dynamic_data/pokemon.rs +++ b/pkmn_lib_interface/src/app_interface/dynamic_data/pokemon.rs @@ -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, + reference: ExternRef, library: CachedValue, // We cache the reference to the data, not the values stored inside, which are dynamic. - flat_stats: CachedValue>, + 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>, + 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>, } +pub type Pokemon = Rc; +#[cfg(feature = "mock_data")] +pub type MockPokemon = MockPokemonTrait; + #[derive(Clone)] -pub struct Pokemon { +pub struct PokemonImpl { inner: Rc, } -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; + 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; + 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; + 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 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; +} + +#[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; + 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 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); + } + 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 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 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 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::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; - pub fn stat_boosts(&self) -> ClampedStatisticSet; - pub fn boosted_stats(&self) -> StatisticSet; - pub fn individual_values(&self) -> ClampedStatisticSet; - pub fn effort_values(&self) -> ClampedStatisticSet; - } - - #[cfg(not(feature = "mock_data"))] - pub fn has_held_item(&self, name: &str) -> bool { - let cstr = CString::new(name).unwrap(); - unsafe { pokemon_has_held_item(self.inner.reference, cstr.as_ptr()) } - } - - #[cfg(not(feature = "mock_data"))] - pub fn set_held_item(&self, item: &Item) -> Option { - unsafe { pokemon_set_held_item(self.inner.reference, item.reference()).get_value() } - } - - #[cfg(not(feature = "mock_data"))] - pub fn remove_held_item(&self) -> Option { - unsafe { pokemon_remove_held_item(self.inner.reference).get_value() } - } - - #[cfg(not(feature = "mock_data"))] - pub fn consume_held_item(&self) -> bool { - unsafe { pokemon_consume_held_item(self.inner.reference) } - } - - #[cfg(not(feature = "mock_data"))] - pub fn max_health(&self) -> u32 { - self.boosted_stats().hp() - } - - #[cfg(not(feature = "mock_data"))] - pub fn get_type(&self, index: usize) -> u8 { - unsafe { pokemon_get_type(self.inner.reference, index) } - } - #[cfg(not(feature = "mock_data"))] - pub fn has_type(&self, type_identifier: TypeIdentifier) -> bool { - unsafe { pokemon_has_type(self.inner.reference, type_identifier.into()) } - } - #[cfg(not(feature = "mock_data"))] - pub fn has_type_by_name(&self, type_name: &str) -> bool { - let type_identifier = self - .library() - .data_library() - .type_library() - .get_type_from_name(type_name); - if let Some(type_identifier) = type_identifier { - return self.has_type(type_identifier); - } - false - } - - #[cfg(not(feature = "mock_data"))] - pub fn get_learned_move(&self, index: usize) -> Option { - unsafe { pokemon_get_learned_move(self.inner.reference, index).get_value() } - } - #[cfg(not(feature = "mock_data"))] - pub fn change_stat_boost( - &self, - stat: Statistic, - diff_amount: i8, - self_inflicted: bool, - ) -> bool { - unsafe { - pokemon_change_stat_boost(self.inner.reference, stat, diff_amount, self_inflicted) - } - } - - #[cfg(not(feature = "mock_data"))] - pub fn ability_script(&self) -> Option<&Box> { - unsafe { pokemon_get_ability_script(self.inner.reference).as_ref() } - } - - #[cfg(not(feature = "mock_data"))] - pub fn change_species(&self, species: Species, form: Form) { - unsafe { - pokemon_change_species(self.inner.reference, species.reference(), form.reference()); - } - } - - #[cfg(not(feature = "mock_data"))] - pub fn change_form(&self, form: Form) { - unsafe { - pokemon_change_form(self.inner.reference, form.reference()); - } - } - - pub fn is_fainted(&self) -> bool { - self.current_health() == 0 - } - - #[cfg(not(feature = "mock_data"))] - pub fn damage(&self, damage: u32, source: DamageSource) { - unsafe { pokemon_damage(self.inner.reference, damage, source) } - } - - #[cfg(not(feature = "mock_data"))] - pub fn heal(&self, amount: u32, allow_revive: bool) -> bool { - unsafe { pokemon_heal(self.inner.reference, amount, allow_revive) } - } - - #[cfg(not(feature = "mock_data"))] - pub fn 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 { - 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(&self, script_name: &str) -> Option<&T> + fn get_volatile(&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; pub fn display_form(&self) -> Option; - pub fn held_item(&self) -> Option; - pub fn battle(&self) -> Option; + pub fn held_item(&self) -> Option; + pub fn battle(&self) -> Option; } #[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::new(reference) } @@ -306,51 +420,46 @@ impl ExternalReferenceType for Pokemon { #[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_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, + 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_get_ability_script(r: ExternRef) -> *const Box; fn pokemon_change_species( - r: ExternRef, + 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_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")] -impl Pokemon { - pub fn current_health(&self) -> u32 { - unimplemented!() - } - pub fn species(&self) -> Species { - unimplemented!() - } + 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/statistic_set.rs b/pkmn_lib_interface/src/app_interface/dynamic_data/statistic_set.rs index f745fd3..c03d181 100755 --- a/pkmn_lib_interface/src/app_interface/dynamic_data/statistic_set.rs +++ b/pkmn_lib_interface/src/app_interface/dynamic_data/statistic_set.rs @@ -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 +pub trait StatisticSetTrait where T: TryFrom, T: TryInto, + >::Error: Debug, + >::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 = Rc>; + +#[derive(Clone)] +pub struct StatisticSetImpl +where + T: TryFrom, + T: TryInto, + >::Error: Debug, + >::Error: Debug, { reference: ExternRef, _p: PhantomData, } -impl StatisticSet +#[cfg(not(feature = "mock_data"))] +impl StatisticSetImpl where T: TryFrom, T: TryInto, @@ -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 StatisticSetTrait for StatisticSetImpl +where + T: TryFrom, + T: TryInto, + >::Error: Debug, + >::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 ExternalReferenceType for StatisticSet +#[cfg(not(feature = "mock_data"))] +impl ExternalReferenceType for StatisticSetImpl where T: TryFrom, T: TryInto, @@ -89,7 +105,7 @@ where >::Error: Debug, { fn from_extern_value(reference: ExternRef) -> Self { - StatisticSet::::new(reference) + StatisticSetImpl::::new(reference) } } @@ -98,6 +114,8 @@ pub struct ClampedStatisticSet where T: TryFrom, T: TryInto, + >::Error: Debug, + >::Error: Debug, { reference: ExternRef, _p: PhantomData, @@ -192,10 +210,18 @@ where #[cfg(not(feature = "mock_data"))] extern "wasm" { - fn statistic_set_get(r: ExternRef>, stat: Statistic) -> i64; - fn statistic_set_set(r: ExternRef>, stat: Statistic, value: i64); - fn statistic_set_increase_stat(r: ExternRef>, stat: Statistic, value: i64); - fn statistic_set_decrease_stat(r: ExternRef>, stat: Statistic, value: i64); + fn statistic_set_get(r: ExternRef>, stat: Statistic) -> i64; + fn statistic_set_set(r: ExternRef>, stat: Statistic, value: i64); + fn statistic_set_increase_stat( + r: ExternRef>, + stat: Statistic, + value: i64, + ); + fn statistic_set_decrease_stat( + r: ExternRef>, + stat: Statistic, + value: i64, + ); fn clamped_statistic_set_get(r: ExternRef>, stat: Statistic) -> i64; fn clamped_statistic_set_set( 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 1f6de76..2f11e56 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,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, - user: CachedValue, +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, + user: CachedValue>, +} + +#[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; + struct MoveTurnChoiceDataInner { base: BaseTurnChoiceData, used_move: CachedValue, @@ -19,13 +48,22 @@ struct MoveTurnChoiceDataInner { target_index: CachedValue, } +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>; +} + #[derive(Clone)] -pub struct MoveTurnChoiceData { +pub struct MoveTurnChoiceDataImpl { inner: Temporary, } pub enum TurnChoice { - Move(MoveTurnChoiceData), + Move(Box), 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> { - 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> { + 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 { 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) -> Self { + fn from_reference(reference: ExternRef) -> 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) -> u8; - fn turn_choice_get_user(r: ExternRef) -> ExternRef; + fn turn_choice_get_user(r: ExternRef) -> ExternRef; fn turn_choice_get_speed(r: ExternRef) -> u32; fn turn_choice_has_failed(r: ExternRef) -> bool; fn turn_choice_fail(r: ExternRef); - fn turn_choice_move_used_move(r: ExternRef) -> ExternRef; - fn turn_choice_move_target_side(r: ExternRef) -> u8; - fn turn_choice_move_target_index(r: ExternRef) -> u8; - fn turn_choice_move_priority(r: ExternRef) -> i8; + fn turn_choice_move_used_move(r: ExternRef) -> ExternRef; + fn turn_choice_move_target_side(r: ExternRef) -> u8; + fn turn_choice_move_target_index(r: ExternRef) -> u8; + fn turn_choice_move_priority(r: ExternRef) -> i8; #[allow(improper_ctypes)] - fn turn_choice_move_script(r: ExternRef) -> *const Box; + fn turn_choice_move_script(r: ExternRef) -> *const Box; } 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 new file mode 100644 index 0000000..58e9927 --- /dev/null +++ b/pkmn_lib_interface/src/app_interface/dynamic_data/with_volatile.rs @@ -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) -> &'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::().unwrap()) + } else { + None + } +} diff --git a/pkmn_lib_interface/src/app_interface/static_data/ability.rs b/pkmn_lib_interface/src/app_interface/static_data/ability.rs index 3b6baa2..2833996 100755 --- a/pkmn_lib_interface/src/app_interface/static_data/ability.rs +++ b/pkmn_lib_interface/src/app_interface/static_data/ability.rs @@ -7,18 +7,24 @@ use crate::{ use alloc::rc::Rc; struct AbilityInner { - reference: ExternRef, + reference: ExternRef, name: CachedValue, effect: CachedValue, parameters: CachedValue>, } +#[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, } -impl Ability { +impl AbilityImpl { #[cfg(not(feature = "mock_data"))] pub fn new(reference: ExternRef) -> 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::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) -> ExternRef; - fn ability_get_effect(r: ExternRef) -> ExternRef; - fn ability_get_parameters(r: ExternRef) -> VecExternRef; + fn ability_get_name(r: ExternRef) -> ExternRef; + fn ability_get_effect(r: ExternRef) -> ExternRef; + fn ability_get_parameters(r: ExternRef) -> VecExternRef; } diff --git a/pkmn_lib_interface/src/app_interface/static_data/data_libraries/item_library.rs b/pkmn_lib_interface/src/app_interface/static_data/data_libraries/item_library.rs index c5df78a..a9d2efc 100755 --- a/pkmn_lib_interface/src/app_interface/static_data/data_libraries/item_library.rs +++ b/pkmn_lib_interface/src/app_interface/static_data/data_libraries/item_library.rs @@ -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, - cache: RwLock>, + cache: RwLock>, } #[derive(Clone)] @@ -25,8 +25,8 @@ impl ItemLibrary { } } -impl DataLibrary for ItemLibrary { - fn get_cache(&self) -> &spin::rwlock::RwLock> { +impl DataLibrary for ItemLibrary { + fn get_cache(&self) -> &spin::rwlock::RwLock> { &self.inner.cache } @@ -35,12 +35,12 @@ impl DataLibrary for ItemLibrary { } #[cfg(not(feature = "mock_data"))] - fn _get_ref_by_name(ptr: ExternRef, name: ExternRef) -> ExternRef { + fn _get_ref_by_name(ptr: ExternRef, name: ExternRef) -> ExternRef { unsafe { item_library_get_item(ptr, name) } } #[cfg(not(feature = "mock_data"))] - fn _get_ref_by_hash(ptr: ExternRef, hash: u32) -> ExternRef { + fn _get_ref_by_hash(ptr: ExternRef, hash: u32) -> ExternRef { unsafe { item_library_get_item_by_hash(ptr, hash) } } } @@ -59,8 +59,9 @@ extern "wasm" { fn item_library_get_item( ptr: ExternRef, name: ExternRef, - ) -> ExternRef; - fn item_library_get_item_by_hash(ptr: ExternRef, hash: u32) -> ExternRef; + ) -> ExternRef; + fn item_library_get_item_by_hash(ptr: ExternRef, hash: u32) + -> ExternRef; } #[cfg(feature = "mock_data")] diff --git a/pkmn_lib_interface/src/app_interface/static_data/item.rs b/pkmn_lib_interface/src/app_interface/static_data/item.rs index 09e71f2..066100a 100755 --- a/pkmn_lib_interface/src/app_interface/static_data/item.rs +++ b/pkmn_lib_interface/src/app_interface/static_data/item.rs @@ -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; +#[cfg(feature = "mock_data")] +pub type MockItem = MockItemTrait; + struct ItemInner { - reference: ExternRef, + reference: ExternRef, name: CachedValue, category: CachedValue, battle_category: CachedValue, @@ -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, } -impl Item { - #[cfg(not(feature = "mock_data"))] +#[cfg(not(feature = "mock_data"))] +impl ItemImpl { pub(crate) fn new(reference: ExternRef) -> 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.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 { - Item::new(reference) + ItemImpl::new(reference) } } #[cfg(not(feature = "mock_data"))] extern "wasm" { - fn item_get_name(ptr: ExternRef) -> ExternRef; - fn item_get_category(ptr: ExternRef) -> ItemCategory; - fn item_get_battle_category(ptr: ExternRef) -> BattleItemCategory; - fn item_get_price(ptr: ExternRef) -> i32; - fn item_has_flag(ptr: ExternRef, flag: ExternRef) -> 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) -> ExternRef; + fn item_get_category(ptr: ExternRef) -> ItemCategory; + fn item_get_battle_category(ptr: ExternRef) -> BattleItemCategory; + fn item_get_price(ptr: ExternRef) -> i32; + fn item_has_flag(ptr: ExternRef, flag: ExternRef) -> bool; } diff --git a/pkmn_lib_interface/src/app_interface/static_data/mod.rs b/pkmn_lib_interface/src/app_interface/static_data/mod.rs index 12bad7e..230a80e 100755 --- a/pkmn_lib_interface/src/app_interface/static_data/mod.rs +++ b/pkmn_lib_interface/src/app_interface/static_data/mod.rs @@ -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::*; diff --git a/pkmn_lib_interface/src/app_interface/string_key.rs b/pkmn_lib_interface/src/app_interface/string_key.rs index 82ee0c5..4756459 100755 --- a/pkmn_lib_interface/src/app_interface/string_key.rs +++ b/pkmn_lib_interface/src/app_interface/string_key.rs @@ -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(), diff --git a/pkmn_lib_interface/src/handling/extern_ref.rs b/pkmn_lib_interface/src/handling/extern_ref.rs index fd3de81..f1b06b5 100755 --- a/pkmn_lib_interface/src/handling/extern_ref.rs +++ b/pkmn_lib_interface/src/handling/extern_ref.rs @@ -1,4 +1,5 @@ -use crate::ImmutableList; +use crate::app_interface::list::ImmutableList; +use alloc::rc::Rc; use core::cmp::Ordering; use core::hash::{Hash, Hasher}; use core::intrinsics::transmute; @@ -29,6 +30,16 @@ impl ExternRef { T::instantiate_from_extern_value(*self) } + #[inline] + pub fn get_value_rc(&self) -> Option> + where + T: ExternalReferenceType, + T: Sized, + T:, + { + T::instantiate_from_extern_value_rc(*self) + } + #[inline] pub fn not_null(&self) -> T where @@ -39,6 +50,16 @@ impl ExternRef { T::instantiate_from_extern_value(*self).unwrap() } + #[inline] + pub fn not_null_rc(&self) -> Rc + where + T: ExternalReferenceType, + T: Sized, + T:, + { + Rc::new(T::instantiate_from_extern_value(*self).unwrap()) + } + #[inline] pub(crate) fn cast(&self) -> ExternRef { ExternRef:: { @@ -93,6 +114,15 @@ impl Hash for ExternRef { } } +impl From for ExternRef { + fn from(value: u32) -> Self { + Self { + p: value, + resource_type: Default::default(), + } + } +} + #[repr(C)] pub struct VecExternRef { v: u64, @@ -179,6 +209,17 @@ pub trait ExternalReferenceType { Some(Self::from_extern_value(reference)) } } + + fn instantiate_from_extern_value_rc(reference: ExternRef) -> Option> + where + Self: Sized, + { + if reference.is_null() { + None + } else { + Some(Rc::new(Self::from_extern_value(reference))) + } + } } #[macro_export] diff --git a/pkmn_lib_interface/src/handling/mod.rs b/pkmn_lib_interface/src/handling/mod.rs index cb9feb4..a384542 100755 --- a/pkmn_lib_interface/src/handling/mod.rs +++ b/pkmn_lib_interface/src/handling/mod.rs @@ -23,6 +23,48 @@ pub enum ScriptCategory { ItemBattleTrigger, } +#[macro_export] +macro_rules! wasm_reference_getters_extern { + ( + $base_type:ty, $type_name:ident, + $( + $(#[$attr:meta])* + $v:vis fn $name:ident(&self) -> $type:ty; + )* + ) => { + #[cfg(not(feature = "mock_data"))] +extern "wasm" { + $( + paste::paste!{ + fn [<$type_name:snake _get_ $name>](r: ExternRef<$base_type>) -> ExternRef<$type>; + } + )* + } + }; +} + +#[macro_export] +macro_rules! wasm_reference_getters_funcs { + ( + $base_type:ty, + $( + $(#[$attr:meta])* + $v:vis fn $name:ident(&self) -> $type:ty; + )* + ) => { + $( + $(#[$attr])* + $v fn $name(&self) -> $type { + paste::paste!{ + unsafe{ + [<$base_type:snake _get_ $name>](self.inner.reference).get_value().unwrap() + } + } + } + )* + }; +} + #[macro_export] macro_rules! wasm_reference_getters { ( @@ -91,6 +133,48 @@ extern "wasm" { }; } +#[macro_export] +macro_rules! wasm_optional_reference_getters_extern { + ( + $base_type:ty, $type_name:ident, + $( + $(#[$attr:meta])* + $v:vis fn $name:ident(&self) -> Option<$type:ty>; + )* + ) => { + #[cfg(not(feature = "mock_data"))] +extern "wasm" { + $( + paste::paste!{ + fn [<$type_name:snake _get_ $name>](r: ExternRef<$base_type>) -> ExternRef<$type>; + } + )* + } + }; +} + +#[macro_export] +macro_rules! wasm_optional_reference_getters_funcs { + ( + $base_type:ty, + $( + $(#[$attr:meta])* + $v:vis fn $name:ident(&self) -> Option<$type:ty>; + )* + ) => { + $( + $(#[$attr])* + $v fn $name(&self) -> Option<$type> { + paste::paste!{ + unsafe{ + [<$base_type:snake _get_ $name>](self.inner.reference).get_value() + } + } + } + )* + }; +} + #[macro_export] macro_rules! wasm_value_getters { ( @@ -125,3 +209,45 @@ extern "wasm" { } }; } + +#[macro_export] +macro_rules! wasm_value_getters_extern { + ( + $base_type:ty, $type_name:ident, + $( + $(#[$attr:meta])* + $v:vis fn $name:ident(&self) -> $type:ty; + )* + ) => { +#[cfg(not(feature = "mock_data"))] +extern "wasm" { + $( + paste::paste!{ + fn [<$type_name:snake _get_ $name>](r: ExternRef<$base_type>) -> $type; + } + )* + } + }; +} + +#[macro_export] +macro_rules! wasm_value_getters_funcs { + ( + $base_type:ty, + $( + $(#[$attr:meta])* + $v:vis fn $name:ident(&self) -> $type:ty; + )* + ) => { + $( + $(#[$attr])* + $v fn $name(&self) -> $type { + paste::paste!{ + unsafe{ + [<$base_type:snake _get_ $name>](self.inner.reference) + } + } + } + )* + }; +} diff --git a/pkmn_lib_interface/src/handling/script.rs b/pkmn_lib_interface/src/handling/script.rs index 986eb0b..2c8e362 100755 --- a/pkmn_lib_interface/src/handling/script.rs +++ b/pkmn_lib_interface/src/handling/script.rs @@ -1,9 +1,11 @@ use crate::app_interface::list::ImmutableList; use crate::app_interface::{ - Battle, DamageSource, DynamicLibrary, EffectParameter, ExecutingMove, Item, Pokemon, Statistic, + Battle, BattleImpl, DamageSource, DynamicLibrary, EffectParameter, ExecutingMove, Item, + Pokemon, Statistic, }; use crate::handling::ScriptCapabilities; use crate::{ExternRef, ExternalReferenceType, ScriptPtr, StringKey, TurnChoice, TypeIdentifier}; +use alloc::boxed::Box; use core::any::Any; use core::fmt::Debug; @@ -321,7 +323,7 @@ pub trait Script { fn on_switch_in(&self, _pokemon: Pokemon) {} /// This function is triggered on a Pokemon and its parents when the given Pokemon consumes the /// held item it had. - fn on_after_held_item_consume(&self, _pokemon: Pokemon, _item: &Item) {} + fn on_after_held_item_consume(&self, _pokemon: Pokemon, _item: Item) {} /// This function is triggered on a Pokemon and its parents when the given Pokemon gains experience, /// and allows for changing this amount of experience. fn change_experience_gained( @@ -356,6 +358,14 @@ pub trait Script { .get_value() } } + + #[cfg(feature = "mock_data")] + fn get_owner(&self) -> Option + where + Self: Sized, + { + unimplemented!() + } } impl Debug for dyn Script { diff --git a/pkmn_lib_interface/src/lib.rs b/pkmn_lib_interface/src/lib.rs index ba3bcaa..c161b9a 100755 --- a/pkmn_lib_interface/src/lib.rs +++ b/pkmn_lib_interface/src/lib.rs @@ -23,12 +23,10 @@ extern crate dlmalloc; static ALLOC: dlmalloc::GlobalDlmalloc = dlmalloc::GlobalDlmalloc {}; use crate::app_interface::list::ImmutableList; -use crate::app_interface::Statistic; use crate::app_interface::{ - Battle, DamageSource, DynamicLibrary, EffectParameter, ExecutingMove, Item, StringKey, - TurnChoice, + BattleImpl, DamageSource, DynamicLibrary, EffectParameter, ExecutingMoveImpl, Item, ItemImpl, + Pokemon, PokemonImpl, Statistic, StringKey, TurnChoice, TypeIdentifier, }; -use crate::app_interface::{Pokemon, TypeIdentifier}; pub(crate) use crate::handling::extern_ref::*; use crate::handling::ffi_array::FFIArray; #[cfg(not(feature = "mock_data"))] @@ -237,305 +235,305 @@ fn script_change_number_of_hits( fn script_prevent_move( script: ScriptPtr, - mv: ExternRef, + mv: ExternRef, out: *mut bool, ) { - script.val().unwrap().prevent_move(mv.not_null(), out.as_mut().unwrap()); + script.val().unwrap().prevent_move(mv.not_null_rc(), out.as_mut().unwrap()); } fn script_fail_move( script: ScriptPtr, - mv: ExternRef, + mv: ExternRef, out: *mut bool, ) { - script.val().unwrap().fail_move(mv.not_null(), out.as_mut().unwrap()); + script.val().unwrap().fail_move(mv.not_null_rc(), out.as_mut().unwrap()); } fn script_stop_before_move( script: ScriptPtr, - mv: ExternRef, + mv: ExternRef, out: *mut bool, ) { - script.val().unwrap().stop_before_move(mv.not_null(), out.as_mut().unwrap()); + script.val().unwrap().stop_before_move(mv.not_null_rc(), out.as_mut().unwrap()); } fn script_on_before_move( script: ScriptPtr, - mv: ExternRef, + mv: ExternRef, ) { - script.val().unwrap().on_before_move(mv.not_null()); + script.val().unwrap().on_before_move(mv.not_null_rc()); } fn script_fail_incoming_move( script: ScriptPtr, - mv: ExternRef, - target: ExternRef, + mv: ExternRef, + target: ExternRef, out: *mut bool, ) { - script.val().unwrap().fail_incoming_move(mv.not_null(), target.not_null(), out.as_mut().unwrap()); + script.val().unwrap().fail_incoming_move(mv.not_null_rc(), target.not_null_rc(), out.as_mut().unwrap()); } fn script_is_invulnerable( script: ScriptPtr, - mv: ExternRef, - target: ExternRef, + mv: ExternRef, + target: ExternRef, out: *mut bool, ) { - script.val().unwrap().is_invulnerable(mv.not_null(), target.not_null(), out.as_mut().unwrap()); + script.val().unwrap().is_invulnerable(mv.not_null_rc(), target.not_null_rc(), out.as_mut().unwrap()); } fn script_on_move_miss( script: ScriptPtr, - mv: ExternRef, - target: ExternRef, + mv: ExternRef, + target: ExternRef, ) { - script.val().unwrap().on_move_miss(mv.not_null(), target.not_null()); + script.val().unwrap().on_move_miss(mv.not_null_rc(), target.not_null_rc()); } fn script_change_move_type( script: ScriptPtr, - mv: ExternRef, - target: ExternRef, + mv: ExternRef, + target: ExternRef, hit: u8, out: *mut TypeIdentifier, ) { - script.val().unwrap().change_move_type(mv.not_null(), target.not_null(), hit, out.as_mut().unwrap()); + script.val().unwrap().change_move_type(mv.not_null_rc(), target.not_null_rc(), hit, out.as_mut().unwrap()); } fn script_change_effectiveness( script: ScriptPtr, - mv: ExternRef, - target: ExternRef, + mv: ExternRef, + target: ExternRef, hit: u8, out: *mut f32, ) { - script.val().unwrap().change_effectiveness(mv.not_null(), target.not_null(), hit, out.as_mut().unwrap()); + script.val().unwrap().change_effectiveness(mv.not_null_rc(), target.not_null_rc(), hit, out.as_mut().unwrap()); } fn script_block_critical( script: ScriptPtr, - mv: ExternRef, - target: ExternRef, + mv: ExternRef, + target: ExternRef, hit: u8, out: *mut bool, ) { - script.val().unwrap().block_critical(mv.not_null(), target.not_null(), hit, out.as_mut().unwrap()); + script.val().unwrap().block_critical(mv.not_null_rc(), target.not_null_rc(), hit, out.as_mut().unwrap()); } fn script_block_incoming_critical( script: ScriptPtr, - mv: ExternRef, - target: ExternRef, + mv: ExternRef, + target: ExternRef, hit: u8, out: *mut bool, ) { - script.val().unwrap().block_incoming_critical(mv.not_null(), target.not_null(), hit, out.as_mut().unwrap()); + script.val().unwrap().block_incoming_critical(mv.not_null_rc(), target.not_null_rc(), hit, out.as_mut().unwrap()); } fn script_change_accuracy( script: ScriptPtr, - mv: ExternRef, - target: ExternRef, + mv: ExternRef, + target: ExternRef, hit: u8, out: *mut u8, ) { - script.val().unwrap().change_accuracy(mv.not_null(), target.not_null(), hit, out.as_mut().unwrap()); + script.val().unwrap().change_accuracy(mv.not_null_rc(), target.not_null_rc(), hit, out.as_mut().unwrap()); } fn script_change_critical_stage( script: ScriptPtr, - mv: ExternRef, - target: ExternRef, + mv: ExternRef, + target: ExternRef, hit: u8, out: *mut u8, ) { - script.val().unwrap().change_critical_stage(mv.not_null(), target.not_null(), hit, out.as_mut().unwrap()); + script.val().unwrap().change_critical_stage(mv.not_null_rc(), target.not_null_rc(), hit, out.as_mut().unwrap()); } fn script_change_critical_modifier( script: ScriptPtr, - mv: ExternRef, - target: ExternRef, + mv: ExternRef, + target: ExternRef, hit: u8, out: *mut f32, ) { - script.val().unwrap().change_critical_modifier(mv.not_null(), target.not_null(), hit, out.as_mut().unwrap()); + script.val().unwrap().change_critical_modifier(mv.not_null_rc(), target.not_null_rc(), hit, out.as_mut().unwrap()); } fn script_change_stab_modifier( script: ScriptPtr, - mv: ExternRef, - target: ExternRef, + mv: ExternRef, + target: ExternRef, hit: u8, out: *mut f32, ) { - script.val().unwrap().change_stab_modifier(mv.not_null(), target.not_null(), hit, out.as_mut().unwrap()); + script.val().unwrap().change_stab_modifier(mv.not_null_rc(), target.not_null_rc(), hit, out.as_mut().unwrap()); } fn script_change_base_power( script: ScriptPtr, - mv: ExternRef, - target: ExternRef, + mv: ExternRef, + target: ExternRef, hit: u8, out: *mut u8, ) { - script.val().unwrap().change_base_power(mv.not_null(), target.not_null(), hit, out.as_mut().unwrap()); + script.val().unwrap().change_base_power(mv.not_null_rc(), target.not_null_rc(), hit, out.as_mut().unwrap()); } fn script_bypass_defensive_stat_boost( script: ScriptPtr, - mv: ExternRef, - target: ExternRef, + mv: ExternRef, + target: ExternRef, hit: u8, out: *mut bool, ) { - script.val().unwrap().bypass_defensive_stat_boost(mv.not_null(), target.not_null(), hit, out.as_mut().unwrap()); + script.val().unwrap().bypass_defensive_stat_boost(mv.not_null_rc(), target.not_null_rc(), hit, out.as_mut().unwrap()); } fn script_bypass_offensive_stat_boost( script: ScriptPtr, - mv: ExternRef, - target: ExternRef, + mv: ExternRef, + target: ExternRef, hit: u8, out: *mut bool, ) { - script.val().unwrap().bypass_offensive_stat_boost(mv.not_null(), target.not_null(), hit, out.as_mut().unwrap()); + script.val().unwrap().bypass_offensive_stat_boost(mv.not_null_rc(), target.not_null_rc(), hit, out.as_mut().unwrap()); } fn script_change_defensive_stat_value( script: ScriptPtr, - mv: ExternRef, - target: ExternRef, + mv: ExternRef, + target: ExternRef, hit: u8, out: *mut u32, ) { - script.val().unwrap().change_defensive_stat_value(mv.not_null(), target.not_null(), hit, out.as_mut().unwrap()); + script.val().unwrap().change_defensive_stat_value(mv.not_null_rc(), target.not_null_rc(), hit, out.as_mut().unwrap()); } fn script_change_offensive_stat_value( script: ScriptPtr, - mv: ExternRef, - target: ExternRef, + mv: ExternRef, + target: ExternRef, hit: u8, out: *mut u32, ) { - script.val().unwrap().change_offensive_stat_value(mv.not_null(), target.not_null(), hit, out.as_mut().unwrap()); + script.val().unwrap().change_offensive_stat_value(mv.not_null_rc(), target.not_null_rc(), hit, out.as_mut().unwrap()); } fn script_change_damage_stat_modifier( script: ScriptPtr, - mv: ExternRef, - target: ExternRef, + mv: ExternRef, + target: ExternRef, hit: u8, out: *mut f32, ) { - script.val().unwrap().change_damage_stat_modifier(mv.not_null(), target.not_null(), hit, out.as_mut().unwrap()); + script.val().unwrap().change_damage_stat_modifier(mv.not_null_rc(), target.not_null_rc(), hit, out.as_mut().unwrap()); } fn script_change_damage_modifier( script: ScriptPtr, - mv: ExternRef, - target: ExternRef, + mv: ExternRef, + target: ExternRef, hit: u8, out: *mut f32, ) { - script.val().unwrap().change_damage_modifier(mv.not_null(), target.not_null(), hit, out.as_mut().unwrap()); + script.val().unwrap().change_damage_modifier(mv.not_null_rc(), target.not_null_rc(), hit, out.as_mut().unwrap()); } fn script_change_damage( script: ScriptPtr, - mv: ExternRef, - target: ExternRef, + mv: ExternRef, + target: ExternRef, hit: u8, out: *mut u32, ) { - script.val().unwrap().change_damage(mv.not_null(), target.not_null(), hit, out.as_mut().unwrap()); + script.val().unwrap().change_damage(mv.not_null_rc(), target.not_null_rc(), hit, out.as_mut().unwrap()); } fn script_change_incoming_damage( script: ScriptPtr, - mv: ExternRef, - target: ExternRef, + mv: ExternRef, + target: ExternRef, hit: u8, out: *mut u32, ) { - script.val().unwrap().change_incoming_damage(mv.not_null(), target.not_null(), hit, out.as_mut().unwrap()); + script.val().unwrap().change_incoming_damage(mv.not_null_rc(), target.not_null_rc(), hit, out.as_mut().unwrap()); } fn script_on_incoming_hit( script: ScriptPtr, - mv: ExternRef, - target: ExternRef, + mv: ExternRef, + target: ExternRef, hit: u8, ) { - script.val().unwrap().on_incoming_hit(mv.not_null(), target.not_null(), hit); + script.val().unwrap().on_incoming_hit(mv.not_null_rc(), target.not_null_rc(), hit); } fn script_on_opponent_faints( script: ScriptPtr, - mv: ExternRef, - target: ExternRef, + mv: ExternRef, + target: ExternRef, hit: u8, ) { - script.val().unwrap().on_opponent_faints(mv.not_null(), target.not_null(), hit); + script.val().unwrap().on_opponent_faints(mv.not_null_rc(), target.not_null_rc(), hit); } fn script_prevent_stat_boost_change( script: ScriptPtr, - target: ExternRef, + target: ExternRef, stat: Statistic, amount: i8, self_inflicted: u8, out: *mut bool, ) { - script.val().unwrap().prevent_stat_boost_change(target.not_null(), stat, amount, self_inflicted == 1, out.as_mut().unwrap()); + script.val().unwrap().prevent_stat_boost_change(target.not_null_rc(), stat, amount, self_inflicted == 1, out.as_mut().unwrap()); } fn script_prevent_secondary_effect( script: ScriptPtr, - mv: ExternRef, - target: ExternRef, + mv: ExternRef, + target: ExternRef, hit: u8, out: *mut bool, ) { - script.val().unwrap().prevent_secondary_effect(mv.not_null(), target.not_null(), hit, out.as_mut().unwrap()); + script.val().unwrap().prevent_secondary_effect(mv.not_null_rc(), target.not_null_rc(), hit, out.as_mut().unwrap()); } fn script_change_effect_chance( script: ScriptPtr, - mv: ExternRef, - target: ExternRef, + mv: ExternRef, + target: ExternRef, hit: u8, out: *mut f32, ) { - script.val().unwrap().change_effect_chance(mv.not_null(), target.not_null(), hit, out.as_mut().unwrap()); + script.val().unwrap().change_effect_chance(mv.not_null_rc(), target.not_null_rc(), hit, out.as_mut().unwrap()); } fn script_change_incoming_effect_chance( script: ScriptPtr, - mv: ExternRef, - target: ExternRef, + mv: ExternRef, + target: ExternRef, hit: u8, out: *mut f32, ) { - script.val().unwrap().change_incoming_effect_chance(mv.not_null(), target.not_null(), hit, out.as_mut().unwrap()); + script.val().unwrap().change_incoming_effect_chance(mv.not_null_rc(), target.not_null_rc(), hit, out.as_mut().unwrap()); } fn script_on_secondary_effect( script: ScriptPtr, - mv: ExternRef, - target: ExternRef, + mv: ExternRef, + target: ExternRef, hit: u8, ) { - script.val().unwrap().on_secondary_effect(mv.not_null(), target.not_null(), hit); + script.val().unwrap().on_secondary_effect(mv.not_null_rc(), target.not_null_rc(), hit); } fn script_on_after_hits( script: ScriptPtr, - mv: ExternRef, - target: ExternRef, + mv: ExternRef, + target: ExternRef, ) { - script.val().unwrap().on_after_hits(mv.not_null(), target.not_null()); + script.val().unwrap().on_after_hits(mv.not_null_rc(), target.not_null_rc()); } fn script_prevent_self_switch( @@ -556,16 +554,16 @@ fn script_prevent_opponent_switch( fn script_on_fail( script: ScriptPtr, - pokemon: ExternRef, + pokemon: ExternRef, ) { - script.val().unwrap().on_fail(pokemon.not_null()); + script.val().unwrap().on_fail(pokemon.not_null_rc()); } fn script_on_opponent_fail( script: ScriptPtr, - pokemon: ExternRef, + pokemon: ExternRef, ) { - script.val().unwrap().on_opponent_fail(pokemon.not_null()); + script.val().unwrap().on_opponent_fail(pokemon.not_null_rc()); } fn script_prevent_self_run_away( @@ -592,70 +590,70 @@ fn script_on_end_turn( fn script_on_damage( script: ScriptPtr, - pokemon: ExternRef, + pokemon: ExternRef, source: DamageSource, old_health: u32, new_health: u32, ) { - script.val().unwrap().on_damage(pokemon.not_null(), source, old_health, new_health); + script.val().unwrap().on_damage(pokemon.not_null_rc(), source, old_health, new_health); } fn script_on_faint( script: ScriptPtr, - pokemon: ExternRef, + pokemon: ExternRef, source: DamageSource, ) { - script.val().unwrap().on_faint(pokemon.not_null(), source); + script.val().unwrap().on_faint(pokemon.not_null_rc(), source); } fn script_on_switch_in( script: ScriptPtr, - pokemon: ExternRef, + pokemon: ExternRef, ) { - script.val().unwrap().on_switch_in(pokemon.not_null()); + script.val().unwrap().on_switch_in(pokemon.not_null_rc()); } fn script_on_after_held_item_consume( script: ScriptPtr, - pokemon: ExternRef, - item: ExternRef + pokemon: ExternRef, + item: ExternRef ) { - script.val().unwrap().on_after_held_item_consume(pokemon.not_null(), &item.not_null()); + script.val().unwrap().on_after_held_item_consume(pokemon.not_null_rc(), item.not_null_rc()); } fn script_change_experience_gained( script: ScriptPtr, - fainted_pokemon: ExternRef, - winning_pokemon: ExternRef, + fainted_pokemon: ExternRef, + winning_pokemon: ExternRef, out: *mut u32 ) { - script.val().unwrap().change_experience_gained(fainted_pokemon.not_null(), winning_pokemon.not_null(), out.as_mut().unwrap()); + script.val().unwrap().change_experience_gained(fainted_pokemon.not_null_rc(), winning_pokemon.not_null_rc(), out.as_mut().unwrap()); } fn script_share_experience( script: ScriptPtr, - fainted_pokemon: ExternRef, - winning_pokemon: ExternRef, + fainted_pokemon: ExternRef, + winning_pokemon: ExternRef, out: *mut bool, ) { - script.val().unwrap().share_experience(fainted_pokemon.not_null(), winning_pokemon.not_null(), out.as_mut().unwrap()); + script.val().unwrap().share_experience(fainted_pokemon.not_null_rc(), winning_pokemon.not_null_rc(), out.as_mut().unwrap()); } fn script_block_weather( script: ScriptPtr, - battle: ExternRef, + battle: ExternRef, out: *mut bool, ) { - script.val().unwrap().block_weather(battle.not_null(), out.as_mut().unwrap()); + script.val().unwrap().block_weather(battle.not_null_rc(), out.as_mut().unwrap()); } fn script_change_capture_rate_bonus( script: ScriptPtr, - target: ExternRef, - pokeball: ExternRef, + target: ExternRef, + pokeball: ExternRef, out: *mut u8, ) { - script.val().unwrap().change_capture_rate_bonus(target.not_null(), pokeball.not_null(), out.as_mut().unwrap()); + script.val().unwrap().change_capture_rate_bonus(target.not_null_rc(), pokeball.not_null_rc(), out.as_mut().unwrap()); }