This commit is contained in:
@@ -7,7 +7,6 @@ use parking_lot::RwLock;
|
||||
|
||||
use crate::dynamic_data::choices::TurnChoice;
|
||||
use crate::dynamic_data::event_hooks::{Event, EventHook};
|
||||
use crate::dynamic_data::is_valid_target;
|
||||
use crate::dynamic_data::models::battle_party::BattleParty;
|
||||
use crate::dynamic_data::models::battle_random::BattleRandom;
|
||||
use crate::dynamic_data::models::battle_result::BattleResult;
|
||||
@@ -17,8 +16,9 @@ use crate::dynamic_data::ChoiceQueue;
|
||||
use crate::dynamic_data::DynamicLibrary;
|
||||
use crate::dynamic_data::Script;
|
||||
use crate::dynamic_data::ScriptSet;
|
||||
use crate::dynamic_data::VolatileScripts;
|
||||
use crate::dynamic_data::{ScriptCategory, ScriptSource, ScriptSourceData, ScriptWrapper};
|
||||
use crate::dynamic_data::VolatileScriptsOwner;
|
||||
use crate::dynamic_data::{is_valid_target, ScriptWrapper};
|
||||
use crate::dynamic_data::{ScriptCategory, ScriptSource, ScriptSourceData};
|
||||
use crate::{script_hook, PkmnResult, StringKey};
|
||||
|
||||
/// A pokemon battle, with any amount of sides and pokemon per side.
|
||||
@@ -322,7 +322,7 @@ impl<'own, 'library> Battle<'own, 'library> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'own, 'library> VolatileScripts<'own> for Battle<'own, 'library> {
|
||||
impl<'own, 'library> VolatileScriptsOwner<'own> for Battle<'own, 'library> {
|
||||
fn volatile_scripts(&self) -> &Arc<ScriptSet> {
|
||||
&self.volatile_scripts
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@ use crate::dynamic_data::models::pokemon::Pokemon;
|
||||
use crate::dynamic_data::script_handling::{ScriptSource, ScriptSourceData, ScriptWrapper};
|
||||
use crate::dynamic_data::Script;
|
||||
use crate::dynamic_data::ScriptSet;
|
||||
use crate::dynamic_data::VolatileScripts;
|
||||
use crate::dynamic_data::VolatileScriptsOwner;
|
||||
use crate::{script_hook, PkmnResult, StringKey};
|
||||
|
||||
/// A side on a battle.
|
||||
@@ -296,7 +296,7 @@ impl<'own, 'library> BattleSide<'own, 'library> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'own, 'library> VolatileScripts<'own> for BattleSide<'own, 'library> {
|
||||
impl<'own, 'library> VolatileScriptsOwner<'own> for BattleSide<'own, 'library> {
|
||||
fn volatile_scripts(&self) -> &Arc<ScriptSet> {
|
||||
&self.volatile_scripts
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ use crate::dynamic_data::models::pokemon::Pokemon;
|
||||
use crate::dynamic_data::script_handling::{ScriptSource, ScriptSourceData, ScriptWrapper};
|
||||
use crate::dynamic_data::ScriptContainer;
|
||||
use crate::dynamic_data::TargetList;
|
||||
use crate::static_data::MoveData;
|
||||
use crate::static_data::{MoveData, TypeIdentifier};
|
||||
use crate::{PkmnResult, PokemonError};
|
||||
|
||||
/// A hit data is the data for a single hit, on a single target.
|
||||
@@ -25,7 +25,7 @@ pub struct HitData {
|
||||
/// The actual damage of the hit.
|
||||
damage: AtomicU32,
|
||||
/// The type id of the type used for the hit.
|
||||
move_type: AtomicU8,
|
||||
move_type: Atomic<TypeIdentifier>,
|
||||
/// Whether or not the hit has failed.
|
||||
has_failed: AtomicBool,
|
||||
}
|
||||
@@ -48,7 +48,7 @@ impl HitData {
|
||||
self.damage.load(Ordering::Relaxed)
|
||||
}
|
||||
/// The type id of the type used for the hit.
|
||||
pub fn move_type(&self) -> u8 {
|
||||
pub fn move_type(&self) -> TypeIdentifier {
|
||||
self.move_type.load(Ordering::Relaxed)
|
||||
}
|
||||
/// Whether or not the hit has failed.
|
||||
@@ -73,7 +73,7 @@ impl HitData {
|
||||
self.damage.store(value, Ordering::SeqCst);
|
||||
}
|
||||
/// Sets the move type id of the hit.
|
||||
pub fn set_move_type(&self, value: u8) {
|
||||
pub fn set_move_type(&self, value: TypeIdentifier) {
|
||||
self.move_type.store(value, Ordering::SeqCst);
|
||||
}
|
||||
/// Marks the hit as failed.
|
||||
|
||||
@@ -2,21 +2,32 @@ use std::sync::atomic::{AtomicU8, Ordering};
|
||||
|
||||
use crate::static_data::MoveData;
|
||||
|
||||
/// A learned move is the data attached to a Pokemon for a move it has learned. It has information
|
||||
/// such as the remaining amount of users, how it has been learned, etc.
|
||||
#[derive(Debug)]
|
||||
pub struct LearnedMove<'library> {
|
||||
/// The immutable move information of the move.
|
||||
move_data: &'library MoveData,
|
||||
/// The maximal power points for this move.
|
||||
max_pp: u8,
|
||||
/// The amount of remaining power points. If this is 0, we can not use the move anymore.
|
||||
remaining_pp: AtomicU8,
|
||||
/// The way the move was learned.
|
||||
learn_method: MoveLearnMethod,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
/// The different ways a move can be learned.
|
||||
#[derive(Copy, Clone, Debug, Default)]
|
||||
pub enum MoveLearnMethod {
|
||||
/// We do not know the learn method.
|
||||
#[default]
|
||||
Unknown = 0,
|
||||
/// The move was learned through level up.
|
||||
Level = 1,
|
||||
}
|
||||
|
||||
impl<'a> LearnedMove<'a> {
|
||||
/// Instantiate a new learned move.
|
||||
pub fn new(move_data: &'a MoveData, learn_method: MoveLearnMethod) -> Self {
|
||||
Self {
|
||||
move_data,
|
||||
@@ -26,36 +37,50 @@ impl<'a> LearnedMove<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
/// The immutable move information of the move.
|
||||
pub fn move_data(&self) -> &MoveData {
|
||||
self.move_data
|
||||
}
|
||||
|
||||
/// The maximal power points for this move.
|
||||
pub fn max_pp(&self) -> u8 {
|
||||
self.max_pp
|
||||
}
|
||||
/// The amount of remaining power points. If this is 0, we can not use the move anymore.
|
||||
pub fn remaining_pp(&self) -> u8 {
|
||||
self.remaining_pp.load(Ordering::Relaxed)
|
||||
}
|
||||
/// The way the move was learned.
|
||||
pub fn learn_method(&self) -> MoveLearnMethod {
|
||||
self.learn_method
|
||||
}
|
||||
|
||||
/// Try and reduce the PP by a certain amount. If the amount is higher than the current uses,
|
||||
/// return false. Otherwise, reduce the PP, and return true.
|
||||
pub fn try_use(&self, amount: u8) -> bool {
|
||||
if amount > self.remaining_pp() {
|
||||
return false;
|
||||
}
|
||||
self.remaining_pp.fetch_sub(amount, Ordering::SeqCst);
|
||||
true
|
||||
let res = self.remaining_pp.fetch_update(Ordering::SeqCst, Ordering::SeqCst, |x| {
|
||||
if amount > x {
|
||||
None
|
||||
} else {
|
||||
Some(x - amount)
|
||||
}
|
||||
});
|
||||
res.is_ok()
|
||||
}
|
||||
|
||||
/// Set the remaining PP to the max amount of PP.
|
||||
pub fn restore_all_uses(&self) {
|
||||
self.remaining_pp.store(self.max_pp, Ordering::SeqCst);
|
||||
}
|
||||
|
||||
/// Restore the remaining PP by a certain amount. Will prevent it from going above max PP.
|
||||
pub fn restore_uses(&self, mut uses: u8) {
|
||||
if self.remaining_pp() + uses > self.max_pp {
|
||||
uses = self.remaining_pp() - uses;
|
||||
}
|
||||
self.remaining_pp.fetch_add(uses, Ordering::SeqCst);
|
||||
self.remaining_pp
|
||||
.fetch_update(Ordering::SeqCst, Ordering::SeqCst, |x| {
|
||||
if x + uses > self.max_pp {
|
||||
uses = self.max_pp - x;
|
||||
}
|
||||
Some(x)
|
||||
})
|
||||
.unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,8 +11,7 @@ use crate::dynamic_data::models::battle::Battle;
|
||||
use crate::dynamic_data::models::damage_source::DamageSource;
|
||||
use crate::dynamic_data::models::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::AbilityIndex;
|
||||
use crate::dynamic_data::{DynamicLibrary, Script, ScriptCategory, ScriptContainer, ScriptSet, VolatileScriptsOwner};
|
||||
use crate::static_data::DataLibrary;
|
||||
use crate::static_data::Form;
|
||||
use crate::static_data::Gender;
|
||||
@@ -20,95 +19,107 @@ use crate::static_data::Item;
|
||||
use crate::static_data::Nature;
|
||||
use crate::static_data::Species;
|
||||
use crate::static_data::{Ability, Statistic};
|
||||
use crate::static_data::{AbilityIndex, TypeIdentifier};
|
||||
use crate::static_data::{ClampedStatisticSet, StatisticSet};
|
||||
use crate::utils::Random;
|
||||
use crate::{script_hook, PkmnResult, StringKey};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct PokemonBattleData<'pokemon, 'library> {
|
||||
battle: *mut Battle<'pokemon, 'library>,
|
||||
battle_side_index: AtomicU8,
|
||||
index: AtomicU8,
|
||||
on_battle_field: AtomicBool,
|
||||
seen_opponents: RwLock<Vec<Weak<Pokemon<'pokemon, 'library>>>>,
|
||||
}
|
||||
|
||||
impl<'pokemon, 'library> PokemonBattleData<'pokemon, 'library> {
|
||||
pub fn battle_mut(&mut self) -> Option<&mut Battle<'pokemon, 'library>> {
|
||||
unsafe { self.battle.as_mut() }
|
||||
}
|
||||
pub fn battle(&self) -> Option<&Battle<'pokemon, 'library>> {
|
||||
unsafe { self.battle.as_ref() }
|
||||
}
|
||||
|
||||
pub fn battle_side_index(&self) -> u8 {
|
||||
self.battle_side_index.load(Ordering::Relaxed)
|
||||
}
|
||||
pub fn index(&self) -> u8 {
|
||||
self.index.load(Ordering::Relaxed)
|
||||
}
|
||||
pub fn on_battle_field(&self) -> bool {
|
||||
self.on_battle_field.load(Ordering::Relaxed)
|
||||
}
|
||||
pub fn seen_opponents(&self) -> &RwLock<Vec<Weak<Pokemon<'pokemon, 'library>>>> {
|
||||
&self.seen_opponents
|
||||
}
|
||||
}
|
||||
|
||||
/// An individual Pokemon as we know and love them.
|
||||
#[derive(Debug)]
|
||||
pub struct Pokemon<'own, 'library>
|
||||
where
|
||||
'own: 'library,
|
||||
{
|
||||
/// The library data of the Pokemon.
|
||||
library: &'own DynamicLibrary,
|
||||
/// The species of the Pokemon.
|
||||
species: &'own Species,
|
||||
/// The form of the Pokemon.
|
||||
form: &'own Form,
|
||||
|
||||
/// An optional display species of the Pokemon. If this is set, the client should display this
|
||||
/// species. An example of usage for this is the Illusion ability.
|
||||
display_species: Option<&'own Species>,
|
||||
/// An optional display form of the Pokemon. If this is set, the client should display this
|
||||
// species. An example of usage for this is the Illusion ability.
|
||||
display_form: Option<&'own Form>,
|
||||
|
||||
/// The current level of the Pokemon.
|
||||
level: LevelInt,
|
||||
/// The amount of experience of the Pokemon.
|
||||
experience: AtomicU32,
|
||||
/// A unique random number for this Pokemon.
|
||||
unique_identifier: u32,
|
||||
|
||||
/// The gender of the Pokemon.
|
||||
gender: Gender,
|
||||
/// The coloring of the Pokemon. Value 0 is the default, value 1 means shiny. Other values are
|
||||
/// currently not used, and can be used for other implementations.
|
||||
coloring: u8,
|
||||
/// The held item of the Pokemon.
|
||||
held_item: RwLock<Option<&'own Item>>,
|
||||
/// The remaining health points of the Pokemon.
|
||||
current_health: AtomicU32,
|
||||
|
||||
/// The weight of the Pokemon in kilograms.
|
||||
weight: Atomic<f32>,
|
||||
/// The height of the Pokemon in meters.
|
||||
height: Atomic<f32>,
|
||||
|
||||
stat_boost: ClampedStatisticSet<AtomicI8, -6, 6>,
|
||||
/// The stats of the Pokemon when disregarding any stat boosts.
|
||||
flat_stats: StatisticSet<AtomicU32>,
|
||||
/// The statistics boosts of the Pokemon. Will prevent the value from going above 6, and below
|
||||
/// -6.
|
||||
stat_boost: ClampedStatisticSet<AtomicI8, -6, 6>,
|
||||
/// The stats of the Pokemon including the stat boosts
|
||||
boosted_stats: StatisticSet<AtomicU32>,
|
||||
/// The [individual values](https://bulbapedia.bulbagarden.net/wiki/Individual_values) of the Pokemon.
|
||||
individual_values: ClampedStatisticSet<AtomicU8, 0, 31>,
|
||||
/// The [effort values](https://bulbapedia.bulbagarden.net/wiki/Effort_values) of the Pokemon.
|
||||
effort_values: ClampedStatisticSet<AtomicU8, 0, 252>,
|
||||
/// The [nature](https://bulbapedia.bulbagarden.net/wiki/Nature) of the Pokemon.
|
||||
nature: &'own Nature,
|
||||
|
||||
/// An optional nickname of the Pokemon.
|
||||
nickname: Option<String>,
|
||||
|
||||
/// An index of the ability to find the actual ability on the form.
|
||||
ability_index: AbilityIndex,
|
||||
is_ability_overridden: bool,
|
||||
/// An ability can be overriden to an arbitrary ability. This is for example used for the Mummy
|
||||
/// ability.
|
||||
override_ability: Option<Ability>,
|
||||
|
||||
/// If in battle, we have additional data.
|
||||
battle_data: RwLock<Option<PokemonBattleData<'own, 'library>>>,
|
||||
|
||||
/// The moves the Pokemon has learned. This is of a set length of [`MAX_MOVES`]. Empty move slots
|
||||
/// are defined by None.
|
||||
moves: RwLock<[Option<Arc<LearnedMove<'library>>>; MAX_MOVES]>,
|
||||
/// Whether or not the Pokemon is allowed to gain experience.
|
||||
allowed_experience: bool,
|
||||
|
||||
types: Vec<u8>,
|
||||
/// The current types of the Pokemon.
|
||||
types: Vec<TypeIdentifier>,
|
||||
/// Whether or not this Pokemon is an egg.
|
||||
is_egg: bool,
|
||||
/// Whether or not this Pokemon was caught this battle.
|
||||
is_caught: bool,
|
||||
|
||||
/// The script for the held item.
|
||||
held_item_trigger_script: ScriptContainer,
|
||||
/// The script for the ability.
|
||||
ability_script: ScriptContainer,
|
||||
/// The script for the status.
|
||||
status_script: ScriptContainer,
|
||||
/// The volatile status scripts of the Pokemon.
|
||||
volatile: Arc<ScriptSet>,
|
||||
|
||||
/// Data required for the Pokemon to be a script source.
|
||||
script_source_data: RwLock<ScriptSourceData>,
|
||||
}
|
||||
|
||||
impl<'own, 'library> Pokemon<'own, 'library> {
|
||||
/// Instantiates a new Pokemon.
|
||||
pub fn new(
|
||||
library: &'own DynamicLibrary,
|
||||
species: &'own Species,
|
||||
@@ -155,7 +166,6 @@ impl<'own, 'library> Pokemon<'own, 'library> {
|
||||
nature,
|
||||
nickname: None,
|
||||
ability_index: ability,
|
||||
is_ability_overridden: false,
|
||||
override_ability: None,
|
||||
battle_data: RwLock::new(None),
|
||||
moves: RwLock::new([None, None, None, None]),
|
||||
@@ -176,15 +186,19 @@ impl<'own, 'library> Pokemon<'own, 'library> {
|
||||
pokemon
|
||||
}
|
||||
|
||||
/// The library data of the Pokemon.
|
||||
pub fn library(&self) -> &'own DynamicLibrary {
|
||||
self.library
|
||||
}
|
||||
/// The species of the Pokemon.
|
||||
pub fn species(&self) -> &'own Species {
|
||||
self.species
|
||||
}
|
||||
/// The form of the Pokemon.
|
||||
pub fn form(&self) -> &'own Form {
|
||||
self.form
|
||||
}
|
||||
/// The species that should be displayed to the user. This handles stuff like the Illusion ability.
|
||||
pub fn display_species(&self) -> &'own Species {
|
||||
if let Some(v) = self.display_species {
|
||||
v
|
||||
@@ -192,6 +206,7 @@ impl<'own, 'library> Pokemon<'own, 'library> {
|
||||
self.species
|
||||
}
|
||||
}
|
||||
/// The form that should be displayed to the user. This handles stuff like the Illusion ability.
|
||||
pub fn display_form(&self) -> &'own Form {
|
||||
if let Some(v) = self.display_form {
|
||||
v
|
||||
@@ -199,25 +214,32 @@ impl<'own, 'library> Pokemon<'own, 'library> {
|
||||
self.form
|
||||
}
|
||||
}
|
||||
|
||||
/// The current level of the Pokemon.
|
||||
pub fn level(&self) -> LevelInt {
|
||||
self.level
|
||||
}
|
||||
/// The amount of experience of the Pokemon.
|
||||
pub fn experience(&self) -> u32 {
|
||||
self.experience.load(Ordering::Relaxed)
|
||||
}
|
||||
/// A unique random number for this Pokemon.
|
||||
pub fn unique_identifier(&self) -> u32 {
|
||||
self.unique_identifier
|
||||
}
|
||||
/// The gender of the Pokemon.
|
||||
pub fn gender(&self) -> Gender {
|
||||
self.gender
|
||||
}
|
||||
/// The coloring of the Pokemon. Value 0 is the default, value 1 means shiny. Other values are
|
||||
/// currently not used, and can be used for other implementations.
|
||||
pub fn coloring(&self) -> u8 {
|
||||
self.coloring
|
||||
}
|
||||
/// Checks whether the Pokemon is holding an item,
|
||||
pub fn held_item(&self) -> &RwLock<Option<&'own Item>> {
|
||||
&self.held_item
|
||||
}
|
||||
/// Checks whether the Pokemon is holding a specific 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.read().deref() {
|
||||
@@ -225,12 +247,15 @@ impl<'own, 'library> Pokemon<'own, 'library> {
|
||||
}
|
||||
false
|
||||
}
|
||||
/// Changes the held item of the Pokemon/
|
||||
pub fn set_held_item(&self, item: &'own Item) -> Option<&'own Item> {
|
||||
self.held_item.write().replace(item)
|
||||
}
|
||||
/// Removes the held item from the Pokemon.
|
||||
pub fn remove_held_item(&self) -> Option<&'own Item> {
|
||||
self.held_item.write().take()
|
||||
}
|
||||
/// Makes the Pokemon uses its held item.
|
||||
pub fn consume_held_item(&self) -> bool {
|
||||
if self.held_item.read().is_none() {
|
||||
return false;
|
||||
@@ -244,42 +269,53 @@ impl<'own, 'library> Pokemon<'own, 'library> {
|
||||
todo!();
|
||||
}
|
||||
|
||||
/// The remaining health points of the Pokemon.
|
||||
pub fn current_health(&self) -> u32 {
|
||||
self.current_health.load(Ordering::Relaxed)
|
||||
}
|
||||
/// The max health points of the Pokemon.
|
||||
pub fn max_health(&self) -> u32 {
|
||||
self.boosted_stats.hp()
|
||||
}
|
||||
/// The weight of the Pokemon in kilograms.
|
||||
pub fn weight(&self) -> f32 {
|
||||
self.weight.load(Ordering::Relaxed)
|
||||
}
|
||||
/// The height of the Pokemon in meters.
|
||||
pub fn height(&self) -> f32 {
|
||||
self.height.load(Ordering::Relaxed)
|
||||
}
|
||||
/// An optional nickname of the Pokemon.
|
||||
pub fn nickname(&self) -> &Option<String> {
|
||||
&self.nickname
|
||||
}
|
||||
/// An index of the ability to find the actual ability on the form.
|
||||
pub fn real_ability(&self) -> &AbilityIndex {
|
||||
&self.ability_index
|
||||
}
|
||||
pub fn types(&self) -> &Vec<u8> {
|
||||
/// The current types of the Pokemon.
|
||||
pub fn types(&self) -> &Vec<TypeIdentifier> {
|
||||
&self.types
|
||||
}
|
||||
/// The moves the Pokemon has learned. This is of a set length of [`MAX_MOVES`]. Empty move slots
|
||||
/// are defined by None.
|
||||
pub fn learned_moves(&self) -> &RwLock<[Option<Arc<LearnedMove<'library>>>; MAX_MOVES]> {
|
||||
&self.moves
|
||||
}
|
||||
pub fn status(&self) -> &ScriptContainer {
|
||||
&self.status_script
|
||||
}
|
||||
|
||||
/// The stats of the Pokemon when disregarding any stat boosts.
|
||||
pub fn flat_stats(&self) -> &StatisticSet<AtomicU32> {
|
||||
&self.flat_stats
|
||||
}
|
||||
/// The stats of the Pokemon including the stat boosts
|
||||
pub fn boosted_stats(&self) -> &StatisticSet<AtomicU32> {
|
||||
&self.boosted_stats
|
||||
}
|
||||
/// Get the stat boosts for a specific stat.
|
||||
pub fn stat_boost(&self, stat: Statistic) -> i8 {
|
||||
self.stat_boost.get_stat(stat)
|
||||
}
|
||||
/// Change a boosted stat by a certain amount.
|
||||
pub fn change_stat_boost(&self, stat: Statistic, mut diff_amount: i8, self_inflicted: bool) -> bool {
|
||||
let mut prevent = false;
|
||||
script_hook!(
|
||||
@@ -328,13 +364,16 @@ impl<'own, 'library> Pokemon<'own, 'library> {
|
||||
return changed;
|
||||
}
|
||||
|
||||
/// The [individual values](https://bulbapedia.bulbagarden.net/wiki/Individual_values) of the Pokemon.
|
||||
pub fn individual_values(&self) -> &ClampedStatisticSet<AtomicU8, 0, 31> {
|
||||
&self.individual_values
|
||||
}
|
||||
/// The [effort values](https://bulbapedia.bulbagarden.net/wiki/Effort_values) of the Pokemon.
|
||||
pub fn effort_values(&self) -> &ClampedStatisticSet<AtomicU8, 0, 252> {
|
||||
&self.effort_values
|
||||
}
|
||||
|
||||
/// Gets the battle the battle is currently in.
|
||||
pub fn get_battle(&self) -> Option<&Battle<'own, 'library>> {
|
||||
let r = self.battle_data.read();
|
||||
if let Some(data) = &r.deref() {
|
||||
@@ -343,20 +382,24 @@ impl<'own, 'library> Pokemon<'own, 'library> {
|
||||
None
|
||||
}
|
||||
}
|
||||
/// Get the index of the side of the battle the Pokemon is in. Only returns a value if the Pokemon
|
||||
/// is on the battlefield.
|
||||
pub fn get_battle_side_index(&self) -> Option<u8> {
|
||||
self.battle_data.read().as_ref().map(|data| data.battle_side_index())
|
||||
}
|
||||
/// Get the index of the slot on the side of the battle the Pokemon is in. Only returns a value
|
||||
/// if the Pokemon is on the battlefield.
|
||||
pub fn get_battle_index(&self) -> Option<u8> {
|
||||
self.battle_data.read().as_ref().map(|data| data.index())
|
||||
}
|
||||
/// Returns whether something overrides the ability.
|
||||
pub fn is_ability_overriden(&self) -> bool {
|
||||
self.is_ability_overridden
|
||||
self.override_ability.is_some()
|
||||
}
|
||||
/// Returns the currently active ability.
|
||||
pub fn active_ability(&self) -> &Ability {
|
||||
if self.is_ability_overridden {
|
||||
if let Some(v) = &self.override_ability {
|
||||
return v;
|
||||
}
|
||||
if let Some(v) = &self.override_ability {
|
||||
return v;
|
||||
}
|
||||
self.library
|
||||
.static_data()
|
||||
@@ -365,33 +408,41 @@ impl<'own, 'library> Pokemon<'own, 'library> {
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
/// The script for the status.
|
||||
pub fn status(&self) -> &ScriptContainer {
|
||||
&self.status_script
|
||||
}
|
||||
|
||||
/// Returns the script for the currently active ability.
|
||||
pub fn ability_script(&self) -> &ScriptContainer {
|
||||
&self.ability_script
|
||||
}
|
||||
|
||||
// pub fn seen_opponents(&self) -> &RwLock<Option<PokemonBattleData<'own, 'library>>> {
|
||||
// &self.battle_data.read
|
||||
// }
|
||||
/// Whether or not the Pokemon is allowed to gain experience.
|
||||
pub fn allowed_experience_gain(&self) -> bool {
|
||||
self.allowed_experience
|
||||
}
|
||||
|
||||
/// The [nature](https://bulbapedia.bulbagarden.net/wiki/Nature) of the Pokemon.
|
||||
pub fn nature(&self) -> &'own Nature {
|
||||
self.nature
|
||||
}
|
||||
|
||||
/// Calculates the flat stats on the Pokemon.
|
||||
pub fn recalculate_flat_stats(&self) {
|
||||
self.library
|
||||
.stat_calculator()
|
||||
.calculate_flat_stats(self, &self.flat_stats);
|
||||
self.recalculate_boosted_stats();
|
||||
}
|
||||
/// Calculates the boosted stats on the Pokemon.
|
||||
pub fn recalculate_boosted_stats(&self) {
|
||||
self.library
|
||||
.stat_calculator()
|
||||
.calculate_boosted_stats(self, &self.boosted_stats);
|
||||
}
|
||||
|
||||
/// Change the species of the Pokemon.
|
||||
pub fn change_species(&mut self, species: &'own Species, form: &'own Form) {
|
||||
self.species = species;
|
||||
self.form = form;
|
||||
@@ -424,6 +475,7 @@ impl<'own, 'library> Pokemon<'own, 'library> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Change the form of the Pokemon.
|
||||
pub fn change_form(&mut self, form: &'own Form) {
|
||||
if std::ptr::eq(self.form, form) {
|
||||
return;
|
||||
@@ -474,14 +526,17 @@ impl<'own, 'library> Pokemon<'own, 'library> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Whether or not the Pokemon is useable in a battle.
|
||||
pub fn is_usable(&self) -> bool {
|
||||
!self.is_caught && !self.is_egg && !self.is_fainted()
|
||||
}
|
||||
|
||||
/// Returns whether the Pokemon is fainted.
|
||||
pub fn is_fainted(&self) -> bool {
|
||||
self.current_health() == 0
|
||||
}
|
||||
|
||||
/// Sets the current battle the Pokemon is in.
|
||||
pub fn set_battle_data(&self, battle: *mut Battle<'own, 'library>, battle_side_index: u8) {
|
||||
let mut w = self.battle_data.write();
|
||||
if let Some(battle_data) = w.deref_mut() {
|
||||
@@ -498,6 +553,7 @@ impl<'own, 'library> Pokemon<'own, 'library> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Sets whether or not the Pokemon is on the battlefield.
|
||||
pub fn set_on_battlefield(&self, value: bool) {
|
||||
let r = self.battle_data.read();
|
||||
if let Some(data) = &mut r.deref() {
|
||||
@@ -510,6 +566,7 @@ impl<'own, 'library> Pokemon<'own, 'library> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Sets the index of the slot of the side the Pokemon is on.
|
||||
pub fn set_battle_index(&self, index: u8) {
|
||||
let r = self.battle_data.read();
|
||||
if let Some(data) = r.deref() {
|
||||
@@ -517,10 +574,12 @@ impl<'own, 'library> Pokemon<'own, 'library> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Whether or not the Pokemon is on the battlefield.
|
||||
pub fn is_on_battlefield(&self) -> bool {
|
||||
self.battle_data.read().is_some_and(|a| a.on_battle_field())
|
||||
}
|
||||
|
||||
/// Marks an opponent as seen, for use in experience gain.
|
||||
pub fn mark_opponent_as_seen(&self, pokemon: Weak<Pokemon<'own, 'library>>) {
|
||||
let r = self.battle_data.read();
|
||||
if let Some(battle_data) = &r.deref() {
|
||||
@@ -534,6 +593,7 @@ impl<'own, 'library> Pokemon<'own, 'library> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Damages the Pokemon by a certain amount of damage, from a specific damage source.
|
||||
pub fn damage(&self, mut damage: u32, source: DamageSource) {
|
||||
if damage > self.current_health() {
|
||||
damage = self.current_health();
|
||||
@@ -563,7 +623,8 @@ impl<'own, 'library> Pokemon<'own, 'library> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn on_faint(&self, source: DamageSource) {
|
||||
/// Triggers when the Pokemon faints.
|
||||
fn on_faint(&self, source: DamageSource) {
|
||||
let r = self.battle_data.read();
|
||||
if let Some(battle_data) = r.deref() {
|
||||
if let Some(battle) = battle_data.battle() {
|
||||
@@ -581,6 +642,7 @@ impl<'own, 'library> Pokemon<'own, 'library> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Learn a move.
|
||||
pub fn learn_move(&self, move_name: &StringKey, learn_method: MoveLearnMethod) {
|
||||
let mut learned_moves = self.learned_moves().write();
|
||||
let move_pos = learned_moves.iter().position(|a| a.is_none());
|
||||
@@ -592,6 +654,49 @@ impl<'own, 'library> Pokemon<'own, 'library> {
|
||||
}
|
||||
}
|
||||
|
||||
/// The data of the Pokemon related to being in a battle.
|
||||
#[derive(Debug)]
|
||||
pub struct PokemonBattleData<'pokemon, 'library> {
|
||||
/// The battle data of the Pokemon
|
||||
battle: *mut Battle<'pokemon, 'library>,
|
||||
/// The index of the side of the Pokemon
|
||||
battle_side_index: AtomicU8,
|
||||
/// The index of the slot on the side of the Pokemon.
|
||||
index: AtomicU8,
|
||||
/// Whether or not the Pokemon is on the battlefield.
|
||||
on_battle_field: AtomicBool,
|
||||
/// A list of opponents the Pokemon has seen this battle.
|
||||
seen_opponents: RwLock<Vec<Weak<Pokemon<'pokemon, 'library>>>>,
|
||||
}
|
||||
|
||||
impl<'pokemon, 'library> PokemonBattleData<'pokemon, 'library> {
|
||||
/// The battle data of the Pokemon
|
||||
pub fn battle_mut(&mut self) -> Option<&mut Battle<'pokemon, 'library>> {
|
||||
unsafe { self.battle.as_mut() }
|
||||
}
|
||||
/// The battle data of the Pokemon
|
||||
pub fn battle(&self) -> Option<&Battle<'pokemon, 'library>> {
|
||||
unsafe { self.battle.as_ref() }
|
||||
}
|
||||
|
||||
/// The index of the side of the Pokemon
|
||||
pub fn battle_side_index(&self) -> u8 {
|
||||
self.battle_side_index.load(Ordering::Relaxed)
|
||||
}
|
||||
/// The index of the slot on the side of the Pokemon.
|
||||
pub fn index(&self) -> u8 {
|
||||
self.index.load(Ordering::Relaxed)
|
||||
}
|
||||
/// Whether or not the Pokemon is on the battlefield.
|
||||
pub fn on_battle_field(&self) -> bool {
|
||||
self.on_battle_field.load(Ordering::Relaxed)
|
||||
}
|
||||
/// A list of opponents the Pokemon has seen this battle.
|
||||
pub fn seen_opponents(&self) -> &RwLock<Vec<Weak<Pokemon<'pokemon, 'library>>>> {
|
||||
&self.seen_opponents
|
||||
}
|
||||
}
|
||||
|
||||
impl<'own, 'library> ScriptSource<'own> for Pokemon<'own, 'library> {
|
||||
fn get_script_count(&self) -> usize {
|
||||
let mut c = 3;
|
||||
@@ -624,7 +729,7 @@ impl<'own, 'library> ScriptSource<'own> for Pokemon<'own, 'library> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'own, 'library> VolatileScripts<'own> for Pokemon<'own, 'library> {
|
||||
impl<'own, 'library> VolatileScriptsOwner<'own> for Pokemon<'own, 'library> {
|
||||
fn volatile_scripts(&self) -> &Arc<ScriptSet> {
|
||||
&self.volatile
|
||||
}
|
||||
|
||||
@@ -3,30 +3,47 @@ use crate::dynamic_data::models::learned_move::MoveLearnMethod;
|
||||
use crate::dynamic_data::models::pokemon::Pokemon;
|
||||
use crate::dynamic_data::DynamicLibrary;
|
||||
use crate::static_data::{AbilityIndex, DataLibrary, Gender};
|
||||
use crate::StringKey;
|
||||
use crate::{Random, StringKey};
|
||||
|
||||
/// This allows for the easy chain building of a Pokemon.
|
||||
pub struct PokemonBuilder<'own> {
|
||||
/// The library of the Pokemon.
|
||||
library: &'own DynamicLibrary,
|
||||
/// The name of the species of the Pokemon.
|
||||
species: StringKey,
|
||||
/// The level of the Pokemon.
|
||||
level: LevelInt,
|
||||
/// The moves the Pokemon will know.
|
||||
learned_moves: Vec<StringKey>,
|
||||
/// A random seed used for any randomization done.
|
||||
random_seed: Option<u128>,
|
||||
}
|
||||
|
||||
impl<'own> PokemonBuilder<'own> {
|
||||
/// Creates a new PokemonBuilder with a library, species, and level.
|
||||
pub fn new(library: &'own DynamicLibrary, species: StringKey, level: LevelInt) -> Self {
|
||||
Self {
|
||||
library,
|
||||
species,
|
||||
level,
|
||||
learned_moves: vec![],
|
||||
random_seed: None,
|
||||
}
|
||||
}
|
||||
/// Makes the Pokemon learn a move.
|
||||
pub fn learn_move(mut self, learned_move: StringKey) -> Self {
|
||||
self.learned_moves.push(learned_move);
|
||||
self
|
||||
}
|
||||
|
||||
/// Finally turn the builder into an actual Pokemon.
|
||||
pub fn build(self) -> Pokemon<'own, 'own> {
|
||||
let mut random = if let Some(seed) = self.random_seed {
|
||||
Random::new(seed)
|
||||
} else {
|
||||
Random::default()
|
||||
};
|
||||
|
||||
let species = self.library.static_data().species().get(&self.species).unwrap();
|
||||
let form = species.get_default_form();
|
||||
let p = Pokemon::new(
|
||||
@@ -38,7 +55,7 @@ impl<'own> PokemonBuilder<'own> {
|
||||
index: 0,
|
||||
},
|
||||
self.level,
|
||||
0,
|
||||
random.get_unsigned(),
|
||||
Gender::Male,
|
||||
0,
|
||||
&"hardy".into(),
|
||||
|
||||
@@ -1,12 +1,16 @@
|
||||
use crate::dynamic_data::models::pokemon::Pokemon;
|
||||
use std::sync::Arc;
|
||||
|
||||
use crate::dynamic_data::models::pokemon::Pokemon;
|
||||
|
||||
/// A list of Pokemon belonging to a trainer.
|
||||
#[derive(Debug)]
|
||||
pub struct PokemonParty<'pokemon, 'library> {
|
||||
/// The underlying list of Pokemon.
|
||||
pokemon: Vec<Option<Arc<Pokemon<'pokemon, 'library>>>>,
|
||||
}
|
||||
|
||||
impl<'own, 'library> PokemonParty<'own, 'library> {
|
||||
/// Instantiates a party with a set size.
|
||||
pub fn new(size: usize) -> Self {
|
||||
let mut pokemon = Vec::with_capacity(size);
|
||||
for _i in 0..size {
|
||||
@@ -15,10 +19,12 @@ impl<'own, 'library> PokemonParty<'own, 'library> {
|
||||
Self { pokemon }
|
||||
}
|
||||
|
||||
/// Instantiates a party with a list.
|
||||
pub fn new_from_vec(pokemon: Vec<Option<Arc<Pokemon<'own, 'library>>>>) -> Self {
|
||||
Self { pokemon }
|
||||
}
|
||||
|
||||
/// Gets a Pokemon at an index in the party.
|
||||
pub fn at(&self, index: usize) -> &Option<Arc<Pokemon<'own, 'library>>> {
|
||||
let opt = self.pokemon.get(index);
|
||||
if let Some(v) = opt {
|
||||
@@ -28,10 +34,12 @@ impl<'own, 'library> PokemonParty<'own, 'library> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Swaps two Pokemon in the party around.
|
||||
pub fn switch(&mut self, a: usize, b: usize) {
|
||||
self.pokemon.swap(a, b);
|
||||
}
|
||||
|
||||
/// Sets the Pokemon at an index to a Pokemon, returning the old Pokemon.
|
||||
pub fn swap_into(
|
||||
&mut self,
|
||||
index: usize,
|
||||
@@ -45,6 +53,7 @@ impl<'own, 'library> PokemonParty<'own, 'library> {
|
||||
old
|
||||
}
|
||||
|
||||
/// Whether or not the party still has Pokemon that can be used in battle.
|
||||
pub fn has_usable_pokemon(&self) -> bool {
|
||||
for pokemon in self.pokemon.iter().flatten() {
|
||||
if pokemon.is_usable() {
|
||||
@@ -54,14 +63,17 @@ impl<'own, 'library> PokemonParty<'own, 'library> {
|
||||
false
|
||||
}
|
||||
|
||||
/// Get the length of the underlying list of Pokemon.
|
||||
pub fn length(&self) -> usize {
|
||||
self.pokemon.len()
|
||||
}
|
||||
|
||||
/// Gets the underlying list of Pokemon.
|
||||
pub fn pokemon(&self) -> &Vec<Option<Arc<Pokemon<'own, 'library>>>> {
|
||||
&self.pokemon
|
||||
}
|
||||
|
||||
/// Makes sure there are no empty spots in the party anymore, leaving the length the same.
|
||||
pub fn pack_party(&mut self) {
|
||||
let mut first_empty = None;
|
||||
let mut i = 0;
|
||||
|
||||
Reference in New Issue
Block a user