diff --git a/src/dynamic_data/event_hooks.rs b/src/dynamic_data/event_hooks.rs index 607b684..c9fa9a1 100755 --- a/src/dynamic_data/event_hooks.rs +++ b/src/dynamic_data/event_hooks.rs @@ -76,16 +76,16 @@ pub enum Event<'own> { /// The pokemon that changed species. pokemon: &'own Pokemon, /// The new species of the Pokemon. - species: Arc, + species: Arc, /// The form of the species the Pokemon will have. - form: Arc
, + form: Arc, }, /// This event happens when a Pokemon changes form during battle. This is rather common. FormChange { /// The pokemon that changed forms. pokemon: &'own Pokemon, /// The new form of the Pokemon. - form: &'own Form, + form: Arc, }, /// This event happens when a Pokemon takes damage. Damage { diff --git a/src/dynamic_data/models/learned_move.rs b/src/dynamic_data/models/learned_move.rs index 99fccfd..4b9239f 100755 --- a/src/dynamic_data/models/learned_move.rs +++ b/src/dynamic_data/models/learned_move.rs @@ -100,7 +100,7 @@ impl ValueIdentifiable for LearnedMove { #[cfg(test)] mod tests { use super::*; - use crate::static_data::MockMoveData; + use crate::static_data::tests::MockMoveData; #[test] fn create_learned_move_restore_uses() { diff --git a/src/dynamic_data/models/pokemon.rs b/src/dynamic_data/models/pokemon.rs index 1e4619d..e634356 100755 --- a/src/dynamic_data/models/pokemon.rs +++ b/src/dynamic_data/models/pokemon.rs @@ -32,16 +32,16 @@ pub struct Pokemon { /// The library data of the Pokemon. library: Arc, /// The species of the Pokemon. - species: RwLock>, + species: RwLock>, /// The form of the Pokemon. - form: RwLock>, + 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. - display_species: Option>, + display_species: Option>, /// An optional display form of the Pokemon. If this is set, the client should display this // species. An example of usage for this is the Illusion ability. - display_form: Option>, + display_form: Option>, /// The current level of the Pokemon. level: Atomic, @@ -121,8 +121,8 @@ impl Pokemon { /// Instantiates a new Pokemon. pub fn new( library: Arc, - species: Arc, - form: &Arc, + species: Arc, + form: &Arc, ability: AbilityIndex, level: LevelInt, unique_identifier: u32, @@ -192,15 +192,15 @@ impl Pokemon { &self.library } /// The species of the Pokemon. - pub fn species(&self) -> Arc { + pub fn species(&self) -> Arc { self.species.read().clone() } /// The form of the Pokemon. - pub fn form(&self) -> Arc { + 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.clone() } else { @@ -208,7 +208,7 @@ impl Pokemon { } } /// 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.clone() } else { @@ -465,7 +465,7 @@ impl Pokemon { } /// Change the species of the Pokemon. - pub fn change_species(&self, species: Arc, form: Arc) { + pub fn change_species(&self, species: Arc, form: Arc) { *self.species.write() = species.clone(); *self.form.write() = form.clone(); @@ -498,7 +498,7 @@ impl Pokemon { } /// Change the form of the Pokemon. - pub fn change_form(&self, form: &Arc) { + pub fn change_form(&self, form: &Arc) { if self.form().value_identifier() == form.value_identifier() { return; } @@ -542,7 +542,10 @@ impl Pokemon { let r = self.battle_data.read(); if let Some(battle_data) = r.deref() { if let Some(battle) = battle_data.battle() { - battle.event_hook().trigger(Event::FormChange { pokemon: self, form }) + battle.event_hook().trigger(Event::FormChange { + pokemon: self, + form: form.clone(), + }) } } } diff --git a/src/ffi/dynamic_data/models/pokemon.rs b/src/ffi/dynamic_data/models/pokemon.rs index a9a56aa..ce100c6 100644 --- a/src/ffi/dynamic_data/models/pokemon.rs +++ b/src/ffi/dynamic_data/models/pokemon.rs @@ -12,8 +12,8 @@ use std::sync::Arc; #[no_mangle] extern "C" fn pokemon_new( library: ExternPointer>, - species: ExternPointer>, - form: ExternPointer>, + species: ExternPointer>, + form: ExternPointer>, hidden_ability: bool, ability_index: u8, level: LevelInt, @@ -54,25 +54,25 @@ extern "C" fn pokemon_library(ptr: ExternPointer>) -> IdentifiableP /// The species of the Pokemon. #[no_mangle] -extern "C" fn pokemon_species(ptr: ExternPointer>) -> IdentifiablePointer> { +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> { +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> { +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> { +extern "C" fn pokemon_display_form(ptr: ExternPointer>) -> IdentifiablePointer> { ptr.as_ref().display_form().into() } @@ -294,8 +294,8 @@ extern "C" fn pokemon_recalculate_boosted_stats(ptr: ExternPointer> #[no_mangle] extern "C" fn pokemon_change_species( ptr: ExternPointer>, - species: ExternPointer>, - form: ExternPointer>, + species: ExternPointer>, + form: ExternPointer>, ) { ptr.as_ref() .change_species(species.as_ref().clone(), form.as_ref().clone()) @@ -303,7 +303,7 @@ extern "C" fn pokemon_change_species( /// Change the form of the Pokemon. #[no_mangle] -extern "C" fn pokemon_change_form(ptr: ExternPointer>, form: ExternPointer>) { +extern "C" fn pokemon_change_form(ptr: ExternPointer>, form: ExternPointer>) { ptr.as_ref().change_form(form.as_ref()) } diff --git a/src/ffi/mod.rs b/src/ffi/mod.rs index 272d910..0acb584 100644 --- a/src/ffi/mod.rs +++ b/src/ffi/mod.rs @@ -58,7 +58,7 @@ macro_rules! ffi_vec_value_getters { /// length function, and a getter. macro_rules! ffi_vec_stringkey_getters { ( - $type:ident, $func:ident + $type:ty, $func:ident ) => { paste::paste! { #[no_mangle] diff --git a/src/ffi/static_data/form.rs b/src/ffi/static_data/form.rs index d9bceb4..925e55d 100644 --- a/src/ffi/static_data/form.rs +++ b/src/ffi/static_data/form.rs @@ -2,7 +2,7 @@ use crate::ffi::{ ffi_arc_getter, ffi_vec_stringkey_getters, ffi_vec_value_getters, BorrowedPtr, ExternPointer, IdentifiablePointer, OwnedPtr, }; -use crate::static_data::{Form, LearnableMoves, StaticStatisticSet, TypeIdentifier}; +use crate::static_data::{Form, FormImpl, LearnableMoves, StaticStatisticSet, TypeIdentifier}; use crate::StringKey; use hashbrown::HashSet; use std::ffi::{c_char, CStr, CString}; @@ -26,7 +26,7 @@ unsafe extern "C" fn form_new( moves: OwnedPtr>, flags: *const *const c_char, flags_length: usize, -) -> IdentifiablePointer> { +) -> IdentifiablePointer> { let name: StringKey = CStr::from_ptr(name).to_str().unwrap().into(); let abilities = std::slice::from_raw_parts(abilities, abilities_length); @@ -46,7 +46,7 @@ unsafe extern "C" fn form_new( flags_set.insert(CStr::from_ptr(*flag).to_str().unwrap().into()); } - Arc::new(Form::new( + let a: Arc = Arc::new(FormImpl::new( &name, height, weight, @@ -57,47 +57,49 @@ unsafe extern "C" fn form_new( hidden_abilities_vec, *Box::from_raw(moves), flags_set, - )) - .into() + )); + a.into() } /// Drops a reference count for a form. #[no_mangle] -unsafe extern "C" fn form_drop(ptr: OwnedPtr>) { +unsafe extern "C" fn form_drop(ptr: OwnedPtr>) { drop_in_place(ptr) } /// The name of the form. #[no_mangle] -unsafe extern "C" fn form_name(ptr: ExternPointer>) -> OwnedPtr { +unsafe extern "C" fn form_name(ptr: ExternPointer>) -> OwnedPtr { let name = ptr.as_ref().name(); CString::new(name.str()).unwrap().into_raw() } -ffi_arc_getter!(Form, height, f32); -ffi_arc_getter!(Form, weight, f32); -ffi_arc_getter!(Form, base_experience, u32); +ffi_arc_getter!(dyn Form, height, f32); +ffi_arc_getter!(dyn Form, weight, f32); +ffi_arc_getter!(dyn Form, base_experience, u32); -ffi_vec_value_getters!(Form, types, TypeIdentifier); +ffi_vec_value_getters!(dyn Form, types, TypeIdentifier); /// The inherent values of a form of species that are used for the stats of a Pokemon. #[no_mangle] -unsafe extern "C" fn form_base_stats(ptr: ExternPointer>) -> IdentifiablePointer> { +unsafe extern "C" fn form_base_stats( + ptr: ExternPointer>, +) -> IdentifiablePointer> { (ptr.as_ref().base_stats() as *const StaticStatisticSet).into() } -ffi_vec_stringkey_getters!(Form, abilities); -ffi_vec_stringkey_getters!(Form, hidden_abilities); +ffi_vec_stringkey_getters!(dyn Form, abilities); +ffi_vec_stringkey_getters!(dyn Form, hidden_abilities); /// The moves a Pokemon with this form can learn. #[no_mangle] -extern "C" fn form_moves(ptr: ExternPointer>) -> BorrowedPtr> { +extern "C" fn form_moves(ptr: ExternPointer>) -> BorrowedPtr> { ptr.as_ref().moves() as *const Box } /// Check if the form has a specific flag set. #[no_mangle] -unsafe extern "C" fn form_has_flag(ptr: ExternPointer>, flag: *const c_char) -> u8 { +unsafe extern "C" fn form_has_flag(ptr: ExternPointer>, flag: *const c_char) -> u8 { let flag = CStr::from_ptr(flag).into(); u8::from(ptr.as_ref().has_flag(&flag)) } diff --git a/src/ffi/static_data/libraries/mod.rs b/src/ffi/static_data/libraries/mod.rs index e1c7b52..1b54cac 100644 --- a/src/ffi/static_data/libraries/mod.rs +++ b/src/ffi/static_data/libraries/mod.rs @@ -72,7 +72,7 @@ macro_rules! library_interface { }; } -library_interface!(SpeciesLibrary, Species); +library_interface!(SpeciesLibrary, dyn Species); library_interface!(MoveLibrary, dyn MoveData); library_interface!(AbilityLibrary, dyn Ability); library_interface!(ItemLibrary, dyn Item); diff --git a/src/ffi/static_data/species.rs b/src/ffi/static_data/species.rs index af8d605..358e74b 100644 --- a/src/ffi/static_data/species.rs +++ b/src/ffi/static_data/species.rs @@ -1,5 +1,5 @@ use crate::ffi::{ffi_arc_getter, ffi_arc_stringkey_getter, BorrowedPtr, ExternPointer, IdentifiablePointer, OwnedPtr}; -use crate::static_data::{Form, Species}; +use crate::static_data::{Form, Species, SpeciesImpl}; use crate::StringKey; use hashbrown::HashSet; use std::ffi::{c_char, CStr}; @@ -14,10 +14,10 @@ unsafe extern "C" fn species_new( gender_rate: f32, growth_rate: BorrowedPtr, capture_rate: u8, - default_form: OwnedPtr>, + default_form: OwnedPtr>, flags: *const *const c_char, flags_length: usize, -) -> IdentifiablePointer> { +) -> IdentifiablePointer> { let name: StringKey = CStr::from_ptr(name).to_str().unwrap().into(); let growth_rate: StringKey = CStr::from_ptr(growth_rate).to_str().unwrap().into(); @@ -26,7 +26,7 @@ unsafe extern "C" fn species_new( for flag in flags { flags_set.insert(CStr::from_ptr(*flag).to_str().unwrap().into()); } - Arc::new(Species::new( + let a: Arc = Arc::new(SpeciesImpl::new( id, &name, gender_rate, @@ -34,28 +34,28 @@ unsafe extern "C" fn species_new( capture_rate, default_form.as_ref().unwrap().clone(), flags_set, - )) - .into() + )); + a.into() } /// Drop a reference to the species. #[no_mangle] -unsafe extern "C" fn species_drop(ptr: OwnedPtr>) { +unsafe extern "C" fn species_drop(ptr: OwnedPtr>) { drop_in_place(ptr); } -ffi_arc_getter!(Species, id, u16); -ffi_arc_stringkey_getter!(Species, name); -ffi_arc_getter!(Species, gender_rate, f32); -ffi_arc_stringkey_getter!(Species, growth_rate); -ffi_arc_getter!(Species, capture_rate, u8); +ffi_arc_getter!(dyn Species, id, u16); +ffi_arc_stringkey_getter!(dyn Species, name); +ffi_arc_getter!(dyn Species, gender_rate, f32); +ffi_arc_stringkey_getter!(dyn Species, growth_rate); +ffi_arc_getter!(dyn Species, capture_rate, u8); /// Adds a new form to the species. #[no_mangle] unsafe extern "C" fn species_add_form( - mut species: ExternPointer>, + mut species: ExternPointer>, name: BorrowedPtr, - form: OwnedPtr>, + form: OwnedPtr>, ) { let form = form.as_ref().unwrap().clone(); species.as_mut().add_form(CStr::from_ptr(name).into(), form) @@ -64,9 +64,9 @@ unsafe extern "C" fn species_add_form( /// Gets a form by name. #[no_mangle] unsafe extern "C" fn species_get_form( - species: ExternPointer>, + species: ExternPointer>, name: BorrowedPtr, -) -> IdentifiablePointer> { +) -> IdentifiablePointer> { let form = species.as_ref().get_form(&CStr::from_ptr(name).into()); if let Some(form) = form { form.into() 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 055c62f..79d6294 100755 --- a/src/script_implementations/wasm/export_registry/dynamic_data/pokemon.rs +++ b/src/script_implementations/wasm/export_registry/dynamic_data/pokemon.rs @@ -63,7 +63,7 @@ register! { fn pokemon_get_species( env: FunctionEnvMut, pokemon: ExternRef, - ) -> ExternRef { + ) -> ExternRef { let species = pokemon.value_func(&env).unwrap().species(); ExternRef::func_new(&env, &species) } diff --git a/src/script_implementations/wasm/export_registry/static_data/species.rs b/src/script_implementations/wasm/export_registry/static_data/species.rs index 5b18814..02ef3e1 100755 --- a/src/script_implementations/wasm/export_registry/static_data/species.rs +++ b/src/script_implementations/wasm/export_registry/static_data/species.rs @@ -11,7 +11,7 @@ fn species_library_get_species( env: FunctionEnvMut, lib: ExternRef, string_key: ExternRef, -) -> ExternRef { +) -> ExternRef { let lib = lib.value_func(&env).unwrap(); let m = lib.get(string_key.value_func(&env).unwrap()); if let Some(v) = m { @@ -23,39 +23,39 @@ fn species_library_get_species( fn species_get_capture_rate( env: FunctionEnvMut, - species: ExternRef, + species: ExternRef, ) -> u8 { - species.value_func(&env).unwrap().capture_rate() + species.value_func_arc(&env).unwrap().capture_rate() } fn species_get_growth_rate( env: FunctionEnvMut, - species: ExternRef, + species: ExternRef, ) -> ExternRef { - let species = species.value_func(&env).unwrap(); + let species = species.value_func_arc(&env).unwrap(); ExternRef::func_new(&env, species.growth_rate()) } fn species_get_gender_rate( env: FunctionEnvMut, - species: ExternRef, + species: ExternRef, ) -> f32 { - species.value_func(&env).unwrap().gender_rate() + species.value_func_arc(&env).unwrap().gender_rate() } fn species_get_name( env: FunctionEnvMut, - species: ExternRef, + species: ExternRef, ) -> ExternRef { - let species = species.value_func(&env).unwrap(); + let species = species.value_func_arc(&env).unwrap(); ExternRef::func_new(&env, species.name()) } fn species_get_id( env: FunctionEnvMut, - species: ExternRef, + species: ExternRef, ) -> u16 { - species.value_func(&env).unwrap().id() + species.value_func_arc(&env).unwrap().id() } diff --git a/src/static_data/growth_rates.rs b/src/static_data/growth_rates.rs index f6321ec..172afdf 100755 --- a/src/static_data/growth_rates.rs +++ b/src/static_data/growth_rates.rs @@ -40,3 +40,17 @@ impl GrowthRate for LookupGrowthRate { } } } + +#[cfg(test)] +pub(crate) mod tests { + use super::*; + + mockall::mock! { + #[derive(Debug)] + pub GrowthRate {} + impl GrowthRate for GrowthRate { + fn calculate_level(&self, experience: u32) -> LevelInt; + fn calculate_experience(&self, level: LevelInt) -> u32; + } + } +} diff --git a/src/static_data/items.rs b/src/static_data/items.rs index 9397567..b900b83 100755 --- a/src/static_data/items.rs +++ b/src/static_data/items.rs @@ -133,3 +133,26 @@ impl ValueIdentifiable for ItemImpl { self.identifier } } + +#[cfg(test)] +pub(crate) mod tests { + use super::*; + + mockall::mock! { + #[derive(Debug)] + pub Item {} + impl Item for Item { + fn name(&self) -> &StringKey; + fn category(&self) -> ItemCategory; + fn battle_category(&self) -> BattleItemCategory; + fn price(&self) -> i32; + fn flags(&self) -> &HashSet; + fn has_flag(&self, key: &StringKey) -> bool; + } + impl ValueIdentifiable for Item { + fn value_identifier(&self) -> ValueIdentifier { + ValueIdentifier::new(0) + } + } + } +} diff --git a/src/static_data/libraries/mod.rs b/src/static_data/libraries/mod.rs index 8bf6976..374108c 100755 --- a/src/static_data/libraries/mod.rs +++ b/src/static_data/libraries/mod.rs @@ -19,6 +19,9 @@ pub use static_data::StaticData; #[doc(inline)] pub use type_library::*; +#[cfg(test)] +pub(crate) mod tests {} + /// The library data for abilities. mod ability_library; /// Basic helper trait for libraries. diff --git a/src/static_data/libraries/species_library.rs b/src/static_data/libraries/species_library.rs index c0dbbd6..31a9682 100755 --- a/src/static_data/libraries/species_library.rs +++ b/src/static_data/libraries/species_library.rs @@ -13,7 +13,7 @@ pub struct SpeciesLibrary { /// A unique identifier so we know what value this is. identifier: ValueIdentifier, /// The underlying map. - map: IndexMap>, + map: IndexMap>, } impl SpeciesLibrary { @@ -26,11 +26,11 @@ impl SpeciesLibrary { } } -impl DataLibrary for SpeciesLibrary { - fn map(&self) -> &IndexMap> { +impl DataLibrary for SpeciesLibrary { + fn map(&self) -> &IndexMap> { &self.map } - fn get_modify(&mut self) -> &mut IndexMap> { + fn get_modify(&mut self) -> &mut IndexMap> { &mut self.map } } @@ -48,18 +48,18 @@ pub mod tests { use crate::static_data::libraries::data_library::DataLibrary; use crate::static_data::libraries::species_library::SpeciesLibrary; - use crate::static_data::Species; - use crate::static_data::StaticStatisticSet; - use crate::static_data::{Form, LearnableMovesImpl}; + use crate::static_data::LearnableMovesImpl; + use crate::static_data::{FormImpl, StaticStatisticSet}; + use crate::static_data::{Species, SpeciesImpl}; - fn build_species() -> Species { - Species::new( + fn build_species() -> Arc { + Arc::new(SpeciesImpl::new( 0, &"foo".into(), 0.5, &"test_growthrate".into(), 0, - Arc::new(Form::new( + Arc::new(FormImpl::new( &"default".into(), 0.0, 0.0, @@ -72,7 +72,7 @@ pub mod tests { HashSet::new(), )), HashSet::new(), - ) + )) } pub fn build() -> SpeciesLibrary { @@ -80,7 +80,7 @@ pub mod tests { let species = build_species(); // Borrow as mut so we can insert let w = &mut lib; - w.add(&"foo".into(), Arc::new(species)); + w.add(&"foo".into(), species); // Drops borrow as mut lib diff --git a/src/static_data/mod.rs b/src/static_data/mod.rs index ac208d8..5ef885b 100755 --- a/src/static_data/mod.rs +++ b/src/static_data/mod.rs @@ -17,6 +17,23 @@ pub use statistic_set::*; pub use statistics::*; use std::fmt::{Display, Formatter}; +#[cfg(test)] +pub(crate) mod tests { + use super::*; + #[doc(inline)] + pub use growth_rates::tests::*; + #[doc(inline)] + pub use items::tests::*; + #[doc(inline)] + pub use libraries::tests::*; + #[doc(inline)] + pub use moves::tests::*; + #[doc(inline)] + pub use natures::tests::*; + #[doc(inline)] + pub use species_data::tests::*; +} + /// Growth rates define how fast a Pokemon can level up. mod growth_rates; /// Items are objects which the player can pick up, keep in their Bag, and use in some manner diff --git a/src/static_data/moves/mod.rs b/src/static_data/moves/mod.rs index 5d23601..bd16a64 100755 --- a/src/static_data/moves/mod.rs +++ b/src/static_data/moves/mod.rs @@ -3,6 +3,16 @@ pub use move_data::*; #[doc(inline)] pub use secondary_effect::*; +#[cfg(test)] +pub(crate) mod tests { + use super::*; + + #[doc(inline)] + pub use move_data::tests::*; + #[doc(inline)] + pub use secondary_effect::tests::*; +} + /// The data belonging to a certain move. mod move_data; /// A secondary effect is an effect on a move that happens after it hits. diff --git a/src/static_data/moves/move_data.rs b/src/static_data/moves/move_data.rs index 73c6c60..6aba0d5 100755 --- a/src/static_data/moves/move_data.rs +++ b/src/static_data/moves/move_data.rs @@ -208,25 +208,29 @@ impl ValueIdentifiable for MoveDataImpl { } #[cfg(test)] -mockall::mock! { - #[derive(Debug)] - pub MoveData{} - impl MoveData for MoveData { - fn name(&self) -> &StringKey; - fn move_type(&self) -> TypeIdentifier; - fn category(&self) -> MoveCategory; - fn base_power(&self) -> u8; - fn accuracy(&self) -> u8; - fn base_usages(&self) -> u8; - fn target(&self) -> MoveTarget; - fn priority(&self) -> i8; - fn secondary_effect(&self) -> &Option>; - fn has_flag(&self, key: &StringKey) -> bool; - fn has_flag_by_hash(&self, key_hash: u32) -> bool; - } - impl ValueIdentifiable for MoveData{ - fn value_identifier(&self) -> ValueIdentifier{ - ValueIdentifier::new(0) +pub(crate) mod tests { + use super::*; + + mockall::mock! { + #[derive(Debug)] + pub MoveData{} + impl MoveData for MoveData { + fn name(&self) -> &StringKey; + fn move_type(&self) -> TypeIdentifier; + fn category(&self) -> MoveCategory; + fn base_power(&self) -> u8; + fn accuracy(&self) -> u8; + fn base_usages(&self) -> u8; + fn target(&self) -> MoveTarget; + fn priority(&self) -> i8; + fn secondary_effect(&self) -> &Option>; + fn has_flag(&self, key: &StringKey) -> bool; + fn has_flag_by_hash(&self, key_hash: u32) -> bool; + } + impl ValueIdentifiable for MoveData{ + fn value_identifier(&self) -> ValueIdentifier{ + ValueIdentifier::new(0) + } } } } diff --git a/src/static_data/moves/secondary_effect.rs b/src/static_data/moves/secondary_effect.rs index fa5c21b..c3f0add 100755 --- a/src/static_data/moves/secondary_effect.rs +++ b/src/static_data/moves/secondary_effect.rs @@ -59,12 +59,28 @@ impl ValueIdentifiable for SecondaryEffectImpl { } #[cfg(test)] -mod tests { +pub(crate) mod tests { + use super::*; use assert_approx_eq::assert_approx_eq; use crate::static_data::moves::secondary_effect::SecondaryEffect; use crate::static_data::SecondaryEffectImpl; + mockall::mock! { + #[derive(Debug)] + pub SecondaryEffect{} + impl SecondaryEffect for SecondaryEffect { + fn chance(&self) -> f32; + fn effect_name(&self) -> &StringKey; + fn parameters(&self) -> &Vec; + } + impl ValueIdentifiable for SecondaryEffect{ + fn value_identifier(&self) -> ValueIdentifier{ + ValueIdentifier::new(0) + } + } + } + #[test] fn create_secondary_effect() { let empty = SecondaryEffectImpl::new(0.0, "".into(), vec![]); diff --git a/src/static_data/natures.rs b/src/static_data/natures.rs index 0c8072a..e80aff8 100755 --- a/src/static_data/natures.rs +++ b/src/static_data/natures.rs @@ -80,3 +80,23 @@ impl ValueIdentifiable for NatureImpl { self.identifier } } + +#[cfg(test)] +pub(crate) mod tests { + use super::*; + + mockall::mock! { + #[derive(Debug)] + pub Nature {} + impl Nature for Nature { + fn increased_stat(&self) -> Statistic; + fn decreased_stat(&self) -> Statistic; + fn get_stat_modifier(&self, stat: Statistic) -> f32; + } + impl ValueIdentifiable for Nature { + fn value_identifier(&self) -> ValueIdentifier { + ValueIdentifier::new(0) + } + } + } +} diff --git a/src/static_data/species_data/ability.rs b/src/static_data/species_data/ability.rs index 6fb8e72..2251b4a 100755 --- a/src/static_data/species_data/ability.rs +++ b/src/static_data/species_data/ability.rs @@ -68,3 +68,23 @@ pub struct AbilityIndex { /// The index of the ability. pub index: u8, } + +#[cfg(test)] +pub(crate) mod tests { + use super::*; + + mockall::mock! { + #[derive(Debug)] + pub Ability{} + impl Ability for Ability { + fn name(&self) -> &StringKey; + fn effect(&self) -> &StringKey; + fn parameters(&self) -> &Vec; + } + impl ValueIdentifiable for Ability { + fn value_identifier(&self) -> ValueIdentifier { + ValueIdentifier::new(0) + } + } + } +} diff --git a/src/static_data/species_data/form.rs b/src/static_data/species_data/form.rs index 507a4be..8dd3239 100755 --- a/src/static_data/species_data/form.rs +++ b/src/static_data/species_data/form.rs @@ -1,4 +1,5 @@ use hashbrown::HashSet; +use std::fmt::Debug; use crate::static_data::Statistic; use crate::static_data::TypeIdentifier; @@ -7,10 +8,56 @@ use crate::static_data::{AbilityIndex, LearnableMoves}; use crate::StringKey; use crate::{Random, ValueIdentifiable, ValueIdentifier}; +/// A form is a variant of a specific species. A species always has at least one form, but can have +/// many more. +pub trait Form: ValueIdentifiable + Debug { + /// The name of the form. + fn name(&self) -> &StringKey; + /// The height of the form in meters. + fn height(&self) -> f32; + /// The weight of the form in kilograms. + fn weight(&self) -> f32; + /// The base amount of experience that is gained when beating a Pokemon with this form. + fn base_experience(&self) -> u32; + /// The normal types a Pokemon with this form has. + fn types(&self) -> &Vec; + /// The inherent values of a form of species that are used for the stats of a Pokemon. + fn base_stats(&self) -> &StaticStatisticSet; + /// The possible abilities a Pokemon with this form can have. + fn abilities(&self) -> &Vec; + /// The possible hidden abilities a Pokemon with this form can have. + fn hidden_abilities(&self) -> &Vec; + + #[allow(clippy::borrowed_box)] + /// The moves a Pokemon with this form can learn. + fn moves(&self) -> &Box; + /// Arbitrary flags can be set on a form for scripting use. + fn flags(&self) -> &HashSet; + + /// Get a type of the move at a certain index. + fn get_type(&self, index: usize) -> TypeIdentifier; + + /// Gets a single base stat value. + fn get_base_stat(&self, stat: Statistic) -> u16; + /// Find the index of an ability that can be on this form. + fn find_ability_index(&self, ability: &dyn Ability) -> Option; + + /// Gets an ability from the form. + fn get_ability(&self, index: AbilityIndex) -> &StringKey; + + /// Gets a random ability from the form. + fn get_random_ability(&self, rand: &mut Random) -> &StringKey; + /// Gets a random hidden ability from the form. + fn get_random_hidden_ability(&self, rand: &mut Random) -> &StringKey; + + /// Check if the form has a specific flag set. + fn has_flag(&self, key: &StringKey) -> bool; +} + /// A form is a variant of a specific species. A species always has at least one form, but can have /// many more. #[derive(Debug)] -pub struct Form { +pub struct FormImpl { /// A unique identifier so we know what value this is. identifier: ValueIdentifier, /// The name of the form. @@ -35,7 +82,7 @@ pub struct Form { flags: HashSet, } -impl Form { +impl FormImpl { /// Instantiates a new form. pub fn new( name: &StringKey, @@ -48,8 +95,8 @@ impl Form { hidden_abilities: Vec, moves: Box, flags: HashSet, - ) -> Form { - Form { + ) -> Self { + Self { identifier: Default::default(), name: name.clone(), height, @@ -63,62 +110,64 @@ impl Form { flags, } } +} +impl Form for FormImpl { /// The name of the form. - pub fn name(&self) -> &StringKey { + fn name(&self) -> &StringKey { &self.name } /// The height of the form in meters. - pub fn height(&self) -> f32 { + fn height(&self) -> f32 { self.height } /// The weight of the form in kilograms. - pub fn weight(&self) -> f32 { + fn weight(&self) -> f32 { self.weight } /// The base amount of experience that is gained when beating a Pokemon with this form. - pub fn base_experience(&self) -> u32 { + fn base_experience(&self) -> u32 { self.base_experience } /// The normal types a Pokemon with this form has. - pub fn types(&self) -> &Vec { + fn types(&self) -> &Vec { &self.types } /// The inherent values of a form of species that are used for the stats of a Pokemon. - pub fn base_stats(&self) -> &StaticStatisticSet { + fn base_stats(&self) -> &StaticStatisticSet { &self.base_stats } /// The possible abilities a Pokemon with this form can have. - pub fn abilities(&self) -> &Vec { + fn abilities(&self) -> &Vec { &self.abilities } /// The possible hidden abilities a Pokemon with this form can have. - pub fn hidden_abilities(&self) -> &Vec { + fn hidden_abilities(&self) -> &Vec { &self.hidden_abilities } #[allow(clippy::borrowed_box)] /// The moves a Pokemon with this form can learn. - pub fn moves(&self) -> &Box { + fn moves(&self) -> &Box { &self.moves } /// Arbitrary flags can be set on a form for scripting use. - pub fn flags(&self) -> &HashSet { + fn flags(&self) -> &HashSet { &self.flags } /// Get a type of the move at a certain index. - pub fn get_type(&self, index: usize) -> TypeIdentifier { + fn get_type(&self, index: usize) -> TypeIdentifier { self.types[index] } /// Gets a single base stat value. - pub fn get_base_stat(&self, stat: Statistic) -> u16 { + fn get_base_stat(&self, stat: Statistic) -> u16 { self.base_stats.get_stat(stat) } /// Find the index of an ability that can be on this form. - pub fn find_ability_index(&self, ability: &dyn Ability) -> Option { + fn find_ability_index(&self, ability: &dyn Ability) -> Option { for (index, a) in self.abilities.iter().enumerate() { if a == ability.name() { return Some(AbilityIndex { @@ -139,7 +188,7 @@ impl Form { } /// Gets an ability from the form. - pub fn get_ability(&self, index: AbilityIndex) -> &StringKey { + fn get_ability(&self, index: AbilityIndex) -> &StringKey { if index.hidden { &self.hidden_abilities[index.index as usize] } else { @@ -148,22 +197,57 @@ impl Form { } /// Gets a random ability from the form. - pub fn get_random_ability(&self, rand: &mut Random) -> &StringKey { + fn get_random_ability(&self, rand: &mut Random) -> &StringKey { &self.abilities[rand.get_between_unsigned(0, self.abilities.len() as u32) as usize] } /// Gets a random hidden ability from the form. - pub fn get_random_hidden_ability(&self, rand: &mut Random) -> &StringKey { + fn get_random_hidden_ability(&self, rand: &mut Random) -> &StringKey { &self.hidden_abilities[rand.get_between_unsigned(0, self.hidden_abilities.len() as u32) as usize] } /// Check if the form has a specific flag set. - pub fn has_flag(&self, key: &StringKey) -> bool { + fn has_flag(&self, key: &StringKey) -> bool { self.flags.contains(key) } } -impl ValueIdentifiable for Form { +impl ValueIdentifiable for FormImpl { fn value_identifier(&self) -> ValueIdentifier { self.identifier } } + +#[cfg(test)] +pub(crate) mod tests { + use super::*; + + mockall::mock! { + #[derive(Debug)] + pub Form {} + impl Form for Form { + fn name(&self) -> &StringKey; + fn height(&self) -> f32; + fn weight(&self) -> f32; + fn base_experience(&self) -> u32; + fn types(&self) -> &Vec; + fn base_stats(&self) -> &StaticStatisticSet; + fn abilities(&self) -> &Vec; + fn hidden_abilities(&self) -> &Vec; + #[allow(clippy::borrowed_box)] + fn moves(&self) -> &Box; + fn flags(&self) -> &HashSet; + fn get_type(&self, index: usize) -> TypeIdentifier; + fn get_base_stat(&self, stat: Statistic) -> u16; + fn find_ability_index(&self, ability: &dyn Ability) -> Option; + fn get_ability(&self, index: AbilityIndex) -> &StringKey; + fn get_random_ability(&self, rand: &mut Random) -> &StringKey; + fn get_random_hidden_ability(&self, rand: &mut Random) -> &StringKey; + fn has_flag(&self, key: &StringKey) -> bool; + } + impl ValueIdentifiable for Form { + fn value_identifier(&self) -> ValueIdentifier { + ValueIdentifier::new(0) + } + } + } +} diff --git a/src/static_data/species_data/learnable_moves.rs b/src/static_data/species_data/learnable_moves.rs index 211fa5c..0d92ff0 100755 --- a/src/static_data/species_data/learnable_moves.rs +++ b/src/static_data/species_data/learnable_moves.rs @@ -59,9 +59,8 @@ impl LearnableMoves for LearnableMovesImpl { } #[cfg(test)] -mod tests { - use crate::static_data::species_data::learnable_moves::LearnableMoves; - use crate::static_data::LearnableMovesImpl; +pub(crate) mod tests { + use super::*; #[test] fn adds_level_moves() { @@ -92,4 +91,12 @@ mod tests { assert_eq!(distinct.len(), 1); assert_eq!(distinct[0], "foo".into()); } + + mockall::mock! { + pub LearnableMoves { + fn add_level_move(&mut self, level: LevelInt, m: &StringKey); + fn get_learned_by_level<'a>(&'a self, level: LevelInt) -> Option<&'a Vec>; + fn get_distinct_level_moves(&self) -> &Vec; + } + } } diff --git a/src/static_data/species_data/mod.rs b/src/static_data/species_data/mod.rs index 99b0604..b5254cc 100755 --- a/src/static_data/species_data/mod.rs +++ b/src/static_data/species_data/mod.rs @@ -9,6 +9,14 @@ pub use learnable_moves::*; #[doc(inline)] pub use species::*; +#[cfg(test)] +pub(crate) mod tests { + pub use super::ability::tests::*; + pub use super::form::tests::*; + pub use super::learnable_moves::tests::*; + pub use super::species::tests::*; +} + /// An ability is a passive effect in battle that is attached to a Pokemon. mod ability; /// A form is a variant of a specific species. A species always has at least one form, but can have diff --git a/src/static_data/species_data/species.rs b/src/static_data/species_data/species.rs index 3a7c935..18352d3 100755 --- a/src/static_data/species_data/species.rs +++ b/src/static_data/species_data/species.rs @@ -1,3 +1,4 @@ +use std::fmt::Debug; use std::sync::{Arc, LazyLock}; use hashbrown::{HashMap, HashSet}; @@ -9,9 +10,38 @@ use crate::static_data::Gender; use crate::StringKey; use crate::{Random, ValueIdentifiable, ValueIdentifier}; +/// The data belonging to a Pokemon with certain characteristics. +pub trait Species: ValueIdentifiable + Debug { + /// The national dex identifier of the Pokemon. + fn id(&self) -> u16; + /// The name of the Pokemon. + fn name(&self) -> &StringKey; + /// The chance between 0.0 and 1.0 that a Pokemon is female. + fn gender_rate(&self) -> f32; + /// How much experience is required for a level. + fn growth_rate(&self) -> &StringKey; + /// How hard it is to capture a Pokemon. 255 means this will be always caught, 0 means this is + /// uncatchable. + fn capture_rate(&self) -> u8; + /// The forms that belong to this Pokemon. + fn forms(&self) -> RwLockReadGuard<'_, RawRwLock, HashMap>>; + /// The arbitrary flags that can be set on a Pokemon for script use. + fn flags(&self) -> &HashSet; + /// Adds a new form to the species. + fn add_form(&self, id: StringKey, form: Arc); + /// Gets a form by name. + fn get_form(&self, id: &StringKey) -> Option>; + /// Gets the form the Pokemon will have by default, if no other form is specified. + fn get_default_form(&self) -> Arc; + /// Gets a random gender. + fn get_random_gender(&self, rand: &mut Random) -> Gender; + /// Check whether the Pokemon has a specific flag set. + fn has_flag(&self, key: &StringKey) -> bool; +} + /// The data belonging to a Pokemon with certain characteristics. #[derive(Debug)] -pub struct Species { +pub struct SpeciesImpl { /// A unique identifier so we know what value this is. identifier: ValueIdentifier, /// The national dex identifier of the Pokemon. @@ -26,7 +56,7 @@ pub struct Species { /// uncatchable. capture_rate: u8, /// The forms that belong to this Pokemon. - forms: RwLock>>, + forms: RwLock>>, /// The arbitrary flags that can be set on a Pokemon for script use. flags: HashSet, } @@ -39,7 +69,7 @@ fn get_default_key() -> StringKey { DEFAULT_KEY.clone() } -impl Species { +impl SpeciesImpl { /// Creates a new species. pub fn new( id: u16, @@ -47,12 +77,12 @@ impl Species { gender_rate: f32, growth_rate: &StringKey, capture_rate: u8, - default_form: Arc, + default_form: Arc, flags: HashSet, - ) -> Species { + ) -> Self { let mut forms = HashMap::with_capacity(1); forms.insert_unique_unchecked(get_default_key(), default_form); - Species { + Self { identifier: Default::default(), id, name: name.clone(), @@ -63,54 +93,56 @@ impl Species { flags, } } +} +impl Species for SpeciesImpl { /// The national dex identifier of the Pokemon. - pub fn id(&self) -> u16 { + fn id(&self) -> u16 { self.id } /// The name of the Pokemon. - pub fn name(&self) -> &StringKey { + fn name(&self) -> &StringKey { &self.name } /// The chance between 0.0 and 1.0 that a Pokemon is female. - pub fn gender_rate(&self) -> f32 { + fn gender_rate(&self) -> f32 { self.gender_rate } /// How much experience is required for a level. - pub fn growth_rate(&self) -> &StringKey { + fn growth_rate(&self) -> &StringKey { &self.growth_rate } /// How hard it is to capture a Pokemon. 255 means this will be always caught, 0 means this is /// uncatchable. - pub fn capture_rate(&self) -> u8 { + fn capture_rate(&self) -> u8 { self.capture_rate } /// The forms that belong to this Pokemon. - pub fn forms(&self) -> RwLockReadGuard<'_, RawRwLock, HashMap>> { + fn forms(&self) -> RwLockReadGuard<'_, RawRwLock, HashMap>> { self.forms.read() } /// The arbitrary flags that can be set on a Pokemon for script use. - pub fn flags(&self) -> &HashSet { + fn flags(&self) -> &HashSet { &self.flags } /// Adds a new form to the species. - pub fn add_form(&self, id: StringKey, form: Arc) { + fn add_form(&self, id: StringKey, form: Arc) { self.forms.write().insert(id, form); } /// Gets a form by name. - pub fn get_form(&self, id: &StringKey) -> Option> { + fn get_form(&self, id: &StringKey) -> Option> { self.forms.read().get(id).cloned() } /// Gets the form the Pokemon will have by default, if no other form is specified. - pub fn get_default_form(&self) -> Arc { + fn get_default_form(&self) -> Arc { self.forms.read().get(&get_default_key()).unwrap().clone() } /// Gets a random gender. - pub fn get_random_gender(&self, rand: &mut Random) -> Gender { + fn get_random_gender(&self, rand: &mut Random) -> Gender { if self.gender_rate < 0.0 { Gender::Genderless } else if rand.get_float() >= self.gender_rate { @@ -121,13 +153,42 @@ impl Species { } /// Check whether the Pokemon has a specific flag set. - pub fn has_flag(&self, key: &StringKey) -> bool { + fn has_flag(&self, key: &StringKey) -> bool { self.flags.contains(key) } } -impl ValueIdentifiable for Species { +impl ValueIdentifiable for SpeciesImpl { fn value_identifier(&self) -> ValueIdentifier { self.identifier } } + +#[cfg(test)] +pub(crate) mod tests { + use super::*; + + mockall::mock! { + #[derive(Debug)] + pub Species {} + impl Species for Species { + fn id(&self) -> u16; + fn name(&self) -> &StringKey; + fn gender_rate(&self) -> f32; + fn growth_rate(&self) -> &StringKey; + fn capture_rate(&self) -> u8; + fn forms(&self) -> RwLockReadGuard<'_, RawRwLock, HashMap>>; + fn flags(&self) -> &HashSet; + fn add_form(&self, id: StringKey, form: Arc); + fn get_form(&self, id: &StringKey) -> Option>; + fn get_default_form(&self) -> Arc; + fn get_random_gender(&self, rand: &mut Random) -> Gender; + fn has_flag(&self, key: &StringKey) -> bool; + } + impl ValueIdentifiable for Species { + fn value_identifier(&self) -> ValueIdentifier { + ValueIdentifier::new(0) + } + } + } +} diff --git a/tests/common/library_loader.rs b/tests/common/library_loader.rs index 75d58b3..b6419a3 100755 --- a/tests/common/library_loader.rs +++ b/tests/common/library_loader.rs @@ -16,10 +16,10 @@ use pkmn_lib::dynamic_data::Gen7DamageLibrary; use pkmn_lib::dynamic_data::Gen7MiscLibrary; use pkmn_lib::script_implementations::wasm::script_resolver::WebAssemblyScriptResolver; use pkmn_lib::static_data::{ - AbilityImpl, AbilityLibrary, BattleItemCategory, DataLibrary, EffectParameter, Form, GrowthRateLibrary, ItemImpl, - ItemLibrary, LearnableMoves, LearnableMovesImpl, LibrarySettings, LookupGrowthRate, MoveDataImpl, MoveLibrary, - NatureImpl, NatureLibrary, SecondaryEffect, SecondaryEffectImpl, Species, StaticData, StaticStatisticSet, - Statistic, TypeLibrary, + AbilityImpl, AbilityLibrary, BattleItemCategory, DataLibrary, EffectParameter, Form, FormImpl, GrowthRateLibrary, + ItemImpl, ItemLibrary, LearnableMoves, LearnableMovesImpl, LibrarySettings, LookupGrowthRate, MoveDataImpl, + MoveLibrary, NatureImpl, NatureLibrary, SecondaryEffect, SecondaryEffectImpl, SpeciesImpl, StaticData, + StaticStatisticSet, Statistic, TypeLibrary, }; use pkmn_lib::StringKey; @@ -263,7 +263,7 @@ pub fn load_species(path: &String, library: &mut StaticData) { let default_form_value = forms.get("default").unwrap(); let default_form = parse_form("default".into(), default_form_value, library); - let species = Species::new( + let species = SpeciesImpl::new( id as u16, &name, gender_rate as f32, @@ -285,7 +285,7 @@ fn load_wasm(path: &String, library: &mut WebAssemblyScriptResolver) { library.finalize(); } -fn parse_form(name: StringKey, value: &Value, library: &mut StaticData) -> Arc { +fn parse_form(name: StringKey, value: &Value, library: &mut StaticData) -> Arc { let mut abilities = Vec::new(); for a in value.get("abilities").unwrap().as_array().unwrap() { abilities.push(a.as_str().unwrap().into()); @@ -310,7 +310,7 @@ fn parse_form(name: StringKey, value: &Value, library: &mut StaticData) -> Arc