diff --git a/gen_7_scripts/src/lib.rs b/gen_7_scripts/src/lib.rs index be04797..c7622e6 100755 --- a/gen_7_scripts/src/lib.rs +++ b/gen_7_scripts/src/lib.rs @@ -13,6 +13,7 @@ use pkmn_lib_interface::set_load_script_fn; pub mod registered_scripts; pub mod moves; +pub mod pokemon; pub mod util_scripts; pub(crate) mod utils; diff --git a/gen_7_scripts/src/moves/attract.rs b/gen_7_scripts/src/moves/attract.rs new file mode 100644 index 0000000..4039e57 --- /dev/null +++ b/gen_7_scripts/src/moves/attract.rs @@ -0,0 +1,40 @@ +use crate::pokemon::infatuated::Infatuated; +use crate::script; +use core::any::Any; +use pkmn_lib_interface::app_interface::{ExecutingMove, Gender, Pokemon}; +use pkmn_lib_interface::handling::{Script, ScriptCapabilities}; + +script!(Attract, "attract"); + +impl Script for Attract { + fn new() -> Self { + Self {} + } + + fn get_name(&self) -> &'static str { + Self::get_const_name() + } + + fn get_capabilities(&self) -> &[ScriptCapabilities] { + &[ScriptCapabilities::OnSecondaryEffect] + } + + fn on_secondary_effect(&self, mv: ExecutingMove, target: Pokemon, hit: u8) { + let user_gender = mv.user().gender(); + let target_gender = target.gender(); + // If the move is used on a Pokémon that is the same gender as the user, it will fail + if target_gender == user_gender { + return mv.get_hit_data(&target, hit).fail(); + } + // It will also fail if used by or on a gender-unknown Pokémon + if user_gender == Gender::Genderless || target_gender == Gender::Genderless { + return mv.get_hit_data(&target, hit).fail(); + } + // If the target is the opposite gender of the Pokémon who launched the move, the target becomes infatuated + target.add_volatile_by_name(Infatuated::get_const_name()); + } + + fn as_any(&self) -> &dyn Any { + self + } +} diff --git a/gen_7_scripts/src/moves/mod.rs b/gen_7_scripts/src/moves/mod.rs index b425e98..0eb2828 100755 --- a/gen_7_scripts/src/moves/mod.rs +++ b/gen_7_scripts/src/moves/mod.rs @@ -1,6 +1,7 @@ pub mod acrobatics; pub mod acupressure; pub mod after_you; -pub mod multi_hit_move; pub mod assist; pub mod assurance; +pub mod attract; +pub mod multi_hit_move; diff --git a/gen_7_scripts/src/pokemon/infatuated.rs b/gen_7_scripts/src/pokemon/infatuated.rs new file mode 100644 index 0000000..8b4fa96 --- /dev/null +++ b/gen_7_scripts/src/pokemon/infatuated.rs @@ -0,0 +1,30 @@ +use crate::script; +use core::any::Any; +use pkmn_lib_interface::app_interface::ExecutingMove; +use pkmn_lib_interface::handling::{Script, ScriptCapabilities}; + +script!(Infatuated, "infatuated"); + +impl Script for Infatuated { + fn new() -> Self { + Self {} + } + + fn get_name(&self) -> &'static str { + Self::get_const_name() + } + + fn get_capabilities(&self) -> &[ScriptCapabilities] { + &[ScriptCapabilities::PreventMove] + } + + fn prevent_move(&self, mv: ExecutingMove, prevent: &mut bool) { + if mv.user().battle().unwrap().random().get_max(2) == 0 { + *prevent = true + } + } + + fn as_any(&self) -> &dyn Any { + self + } +} diff --git a/gen_7_scripts/src/pokemon/mod.rs b/gen_7_scripts/src/pokemon/mod.rs new file mode 100644 index 0000000..cf0a17b --- /dev/null +++ b/gen_7_scripts/src/pokemon/mod.rs @@ -0,0 +1 @@ +pub mod infatuated; diff --git a/gen_7_scripts/src/registered_scripts.rs b/gen_7_scripts/src/registered_scripts.rs index f616152..b06db42 100755 --- a/gen_7_scripts/src/registered_scripts.rs +++ b/gen_7_scripts/src/registered_scripts.rs @@ -1,4 +1,5 @@ use crate::moves::*; +use crate::pokemon::*; use alloc::boxed::Box; use pkmn_lib_interface::app_interface::{get_hash, StringKey}; use pkmn_lib_interface::handling::{Script, ScriptCategory}; @@ -32,11 +33,14 @@ pub fn get_script(category: ScriptCategory, name: &StringKey) -> Option {} ScriptCategory::Status => {} - ScriptCategory::Pokemon => {} + ScriptCategory::Pokemon => { + resolve_match!(name.hash(), infatuated::Infatuated,) + } ScriptCategory::Battle => { resolve_match!(name.hash(), crate::util_scripts::ForceEffectTriggerScript,) } 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 6282c97..9161808 100755 --- a/pkmn_lib_interface/src/app_interface/dynamic_data/pokemon.rs +++ b/pkmn_lib_interface/src/app_interface/dynamic_data/pokemon.rs @@ -7,7 +7,8 @@ use crate::handling::cached_value::CachedValue; use crate::handling::Cacheable; use crate::{ cached_value, cached_value_getters, wasm_optional_reference_getters, wasm_reference_getters, - wasm_value_getters, DynamicLibrary, ExternRef, ExternalReferenceType, Script, TypeIdentifier, + wasm_value_getters, DynamicLibrary, ExternRef, ExternalReferenceType, Script, ScriptPtr, + TypeIdentifier, }; use alloc::boxed::Box; use alloc::rc::Rc; @@ -178,6 +179,49 @@ impl Pokemon { .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.into_raw()) + .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.into_raw()); + } + } + + #[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 = pokemon_get_volatile(self.inner.reference, script_name.into_raw()).val(); + if let Some(s) = s { + Some(s.as_any().downcast_ref().unwrap()) + } else { + None + } + } + } } #[cfg(not(feature = "mock_data"))] @@ -275,6 +319,12 @@ extern "wasm" { 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_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")] diff --git a/pkmn_lib_interface/src/app_interface/static_data/species.rs b/pkmn_lib_interface/src/app_interface/static_data/species.rs index 6b96edb..2bf980b 100755 --- a/pkmn_lib_interface/src/app_interface/static_data/species.rs +++ b/pkmn_lib_interface/src/app_interface/static_data/species.rs @@ -10,6 +10,7 @@ use alloc::vec::Vec; use spin::RwLock; #[repr(u8)] +#[derive(Eq, PartialEq)] pub enum Gender { Male = 0, Female = 1,