Basic implementation of evolutions
continuous-integration/drone/push Build is passing Details

This commit is contained in:
Deukhoofd 2023-07-29 12:57:52 +02:00
parent 3f91f80982
commit d8b8559c2e
Signed by: Deukhoofd
GPG Key ID: F63E044490819F6F
25 changed files with 437 additions and 115 deletions

View File

@ -0,0 +1,57 @@
use crate::dynamic_data::Pokemon;
use crate::static_data::{EvolutionMethod, TimeOfDay};
/// A library for handling the checking of evolution requirements.
pub trait EvolutionLibrary {
/// Checks if the given Pokemon fulfills the given evolution conditions.
fn pokemon_fulfills_evolution_conditions(&self, pokemon: &Pokemon, method: &EvolutionMethod) -> bool;
}
/// A standard implementation of the Evolution Library.
pub struct EvolutionLibraryImpl;
impl EvolutionLibrary for EvolutionLibraryImpl {
fn pokemon_fulfills_evolution_conditions(&self, pokemon: &Pokemon, method: &EvolutionMethod) -> bool {
match method {
EvolutionMethod::Level { level } => pokemon.level() >= *level,
EvolutionMethod::LevelGender { level, gender } => pokemon.level() >= *level && pokemon.gender() == *gender,
EvolutionMethod::Item { .. } => false,
EvolutionMethod::ItemGender { .. } => false,
EvolutionMethod::HoldItem { item } => pokemon.has_held_item(item),
EvolutionMethod::DayHoldItem { item } => {
let time_of_day = pokemon.library().misc_library().time_of_day();
pokemon.has_held_item(item) && time_of_day == TimeOfDay::Morning || time_of_day == TimeOfDay::Day
}
EvolutionMethod::NightHoldItem { item } => {
let time_of_day = pokemon.library().misc_library().time_of_day();
pokemon.has_held_item(item) && time_of_day == TimeOfDay::Evening || time_of_day == TimeOfDay::Night
}
EvolutionMethod::HasMove { move_name } => pokemon
.learned_moves()
.read()
.iter()
.any(|learned_move| learned_move.as_ref().is_some_and(|v| v.move_data().name() == move_name)),
EvolutionMethod::Happiness { happiness } => pokemon.happiness() >= *happiness,
EvolutionMethod::HappinessDay { happiness } => {
let time_of_day = pokemon.library().misc_library().time_of_day();
pokemon.happiness() >= *happiness && time_of_day == TimeOfDay::Morning || time_of_day == TimeOfDay::Day
}
EvolutionMethod::HappinessNight { happiness } => {
let time_of_day = pokemon.library().misc_library().time_of_day();
pokemon.happiness() >= *happiness && time_of_day == TimeOfDay::Evening
|| time_of_day == TimeOfDay::Night
}
EvolutionMethod::Trade => false,
EvolutionMethod::TradeSpecies { .. } => false,
EvolutionMethod::TradeItem { .. } => false,
EvolutionMethod::Location { .. } => {
// TODO: Implement this.
false
}
EvolutionMethod::Custom { .. } => {
// TODO: Implement this.
false
}
}
}
}

View File

@ -19,3 +19,5 @@ pub(crate) mod dynamic_library;
mod misc_library; mod misc_library;
/// Data for dynamically resolving scripts during battles. /// Data for dynamically resolving scripts during battles.
mod script_resolver; mod script_resolver;
/// Handling for checking evolution requirements.
mod evolution_library;

View File

