More documentation.
continuous-integration/drone/push Build is passing
Details
continuous-integration/drone/push Build is passing
Details
This commit is contained in:
parent
03f5e3bb5a
commit
8f6ecdd4ad
|
@ -3,10 +3,10 @@ use std::sync::Arc;
|
||||||
|
|
||||||
use parking_lot::RwLock;
|
use parking_lot::RwLock;
|
||||||
|
|
||||||
use crate::dynamic_data::LearnedMove;
|
|
||||||
use crate::dynamic_data::Pokemon;
|
use crate::dynamic_data::Pokemon;
|
||||||
use crate::dynamic_data::ScriptContainer;
|
use crate::dynamic_data::ScriptContainer;
|
||||||
use crate::dynamic_data::{ScriptSource, ScriptSourceData, ScriptWrapper};
|
use crate::dynamic_data::{LearnedMove, ScriptWrapper};
|
||||||
|
use crate::dynamic_data::{ScriptSource, ScriptSourceData};
|
||||||
|
|
||||||
/// The data on a turn choice that should be contained in every turn choice, regardless of type.
|
/// The data on a turn choice that should be contained in every turn choice, regardless of type.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
|
|
@ -50,13 +50,22 @@ fn get_all_adjacent_opponent<'b, 'library>(
|
||||||
battle.get_pokemon(side, index).as_ref().cloned(),
|
battle.get_pokemon(side, index).as_ref().cloned(),
|
||||||
battle.get_pokemon(side, left as u8).as_ref().cloned(),
|
battle.get_pokemon(side, left as u8).as_ref().cloned(),
|
||||||
battle.get_pokemon(side, right).as_ref().cloned(),
|
battle.get_pokemon(side, right).as_ref().cloned(),
|
||||||
|
battle
|
||||||
|
.get_pokemon(get_opposite_side(side), left as u8)
|
||||||
|
.as_ref()
|
||||||
|
.cloned(),
|
||||||
battle.get_pokemon(get_opposite_side(side), index).as_ref().cloned(),
|
battle.get_pokemon(get_opposite_side(side), index).as_ref().cloned(),
|
||||||
|
battle.get_pokemon(get_opposite_side(side), right).as_ref().cloned(),
|
||||||
]
|
]
|
||||||
} else {
|
} else {
|
||||||
vec![
|
vec![
|
||||||
battle.get_pokemon(side, index).as_ref().cloned(),
|
battle.get_pokemon(side, index).as_ref().cloned(),
|
||||||
battle.get_pokemon(side, left as u8).as_ref().cloned(),
|
battle.get_pokemon(side, left as u8).as_ref().cloned(),
|
||||||
battle.get_pokemon(get_opposite_side(side), index).as_ref().cloned(),
|
battle.get_pokemon(get_opposite_side(side), index).as_ref().cloned(),
|
||||||
|
battle
|
||||||
|
.get_pokemon(get_opposite_side(side), left as u8)
|
||||||
|
.as_ref()
|
||||||
|
.cloned(),
|
||||||
]
|
]
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -65,6 +74,7 @@ fn get_all_adjacent_opponent<'b, 'library>(
|
||||||
battle.get_pokemon(side, index).as_ref().cloned(),
|
battle.get_pokemon(side, index).as_ref().cloned(),
|
||||||
battle.get_pokemon(side, right).as_ref().cloned(),
|
battle.get_pokemon(side, right).as_ref().cloned(),
|
||||||
battle.get_pokemon(get_opposite_side(side), index).as_ref().cloned(),
|
battle.get_pokemon(get_opposite_side(side), index).as_ref().cloned(),
|
||||||
|
battle.get_pokemon(get_opposite_side(side), right).as_ref().cloned(),
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -246,14 +246,18 @@ impl<'own, 'library> Battle<'own, 'library> {
|
||||||
hit_data.set_damage(damage);
|
hit_data.set_damage(damage);
|
||||||
|
|
||||||
let mut accuracy = executing_move.use_move().accuracy();
|
let mut accuracy = executing_move.use_move().accuracy();
|
||||||
script_hook!(
|
// If the accuracy is 255, the move should always hit, and as such we should not allow
|
||||||
change_accuracy,
|
// modifying it.
|
||||||
executing_move,
|
if accuracy != 255 {
|
||||||
executing_move,
|
script_hook!(
|
||||||
target,
|
change_accuracy,
|
||||||
hit_index,
|
executing_move,
|
||||||
&mut accuracy
|
executing_move,
|
||||||
);
|
target,
|
||||||
|
hit_index,
|
||||||
|
&mut accuracy
|
||||||
|
);
|
||||||
|
}
|
||||||
if accuracy < 100 && self.random().get_max(100) as u8 >= accuracy {
|
if accuracy < 100 && self.random().get_max(100) as u8 >= accuracy {
|
||||||
script_hook!(on_move_miss, target, executing_move, target);
|
script_hook!(on_move_miss, target, executing_move, target);
|
||||||
self.event_hook().trigger(Event::Miss {
|
self.event_hook().trigger(Event::Miss {
|
||||||
|
|
|
@ -40,7 +40,7 @@ impl<'library> Gen7MiscLibrary<'library> {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
let struggle_data = Box::new(MoveData::new(
|
let struggle_data = Box::new(MoveData::new(
|
||||||
&StringKey::new("struggle"),
|
&StringKey::new("struggle"),
|
||||||
0,
|
0.into(),
|
||||||
MoveCategory::Physical,
|
MoveCategory::Physical,
|
||||||
50,
|
50,
|
||||||
255,
|
255,
|
||||||
|
|
|
@ -7,7 +7,6 @@ use parking_lot::RwLock;
|
||||||
|
|
||||||
use crate::dynamic_data::choices::TurnChoice;
|
use crate::dynamic_data::choices::TurnChoice;
|
||||||
use crate::dynamic_data::event_hooks::{Event, EventHook};
|
use crate::dynamic_data::event_hooks::{Event, EventHook};
|
||||||
use crate::dynamic_data::is_valid_target;
|
|
||||||
use crate::dynamic_data::models::battle_party::BattleParty;
|
use crate::dynamic_data::models::battle_party::BattleParty;
|
||||||
use crate::dynamic_data::models::battle_random::BattleRandom;
|
use crate::dynamic_data::models::battle_random::BattleRandom;
|
||||||
use crate::dynamic_data::models::battle_result::BattleResult;
|
use crate::dynamic_data::models::battle_result::BattleResult;
|
||||||
|
@ -17,8 +16,9 @@ use crate::dynamic_data::ChoiceQueue;
|
||||||
use crate::dynamic_data::DynamicLibrary;
|
use crate::dynamic_data::DynamicLibrary;
|
||||||
use crate::dynamic_data::Script;
|
use crate::dynamic_data::Script;
|
||||||
use crate::dynamic_data::ScriptSet;
|
use crate::dynamic_data::ScriptSet;
|
||||||
use crate::dynamic_data::VolatileScripts;
|
use crate::dynamic_data::VolatileScriptsOwner;
|
||||||
use crate::dynamic_data::{ScriptCategory, ScriptSource, ScriptSourceData, ScriptWrapper};
|
use crate::dynamic_data::{is_valid_target, ScriptWrapper};
|
||||||
|
use crate::dynamic_data::{ScriptCategory, ScriptSource, ScriptSourceData};
|
||||||
use crate::{script_hook, PkmnResult, StringKey};
|
use crate::{script_hook, PkmnResult, StringKey};
|
||||||
|
|
||||||
/// A pokemon battle, with any amount of sides and pokemon per side.
|
/// A pokemon battle, with any amount of sides and pokemon per side.
|
||||||
|
@ -322,7 +322,7 @@ impl<'own, 'library> Battle<'own, 'library> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'own, 'library> VolatileScripts<'own> for Battle<'own, 'library> {
|
impl<'own, 'library> VolatileScriptsOwner<'own> for Battle<'own, 'library> {
|
||||||
fn volatile_scripts(&self) -> &Arc<ScriptSet> {
|
fn volatile_scripts(&self) -> &Arc<ScriptSet> {
|
||||||
&self.volatile_scripts
|
&self.volatile_scripts
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,7 +13,7 @@ use crate::dynamic_data::models::pokemon::Pokemon;
|
||||||
use crate::dynamic_data::script_handling::{ScriptSource, ScriptSourceData, ScriptWrapper};
|
use crate::dynamic_data::script_handling::{ScriptSource, ScriptSourceData, ScriptWrapper};
|
||||||
use crate::dynamic_data::Script;
|
use crate::dynamic_data::Script;
|
||||||
use crate::dynamic_data::ScriptSet;
|
use crate::dynamic_data::ScriptSet;
|
||||||
use crate::dynamic_data::VolatileScripts;
|
use crate::dynamic_data::VolatileScriptsOwner;
|
||||||
use crate::{script_hook, PkmnResult, StringKey};
|
use crate::{script_hook, PkmnResult, StringKey};
|
||||||
|
|
||||||
/// A side on a battle.
|
/// A side on a battle.
|
||||||
|
@ -296,7 +296,7 @@ impl<'own, 'library> BattleSide<'own, 'library> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'own, 'library> VolatileScripts<'own> for BattleSide<'own, 'library> {
|
impl<'own, 'library> VolatileScriptsOwner<'own> for BattleSide<'own, 'library> {
|
||||||
fn volatile_scripts(&self) -> &Arc<ScriptSet> {
|
fn volatile_scripts(&self) -> &Arc<ScriptSet> {
|
||||||
&self.volatile_scripts
|
&self.volatile_scripts
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,7 +10,7 @@ use crate::dynamic_data::models::pokemon::Pokemon;
|
||||||
use crate::dynamic_data::script_handling::{ScriptSource, ScriptSourceData, ScriptWrapper};
|
use crate::dynamic_data::script_handling::{ScriptSource, ScriptSourceData, ScriptWrapper};
|
||||||
use crate::dynamic_data::ScriptContainer;
|
use crate::dynamic_data::ScriptContainer;
|
||||||
use crate::dynamic_data::TargetList;
|
use crate::dynamic_data::TargetList;
|
||||||
use crate::static_data::MoveData;
|
use crate::static_data::{MoveData, TypeIdentifier};
|
||||||
use crate::{PkmnResult, PokemonError};
|
use crate::{PkmnResult, PokemonError};
|
||||||
|
|
||||||
/// A hit data is the data for a single hit, on a single target.
|
/// A hit data is the data for a single hit, on a single target.
|
||||||
|
@ -25,7 +25,7 @@ pub struct HitData {
|
||||||
/// The actual damage of the hit.
|
/// The actual damage of the hit.
|
||||||
damage: AtomicU32,
|
damage: AtomicU32,
|
||||||
/// The type id of the type used for the hit.
|
/// The type id of the type used for the hit.
|
||||||
move_type: AtomicU8,
|
move_type: Atomic<TypeIdentifier>,
|
||||||
/// Whether or not the hit has failed.
|
/// Whether or not the hit has failed.
|
||||||
has_failed: AtomicBool,
|
has_failed: AtomicBool,
|
||||||
}
|
}
|
||||||
|
@ -48,7 +48,7 @@ impl HitData {
|
||||||
self.damage.load(Ordering::Relaxed)
|
self.damage.load(Ordering::Relaxed)
|
||||||
}
|
}
|
||||||
/// The type id of the type used for the hit.
|
/// The type id of the type used for the hit.
|
||||||
pub fn move_type(&self) -> u8 {
|
pub fn move_type(&self) -> TypeIdentifier {
|
||||||
self.move_type.load(Ordering::Relaxed)
|
self.move_type.load(Ordering::Relaxed)
|
||||||
}
|
}
|
||||||
/// Whether or not the hit has failed.
|
/// Whether or not the hit has failed.
|
||||||
|
@ -73,7 +73,7 @@ impl HitData {
|
||||||
self.damage.store(value, Ordering::SeqCst);
|
self.damage.store(value, Ordering::SeqCst);
|
||||||
}
|
}
|
||||||
/// Sets the move type id of the hit.
|
/// Sets the move type id of the hit.
|
||||||
pub fn set_move_type(&self, value: u8) {
|
pub fn set_move_type(&self, value: TypeIdentifier) {
|
||||||
self.move_type.store(value, Ordering::SeqCst);
|
self.move_type.store(value, Ordering::SeqCst);
|
||||||
}
|
}
|
||||||
/// Marks the hit as failed.
|
/// Marks the hit as failed.
|
||||||
|
|
|
@ -2,21 +2,32 @@ use std::sync::atomic::{AtomicU8, Ordering};
|
||||||
|
|
||||||
use crate::static_data::MoveData;
|
use crate::static_data::MoveData;
|
||||||
|
|
||||||
|
/// A learned move is the data attached to a Pokemon for a move it has learned. It has information
|
||||||
|
/// such as the remaining amount of users, how it has been learned, etc.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct LearnedMove<'library> {
|
pub struct LearnedMove<'library> {
|
||||||
|
/// The immutable move information of the move.
|
||||||
move_data: &'library MoveData,
|
move_data: &'library MoveData,
|
||||||
|
/// The maximal power points for this move.
|
||||||
max_pp: u8,
|
max_pp: u8,
|
||||||
|
/// The amount of remaining power points. If this is 0, we can not use the move anymore.
|
||||||
remaining_pp: AtomicU8,
|
remaining_pp: AtomicU8,
|
||||||
|
/// The way the move was learned.
|
||||||
learn_method: MoveLearnMethod,
|
learn_method: MoveLearnMethod,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug)]
|
/// The different ways a move can be learned.
|
||||||
|
#[derive(Copy, Clone, Debug, Default)]
|
||||||
pub enum MoveLearnMethod {
|
pub enum MoveLearnMethod {
|
||||||
|
/// We do not know the learn method.
|
||||||
|
#[default]
|
||||||
Unknown = 0,
|
Unknown = 0,
|
||||||
|
/// The move was learned through level up.
|
||||||
Level = 1,
|
Level = 1,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> LearnedMove<'a> {
|
impl<'a> LearnedMove<'a> {
|
||||||
|
/// Instantiate a new learned move.
|
||||||
pub fn new(move_data: &'a MoveData, learn_method: MoveLearnMethod) -> Self {
|
pub fn new(move_data: &'a MoveData, learn_method: MoveLearnMethod) -> Self {
|
||||||
Self {
|
Self {
|
||||||
move_data,
|
move_data,
|
||||||
|
@ -26,36 +37,50 @@ impl<'a> LearnedMove<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The immutable move information of the move.
|
||||||
pub fn move_data(&self) -> &MoveData {
|
pub fn move_data(&self) -> &MoveData {
|
||||||
self.move_data
|
self.move_data
|
||||||
}
|
}
|
||||||
|
/// The maximal power points for this move.
|
||||||
pub fn max_pp(&self) -> u8 {
|
pub fn max_pp(&self) -> u8 {
|
||||||
self.max_pp
|
self.max_pp
|
||||||
}
|
}
|
||||||
|
/// The amount of remaining power points. If this is 0, we can not use the move anymore.
|
||||||
pub fn remaining_pp(&self) -> u8 {
|
pub fn remaining_pp(&self) -> u8 {
|
||||||
self.remaining_pp.load(Ordering::Relaxed)
|
self.remaining_pp.load(Ordering::Relaxed)
|
||||||
}
|
}
|
||||||
|
/// The way the move was learned.
|
||||||
pub fn learn_method(&self) -> MoveLearnMethod {
|
pub fn learn_method(&self) -> MoveLearnMethod {
|
||||||
self.learn_method
|
self.learn_method
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Try and reduce the PP by a certain amount. If the amount is higher than the current uses,
|
||||||
|
/// return false. Otherwise, reduce the PP, and return true.
|
||||||
pub fn try_use(&self, amount: u8) -> bool {
|
pub fn try_use(&self, amount: u8) -> bool {
|
||||||
if amount > self.remaining_pp() {
|
let res = self.remaining_pp.fetch_update(Ordering::SeqCst, Ordering::SeqCst, |x| {
|
||||||
return false;
|
if amount > x {
|
||||||
}
|
None
|
||||||
self.remaining_pp.fetch_sub(amount, Ordering::SeqCst);
|
} else {
|
||||||
true
|
Some(x - amount)
|
||||||
|
}
|
||||||
|
});
|
||||||
|
res.is_ok()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Set the remaining PP to the max amount of PP.
|
||||||
pub fn restore_all_uses(&self) {
|
pub fn restore_all_uses(&self) {
|
||||||
self.remaining_pp.store(self.max_pp, Ordering::SeqCst);
|
self.remaining_pp.store(self.max_pp, Ordering::SeqCst);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Restore the remaining PP by a certain amount. Will prevent it from going above max PP.
|
||||||
pub fn restore_uses(&self, mut uses: u8) {
|
pub fn restore_uses(&self, mut uses: u8) {
|
||||||
if self.remaining_pp() + uses > self.max_pp {
|
self.remaining_pp
|
||||||
uses = self.remaining_pp() - uses;
|
.fetch_update(Ordering::SeqCst, Ordering::SeqCst, |x| {
|
||||||
}
|
if x + uses > self.max_pp {
|
||||||
self.remaining_pp.fetch_add(uses, Ordering::SeqCst);
|
uses = self.max_pp - x;
|
||||||
|
}
|
||||||
|
Some(x)
|
||||||
|
})
|
||||||
|
.unwrap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,8 +11,7 @@ use crate::dynamic_data::models::battle::Battle;
|
||||||
use crate::dynamic_data::models::damage_source::DamageSource;
|
use crate::dynamic_data::models::damage_source::DamageSource;
|
||||||
use crate::dynamic_data::models::learned_move::{LearnedMove, MoveLearnMethod};
|
use crate::dynamic_data::models::learned_move::{LearnedMove, MoveLearnMethod};
|
||||||
use crate::dynamic_data::script_handling::{ScriptSource, ScriptSourceData, ScriptWrapper};
|
use crate::dynamic_data::script_handling::{ScriptSource, ScriptSourceData, ScriptWrapper};
|
||||||
use crate::dynamic_data::{DynamicLibrary, Script, ScriptCategory, ScriptContainer, ScriptSet, VolatileScripts};
|
use crate::dynamic_data::{DynamicLibrary, Script, ScriptCategory, ScriptContainer, ScriptSet, VolatileScriptsOwner};
|
||||||
use crate::static_data::AbilityIndex;
|
|
||||||
use crate::static_data::DataLibrary;
|
use crate::static_data::DataLibrary;
|
||||||
use crate::static_data::Form;
|
use crate::static_data::Form;
|
||||||
use crate::static_data::Gender;
|
use crate::static_data::Gender;
|
||||||
|
@ -20,95 +19,107 @@ use crate::static_data::Item;
|
||||||
use crate::static_data::Nature;
|
use crate::static_data::Nature;
|
||||||
use crate::static_data::Species;
|
use crate::static_data::Species;
|
||||||
use crate::static_data::{Ability, Statistic};
|
use crate::static_data::{Ability, Statistic};
|
||||||
|
use crate::static_data::{AbilityIndex, TypeIdentifier};
|
||||||
use crate::static_data::{ClampedStatisticSet, StatisticSet};
|
use crate::static_data::{ClampedStatisticSet, StatisticSet};
|
||||||
use crate::utils::Random;
|
use crate::utils::Random;
|
||||||
use crate::{script_hook, PkmnResult, StringKey};
|
use crate::{script_hook, PkmnResult, StringKey};
|
||||||
|
|
||||||
#[derive(Debug)]
|
/// An individual Pokemon as we know and love them.
|
||||||
pub struct PokemonBattleData<'pokemon, 'library> {
|
|
||||||
battle: *mut Battle<'pokemon, 'library>,
|
|
||||||
battle_side_index: AtomicU8,
|
|
||||||
index: AtomicU8,
|
|
||||||
on_battle_field: AtomicBool,
|
|
||||||
seen_opponents: RwLock<Vec<Weak<Pokemon<'pokemon, 'library>>>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'pokemon, 'library> PokemonBattleData<'pokemon, 'library> {
|
|
||||||
pub fn battle_mut(&mut self) -> Option<&mut Battle<'pokemon, 'library>> {
|
|
||||||
unsafe { self.battle.as_mut() }
|
|
||||||
}
|
|
||||||
pub fn battle(&self) -> Option<&Battle<'pokemon, 'library>> {
|
|
||||||
unsafe { self.battle.as_ref() }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn battle_side_index(&self) -> u8 {
|
|
||||||
self.battle_side_index.load(Ordering::Relaxed)
|
|
||||||
}
|
|
||||||
pub fn index(&self) -> u8 {
|
|
||||||
self.index.load(Ordering::Relaxed)
|
|
||||||
}
|
|
||||||
pub fn on_battle_field(&self) -> bool {
|
|
||||||
self.on_battle_field.load(Ordering::Relaxed)
|
|
||||||
}
|
|
||||||
pub fn seen_opponents(&self) -> &RwLock<Vec<Weak<Pokemon<'pokemon, 'library>>>> {
|
|
||||||
&self.seen_opponents
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Pokemon<'own, 'library>
|
pub struct Pokemon<'own, 'library>
|
||||||
where
|
where
|
||||||
'own: 'library,
|
'own: 'library,
|
||||||
{
|
{
|
||||||
|
/// The library data of the Pokemon.
|
||||||
library: &'own DynamicLibrary,
|
library: &'own DynamicLibrary,
|
||||||
|
/// The species of the Pokemon.
|
||||||
species: &'own Species,
|
species: &'own Species,
|
||||||
|
/// The form of the Pokemon.
|
||||||
form: &'own Form,
|
form: &'own Form,
|
||||||
|
|
||||||
|
/// An optional display species of the Pokemon. If this is set, the client should display this
|
||||||
|
/// species. An example of usage for this is the Illusion ability.
|
||||||
display_species: Option<&'own Species>,
|
display_species: Option<&'own Species>,
|
||||||
|
/// An optional display form of the Pokemon. If this is set, the client should display this
|
||||||
|
// species. An example of usage for this is the Illusion ability.
|
||||||
display_form: Option<&'own Form>,
|
display_form: Option<&'own Form>,
|
||||||
|
|
||||||
|
/// The current level of the Pokemon.
|
||||||
level: LevelInt,
|
level: LevelInt,
|
||||||
|
/// The amount of experience of the Pokemon.
|
||||||
experience: AtomicU32,
|
experience: AtomicU32,
|
||||||
|
/// A unique random number for this Pokemon.
|
||||||
unique_identifier: u32,
|
unique_identifier: u32,
|
||||||
|
|
||||||
|
/// The gender of the Pokemon.
|
||||||
gender: Gender,
|
gender: Gender,
|
||||||
|
/// The coloring of the Pokemon. Value 0 is the default, value 1 means shiny. Other values are
|
||||||
|
/// currently not used, and can be used for other implementations.
|
||||||
coloring: u8,
|
coloring: u8,
|
||||||
|
/// The held item of the Pokemon.
|
||||||
held_item: RwLock<Option<&'own Item>>,
|
held_item: RwLock<Option<&'own Item>>,
|
||||||
|
/// The remaining health points of the Pokemon.
|
||||||
current_health: AtomicU32,
|
current_health: AtomicU32,
|
||||||
|
|
||||||
|
/// The weight of the Pokemon in kilograms.
|
||||||
weight: Atomic<f32>,
|
weight: Atomic<f32>,
|
||||||
|
/// The height of the Pokemon in meters.
|
||||||
height: Atomic<f32>,
|
height: Atomic<f32>,
|
||||||
|
|
||||||
stat_boost: ClampedStatisticSet<AtomicI8, -6, 6>,
|
/// The stats of the Pokemon when disregarding any stat boosts.
|
||||||
flat_stats: StatisticSet<AtomicU32>,
|
flat_stats: StatisticSet<AtomicU32>,
|
||||||
|
/// The statistics boosts of the Pokemon. Will prevent the value from going above 6, and below
|
||||||
|
/// -6.
|
||||||
|
stat_boost: ClampedStatisticSet<AtomicI8, -6, 6>,
|
||||||
|
/// The stats of the Pokemon including the stat boosts
|
||||||
boosted_stats: StatisticSet<AtomicU32>,
|
boosted_stats: StatisticSet<AtomicU32>,
|
||||||
|
/// The [individual values](https://bulbapedia.bulbagarden.net/wiki/Individual_values) of the Pokemon.
|
||||||
individual_values: ClampedStatisticSet<AtomicU8, 0, 31>,
|
individual_values: ClampedStatisticSet<AtomicU8, 0, 31>,
|
||||||
|
/// The [effort values](https://bulbapedia.bulbagarden.net/wiki/Effort_values) of the Pokemon.
|
||||||
effort_values: ClampedStatisticSet<AtomicU8, 0, 252>,
|
effort_values: ClampedStatisticSet<AtomicU8, 0, 252>,
|
||||||
|
/// The [nature](https://bulbapedia.bulbagarden.net/wiki/Nature) of the Pokemon.
|
||||||
nature: &'own Nature,
|
nature: &'own Nature,
|
||||||
|
|
||||||
|
/// An optional nickname of the Pokemon.
|
||||||
nickname: Option<String>,
|
nickname: Option<String>,
|
||||||
|
|
||||||
|
/// An index of the ability to find the actual ability on the form.
|
||||||
ability_index: AbilityIndex,
|
ability_index: AbilityIndex,
|
||||||
is_ability_overridden: bool,
|
/// An ability can be overriden to an arbitrary ability. This is for example used for the Mummy
|
||||||
|
/// ability.
|
||||||
override_ability: Option<Ability>,
|
override_ability: Option<Ability>,
|
||||||
|
|
||||||
|
/// If in battle, we have additional data.
|
||||||
battle_data: RwLock<Option<PokemonBattleData<'own, 'library>>>,
|
battle_data: RwLock<Option<PokemonBattleData<'own, 'library>>>,
|
||||||
|
|
||||||
|
/// The moves the Pokemon has learned. This is of a set length of [`MAX_MOVES`]. Empty move slots
|
||||||
|
/// are defined by None.
|
||||||
moves: RwLock<[Option<Arc<LearnedMove<'library>>>; MAX_MOVES]>,
|
moves: RwLock<[Option<Arc<LearnedMove<'library>>>; MAX_MOVES]>,
|
||||||
|
/// Whether or not the Pokemon is allowed to gain experience.
|
||||||
allowed_experience: bool,
|
allowed_experience: bool,
|
||||||
|
|
||||||
types: Vec<u8>,
|
/// The current types of the Pokemon.
|
||||||
|
types: Vec<TypeIdentifier>,
|
||||||
|
/// Whether or not this Pokemon is an egg.
|
||||||
is_egg: bool,
|
is_egg: bool,
|
||||||
|
/// Whether or not this Pokemon was caught this battle.
|
||||||
is_caught: bool,
|
is_caught: bool,
|
||||||
|
|
||||||
|
/// The script for the held item.
|
||||||
held_item_trigger_script: ScriptContainer,
|
held_item_trigger_script: ScriptContainer,
|
||||||
|
/// The script for the ability.
|
||||||
ability_script: ScriptContainer,
|
ability_script: ScriptContainer,
|
||||||
|
/// The script for the status.
|
||||||
status_script: ScriptContainer,
|
status_script: ScriptContainer,
|
||||||
|
/// The volatile status scripts of the Pokemon.
|
||||||
volatile: Arc<ScriptSet>,
|
volatile: Arc<ScriptSet>,
|
||||||
|
|
||||||
|
/// Data required for the Pokemon to be a script source.
|
||||||
script_source_data: RwLock<ScriptSourceData>,
|
script_source_data: RwLock<ScriptSourceData>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'own, 'library> Pokemon<'own, 'library> {
|
impl<'own, 'library> Pokemon<'own, 'library> {
|
||||||
|
/// Instantiates a new Pokemon.
|
||||||
pub fn new(
|
pub fn new(
|
||||||
library: &'own DynamicLibrary,
|
library: &'own DynamicLibrary,
|
||||||
species: &'own Species,
|
species: &'own Species,
|
||||||
|
@ -155,7 +166,6 @@ impl<'own, 'library> Pokemon<'own, 'library> {
|
||||||
nature,
|
nature,
|
||||||
nickname: None,
|
nickname: None,
|
||||||
ability_index: ability,
|
ability_index: ability,
|
||||||
is_ability_overridden: false,
|
|
||||||
override_ability: None,
|
override_ability: None,
|
||||||
battle_data: RwLock::new(None),
|
battle_data: RwLock::new(None),
|
||||||
moves: RwLock::new([None, None, None, None]),
|
moves: RwLock::new([None, None, None, None]),
|
||||||
|
@ -176,15 +186,19 @@ impl<'own, 'library> Pokemon<'own, 'library> {
|
||||||
pokemon
|
pokemon
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The library data of the Pokemon.
|
||||||
pub fn library(&self) -> &'own DynamicLibrary {
|
pub fn library(&self) -> &'own DynamicLibrary {
|
||||||
self.library
|
self.library
|
||||||
}
|
}
|
||||||
|
/// The species of the Pokemon.
|
||||||
pub fn species(&self) -> &'own Species {
|
pub fn species(&self) -> &'own Species {
|
||||||
self.species
|
self.species
|
||||||
}
|
}
|
||||||
|
/// The form of the Pokemon.
|
||||||
pub fn form(&self) -> &'own Form {
|
pub fn form(&self) -> &'own Form {
|
||||||
self.form
|
self.form
|
||||||
}
|
}
|
||||||
|
/// The species that should be displayed to the user. This handles stuff like the Illusion ability.
|
||||||
pub fn display_species(&self) -> &'own Species {
|
pub fn display_species(&self) -> &'own Species {
|
||||||
if let Some(v) = self.display_species {
|
if let Some(v) = self.display_species {
|
||||||
v
|
v
|
||||||
|
@ -192,6 +206,7 @@ impl<'own, 'library> Pokemon<'own, 'library> {
|
||||||
self.species
|
self.species
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
/// The form that should be displayed to the user. This handles stuff like the Illusion ability.
|
||||||
pub fn display_form(&self) -> &'own Form {
|
pub fn display_form(&self) -> &'own Form {
|
||||||
if let Some(v) = self.display_form {
|
if let Some(v) = self.display_form {
|
||||||
v
|
v
|
||||||
|
@ -199,25 +214,32 @@ impl<'own, 'library> Pokemon<'own, 'library> {
|
||||||
self.form
|
self.form
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
/// The current level of the Pokemon.
|
||||||
pub fn level(&self) -> LevelInt {
|
pub fn level(&self) -> LevelInt {
|
||||||
self.level
|
self.level
|
||||||
}
|
}
|
||||||
|
/// The amount of experience of the Pokemon.
|
||||||
pub fn experience(&self) -> u32 {
|
pub fn experience(&self) -> u32 {
|
||||||
self.experience.load(Ordering::Relaxed)
|
self.experience.load(Ordering::Relaxed)
|
||||||
}
|
}
|
||||||
|
/// A unique random number for this Pokemon.
|
||||||
pub fn unique_identifier(&self) -> u32 {
|
pub fn unique_identifier(&self) -> u32 {
|
||||||
self.unique_identifier
|
self.unique_identifier
|
||||||
}
|
}
|
||||||
|
/// The gender of the Pokemon.
|
||||||
pub fn gender(&self) -> Gender {
|
pub fn gender(&self) -> Gender {
|
||||||
self.gender
|
self.gender
|
||||||
}
|
}
|
||||||
|
/// The coloring of the Pokemon. Value 0 is the default, value 1 means shiny. Other values are
|
||||||
|
/// currently not used, and can be used for other implementations.
|
||||||
pub fn coloring(&self) -> u8 {
|
pub fn coloring(&self) -> u8 {
|
||||||
self.coloring
|
self.coloring
|
||||||
}
|
}
|
||||||
|
/// Checks whether the Pokemon is holding an item,
|
||||||
pub fn held_item(&self) -> &RwLock<Option<&'own Item>> {
|
pub fn held_item(&self) -> &RwLock<Option<&'own Item>> {
|
||||||
&self.held_item
|
&self.held_item
|
||||||
}
|
}
|
||||||
|
/// Checks whether the Pokemon is holding a specific item.
|
||||||
pub fn has_held_item(&self, name: &StringKey) -> bool {
|
pub fn has_held_item(&self, name: &StringKey) -> bool {
|
||||||
// Only true if we have an item, and the item name is the same as the requested item.
|
// Only true if we have an item, and the item name is the same as the requested item.
|
||||||
if let Some(v) = self.held_item.read().deref() {
|
if let Some(v) = self.held_item.read().deref() {
|
||||||
|
@ -225,12 +247,15 @@ impl<'own, 'library> Pokemon<'own, 'library> {
|
||||||
}
|
}
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
/// Changes the held item of the Pokemon/
|
||||||
pub fn set_held_item(&self, item: &'own Item) -> Option<&'own Item> {
|
pub fn set_held_item(&self, item: &'own Item) -> Option<&'own Item> {
|
||||||
self.held_item.write().replace(item)
|
self.held_item.write().replace(item)
|
||||||
}
|
}
|
||||||
|
/// Removes the held item from the Pokemon.
|
||||||
pub fn remove_held_item(&self) -> Option<&'own Item> {
|
pub fn remove_held_item(&self) -> Option<&'own Item> {
|
||||||
self.held_item.write().take()
|
self.held_item.write().take()
|
||||||
}
|
}
|
||||||
|
/// Makes the Pokemon uses its held item.
|
||||||
pub fn consume_held_item(&self) -> bool {
|
pub fn consume_held_item(&self) -> bool {
|
||||||
if self.held_item.read().is_none() {
|
if self.held_item.read().is_none() {
|
||||||
return false;
|
return false;
|
||||||
|
@ -244,42 +269,53 @@ impl<'own, 'library> Pokemon<'own, 'library> {
|
||||||
todo!();
|
todo!();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The remaining health points of the Pokemon.
|
||||||
pub fn current_health(&self) -> u32 {
|
pub fn current_health(&self) -> u32 {
|
||||||
self.current_health.load(Ordering::Relaxed)
|
self.current_health.load(Ordering::Relaxed)
|
||||||
}
|
}
|
||||||
|
/// The max health points of the Pokemon.
|
||||||
pub fn max_health(&self) -> u32 {
|
pub fn max_health(&self) -> u32 {
|
||||||
self.boosted_stats.hp()
|
self.boosted_stats.hp()
|
||||||
}
|
}
|
||||||
|
/// The weight of the Pokemon in kilograms.
|
||||||
pub fn weight(&self) -> f32 {
|
pub fn weight(&self) -> f32 {
|
||||||
self.weight.load(Ordering::Relaxed)
|
self.weight.load(Ordering::Relaxed)
|
||||||
}
|
}
|
||||||
|
/// The height of the Pokemon in meters.
|
||||||
pub fn height(&self) -> f32 {
|
pub fn height(&self) -> f32 {
|
||||||
self.height.load(Ordering::Relaxed)
|
self.height.load(Ordering::Relaxed)
|
||||||
}
|
}
|
||||||
|
/// An optional nickname of the Pokemon.
|
||||||
pub fn nickname(&self) -> &Option<String> {
|
pub fn nickname(&self) -> &Option<String> {
|
||||||
&self.nickname
|
&self.nickname
|
||||||
}
|
}
|
||||||
|
/// An index of the ability to find the actual ability on the form.
|
||||||
pub fn real_ability(&self) -> &AbilityIndex {
|
pub fn real_ability(&self) -> &AbilityIndex {
|
||||||
&self.ability_index
|
&self.ability_index
|
||||||
}
|
}
|
||||||
pub fn types(&self) -> &Vec<u8> {
|
/// The current types of the Pokemon.
|
||||||
|
pub fn types(&self) -> &Vec<TypeIdentifier> {
|
||||||
&self.types
|
&self.types
|
||||||
}
|
}
|
||||||
|
/// The moves the Pokemon has learned. This is of a set length of [`MAX_MOVES`]. Empty move slots
|
||||||
|
/// are defined by None.
|
||||||
pub fn learned_moves(&self) -> &RwLock<[Option<Arc<LearnedMove<'library>>>; MAX_MOVES]> {
|
pub fn learned_moves(&self) -> &RwLock<[Option<Arc<LearnedMove<'library>>>; MAX_MOVES]> {
|
||||||
&self.moves
|
&self.moves
|
||||||
}
|
}
|
||||||
pub fn status(&self) -> &ScriptContainer {
|
|
||||||
&self.status_script
|
/// The stats of the Pokemon when disregarding any stat boosts.
|
||||||
}
|
|
||||||
pub fn flat_stats(&self) -> &StatisticSet<AtomicU32> {
|
pub fn flat_stats(&self) -> &StatisticSet<AtomicU32> {
|
||||||
&self.flat_stats
|
&self.flat_stats
|
||||||
}
|
}
|
||||||
|
/// The stats of the Pokemon including the stat boosts
|
||||||
pub fn boosted_stats(&self) -> &StatisticSet<AtomicU32> {
|
pub fn boosted_stats(&self) -> &StatisticSet<AtomicU32> {
|
||||||
&self.boosted_stats
|
&self.boosted_stats
|
||||||
}
|
}
|
||||||
|
/// Get the stat boosts for a specific stat.
|
||||||
pub fn stat_boost(&self, stat: Statistic) -> i8 {
|
pub fn stat_boost(&self, stat: Statistic) -> i8 {
|
||||||
self.stat_boost.get_stat(stat)
|
self.stat_boost.get_stat(stat)
|
||||||
}
|
}
|
||||||
|
/// Change a boosted stat by a certain amount.
|
||||||
pub fn change_stat_boost(&self, stat: Statistic, mut diff_amount: i8, self_inflicted: bool) -> bool {
|
pub fn change_stat_boost(&self, stat: Statistic, mut diff_amount: i8, self_inflicted: bool) -> bool {
|
||||||
let mut prevent = false;
|
let mut prevent = false;
|
||||||
script_hook!(
|
script_hook!(
|
||||||
|
@ -328,13 +364,16 @@ impl<'own, 'library> Pokemon<'own, 'library> {
|
||||||
return changed;
|
return changed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The [individual values](https://bulbapedia.bulbagarden.net/wiki/Individual_values) of the Pokemon.
|
||||||
pub fn individual_values(&self) -> &ClampedStatisticSet<AtomicU8, 0, 31> {
|
pub fn individual_values(&self) -> &ClampedStatisticSet<AtomicU8, 0, 31> {
|
||||||
&self.individual_values
|
&self.individual_values
|
||||||
}
|
}
|
||||||
|
/// The [effort values](https://bulbapedia.bulbagarden.net/wiki/Effort_values) of the Pokemon.
|
||||||
pub fn effort_values(&self) -> &ClampedStatisticSet<AtomicU8, 0, 252> {
|
pub fn effort_values(&self) -> &ClampedStatisticSet<AtomicU8, 0, 252> {
|
||||||
&self.effort_values
|
&self.effort_values
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Gets the battle the battle is currently in.
|
||||||
pub fn get_battle(&self) -> Option<&Battle<'own, 'library>> {
|
pub fn get_battle(&self) -> Option<&Battle<'own, 'library>> {
|
||||||
let r = self.battle_data.read();
|
let r = self.battle_data.read();
|
||||||
if let Some(data) = &r.deref() {
|
if let Some(data) = &r.deref() {
|
||||||
|
@ -343,20 +382,24 @@ impl<'own, 'library> Pokemon<'own, 'library> {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
/// Get the index of the side of the battle the Pokemon is in. Only returns a value if the Pokemon
|
||||||
|
/// is on the battlefield.
|
||||||
pub fn get_battle_side_index(&self) -> Option<u8> {
|
pub fn get_battle_side_index(&self) -> Option<u8> {
|
||||||
self.battle_data.read().as_ref().map(|data| data.battle_side_index())
|
self.battle_data.read().as_ref().map(|data| data.battle_side_index())
|
||||||
}
|
}
|
||||||
|
/// Get the index of the slot on the side of the battle the Pokemon is in. Only returns a value
|
||||||
|
/// if the Pokemon is on the battlefield.
|
||||||
pub fn get_battle_index(&self) -> Option<u8> {
|
pub fn get_battle_index(&self) -> Option<u8> {
|
||||||
self.battle_data.read().as_ref().map(|data| data.index())
|
self.battle_data.read().as_ref().map(|data| data.index())
|
||||||
}
|
}
|
||||||
|
/// Returns whether something overrides the ability.
|
||||||
pub fn is_ability_overriden(&self) -> bool {
|
pub fn is_ability_overriden(&self) -> bool {
|
||||||
self.is_ability_overridden
|
self.override_ability.is_some()
|
||||||
}
|
}
|
||||||
|
/// Returns the currently active ability.
|
||||||
pub fn active_ability(&self) -> &Ability {
|
pub fn active_ability(&self) -> &Ability {
|
||||||
if self.is_ability_overridden {
|
if let Some(v) = &self.override_ability {
|
||||||
if let Some(v) = &self.override_ability {
|
return v;
|
||||||
return v;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
self.library
|
self.library
|
||||||
.static_data()
|
.static_data()
|
||||||
|
@ -365,33 +408,41 @@ impl<'own, 'library> Pokemon<'own, 'library> {
|
||||||
.unwrap()
|
.unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The script for the status.
|
||||||
|
pub fn status(&self) -> &ScriptContainer {
|
||||||
|
&self.status_script
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the script for the currently active ability.
|
||||||
pub fn ability_script(&self) -> &ScriptContainer {
|
pub fn ability_script(&self) -> &ScriptContainer {
|
||||||
&self.ability_script
|
&self.ability_script
|
||||||
}
|
}
|
||||||
|
|
||||||
// pub fn seen_opponents(&self) -> &RwLock<Option<PokemonBattleData<'own, 'library>>> {
|
/// Whether or not the Pokemon is allowed to gain experience.
|
||||||
// &self.battle_data.read
|
|
||||||
// }
|
|
||||||
pub fn allowed_experience_gain(&self) -> bool {
|
pub fn allowed_experience_gain(&self) -> bool {
|
||||||
self.allowed_experience
|
self.allowed_experience
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The [nature](https://bulbapedia.bulbagarden.net/wiki/Nature) of the Pokemon.
|
||||||
pub fn nature(&self) -> &'own Nature {
|
pub fn nature(&self) -> &'own Nature {
|
||||||
self.nature
|
self.nature
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Calculates the flat stats on the Pokemon.
|
||||||
pub fn recalculate_flat_stats(&self) {
|
pub fn recalculate_flat_stats(&self) {
|
||||||
self.library
|
self.library
|
||||||
.stat_calculator()
|
.stat_calculator()
|
||||||
.calculate_flat_stats(self, &self.flat_stats);
|
.calculate_flat_stats(self, &self.flat_stats);
|
||||||
self.recalculate_boosted_stats();
|
self.recalculate_boosted_stats();
|
||||||
}
|
}
|
||||||
|
/// Calculates the boosted stats on the Pokemon.
|
||||||
pub fn recalculate_boosted_stats(&self) {
|
pub fn recalculate_boosted_stats(&self) {
|
||||||
self.library
|
self.library
|
||||||
.stat_calculator()
|
.stat_calculator()
|
||||||
.calculate_boosted_stats(self, &self.boosted_stats);
|
.calculate_boosted_stats(self, &self.boosted_stats);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Change the species of the Pokemon.
|
||||||
pub fn change_species(&mut self, species: &'own Species, form: &'own Form) {
|
pub fn change_species(&mut self, species: &'own Species, form: &'own Form) {
|
||||||
self.species = species;
|
self.species = species;
|
||||||
self.form = form;
|
self.form = form;
|
||||||
|
@ -424,6 +475,7 @@ impl<'own, 'library> Pokemon<'own, 'library> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Change the form of the Pokemon.
|
||||||
pub fn change_form(&mut self, form: &'own Form) {
|
pub fn change_form(&mut self, form: &'own Form) {
|
||||||
if std::ptr::eq(self.form, form) {
|
if std::ptr::eq(self.form, form) {
|
||||||
return;
|
return;
|
||||||
|
@ -474,14 +526,17 @@ impl<'own, 'library> Pokemon<'own, 'library> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Whether or not the Pokemon is useable in a battle.
|
||||||
pub fn is_usable(&self) -> bool {
|
pub fn is_usable(&self) -> bool {
|
||||||
!self.is_caught && !self.is_egg && !self.is_fainted()
|
!self.is_caught && !self.is_egg && !self.is_fainted()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns whether the Pokemon is fainted.
|
||||||
pub fn is_fainted(&self) -> bool {
|
pub fn is_fainted(&self) -> bool {
|
||||||
self.current_health() == 0
|
self.current_health() == 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Sets the current battle the Pokemon is in.
|
||||||
pub fn set_battle_data(&self, battle: *mut Battle<'own, 'library>, battle_side_index: u8) {
|
pub fn set_battle_data(&self, battle: *mut Battle<'own, 'library>, battle_side_index: u8) {
|
||||||
let mut w = self.battle_data.write();
|
let mut w = self.battle_data.write();
|
||||||
if let Some(battle_data) = w.deref_mut() {
|
if let Some(battle_data) = w.deref_mut() {
|
||||||
|
@ -498,6 +553,7 @@ impl<'own, 'library> Pokemon<'own, 'library> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Sets whether or not the Pokemon is on the battlefield.
|
||||||
pub fn set_on_battlefield(&self, value: bool) {
|
pub fn set_on_battlefield(&self, value: bool) {
|
||||||
let r = self.battle_data.read();
|
let r = self.battle_data.read();
|
||||||
if let Some(data) = &mut r.deref() {
|
if let Some(data) = &mut r.deref() {
|
||||||
|
@ -510,6 +566,7 @@ impl<'own, 'library> Pokemon<'own, 'library> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Sets the index of the slot of the side the Pokemon is on.
|
||||||
pub fn set_battle_index(&self, index: u8) {
|
pub fn set_battle_index(&self, index: u8) {
|
||||||
let r = self.battle_data.read();
|
let r = self.battle_data.read();
|
||||||
if let Some(data) = r.deref() {
|
if let Some(data) = r.deref() {
|
||||||
|
@ -517,10 +574,12 @@ impl<'own, 'library> Pokemon<'own, 'library> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Whether or not the Pokemon is on the battlefield.
|
||||||
pub fn is_on_battlefield(&self) -> bool {
|
pub fn is_on_battlefield(&self) -> bool {
|
||||||
self.battle_data.read().is_some_and(|a| a.on_battle_field())
|
self.battle_data.read().is_some_and(|a| a.on_battle_field())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Marks an opponent as seen, for use in experience gain.
|
||||||
pub fn mark_opponent_as_seen(&self, pokemon: Weak<Pokemon<'own, 'library>>) {
|
pub fn mark_opponent_as_seen(&self, pokemon: Weak<Pokemon<'own, 'library>>) {
|
||||||
let r = self.battle_data.read();
|
let r = self.battle_data.read();
|
||||||
if let Some(battle_data) = &r.deref() {
|
if let Some(battle_data) = &r.deref() {
|
||||||
|
@ -534,6 +593,7 @@ impl<'own, 'library> Pokemon<'own, 'library> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Damages the Pokemon by a certain amount of damage, from a specific damage source.
|
||||||
pub fn damage(&self, mut damage: u32, source: DamageSource) {
|
pub fn damage(&self, mut damage: u32, source: DamageSource) {
|
||||||
if damage > self.current_health() {
|
if damage > self.current_health() {
|
||||||
damage = self.current_health();
|
damage = self.current_health();
|
||||||
|
@ -563,7 +623,8 @@ impl<'own, 'library> Pokemon<'own, 'library> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn on_faint(&self, source: DamageSource) {
|
/// Triggers when the Pokemon faints.
|
||||||
|
fn on_faint(&self, source: DamageSource) {
|
||||||
let r = self.battle_data.read();
|
let r = self.battle_data.read();
|
||||||
if let Some(battle_data) = r.deref() {
|
if let Some(battle_data) = r.deref() {
|
||||||
if let Some(battle) = battle_data.battle() {
|
if let Some(battle) = battle_data.battle() {
|
||||||
|
@ -581,6 +642,7 @@ impl<'own, 'library> Pokemon<'own, 'library> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Learn a move.
|
||||||
pub fn learn_move(&self, move_name: &StringKey, learn_method: MoveLearnMethod) {
|
pub fn learn_move(&self, move_name: &StringKey, learn_method: MoveLearnMethod) {
|
||||||
let mut learned_moves = self.learned_moves().write();
|
let mut learned_moves = self.learned_moves().write();
|
||||||
let move_pos = learned_moves.iter().position(|a| a.is_none());
|
let move_pos = learned_moves.iter().position(|a| a.is_none());
|
||||||
|
@ -592,6 +654,49 @@ impl<'own, 'library> Pokemon<'own, 'library> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The data of the Pokemon related to being in a battle.
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct PokemonBattleData<'pokemon, 'library> {
|
||||||
|
/// The battle data of the Pokemon
|
||||||
|
battle: *mut Battle<'pokemon, 'library>,
|
||||||
|
/// The index of the side of the Pokemon
|
||||||
|
battle_side_index: AtomicU8,
|
||||||
|
/// The index of the slot on the side of the Pokemon.
|
||||||
|
index: AtomicU8,
|
||||||
|
/// Whether or not the Pokemon is on the battlefield.
|
||||||
|
on_battle_field: AtomicBool,
|
||||||
|
/// A list of opponents the Pokemon has seen this battle.
|
||||||
|
seen_opponents: RwLock<Vec<Weak<Pokemon<'pokemon, 'library>>>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'pokemon, 'library> PokemonBattleData<'pokemon, 'library> {
|
||||||
|
/// The battle data of the Pokemon
|
||||||
|
pub fn battle_mut(&mut self) -> Option<&mut Battle<'pokemon, 'library>> {
|
||||||
|
unsafe { self.battle.as_mut() }
|
||||||
|
}
|
||||||
|
/// The battle data of the Pokemon
|
||||||
|
pub fn battle(&self) -> Option<&Battle<'pokemon, 'library>> {
|
||||||
|
unsafe { self.battle.as_ref() }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The index of the side of the Pokemon
|
||||||
|
pub fn battle_side_index(&self) -> u8 {
|
||||||
|
self.battle_side_index.load(Ordering::Relaxed)
|
||||||
|
}
|
||||||
|
/// The index of the slot on the side of the Pokemon.
|
||||||
|
pub fn index(&self) -> u8 {
|
||||||
|
self.index.load(Ordering::Relaxed)
|
||||||
|
}
|
||||||
|
/// Whether or not the Pokemon is on the battlefield.
|
||||||
|
pub fn on_battle_field(&self) -> bool {
|
||||||
|
self.on_battle_field.load(Ordering::Relaxed)
|
||||||
|
}
|
||||||
|
/// A list of opponents the Pokemon has seen this battle.
|
||||||
|
pub fn seen_opponents(&self) -> &RwLock<Vec<Weak<Pokemon<'pokemon, 'library>>>> {
|
||||||
|
&self.seen_opponents
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<'own, 'library> ScriptSource<'own> for Pokemon<'own, 'library> {
|
impl<'own, 'library> ScriptSource<'own> for Pokemon<'own, 'library> {
|
||||||
fn get_script_count(&self) -> usize {
|
fn get_script_count(&self) -> usize {
|
||||||
let mut c = 3;
|
let mut c = 3;
|
||||||
|
@ -624,7 +729,7 @@ impl<'own, 'library> ScriptSource<'own> for Pokemon<'own, 'library> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'own, 'library> VolatileScripts<'own> for Pokemon<'own, 'library> {
|
impl<'own, 'library> VolatileScriptsOwner<'own> for Pokemon<'own, 'library> {
|
||||||
fn volatile_scripts(&self) -> &Arc<ScriptSet> {
|
fn volatile_scripts(&self) -> &Arc<ScriptSet> {
|
||||||
&self.volatile
|
&self.volatile
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,30 +3,47 @@ use crate::dynamic_data::models::learned_move::MoveLearnMethod;
|
||||||
use crate::dynamic_data::models::pokemon::Pokemon;
|
use crate::dynamic_data::models::pokemon::Pokemon;
|
||||||
use crate::dynamic_data::DynamicLibrary;
|
use crate::dynamic_data::DynamicLibrary;
|
||||||
use crate::static_data::{AbilityIndex, DataLibrary, Gender};
|
use crate::static_data::{AbilityIndex, DataLibrary, Gender};
|
||||||
use crate::StringKey;
|
use crate::{Random, StringKey};
|
||||||
|
|
||||||
|
/// This allows for the easy chain building of a Pokemon.
|
||||||
pub struct PokemonBuilder<'own> {
|
pub struct PokemonBuilder<'own> {
|
||||||
|
/// The library of the Pokemon.
|
||||||
library: &'own DynamicLibrary,
|
library: &'own DynamicLibrary,
|
||||||
|
/// The name of the species of the Pokemon.
|
||||||
species: StringKey,
|
species: StringKey,
|
||||||
|
/// The level of the Pokemon.
|
||||||
level: LevelInt,
|
level: LevelInt,
|
||||||
|
/// The moves the Pokemon will know.
|
||||||
learned_moves: Vec<StringKey>,
|
learned_moves: Vec<StringKey>,
|
||||||
|
/// A random seed used for any randomization done.
|
||||||
|
random_seed: Option<u128>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'own> PokemonBuilder<'own> {
|
impl<'own> PokemonBuilder<'own> {
|
||||||
|
/// Creates a new PokemonBuilder with a library, species, and level.
|
||||||
pub fn new(library: &'own DynamicLibrary, species: StringKey, level: LevelInt) -> Self {
|
pub fn new(library: &'own DynamicLibrary, species: StringKey, level: LevelInt) -> Self {
|
||||||
Self {
|
Self {
|
||||||
library,
|
library,
|
||||||
species,
|
species,
|
||||||
level,
|
level,
|
||||||
learned_moves: vec![],
|
learned_moves: vec![],
|
||||||
|
random_seed: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
/// Makes the Pokemon learn a move.
|
||||||
pub fn learn_move(mut self, learned_move: StringKey) -> Self {
|
pub fn learn_move(mut self, learned_move: StringKey) -> Self {
|
||||||
self.learned_moves.push(learned_move);
|
self.learned_moves.push(learned_move);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Finally turn the builder into an actual Pokemon.
|
||||||
pub fn build(self) -> Pokemon<'own, 'own> {
|
pub fn build(self) -> Pokemon<'own, 'own> {
|
||||||
|
let mut random = if let Some(seed) = self.random_seed {
|
||||||
|
Random::new(seed)
|
||||||
|
} else {
|
||||||
|
Random::default()
|
||||||
|
};
|
||||||
|
|
||||||
let species = self.library.static_data().species().get(&self.species).unwrap();
|
let species = self.library.static_data().species().get(&self.species).unwrap();
|
||||||
let form = species.get_default_form();
|
let form = species.get_default_form();
|
||||||
let p = Pokemon::new(
|
let p = Pokemon::new(
|
||||||
|
@ -38,7 +55,7 @@ impl<'own> PokemonBuilder<'own> {
|
||||||
index: 0,
|
index: 0,
|
||||||
},
|
},
|
||||||
self.level,
|
self.level,
|
||||||
0,
|
random.get_unsigned(),
|
||||||
Gender::Male,
|
Gender::Male,
|
||||||
0,
|
0,
|
||||||
&"hardy".into(),
|
&"hardy".into(),
|
||||||
|
|
|
@ -1,12 +1,16 @@
|
||||||
use crate::dynamic_data::models::pokemon::Pokemon;
|
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
use crate::dynamic_data::models::pokemon::Pokemon;
|
||||||
|
|
||||||
|
/// A list of Pokemon belonging to a trainer.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct PokemonParty<'pokemon, 'library> {
|
pub struct PokemonParty<'pokemon, 'library> {
|
||||||
|
/// The underlying list of Pokemon.
|
||||||
pokemon: Vec<Option<Arc<Pokemon<'pokemon, 'library>>>>,
|
pokemon: Vec<Option<Arc<Pokemon<'pokemon, 'library>>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'own, 'library> PokemonParty<'own, 'library> {
|
impl<'own, 'library> PokemonParty<'own, 'library> {
|
||||||
|
/// Instantiates a party with a set size.
|
||||||
pub fn new(size: usize) -> Self {
|
pub fn new(size: usize) -> Self {
|
||||||
let mut pokemon = Vec::with_capacity(size);
|
let mut pokemon = Vec::with_capacity(size);
|
||||||
for _i in 0..size {
|
for _i in 0..size {
|
||||||
|
@ -15,10 +19,12 @@ impl<'own, 'library> PokemonParty<'own, 'library> {
|
||||||
Self { pokemon }
|
Self { pokemon }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Instantiates a party with a list.
|
||||||
pub fn new_from_vec(pokemon: Vec<Option<Arc<Pokemon<'own, 'library>>>>) -> Self {
|
pub fn new_from_vec(pokemon: Vec<Option<Arc<Pokemon<'own, 'library>>>>) -> Self {
|
||||||
Self { pokemon }
|
Self { pokemon }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Gets a Pokemon at an index in the party.
|
||||||
pub fn at(&self, index: usize) -> &Option<Arc<Pokemon<'own, 'library>>> {
|
pub fn at(&self, index: usize) -> &Option<Arc<Pokemon<'own, 'library>>> {
|
||||||
let opt = self.pokemon.get(index);
|
let opt = self.pokemon.get(index);
|
||||||
if let Some(v) = opt {
|
if let Some(v) = opt {
|
||||||
|
@ -28,10 +34,12 @@ impl<'own, 'library> PokemonParty<'own, 'library> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Swaps two Pokemon in the party around.
|
||||||
pub fn switch(&mut self, a: usize, b: usize) {
|
pub fn switch(&mut self, a: usize, b: usize) {
|
||||||
self.pokemon.swap(a, b);
|
self.pokemon.swap(a, b);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Sets the Pokemon at an index to a Pokemon, returning the old Pokemon.
|
||||||
pub fn swap_into(
|
pub fn swap_into(
|
||||||
&mut self,
|
&mut self,
|
||||||
index: usize,
|
index: usize,
|
||||||
|
@ -45,6 +53,7 @@ impl<'own, 'library> PokemonParty<'own, 'library> {
|
||||||
old
|
old
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Whether or not the party still has Pokemon that can be used in battle.
|
||||||
pub fn has_usable_pokemon(&self) -> bool {
|
pub fn has_usable_pokemon(&self) -> bool {
|
||||||
for pokemon in self.pokemon.iter().flatten() {
|
for pokemon in self.pokemon.iter().flatten() {
|
||||||
if pokemon.is_usable() {
|
if pokemon.is_usable() {
|
||||||
|
@ -54,14 +63,17 @@ impl<'own, 'library> PokemonParty<'own, 'library> {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get the length of the underlying list of Pokemon.
|
||||||
pub fn length(&self) -> usize {
|
pub fn length(&self) -> usize {
|
||||||
self.pokemon.len()
|
self.pokemon.len()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Gets the underlying list of Pokemon.
|
||||||
pub fn pokemon(&self) -> &Vec<Option<Arc<Pokemon<'own, 'library>>>> {
|
pub fn pokemon(&self) -> &Vec<Option<Arc<Pokemon<'own, 'library>>>> {
|
||||||
&self.pokemon
|
&self.pokemon
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Makes sure there are no empty spots in the party anymore, leaving the length the same.
|
||||||
pub fn pack_party(&mut self) {
|
pub fn pack_party(&mut self) {
|
||||||
let mut first_empty = None;
|
let mut first_empty = None;
|
||||||
let mut i = 0;
|
let mut i = 0;
|
||||||
|
|
|
@ -1 +1,2 @@
|
||||||
|
/// The script functions that are relevant to item use.
|
||||||
pub trait ItemScript {}
|
pub trait ItemScript {}
|
||||||
|
|
|
@ -9,13 +9,15 @@ pub use script::*;
|
||||||
#[doc(inline)]
|
#[doc(inline)]
|
||||||
pub use script_set::*;
|
pub use script_set::*;
|
||||||
#[doc(inline)]
|
#[doc(inline)]
|
||||||
pub use volatile_scripts::*;
|
pub use volatile_scripts_owner::*;
|
||||||
|
|
||||||
mod item_script;
|
mod item_script;
|
||||||
mod script;
|
mod script;
|
||||||
mod script_set;
|
mod script_set;
|
||||||
mod volatile_scripts;
|
mod volatile_scripts_owner;
|
||||||
|
|
||||||
|
/// This macro runs a script function on a given ScriptSource, and all its parents. It will ensure
|
||||||
|
/// to only run the script function if it is not suppressed, and can take any amount of parameters.
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! script_hook {
|
macro_rules! script_hook {
|
||||||
($hook_name: ident, $source: ident, $($parameters: expr),*) => {
|
($hook_name: ident, $source: ident, $($parameters: expr),*) => {
|
||||||
|
@ -33,6 +35,8 @@ macro_rules! script_hook {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// This macro runs a script function on all scripts in a Vec of scripts. It will ensure it only
|
||||||
|
/// runs the script function if it is not suppressed, and can take any amount of parameters.
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! run_scripts {
|
macro_rules! run_scripts {
|
||||||
($hook_name: ident, $source: ident, $($parameters: expr),*) => {
|
($hook_name: ident, $source: ident, $($parameters: expr),*) => {
|
||||||
|
@ -68,14 +72,20 @@ macro_rules! run_scripts {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The script source data is the basic data required for any script source.
|
||||||
#[derive(Default, Debug)]
|
#[derive(Default, Debug)]
|
||||||
pub struct ScriptSourceData {
|
pub struct ScriptSourceData {
|
||||||
|
/// Whether or not the data has been initialized yet.
|
||||||
is_initialized: bool,
|
is_initialized: bool,
|
||||||
|
/// A list that references all possible scripts on this source, and it's parents.
|
||||||
scripts: Vec<ScriptWrapper>,
|
scripts: Vec<ScriptWrapper>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A script source is a struct on which we can trigger scripts to be run from.
|
||||||
pub trait ScriptSource<'a> {
|
pub trait ScriptSource<'a> {
|
||||||
fn get_script_iterator(&self) -> ScriptAggregator {
|
/// Gets an iterator over all the scripts that are relevant to this script source. If the data
|
||||||
|
/// has not been initialised, it will do so here.
|
||||||
|
fn get_script_iterator(&self) -> ScriptIterator {
|
||||||
let lock = self.get_script_source_data();
|
let lock = self.get_script_source_data();
|
||||||
if !lock.read().is_initialized {
|
if !lock.read().is_initialized {
|
||||||
let mut data = lock.write();
|
let mut data = lock.write();
|
||||||
|
@ -83,17 +93,28 @@ pub trait ScriptSource<'a> {
|
||||||
self.collect_scripts(&mut data.scripts);
|
self.collect_scripts(&mut data.scripts);
|
||||||
data.is_initialized = true;
|
data.is_initialized = true;
|
||||||
}
|
}
|
||||||
ScriptAggregator::new(&lock.read().scripts as *const Vec<ScriptWrapper>)
|
ScriptIterator::new(&lock.read().scripts as *const Vec<ScriptWrapper>)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The number of scripts that are expected to be relevant for this source. This generally is
|
||||||
|
/// the number of its own scripts + the number of scripts for any parents.
|
||||||
fn get_script_count(&self) -> usize;
|
fn get_script_count(&self) -> usize;
|
||||||
|
/// Returns the underlying data required for us to be a script source.
|
||||||
fn get_script_source_data(&self) -> &RwLock<ScriptSourceData>;
|
fn get_script_source_data(&self) -> &RwLock<ScriptSourceData>;
|
||||||
|
/// This should add all scripts belonging to this source to the scripts Vec, disregarding its
|
||||||
|
/// potential parents.
|
||||||
fn get_own_scripts(&self, scripts: &mut Vec<ScriptWrapper>);
|
fn get_own_scripts(&self, scripts: &mut Vec<ScriptWrapper>);
|
||||||
|
/// This should add all scripts that are relevant to the source the the scripts Vec, including
|
||||||
|
/// everything that belongs to its parents.
|
||||||
fn collect_scripts(&self, scripts: &mut Vec<ScriptWrapper>);
|
fn collect_scripts(&self, scripts: &mut Vec<ScriptWrapper>);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Enum to store both ScriptSets and sets in a single value.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum ScriptWrapper {
|
pub enum ScriptWrapper {
|
||||||
|
/// A reference to a single script.
|
||||||
Script(Weak<RwLock<Option<Arc<dyn Script>>>>),
|
Script(Weak<RwLock<Option<Arc<dyn Script>>>>),
|
||||||
|
/// A reference to a ScriptSet.
|
||||||
Set(Weak<ScriptSet>),
|
Set(Weak<ScriptSet>),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -109,29 +130,31 @@ impl From<&Arc<ScriptSet>> for ScriptWrapper {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct ScriptAggregator {
|
/// This struct allows for the iteration over scripts.
|
||||||
|
pub struct ScriptIterator {
|
||||||
|
/// A pointer to the vector of ScriptWrappers. This can be a pointer, as we know it remains valid
|
||||||
|
/// while we're using it.
|
||||||
scripts: *const Vec<ScriptWrapper>,
|
scripts: *const Vec<ScriptWrapper>,
|
||||||
size: i32,
|
/// The current index in the scripts.
|
||||||
index: i32,
|
index: i32,
|
||||||
|
/// If we're currently inside a set, the current index inside the set.
|
||||||
set_index: i32,
|
set_index: i32,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ScriptAggregator {
|
impl ScriptIterator {
|
||||||
|
/// Instantiates an iterator.
|
||||||
pub fn new(scripts: *const Vec<ScriptWrapper>) -> Self {
|
pub fn new(scripts: *const Vec<ScriptWrapper>) -> Self {
|
||||||
unsafe {
|
Self {
|
||||||
let len = scripts.as_ref().unwrap().len();
|
scripts,
|
||||||
Self {
|
index: -1,
|
||||||
scripts,
|
set_index: -1,
|
||||||
size: len as i32,
|
|
||||||
index: -1,
|
|
||||||
set_index: -1,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Move to the next valid value in the scripts.
|
||||||
fn increment_to_next_value(&mut self) -> bool {
|
fn increment_to_next_value(&mut self) -> bool {
|
||||||
if self.index != -1 {
|
if self.index != -1 {
|
||||||
let wrapper = unsafe { &self.scripts.as_ref().unwrap()[self.index as usize] };
|
let wrapper = unsafe { &(*self.scripts)[self.index as usize] };
|
||||||
if let ScriptWrapper::Set(set) = wrapper {
|
if let ScriptWrapper::Set(set) = wrapper {
|
||||||
if let Some(set) = set.upgrade() {
|
if let Some(set) = set.upgrade() {
|
||||||
self.set_index += 1;
|
self.set_index += 1;
|
||||||
|
@ -144,7 +167,8 @@ impl ScriptAggregator {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.index += 1;
|
self.index += 1;
|
||||||
for index in self.index..self.size {
|
let len = (unsafe { &*self.scripts }).len() as i32;
|
||||||
|
for index in self.index..len {
|
||||||
self.index = index;
|
self.index = index;
|
||||||
let wrapper = unsafe { &self.scripts.as_ref().unwrap()[self.index as usize] };
|
let wrapper = unsafe { &self.scripts.as_ref().unwrap()[self.index as usize] };
|
||||||
if let ScriptWrapper::Set(s) = wrapper {
|
if let ScriptWrapper::Set(s) = wrapper {
|
||||||
|
@ -166,6 +190,7 @@ impl ScriptAggregator {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Gets the next valid script. If none is found, returns None.
|
||||||
pub fn get_next(&mut self) -> Option<ScriptContainer> {
|
pub fn get_next(&mut self) -> Option<ScriptContainer> {
|
||||||
if !self.increment_to_next_value() {
|
if !self.increment_to_next_value() {
|
||||||
return None;
|
return None;
|
||||||
|
@ -183,6 +208,7 @@ impl ScriptAggregator {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Resets the iterator to the start.
|
||||||
pub fn reset(&mut self) {
|
pub fn reset(&mut self) {
|
||||||
self.index = -1;
|
self.index = -1;
|
||||||
self.set_index = -1;
|
self.set_index = -1;
|
||||||
|
@ -260,7 +286,7 @@ mod tests {
|
||||||
fn script_aggregator_property_iterates_single_script() {
|
fn script_aggregator_property_iterates_single_script() {
|
||||||
let script = ScriptContainer::new(Arc::new(TestScript::new()));
|
let script = ScriptContainer::new(Arc::new(TestScript::new()));
|
||||||
let scripts = vec![ScriptWrapper::from(&script)];
|
let scripts = vec![ScriptWrapper::from(&script)];
|
||||||
let mut aggregator = ScriptAggregator::new(&scripts as *const Vec<ScriptWrapper>);
|
let mut aggregator = ScriptIterator::new(&scripts as *const Vec<ScriptWrapper>);
|
||||||
while let Some(v) = aggregator.get_next() {
|
while let Some(v) = aggregator.get_next() {
|
||||||
v.get().unwrap().read().as_ref().unwrap().on_initialize(&[]);
|
v.get().unwrap().read().as_ref().unwrap().on_initialize(&[]);
|
||||||
}
|
}
|
||||||
|
@ -272,7 +298,7 @@ mod tests {
|
||||||
fn script_aggregator_property_iterates_single_script_with_resets() {
|
fn script_aggregator_property_iterates_single_script_with_resets() {
|
||||||
let script = ScriptContainer::new(Arc::new(TestScript::new()));
|
let script = ScriptContainer::new(Arc::new(TestScript::new()));
|
||||||
let scripts = vec![ScriptWrapper::from(&script)];
|
let scripts = vec![ScriptWrapper::from(&script)];
|
||||||
let mut aggregator = ScriptAggregator::new(&scripts as *const Vec<ScriptWrapper>);
|
let mut aggregator = ScriptIterator::new(&scripts as *const Vec<ScriptWrapper>);
|
||||||
for i in 1..11 {
|
for i in 1..11 {
|
||||||
aggregator.reset();
|
aggregator.reset();
|
||||||
while let Some(v) = aggregator.get_next() {
|
while let Some(v) = aggregator.get_next() {
|
||||||
|
@ -293,7 +319,7 @@ mod tests {
|
||||||
ScriptWrapper::from(&script2),
|
ScriptWrapper::from(&script2),
|
||||||
ScriptWrapper::from(&script3),
|
ScriptWrapper::from(&script3),
|
||||||
];
|
];
|
||||||
let mut aggregator = ScriptAggregator::new(&scripts as *const Vec<ScriptWrapper>);
|
let mut aggregator = ScriptIterator::new(&scripts as *const Vec<ScriptWrapper>);
|
||||||
while let Some(v) = aggregator.get_next() {
|
while let Some(v) = aggregator.get_next() {
|
||||||
v.get().unwrap().read().as_ref().unwrap().on_initialize(&[]);
|
v.get().unwrap().read().as_ref().unwrap().on_initialize(&[]);
|
||||||
}
|
}
|
||||||
|
@ -315,7 +341,7 @@ mod tests {
|
||||||
ScriptWrapper::from(&script2),
|
ScriptWrapper::from(&script2),
|
||||||
ScriptWrapper::from(&script3),
|
ScriptWrapper::from(&script3),
|
||||||
];
|
];
|
||||||
let mut aggregator = ScriptAggregator::new(&scripts as *const Vec<ScriptWrapper>);
|
let mut aggregator = ScriptIterator::new(&scripts as *const Vec<ScriptWrapper>);
|
||||||
for i in 1..11 {
|
for i in 1..11 {
|
||||||
aggregator.reset();
|
aggregator.reset();
|
||||||
while let Some(v) = aggregator.get_next() {
|
while let Some(v) = aggregator.get_next() {
|
||||||
|
@ -338,7 +364,7 @@ mod tests {
|
||||||
set.add(Arc::new(TestScript::new_with_name("test_c")));
|
set.add(Arc::new(TestScript::new_with_name("test_c")));
|
||||||
|
|
||||||
let scripts = vec![ScriptWrapper::from(&set)];
|
let scripts = vec![ScriptWrapper::from(&set)];
|
||||||
let mut aggregator = ScriptAggregator::new(&scripts as *const Vec<ScriptWrapper>);
|
let mut aggregator = ScriptIterator::new(&scripts as *const Vec<ScriptWrapper>);
|
||||||
for i in 1..11 {
|
for i in 1..11 {
|
||||||
aggregator.reset();
|
aggregator.reset();
|
||||||
while let Some(v) = aggregator.get_next() {
|
while let Some(v) = aggregator.get_next() {
|
||||||
|
@ -367,7 +393,7 @@ mod tests {
|
||||||
set.add(Arc::new(TestScript::new_with_name("test_c")));
|
set.add(Arc::new(TestScript::new_with_name("test_c")));
|
||||||
|
|
||||||
let scripts = vec![ScriptWrapper::from(&set)];
|
let scripts = vec![ScriptWrapper::from(&set)];
|
||||||
let mut aggregator = ScriptAggregator::new(&scripts as *const Vec<ScriptWrapper>);
|
let mut aggregator = ScriptIterator::new(&scripts as *const Vec<ScriptWrapper>);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
aggregator
|
aggregator
|
||||||
.get_next()
|
.get_next()
|
||||||
|
@ -407,7 +433,7 @@ mod tests {
|
||||||
set.add(Arc::new(TestScript::new_with_name("test_c")));
|
set.add(Arc::new(TestScript::new_with_name("test_c")));
|
||||||
|
|
||||||
let scripts = vec![ScriptWrapper::from(&set)];
|
let scripts = vec![ScriptWrapper::from(&set)];
|
||||||
let mut aggregator = ScriptAggregator::new(&scripts as *const Vec<ScriptWrapper>);
|
let mut aggregator = ScriptIterator::new(&scripts as *const Vec<ScriptWrapper>);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
aggregator
|
aggregator
|
||||||
.get_next()
|
.get_next()
|
||||||
|
|
|
@ -12,7 +12,7 @@ use crate::dynamic_data::Battle;
|
||||||
use crate::dynamic_data::DamageSource;
|
use crate::dynamic_data::DamageSource;
|
||||||
use crate::dynamic_data::ExecutingMove;
|
use crate::dynamic_data::ExecutingMove;
|
||||||
use crate::dynamic_data::Pokemon;
|
use crate::dynamic_data::Pokemon;
|
||||||
use crate::static_data::EffectParameter;
|
use crate::static_data::{EffectParameter, TypeIdentifier};
|
||||||
use crate::static_data::{Item, Statistic};
|
use crate::static_data::{Item, Statistic};
|
||||||
use crate::StringKey;
|
use crate::StringKey;
|
||||||
|
|
||||||
|
@ -105,7 +105,14 @@ pub trait Script: Send + Sync {
|
||||||
/// move, which include the scripts that are attached to the owner of the script.
|
/// move, which include the scripts that are attached to the owner of the script.
|
||||||
fn on_move_miss(&self, _move: &ExecutingMove, _target: &Arc<Pokemon>) {}
|
fn on_move_miss(&self, _move: &ExecutingMove, _target: &Arc<Pokemon>) {}
|
||||||
/// This function allows the script to change the actual type that is used for the move on a target.
|
/// This function allows the script to change the actual type that is used for the move on a target.
|
||||||
fn change_move_type(&self, _move: &ExecutingMove, _target: &Arc<Pokemon>, _hit: u8, _move_type: &mut u8) {}
|
fn change_move_type(
|
||||||
|
&self,
|
||||||
|
_move: &ExecutingMove,
|
||||||
|
_target: &Arc<Pokemon>,
|
||||||
|
_hit: u8,
|
||||||
|
_move_type: &mut TypeIdentifier,
|
||||||
|
) {
|
||||||
|
}
|
||||||
/// This function allows the script to change how effective a move is on a target.
|
/// This function allows the script to change how effective a move is on a target.
|
||||||
fn change_effectiveness(&self, _move: &ExecutingMove, _target: &Arc<Pokemon>, _hit: u8, _effectiveness: &mut f32) {}
|
fn change_effectiveness(&self, _move: &ExecutingMove, _target: &Arc<Pokemon>, _hit: u8, _effectiveness: &mut f32) {}
|
||||||
/// This function allows a script to block an outgoing move from being critical.
|
/// This function allows a script to block an outgoing move from being critical.
|
||||||
|
|
|
@ -1,16 +1,23 @@
|
||||||
use crate::dynamic_data::script_handling::script::{Script, ScriptContainer};
|
|
||||||
use crate::{PkmnResult, StringKey};
|
|
||||||
use indexmap::IndexMap;
|
|
||||||
use parking_lot::RwLock;
|
|
||||||
use std::ops::Deref;
|
use std::ops::Deref;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
use indexmap::IndexMap;
|
||||||
|
use parking_lot::RwLock;
|
||||||
|
|
||||||
|
use crate::dynamic_data::script_handling::script::{Script, ScriptContainer};
|
||||||
|
use crate::{PkmnResult, StringKey};
|
||||||
|
|
||||||
|
/// A collection of unique scripts.
|
||||||
#[derive(Debug, Default)]
|
#[derive(Debug, Default)]
|
||||||
pub struct ScriptSet {
|
pub struct ScriptSet {
|
||||||
|
/// The scripts collection. This is an indexmap so we can iterate over them and always get the
|
||||||
|
/// scripts in the same order., while still allowing fast lookup.
|
||||||
scripts: RwLock<IndexMap<StringKey, ScriptContainer>>,
|
scripts: RwLock<IndexMap<StringKey, ScriptContainer>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ScriptSet {
|
impl ScriptSet {
|
||||||
|
/// Adds a script to the set. If the script with that name already exists in this set, this
|
||||||
|
/// makes that script stack instead. The return value here is that script.
|
||||||
pub fn add(&self, script: Arc<dyn Script>) -> ScriptContainer {
|
pub fn add(&self, script: Arc<dyn Script>) -> ScriptContainer {
|
||||||
if let Some(lock) = self.scripts.read().get(script.name()) {
|
if let Some(lock) = self.scripts.read().get(script.name()) {
|
||||||
if let Some(existing) = lock.get() {
|
if let Some(existing) = lock.get() {
|
||||||
|
@ -27,6 +34,8 @@ impl ScriptSet {
|
||||||
self.scripts.read().last().unwrap().1.clone()
|
self.scripts.read().last().unwrap().1.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Adds a script with a name to the set. If the script with that name already exists in this
|
||||||
|
/// set, this makes that script stack instead. The return value here is that script.
|
||||||
pub fn stack_or_add<'b, F>(&self, key: &StringKey, instantiation: &'b F) -> PkmnResult<Option<ScriptContainer>>
|
pub fn stack_or_add<'b, F>(&self, key: &StringKey, instantiation: &'b F) -> PkmnResult<Option<ScriptContainer>>
|
||||||
where
|
where
|
||||||
F: Fn() -> PkmnResult<Option<Arc<dyn Script>>>,
|
F: Fn() -> PkmnResult<Option<Arc<dyn Script>>>,
|
||||||
|
@ -51,10 +60,12 @@ impl ScriptSet {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Gets a script from the set using its unique name.
|
||||||
pub fn get(&self, key: &StringKey) -> Option<ScriptContainer> {
|
pub fn get(&self, key: &StringKey) -> Option<ScriptContainer> {
|
||||||
self.scripts.read().get(key).cloned()
|
self.scripts.read().get(key).cloned()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Removes a script from the set using its unique name.
|
||||||
pub fn remove(&self, key: &StringKey) {
|
pub fn remove(&self, key: &StringKey) {
|
||||||
let value = self.scripts.write().shift_remove(key);
|
let value = self.scripts.write().shift_remove(key);
|
||||||
if let Some(script) = value {
|
if let Some(script) = value {
|
||||||
|
@ -66,6 +77,7 @@ impl ScriptSet {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Clears all scripts from the set.
|
||||||
pub fn clear(&self) {
|
pub fn clear(&self) {
|
||||||
for script in self.scripts.read().deref() {
|
for script in self.scripts.read().deref() {
|
||||||
if let Some(script) = script.1.get() {
|
if let Some(script) = script.1.get() {
|
||||||
|
@ -77,18 +89,24 @@ impl ScriptSet {
|
||||||
self.scripts.write().clear();
|
self.scripts.write().clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Checks if the set has a script with the given name.
|
||||||
pub fn has(&self, key: &StringKey) -> bool {
|
pub fn has(&self, key: &StringKey) -> bool {
|
||||||
self.scripts.read().contains_key(key)
|
self.scripts.read().contains_key(key)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Gets a script from the set at a specific index.
|
||||||
pub fn at(&self, index: usize) -> ScriptContainer {
|
pub fn at(&self, index: usize) -> ScriptContainer {
|
||||||
self.scripts.read()[index].clone()
|
self.scripts.read()[index].clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Gets the number of scripts in the set.
|
||||||
pub fn count(&self) -> usize {
|
pub fn count(&self) -> usize {
|
||||||
self.scripts.read().len()
|
self.scripts.read().len()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get a vector of the scripts in this set. This copies the current scripts into a Vec, and
|
||||||
|
/// returns that. This allows modifying the scripts in the set, while still being able to iterate
|
||||||
|
/// over them.
|
||||||
pub(crate) fn get_owning_iterator(&self) -> Vec<ScriptContainer> {
|
pub(crate) fn get_owning_iterator(&self) -> Vec<ScriptContainer> {
|
||||||
let s = self.scripts.read();
|
let s = self.scripts.read();
|
||||||
let mut v = Vec::with_capacity(s.deref().len());
|
let mut v = Vec::with_capacity(s.deref().len());
|
||||||
|
|
|
@ -1,25 +1,33 @@
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
use crate::dynamic_data::script_handling::script::{Script, ScriptContainer};
|
use crate::dynamic_data::script_handling::script::{Script, ScriptContainer};
|
||||||
use crate::dynamic_data::script_handling::script_set::ScriptSet;
|
use crate::dynamic_data::script_handling::script_set::ScriptSet;
|
||||||
use crate::{PkmnResult, StringKey};
|
use crate::{PkmnResult, StringKey};
|
||||||
use std::sync::Arc;
|
|
||||||
|
|
||||||
pub trait VolatileScripts<'a> {
|
/// This trait adds a bunch of helper functions to deal with volatile scripts on a struct.
|
||||||
|
pub trait VolatileScriptsOwner<'a> {
|
||||||
|
/// Return the [`ScriptSet`] that are our volatile scripts.
|
||||||
fn volatile_scripts(&self) -> &Arc<ScriptSet>;
|
fn volatile_scripts(&self) -> &Arc<ScriptSet>;
|
||||||
|
/// Loads a volatile script by name.
|
||||||
fn load_volatile_script(&self, key: &StringKey) -> PkmnResult<Option<Arc<dyn Script>>>;
|
fn load_volatile_script(&self, key: &StringKey) -> PkmnResult<Option<Arc<dyn Script>>>;
|
||||||
|
|
||||||
|
/// Check if a volatile script with given name exists.
|
||||||
fn has_volatile_script(&self, key: &StringKey) -> bool {
|
fn has_volatile_script(&self, key: &StringKey) -> bool {
|
||||||
self.volatile_scripts().has(key)
|
self.volatile_scripts().has(key)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Gets a volatile script by name.
|
||||||
fn get_volatile_script(&self, key: &StringKey) -> Option<ScriptContainer> {
|
fn get_volatile_script(&self, key: &StringKey) -> Option<ScriptContainer> {
|
||||||
self.volatile_scripts().get(key)
|
self.volatile_scripts().get(key)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Adds a volatile script by name.
|
||||||
fn add_volatile_script(&mut self, key: &StringKey) -> PkmnResult<Option<ScriptContainer>> {
|
fn add_volatile_script(&mut self, key: &StringKey) -> PkmnResult<Option<ScriptContainer>> {
|
||||||
self.volatile_scripts()
|
self.volatile_scripts()
|
||||||
.stack_or_add(key, &|| self.load_volatile_script(key))
|
.stack_or_add(key, &|| self.load_volatile_script(key))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Removes a volatile script by name.
|
||||||
fn remove_volatile_script(&mut self, key: &StringKey) {
|
fn remove_volatile_script(&mut self, key: &StringKey) {
|
||||||
self.volatile_scripts().remove(key)
|
self.volatile_scripts().remove(key)
|
||||||
}
|
}
|
|
@ -1,15 +1,21 @@
|
||||||
use crate::defines::LevelInt;
|
use crate::defines::LevelInt;
|
||||||
|
|
||||||
|
/// A growth rate defines how much experience is required per level.
|
||||||
pub trait GrowthRate {
|
pub trait GrowthRate {
|
||||||
|
/// Calculate the level something with this growth rate would have at a certain experience.
|
||||||
fn calculate_level(&self, experience: u32) -> LevelInt;
|
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;
|
fn calculate_experience(&self, level: LevelInt) -> u32;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// An implementation of the growth rate that uses a lookup table for experience.
|
||||||
pub struct LookupGrowthRate {
|
pub struct LookupGrowthRate {
|
||||||
|
/// The lookup Vec.
|
||||||
experience: Vec<u32>,
|
experience: Vec<u32>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl LookupGrowthRate {
|
impl LookupGrowthRate {
|
||||||
|
/// Instantiates a new lookup growth rate.
|
||||||
pub fn new(experience: Vec<u32>) -> LookupGrowthRate {
|
pub fn new(experience: Vec<u32>) -> LookupGrowthRate {
|
||||||
LookupGrowthRate { experience }
|
LookupGrowthRate { experience }
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,41 +4,63 @@ use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::StringKey;
|
use crate::StringKey;
|
||||||
|
|
||||||
|
/// An item category defines which bag slot items are stored in.
|
||||||
#[derive(Debug, Copy, Clone)]
|
#[derive(Debug, Copy, Clone)]
|
||||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||||
#[repr(u8)]
|
#[repr(u8)]
|
||||||
pub enum ItemCategory {
|
pub enum ItemCategory {
|
||||||
|
/// This is where most items should go.
|
||||||
MiscItem,
|
MiscItem,
|
||||||
|
/// Pokeballs are used for capturing Pokemons.
|
||||||
Pokeball,
|
Pokeball,
|
||||||
|
/// Medicine is used for healing HP, PP, and status effects
|
||||||
Medicine,
|
Medicine,
|
||||||
|
/// Berry is used for all berries.
|
||||||
Berry,
|
Berry,
|
||||||
|
/// TMHM is used for Technical and Hidden Machines.
|
||||||
TMHM,
|
TMHM,
|
||||||
|
/// Form Changer is used for items that change forms, such as mega stones.
|
||||||
FormChanger,
|
FormChanger,
|
||||||
|
/// Key Items are single stored items, generally used for story progression.
|
||||||
KeyItem,
|
KeyItem,
|
||||||
|
/// Mail is used for mail items.
|
||||||
Mail,
|
Mail,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A battle item category defines how the item is categorized when in battle.
|
||||||
#[derive(Debug, Copy, Clone)]
|
#[derive(Debug, Copy, Clone)]
|
||||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||||
#[repr(u8)]
|
#[repr(u8)]
|
||||||
pub enum BattleItemCategory {
|
pub enum BattleItemCategory {
|
||||||
|
/// This item can't be used in battle.
|
||||||
None,
|
None,
|
||||||
|
/// This item is used for healing Pokemon.
|
||||||
Healing,
|
Healing,
|
||||||
|
/// This item is used for healing Pokemon from a status.
|
||||||
StatusHealing,
|
StatusHealing,
|
||||||
|
/// This item is used for capturing Pokemon.
|
||||||
Pokeball,
|
Pokeball,
|
||||||
|
/// This item does not belong in above categories, but is still a battle item.
|
||||||
MiscBattleItem,
|
MiscBattleItem,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// An item is an object which the player can pick up, keep in their Bag, and use in some manner
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Item {
|
pub struct Item {
|
||||||
|
/// The name of the item.
|
||||||
name: StringKey,
|
name: StringKey,
|
||||||
|
/// Which bag slot items are stored in.
|
||||||
category: ItemCategory,
|
category: ItemCategory,
|
||||||
|
/// How the item is categorized when in battle.
|
||||||
battle_category: BattleItemCategory,
|
battle_category: BattleItemCategory,
|
||||||
|
/// The buying value of the item.
|
||||||
price: i32,
|
price: i32,
|
||||||
|
/// A set of arbitrary flags that can be set on the item.
|
||||||
flags: HashSet<StringKey>,
|
flags: HashSet<StringKey>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Item {
|
impl Item {
|
||||||
|
/// Instantiates an item.
|
||||||
pub fn new(
|
pub fn new(
|
||||||
name: &StringKey,
|
name: &StringKey,
|
||||||
category: ItemCategory,
|
category: ItemCategory,
|
||||||
|
@ -55,22 +77,28 @@ impl Item {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The name of the item.
|
||||||
pub fn name(&self) -> &StringKey {
|
pub fn name(&self) -> &StringKey {
|
||||||
&self.name
|
&self.name
|
||||||
}
|
}
|
||||||
|
/// Which bag slot items are stored in.
|
||||||
pub fn category(&self) -> ItemCategory {
|
pub fn category(&self) -> ItemCategory {
|
||||||
self.category
|
self.category
|
||||||
}
|
}
|
||||||
|
/// How the item is categorized when in battle.
|
||||||
pub fn battle_category(&self) -> BattleItemCategory {
|
pub fn battle_category(&self) -> BattleItemCategory {
|
||||||
self.battle_category
|
self.battle_category
|
||||||
}
|
}
|
||||||
|
/// The buying value of the item.
|
||||||
pub fn price(&self) -> i32 {
|
pub fn price(&self) -> i32 {
|
||||||
self.price
|
self.price
|
||||||
}
|
}
|
||||||
|
/// A set of arbitrary flags that can be set on the item.
|
||||||
pub fn flags(&self) -> &HashSet<StringKey> {
|
pub fn flags(&self) -> &HashSet<StringKey> {
|
||||||
&self.flags
|
&self.flags
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Checks whether the item has a specific flag.
|
||||||
pub fn has_flag(&self, key: &StringKey) -> bool {
|
pub fn has_flag(&self, key: &StringKey) -> bool {
|
||||||
self.flags.contains(key)
|
self.flags.contains(key)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,35 +1,31 @@
|
||||||
use hashbrown::HashMap;
|
use indexmap::IndexMap;
|
||||||
|
|
||||||
use crate::static_data::Ability;
|
use crate::static_data::Ability;
|
||||||
use crate::static_data::DataLibrary;
|
use crate::static_data::DataLibrary;
|
||||||
use crate::StringKey;
|
use crate::StringKey;
|
||||||
|
|
||||||
|
/// A storage for all abilities that can be used in this data library.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct AbilityLibrary {
|
pub struct AbilityLibrary {
|
||||||
map: HashMap<StringKey, Box<Ability>>,
|
/// The underlying map for the library.
|
||||||
list: Vec<StringKey>,
|
map: IndexMap<StringKey, Box<Ability>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AbilityLibrary {
|
impl AbilityLibrary {
|
||||||
|
/// Instantiates a new ability library.
|
||||||
pub fn new(capacity: usize) -> AbilityLibrary {
|
pub fn new(capacity: usize) -> AbilityLibrary {
|
||||||
AbilityLibrary {
|
AbilityLibrary {
|
||||||
map: HashMap::with_capacity(capacity),
|
map: IndexMap::with_capacity(capacity),
|
||||||
list: Vec::with_capacity(capacity),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DataLibrary<'_, Box<Ability>> for AbilityLibrary {
|
impl DataLibrary<'_, Box<Ability>> for AbilityLibrary {
|
||||||
fn map(&self) -> &HashMap<StringKey, Box<Ability>> {
|
fn map(&self) -> &IndexMap<StringKey, Box<Ability>> {
|
||||||
&self.map
|
&self.map
|
||||||
}
|
}
|
||||||
|
fn get_modify(&mut self) -> &mut IndexMap<StringKey, Box<Ability>> {
|
||||||
fn list_values(&self) -> &Vec<StringKey> {
|
&mut self.map
|
||||||
&self.list
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_modify(&mut self) -> (&mut HashMap<StringKey, Box<Ability>>, &mut Vec<StringKey>) {
|
|
||||||
(&mut self.map, &mut self.list)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -62,17 +58,8 @@ pub mod tests {
|
||||||
#[test]
|
#[test]
|
||||||
fn get_ability_library_direct_map_access() {
|
fn get_ability_library_direct_map_access() {
|
||||||
let lib = build();
|
let lib = build();
|
||||||
let map = lib.map();
|
let ability = lib.get(&"test_ability".into());
|
||||||
let ability = map.get(&"test_ability".into());
|
|
||||||
assert!(ability.is_some());
|
assert!(ability.is_some());
|
||||||
assert_eq!(ability.unwrap().name(), &"test_ability".into());
|
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::Random;
|
||||||
use crate::StringKey;
|
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> {
|
pub trait DataLibrary<'a, T: 'a> {
|
||||||
fn map(&self) -> &HashMap<StringKey, T>;
|
/// Returns the underlying map.
|
||||||
fn list_values(&self) -> &Vec<StringKey>;
|
fn map(&self) -> &IndexMap<StringKey, T>;
|
||||||
fn get_modify(&mut self) -> (&mut HashMap<StringKey, T>, &mut Vec<StringKey>);
|
/// 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) {
|
fn add(&mut self, key: &StringKey, value: T) {
|
||||||
let modifies = self.get_modify();
|
self.get_modify().insert(key.clone(), value);
|
||||||
modifies.0.insert(key.clone(), value);
|
|
||||||
modifies.1.push(key.clone());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Removes a value from the library.
|
||||||
fn remove(&mut self, key: &StringKey) {
|
fn remove(&mut self, key: &StringKey) {
|
||||||
let modifies = self.get_modify();
|
self.get_modify().remove(key);
|
||||||
let index = modifies.1.iter().position(|r| r == key).unwrap();
|
|
||||||
modifies.0.remove(key);
|
|
||||||
modifies.1.remove(index);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Gets a value from the library.
|
||||||
fn get(&'a self, key: &StringKey) -> Option<&'a T> {
|
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> {
|
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 {
|
fn len(&self) -> usize {
|
||||||
self.map().len()
|
self.map().len()
|
||||||
}
|
}
|
||||||
|
/// Returns whether the library has no values.
|
||||||
fn is_empty(&self) -> bool {
|
fn is_empty(&self) -> bool {
|
||||||
self.map().is_empty()
|
self.map().is_empty()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Gets a random value from the library.
|
||||||
fn random_value(&self, rand: &mut Random) -> &T {
|
fn random_value(&self, rand: &mut Random) -> &T {
|
||||||
let i = rand.get_between(0, self.list_values().len() as i32);
|
let i = rand.get_between(0, self.len() as i32);
|
||||||
let key = &self.list_values()[i as usize];
|
return &self.map().get_index(i as usize).unwrap().1;
|
||||||
return &self.map()[key];
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,23 +7,30 @@ use crate::defines::LevelInt;
|
||||||
use crate::static_data::GrowthRate;
|
use crate::static_data::GrowthRate;
|
||||||
use crate::StringKey;
|
use crate::StringKey;
|
||||||
|
|
||||||
|
/// A library to store all growth rates.
|
||||||
pub struct GrowthRateLibrary {
|
pub struct GrowthRateLibrary {
|
||||||
|
/// The underlying data structure.
|
||||||
growth_rates: HashMap<StringKey, Box<dyn GrowthRate>>,
|
growth_rates: HashMap<StringKey, Box<dyn GrowthRate>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl GrowthRateLibrary {
|
impl GrowthRateLibrary {
|
||||||
|
/// Instantiates a new growth rate library with a capacity.
|
||||||
pub fn new(capacity: usize) -> GrowthRateLibrary {
|
pub fn new(capacity: usize) -> GrowthRateLibrary {
|
||||||
GrowthRateLibrary {
|
GrowthRateLibrary {
|
||||||
growth_rates: HashMap::with_capacity(capacity),
|
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 {
|
pub fn calculate_level(&self, growth_rate: &StringKey, experience: u32) -> LevelInt {
|
||||||
self.growth_rates[growth_rate].calculate_level(experience)
|
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 {
|
pub fn calculate_experience(&self, growth_rate: &StringKey, level: LevelInt) -> u32 {
|
||||||
self.growth_rates[growth_rate].calculate_experience(level)
|
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>) {
|
pub fn add_growth_rate(&mut self, key: &StringKey, value: Box<dyn GrowthRate>) {
|
||||||
self.growth_rates.insert(key.clone(), value);
|
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::DataLibrary;
|
||||||
use crate::static_data::Item;
|
use crate::static_data::Item;
|
||||||
use crate::StringKey;
|
use crate::StringKey;
|
||||||
|
|
||||||
|
/// A library to store all items.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct ItemLibrary {
|
pub struct ItemLibrary {
|
||||||
map: HashMap<StringKey, Box<Item>>,
|
/// The underlying data structure.
|
||||||
list: Vec<StringKey>,
|
map: IndexMap<StringKey, Box<Item>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ItemLibrary {
|
impl ItemLibrary {
|
||||||
|
/// Instantiates a new Item Library.
|
||||||
pub fn new(capacity: usize) -> ItemLibrary {
|
pub fn new(capacity: usize) -> ItemLibrary {
|
||||||
ItemLibrary {
|
ItemLibrary {
|
||||||
map: HashMap::with_capacity(capacity),
|
map: IndexMap::with_capacity(capacity),
|
||||||
list: Vec::with_capacity(capacity),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DataLibrary<'_, Box<Item>> for ItemLibrary {
|
impl DataLibrary<'_, Box<Item>> for ItemLibrary {
|
||||||
fn map(&self) -> &HashMap<StringKey, Box<Item>> {
|
fn map(&self) -> &IndexMap<StringKey, Box<Item>> {
|
||||||
&self.map
|
&self.map
|
||||||
}
|
}
|
||||||
|
|
||||||
fn list_values(&self) -> &Vec<StringKey> {
|
fn get_modify(&mut self) -> &mut IndexMap<StringKey, Box<Item>> {
|
||||||
&self.list
|
&mut self.map
|
||||||
}
|
|
||||||
|
|
||||||
fn get_modify(&mut self) -> (&mut HashMap<StringKey, Box<Item>>, &mut Vec<StringKey>) {
|
|
||||||
(&mut self.map, &mut self.list)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,15 +1,19 @@
|
||||||
use crate::defines::LevelInt;
|
use crate::defines::LevelInt;
|
||||||
|
|
||||||
|
/// This library holds several misc settings for the library.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct LibrarySettings {
|
pub struct LibrarySettings {
|
||||||
|
/// The highest level a Pokemon can be.
|
||||||
maximum_level: LevelInt,
|
maximum_level: LevelInt,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl LibrarySettings {
|
impl LibrarySettings {
|
||||||
|
/// Creates a new settings library.
|
||||||
pub fn new(maximum_level: LevelInt) -> Self {
|
pub fn new(maximum_level: LevelInt) -> Self {
|
||||||
Self { maximum_level }
|
Self { maximum_level }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The highest level a Pokemon can be.
|
||||||
pub fn maximum_level(&self) -> LevelInt {
|
pub fn maximum_level(&self) -> LevelInt {
|
||||||
self.maximum_level
|
self.maximum_level
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,7 +15,7 @@ pub use species_library::SpeciesLibrary;
|
||||||
#[doc(inline)]
|
#[doc(inline)]
|
||||||
pub use static_data::StaticData;
|
pub use static_data::StaticData;
|
||||||
#[doc(inline)]
|
#[doc(inline)]
|
||||||
pub use type_library::TypeLibrary;
|
pub use type_library::*;
|
||||||
|
|
||||||
mod ability_library;
|
mod ability_library;
|
||||||
mod data_library;
|
mod data_library;
|
||||||
|
|
|
@ -1,35 +1,31 @@
|
||||||
use hashbrown::HashMap;
|
use indexmap::IndexMap;
|
||||||
|
|
||||||
use crate::static_data::DataLibrary;
|
use crate::static_data::DataLibrary;
|
||||||
use crate::static_data::MoveData;
|
use crate::static_data::MoveData;
|
||||||
use crate::StringKey;
|
use crate::StringKey;
|
||||||
|
|
||||||
|
/// A library to store all data for moves.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct MoveLibrary {
|
pub struct MoveLibrary {
|
||||||
map: HashMap<StringKey, MoveData>,
|
/// The underlying map.
|
||||||
list: Vec<StringKey>,
|
map: IndexMap<StringKey, MoveData>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MoveLibrary {
|
impl MoveLibrary {
|
||||||
|
/// Instantiates a new Move Library.
|
||||||
pub fn new(capacity: usize) -> MoveLibrary {
|
pub fn new(capacity: usize) -> MoveLibrary {
|
||||||
MoveLibrary {
|
MoveLibrary {
|
||||||
map: HashMap::with_capacity(capacity),
|
map: IndexMap::with_capacity(capacity),
|
||||||
list: Vec::with_capacity(capacity),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DataLibrary<'_, MoveData> for MoveLibrary {
|
impl DataLibrary<'_, MoveData> for MoveLibrary {
|
||||||
fn map(&self) -> &HashMap<StringKey, MoveData> {
|
fn map(&self) -> &IndexMap<StringKey, MoveData> {
|
||||||
&self.map
|
&self.map
|
||||||
}
|
}
|
||||||
|
fn get_modify(&mut self) -> &mut IndexMap<StringKey, MoveData> {
|
||||||
fn list_values(&self) -> &Vec<StringKey> {
|
&mut self.map
|
||||||
&self.list
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_modify(&mut self) -> (&mut HashMap<StringKey, MoveData>, &mut Vec<StringKey>) {
|
|
||||||
(&mut self.map, &mut self.list)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -45,7 +41,7 @@ pub mod tests {
|
||||||
fn build_move() -> MoveData {
|
fn build_move() -> MoveData {
|
||||||
MoveData::new(
|
MoveData::new(
|
||||||
&"foo".into(),
|
&"foo".into(),
|
||||||
0,
|
0.into(),
|
||||||
MoveCategory::Physical,
|
MoveCategory::Physical,
|
||||||
100,
|
100,
|
||||||
100,
|
100,
|
||||||
|
|
|
@ -1,35 +1,31 @@
|
||||||
use hashbrown::HashMap;
|
use indexmap::IndexMap;
|
||||||
|
|
||||||
use crate::static_data::DataLibrary;
|
use crate::static_data::DataLibrary;
|
||||||
use crate::static_data::Species;
|
use crate::static_data::Species;
|
||||||
use crate::StringKey;
|
use crate::StringKey;
|
||||||
|
|
||||||
|
/// A library to store all data for Pokemon species.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct SpeciesLibrary {
|
pub struct SpeciesLibrary {
|
||||||
map: HashMap<StringKey, Box<Species>>,
|
/// The underlying map.
|
||||||
list: Vec<StringKey>,
|
map: IndexMap<StringKey, Box<Species>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SpeciesLibrary {
|
impl SpeciesLibrary {
|
||||||
|
/// Instantiates a new Species Library.
|
||||||
pub fn new(capacity: usize) -> SpeciesLibrary {
|
pub fn new(capacity: usize) -> SpeciesLibrary {
|
||||||
SpeciesLibrary {
|
SpeciesLibrary {
|
||||||
map: HashMap::with_capacity(capacity),
|
map: IndexMap::with_capacity(capacity),
|
||||||
list: Vec::with_capacity(capacity),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> DataLibrary<'a, Box<Species>> for SpeciesLibrary {
|
impl<'a> DataLibrary<'a, Box<Species>> for SpeciesLibrary {
|
||||||
fn map(&self) -> &HashMap<StringKey, Box<Species>> {
|
fn map(&self) -> &IndexMap<StringKey, Box<Species>> {
|
||||||
&self.map
|
&self.map
|
||||||
}
|
}
|
||||||
|
fn get_modify(&mut self) -> &mut IndexMap<StringKey, Box<Species>> {
|
||||||
fn list_values(&self) -> &Vec<StringKey> {
|
&mut self.map
|
||||||
&self.list
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_modify(&mut self) -> (&mut HashMap<StringKey, Box<Species>>, &mut Vec<StringKey>) {
|
|
||||||
(&mut self.map, &mut self.list)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,19 +7,29 @@ use crate::static_data::NatureLibrary;
|
||||||
use crate::static_data::SpeciesLibrary;
|
use crate::static_data::SpeciesLibrary;
|
||||||
use crate::static_data::TypeLibrary;
|
use crate::static_data::TypeLibrary;
|
||||||
|
|
||||||
|
/// The storage for all different libraries.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct StaticData {
|
pub struct StaticData {
|
||||||
|
/// Several misc settings for the library.
|
||||||
settings: LibrarySettings,
|
settings: LibrarySettings,
|
||||||
|
/// All data for Pokemon species.
|
||||||
species: SpeciesLibrary,
|
species: SpeciesLibrary,
|
||||||
|
/// All data for the moves.
|
||||||
moves: MoveLibrary,
|
moves: MoveLibrary,
|
||||||
|
/// All data for the items.
|
||||||
items: ItemLibrary,
|
items: ItemLibrary,
|
||||||
|
/// All data for growth rates.
|
||||||
growth_rates: GrowthRateLibrary,
|
growth_rates: GrowthRateLibrary,
|
||||||
|
/// All data related to types and type effectiveness.
|
||||||
types: TypeLibrary,
|
types: TypeLibrary,
|
||||||
|
/// All data related to natures.
|
||||||
natures: NatureLibrary,
|
natures: NatureLibrary,
|
||||||
|
/// All data related to abilities.
|
||||||
abilities: AbilityLibrary,
|
abilities: AbilityLibrary,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl StaticData {
|
impl StaticData {
|
||||||
|
/// Instantiates a new data collection.
|
||||||
pub fn new(settings: LibrarySettings) -> Self {
|
pub fn new(settings: LibrarySettings) -> Self {
|
||||||
Self {
|
Self {
|
||||||
settings,
|
settings,
|
||||||
|
@ -32,50 +42,64 @@ impl StaticData {
|
||||||
abilities: AbilityLibrary::new(0),
|
abilities: AbilityLibrary::new(0),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
/// Several misc settings for the library.
|
||||||
pub fn settings(&self) -> &LibrarySettings {
|
pub fn settings(&self) -> &LibrarySettings {
|
||||||
&self.settings
|
&self.settings
|
||||||
}
|
}
|
||||||
|
/// All data for Pokemon species.
|
||||||
pub fn species(&self) -> &SpeciesLibrary {
|
pub fn species(&self) -> &SpeciesLibrary {
|
||||||
&self.species
|
&self.species
|
||||||
}
|
}
|
||||||
|
/// All data for Pokemon species.
|
||||||
pub fn species_mut(&mut self) -> &mut SpeciesLibrary {
|
pub fn species_mut(&mut self) -> &mut SpeciesLibrary {
|
||||||
&mut self.species
|
&mut self.species
|
||||||
}
|
}
|
||||||
|
/// All data for the moves.
|
||||||
pub fn moves(&self) -> &MoveLibrary {
|
pub fn moves(&self) -> &MoveLibrary {
|
||||||
&self.moves
|
&self.moves
|
||||||
}
|
}
|
||||||
|
/// All data for the moves.
|
||||||
pub fn moves_mut(&mut self) -> &mut MoveLibrary {
|
pub fn moves_mut(&mut self) -> &mut MoveLibrary {
|
||||||
&mut self.moves
|
&mut self.moves
|
||||||
}
|
}
|
||||||
|
/// All data for the items.
|
||||||
pub fn items(&self) -> &ItemLibrary {
|
pub fn items(&self) -> &ItemLibrary {
|
||||||
&self.items
|
&self.items
|
||||||
}
|
}
|
||||||
|
/// All data for the items.
|
||||||
pub fn items_mut(&mut self) -> &mut ItemLibrary {
|
pub fn items_mut(&mut self) -> &mut ItemLibrary {
|
||||||
&mut self.items
|
&mut self.items
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// All data for growth rates.
|
||||||
pub fn growth_rates(&self) -> &GrowthRateLibrary {
|
pub fn growth_rates(&self) -> &GrowthRateLibrary {
|
||||||
&self.growth_rates
|
&self.growth_rates
|
||||||
}
|
}
|
||||||
|
/// All data for growth rates.
|
||||||
pub fn growth_rates_mut(&mut self) -> &mut GrowthRateLibrary {
|
pub fn growth_rates_mut(&mut self) -> &mut GrowthRateLibrary {
|
||||||
&mut self.growth_rates
|
&mut self.growth_rates
|
||||||
}
|
}
|
||||||
|
/// All data related to types and type effectiveness.
|
||||||
pub fn types(&self) -> &TypeLibrary {
|
pub fn types(&self) -> &TypeLibrary {
|
||||||
&self.types
|
&self.types
|
||||||
}
|
}
|
||||||
|
/// All data related to types and type effectiveness.
|
||||||
pub fn types_mut(&mut self) -> &mut TypeLibrary {
|
pub fn types_mut(&mut self) -> &mut TypeLibrary {
|
||||||
&mut self.types
|
&mut self.types
|
||||||
}
|
}
|
||||||
|
/// All data related to natures.
|
||||||
pub fn natures(&self) -> &NatureLibrary {
|
pub fn natures(&self) -> &NatureLibrary {
|
||||||
&self.natures
|
&self.natures
|
||||||
}
|
}
|
||||||
|
/// All data related to natures.
|
||||||
pub fn natures_mut(&mut self) -> &mut NatureLibrary {
|
pub fn natures_mut(&mut self) -> &mut NatureLibrary {
|
||||||
&mut self.natures
|
&mut self.natures
|
||||||
}
|
}
|
||||||
|
/// All data related to abilities.
|
||||||
pub fn abilities(&self) -> &AbilityLibrary {
|
pub fn abilities(&self) -> &AbilityLibrary {
|
||||||
&self.abilities
|
&self.abilities
|
||||||
}
|
}
|
||||||
|
/// All data related to abilities.
|
||||||
pub fn abilities_mut(&mut self) -> &mut AbilityLibrary {
|
pub fn abilities_mut(&mut self) -> &mut AbilityLibrary {
|
||||||
&mut self.abilities
|
&mut self.abilities
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,13 +1,32 @@
|
||||||
use crate::StringKey;
|
|
||||||
use hashbrown::HashMap;
|
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)]
|
#[derive(Debug)]
|
||||||
pub struct TypeLibrary {
|
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>>,
|
effectiveness: Vec<Vec<f32>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TypeLibrary {
|
impl TypeLibrary {
|
||||||
|
/// Instantiates a new type library with a specific capacity.
|
||||||
pub fn new(capacity: usize) -> TypeLibrary {
|
pub fn new(capacity: usize) -> TypeLibrary {
|
||||||
TypeLibrary {
|
TypeLibrary {
|
||||||
types: HashMap::with_capacity(capacity),
|
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]
|
self.types[key]
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_single_effectiveness(&self, attacking: u8, defending: u8) -> f32 {
|
/// Gets the effectiveness for a single attacking type against a single defending type.
|
||||||
self.effectiveness[attacking as usize][defending as usize]
|
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;
|
let mut e = 1.0;
|
||||||
for def in defending {
|
for def in defending {
|
||||||
e *= self.get_single_effectiveness(attacking, *def);
|
e *= self.get_single_effectiveness(attacking, *def);
|
||||||
|
@ -31,37 +55,42 @@ impl TypeLibrary {
|
||||||
e
|
e
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn register_type(&mut self, name: &StringKey) -> u8 {
|
/// Registers a new type in the library.
|
||||||
let id = self.types.len() as u8;
|
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.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 {
|
for effectiveness in &mut self.effectiveness {
|
||||||
effectiveness.resize((id + 1) as usize, 1.0)
|
effectiveness.resize((id.val + 1) as usize, 1.0)
|
||||||
}
|
}
|
||||||
id
|
id
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_effectiveness(&mut self, attacking: u8, defending: u8, effectiveness: f32) {
|
/// Sets the effectiveness for an attacking type against a defending type.
|
||||||
self.effectiveness[attacking as usize][defending as usize] = effectiveness;
|
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)]
|
#[cfg(test)]
|
||||||
pub mod tests {
|
pub mod tests {
|
||||||
use crate::static_data::libraries::type_library::TypeLibrary;
|
|
||||||
use assert_approx_eq::assert_approx_eq;
|
use assert_approx_eq::assert_approx_eq;
|
||||||
|
|
||||||
|
use crate::static_data::libraries::type_library::TypeLibrary;
|
||||||
|
|
||||||
pub fn build() -> TypeLibrary {
|
pub fn build() -> TypeLibrary {
|
||||||
let mut lib = TypeLibrary::new(2);
|
let mut lib = TypeLibrary::new(2);
|
||||||
|
|
||||||
// Borrow as mut so we can insert
|
// Borrow as mut so we can insert
|
||||||
let w = &mut lib;
|
let w = &mut lib;
|
||||||
w.register_type(&"foo".into());
|
let t0 = w.register_type(&"foo".into());
|
||||||
w.register_type(&"bar".into());
|
let t1 = w.register_type(&"bar".into());
|
||||||
// Drops borrow as mut
|
// Drops borrow as mut
|
||||||
|
|
||||||
w.set_effectiveness(0, 1, 0.5);
|
w.set_effectiveness(t0, t1, 0.5);
|
||||||
w.set_effectiveness(1, 0, 2.0);
|
w.set_effectiveness(t1, t0, 2.0);
|
||||||
|
|
||||||
lib
|
lib
|
||||||
}
|
}
|
||||||
|
@ -72,14 +101,14 @@ pub mod tests {
|
||||||
|
|
||||||
// Borrow as mut so we can insert
|
// Borrow as mut so we can insert
|
||||||
let w = &mut lib;
|
let w = &mut lib;
|
||||||
w.register_type(&"foo".into());
|
let t0 = w.register_type(&"foo".into());
|
||||||
w.register_type(&"bar".into());
|
let t1 = w.register_type(&"bar".into());
|
||||||
// Drops borrow as mut
|
// Drops borrow as mut
|
||||||
|
|
||||||
// Borrow as read so we can read
|
// Borrow as read so we can read
|
||||||
let r = &lib;
|
let r = &lib;
|
||||||
assert_eq!(r.get_type_id(&"foo".into()), 0);
|
assert_eq!(r.get_type_id(&"foo".into()), t0);
|
||||||
assert_eq!(r.get_type_id(&"bar".into()), 1);
|
assert_eq!(r.get_type_id(&"bar".into()), t1);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -88,16 +117,16 @@ pub mod tests {
|
||||||
|
|
||||||
// Borrow as mut so we can insert
|
// Borrow as mut so we can insert
|
||||||
let w = &mut lib;
|
let w = &mut lib;
|
||||||
w.register_type(&"foo".into());
|
let t0 = w.register_type(&"foo".into());
|
||||||
w.register_type(&"bar".into());
|
let t1 = w.register_type(&"bar".into());
|
||||||
w.set_effectiveness(0, 1, 0.5);
|
w.set_effectiveness(t0, t1, 0.5);
|
||||||
w.set_effectiveness(1, 0, 2.0);
|
w.set_effectiveness(t1, t0, 2.0);
|
||||||
// Drops borrow as mut
|
// Drops borrow as mut
|
||||||
|
|
||||||
// Borrow as read so we can read
|
// Borrow as read so we can read
|
||||||
let r = &lib;
|
let r = &lib;
|
||||||
assert_approx_eq!(r.get_single_effectiveness(0, 1), 0.5);
|
assert_approx_eq!(r.get_single_effectiveness(t0, t1), 0.5);
|
||||||
assert_approx_eq!(r.get_single_effectiveness(1, 0), 2.0);
|
assert_approx_eq!(r.get_single_effectiveness(t1, t0), 2.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -106,15 +135,15 @@ pub mod tests {
|
||||||
|
|
||||||
// Borrow as mut so we can insert
|
// Borrow as mut so we can insert
|
||||||
let w = &mut lib;
|
let w = &mut lib;
|
||||||
w.register_type(&"foo".into());
|
let t0 = w.register_type(&"foo".into());
|
||||||
w.register_type(&"bar".into());
|
let t1 = w.register_type(&"bar".into());
|
||||||
w.set_effectiveness(0, 1, 0.5);
|
w.set_effectiveness(t0, t1, 0.5);
|
||||||
w.set_effectiveness(1, 0, 2.0);
|
w.set_effectiveness(t1, t0, 2.0);
|
||||||
// Drops borrow as mut
|
// Drops borrow as mut
|
||||||
|
|
||||||
// Borrow as read so we can read
|
// Borrow as read so we can read
|
||||||
let r = &lib;
|
let r = &lib;
|
||||||
assert_approx_eq!(r.get_effectiveness(0, &[1_u8, 1_u8]), 0.25);
|
assert_approx_eq!(r.get_effectiveness(t0, &[t1, t1]), 0.25);
|
||||||
assert_approx_eq!(r.get_effectiveness(1, &[0_u8, 0_u8]), 4.0);
|
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;
|
use hashbrown::HashSet;
|
||||||
|
|
||||||
#[cfg(feature = "serde")]
|
#[cfg(feature = "serde")]
|
||||||
use serde::{Deserialize, Serialize};
|
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)]
|
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
|
||||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||||
#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))]
|
#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))]
|
||||||
pub enum MoveCategory {
|
pub enum MoveCategory {
|
||||||
|
/// A physical move uses the physical attack stats and physical defense stats to calculate damage.
|
||||||
Physical = 0,
|
Physical = 0,
|
||||||
|
/// A special move uses the special attack stats and special defense stats to calculate damage.
|
||||||
Special = 1,
|
Special = 1,
|
||||||
|
/// A status move does not do damage, and only runs a secondary effect.
|
||||||
Status = 2,
|
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))]
|
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||||
pub enum MoveTarget {
|
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,
|
Adjacent = 0,
|
||||||
|
/// AdjacentAlly allows a move to target any Pokemon that is directly to the left or right of
|
||||||
|
/// the user.
|
||||||
AdjacentAlly,
|
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,
|
AdjacentAllySelf,
|
||||||
|
/// AdjacentOpponent allows a move to target any Pokemon that is either the opponent, or directly
|
||||||
|
/// to the left or right of it.
|
||||||
AdjacentOpponent,
|
AdjacentOpponent,
|
||||||
|
|
||||||
|
/// All makes the move target everything on the field.
|
||||||
All,
|
All,
|
||||||
|
/// AllAdjacent makes the move target everything adjacent on the field.
|
||||||
AllAdjacent,
|
AllAdjacent,
|
||||||
|
/// AllAdjacentOpponent makes the move target everything adjacent to the opponent, and the opponent.
|
||||||
AllAdjacentOpponent,
|
AllAdjacentOpponent,
|
||||||
|
/// AllAlly targets all Pokemon on the same side as the user.
|
||||||
AllAlly,
|
AllAlly,
|
||||||
|
/// AllOpponent targets all Pokemon on an opposing side from the user.
|
||||||
AllOpponent,
|
AllOpponent,
|
||||||
|
|
||||||
|
/// Any allows a move to target a single Pokemon, in any position.
|
||||||
Any,
|
Any,
|
||||||
|
|
||||||
|
/// RandomOpponent allows a move to target a single Pokemon, in a random position.
|
||||||
RandomOpponent,
|
RandomOpponent,
|
||||||
|
/// SelfUse makes the move target the user itself.
|
||||||
#[cfg_attr(feature = "serde", serde(rename = "Self"))]
|
#[cfg_attr(feature = "serde", serde(rename = "Self"))]
|
||||||
SelfUse,
|
SelfUse,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A move is the skill Pokémon primarily use in battle. This is the data related to that.
|
||||||
#[derive(PartialEq, Debug)]
|
#[derive(PartialEq, Debug)]
|
||||||
pub struct MoveData {
|
pub struct MoveData {
|
||||||
|
/// The name of the move.
|
||||||
name: StringKey,
|
name: StringKey,
|
||||||
move_type: u8,
|
/// The attacking type of the move.
|
||||||
|
move_type: TypeIdentifier,
|
||||||
|
/// The category of the move.
|
||||||
category: MoveCategory,
|
category: MoveCategory,
|
||||||
|
/// The base power, not considering any modifiers, the move has.
|
||||||
base_power: u8,
|
base_power: u8,
|
||||||
|
/// The accuracy of the move in percentage. Should be 255 for moves that always hit.
|
||||||
accuracy: u8,
|
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,
|
base_usages: u8,
|
||||||
|
/// How the move handles targets.
|
||||||
target: MoveTarget,
|
target: MoveTarget,
|
||||||
|
/// The priority of the move. A higher priority means the move should go before other moves.
|
||||||
priority: i8,
|
priority: i8,
|
||||||
|
/// The optional secondary effect the move has.
|
||||||
secondary_effect: Option<SecondaryEffect>,
|
secondary_effect: Option<SecondaryEffect>,
|
||||||
|
/// Arbitrary flags that can be applied to the move.
|
||||||
flags: HashSet<StringKey>,
|
flags: HashSet<StringKey>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MoveData {
|
impl MoveData {
|
||||||
|
/// Instantiates a new move.
|
||||||
pub fn new(
|
pub fn new(
|
||||||
name: &StringKey,
|
name: &StringKey,
|
||||||
move_type: u8,
|
move_type: TypeIdentifier,
|
||||||
category: MoveCategory,
|
category: MoveCategory,
|
||||||
base_power: u8,
|
base_power: u8,
|
||||||
accuracy: u8,
|
accuracy: u8,
|
||||||
|
@ -75,37 +110,47 @@ impl MoveData {
|
||||||
flags,
|
flags,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
/// The name of the move.
|
||||||
pub fn name(&self) -> &StringKey {
|
pub fn name(&self) -> &StringKey {
|
||||||
&self.name
|
&self.name
|
||||||
}
|
}
|
||||||
pub fn move_type(&self) -> u8 {
|
/// The attacking type of the move.
|
||||||
|
pub fn move_type(&self) -> TypeIdentifier {
|
||||||
self.move_type
|
self.move_type
|
||||||
}
|
}
|
||||||
|
/// The category of the move.
|
||||||
pub fn category(&self) -> MoveCategory {
|
pub fn category(&self) -> MoveCategory {
|
||||||
self.category
|
self.category
|
||||||
}
|
}
|
||||||
|
/// The base power, not considering any modifiers, the move has.
|
||||||
pub fn base_power(&self) -> u8 {
|
pub fn base_power(&self) -> u8 {
|
||||||
self.base_power
|
self.base_power
|
||||||
}
|
}
|
||||||
|
/// The accuracy of the move in percentage. Should be 255 for moves that always hit.
|
||||||
pub fn accuracy(&self) -> u8 {
|
pub fn accuracy(&self) -> u8 {
|
||||||
self.accuracy
|
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 {
|
pub fn base_usages(&self) -> u8 {
|
||||||
self.base_usages
|
self.base_usages
|
||||||
}
|
}
|
||||||
|
/// How the move handles targets.
|
||||||
pub fn target(&self) -> MoveTarget {
|
pub fn target(&self) -> MoveTarget {
|
||||||
self.target
|
self.target
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The priority of the move. A higher priority means the move should go before other moves.
|
||||||
pub fn priority(&self) -> i8 {
|
pub fn priority(&self) -> i8 {
|
||||||
self.priority
|
self.priority
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The optional secondary effect the move has.
|
||||||
pub fn secondary_effect(&self) -> &Option<SecondaryEffect> {
|
pub fn secondary_effect(&self) -> &Option<SecondaryEffect> {
|
||||||
&self.secondary_effect
|
&self.secondary_effect
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Arbitrary flags that can be applied to the move.
|
||||||
pub fn has_flag(&self, key: &StringKey) -> bool {
|
pub fn has_flag(&self, key: &StringKey) -> bool {
|
||||||
self.flags.contains(key)
|
self.flags.contains(key)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,21 +1,32 @@
|
||||||
use crate::StringKey;
|
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)]
|
#[derive(PartialEq, Debug)]
|
||||||
pub enum EffectParameter {
|
pub enum EffectParameter {
|
||||||
|
/// A boolean value.
|
||||||
Bool(bool),
|
Bool(bool),
|
||||||
|
/// An integer value. Stored as a 64 bit int to deal with potentially large numbers.
|
||||||
Int(i64),
|
Int(i64),
|
||||||
|
/// A float value. Stored as a 32 bit float.
|
||||||
Float(f32),
|
Float(f32),
|
||||||
|
/// A string value.
|
||||||
String(String),
|
String(String),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A secondary effect is an effect on a move that happens after it hits.
|
||||||
#[derive(PartialEq, Debug)]
|
#[derive(PartialEq, Debug)]
|
||||||
pub struct SecondaryEffect {
|
pub struct SecondaryEffect {
|
||||||
|
/// The chance in percentages that the effect triggers. -1 to make it always trigger.
|
||||||
chance: f32,
|
chance: f32,
|
||||||
|
/// The name of the effect.
|
||||||
effect_name: StringKey,
|
effect_name: StringKey,
|
||||||
|
/// A list of parameters for the effect.
|
||||||
parameters: Vec<EffectParameter>,
|
parameters: Vec<EffectParameter>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SecondaryEffect {
|
impl SecondaryEffect {
|
||||||
|
/// Instantiates a new Secondary Effect.
|
||||||
pub fn new(chance: f32, effect_name: StringKey, parameters: Vec<EffectParameter>) -> SecondaryEffect {
|
pub fn new(chance: f32, effect_name: StringKey, parameters: Vec<EffectParameter>) -> SecondaryEffect {
|
||||||
SecondaryEffect {
|
SecondaryEffect {
|
||||||
chance,
|
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 {
|
pub fn chance(&self) -> f32 {
|
||||||
self.chance
|
self.chance
|
||||||
}
|
}
|
||||||
|
/// The name of the effect.
|
||||||
pub fn effect_name(&self) -> &StringKey {
|
pub fn effect_name(&self) -> &StringKey {
|
||||||
&self.effect_name
|
&self.effect_name
|
||||||
}
|
}
|
||||||
|
/// A list of parameters for the effect.
|
||||||
pub fn parameters(&self) -> &Vec<EffectParameter> {
|
pub fn parameters(&self) -> &Vec<EffectParameter> {
|
||||||
&self.parameters
|
&self.parameters
|
||||||
}
|
}
|
||||||
|
@ -37,9 +51,10 @@ impl SecondaryEffect {
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use crate::static_data::moves::secondary_effect::SecondaryEffect;
|
|
||||||
use assert_approx_eq::assert_approx_eq;
|
use assert_approx_eq::assert_approx_eq;
|
||||||
|
|
||||||
|
use crate::static_data::moves::secondary_effect::SecondaryEffect;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn create_secondary_effect() {
|
fn create_secondary_effect() {
|
||||||
let empty = SecondaryEffect::new(0.0, "".into(), vec![]);
|
let empty = SecondaryEffect::new(0.0, "".into(), vec![]);
|
||||||
|
|
|
@ -1,16 +1,24 @@
|
||||||
use crate::static_data::Statistic;
|
|
||||||
use crate::StringKey;
|
|
||||||
use hashbrown::HashMap;
|
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)]
|
#[derive(Debug)]
|
||||||
pub struct Nature {
|
pub struct Nature {
|
||||||
|
/// The stat that should receive the increased modifier.
|
||||||
increase_stat: Statistic,
|
increase_stat: Statistic,
|
||||||
|
/// The stat that should receive the decreased modifier.
|
||||||
decrease_stat: Statistic,
|
decrease_stat: Statistic,
|
||||||
|
/// The amount by which the increased stat is multiplied.
|
||||||
increase_modifier: f32,
|
increase_modifier: f32,
|
||||||
|
/// The amount by which the decreased stat is multiplied.
|
||||||
decrease_modifier: f32,
|
decrease_modifier: f32,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Nature {
|
impl Nature {
|
||||||
|
/// Instantiates a new statistic.
|
||||||
pub fn new(
|
pub fn new(
|
||||||
increase_stat: Statistic,
|
increase_stat: Statistic,
|
||||||
decrease_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 {
|
pub fn increased_stat(&self) -> Statistic {
|
||||||
self.increase_stat
|
self.increase_stat
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The stat that should receive the decreased modifier.
|
||||||
pub fn decreased_stat(&self) -> Statistic {
|
pub fn decreased_stat(&self) -> Statistic {
|
||||||
self.decrease_stat
|
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 {
|
pub fn get_stat_modifier(&self, stat: Statistic) -> f32 {
|
||||||
if stat == self.increase_stat {
|
if stat == self.increase_stat {
|
||||||
self.increase_modifier
|
self.increase_modifier
|
||||||
|
@ -44,26 +56,32 @@ impl Nature {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A library of all natures that can be used, stored by their names.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct NatureLibrary {
|
pub struct NatureLibrary {
|
||||||
|
/// The underlying data structure.
|
||||||
map: HashMap<StringKey, Nature>,
|
map: HashMap<StringKey, Nature>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl NatureLibrary {
|
impl NatureLibrary {
|
||||||
|
/// Creates a new nature library with a given capacity.
|
||||||
pub fn new(capacity: usize) -> Self {
|
pub fn new(capacity: usize) -> Self {
|
||||||
NatureLibrary {
|
NatureLibrary {
|
||||||
map: HashMap::with_capacity(capacity),
|
map: HashMap::with_capacity(capacity),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Adds a new nature with name to the library.
|
||||||
pub fn load_nature(&mut self, name: StringKey, nature: Nature) {
|
pub fn load_nature(&mut self, name: StringKey, nature: Nature) {
|
||||||
self.map.insert(name, nature);
|
self.map.insert(name, nature);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Gets a nature by name.
|
||||||
pub fn get_nature(&self, key: &StringKey) -> Option<&Nature> {
|
pub fn get_nature(&self, key: &StringKey) -> Option<&Nature> {
|
||||||
self.map.get(key)
|
self.map.get(key)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Finds a nature name by nature.
|
||||||
pub fn get_nature_name(&self, nature: &Nature) -> StringKey {
|
pub fn get_nature_name(&self, nature: &Nature) -> StringKey {
|
||||||
for kv in &self.map {
|
for kv in &self.map {
|
||||||
// As natures can't be copied, and should always be the same reference as the value
|
// 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::LearnableMoves;
|
||||||
use crate::static_data::Statistic;
|
use crate::static_data::Statistic;
|
||||||
use crate::static_data::{Ability, StaticStatisticSet};
|
use crate::static_data::{Ability, StaticStatisticSet};
|
||||||
|
use crate::static_data::{AbilityIndex, TypeIdentifier};
|
||||||
use crate::Random;
|
use crate::Random;
|
||||||
use crate::StringKey;
|
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)]
|
#[derive(Debug)]
|
||||||
pub struct Form {
|
pub struct Form {
|
||||||
|
/// The name of the form.
|
||||||
name: StringKey,
|
name: StringKey,
|
||||||
|
/// The height of the form in meters.
|
||||||
height: f32,
|
height: f32,
|
||||||
|
/// The weight of the form in kilograms.
|
||||||
weight: f32,
|
weight: f32,
|
||||||
|
/// The base amount of experience that is gained when beating a Pokemon with this form.
|
||||||
base_experience: u32,
|
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>,
|
base_stats: StaticStatisticSet<u16>,
|
||||||
|
/// The possible abilities a Pokemon with this form can have.
|
||||||
abilities: Vec<StringKey>,
|
abilities: Vec<StringKey>,
|
||||||
|
/// The possible hidden abilities a Pokemon with this form can have.
|
||||||
hidden_abilities: Vec<StringKey>,
|
hidden_abilities: Vec<StringKey>,
|
||||||
|
/// The moves a Pokemon with this form can learn.
|
||||||
moves: LearnableMoves,
|
moves: LearnableMoves,
|
||||||
|
/// Arbitrary flags can be set on a form for scripting use.
|
||||||
flags: HashSet<StringKey>,
|
flags: HashSet<StringKey>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Form {
|
impl Form {
|
||||||
|
/// Instantiates a new form.
|
||||||
pub fn new(
|
pub fn new(
|
||||||
name: &StringKey,
|
name: &StringKey,
|
||||||
height: f32,
|
height: f32,
|
||||||
weight: f32,
|
weight: f32,
|
||||||
base_experience: u32,
|
base_experience: u32,
|
||||||
types: Vec<u8>,
|
types: Vec<TypeIdentifier>,
|
||||||
base_stats: StaticStatisticSet<u16>,
|
base_stats: StaticStatisticSet<u16>,
|
||||||
abilities: Vec<StringKey>,
|
abilities: Vec<StringKey>,
|
||||||
hidden_abilities: Vec<StringKey>,
|
hidden_abilities: Vec<StringKey>,
|
||||||
|
@ -47,45 +61,58 @@ impl Form {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The name of the form.
|
||||||
pub fn name(&self) -> &StringKey {
|
pub fn name(&self) -> &StringKey {
|
||||||
&self.name
|
&self.name
|
||||||
}
|
}
|
||||||
|
/// The height of the form in meters.
|
||||||
pub fn height(&self) -> f32 {
|
pub fn height(&self) -> f32 {
|
||||||
self.height
|
self.height
|
||||||
}
|
}
|
||||||
|
/// The weight of the form in kilograms.
|
||||||
pub fn weight(&self) -> f32 {
|
pub fn weight(&self) -> f32 {
|
||||||
self.weight
|
self.weight
|
||||||
}
|
}
|
||||||
|
/// The base amount of experience that is gained when beating a Pokemon with this form.
|
||||||
pub fn base_experience(&self) -> u32 {
|
pub fn base_experience(&self) -> u32 {
|
||||||
self.base_experience
|
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
|
&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> {
|
pub fn base_stats(&self) -> &StaticStatisticSet<u16> {
|
||||||
&self.base_stats
|
&self.base_stats
|
||||||
}
|
}
|
||||||
|
/// The possible abilities a Pokemon with this form can have.
|
||||||
pub fn abilities(&self) -> &Vec<StringKey> {
|
pub fn abilities(&self) -> &Vec<StringKey> {
|
||||||
&self.abilities
|
&self.abilities
|
||||||
}
|
}
|
||||||
|
/// The possible hidden abilities a Pokemon with this form can have.
|
||||||
pub fn hidden_abilities(&self) -> &Vec<StringKey> {
|
pub fn hidden_abilities(&self) -> &Vec<StringKey> {
|
||||||
&self.hidden_abilities
|
&self.hidden_abilities
|
||||||
}
|
}
|
||||||
|
/// The moves a Pokemon with this form can learn.
|
||||||
pub fn moves(&self) -> &LearnableMoves {
|
pub fn moves(&self) -> &LearnableMoves {
|
||||||
&self.moves
|
&self.moves
|
||||||
}
|
}
|
||||||
|
/// Arbitrary flags can be set on a form for scripting use.
|
||||||
pub fn flags(&self) -> &HashSet<StringKey> {
|
pub fn flags(&self) -> &HashSet<StringKey> {
|
||||||
&self.flags
|
&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]
|
self.types[index]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Gets a single base stat value.
|
||||||
pub fn get_base_stat(&self, stat: Statistic) -> u16 {
|
pub fn get_base_stat(&self, stat: Statistic) -> u16 {
|
||||||
self.base_stats.get_stat(stat)
|
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> {
|
pub fn find_ability_index(&self, ability: &Ability) -> Option<AbilityIndex> {
|
||||||
for (index, a) in self.abilities.iter().enumerate() {
|
for (index, a) in self.abilities.iter().enumerate() {
|
||||||
if a == ability.name() {
|
if a == ability.name() {
|
||||||
|
@ -106,6 +133,7 @@ impl Form {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Gets an ability from the form.
|
||||||
pub fn get_ability(&self, index: AbilityIndex) -> &StringKey {
|
pub fn get_ability(&self, index: AbilityIndex) -> &StringKey {
|
||||||
if index.hidden {
|
if index.hidden {
|
||||||
&self.hidden_abilities[index.index as usize]
|
&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 {
|
pub fn get_random_ability(&self, rand: &mut Random) -> &StringKey {
|
||||||
&self.abilities[rand.get_between_unsigned(0, self.abilities.len() as u32) as usize]
|
&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 {
|
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]
|
&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 {
|
pub fn has_flag(&self, key: &StringKey) -> bool {
|
||||||
self.flags.contains(key)
|
self.flags.contains(key)
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,25 +2,27 @@ use rand::distributions::{Distribution, Uniform};
|
||||||
use rand::{Rng, SeedableRng};
|
use rand::{Rng, SeedableRng};
|
||||||
use rand_pcg::Pcg32;
|
use rand_pcg::Pcg32;
|
||||||
|
|
||||||
|
/// A random number generator.
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct Random {
|
pub struct Random {
|
||||||
|
/// The seed of the random number generator.
|
||||||
seed: u128,
|
seed: u128,
|
||||||
|
/// A float distribution.
|
||||||
distribution: Uniform<f64>,
|
distribution: Uniform<f64>,
|
||||||
|
/// The underlying RNG. PCG for fast, hard to predict random number generation.
|
||||||
random_gen: Pcg32,
|
random_gen: Pcg32,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for Random {
|
impl Default for Random {
|
||||||
|
/// The default for the RNG uses the nanoseconds since epoch as seed.
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
let seed = chrono::Utc::now().timestamp_nanos() as u128;
|
let seed = chrono::Utc::now().timestamp_nanos() as u128;
|
||||||
Random {
|
Random::new(seed)
|
||||||
seed,
|
|
||||||
distribution: Uniform::from(0.0..1.0),
|
|
||||||
random_gen: Pcg32::from_seed(seed.to_be_bytes()),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Random {
|
impl Random {
|
||||||
|
/// Creates a new RNG with a specific seed.
|
||||||
pub fn new(seed: u128) -> Self {
|
pub fn new(seed: u128) -> Self {
|
||||||
Random {
|
Random {
|
||||||
seed,
|
seed,
|
||||||
|
@ -29,41 +31,60 @@ impl Random {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The seed used for the RNG.
|
||||||
pub fn get_seed(&self) -> u128 {
|
pub fn get_seed(&self) -> u128 {
|
||||||
self.seed
|
self.seed
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get a random 32 bit integer between minimal and maximal 32 bit integer
|
||||||
pub fn get(&mut self) -> i32 {
|
pub fn get(&mut self) -> i32 {
|
||||||
self.random_gen.gen()
|
self.random_gen.gen()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get a random 32 bit signed integer between 0 and max. If max equals 0, always returns 0.
|
||||||
pub fn get_max(&mut self, max: i32) -> i32 {
|
pub fn get_max(&mut self, max: i32) -> i32 {
|
||||||
assert!(max > 0);
|
if max <= 0 {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
Uniform::from(0..max).sample(&mut self.random_gen)
|
Uniform::from(0..max).sample(&mut self.random_gen)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get a random 32 bit signed integer between min and max. If max is equal or less than min,
|
||||||
|
/// always returns min.
|
||||||
pub fn get_between(&mut self, min: i32, max: i32) -> i32 {
|
pub fn get_between(&mut self, min: i32, max: i32) -> i32 {
|
||||||
assert!(max > min);
|
if max <= min {
|
||||||
|
return min;
|
||||||
|
}
|
||||||
Uniform::from(min..max).sample(&mut self.random_gen)
|
Uniform::from(min..max).sample(&mut self.random_gen)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get a random 32 bit integer unsigned between 0 and maximal 32 bit unsigned int.
|
||||||
pub fn get_unsigned(&mut self) -> u32 {
|
pub fn get_unsigned(&mut self) -> u32 {
|
||||||
self.random_gen.gen()
|
self.random_gen.gen()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get a random 32 bit signed integer between 0 and max. If max equals 0, always returns 0.
|
||||||
pub fn get_max_unsigned(&mut self, max: u32) -> u32 {
|
pub fn get_max_unsigned(&mut self, max: u32) -> u32 {
|
||||||
assert!(max > 0);
|
if max == 0 {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
Uniform::from(0..max).sample(&mut self.random_gen)
|
Uniform::from(0..max).sample(&mut self.random_gen)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get a random 32 bit unsigned integer between min and max. If max is equal or less than min,
|
||||||
|
/// always returns min.
|
||||||
pub fn get_between_unsigned(&mut self, min: u32, max: u32) -> u32 {
|
pub fn get_between_unsigned(&mut self, min: u32, max: u32) -> u32 {
|
||||||
assert!(max > min);
|
if max <= min {
|
||||||
|
return min;
|
||||||
|
}
|
||||||
Uniform::from(min..max).sample(&mut self.random_gen)
|
Uniform::from(min..max).sample(&mut self.random_gen)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Gets a random 32 bit float between 0.0 and 1.0
|
||||||
pub fn get_float(&mut self) -> f32 {
|
pub fn get_float(&mut self) -> f32 {
|
||||||
self.get_double() as f32
|
self.get_double() as f32
|
||||||
}
|
}
|
||||||
|
/// Gets a random 64 bit float between 0.0 and 1.0
|
||||||
pub fn get_double(&mut self) -> f64 {
|
pub fn get_double(&mut self) -> f64 {
|
||||||
self.distribution.sample(&mut self.random_gen)
|
self.distribution.sample(&mut self.random_gen)
|
||||||
}
|
}
|
||||||
|
@ -71,11 +92,13 @@ impl Random {
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use crate::utils::random::Random;
|
|
||||||
extern crate test;
|
|
||||||
use std::hint::black_box;
|
use std::hint::black_box;
|
||||||
use test::Bencher;
|
use test::Bencher;
|
||||||
|
|
||||||
|
use crate::utils::random::Random;
|
||||||
|
|
||||||
|
extern crate test;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[cfg_attr(miri, ignore)]
|
#[cfg_attr(miri, ignore)]
|
||||||
fn create_random() {
|
fn create_random() {
|
||||||
|
|
|
@ -1,23 +1,30 @@
|
||||||
use hashbrown::HashMap;
|
|
||||||
use std::fmt::{Display, Formatter};
|
use std::fmt::{Display, Formatter};
|
||||||
use std::hash::{Hash, Hasher};
|
use std::hash::{Hash, Hasher};
|
||||||
use std::lazy::SyncLazy;
|
use std::lazy::SyncLazy;
|
||||||
use std::sync::{Arc, Mutex, Weak};
|
use std::sync::{Arc, Mutex, Weak};
|
||||||
|
|
||||||
|
use hashbrown::HashMap;
|
||||||
|
|
||||||
/// StringKey is an immutable string that is used for indexing of hashmaps or equality a lot.
|
/// StringKey is an immutable string that is used for indexing of hashmaps or equality a lot.
|
||||||
/// By reference counting the string instead of copying, and caching the hash, we can get some
|
/// By reference counting the string instead of copying, and caching the hash, we can get some
|
||||||
/// free speed out of it. Note that StringKeys also compare case insensitive, so that for example
|
/// free speed out of it. Note that StringKeys also compare case insensitive, so that for example
|
||||||
/// `charmander` == `Charmander`.
|
/// `charmander` == `Charmander`.
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct StringKey {
|
pub struct StringKey {
|
||||||
|
/// The underlying reference counted string.
|
||||||
str: Arc<str>,
|
str: Arc<str>,
|
||||||
|
/// The unique hash of the string.
|
||||||
hash: u32,
|
hash: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A cache of all allocated strings. This allows us to re-use strings that are often used without
|
||||||
|
/// allocation.
|
||||||
static STRING_CACHE: SyncLazy<Mutex<HashMap<u32, Weak<str>>>> = SyncLazy::new(|| Mutex::new(HashMap::new()));
|
static STRING_CACHE: SyncLazy<Mutex<HashMap<u32, Weak<str>>>> = SyncLazy::new(|| Mutex::new(HashMap::new()));
|
||||||
|
/// An empty StringKey
|
||||||
static EMPTY: SyncLazy<StringKey> = SyncLazy::new(|| StringKey::new(""));
|
static EMPTY: SyncLazy<StringKey> = SyncLazy::new(|| StringKey::new(""));
|
||||||
|
|
||||||
impl StringKey {
|
impl StringKey {
|
||||||
|
/// Calculates the hash of a string key in a const manner.
|
||||||
pub const fn get_hash_const<const N: usize>(s: &[u8; N]) -> u32 {
|
pub const fn get_hash_const<const N: usize>(s: &[u8; N]) -> u32 {
|
||||||
let mut crc: u32 = 0xffffffff;
|
let mut crc: u32 = 0xffffffff;
|
||||||
|
|
||||||
|
@ -29,6 +36,7 @@ impl StringKey {
|
||||||
crc ^ 0xffffffff
|
crc ^ 0xffffffff
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Gets the hash of a string.
|
||||||
pub fn get_hash(s: &str) -> u32 {
|
pub fn get_hash(s: &str) -> u32 {
|
||||||
let mut crc: u32 = 0xffffffff;
|
let mut crc: u32 = 0xffffffff;
|
||||||
for byte in s.bytes() {
|
for byte in s.bytes() {
|
||||||
|
@ -37,6 +45,8 @@ impl StringKey {
|
||||||
crc ^ 0xffffffff
|
crc ^ 0xffffffff
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Creates a new StringKey. If we can find a value for this StringKey in the cache, we re-use
|
||||||
|
/// that value.
|
||||||
pub fn new(s: &str) -> Self {
|
pub fn new(s: &str) -> Self {
|
||||||
let hash = StringKey::get_hash(s);
|
let hash = StringKey::get_hash(s);
|
||||||
let mut cache = STRING_CACHE.lock().unwrap();
|
let mut cache = STRING_CACHE.lock().unwrap();
|
||||||
|
@ -54,14 +64,17 @@ impl StringKey {
|
||||||
v
|
v
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Gets the empty StringKey.
|
||||||
pub fn empty() -> Self {
|
pub fn empty() -> Self {
|
||||||
EMPTY.clone()
|
EMPTY.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Gets the underlying string for the StringKey.
|
||||||
pub fn str(&self) -> &str {
|
pub fn str(&self) -> &str {
|
||||||
&self.str
|
&self.str
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Gets the hash of the string value.
|
||||||
pub fn hash(&self) -> u32 {
|
pub fn hash(&self) -> u32 {
|
||||||
self.hash
|
self.hash
|
||||||
}
|
}
|
||||||
|
@ -93,6 +106,7 @@ impl Display for StringKey {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Converts a character to lowercased in a const safe way.
|
||||||
const fn to_lower(c: u8) -> u8 {
|
const fn to_lower(c: u8) -> u8 {
|
||||||
if c >= b'A' && c <= b'Z' {
|
if c >= b'A' && c <= b'Z' {
|
||||||
return c + (b'a' - b'A');
|
return c + (b'a' - b'A');
|
||||||
|
@ -100,6 +114,7 @@ const fn to_lower(c: u8) -> u8 {
|
||||||
c
|
c
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A lookup table for use in CRC32 hash.
|
||||||
const CRC_TABLE: &[u32] = &[
|
const CRC_TABLE: &[u32] = &[
|
||||||
0, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3, 0x0EDB8832, 0x79DCB8A4,
|
0, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3, 0x0EDB8832, 0x79DCB8A4,
|
||||||
0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, 0x1DB71064, 0x6AB020F2, 0xF3B97148,
|
0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, 0x1DB71064, 0x6AB020F2, 0xF3B97148,
|
||||||
|
|
|
@ -59,7 +59,7 @@ pub fn load_types(path: &String, type_library: &mut TypeLibrary) {
|
||||||
|
|
||||||
for (i, v) in record.iter().skip(1).enumerate() {
|
for (i, v) in record.iter().skip(1).enumerate() {
|
||||||
let effectiveness = v.parse::<f32>().unwrap();
|
let effectiveness = v.parse::<f32>().unwrap();
|
||||||
type_library.set_effectiveness(offensive_type_id, i as u8, effectiveness);
|
type_library.set_effectiveness(offensive_type_id, (i as u8).into(), effectiveness);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue