This commit is contained in:
@@ -1,15 +1,21 @@
|
||||
use crate::defines::LevelInt;
|
||||
|
||||
/// A growth rate defines how much experience is required per level.
|
||||
pub trait GrowthRate {
|
||||
/// 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.
|
||||
fn calculate_experience(&self, level: LevelInt) -> u32;
|
||||
}
|
||||
|
||||
/// An implementation of the growth rate that uses a lookup table for experience.
|
||||
pub struct LookupGrowthRate {
|
||||
/// The lookup Vec.
|
||||
experience: Vec<u32>,
|
||||
}
|
||||
|
||||
impl LookupGrowthRate {
|
||||
/// Instantiates a new lookup growth rate.
|
||||
pub fn new(experience: Vec<u32>) -> LookupGrowthRate {
|
||||
LookupGrowthRate { experience }
|
||||
}
|
||||
|
||||
@@ -4,41 +4,63 @@ use serde::{Deserialize, Serialize};
|
||||
|
||||
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))]
|
||||
#[repr(u8)]
|
||||
pub enum ItemCategory {
|
||||
/// This is where most items should go.
|
||||
MiscItem,
|
||||
/// Pokeballs are used for capturing Pokemons.
|
||||
Pokeball,
|
||||
/// Medicine is used for healing HP, PP, and status effects
|
||||
Medicine,
|
||||
/// Berry is used for all berries.
|
||||
Berry,
|
||||
/// TMHM is used for Technical and Hidden Machines.
|
||||
TMHM,
|
||||
/// Form Changer is used for items that change forms, such as mega stones.
|
||||
FormChanger,
|
||||
/// Key Items are single stored items, generally used for story progression.
|
||||
KeyItem,
|
||||
/// Mail is used for mail items.
|
||||
Mail,
|
||||
}
|
||||
|
||||
/// A battle item category defines how the item is categorized when in battle.
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
#[repr(u8)]
|
||||
pub enum BattleItemCategory {
|
||||
/// This item can't be used in battle.
|
||||
None,
|
||||
/// This item is used for healing Pokemon.
|
||||
Healing,
|
||||
/// This item is used for healing Pokemon from a status.
|
||||
StatusHealing,
|
||||
/// This item is used for capturing Pokemon.
|
||||
Pokeball,
|
||||
/// This item does not belong in above categories, but is still a battle item.
|
||||
MiscBattleItem,
|
||||
}
|
||||
|
||||
/// An item is an object which the player can pick up, keep in their Bag, and use in some manner
|
||||
#[derive(Debug)]
|
||||
pub struct Item {
|
||||
/// The name of the item.
|
||||
name: StringKey,
|
||||
/// Which bag slot items are stored in.
|
||||
category: ItemCategory,
|
||||
/// How the item is categorized when in battle.
|
||||
battle_category: BattleItemCategory,
|
||||
/// The buying value of the item.
|
||||
price: i32,
|
||||
/// A set of arbitrary flags that can be set on the item.
|
||||
flags: HashSet<StringKey>,
|
||||
}
|
||||
|
||||
impl Item {
|
||||
/// Instantiates an item.
|
||||
pub fn new(
|
||||
name: &StringKey,
|
||||
category: ItemCategory,
|
||||
@@ -55,22 +77,28 @@ impl Item {
|
||||
}
|
||||
}
|
||||
|
||||
/// The name of the item.
|
||||
pub fn name(&self) -> &StringKey {
|
||||
&self.name
|
||||
}
|
||||
/// Which bag slot items are stored in.
|
||||
pub fn category(&self) -> ItemCategory {
|
||||
self.category
|
||||
}
|
||||
/// How the item is categorized when in battle.
|
||||
pub fn battle_category(&self) -> BattleItemCategory {
|
||||
self.battle_category
|
||||
}
|
||||
/// The buying value of the item.
|
||||
pub fn price(&self) -> i32 {
|
||||
self.price
|
||||
}
|
||||
/// A set of arbitrary flags that can be set on the item.
|
||||
pub fn flags(&self) -> &HashSet<StringKey> {
|
||||
&self.flags
|
||||
}
|
||||
|
||||
/// Checks whether the item has a specific flag.
|
||||
pub fn has_flag(&self, key: &StringKey) -> bool {
|
||||
self.flags.contains(key)
|
||||
}
|
||||
|
||||
@@ -1,35 +1,31 @@
|
||||
use hashbrown::HashMap;
|
||||
use indexmap::IndexMap;
|
||||
|
||||
use crate::static_data::Ability;
|
||||
use crate::static_data::DataLibrary;
|
||||
use crate::StringKey;
|
||||
|
||||
/// A storage for all abilities that can be used in this data library.
|
||||
#[derive(Debug)]
|
||||
pub struct AbilityLibrary {
|
||||
map: HashMap<StringKey, Box<Ability>>,
|
||||
list: Vec<StringKey>,
|
||||
/// The underlying map for the library.
|
||||
map: IndexMap<StringKey, Box<Ability>>,
|
||||
}
|
||||
|
||||
impl AbilityLibrary {
|
||||
/// Instantiates a new ability library.
|
||||
pub fn new(capacity: usize) -> AbilityLibrary {
|
||||
AbilityLibrary {
|
||||
map: HashMap::with_capacity(capacity),
|
||||
list: Vec::with_capacity(capacity),
|
||||
map: IndexMap::with_capacity(capacity),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl DataLibrary<'_, Box<Ability>> for AbilityLibrary {
|
||||
fn map(&self) -> &HashMap<StringKey, Box<Ability>> {
|
||||
fn map(&self) -> &IndexMap<StringKey, Box<Ability>> {
|
||||
&self.map
|
||||
}
|
||||
|
||||
fn list_values(&self) -> &Vec<StringKey> {
|
||||
&self.list
|
||||
}
|
||||
|
||||
fn get_modify(&mut self) -> (&mut HashMap<StringKey, Box<Ability>>, &mut Vec<StringKey>) {
|
||||
(&mut self.map, &mut self.list)
|
||||
fn get_modify(&mut self) -> &mut IndexMap<StringKey, Box<Ability>> {
|
||||
&mut self.map
|
||||
}
|
||||
}
|
||||
|
||||
@@ -62,17 +58,8 @@ pub mod tests {
|
||||
#[test]
|
||||
fn get_ability_library_direct_map_access() {
|
||||
let lib = build();
|
||||
let map = lib.map();
|
||||
let ability = map.get(&"test_ability".into());
|
||||
let ability = lib.get(&"test_ability".into());
|
||||
assert!(ability.is_some());
|
||||
assert_eq!(ability.unwrap().name(), &"test_ability".into());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn get_ability_library_direct_list_access() {
|
||||
let lib = build();
|
||||
let list = lib.list_values();
|
||||
assert_eq!(list.len(), 1);
|
||||
assert!(list.contains(&StringKey::new("test_ability")));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,43 +1,48 @@
|
||||
use indexmap::IndexMap;
|
||||
|
||||
use crate::Random;
|
||||
use crate::StringKey;
|
||||
use hashbrown::HashMap;
|
||||
|
||||
/// 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<'a, T: 'a> {
|
||||
fn map(&self) -> &HashMap<StringKey, T>;
|
||||
fn list_values(&self) -> &Vec<StringKey>;
|
||||
fn get_modify(&mut self) -> (&mut HashMap<StringKey, T>, &mut Vec<StringKey>);
|
||||
/// Returns the underlying map.
|
||||
fn map(&self) -> &IndexMap<StringKey, T>;
|
||||
/// Returns the underlying map in mutable manner.
|
||||
fn get_modify(&mut self) -> &mut IndexMap<StringKey, T>;
|
||||
|
||||
/// Adds a new value to the library.
|
||||
fn add(&mut self, key: &StringKey, value: T) {
|
||||
let modifies = self.get_modify();
|
||||
modifies.0.insert(key.clone(), value);
|
||||
modifies.1.push(key.clone());
|
||||
self.get_modify().insert(key.clone(), value);
|
||||
}
|
||||
|
||||
/// Removes a value from the library.
|
||||
fn remove(&mut self, key: &StringKey) {
|
||||
let modifies = self.get_modify();
|
||||
let index = modifies.1.iter().position(|r| r == key).unwrap();
|
||||
modifies.0.remove(key);
|
||||
modifies.1.remove(index);
|
||||
self.get_modify().remove(key);
|
||||
}
|
||||
|
||||
/// Gets a value from the library.
|
||||
fn get(&'a self, key: &StringKey) -> Option<&'a T> {
|
||||
self.map().get(key)
|
||||
self.map().get::<StringKey>(key)
|
||||
}
|
||||
|
||||
/// Gets a mutable value from the library.
|
||||
fn get_mut(&mut self, key: &StringKey) -> Option<&mut T> {
|
||||
self.get_modify().0.get_mut(key)
|
||||
self.get_modify().get_mut(key)
|
||||
}
|
||||
|
||||
/// Gets the amount of values in the library.
|
||||
fn len(&self) -> usize {
|
||||
self.map().len()
|
||||
}
|
||||
/// Returns whether the library has no values.
|
||||
fn is_empty(&self) -> bool {
|
||||
self.map().is_empty()
|
||||
}
|
||||
|
||||
/// Gets a random value from the library.
|
||||
fn random_value(&self, rand: &mut Random) -> &T {
|
||||
let i = rand.get_between(0, self.list_values().len() as i32);
|
||||
let key = &self.list_values()[i as usize];
|
||||
return &self.map()[key];
|
||||
let i = rand.get_between(0, self.len() as i32);
|
||||
return &self.map().get_index(i as usize).unwrap().1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,23 +7,30 @@ use crate::defines::LevelInt;
|
||||
use crate::static_data::GrowthRate;
|
||||
use crate::StringKey;
|
||||
|
||||
/// A library to store all growth rates.
|
||||
pub struct GrowthRateLibrary {
|
||||
/// The underlying data structure.
|
||||
growth_rates: HashMap<StringKey, Box<dyn GrowthRate>>,
|
||||
}
|
||||
|
||||
impl GrowthRateLibrary {
|
||||
/// Instantiates a new growth rate library with a capacity.
|
||||
pub fn new(capacity: usize) -> GrowthRateLibrary {
|
||||
GrowthRateLibrary {
|
||||
growth_rates: HashMap::with_capacity(capacity),
|
||||
}
|
||||
}
|
||||
|
||||
/// Calculates the level for a given growth key name and a certain experience.
|
||||
pub fn calculate_level(&self, growth_rate: &StringKey, experience: u32) -> LevelInt {
|
||||
self.growth_rates[growth_rate].calculate_level(experience)
|
||||
}
|
||||
/// Calculates the experience for a given growth key name and a certain level.
|
||||
pub fn calculate_experience(&self, growth_rate: &StringKey, level: LevelInt) -> u32 {
|
||||
self.growth_rates[growth_rate].calculate_experience(level)
|
||||
}
|
||||
|
||||
/// Adds a new growth rate with a name and value.
|
||||
pub fn add_growth_rate(&mut self, key: &StringKey, value: Box<dyn GrowthRate>) {
|
||||
self.growth_rates.insert(key.clone(), value);
|
||||
}
|
||||
|
||||
@@ -1,35 +1,32 @@
|
||||
use hashbrown::HashMap;
|
||||
use indexmap::IndexMap;
|
||||
|
||||
use crate::static_data::DataLibrary;
|
||||
use crate::static_data::Item;
|
||||
use crate::StringKey;
|
||||
|
||||
/// A library to store all items.
|
||||
#[derive(Debug)]
|
||||
pub struct ItemLibrary {
|
||||
map: HashMap<StringKey, Box<Item>>,
|
||||
list: Vec<StringKey>,
|
||||
/// The underlying data structure.
|
||||
map: IndexMap<StringKey, Box<Item>>,
|
||||
}
|
||||
|
||||
impl ItemLibrary {
|
||||
/// Instantiates a new Item Library.
|
||||
pub fn new(capacity: usize) -> ItemLibrary {
|
||||
ItemLibrary {
|
||||
map: HashMap::with_capacity(capacity),
|
||||
list: Vec::with_capacity(capacity),
|
||||
map: IndexMap::with_capacity(capacity),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl DataLibrary<'_, Box<Item>> for ItemLibrary {
|
||||
fn map(&self) -> &HashMap<StringKey, Box<Item>> {
|
||||
fn map(&self) -> &IndexMap<StringKey, Box<Item>> {
|
||||
&self.map
|
||||
}
|
||||
|
||||
fn list_values(&self) -> &Vec<StringKey> {
|
||||
&self.list
|
||||
}
|
||||
|
||||
fn get_modify(&mut self) -> (&mut HashMap<StringKey, Box<Item>>, &mut Vec<StringKey>) {
|
||||
(&mut self.map, &mut self.list)
|
||||
fn get_modify(&mut self) -> &mut IndexMap<StringKey, Box<Item>> {
|
||||
&mut self.map
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,15 +1,19 @@
|
||||
use crate::defines::LevelInt;
|
||||
|
||||
/// This library holds several misc settings for the library.
|
||||
#[derive(Debug)]
|
||||
pub struct LibrarySettings {
|
||||
/// The highest level a Pokemon can be.
|
||||
maximum_level: LevelInt,
|
||||
}
|
||||
|
||||
impl LibrarySettings {
|
||||
/// Creates a new settings library.
|
||||
pub fn new(maximum_level: LevelInt) -> Self {
|
||||
Self { maximum_level }
|
||||
}
|
||||
|
||||
/// The highest level a Pokemon can be.
|
||||
pub fn maximum_level(&self) -> LevelInt {
|
||||
self.maximum_level
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@ pub use species_library::SpeciesLibrary;
|
||||
#[doc(inline)]
|
||||
pub use static_data::StaticData;
|
||||
#[doc(inline)]
|
||||
pub use type_library::TypeLibrary;
|
||||
pub use type_library::*;
|
||||
|
||||
mod ability_library;
|
||||
mod data_library;
|
||||
|
||||
@@ -1,35 +1,31 @@
|
||||
use hashbrown::HashMap;
|
||||
use indexmap::IndexMap;
|
||||
|
||||
use crate::static_data::DataLibrary;
|
||||
use crate::static_data::MoveData;
|
||||
use crate::StringKey;
|
||||
|
||||
/// A library to store all data for moves.
|
||||
#[derive(Debug)]
|
||||
pub struct MoveLibrary {
|
||||
map: HashMap<StringKey, MoveData>,
|
||||
list: Vec<StringKey>,
|
||||
/// The underlying map.
|
||||
map: IndexMap<StringKey, MoveData>,
|
||||
}
|
||||
|
||||
impl MoveLibrary {
|
||||
/// Instantiates a new Move Library.
|
||||
pub fn new(capacity: usize) -> MoveLibrary {
|
||||
MoveLibrary {
|
||||
map: HashMap::with_capacity(capacity),
|
||||
list: Vec::with_capacity(capacity),
|
||||
map: IndexMap::with_capacity(capacity),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl DataLibrary<'_, MoveData> for MoveLibrary {
|
||||
fn map(&self) -> &HashMap<StringKey, MoveData> {
|
||||
fn map(&self) -> &IndexMap<StringKey, MoveData> {
|
||||
&self.map
|
||||
}
|
||||
|
||||
fn list_values(&self) -> &Vec<StringKey> {
|
||||
&self.list
|
||||
}
|
||||
|
||||
fn get_modify(&mut self) -> (&mut HashMap<StringKey, MoveData>, &mut Vec<StringKey>) {
|
||||
(&mut self.map, &mut self.list)
|
||||
fn get_modify(&mut self) -> &mut IndexMap<StringKey, MoveData> {
|
||||
&mut self.map
|
||||
}
|
||||
}
|
||||
|
||||
@@ -45,7 +41,7 @@ pub mod tests {
|
||||
fn build_move() -> MoveData {
|
||||
MoveData::new(
|
||||
&"foo".into(),
|
||||
0,
|
||||
0.into(),
|
||||
MoveCategory::Physical,
|
||||
100,
|
||||
100,
|
||||
|
||||
@@ -1,35 +1,31 @@
|
||||
use hashbrown::HashMap;
|
||||
use indexmap::IndexMap;
|
||||
|
||||
use crate::static_data::DataLibrary;
|
||||
use crate::static_data::Species;
|
||||
use crate::StringKey;
|
||||
|
||||
/// A library to store all data for Pokemon species.
|
||||
#[derive(Debug)]
|
||||
pub struct SpeciesLibrary {
|
||||
map: HashMap<StringKey, Box<Species>>,
|
||||
list: Vec<StringKey>,
|
||||
/// The underlying map.
|
||||
map: IndexMap<StringKey, Box<Species>>,
|
||||
}
|
||||
|
||||
impl SpeciesLibrary {
|
||||
/// Instantiates a new Species Library.
|
||||
pub fn new(capacity: usize) -> SpeciesLibrary {
|
||||
SpeciesLibrary {
|
||||
map: HashMap::with_capacity(capacity),
|
||||
list: Vec::with_capacity(capacity),
|
||||
map: IndexMap::with_capacity(capacity),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> DataLibrary<'a, Box<Species>> for SpeciesLibrary {
|
||||
fn map(&self) -> &HashMap<StringKey, Box<Species>> {
|
||||
fn map(&self) -> &IndexMap<StringKey, Box<Species>> {
|
||||
&self.map
|
||||
}
|
||||
|
||||
fn list_values(&self) -> &Vec<StringKey> {
|
||||
&self.list
|
||||
}
|
||||
|
||||
fn get_modify(&mut self) -> (&mut HashMap<StringKey, Box<Species>>, &mut Vec<StringKey>) {
|
||||
(&mut self.map, &mut self.list)
|
||||
fn get_modify(&mut self) -> &mut IndexMap<StringKey, Box<Species>> {
|
||||
&mut self.map
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -7,19 +7,29 @@ use crate::static_data::NatureLibrary;
|
||||
use crate::static_data::SpeciesLibrary;
|
||||
use crate::static_data::TypeLibrary;
|
||||
|
||||
/// The storage for all different libraries.
|
||||
#[derive(Debug)]
|
||||
pub struct StaticData {
|
||||
/// Several misc settings for the library.
|
||||
settings: LibrarySettings,
|
||||
/// All data for Pokemon species.
|
||||
species: SpeciesLibrary,
|
||||
/// All data for the moves.
|
||||
moves: MoveLibrary,
|
||||
/// All data for the items.
|
||||
items: ItemLibrary,
|
||||
/// All data for growth rates.
|
||||
growth_rates: GrowthRateLibrary,
|
||||
/// All data related to types and type effectiveness.
|
||||
types: TypeLibrary,
|
||||
/// All data related to natures.
|
||||
natures: NatureLibrary,
|
||||
/// All data related to abilities.
|
||||
abilities: AbilityLibrary,
|
||||
}
|
||||
|
||||
impl StaticData {
|
||||
/// Instantiates a new data collection.
|
||||
pub fn new(settings: LibrarySettings) -> Self {
|
||||
Self {
|
||||
settings,
|
||||
@@ -32,50 +42,64 @@ impl StaticData {
|
||||
abilities: AbilityLibrary::new(0),
|
||||
}
|
||||
}
|
||||
|
||||
/// Several misc settings for the library.
|
||||
pub fn settings(&self) -> &LibrarySettings {
|
||||
&self.settings
|
||||
}
|
||||
/// All data for Pokemon species.
|
||||
pub fn species(&self) -> &SpeciesLibrary {
|
||||
&self.species
|
||||
}
|
||||
/// All data for Pokemon species.
|
||||
pub fn species_mut(&mut self) -> &mut SpeciesLibrary {
|
||||
&mut self.species
|
||||
}
|
||||
/// All data for the moves.
|
||||
pub fn moves(&self) -> &MoveLibrary {
|
||||
&self.moves
|
||||
}
|
||||
/// All data for the moves.
|
||||
pub fn moves_mut(&mut self) -> &mut MoveLibrary {
|
||||
&mut self.moves
|
||||
}
|
||||
/// All data for the items.
|
||||
pub fn items(&self) -> &ItemLibrary {
|
||||
&self.items
|
||||
}
|
||||
/// All data for the items.
|
||||
pub fn items_mut(&mut self) -> &mut ItemLibrary {
|
||||
&mut self.items
|
||||
}
|
||||
|
||||
/// All data for growth rates.
|
||||
pub fn growth_rates(&self) -> &GrowthRateLibrary {
|
||||
&self.growth_rates
|
||||
}
|
||||
/// All data for growth rates.
|
||||
pub fn growth_rates_mut(&mut self) -> &mut GrowthRateLibrary {
|
||||
&mut self.growth_rates
|
||||
}
|
||||
/// All data related to types and type effectiveness.
|
||||
pub fn types(&self) -> &TypeLibrary {
|
||||
&self.types
|
||||
}
|
||||
/// All data related to types and type effectiveness.
|
||||
pub fn types_mut(&mut self) -> &mut TypeLibrary {
|
||||
&mut self.types
|
||||
}
|
||||
/// All data related to natures.
|
||||
pub fn natures(&self) -> &NatureLibrary {
|
||||
&self.natures
|
||||
}
|
||||
/// All data related to natures.
|
||||
pub fn natures_mut(&mut self) -> &mut NatureLibrary {
|
||||
&mut self.natures
|
||||
}
|
||||
/// All data related to abilities.
|
||||
pub fn abilities(&self) -> &AbilityLibrary {
|
||||
&self.abilities
|
||||
}
|
||||
/// All data related to abilities.
|
||||
pub fn abilities_mut(&mut self) -> &mut AbilityLibrary {
|
||||
&mut self.abilities
|
||||
}
|
||||
|
||||
@@ -1,13 +1,32 @@
|
||||
use crate::StringKey;
|
||||
use hashbrown::HashMap;
|
||||
|
||||
use crate::StringKey;
|
||||
|
||||
/// A unique key that can be used to store a reference to a type. Opaque reference to a byte
|
||||
/// internally.
|
||||
#[derive(Debug, Copy, Clone, Eq, PartialEq, Default, Hash)]
|
||||
pub struct TypeIdentifier {
|
||||
/// The unique internal value.
|
||||
val: u8,
|
||||
}
|
||||
|
||||
impl From<u8> for TypeIdentifier {
|
||||
fn from(val: u8) -> Self {
|
||||
Self { val }
|
||||
}
|
||||
}
|
||||
|
||||
/// All data related to types and effectiveness.
|
||||
#[derive(Debug)]
|
||||
pub struct TypeLibrary {
|
||||
types: HashMap<StringKey, u8>,
|
||||
/// A list of types
|
||||
types: HashMap<StringKey, TypeIdentifier>,
|
||||
/// The effectiveness of the different types against each other.
|
||||
effectiveness: Vec<Vec<f32>>,
|
||||
}
|
||||
|
||||
impl TypeLibrary {
|
||||
/// Instantiates a new type library with a specific capacity.
|
||||
pub fn new(capacity: usize) -> TypeLibrary {
|
||||
TypeLibrary {
|
||||
types: HashMap::with_capacity(capacity),
|
||||
@@ -15,15 +34,20 @@ impl TypeLibrary {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_type_id(&self, key: &StringKey) -> u8 {
|
||||
/// Gets the type identifier for a type with a name.
|
||||
pub fn get_type_id(&self, key: &StringKey) -> TypeIdentifier {
|
||||
self.types[key]
|
||||
}
|
||||
|
||||
pub fn get_single_effectiveness(&self, attacking: u8, defending: u8) -> f32 {
|
||||
self.effectiveness[attacking as usize][defending as usize]
|
||||
/// Gets the effectiveness for a single attacking type against a single defending type.
|
||||
pub fn get_single_effectiveness(&self, attacking: TypeIdentifier, defending: TypeIdentifier) -> f32 {
|
||||
self.effectiveness[attacking.val as usize][defending.val as usize]
|
||||
}
|
||||
|
||||
pub fn get_effectiveness(&self, attacking: u8, defending: &[u8]) -> f32 {
|
||||
/// Gets the effectiveness for a single attacking type against an amount of defending types.
|
||||
/// This is equivalent to running [`get_single_effectiveness`] on each defending type, and
|
||||
/// multiplying the results with each other.
|
||||
pub fn get_effectiveness(&self, attacking: TypeIdentifier, defending: &[TypeIdentifier]) -> f32 {
|
||||
let mut e = 1.0;
|
||||
for def in defending {
|
||||
e *= self.get_single_effectiveness(attacking, *def);
|
||||
@@ -31,37 +55,42 @@ impl TypeLibrary {
|
||||
e
|
||||
}
|
||||
|
||||
pub fn register_type(&mut self, name: &StringKey) -> u8 {
|
||||
let id = self.types.len() as u8;
|
||||
/// Registers a new type in the library.
|
||||
pub fn register_type(&mut self, name: &StringKey) -> TypeIdentifier {
|
||||
let id = TypeIdentifier {
|
||||
val: self.types.len() as u8,
|
||||
};
|
||||
self.types.insert(name.clone(), id);
|
||||
self.effectiveness.resize((id + 1) as usize, vec![]);
|
||||
self.effectiveness.resize((id.val + 1) as usize, vec![]);
|
||||
for effectiveness in &mut self.effectiveness {
|
||||
effectiveness.resize((id + 1) as usize, 1.0)
|
||||
effectiveness.resize((id.val + 1) as usize, 1.0)
|
||||
}
|
||||
id
|
||||
}
|
||||
|
||||
pub fn set_effectiveness(&mut self, attacking: u8, defending: u8, effectiveness: f32) {
|
||||
self.effectiveness[attacking as usize][defending as usize] = effectiveness;
|
||||
/// Sets the effectiveness for an attacking type against a defending type.
|
||||
pub fn set_effectiveness(&mut self, attacking: TypeIdentifier, defending: TypeIdentifier, effectiveness: f32) {
|
||||
self.effectiveness[attacking.val as usize][defending.val as usize] = effectiveness;
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
pub mod tests {
|
||||
use crate::static_data::libraries::type_library::TypeLibrary;
|
||||
use assert_approx_eq::assert_approx_eq;
|
||||
|
||||
use crate::static_data::libraries::type_library::TypeLibrary;
|
||||
|
||||
pub fn build() -> TypeLibrary {
|
||||
let mut lib = TypeLibrary::new(2);
|
||||
|
||||
// Borrow as mut so we can insert
|
||||
let w = &mut lib;
|
||||
w.register_type(&"foo".into());
|
||||
w.register_type(&"bar".into());
|
||||
let t0 = w.register_type(&"foo".into());
|
||||
let t1 = w.register_type(&"bar".into());
|
||||
// Drops borrow as mut
|
||||
|
||||
w.set_effectiveness(0, 1, 0.5);
|
||||
w.set_effectiveness(1, 0, 2.0);
|
||||
w.set_effectiveness(t0, t1, 0.5);
|
||||
w.set_effectiveness(t1, t0, 2.0);
|
||||
|
||||
lib
|
||||
}
|
||||
@@ -72,14 +101,14 @@ pub mod tests {
|
||||
|
||||
// Borrow as mut so we can insert
|
||||
let w = &mut lib;
|
||||
w.register_type(&"foo".into());
|
||||
w.register_type(&"bar".into());
|
||||
let t0 = w.register_type(&"foo".into());
|
||||
let t1 = w.register_type(&"bar".into());
|
||||
// Drops borrow as mut
|
||||
|
||||
// Borrow as read so we can read
|
||||
let r = &lib;
|
||||
assert_eq!(r.get_type_id(&"foo".into()), 0);
|
||||
assert_eq!(r.get_type_id(&"bar".into()), 1);
|
||||
assert_eq!(r.get_type_id(&"foo".into()), t0);
|
||||
assert_eq!(r.get_type_id(&"bar".into()), t1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -88,16 +117,16 @@ pub mod tests {
|
||||
|
||||
// Borrow as mut so we can insert
|
||||
let w = &mut lib;
|
||||
w.register_type(&"foo".into());
|
||||
w.register_type(&"bar".into());
|
||||
w.set_effectiveness(0, 1, 0.5);
|
||||
w.set_effectiveness(1, 0, 2.0);
|
||||
let t0 = w.register_type(&"foo".into());
|
||||
let t1 = w.register_type(&"bar".into());
|
||||
w.set_effectiveness(t0, t1, 0.5);
|
||||
w.set_effectiveness(t1, t0, 2.0);
|
||||
// Drops borrow as mut
|
||||
|
||||
// Borrow as read so we can read
|
||||
let r = &lib;
|
||||
assert_approx_eq!(r.get_single_effectiveness(0, 1), 0.5);
|
||||
assert_approx_eq!(r.get_single_effectiveness(1, 0), 2.0);
|
||||
assert_approx_eq!(r.get_single_effectiveness(t0, t1), 0.5);
|
||||
assert_approx_eq!(r.get_single_effectiveness(t1, t0), 2.0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -106,15 +135,15 @@ pub mod tests {
|
||||
|
||||
// Borrow as mut so we can insert
|
||||
let w = &mut lib;
|
||||
w.register_type(&"foo".into());
|
||||
w.register_type(&"bar".into());
|
||||
w.set_effectiveness(0, 1, 0.5);
|
||||
w.set_effectiveness(1, 0, 2.0);
|
||||
let t0 = w.register_type(&"foo".into());
|
||||
let t1 = w.register_type(&"bar".into());
|
||||
w.set_effectiveness(t0, t1, 0.5);
|
||||
w.set_effectiveness(t1, t0, 2.0);
|
||||
// Drops borrow as mut
|
||||
|
||||
// Borrow as read so we can read
|
||||
let r = &lib;
|
||||
assert_approx_eq!(r.get_effectiveness(0, &[1_u8, 1_u8]), 0.25);
|
||||
assert_approx_eq!(r.get_effectiveness(1, &[0_u8, 0_u8]), 4.0);
|
||||
assert_approx_eq!(r.get_effectiveness(t0, &[t1, t1]), 0.25);
|
||||
assert_approx_eq!(r.get_effectiveness(t1, &[t0, t0]), 4.0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,58 +1,93 @@
|
||||
use crate::static_data::SecondaryEffect;
|
||||
use crate::StringKey;
|
||||
use hashbrown::HashSet;
|
||||
|
||||
#[cfg(feature = "serde")]
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::static_data::{SecondaryEffect, TypeIdentifier};
|
||||
use crate::StringKey;
|
||||
|
||||
/// The move category defines what global kind of move this move is.
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))]
|
||||
pub enum MoveCategory {
|
||||
/// A physical move uses the physical attack stats and physical defense stats to calculate damage.
|
||||
Physical = 0,
|
||||
/// A special move uses the special attack stats and special defense stats to calculate damage.
|
||||
Special = 1,
|
||||
/// A status move does not do damage, and only runs a secondary effect.
|
||||
Status = 2,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
|
||||
/// 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))]
|
||||
pub enum MoveTarget {
|
||||
/// Adjacent allows a move to target any Pokemon that is either directly to the left or right of
|
||||
/// the user, opposed to the user, or left or right of the slot that is opposing the user.
|
||||
#[default]
|
||||
Adjacent = 0,
|
||||
/// AdjacentAlly allows a move to target any Pokemon that is directly to the left or right of
|
||||
/// the user.
|
||||
AdjacentAlly,
|
||||
/// AdjacentAllySelf allows a move to target any Pokemon that is either directly to the left or
|
||||
/// right of the user, or the user itself.
|
||||
AdjacentAllySelf,
|
||||
/// AdjacentOpponent allows a move to target any Pokemon that is either the opponent, or directly
|
||||
/// to the left or right of it.
|
||||
AdjacentOpponent,
|
||||
|
||||
/// All makes the move target everything on the field.
|
||||
All,
|
||||
/// AllAdjacent makes the move target everything adjacent on the field.
|
||||
AllAdjacent,
|
||||
/// AllAdjacentOpponent makes the move target everything adjacent to the opponent, and the opponent.
|
||||
AllAdjacentOpponent,
|
||||
/// AllAlly targets all Pokemon on the same side as the user.
|
||||
AllAlly,
|
||||
/// AllOpponent targets all Pokemon on an opposing side from the user.
|
||||
AllOpponent,
|
||||
|
||||
/// Any allows a move to target a single Pokemon, in any position.
|
||||
Any,
|
||||
|
||||
/// RandomOpponent allows a move to target a single Pokemon, in a random position.
|
||||
RandomOpponent,
|
||||
/// SelfUse makes the move target the user itself.
|
||||
#[cfg_attr(feature = "serde", serde(rename = "Self"))]
|
||||
SelfUse,
|
||||
}
|
||||
|
||||
/// A move is the skill Pokémon primarily use in battle. This is the data related to that.
|
||||
#[derive(PartialEq, Debug)]
|
||||
pub struct MoveData {
|
||||
/// The name of the move.
|
||||
name: StringKey,
|
||||
move_type: u8,
|
||||
/// The attacking type of the move.
|
||||
move_type: TypeIdentifier,
|
||||
/// The category of the move.
|
||||
category: MoveCategory,
|
||||
/// The base power, not considering any modifiers, the move has.
|
||||
base_power: u8,
|
||||
/// The accuracy of the move in percentage. Should be 255 for moves that always hit.
|
||||
accuracy: u8,
|
||||
/// The number of times the move can be used. This can be modified on actually learned moves using
|
||||
/// PP-Ups
|
||||
base_usages: u8,
|
||||
/// How the move handles targets.
|
||||
target: MoveTarget,
|
||||
/// 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>,
|
||||
/// Arbitrary flags that can be applied to the move.
|
||||
flags: HashSet<StringKey>,
|
||||
}
|
||||
|
||||
impl MoveData {
|
||||
/// Instantiates a new move.
|
||||
pub fn new(
|
||||
name: &StringKey,
|
||||
move_type: u8,
|
||||
move_type: TypeIdentifier,
|
||||
category: MoveCategory,
|
||||
base_power: u8,
|
||||
accuracy: u8,
|
||||
@@ -75,37 +110,47 @@ impl MoveData {
|
||||
flags,
|
||||
}
|
||||
}
|
||||
|
||||
/// The name of the move.
|
||||
pub fn name(&self) -> &StringKey {
|
||||
&self.name
|
||||
}
|
||||
pub fn move_type(&self) -> u8 {
|
||||
/// The attacking type of the move.
|
||||
pub fn move_type(&self) -> TypeIdentifier {
|
||||
self.move_type
|
||||
}
|
||||
/// The category of the move.
|
||||
pub fn category(&self) -> MoveCategory {
|
||||
self.category
|
||||
}
|
||||
/// The base power, not considering any modifiers, the move has.
|
||||
pub 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 {
|
||||
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 {
|
||||
self.base_usages
|
||||
}
|
||||
/// How the move handles targets.
|
||||
pub 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 {
|
||||
self.priority
|
||||
}
|
||||
|
||||
/// The optional secondary effect the move has.
|
||||
pub fn secondary_effect(&self) -> &Option<SecondaryEffect> {
|
||||
&self.secondary_effect
|
||||
}
|
||||
|
||||
/// Arbitrary flags that can be applied to the move.
|
||||
pub fn has_flag(&self, key: &StringKey) -> bool {
|
||||
self.flags.contains(key)
|
||||
}
|
||||
|
||||
@@ -1,21 +1,32 @@
|
||||
use crate::StringKey;
|
||||
|
||||
/// A parameter for an effect. This is basically a simple way to dynamically store multiple different
|
||||
/// primitives on data.
|
||||
#[derive(PartialEq, Debug)]
|
||||
pub enum EffectParameter {
|
||||
/// A boolean value.
|
||||
Bool(bool),
|
||||
/// An integer value. Stored as a 64 bit int to deal with potentially large numbers.
|
||||
Int(i64),
|
||||
/// A float value. Stored as a 32 bit float.
|
||||
Float(f32),
|
||||
/// A string value.
|
||||
String(String),
|
||||
}
|
||||
|
||||
/// A secondary effect is an effect on a move that happens after it hits.
|
||||
#[derive(PartialEq, Debug)]
|
||||
pub struct SecondaryEffect {
|
||||
/// The chance in percentages that the effect triggers. -1 to make it always trigger.
|
||||
chance: f32,
|
||||
/// The name of the effect.
|
||||
effect_name: StringKey,
|
||||
/// A list of parameters for the effect.
|
||||
parameters: Vec<EffectParameter>,
|
||||
}
|
||||
|
||||
impl SecondaryEffect {
|
||||
/// Instantiates a new Secondary Effect.
|
||||
pub fn new(chance: f32, effect_name: StringKey, parameters: Vec<EffectParameter>) -> SecondaryEffect {
|
||||
SecondaryEffect {
|
||||
chance,
|
||||
@@ -24,12 +35,15 @@ impl SecondaryEffect {
|
||||
}
|
||||
}
|
||||
|
||||
/// The chance in percentages that the effect triggers. -1 to make it always trigger.
|
||||
pub fn chance(&self) -> f32 {
|
||||
self.chance
|
||||
}
|
||||
/// The name of the effect.
|
||||
pub fn effect_name(&self) -> &StringKey {
|
||||
&self.effect_name
|
||||
}
|
||||
/// A list of parameters for the effect.
|
||||
pub fn parameters(&self) -> &Vec<EffectParameter> {
|
||||
&self.parameters
|
||||
}
|
||||
@@ -37,9 +51,10 @@ impl SecondaryEffect {
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::static_data::moves::secondary_effect::SecondaryEffect;
|
||||
use assert_approx_eq::assert_approx_eq;
|
||||
|
||||
use crate::static_data::moves::secondary_effect::SecondaryEffect;
|
||||
|
||||
#[test]
|
||||
fn create_secondary_effect() {
|
||||
let empty = SecondaryEffect::new(0.0, "".into(), vec![]);
|
||||
|
||||
@@ -1,16 +1,24 @@
|
||||
use crate::static_data::Statistic;
|
||||
use crate::StringKey;
|
||||
use hashbrown::HashMap;
|
||||
|
||||
use crate::static_data::Statistic;
|
||||
use crate::StringKey;
|
||||
|
||||
/// A nature is an attribute on a Pokemon that modifies the effective base stats on a Pokemon. They
|
||||
/// can have an increased statistic and a decreased statistic, or be neutral.
|
||||
#[derive(Debug)]
|
||||
pub struct Nature {
|
||||
/// The stat that should receive the increased modifier.
|
||||
increase_stat: Statistic,
|
||||
/// The stat that should receive the decreased modifier.
|
||||
decrease_stat: Statistic,
|
||||
/// The amount by which the increased stat is multiplied.
|
||||
increase_modifier: f32,
|
||||
/// The amount by which the decreased stat is multiplied.
|
||||
decrease_modifier: f32,
|
||||
}
|
||||
|
||||
impl Nature {
|
||||
/// Instantiates a new statistic.
|
||||
pub fn new(
|
||||
increase_stat: Statistic,
|
||||
decrease_stat: Statistic,
|
||||
@@ -25,14 +33,18 @@ impl Nature {
|
||||
}
|
||||
}
|
||||
|
||||
/// The stat that should receive the increased modifier.
|
||||
pub fn increased_stat(&self) -> Statistic {
|
||||
self.increase_stat
|
||||
}
|
||||
|
||||
/// The stat that should receive the decreased modifier.
|
||||
pub fn decreased_stat(&self) -> Statistic {
|
||||
self.decrease_stat
|
||||
}
|
||||
|
||||
/// Calculates the modifier for a given stat. If it's the increased stat, returns the increased
|
||||
/// modifier, if it's the decreased stat, returns the decreased modifier. Otherwise returns 1.0
|
||||
pub fn get_stat_modifier(&self, stat: Statistic) -> f32 {
|
||||
if stat == self.increase_stat {
|
||||
self.increase_modifier
|
||||
@@ -44,26 +56,32 @@ impl Nature {
|
||||
}
|
||||
}
|
||||
|
||||
/// A library of all natures that can be used, stored by their names.
|
||||
#[derive(Debug)]
|
||||
pub struct NatureLibrary {
|
||||
/// The underlying data structure.
|
||||
map: HashMap<StringKey, Nature>,
|
||||
}
|
||||
|
||||
impl NatureLibrary {
|
||||
/// Creates a new nature library with a given capacity.
|
||||
pub fn new(capacity: usize) -> Self {
|
||||
NatureLibrary {
|
||||
map: HashMap::with_capacity(capacity),
|
||||
}
|
||||
}
|
||||
|
||||
/// Adds a new nature with name to the library.
|
||||
pub fn load_nature(&mut self, name: StringKey, nature: Nature) {
|
||||
self.map.insert(name, nature);
|
||||
}
|
||||
|
||||
/// Gets a nature by name.
|
||||
pub fn get_nature(&self, key: &StringKey) -> Option<&Nature> {
|
||||
self.map.get(key)
|
||||
}
|
||||
|
||||
/// Finds a nature name by nature.
|
||||
pub fn get_nature_name(&self, nature: &Nature) -> StringKey {
|
||||
for kv in &self.map {
|
||||
// As natures can't be copied, and should always be the same reference as the value
|
||||
|
||||
@@ -1,32 +1,46 @@
|
||||
use crate::static_data::AbilityIndex;
|
||||
use hashbrown::HashSet;
|
||||
|
||||
use crate::static_data::LearnableMoves;
|
||||
use crate::static_data::Statistic;
|
||||
use crate::static_data::{Ability, StaticStatisticSet};
|
||||
use crate::static_data::{AbilityIndex, TypeIdentifier};
|
||||
use crate::Random;
|
||||
use crate::StringKey;
|
||||
use hashbrown::HashSet;
|
||||
|
||||
/// A form is a variant of a specific species. A species always has at least one form, but can have
|
||||
/// many more.
|
||||
#[derive(Debug)]
|
||||
pub struct Form {
|
||||
/// The name of the form.
|
||||
name: StringKey,
|
||||
/// The height of the form in meters.
|
||||
height: f32,
|
||||
/// The weight of the form in kilograms.
|
||||
weight: f32,
|
||||
/// The base amount of experience that is gained when beating a Pokemon with this form.
|
||||
base_experience: u32,
|
||||
types: Vec<u8>,
|
||||
/// The normal types a Pokemon with this form has.
|
||||
types: Vec<TypeIdentifier>,
|
||||
/// The inherent values of a form of species that are used for the stats of a Pokemon.
|
||||
base_stats: StaticStatisticSet<u16>,
|
||||
/// The possible abilities a Pokemon with this form can have.
|
||||
abilities: Vec<StringKey>,
|
||||
/// The possible hidden abilities a Pokemon with this form can have.
|
||||
hidden_abilities: Vec<StringKey>,
|
||||
/// The moves a Pokemon with this form can learn.
|
||||
moves: LearnableMoves,
|
||||
/// Arbitrary flags can be set on a form for scripting use.
|
||||
flags: HashSet<StringKey>,
|
||||
}
|
||||
|
||||
impl Form {
|
||||
/// Instantiates a new form.
|
||||
pub fn new(
|
||||
name: &StringKey,
|
||||
height: f32,
|
||||
weight: f32,
|
||||
base_experience: u32,
|
||||
types: Vec<u8>,
|
||||
types: Vec<TypeIdentifier>,
|
||||
base_stats: StaticStatisticSet<u16>,
|
||||
abilities: Vec<StringKey>,
|
||||
hidden_abilities: Vec<StringKey>,
|
||||
@@ -47,45 +61,58 @@ impl Form {
|
||||
}
|
||||
}
|
||||
|
||||
/// The name of the form.
|
||||
pub fn name(&self) -> &StringKey {
|
||||
&self.name
|
||||
}
|
||||
/// The height of the form in meters.
|
||||
pub fn height(&self) -> f32 {
|
||||
self.height
|
||||
}
|
||||
/// The weight of the form in kilograms.
|
||||
pub fn weight(&self) -> f32 {
|
||||
self.weight
|
||||
}
|
||||
/// The base amount of experience that is gained when beating a Pokemon with this form.
|
||||
pub fn base_experience(&self) -> u32 {
|
||||
self.base_experience
|
||||
}
|
||||
pub fn types(&self) -> &Vec<u8> {
|
||||
/// The normal types a Pokemon with this form has.
|
||||
pub fn types(&self) -> &Vec<TypeIdentifier> {
|
||||
&self.types
|
||||
}
|
||||
/// The inherent values of a form of species that are used for the stats of a Pokemon.
|
||||
pub fn base_stats(&self) -> &StaticStatisticSet<u16> {
|
||||
&self.base_stats
|
||||
}
|
||||
/// The possible abilities a Pokemon with this form can have.
|
||||
pub fn abilities(&self) -> &Vec<StringKey> {
|
||||
&self.abilities
|
||||
}
|
||||
/// The possible hidden abilities a Pokemon with this form can have.
|
||||
pub fn hidden_abilities(&self) -> &Vec<StringKey> {
|
||||
&self.hidden_abilities
|
||||
}
|
||||
/// The moves a Pokemon with this form can learn.
|
||||
pub fn moves(&self) -> &LearnableMoves {
|
||||
&self.moves
|
||||
}
|
||||
/// Arbitrary flags can be set on a form for scripting use.
|
||||
pub fn flags(&self) -> &HashSet<StringKey> {
|
||||
&self.flags
|
||||
}
|
||||
|
||||
pub fn get_type(&self, index: usize) -> u8 {
|
||||
/// Get a type of the move at a certain index.
|
||||
pub fn get_type(&self, index: usize) -> TypeIdentifier {
|
||||
self.types[index]
|
||||
}
|
||||
|
||||
/// Gets a single base stat value.
|
||||
pub fn get_base_stat(&self, stat: Statistic) -> u16 {
|
||||
self.base_stats.get_stat(stat)
|
||||
}
|
||||
|
||||
/// Find the index of an ability that can be on this form.
|
||||
pub fn find_ability_index(&self, ability: &Ability) -> Option<AbilityIndex> {
|
||||
for (index, a) in self.abilities.iter().enumerate() {
|
||||
if a == ability.name() {
|
||||
@@ -106,6 +133,7 @@ impl Form {
|
||||
None
|
||||
}
|
||||
|
||||
/// Gets an ability from the form.
|
||||
pub fn get_ability(&self, index: AbilityIndex) -> &StringKey {
|
||||
if index.hidden {
|
||||
&self.hidden_abilities[index.index as usize]
|
||||
@@ -114,13 +142,16 @@ impl Form {
|
||||
}
|
||||
}
|
||||
|
||||
/// Gets a random ability from the form.
|
||||
pub fn get_random_ability(&self, rand: &mut Random) -> &StringKey {
|
||||
&self.abilities[rand.get_between_unsigned(0, self.abilities.len() as u32) as usize]
|
||||
}
|
||||
/// Gets a random hidden ability from the form.
|
||||
pub fn get_random_hidden_ability(&self, rand: &mut Random) -> &StringKey {
|
||||
&self.hidden_abilities[rand.get_between_unsigned(0, self.hidden_abilities.len() as u32) as usize]
|
||||
}
|
||||
|
||||
/// Check if the form has a specific flag set.
|
||||
pub fn has_flag(&self, key: &StringKey) -> bool {
|
||||
self.flags.contains(key)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user