@ -68,6 +68,9 @@ struct PokemonData {
/// The height of the Pokemon in meters. /// The height of the Pokemon in meters.
height: Atomic<f32>, height: Atomic<f32>,
/// The happiness of the Pokemon. Also known as friendship.
happiness: AtomicU8,
/// The stats of the Pokemon when disregarding any stat boosts. /// The stats of the Pokemon when disregarding any stat boosts.
flat_stats: Arc<StatisticSet<u32>>, flat_stats: Arc<StatisticSet<u32>>,
/// The statistics boosts of the Pokemon. Will prevent the value from going above 6, and below /// The statistics boosts of the Pokemon. Will prevent the value from going above 6, and below
@ -158,6 +161,7 @@ impl Pokemon {
.calculate_experience(species.growth_rate(), level)?; .calculate_experience(species.growth_rate(), level)?;
let weight = form.weight(); let weight = form.weight();
let height = form.height(); let height = form.height();
let base_happiness = species.base_happiness();
let nature = library let nature = library
.static_data() .static_data()
.natures() .natures()
@ -198,6 +202,7 @@ impl Pokemon {
status_script: ScriptContainer::default(), status_script: ScriptContainer::default(),
volatile: Default::default(), volatile: Default::default(),
script_source_data: Default::default(), script_source_data: Default::default(),
happiness: AtomicU8::new(base_happiness),
}; };
let pokemon = Self { let pokemon = Self {
@ -326,11 +331,16 @@ impl Pokemon {
pub fn set_weight(&self, weight: f32) { pub fn set_weight(&self, weight: f32) {
self.data.weight.store(weight, Ordering::Relaxed) self.data.weight.store(weight, Ordering::Relaxed)
} }
/// The height of the Pokemon in meters. /// The height of the Pokemon in meters.
pub fn height(&self) -> f32 { pub fn height(&self) -> f32 {
self.data.height.load(Ordering::Relaxed) self.data.height.load(Ordering::Relaxed)
} }
/// The current happiness of the Pokemon. Also known as friendship.
pub fn happiness(&self) -> u8 {
self.data.happiness.load(Ordering::Relaxed)
}
/// An optional nickname of the Pokemon. /// An optional nickname of the Pokemon.
pub fn nickname(&self) -> &Option<String> { pub fn nickname(&self) -> &Option<String> {
&self.data.nickname &self.data.nickname
@ -921,6 +931,7 @@ impl Pokemon {
current_health: AtomicU32::new(value.current_health), current_health: AtomicU32::new(value.current_health),
weight: Atomic::new(value.weight), weight: Atomic::new(value.weight),
height: Atomic::new(value.height), height: Atomic::new(value.height),
happiness: AtomicU8::new(value.happiness),
flat_stats: Arc::new(Default::default()), flat_stats: Arc::new(Default::default()),
stat_boost: Arc::new(value.stat_boosts.clone()), stat_boost: Arc::new(value.stat_boosts.clone()),
boosted_stats: Arc::new(Default::default()), boosted_stats: Arc::new(Default::default()),
@ -1163,6 +1174,7 @@ pub mod test {
}); });
species.expect_growth_rate().return_const(StringKey::empty()); species.expect_growth_rate().return_const(StringKey::empty());
species.expect_name().return_const(StringKey::new("test_species")); species.expect_name().return_const(StringKey::new("test_species"));
species.expect_base_happiness().return_const(100);
let s: Arc<dyn Species> = Arc::new(species); let s: Arc<dyn Species> = Arc::new(species);
Some(s) Some(s)

View File

@ -34,6 +34,8 @@ pub struct SerializedPokemon {
pub weight: f32, pub weight: f32,
/// The height of the Pokemon. /// The height of the Pokemon.
pub height: f32, pub height: f32,
/// The happiness of the Pokemon.
pub happiness: u8,
/// The stat boosts of the Pokemon. /// The stat boosts of the Pokemon.
pub stat_boosts: ClampedStatisticSet<i8, -6, 6>, pub stat_boosts: ClampedStatisticSet<i8, -6, 6>,
/// The individual values of the Pokemon. /// The individual values of the Pokemon.
@ -101,6 +103,7 @@ impl Into<anyhow_ext::Result<SerializedPokemon>> for &Pokemon {
current_health: self.current_health(), current_health: self.current_health(),
weight: self.weight(), weight: self.weight(),
height: self.height(), height: self.height(),
happiness: self.happiness(),
stat_boosts: self.stat_boosts().deref().deref().clone(), stat_boosts: self.stat_boosts().deref().deref().clone(),
individual_values: self.individual_values().deref().deref().clone(), individual_values: self.individual_values().deref().deref().clone(),
effort_values: self.effort_values().deref().deref().clone(), effort_values: self.effort_values().deref().deref().clone(),

View File

@ -1,11 +1,11 @@
use crate::dynamic_data::Pokemon; use crate::dynamic_data::Pokemon;
use crate::static_data::EffectParameter; use crate::static_data::Parameter;
use std::sync::Arc; use std::sync::Arc;
/// The script functions that are relevant to item use. /// The script functions that are relevant to item use.
pub trait ItemScript { pub trait ItemScript {
/// Initializes the script with the given parameters for a specific item /// Initializes the script with the given parameters for a specific item
fn on_initialize(&self, _pars: Vec<Arc<EffectParameter>>) -> anyhow_ext::Result<()> { fn on_initialize(&self, _pars: Vec<Arc<Parameter>>) -> anyhow_ext::Result<()> {
Ok(()) Ok(())
} }

View File

@ -13,8 +13,8 @@ use crate::dynamic_data::{Battle, DynamicLibrary};
use crate::dynamic_data::{BattleSide, DamageSource}; use crate::dynamic_data::{BattleSide, DamageSource};
use crate::dynamic_data::{ExecutingMove, WeakBattleReference, WeakPokemonReference}; use crate::dynamic_data::{ExecutingMove, WeakBattleReference, WeakPokemonReference};
use crate::dynamic_data::{Pokemon, WeakBattleSideReference}; use crate::dynamic_data::{Pokemon, WeakBattleSideReference};
use crate::static_data::{EffectParameter, TypeIdentifier};
use crate::static_data::{Item, Statistic}; use crate::static_data::{Item, Statistic};
use crate::static_data::{Parameter, TypeIdentifier};
use crate::StringKey; use crate::StringKey;
/// The script trait is used to make changes to how a battle executes, without requiring hardcoded /// The script trait is used to make changes to how a battle executes, without requiring hardcoded
@ -69,7 +69,7 @@ pub trait Script: Send + Sync {
Ok(()) Ok(())
} }
/// This function is ran when this script starts being in effect. /// This function is ran when this script starts being in effect.
fn on_initialize(&self, _library: &Arc<dyn DynamicLibrary>, _pars: Vec<Arc<EffectParameter>>) -> Result<()> { fn on_initialize(&self, _library: &Arc<dyn DynamicLibrary>, _pars: Vec<Arc<Parameter>>) -> Result<()> {
Ok(()) Ok(())
} }
/// This function is ran just before the start of the turn. Everyone has made its choices here, /// This function is ran just before the start of the turn. Everyone has made its choices here,

View File

@ -1,5 +1,5 @@
use crate::static_data::{ use crate::static_data::{
Ability, EffectParameter, Form, GrowthRate, Item, LearnableMoves, MoveData, Nature, SecondaryEffect, Species, Ability, Form, GrowthRate, Item, LearnableMoves, MoveData, Nature, Parameter, SecondaryEffect, Species,
StaticStatisticSet, StatisticSet, StaticStatisticSet, StatisticSet,
}; };
use anyhow::anyhow; use anyhow::anyhow;
@ -60,7 +60,7 @@ impl<T> Default for FFIHandle<T> {
#[allow(clippy::missing_docs_in_private_items)] // I'm not documenting these items. #[allow(clippy::missing_docs_in_private_items)] // I'm not documenting these items.
pub(super) enum FFIObject { pub(super) enum FFIObject {
Ability(Arc<dyn Ability>), Ability(Arc<dyn Ability>),
EffectParameter(Arc<EffectParameter>), EffectParameter(Arc<Parameter>),
StatisticSetU8(Arc<StatisticSet<u8>>), StatisticSetU8(Arc<StatisticSet<u8>>),
StatisticSetI8(Arc<StatisticSet<i8>>), StatisticSetI8(Arc<StatisticSet<i8>>),
StatisticSetU32(Arc<StatisticSet<u32>>), StatisticSetU32(Arc<StatisticSet<u32>>),
@ -307,7 +307,7 @@ macro_rules! ffi_obj_conversions {
} }
ffi_obj_conversions!(Arc<dyn Ability>, Ability); ffi_obj_conversions!(Arc<dyn Ability>, Ability);
ffi_obj_conversions!(Arc<EffectParameter>, EffectParameter); ffi_obj_conversions!(Arc<Parameter>, EffectParameter);
ffi_obj_conversions!(Arc<StatisticSet<i8>>, StatisticSetI8); ffi_obj_conversions!(Arc<StatisticSet<i8>>, StatisticSetI8);
ffi_obj_conversions!(Arc<StatisticSet<u8>>, StatisticSetU8); ffi_obj_conversions!(Arc<StatisticSet<u8>>, StatisticSetU8);
ffi_obj_conversions!(Arc<StatisticSet<u32>>, StatisticSetU32); ffi_obj_conversions!(Arc<StatisticSet<u32>>, StatisticSetU32);

View File

@ -1,7 +1,7 @@
use crate::ffi::FFIHandle; use crate::ffi::FFIHandle;
use crate::ffi::FromFFIHandle; use crate::ffi::FromFFIHandle;
use crate::ffi::{FFIResult, OwnedPtrString}; use crate::ffi::{FFIResult, OwnedPtrString};
use crate::static_data::{Ability, AbilityImpl, EffectParameter}; use crate::static_data::{Ability, AbilityImpl, Parameter};
use crate::StringKey; use crate::StringKey;
use anyhow::anyhow; use anyhow::anyhow;
use std::ffi::{c_char, CStr, CString}; use std::ffi::{c_char, CStr, CString};
@ -12,11 +12,11 @@ use std::sync::Arc;
unsafe extern "C" fn ability_new( unsafe extern "C" fn ability_new(
name: *const c_char, name: *const c_char,
effect: *const c_char, effect: *const c_char,
parameters: *const FFIHandle<Arc<EffectParameter>>, parameters: *const FFIHandle<Arc<Parameter>>,
parameters_length: usize, parameters_length: usize,
) -> FFIResult<FFIHandle<Arc<dyn Ability>>> { ) -> FFIResult<FFIHandle<Arc<dyn Ability>>> {
let parameters = std::slice::from_raw_parts(parameters, parameters_length); let parameters = std::slice::from_raw_parts(parameters, parameters_length);
let mut parameters_vec: Vec<Arc<EffectParameter>> = Vec::with_capacity(parameters_length); let mut parameters_vec: Vec<Arc<Parameter>> = Vec::with_capacity(parameters_length);
for parameter in parameters { for parameter in parameters {
parameters_vec.push(parameter.from_ffi_handle()); parameters_vec.push(parameter.from_ffi_handle());
} }
@ -63,7 +63,7 @@ unsafe extern "C" fn ability_parameter_length(ptr: FFIHandle<Arc<dyn Ability>>)
unsafe extern "C" fn ability_parameter_get( unsafe extern "C" fn ability_parameter_get(
ptr: FFIHandle<Arc<dyn Ability>>, ptr: FFIHandle<Arc<dyn Ability>>,
index: usize, index: usize,
) -> FFIHandle<Arc<EffectParameter>> { ) -> FFIHandle<Arc<Parameter>> {
if let Some(p) = ptr.from_ffi_handle().parameters().get(index) { if let Some(p) = ptr.from_ffi_handle().parameters().get(index) {
FFIHandle::get_handle(p.clone().into()) FFIHandle::get_handle(p.clone().into())
} else { } else {

View File

@ -1,6 +1,6 @@
use crate::ffi::ffi_handle::{FFIHandle, FFIObject, FromFFIHandle}; use crate::ffi::ffi_handle::{FFIHandle, FFIObject, FromFFIHandle};
use crate::ffi::{FFIResult, OwnedPtrString}; use crate::ffi::{FFIResult, OwnedPtrString};
use crate::static_data::EffectParameter; use crate::static_data::Parameter;
use crate::{PkmnError, StringKey}; use crate::{PkmnError, StringKey};
use anyhow::anyhow; use anyhow::anyhow;
use std::ffi::{c_char, CStr, CString}; use std::ffi::{c_char, CStr, CString};
@ -30,50 +30,50 @@ mod statistic_set;
/// Instantiates an effect parameter with a boolean. /// Instantiates an effect parameter with a boolean.
#[no_mangle] #[no_mangle]
extern "C" fn effect_parameter_new_bool(value: u8) -> FFIHandle<Arc<EffectParameter>> { extern "C" fn effect_parameter_new_bool(value: u8) -> FFIHandle<Arc<Parameter>> {
FFIHandle::get_handle(FFIObject::EffectParameter(Arc::new(EffectParameter::from(value == 1)))) FFIHandle::get_handle(FFIObject::EffectParameter(Arc::new(Parameter::from(value == 1))))
} }
/// Instantiates an effect parameter with an integer. /// Instantiates an effect parameter with an integer.
#[no_mangle] #[no_mangle]
extern "C" fn effect_parameter_new_int(value: i64) -> FFIHandle<Arc<EffectParameter>> { extern "C" fn effect_parameter_new_int(value: i64) -> FFIHandle<Arc<Parameter>> {
FFIHandle::get_handle(FFIObject::EffectParameter(Arc::new(EffectParameter::from(value)))) FFIHandle::get_handle(FFIObject::EffectParameter(Arc::new(Parameter::from(value))))
} }
/// Instantiates an effect parameter with a float. /// Instantiates an effect parameter with a float.
#[no_mangle] #[no_mangle]
extern "C" fn effect_parameter_new_float(value: f32) -> FFIHandle<Arc<EffectParameter>> { extern "C" fn effect_parameter_new_float(value: f32) -> FFIHandle<Arc<Parameter>> {
FFIHandle::get_handle(FFIObject::EffectParameter(Arc::new(EffectParameter::from(value)))) FFIHandle::get_handle(FFIObject::EffectParameter(Arc::new(Parameter::from(value))))
} }
/// Instantiates an effect parameter with a string. /// Instantiates an effect parameter with a string.
#[no_mangle] #[no_mangle]
unsafe extern "C" fn effect_parameter_new_string(value: *const c_char) -> FFIResult<FFIHandle<Arc<EffectParameter>>> { unsafe extern "C" fn effect_parameter_new_string(value: *const c_char) -> FFIResult<FFIHandle<Arc<Parameter>>> {
let sk: StringKey = match CStr::from_ptr(value).to_str() { let sk: StringKey = match CStr::from_ptr(value).to_str() {
Ok(sk) => sk.into(), Ok(sk) => sk.into(),
Err(_) => return FFIResult::err(PkmnError::InvalidCString.into()), Err(_) => return FFIResult::err(PkmnError::InvalidCString.into()),
}; };
FFIResult::ok(FFIHandle::get_handle(FFIObject::EffectParameter(Arc::new( FFIResult::ok(FFIHandle::get_handle(FFIObject::EffectParameter(Arc::new(
EffectParameter::from(sk), Parameter::from(sk),
)))) ))))
} }
/// Get the type of an effect parameter. /// Get the type of an effect parameter.
#[no_mangle] #[no_mangle]
extern "C" fn effect_parameter_get_type(ptr: FFIHandle<Arc<EffectParameter>>) -> u8 { extern "C" fn effect_parameter_get_type(ptr: FFIHandle<Arc<Parameter>>) -> u8 {
match ptr.from_ffi_handle().deref() { match ptr.from_ffi_handle().deref() {
EffectParameter::Bool(_) => 0, Parameter::Bool(_) => 0,
EffectParameter::Int(_) => 1, Parameter::Int(_) => 1,
EffectParameter::Float(_) => 2, Parameter::Float(_) => 2,
EffectParameter::String(_) => 3, Parameter::String(_) => 3,
} }
} }
/// Get the boolean contained in the effect parameter, panics if the effect parameter is not a bool. /// Get the boolean contained in the effect parameter, panics if the effect parameter is not a bool.
#[no_mangle] #[no_mangle]
extern "C" fn effect_parameter_get_as_bool(ptr: FFIHandle<Arc<EffectParameter>>) -> FFIResult<u8> { extern "C" fn effect_parameter_get_as_bool(ptr: FFIHandle<Arc<Parameter>>) -> FFIResult<u8> {
let p = ptr.from_ffi_handle(); let p = ptr.from_ffi_handle();
if let EffectParameter::Bool(b) = p.deref() { if let Parameter::Bool(b) = p.deref() {
FFIResult::ok(u8::from(*b)) FFIResult::ok(u8::from(*b))
} else { } else {
FFIResult::err(anyhow!("Unexpected effect parameter. Expected bool, was: {}", p)) FFIResult::err(anyhow!("Unexpected effect parameter. Expected bool, was: {}", p))
@ -82,9 +82,9 @@ extern "C" fn effect_parameter_get_as_bool(ptr: FFIHandle<Arc<EffectParameter>>)
/// Get the int contained in the effect parameter, panics if the effect parameter is not a int. /// Get the int contained in the effect parameter, panics if the effect parameter is not a int.
#[no_mangle] #[no_mangle]
extern "C" fn effect_parameter_get_as_int(ptr: FFIHandle<Arc<EffectParameter>>) -> FFIResult<i64> { extern "C" fn effect_parameter_get_as_int(ptr: FFIHandle<Arc<Parameter>>) -> FFIResult<i64> {
let p = ptr.from_ffi_handle(); let p = ptr.from_ffi_handle();
if let EffectParameter::Int(b) = p.deref() { if let Parameter::Int(b) = p.deref() {
FFIResult::ok(*b) FFIResult::ok(*b)
} else { } else {
FFIResult::err(anyhow!("Unexpected effect parameter. Expected int, was: {}", p)) FFIResult::err(anyhow!("Unexpected effect parameter. Expected int, was: {}", p))
@ -93,9 +93,9 @@ extern "C" fn effect_parameter_get_as_int(ptr: FFIHandle<Arc<EffectParameter>>)
/// Get the float contained in the effect parameter, panics if the effect parameter is not a float. /// Get the float contained in the effect parameter, panics if the effect parameter is not a float.
#[no_mangle] #[no_mangle]
extern "C" fn effect_parameter_get_as_float(ptr: FFIHandle<Arc<EffectParameter>>) -> FFIResult<f32> { extern "C" fn effect_parameter_get_as_float(ptr: FFIHandle<Arc<Parameter>>) -> FFIResult<f32> {
let p = ptr.from_ffi_handle(); let p = ptr.from_ffi_handle();
if let EffectParameter::Float(b) = p.deref() { if let Parameter::Float(b) = p.deref() {
FFIResult::ok(*b) FFIResult::ok(*b)
} else { } else {
FFIResult::err(anyhow!("Unexpected effect parameter. Expected float, was: {}", p)) FFIResult::err(anyhow!("Unexpected effect parameter. Expected float, was: {}", p))
@ -104,9 +104,9 @@ extern "C" fn effect_parameter_get_as_float(ptr: FFIHandle<Arc<EffectParameter>>
/// Get the string contained in the effect parameter, panics if the effect parameter is not a string. /// Get the string contained in the effect parameter, panics if the effect parameter is not a string.
#[no_mangle] #[no_mangle]
extern "C" fn effect_parameter_get_as_string(ptr: FFIHandle<Arc<EffectParameter>>) -> FFIResult<OwnedPtrString> { extern "C" fn effect_parameter_get_as_string(ptr: FFIHandle<Arc<Parameter>>) -> FFIResult<OwnedPtrString> {
let p = ptr.from_ffi_handle(); let p = ptr.from_ffi_handle();
if let EffectParameter::String(b) = p.deref() { if let Parameter::String(b) = p.deref() {
match CString::new(b.str().to_string()) { match CString::new(b.str().to_string()) {
Ok(cstr) => FFIResult::ok(OwnedPtrString(cstr.into_raw())), Ok(cstr) => FFIResult::ok(OwnedPtrString(cstr.into_raw())),
Err(_) => FFIResult::err(PkmnError::InvalidCString.into()), Err(_) => FFIResult::err(PkmnError::InvalidCString.into()),

View File

@ -1,8 +1,7 @@
use crate::ffi::ffi_handle::{FFIHandle, FromFFIHandle}; use crate::ffi::ffi_handle::{FFIHandle, FromFFIHandle};
use crate::ffi::{ffi_handle_arc_dyn_getter, FFIResult, NonOwnedPtrString, OwnedPtrString}; use crate::ffi::{ffi_handle_arc_dyn_getter, FFIResult, NonOwnedPtrString, OwnedPtrString};
use crate::static_data::{ use crate::static_data::{
EffectParameter, MoveCategory, MoveData, MoveDataImpl, MoveTarget, SecondaryEffect, SecondaryEffectImpl, MoveCategory, MoveData, MoveDataImpl, MoveTarget, Parameter, SecondaryEffect, SecondaryEffectImpl, TypeIdentifier,
TypeIdentifier,
}; };
use crate::StringKey; use crate::StringKey;
use anyhow::anyhow; use anyhow::anyhow;
@ -100,7 +99,7 @@ unsafe extern "C" fn move_data_has_flag(ptr: FFIHandle<Arc<dyn MoveData>>, flag:
unsafe extern "C" fn secondary_effect_new( unsafe extern "C" fn secondary_effect_new(
chance: f32, chance: f32,
effect_name: NonOwnedPtrString, effect_name: NonOwnedPtrString,
parameters: *mut FFIHandle<Arc<EffectParameter>>, parameters: *mut FFIHandle<Arc<Parameter>>,
parameters_length: usize, parameters_length: usize,
) -> FFIHandle<Box<dyn SecondaryEffect>> { ) -> FFIHandle<Box<dyn SecondaryEffect>> {
let parameter_slice = std::slice::from_raw_parts(parameters, parameters_length); let parameter_slice = std::slice::from_raw_parts(parameters, parameters_length);
@ -148,7 +147,7 @@ unsafe extern "C" fn secondary_effect_parameter_length(ptr: FFIHandle<Arc<dyn Se
unsafe extern "C" fn secondary_effect_parameter_get( unsafe extern "C" fn secondary_effect_parameter_get(
ptr: FFIHandle<Arc<dyn SecondaryEffect>>, ptr: FFIHandle<Arc<dyn SecondaryEffect>>,
index: usize, index: usize,
) -> FFIHandle<Arc<EffectParameter>> { ) -> FFIHandle<Arc<Parameter>> {
if let Some(v) = ptr.from_ffi_handle().parameters().get(index) { if let Some(v) = ptr.from_ffi_handle().parameters().get(index) {
FFIHandle::get_handle(v.clone().into()) FFIHandle::get_handle(v.clone().into())
} else { } else {

View File

@ -50,8 +50,10 @@ unsafe extern "C" fn species_new(
gender_rate, gender_rate,
&growth_rate, &growth_rate,
capture_rate, capture_rate,
120,
default_form.clone(), default_form.clone(),
flags_set, flags_set,
Vec::new(),
)); ));
FFIResult::ok(FFIHandle::get_handle(a.into())) FFIResult::ok(FFIHandle::get_handle(a.into()))
} }

View File

@ -6,7 +6,7 @@ use wasmer::{FunctionEnv, FunctionEnvMut, Imports, StoreMut};
use crate::script_implementations::wasm::extern_ref::ExternRef; use crate::script_implementations::wasm::extern_ref::ExternRef;
use crate::script_implementations::wasm::script_resolver::WebAssemblyEnv; use crate::script_implementations::wasm::script_resolver::WebAssemblyEnv;
use crate::static_data::EffectParameter; use crate::static_data::Parameter;
use crate::StringKey; use crate::StringKey;
/// Dynamic data registration /// Dynamic data registration
@ -140,51 +140,39 @@ fn string_key_get_str(env: FunctionEnvMut<WebAssemblyEnv>, string_key: ExternRef
} }
/// Gets the type of an EffectParameter /// Gets the type of an EffectParameter
fn effect_parameter_get_type( fn effect_parameter_get_type(env: FunctionEnvMut<WebAssemblyEnv>, parameter: ExternRef<Parameter>) -> WasmResult<u8> {
env: FunctionEnvMut<WebAssemblyEnv>,
parameter: ExternRef<EffectParameter>,
) -> WasmResult<u8> {
let value = get_value_arc!(parameter, env); let value = get_value_arc!(parameter, env);
wasm_ok(match value.deref() { wasm_ok(match value.deref() {
EffectParameter::Bool(_) => 1, Parameter::Bool(_) => 1,
EffectParameter::Int(_) => 2, Parameter::Int(_) => 2,
EffectParameter::Float(_) => 3, Parameter::Float(_) => 3,
EffectParameter::String(_) => 4, Parameter::String(_) => 4,
}) })
} }
/// Gets the inner bool data of an EffectParameter. Panics if it's not a bool. /// Gets the inner bool data of an EffectParameter. Panics if it's not a bool.
fn effect_parameter_as_bool( fn effect_parameter_as_bool(env: FunctionEnvMut<WebAssemblyEnv>, parameter: ExternRef<Parameter>) -> WasmResult<u8> {
env: FunctionEnvMut<WebAssemblyEnv>,
parameter: ExternRef<EffectParameter>,
) -> WasmResult<u8> {
let value = get_value_arc!(parameter, env); let value = get_value_arc!(parameter, env);
match value.deref() { match value.deref() {
EffectParameter::Bool(b) => wasm_ok(<u8 as From<bool>>::from(*b)), Parameter::Bool(b) => wasm_ok(<u8 as From<bool>>::from(*b)),
_ => wasm_err::<u8>(anyhow!("Unexpected parameter type. Expected bool, got {}", value), &env), _ => wasm_err::<u8>(anyhow!("Unexpected parameter type. Expected bool, got {}", value), &env),
} }
} }
/// Gets the inner int data of an EffectParameter. Panics if it's not an int. /// Gets the inner int data of an EffectParameter. Panics if it's not an int.
fn effect_parameter_as_int( fn effect_parameter_as_int(env: FunctionEnvMut<WebAssemblyEnv>, parameter: ExternRef<Parameter>) -> WasmResult<i64> {
env: FunctionEnvMut<WebAssemblyEnv>,
parameter: ExternRef<EffectParameter>,
) -> WasmResult<i64> {
let value = get_value_arc!(parameter, env); let value = get_value_arc!(parameter, env);
match value.deref() { match value.deref() {
EffectParameter::Int(i) => wasm_ok(*i), Parameter::Int(i) => wasm_ok(*i),
_ => wasm_err::<i64>(anyhow!("Unexpected parameter type. Expected int, got {}", value), &env), _ => wasm_err::<i64>(anyhow!("Unexpected parameter type. Expected int, got {}", value), &env),
} }
} }
/// Gets the inner float data of an EffectParameter. Panics if it's not a float. /// Gets the inner float data of an EffectParameter. Panics if it's not a float.
fn effect_parameter_as_float( fn effect_parameter_as_float(env: FunctionEnvMut<WebAssemblyEnv>, parameter: ExternRef<Parameter>) -> WasmResult<f32> {
env: FunctionEnvMut<WebAssemblyEnv>,
parameter: ExternRef<EffectParameter>,
) -> WasmResult<f32> {
let value = get_value_arc!(parameter, env); let value = get_value_arc!(parameter, env);
match value.deref() { match value.deref() {
EffectParameter::Float(f) => wasm_ok(*f), Parameter::Float(f) => wasm_ok(*f),
_ => wasm_err::<f32>( _ => wasm_err::<f32>(
anyhow!("Unexpected parameter type. Expected float, got {}", value), anyhow!("Unexpected parameter type. Expected float, got {}", value),
&env, &env,
@ -195,11 +183,11 @@ fn effect_parameter_as_float(
/// Gets the inner string data of an EffectParameter. Panics if it's not a string. /// Gets the inner string data of an EffectParameter. Panics if it's not a string.
fn effect_parameter_as_string( fn effect_parameter_as_string(
env: FunctionEnvMut<WebAssemblyEnv>, env: FunctionEnvMut<WebAssemblyEnv>,
parameter: ExternRef<EffectParameter>, parameter: ExternRef<Parameter>,
) -> WasmResult<ExternRef<StringKey>> { ) -> WasmResult<ExternRef<StringKey>> {
let value = get_value_arc!(parameter, env); let value = get_value_arc!(parameter, env);
match value.deref() { match value.deref() {
EffectParameter::String(s) => wasm_ok(ExternRef::<StringKey>::func_new(&env, s.clone().into())), Parameter::String(s) => wasm_ok(ExternRef::<StringKey>::func_new(&env, s.clone().into())),
_ => wasm_err::<ExternRef<StringKey>>( _ => wasm_err::<ExternRef<StringKey>>(
anyhow!("Unexpected parameter type. Expected string, got {}", value), anyhow!("Unexpected parameter type. Expected string, got {}", value),
&env, &env,

View File

@ -3,7 +3,7 @@ use crate::script_implementations::wasm::export_registry::FunctionEnvMut;
use crate::script_implementations::wasm::export_registry::{register, try_wasm, wasm_ok, WasmResult}; use crate::script_implementations::wasm::export_registry::{register, try_wasm, wasm_ok, WasmResult};
use crate::script_implementations::wasm::extern_ref::ExternRef; use crate::script_implementations::wasm::extern_ref::ExternRef;
use crate::script_implementations::wasm::script_resolver::WebAssemblyEnv; use crate::script_implementations::wasm::script_resolver::WebAssemblyEnv;
use crate::static_data::{Ability, EffectParameter}; use crate::static_data::{Ability, Parameter};
use crate::StringKey; use crate::StringKey;
register! { register! {
@ -32,7 +32,7 @@ fn ability_get_parameters(
let parameters = ability.parameters(); let parameters = ability.parameters();
let mut vec : Vec<u32> = Vec::with_capacity(parameters.len()); let mut vec : Vec<u32> = Vec::with_capacity(parameters.len());
for parameter in parameters { for parameter in parameters {
vec.push(ExternRef::<EffectParameter>::func_new(&env, parameter.into()).index() as u32); vec.push(ExternRef::<Parameter>::func_new(&env, parameter.into()).index() as u32);
} }
let wasm_ptr = try_wasm!(env.data().data().copy_value_vec_to_wasm(&vec), env); let wasm_ptr = try_wasm!(env.data().data().copy_value_vec_to_wasm(&vec), env);
let r: u64 = unsafe { std::mem::transmute((wasm_ptr, vec.len() as u32)) }; let r: u64 = unsafe { std::mem::transmute((wasm_ptr, vec.len() as u32)) };

View File

@ -9,7 +9,7 @@ use std::sync::{Arc, Weak};
pub(crate) enum WasmObject { pub(crate) enum WasmObject {
// Static data // Static data
StringKey(crate::StringKey), StringKey(crate::StringKey),
EffectParameter(Weak<crate::static_data::EffectParameter>), EffectParameter(Weak<crate::static_data::Parameter>),
MoveData(Weak<dyn crate::static_data::MoveData>), MoveData(Weak<dyn crate::static_data::MoveData>),
Species(Weak<dyn crate::static_data::Species>), Species(Weak<dyn crate::static_data::Species>),
@ -182,13 +182,13 @@ impl FromWasmObj for crate::StringKey {
} }
} }
impl From<&Arc<crate::static_data::EffectParameter>> for WasmObject { impl From<&Arc<crate::static_data::Parameter>> for WasmObject {
fn from(value: &Arc<crate::static_data::EffectParameter>) -> Self { fn from(value: &Arc<crate::static_data::Parameter>) -> Self {
Self::EffectParameter(Arc::downgrade(value)) Self::EffectParameter(Arc::downgrade(value))
} }
} }
impl_from_wasm_obj!(EffectParameter, Arc<crate::static_data::EffectParameter>); impl_from_wasm_obj!(EffectParameter, Arc<crate::static_data::Parameter>);
impl From<&Arc<dyn crate::static_data::MoveData>> for WasmObject { impl From<&Arc<dyn crate::static_data::MoveData>> for WasmObject {
fn from(value: &Arc<dyn crate::static_data::MoveData>) -> Self { fn from(value: &Arc<dyn crate::static_data::MoveData>) -> Self {

View File

@ -2,7 +2,7 @@ use crate::dynamic_data::{ItemScript, Pokemon};
use crate::script_implementations::wasm::export_registry::WasmVoidResultExtension; use crate::script_implementations::wasm::export_registry::WasmVoidResultExtension;
use crate::script_implementations::wasm::extern_ref::ExternRef; use crate::script_implementations::wasm::extern_ref::ExternRef;
use crate::script_implementations::wasm::script_resolver::WebAssemblyEnvironmentData; use crate::script_implementations::wasm::script_resolver::WebAssemblyEnvironmentData;
use crate::static_data::EffectParameter; use crate::static_data::Parameter;
use crate::StringKey; use crate::StringKey;
use std::sync::Arc; use std::sync::Arc;
@ -64,12 +64,12 @@ macro_rules! ex_ref {
} }
impl ItemScript for WebAssemblyItemScript { impl ItemScript for WebAssemblyItemScript {
fn on_initialize(&self, pars: Vec<Arc<EffectParameter>>) -> anyhow_ext::Result<()> { fn on_initialize(&self, pars: Vec<Arc<Parameter>>) -> anyhow_ext::Result<()> {
let env = &self.environment; let env = &self.environment;
if let Some(func) = env.script_function_cache().item_on_initialize(env) { if let Some(func) = env.script_function_cache().item_on_initialize(env) {
let pars = pars let pars = pars
.into_iter() .into_iter()
.map(|p| ExternRef::<EffectParameter>::new(env, (&p).into()).index() as u32) .map(|p| ExternRef::<Parameter>::new(env, (&p).into()).index() as u32)
.collect::<Vec<_>>(); .collect::<Vec<_>>();
let wasm_ptr = env.copy_value_vec_to_wasm(&pars)?; let wasm_ptr = env.copy_value_vec_to_wasm(&pars)?;
let r: u64 = unsafe { std::mem::transmute((wasm_ptr, pars.len() as u32)) }; let r: u64 = unsafe { std::mem::transmute((wasm_ptr, pars.len() as u32)) };

View File

@ -12,7 +12,7 @@ use crate::script_implementations::wasm::export_registry::WasmVoidResultExtensio
use crate::script_implementations::wasm::extern_ref::ExternRef; use crate::script_implementations::wasm::extern_ref::ExternRef;
use crate::script_implementations::wasm::script_resolver::WebAssemblyEnvironmentData; use crate::script_implementations::wasm::script_resolver::WebAssemblyEnvironmentData;
use crate::script_implementations::wasm::WebAssemblyScriptCapabilities; use crate::script_implementations::wasm::WebAssemblyScriptCapabilities;
use crate::static_data::{EffectParameter, Item, Statistic, TypeIdentifier}; use crate::static_data::{Item, Parameter, Statistic, TypeIdentifier};
use crate::StringKey; use crate::StringKey;
/// A WebAssemblyScript is there to implement the Script trait within WebAssemblyScript. /// A WebAssemblyScript is there to implement the Script trait within WebAssemblyScript.
@ -125,7 +125,7 @@ impl Script for WebAssemblyScript {
Ok(()) Ok(())
} }
fn on_initialize(&self, library: &Arc<dyn DynamicLibrary>, pars: Vec<Arc<EffectParameter>>) -> Result<()> { fn on_initialize(&self, library: &Arc<dyn DynamicLibrary>, pars: Vec<Arc<Parameter>>) -> Result<()> {
if !self.has_capability(&WebAssemblyScriptCapabilities::Initialize) { if !self.has_capability(&WebAssemblyScriptCapabilities::Initialize) {
return Ok(()); return Ok(());
} }
@ -134,7 +134,7 @@ impl Script for WebAssemblyScript {
if let Some(func) = env.script_function_cache().on_initialize(env) { if let Some(func) = env.script_function_cache().on_initialize(env) {
let pars = pars let pars = pars
.into_iter() .into_iter()
.map(|p| ExternRef::<EffectParameter>::new(env, (&p).into()).index() as u32) .map(|p| ExternRef::<Parameter>::new(env, (&p).into()).index() as u32)
.collect::<Vec<_>>(); .collect::<Vec<_>>();
let wasm_ptr = env.copy_value_vec_to_wasm(&pars)?; let wasm_ptr = env.copy_value_vec_to_wasm(&pars)?;
let r: u64 = unsafe { std::mem::transmute((wasm_ptr, pars.len() as u32)) }; let r: u64 = unsafe { std::mem::transmute((wasm_ptr, pars.len() as u32)) };

View File

@ -65,6 +65,7 @@ pub mod tests {
0.5, 0.5,
&"test_growthrate".into(), &"test_growthrate".into(),
0, 0,
120,
Arc::new(FormImpl::new( Arc::new(FormImpl::new(
&"default".into(), &"default".into(),
0.0, 0.0,
@ -78,6 +79,7 @@ pub mod tests {
HashSet::new(), HashSet::new(),
)), )),
HashSet::new(), HashSet::new(),
Vec::new(),
)) ))
} }

View File

@ -59,7 +59,7 @@ mod time_of_day;
/// A parameter for an effect. This is basically a simple way to dynamically store multiple different /// A parameter for an effect. This is basically a simple way to dynamically store multiple different
/// primitives on data. /// primitives on data.
#[derive(PartialEq, Debug, Clone)] #[derive(PartialEq, Debug, Clone)]
pub enum EffectParameter { pub enum Parameter {
/// A boolean value. /// A boolean value.
Bool(bool), Bool(bool),
/// An integer value. Stored as a 64 bit int to deal with potentially large numbers. /// An integer value. Stored as a 64 bit int to deal with potentially large numbers.
@ -70,37 +70,37 @@ pub enum EffectParameter {
String(StringKey), String(StringKey),
} }
impl From<bool> for EffectParameter { impl From<bool> for Parameter {
fn from(b: bool) -> Self { fn from(b: bool) -> Self {
EffectParameter::Bool(b) Parameter::Bool(b)
} }
} }
impl From<i64> for EffectParameter { impl From<i64> for Parameter {
fn from(i: i64) -> Self { fn from(i: i64) -> Self {
EffectParameter::Int(i) Parameter::Int(i)
} }
} }
impl From<f32> for EffectParameter { impl From<f32> for Parameter {
fn from(f: f32) -> Self { fn from(f: f32) -> Self {
EffectParameter::Float(f) Parameter::Float(f)
} }
} }
impl From<StringKey> for EffectParameter { impl From<StringKey> for Parameter {
fn from(s: StringKey) -> Self { fn from(s: StringKey) -> Self {
EffectParameter::String(s) Parameter::String(s)
} }
} }
impl Display for EffectParameter { impl Display for Parameter {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self { match self {
EffectParameter::Bool(v) => f.write_fmt(format_args!("EffectParameter::Bool({v})")), Parameter::Bool(v) => f.write_fmt(format_args!("EffectParameter::Bool({v})")),
EffectParameter::Int(v) => f.write_fmt(format_args!("EffectParameter::Int({v})")), Parameter::Int(v) => f.write_fmt(format_args!("EffectParameter::Int({v})")),
EffectParameter::Float(v) => f.write_fmt(format_args!("EffectParameter::Float({v})")), Parameter::Float(v) => f.write_fmt(format_args!("EffectParameter::Float({v})")),
EffectParameter::String(v) => f.write_fmt(format_args!("EffectParameter::String({v})")), Parameter::String(v) => f.write_fmt(format_args!("EffectParameter::String({v})")),
} }
} }
} }

View File

@ -1,4 +1,4 @@
use crate::static_data::EffectParameter; use crate::static_data::Parameter;
use crate::StringKey; use crate::StringKey;
use std::fmt::Debug; use std::fmt::Debug;
use std::sync::Arc; use std::sync::Arc;
@ -10,7 +10,7 @@ pub trait SecondaryEffect: Debug {
/// The name of the effect. /// The name of the effect.
fn effect_name(&self) -> &StringKey; fn effect_name(&self) -> &StringKey;
/// A list of parameters for the effect. /// A list of parameters for the effect.
fn parameters(&self) -> &Vec<Arc<EffectParameter>>; fn parameters(&self) -> &Vec<Arc<Parameter>>;
} }
/// A secondary effect is an effect on a move that happens after it hits. /// A secondary effect is an effect on a move that happens after it hits.
@ -21,12 +21,12 @@ pub struct SecondaryEffectImpl {
/// The name of the effect. /// The name of the effect.
effect_name: StringKey, effect_name: StringKey,
/// A list of parameters for the effect. /// A list of parameters for the effect.
parameters: Vec<Arc<EffectParameter>>, parameters: Vec<Arc<Parameter>>,
} }
impl SecondaryEffectImpl { impl SecondaryEffectImpl {
/// Instantiates a new Secondary Effect. /// Instantiates a new Secondary Effect.
pub fn new(chance: f32, effect_name: StringKey, parameters: Vec<Arc<EffectParameter>>) -> Self { pub fn new(chance: f32, effect_name: StringKey, parameters: Vec<Arc<Parameter>>) -> Self {
Self { Self {
chance, chance,
effect_name, effect_name,
@ -45,7 +45,7 @@ impl SecondaryEffect for SecondaryEffectImpl {
&self.effect_name &self.effect_name
} }
/// A list of parameters for the effect. /// A list of parameters for the effect.
fn parameters(&self) -> &Vec<Arc<EffectParameter>> { fn parameters(&self) -> &Vec<Arc<Parameter>> {
&self.parameters &self.parameters
} }
} }
@ -66,7 +66,7 @@ pub(crate) mod tests {
impl SecondaryEffect for SecondaryEffect { impl SecondaryEffect for SecondaryEffect {
fn chance(&self) -> f32; fn chance(&self) -> f32;
fn effect_name(&self) -> &StringKey; fn effect_name(&self) -> &StringKey;
fn parameters(&self) -> &Vec<Arc<EffectParameter>>; fn parameters(&self) -> &Vec<Arc<Parameter >>;
} }
} }

View File

@ -1,4 +1,4 @@
use crate::static_data::EffectParameter; use crate::static_data::Parameter;
use crate::StringKey; use crate::StringKey;
use std::fmt::Debug; use std::fmt::Debug;
use std::sync::Arc; use std::sync::Arc;
@ -10,7 +10,7 @@ pub trait Ability: Debug {
/// The name of the script effect of the ability. /// The name of the script effect of the ability.
fn effect(&self) -> &StringKey; fn effect(&self) -> &StringKey;
/// The parameters for the script effect of the ability. /// The parameters for the script effect of the ability.
fn parameters(&self) -> &Vec<Arc<EffectParameter>>; fn parameters(&self) -> &Vec<Arc<Parameter>>;
} }
/// An ability is a passive effect in battle that is attached to a Pokemon. /// An ability is a passive effect in battle that is attached to a Pokemon.
@ -21,12 +21,12 @@ pub struct AbilityImpl {
/// The name of the script effect of the ability. /// The name of the script effect of the ability.
effect: StringKey, effect: StringKey,
/// The parameters for the script effect of the ability. /// The parameters for the script effect of the ability.
parameters: Vec<Arc<EffectParameter>>, parameters: Vec<Arc<Parameter>>,
} }
impl AbilityImpl { impl AbilityImpl {
/// Instantiates a new ability. /// Instantiates a new ability.
pub fn new(name: &StringKey, effect: &StringKey, parameters: Vec<Arc<EffectParameter>>) -> Self { pub fn new(name: &StringKey, effect: &StringKey, parameters: Vec<Arc<Parameter>>) -> Self {
Self { Self {
name: name.clone(), name: name.clone(),
effect: effect.clone(), effect: effect.clone(),
@ -45,7 +45,7 @@ impl Ability for AbilityImpl {
&self.effect &self.effect
} }
/// The parameters for the script effect of the ability. /// The parameters for the script effect of the ability.
fn parameters(&self) -> &Vec<Arc<EffectParameter>> { fn parameters(&self) -> &Vec<Arc<Parameter>> {
&self.parameters &self.parameters
} }
} }
@ -74,7 +74,7 @@ pub(crate) mod tests {
impl Ability for Ability { impl Ability for Ability {
fn name(&self) -> &StringKey; fn name(&self) -> &StringKey;
fn effect(&self) -> &StringKey; fn effect(&self) -> &StringKey;
fn parameters(&self) -> &Vec<Arc<EffectParameter>>; fn parameters(&self) -> &Vec<Arc<Parameter >>;
} }
} }
} }

View File

@ -0,0 +1,118 @@
use crate::defines::LevelInt;
use crate::static_data::{Gender, Parameter};
use crate::StringKey;
use std::sync::Arc;
/// The different ways a Pokemon can evolve.
#[derive(Debug)]
pub enum EvolutionMethod {
/// Evolves when a certain level is reached.
Level {
/// The level at which the Pokemon evolves.
level: LevelInt,
},
/// Evolves when a certain level is reached, and the Pokemon is a specific gender.
LevelGender {
/// The level at which the Pokemon evolves.
level: LevelInt,
/// The gender the Pokemon needs to be.
gender: Gender,
},
/// Evolves when an item is used.
Item {
/// The item that needs to be used.
item: StringKey,
},
/// Evolves when an item is used, and the Pokemon is a specific gender.
ItemGender {
/// The item that needs to be used.
item: StringKey,
/// The gender the Pokemon needs to be.
gender: Gender,
},
/// Evolves if an item is held.
HoldItem {
/// The item that needs to be held.
item: StringKey,
},
/// Evolves if a held item is held, and it's day.
DayHoldItem {
/// The item that needs to be held.
item: StringKey,
},
/// Evolves if a held item is held, and it's night.
NightHoldItem {
/// The item that needs to be held.
item: StringKey,
},
/// Evolves if the Pokemon knows a certain move.
HasMove {
/// The move that needs to be known.
move_name: StringKey,
},
/// Evolves when above a certain happiness level.
Happiness {
/// The happiness level that needs to be reached.
happiness: u8,
},
/// Evolves when above a certain happiness level, and it's day.
HappinessDay {
/// The happiness level that needs to be reached.
happiness: u8,
},
/// Evolves when above a certain happiness level, and it's night.
HappinessNight {
/// The happiness level that needs to be reached.
happiness: u8,
},
/// Evolves when traded.
Trade,
/// Evolves when traded with a certain species.
TradeSpecies {
/// The species that needs to be traded with.
species: StringKey,
},
/// Evolves when traded while it's holding a certain item.
TradeItem {
/// The item that needs to be held.
item: StringKey,
},
/// Evolves in a certain location.
Location {
/// The location the Pokemon needs to be in.
location: StringKey,
},
/// A custom evolution method, implemented by the user.
Custom {
/// The name of the custom evolution method.
name: StringKey,
/// The parameters of the custom evolution method.
params: Vec<Arc<Parameter>>,
},
}
#[derive(Debug)]
/// Data about how and into which Pokemon a species can evolve.
pub struct EvolutionData {
/// The method of evolution.
method: EvolutionMethod,
/// The Pokemon the species evolves into.
to: StringKey,
}
impl EvolutionData {
/// Creates a new evolution data instance.
pub fn new(method: EvolutionMethod, to: StringKey) -> Self {
Self { method, to }
}
/// Returns the method of evolution.
pub fn method(&self) -> &EvolutionMethod {
&self.method
}
/// Returns the Pokemon the species evolves into.
pub fn to(&self) -> &StringKey {
&self.to
}
}

View File

@ -1,6 +1,8 @@
#[doc(inline)] #[doc(inline)]
pub use ability::*; pub use ability::*;
#[doc(inline)] #[doc(inline)]
pub use evolution_data::*;
#[doc(inline)]
pub use form::*; pub use form::*;
#[doc(inline)] #[doc(inline)]
pub use gender::*; pub use gender::*;
@ -19,6 +21,8 @@ pub(crate) mod tests {
/// An ability is a passive effect in battle that is attached to a Pokemon. /// An ability is a passive effect in battle that is attached to a Pokemon.
mod ability; mod ability;
/// Data regarding into which Pokemon a species can evolve.
mod evolution_data;
/// A form is a variant of a specific species. A species always has at least one form, but can have /// A form is a variant of a specific species. A species always has at least one form, but can have
/// many more. /// many more.
mod form; mod form;

View File

@ -6,6 +6,7 @@ use hashbrown::{HashMap, HashSet};
use parking_lot::lock_api::RwLockReadGuard; use parking_lot::lock_api::RwLockReadGuard;
use parking_lot::{RawRwLock, RwLock}; use parking_lot::{RawRwLock, RwLock};
use crate::static_data::species_data::evolution_data::EvolutionData;
use crate::static_data::Form; use crate::static_data::Form;
use crate::static_data::Gender; use crate::static_data::Gender;
use crate::Random; use crate::Random;
@ -24,6 +25,8 @@ pub trait Species: Debug {
/// How hard it is to capture a Pokemon. 255 means this will be always caught, 0 means this is /// How hard it is to capture a Pokemon. 255 means this will be always caught, 0 means this is
/// uncatchable. /// uncatchable.
fn capture_rate(&self) -> u8; fn capture_rate(&self) -> u8;
/// The base happiness of the Pokemon.
fn base_happiness(&self) -> u8;
/// The forms that belong to this Pokemon. /// The forms that belong to this Pokemon.
fn forms(&self) -> RwLockReadGuard<'_, RawRwLock, HashMap<StringKey, Arc<dyn Form>>>; fn forms(&self) -> RwLockReadGuard<'_, RawRwLock, HashMap<StringKey, Arc<dyn Form>>>;
/// The arbitrary flags that can be set on a Pokemon for script use. /// The arbitrary flags that can be set on a Pokemon for script use.
@ -42,6 +45,8 @@ pub trait Species: Debug {
fn has_flag(&self, key: &StringKey) -> bool; fn has_flag(&self, key: &StringKey) -> bool;
/// Check whether the Pokemon has a specific flag set. /// Check whether the Pokemon has a specific flag set.
fn has_flag_by_hash(&self, key_hash: u32) -> bool; fn has_flag_by_hash(&self, key_hash: u32) -> bool;
/// The data regarding into which Pokemons this species can evolve, and how.
fn evolution_data(&self) -> &Vec<EvolutionData>;
} }
/// The data belonging to a Pokemon with certain characteristics. /// The data belonging to a Pokemon with certain characteristics.
@ -58,10 +63,14 @@ pub struct SpeciesImpl {
/// How hard it is to capture a Pokemon. 255 means this will be always caught, 0 means this is /// How hard it is to capture a Pokemon. 255 means this will be always caught, 0 means this is
/// uncatchable. /// uncatchable.
capture_rate: u8, capture_rate: u8,
/// The base happiness of the Pokemon.
base_happiness: u8,
/// The forms that belong to this Pokemon. /// The forms that belong to this Pokemon.
forms: RwLock<HashMap<StringKey, Arc<dyn Form>>>, forms: RwLock<HashMap<StringKey, Arc<dyn Form>>>,
/// The arbitrary flags that can be set on a Pokemon for script use. /// The arbitrary flags that can be set on a Pokemon for script use.
flags: HashSet<StringKey>, flags: HashSet<StringKey>,
/// The data regarding into which Pokemons this species can evolve, and how.
evolution_data: Vec<EvolutionData>,
} }
/// A cached String Key to get the default form. /// A cached String Key to get the default form.
@ -80,8 +89,10 @@ impl SpeciesImpl {
gender_rate: f32, gender_rate: f32,
growth_rate: &StringKey, growth_rate: &StringKey,
capture_rate: u8, capture_rate: u8,
base_happiness: u8,
default_form: Arc<dyn Form>, default_form: Arc<dyn Form>,
flags: HashSet<StringKey>, flags: HashSet<StringKey>,
evolution_data: Vec<EvolutionData>,
) -> Self { ) -> Self {
let mut forms = HashMap::with_capacity(1); let mut forms = HashMap::with_capacity(1);
forms.insert_unique_unchecked(get_default_key(), default_form); forms.insert_unique_unchecked(get_default_key(), default_form);
@ -91,8 +102,10 @@ impl SpeciesImpl {
gender_rate, gender_rate,
growth_rate: growth_rate.clone(), growth_rate: growth_rate.clone(),
capture_rate, capture_rate,
base_happiness,
forms: RwLock::new(forms), forms: RwLock::new(forms),
flags, flags,
evolution_data,
} }
} }
} }
@ -119,6 +132,11 @@ impl Species for SpeciesImpl {
fn capture_rate(&self) -> u8 { fn capture_rate(&self) -> u8 {
self.capture_rate self.capture_rate
} }
fn base_happiness(&self) -> u8 {
self.base_happiness
}
/// The forms that belong to this Pokemon. /// The forms that belong to this Pokemon.
fn forms(&self) -> RwLockReadGuard<'_, RawRwLock, HashMap<StringKey, Arc<dyn Form>>> { fn forms(&self) -> RwLockReadGuard<'_, RawRwLock, HashMap<StringKey, Arc<dyn Form>>> {
self.forms.read() self.forms.read()
@ -171,6 +189,10 @@ impl Species for SpeciesImpl {
fn has_flag_by_hash(&self, key_hash: u32) -> bool { fn has_flag_by_hash(&self, key_hash: u32) -> bool {
self.flags.contains::<u32>(&key_hash) self.flags.contains::<u32>(&key_hash)
} }
fn evolution_data(&self) -> &Vec<EvolutionData> {
&self.evolution_data
}
} }
#[cfg(test)] #[cfg(test)]
@ -188,6 +210,7 @@ pub(crate) mod tests {
fn gender_rate(&self) -> f32; fn gender_rate(&self) -> f32;
fn growth_rate(&self) -> &StringKey; fn growth_rate(&self) -> &StringKey;
fn capture_rate(&self) -> u8; fn capture_rate(&self) -> u8;
fn base_happiness(&self) -> u8;
fn forms(&self) -> RwLockReadGuard<'_, RawRwLock, HashMap<StringKey, Arc<dyn Form>>>; fn forms(&self) -> RwLockReadGuard<'_, RawRwLock, HashMap<StringKey, Arc<dyn Form>>>;
fn flags(&self) -> &HashSet<StringKey>; fn flags(&self) -> &HashSet<StringKey>;
fn add_form(&self, id: StringKey, form: Arc<dyn Form>); fn add_form(&self, id: StringKey, form: Arc<dyn Form>);
@ -197,6 +220,7 @@ pub(crate) mod tests {
fn get_random_gender(&self, rand: &mut Random) -> Gender; fn get_random_gender(&self, rand: &mut Random) -> Gender;
fn has_flag(&self, key: &StringKey) -> bool; fn has_flag(&self, key: &StringKey) -> bool;
fn has_flag_by_hash(&self, key_hash: u32) -> bool; fn has_flag_by_hash(&self, key_hash: u32) -> bool;
fn evolution_data(&self) -> &Vec<EvolutionData>;
} }
} }
} }

View File

@ -16,11 +16,12 @@ use pkmn_lib::dynamic_data::Gen7MiscLibrary;
use pkmn_lib::dynamic_data::{DynamicLibrary, DynamicLibraryImpl}; use pkmn_lib::dynamic_data::{DynamicLibrary, DynamicLibraryImpl};
use pkmn_lib::dynamic_data::{Gen7BattleStatCalculator, ScriptResolver}; use pkmn_lib::dynamic_data::{Gen7BattleStatCalculator, ScriptResolver};
use pkmn_lib::static_data::{ use pkmn_lib::static_data::{
AbilityImpl, AbilityLibrary, AbilityLibraryImpl, BattleItemCategory, DataLibrary, EffectParameter, Form, FormImpl, AbilityImpl, AbilityLibrary, AbilityLibraryImpl, BattleItemCategory, DataLibrary, EvolutionData, EvolutionMethod,
GrowthRateLibrary, GrowthRateLibraryImpl, ItemImpl, ItemLibrary, ItemLibraryImpl, LearnableMoves, Form, FormImpl, Gender, GrowthRateLibrary, GrowthRateLibraryImpl, ItemImpl, ItemLibrary, ItemLibraryImpl,
LearnableMovesImpl, LibrarySettingsImpl, LookupGrowthRate, MoveDataImpl, MoveLibrary, MoveLibraryImpl, NatureImpl, LearnableMoves, LearnableMovesImpl, LibrarySettingsImpl, LookupGrowthRate, MoveDataImpl, MoveLibrary,
NatureLibrary, NatureLibraryImpl, SecondaryEffect, SecondaryEffectImpl, SpeciesImpl, SpeciesLibrary, MoveLibraryImpl, NatureImpl, NatureLibrary, NatureLibraryImpl, Parameter, SecondaryEffect, SecondaryEffectImpl,
SpeciesLibraryImpl, StaticDataImpl, StaticStatisticSet, Statistic, TimeOfDay, TypeLibrary, TypeLibraryImpl, SpeciesImpl, SpeciesLibrary, SpeciesLibraryImpl, StaticDataImpl, StaticStatisticSet, Statistic, TimeOfDay,
TypeLibrary, TypeLibraryImpl,
}; };
use pkmn_lib::StringKey; use pkmn_lib::StringKey;
@ -225,7 +226,7 @@ pub fn load_abilities(path: &String) -> Arc<dyn AbilityLibrary> {
let mut parameters = Vec::new(); let mut parameters = Vec::new();
if let Some(p) = value.get("parameters") { if let Some(p) = value.get("parameters") {
for par in p.as_array().unwrap() { for par in p.as_array().unwrap() {
parameters.push(parse_effect_parameter(par)); parameters.push(parse_parameter(par));
} }
} }
@ -261,7 +262,7 @@ pub fn load_moves(path: &String, types: &Arc<dyn TypeLibrary>) -> Arc<dyn MoveLi
if let Some(pars) = v.get("parameters") { if let Some(pars) = v.get("parameters") {
let pars = pars.as_array().unwrap(); let pars = pars.as_array().unwrap();
for par in pars { for par in pars {
parameters.push(parse_effect_parameter(par)); parameters.push(parse_parameter(par));
} }
} }
@ -321,7 +322,7 @@ pub fn load_species(
let id = value.get("id").unwrap().as_i64().unwrap(); let id = value.get("id").unwrap().as_i64().unwrap();
let gender_rate = value.get("genderRatio").unwrap().as_f64().unwrap(); let gender_rate = value.get("genderRatio").unwrap().as_f64().unwrap();
let growth_rate_name = value.get("growthRate").unwrap().as_str().unwrap().into(); let growth_rate_name = value.get("growthRate").unwrap().as_str().unwrap().into();
let _base_happiness = value.get("baseHappiness").unwrap().as_i64().unwrap(); let base_happiness = value.get("baseHappiness").unwrap().as_i64().unwrap();
let catch_rate = value.get("catchRate").unwrap().as_i64().unwrap(); let catch_rate = value.get("catchRate").unwrap().as_i64().unwrap();
let _color = value.get("color").unwrap().as_str().unwrap(); let _color = value.get("color").unwrap().as_str().unwrap();
// let egg_groups = value.get("eggGroups").unwrap() // let egg_groups = value.get("eggGroups").unwrap()
@ -332,7 +333,11 @@ pub fn load_species(
// .collect(); // .collect();
let _egg_cycle = value.get("eggCycles").unwrap().as_i64().unwrap(); let _egg_cycle = value.get("eggCycles").unwrap().as_i64().unwrap();
// TODO: tags // TODO: tags
// TODO: evolutions let evolutions = if let Some(evolutions) = value.get("evolutions") {
evolutions.as_array().unwrap().iter().map(parse_evolution).collect()
} else {
Vec::new()
};
let forms = value.get("formes").unwrap().as_object().unwrap(); let forms = value.get("formes").unwrap().as_object().unwrap();
let default_form_value = forms.get("default").unwrap(); let default_form_value = forms.get("default").unwrap();
@ -344,14 +349,108 @@ pub fn load_species(
gender_rate as f32, gender_rate as f32,
&growth_rate_name, &growth_rate_name,
catch_rate as u8, catch_rate as u8,
base_happiness as u8,
default_form, default_form,
Default::default(), Default::default(),
evolutions,
); );
species_library.add(&name, Arc::new(species)); species_library.add(&name, Arc::new(species));
} }
Arc::new(species_library) Arc::new(species_library)
} }
fn parse_evolution(value: &Value) -> EvolutionData {
let species = StringKey::new(value.get("species").unwrap().as_str().unwrap());
let method = value.get("method").unwrap().as_str().unwrap();
let method = match method {
"level" => {
let level = value.get("data").unwrap().as_i64().unwrap() as LevelInt;
EvolutionMethod::Level { level }
}
"levelfemale" => {
let level = value.get("data").unwrap().as_i64().unwrap() as LevelInt;
EvolutionMethod::LevelGender {
level,
gender: Gender::Female,
}
}
"levelmale" => {
let level = value.get("data").unwrap().as_i64().unwrap() as LevelInt;
EvolutionMethod::LevelGender {
level,
gender: Gender::Male,
}
}
"happiness" => {
let happiness = value.get("data").unwrap().as_i64().unwrap() as u8;
EvolutionMethod::Happiness { happiness }
}
"happinessday" => {
let happiness = value.get("data").unwrap().as_i64().unwrap() as u8;
EvolutionMethod::HappinessDay { happiness }
}
"happinessnight" => {
let happiness = value.get("data").unwrap().as_i64().unwrap() as u8;
EvolutionMethod::HappinessNight { happiness }
}
"item" => {
let item = StringKey::new(value.get("data").unwrap().as_str().unwrap());
EvolutionMethod::Item { item }
}
"itemmale" => {
let item = StringKey::new(value.get("data").unwrap().as_str().unwrap());
EvolutionMethod::ItemGender {
item,
gender: Gender::Male,
}
}
"itemfemale" => {
let item = StringKey::new(value.get("data").unwrap().as_str().unwrap());
EvolutionMethod::ItemGender {
item,
gender: Gender::Female,
}
}
"holditem" => {
let item = StringKey::new(value.get("data").unwrap().as_str().unwrap());
EvolutionMethod::HoldItem { item }
}
"dayholditem" => {
let item = StringKey::new(value.get("data").unwrap().as_str().unwrap());
EvolutionMethod::DayHoldItem { item }
}
"nightholditem" => {
let item = StringKey::new(value.get("data").unwrap().as_str().unwrap());
EvolutionMethod::NightHoldItem { item }
}
"hasmove" => {
let move_name = StringKey::new(value.get("data").unwrap().as_str().unwrap());
EvolutionMethod::HasMove { move_name }
}
"trade" => EvolutionMethod::Trade,
"tradespecies" => {
let species = StringKey::new(value.get("data").unwrap().as_str().unwrap());
EvolutionMethod::TradeSpecies { species }
}
"tradeitem" => {
let item = StringKey::new(value.get("data").unwrap().as_str().unwrap());
EvolutionMethod::TradeItem { item }
}
"location" => {
let location = StringKey::new(value.get("data").unwrap().as_str().unwrap());
EvolutionMethod::Location { location }
}
"custom" => {
let data = value.get("data").unwrap().as_array().unwrap();
let name = StringKey::new(data[0].as_str().unwrap());
let params = data[1..].iter().map(parse_parameter).collect();
EvolutionMethod::Custom { name, params }
}
_ => panic!("Unknown evolution method: {}", method),
};
EvolutionData::new(method, species)
}
#[cfg(not(feature = "wasm"))] #[cfg(not(feature = "wasm"))]
fn load_script_resolver(path: &String) -> Arc<dyn ScriptResolver> { fn load_script_resolver(path: &String) -> Arc<dyn ScriptResolver> {
Arc::new(EmptyScriptResolver::default()) Arc::new(EmptyScriptResolver::default())
@ -471,7 +570,7 @@ fn parse_moves(value: &Value, move_library: &Arc<dyn MoveLibrary>) -> Arc<dyn Le
Arc::new(moves) Arc::new(moves)
} }
fn parse_effect_parameter(value: &Value) -> Arc<EffectParameter> { fn parse_parameter(value: &Value) -> Arc<Parameter> {
Arc::new(match value { Arc::new(match value {
Value::Null => { Value::Null => {
panic!("Unexpected type") panic!("Unexpected type")

View File

@ -8390,8 +8390,16 @@
} }
}, },
"evolutions": [ "evolutions": [
{ "species": "wormadam", "method": "levelfemale", "data": "20" }, {
{ "species": "mothim", "method": "levelmale", "data": "20" } "species": "wormadam",
"method": "levelfemale",
"data": 20
},
{
"species": "mothim",
"method": "levelmale",
"data": 20
}
] ]
}, },
"butterfree": { "butterfree": {
@ -12710,7 +12718,11 @@
} }
}, },
"evolutions": [ "evolutions": [
{ "species": "vespiquen", "method": "levelfemale", "data": "21" } {
"species": "vespiquen",
"method": "levelfemale",
"data": 21
}
] ]
}, },
"combusken": { "combusken": {