Make SecondaryEffect a trait
continuous-integration/drone/push Build is passing Details

This commit is contained in:
Deukhoofd 2022-11-27 18:22:57 +01:00
parent e04f61d9e6
commit 1c0b953d9a
Signed by: Deukhoofd
GPG Key ID: F63E044490819F6F
6 changed files with 95 additions and 40 deletions

View File

@ -6,7 +6,7 @@ use hashbrown::HashSet;
use crate::dynamic_data::choices::{MoveChoice, TurnChoice}; use crate::dynamic_data::choices::{MoveChoice, TurnChoice};
use crate::dynamic_data::Pokemon; use crate::dynamic_data::Pokemon;
use crate::dynamic_data::{LearnedMove, MoveLearnMethod}; use crate::dynamic_data::{LearnedMove, MoveLearnMethod};
use crate::static_data::{MoveCategory, MoveData, MoveTarget, SecondaryEffect}; use crate::static_data::{MoveCategory, MoveData, MoveTarget, SecondaryEffectImpl};
use crate::{StringKey, ValueIdentifiable, ValueIdentifier}; use crate::{StringKey, ValueIdentifiable, ValueIdentifier};
/// The misc library holds several misc functions required for the battle to run. /// The misc library holds several misc functions required for the battle to run.
@ -40,7 +40,11 @@ impl Gen7MiscLibrary {
255, 255,
MoveTarget::Any, MoveTarget::Any,
0, 0,
Some(SecondaryEffect::new(-1.0, StringKey::new("struggle"), vec![])), Some(Box::new(SecondaryEffectImpl::new(
-1.0,
StringKey::new("struggle"),
vec![],
))),
HashSet::new(), HashSet::new(),
)); ));
let struggle_learned_move = Arc::new(LearnedMove::new(&struggle_data, MoveLearnMethod::Unknown)); let struggle_learned_move = Arc::new(LearnedMove::new(&struggle_data, MoveLearnMethod::Unknown));

View File

