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::Pokemon;
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};
/// The misc library holds several misc functions required for the battle to run.
@ -40,7 +40,11 @@ impl Gen7MiscLibrary {
255,
MoveTarget::Any,
0,
Some(SecondaryEffect::new(-1.0, StringKey::new("struggle"), vec![])),
Some(Box::new(SecondaryEffectImpl::new(
-1.0,
StringKey::new("struggle"),
vec![],
))),
HashSet::new(),
));
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 {
if let Some(v) = v {
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> {
fn from(v: Box<T>) -> Self {
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::static_data::{EffectParameter, MoveCategory, MoveData, MoveTarget, SecondaryEffect, TypeIdentifier};
use crate::static_data::{
EffectParameter, MoveCategory, MoveData, MoveTarget, SecondaryEffect, SecondaryEffectImpl, TypeIdentifier,
};
use crate::StringKey;
use hashbrown::HashSet;
use std::ffi::{c_char, CStr, CString};
@ -17,7 +19,7 @@ unsafe extern "C" fn move_data_new(
base_usages: u8,
target: MoveTarget,
priority: i8,
secondary_effect: *mut SecondaryEffect,
secondary_effect: *mut Box<dyn SecondaryEffect>,
flags: *const *const c_char,
flags_length: usize,
) -> IdentifiablePointer<Arc<MoveData>> {
@ -72,13 +74,8 @@ ffi_arc_getter!(MoveData, priority, i8);
#[no_mangle]
unsafe extern "C" fn move_data_secondary_effect(
ptr: ExternPointer<Arc<MoveData>>,
) -> IdentifiablePointer<SecondaryEffect> {
let effect = ptr.as_ref().secondary_effect();
if let Some(v) = effect {
(v as *const SecondaryEffect).into()
} else {
IdentifiablePointer::none()
}
) -> IdentifiablePointer<Box<dyn SecondaryEffect>> {
ptr.as_ref().secondary_effect().into()
}
/// 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>,
parameters: *mut OwnedPtr<EffectParameter>,
parameters_length: usize,
) -> IdentifiablePointer<SecondaryEffect> {
) -> IdentifiablePointer<Box<dyn SecondaryEffect>> {
let parameter_slice = std::slice::from_raw_parts(parameters, parameters_length);
let mut parameters = Vec::with_capacity(parameters_length);
for parameter in parameter_slice {
parameters.push(*Box::from_raw(*parameter))
}
Box::new(SecondaryEffect::new(
let b: Box<dyn SecondaryEffect> = Box::new(SecondaryEffectImpl::new(
chance,
CStr::from_ptr(effect_name).into(),
parameters,
))
.into()
));
b.into()
}
/// Drop a secondary effect.
#[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)
}
/// The chance the effect triggers.
#[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()
}
/// The name of the effect.
#[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()
}
/// The length of parameters of the effect.
#[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()
}
/// Get a parameter of the effect.
#[no_mangle]
unsafe extern "C" fn secondary_effect_parameter_get(
ptr: ExternPointer<SecondaryEffect>,
ptr: ExternPointer<Box<dyn SecondaryEffect>>,
index: usize,
) -> IdentifiablePointer<EffectParameter> {
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.
#[derive(PartialEq, Debug)]
#[derive(Debug)]
pub struct MoveData {
/// A unique identifier so we know what value this is.
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.
priority: i8,
/// 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.
flags: HashSet<StringKey>,
}
@ -98,7 +98,7 @@ impl MoveData {
base_usages: u8,
target: MoveTarget,
priority: i8,
secondary_effect: Option<SecondaryEffect>,
secondary_effect: Option<Box<dyn SecondaryEffect>>,
flags: HashSet<StringKey>,
) -> MoveData {
MoveData {
@ -151,7 +151,7 @@ impl MoveData {
}
/// 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
}

View File

@ -1,9 +1,20 @@
use crate::static_data::EffectParameter;
use crate::{StringKey, ValueIdentifiable, ValueIdentifier};
use std::fmt::Debug;
/// A secondary effect is an effect on a move that happens after it hits.
#[derive(PartialEq, Debug)]
pub struct SecondaryEffect {
pub trait SecondaryEffect: Debug + ValueIdentifiable {
/// 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.
identifier: ValueIdentifier,
/// The chance in percentages that the effect triggers. -1 to make it always trigger.
@ -14,32 +25,34 @@ pub struct SecondaryEffect {
parameters: Vec<EffectParameter>,
}
impl SecondaryEffect {
impl SecondaryEffectImpl {
/// Instantiates a new Secondary Effect.
pub fn new(chance: f32, effect_name: StringKey, parameters: Vec<EffectParameter>) -> SecondaryEffect {
SecondaryEffect {
pub fn new(chance: f32, effect_name: StringKey, parameters: Vec<EffectParameter>) -> Self {
Self {
identifier: Default::default(),
chance,
effect_name,
parameters,
}
}
}
impl SecondaryEffect for SecondaryEffectImpl {
/// 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
}
/// The name of the effect.
pub fn effect_name(&self) -> &StringKey {
fn effect_name(&self) -> &StringKey {
&self.effect_name
}
/// A list of parameters for the effect.
pub fn parameters(&self) -> &Vec<EffectParameter> {
fn parameters(&self) -> &Vec<EffectParameter> {
&self.parameters
}
}
impl ValueIdentifiable for SecondaryEffect {
impl ValueIdentifiable for SecondaryEffectImpl {
fn value_identifier(&self) -> ValueIdentifier {
self.identifier
}
@ -50,14 +63,15 @@ mod tests {
use assert_approx_eq::assert_approx_eq;
use crate::static_data::moves::secondary_effect::SecondaryEffect;
use crate::static_data::SecondaryEffectImpl;
#[test]
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_eq!(empty.effect_name(), &"".into());
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_eq!(set.effect_name(), &"foo".into());
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::{
AbilityImpl, AbilityLibrary, BattleItemCategory, DataLibrary, EffectParameter, Form, GrowthRateLibrary, ItemImpl,
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;
@ -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 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 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;
if let Some(chance_value) = v.get("chance") {
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,
v.get("name").unwrap().as_str().unwrap().into(),
parameters,
))
)))
} else {
None
};