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

This commit is contained in:
Deukhoofd 2022-11-27 22:29:11 +01:00
parent 27164616e9
commit ad9f17ccf1
Signed by: Deukhoofd
GPG Key ID: F63E044490819F6F
12 changed files with 118 additions and 81 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, SecondaryEffectImpl};
use crate::static_data::{MoveCategory, MoveData, MoveDataImpl, MoveTarget, SecondaryEffectImpl};
use crate::{StringKey, ValueIdentifiable, ValueIdentifier};
/// The misc library holds several misc functions required for the battle to run.
@ -31,7 +31,7 @@ pub struct Gen7MiscLibrary {
impl Gen7MiscLibrary {
/// Instantiates a new MiscLibrary.
pub fn new() -> Self {
let struggle_data = Arc::new(MoveData::new(
let struggle_data: Arc<dyn MoveData> = Arc::new(MoveDataImpl::new(
&StringKey::new("struggle"),
0.into(),
MoveCategory::Physical,

View File

@ -101,7 +101,7 @@ pub struct ExecutingMove {
/// The move the user has actually chosen to do.
chosen_move: Arc<LearnedMove>,
/// The move that the user is actually going to do.
use_move: Arc<MoveData>,
use_move: Arc<dyn MoveData>,
/// The script of the move.
script: ScriptContainer,
/// The targets for this move.
@ -117,7 +117,7 @@ impl ExecutingMove {
number_of_hits: u8,
user: Arc<Pokemon>,
chosen_move: Arc<LearnedMove>,
use_move: Arc<MoveData>,
use_move: Arc<dyn MoveData>,
script: ScriptContainer,
) -> Self {
let total_hits = number_of_hits as usize * targets.len();
@ -155,7 +155,7 @@ impl ExecutingMove {
&self.chosen_move
}
/// The move that the user is actually going to do.
pub fn use_move(&self) -> &Arc<MoveData> {
pub fn use_move(&self) -> &Arc<dyn MoveData> {
&self.use_move
}
/// The script of the move.

View File

@ -11,7 +11,7 @@ pub struct LearnedMove {
/// A unique identifier so we know what value this is.
identifier: ValueIdentifier,
/// The immutable move information of the move.
move_data: Arc<MoveData>,
move_data: Arc<dyn MoveData>,
/// The maximal power points for this move.
max_pp: u8,
/// The amount of remaining power points. If this is 0, we can not use the move anymore.
@ -33,7 +33,7 @@ pub enum MoveLearnMethod {
impl LearnedMove {
/// Instantiate a new learned move.
pub fn new(move_data: &Arc<MoveData>, learn_method: MoveLearnMethod) -> Self {
pub fn new(move_data: &Arc<dyn MoveData>, learn_method: MoveLearnMethod) -> Self {
Self {
identifier: Default::default(),
move_data: move_data.clone(),
@ -44,7 +44,7 @@ impl LearnedMove {
}
/// The immutable move information of the move.
pub fn move_data(&self) -> &Arc<MoveData> {
pub fn move_data(&self) -> &Arc<dyn MoveData> {
&self.move_data
}
/// The maximal power points for this move.
@ -100,11 +100,11 @@ impl ValueIdentifiable for LearnedMove {
#[cfg(test)]
mod tests {
use super::*;
use crate::static_data::{MoveCategory, MoveTarget};
use crate::static_data::{MoveCategory, MoveDataImpl, MoveTarget};
#[test]
fn create_learned_move_restore_uses() {
let data = Arc::new(MoveData::new(
let data: Arc<dyn MoveData> = Arc::new(MoveDataImpl::new(
&"foo".into(),
0u8.into(),
MoveCategory::Special,

View File

@ -7,7 +7,7 @@ use std::sync::Arc;
/// Instantiate a new learned move.
#[no_mangle]
extern "C" fn learned_move_new(
move_data: ExternPointer<Arc<MoveData>>,
move_data: ExternPointer<Arc<dyn MoveData>>,
learn_method: MoveLearnMethod,
) -> IdentifiablePointer<Arc<LearnedMove>> {
Arc::new(LearnedMove::new(move_data.as_ref(), learn_method)).into()
@ -23,7 +23,7 @@ extern "C" fn learned_move_drop(learned_move: OwnedPtr<Arc<LearnedMove>>) {
#[no_mangle]
extern "C" fn learned_move_move_data(
learned_move: ExternPointer<Arc<LearnedMove>>,
) -> IdentifiablePointer<Arc<MoveData>> {
) -> IdentifiablePointer<Arc<dyn MoveData>> {
learned_move.as_ref().move_data().clone().into()
}

View File

@ -73,6 +73,6 @@ macro_rules! library_interface {
}
library_interface!(SpeciesLibrary, Species);
library_interface!(MoveLibrary, MoveData);
library_interface!(MoveLibrary, dyn MoveData);
library_interface!(AbilityLibrary, dyn Ability);
library_interface!(ItemLibrary, dyn Item);

View File

@ -1,6 +1,7 @@
use crate::ffi::{ffi_arc_getter, BorrowedPtr, ExternPointer, IdentifiablePointer, OwnedPtr};
use crate::static_data::{
EffectParameter, MoveCategory, MoveData, MoveTarget, SecondaryEffect, SecondaryEffectImpl, TypeIdentifier,
EffectParameter, MoveCategory, MoveData, MoveDataImpl, MoveTarget, SecondaryEffect, SecondaryEffectImpl,
TypeIdentifier,
};
use crate::StringKey;
use hashbrown::HashSet;
@ -22,7 +23,7 @@ unsafe extern "C" fn move_data_new(
secondary_effect: *mut Box<dyn SecondaryEffect>,
flags: *const *const c_char,
flags_length: usize,
) -> IdentifiablePointer<Arc<MoveData>> {
) -> IdentifiablePointer<Arc<dyn MoveData>> {
let flags = std::slice::from_raw_parts(flags, flags_length);
let name: StringKey = CStr::from_ptr(name).to_str().unwrap().into();
let mut flags_set: HashSet<StringKey> = HashSet::with_capacity(flags_length);
@ -34,7 +35,7 @@ unsafe extern "C" fn move_data_new(
} else {
Some(*Box::from_raw(secondary_effect))
};
Arc::new(MoveData::new(
let a: Arc<dyn MoveData> = Arc::new(MoveDataImpl::new(
&name,
move_type,
category,
@ -45,42 +46,42 @@ unsafe extern "C" fn move_data_new(
priority,
secondary_effect,
flags_set,
))
.into()
));
a.into()
}
/// Drops a reference counted move.
#[no_mangle]
unsafe extern "C" fn move_data_drop(ptr: OwnedPtr<Arc<MoveData>>) {
unsafe extern "C" fn move_data_drop(ptr: OwnedPtr<Arc<dyn MoveData>>) {
drop_in_place(ptr)
}
/// The name of the move.
#[no_mangle]
unsafe extern "C" fn move_data_name(ptr: ExternPointer<Arc<MoveData>>) -> OwnedPtr<c_char> {
unsafe extern "C" fn move_data_name(ptr: ExternPointer<Arc<dyn MoveData>>) -> OwnedPtr<c_char> {
let name = ptr.as_ref().name();
CString::new(name.str()).unwrap().into_raw()
}
ffi_arc_getter!(MoveData, move_type, TypeIdentifier);
ffi_arc_getter!(MoveData, category, MoveCategory);
ffi_arc_getter!(MoveData, base_power, u8);
ffi_arc_getter!(MoveData, accuracy, u8);
ffi_arc_getter!(MoveData, base_usages, u8);
ffi_arc_getter!(MoveData, target, MoveTarget);
ffi_arc_getter!(MoveData, priority, i8);
ffi_arc_getter!(dyn MoveData, move_type, TypeIdentifier);
ffi_arc_getter!(dyn MoveData, category, MoveCategory);
ffi_arc_getter!(dyn MoveData, base_power, u8);
ffi_arc_getter!(dyn MoveData, accuracy, u8);
ffi_arc_getter!(dyn MoveData, base_usages, u8);
ffi_arc_getter!(dyn MoveData, target, MoveTarget);
ffi_arc_getter!(dyn MoveData, priority, i8);
/// The optional secondary effect the move has.
#[no_mangle]
unsafe extern "C" fn move_data_secondary_effect(
ptr: ExternPointer<Arc<MoveData>>,
ptr: ExternPointer<Arc<dyn MoveData>>,
) -> IdentifiablePointer<Box<dyn SecondaryEffect>> {
ptr.as_ref().secondary_effect().into()
}
/// Arbitrary flags that can be applied to the move.
#[no_mangle]
unsafe extern "C" fn move_data_has_flag(ptr: ExternPointer<Arc<MoveData>>, flag: *const c_char) -> u8 {
unsafe extern "C" fn move_data_has_flag(ptr: ExternPointer<Arc<dyn MoveData>>, flag: *const c_char) -> u8 {
let flag = CStr::from_ptr(flag).into();
u8::from(ptr.as_ref().has_flag(&flag))
}

View File

@ -16,15 +16,15 @@ register! {
fn executing_move_get_use_move(
env: FunctionEnvMut<WebAssemblyEnv>,
executing_move: ExternRef<ExecutingMove>,
) -> ExternRef<MoveData> {
ExternRef::func_new(&env, executing_move.value_func(&env).unwrap().use_move().as_ref())
) -> ExternRef<dyn MoveData> {
ExternRef::func_new(&env, executing_move.value_func(&env).unwrap().use_move())
}
fn executing_move_get_chosen_move(
env: FunctionEnvMut<WebAssemblyEnv>,
executing_move: ExternRef<ExecutingMove>,
) -> ExternRef<LearnedMove> {
ExternRef::func_new(&env, executing_move.value_func(&env).unwrap().chosen_move().as_ref())
ExternRef::func_new(&env, executing_move.value_func_arc(&env).unwrap().chosen_move().as_ref())
}
fn executing_move_get_number_of_hits(

View File

@ -20,7 +20,7 @@ register! {
fn learned_move_get_move_data(
env: FunctionEnvMut<WebAssemblyEnv>,
turn_choice: ExternRef<LearnedMove>,
) -> ExternRef<MoveData> {
) -> ExternRef<dyn MoveData> {
ExternRef::func_new(&env, turn_choice.value_func(&env).unwrap().move_data())
}
}

View File

@ -10,7 +10,7 @@ fn move_library_get_move(
env: FunctionEnvMut<WebAssemblyEnv>,
lib: ExternRef<MoveLibrary>,
string_key: ExternRef<StringKey>,
) -> ExternRef<MoveData> {
) -> ExternRef<dyn MoveData> {
let lib = lib.value_func(&env).unwrap();
let m = lib.get(string_key.value_func(&env).unwrap());
if let Some(v) = m {
@ -20,7 +20,7 @@ fn move_library_get_move(
}
}
fn move_library_get_move_by_hash(env: FunctionEnvMut<WebAssemblyEnv>, lib: ExternRef<MoveLibrary>, hash: u32) -> ExternRef<MoveData> {
fn move_library_get_move_by_hash(env: FunctionEnvMut<WebAssemblyEnv>, lib: ExternRef<MoveLibrary>, hash: u32) -> ExternRef<dyn MoveData> {
let lib = lib.value_func(&env).unwrap();
let m = lib.get_by_hash(hash);
if let Some(v) = m {
@ -30,35 +30,35 @@ fn move_library_get_move_by_hash(env: FunctionEnvMut<WebAssemblyEnv>, lib: Exter
}
}
fn move_data_get_name(env: FunctionEnvMut<WebAssemblyEnv>, move_data: ExternRef<MoveData>) -> ExternRef<StringKey> {
ExternRef::func_new(&env, move_data.value_func(&env).unwrap().name())
fn move_data_get_name(env: FunctionEnvMut<WebAssemblyEnv>, move_data: ExternRef<dyn MoveData>) -> ExternRef<StringKey> {
ExternRef::func_new(&env, move_data.value_func_arc(&env).unwrap().name())
}
fn move_data_get_type(env: FunctionEnvMut<WebAssemblyEnv>, move_data: ExternRef<MoveData>) -> u8 {
move_data.value_func(&env).unwrap().move_type().into()
fn move_data_get_type(env: FunctionEnvMut<WebAssemblyEnv>, move_data: ExternRef<dyn MoveData>) -> u8 {
move_data.value_func_arc(&env).unwrap().move_type().into()
}
fn move_data_get_category(env: FunctionEnvMut<WebAssemblyEnv>, move_data: ExternRef<MoveData>) -> u8 {
move_data.value_func(&env).unwrap().category() as u8
fn move_data_get_category(env: FunctionEnvMut<WebAssemblyEnv>, move_data: ExternRef<dyn MoveData>) -> u8 {
move_data.value_func_arc(&env).unwrap().category() as u8
}
fn move_data_get_base_power(env: FunctionEnvMut<WebAssemblyEnv>, move_data: ExternRef<MoveData>) -> u8 {
move_data.value_func(&env).unwrap().base_power()
fn move_data_get_base_power(env: FunctionEnvMut<WebAssemblyEnv>, move_data: ExternRef<dyn MoveData>) -> u8 {
move_data.value_func_arc(&env).unwrap().base_power()
}
fn move_data_get_accuracy(env: FunctionEnvMut<WebAssemblyEnv>, move_data: ExternRef<MoveData>) -> u8 {
move_data.value_func(&env).unwrap().accuracy()
fn move_data_get_accuracy(env: FunctionEnvMut<WebAssemblyEnv>, move_data: ExternRef<dyn MoveData>) -> u8 {
move_data.value_func_arc(&env).unwrap().accuracy()
}
fn move_data_get_base_usages(env: FunctionEnvMut<WebAssemblyEnv>, move_data: ExternRef<MoveData>) -> u8 {
move_data.value_func(&env).unwrap().base_usages()
fn move_data_get_base_usages(env: FunctionEnvMut<WebAssemblyEnv>, move_data: ExternRef<dyn MoveData>) -> u8 {
move_data.value_func_arc(&env).unwrap().base_usages()
}
fn move_data_get_target(env: FunctionEnvMut<WebAssemblyEnv>, move_data: ExternRef<MoveData>) -> u8 {
move_data.value_func(&env).unwrap().target() as u8
fn move_data_get_target(env: FunctionEnvMut<WebAssemblyEnv>, move_data: ExternRef<dyn MoveData>) -> u8 {
move_data.value_func_arc(&env).unwrap().target() as u8
}
fn move_data_get_priority(env: FunctionEnvMut<WebAssemblyEnv>, move_data: ExternRef<MoveData>) -> i8 {
move_data.value_func(&env).unwrap().priority()
fn move_data_get_priority(env: FunctionEnvMut<WebAssemblyEnv>, move_data: ExternRef<dyn MoveData>) -> i8 {
move_data.value_func_arc(&env).unwrap().priority()
}
fn move_data_has_flag(env: FunctionEnvMut<WebAssemblyEnv>, move_data: ExternRef<MoveData>, flag: ExternRef<StringKey>) -> u8 {
u8::from(move_data.value_func(&env).unwrap().has_flag(flag.value_func(&env).unwrap()))
fn move_data_has_flag(env: FunctionEnvMut<WebAssemblyEnv>, move_data: ExternRef<dyn MoveData>, flag: ExternRef<StringKey>) -> u8 {
u8::from(move_data.value_func_arc(&env).unwrap().has_flag(flag.value_func(&env).unwrap()))
}
fn move_data_has_flag_by_hash(env: FunctionEnvMut<WebAssemblyEnv>, move_data: ExternRef<MoveData>, flag_hash: u32) -> u8 {
u8::from(move_data.value_func(&env).unwrap().has_flag_by_hash(flag_hash))
fn move_data_has_flag_by_hash(env: FunctionEnvMut<WebAssemblyEnv>, move_data: ExternRef<dyn MoveData>, flag_hash: u32) -> u8 {
u8::from(move_data.value_func_arc(&env).unwrap().has_flag_by_hash(flag_hash))
}
}

View File

@ -13,7 +13,7 @@ pub struct MoveLibrary {
/// A unique identifier so we know what value this is.
identifier: ValueIdentifier,
/// The underlying map.
map: IndexMap<StringKey, Arc<MoveData>>,
map: IndexMap<StringKey, Arc<dyn MoveData>>,
}
impl MoveLibrary {
@ -26,11 +26,11 @@ impl MoveLibrary {
}
}
impl DataLibrary<MoveData> for MoveLibrary {
fn map(&self) -> &IndexMap<StringKey, Arc<MoveData>> {
impl DataLibrary<dyn MoveData> for MoveLibrary {
fn map(&self) -> &IndexMap<StringKey, Arc<dyn MoveData>> {
&self.map
}
fn get_modify(&mut self) -> &mut IndexMap<StringKey, Arc<MoveData>> {
fn get_modify(&mut self) -> &mut IndexMap<StringKey, Arc<dyn MoveData>> {
&mut self.map
}
}
@ -48,11 +48,11 @@ pub mod tests {
use crate::static_data::libraries::data_library::DataLibrary;
use crate::static_data::libraries::move_library::MoveLibrary;
use crate::static_data::{MoveCategory, MoveData, MoveTarget};
use crate::static_data::{MoveCategory, MoveDataImpl, MoveTarget};
use crate::StringKey;
fn build_move() -> MoveData {
MoveData::new(
fn build_move() -> MoveDataImpl {
MoveDataImpl::new(
&"foo".into(),
0.into(),
MoveCategory::Physical,

View File

@ -1,6 +1,7 @@
use hashbrown::HashSet;
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
use std::fmt::Debug;
use crate::static_data::{SecondaryEffect, TypeIdentifier};
use crate::{StringKey, ValueIdentifiable, ValueIdentifier};
@ -59,9 +60,40 @@ pub enum MoveTarget {
SelfUse,
}
/// A move is the skill Pokémon primarily use in battle. This is the data related to that.
pub trait MoveData: Debug + ValueIdentifiable {
/// The name of the move.
fn name(&self) -> &StringKey;
/// The attacking type of the move.
fn move_type(&self) -> TypeIdentifier;
/// The category of the move.
fn category(&self) -> MoveCategory;
/// The base power, not considering any modifiers, the move has.
fn base_power(&self) -> u8;
/// The accuracy of the move in percentage. Should be 255 for moves that always hit.
fn accuracy(&self) -> u8;
/// The number of times the move can be used. This can be modified on actually learned moves using
/// PP-Ups
fn base_usages(&self) -> u8;
/// How the move handles targets.
fn target(&self) -> MoveTarget;
/// The priority of the move. A higher priority means the move should go before other moves.
fn priority(&self) -> i8;
/// The optional secondary effect the move has.
fn secondary_effect(&self) -> &Option<Box<dyn SecondaryEffect>>;
/// Arbitrary flags that can be applied to the move.
fn has_flag(&self, key: &StringKey) -> bool;
/// Arbitrary flags that can be applied to the move.
fn has_flag_by_hash(&self, key_hash: u32) -> bool;
}
/// A move is the skill Pokémon primarily use in battle. This is the data related to that.
#[derive(Debug)]
pub struct MoveData {
pub struct MoveDataImpl {
/// A unique identifier so we know what value this is.
identifier: ValueIdentifier,
/// The name of the move.
@ -87,7 +119,7 @@ pub struct MoveData {
flags: HashSet<StringKey>,
}
impl MoveData {
impl MoveDataImpl {
/// Instantiates a new move.
pub fn new(
name: &StringKey,
@ -100,8 +132,8 @@ impl MoveData {
priority: i8,
secondary_effect: Option<Box<dyn SecondaryEffect>>,
flags: HashSet<StringKey>,
) -> MoveData {
MoveData {
) -> Self {
Self {
identifier: Default::default(),
name: name.clone(),
move_type,
@ -115,58 +147,61 @@ impl MoveData {
flags,
}
}
}
impl MoveData for MoveDataImpl {
/// The name of the move.
pub fn name(&self) -> &StringKey {
fn name(&self) -> &StringKey {
&self.name
}
/// The attacking type of the move.
pub fn move_type(&self) -> TypeIdentifier {
fn move_type(&self) -> TypeIdentifier {
self.move_type
}
/// The category of the move.
pub fn category(&self) -> MoveCategory {
fn category(&self) -> MoveCategory {
self.category
}
/// The base power, not considering any modifiers, the move has.
pub fn base_power(&self) -> u8 {
fn base_power(&self) -> u8 {
self.base_power
}
/// The accuracy of the move in percentage. Should be 255 for moves that always hit.
pub fn accuracy(&self) -> u8 {
fn accuracy(&self) -> u8 {
self.accuracy
}
/// The number of times the move can be used. This can be modified on actually learned moves using
/// PP-Ups
pub fn base_usages(&self) -> u8 {
fn base_usages(&self) -> u8 {
self.base_usages
}
/// How the move handles targets.
pub fn target(&self) -> MoveTarget {
fn target(&self) -> MoveTarget {
self.target
}
/// The priority of the move. A higher priority means the move should go before other moves.
pub fn priority(&self) -> i8 {
fn priority(&self) -> i8 {
self.priority
}
/// The optional secondary effect the move has.
pub fn secondary_effect(&self) -> &Option<Box<dyn SecondaryEffect>> {
fn secondary_effect(&self) -> &Option<Box<dyn SecondaryEffect>> {
&self.secondary_effect
}
/// Arbitrary flags that can be applied to the move.
pub fn has_flag(&self, key: &StringKey) -> bool {
fn has_flag(&self, key: &StringKey) -> bool {
self.flags.contains::<StringKey>(key)
}
/// Arbitrary flags that can be applied to the move.
pub 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)
}
}
impl ValueIdentifiable for MoveData {
impl ValueIdentifiable for MoveDataImpl {
fn value_identifier(&self) -> ValueIdentifier {
self.identifier
}

View File

@ -17,8 +17,9 @@ 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, LibrarySettings, LookupGrowthRate, MoveData, MoveLibrary, NatureImpl, NatureLibrary,
SecondaryEffect, SecondaryEffectImpl, Species, StaticData, StaticStatisticSet, Statistic, TypeLibrary,
ItemLibrary, LearnableMoves, LibrarySettings, LookupGrowthRate, MoveDataImpl, MoveLibrary, NatureImpl,
NatureLibrary, SecondaryEffect, SecondaryEffectImpl, Species, StaticData, StaticStatisticSet, Statistic,
TypeLibrary,
};
use pkmn_lib::StringKey;
@ -214,7 +215,7 @@ pub fn load_moves(path: &String, lib: &mut StaticData) {
lib.moves_mut().add(
&move_name,
Arc::new(MoveData::new(
Arc::new(MoveDataImpl::new(
&move_name.clone(),
move_type_id,
move_category,