use hashbrown::HashSet; use std::fmt::Debug; use crate::static_data::Statistic; use crate::static_data::TypeIdentifier; use crate::static_data::{Ability, StaticStatisticSet}; use crate::static_data::{AbilityIndex, LearnableMoves}; use crate::StringKey; use crate::{Random, ValueIdentifiable, ValueIdentifier}; /// A form is a variant of a specific species. A species always has at least one form, but can have /// many more. pub trait Form: ValueIdentifiable + Debug { /// The name of the form. fn name(&self) -> &StringKey; /// The height of the form in meters. fn height(&self) -> f32; /// The weight of the form in kilograms. fn weight(&self) -> f32; /// The base amount of experience that is gained when beating a Pokemon with this form. fn base_experience(&self) -> u32; /// The normal types a Pokemon with this form has. fn types(&self) -> &Vec; /// The inherent values of a form of species that are used for the stats of a Pokemon. fn base_stats(&self) -> &StaticStatisticSet; /// The possible abilities a Pokemon with this form can have. fn abilities(&self) -> &Vec; /// The possible hidden abilities a Pokemon with this form can have. fn hidden_abilities(&self) -> &Vec; /// The moves a Pokemon with this form can learn. fn moves(&self) -> &Box; /// Arbitrary flags can be set on a form for scripting use. fn flags(&self) -> &HashSet; /// Get a type of the move at a certain index. fn get_type(&self, index: usize) -> TypeIdentifier; /// Gets a single base stat value. fn get_base_stat(&self, stat: Statistic) -> u16; /// Find the index of an ability that can be on this form. fn find_ability_index(&self, ability: &dyn Ability) -> Option; /// Gets an ability from the form. fn get_ability(&self, index: AbilityIndex) -> &StringKey; /// Gets a random ability from the form. fn get_random_ability(&self, rand: &mut Random) -> &StringKey; /// Gets a random hidden ability from the form. fn get_random_hidden_ability(&self, rand: &mut Random) -> &StringKey; /// Check if the form has a specific flag set. 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 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 FormImpl { /// A unique identifier so we know what value this is. identifier: ValueIdentifier, /// 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, /// The normal types a Pokemon with this form has. types: Vec, /// The inherent values of a form of species that are used for the stats of a Pokemon. base_stats: StaticStatisticSet, /// The possible abilities a Pokemon with this form can have. abilities: Vec, /// The possible hidden abilities a Pokemon with this form can have. hidden_abilities: Vec, /// The moves a Pokemon with this form can learn. moves: Box, /// Arbitrary flags can be set on a form for scripting use. flags: HashSet, } impl FormImpl { /// Instantiates a new form. pub fn new( name: &StringKey, height: f32, weight: f32, base_experience: u32, types: Vec, base_stats: StaticStatisticSet, abilities: Vec, hidden_abilities: Vec, moves: Box, flags: HashSet, ) -> Self { Self { identifier: Default::default(), name: name.clone(), height, weight, base_experience, types, base_stats, abilities, hidden_abilities, moves, flags, } } } impl Form for FormImpl { /// The name of the form. fn name(&self) -> &StringKey { &self.name } /// The height of the form in meters. fn height(&self) -> f32 { self.height } /// The weight of the form in kilograms. fn weight(&self) -> f32 { self.weight } /// The base amount of experience that is gained when beating a Pokemon with this form. fn base_experience(&self) -> u32 { self.base_experience } /// The normal types a Pokemon with this form has. fn types(&self) -> &Vec { &self.types } /// The inherent values of a form of species that are used for the stats of a Pokemon. fn base_stats(&self) -> &StaticStatisticSet { &self.base_stats } /// The possible abilities a Pokemon with this form can have. fn abilities(&self) -> &Vec { &self.abilities } /// The possible hidden abilities a Pokemon with this form can have. fn hidden_abilities(&self) -> &Vec { &self.hidden_abilities } /// The moves a Pokemon with this form can learn. fn moves(&self) -> &Box { &self.moves } /// Arbitrary flags can be set on a form for scripting use. fn flags(&self) -> &HashSet { &self.flags } /// Get a type of the move at a certain index. fn get_type(&self, index: usize) -> TypeIdentifier { self.types[index] } /// Gets a single base stat value. 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. fn find_ability_index(&self, ability: &dyn Ability) -> Option { for (index, a) in self.abilities.iter().enumerate() { if a == ability.name() { return Some(AbilityIndex { hidden: false, index: index as u8, }); } } for (index, a) in self.hidden_abilities.iter().enumerate() { if a == ability.name() { return Some(AbilityIndex { hidden: true, index: index as u8, }); } } None } /// Gets an ability from the form. fn get_ability(&self, index: AbilityIndex) -> &StringKey { if index.hidden { &self.hidden_abilities[index.index as usize] } else { &self.abilities[index.index as usize] } } /// Gets a random ability from the form. 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. 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. fn has_flag(&self, key: &StringKey) -> bool { self.flags.contains(key) } fn has_flag_by_hash(&self, key_hash: u32) -> bool { self.flags.contains::(&key_hash) } } impl ValueIdentifiable for FormImpl { fn value_identifier(&self) -> ValueIdentifier { self.identifier } } #[cfg(test)] pub(crate) mod tests { use super::*; mockall::mock! { #[derive(Debug)] pub Form {} impl Form for Form { fn name(&self) -> &StringKey; fn height(&self) -> f32; fn weight(&self) -> f32; fn base_experience(&self) -> u32; fn types(&self) -> &Vec; fn base_stats(&self) -> &StaticStatisticSet; fn abilities(&self) -> &Vec; fn hidden_abilities(&self) -> &Vec; fn moves(&self) -> &Box; fn flags(&self) -> &HashSet; fn get_type(&self, index: usize) -> TypeIdentifier; fn get_base_stat(&self, stat: Statistic) -> u16; fn find_ability_index(&self, ability: &dyn Ability) -> Option; fn get_ability(&self, index: AbilityIndex) -> &StringKey; fn get_random_ability(&self, rand: &mut Random) -> &StringKey; fn get_random_hidden_ability(&self, rand: &mut Random) -> &StringKey; fn has_flag(&self, key: &StringKey) -> bool; fn has_flag_by_hash(&self, key_hash: u32) -> bool; } impl ValueIdentifiable for Form { fn value_identifier(&self) -> ValueIdentifier { ValueIdentifier::new(0) } } } }