diff --git a/src/dynamic_data/event_hooks.rs b/src/dynamic_data/event_hooks.rs index a706c83..607b684 100755 --- a/src/dynamic_data/event_hooks.rs +++ b/src/dynamic_data/event_hooks.rs @@ -58,7 +58,7 @@ pub enum Event<'own> { /// The index of the Pokemon that got switched in/out on its side index: u8, /// The new Pokemon that will be on the spot. If none, the spot will now be empty. - pokemon: Option<&'own Pokemon>, + pokemon: Option>, }, /// A swap event happens when two Pokemon on a side swap positions. Note that this is rare. Swap { diff --git a/src/dynamic_data/models/battle_side.rs b/src/dynamic_data/models/battle_side.rs index 5e3bc38..cb3aaae 100755 --- a/src/dynamic_data/models/battle_side.rs +++ b/src/dynamic_data/models/battle_side.rs @@ -193,7 +193,7 @@ impl BattleSide { battle.event_hook().trigger(Event::Switch { side_index: self.index, index, - pokemon: Some(pokemon), + pokemon: Some(pokemon.clone()), }); script_hook!(on_switch_in, pokemon, pokemon); } else { diff --git a/src/dynamic_data/models/learned_move.rs b/src/dynamic_data/models/learned_move.rs index 6187aba..ea10441 100755 --- a/src/dynamic_data/models/learned_move.rs +++ b/src/dynamic_data/models/learned_move.rs @@ -86,7 +86,7 @@ impl LearnedMove { if x + uses > self.max_pp { uses = self.max_pp - x; } - Some(x) + Some(x + uses) }) .unwrap(); } @@ -97,3 +97,29 @@ impl ValueIdentifiable for LearnedMove { self.identifier } } + +#[cfg(test)] +mod tests { + use super::*; + use crate::static_data::{MoveCategory, MoveTarget}; + + #[test] + fn create_learned_move_restore_uses() { + let data = Arc::new(MoveData::new( + &"foo".into(), + 0u8.into(), + MoveCategory::Special, + 100, + 20, + 30, + MoveTarget::All, + 0, + None, + Default::default(), + )); + let learned_move = LearnedMove::new(&data, MoveLearnMethod::Level); + assert!(learned_move.try_use(15)); + learned_move.restore_uses(5); + assert_eq!(20, learned_move.remaining_pp()); + } +} diff --git a/src/ffi/dynamic_data/models/event.rs b/src/ffi/dynamic_data/models/event.rs new file mode 100644 index 0000000..4052073 --- /dev/null +++ b/src/ffi/dynamic_data/models/event.rs @@ -0,0 +1,97 @@ +use crate::dynamic_data::{Event, Pokemon}; +use crate::ffi::{ExternPointer, IdentifiablePointer}; +use std::sync::Arc; + +/// The kind of the event. +#[no_mangle] +extern "C" fn event_kind(ptr: ExternPointer) -> u8 { + match ptr.as_ref() { + Event::Switch { .. } => 1, + Event::Swap { .. } => 2, + Event::SpeciesChange { .. } => 3, + Event::FormChange { .. } => 4, + Event::Damage { .. } => 5, + Event::Heal { .. } => 6, + Event::Faint { .. } => 7, + Event::MoveUse { .. } => 8, + Event::Miss { .. } => 9, + Event::EndTurn => 10, + Event::StatBoostChange { .. } => 11, + } +} + +/// Generates the entire FFI function we need for an event. +macro_rules! event_ffi { + ( + $event_name:ident + { + $( + $(#[doc = $doc:expr])? + $par_name:ident: $par_type:ty, + )+ + }, + $ctor:block + ) => { + paste::paste!{ + /// A C struct to hold the data for the event + #[repr(C)] + struct [<$event_name Data>]{ + $( + $(#[doc = $doc])? + $par_name: $par_type, + )+ + } + /// The getter for the data for the relevant event. + #[no_mangle] + extern "C" fn [](ptr: ExternPointer) -> [<$event_name Data>] { + if let Event::$event_name { + $( + $par_name, + )+ + } = ptr.as_ref() + { + $ctor + } + panic!(concat!("Event was not a ", stringify!($event_name), " data")); + } + + } + }; +} + +event_ffi!( + Switch + { + /// The side the Pokemon got switched from/on + side_index: u8, + /// The index of the Pokemon that got switched in/out on its side + index: u8, + /// The new Pokemon that will be on the spot. If none, the spot will be null. + pokemon: IdentifiablePointer>, + }, + { + return SwitchData{ + side_index: *side_index, + index: *index, + pokemon: pokemon.clone().into(), + } + } +); + +event_ffi!( + Swap { + /// The side the Pokemon swapped on. + side_index: u8, + /// The index on the side of the first Pokemon that was swapped. + index_a: u8, + /// The index on the side of the second pokemon that was swapped. + index_b: u8, + }, + { + return SwapData { + side_index: *side_index, + index_a: *index_a, + index_b: *index_b, + }; + } +); diff --git a/src/ffi/dynamic_data/models/learned_move.rs b/src/ffi/dynamic_data/models/learned_move.rs index ef0c7ce..abcac96 100644 --- a/src/ffi/dynamic_data/models/learned_move.rs +++ b/src/ffi/dynamic_data/models/learned_move.rs @@ -1,6 +1,7 @@ use crate::dynamic_data::{LearnedMove, MoveLearnMethod}; -use crate::ffi::{ExternPointer, IdentifiablePointer}; +use crate::ffi::{ExternPointer, IdentifiablePointer, OwnedPtr}; use crate::static_data::MoveData; +use std::ptr::drop_in_place; use std::sync::Arc; /// Instantiate a new learned move. @@ -12,6 +13,12 @@ extern "C" fn learned_move_new( Arc::new(LearnedMove::new(move_data.as_ref(), learn_method)).into() } +/// Drops a learned move. +#[no_mangle] +extern "C" fn learned_move_drop(learned_move: OwnedPtr>) { + unsafe { drop_in_place(learned_move) } +} + /// The immutable move information of the move. #[no_mangle] extern "C" fn learned_move_move_data( @@ -39,7 +46,7 @@ extern "C" fn learned_move_learn_method(learned_move: ExternPointer>, amount: u8) -> u8 { u8::from(learned_move.as_ref().try_use(amount)) diff --git a/src/ffi/dynamic_data/models/mod.rs b/src/ffi/dynamic_data/models/mod.rs index 344c989..ee3f1cd 100644 --- a/src/ffi/dynamic_data/models/mod.rs +++ b/src/ffi/dynamic_data/models/mod.rs @@ -2,6 +2,8 @@ mod battle; /// The foreign function interface for a battle wrapper of a party. mod battle_party; +/// The foreign function interface for a battle event +mod event; /// The foreign function interface for a Learned Move. mod learned_move; /// Wrapper classed for the event hooks. diff --git a/src/ffi/dynamic_data/models/native_event_hook.rs b/src/ffi/dynamic_data/models/native_event_hook.rs index 617113a..f3e7944 100644 --- a/src/ffi/dynamic_data/models/native_event_hook.rs +++ b/src/ffi/dynamic_data/models/native_event_hook.rs @@ -1,10 +1,11 @@ use crate::dynamic_data::Event; +use crate::ffi::BorrowedPtr; /// Wrapper class for easier use of an external function pointer. #[repr(C)] pub(super) struct NativeEventHook { /// The actual C function to be called. - f: extern "C" fn(*const Event), + f: extern "C" fn(BorrowedPtr), } impl NativeEventHook { diff --git a/src/ffi/mod.rs b/src/ffi/mod.rs index d455397..49a033b 100644 --- a/src/ffi/mod.rs +++ b/src/ffi/mod.rs @@ -139,6 +139,20 @@ 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()) }; + Self { + ptr: Box::into_raw(Box::new(v)), + id, + } + } else { + IdentifiablePointer::none() + } + } +} + impl From> for IdentifiablePointer { fn from(v: Box) -> Self { let id = unsafe { transmute(v.value_identifier()) };