@ -139,7 +139,7 @@ impl<T: ValueIdentifiable + ?Sized> From<Arc<T>> for IdentifiablePointer<Arc<T>>
} }
} }
impl<T: ValueIdentifiable> From<Option<Arc<T>>> for IdentifiablePointer<Arc<T>> { impl<T: ValueIdentifiable + ?Sized> From<Option<Arc<T>>> for IdentifiablePointer<Arc<T>> {
fn from(v: Option<Arc<T>>) -> Self { fn from(v: Option<Arc<T>>) -> Self {
if let Some(v) = v { if let Some(v) = v {
let id = unsafe { transmute(v.value_identifier()) }; let id = unsafe { transmute(v.value_identifier()) };
@ -153,6 +153,46 @@ impl<T: ValueIdentifiable> From<Option<Arc<T>>> for IdentifiablePointer<Arc<T>>
} }
} }
impl<T: ValueIdentifiable + ?Sized> From<Box<T>> for IdentifiablePointer<Box<T>> {
fn from(v: Box<T>) -> Self {
let id = unsafe { transmute(v.value_identifier()) };
Self {
ptr: Box::into_raw(Box::new(v)),
id,
}
}
}
impl<T: ValueIdentifiable + ?Sized> From<Option<Box<T>>> for IdentifiablePointer<Box<T>> {
fn from(v: Option<Box<T>>) -> Self {
if let Some(v) = v {
let id = unsafe { transmute(v.value_identifier()) };
Self {
ptr: Box::into_raw(Box::new(v)),
id,
}
} else {
IdentifiablePointer::none()
}
}
}
impl<T: ValueIdentifiable + ?Sized> From<&Option<Box<T>>> for IdentifiablePointer<Box<T>> {
fn from(v: &Option<Box<T>>) -> Self {
if let Some(v) = v {
let id = unsafe { transmute(v.value_identifier()) };
unsafe {
Self {
ptr: *Box::into_raw(Box::new(v as *const Box<T>)),
id,
}
}
} else {
IdentifiablePointer::none()
}
}
}
impl<T: ValueIdentifiable> From<Box<T>> for IdentifiablePointer<T> { impl<T: ValueIdentifiable> From<Box<T>> for IdentifiablePointer<T> {
fn from(v: Box<T>) -> Self { fn from(v: Box<T>) -> Self {
let id = unsafe { transmute(v.value_identifier()) }; let id = unsafe { transmute(v.value_identifier()) };

View File

@ -1,5 +1,7 @@
use crate::ffi::{ffi_arc_getter, BorrowedPtr, ExternPointer, IdentifiablePointer, OwnedPtr}; use crate::ffi::{ffi_arc_getter, BorrowedPtr, ExternPointer, IdentifiablePointer, OwnedPtr};
use crate::static_data::{EffectParameter, MoveCategory, MoveData, MoveTarget, SecondaryEffect, TypeIdentifier}; use crate::static_data::{
EffectParameter, MoveCategory, MoveData, MoveTarget, SecondaryEffect, SecondaryEffectImpl, TypeIdentifier,
};
use crate::StringKey; use crate::StringKey;
use hashbrown::HashSet; use hashbrown::HashSet;
use std::ffi::{c_char, CStr, CString}; use std::ffi::{c_char, CStr, CString};
@ -17,7 +19,7 @@ unsafe extern "C" fn move_data_new(
base_usages: u8, base_usages: u8,
target: MoveTarget, target: MoveTarget,
priority: i8, priority: i8,
secondary_effect: *mut SecondaryEffect, secondary_effect: *mut Box<dyn SecondaryEffect>,
flags: *const *const c_char, flags: *const *const c_char,
flags_length: usize, flags_length: usize,
) -> IdentifiablePointer<Arc<MoveData>> { ) -> IdentifiablePointer<Arc<MoveData>> {
@ -72,13 +74,8 @@ ffi_arc_getter!(MoveData, priority, i8);
#[no_mangle] #[no_mangle]
unsafe extern "C" fn move_data_secondary_effect( unsafe extern "C" fn move_data_secondary_effect(
ptr: ExternPointer<Arc<MoveData>>, ptr: ExternPointer<Arc<MoveData>>,
) -> IdentifiablePointer<SecondaryEffect> { ) -> IdentifiablePointer<Box<dyn SecondaryEffect>> {
let effect = ptr.as_ref().secondary_effect(); ptr.as_ref().secondary_effect().into()
if let Some(v) = effect {
(v as *const SecondaryEffect).into()
} else {
IdentifiablePointer::none()
}
} }
/// Arbitrary flags that can be applied to the move. /// Arbitrary flags that can be applied to the move.
@ -95,49 +92,49 @@ unsafe extern "C" fn secondary_effect_new(
effect_name: BorrowedPtr<c_char>, effect_name: BorrowedPtr<c_char>,
parameters: *mut OwnedPtr<EffectParameter>, parameters: *mut OwnedPtr<EffectParameter>,
parameters_length: usize, parameters_length: usize,
) -> IdentifiablePointer<SecondaryEffect> { ) -> IdentifiablePointer<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);
let mut parameters = Vec::with_capacity(parameters_length); let mut parameters = Vec::with_capacity(parameters_length);
for parameter in parameter_slice { for parameter in parameter_slice {
parameters.push(*Box::from_raw(*parameter)) parameters.push(*Box::from_raw(*parameter))
} }
Box::new(SecondaryEffect::new( let b: Box<dyn SecondaryEffect> = Box::new(SecondaryEffectImpl::new(
chance, chance,
CStr::from_ptr(effect_name).into(), CStr::from_ptr(effect_name).into(),
parameters, parameters,
)) ));
.into() b.into()
} }
/// Drop a secondary effect. /// Drop a secondary effect.
#[no_mangle] #[no_mangle]
unsafe extern "C" fn secondary_effect_drop(ptr: OwnedPtr<SecondaryEffect>) { unsafe extern "C" fn secondary_effect_drop(ptr: OwnedPtr<Box<dyn SecondaryEffect>>) {
drop_in_place(ptr) drop_in_place(ptr)
} }
/// The chance the effect triggers. /// The chance the effect triggers.
#[no_mangle] #[no_mangle]
unsafe extern "C" fn secondary_effect_chance(ptr: ExternPointer<SecondaryEffect>) -> f32 { unsafe extern "C" fn secondary_effect_chance(ptr: ExternPointer<Box<dyn SecondaryEffect>>) -> f32 {
ptr.as_ref().chance() ptr.as_ref().chance()
} }
/// The name of the effect. /// The name of the effect.
#[no_mangle] #[no_mangle]
unsafe extern "C" fn secondary_effect_effect_name(ptr: ExternPointer<SecondaryEffect>) -> OwnedPtr<c_char> { unsafe extern "C" fn secondary_effect_effect_name(ptr: ExternPointer<Box<dyn SecondaryEffect>>) -> OwnedPtr<c_char> {
CString::new(ptr.as_ref().effect_name().str()).unwrap().into_raw() CString::new(ptr.as_ref().effect_name().str()).unwrap().into_raw()
} }
/// The length of parameters of the effect. /// The length of parameters of the effect.
#[no_mangle] #[no_mangle]
unsafe extern "C" fn secondary_effect_parameter_length(ptr: ExternPointer<SecondaryEffect>) -> usize { unsafe extern "C" fn secondary_effect_parameter_length(ptr: ExternPointer<Box<dyn SecondaryEffect>>) -> usize {
ptr.as_ref().parameters().len() ptr.as_ref().parameters().len()
} }
/// Get a parameter of the effect. /// Get a parameter of the effect.
#[no_mangle] #[no_mangle]
unsafe extern "C" fn secondary_effect_parameter_get( unsafe extern "C" fn secondary_effect_parameter_get(
ptr: ExternPointer<SecondaryEffect>, ptr: ExternPointer<Box<dyn SecondaryEffect>>,
index: usize, index: usize,
) -> IdentifiablePointer<EffectParameter> { ) -> IdentifiablePointer<EffectParameter> {
if let Some(v) = ptr.as_ref().parameters().get(index) { if let Some(v) = ptr.as_ref().parameters().get(index) {

View File

@ -60,7 +60,7 @@ pub enum MoveTarget {
} }
/// A move is the skill Pokémon primarily use in battle. This is the data related to that. /// A move is the skill Pokémon primarily use in battle. This is the data related to that.
#[derive(PartialEq, Debug)] #[derive(Debug)]
pub struct MoveData { pub struct MoveData {
/// A unique identifier so we know what value this is. /// A unique identifier so we know what value this is.
identifier: ValueIdentifier, identifier: ValueIdentifier,
@ -82,7 +82,7 @@ pub struct MoveData {
/// The priority of the move. A higher priority means the move should go before other moves. /// The priority of the move. A higher priority means the move should go before other moves.
priority: i8, priority: i8,
/// The optional secondary effect the move has. /// The optional secondary effect the move has.
secondary_effect: Option<SecondaryEffect>, secondary_effect: Option<Box<dyn SecondaryEffect>>,
/// Arbitrary flags that can be applied to the move. /// Arbitrary flags that can be applied to the move.
flags: HashSet<StringKey>, flags: HashSet<StringKey>,
} }
@ -98,7 +98,7 @@ impl MoveData {
base_usages: u8, base_usages: u8,
target: MoveTarget, target: MoveTarget,
priority: i8, priority: i8,
secondary_effect: Option<SecondaryEffect>, secondary_effect: Option<Box<dyn SecondaryEffect>>,
flags: HashSet<StringKey>, flags: HashSet<StringKey>,
) -> MoveData { ) -> MoveData {
MoveData { MoveData {
@ -151,7 +151,7 @@ impl MoveData {
} }
/// The optional secondary effect the move has. /// The optional secondary effect the move has.
pub fn secondary_effect(&self) -> &Option<SecondaryEffect> { pub fn secondary_effect(&self) -> &Option<Box<dyn SecondaryEffect>> {
&self.secondary_effect &self.secondary_effect
} }

View File

@ -1,9 +1,20 @@
use crate::static_data::EffectParameter; use crate::static_data::EffectParameter;
use crate::{StringKey, ValueIdentifiable, ValueIdentifier}; use crate::{StringKey, ValueIdentifiable, ValueIdentifier};
use std::fmt::Debug;
/// 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.
#[derive(PartialEq, Debug)] pub trait SecondaryEffect: Debug + ValueIdentifiable {
pub struct SecondaryEffect { /// The chance in percentages that the effect triggers. -1 to make it always trigger.
fn chance(&self) -> f32;
/// The name of the effect.
fn effect_name(&self) -> &StringKey;
/// A list of parameters for the effect.
fn parameters(&self) -> &Vec<EffectParameter>;
}
/// A secondary effect is an effect on a move that happens after it hits.
#[derive(Debug)]
pub struct SecondaryEffectImpl {
/// A unique identifier so we know what value this is. /// A unique identifier so we know what value this is.
identifier: ValueIdentifier, identifier: ValueIdentifier,
/// The chance in percentages that the effect triggers. -1 to make it always trigger. /// The chance in percentages that the effect triggers. -1 to make it always trigger.
@ -14,32 +25,34 @@ pub struct SecondaryEffect {
parameters: Vec<EffectParameter>, parameters: Vec<EffectParameter>,
} }
impl SecondaryEffect { impl SecondaryEffectImpl {
/// Instantiates a new Secondary Effect. /// Instantiates a new Secondary Effect.
pub fn new(chance: f32, effect_name: StringKey, parameters: Vec<EffectParameter>) -> SecondaryEffect { pub fn new(chance: f32, effect_name: StringKey, parameters: Vec<EffectParameter>) -> Self {
SecondaryEffect { Self {
identifier: Default::default(), identifier: Default::default(),
chance, chance,
effect_name, effect_name,
parameters, parameters,
} }
} }
}
impl SecondaryEffect for SecondaryEffectImpl {
/// The chance in percentages that the effect triggers. -1 to make it always trigger. /// The chance in percentages that the effect triggers. -1 to make it always trigger.
pub fn chance(&self) -> f32 { fn chance(&self) -> f32 {
self.chance self.chance
} }
/// The name of the effect. /// The name of the effect.
pub fn effect_name(&self) -> &StringKey { fn effect_name(&self) -> &StringKey {
&self.effect_name &self.effect_name
} }
/// A list of parameters for the effect. /// A list of parameters for the effect.
pub fn parameters(&self) -> &Vec<EffectParameter> { fn parameters(&self) -> &Vec<EffectParameter> {
&self.parameters &self.parameters
} }
} }
impl ValueIdentifiable for SecondaryEffect { impl ValueIdentifiable for SecondaryEffectImpl {
fn value_identifier(&self) -> ValueIdentifier { fn value_identifier(&self) -> ValueIdentifier {
self.identifier self.identifier
} }
@ -50,14 +63,15 @@ mod tests {
use assert_approx_eq::assert_approx_eq; use assert_approx_eq::assert_approx_eq;
use crate::static_data::moves::secondary_effect::SecondaryEffect; use crate::static_data::moves::secondary_effect::SecondaryEffect;
use crate::static_data::SecondaryEffectImpl;
#[test] #[test]
fn create_secondary_effect() { fn create_secondary_effect() {
let empty = SecondaryEffect::new(0.0, "".into(), vec![]); let empty = SecondaryEffectImpl::new(0.0, "".into(), vec![]);
assert_approx_eq!(empty.chance(), 0.0); assert_approx_eq!(empty.chance(), 0.0);
assert_eq!(empty.effect_name(), &"".into()); assert_eq!(empty.effect_name(), &"".into());
assert_eq!(empty.parameters().len(), 0); assert_eq!(empty.parameters().len(), 0);
let set = SecondaryEffect::new(50.0, "foo".into(), Vec::new()); let set = SecondaryEffectImpl::new(50.0, "foo".into(), Vec::new());
assert_approx_eq!(set.chance(), 50.0); assert_approx_eq!(set.chance(), 50.0);
assert_eq!(set.effect_name(), &"foo".into()); assert_eq!(set.effect_name(), &"foo".into());
assert_eq!(set.parameters().len(), 0); assert_eq!(set.parameters().len(), 0);

View File

@ -18,7 +18,7 @@ use pkmn_lib::script_implementations::wasm::script_resolver::WebAssemblyScriptRe
use pkmn_lib::static_data::{ use pkmn_lib::static_data::{
AbilityImpl, AbilityLibrary, BattleItemCategory, DataLibrary, EffectParameter, Form, GrowthRateLibrary, ItemImpl, AbilityImpl, AbilityLibrary, BattleItemCategory, DataLibrary, EffectParameter, Form, GrowthRateLibrary, ItemImpl,
ItemLibrary, LearnableMoves, LibrarySettings, LookupGrowthRate, MoveData, MoveLibrary, NatureImpl, NatureLibrary, ItemLibrary, LearnableMoves, LibrarySettings, LookupGrowthRate, MoveData, MoveLibrary, NatureImpl, NatureLibrary,
SecondaryEffect, Species, StaticData, StaticStatisticSet, Statistic, TypeLibrary, SecondaryEffect, SecondaryEffectImpl, Species, StaticData, StaticStatisticSet, Statistic, TypeLibrary,
}; };
use pkmn_lib::StringKey; use pkmn_lib::StringKey;
@ -182,7 +182,7 @@ pub fn load_moves(path: &String, lib: &mut StaticData) {
let pp = move_data.get("pp").unwrap().as_i64().unwrap() as u8; let pp = move_data.get("pp").unwrap().as_i64().unwrap() as u8;
let target = serde_json::from_value(move_data.get("target").unwrap().clone()).unwrap(); let target = serde_json::from_value(move_data.get("target").unwrap().clone()).unwrap();
let priority = move_data.get("priority").unwrap().as_i64().unwrap() as i8; let priority = move_data.get("priority").unwrap().as_i64().unwrap() as i8;
let secondary_effect = if let Some(v) = move_data.get("effect") { let secondary_effect: Option<Box<dyn SecondaryEffect>> = if let Some(v) = move_data.get("effect") {
let mut chance = -1.0; let mut chance = -1.0;
if let Some(chance_value) = v.get("chance") { if let Some(chance_value) = v.get("chance") {
chance = chance_value.as_f64().unwrap() as f32; chance = chance_value.as_f64().unwrap() as f32;
@ -195,11 +195,11 @@ pub fn load_moves(path: &String, lib: &mut StaticData) {
} }
} }
Some(SecondaryEffect::new( Some(Box::new(SecondaryEffectImpl::new(
chance, chance,
v.get("name").unwrap().as_str().unwrap().into(), v.get("name").unwrap().as_str().unwrap().into(),
parameters, parameters,
)) )))
} else { } else {
None None
}; };