From 9efe1b4e2246e92d0b9ccf2595d88c00e87ecec7 Mon Sep 17 00:00:00 2001 From: Deukhoofd Date: Fri, 14 Oct 2022 13:59:04 +0200 Subject: [PATCH] FFI for Pokemon class --- src/dynamic_data/flow/turn_runner.rs | 2 +- src/dynamic_data/models/battle.rs | 11 +- src/dynamic_data/models/learned_move.rs | 11 + src/dynamic_data/models/pokemon.rs | 109 +++--- .../dynamic_data/libraries/dynamic_library.rs | 5 +- src/ffi/dynamic_data/mod.rs | 3 +- src/ffi/dynamic_data/models/mod.rs | 1 + src/ffi/dynamic_data/models/pokemon.rs | 342 ++++++++++++++++++ src/ffi/mod.rs | 12 +- .../export_registry/dynamic_data/pokemon.rs | 2 +- 10 files changed, 439 insertions(+), 59 deletions(-) create mode 100644 src/ffi/dynamic_data/models/mod.rs create mode 100644 src/ffi/dynamic_data/models/pokemon.rs diff --git a/src/dynamic_data/flow/turn_runner.rs b/src/dynamic_data/flow/turn_runner.rs index 81f3c92..5189710 100755 --- a/src/dynamic_data/flow/turn_runner.rs +++ b/src/dynamic_data/flow/turn_runner.rs @@ -194,7 +194,7 @@ impl Battle { .library() .static_data() .types() - .get_effectiveness(hit_type, target.types()); + .get_effectiveness(hit_type, &target.types()); script_hook!( change_effectiveness, executing_move, diff --git a/src/dynamic_data/models/battle.rs b/src/dynamic_data/models/battle.rs index f9fec84..09c83a0 100755 --- a/src/dynamic_data/models/battle.rs +++ b/src/dynamic_data/models/battle.rs @@ -18,12 +18,14 @@ use crate::dynamic_data::VolatileScriptsOwner; use crate::dynamic_data::{is_valid_target, ScriptWrapper}; use crate::dynamic_data::{ChoiceQueue, ScriptContainer}; use crate::dynamic_data::{ScriptCategory, ScriptSource, ScriptSourceData}; -use crate::{script_hook, PkmnResult, StringKey}; +use crate::{script_hook, PkmnResult, StringKey, ValueIdentifiable, ValueIdentifier}; /// A pokemon battle, with any amount of sides and pokemon per side. #[derive(Debug)] #[cfg_attr(feature = "wasm", derive(unique_type_id_derive::UniqueTypeId))] pub struct Battle { + /// A unique identifier so we know what value this is. + identifier: ValueIdentifier, /// The library the battle uses for handling. library: Arc, /// A list of all different parties in the battle. @@ -81,6 +83,7 @@ impl Battle { } let mut battle = Self { + identifier: Default::default(), library, parties, can_flee, @@ -389,6 +392,12 @@ impl ScriptSource for Battle { } } +impl ValueIdentifiable for Battle { + fn value_identifier(&self) -> ValueIdentifier { + self.identifier + } +} + /// The result of a battle. #[derive(Debug, Copy, Clone)] pub enum BattleResult { diff --git a/src/dynamic_data/models/learned_move.rs b/src/dynamic_data/models/learned_move.rs index 5a151f2..d216799 100755 --- a/src/dynamic_data/models/learned_move.rs +++ b/src/dynamic_data/models/learned_move.rs @@ -1,13 +1,17 @@ use std::sync::atomic::{AtomicU8, Ordering}; use std::sync::Arc; +use crate::dynamic_data::Pokemon; use crate::static_data::MoveData; +use crate::{ValueIdentifiable, ValueIdentifier}; /// A learned move is the data attached to a Pokemon for a move it has learned. It has information /// such as the remaining amount of users, how it has been learned, etc. #[derive(Debug)] #[cfg_attr(feature = "wasm", derive(unique_type_id_derive::UniqueTypeId))] pub struct LearnedMove { + /// A unique identifier so we know what value this is. + identifier: ValueIdentifier, /// The immutable move information of the move. move_data: Arc, /// The maximal power points for this move. @@ -33,6 +37,7 @@ impl LearnedMove { /// Instantiate a new learned move. pub fn new(move_data: &Arc, learn_method: MoveLearnMethod) -> Self { Self { + identifier: Default::default(), move_data: move_data.clone(), max_pp: move_data.base_usages(), remaining_pp: AtomicU8::new(move_data.base_usages()), @@ -87,3 +92,9 @@ impl LearnedMove { .unwrap(); } } + +impl ValueIdentifiable for LearnedMove { + fn value_identifier(&self) -> ValueIdentifier { + self.identifier + } +} diff --git a/src/dynamic_data/models/pokemon.rs b/src/dynamic_data/models/pokemon.rs index 4b3285d..e43c336 100755 --- a/src/dynamic_data/models/pokemon.rs +++ b/src/dynamic_data/models/pokemon.rs @@ -3,7 +3,8 @@ use std::sync::atomic::{AtomicBool, AtomicU32, AtomicU8, Ordering}; use std::sync::{Arc, Weak}; use atomig::Atomic; -use parking_lot::RwLock; +use parking_lot::lock_api::RwLockReadGuard; +use parking_lot::{RawRwLock, RwLock}; use crate::defines::{LevelInt, MAX_MOVES}; use crate::dynamic_data::event_hooks::Event; @@ -21,18 +22,20 @@ use crate::static_data::{Ability, Statistic}; use crate::static_data::{AbilityIndex, DataLibrary}; use crate::static_data::{ClampedStatisticSet, StatisticSet}; use crate::utils::Random; -use crate::{script_hook, PkmnResult, StringKey}; +use crate::{script_hook, PkmnResult, StringKey, ValueIdentifiable, ValueIdentifier}; /// An individual Pokemon as we know and love them. #[derive(Debug)] #[cfg_attr(feature = "wasm", derive(unique_type_id_derive::UniqueTypeId))] pub struct Pokemon { + /// A unique identifier so we know what value this is. + identifier: ValueIdentifier, /// The library data of the Pokemon. library: Arc, /// The species of the Pokemon. - species: Arc, + species: RwLock>, /// The form of the Pokemon. - form: Arc
, + form: RwLock>, /// An optional display species of the Pokemon. If this is set, the client should display this /// species. An example of usage for this is the Illusion ability. @@ -49,7 +52,7 @@ pub struct Pokemon { unique_identifier: u32, /// The gender of the Pokemon. - gender: Gender, + gender: RwLock, /// The coloring of the Pokemon. Value 0 is the default, value 1 means shiny. Other values are /// currently not used, and can be used for other implementations. coloring: u8, @@ -96,7 +99,7 @@ pub struct Pokemon { allowed_experience: bool, /// The current types of the Pokemon. - types: Vec, + types: RwLock>, /// Whether or not this Pokemon is an egg. is_egg: bool, /// Whether or not this Pokemon was caught this battle. @@ -142,15 +145,16 @@ impl Pokemon { .unwrap_or_else(|| panic!("Unknown nature name was given: {}.", &nature)) .clone(); let mut pokemon = Self { + identifier: Default::default(), library, - species, - form: form.clone(), + species: RwLock::new(species), + form: RwLock::new(form.clone()), display_species: None, display_form: None, level, experience: AtomicU32::new(experience), unique_identifier, - gender, + gender: RwLock::new(gender), coloring, held_item: RwLock::new(None), current_health: AtomicU32::new(1), @@ -168,7 +172,7 @@ impl Pokemon { battle_data: RwLock::new(None), moves: RwLock::new([None, None, None, None]), allowed_experience: false, - types: form.types().to_vec(), + types: RwLock::new(form.types().to_vec()), is_egg: false, is_caught: false, held_item_trigger_script: ScriptContainer::default(), @@ -189,27 +193,27 @@ impl Pokemon { &self.library } /// The species of the Pokemon. - pub fn species(&self) -> &Arc { - &self.species + pub fn species(&self) -> Arc { + self.species.read().clone() } /// The form of the Pokemon. - pub fn form(&self) -> &Arc { - &self.form + pub fn form(&self) -> Arc { + self.form.read().clone() } /// The species that should be displayed to the user. This handles stuff like the Illusion ability. - pub fn display_species(&self) -> &Arc { + pub fn display_species(&self) -> Arc { if let Some(v) = &self.display_species { - v + v.clone() } else { - &self.species + self.species() } } /// The form that should be displayed to the user. This handles stuff like the Illusion ability. - pub fn display_form(&self) -> &Arc { + pub fn display_form(&self) -> Arc { if let Some(v) = &self.display_form { - v + v.clone() } else { - &self.form + self.form() } } /// The current level of the Pokemon. @@ -226,7 +230,7 @@ impl Pokemon { } /// The gender of the Pokemon. pub fn gender(&self) -> Gender { - self.gender + *self.gender.read() } /// The coloring of the Pokemon. Value 0 is the default, value 1 means shiny. Other values are /// currently not used, and can be used for other implementations. @@ -245,11 +249,11 @@ impl Pokemon { } false } - /// Changes the held item of the Pokemon/ + /// Changes the held item of the Pokemon. Returns the previously held item. pub fn set_held_item(&self, item: &Arc) -> Option> { self.held_item.write().replace(item.clone()) } - /// Removes the held item from the Pokemon. + /// Removes the held item from the Pokemon. Returns the previously held item. pub fn remove_held_item(&self) -> Option> { self.held_item.write().take() } @@ -300,8 +304,8 @@ impl Pokemon { &self.ability_index } /// The current types of the Pokemon. - pub fn types(&self) -> &Vec { - &self.types + pub fn types(&self) -> RwLockReadGuard<'_, RawRwLock, Vec> { + self.types.read() } /// The moves the Pokemon has learned. This is of a set length of [`MAX_MOVES`]. Empty move slots /// are defined by None. @@ -314,7 +318,7 @@ impl Pokemon { &self.flat_stats } - /// The stats of the Pokemon including the stat boosts + /// The amount of boosts on a specific stat. pub fn stat_boosts(&self) -> &ClampedStatisticSet { &self.stat_boost } @@ -420,7 +424,7 @@ impl Pokemon { self.library .static_data() .abilities() - .get(self.form.get_ability(self.ability_index)) + .get(self.form().get_ability(self.ability_index)) .unwrap() } @@ -444,14 +448,16 @@ impl Pokemon { &self.nature } - /// Calculates the flat stats on the Pokemon. + /// Calculates the flat stats on the Pokemon. This should be called when for example the base + /// stats, level, nature, IV, or EV changes. This has a side effect of recalculating the boosted + /// stats, as those depend on the flat stats. pub fn recalculate_flat_stats(&self) { self.library .stat_calculator() .calculate_flat_stats(self, &self.flat_stats); self.recalculate_boosted_stats(); } - /// Calculates the boosted stats on the Pokemon. + /// Calculates the boosted stats on the Pokemon. This should be called when a stat boost changes. pub fn recalculate_boosted_stats(&self) { self.library .stat_calculator() @@ -459,25 +465,25 @@ impl Pokemon { } /// Change the species of the Pokemon. - pub fn change_species(&mut self, species: Arc, form: Arc) { - self.species = species.clone(); - self.form = form.clone(); + pub fn change_species(&self, species: Arc, form: Arc) { + *self.species.write() = species.clone(); + *self.form.write() = form.clone(); // If the pokemon is genderless, but it's new species is not, we want to set its gender - if self.gender != Gender::Genderless && species.gender_rate() < 0.0 { + if self.gender() != Gender::Genderless && species.gender_rate() < 0.0 { // If we're in battle, use the battle random for predictability let r = self.battle_data.read(); if let Some(data) = r.deref() { let mut random = data.battle().unwrap().random().get_rng().lock().unwrap(); - self.gender = species.get_random_gender(random.deref_mut()); + *self.gender.write() = species.get_random_gender(random.deref_mut()); } else { // If we're not in battle, just use a new random. - self.gender = species.get_random_gender(&mut Random::default()); + *self.gender.write() = species.get_random_gender(&mut Random::default()); } } // Else if the new species is genderless, but the pokemon has a gender, make the creature genderless. - else if species.gender_rate() < 0.0 && self.gender != Gender::Genderless { - self.gender = Gender::Genderless; + else if species.gender_rate() < 0.0 && self.gender() != Gender::Genderless { + *self.gender.write() = Gender::Genderless; } let r = self.battle_data.read(); if let Some(battle_data) = &r.deref() { @@ -492,15 +498,18 @@ impl Pokemon { } /// Change the form of the Pokemon. - pub fn change_form(&mut self, form: &Arc) { - if Arc::ptr_eq(&self.form, form) { + pub fn change_form(&self, form: &Arc) { + if self.form().value_identifier() == form.value_identifier() { return; } - self.form = form.clone(); + *self.form.write() = form.clone(); - self.types.clear(); - for t in form.types() { - self.types.push(*t); + { + let mut type_lock = self.types.write(); + type_lock.clear(); + for t in form.types() { + type_lock.push(*t); + } } self.weight.store(form.weight(), Ordering::SeqCst); self.height.store(form.height(), Ordering::SeqCst); @@ -572,8 +581,8 @@ impl Pokemon { data.on_battle_field.store(value, Ordering::SeqCst); if !value { self.volatile.clear(); - self.weight.store(self.form.weight(), Ordering::SeqCst); - self.height.store(self.form.height(), Ordering::SeqCst); + self.weight.store(self.form().weight(), Ordering::SeqCst); + self.height.store(self.form().height(), Ordering::SeqCst); } } } @@ -782,6 +791,12 @@ impl VolatileScriptsOwner for Pokemon { } } +impl ValueIdentifiable for Pokemon { + fn value_identifier(&self) -> ValueIdentifier { + self.identifier + } +} + /// A source of damage. This should be as unique as possible. #[derive(Debug, Clone, Copy)] #[repr(u8)] @@ -821,7 +836,7 @@ pub mod test { 0, &"test_nature".into(), ); - assert_eq!(pokemon.species.name(), &"foo".into()); - assert_eq!(pokemon.form.name(), &"default".into()); + assert_eq!(pokemon.species().name(), &"foo".into()); + assert_eq!(pokemon.form().name(), &"default".into()); } } diff --git a/src/ffi/dynamic_data/libraries/dynamic_library.rs b/src/ffi/dynamic_data/libraries/dynamic_library.rs index 6d7c9b9..fd86e9e 100644 --- a/src/ffi/dynamic_data/libraries/dynamic_library.rs +++ b/src/ffi/dynamic_data/libraries/dynamic_library.rs @@ -1,6 +1,7 @@ use crate::dynamic_data::{BattleStatCalculator, DamageLibrary, DynamicLibrary, MiscLibrary, ScriptResolver}; use crate::ffi::{IdentifiablePointer, OwnedPtr}; use crate::static_data::StaticData; +use std::sync::Arc; #[no_mangle] extern "C" fn dynamic_library_new( @@ -9,9 +10,9 @@ extern "C" fn dynamic_library_new( damage_library: OwnedPtr>, misc_library: OwnedPtr>, script_resolver: OwnedPtr>, -) -> IdentifiablePointer { +) -> IdentifiablePointer> { unsafe { - Box::new(DynamicLibrary::new( + Arc::new(DynamicLibrary::new( *Box::from_raw(static_data), *Box::from_raw(stat_calculator), *Box::from_raw(damage_library), diff --git a/src/ffi/dynamic_data/mod.rs b/src/ffi/dynamic_data/mod.rs index 87ec77b..b8f1f0a 100644 --- a/src/ffi/dynamic_data/mod.rs +++ b/src/ffi/dynamic_data/mod.rs @@ -1 +1,2 @@ -mod libraries; \ No newline at end of file +mod libraries; +mod models; \ No newline at end of file diff --git a/src/ffi/dynamic_data/models/mod.rs b/src/ffi/dynamic_data/models/mod.rs new file mode 100644 index 0000000..f801f25 --- /dev/null +++ b/src/ffi/dynamic_data/models/mod.rs @@ -0,0 +1 @@ +mod pokemon; diff --git a/src/ffi/dynamic_data/models/pokemon.rs b/src/ffi/dynamic_data/models/pokemon.rs new file mode 100644 index 0000000..18dcfe1 --- /dev/null +++ b/src/ffi/dynamic_data/models/pokemon.rs @@ -0,0 +1,342 @@ +use crate::defines::LevelInt; +use crate::dynamic_data::{Battle, DamageSource, DynamicLibrary, LearnedMove, MoveLearnMethod, Pokemon}; +use crate::ffi::{ffi_arc_getter, ffi_vec_value_getters, ExternPointer, IdentifiablePointer, OwnedPtr}; +use crate::static_data::{ + Ability, AbilityIndex, Form, Gender, Item, Nature, Species, Statistic, StatisticSet, TypeIdentifier, +}; +use std::ffi::{c_char, CStr, CString}; +use std::ptr::drop_in_place; +use std::sync::Arc; + +#[no_mangle] +extern "C" fn pokemon_new( + library: ExternPointer>, + species: ExternPointer>, + form: ExternPointer>, + hidden_ability: bool, + ability_index: u8, + level: LevelInt, + unique_identifier: u32, + gender: Gender, + coloring: u8, + nature: *const c_char, +) -> IdentifiablePointer> { + let nature = unsafe { CStr::from_ptr(nature) }.into(); + Arc::new(Pokemon::new( + library.as_ref().clone(), + species.as_ref().clone(), + form.as_ref(), + AbilityIndex { + hidden: hidden_ability, + index: ability_index, + }, + level, + unique_identifier, + gender, + coloring, + &nature, + )) + .into() +} + +#[no_mangle] +unsafe extern "C" fn pokemon_drop(ptr: OwnedPtr>) { + drop_in_place(ptr); +} + +#[no_mangle] +extern "C" fn pokemon_library(ptr: ExternPointer>) -> IdentifiablePointer> { + ptr.as_ref().library().clone().into() +} + +#[no_mangle] +extern "C" fn pokemon_species(ptr: ExternPointer>) -> IdentifiablePointer> { + ptr.as_ref().species().clone().into() +} + +#[no_mangle] +extern "C" fn pokemon_form(ptr: ExternPointer>) -> IdentifiablePointer> { + ptr.as_ref().form().clone().into() +} + +#[no_mangle] +extern "C" fn pokemon_display_species(ptr: ExternPointer>) -> IdentifiablePointer> { + ptr.as_ref().display_species().clone().into() +} + +#[no_mangle] +extern "C" fn pokemon_display_form(ptr: ExternPointer>) -> IdentifiablePointer> { + ptr.as_ref().display_form().clone().into() +} + +ffi_arc_getter!(Pokemon, level, LevelInt); +ffi_arc_getter!(Pokemon, experience, u32); +ffi_arc_getter!(Pokemon, unique_identifier, u32); +ffi_arc_getter!(Pokemon, gender, Gender); +ffi_arc_getter!(Pokemon, coloring, u8); + +#[no_mangle] +extern "C" fn pokemon_held_item(ptr: ExternPointer>) -> IdentifiablePointer> { + if let Some(v) = ptr.as_ref().held_item().read().as_ref() { + v.clone().into() + } else { + IdentifiablePointer::none() + } +} + +#[no_mangle] +extern "C" fn pokemon_has_held_item(ptr: ExternPointer>, name: *const c_char) -> u8 { + let name = unsafe { CStr::from_ptr(name) }.into(); + if ptr.as_ref().has_held_item(&name) { + 1 + } else { + 0 + } +} + +#[no_mangle] +extern "C" fn pokemon_set_held_item( + ptr: ExternPointer>, + item: ExternPointer>, +) -> IdentifiablePointer> { + if let Some(v) = ptr.as_ref().set_held_item(item.as_ref()) { + v.clone().into() + } else { + IdentifiablePointer::none() + } +} + +#[no_mangle] +extern "C" fn pokemon_remove_held_item(ptr: ExternPointer>) -> IdentifiablePointer> { + if let Some(v) = ptr.as_ref().remove_held_item() { + v.clone().into() + } else { + IdentifiablePointer::none() + } +} + +#[no_mangle] +extern "C" fn pokemon_consume_held_item(ptr: ExternPointer>) -> u8 { + if ptr.as_ref().consume_held_item() { + 1 + } else { + 0 + } +} + +ffi_arc_getter!(Pokemon, current_health, u32); +ffi_arc_getter!(Pokemon, max_health, u32); +ffi_arc_getter!(Pokemon, weight, f32); +ffi_arc_getter!(Pokemon, height, f32); + +#[no_mangle] +extern "C" fn pokemon_nickname(ptr: ExternPointer>) -> *mut c_char { + let name = ptr.as_ref().nickname(); + if let Some(v) = name { + CString::new(v.as_str()).unwrap().into_raw() + } else { + std::ptr::null_mut() + } +} + +#[no_mangle] +extern "C" fn pokemon_real_ability_is_hidden(ptr: ExternPointer>) -> u8 { + if ptr.as_ref().real_ability().hidden { + 1 + } else { + 0 + } +} + +#[no_mangle] +extern "C" fn pokemon_real_ability_index(ptr: ExternPointer>) -> u8 { + ptr.as_ref().real_ability().index +} + +ffi_vec_value_getters!(Pokemon, types, TypeIdentifier); + +#[no_mangle] +extern "C" fn pokemon_learned_move_get( + ptr: ExternPointer>, + index: usize, +) -> IdentifiablePointer> { + if let Some(Some(v)) = ptr.as_ref().learned_moves().read().get(index) { + v.clone().into() + } else { + IdentifiablePointer::none() + } +} + +#[no_mangle] +extern "C" fn pokemon_flat_stats(ptr: ExternPointer>) -> IdentifiablePointer> { + (ptr.as_ref().flat_stats() as *const StatisticSet).into() +} + +#[no_mangle] +extern "C" fn pokemon_boosted_stats(ptr: ExternPointer>) -> IdentifiablePointer> { + (ptr.as_ref().boosted_stats() as *const StatisticSet).into() +} + +#[no_mangle] +extern "C" fn pokemon_get_stat_boost(ptr: ExternPointer>, statistic: Statistic) -> i8 { + ptr.as_ref().stat_boost(statistic) +} + +#[no_mangle] +extern "C" fn pokemon_change_stat_boost( + ptr: ExternPointer>, + stat: Statistic, + diff_amount: i8, + self_inflicted: u8, +) -> u8 { + if ptr.as_ref().change_stat_boost(stat, diff_amount, self_inflicted == 1) { + 1 + } else { + 0 + } +} + +#[no_mangle] +extern "C" fn pokemon_get_individual_value(ptr: ExternPointer>, stat: Statistic) -> u8 { + ptr.as_ref().individual_values().get_stat(stat) +} + +#[no_mangle] +extern "C" fn pokemon_set_individual_value(ptr: ExternPointer>, stat: Statistic, value: u8) { + ptr.as_ref().individual_values().set_stat(stat, value); + ptr.as_ref().recalculate_flat_stats(); +} + +#[no_mangle] +extern "C" fn pokemon_get_effort_value(ptr: ExternPointer>, stat: Statistic) -> u8 { + ptr.as_ref().effort_values().get_stat(stat) +} + +#[no_mangle] +extern "C" fn pokemon_set_effort_value(ptr: ExternPointer>, stat: Statistic, value: u8) { + ptr.as_ref().effort_values().set_stat(stat, value); + ptr.as_ref().recalculate_flat_stats(); +} + +#[no_mangle] +extern "C" fn pokemon_get_battle(ptr: ExternPointer>) -> IdentifiablePointer { + if let Some(v) = ptr.as_ref().get_battle() { + (v as *const Battle).into() + } else { + IdentifiablePointer::none() + } +} + +#[no_mangle] +extern "C" fn pokemon_get_battle_side_index(ptr: ExternPointer>) -> u8 { + ptr.as_ref().get_battle_side_index().unwrap_or_default() +} + +#[no_mangle] +extern "C" fn pokemon_get_battle_index(ptr: ExternPointer>) -> u8 { + ptr.as_ref().get_battle_index().unwrap_or_default() +} + +#[no_mangle] +extern "C" fn pokemon_is_ability_overriden(ptr: ExternPointer>) -> u8 { + if ptr.as_ref().is_ability_overriden() { + 1 + } else { + 0 + } +} + +#[no_mangle] +extern "C" fn pokemon_active_ability(ptr: ExternPointer>) -> IdentifiablePointer { + (ptr.as_ref().active_ability() as *const Ability).into() +} + +#[no_mangle] +extern "C" fn pokemon_allowed_experience_gain(ptr: ExternPointer>) -> u8 { + if ptr.as_ref().allowed_experience_gain() { + 1 + } else { + 0 + } +} + +#[no_mangle] +extern "C" fn pokemon_nature(ptr: ExternPointer>) -> IdentifiablePointer> { + ptr.as_ref().nature().clone().into() +} + +#[no_mangle] +extern "C" fn pokemon_recalculate_flat_stats(ptr: ExternPointer>) { + ptr.as_ref().recalculate_flat_stats() +} + +#[no_mangle] +extern "C" fn pokemon_recalculate_boosted_stats(ptr: ExternPointer>) { + ptr.as_ref().recalculate_boosted_stats() +} + +#[no_mangle] +extern "C" fn pokemon_change_species( + ptr: ExternPointer>, + species: ExternPointer>, + form: ExternPointer>, +) { + ptr.as_ref() + .change_species(species.as_ref().clone(), form.as_ref().clone()) +} + +#[no_mangle] +extern "C" fn pokemon_change_form(ptr: ExternPointer>, form: ExternPointer>) { + ptr.as_ref().change_form(form.as_ref()) +} + +#[no_mangle] +extern "C" fn pokemon_is_usable(ptr: ExternPointer>) -> u8 { + if ptr.as_ref().is_usable() { + 1 + } else { + 0 + } +} + +#[no_mangle] +extern "C" fn pokemon_is_fainted(ptr: ExternPointer>) -> u8 { + if ptr.as_ref().is_fainted() { + 1 + } else { + 0 + } +} + +#[no_mangle] +extern "C" fn pokemon_is_on_battlefield(ptr: ExternPointer>) -> u8 { + if ptr.as_ref().is_on_battlefield() { + 1 + } else { + 0 + } +} + +#[no_mangle] +extern "C" fn pokemon_damage(ptr: ExternPointer>, damage: u32, source: DamageSource) { + ptr.as_ref().damage(damage, source) +} + +#[no_mangle] +extern "C" fn pokemon_heal(ptr: ExternPointer>, amount: u32, allow_revive: u8) -> bool { + ptr.as_ref().heal(amount, allow_revive == 1) +} + +#[no_mangle] +extern "C" fn pokemon_learn_move( + ptr: ExternPointer>, + move_name: *const c_char, + learn_method: MoveLearnMethod, +) { + unsafe { ptr.as_ref().learn_move(&CStr::from_ptr(move_name).into(), learn_method) } +} + +#[no_mangle] +extern "C" fn pokemon_clear_status(ptr: ExternPointer>) { + ptr.as_ref().clear_status() +} diff --git a/src/ffi/mod.rs b/src/ffi/mod.rs index df5b374..6a029d7 100644 --- a/src/ffi/mod.rs +++ b/src/ffi/mod.rs @@ -110,12 +110,6 @@ impl ExternPointer { } } -impl Into> for *mut T { - fn into(self) -> ExternPointer { - ExternPointer { ptr: self } - } -} - #[repr(C)] pub(self) struct IdentifiablePointer { pub ptr: *const T, @@ -128,6 +122,12 @@ impl IdentifiablePointer { } } +impl Into> for *mut T { + fn into(self) -> ExternPointer { + ExternPointer { ptr: self } + } +} + impl From> for IdentifiablePointer> { fn from(v: Arc) -> Self { let id = v.value_identifier(); diff --git a/src/script_implementations/wasm/export_registry/dynamic_data/pokemon.rs b/src/script_implementations/wasm/export_registry/dynamic_data/pokemon.rs index 117f55b..38015d3 100755 --- a/src/script_implementations/wasm/export_registry/dynamic_data/pokemon.rs +++ b/src/script_implementations/wasm/export_registry/dynamic_data/pokemon.rs @@ -65,7 +65,7 @@ register! { pokemon: ExternRef, ) -> ExternRef { let species = pokemon.value_func(&env).unwrap().species(); - ExternRef::func_new(&env, species) + ExternRef::func_new(&env, &species) } fn pokemon_get_weight(