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; /// Instantiates a new Pokemon. #[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() } /// Drops an Arc reference held by the FFI. #[no_mangle] unsafe extern "C" fn pokemon_drop(ptr: OwnedPtr>) { drop_in_place(ptr); } /// The library data of the Pokemon. #[no_mangle] extern "C" fn pokemon_library(ptr: ExternPointer>) -> IdentifiablePointer> { ptr.as_ref().library().clone().into() } /// The species of the Pokemon. #[no_mangle] extern "C" fn pokemon_species(ptr: ExternPointer>) -> IdentifiablePointer> { ptr.as_ref().species().into() } /// The form of the Pokemon. #[no_mangle] extern "C" fn pokemon_form(ptr: ExternPointer>) -> IdentifiablePointer> { ptr.as_ref().form().into() } /// The species that should be displayed to the user. This handles stuff like the Illusion ability. #[no_mangle] extern "C" fn pokemon_display_species(ptr: ExternPointer>) -> IdentifiablePointer> { ptr.as_ref().display_species().into() } /// The form that should be displayed to the user. This handles stuff like the Illusion ability. #[no_mangle] extern "C" fn pokemon_display_form(ptr: ExternPointer>) -> IdentifiablePointer> { ptr.as_ref().display_form().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); /// Gets the held item of a Pokemon #[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() } } /// Checks whether the Pokemon is holding a specific item. #[no_mangle] extern "C" fn pokemon_has_held_item(ptr: ExternPointer>, name: *const c_char) -> u8 { let name = unsafe { CStr::from_ptr(name) }.into(); u8::from(ptr.as_ref().has_held_item(&name)) } /// Changes the held item of the Pokemon. Returns the previously held item. #[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.into() } else { IdentifiablePointer::none() } } /// Removes the held item from the Pokemon. Returns the previously held item. #[no_mangle] extern "C" fn pokemon_remove_held_item(ptr: ExternPointer>) -> IdentifiablePointer> { if let Some(v) = ptr.as_ref().remove_held_item() { v.into() } else { IdentifiablePointer::none() } } /// Makes the Pokemon uses its held item. #[no_mangle] extern "C" fn pokemon_consume_held_item(ptr: ExternPointer>) -> u8 { u8::from(ptr.as_ref().consume_held_item()) } 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); /// An optional nickname of the Pokemon. #[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() } } /// Whether the actual ability on the form is a hidden ability. #[no_mangle] extern "C" fn pokemon_real_ability_is_hidden(ptr: ExternPointer>) -> u8 { u8::from(ptr.as_ref().real_ability().hidden) } /// The index of the actual ability on the form. #[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); /// Gets a learned move of the Pokemon. Index should generally be below [`MAX_MOVES`], you will get /// a null pointer otherwise. #[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() } } /// The stats of the Pokemon when disregarding any stat boosts. #[no_mangle] extern "C" fn pokemon_flat_stats(ptr: ExternPointer>) -> IdentifiablePointer> { (ptr.as_ref().flat_stats() as *const StatisticSet).into() } /// The stats of the Pokemon including the stat boosts. #[no_mangle] extern "C" fn pokemon_boosted_stats(ptr: ExternPointer>) -> IdentifiablePointer> { (ptr.as_ref().boosted_stats() as *const StatisticSet).into() } /// Get the stat boosts for a specific stat. #[no_mangle] extern "C" fn pokemon_get_stat_boost(ptr: ExternPointer>, statistic: Statistic) -> i8 { ptr.as_ref().stat_boost(statistic) } /// Change a boosted stat by a certain amount. #[no_mangle] extern "C" fn pokemon_change_stat_boost( ptr: ExternPointer>, stat: Statistic, diff_amount: i8, self_inflicted: u8, ) -> u8 { u8::from(ptr.as_ref().change_stat_boost(stat, diff_amount, self_inflicted == 1)) } /// Gets a [individual value](https://bulbapedia.bulbagarden.net/wiki/Individual_values) of the Pokemon. #[no_mangle] extern "C" fn pokemon_get_individual_value(ptr: ExternPointer>, stat: Statistic) -> u8 { ptr.as_ref().individual_values().get_stat(stat) } /// Modifies a [individual value](https://bulbapedia.bulbagarden.net/wiki/Individual_values) of the Pokemon. #[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(); } /// Gets a [effort value](https://bulbapedia.bulbagarden.net/wiki/Effort_values) of the Pokemon. #[no_mangle] extern "C" fn pokemon_get_effort_value(ptr: ExternPointer>, stat: Statistic) -> u8 { ptr.as_ref().effort_values().get_stat(stat) } /// Modifies a [effort value](https://bulbapedia.bulbagarden.net/wiki/Effort_values) of the Pokemon. #[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(); } /// Gets the data for the battle the Pokemon is currently in. If the Pokemon is not in a battle, this /// returns null. #[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() } } /// Get the index of the side of the battle the Pokemon is in. If the Pokemon /// is not on the battlefield, this always returns 0. #[no_mangle] extern "C" fn pokemon_get_battle_side_index(ptr: ExternPointer>) -> u8 { ptr.as_ref().get_battle_side_index().unwrap_or_default() } /// Get the index of the slot on the side of the battle the Pokemon is in. If the Pokemon // is not on the battlefield, this always returns 0. #[no_mangle] extern "C" fn pokemon_get_battle_index(ptr: ExternPointer>) -> u8 { ptr.as_ref().get_battle_index().unwrap_or_default() } /// Returns whether something overrides the ability. #[no_mangle] extern "C" fn pokemon_is_ability_overriden(ptr: ExternPointer>) -> u8 { u8::from(ptr.as_ref().is_ability_overriden()) } /// Returns the currently active ability. #[no_mangle] extern "C" fn pokemon_active_ability(ptr: ExternPointer>) -> IdentifiablePointer> { ptr.as_ref().active_ability().into() } /// Whether or not the Pokemon is allowed to gain experience. #[no_mangle] extern "C" fn pokemon_allowed_experience_gain(ptr: ExternPointer>) -> u8 { u8::from(ptr.as_ref().allowed_experience_gain()) } /// The [nature](https://bulbapedia.bulbagarden.net/wiki/Nature) of the Pokemon. #[no_mangle] extern "C" fn pokemon_nature(ptr: ExternPointer>) -> IdentifiablePointer> { ptr.as_ref().nature().clone().into() } /// 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. #[no_mangle] extern "C" fn pokemon_recalculate_flat_stats(ptr: ExternPointer>) { ptr.as_ref().recalculate_flat_stats() } /// Calculates the boosted stats on the Pokemon. This should be called when a stat boost changes. #[no_mangle] extern "C" fn pokemon_recalculate_boosted_stats(ptr: ExternPointer>) { ptr.as_ref().recalculate_boosted_stats() } /// Change the species of the Pokemon. #[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()) } /// Change the form of the Pokemon. #[no_mangle] extern "C" fn pokemon_change_form(ptr: ExternPointer>, form: ExternPointer>) { ptr.as_ref().change_form(form.as_ref()) } /// Whether or not the Pokemon is useable in a battle. #[no_mangle] extern "C" fn pokemon_is_usable(ptr: ExternPointer>) -> u8 { u8::from(ptr.as_ref().is_usable()) } /// Returns whether the Pokemon is fainted. #[no_mangle] extern "C" fn pokemon_is_fainted(ptr: ExternPointer>) -> u8 { u8::from(ptr.as_ref().is_fainted()) } /// Whether or not the Pokemon is on the battlefield. #[no_mangle] extern "C" fn pokemon_is_on_battlefield(ptr: ExternPointer>) -> u8 { u8::from(ptr.as_ref().is_on_battlefield()) } /// Damages the Pokemon by a certain amount of damage, from a damage source. #[no_mangle] extern "C" fn pokemon_damage(ptr: ExternPointer>, damage: u32, source: DamageSource) { ptr.as_ref().damage(damage, source) } /// Heals the Pokemon by a specific amount. Unless allow_revive is set to true, this will not /// heal if the Pokemon has 0 health. If the amount healed is 0, this will return false. #[no_mangle] extern "C" fn pokemon_heal(ptr: ExternPointer>, amount: u32, allow_revive: u8) -> bool { ptr.as_ref().heal(amount, allow_revive == 1) } /// Learn a move. #[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) } } /// Removes the current non-volatile status from the Pokemon. #[no_mangle] extern "C" fn pokemon_clear_status(ptr: ExternPointer>) { ptr.as_ref().clear_status() }