This commit is contained in:
@@ -2,9 +2,10 @@ use crate::defines::LevelInt;
|
||||
use crate::VecExt;
|
||||
use anyhow::Result;
|
||||
use anyhow_ext::ensure;
|
||||
use std::fmt::Debug;
|
||||
|
||||
/// A growth rate defines how much experience is required per level.
|
||||
pub trait GrowthRate {
|
||||
pub trait GrowthRate: Debug {
|
||||
/// Calculate the level something with this growth rate would have at a certain experience.
|
||||
fn calculate_level(&self, experience: u32) -> LevelInt;
|
||||
/// Calculate the experience something with this growth rate would have at a certain level.
|
||||
@@ -12,6 +13,7 @@ pub trait GrowthRate {
|
||||
}
|
||||
|
||||
/// An implementation of the growth rate that uses a lookup table for experience.
|
||||
#[derive(Debug)]
|
||||
pub struct LookupGrowthRate {
|
||||
/// The lookup Vec.
|
||||
experience: Vec<u32>,
|
||||
@@ -20,9 +22,7 @@ pub struct LookupGrowthRate {
|
||||
impl LookupGrowthRate {
|
||||
/// Instantiates a new lookup growth rate. The experience vec should be the amount of experience
|
||||
/// required per level, with the first element being the experience required for level 1 (generally 0).
|
||||
pub fn new(experience: Vec<u32>) -> LookupGrowthRate {
|
||||
LookupGrowthRate { experience }
|
||||
}
|
||||
pub fn new(experience: Vec<u32>) -> LookupGrowthRate { LookupGrowthRate { experience } }
|
||||
}
|
||||
|
||||
impl GrowthRate for LookupGrowthRate {
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
use hashbrown::HashSet;
|
||||
#[cfg(feature = "serde")]
|
||||
use serde::{Deserialize, Serialize};
|
||||
#[cfg(feature = "serde")] use serde::{Deserialize, Serialize};
|
||||
use std::any::Any;
|
||||
use std::fmt::Debug;
|
||||
|
||||
@@ -9,6 +8,7 @@ use crate::StringKey;
|
||||
/// An item category defines which bag slot items are stored in.
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
#[cfg_attr(feature = "rune", derive(rune::Any))]
|
||||
#[repr(u8)]
|
||||
pub enum ItemCategory {
|
||||
/// This is where most items should go.
|
||||
@@ -32,6 +32,7 @@ pub enum ItemCategory {
|
||||
/// A battle item category defines how the item is categorized when in battle.
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
#[cfg_attr(feature = "rune", derive(rune::Any))]
|
||||
#[repr(u8)]
|
||||
pub enum BattleItemCategory {
|
||||
/// This item can't be used in battle.
|
||||
@@ -99,30 +100,18 @@ impl ItemImpl {
|
||||
|
||||
impl Item for ItemImpl {
|
||||
/// The name of the item.
|
||||
fn name(&self) -> &StringKey {
|
||||
&self.name
|
||||
}
|
||||
fn name(&self) -> &StringKey { &self.name }
|
||||
/// Which bag slot items are stored in.
|
||||
fn category(&self) -> ItemCategory {
|
||||
self.category
|
||||
}
|
||||
fn category(&self) -> ItemCategory { self.category }
|
||||
/// How the item is categorized when in battle.
|
||||
fn battle_category(&self) -> BattleItemCategory {
|
||||
self.battle_category
|
||||
}
|
||||
fn battle_category(&self) -> BattleItemCategory { self.battle_category }
|
||||
/// The buying value of the item.
|
||||
fn price(&self) -> i32 {
|
||||
self.price
|
||||
}
|
||||
fn price(&self) -> i32 { self.price }
|
||||
/// A set of arbitrary flags that can be set on the item.
|
||||
fn flags(&self) -> &HashSet<StringKey> {
|
||||
&self.flags
|
||||
}
|
||||
fn flags(&self) -> &HashSet<StringKey> { &self.flags }
|
||||
|
||||
/// Checks whether the item has a specific flag.
|
||||
fn has_flag(&self, key: &StringKey) -> bool {
|
||||
self.flags.contains(key)
|
||||
}
|
||||
fn has_flag(&self, key: &StringKey) -> bool { self.flags.contains(key) }
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
use anyhow_ext::Result;
|
||||
use std::fmt::Debug;
|
||||
use std::sync::Arc;
|
||||
|
||||
use indexmap::IndexMap;
|
||||
@@ -8,7 +9,7 @@ use crate::StringKey;
|
||||
|
||||
/// A data library is a collection of methods to set up a default library, where values are stored
|
||||
/// by both key, while keeping their insertion order.
|
||||
pub trait DataLibrary<T: ?Sized> {
|
||||
pub trait DataLibrary<T: ?Sized>: Debug {
|
||||
/// Returns the underlying map.
|
||||
fn map(&self) -> &IndexMap<StringKey, Arc<T>>;
|
||||
/// Returns the underlying map in mutable manner.
|
||||
@@ -25,32 +26,22 @@ pub trait DataLibrary<T: ?Sized> {
|
||||
fn remove(&self, key: &StringKey) {
|
||||
#[allow(clippy::unwrap_used)] // We know this cant fail.
|
||||
let self_mut = unsafe { (self as *const Self as *mut Self).as_mut() }.unwrap();
|
||||
self_mut.get_modify().remove(key);
|
||||
self_mut.get_modify().swap_remove(key);
|
||||
}
|
||||
|
||||
/// Gets a value from the library.
|
||||
fn get(&self, key: &StringKey) -> Option<Arc<T>> {
|
||||
self.map().get::<StringKey>(key).cloned()
|
||||
}
|
||||
fn get(&self, key: &StringKey) -> Option<Arc<T>> { self.map().get::<StringKey>(key).cloned() }
|
||||
|
||||
/// Gets a value from the library.
|
||||
fn get_by_hash(&self, key: u32) -> Option<Arc<T>> {
|
||||
self.map().get::<u32>(&key).cloned()
|
||||
}
|
||||
fn get_by_hash(&self, key: u32) -> Option<Arc<T>> { self.map().get::<u32>(&key).cloned() }
|
||||
|
||||
/// Gets a value from the library by the index where it is stored.
|
||||
fn get_key_by_index(&self, index: usize) -> Option<StringKey> {
|
||||
self.map().get_index(index).map(|a| a.0.clone())
|
||||
}
|
||||
fn get_key_by_index(&self, index: usize) -> Option<StringKey> { self.map().get_index(index).map(|a| a.0.clone()) }
|
||||
|
||||
/// Gets the amount of values in the library.
|
||||
fn len(&self) -> usize {
|
||||
self.map().len()
|
||||
}
|
||||
fn len(&self) -> usize { self.map().len() }
|
||||
/// Returns whether the library has no values.
|
||||
fn is_empty(&self) -> bool {
|
||||
self.map().is_empty()
|
||||
}
|
||||
fn is_empty(&self) -> bool { self.map().is_empty() }
|
||||
|
||||
/// Gets a random value from the library.
|
||||
fn random_value(&self, rand: &mut Random) -> Result<&Arc<T>> {
|
||||
|
||||
@@ -61,9 +61,7 @@ impl GrowthRateLibrary for GrowthRateLibraryImpl {
|
||||
}
|
||||
|
||||
impl Debug for GrowthRateLibraryImpl {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||
f.debug_struct("GrowthRateLibrary").finish()
|
||||
}
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { f.debug_struct("GrowthRateLibrary").finish() }
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
@@ -72,8 +70,6 @@ impl Debug for GrowthRateLibraryImpl {
|
||||
pub mod tests {
|
||||
use super::*;
|
||||
use crate::static_data::growth_rates::LookupGrowthRate;
|
||||
use crate::static_data::libraries::growth_rate_library::GrowthRateLibrary;
|
||||
use crate::static_data::GrowthRateLibraryImpl;
|
||||
|
||||
pub fn build() -> GrowthRateLibraryImpl {
|
||||
let mut lib = GrowthRateLibraryImpl::new(1);
|
||||
|
||||
@@ -38,14 +38,10 @@ impl NatureLibraryImpl {
|
||||
|
||||
impl NatureLibrary for NatureLibraryImpl {
|
||||
/// Adds a new nature with name to the library.
|
||||
fn load_nature(&self, name: StringKey, nature: Arc<dyn Nature>) {
|
||||
self.map.write().insert(name, nature);
|
||||
}
|
||||
fn load_nature(&self, name: StringKey, nature: Arc<dyn Nature>) { self.map.write().insert(name, nature); }
|
||||
|
||||
/// Gets a nature by name.
|
||||
fn get_nature(&self, key: &StringKey) -> Option<Arc<dyn Nature>> {
|
||||
self.map.read().get(key).cloned()
|
||||
}
|
||||
fn get_nature(&self, key: &StringKey) -> Option<Arc<dyn Nature>> { self.map.read().get(key).cloned() }
|
||||
|
||||
fn get_random_nature(&self, rand: &mut Random) -> Result<Arc<dyn Nature>> {
|
||||
let map = self.map.read();
|
||||
@@ -80,7 +76,7 @@ impl NatureLibrary for NatureLibraryImpl {
|
||||
pub mod tests {
|
||||
use super::*;
|
||||
use crate::static_data::statistics::Statistic;
|
||||
use crate::static_data::{NatureImpl, NatureLibrary, NatureLibraryImpl};
|
||||
use crate::static_data::NatureImpl;
|
||||
|
||||
pub fn build() -> NatureLibraryImpl {
|
||||
let lib = NatureLibraryImpl::new(2);
|
||||
|
||||
@@ -11,27 +11,18 @@ use crate::{PkmnError, StringKey};
|
||||
#[derive(Debug, Copy, Clone, Eq, PartialEq, Default, Hash, Atom)]
|
||||
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||
#[repr(transparent)]
|
||||
pub struct TypeIdentifier {
|
||||
/// The unique internal value.
|
||||
val: u8,
|
||||
}
|
||||
pub struct TypeIdentifier(u8);
|
||||
|
||||
impl From<u8> for TypeIdentifier {
|
||||
fn from(val: u8) -> Self {
|
||||
Self { val }
|
||||
}
|
||||
fn from(val: u8) -> Self { Self(val) }
|
||||
}
|
||||
|
||||
impl From<TypeIdentifier> for u8 {
|
||||
fn from(id: TypeIdentifier) -> Self {
|
||||
id.val
|
||||
}
|
||||
fn from(id: TypeIdentifier) -> Self { id.0 }
|
||||
}
|
||||
|
||||
impl Display for TypeIdentifier {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "TypeId({})", self.val)
|
||||
}
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "TypeId({})", self.0) }
|
||||
}
|
||||
|
||||
/// All data related to types and effectiveness.
|
||||
@@ -87,18 +78,16 @@ impl TypeLibraryImpl {
|
||||
defending: TypeIdentifier,
|
||||
) -> Result<f32> {
|
||||
Ok(*lock
|
||||
.get((attacking.val - 1) as usize)
|
||||
.get((attacking.0 - 1) as usize)
|
||||
.ok_or(PkmnError::InvalidTypeIdentifier { type_id: attacking })?
|
||||
.get((defending.val - 1) as usize)
|
||||
.get((defending.0 - 1) as usize)
|
||||
.ok_or(PkmnError::InvalidTypeIdentifier { type_id: defending })?)
|
||||
}
|
||||
}
|
||||
|
||||
impl TypeLibrary for TypeLibraryImpl {
|
||||
/// Gets the type identifier for a type with a name.
|
||||
fn get_type_id(&self, key: &StringKey) -> Option<TypeIdentifier> {
|
||||
self.types.read().get(key).cloned()
|
||||
}
|
||||
fn get_type_id(&self, key: &StringKey) -> Option<TypeIdentifier> { self.types.read().get(key).cloned() }
|
||||
|
||||
/// Gets the type name from the type identifier.
|
||||
fn get_type_name(&self, t: TypeIdentifier) -> Option<StringKey> {
|
||||
@@ -133,13 +122,11 @@ impl TypeLibrary for TypeLibraryImpl {
|
||||
let mut types_write_lock = self.types.write();
|
||||
let mut effectiveness_write_lock = self.effectiveness.write();
|
||||
|
||||
let id = TypeIdentifier {
|
||||
val: (types_write_lock.len() + 1) as u8,
|
||||
};
|
||||
let id = TypeIdentifier((types_write_lock.len() + 1) as u8);
|
||||
types_write_lock.insert(name.clone(), id);
|
||||
effectiveness_write_lock.resize((id.val) as usize, vec![]);
|
||||
effectiveness_write_lock.resize((id.0) as usize, vec![]);
|
||||
for effectiveness in &mut effectiveness_write_lock.iter_mut() {
|
||||
effectiveness.resize((id.val) as usize, 1.0)
|
||||
effectiveness.resize((id.0) as usize, 1.0)
|
||||
}
|
||||
id
|
||||
}
|
||||
@@ -154,9 +141,9 @@ impl TypeLibrary for TypeLibraryImpl {
|
||||
*self
|
||||
.effectiveness
|
||||
.write()
|
||||
.get_mut((attacking.val - 1) as usize)
|
||||
.get_mut((attacking.0 - 1) as usize)
|
||||
.ok_or(PkmnError::InvalidTypeIdentifier { type_id: attacking })?
|
||||
.get_mut((defending.val - 1) as usize)
|
||||
.get_mut((defending.0 - 1) as usize)
|
||||
.ok_or(PkmnError::InvalidTypeIdentifier { type_id: defending })? = effectiveness;
|
||||
Ok(())
|
||||
}
|
||||
@@ -169,7 +156,6 @@ pub mod tests {
|
||||
use assert_approx_eq::assert_approx_eq;
|
||||
|
||||
use super::*;
|
||||
use crate::static_data::libraries::type_library::TypeLibrary;
|
||||
|
||||
pub fn build() -> TypeLibraryImpl {
|
||||
let mut lib = TypeLibraryImpl::new(2);
|
||||
|
||||
@@ -24,12 +24,6 @@ use std::fmt::{Display, Formatter};
|
||||
pub(crate) mod tests {
|
||||
use super::*;
|
||||
#[doc(inline)]
|
||||
pub use growth_rates::tests::*;
|
||||
#[doc(inline)]
|
||||
pub use items::tests::*;
|
||||
#[doc(inline)]
|
||||
pub use libraries::tests::*;
|
||||
#[doc(inline)]
|
||||
pub use moves::tests::*;
|
||||
#[doc(inline)]
|
||||
pub use natures::tests::*;
|
||||
@@ -71,27 +65,19 @@ pub enum Parameter {
|
||||
}
|
||||
|
||||
impl From<bool> for Parameter {
|
||||
fn from(b: bool) -> Self {
|
||||
Parameter::Bool(b)
|
||||
}
|
||||
fn from(b: bool) -> Self { Parameter::Bool(b) }
|
||||
}
|
||||
|
||||
impl From<i64> for Parameter {
|
||||
fn from(i: i64) -> Self {
|
||||
Parameter::Int(i)
|
||||
}
|
||||
fn from(i: i64) -> Self { Parameter::Int(i) }
|
||||
}
|
||||
|
||||
impl From<f32> for Parameter {
|
||||
fn from(f: f32) -> Self {
|
||||
Parameter::Float(f)
|
||||
}
|
||||
fn from(f: f32) -> Self { Parameter::Float(f) }
|
||||
}
|
||||
|
||||
impl From<StringKey> for Parameter {
|
||||
fn from(s: StringKey) -> Self {
|
||||
Parameter::String(s)
|
||||
}
|
||||
fn from(s: StringKey) -> Self { Parameter::String(s) }
|
||||
}
|
||||
|
||||
impl Display for Parameter {
|
||||
|
||||
@@ -1,16 +1,11 @@
|
||||
#[doc(inline)]
|
||||
pub use move_data::*;
|
||||
#[doc(inline)]
|
||||
pub use secondary_effect::*;
|
||||
#[doc(inline)] pub use move_data::*;
|
||||
#[doc(inline)] pub use secondary_effect::*;
|
||||
|
||||
#[cfg(test)]
|
||||
pub(crate) mod tests {
|
||||
use super::*;
|
||||
|
||||
#[doc(inline)]
|
||||
pub use move_data::tests::*;
|
||||
#[doc(inline)]
|
||||
pub use secondary_effect::tests::*;
|
||||
#[doc(inline)] pub use move_data::tests::*;
|
||||
}
|
||||
|
||||
/// The data belonging to a certain move.
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
use hashbrown::HashSet;
|
||||
#[cfg(feature = "serde")]
|
||||
use serde::{Deserialize, Serialize};
|
||||
#[cfg(feature = "serde")] use serde::{Deserialize, Serialize};
|
||||
use std::fmt::Debug;
|
||||
use std::sync::Arc;
|
||||
|
||||
@@ -11,6 +10,7 @@ use crate::StringKey;
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))]
|
||||
#[cfg_attr(feature = "rune", derive(rune::Any))]
|
||||
#[repr(u8)]
|
||||
pub enum MoveCategory {
|
||||
/// A physical move uses the physical attack stats and physical defense stats to calculate damage.
|
||||
@@ -24,6 +24,7 @@ pub enum MoveCategory {
|
||||
/// The move target defines what kind of targets the move can touch.
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Debug, Default)]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
#[cfg_attr(feature = "rune", derive(rune::Any))]
|
||||
#[repr(u8)]
|
||||
pub enum MoveTarget {
|
||||
/// Adjacent allows a move to target any Pokemon that is either directly to the left or right of
|
||||
@@ -149,54 +150,32 @@ impl MoveDataImpl {
|
||||
|
||||
impl MoveData for MoveDataImpl {
|
||||
/// The name of the move.
|
||||
fn name(&self) -> &StringKey {
|
||||
&self.name
|
||||
}
|
||||
fn name(&self) -> &StringKey { &self.name }
|
||||
/// The attacking type of the move.
|
||||
fn move_type(&self) -> TypeIdentifier {
|
||||
self.move_type
|
||||
}
|
||||
fn move_type(&self) -> TypeIdentifier { self.move_type }
|
||||
/// The category of the move.
|
||||
fn category(&self) -> MoveCategory {
|
||||
self.category
|
||||
}
|
||||
fn category(&self) -> MoveCategory { self.category }
|
||||
/// The base power, not considering any modifiers, the move has.
|
||||
fn base_power(&self) -> u8 {
|
||||
self.base_power
|
||||
}
|
||||
fn base_power(&self) -> u8 { self.base_power }
|
||||
/// The accuracy of the move in percentage. Should be 255 for moves that always hit.
|
||||
fn accuracy(&self) -> u8 {
|
||||
self.accuracy
|
||||
}
|
||||
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
|
||||
fn base_usages(&self) -> u8 {
|
||||
self.base_usages
|
||||
}
|
||||
fn base_usages(&self) -> u8 { self.base_usages }
|
||||
/// How the move handles targets.
|
||||
fn target(&self) -> MoveTarget {
|
||||
self.target
|
||||
}
|
||||
fn target(&self) -> MoveTarget { self.target }
|
||||
|
||||
/// The priority of the move. A higher priority means the move should go before other moves.
|
||||
fn priority(&self) -> i8 {
|
||||
self.priority
|
||||
}
|
||||
fn priority(&self) -> i8 { self.priority }
|
||||
|
||||
/// The optional secondary effect the move has.
|
||||
fn secondary_effect(&self) -> &Option<Arc<dyn SecondaryEffect>> {
|
||||
&self.secondary_effect
|
||||
}
|
||||
fn secondary_effect(&self) -> &Option<Arc<dyn SecondaryEffect>> { &self.secondary_effect }
|
||||
|
||||
/// Checks if the move has a specific flag.
|
||||
fn has_flag(&self, key: &StringKey) -> bool {
|
||||
self.flags.contains::<StringKey>(key)
|
||||
}
|
||||
fn has_flag(&self, key: &StringKey) -> bool { self.flags.contains::<StringKey>(key) }
|
||||
|
||||
/// Checks if the move has a specific flag.
|
||||
fn has_flag_by_hash(&self, key_hash: u32) -> bool {
|
||||
self.flags.contains::<u32>(&key_hash)
|
||||
}
|
||||
fn has_flag_by_hash(&self, key_hash: u32) -> bool { self.flags.contains::<u32>(&key_hash) }
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
||||
@@ -52,9 +52,6 @@ pub(crate) mod tests {
|
||||
use super::*;
|
||||
use assert_approx_eq::assert_approx_eq;
|
||||
|
||||
use crate::static_data::moves::secondary_effect::SecondaryEffect;
|
||||
use crate::static_data::SecondaryEffectImpl;
|
||||
|
||||
mockall::mock! {
|
||||
#[derive(Debug)]
|
||||
pub SecondaryEffect{}
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
/// that allows for a more progressive gender system for those that want it?
|
||||
#[derive(Eq, PartialEq, Copy, Clone, Debug)]
|
||||
#[cfg_attr(feature = "serde", derive(serde_repr::Serialize_repr, serde_repr::Deserialize_repr))]
|
||||
#[cfg_attr(feature = "rune", derive(rune::Any))]
|
||||
#[repr(u8)]
|
||||
pub enum Gender {
|
||||
/// The Pokemon has no gender.
|
||||
|
||||
@@ -13,9 +13,7 @@ pub use species::*;
|
||||
|
||||
#[cfg(test)]
|
||||
pub(crate) mod tests {
|
||||
pub use super::ability::tests::*;
|
||||
pub use super::form::tests::*;
|
||||
pub use super::learnable_moves::tests::*;
|
||||
pub use super::species::tests::*;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
#[cfg(feature = "serde")]
|
||||
use serde::{Deserialize, Serialize};
|
||||
#[cfg(feature = "serde")] use serde::{Deserialize, Serialize};
|
||||
|
||||
/// Stats are numerical values on Pokemon that are used in battle.
|
||||
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
|
||||
|
||||
Reference in New Issue
Block a user