FFI for Pokemon class
This commit is contained in:
parent
a840605bf7
commit
9efe1b4e22
|
@ -194,7 +194,7 @@ impl Battle {
|
||||||
.library()
|
.library()
|
||||||
.static_data()
|
.static_data()
|
||||||
.types()
|
.types()
|
||||||
.get_effectiveness(hit_type, target.types());
|
.get_effectiveness(hit_type, &target.types());
|
||||||
script_hook!(
|
script_hook!(
|
||||||
change_effectiveness,
|
change_effectiveness,
|
||||||
executing_move,
|
executing_move,
|
||||||
|
|
|
@ -18,12 +18,14 @@ use crate::dynamic_data::VolatileScriptsOwner;
|
||||||
use crate::dynamic_data::{is_valid_target, ScriptWrapper};
|
use crate::dynamic_data::{is_valid_target, ScriptWrapper};
|
||||||
use crate::dynamic_data::{ChoiceQueue, ScriptContainer};
|
use crate::dynamic_data::{ChoiceQueue, ScriptContainer};
|
||||||
use crate::dynamic_data::{ScriptCategory, ScriptSource, ScriptSourceData};
|
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.
|
/// A pokemon battle, with any amount of sides and pokemon per side.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
#[cfg_attr(feature = "wasm", derive(unique_type_id_derive::UniqueTypeId))]
|
#[cfg_attr(feature = "wasm", derive(unique_type_id_derive::UniqueTypeId))]
|
||||||
pub struct Battle {
|
pub struct Battle {
|
||||||
|
/// A unique identifier so we know what value this is.
|
||||||
|
identifier: ValueIdentifier,
|
||||||
/// The library the battle uses for handling.
|
/// The library the battle uses for handling.
|
||||||
library: Arc<DynamicLibrary>,
|
library: Arc<DynamicLibrary>,
|
||||||
/// A list of all different parties in the battle.
|
/// A list of all different parties in the battle.
|
||||||
|
@ -81,6 +83,7 @@ impl Battle {
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut battle = Self {
|
let mut battle = Self {
|
||||||
|
identifier: Default::default(),
|
||||||
library,
|
library,
|
||||||
parties,
|
parties,
|
||||||
can_flee,
|
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.
|
/// The result of a battle.
|
||||||
#[derive(Debug, Copy, Clone)]
|
#[derive(Debug, Copy, Clone)]
|
||||||
pub enum BattleResult {
|
pub enum BattleResult {
|
||||||
|
|
|
@ -1,13 +1,17 @@
|
||||||
use std::sync::atomic::{AtomicU8, Ordering};
|
use std::sync::atomic::{AtomicU8, Ordering};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
use crate::dynamic_data::Pokemon;
|
||||||
use crate::static_data::MoveData;
|
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
|
/// 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.
|
/// such as the remaining amount of users, how it has been learned, etc.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
#[cfg_attr(feature = "wasm", derive(unique_type_id_derive::UniqueTypeId))]
|
#[cfg_attr(feature = "wasm", derive(unique_type_id_derive::UniqueTypeId))]
|
||||||
pub struct LearnedMove {
|
pub struct LearnedMove {
|
||||||
|
/// A unique identifier so we know what value this is.
|
||||||
|
identifier: ValueIdentifier,
|
||||||
/// The immutable move information of the move.
|
/// The immutable move information of the move.
|
||||||
move_data: Arc<MoveData>,
|
move_data: Arc<MoveData>,
|
||||||
/// The maximal power points for this move.
|
/// The maximal power points for this move.
|
||||||
|
@ -33,6 +37,7 @@ impl LearnedMove {
|
||||||
/// Instantiate a new learned move.
|
/// Instantiate a new learned move.
|
||||||
pub fn new(move_data: &Arc<MoveData>, learn_method: MoveLearnMethod) -> Self {
|
pub fn new(move_data: &Arc<MoveData>, learn_method: MoveLearnMethod) -> Self {
|
||||||
Self {
|
Self {
|
||||||
|
identifier: Default::default(),
|
||||||
move_data: move_data.clone(),
|
move_data: move_data.clone(),
|
||||||
max_pp: move_data.base_usages(),
|
max_pp: move_data.base_usages(),
|
||||||
remaining_pp: AtomicU8::new(move_data.base_usages()),
|
remaining_pp: AtomicU8::new(move_data.base_usages()),
|
||||||
|
@ -87,3 +92,9 @@ impl LearnedMove {
|
||||||
.unwrap();
|
.unwrap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl ValueIdentifiable for LearnedMove {
|
||||||
|
fn value_identifier(&self) -> ValueIdentifier {
|
||||||
|
self.identifier
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -3,7 +3,8 @@ use std::sync::atomic::{AtomicBool, AtomicU32, AtomicU8, Ordering};
|
||||||
use std::sync::{Arc, Weak};
|
use std::sync::{Arc, Weak};
|
||||||
|
|
||||||
use atomig::Atomic;
|
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::defines::{LevelInt, MAX_MOVES};
|
||||||
use crate::dynamic_data::event_hooks::Event;
|
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::{AbilityIndex, DataLibrary};
|
||||||
use crate::static_data::{ClampedStatisticSet, StatisticSet};
|
use crate::static_data::{ClampedStatisticSet, StatisticSet};
|
||||||
use crate::utils::Random;
|
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.
|
/// An individual Pokemon as we know and love them.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
#[cfg_attr(feature = "wasm", derive(unique_type_id_derive::UniqueTypeId))]
|
#[cfg_attr(feature = "wasm", derive(unique_type_id_derive::UniqueTypeId))]
|
||||||
pub struct Pokemon {
|
pub struct Pokemon {
|
||||||
|
/// A unique identifier so we know what value this is.
|
||||||
|
identifier: ValueIdentifier,
|
||||||
/// The library data of the Pokemon.
|
/// The library data of the Pokemon.
|
||||||
library: Arc<DynamicLibrary>,
|
library: Arc<DynamicLibrary>,
|
||||||
/// The species of the Pokemon.
|
/// The species of the Pokemon.
|
||||||
species: Arc<Species>,
|
species: RwLock<Arc<Species>>,
|
||||||
/// The form of the Pokemon.
|
/// The form of the Pokemon.
|
||||||
form: Arc<Form>,
|
form: RwLock<Arc<Form>>,
|
||||||
|
|
||||||
/// An optional display species of the Pokemon. If this is set, the client should display this
|
/// 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.
|
/// species. An example of usage for this is the Illusion ability.
|
||||||
|
@ -49,7 +52,7 @@ pub struct Pokemon {
|
||||||
unique_identifier: u32,
|
unique_identifier: u32,
|
||||||
|
|
||||||
/// The gender of the Pokemon.
|
/// The gender of the Pokemon.
|
||||||
gender: Gender,
|
gender: RwLock<Gender>,
|
||||||
/// The coloring of the Pokemon. Value 0 is the default, value 1 means shiny. Other values are
|
/// 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.
|
/// currently not used, and can be used for other implementations.
|
||||||
coloring: u8,
|
coloring: u8,
|
||||||
|
@ -96,7 +99,7 @@ pub struct Pokemon {
|
||||||
allowed_experience: bool,
|
allowed_experience: bool,
|
||||||
|
|
||||||
/// The current types of the Pokemon.
|
/// The current types of the Pokemon.
|
||||||
types: Vec<TypeIdentifier>,
|
types: RwLock<Vec<TypeIdentifier>>,
|
||||||
/// Whether or not this Pokemon is an egg.
|
/// Whether or not this Pokemon is an egg.
|
||||||
is_egg: bool,
|
is_egg: bool,
|
||||||
/// Whether or not this Pokemon was caught this battle.
|
/// 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))
|
.unwrap_or_else(|| panic!("Unknown nature name was given: {}.", &nature))
|
||||||
.clone();
|
.clone();
|
||||||
let mut pokemon = Self {
|
let mut pokemon = Self {
|
||||||
|
identifier: Default::default(),
|
||||||
library,
|
library,
|
||||||
species,
|
species: RwLock::new(species),
|
||||||
form: form.clone(),
|
form: RwLock::new(form.clone()),
|
||||||
display_species: None,
|
display_species: None,
|
||||||
display_form: None,
|
display_form: None,
|
||||||
level,
|
level,
|
||||||
experience: AtomicU32::new(experience),
|
experience: AtomicU32::new(experience),
|
||||||
unique_identifier,
|
unique_identifier,
|
||||||
gender,
|
gender: RwLock::new(gender),
|
||||||
coloring,
|
coloring,
|
||||||
held_item: RwLock::new(None),
|
held_item: RwLock::new(None),
|
||||||
current_health: AtomicU32::new(1),
|
current_health: AtomicU32::new(1),
|
||||||
|
@ -168,7 +172,7 @@ impl Pokemon {
|
||||||
battle_data: RwLock::new(None),
|
battle_data: RwLock::new(None),
|
||||||
moves: RwLock::new([None, None, None, None]),
|
moves: RwLock::new([None, None, None, None]),
|
||||||
allowed_experience: false,
|
allowed_experience: false,
|
||||||
types: form.types().to_vec(),
|
types: RwLock::new(form.types().to_vec()),
|
||||||
is_egg: false,
|
is_egg: false,
|
||||||
is_caught: false,
|
is_caught: false,
|
||||||
held_item_trigger_script: ScriptContainer::default(),
|
held_item_trigger_script: ScriptContainer::default(),
|
||||||
|
@ -189,27 +193,27 @@ impl Pokemon {
|
||||||
&self.library
|
&self.library
|
||||||
}
|
}
|
||||||
/// The species of the Pokemon.
|
/// The species of the Pokemon.
|
||||||
pub fn species(&self) -> &Arc<Species> {
|
pub fn species(&self) -> Arc<Species> {
|
||||||
&self.species
|
self.species.read().clone()
|
||||||
}
|
}
|
||||||
/// The form of the Pokemon.
|
/// The form of the Pokemon.
|
||||||
pub fn form(&self) -> &Arc<Form> {
|
pub fn form(&self) -> Arc<Form> {
|
||||||
&self.form
|
self.form.read().clone()
|
||||||
}
|
}
|
||||||
/// The species that should be displayed to the user. This handles stuff like the Illusion ability.
|
/// The species that should be displayed to the user. This handles stuff like the Illusion ability.
|
||||||
pub fn display_species(&self) -> &Arc<Species> {
|
pub fn display_species(&self) -> Arc<Species> {
|
||||||
if let Some(v) = &self.display_species {
|
if let Some(v) = &self.display_species {
|
||||||
v
|
v.clone()
|
||||||
} else {
|
} else {
|
||||||
&self.species
|
self.species()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/// The form that should be displayed to the user. This handles stuff like the Illusion ability.
|
/// The form that should be displayed to the user. This handles stuff like the Illusion ability.
|
||||||
pub fn display_form(&self) -> &Arc<Form> {
|
pub fn display_form(&self) -> Arc<Form> {
|
||||||
if let Some(v) = &self.display_form {
|
if let Some(v) = &self.display_form {
|
||||||
v
|
v.clone()
|
||||||
} else {
|
} else {
|
||||||
&self.form
|
self.form()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/// The current level of the Pokemon.
|
/// The current level of the Pokemon.
|
||||||
|
@ -226,7 +230,7 @@ impl Pokemon {
|
||||||
}
|
}
|
||||||
/// The gender of the Pokemon.
|
/// The gender of the Pokemon.
|
||||||
pub fn gender(&self) -> Gender {
|
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
|
/// 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.
|
/// currently not used, and can be used for other implementations.
|
||||||
|
@ -245,11 +249,11 @@ impl Pokemon {
|
||||||
}
|
}
|
||||||
false
|
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<Item>) -> Option<Arc<Item>> {
|
pub fn set_held_item(&self, item: &Arc<Item>) -> Option<Arc<Item>> {
|
||||||
self.held_item.write().replace(item.clone())
|
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<Arc<Item>> {
|
pub fn remove_held_item(&self) -> Option<Arc<Item>> {
|
||||||
self.held_item.write().take()
|
self.held_item.write().take()
|
||||||
}
|
}
|
||||||
|
@ -300,8 +304,8 @@ impl Pokemon {
|
||||||
&self.ability_index
|
&self.ability_index
|
||||||
}
|
}
|
||||||
/// The current types of the Pokemon.
|
/// The current types of the Pokemon.
|
||||||
pub fn types(&self) -> &Vec<TypeIdentifier> {
|
pub fn types(&self) -> RwLockReadGuard<'_, RawRwLock, Vec<TypeIdentifier>> {
|
||||||
&self.types
|
self.types.read()
|
||||||
}
|
}
|
||||||
/// The moves the Pokemon has learned. This is of a set length of [`MAX_MOVES`]. Empty move slots
|
/// The moves the Pokemon has learned. This is of a set length of [`MAX_MOVES`]. Empty move slots
|
||||||
/// are defined by None.
|
/// are defined by None.
|
||||||
|
@ -314,7 +318,7 @@ impl Pokemon {
|
||||||
&self.flat_stats
|
&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<i8, -6, 6> {
|
pub fn stat_boosts(&self) -> &ClampedStatisticSet<i8, -6, 6> {
|
||||||
&self.stat_boost
|
&self.stat_boost
|
||||||
}
|
}
|
||||||
|
@ -420,7 +424,7 @@ impl Pokemon {
|
||||||
self.library
|
self.library
|
||||||
.static_data()
|
.static_data()
|
||||||
.abilities()
|
.abilities()
|
||||||
.get(self.form.get_ability(self.ability_index))
|
.get(self.form().get_ability(self.ability_index))
|
||||||
.unwrap()
|
.unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -444,14 +448,16 @@ impl Pokemon {
|
||||||
&self.nature
|
&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) {
|
pub fn recalculate_flat_stats(&self) {
|
||||||
self.library
|
self.library
|
||||||
.stat_calculator()
|
.stat_calculator()
|
||||||
.calculate_flat_stats(self, &self.flat_stats);
|
.calculate_flat_stats(self, &self.flat_stats);
|
||||||
self.recalculate_boosted_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) {
|
pub fn recalculate_boosted_stats(&self) {
|
||||||
self.library
|
self.library
|
||||||
.stat_calculator()
|
.stat_calculator()
|
||||||
|
@ -459,25 +465,25 @@ impl Pokemon {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Change the species of the Pokemon.
|
/// Change the species of the Pokemon.
|
||||||
pub fn change_species(&mut self, species: Arc<Species>, form: Arc<Form>) {
|
pub fn change_species(&self, species: Arc<Species>, form: Arc<Form>) {
|
||||||
self.species = species.clone();
|
*self.species.write() = species.clone();
|
||||||
self.form = form.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 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
|
// If we're in battle, use the battle random for predictability
|
||||||
let r = self.battle_data.read();
|
let r = self.battle_data.read();
|
||||||
if let Some(data) = r.deref() {
|
if let Some(data) = r.deref() {
|
||||||
let mut random = data.battle().unwrap().random().get_rng().lock().unwrap();
|
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 {
|
} else {
|
||||||
// If we're not in battle, just use a new random.
|
// 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 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 {
|
else if species.gender_rate() < 0.0 && self.gender() != Gender::Genderless {
|
||||||
self.gender = Gender::Genderless;
|
*self.gender.write() = Gender::Genderless;
|
||||||
}
|
}
|
||||||
let r = self.battle_data.read();
|
let r = self.battle_data.read();
|
||||||
if let Some(battle_data) = &r.deref() {
|
if let Some(battle_data) = &r.deref() {
|
||||||
|
@ -492,15 +498,18 @@ impl Pokemon {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Change the form of the Pokemon.
|
/// Change the form of the Pokemon.
|
||||||
pub fn change_form(&mut self, form: &Arc<Form>) {
|
pub fn change_form(&self, form: &Arc<Form>) {
|
||||||
if Arc::ptr_eq(&self.form, form) {
|
if self.form().value_identifier() == form.value_identifier() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
self.form = form.clone();
|
*self.form.write() = form.clone();
|
||||||
|
|
||||||
self.types.clear();
|
{
|
||||||
for t in form.types() {
|
let mut type_lock = self.types.write();
|
||||||
self.types.push(*t);
|
type_lock.clear();
|
||||||
|
for t in form.types() {
|
||||||
|
type_lock.push(*t);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
self.weight.store(form.weight(), Ordering::SeqCst);
|
self.weight.store(form.weight(), Ordering::SeqCst);
|
||||||
self.height.store(form.height(), Ordering::SeqCst);
|
self.height.store(form.height(), Ordering::SeqCst);
|
||||||
|
@ -572,8 +581,8 @@ impl Pokemon {
|
||||||
data.on_battle_field.store(value, Ordering::SeqCst);
|
data.on_battle_field.store(value, Ordering::SeqCst);
|
||||||
if !value {
|
if !value {
|
||||||
self.volatile.clear();
|
self.volatile.clear();
|
||||||
self.weight.store(self.form.weight(), Ordering::SeqCst);
|
self.weight.store(self.form().weight(), Ordering::SeqCst);
|
||||||
self.height.store(self.form.height(), 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.
|
/// A source of damage. This should be as unique as possible.
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
#[repr(u8)]
|
#[repr(u8)]
|
||||||
|
@ -821,7 +836,7 @@ pub mod test {
|
||||||
0,
|
0,
|
||||||
&"test_nature".into(),
|
&"test_nature".into(),
|
||||||
);
|
);
|
||||||
assert_eq!(pokemon.species.name(), &"foo".into());
|
assert_eq!(pokemon.species().name(), &"foo".into());
|
||||||
assert_eq!(pokemon.form.name(), &"default".into());
|
assert_eq!(pokemon.form().name(), &"default".into());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
use crate::dynamic_data::{BattleStatCalculator, DamageLibrary, DynamicLibrary, MiscLibrary, ScriptResolver};
|
use crate::dynamic_data::{BattleStatCalculator, DamageLibrary, DynamicLibrary, MiscLibrary, ScriptResolver};
|
||||||
use crate::ffi::{IdentifiablePointer, OwnedPtr};
|
use crate::ffi::{IdentifiablePointer, OwnedPtr};
|
||||||
use crate::static_data::StaticData;
|
use crate::static_data::StaticData;
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
extern "C" fn dynamic_library_new(
|
extern "C" fn dynamic_library_new(
|
||||||
|
@ -9,9 +10,9 @@ extern "C" fn dynamic_library_new(
|
||||||
damage_library: OwnedPtr<Box<dyn DamageLibrary>>,
|
damage_library: OwnedPtr<Box<dyn DamageLibrary>>,
|
||||||
misc_library: OwnedPtr<Box<dyn MiscLibrary>>,
|
misc_library: OwnedPtr<Box<dyn MiscLibrary>>,
|
||||||
script_resolver: OwnedPtr<Box<dyn ScriptResolver>>,
|
script_resolver: OwnedPtr<Box<dyn ScriptResolver>>,
|
||||||
) -> IdentifiablePointer<DynamicLibrary> {
|
) -> IdentifiablePointer<Arc<DynamicLibrary>> {
|
||||||
unsafe {
|
unsafe {
|
||||||
Box::new(DynamicLibrary::new(
|
Arc::new(DynamicLibrary::new(
|
||||||
*Box::from_raw(static_data),
|
*Box::from_raw(static_data),
|
||||||
*Box::from_raw(stat_calculator),
|
*Box::from_raw(stat_calculator),
|
||||||
*Box::from_raw(damage_library),
|
*Box::from_raw(damage_library),
|
||||||
|
|
|
@ -1 +1,2 @@
|
||||||
mod libraries;
|
mod libraries;
|
||||||
|
mod models;
|
|
@ -0,0 +1 @@
|
||||||
|
mod pokemon;
|
|
@ -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<Arc<DynamicLibrary>>,
|
||||||
|
species: ExternPointer<Arc<Species>>,
|
||||||
|
form: ExternPointer<Arc<Form>>,
|
||||||
|
hidden_ability: bool,
|
||||||
|
ability_index: u8,
|
||||||
|
level: LevelInt,
|
||||||
|
unique_identifier: u32,
|
||||||
|
gender: Gender,
|
||||||
|
coloring: u8,
|
||||||
|
nature: *const c_char,
|
||||||
|
) -> IdentifiablePointer<Arc<Pokemon>> {
|
||||||
|
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<Arc<Pokemon>>) {
|
||||||
|
drop_in_place(ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
extern "C" fn pokemon_library(ptr: ExternPointer<Arc<Pokemon>>) -> IdentifiablePointer<Arc<DynamicLibrary>> {
|
||||||
|
ptr.as_ref().library().clone().into()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
extern "C" fn pokemon_species(ptr: ExternPointer<Arc<Pokemon>>) -> IdentifiablePointer<Arc<Species>> {
|
||||||
|
ptr.as_ref().species().clone().into()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
extern "C" fn pokemon_form(ptr: ExternPointer<Arc<Pokemon>>) -> IdentifiablePointer<Arc<Form>> {
|
||||||
|
ptr.as_ref().form().clone().into()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
extern "C" fn pokemon_display_species(ptr: ExternPointer<Arc<Pokemon>>) -> IdentifiablePointer<Arc<Species>> {
|
||||||
|
ptr.as_ref().display_species().clone().into()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
extern "C" fn pokemon_display_form(ptr: ExternPointer<Arc<Pokemon>>) -> IdentifiablePointer<Arc<Form>> {
|
||||||
|
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<Arc<Pokemon>>) -> IdentifiablePointer<Arc<Item>> {
|
||||||
|
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<Arc<Pokemon>>, 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<Arc<Pokemon>>,
|
||||||
|
item: ExternPointer<Arc<Item>>,
|
||||||
|
) -> IdentifiablePointer<Arc<Item>> {
|
||||||
|
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<Arc<Pokemon>>) -> IdentifiablePointer<Arc<Item>> {
|
||||||
|
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<Arc<Pokemon>>) -> 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<Arc<Pokemon>>) -> *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<Arc<Pokemon>>) -> u8 {
|
||||||
|
if ptr.as_ref().real_ability().hidden {
|
||||||
|
1
|
||||||
|
} else {
|
||||||
|
0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
extern "C" fn pokemon_real_ability_index(ptr: ExternPointer<Arc<Pokemon>>) -> 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<Arc<Pokemon>>,
|
||||||
|
index: usize,
|
||||||
|
) -> IdentifiablePointer<Arc<LearnedMove>> {
|
||||||
|
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<Arc<Pokemon>>) -> IdentifiablePointer<StatisticSet<u32>> {
|
||||||
|
(ptr.as_ref().flat_stats() as *const StatisticSet<u32>).into()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
extern "C" fn pokemon_boosted_stats(ptr: ExternPointer<Arc<Pokemon>>) -> IdentifiablePointer<StatisticSet<u32>> {
|
||||||
|
(ptr.as_ref().boosted_stats() as *const StatisticSet<u32>).into()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
extern "C" fn pokemon_get_stat_boost(ptr: ExternPointer<Arc<Pokemon>>, statistic: Statistic) -> i8 {
|
||||||
|
ptr.as_ref().stat_boost(statistic)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
extern "C" fn pokemon_change_stat_boost(
|
||||||
|
ptr: ExternPointer<Arc<Pokemon>>,
|
||||||
|
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<Arc<Pokemon>>, stat: Statistic) -> u8 {
|
||||||
|
ptr.as_ref().individual_values().get_stat(stat)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
extern "C" fn pokemon_set_individual_value(ptr: ExternPointer<Arc<Pokemon>>, 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<Arc<Pokemon>>, stat: Statistic) -> u8 {
|
||||||
|
ptr.as_ref().effort_values().get_stat(stat)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
extern "C" fn pokemon_set_effort_value(ptr: ExternPointer<Arc<Pokemon>>, 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<Arc<Pokemon>>) -> IdentifiablePointer<Battle> {
|
||||||
|
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<Arc<Pokemon>>) -> u8 {
|
||||||
|
ptr.as_ref().get_battle_side_index().unwrap_or_default()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
extern "C" fn pokemon_get_battle_index(ptr: ExternPointer<Arc<Pokemon>>) -> u8 {
|
||||||
|
ptr.as_ref().get_battle_index().unwrap_or_default()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
extern "C" fn pokemon_is_ability_overriden(ptr: ExternPointer<Arc<Pokemon>>) -> u8 {
|
||||||
|
if ptr.as_ref().is_ability_overriden() {
|
||||||
|
1
|
||||||
|
} else {
|
||||||
|
0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
extern "C" fn pokemon_active_ability(ptr: ExternPointer<Arc<Pokemon>>) -> IdentifiablePointer<Ability> {
|
||||||
|
(ptr.as_ref().active_ability() as *const Ability).into()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
extern "C" fn pokemon_allowed_experience_gain(ptr: ExternPointer<Arc<Pokemon>>) -> u8 {
|
||||||
|
if ptr.as_ref().allowed_experience_gain() {
|
||||||
|
1
|
||||||
|
} else {
|
||||||
|
0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
extern "C" fn pokemon_nature(ptr: ExternPointer<Arc<Pokemon>>) -> IdentifiablePointer<Arc<Nature>> {
|
||||||
|
ptr.as_ref().nature().clone().into()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
extern "C" fn pokemon_recalculate_flat_stats(ptr: ExternPointer<Arc<Pokemon>>) {
|
||||||
|
ptr.as_ref().recalculate_flat_stats()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
extern "C" fn pokemon_recalculate_boosted_stats(ptr: ExternPointer<Arc<Pokemon>>) {
|
||||||
|
ptr.as_ref().recalculate_boosted_stats()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
extern "C" fn pokemon_change_species(
|
||||||
|
ptr: ExternPointer<Arc<Pokemon>>,
|
||||||
|
species: ExternPointer<Arc<Species>>,
|
||||||
|
form: ExternPointer<Arc<Form>>,
|
||||||
|
) {
|
||||||
|
ptr.as_ref()
|
||||||
|
.change_species(species.as_ref().clone(), form.as_ref().clone())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
extern "C" fn pokemon_change_form(ptr: ExternPointer<Arc<Pokemon>>, form: ExternPointer<Arc<Form>>) {
|
||||||
|
ptr.as_ref().change_form(form.as_ref())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
extern "C" fn pokemon_is_usable(ptr: ExternPointer<Arc<Pokemon>>) -> u8 {
|
||||||
|
if ptr.as_ref().is_usable() {
|
||||||
|
1
|
||||||
|
} else {
|
||||||
|
0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
extern "C" fn pokemon_is_fainted(ptr: ExternPointer<Arc<Pokemon>>) -> u8 {
|
||||||
|
if ptr.as_ref().is_fainted() {
|
||||||
|
1
|
||||||
|
} else {
|
||||||
|
0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
extern "C" fn pokemon_is_on_battlefield(ptr: ExternPointer<Arc<Pokemon>>) -> u8 {
|
||||||
|
if ptr.as_ref().is_on_battlefield() {
|
||||||
|
1
|
||||||
|
} else {
|
||||||
|
0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
extern "C" fn pokemon_damage(ptr: ExternPointer<Arc<Pokemon>>, damage: u32, source: DamageSource) {
|
||||||
|
ptr.as_ref().damage(damage, source)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
extern "C" fn pokemon_heal(ptr: ExternPointer<Arc<Pokemon>>, amount: u32, allow_revive: u8) -> bool {
|
||||||
|
ptr.as_ref().heal(amount, allow_revive == 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
extern "C" fn pokemon_learn_move(
|
||||||
|
ptr: ExternPointer<Arc<Pokemon>>,
|
||||||
|
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<Arc<Pokemon>>) {
|
||||||
|
ptr.as_ref().clear_status()
|
||||||
|
}
|
|
@ -110,12 +110,6 @@ impl<T: ?Sized> ExternPointer<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> Into<ExternPointer<T>> for *mut T {
|
|
||||||
fn into(self) -> ExternPointer<T> {
|
|
||||||
ExternPointer { ptr: self }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
pub(self) struct IdentifiablePointer<T> {
|
pub(self) struct IdentifiablePointer<T> {
|
||||||
pub ptr: *const T,
|
pub ptr: *const T,
|
||||||
|
@ -128,6 +122,12 @@ impl<T> IdentifiablePointer<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<T> Into<ExternPointer<T>> for *mut T {
|
||||||
|
fn into(self) -> ExternPointer<T> {
|
||||||
|
ExternPointer { ptr: self }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<T: ValueIdentifiable> From<Arc<T>> for IdentifiablePointer<Arc<T>> {
|
impl<T: ValueIdentifiable> From<Arc<T>> for IdentifiablePointer<Arc<T>> {
|
||||||
fn from(v: Arc<T>) -> Self {
|
fn from(v: Arc<T>) -> Self {
|
||||||
let id = v.value_identifier();
|
let id = v.value_identifier();
|
||||||
|
|
|
@ -65,7 +65,7 @@ register! {
|
||||||
pokemon: ExternRef<Pokemon>,
|
pokemon: ExternRef<Pokemon>,
|
||||||
) -> ExternRef<Species> {
|
) -> ExternRef<Species> {
|
||||||
let species = pokemon.value_func(&env).unwrap().species();
|
let species = pokemon.value_func(&env).unwrap().species();
|
||||||
ExternRef::func_new(&env, species)
|
ExternRef::func_new(&env, &species)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn pokemon_get_weight(
|
fn pokemon_get_weight(
|
||||||
|
|
Loading…
Reference in New Issue