diff --git a/src/dynamic_data/libraries/misc_library.rs b/src/dynamic_data/libraries/misc_library.rs index f339d9d..77ed7a7 100755 --- a/src/dynamic_data/libraries/misc_library.rs +++ b/src/dynamic_data/libraries/misc_library.rs @@ -6,7 +6,7 @@ use hashbrown::HashSet; use crate::dynamic_data::choices::{MoveChoice, TurnChoice}; use crate::dynamic_data::Pokemon; use crate::dynamic_data::{LearnedMove, MoveLearnMethod}; -use crate::static_data::{MoveCategory, MoveData, MoveTarget, SecondaryEffect}; +use crate::static_data::{MoveCategory, MoveData, MoveTarget, SecondaryEffectImpl}; use crate::{StringKey, ValueIdentifiable, ValueIdentifier}; /// The misc library holds several misc functions required for the battle to run. @@ -40,7 +40,11 @@ impl Gen7MiscLibrary { 255, MoveTarget::Any, 0, - Some(SecondaryEffect::new(-1.0, StringKey::new("struggle"), vec![])), + Some(Box::new(SecondaryEffectImpl::new( + -1.0, + StringKey::new("struggle"), + vec![], + ))), HashSet::new(), )); let struggle_learned_move = Arc::new(LearnedMove::new(&struggle_data, MoveLearnMethod::Unknown)); diff --git a/src/ffi/mod.rs b/src/ffi/mod.rs index a7c269e..272d910 100644 --- a/src/ffi/mod.rs +++ b/src/ffi/mod.rs @@ -139,7 +139,7 @@ impl From> for IdentifiablePointer> } } -impl From>> for IdentifiablePointer> { +impl From>> for IdentifiablePointer> { fn from(v: Option>) -> Self { if let Some(v) = v { let id = unsafe { transmute(v.value_identifier()) }; @@ -153,6 +153,46 @@ impl From>> for IdentifiablePointer> } } +impl From> for IdentifiablePointer> { + fn from(v: Box) -> Self { + let id = unsafe { transmute(v.value_identifier()) }; + Self { + ptr: Box::into_raw(Box::new(v)), + id, + } + } +} + +impl From>> for IdentifiablePointer> { + fn from(v: Option>) -> Self { + if let Some(v) = v { + let id = unsafe { transmute(v.value_identifier()) }; + Self { + ptr: Box::into_raw(Box::new(v)), + id, + } + } else { + IdentifiablePointer::none() + } + } +} + +impl From<&Option>> for IdentifiablePointer> { + fn from(v: &Option>) -> Self { + if let Some(v) = v { + let id = unsafe { transmute(v.value_identifier()) }; + unsafe { + Self { + ptr: *Box::into_raw(Box::new(v as *const Box)), + id, + } + } + } else { + IdentifiablePointer::none() + } + } +} + impl From> for IdentifiablePointer { fn from(v: Box) -> Self { let id = unsafe { transmute(v.value_identifier()) }; diff --git a/src/ffi/static_data/move_data.rs b/src/ffi/static_data/move_data.rs index fd7a92e..2a02664 100644 --- a/src/ffi/static_data/move_data.rs +++ b/src/ffi/static_data/move_data.rs @@ -1,5 +1,7 @@ use crate::ffi::{ffi_arc_getter, BorrowedPtr, ExternPointer, IdentifiablePointer, OwnedPtr}; -use crate::static_data::{EffectParameter, MoveCategory, MoveData, MoveTarget, SecondaryEffect, TypeIdentifier}; +use crate::static_data::{ + EffectParameter, MoveCategory, MoveData, MoveTarget, SecondaryEffect, SecondaryEffectImpl, TypeIdentifier, +}; use crate::StringKey; use hashbrown::HashSet; use std::ffi::{c_char, CStr, CString}; @@ -17,7 +19,7 @@ unsafe extern "C" fn move_data_new( base_usages: u8, target: MoveTarget, priority: i8, - secondary_effect: *mut SecondaryEffect, + secondary_effect: *mut Box, flags: *const *const c_char, flags_length: usize, ) -> IdentifiablePointer> { @@ -72,13 +74,8 @@ ffi_arc_getter!(MoveData, priority, i8); #[no_mangle] unsafe extern "C" fn move_data_secondary_effect( ptr: ExternPointer>, -) -> IdentifiablePointer { - let effect = ptr.as_ref().secondary_effect(); - if let Some(v) = effect { - (v as *const SecondaryEffect).into() - } else { - IdentifiablePointer::none() - } +) -> IdentifiablePointer> { + ptr.as_ref().secondary_effect().into() } /// Arbitrary flags that can be applied to the move. @@ -95,49 +92,49 @@ unsafe extern "C" fn secondary_effect_new( effect_name: BorrowedPtr, parameters: *mut OwnedPtr, parameters_length: usize, -) -> IdentifiablePointer { +) -> IdentifiablePointer> { let parameter_slice = std::slice::from_raw_parts(parameters, parameters_length); let mut parameters = Vec::with_capacity(parameters_length); for parameter in parameter_slice { parameters.push(*Box::from_raw(*parameter)) } - Box::new(SecondaryEffect::new( + let b: Box = Box::new(SecondaryEffectImpl::new( chance, CStr::from_ptr(effect_name).into(), parameters, - )) - .into() + )); + b.into() } /// Drop a secondary effect. #[no_mangle] -unsafe extern "C" fn secondary_effect_drop(ptr: OwnedPtr) { +unsafe extern "C" fn secondary_effect_drop(ptr: OwnedPtr>) { drop_in_place(ptr) } /// The chance the effect triggers. #[no_mangle] -unsafe extern "C" fn secondary_effect_chance(ptr: ExternPointer) -> f32 { +unsafe extern "C" fn secondary_effect_chance(ptr: ExternPointer>) -> f32 { ptr.as_ref().chance() } /// The name of the effect. #[no_mangle] -unsafe extern "C" fn secondary_effect_effect_name(ptr: ExternPointer) -> OwnedPtr { +unsafe extern "C" fn secondary_effect_effect_name(ptr: ExternPointer>) -> OwnedPtr { CString::new(ptr.as_ref().effect_name().str()).unwrap().into_raw() } /// The length of parameters of the effect. #[no_mangle] -unsafe extern "C" fn secondary_effect_parameter_length(ptr: ExternPointer) -> usize { +unsafe extern "C" fn secondary_effect_parameter_length(ptr: ExternPointer>) -> usize { ptr.as_ref().parameters().len() } /// Get a parameter of the effect. #[no_mangle] unsafe extern "C" fn secondary_effect_parameter_get( - ptr: ExternPointer, + ptr: ExternPointer>, index: usize, ) -> IdentifiablePointer { if let Some(v) = ptr.as_ref().parameters().get(index) { diff --git a/src/static_data/moves/move_data.rs b/src/static_data/moves/move_data.rs index 2b86626..98b56c0 100755 --- a/src/static_data/moves/move_data.rs +++ b/src/static_data/moves/move_data.rs @@ -60,7 +60,7 @@ pub enum MoveTarget { } /// A move is the skill Pokémon primarily use in battle. This is the data related to that. -#[derive(PartialEq, Debug)] +#[derive(Debug)] pub struct MoveData { /// A unique identifier so we know what value this is. identifier: ValueIdentifier, @@ -82,7 +82,7 @@ pub struct MoveData { /// The priority of the move. A higher priority means the move should go before other moves. priority: i8, /// The optional secondary effect the move has. - secondary_effect: Option, + secondary_effect: Option>, /// Arbitrary flags that can be applied to the move. flags: HashSet, } @@ -98,7 +98,7 @@ impl MoveData { base_usages: u8, target: MoveTarget, priority: i8, - secondary_effect: Option, + secondary_effect: Option>, flags: HashSet, ) -> MoveData { MoveData { @@ -151,7 +151,7 @@ impl MoveData { } /// The optional secondary effect the move has. - pub fn secondary_effect(&self) -> &Option { + pub fn secondary_effect(&self) -> &Option> { &self.secondary_effect } diff --git a/src/static_data/moves/secondary_effect.rs b/src/static_data/moves/secondary_effect.rs index d4ab9bd..fa5c21b 100755 --- a/src/static_data/moves/secondary_effect.rs +++ b/src/static_data/moves/secondary_effect.rs @@ -1,9 +1,20 @@ use crate::static_data::EffectParameter; use crate::{StringKey, ValueIdentifiable, ValueIdentifier}; +use std::fmt::Debug; /// A secondary effect is an effect on a move that happens after it hits. -#[derive(PartialEq, Debug)] -pub struct SecondaryEffect { +pub trait SecondaryEffect: Debug + ValueIdentifiable { + /// The chance in percentages that the effect triggers. -1 to make it always trigger. + fn chance(&self) -> f32; + /// The name of the effect. + fn effect_name(&self) -> &StringKey; + /// A list of parameters for the effect. + fn parameters(&self) -> &Vec; +} + +/// A secondary effect is an effect on a move that happens after it hits. +#[derive(Debug)] +pub struct SecondaryEffectImpl { /// A unique identifier so we know what value this is. identifier: ValueIdentifier, /// The chance in percentages that the effect triggers. -1 to make it always trigger. @@ -14,32 +25,34 @@ pub struct SecondaryEffect { parameters: Vec, } -impl SecondaryEffect { +impl SecondaryEffectImpl { /// Instantiates a new Secondary Effect. - pub fn new(chance: f32, effect_name: StringKey, parameters: Vec) -> SecondaryEffect { - SecondaryEffect { + pub fn new(chance: f32, effect_name: StringKey, parameters: Vec) -> Self { + Self { identifier: Default::default(), chance, effect_name, parameters, } } +} +impl SecondaryEffect for SecondaryEffectImpl { /// The chance in percentages that the effect triggers. -1 to make it always trigger. - pub fn chance(&self) -> f32 { + fn chance(&self) -> f32 { self.chance } /// The name of the effect. - pub fn effect_name(&self) -> &StringKey { + fn effect_name(&self) -> &StringKey { &self.effect_name } /// A list of parameters for the effect. - pub fn parameters(&self) -> &Vec { + fn parameters(&self) -> &Vec { &self.parameters } } -impl ValueIdentifiable for SecondaryEffect { +impl ValueIdentifiable for SecondaryEffectImpl { fn value_identifier(&self) -> ValueIdentifier { self.identifier } @@ -50,14 +63,15 @@ mod tests { use assert_approx_eq::assert_approx_eq; use crate::static_data::moves::secondary_effect::SecondaryEffect; + use crate::static_data::SecondaryEffectImpl; #[test] fn create_secondary_effect() { - let empty = SecondaryEffect::new(0.0, "".into(), vec![]); + let empty = SecondaryEffectImpl::new(0.0, "".into(), vec![]); assert_approx_eq!(empty.chance(), 0.0); assert_eq!(empty.effect_name(), &"".into()); assert_eq!(empty.parameters().len(), 0); - let set = SecondaryEffect::new(50.0, "foo".into(), Vec::new()); + let set = SecondaryEffectImpl::new(50.0, "foo".into(), Vec::new()); assert_approx_eq!(set.chance(), 50.0); assert_eq!(set.effect_name(), &"foo".into()); assert_eq!(set.parameters().len(), 0); diff --git a/tests/common/library_loader.rs b/tests/common/library_loader.rs index ecec0d9..d648f2e 100755 --- a/tests/common/library_loader.rs +++ b/tests/common/library_loader.rs @@ -18,7 +18,7 @@ use pkmn_lib::script_implementations::wasm::script_resolver::WebAssemblyScriptRe use pkmn_lib::static_data::{ AbilityImpl, AbilityLibrary, BattleItemCategory, DataLibrary, EffectParameter, Form, GrowthRateLibrary, ItemImpl, ItemLibrary, LearnableMoves, LibrarySettings, LookupGrowthRate, MoveData, MoveLibrary, NatureImpl, NatureLibrary, - SecondaryEffect, Species, StaticData, StaticStatisticSet, Statistic, TypeLibrary, + SecondaryEffect, SecondaryEffectImpl, Species, StaticData, StaticStatisticSet, Statistic, TypeLibrary, }; use pkmn_lib::StringKey; @@ -182,7 +182,7 @@ pub fn load_moves(path: &String, lib: &mut StaticData) { let pp = move_data.get("pp").unwrap().as_i64().unwrap() as u8; let target = serde_json::from_value(move_data.get("target").unwrap().clone()).unwrap(); let priority = move_data.get("priority").unwrap().as_i64().unwrap() as i8; - let secondary_effect = if let Some(v) = move_data.get("effect") { + let secondary_effect: Option> = if let Some(v) = move_data.get("effect") { let mut chance = -1.0; if let Some(chance_value) = v.get("chance") { chance = chance_value.as_f64().unwrap() as f32; @@ -195,11 +195,11 @@ pub fn load_moves(path: &String, lib: &mut StaticData) { } } - Some(SecondaryEffect::new( + Some(Box::new(SecondaryEffectImpl::new( chance, v.get("name").unwrap().as_str().unwrap().into(), parameters, - )) + ))) } else { None };