Initial work on adding documentation, reorganises modules
continuous-integration/drone/push Build is passing Details

This commit is contained in:
Deukhoofd 2022-06-19 21:34:08 +02:00
parent 715f16e2b8
commit 314e9dbe1a
Signed by: Deukhoofd
GPG Key ID: F63E044490819F6F
49 changed files with 806 additions and 473 deletions

View File

@ -1,2 +1,8 @@
/// The type we store a level in. As our implementation is aimed at normal Pokemon behaviour, a u8
/// is probably enough, as we'd go up to 100. For other users this might however not be enough. This
/// allows them to easily change it.
pub type LevelInt = u8; pub type LevelInt = u8;
/// The amount of moves a Pokemon can have at once. This is set to 4, as that is the default in most
/// current Pokemon generations. A developer should be able to modify this however.
pub const MAX_MOVES: usize = 4; pub const MAX_MOVES: usize = 4;

View File

@ -1,30 +1,49 @@
use crate::dynamic_data::models::learned_move::LearnedMove;
use crate::dynamic_data::models::pokemon::Pokemon;
use crate::dynamic_data::script_handling::script::ScriptContainer;
use crate::dynamic_data::script_handling::{ScriptSource, ScriptSourceData, ScriptWrapper};
use parking_lot::RwLock;
use std::cmp::Ordering; use std::cmp::Ordering;
use std::sync::Arc; use std::sync::Arc;
use parking_lot::RwLock;
use crate::dynamic_data::LearnedMove;
use crate::dynamic_data::Pokemon;
use crate::dynamic_data::ScriptContainer;
use crate::dynamic_data::{ScriptSource, ScriptSourceData, ScriptWrapper};
/// The data on a turn choice that should be contained in every turn choice, regardless of type.
#[derive(Debug)] #[derive(Debug)]
struct CommonChoiceData<'user, 'library> { struct CommonChoiceData<'user, 'library> {
/// The user of the turn choice
user: Arc<Pokemon<'user, 'library>>, user: Arc<Pokemon<'user, 'library>>,
/// The speed of the user at the beginning of the turn.
speed: u32, speed: u32,
/// This random value is set at the beginning of the turn. It is used for tie breaking of the
/// turn order in a predictable way, regardless of implementation and hardware.
random_value: u32, random_value: u32,
/// Whether or not the choice has failed. A failed choice will stop running, and execute special
/// fail handling during turn execution.
has_failed: bool, has_failed: bool,
/// The data we can use to retrieve scripts that are affecting this choice. This will be written
/// to once: when we need to initialize it. After that, this is only used to read. To prevent a
/// read while we're writing to it, this is a RwLock.
script_source_data: RwLock<ScriptSourceData>, script_source_data: RwLock<ScriptSourceData>,
} }
/// This enum defines a single choice for a Pokemon for a battle turn.
#[derive(Debug)] #[derive(Debug)]
pub enum TurnChoice<'user, 'library> { pub enum TurnChoice<'user, 'library> {
/// A move choice tells a Pokemon to use a move on a target for this turn.
Move(MoveChoice<'user, 'library>), Move(MoveChoice<'user, 'library>),
/// An item choice tells a Pokemon to use an item.
Item(ItemChoice<'user, 'library>), Item(ItemChoice<'user, 'library>),
/// A switch choice tells a Pokemon to switch with another Pokemon from the party.
Switch(SwitchChoice<'user, 'library>), Switch(SwitchChoice<'user, 'library>),
/// A flee choice tells a Pokemon to flee from battle.
Flee(FleeChoice<'user, 'library>), Flee(FleeChoice<'user, 'library>),
/// A pass choice tells the user to do nothing that turn.
Pass(PassChoice<'user, 'library>), Pass(PassChoice<'user, 'library>),
} }
impl<'user, 'library> TurnChoice<'user, 'library> { impl<'user, 'library> TurnChoice<'user, 'library> {
/// The shared choice data between each of the different turn choices.
fn choice_data(&self) -> &CommonChoiceData<'user, 'library> { fn choice_data(&self) -> &CommonChoiceData<'user, 'library> {
match self { match self {
TurnChoice::Move(data) => &data.choice_data, TurnChoice::Move(data) => &data.choice_data,
@ -34,6 +53,7 @@ impl<'user, 'library> TurnChoice<'user, 'library> {
TurnChoice::Pass(data) => &data.choice_data, TurnChoice::Pass(data) => &data.choice_data,
} }
} }
/// The shared choice data between each of the different turn choices.
fn choice_data_mut(&mut self) -> &mut Box<CommonChoiceData<'user, 'library>> { fn choice_data_mut(&mut self) -> &mut Box<CommonChoiceData<'user, 'library>> {
match self { match self {
TurnChoice::Move(data) => &mut data.choice_data, TurnChoice::Move(data) => &mut data.choice_data,
@ -44,34 +64,49 @@ impl<'user, 'library> TurnChoice<'user, 'library> {
} }
} }
/// Get the user of the given choice.
pub fn user(&self) -> &Arc<Pokemon<'user, 'library>> { pub fn user(&self) -> &Arc<Pokemon<'user, 'library>> {
&self.choice_data().user &self.choice_data().user
} }
/// Get the speed of the user for the choice. Note that this speed is the speed of the Pokemon
/// at the start of the turn!
pub fn speed(&self) -> u32 { pub fn speed(&self) -> u32 {
self.choice_data().speed self.choice_data().speed
} }
/// Get the mutable speed of the user for the choice. Note that this speed is the speed of the Pokemon
/// at the start of the turn!
pub fn speed_mut(&mut self) -> &mut u32 { pub fn speed_mut(&mut self) -> &mut u32 {
&mut self.choice_data_mut().speed &mut self.choice_data_mut().speed
} }
/// Gets whether or not the choice has failed. If we notice this when we execute the choice, we
/// will not execute it.
pub fn has_failed(&self) -> bool { pub fn has_failed(&self) -> bool {
self.choice_data().has_failed self.choice_data().has_failed
} }
/// Fails the choice. This will prevent it from executing and run a specific fail handling during
/// execution. Note that this can not be undone.
pub fn fail(&mut self) { pub fn fail(&mut self) {
self.choice_data_mut().has_failed = true self.choice_data_mut().has_failed = true
} }
/// The random value of a turn choice gets set during the start of a choice, and is used for tie
/// breaking of turn executions. This means that choices get executed with a predictable order,
/// regardless of implementation details.
pub(crate) fn random_value(&self) -> u32 { pub(crate) fn random_value(&self) -> u32 {
self.choice_data().random_value self.choice_data().random_value
} }
/// This sets the above random value.
pub(crate) fn set_random_value(&mut self, val: u32) { pub(crate) fn set_random_value(&mut self, val: u32) {
self.choice_data_mut().random_value = val; self.choice_data_mut().random_value = val;
} }
/// Helper function to get the move choice data from a turn. Note that this will panic if not
/// used on a move choice.
pub(crate) fn get_move_turn_data<'b>(&'b self) -> &'b MoveChoice<'user, 'library> { pub(crate) fn get_move_turn_data<'b>(&'b self) -> &'b MoveChoice<'user, 'library> {
if let TurnChoice::Move(data) = self { if let TurnChoice::Move(data) = self {
return data; return data;
@ -122,17 +157,25 @@ impl<'user, 'library> ScriptSource<'user> for TurnChoice<'user, 'library> {
} }
} }
/// The data attached to a move choice.
#[derive(Debug)] #[derive(Debug)]
pub struct MoveChoice<'user, 'library> { pub struct MoveChoice<'user, 'library> {
/// The move that is used for this choice.
used_move: Arc<LearnedMove<'library>>, used_move: Arc<LearnedMove<'library>>,
/// The side this move is aimed at.
target_side: u8, target_side: u8,
/// The index of the Pokemon on the side we're aiming at.
target_index: u8, target_index: u8,
/// The move script.
script: ScriptContainer, script: ScriptContainer,
/// The priority of the move choice at the beginning of the turn.
priority: i8, priority: i8,
/// The common turn choice data.
choice_data: Box<CommonChoiceData<'user, 'library>>, choice_data: Box<CommonChoiceData<'user, 'library>>,
} }
impl<'user, 'library> MoveChoice<'user, 'library> { impl<'user, 'library> MoveChoice<'user, 'library> {
/// Initializes the data for a new move choice.
pub fn new( pub fn new(
user: Arc<Pokemon<'user, 'library>>, user: Arc<Pokemon<'user, 'library>>,
used_move: Arc<LearnedMove<'library>>, used_move: Arc<LearnedMove<'library>>,
@ -155,29 +198,35 @@ impl<'user, 'library> MoveChoice<'user, 'library> {
} }
} }
/// The actual learned move on the Pokemon we use for this choice.
pub fn used_move(&self) -> &Arc<LearnedMove<'library>> { pub fn used_move(&self) -> &Arc<LearnedMove<'library>> {
&self.used_move &self.used_move
} }
/// The target side the move is aimed at.
pub fn target_side(&self) -> u8 { pub fn target_side(&self) -> u8 {
self.target_side self.target_side
} }
/// The Pokemon index on the side we're aiming at.
pub fn target_index(&self) -> u8 { pub fn target_index(&self) -> u8 {
self.target_index self.target_index
} }
/// The priority of the move choice at the beginning of the turn.
pub fn priority(&self) -> i8 { pub fn priority(&self) -> i8 {
self.priority self.priority
} }
/// The priority of the move choice at the beginning of the turn.
pub fn priority_mut(&mut self) -> &mut i8 {
&mut self.priority
}
/// The user of the choice.
pub fn user(&self) -> &Arc<Pokemon<'user, 'library>> { pub fn user(&self) -> &Arc<Pokemon<'user, 'library>> {
&self.choice_data.user &self.choice_data.user
} }
/// The move script of the choice.
pub fn script(&self) -> &ScriptContainer { pub fn script(&self) -> &ScriptContainer {
&self.script &self.script
} }
pub fn priority_mut(&mut self) -> &mut i8 {
&mut self.priority
}
} }
impl<'user, 'library> ScriptSource<'user> for MoveChoice<'user, 'library> { impl<'user, 'library> ScriptSource<'user> for MoveChoice<'user, 'library> {
@ -199,12 +248,15 @@ impl<'user, 'library> ScriptSource<'user> for MoveChoice<'user, 'library> {
} }
} }
/// The data given when we select an item choice.
#[derive(Debug)] #[derive(Debug)]
pub struct ItemChoice<'user, 'library> { pub struct ItemChoice<'user, 'library> {
/// The shared data of all turn choices.
choice_data: Box<CommonChoiceData<'user, 'library>>, choice_data: Box<CommonChoiceData<'user, 'library>>,
} }
impl<'user, 'library> ItemChoice<'user, 'library> { impl<'user, 'library> ItemChoice<'user, 'library> {
/// Initialised a new item choice.
pub fn new(user: Arc<Pokemon<'user, 'library>>) -> Self { pub fn new(user: Arc<Pokemon<'user, 'library>>) -> Self {
Self { Self {
choice_data: Box::new(CommonChoiceData { choice_data: Box::new(CommonChoiceData {
@ -234,12 +286,15 @@ impl<'user, 'library> ScriptSource<'user> for ItemChoice<'user, 'library> {
} }
} }
/// The data given when we select a switch choice.
#[derive(Debug)] #[derive(Debug)]
pub struct SwitchChoice<'user, 'library> { pub struct SwitchChoice<'user, 'library> {
/// The shared data of all turn choices.
choice_data: Box<CommonChoiceData<'user, 'library>>, choice_data: Box<CommonChoiceData<'user, 'library>>,
} }
impl<'user, 'library> SwitchChoice<'user, 'library> { impl<'user, 'library> SwitchChoice<'user, 'library> {
/// Initialise the turn choice data.
pub fn new(user: Arc<Pokemon<'user, 'library>>) -> Self { pub fn new(user: Arc<Pokemon<'user, 'library>>) -> Self {
Self { Self {
choice_data: Box::new(CommonChoiceData { choice_data: Box::new(CommonChoiceData {
@ -269,12 +324,15 @@ impl<'user, 'library> ScriptSource<'user> for SwitchChoice<'user, 'library> {
} }
} }
/// The data given when we select a flee choice.
#[derive(Debug)] #[derive(Debug)]
pub struct FleeChoice<'user, 'library> { pub struct FleeChoice<'user, 'library> {
/// The common data all turn choices share.
choice_data: Box<CommonChoiceData<'user, 'library>>, choice_data: Box<CommonChoiceData<'user, 'library>>,
} }
impl<'user, 'library> FleeChoice<'user, 'library> { impl<'user, 'library> FleeChoice<'user, 'library> {
/// Initialises a new flee choice.
pub fn new(user: Arc<Pokemon<'user, 'library>>) -> Self { pub fn new(user: Arc<Pokemon<'user, 'library>>) -> Self {
Self { Self {
choice_data: Box::new(CommonChoiceData { choice_data: Box::new(CommonChoiceData {
@ -304,12 +362,15 @@ impl<'user, 'library> ScriptSource<'user> for FleeChoice<'user, 'library> {
} }
} }
/// The data given when we select a pass choice.
#[derive(Debug)] #[derive(Debug)]
pub struct PassChoice<'user, 'library> { pub struct PassChoice<'user, 'library> {
/// The common data of all turn choices.
choice_data: Box<CommonChoiceData<'user, 'library>>, choice_data: Box<CommonChoiceData<'user, 'library>>,
} }
impl<'user, 'library> PassChoice<'user, 'library> { impl<'user, 'library> PassChoice<'user, 'library> {
/// Initialised a new pass choice.
pub fn new(user: Arc<Pokemon<'user, 'library>>) -> Self { pub fn new(user: Arc<Pokemon<'user, 'library>>) -> Self {
Self { Self {
choice_data: Box::new(CommonChoiceData { choice_data: Box::new(CommonChoiceData {

View File

@ -0,0 +1,111 @@
use std::fmt::{Debug, Formatter};
use crate::dynamic_data::DamageSource;
use crate::dynamic_data::ExecutingMove;
use crate::dynamic_data::Pokemon;
use crate::static_data::Form;
use crate::static_data::Species;
/// The event hook is used to store external functions that listen to events.
///
/// Events happen in many
/// different places in the battle, and can be used for GUI applications to show that these events
/// are happening.
#[derive(Default)]
pub struct EventHook {
/// All the registered event listeners on the hook.
evt_hook_function: Vec<fn(&Box<&Event>)>,
}
impl<'battle, 'library> EventHook {
/// Register a new listener. This will start receiving all events in the battle. Multiple event
/// listeners can exist at the same time. Note that for these functions the event will be disposed
/// of after the event is finished being sent.
pub fn register_listener(&mut self, func: fn(&Box<&Event>)) {
self.evt_hook_function.push(func);
}
/// Run a new event. This will send the event to all externally defined event listeners. It will
/// dispose of the event afterwards.
pub fn trigger<'b>(&self, evt: Event<'b, 'battle, 'library>) {
let b = Box::new(&evt);
for f in &self.evt_hook_function {
f(&b);
}
}
}
impl Debug for EventHook {
fn fmt(&self, _f: &mut Formatter<'_>) -> std::fmt::Result {
Ok(())
}
}
/// The different events that can occur during the battle, for which a GUI should show something.
#[derive(Debug)]
pub enum Event<'own, 'battle, 'library> {
/// A switch event happens when a Pokemon gets switched out for something else.
Switch {
/// The side the Pokemon got switched from/on
side_index: u8,
/// The index of the Pokemon that got switched in/out on its side
index: u8,
/// The new Pokemon that will be on the spot. If none, the spot will now be empty.
pokemon: Option<&'own Pokemon<'battle, 'library>>,
},
/// A swap event happens when two Pokemon on a side swap positions. Note that this is rare.
Swap {
/// The side the Pokemon swapped on.
side_index: u8,
/// The index on the side of the first Pokemon that was swapped.
index_a: u8,
/// The index on the side of the second pokemon that was swapped.
index_b: u8,
},
/// This event happens when a Pokemon changes species during battle. While not normally occuring
/// this can be useful for things such as mid-battle evolutions, which some fanmade implementations
/// enjoy.
SpeciesChange {
/// The pokemon that changed species.
pokemon: &'own Pokemon<'battle, 'library>,
/// The new species of the Pokemon.
species: &'own Species,
/// The form of the species the Pokemon will have.
form: &'own Form,
},
/// This event happens when a Pokemon changes form during battle. This is rather common.
FormChange {
/// The pokemon that changed forms.
pokemon: &'own Pokemon<'battle, 'library>,
/// The new form of the Pokemon.
form: &'own Form,
},
/// This event happens when a Pokemon takes damage.
Damage {
/// The Pokemon that takes damage.
pokemon: &'own Pokemon<'battle, 'library>,
/// The source of damage.
source: DamageSource,
/// The health of the Pokemon before the damage.
original_health: u32,
/// The health of the Pokemon after the damage.
new_health: u32,
},
/// This event happens when a Pokemon faints.
Faint {
/// The pokemon that has fainted.
pokemon: &'own Pokemon<'battle, 'library>,
},
/// This event happens when a Pokemon uses a move on a target, just before any hits.
MoveUse {
/// The data of the move used.
executing_move: &'own ExecutingMove<'own, 'battle, 'library>,
},
/// This event happens when a Pokemon missed.
Miss {
/// The pokemon that missed.
user: &'own Pokemon<'battle, 'library>,
},
/// The turn is finished running, waiting for new input.
EndTurn,
}

View File

@ -1,69 +0,0 @@
use crate::dynamic_data::models::damage_source::DamageSource;
use crate::dynamic_data::models::executing_move::ExecutingMove;
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};
#[derive(Default)]
pub struct EventHook {
evt_hook_function: Vec<fn(&Box<&Event>)>,
}
impl<'battle, 'library> EventHook {
pub fn register_listener(&mut self, func: fn(&Box<&Event>)) {
self.evt_hook_function.push(func);
}
pub fn trigger<'b>(&self, evt: Event<'b, 'battle, 'library>) {
let b = Box::new(&evt);
for f in &self.evt_hook_function {
f(&b);
}
}
}
impl Debug for EventHook {
fn fmt(&self, _f: &mut Formatter<'_>) -> std::fmt::Result {
Ok(())
}
}
#[derive(Debug)]
pub enum Event<'own, 'battle, 'library> {
Switch {
side_index: u8,
index: u8,
pokemon: Option<&'own Pokemon<'battle, 'library>>,
},
Swap {
side_index: u8,
index_a: u8,
index_b: u8,
},
SpeciesChange {
pokemon: &'own Pokemon<'battle, 'library>,
species: &'own Species,
form: &'own Form,
},
FormChange {
pokemon: &'own Pokemon<'battle, 'library>,
form: &'own Form,
},
Damage {
pokemon: &'own Pokemon<'battle, 'library>,
source: DamageSource,
original_health: u32,
new_health: u32,
},
Faint {
pokemon: &'own Pokemon<'battle, 'library>,
},
MoveUse {
executing_move: &'own ExecutingMove<'own, 'battle, 'library>,
},
Miss {
user: &'own Pokemon<'battle, 'library>,
},
EndTurn,
}

View File

@ -1 +0,0 @@
pub mod event_hook;

View File

@ -1,35 +1,60 @@
use crate::dynamic_data::choices::TurnChoice; use crate::dynamic_data::choices::TurnChoice;
use crate::dynamic_data::models::pokemon::Pokemon; use crate::dynamic_data::Pokemon;
/// The ChoiceQueue is used to run choices one by one.
///
/// It functions internally by holding a vector of choices, and passing ownership of the turn choice
/// to the turn executor one by one, replacing it with empty spots at the start. It holds several
/// helper functions to change the turn order while doing the execution. This is needed, as several
/// moves in Pokemon actively mess with this order.
#[derive(Debug)] #[derive(Debug)]
pub struct ChoiceQueue<'battle, 'library> { pub struct ChoiceQueue<'battle, 'library> {
/// Our storage of turn choices. Starts out completely filled, then slowly empties as turns get
/// executed.
queue: Vec<Option<TurnChoice<'battle, 'library>>>, queue: Vec<Option<TurnChoice<'battle, 'library>>>,
/// The current index of the turn we need to execute next.
current: usize, current: usize,
} }
impl<'battle, 'library> ChoiceQueue<'battle, 'library> { impl<'battle, 'library> ChoiceQueue<'battle, 'library> {
pub fn new(queue: Vec<Option<TurnChoice<'battle, 'library>>>) -> Self { /// Initializes a ChoiceQueue. We expect the given queue to already be sorted here.
pub(crate) fn new(queue: Vec<Option<TurnChoice<'battle, 'library>>>) -> Self {
Self { queue, current: 0 } Self { queue, current: 0 }
} }
/// Dequeues the next turn choice to be executed. This gives ownership to the callee, and replaces
/// our own reference to the turn choice with an empty spot. It also increments the current position
/// by one.
pub fn dequeue<'b>(&'b mut self) -> TurnChoice<'battle, 'library> { pub fn dequeue<'b>(&'b mut self) -> TurnChoice<'battle, 'library> {
let c = self.queue[self.current].take(); let c = self.queue[self.current].take();
self.current += 1; self.current += 1;
c.unwrap() c.unwrap()
} }
pub fn peek(&mut self) -> &'battle TurnChoice { /// This reads what the next choice to execute will be, without modifying state.
pub fn peek(&self) -> &'battle TurnChoice {
self.queue[self.current].as_ref().unwrap() self.queue[self.current].as_ref().unwrap()
} }
/// Check if we have any choices remaining.
pub fn has_next(&self) -> bool { pub fn has_next(&self) -> bool {
self.current < self.queue.len() self.current < self.queue.len()
} }
/// This resorts the yet to be executed choices. This can be useful for dealing with situations
/// such as Pokemon changing forms just after the very start of a turn, when turn order has
/// technically already been decided.
pub fn resort(&mut self) {
let len = self.queue.len();
self.queue[self.current..len].sort_unstable_by(|a, b| b.cmp(a));
}
/// This moves the choice of a specific Pokemon up to the next choice to be executed.
pub fn move_pokemon_choice_next(&mut self, _pokemon: &Pokemon) { pub fn move_pokemon_choice_next(&mut self, _pokemon: &Pokemon) {
todo!() todo!()
} }
/// Internal helper function to be easily able to iterate over the yet to be executed choices.
pub(crate) fn get_queue(&self) -> &[Option<TurnChoice<'battle, 'library>>] { pub(crate) fn get_queue(&self) -> &[Option<TurnChoice<'battle, 'library>>] {
&self.queue[self.current..self.queue.len()] &self.queue[self.current..self.queue.len()]
} }

View File

@ -1,3 +1,10 @@
pub mod choice_queue; #[doc(inline)]
pub mod target_resolver; pub use choice_queue::*;
pub mod turn_runner; #[doc(inline)]
pub use target_resolver::*;
#[doc(inline)]
pub use turn_runner::*;
mod choice_queue;
mod target_resolver;
mod turn_runner;

View File

@ -1,12 +1,16 @@
use crate::dynamic_data::models::battle::Battle;
use crate::dynamic_data::models::pokemon::Pokemon;
use crate::static_data::MoveTarget;
use num_traits::abs;
use std::ops::Deref; use std::ops::Deref;
use std::sync::Arc; use std::sync::Arc;
use num_traits::abs;
use crate::dynamic_data::Battle;
use crate::dynamic_data::Pokemon;
use crate::static_data::MoveTarget;
/// Helper type for the vector of targets we will return.
pub type TargetList<'own, 'library> = Vec<Option<Arc<Pokemon<'own, 'library>>>>; pub type TargetList<'own, 'library> = Vec<Option<Arc<Pokemon<'own, 'library>>>>;
/// This returns all Pokemon in the battle.
fn get_all_targets<'b, 'library>(battle: &Battle<'b, 'library>) -> TargetList<'b, 'library> { fn get_all_targets<'b, 'library>(battle: &Battle<'b, 'library>) -> TargetList<'b, 'library> {
let mut v = Vec::with_capacity(battle.pokemon_per_side() as usize * battle.number_of_sides() as usize); let mut v = Vec::with_capacity(battle.pokemon_per_side() as usize * battle.number_of_sides() as usize);
for side in battle.sides() { for side in battle.sides() {
@ -17,6 +21,7 @@ fn get_all_targets<'b, 'library>(battle: &Battle<'b, 'library>) -> TargetList<'b
v v
} }
/// Little helper function to get the other side. 1 --> 0, 0 --> 1
fn get_opposite_side(side: u8) -> u8 { fn get_opposite_side(side: u8) -> u8 {
if side == 0 { if side == 0 {
return 1; return 1;
@ -24,7 +29,13 @@ fn get_opposite_side(side: u8) -> u8 {
0 0
} }
fn get_all_adjacent<'b, 'library>(side: u8, index: u8, battle: &Battle<'b, 'library>) -> TargetList<'b, 'library> { /// Gets all Pokemon that are adjacent to of directly opposite of a Pokemon. This means the target,
/// the Pokemon left of it, the Pokemon right of it, and the Pokemon opposite of it.
fn get_all_adjacent_opponent<'b, 'library>(
side: u8,
index: u8,
battle: &Battle<'b, 'library>,
) -> TargetList<'b, 'library> {
let left = index as i32 - 1; let left = index as i32 - 1;
let right = index + 1; let right = index + 1;
if left < 0 && right >= battle.pokemon_per_side() { if left < 0 && right >= battle.pokemon_per_side() {
@ -57,11 +68,9 @@ fn get_all_adjacent<'b, 'library>(side: u8, index: u8, battle: &Battle<'b, 'libr
] ]
} }
fn get_all_adjacent_opponent<'b, 'library>( /// Gets all Pokemon that are adjacent to a Pokemon. This includes the target, the pokemon to the
side: u8, /// left of it, and the Pokemon to the right of it.
index: u8, fn get_all_adjacent<'b, 'library>(side: u8, index: u8, battle: &Battle<'b, 'library>) -> TargetList<'b, 'library> {
battle: &Battle<'b, 'library>,
) -> TargetList<'b, 'library> {
let left = index as i32 - 1; let left = index as i32 - 1;
let right = index + 1; let right = index + 1;
if left < 0 && right >= battle.pokemon_per_side() { if left < 0 && right >= battle.pokemon_per_side() {
@ -86,6 +95,7 @@ fn get_all_adjacent_opponent<'b, 'library>(
] ]
} }
/// Gets the target for a specific move target type, given the targeted position.
pub fn resolve_targets<'b, 'library>( pub fn resolve_targets<'b, 'library>(
side: u8, side: u8,
index: u8, index: u8,
@ -93,6 +103,8 @@ pub fn resolve_targets<'b, 'library>(
battle: &Battle<'b, 'library>, battle: &Battle<'b, 'library>,
) -> TargetList<'b, 'library> { ) -> TargetList<'b, 'library> {
match target { match target {
// These all resolve to a single position. We let the client deal with where the target is,
// and just return the Pokemon at that given target here.
MoveTarget::Adjacent MoveTarget::Adjacent
| MoveTarget::AdjacentAlly | MoveTarget::AdjacentAlly
| MoveTarget::AdjacentAllySelf | MoveTarget::AdjacentAllySelf
@ -102,9 +114,14 @@ pub fn resolve_targets<'b, 'library>(
| MoveTarget::SelfUse => { | MoveTarget::SelfUse => {
vec![battle.get_pokemon(side, index).as_ref().cloned()] vec![battle.get_pokemon(side, index).as_ref().cloned()]
} }
// If all pokemon are requested, give all Pokemon on the battlefield
MoveTarget::All => get_all_targets(battle), MoveTarget::All => get_all_targets(battle),
// If the adjacent Pokemon are requested, pass those.
MoveTarget::AllAdjacent => get_all_adjacent(side, index, battle), MoveTarget::AllAdjacent => get_all_adjacent(side, index, battle),
// If the adjacent and opponent Pokemon are requested, give those.
MoveTarget::AllAdjacentOpponent => get_all_adjacent_opponent(side, index, battle), MoveTarget::AllAdjacentOpponent => get_all_adjacent_opponent(side, index, battle),
// If all Pokemon on a side are requested, simply give all Pokemon on the side back, and let
// the client deal with what side is passed.
MoveTarget::AllAlly | MoveTarget::AllOpponent => { MoveTarget::AllAlly | MoveTarget::AllOpponent => {
let mut v = Vec::new(); let mut v = Vec::new();
for pokemon in battle.sides()[side as usize].pokemon().deref() { for pokemon in battle.sides()[side as usize].pokemon().deref() {
@ -115,6 +132,7 @@ pub fn resolve_targets<'b, 'library>(
} }
} }
/// Checks whether a given side and index are valid for a given movetarget and user.
pub fn is_valid_target(side: u8, index: u8, target: MoveTarget, user: &Pokemon) -> bool { pub fn is_valid_target(side: u8, index: u8, target: MoveTarget, user: &Pokemon) -> bool {
let user_side = user.get_battle_side_index(); let user_side = user.get_battle_side_index();
let user_index = user.get_battle_index(); let user_index = user.get_battle_index();

View File

@ -1,17 +1,19 @@
use crate::dynamic_data::choices::TurnChoice;
use crate::dynamic_data::event_hooks::event_hook::Event;
use crate::dynamic_data::flow::target_resolver::resolve_targets;
use crate::dynamic_data::models::battle::Battle;
use crate::dynamic_data::models::damage_source::DamageSource;
use crate::dynamic_data::models::executing_move::ExecutingMove;
use crate::dynamic_data::models::pokemon::Pokemon;
use crate::dynamic_data::script_handling::{ScriptSource, ScriptWrapper};
use crate::static_data::{DataLibrary, MoveCategory};
use crate::{run_scripts, script_hook, PkmnResult};
use std::ops::Deref; use std::ops::Deref;
use std::sync::Arc; use std::sync::Arc;
use crate::dynamic_data::choices::TurnChoice;
use crate::dynamic_data::event_hooks::Event;
use crate::dynamic_data::flow::target_resolver::resolve_targets;
use crate::dynamic_data::script_handling::{ScriptSource, ScriptWrapper};
use crate::dynamic_data::Battle;
use crate::dynamic_data::DamageSource;
use crate::dynamic_data::ExecutingMove;
use crate::dynamic_data::Pokemon;
use crate::static_data::{DataLibrary, MoveCategory};
use crate::{run_scripts, script_hook, PkmnResult};
impl<'own, 'library> Battle<'own, 'library> { impl<'own, 'library> Battle<'own, 'library> {
/// Execute the entire turn after the choices are all set.
pub(crate) fn run_turn(&self) -> PkmnResult<()> { pub(crate) fn run_turn(&self) -> PkmnResult<()> {
let choice_queue = self.current_turn_queue(); let choice_queue = self.current_turn_queue();
@ -60,20 +62,19 @@ impl<'own, 'library> Battle<'own, 'library> {
} }
fn execute_choice(&self, choice: &TurnChoice<'own, 'library>) -> PkmnResult<()> { fn execute_choice(&self, choice: &TurnChoice<'own, 'library>) -> PkmnResult<()> {
// A pass turn choice means the user does not intend to do anything. As such, return.
if let TurnChoice::Pass(..) = choice { if let TurnChoice::Pass(..) = choice {
return Ok(()); return Ok(());
} }
if self.has_ended() { if self.has_ended() {
return Ok(()); return Ok(());
} }
{ let user = choice.user();
let user = choice.user(); if !user.is_usable() {
if !user.is_usable() { return Ok(());
return Ok(()); }
} if !user.is_on_battlefield() {
if !user.is_on_battlefield() { return Ok(());
return Ok(());
}
} }
if !self.can_use(choice) { if !self.can_use(choice) {
return Ok(()); return Ok(());

View File

@ -1,2 +0,0 @@
#[derive(Debug)]
pub struct HistoryHolder {}

View File

@ -1 +1,3 @@
pub mod history_holder; /// The history holder holds all specific history events that happened in the battle.
#[derive(Debug)]
pub struct HistoryHolder {}

View File

@ -1,63 +1,28 @@
use crate::dynamic_data::models::pokemon::Pokemon; use std::fmt::Debug;
use crate::static_data::statistic_set::StatisticSet;
use crate::static_data::statistics::Statistic;
use std::sync::atomic::AtomicU32; use std::sync::atomic::AtomicU32;
use crate::dynamic_data::Pokemon;
use crate::static_data::Statistic;
use crate::static_data::StatisticSet;
/// A battle stat calculator is used to calculate stats for a pokemon.
pub trait BattleStatCalculator: Debug {
/// Calculate all the flat stats of a Pokemon, disregarding stat boosts.
fn calculate_flat_stats(&self, pokemon: &Pokemon, stats: &StatisticSet<AtomicU32>);
/// Calculate a single flat stat of a Pokemon, disregarding stat boost
fn calculate_flat_stat(&self, pokemon: &Pokemon, stat: Statistic) -> u32;
/// Calculate all the boosted stats of a pokemon, including stat boosts.
fn calculate_boosted_stats(&self, pokemon: &Pokemon, stats: &StatisticSet<AtomicU32>);
/// Calculate a single boosted stat of a Pokemon, including stat boosts.
fn calculate_boosted_stat(&self, pokemon: &Pokemon, stat: Statistic) -> u32;
}
/// A basic implementation of the Gen 7 stat calculator.
#[derive(Debug)] #[derive(Debug)]
pub struct BattleStatCalculator {} pub struct Gen7BattleStatCalculator {}
impl BattleStatCalculator {
pub fn calculate_flat_stats(&self, pokemon: &Pokemon, stats: &StatisticSet<AtomicU32>) {
stats.set_stat(Statistic::HP, self.calculate_health_stat(pokemon));
stats.set_stat(Statistic::Attack, self.calculate_other_stat(pokemon, Statistic::Attack));
stats.set_stat(
Statistic::Defense,
self.calculate_other_stat(pokemon, Statistic::Defense),
);
stats.set_stat(
Statistic::SpecialAttack,
self.calculate_other_stat(pokemon, Statistic::SpecialAttack),
);
stats.set_stat(
Statistic::SpecialDefense,
self.calculate_other_stat(pokemon, Statistic::SpecialDefense),
);
stats.set_stat(Statistic::Speed, self.calculate_other_stat(pokemon, Statistic::Speed));
}
pub fn calculate_flat_stat(&self, pokemon: &Pokemon, stat: Statistic) -> u32 {
if stat == Statistic::HP {
self.calculate_health_stat(pokemon)
} else {
self.calculate_other_stat(pokemon, stat)
}
}
pub fn calculate_boosted_stats(&self, pokemon: &Pokemon, stats: &StatisticSet<AtomicU32>) {
stats.set_stat(Statistic::HP, self.calculate_boosted_stat(pokemon, Statistic::HP));
stats.set_stat(
Statistic::Attack,
self.calculate_boosted_stat(pokemon, Statistic::Attack),
);
stats.set_stat(
Statistic::Defense,
self.calculate_boosted_stat(pokemon, Statistic::Defense),
);
stats.set_stat(
Statistic::SpecialAttack,
self.calculate_boosted_stat(pokemon, Statistic::SpecialAttack),
);
stats.set_stat(
Statistic::SpecialDefense,
self.calculate_boosted_stat(pokemon, Statistic::SpecialDefense),
);
stats.set_stat(Statistic::Speed, self.calculate_boosted_stat(pokemon, Statistic::Speed));
}
pub fn calculate_boosted_stat(&self, pokemon: &Pokemon, stat: Statistic) -> u32 {
(self.calculate_flat_stat(pokemon, stat) as f32 * self.get_stat_boost_modifier(pokemon, stat)) as u32
}
impl Gen7BattleStatCalculator {
/// The calculation used for health points.
fn calculate_health_stat(&self, pokemon: &Pokemon) -> u32 { fn calculate_health_stat(&self, pokemon: &Pokemon) -> u32 {
let base = pokemon.form().get_base_stat(Statistic::HP) as u32; let base = pokemon.form().get_base_stat(Statistic::HP) as u32;
let iv = pokemon.individual_values().hp() as u32; let iv = pokemon.individual_values().hp() as u32;
@ -66,6 +31,7 @@ impl BattleStatCalculator {
(((2 * base + iv + (ev / 4)) * level) / 100) + level + 10 (((2 * base + iv + (ev / 4)) * level) / 100) + level + 10
} }
/// The calculation used for all other stats
fn calculate_other_stat(&self, pokemon: &Pokemon, stat: Statistic) -> u32 { fn calculate_other_stat(&self, pokemon: &Pokemon, stat: Statistic) -> u32 {
let base = pokemon.form().get_base_stat(stat) as u32; let base = pokemon.form().get_base_stat(stat) as u32;
let iv = pokemon.individual_values().get_stat(stat) as u32; let iv = pokemon.individual_values().get_stat(stat) as u32;
@ -75,6 +41,7 @@ impl BattleStatCalculator {
return (unmodified as f32 * pokemon.nature().get_stat_modifier(stat)) as u32; return (unmodified as f32 * pokemon.nature().get_stat_modifier(stat)) as u32;
} }
/// This functions returns the modifier we need to do to a stat for a given stat boost.
fn get_stat_boost_modifier(&self, pokemon: &Pokemon, stat: Statistic) -> f32 { fn get_stat_boost_modifier(&self, pokemon: &Pokemon, stat: Statistic) -> f32 {
let boost = pokemon.stat_boost().get_stat(stat); let boost = pokemon.stat_boost().get_stat(stat);
match boost { match boost {
@ -95,3 +62,56 @@ impl BattleStatCalculator {
} }
} }
} }
impl BattleStatCalculator for Gen7BattleStatCalculator {
fn calculate_flat_stats(&self, pokemon: &Pokemon, stats: &StatisticSet<AtomicU32>) {
stats.set_stat(Statistic::HP, self.calculate_health_stat(pokemon));
stats.set_stat(Statistic::Attack, self.calculate_other_stat(pokemon, Statistic::Attack));
stats.set_stat(
Statistic::Defense,
self.calculate_other_stat(pokemon, Statistic::Defense),
);
stats.set_stat(
Statistic::SpecialAttack,
self.calculate_other_stat(pokemon, Statistic::SpecialAttack),
);
stats.set_stat(
Statistic::SpecialDefense,
self.calculate_other_stat(pokemon, Statistic::SpecialDefense),
);
stats.set_stat(Statistic::Speed, self.calculate_other_stat(pokemon, Statistic::Speed));
}
fn calculate_flat_stat(&self, pokemon: &Pokemon, stat: Statistic) -> u32 {
if stat == Statistic::HP {
self.calculate_health_stat(pokemon)
} else {
self.calculate_other_stat(pokemon, stat)
}
}
fn calculate_boosted_stats(&self, pokemon: &Pokemon, stats: &StatisticSet<AtomicU32>) {
stats.set_stat(Statistic::HP, self.calculate_boosted_stat(pokemon, Statistic::HP));
stats.set_stat(
Statistic::Attack,
self.calculate_boosted_stat(pokemon, Statistic::Attack),
);
stats.set_stat(
Statistic::Defense,
self.calculate_boosted_stat(pokemon, Statistic::Defense),
);
stats.set_stat(
Statistic::SpecialAttack,
self.calculate_boosted_stat(pokemon, Statistic::SpecialAttack),
);
stats.set_stat(
Statistic::SpecialDefense,
self.calculate_boosted_stat(pokemon, Statistic::SpecialDefense),
);
stats.set_stat(Statistic::Speed, self.calculate_boosted_stat(pokemon, Statistic::Speed));
}
fn calculate_boosted_stat(&self, pokemon: &Pokemon, stat: Statistic) -> u32 {
(self.calculate_flat_stat(pokemon, stat) as f32 * self.get_stat_boost_modifier(pokemon, stat)) as u32
}
}

View File

@ -1,9 +1,10 @@
use crate::dynamic_data::models::executing_move::{ExecutingMove, HitData}; use std::sync::Arc;
use crate::dynamic_data::models::pokemon::Pokemon;
use crate::dynamic_data::script_handling::ScriptSource; use crate::dynamic_data::script_handling::ScriptSource;
use crate::dynamic_data::Pokemon;
use crate::dynamic_data::{ExecutingMove, HitData};
use crate::script_hook; use crate::script_hook;
use crate::static_data::{MoveCategory, Statistic}; use crate::static_data::{MoveCategory, Statistic};
use std::sync::Arc;
pub trait DamageLibrary: std::fmt::Debug { pub trait DamageLibrary: std::fmt::Debug {
fn has_randomness(&self) -> bool; fn has_randomness(&self) -> bool;

View File

@ -1,19 +1,20 @@
use std::ops::Deref;
use std::sync::Arc;
use crate::dynamic_data::libraries::battle_stat_calculator::BattleStatCalculator; use crate::dynamic_data::libraries::battle_stat_calculator::BattleStatCalculator;
use crate::dynamic_data::libraries::damage_library::DamageLibrary; use crate::dynamic_data::libraries::damage_library::DamageLibrary;
use crate::dynamic_data::libraries::misc_library::MiscLibrary; use crate::dynamic_data::libraries::misc_library::MiscLibrary;
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::ItemScript;
use crate::dynamic_data::script_handling::script::Script; use crate::dynamic_data::Script;
use crate::static_data::items::item::Item; use crate::static_data::Item;
use crate::static_data::libraries::static_data::StaticData; use crate::static_data::StaticData;
use crate::{PkmnResult, StringKey}; use crate::{PkmnResult, StringKey};
use std::ops::Deref;
use std::sync::Arc;
#[derive(Debug)] #[derive(Debug)]
pub struct DynamicLibrary { pub struct DynamicLibrary {
static_data: StaticData, static_data: StaticData,
stat_calculator: BattleStatCalculator, stat_calculator: Box<dyn BattleStatCalculator>,
damage_calculator: Box<dyn DamageLibrary>, damage_calculator: Box<dyn DamageLibrary>,
misc_library: Box<dyn MiscLibrary<'static>>, misc_library: Box<dyn MiscLibrary<'static>>,
} }
@ -25,7 +26,7 @@ unsafe impl Send for DynamicLibrary {}
impl DynamicLibrary { impl DynamicLibrary {
pub fn new( pub fn new(
static_data: StaticData, static_data: StaticData,
stat_calculator: BattleStatCalculator, stat_calculator: Box<dyn BattleStatCalculator>,
damage_calculator: Box<dyn DamageLibrary>, damage_calculator: Box<dyn DamageLibrary>,
misc_library: Box<dyn MiscLibrary<'static>>, misc_library: Box<dyn MiscLibrary<'static>>,
) -> Self { ) -> Self {
@ -40,8 +41,8 @@ impl DynamicLibrary {
pub fn static_data(&self) -> &StaticData { pub fn static_data(&self) -> &StaticData {
&self.static_data &self.static_data
} }
pub fn stat_calculator(&self) -> &BattleStatCalculator { pub fn stat_calculator(&self) -> &dyn BattleStatCalculator {
&self.stat_calculator self.stat_calculator.deref()
} }
pub fn damage_calculator(&self) -> &dyn DamageLibrary { pub fn damage_calculator(&self) -> &dyn DamageLibrary {
self.damage_calculator.deref() self.damage_calculator.deref()
@ -60,16 +61,15 @@ impl DynamicLibrary {
#[cfg(test)] #[cfg(test)]
pub mod test { pub mod test {
use crate::dynamic_data::libraries::battle_stat_calculator::BattleStatCalculator; use crate::dynamic_data::libraries::battle_stat_calculator::Gen7BattleStatCalculator;
use crate::dynamic_data::libraries::damage_library::Gen7DamageLibrary; use crate::dynamic_data::libraries::damage_library::Gen7DamageLibrary;
use crate::dynamic_data::libraries::dynamic_library::DynamicLibrary; use crate::dynamic_data::libraries::dynamic_library::DynamicLibrary;
use crate::dynamic_data::libraries::misc_library::Gen7MiscLibrary; use crate::dynamic_data::libraries::misc_library::Gen7MiscLibrary;
use crate::static_data::libraries::static_data;
pub fn build() -> DynamicLibrary { pub fn build() -> DynamicLibrary {
DynamicLibrary { DynamicLibrary {
static_data: static_data::test::build(), static_data: crate::static_data::libraries::static_data::test::build(),
stat_calculator: BattleStatCalculator {}, stat_calculator: Box::new(Gen7BattleStatCalculator {}),
damage_calculator: Box::new(Gen7DamageLibrary::new(false)), damage_calculator: Box::new(Gen7DamageLibrary::new(false)),
misc_library: Box::new(Gen7MiscLibrary::new()), misc_library: Box::new(Gen7MiscLibrary::new()),
} }

View File

@ -1,16 +1,18 @@
use crate::dynamic_data::choices::{MoveChoice, SwitchChoice, TurnChoice}; use std::fmt::Debug;
use crate::dynamic_data::models::battle::Battle;
use crate::dynamic_data::models::executing_move::ExecutingMove;
use crate::dynamic_data::models::learned_move::{LearnedMove, MoveLearnMethod};
use crate::dynamic_data::models::pokemon::Pokemon;
use crate::dynamic_data::script_handling::ScriptSource;
use crate::static_data::{MoveCategory, MoveData, MoveTarget, SecondaryEffect};
use crate::{script_hook, StringKey};
use hashbrown::HashSet;
use std::fmt::{Debug, Formatter};
use std::sync::Arc; use std::sync::Arc;
pub trait MiscLibrary<'library> { use hashbrown::HashSet;
use crate::dynamic_data::choices::{MoveChoice, SwitchChoice, TurnChoice};
use crate::dynamic_data::script_handling::ScriptSource;
use crate::dynamic_data::Battle;
use crate::dynamic_data::ExecutingMove;
use crate::dynamic_data::Pokemon;
use crate::dynamic_data::{LearnedMove, MoveLearnMethod};
use crate::static_data::{MoveCategory, MoveData, MoveTarget, SecondaryEffect};
use crate::{script_hook, StringKey};
pub trait MiscLibrary<'library>: Debug {
fn is_critical( fn is_critical(
&self, &self,
battle: &Battle, battle: &Battle,
@ -29,12 +31,6 @@ pub trait MiscLibrary<'library> {
// TODO: get time // TODO: get time
} }
impl<'library> Debug for dyn MiscLibrary<'library> {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
f.write_str("MiscLibrary")
}
}
#[derive(Debug)] #[derive(Debug)]
pub struct Gen7MiscLibrary<'library> { pub struct Gen7MiscLibrary<'library> {
struggle_data: *const MoveData, struggle_data: *const MoveData,

View File

@ -1,5 +1,16 @@
pub mod battle_stat_calculator; #[doc(inline)]
pub mod damage_library; pub use battle_stat_calculator::*;
pub mod dynamic_library; #[doc(inline)]
pub mod misc_library; pub use damage_library::*;
pub mod script_resolver; #[doc(inline)]
pub use dynamic_library::*;
#[doc(inline)]
pub use misc_library::*;
#[doc(inline)]
pub use script_resolver::*;
mod battle_stat_calculator;
mod damage_library;
pub(crate) mod dynamic_library;
mod misc_library;
mod script_resolver;

View File

@ -1,7 +1,22 @@
pub mod choices; #[doc(inline)]
pub mod event_hooks; pub use choices::*;
pub mod flow; #[doc(inline)]
pub mod history; pub use event_hooks::*;
pub mod libraries; #[doc(inline)]
pub mod models; pub use flow::*;
pub mod script_handling; #[doc(inline)]
pub use history::*;
#[doc(inline)]
pub use libraries::*;
#[doc(inline)]
pub use models::*;
#[doc(inline)]
pub use script_handling::*;
mod choices;
mod event_hooks;
mod flow;
mod history;
pub(crate) mod libraries;
mod models;
mod script_handling;

View File

@ -1,24 +1,26 @@
use std::ops::{Deref, DerefMut};
use std::sync::atomic::{AtomicBool, AtomicU32, Ordering};
use std::sync::Arc;
use atomic::Atomic;
use parking_lot::RwLock;
use crate::dynamic_data::choices::TurnChoice; use crate::dynamic_data::choices::TurnChoice;
use crate::dynamic_data::event_hooks::event_hook::{Event, EventHook}; use crate::dynamic_data::event_hooks::{Event, EventHook};
use crate::dynamic_data::flow::choice_queue::ChoiceQueue; use crate::dynamic_data::history::HistoryHolder;
use crate::dynamic_data::flow::target_resolver::is_valid_target; use crate::dynamic_data::is_valid_target;
use crate::dynamic_data::history::history_holder::HistoryHolder;
use crate::dynamic_data::libraries::dynamic_library::DynamicLibrary;
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;
use crate::dynamic_data::models::battle_side::BattleSide; use crate::dynamic_data::models::battle_side::BattleSide;
use crate::dynamic_data::models::pokemon::Pokemon; use crate::dynamic_data::models::pokemon::Pokemon;
use crate::dynamic_data::script_handling::script::Script; use crate::dynamic_data::ChoiceQueue;
use crate::dynamic_data::script_handling::script_set::ScriptSet; use crate::dynamic_data::DynamicLibrary;
use crate::dynamic_data::script_handling::volatile_scripts::VolatileScripts; use crate::dynamic_data::Script;
use crate::dynamic_data::script_handling::{ScriptSource, ScriptSourceData, ScriptWrapper}; use crate::dynamic_data::ScriptSet;
use crate::{script_hook, PkmnResult, ScriptCategory, StringKey}; use crate::dynamic_data::VolatileScripts;
use atomic::Atomic; use crate::dynamic_data::{ScriptCategory, ScriptSource, ScriptSourceData, ScriptWrapper};
use parking_lot::RwLock; use crate::{script_hook, PkmnResult, StringKey};
use std::ops::{Deref, DerefMut};
use std::sync::atomic::{AtomicBool, AtomicU32, Ordering};
use std::sync::Arc;
#[derive(Debug)] #[derive(Debug)]
pub struct Battle<'own, 'library> { pub struct Battle<'own, 'library> {

View File

@ -1,10 +1,11 @@
use std::fmt::{Debug, Formatter};
use std::sync::{Arc, Mutex};
use crate::dynamic_data::models::executing_move::ExecutingMove; use crate::dynamic_data::models::executing_move::ExecutingMove;
use crate::dynamic_data::models::pokemon::Pokemon; use crate::dynamic_data::models::pokemon::Pokemon;
use crate::dynamic_data::script_handling::ScriptSource; use crate::dynamic_data::script_handling::ScriptSource;
use crate::script_hook; use crate::script_hook;
use crate::utils::random::Random; use crate::utils::Random;
use std::fmt::{Debug, Formatter};
use std::sync::{Arc, Mutex};
#[derive(Default)] #[derive(Default)]
pub struct BattleRandom { pub struct BattleRandom {

View File

@ -1,19 +1,21 @@
use crate::dynamic_data::choices::TurnChoice;
use crate::dynamic_data::event_hooks::event_hook::Event;
use crate::dynamic_data::models::battle::Battle;
use crate::dynamic_data::models::battle_party::BattleParty;
use crate::dynamic_data::models::pokemon::Pokemon;
use crate::dynamic_data::script_handling::script::Script;
use crate::dynamic_data::script_handling::script_set::ScriptSet;
use crate::dynamic_data::script_handling::volatile_scripts::VolatileScripts;
use crate::dynamic_data::script_handling::{ScriptSource, ScriptSourceData, ScriptWrapper};
use crate::{script_hook, PkmnResult, StringKey};
use parking_lot::lock_api::RwLockReadGuard;
use parking_lot::{RawRwLock, RwLock};
use std::ops::Deref; use std::ops::Deref;
use std::sync::atomic::{AtomicBool, AtomicU8, Ordering}; use std::sync::atomic::{AtomicBool, AtomicU8, Ordering};
use std::sync::Arc; use std::sync::Arc;
use parking_lot::lock_api::RwLockReadGuard;
use parking_lot::{RawRwLock, RwLock};
use crate::dynamic_data::choices::TurnChoice;
use crate::dynamic_data::event_hooks::Event;
use crate::dynamic_data::models::battle::Battle;
use crate::dynamic_data::models::battle_party::BattleParty;
use crate::dynamic_data::models::pokemon::Pokemon;
use crate::dynamic_data::script_handling::{ScriptSource, ScriptSourceData, ScriptWrapper};
use crate::dynamic_data::Script;
use crate::dynamic_data::ScriptSet;
use crate::dynamic_data::VolatileScripts;
use crate::{script_hook, PkmnResult, StringKey};
#[derive(Debug)] #[derive(Debug)]
pub struct BattleSide<'own, 'library> { pub struct BattleSide<'own, 'library> {
index: u8, index: u8,

View File

@ -1,16 +1,18 @@
use crate::dynamic_data::flow::target_resolver::TargetList;
use crate::dynamic_data::models::learned_move::LearnedMove;
use crate::dynamic_data::models::pokemon::Pokemon;
use crate::dynamic_data::script_handling::script::ScriptContainer;
use crate::dynamic_data::script_handling::{ScriptSource, ScriptSourceData, ScriptWrapper};
use crate::static_data::MoveData;
use crate::{PkmnResult, PokemonError};
use atomic::Atomic;
use parking_lot::RwLock;
use std::ops::Deref; use std::ops::Deref;
use std::sync::atomic::{AtomicBool, AtomicU32, AtomicU8, Ordering}; use std::sync::atomic::{AtomicBool, AtomicU32, AtomicU8, Ordering};
use std::sync::Arc; use std::sync::Arc;
use atomic::Atomic;
use parking_lot::RwLock;
use crate::dynamic_data::models::learned_move::LearnedMove;
use crate::dynamic_data::models::pokemon::Pokemon;
use crate::dynamic_data::script_handling::{ScriptSource, ScriptSourceData, ScriptWrapper};
use crate::dynamic_data::ScriptContainer;
use crate::dynamic_data::TargetList;
use crate::static_data::MoveData;
use crate::{PkmnResult, PokemonError};
#[derive(Default, Debug)] #[derive(Default, Debug)]
pub struct HitData { pub struct HitData {
critical: AtomicBool, critical: AtomicBool,

View File

@ -1,11 +1,34 @@
pub mod battle; #[doc(inline)]
pub mod battle_party; pub use battle::*;
pub mod battle_random; #[doc(inline)]
pub mod battle_result; pub use battle_party::*;
pub mod battle_side; #[doc(inline)]
pub mod damage_source; pub use battle_random::*;
pub mod executing_move; #[doc(inline)]
pub mod learned_move; pub use battle_result::*;
pub mod pokemon; #[doc(inline)]
pub mod pokemon_builder; pub use battle_side::*;
pub mod pokemon_party; #[doc(inline)]
pub use damage_source::*;
#[doc(inline)]
pub use executing_move::*;
#[doc(inline)]
pub use learned_move::*;
#[doc(inline)]
pub use pokemon::*;
#[doc(inline)]
pub use pokemon_builder::*;
#[doc(inline)]
pub use pokemon_party::*;
mod battle;
mod battle_party;
mod battle_random;
mod battle_result;
mod battle_side;
mod damage_source;
mod executing_move;
mod learned_move;
mod pokemon;
mod pokemon_builder;
mod pokemon_party;

View File

@ -1,30 +1,29 @@
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::models::battle::Battle;
use crate::dynamic_data::models::damage_source::DamageSource;
use crate::dynamic_data::models::learned_move::{LearnedMove, MoveLearnMethod};
use crate::dynamic_data::script_handling::script::{Script, ScriptContainer};
use crate::dynamic_data::script_handling::script_set::ScriptSet;
use crate::dynamic_data::script_handling::volatile_scripts::VolatileScripts;
use crate::dynamic_data::script_handling::{ScriptSource, ScriptSourceData, ScriptWrapper};
use crate::static_data::items::item::Item;
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::form::Form;
use crate::static_data::species_data::gender::Gender;
use crate::static_data::species_data::species::Species;
use crate::static_data::statistic_set::{ClampedStatisticSet, StatisticSet};
use crate::static_data::DataLibrary;
use crate::utils::random::Random;
use crate::{script_hook, PkmnResult, ScriptCategory, StringKey};
use atomic::Atomic;
use parking_lot::RwLock;
use std::ops::{Deref, DerefMut}; use std::ops::{Deref, DerefMut};
use std::sync::atomic::{AtomicBool, AtomicI8, AtomicU32, AtomicU8, Ordering}; use std::sync::atomic::{AtomicBool, AtomicI8, AtomicU32, AtomicU8, Ordering};
use std::sync::{Arc, Weak}; use std::sync::{Arc, Weak};
use atomic::Atomic;
use parking_lot::RwLock;
use crate::defines::{LevelInt, MAX_MOVES};
use crate::dynamic_data::event_hooks::Event;
use crate::dynamic_data::models::battle::Battle;
use crate::dynamic_data::models::damage_source::DamageSource;
use crate::dynamic_data::models::learned_move::{LearnedMove, MoveLearnMethod};
use crate::dynamic_data::script_handling::{ScriptSource, ScriptSourceData, ScriptWrapper};
use crate::dynamic_data::{DynamicLibrary, Script, ScriptCategory, ScriptContainer, ScriptSet, VolatileScripts};
use crate::static_data::Ability;
use crate::static_data::AbilityIndex;
use crate::static_data::DataLibrary;
use crate::static_data::Form;
use crate::static_data::Gender;
use crate::static_data::Item;
use crate::static_data::Nature;
use crate::static_data::Species;
use crate::static_data::{ClampedStatisticSet, StatisticSet};
use crate::utils::Random;
use crate::{script_hook, PkmnResult, StringKey};
#[derive(Debug)] #[derive(Debug)]
pub struct PokemonBattleData<'pokemon, 'library> { pub struct PokemonBattleData<'pokemon, 'library> {
battle: *mut Battle<'pokemon, 'library>, battle: *mut Battle<'pokemon, 'library>,
@ -585,15 +584,15 @@ impl<'own, 'library> VolatileScripts<'own> for Pokemon<'own, 'library> {
#[cfg(test)] #[cfg(test)]
pub mod test { pub mod test {
use crate::dynamic_data::libraries::dynamic_library;
use crate::dynamic_data::models::pokemon::Pokemon; use crate::dynamic_data::models::pokemon::Pokemon;
use crate::static_data::libraries::data_library::DataLibrary; use crate::dynamic_data::DynamicLibrary;
use crate::static_data::species_data::ability_index::AbilityIndex; use crate::static_data::AbilityIndex;
use crate::static_data::species_data::gender::Gender; use crate::static_data::DataLibrary;
use crate::static_data::Gender;
#[test] #[test]
fn construct_pokemon() { fn construct_pokemon() {
let lib = dynamic_library::test::build(); let lib = crate::dynamic_data::libraries::dynamic_library::test::build();
let species = lib.static_data().species().get(&"foo".into()).unwrap(); let species = lib.static_data().species().get(&"foo".into()).unwrap();
let form = species.get_form(&"default".into()).unwrap(); let form = species.get_form(&"default".into()).unwrap();

View File

@ -1,7 +1,7 @@
use crate::defines::LevelInt; use crate::defines::LevelInt;
use crate::dynamic_data::libraries::dynamic_library::DynamicLibrary;
use crate::dynamic_data::models::learned_move::MoveLearnMethod; 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::static_data::{AbilityIndex, DataLibrary, Gender}; use crate::static_data::{AbilityIndex, DataLibrary, Gender};
use crate::StringKey; use crate::StringKey;

View File

@ -1,12 +1,20 @@
use crate::dynamic_data::script_handling::script::{Script, ScriptContainer};
use crate::dynamic_data::script_handling::script_set::ScriptSet;
use parking_lot::RwLock;
use std::sync::{Arc, Weak}; use std::sync::{Arc, Weak};
pub mod item_script; use parking_lot::RwLock;
pub mod script;
pub mod script_set; #[doc(inline)]
pub mod volatile_scripts; pub use item_script::*;
#[doc(inline)]
pub use script::*;
#[doc(inline)]
pub use script_set::*;
#[doc(inline)]
pub use volatile_scripts::*;
mod item_script;
mod script;
mod script_set;
mod volatile_scripts;
#[macro_export] #[macro_export]
macro_rules! script_hook { macro_rules! script_hook {
@ -25,21 +33,6 @@ macro_rules! script_hook {
}; };
} }
#[macro_export]
macro_rules! script_hook_on_lock {
($hook_name: ident, $source: ident, $($parameters: expr),*) => {
let mut aggregator = $source.read().get_script_iterator();
while let Some(script) = aggregator.get_next() {
let lock = &mut script.get().read();
let script = lock.as_mut().unwrap();
if script.is_suppressed() {
continue;
}
script.$hook_name($($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),*) => {
@ -198,12 +191,14 @@ impl ScriptAggregator {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use std::any::Any;
use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering};
use crate::dynamic_data::script_handling::script::ScriptContainer; use crate::dynamic_data::script_handling::script::ScriptContainer;
use crate::static_data::EffectParameter; use crate::static_data::EffectParameter;
use crate::StringKey; use crate::StringKey;
use std::any::Any;
use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering}; use super::*;
pub struct TestScript { pub struct TestScript {
name: StringKey, name: StringKey,

View File

@ -1,12 +1,3 @@
use crate::dynamic_data::choices::{MoveChoice, TurnChoice};
use crate::dynamic_data::models::battle::Battle;
use crate::dynamic_data::models::damage_source::DamageSource;
use crate::dynamic_data::models::executing_move::ExecutingMove;
use crate::dynamic_data::models::pokemon::Pokemon;
use crate::static_data::moves::secondary_effect::EffectParameter;
use crate::static_data::{Item, Statistic};
use crate::StringKey;
use parking_lot::{MappedRwLockReadGuard, RwLock, RwLockReadGuard};
use std::any::Any; use std::any::Any;
use std::fmt::{Debug, Formatter}; use std::fmt::{Debug, Formatter};
use std::ops::Deref; use std::ops::Deref;
@ -14,6 +5,17 @@ use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering};
use std::sync::Arc; use std::sync::Arc;
use std::thread::JoinHandle; use std::thread::JoinHandle;
use parking_lot::{MappedRwLockReadGuard, RwLock, RwLockReadGuard};
use crate::dynamic_data::choices::{MoveChoice, TurnChoice};
use crate::dynamic_data::Battle;
use crate::dynamic_data::DamageSource;
use crate::dynamic_data::ExecutingMove;
use crate::dynamic_data::Pokemon;
use crate::static_data::EffectParameter;
use crate::static_data::{Item, Statistic};
use crate::StringKey;
pub trait Script: Send + Sync { pub trait Script: Send + Sync {
fn name(&self) -> &StringKey; fn name(&self) -> &StringKey;
fn get_marked_for_deletion(&self) -> &AtomicBool; fn get_marked_for_deletion(&self) -> &AtomicBool;
@ -231,9 +233,10 @@ impl Clone for ScriptContainer {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*;
use std::sync::atomic::{AtomicBool, AtomicPtr}; use std::sync::atomic::{AtomicBool, AtomicPtr};
use super::*;
pub struct TestScript { pub struct TestScript {
name: StringKey, name: StringKey,
container: AtomicPtr<ScriptContainer>, container: AtomicPtr<ScriptContainer>,

View File

@ -1,6 +1,8 @@
// The too many arguments is annoying, especially for when we create constructors, disable. // The too many arguments is annoying, especially for when we create constructor, disable.
#![allow(clippy::too_many_arguments, clippy::needless_range_loop)] #![allow(clippy::too_many_arguments, clippy::needless_range_loop)]
#![allow(clippy::not_unsafe_ptr_arg_deref)] #![allow(clippy::not_unsafe_ptr_arg_deref)]
#![warn(missing_docs)]
#![warn(clippy::missing_docs_in_private_items)]
#![feature(test)] #![feature(test)]
#![feature(bench_black_box)] #![feature(bench_black_box)]
#![feature(let_chains)] #![feature(let_chains)]
@ -8,22 +10,45 @@
#![feature(const_option)] #![feature(const_option)]
#![feature(is_some_with)] #![feature(is_some_with)]
//! PkmnLib
//! PkmnLib is a full featured implementation of Pokemon. while currently focused on implementing
//! generation 7, this library tries to offload generational differences such as move effects
//! to a scripting library.
//!
extern crate core; extern crate core;
use crate::dynamic_data::libraries::script_resolver::ScriptCategory; #[doc(hidden)]
pub use utils::*;
use crate::dynamic_data::ScriptCategory;
/// The defines module holds the core defines of the library
pub mod defines; pub mod defines;
/// The dynamic data module holds data that can change during execution, and things that relate to
/// this. This includes things as Pokemon themselves, battles, etc.
pub mod dynamic_data; pub mod dynamic_data;
/// The static data module holds data that can be set once, and then never change. This includes
/// things such as data about Pokemon species, data about items, etc.
pub mod static_data; pub mod static_data;
/// The utils module includes misc utils that are used within PkmnLib
pub mod utils; pub mod utils;
/// The PokemonError enum holds all different error states that can be encountered in PkmnLib.
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub enum PokemonError { pub enum PokemonError {
ScriptNotFound { category: ScriptCategory, name: String }, /// A script was requested, but we were unable to find it.
MiscError, ScriptNotFound {
/// The category of the script we requested,
category: ScriptCategory,
/// The unique key of the requested script.
name: StringKey,
},
/// We requested data for a specific target, but that target does not exist on the battle field.
InvalidTargetRequested, InvalidTargetRequested,
/// Misc errors. Use of this should be minimized, but it is useful for early development.
MiscError,
} }
/// A simple result type.
pub type PkmnResult<T> = Result<T, PokemonError>; pub type PkmnResult<T> = Result<T, PokemonError>;
pub use utils::*;

View File

@ -1,5 +1,9 @@
use crate::defines::LevelInt; use crate::defines::LevelInt;
use crate::static_data::growth_rates::growth_rate::GrowthRate;
pub trait GrowthRate {
fn calculate_level(&self, experience: u32) -> LevelInt;
fn calculate_experience(&self, level: LevelInt) -> u32;
}
pub struct LookupGrowthRate { pub struct LookupGrowthRate {
experience: Vec<u32>, experience: Vec<u32>,

View File

@ -1,6 +0,0 @@
use crate::defines::LevelInt;
pub trait GrowthRate {
fn calculate_level(&self, experience: u32) -> LevelInt;
fn calculate_experience(&self, level: LevelInt) -> u32;
}

View File

@ -1,5 +0,0 @@
pub mod growth_rate;
pub mod lookup_growth_rate;
pub use growth_rate::*;
pub use lookup_growth_rate::*;

View File

@ -1,6 +1,33 @@
use super::item_category::{BattleItemCategory, ItemCategory};
use crate::StringKey;
use hashbrown::HashSet; use hashbrown::HashSet;
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
use crate::StringKey;
#[derive(Debug, Copy, Clone)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[repr(u8)]
pub enum ItemCategory {
MiscItem,
Pokeball,
Medicine,
Berry,
TMHM,
FormChanger,
KeyItem,
Mail,
}
#[derive(Debug, Copy, Clone)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[repr(u8)]
pub enum BattleItemCategory {
None,
Healing,
StatusHealing,
Pokeball,
MiscBattleItem,
}
#[derive(Debug)] #[derive(Debug)]
pub struct Item { pub struct Item {

View File

@ -1,27 +0,0 @@
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
#[derive(Debug, Copy, Clone)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[repr(u8)]
pub enum ItemCategory {
MiscItem,
Pokeball,
Medicine,
Berry,
TMHM,
FormChanger,
KeyItem,
Mail,
}
#[derive(Debug, Copy, Clone)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[repr(u8)]
pub enum BattleItemCategory {
None,
Healing,
StatusHealing,
Pokeball,
MiscBattleItem,
}

View File

@ -1,5 +0,0 @@
pub mod item;
pub mod item_category;
pub use item::*;
pub use item_category::*;

View File

@ -1,7 +1,8 @@
use hashbrown::HashMap;
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;
use hashbrown::HashMap;
#[derive(Debug)] #[derive(Debug)]
pub struct AbilityLibrary { pub struct AbilityLibrary {
@ -34,9 +35,9 @@ impl DataLibrary<'_, Box<Ability>> for AbilityLibrary {
#[cfg(test)] #[cfg(test)]
pub mod tests { pub mod tests {
use crate::static_data::libraries::ability_library::AbilityLibrary; use crate::static_data::Ability;
use crate::static_data::libraries::data_library::DataLibrary; use crate::static_data::AbilityLibrary;
use crate::static_data::species_data::ability::Ability; use crate::static_data::DataLibrary;
use crate::StringKey; use crate::StringKey;
pub fn build() -> AbilityLibrary { pub fn build() -> AbilityLibrary {

View File

@ -1,9 +1,11 @@
use std::fmt;
use std::fmt::{Debug, Formatter};
use hashbrown::HashMap;
use crate::defines::LevelInt; use crate::defines::LevelInt;
use crate::static_data::GrowthRate; use crate::static_data::GrowthRate;
use crate::StringKey; use crate::StringKey;
use hashbrown::HashMap;
use std::fmt;
use std::fmt::{Debug, Formatter};
pub struct GrowthRateLibrary { pub struct GrowthRateLibrary {
growth_rates: HashMap<StringKey, Box<dyn GrowthRate>>, growth_rates: HashMap<StringKey, Box<dyn GrowthRate>>,
@ -35,7 +37,7 @@ impl Debug for GrowthRateLibrary {
#[cfg(test)] #[cfg(test)]
pub mod tests { pub mod tests {
use crate::static_data::growth_rates::lookup_growth_rate::LookupGrowthRate; use crate::static_data::growth_rates::LookupGrowthRate;
use crate::static_data::libraries::growth_rate_library::GrowthRateLibrary; use crate::static_data::libraries::growth_rate_library::GrowthRateLibrary;
pub fn build() -> GrowthRateLibrary { pub fn build() -> GrowthRateLibrary {

View File

@ -1,7 +1,8 @@
use hashbrown::HashMap;
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;
use hashbrown::HashMap;
#[derive(Debug)] #[derive(Debug)]
pub struct ItemLibrary { pub struct ItemLibrary {
@ -34,11 +35,12 @@ impl DataLibrary<'_, Box<Item>> for ItemLibrary {
#[cfg(test)] #[cfg(test)]
pub mod tests { pub mod tests {
use crate::static_data::items::item::Item; use hashbrown::HashSet;
use crate::static_data::items::item_category::{BattleItemCategory, ItemCategory};
use crate::static_data::libraries::data_library::DataLibrary; use crate::static_data::libraries::data_library::DataLibrary;
use crate::static_data::libraries::item_library::ItemLibrary; use crate::static_data::libraries::item_library::ItemLibrary;
use hashbrown::HashSet; use crate::static_data::Item;
use crate::static_data::{BattleItemCategory, ItemCategory};
fn build_item() -> Item { fn build_item() -> Item {
Item::new( Item::new(

View File

@ -1,19 +1,28 @@
pub mod ability_library; #[doc(inline)]
pub mod data_library;
pub mod growth_rate_library;
pub mod item_library;
pub mod library_settings;
pub mod move_library;
pub mod species_library;
pub mod static_data;
pub mod type_library;
pub use ability_library::AbilityLibrary; pub use ability_library::AbilityLibrary;
#[doc(inline)]
pub use data_library::DataLibrary; pub use data_library::DataLibrary;
#[doc(inline)]
pub use growth_rate_library::GrowthRateLibrary; pub use growth_rate_library::GrowthRateLibrary;
#[doc(inline)]
pub use item_library::ItemLibrary; pub use item_library::ItemLibrary;
#[doc(inline)]
pub use library_settings::LibrarySettings; pub use library_settings::LibrarySettings;
#[doc(inline)]
pub use move_library::MoveLibrary; pub use move_library::MoveLibrary;
#[doc(inline)]
pub use species_library::SpeciesLibrary; pub use species_library::SpeciesLibrary;
#[doc(inline)]
pub use static_data::StaticData; pub use static_data::StaticData;
#[doc(inline)]
pub use type_library::TypeLibrary; pub use type_library::TypeLibrary;
mod ability_library;
mod data_library;
mod growth_rate_library;
mod item_library;
mod library_settings;
mod move_library;
mod species_library;
pub(crate) mod static_data;
mod type_library;

View File

@ -1,7 +1,8 @@
use hashbrown::HashMap;
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;
use hashbrown::HashMap;
#[derive(Debug)] #[derive(Debug)]
pub struct MoveLibrary { pub struct MoveLibrary {
@ -34,11 +35,12 @@ impl DataLibrary<'_, MoveData> for MoveLibrary {
#[cfg(test)] #[cfg(test)]
pub mod tests { pub mod tests {
use hashbrown::HashSet;
use crate::static_data::libraries::data_library::DataLibrary; use crate::static_data::libraries::data_library::DataLibrary;
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::{MoveCategory, MoveData, MoveTarget};
use crate::StringKey; use crate::StringKey;
use hashbrown::HashSet;
fn build_move() -> MoveData { fn build_move() -> MoveData {
MoveData::new( MoveData::new(

View File

@ -1,7 +1,8 @@
use hashbrown::HashMap;
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;
use hashbrown::HashMap;
#[derive(Debug)] #[derive(Debug)]
pub struct SpeciesLibrary { pub struct SpeciesLibrary {
@ -34,13 +35,14 @@ impl<'a> DataLibrary<'a, Box<Species>> for SpeciesLibrary {
#[cfg(test)] #[cfg(test)]
pub mod tests { pub mod tests {
use hashbrown::HashSet;
use crate::static_data::libraries::data_library::DataLibrary; use crate::static_data::libraries::data_library::DataLibrary;
use crate::static_data::libraries::species_library::SpeciesLibrary; use crate::static_data::libraries::species_library::SpeciesLibrary;
use crate::static_data::species_data::form::Form; use crate::static_data::Form;
use crate::static_data::species_data::learnable_moves::LearnableMoves; use crate::static_data::LearnableMoves;
use crate::static_data::species_data::species::Species; use crate::static_data::Species;
use crate::static_data::StaticStatisticSet; use crate::static_data::StaticStatisticSet;
use hashbrown::HashSet;
fn build_species() -> Species { fn build_species() -> Species {
Species::new( Species::new(

View File

@ -1,17 +1,25 @@
pub mod growth_rates; #[doc(inline)]
pub mod items;
pub mod libraries;
pub mod moves;
pub mod natures;
pub mod species_data;
pub mod statistic_set;
pub mod statistics;
pub use growth_rates::*; pub use growth_rates::*;
#[doc(inline)]
pub use items::*; pub use items::*;
#[doc(inline)]
pub use libraries::*; pub use libraries::*;
#[doc(inline)]
pub use moves::*; pub use moves::*;
#[doc(inline)]
pub use natures::*; pub use natures::*;
#[doc(inline)]
pub use species_data::*; pub use species_data::*;
#[doc(inline)]
pub use statistic_set::*; pub use statistic_set::*;
#[doc(inline)]
pub use statistics::*; pub use statistics::*;
mod growth_rates;
mod items;
pub(crate) mod libraries;
mod moves;
mod natures;
mod species_data;
mod statistic_set;
mod statistics;

View File

@ -1,9 +1,7 @@
pub mod move_data; #[doc(inline)]
pub mod secondary_effect; pub use move_data::*;
#[doc(inline)]
pub use secondary_effect::*;
pub use move_data::MoveCategory; mod move_data;
pub use move_data::MoveData; mod secondary_effect;
pub use move_data::MoveTarget;
pub use secondary_effect::EffectParameter;
pub use secondary_effect::SecondaryEffect;

View File

@ -1,13 +1,19 @@
pub mod ability; #[doc(inline)]
pub mod ability_index;
pub mod form;
pub mod gender;
pub mod learnable_moves;
pub mod species;
pub use ability::Ability; pub use ability::Ability;
#[doc(inline)]
pub use ability_index::AbilityIndex; pub use ability_index::AbilityIndex;
#[doc(inline)]
pub use form::Form; pub use form::Form;
#[doc(inline)]
pub use gender::Gender; pub use gender::Gender;
#[doc(inline)]
pub use learnable_moves::LearnableMoves; pub use learnable_moves::LearnableMoves;
#[doc(inline)]
pub use species::Species; pub use species::Species;
mod ability;
mod ability_index;
mod form;
mod gender;
mod learnable_moves;
mod species;

View File

@ -1,18 +1,30 @@
use super::statistics::Statistic;
use atomic_prim_traits::AtomicInt;
use num_traits::{clamp, NumCast, PrimInt};
use std::sync::atomic::Ordering; use std::sync::atomic::Ordering;
use atomic_prim_traits::AtomicInt;
use num_traits::{clamp, NumCast, PrimInt};
use super::statistics::Statistic;
/// A collection of every individual stat. This set can hold any value that is valid for its integer
/// type, and can be modified at will.
///
/// As all data in this type is atomic, threaded access to this struct is completely legal.
#[derive(Default, Eq, PartialEq, Clone, Debug)] #[derive(Default, Eq, PartialEq, Clone, Debug)]
pub struct StatisticSet<T> pub struct StatisticSet<T>
where where
T: AtomicInt, T: AtomicInt,
{ {
/// The health point stat value.
hp: T, hp: T,
/// The physical attack stat value.
attack: T, attack: T,
/// The physical defense stat value.
defense: T, defense: T,
/// The special attack stat value.
special_attack: T, special_attack: T,
/// The special defense stat value.
special_defense: T, special_defense: T,
/// The speed stat value.
speed: T, speed: T,
} }
@ -20,6 +32,7 @@ impl<T> StatisticSet<T>
where where
T: AtomicInt, T: AtomicInt,
{ {
/// Creates a new statistic set with given stats.
pub fn new( pub fn new(
hp: T::Prim, hp: T::Prim,
attack: T::Prim, attack: T::Prim,
@ -38,25 +51,32 @@ where
} }
} }
/// The health point stat value.
pub fn hp(&self) -> T::Prim { pub fn hp(&self) -> T::Prim {
self.hp.load(Ordering::Relaxed) self.hp.load(Ordering::Relaxed)
} }
/// The physical attack stat value.
pub fn attack(&self) -> T::Prim { pub fn attack(&self) -> T::Prim {
self.attack.load(Ordering::Relaxed) self.attack.load(Ordering::Relaxed)
} }
/// The physical defense stat value.
pub fn defense(&self) -> T::Prim { pub fn defense(&self) -> T::Prim {
self.defense.load(Ordering::Relaxed) self.defense.load(Ordering::Relaxed)
} }
/// The special attack stat value.
pub fn special_attack(&self) -> T::Prim { pub fn special_attack(&self) -> T::Prim {
self.special_attack.load(Ordering::Relaxed) self.special_attack.load(Ordering::Relaxed)
} }
/// The special defense stat value.
pub fn special_defense(&self) -> T::Prim { pub fn special_defense(&self) -> T::Prim {
self.special_defense.load(Ordering::Relaxed) self.special_defense.load(Ordering::Relaxed)
} }
/// The speed stat value.
pub fn speed(&self) -> T::Prim { pub fn speed(&self) -> T::Prim {
self.speed.load(Ordering::Relaxed) self.speed.load(Ordering::Relaxed)
} }
/// Get the value of a specific stat
pub fn get_stat(&self, stat: Statistic) -> T::Prim { pub fn get_stat(&self, stat: Statistic) -> T::Prim {
match stat { match stat {
Statistic::HP => self.hp.load(Ordering::Relaxed), Statistic::HP => self.hp.load(Ordering::Relaxed),
@ -68,6 +88,7 @@ where
} }
} }
/// Modify the value of a specific stat.
pub fn set_stat(&self, stat: Statistic, value: T::Prim) { pub fn set_stat(&self, stat: Statistic, value: T::Prim) {
match stat { match stat {
Statistic::HP => self.hp.store(value, Ordering::SeqCst), Statistic::HP => self.hp.store(value, Ordering::SeqCst),
@ -79,6 +100,7 @@ where
} }
} }
/// Increase the value of a given stat by a value.
pub fn increase_stat(&self, stat: Statistic, value: T::Prim) { pub fn increase_stat(&self, stat: Statistic, value: T::Prim) {
match stat { match stat {
Statistic::HP => self.hp.fetch_add(value, Ordering::SeqCst), Statistic::HP => self.hp.fetch_add(value, Ordering::SeqCst),
@ -90,6 +112,7 @@ where
}; };
} }
/// Decrease the value of a given stat by a value.
pub fn decrease_stat(&self, stat: Statistic, value: T::Prim) { pub fn decrease_stat(&self, stat: Statistic, value: T::Prim) {
match stat { match stat {
Statistic::HP => self.hp.fetch_sub(value, Ordering::SeqCst), Statistic::HP => self.hp.fetch_sub(value, Ordering::SeqCst),
@ -102,16 +125,25 @@ where
} }
} }
/// A collection of statistics that can not be modified after creation.
///
/// As no modifications happen, this struct does not use atomics.
#[derive(Default, Eq, PartialEq, Clone, Debug)] #[derive(Default, Eq, PartialEq, Clone, Debug)]
pub struct StaticStatisticSet<T> pub struct StaticStatisticSet<T>
where where
T: PrimInt, T: PrimInt,
{ {
/// The health point stat value.
hp: T, hp: T,
/// The physical attack stat value.
attack: T, attack: T,
/// The physical defense stat value.
defense: T, defense: T,
/// The special attack stat value.
special_attack: T, special_attack: T,
/// The special defense stat value.
special_defense: T, special_defense: T,
/// The speed stat value.
speed: T, speed: T,
} }
@ -119,6 +151,7 @@ impl<T> StaticStatisticSet<T>
where where
T: PrimInt, T: PrimInt,
{ {
/// Create a new static statistic set.
pub const fn new(hp: T, attack: T, defense: T, special_attack: T, special_defense: T, speed: T) -> Self { pub const fn new(hp: T, attack: T, defense: T, special_attack: T, special_defense: T, speed: T) -> Self {
Self { Self {
hp, hp,
@ -130,25 +163,32 @@ where
} }
} }
/// The health point stat value.=
pub const fn hp(&self) -> T { pub const fn hp(&self) -> T {
self.hp self.hp
} }
/// The physical attack stat value.
pub const fn attack(&self) -> T { pub const fn attack(&self) -> T {
self.attack self.attack
} }
/// The physical defense stat value.
pub const fn defense(&self) -> T { pub const fn defense(&self) -> T {
self.defense self.defense
} }
/// The special attack stat value.
pub const fn special_attack(&self) -> T { pub const fn special_attack(&self) -> T {
self.special_attack self.special_attack
} }
/// The special defense stat value.
pub const fn special_defense(&self) -> T { pub const fn special_defense(&self) -> T {
self.special_defense self.special_defense
} }
/// The speed stat value.
pub const fn speed(&self) -> T { pub const fn speed(&self) -> T {
self.speed self.speed
} }
/// Get the value of a specific stat
pub const fn get_stat(&self, stat: Statistic) -> T { pub const fn get_stat(&self, stat: Statistic) -> T {
match stat { match stat {
Statistic::HP => self.hp, Statistic::HP => self.hp,
@ -166,14 +206,22 @@ pub struct ClampedStatisticSet<T, const MIN: i64, const MAX: i64>
where where
T: AtomicInt, T: AtomicInt,
{ {
/// The health point stat value.
hp: T, hp: T,
/// The physical attack stat value.
attack: T, attack: T,
/// The physical defense stat value.
defense: T, defense: T,
/// The special attack stat value.
special_attack: T, special_attack: T,
/// The special defense stat value.
special_defense: T, special_defense: T,
/// The speed stat value.
speed: T, speed: T,
} }
/// A clamped statistic set is a collection of each statistics that can be modified, but that will
/// always remain between two compile time constant values (Min, Max).
impl<T, const MIN: i64, const MAX: i64> ClampedStatisticSet<T, MIN, MAX> impl<T, const MIN: i64, const MAX: i64> ClampedStatisticSet<T, MIN, MAX>
where where
T: AtomicInt, T: AtomicInt,
@ -302,9 +350,10 @@ where
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*;
use std::sync::atomic::AtomicI32; use std::sync::atomic::AtomicI32;
use super::*;
#[test] #[test]
fn create_get_values() { fn create_get_values() {
let set = StatisticSet::<AtomicI32>::new(1, 2, 3, 4, 5, 6); let set = StatisticSet::<AtomicI32>::new(1, 2, 3, 4, 5, 6);

View File

@ -1,5 +1,7 @@
pub mod random; #[doc(inline)]
pub mod string_key;
pub use random::Random; pub use random::Random;
#[doc(inline)]
pub use string_key::StringKey; pub use string_key::StringKey;
mod random;
mod string_key;

View File

@ -1,6 +1,7 @@
use pkmn_lib::dynamic_data::models::battle::Battle;
use serde::Deserialize; use serde::Deserialize;
use pkmn_lib::dynamic_data::Battle;
#[derive(Deserialize)] #[derive(Deserialize)]
#[serde(rename_all = "snake_case")] #[serde(rename_all = "snake_case")]
pub enum TestDataGetter { pub enum TestDataGetter {

View File

@ -1,22 +1,24 @@
use std::convert::TryFrom;
use std::fmt::Debug;
use std::fs::File;
use std::io::Read;
use hashbrown::HashSet; use hashbrown::HashSet;
use num_traits::PrimInt; use num_traits::PrimInt;
use project_root::get_project_root;
use serde_json::Value;
use pkmn_lib::defines::LevelInt; use pkmn_lib::defines::LevelInt;
use pkmn_lib::dynamic_data::libraries::battle_stat_calculator::BattleStatCalculator; use pkmn_lib::dynamic_data::DynamicLibrary;
use pkmn_lib::dynamic_data::libraries::damage_library::Gen7DamageLibrary; use pkmn_lib::dynamic_data::Gen7BattleStatCalculator;
use pkmn_lib::dynamic_data::libraries::dynamic_library::DynamicLibrary; use pkmn_lib::dynamic_data::Gen7DamageLibrary;
use pkmn_lib::dynamic_data::libraries::misc_library::Gen7MiscLibrary; use pkmn_lib::dynamic_data::Gen7MiscLibrary;
use pkmn_lib::static_data::{ use pkmn_lib::static_data::{
Ability, AbilityLibrary, BattleItemCategory, DataLibrary, EffectParameter, Form, GrowthRateLibrary, Item, Ability, AbilityLibrary, BattleItemCategory, DataLibrary, EffectParameter, Form, GrowthRateLibrary, Item,
ItemLibrary, LearnableMoves, LibrarySettings, LookupGrowthRate, MoveData, MoveLibrary, Nature, NatureLibrary, ItemLibrary, LearnableMoves, LibrarySettings, LookupGrowthRate, MoveData, MoveLibrary, Nature, NatureLibrary,
SecondaryEffect, Species, StaticData, StaticStatisticSet, Statistic, TypeLibrary, SecondaryEffect, Species, StaticData, StaticStatisticSet, Statistic, TypeLibrary,
}; };
use pkmn_lib::StringKey; use pkmn_lib::StringKey;
use project_root::get_project_root;
use serde_json::Value;
use std::convert::TryFrom;
use std::fmt::Debug;
use std::fs::File;
use std::io::Read;
pub fn load_library() -> DynamicLibrary { pub fn load_library() -> DynamicLibrary {
let mut path = get_project_root().unwrap(); let mut path = get_project_root().unwrap();
@ -32,7 +34,7 @@ pub fn load_library() -> DynamicLibrary {
load_species(&path, &mut data); load_species(&path, &mut data);
let dynamic = DynamicLibrary::new( let dynamic = DynamicLibrary::new(
data, data,
BattleStatCalculator {}, Box::new(Gen7BattleStatCalculator {}),
Box::new(Gen7DamageLibrary::new(false)), Box::new(Gen7DamageLibrary::new(false)),
Box::new(Gen7MiscLibrary::new()), Box::new(Gen7MiscLibrary::new()),
); );

View File

@ -1,15 +1,18 @@
use super::test_step::TestStep;
use pkmn_lib::defines::LevelInt;
use pkmn_lib::dynamic_data::libraries::dynamic_library::DynamicLibrary;
use pkmn_lib::dynamic_data::models::battle::Battle;
use pkmn_lib::dynamic_data::models::battle_party::BattleParty;
use pkmn_lib::dynamic_data::models::pokemon::Pokemon;
use pkmn_lib::dynamic_data::models::pokemon_builder::PokemonBuilder;
use pkmn_lib::dynamic_data::models::pokemon_party::PokemonParty;
use pkmn_lib::StringKey;
use serde::Deserialize;
use std::sync::Arc; use std::sync::Arc;
use serde::Deserialize;
use pkmn_lib::defines::LevelInt;
use pkmn_lib::dynamic_data::Battle;
use pkmn_lib::dynamic_data::BattleParty;
use pkmn_lib::dynamic_data::DynamicLibrary;
use pkmn_lib::dynamic_data::Pokemon;
use pkmn_lib::dynamic_data::PokemonBuilder;
use pkmn_lib::dynamic_data::PokemonParty;
use pkmn_lib::StringKey;
use super::test_step::TestStep;
#[derive(Deserialize)] #[derive(Deserialize)]
pub struct TestCase { pub struct TestCase {
pub name: String, pub name: String,

View File

@ -1,9 +1,11 @@
use super::data_getter::TestDataGetter;
use pkmn_lib::dynamic_data::choices::{MoveChoice, PassChoice, TurnChoice};
use pkmn_lib::dynamic_data::models::battle::Battle;
use pkmn_lib::StringKey;
use serde::Deserialize; use serde::Deserialize;
use pkmn_lib::dynamic_data::Battle;
use pkmn_lib::dynamic_data::{MoveChoice, PassChoice, TurnChoice};
use pkmn_lib::StringKey;
use super::data_getter::TestDataGetter;
#[derive(Deserialize)] #[derive(Deserialize)]
#[serde(rename_all = "snake_case")] #[serde(rename_all = "snake_case")]
pub enum TestStep { pub enum TestStep {

View File

@ -2,13 +2,15 @@
#![feature(once_cell)] #![feature(once_cell)]
#![test_runner(datatest::runner)] #![test_runner(datatest::runner)]
use crate::common::{library_loader, TestCase};
use pkmn_lib::dynamic_data::libraries::dynamic_library::DynamicLibrary;
use std::fs::File; use std::fs::File;
use std::io::Read; use std::io::Read;
use std::lazy::SyncLazy; use std::lazy::SyncLazy;
use std::path::Path; use std::path::Path;
use pkmn_lib::dynamic_data::DynamicLibrary;
use crate::common::{library_loader, TestCase};
pub mod common; pub mod common;
static LIBRARY: SyncLazy<DynamicLibrary> = SyncLazy::new(|| { static LIBRARY: SyncLazy<DynamicLibrary> = SyncLazy::new(|| {