A lot more work on a bunch of different parts of the system.
This commit is contained in:
parent
10e93949e4
commit
6e8f4dd4a5
|
@ -29,12 +29,12 @@ ffi! {
|
||||||
let v = slice::from_raw_parts(flags, flags_length as usize).to_vec();
|
let v = slice::from_raw_parts(flags, flags_length as usize).to_vec();
|
||||||
let mut flags_map = HashSet::new();
|
let mut flags_map = HashSet::new();
|
||||||
for flag in v {
|
for flag in v {
|
||||||
flags_map.insert(CStr::from_ptr(flag).to_str().unwrap().to_string());
|
flags_map.insert(CStr::from_ptr(flag).to_str().unwrap().into());
|
||||||
}
|
}
|
||||||
|
|
||||||
let handle = ItemHandle::alloc(ItemC {
|
let handle = ItemHandle::alloc(ItemC {
|
||||||
inner: thread_bound::DeferredCleanup::new(Item::new(
|
inner: thread_bound::DeferredCleanup::new(Item::new(
|
||||||
CStr::from_ptr(name).to_str().unwrap(),
|
&CStr::from_ptr(name).to_str().unwrap().into(),
|
||||||
std::mem::transmute(category),
|
std::mem::transmute(category),
|
||||||
std::mem::transmute(battle_category),
|
std::mem::transmute(battle_category),
|
||||||
price,
|
price,
|
||||||
|
|
|
@ -1,18 +1,20 @@
|
||||||
|
use crate::dynamic_data::models::damage_source::DamageSource;
|
||||||
use crate::dynamic_data::models::pokemon::Pokemon;
|
use crate::dynamic_data::models::pokemon::Pokemon;
|
||||||
|
use crate::static_data::species_data::form::Form;
|
||||||
|
use crate::static_data::species_data::species::Species;
|
||||||
use std::fmt::{Debug, Formatter};
|
use std::fmt::{Debug, Formatter};
|
||||||
use std::sync::{Arc, RwLock};
|
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct EventHook {
|
pub struct EventHook {
|
||||||
evt_hook_function: Vec<fn(&Box<&Event>)>,
|
evt_hook_function: Vec<fn(&Box<&Event>)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl EventHook {
|
impl<'a> EventHook {
|
||||||
pub fn register_listener(&mut self, func: fn(&Box<&Event>)) {
|
pub fn register_listener(&mut self, func: fn(&Box<&Event>)) {
|
||||||
self.evt_hook_function.push(func);
|
self.evt_hook_function.push(func);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn trigger(&self, evt: Event) {
|
pub fn trigger<'b>(&self, evt: Event<'a, 'b>) {
|
||||||
let b = Box::new(&evt);
|
let b = Box::new(&evt);
|
||||||
for f in &self.evt_hook_function {
|
for f in &self.evt_hook_function {
|
||||||
f(&b);
|
f(&b);
|
||||||
|
@ -27,15 +29,33 @@ impl Debug for EventHook {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum Event<'a> {
|
pub enum Event<'a, 'b> {
|
||||||
Switch {
|
Switch {
|
||||||
side_index: u8,
|
side_index: u8,
|
||||||
index: u8,
|
index: u8,
|
||||||
pokemon: Option<Arc<RwLock<Pokemon<'a>>>>,
|
pokemon: Option<&'a Pokemon<'b>>,
|
||||||
},
|
},
|
||||||
Swap {
|
Swap {
|
||||||
side_index: u8,
|
side_index: u8,
|
||||||
index_a: u8,
|
index_a: u8,
|
||||||
index_b: u8,
|
index_b: u8,
|
||||||
},
|
},
|
||||||
|
SpeciesChange {
|
||||||
|
pokemon: &'a Pokemon<'b>,
|
||||||
|
species: &'a Species<'b>,
|
||||||
|
form: &'a Form<'b>,
|
||||||
|
},
|
||||||
|
FormChange {
|
||||||
|
pokemon: &'a Pokemon<'b>,
|
||||||
|
form: &'a Form<'b>,
|
||||||
|
},
|
||||||
|
Damage {
|
||||||
|
pokemon: &'a Pokemon<'b>,
|
||||||
|
source: DamageSource,
|
||||||
|
original_health: u32,
|
||||||
|
new_health: u32,
|
||||||
|
},
|
||||||
|
Faint {
|
||||||
|
pokemon: &'a Pokemon<'b>,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,2 +1,32 @@
|
||||||
|
use crate::dynamic_data::models::pokemon::Pokemon;
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct ChoiceQueue {}
|
pub struct ChoiceQueue {
|
||||||
|
queue: Vec<Arc<ChoiceQueue>>,
|
||||||
|
current: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ChoiceQueue {
|
||||||
|
pub fn new(queue: Vec<Arc<ChoiceQueue>>) -> Self {
|
||||||
|
Self { queue, current: 0 }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn dequeue(&mut self) -> &Arc<ChoiceQueue> {
|
||||||
|
let c = &self.queue[self.current];
|
||||||
|
self.current += 1;
|
||||||
|
c
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn peek(&mut self) -> &Arc<ChoiceQueue> {
|
||||||
|
&self.queue[self.current]
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn has_next(&self) -> bool {
|
||||||
|
self.current < self.queue.len()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn move_pokemon_choice_next(&mut self, _pokemon: &Pokemon) {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,8 +1,10 @@
|
||||||
use crate::dynamic_data::libraries::battle_stat_calculator::BattleStatCalculator;
|
use crate::dynamic_data::libraries::battle_stat_calculator::BattleStatCalculator;
|
||||||
use crate::dynamic_data::libraries::script_resolver::ScriptCategory;
|
use crate::dynamic_data::libraries::script_resolver::ScriptCategory;
|
||||||
|
use crate::dynamic_data::script_handling::item_script::ItemScript;
|
||||||
use crate::dynamic_data::script_handling::script::Script;
|
use crate::dynamic_data::script_handling::script::Script;
|
||||||
|
use crate::static_data::items::item::Item;
|
||||||
use crate::static_data::libraries::static_data::StaticData;
|
use crate::static_data::libraries::static_data::StaticData;
|
||||||
use crate::PkmnResult;
|
use crate::{PkmnResult, StringKey};
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct DynamicLibrary<'a> {
|
pub struct DynamicLibrary<'a> {
|
||||||
|
@ -21,8 +23,12 @@ impl<'a> DynamicLibrary<'a> {
|
||||||
pub fn load_script(
|
pub fn load_script(
|
||||||
&self,
|
&self,
|
||||||
_category: ScriptCategory,
|
_category: ScriptCategory,
|
||||||
_key: &str,
|
_key: &StringKey,
|
||||||
) -> PkmnResult<Box<dyn Script>> {
|
) -> PkmnResult<Option<Box<dyn Script>>> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn load_item_script(&self, _key: &Item) -> PkmnResult<Option<Box<dyn ItemScript>>> {
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,7 +9,7 @@ use crate::dynamic_data::models::battle_side::BattleSide;
|
||||||
use crate::dynamic_data::script_handling::script::Script;
|
use crate::dynamic_data::script_handling::script::Script;
|
||||||
use crate::dynamic_data::script_handling::script_set::ScriptSet;
|
use crate::dynamic_data::script_handling::script_set::ScriptSet;
|
||||||
use crate::dynamic_data::script_handling::volatile_scripts::VolatileScripts;
|
use crate::dynamic_data::script_handling::volatile_scripts::VolatileScripts;
|
||||||
use crate::{PkmnResult, ScriptCategory};
|
use crate::{PkmnResult, ScriptCategory, StringKey};
|
||||||
use std::sync::{Arc, RwLock};
|
use std::sync::{Arc, RwLock};
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
@ -21,7 +21,7 @@ pub struct Battle<'a> {
|
||||||
pokemon_per_side: u8,
|
pokemon_per_side: u8,
|
||||||
sides: Vec<BattleSide<'a>>,
|
sides: Vec<BattleSide<'a>>,
|
||||||
random: BattleRandom,
|
random: BattleRandom,
|
||||||
choice_queue: ChoiceQueue,
|
current_turn_queue: Option<ChoiceQueue>,
|
||||||
has_ended: bool,
|
has_ended: bool,
|
||||||
result: BattleResult,
|
result: BattleResult,
|
||||||
event_hook: EventHook,
|
event_hook: EventHook,
|
||||||
|
@ -54,7 +54,7 @@ impl<'a> Battle<'a> {
|
||||||
pokemon_per_side,
|
pokemon_per_side,
|
||||||
sides,
|
sides,
|
||||||
random,
|
random,
|
||||||
choice_queue: ChoiceQueue {},
|
current_turn_queue: None,
|
||||||
has_ended: false,
|
has_ended: false,
|
||||||
result: BattleResult::Inconclusive,
|
result: BattleResult::Inconclusive,
|
||||||
event_hook: Default::default(),
|
event_hook: Default::default(),
|
||||||
|
@ -89,6 +89,10 @@ impl<'a> Battle<'a> {
|
||||||
pub fn sides(&self) -> &Vec<BattleSide<'a>> {
|
pub fn sides(&self) -> &Vec<BattleSide<'a>> {
|
||||||
&self.sides
|
&self.sides
|
||||||
}
|
}
|
||||||
|
pub fn sides_mut(&mut self) -> &mut Vec<BattleSide<'a>> {
|
||||||
|
&mut self.sides
|
||||||
|
}
|
||||||
|
|
||||||
pub fn random(&self) -> &BattleRandom {
|
pub fn random(&self) -> &BattleRandom {
|
||||||
&self.random
|
&self.random
|
||||||
}
|
}
|
||||||
|
@ -110,12 +114,51 @@ impl<'a> Battle<'a> {
|
||||||
pub fn last_turn_time(&self) -> i64 {
|
pub fn last_turn_time(&self) -> i64 {
|
||||||
self.last_turn_time
|
self.last_turn_time
|
||||||
}
|
}
|
||||||
pub fn choice_queue(&self) -> &ChoiceQueue {
|
pub fn current_turn_queue(&self) -> &Option<ChoiceQueue> {
|
||||||
&self.choice_queue
|
&self.current_turn_queue
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn can_slot_be_filled(&self) -> bool {
|
pub fn can_slot_be_filled(&self, side: u8, index: u8) -> bool {
|
||||||
todo!()
|
for party in &self.parties {
|
||||||
|
if party.is_responsible_for_index(side, index) && party.has_pokemon_not_in_field() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn validate_battle_state(&mut self) {
|
||||||
|
if self.has_ended {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let mut surviving_side_exists = false;
|
||||||
|
let mut winning_side = None;
|
||||||
|
for (side_index, side) in self.sides.iter().enumerate() {
|
||||||
|
// If any side has fled, the battle end.
|
||||||
|
if side.has_fled() {
|
||||||
|
self.result = BattleResult::Inconclusive;
|
||||||
|
self.has_ended = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// If the side is not defeated
|
||||||
|
if !side.is_defeated() {
|
||||||
|
// More than 1 surviving side. Battle is not ended
|
||||||
|
if surviving_side_exists {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
surviving_side_exists = true;
|
||||||
|
winning_side = Some(side_index as u8);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Everyone died :(
|
||||||
|
if !surviving_side_exists {
|
||||||
|
self.result = BattleResult::Inconclusive;
|
||||||
|
}
|
||||||
|
// Someone survived, they won!
|
||||||
|
else {
|
||||||
|
self.result = BattleResult::Conclusive(winning_side.unwrap());
|
||||||
|
}
|
||||||
|
self.has_ended = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -124,7 +167,7 @@ impl<'a> VolatileScripts<'a> for Battle<'a> {
|
||||||
&self.volatile
|
&self.volatile
|
||||||
}
|
}
|
||||||
|
|
||||||
fn load_volatile_script(&self, key: &str) -> PkmnResult<Box<dyn Script>> {
|
fn load_volatile_script(&self, key: &StringKey) -> PkmnResult<Option<Box<dyn Script>>> {
|
||||||
self.library.load_script(ScriptCategory::Battle, key)
|
self.library.load_script(ScriptCategory::Battle, key)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,8 @@ use crate::dynamic_data::script_handling::script::Script;
|
||||||
use crate::dynamic_data::script_handling::script_set::ScriptSet;
|
use crate::dynamic_data::script_handling::script_set::ScriptSet;
|
||||||
use crate::dynamic_data::script_handling::volatile_scripts::VolatileScripts;
|
use crate::dynamic_data::script_handling::volatile_scripts::VolatileScripts;
|
||||||
use crate::dynamic_data::script_handling::ScriptSource;
|
use crate::dynamic_data::script_handling::ScriptSource;
|
||||||
use crate::{script_hook, PkmnResult};
|
use crate::{script_hook, PkmnResult, StringKey};
|
||||||
|
use std::ops::Deref;
|
||||||
use std::sync::{Arc, RwLock, Weak};
|
use std::sync::{Arc, RwLock, Weak};
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
@ -83,7 +84,7 @@ impl<'a> BattleSide<'a> {
|
||||||
/// responsible for them. Returns false if all slots are filled with usable pokemon, or slots are
|
/// responsible for them. Returns false if all slots are filled with usable pokemon, or slots are
|
||||||
/// empty, but can't be filled by any party anymore.
|
/// empty, but can't be filled by any party anymore.
|
||||||
pub fn all_slots_filled(&self) -> bool {
|
pub fn all_slots_filled(&self) -> bool {
|
||||||
for pokemon in &self.pokemon {
|
for (i, pokemon) in self.pokemon.iter().enumerate() {
|
||||||
if (!pokemon.is_none() || !pokemon.as_ref().unwrap().read().unwrap().is_usable())
|
if (!pokemon.is_none() || !pokemon.as_ref().unwrap().read().unwrap().is_usable())
|
||||||
&& self
|
&& self
|
||||||
.battle
|
.battle
|
||||||
|
@ -91,7 +92,7 @@ impl<'a> BattleSide<'a> {
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.read()
|
.read()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.can_slot_be_filled()
|
.can_slot_be_filled(self.index, i as u8)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -146,7 +147,7 @@ impl<'a> BattleSide<'a> {
|
||||||
battle.event_hook().trigger(Event::Switch {
|
battle.event_hook().trigger(Event::Switch {
|
||||||
side_index: self.index,
|
side_index: self.index,
|
||||||
index,
|
index,
|
||||||
pokemon: Some(pokemon_mutex.clone()),
|
pokemon: Some(&pokemon),
|
||||||
});
|
});
|
||||||
script_hook!(on_switch_in, pokemon, &pokemon);
|
script_hook!(on_switch_in, pokemon, &pokemon);
|
||||||
} else {
|
} else {
|
||||||
|
@ -169,10 +170,10 @@ impl<'a> BattleSide<'a> {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn mark_slot_as_unfillable(&mut self, pokemon: Arc<Pokemon<'a>>) {
|
pub fn mark_slot_as_unfillable(&mut self, pokemon: &Pokemon<'a>) {
|
||||||
for (i, slot) in self.pokemon.iter().enumerate() {
|
for (i, slot) in self.pokemon.iter().enumerate() {
|
||||||
if let Some(p) = slot {
|
if let Some(p) = slot {
|
||||||
if p.read().unwrap().unique_identifier() == pokemon.unique_identifier() {
|
if p.read().unwrap().deref() as *const Pokemon == pokemon as *const Pokemon {
|
||||||
self.fillable_slots[i] = false;
|
self.fillable_slots[i] = false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -266,7 +267,7 @@ impl<'a> VolatileScripts<'a> for BattleSide<'a> {
|
||||||
&self.volatile_scripts
|
&self.volatile_scripts
|
||||||
}
|
}
|
||||||
|
|
||||||
fn load_volatile_script(&self, key: &str) -> PkmnResult<Box<dyn Script>> {
|
fn load_volatile_script(&self, key: &StringKey) -> PkmnResult<Option<Box<dyn Script>>> {
|
||||||
self.battle
|
self.battle
|
||||||
.upgrade()
|
.upgrade()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
pub enum DamageSource {
|
||||||
|
AttackDamage = 0,
|
||||||
|
Misc = 1,
|
||||||
|
}
|
|
@ -3,6 +3,7 @@ pub mod battle_party;
|
||||||
pub mod battle_random;
|
pub mod battle_random;
|
||||||
pub mod battle_result;
|
pub mod battle_result;
|
||||||
pub mod battle_side;
|
pub mod battle_side;
|
||||||
|
pub mod damage_source;
|
||||||
pub mod learned_move;
|
pub mod learned_move;
|
||||||
pub mod pokemon;
|
pub mod pokemon;
|
||||||
pub mod pokemon_party;
|
pub mod pokemon_party;
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
use crate::defines::{LevelInt, MAX_MOVES};
|
use crate::defines::{LevelInt, MAX_MOVES};
|
||||||
|
use crate::dynamic_data::event_hooks::event_hook::Event;
|
||||||
use crate::dynamic_data::libraries::dynamic_library::DynamicLibrary;
|
use crate::dynamic_data::libraries::dynamic_library::DynamicLibrary;
|
||||||
use crate::dynamic_data::models::battle::Battle;
|
use crate::dynamic_data::models::battle::Battle;
|
||||||
|
use crate::dynamic_data::models::damage_source::DamageSource;
|
||||||
use crate::dynamic_data::models::learned_move::LearnedMove;
|
use crate::dynamic_data::models::learned_move::LearnedMove;
|
||||||
use crate::dynamic_data::script_handling::script::Script;
|
use crate::dynamic_data::script_handling::script::Script;
|
||||||
use crate::dynamic_data::script_handling::script_set::ScriptSet;
|
use crate::dynamic_data::script_handling::script_set::ScriptSet;
|
||||||
|
@ -8,6 +10,7 @@ use crate::dynamic_data::script_handling::volatile_scripts::VolatileScripts;
|
||||||
use crate::dynamic_data::script_handling::ScriptSource;
|
use crate::dynamic_data::script_handling::ScriptSource;
|
||||||
use crate::static_data::items::item::Item;
|
use crate::static_data::items::item::Item;
|
||||||
use crate::static_data::natures::Nature;
|
use crate::static_data::natures::Nature;
|
||||||
|
use crate::static_data::species_data::ability::Ability;
|
||||||
use crate::static_data::species_data::ability_index::AbilityIndex;
|
use crate::static_data::species_data::ability_index::AbilityIndex;
|
||||||
use crate::static_data::species_data::form::Form;
|
use crate::static_data::species_data::form::Form;
|
||||||
use crate::static_data::species_data::gender::Gender;
|
use crate::static_data::species_data::gender::Gender;
|
||||||
|
@ -15,7 +18,7 @@ use crate::static_data::species_data::species::Species;
|
||||||
use crate::static_data::statistic_set::{ClampedStatisticSet, StatisticSet};
|
use crate::static_data::statistic_set::{ClampedStatisticSet, StatisticSet};
|
||||||
use crate::static_data::statistics::Statistic;
|
use crate::static_data::statistics::Statistic;
|
||||||
use crate::utils::random::Random;
|
use crate::utils::random::Random;
|
||||||
use crate::{PkmnResult, ScriptCategory};
|
use crate::{script_hook, PkmnResult, ScriptCategory, StringKey};
|
||||||
use std::sync::{Arc, RwLock, Weak};
|
use std::sync::{Arc, RwLock, Weak};
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
@ -73,6 +76,7 @@ pub struct Pokemon<'a> {
|
||||||
|
|
||||||
ability_index: AbilityIndex,
|
ability_index: AbilityIndex,
|
||||||
is_ability_overridden: bool,
|
is_ability_overridden: bool,
|
||||||
|
override_ability: Option<Ability>,
|
||||||
|
|
||||||
battle_data: Option<PokemonBattleData<'a>>,
|
battle_data: Option<PokemonBattleData<'a>>,
|
||||||
|
|
||||||
|
@ -80,8 +84,10 @@ pub struct Pokemon<'a> {
|
||||||
allowed_experience: bool,
|
allowed_experience: bool,
|
||||||
|
|
||||||
types: Vec<u8>,
|
types: Vec<u8>,
|
||||||
|
is_egg: bool,
|
||||||
|
is_caught: bool,
|
||||||
|
|
||||||
ability_script: Option<Box<dyn Script>>,
|
ability_script: Option<Arc<Box<dyn Script>>>,
|
||||||
status_script: Option<Box<dyn Script>>,
|
status_script: Option<Box<dyn Script>>,
|
||||||
volatile: Arc<RwLock<ScriptSet>>,
|
volatile: Arc<RwLock<ScriptSet>>,
|
||||||
}
|
}
|
||||||
|
@ -96,7 +102,7 @@ impl<'a> Pokemon<'a> {
|
||||||
unique_identifier: u32,
|
unique_identifier: u32,
|
||||||
gender: Gender,
|
gender: Gender,
|
||||||
coloring: u8,
|
coloring: u8,
|
||||||
nature: String,
|
nature: &StringKey,
|
||||||
) -> Pokemon<'a> {
|
) -> Pokemon<'a> {
|
||||||
// Calculate experience from the level for the specified growth rate.
|
// Calculate experience from the level for the specified growth rate.
|
||||||
let experience = library
|
let experience = library
|
||||||
|
@ -135,16 +141,18 @@ impl<'a> Pokemon<'a> {
|
||||||
nickname: None,
|
nickname: None,
|
||||||
ability_index: ability,
|
ability_index: ability,
|
||||||
is_ability_overridden: false,
|
is_ability_overridden: false,
|
||||||
|
override_ability: None,
|
||||||
battle_data: None,
|
battle_data: None,
|
||||||
moves: [None, None, None, None],
|
moves: [None, None, None, None],
|
||||||
allowed_experience: false,
|
allowed_experience: false,
|
||||||
types: form.types().to_vec(),
|
types: form.types().to_vec(),
|
||||||
|
is_egg: false,
|
||||||
|
is_caught: false,
|
||||||
ability_script: None,
|
ability_script: None,
|
||||||
status_script: None,
|
status_script: None,
|
||||||
volatile: Default::default(),
|
volatile: Default::default(),
|
||||||
};
|
};
|
||||||
pokemon.recalculate_flat_stats();
|
pokemon.recalculate_flat_stats();
|
||||||
|
|
||||||
pokemon
|
pokemon
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -190,6 +198,35 @@ impl<'a> Pokemon<'a> {
|
||||||
pub fn held_item(&self) -> Option<&'a Item> {
|
pub fn held_item(&self) -> Option<&'a Item> {
|
||||||
self.held_item
|
self.held_item
|
||||||
}
|
}
|
||||||
|
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.
|
||||||
|
if let Some(v) = self.held_item {
|
||||||
|
return v.name() == name;
|
||||||
|
}
|
||||||
|
false
|
||||||
|
}
|
||||||
|
pub fn set_held_item(&mut self, item: &'a Item) {
|
||||||
|
self.held_item = Some(item);
|
||||||
|
}
|
||||||
|
pub fn remove_held_item(&mut self) {
|
||||||
|
self.held_item = None;
|
||||||
|
}
|
||||||
|
pub fn consume_held_item(&mut self) -> bool {
|
||||||
|
if self.held_item.is_none() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
let script = self
|
||||||
|
.library
|
||||||
|
.load_item_script(self.held_item.unwrap())
|
||||||
|
.unwrap();
|
||||||
|
if script.is_none() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: the entire item use part.
|
||||||
|
todo!();
|
||||||
|
}
|
||||||
|
|
||||||
pub fn current_health(&self) -> u32 {
|
pub fn current_health(&self) -> u32 {
|
||||||
self.current_health
|
self.current_health
|
||||||
}
|
}
|
||||||
|
@ -249,9 +286,19 @@ impl<'a> Pokemon<'a> {
|
||||||
pub fn is_ability_overriden(&self) -> bool {
|
pub fn is_ability_overriden(&self) -> bool {
|
||||||
self.is_ability_overridden
|
self.is_ability_overridden
|
||||||
}
|
}
|
||||||
pub fn active_ability(&self) -> &Option<Box<dyn Script>> {
|
pub fn active_ability(&self) -> &Ability {
|
||||||
|
if self.is_ability_overridden {
|
||||||
|
if let Some(v) = &self.override_ability {
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.form.get_ability(self.ability_index)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn ability_script(&self) -> &Option<Arc<Box<dyn Script>>> {
|
||||||
&self.ability_script
|
&self.ability_script
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn seen_opponents(&self) -> Option<&Vec<Weak<RwLock<Pokemon<'a>>>>> {
|
pub fn seen_opponents(&self) -> Option<&Vec<Weak<RwLock<Pokemon<'a>>>>> {
|
||||||
if let Some(data) = &self.battle_data {
|
if let Some(data) = &self.battle_data {
|
||||||
Some(&data.seen_opponents)
|
Some(&data.seen_opponents)
|
||||||
|
@ -281,6 +328,7 @@ impl<'a> Pokemon<'a> {
|
||||||
|
|
||||||
// If the pokemon is genderless, but it's new species is not, we want to set its gender
|
// If the pokemon is genderless, but it's new species is not, we want to set its gender
|
||||||
if self.gender != Gender::Genderless && species.gender_rate() < 0.0 {
|
if self.gender != Gender::Genderless && species.gender_rate() < 0.0 {
|
||||||
|
// If we're in battle, use the battle random for predictability
|
||||||
if self.battle_data.is_some() {
|
if self.battle_data.is_some() {
|
||||||
let battle_data = self.battle_data.as_mut().unwrap();
|
let battle_data = self.battle_data.as_mut().unwrap();
|
||||||
self.gender = species.get_random_gender(
|
self.gender = species.get_random_gender(
|
||||||
|
@ -296,6 +344,7 @@ impl<'a> Pokemon<'a> {
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
|
// If we're not in battle, just use a new random.
|
||||||
self.gender = species.get_random_gender(&mut Random::default());
|
self.gender = species.get_random_gender(&mut Random::default());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -303,11 +352,78 @@ impl<'a> Pokemon<'a> {
|
||||||
else if species.gender_rate() < 0.0 && self.gender != Gender::Genderless {
|
else if species.gender_rate() < 0.0 && self.gender != Gender::Genderless {
|
||||||
self.gender = Gender::Genderless;
|
self.gender = Gender::Genderless;
|
||||||
}
|
}
|
||||||
// TODO: Battle Event trigger
|
if let Some(battle_data) = &self.battle_data {
|
||||||
|
if let Some(battle) = battle_data.battle.upgrade() {
|
||||||
|
battle
|
||||||
|
.read()
|
||||||
|
.unwrap()
|
||||||
|
.event_hook()
|
||||||
|
.trigger(Event::SpeciesChange {
|
||||||
|
pokemon: self,
|
||||||
|
species,
|
||||||
|
form,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn change_form(&mut self, form: &'a Form) {
|
||||||
|
if std::ptr::eq(self.form, form) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
self.form = form;
|
||||||
|
|
||||||
|
self.types.clear();
|
||||||
|
for t in form.types() {
|
||||||
|
self.types.push(*t);
|
||||||
|
}
|
||||||
|
self.weight = form.weight();
|
||||||
|
self.height = form.height();
|
||||||
|
|
||||||
|
let ability_script = self
|
||||||
|
.library
|
||||||
|
.load_script(ScriptCategory::Ability, self.active_ability().name())
|
||||||
|
.unwrap();
|
||||||
|
if let Some(ability_script) = ability_script {
|
||||||
|
self.ability_script = Some(Arc::new(ability_script));
|
||||||
|
// Ensure the ability script gets initialized with the parameters for the ability.
|
||||||
|
self.ability_script()
|
||||||
|
.as_ref()
|
||||||
|
.unwrap()
|
||||||
|
.on_initialize(self.active_ability().parameters())
|
||||||
|
} else {
|
||||||
|
self.ability_script = None;
|
||||||
|
}
|
||||||
|
let old_health = self.max_health();
|
||||||
|
self.recalculate_flat_stats();
|
||||||
|
let diff_health = (self.max_health() - old_health) as i32;
|
||||||
|
if self.current_health == 0 && (self.current_health as i32) < -diff_health {
|
||||||
|
self.current_health = 0;
|
||||||
|
} else {
|
||||||
|
self.current_health = self.current_health() + diff_health as u32;
|
||||||
|
}
|
||||||
|
// TODO: consider form specific attacks?
|
||||||
|
|
||||||
|
if let Some(battle_data) = &self.battle_data {
|
||||||
|
if let Some(battle) = battle_data.battle.upgrade() {
|
||||||
|
battle
|
||||||
|
.read()
|
||||||
|
.unwrap()
|
||||||
|
.event_hook()
|
||||||
|
.trigger(Event::FormChange {
|
||||||
|
pokemon: self,
|
||||||
|
form,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_usable(&self) -> bool {
|
pub fn is_usable(&self) -> bool {
|
||||||
todo!()
|
!self.is_caught && !self.is_egg && !self.is_fainted()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_fainted(&self) -> bool {
|
||||||
|
self.current_health == 0
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_battle_data(&mut self, battle: Weak<RwLock<Battle<'a>>>, battle_side_index: u8) {
|
pub fn set_battle_data(&mut self, battle: Weak<RwLock<Battle<'a>>>, battle_side_index: u8) {
|
||||||
|
@ -360,6 +476,67 @@ impl<'a> Pokemon<'a> {
|
||||||
battle_data.seen_opponents.push(pokemon);
|
battle_data.seen_opponents.push(pokemon);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn damage(&mut self, mut damage: u32, source: DamageSource) {
|
||||||
|
if damage > self.current_health {
|
||||||
|
damage = self.current_health;
|
||||||
|
}
|
||||||
|
if damage == 0 {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let new_health = self.current_health() - damage;
|
||||||
|
if let Some(battle_data) = &self.battle_data {
|
||||||
|
if let Some(battle) = battle_data.battle.upgrade() {
|
||||||
|
battle.read().unwrap().event_hook().trigger(Event::Damage {
|
||||||
|
pokemon: self,
|
||||||
|
source,
|
||||||
|
original_health: self.current_health(),
|
||||||
|
new_health,
|
||||||
|
});
|
||||||
|
// TODO: register history
|
||||||
|
script_hook!(
|
||||||
|
on_damage,
|
||||||
|
self,
|
||||||
|
self,
|
||||||
|
source,
|
||||||
|
self.current_health,
|
||||||
|
new_health
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.current_health = new_health;
|
||||||
|
if self.is_fainted() && damage > 0 {
|
||||||
|
self.on_faint(source);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn on_faint(&self, source: DamageSource) {
|
||||||
|
if let Some(battle_data) = &self.battle_data {
|
||||||
|
if let Some(battle) = battle_data.battle.upgrade() {
|
||||||
|
battle
|
||||||
|
.read()
|
||||||
|
.unwrap()
|
||||||
|
.event_hook()
|
||||||
|
.trigger(Event::Faint { pokemon: self });
|
||||||
|
script_hook!(on_faint, self, self, source);
|
||||||
|
script_hook!(on_remove, self,);
|
||||||
|
}
|
||||||
|
// TODO: Experience gain
|
||||||
|
|
||||||
|
if let Some(battle) = battle_data.battle.upgrade() {
|
||||||
|
if !battle
|
||||||
|
.read()
|
||||||
|
.unwrap()
|
||||||
|
.can_slot_be_filled(battle_data.battle_side_index, battle_data.index)
|
||||||
|
{
|
||||||
|
let mut battle = battle.write().unwrap();
|
||||||
|
let side = &mut battle.sides_mut()[battle_data.battle_side_index as usize];
|
||||||
|
side.mark_slot_as_unfillable(self);
|
||||||
|
}
|
||||||
|
battle.write().unwrap().validate_battle_state();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> ScriptSource for Pokemon<'a> {
|
impl<'a> ScriptSource for Pokemon<'a> {
|
||||||
|
@ -373,7 +550,7 @@ impl<'a> VolatileScripts<'a> for Pokemon<'a> {
|
||||||
&self.volatile
|
&self.volatile
|
||||||
}
|
}
|
||||||
|
|
||||||
fn load_volatile_script(&self, key: &str) -> PkmnResult<Box<dyn Script>> {
|
fn load_volatile_script(&self, key: &StringKey) -> PkmnResult<Option<Box<dyn Script>>> {
|
||||||
self.library.load_script(ScriptCategory::Pokemon, key)
|
self.library.load_script(ScriptCategory::Pokemon, key)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -389,8 +566,8 @@ pub mod test {
|
||||||
#[test]
|
#[test]
|
||||||
fn construct_pokemon() {
|
fn construct_pokemon() {
|
||||||
let lib = dynamic_library::test::build();
|
let lib = dynamic_library::test::build();
|
||||||
let species = lib.static_data().species().get("foo").unwrap();
|
let species = lib.static_data().species().get(&"foo".into()).unwrap();
|
||||||
let form = species.get_form("default").unwrap();
|
let form = species.get_form(&"default".into()).unwrap();
|
||||||
|
|
||||||
let pokemon = Pokemon::new(
|
let pokemon = Pokemon::new(
|
||||||
&lib,
|
&lib,
|
||||||
|
@ -404,9 +581,9 @@ pub mod test {
|
||||||
0,
|
0,
|
||||||
Gender::Male,
|
Gender::Male,
|
||||||
0,
|
0,
|
||||||
"test_nature".to_string(),
|
&"test_nature".into(),
|
||||||
);
|
);
|
||||||
assert_eq!(pokemon.species.name(), "foo");
|
assert_eq!(pokemon.species.name(), &"foo".into());
|
||||||
assert_eq!(pokemon.form.name(), "default");
|
assert_eq!(pokemon.form.name(), &"default".into());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
pub trait ItemScript {}
|
|
@ -2,6 +2,7 @@ use crate::dynamic_data::script_handling::script::Script;
|
||||||
use crate::dynamic_data::script_handling::script_set::ScriptSet;
|
use crate::dynamic_data::script_handling::script_set::ScriptSet;
|
||||||
use std::sync::Weak;
|
use std::sync::Weak;
|
||||||
|
|
||||||
|
pub mod item_script;
|
||||||
pub mod script;
|
pub mod script;
|
||||||
pub mod script_set;
|
pub mod script_set;
|
||||||
pub mod volatile_scripts;
|
pub mod volatile_scripts;
|
||||||
|
|
|
@ -1,8 +1,11 @@
|
||||||
|
use crate::dynamic_data::models::damage_source::DamageSource;
|
||||||
use crate::dynamic_data::models::pokemon::Pokemon;
|
use crate::dynamic_data::models::pokemon::Pokemon;
|
||||||
|
use crate::static_data::moves::secondary_effect::EffectParameter;
|
||||||
|
use crate::StringKey;
|
||||||
use std::fmt::{Debug, Formatter};
|
use std::fmt::{Debug, Formatter};
|
||||||
|
|
||||||
pub trait Script {
|
pub trait Script {
|
||||||
fn name(&self) -> &str;
|
fn name(&self) -> &StringKey;
|
||||||
|
|
||||||
fn is_suppressed(&self) -> bool {
|
fn is_suppressed(&self) -> bool {
|
||||||
self.get_suppressed_count() > 0
|
self.get_suppressed_count() > 0
|
||||||
|
@ -14,7 +17,7 @@ pub trait Script {
|
||||||
// FIXME: add missing parameters
|
// FIXME: add missing parameters
|
||||||
fn stack(&self);
|
fn stack(&self);
|
||||||
fn on_remove(&self);
|
fn on_remove(&self);
|
||||||
fn on_initialize(&self);
|
fn on_initialize(&self, pars: &Vec<EffectParameter>);
|
||||||
fn on_before_turn(&self);
|
fn on_before_turn(&self);
|
||||||
fn change_speed(&self);
|
fn change_speed(&self);
|
||||||
fn change_priority(&self);
|
fn change_priority(&self);
|
||||||
|
@ -52,9 +55,9 @@ pub trait Script {
|
||||||
fn prevent_self_run_away(&self);
|
fn prevent_self_run_away(&self);
|
||||||
fn prevent_opponent_run_away(&self);
|
fn prevent_opponent_run_away(&self);
|
||||||
fn on_end_turn(&self);
|
fn on_end_turn(&self);
|
||||||
fn on_damage(&self);
|
fn on_damage(&self, pokemon: &Pokemon, source: DamageSource, old_health: u32, new_health: u32);
|
||||||
fn on_faint(&self);
|
fn on_faint(&self, pokemon: &Pokemon, source: DamageSource);
|
||||||
fn on_switch_in<'b>(&self, pokemon: &'b Pokemon);
|
fn on_switch_in(&self, pokemon: &Pokemon);
|
||||||
fn on_after_held_item_consume(&self);
|
fn on_after_held_item_consume(&self);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
use crate::dynamic_data::script_handling::script::Script;
|
use crate::dynamic_data::script_handling::script::Script;
|
||||||
use crate::PkmnResult;
|
use crate::{PkmnResult, StringKey};
|
||||||
use indexmap::IndexMap;
|
use indexmap::IndexMap;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
#[derive(Debug, Default)]
|
#[derive(Debug, Default)]
|
||||||
pub struct ScriptSet {
|
pub struct ScriptSet {
|
||||||
scripts: IndexMap<String, Arc<Box<dyn Script>>>,
|
scripts: IndexMap<StringKey, Arc<Box<dyn Script>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ScriptSet {
|
impl ScriptSet {
|
||||||
|
@ -15,33 +15,37 @@ impl ScriptSet {
|
||||||
return existing.clone();
|
return existing.clone();
|
||||||
}
|
}
|
||||||
let arc = Arc::new(script);
|
let arc = Arc::new(script);
|
||||||
self.scripts.insert(arc.name().to_string(), arc.clone());
|
self.scripts.insert(arc.name().clone(), arc.clone());
|
||||||
self.scripts.last().unwrap().1.clone()
|
self.scripts.last().unwrap().1.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn stack_or_add<'b, F>(
|
pub fn stack_or_add<'b, F>(
|
||||||
&mut self,
|
&mut self,
|
||||||
key: &str,
|
key: &StringKey,
|
||||||
instantiation: &'b F,
|
instantiation: &'b F,
|
||||||
) -> PkmnResult<Arc<Box<dyn Script>>>
|
) -> PkmnResult<Option<Arc<Box<dyn Script>>>>
|
||||||
where
|
where
|
||||||
F: Fn() -> PkmnResult<Box<dyn Script>>,
|
F: Fn() -> PkmnResult<Option<Box<dyn Script>>>,
|
||||||
{
|
{
|
||||||
if let Some(existing) = self.scripts.get(key) {
|
if let Some(existing) = self.scripts.get(key) {
|
||||||
existing.stack();
|
existing.stack();
|
||||||
return Ok(existing.clone());
|
return Ok(Some(existing.clone()));
|
||||||
}
|
}
|
||||||
let script = instantiation()?;
|
let script = instantiation()?;
|
||||||
let arc = Arc::new(script);
|
if let Some(script) = script {
|
||||||
self.scripts.insert(arc.name().to_string(), arc.clone());
|
let arc = Arc::new(script);
|
||||||
Ok(self.scripts.last().unwrap().1.clone())
|
self.scripts.insert(arc.name().clone(), arc.clone());
|
||||||
|
Ok(Some(self.scripts.last().unwrap().1.clone()))
|
||||||
|
} else {
|
||||||
|
Ok(None)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get(&self, key: &str) -> Option<&Arc<Box<dyn Script>>> {
|
pub fn get(&self, key: &StringKey) -> Option<&Arc<Box<dyn Script>>> {
|
||||||
self.scripts.get(key)
|
self.scripts.get(key)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn remove(&mut self, key: &str) {
|
pub fn remove(&mut self, key: &StringKey) {
|
||||||
let value = self.scripts.shift_remove(key);
|
let value = self.scripts.shift_remove(key);
|
||||||
if let Some(script) = value {
|
if let Some(script) = value {
|
||||||
script.on_remove();
|
script.on_remove();
|
||||||
|
@ -55,7 +59,7 @@ impl ScriptSet {
|
||||||
self.scripts.clear();
|
self.scripts.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn has(&self, key: &str) -> bool {
|
pub fn has(&self, key: &StringKey) -> bool {
|
||||||
self.scripts.contains_key(key)
|
self.scripts.contains_key(key)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,30 +1,30 @@
|
||||||
use crate::dynamic_data::script_handling::script::Script;
|
use crate::dynamic_data::script_handling::script::Script;
|
||||||
use crate::dynamic_data::script_handling::script_set::ScriptSet;
|
use crate::dynamic_data::script_handling::script_set::ScriptSet;
|
||||||
use crate::PkmnResult;
|
use crate::{PkmnResult, StringKey};
|
||||||
use std::sync::{Arc, RwLock};
|
use std::sync::{Arc, RwLock};
|
||||||
|
|
||||||
pub trait VolatileScripts<'a> {
|
pub trait VolatileScripts<'a> {
|
||||||
fn volatile_scripts(&self) -> &Arc<RwLock<ScriptSet>>;
|
fn volatile_scripts(&self) -> &Arc<RwLock<ScriptSet>>;
|
||||||
fn load_volatile_script(&self, key: &str) -> PkmnResult<Box<dyn Script>>;
|
fn load_volatile_script(&self, key: &StringKey) -> PkmnResult<Option<Box<dyn Script>>>;
|
||||||
|
|
||||||
fn has_volatile_script(&self, key: &str) -> bool {
|
fn has_volatile_script(&self, key: &StringKey) -> bool {
|
||||||
self.volatile_scripts().read().unwrap().has(key)
|
self.volatile_scripts().read().unwrap().has(key)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_volatile_script(&self, key: &str) -> Option<Arc<Box<dyn Script>>> {
|
fn get_volatile_script(&self, key: &StringKey) -> Option<Arc<Box<dyn Script>>> {
|
||||||
let scripts = self.volatile_scripts().read().unwrap();
|
let scripts = self.volatile_scripts().read().unwrap();
|
||||||
let s = scripts.get(key);
|
let s = scripts.get(key);
|
||||||
s.cloned()
|
s.cloned()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_volatile_script(&mut self, key: &str) -> PkmnResult<Arc<Box<dyn Script>>> {
|
fn add_volatile_script(&mut self, key: &StringKey) -> PkmnResult<Option<Arc<Box<dyn Script>>>> {
|
||||||
self.volatile_scripts()
|
self.volatile_scripts()
|
||||||
.write()
|
.write()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.stack_or_add(key, &|| self.load_volatile_script(key))
|
.stack_or_add(key, &|| self.load_volatile_script(key))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn remove_volatile_script(&mut self, key: &str) {
|
fn remove_volatile_script(&mut self, key: &StringKey) {
|
||||||
self.volatile_scripts().write().unwrap().remove(key)
|
self.volatile_scripts().write().unwrap().remove(key)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,12 +4,11 @@
|
||||||
#![feature(bench_black_box)]
|
#![feature(bench_black_box)]
|
||||||
#![feature(let_chains)]
|
#![feature(let_chains)]
|
||||||
|
|
||||||
#[cfg(feature = "c_interface")]
|
|
||||||
#[macro_use]
|
|
||||||
extern crate lazy_static;
|
extern crate lazy_static;
|
||||||
|
|
||||||
use crate::dynamic_data::libraries::script_resolver::ScriptCategory;
|
use crate::dynamic_data::libraries::script_resolver::ScriptCategory;
|
||||||
|
|
||||||
|
#[cfg(feature = "c_interface")]
|
||||||
mod c_interface;
|
mod c_interface;
|
||||||
|
|
||||||
pub mod defines;
|
pub mod defines;
|
||||||
|
@ -26,4 +25,6 @@ pub enum PokemonError {
|
||||||
MiscError,
|
MiscError,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub type PkmnResult<T> = std::result::Result<T, PokemonError>;
|
pub type PkmnResult<T> = Result<T, PokemonError>;
|
||||||
|
|
||||||
|
pub use utils::*;
|
||||||
|
|
|
@ -1,25 +1,26 @@
|
||||||
use super::item_category::{BattleItemCategory, ItemCategory};
|
use super::item_category::{BattleItemCategory, ItemCategory};
|
||||||
|
use crate::StringKey;
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Item {
|
pub struct Item {
|
||||||
name: String,
|
name: StringKey,
|
||||||
category: ItemCategory,
|
category: ItemCategory,
|
||||||
battle_category: BattleItemCategory,
|
battle_category: BattleItemCategory,
|
||||||
price: i32,
|
price: i32,
|
||||||
flags: HashSet<String>,
|
flags: HashSet<StringKey>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Item {
|
impl Item {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
name: &str,
|
name: &StringKey,
|
||||||
category: ItemCategory,
|
category: ItemCategory,
|
||||||
battle_category: BattleItemCategory,
|
battle_category: BattleItemCategory,
|
||||||
price: i32,
|
price: i32,
|
||||||
flags: HashSet<String>,
|
flags: HashSet<StringKey>,
|
||||||
) -> Item {
|
) -> Item {
|
||||||
Item {
|
Item {
|
||||||
name: name.to_string(),
|
name: name.clone(),
|
||||||
category,
|
category,
|
||||||
battle_category,
|
battle_category,
|
||||||
price,
|
price,
|
||||||
|
@ -27,7 +28,7 @@ impl Item {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn name(&self) -> &str {
|
pub fn name(&self) -> &StringKey {
|
||||||
&self.name
|
&self.name
|
||||||
}
|
}
|
||||||
pub fn category(&self) -> ItemCategory {
|
pub fn category(&self) -> ItemCategory {
|
||||||
|
@ -39,11 +40,11 @@ impl Item {
|
||||||
pub fn price(&self) -> i32 {
|
pub fn price(&self) -> i32 {
|
||||||
self.price
|
self.price
|
||||||
}
|
}
|
||||||
pub fn flags(&self) -> &HashSet<String> {
|
pub fn flags(&self) -> &HashSet<StringKey> {
|
||||||
&self.flags
|
&self.flags
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn has_flag(&self, key: &str) -> bool {
|
pub fn has_flag(&self, key: &StringKey) -> bool {
|
||||||
self.flags.contains(key)
|
self.flags.contains(key)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,7 @@ pub enum ItemCategory {
|
||||||
Medicine,
|
Medicine,
|
||||||
Berry,
|
Berry,
|
||||||
TMHM,
|
TMHM,
|
||||||
FormeChanger,
|
FormChanger,
|
||||||
KeyItem,
|
KeyItem,
|
||||||
Mail,
|
Mail,
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,56 @@
|
||||||
|
use crate::static_data::libraries::data_library::DataLibrary;
|
||||||
|
use crate::static_data::species_data::ability::Ability;
|
||||||
|
use crate::StringKey;
|
||||||
|
use hashbrown::HashMap;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct AbilityLibrary {
|
||||||
|
map: HashMap<StringKey, Box<Ability>>,
|
||||||
|
list: Vec<StringKey>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AbilityLibrary {
|
||||||
|
pub fn new(capacity: usize) -> AbilityLibrary {
|
||||||
|
AbilityLibrary {
|
||||||
|
map: HashMap::with_capacity(capacity),
|
||||||
|
list: Vec::with_capacity(capacity),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DataLibrary<'_, Box<Ability>> for AbilityLibrary {
|
||||||
|
fn map(&self) -> &HashMap<StringKey, Box<Ability>> {
|
||||||
|
&self.map
|
||||||
|
}
|
||||||
|
|
||||||
|
fn list_values(&self) -> &Vec<StringKey> {
|
||||||
|
&self.list
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_modify(&mut self) -> (&mut HashMap<StringKey, Box<Ability>>, &mut Vec<StringKey>) {
|
||||||
|
(&mut self.map, &mut self.list)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
pub mod tests {
|
||||||
|
use crate::static_data::libraries::ability_library::AbilityLibrary;
|
||||||
|
use crate::static_data::libraries::data_library::DataLibrary;
|
||||||
|
use crate::static_data::species_data::ability::Ability;
|
||||||
|
use crate::StringKey;
|
||||||
|
|
||||||
|
pub fn build() -> AbilityLibrary {
|
||||||
|
let mut lib = AbilityLibrary::new(1);
|
||||||
|
lib.add(
|
||||||
|
&StringKey::new("test_ability"),
|
||||||
|
Box::new(Ability::new(
|
||||||
|
&"test_ability".into(),
|
||||||
|
&"test_ability".into(),
|
||||||
|
Vec::new(),
|
||||||
|
)),
|
||||||
|
);
|
||||||
|
// Drops borrow as mut
|
||||||
|
|
||||||
|
lib
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,29 +1,30 @@
|
||||||
use crate::utils::random::Random;
|
use crate::utils::random::Random;
|
||||||
|
use crate::StringKey;
|
||||||
use hashbrown::HashMap;
|
use hashbrown::HashMap;
|
||||||
|
|
||||||
pub trait DataLibrary<'a, T: 'a> {
|
pub trait DataLibrary<'a, T: 'a> {
|
||||||
fn map(&self) -> &HashMap<String, T>;
|
fn map(&self) -> &HashMap<StringKey, T>;
|
||||||
fn list_values(&self) -> &Vec<String>;
|
fn list_values(&self) -> &Vec<StringKey>;
|
||||||
fn get_modify(&mut self) -> (&mut HashMap<String, T>, &mut Vec<String>);
|
fn get_modify(&mut self) -> (&mut HashMap<StringKey, T>, &mut Vec<StringKey>);
|
||||||
|
|
||||||
fn add(&mut self, key: &str, value: T) {
|
fn add(&mut self, key: &StringKey, value: T) {
|
||||||
let modifies = self.get_modify();
|
let modifies = self.get_modify();
|
||||||
modifies.0.insert(key.to_string(), value);
|
modifies.0.insert(key.clone(), value);
|
||||||
modifies.1.push(key.to_string());
|
modifies.1.push(key.clone());
|
||||||
}
|
}
|
||||||
|
|
||||||
fn remove(&mut self, key: &str) {
|
fn remove(&mut self, key: &StringKey) {
|
||||||
let modifies = self.get_modify();
|
let modifies = self.get_modify();
|
||||||
let index = modifies.1.iter().position(|r| *r == key).unwrap();
|
let index = modifies.1.iter().position(|r| r == key).unwrap();
|
||||||
modifies.0.remove(key);
|
modifies.0.remove(key);
|
||||||
modifies.1.remove(index);
|
modifies.1.remove(index);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get(&self, key: &str) -> Option<&T> {
|
fn get(&self, key: &StringKey) -> Option<&T> {
|
||||||
self.map().get(key)
|
self.map().get(key)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_mut(&mut self, key: &str) -> Option<&mut T> {
|
fn get_mut(&mut self, key: &StringKey) -> Option<&mut T> {
|
||||||
self.get_modify().0.get_mut(key)
|
self.get_modify().0.get_mut(key)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,11 +1,12 @@
|
||||||
use crate::defines::LevelInt;
|
use crate::defines::LevelInt;
|
||||||
use crate::static_data::growth_rates::growth_rate::GrowthRate;
|
use crate::static_data::growth_rates::growth_rate::GrowthRate;
|
||||||
|
use crate::StringKey;
|
||||||
use hashbrown::HashMap;
|
use hashbrown::HashMap;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::fmt::{Debug, Formatter};
|
use std::fmt::{Debug, Formatter};
|
||||||
|
|
||||||
pub struct GrowthRateLibrary {
|
pub struct GrowthRateLibrary {
|
||||||
growth_rates: HashMap<String, Box<dyn GrowthRate>>,
|
growth_rates: HashMap<StringKey, Box<dyn GrowthRate>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl GrowthRateLibrary {
|
impl GrowthRateLibrary {
|
||||||
|
@ -15,14 +16,14 @@ impl GrowthRateLibrary {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn calculate_level(&self, growth_rate: &str, 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)
|
||||||
}
|
}
|
||||||
pub fn calculate_experience(&self, growth_rate: &str, 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)
|
||||||
}
|
}
|
||||||
pub fn add_growth_rate(&mut self, key: &str, value: Box<dyn GrowthRate>) {
|
pub fn add_growth_rate(&mut self, key: &StringKey, value: Box<dyn GrowthRate>) {
|
||||||
self.growth_rates.insert(key.to_string(), value);
|
self.growth_rates.insert(key.clone(), value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -43,7 +44,7 @@ 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.add_growth_rate(
|
w.add_growth_rate(
|
||||||
"test_growthrate",
|
&"test_growthrate".into(),
|
||||||
Box::new(LookupGrowthRate::new(vec![0, 5, 10, 100])),
|
Box::new(LookupGrowthRate::new(vec![0, 5, 10, 100])),
|
||||||
);
|
);
|
||||||
// Drops borrow as mut
|
// Drops borrow as mut
|
||||||
|
@ -54,14 +55,14 @@ pub mod tests {
|
||||||
#[test]
|
#[test]
|
||||||
fn add_growth_rate_to_library_and_calculate_level() {
|
fn add_growth_rate_to_library_and_calculate_level() {
|
||||||
let lib = build();
|
let lib = build();
|
||||||
assert_eq!(lib.calculate_level("test_growthrate", 3), 1);
|
assert_eq!(lib.calculate_level(&"test_growthrate".into(), 3), 1);
|
||||||
assert_eq!(lib.calculate_level("test_growthrate", 50), 3);
|
assert_eq!(lib.calculate_level(&"test_growthrate".into(), 50), 3);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn add_growth_rate_to_library_and_calculate_experience() {
|
fn add_growth_rate_to_library_and_calculate_experience() {
|
||||||
let lib = build();
|
let lib = build();
|
||||||
assert_eq!(lib.calculate_experience("test_growthrate", 1), 0);
|
assert_eq!(lib.calculate_experience(&"test_growthrate".into(), 1), 0);
|
||||||
assert_eq!(lib.calculate_experience("test_growthrate", 3), 10);
|
assert_eq!(lib.calculate_experience(&"test_growthrate".into(), 3), 10);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,12 @@
|
||||||
use crate::static_data::items::item::Item;
|
use crate::static_data::items::item::Item;
|
||||||
use crate::static_data::libraries::data_library::DataLibrary;
|
use crate::static_data::libraries::data_library::DataLibrary;
|
||||||
|
use crate::StringKey;
|
||||||
use hashbrown::HashMap;
|
use hashbrown::HashMap;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct ItemLibrary {
|
pub struct ItemLibrary {
|
||||||
map: HashMap<String, Box<Item>>,
|
map: HashMap<StringKey, Box<Item>>,
|
||||||
list: Vec<String>,
|
list: Vec<StringKey>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ItemLibrary {
|
impl ItemLibrary {
|
||||||
|
@ -18,15 +19,15 @@ impl ItemLibrary {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DataLibrary<'_, Box<Item>> for ItemLibrary {
|
impl DataLibrary<'_, Box<Item>> for ItemLibrary {
|
||||||
fn map(&self) -> &HashMap<String, Box<Item>> {
|
fn map(&self) -> &HashMap<StringKey, Box<Item>> {
|
||||||
&self.map
|
&self.map
|
||||||
}
|
}
|
||||||
|
|
||||||
fn list_values(&self) -> &Vec<String> {
|
fn list_values(&self) -> &Vec<StringKey> {
|
||||||
&self.list
|
&self.list
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_modify(&mut self) -> (&mut HashMap<String, Box<Item>>, &mut Vec<String>) {
|
fn get_modify(&mut self) -> (&mut HashMap<StringKey, Box<Item>>, &mut Vec<StringKey>) {
|
||||||
(&mut self.map, &mut self.list)
|
(&mut self.map, &mut self.list)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -41,7 +42,7 @@ pub mod tests {
|
||||||
|
|
||||||
fn build_item() -> Item {
|
fn build_item() -> Item {
|
||||||
Item::new(
|
Item::new(
|
||||||
"foo",
|
&"foo".into(),
|
||||||
ItemCategory::MiscItem,
|
ItemCategory::MiscItem,
|
||||||
BattleItemCategory::MiscBattleItem,
|
BattleItemCategory::MiscBattleItem,
|
||||||
100,
|
100,
|
||||||
|
@ -54,7 +55,7 @@ pub mod tests {
|
||||||
let m = build_item();
|
let m = build_item();
|
||||||
// Borrow as mut so we can insert
|
// Borrow as mut so we can insert
|
||||||
let w = &mut lib;
|
let w = &mut lib;
|
||||||
w.add("foo", Box::from(m));
|
w.add(&"foo".into(), Box::from(m));
|
||||||
// Drops borrow as mut
|
// Drops borrow as mut
|
||||||
|
|
||||||
lib
|
lib
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
pub mod ability_library;
|
||||||
pub mod data_library;
|
pub mod data_library;
|
||||||
pub mod growth_rate_library;
|
pub mod growth_rate_library;
|
||||||
pub mod item_library;
|
pub mod item_library;
|
||||||
|
|
|
@ -1,11 +1,12 @@
|
||||||
use crate::static_data::libraries::data_library::DataLibrary;
|
use crate::static_data::libraries::data_library::DataLibrary;
|
||||||
use crate::static_data::moves::move_data::MoveData;
|
use crate::static_data::moves::move_data::MoveData;
|
||||||
|
use crate::StringKey;
|
||||||
use hashbrown::HashMap;
|
use hashbrown::HashMap;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct MoveLibrary {
|
pub struct MoveLibrary {
|
||||||
map: HashMap<String, MoveData>,
|
map: HashMap<StringKey, MoveData>,
|
||||||
list: Vec<String>,
|
list: Vec<StringKey>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MoveLibrary {
|
impl MoveLibrary {
|
||||||
|
@ -18,15 +19,15 @@ impl MoveLibrary {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DataLibrary<'_, MoveData> for MoveLibrary {
|
impl DataLibrary<'_, MoveData> for MoveLibrary {
|
||||||
fn map(&self) -> &HashMap<String, MoveData> {
|
fn map(&self) -> &HashMap<StringKey, MoveData> {
|
||||||
&self.map
|
&self.map
|
||||||
}
|
}
|
||||||
|
|
||||||
fn list_values(&self) -> &Vec<String> {
|
fn list_values(&self) -> &Vec<StringKey> {
|
||||||
&self.list
|
&self.list
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_modify(&mut self) -> (&mut HashMap<String, MoveData>, &mut Vec<String>) {
|
fn get_modify(&mut self) -> (&mut HashMap<StringKey, MoveData>, &mut Vec<StringKey>) {
|
||||||
(&mut self.map, &mut self.list)
|
(&mut self.map, &mut self.list)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -37,11 +38,12 @@ pub mod tests {
|
||||||
use crate::static_data::libraries::move_library::MoveLibrary;
|
use crate::static_data::libraries::move_library::MoveLibrary;
|
||||||
use crate::static_data::moves::move_data::{MoveCategory, MoveData, MoveTarget};
|
use crate::static_data::moves::move_data::{MoveCategory, MoveData, MoveTarget};
|
||||||
use crate::static_data::moves::secondary_effect::SecondaryEffect;
|
use crate::static_data::moves::secondary_effect::SecondaryEffect;
|
||||||
|
use crate::StringKey;
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
|
|
||||||
fn build_move() -> MoveData {
|
fn build_move() -> MoveData {
|
||||||
MoveData::new(
|
MoveData::new(
|
||||||
"foo",
|
&"foo".into(),
|
||||||
0,
|
0,
|
||||||
MoveCategory::Physical,
|
MoveCategory::Physical,
|
||||||
100,
|
100,
|
||||||
|
@ -59,7 +61,7 @@ pub mod tests {
|
||||||
let m = build_move();
|
let m = build_move();
|
||||||
// Borrow as mut so we can insert
|
// Borrow as mut so we can insert
|
||||||
let w = &mut lib;
|
let w = &mut lib;
|
||||||
w.add("foo", m);
|
w.add(&StringKey::new("foo"), m);
|
||||||
// Drops borrow as mut
|
// Drops borrow as mut
|
||||||
|
|
||||||
lib
|
lib
|
||||||
|
|
|
@ -1,11 +1,12 @@
|
||||||
use crate::static_data::libraries::data_library::DataLibrary;
|
use crate::static_data::libraries::data_library::DataLibrary;
|
||||||
use crate::static_data::species_data::species::Species;
|
use crate::static_data::species_data::species::Species;
|
||||||
|
use crate::StringKey;
|
||||||
use hashbrown::HashMap;
|
use hashbrown::HashMap;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct SpeciesLibrary<'a> {
|
pub struct SpeciesLibrary<'a> {
|
||||||
map: HashMap<String, Box<Species<'a>>>,
|
map: HashMap<StringKey, Box<Species<'a>>>,
|
||||||
list: Vec<String>,
|
list: Vec<StringKey>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> SpeciesLibrary<'a> {
|
impl<'a> SpeciesLibrary<'a> {
|
||||||
|
@ -18,15 +19,20 @@ impl<'a> SpeciesLibrary<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> DataLibrary<'a, Box<Species<'a>>> for SpeciesLibrary<'a> {
|
impl<'a> DataLibrary<'a, Box<Species<'a>>> for SpeciesLibrary<'a> {
|
||||||
fn map(&self) -> &HashMap<String, Box<Species<'a>>> {
|
fn map(&self) -> &HashMap<StringKey, Box<Species<'a>>> {
|
||||||
&self.map
|
&self.map
|
||||||
}
|
}
|
||||||
|
|
||||||
fn list_values(&self) -> &Vec<String> {
|
fn list_values(&self) -> &Vec<StringKey> {
|
||||||
&self.list
|
&self.list
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_modify(&mut self) -> (&mut HashMap<String, Box<Species<'a>>>, &mut Vec<String>) {
|
fn get_modify(
|
||||||
|
&mut self,
|
||||||
|
) -> (
|
||||||
|
&mut HashMap<StringKey, Box<Species<'a>>>,
|
||||||
|
&mut Vec<StringKey>,
|
||||||
|
) {
|
||||||
(&mut self.map, &mut self.list)
|
(&mut self.map, &mut self.list)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -44,12 +50,12 @@ pub mod tests {
|
||||||
fn build_species<'a>() -> Species<'a> {
|
fn build_species<'a>() -> Species<'a> {
|
||||||
Species::new(
|
Species::new(
|
||||||
0,
|
0,
|
||||||
"foo",
|
&"foo".into(),
|
||||||
0.5,
|
0.5,
|
||||||
"test_growthrate",
|
&"test_growthrate".into(),
|
||||||
0,
|
0,
|
||||||
Form::new(
|
Form::new(
|
||||||
"default",
|
&"default".into(),
|
||||||
0.0,
|
0.0,
|
||||||
0.0,
|
0.0,
|
||||||
0,
|
0,
|
||||||
|
@ -69,7 +75,7 @@ pub mod tests {
|
||||||
let species = build_species();
|
let species = build_species();
|
||||||
// Borrow as mut so we can insert
|
// Borrow as mut so we can insert
|
||||||
let w = &mut lib;
|
let w = &mut lib;
|
||||||
w.add("foo", Box::from(species));
|
w.add(&"foo".into(), Box::from(species));
|
||||||
// Drops borrow as mut
|
// Drops borrow as mut
|
||||||
|
|
||||||
lib
|
lib
|
||||||
|
@ -81,10 +87,10 @@ pub mod tests {
|
||||||
|
|
||||||
// Borrow as read so we can read
|
// Borrow as read so we can read
|
||||||
let r = &lib;
|
let r = &lib;
|
||||||
let mon = r.get("foo");
|
let mon = r.get(&"foo".into());
|
||||||
assert!(mon.is_some());
|
assert!(mon.is_some());
|
||||||
assert_eq!(mon.unwrap().id(), 0_u16);
|
assert_eq!(mon.unwrap().id(), 0_u16);
|
||||||
assert_eq!(mon.unwrap().as_ref().name(), "foo");
|
assert_eq!(mon.unwrap().as_ref().name(), &"foo".into());
|
||||||
assert_eq!(r.len(), 1);
|
assert_eq!(r.len(), 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -92,11 +98,11 @@ pub mod tests {
|
||||||
fn add_species_to_library_then_remove() {
|
fn add_species_to_library_then_remove() {
|
||||||
let mut lib = build();
|
let mut lib = build();
|
||||||
|
|
||||||
lib.remove("foo");
|
lib.remove(&"foo".into());
|
||||||
|
|
||||||
// Borrow as read so we can read
|
// Borrow as read so we can read
|
||||||
let r = &lib;
|
let r = &lib;
|
||||||
let mon = r.get("foo");
|
let mon = r.get(&"foo".into());
|
||||||
assert!(mon.is_none());
|
assert!(mon.is_none());
|
||||||
assert_eq!(r.len(), 0);
|
assert_eq!(r.len(), 0);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
use crate::static_data::libraries::ability_library::AbilityLibrary;
|
||||||
use crate::static_data::libraries::growth_rate_library::GrowthRateLibrary;
|
use crate::static_data::libraries::growth_rate_library::GrowthRateLibrary;
|
||||||
use crate::static_data::libraries::item_library::ItemLibrary;
|
use crate::static_data::libraries::item_library::ItemLibrary;
|
||||||
use crate::static_data::libraries::library_settings::LibrarySettings;
|
use crate::static_data::libraries::library_settings::LibrarySettings;
|
||||||
|
@ -15,6 +16,7 @@ pub struct StaticData<'a> {
|
||||||
growth_rates: GrowthRateLibrary,
|
growth_rates: GrowthRateLibrary,
|
||||||
types: TypeLibrary,
|
types: TypeLibrary,
|
||||||
natures: NatureLibrary,
|
natures: NatureLibrary,
|
||||||
|
abilities: AbilityLibrary,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> StaticData<'a> {
|
impl<'a> StaticData<'a> {
|
||||||
|
@ -26,6 +28,7 @@ impl<'a> StaticData<'a> {
|
||||||
growth_rates: GrowthRateLibrary,
|
growth_rates: GrowthRateLibrary,
|
||||||
types: TypeLibrary,
|
types: TypeLibrary,
|
||||||
natures: NatureLibrary,
|
natures: NatureLibrary,
|
||||||
|
abilities: AbilityLibrary,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
settings,
|
settings,
|
||||||
|
@ -35,6 +38,7 @@ impl<'a> StaticData<'a> {
|
||||||
growth_rates,
|
growth_rates,
|
||||||
types,
|
types,
|
||||||
natures,
|
natures,
|
||||||
|
abilities,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -59,6 +63,9 @@ impl<'a> StaticData<'a> {
|
||||||
pub fn natures(&self) -> &NatureLibrary {
|
pub fn natures(&self) -> &NatureLibrary {
|
||||||
&self.natures
|
&self.natures
|
||||||
}
|
}
|
||||||
|
pub fn abilities(&self) -> &AbilityLibrary {
|
||||||
|
&self.abilities
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
@ -66,7 +73,8 @@ pub mod test {
|
||||||
use crate::static_data::libraries::library_settings::LibrarySettings;
|
use crate::static_data::libraries::library_settings::LibrarySettings;
|
||||||
use crate::static_data::libraries::static_data::StaticData;
|
use crate::static_data::libraries::static_data::StaticData;
|
||||||
use crate::static_data::libraries::{
|
use crate::static_data::libraries::{
|
||||||
growth_rate_library, item_library, move_library, species_library, type_library,
|
ability_library, growth_rate_library, item_library, move_library, species_library,
|
||||||
|
type_library,
|
||||||
};
|
};
|
||||||
use crate::static_data::natures;
|
use crate::static_data::natures;
|
||||||
|
|
||||||
|
@ -79,6 +87,7 @@ pub mod test {
|
||||||
growth_rates: growth_rate_library::tests::build(),
|
growth_rates: growth_rate_library::tests::build(),
|
||||||
types: type_library::tests::build(),
|
types: type_library::tests::build(),
|
||||||
natures: natures::tests::build(),
|
natures: natures::tests::build(),
|
||||||
|
abilities: ability_library::tests::build(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
|
use crate::StringKey;
|
||||||
use hashbrown::HashMap;
|
use hashbrown::HashMap;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct TypeLibrary {
|
pub struct TypeLibrary {
|
||||||
types: HashMap<String, u8>,
|
types: HashMap<StringKey, u8>,
|
||||||
effectiveness: Vec<Vec<f32>>,
|
effectiveness: Vec<Vec<f32>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -14,7 +15,7 @@ impl TypeLibrary {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_type_id(&self, key: &str) -> u8 {
|
pub fn get_type_id(&self, key: &StringKey) -> u8 {
|
||||||
self.types[key]
|
self.types[key]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -30,9 +31,9 @@ impl TypeLibrary {
|
||||||
e
|
e
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn register_type(&mut self, name: &str) -> u8 {
|
pub fn register_type(&mut self, name: &StringKey) -> u8 {
|
||||||
let id = self.types.len() as u8;
|
let id = self.types.len() as u8;
|
||||||
self.types.insert(name.to_string(), id);
|
self.types.insert(name.clone(), id);
|
||||||
self.effectiveness.resize((id + 1) as usize, vec![]);
|
self.effectiveness.resize((id + 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 + 1) as usize, 1.0)
|
||||||
|
@ -55,8 +56,8 @@ 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");
|
w.register_type(&"foo".into());
|
||||||
w.register_type("bar");
|
w.register_type(&"bar".into());
|
||||||
// Drops borrow as mut
|
// Drops borrow as mut
|
||||||
|
|
||||||
w.set_effectiveness(0, 1, 0.5);
|
w.set_effectiveness(0, 1, 0.5);
|
||||||
|
@ -71,14 +72,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");
|
w.register_type(&"foo".into());
|
||||||
w.register_type("bar");
|
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"), 0);
|
assert_eq!(r.get_type_id(&"foo".into()), 0);
|
||||||
assert_eq!(r.get_type_id("bar"), 1);
|
assert_eq!(r.get_type_id(&"bar".into()), 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -87,8 +88,8 @@ 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");
|
w.register_type(&"foo".into());
|
||||||
w.register_type("bar");
|
w.register_type(&"bar".into());
|
||||||
w.set_effectiveness(0, 1, 0.5);
|
w.set_effectiveness(0, 1, 0.5);
|
||||||
w.set_effectiveness(1, 0, 2.0);
|
w.set_effectiveness(1, 0, 2.0);
|
||||||
// Drops borrow as mut
|
// Drops borrow as mut
|
||||||
|
@ -105,8 +106,8 @@ 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");
|
w.register_type(&"foo".into());
|
||||||
w.register_type("bar");
|
w.register_type(&"bar".into());
|
||||||
w.set_effectiveness(0, 1, 0.5);
|
w.set_effectiveness(0, 1, 0.5);
|
||||||
w.set_effectiveness(1, 0, 2.0);
|
w.set_effectiveness(1, 0, 2.0);
|
||||||
// Drops borrow as mut
|
// Drops borrow as mut
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
use self::super::secondary_effect::SecondaryEffect;
|
use self::super::secondary_effect::SecondaryEffect;
|
||||||
|
use crate::StringKey;
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
|
|
||||||
#[derive(PartialEq, Debug)]
|
#[derive(PartialEq, Debug)]
|
||||||
|
@ -30,7 +31,7 @@ pub enum MoveTarget {
|
||||||
|
|
||||||
#[derive(PartialEq, Debug)]
|
#[derive(PartialEq, Debug)]
|
||||||
pub struct MoveData {
|
pub struct MoveData {
|
||||||
name: String,
|
name: StringKey,
|
||||||
move_type: u8,
|
move_type: u8,
|
||||||
category: MoveCategory,
|
category: MoveCategory,
|
||||||
base_power: u8,
|
base_power: u8,
|
||||||
|
@ -44,7 +45,7 @@ pub struct MoveData {
|
||||||
|
|
||||||
impl MoveData {
|
impl MoveData {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
name: &str,
|
name: &StringKey,
|
||||||
move_type: u8,
|
move_type: u8,
|
||||||
category: MoveCategory,
|
category: MoveCategory,
|
||||||
base_power: u8,
|
base_power: u8,
|
||||||
|
@ -56,7 +57,7 @@ impl MoveData {
|
||||||
flags: HashSet<String>,
|
flags: HashSet<String>,
|
||||||
) -> MoveData {
|
) -> MoveData {
|
||||||
MoveData {
|
MoveData {
|
||||||
name: name.to_string(),
|
name: name.clone(),
|
||||||
move_type,
|
move_type,
|
||||||
category,
|
category,
|
||||||
base_power,
|
base_power,
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
use crate::static_data::statistics::Statistic;
|
use crate::static_data::statistics::Statistic;
|
||||||
|
use crate::StringKey;
|
||||||
use hashbrown::HashMap;
|
use hashbrown::HashMap;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
@ -45,7 +46,7 @@ impl Nature {
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct NatureLibrary {
|
pub struct NatureLibrary {
|
||||||
map: HashMap<String, Nature>,
|
map: HashMap<StringKey, Nature>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl NatureLibrary {
|
impl NatureLibrary {
|
||||||
|
@ -55,20 +56,20 @@ impl NatureLibrary {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn load_nature(&mut self, name: &str, nature: Nature) {
|
pub fn load_nature(&mut self, name: StringKey, nature: Nature) {
|
||||||
self.map.insert(name.to_string(), nature);
|
self.map.insert(name, nature);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_nature(&self, key: &str) -> Option<&Nature> {
|
pub fn get_nature(&self, key: &StringKey) -> Option<&Nature> {
|
||||||
self.map.get(key)
|
self.map.get(key)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_nature_name(&self, nature: &Nature) -> String {
|
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
|
||||||
// in the map, we just compare by reference.
|
// in the map, we just compare by reference.
|
||||||
if (kv.1 as *const Nature) == (nature as *const Nature) {
|
if (kv.1 as *const Nature) == (nature as *const Nature) {
|
||||||
return kv.0.to_string();
|
return kv.0.clone();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
panic!("No name was found for the given nature. This should never happen.");
|
panic!("No name was found for the given nature. This should never happen.");
|
||||||
|
@ -84,7 +85,7 @@ pub mod tests {
|
||||||
let mut lib = NatureLibrary::new(2);
|
let mut lib = NatureLibrary::new(2);
|
||||||
|
|
||||||
lib.load_nature(
|
lib.load_nature(
|
||||||
"test_nature",
|
"test_nature".into(),
|
||||||
Nature::new(Statistic::HP, Statistic::Attack, 1.1, 0.9),
|
Nature::new(Statistic::HP, Statistic::Attack, 1.1, 0.9),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -95,14 +96,14 @@ pub mod tests {
|
||||||
fn create_nature_library_insert_and_retrieve() {
|
fn create_nature_library_insert_and_retrieve() {
|
||||||
let mut lib = NatureLibrary::new(2);
|
let mut lib = NatureLibrary::new(2);
|
||||||
lib.load_nature(
|
lib.load_nature(
|
||||||
"foo",
|
"foo".into(),
|
||||||
Nature::new(Statistic::HP, Statistic::Attack, 1.1, 0.9),
|
Nature::new(Statistic::HP, Statistic::Attack, 1.1, 0.9),
|
||||||
);
|
);
|
||||||
lib.load_nature(
|
lib.load_nature(
|
||||||
"bar",
|
"bar".into(),
|
||||||
Nature::new(Statistic::Attack, Statistic::Defense, 1.1, 0.9),
|
Nature::new(Statistic::Attack, Statistic::Defense, 1.1, 0.9),
|
||||||
);
|
);
|
||||||
let n1 = lib.get_nature("foo").expect("Nature was not found");
|
let n1 = lib.get_nature(&"foo".into()).expect("Nature was not found");
|
||||||
assert_eq!(n1.increase_stat, Statistic::HP);
|
assert_eq!(n1.increase_stat, Statistic::HP);
|
||||||
assert_eq!(n1.decrease_stat, Statistic::Attack);
|
assert_eq!(n1.decrease_stat, Statistic::Attack);
|
||||||
assert_eq!(n1.increase_modifier, 1.1);
|
assert_eq!(n1.increase_modifier, 1.1);
|
||||||
|
@ -113,19 +114,19 @@ pub mod tests {
|
||||||
fn create_nature_library_insert_and_get_name() {
|
fn create_nature_library_insert_and_get_name() {
|
||||||
let mut lib = NatureLibrary::new(2);
|
let mut lib = NatureLibrary::new(2);
|
||||||
lib.load_nature(
|
lib.load_nature(
|
||||||
"foo",
|
"foo".into(),
|
||||||
Nature::new(Statistic::HP, Statistic::Attack, 1.1, 0.9),
|
Nature::new(Statistic::HP, Statistic::Attack, 1.1, 0.9),
|
||||||
);
|
);
|
||||||
lib.load_nature(
|
lib.load_nature(
|
||||||
"bar",
|
"bar".into(),
|
||||||
Nature::new(Statistic::Attack, Statistic::Defense, 1.1, 0.9),
|
Nature::new(Statistic::Attack, Statistic::Defense, 1.1, 0.9),
|
||||||
);
|
);
|
||||||
|
|
||||||
let n1 = lib.get_nature("foo").expect("Nature was not found");
|
let n1 = lib.get_nature(&"foo".into()).expect("Nature was not found");
|
||||||
let name = lib.get_nature_name(n1);
|
let name = lib.get_nature_name(n1);
|
||||||
assert_eq!(name, "foo");
|
assert_eq!(name, "foo".into());
|
||||||
let n2 = lib.get_nature("bar").expect("Nature was not found");
|
let n2 = lib.get_nature(&"bar".into()).expect("Nature was not found");
|
||||||
let name2 = lib.get_nature_name(n2);
|
let name2 = lib.get_nature_name(n2);
|
||||||
assert_eq!(name2, "bar");
|
assert_eq!(name2, "bar".into());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,29 @@
|
||||||
|
use crate::static_data::moves::secondary_effect::EffectParameter;
|
||||||
|
use crate::StringKey;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Ability {
|
||||||
|
name: StringKey,
|
||||||
|
effect: StringKey,
|
||||||
|
parameters: Vec<EffectParameter>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Ability {
|
||||||
|
pub fn new(name: &StringKey, effect: &StringKey, parameters: Vec<EffectParameter>) -> Self {
|
||||||
|
Self {
|
||||||
|
name: name.clone(),
|
||||||
|
effect: effect.clone(),
|
||||||
|
parameters,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn name(&self) -> &StringKey {
|
||||||
|
&self.name
|
||||||
|
}
|
||||||
|
pub fn effect(&self) -> &StringKey {
|
||||||
|
&self.effect
|
||||||
|
}
|
||||||
|
pub fn parameters(&self) -> &Vec<EffectParameter> {
|
||||||
|
&self.parameters
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,39 +1,42 @@
|
||||||
use self::super::learnable_moves::LearnableMoves;
|
use self::super::learnable_moves::LearnableMoves;
|
||||||
|
use crate::static_data::species_data::ability::Ability;
|
||||||
use crate::static_data::species_data::ability_index::AbilityIndex;
|
use crate::static_data::species_data::ability_index::AbilityIndex;
|
||||||
use crate::static_data::statistic_set::StatisticSet;
|
use crate::static_data::statistic_set::StatisticSet;
|
||||||
use crate::static_data::statistics::Statistic;
|
use crate::static_data::statistics::Statistic;
|
||||||
use crate::utils::random::Random;
|
use crate::utils::random::Random;
|
||||||
|
use crate::StringKey;
|
||||||
use hashbrown::HashSet;
|
use hashbrown::HashSet;
|
||||||
|
use std::ops::Deref;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Form<'a> {
|
pub struct Form<'a> {
|
||||||
name: String,
|
name: StringKey,
|
||||||
height: f32,
|
height: f32,
|
||||||
weight: f32,
|
weight: f32,
|
||||||
base_experience: u32,
|
base_experience: u32,
|
||||||
types: Vec<u8>,
|
types: Vec<u8>,
|
||||||
base_stats: StatisticSet<u16>,
|
base_stats: StatisticSet<u16>,
|
||||||
abilities: Vec<String>,
|
abilities: Vec<&'a Ability>,
|
||||||
hidden_abilities: Vec<String>,
|
hidden_abilities: Vec<&'a Ability>,
|
||||||
moves: LearnableMoves<'a>,
|
moves: LearnableMoves<'a>,
|
||||||
flags: HashSet<String>,
|
flags: HashSet<StringKey>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Form<'a> {
|
impl<'a> Form<'a> {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
name: &str,
|
name: &StringKey,
|
||||||
height: f32,
|
height: f32,
|
||||||
weight: f32,
|
weight: f32,
|
||||||
base_experience: u32,
|
base_experience: u32,
|
||||||
types: Vec<u8>,
|
types: Vec<u8>,
|
||||||
base_stats: StatisticSet<u16>,
|
base_stats: StatisticSet<u16>,
|
||||||
abilities: Vec<String>,
|
abilities: Vec<&'a Ability>,
|
||||||
hidden_abilities: Vec<String>,
|
hidden_abilities: Vec<&'a Ability>,
|
||||||
moves: LearnableMoves<'a>,
|
moves: LearnableMoves<'a>,
|
||||||
flags: HashSet<String>,
|
flags: HashSet<StringKey>,
|
||||||
) -> Form<'a> {
|
) -> Form<'a> {
|
||||||
Form {
|
Form {
|
||||||
name: name.to_string(),
|
name: name.clone(),
|
||||||
height,
|
height,
|
||||||
weight,
|
weight,
|
||||||
base_experience,
|
base_experience,
|
||||||
|
@ -46,7 +49,7 @@ impl<'a> Form<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn name(&self) -> &str {
|
pub fn name(&self) -> &StringKey {
|
||||||
&self.name
|
&self.name
|
||||||
}
|
}
|
||||||
pub fn height(&self) -> f32 {
|
pub fn height(&self) -> f32 {
|
||||||
|
@ -64,16 +67,16 @@ impl<'a> Form<'a> {
|
||||||
pub fn base_stats(&self) -> StatisticSet<u16> {
|
pub fn base_stats(&self) -> StatisticSet<u16> {
|
||||||
self.base_stats
|
self.base_stats
|
||||||
}
|
}
|
||||||
pub fn abilities(&self) -> &Vec<String> {
|
pub fn abilities(&self) -> &Vec<&'a Ability> {
|
||||||
&self.abilities
|
&self.abilities
|
||||||
}
|
}
|
||||||
pub fn hidden_abilities(&self) -> &Vec<String> {
|
pub fn hidden_abilities(&self) -> &Vec<&'a Ability> {
|
||||||
&self.hidden_abilities
|
&self.hidden_abilities
|
||||||
}
|
}
|
||||||
pub fn moves(&self) -> &LearnableMoves<'a> {
|
pub fn moves(&self) -> &LearnableMoves<'a> {
|
||||||
&self.moves
|
&self.moves
|
||||||
}
|
}
|
||||||
pub fn flags(&self) -> &HashSet<String> {
|
pub fn flags(&self) -> &HashSet<StringKey> {
|
||||||
&self.flags
|
&self.flags
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -85,9 +88,9 @@ impl<'a> Form<'a> {
|
||||||
self.base_stats.get_stat(stat)
|
self.base_stats.get_stat(stat)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn find_ability_index(&self, ability: &str) -> 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 {
|
if std::ptr::eq(a.deref(), ability as *const Ability) {
|
||||||
return Some(AbilityIndex {
|
return Some(AbilityIndex {
|
||||||
hidden: false,
|
hidden: false,
|
||||||
index: index as u8,
|
index: index as u8,
|
||||||
|
@ -95,7 +98,7 @@ impl<'a> Form<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (index, a) in self.hidden_abilities.iter().enumerate() {
|
for (index, a) in self.hidden_abilities.iter().enumerate() {
|
||||||
if a == ability {
|
if std::ptr::eq(a.deref(), ability as *const Ability) {
|
||||||
return Some(AbilityIndex {
|
return Some(AbilityIndex {
|
||||||
hidden: true,
|
hidden: true,
|
||||||
index: index as u8,
|
index: index as u8,
|
||||||
|
@ -105,15 +108,23 @@ impl<'a> Form<'a> {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_random_ability(&self, rand: &mut Random) -> &String {
|
pub fn get_ability(&self, index: AbilityIndex) -> &Ability {
|
||||||
&self.abilities[rand.get_between_unsigned(0, self.abilities.len() as u32) as usize]
|
if index.hidden {
|
||||||
|
self.hidden_abilities[index.index as usize]
|
||||||
|
} else {
|
||||||
|
self.abilities[index.index as usize]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
pub fn get_random_hidden_ability(&self, rand: &mut Random) -> &String {
|
|
||||||
&self.hidden_abilities
|
pub fn get_random_ability(&self, rand: &mut Random) -> &Ability {
|
||||||
|
self.abilities[rand.get_between_unsigned(0, self.abilities.len() as u32) as usize]
|
||||||
|
}
|
||||||
|
pub fn get_random_hidden_ability(&self, rand: &mut Random) -> &Ability {
|
||||||
|
self.hidden_abilities
|
||||||
[rand.get_between_unsigned(0, self.hidden_abilities.len() as u32) as usize]
|
[rand.get_between_unsigned(0, self.hidden_abilities.len() as u32) as usize]
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn has_flag(&self, key: &str) -> bool {
|
pub fn has_flag(&self, key: &StringKey) -> bool {
|
||||||
self.flags.contains(key)
|
self.flags.contains(key)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -46,7 +46,7 @@ mod tests {
|
||||||
#[test]
|
#[test]
|
||||||
fn adds_level_moves() {
|
fn adds_level_moves() {
|
||||||
let move1 = MoveData::new(
|
let move1 = MoveData::new(
|
||||||
"foo",
|
&"foo".into(),
|
||||||
0,
|
0,
|
||||||
MoveCategory::Physical,
|
MoveCategory::Physical,
|
||||||
0,
|
0,
|
||||||
|
@ -58,7 +58,7 @@ mod tests {
|
||||||
Default::default(),
|
Default::default(),
|
||||||
);
|
);
|
||||||
let move2 = MoveData::new(
|
let move2 = MoveData::new(
|
||||||
"bar",
|
&"bar".into(),
|
||||||
0,
|
0,
|
||||||
MoveCategory::Physical,
|
MoveCategory::Physical,
|
||||||
0,
|
0,
|
||||||
|
@ -83,7 +83,7 @@ mod tests {
|
||||||
#[test]
|
#[test]
|
||||||
fn adds_two_same_moves_at_different_level() {
|
fn adds_two_same_moves_at_different_level() {
|
||||||
let move1 = MoveData::new(
|
let move1 = MoveData::new(
|
||||||
"foo",
|
&"foo".into(),
|
||||||
0,
|
0,
|
||||||
MoveCategory::Physical,
|
MoveCategory::Physical,
|
||||||
0,
|
0,
|
||||||
|
|
|
@ -3,3 +3,4 @@ pub mod form;
|
||||||
pub mod gender;
|
pub mod gender;
|
||||||
pub mod learnable_moves;
|
pub mod learnable_moves;
|
||||||
pub mod species;
|
pub mod species;
|
||||||
|
pub mod ability;
|
||||||
|
|
|
@ -1,36 +1,40 @@
|
||||||
use self::super::form::Form;
|
use self::super::form::Form;
|
||||||
use crate::static_data::species_data::gender::Gender;
|
use crate::static_data::species_data::gender::Gender;
|
||||||
use crate::utils::random::Random;
|
use crate::utils::random::Random;
|
||||||
|
use crate::StringKey;
|
||||||
use hashbrown::{HashMap, HashSet};
|
use hashbrown::{HashMap, HashSet};
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Species<'a> {
|
pub struct Species<'a> {
|
||||||
id: u16,
|
id: u16,
|
||||||
name: String,
|
name: StringKey,
|
||||||
gender_rate: f32,
|
gender_rate: f32,
|
||||||
growth_rate: String,
|
growth_rate: StringKey,
|
||||||
capture_rate: u8,
|
capture_rate: u8,
|
||||||
forms: HashMap<String, Form<'a>>,
|
forms: HashMap<StringKey, Form<'a>>,
|
||||||
flags: HashSet<String>,
|
flags: HashSet<StringKey>,
|
||||||
|
}
|
||||||
|
lazy_static::lazy_static! {
|
||||||
|
static ref DEFAULT_KEY: StringKey = StringKey::new("default");
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Species<'a> {
|
impl<'a> Species<'a> {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
id: u16,
|
id: u16,
|
||||||
name: &str,
|
name: &StringKey,
|
||||||
gender_rate: f32,
|
gender_rate: f32,
|
||||||
growth_rate: &str,
|
growth_rate: &StringKey,
|
||||||
capture_rate: u8,
|
capture_rate: u8,
|
||||||
default_form: Form<'a>,
|
default_form: Form<'a>,
|
||||||
flags: HashSet<String>,
|
flags: HashSet<StringKey>,
|
||||||
) -> Species<'a> {
|
) -> Species<'a> {
|
||||||
let mut forms = HashMap::with_capacity(1);
|
let mut forms = HashMap::with_capacity(1);
|
||||||
forms.insert("default".to_string(), default_form);
|
forms.insert_unique_unchecked(DEFAULT_KEY.clone(), default_form);
|
||||||
Species {
|
Species {
|
||||||
id,
|
id,
|
||||||
name: name.to_string(),
|
name: name.clone(),
|
||||||
gender_rate,
|
gender_rate,
|
||||||
growth_rate: growth_rate.to_string(),
|
growth_rate: growth_rate.clone(),
|
||||||
capture_rate,
|
capture_rate,
|
||||||
forms,
|
forms,
|
||||||
flags,
|
flags,
|
||||||
|
@ -39,33 +43,37 @@ impl<'a> Species<'a> {
|
||||||
pub fn id(&self) -> u16 {
|
pub fn id(&self) -> u16 {
|
||||||
self.id
|
self.id
|
||||||
}
|
}
|
||||||
pub fn name(&self) -> &str {
|
pub fn name(&self) -> &StringKey {
|
||||||
&self.name
|
&self.name
|
||||||
}
|
}
|
||||||
pub fn gender_rate(&self) -> f32 {
|
pub fn gender_rate(&self) -> f32 {
|
||||||
self.gender_rate
|
self.gender_rate
|
||||||
}
|
}
|
||||||
pub fn growth_rate(&self) -> &str {
|
pub fn growth_rate(&self) -> &StringKey {
|
||||||
&self.growth_rate
|
&self.growth_rate
|
||||||
}
|
}
|
||||||
pub fn capture_rate(&self) -> u8 {
|
pub fn capture_rate(&self) -> u8 {
|
||||||
self.capture_rate
|
self.capture_rate
|
||||||
}
|
}
|
||||||
pub fn forms(&self) -> &HashMap<String, Form<'a>> {
|
pub fn forms(&self) -> &HashMap<StringKey, Form<'a>> {
|
||||||
&self.forms
|
&self.forms
|
||||||
}
|
}
|
||||||
pub fn flags(&self) -> &HashSet<String> {
|
pub fn flags(&self) -> &HashSet<StringKey> {
|
||||||
&self.flags
|
&self.flags
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_form(&mut self, id: String, form: Form<'a>) {
|
pub fn add_form(&mut self, id: StringKey, form: Form<'a>) {
|
||||||
self.forms.insert(id, form);
|
self.forms.insert(id, form);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_form(&self, id: &str) -> Option<&Form> {
|
pub fn get_form(&self, id: &StringKey) -> Option<&Form> {
|
||||||
self.forms.get(id)
|
self.forms.get(id)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_default_form(&self) -> &Form {
|
||||||
|
self.forms.get(&DEFAULT_KEY).unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
pub fn get_random_gender(&self, rand: &mut Random) -> Gender {
|
pub fn get_random_gender(&self, rand: &mut Random) -> Gender {
|
||||||
if self.gender_rate < 0.0 {
|
if self.gender_rate < 0.0 {
|
||||||
Gender::Genderless
|
Gender::Genderless
|
||||||
|
@ -76,7 +84,7 @@ impl<'a> Species<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn has_flag(&self, key: &str) -> bool {
|
pub fn has_flag(&self, key: &StringKey) -> bool {
|
||||||
self.flags.contains(key)
|
self.flags.contains(key)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1 +1,5 @@
|
||||||
pub mod random;
|
pub mod random;
|
||||||
|
pub mod string_key;
|
||||||
|
|
||||||
|
pub use random::Random;
|
||||||
|
pub use string_key::StringKey;
|
||||||
|
|
|
@ -0,0 +1,111 @@
|
||||||
|
use std::hash::{Hash, Hasher};
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
/// 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
|
||||||
|
/// free speed out of it. Note that StringKeys also compare case insensitive, so that for example
|
||||||
|
/// `charmander` == `Charmander`.
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub struct StringKey {
|
||||||
|
str: Arc<String>,
|
||||||
|
hash: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl StringKey {
|
||||||
|
pub const fn get_hash_const<const N: usize>(s: &[u8; N]) -> u32 {
|
||||||
|
let mut crc: u32 = 0xffffffff;
|
||||||
|
|
||||||
|
let mut i: usize = 0;
|
||||||
|
while i < N {
|
||||||
|
crc = (crc >> 8) ^ CRC_TABLE[((crc ^ (to_lower(s[i]) as u32)) & 0xff) as usize];
|
||||||
|
i += 1;
|
||||||
|
}
|
||||||
|
crc ^ 0xffffffff
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_hash(s: &str) -> u32 {
|
||||||
|
let mut crc: u32 = 0xffffffff;
|
||||||
|
for byte in s.bytes() {
|
||||||
|
crc = (crc >> 8) ^ CRC_TABLE[((crc ^ (to_lower(byte) as u32)) & 0xff) as usize];
|
||||||
|
}
|
||||||
|
crc ^ 0xffffffff
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new(s: &str) -> Self {
|
||||||
|
let hash = StringKey::get_hash(s);
|
||||||
|
Self {
|
||||||
|
str: Arc::new(s.to_string()),
|
||||||
|
hash,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn str(&self) -> &str {
|
||||||
|
self.str.as_str()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn hash(&self) -> u32 {
|
||||||
|
self.hash
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PartialEq<Self> for StringKey {
|
||||||
|
fn eq(&self, other: &Self) -> bool {
|
||||||
|
self.hash == other.hash
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Eq for StringKey {}
|
||||||
|
|
||||||
|
impl Hash for StringKey {
|
||||||
|
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||||
|
self.hash.hash(state);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<&str> for StringKey {
|
||||||
|
fn from(s: &str) -> Self {
|
||||||
|
StringKey::new(s)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const fn to_lower(c: u8) -> u8 {
|
||||||
|
if c >= b'A' && c <= b'Z' {
|
||||||
|
return c + (b'a' - b'A');
|
||||||
|
}
|
||||||
|
c
|
||||||
|
}
|
||||||
|
|
||||||
|
const CRC_TABLE: &[u32] = &[
|
||||||
|
0, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3,
|
||||||
|
0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91,
|
||||||
|
0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
|
||||||
|
0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5,
|
||||||
|
0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B,
|
||||||
|
0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
|
||||||
|
0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
|
||||||
|
0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D,
|
||||||
|
0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
|
||||||
|
0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01,
|
||||||
|
0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457,
|
||||||
|
0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
|
||||||
|
0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB,
|
||||||
|
0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9,
|
||||||
|
0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
|
||||||
|
0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD,
|
||||||
|
0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683,
|
||||||
|
0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
|
||||||
|
0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7,
|
||||||
|
0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5,
|
||||||
|
0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
|
||||||
|
0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79,
|
||||||
|
0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,
|
||||||
|
0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
|
||||||
|
0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713,
|
||||||
|
0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21,
|
||||||
|
0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
|
||||||
|
0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45,
|
||||||
|
0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB,
|
||||||
|
0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
|
||||||
|
0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,
|
||||||
|
0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D,
|
||||||
|
];
|
Loading…
Reference in New Issue