diff --git a/src/dynamic_data/flow/target_resolver.rs b/src/dynamic_data/flow/target_resolver.rs index 3fae6d1..4fd3ca5 100644 --- a/src/dynamic_data/flow/target_resolver.rs +++ b/src/dynamic_data/flow/target_resolver.rs @@ -68,7 +68,7 @@ fn get_all_adjacent_opponent<'b, 'library>( ] } -/// Gets all Pokemon that are adjacent to a Pokemon. This includes the target, the pokemon to the +/// Gets all Pokemon that are adjacent to a Pokemon. This includes the target, the Pokemon to the /// left of it, and the Pokemon to the right of it. fn get_all_adjacent<'b, 'library>(side: u8, index: u8, battle: &Battle<'b, 'library>) -> TargetList<'b, 'library> { let left = index as i32 - 1; @@ -132,7 +132,7 @@ pub fn resolve_targets<'b, 'library>( } } -/// Checks whether a given side and index are valid for a given movetarget and user. +/// Checks whether a given side and index are valid for a given move target and user. pub fn is_valid_target(side: u8, index: u8, target: MoveTarget, user: &Pokemon) -> bool { let user_side = user.get_battle_side_index(); let user_index = user.get_battle_index(); diff --git a/src/dynamic_data/libraries/battle_stat_calculator.rs b/src/dynamic_data/libraries/battle_stat_calculator.rs index 7b238e2..32ca1da 100644 --- a/src/dynamic_data/libraries/battle_stat_calculator.rs +++ b/src/dynamic_data/libraries/battle_stat_calculator.rs @@ -5,13 +5,13 @@ 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. +/// 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); /// 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. + /// Calculate all the boosted stats of a Pokemon, including stat boosts. fn calculate_boosted_stats(&self, pokemon: &Pokemon, stats: &StatisticSet); /// Calculate a single boosted stat of a Pokemon, including stat boosts. fn calculate_boosted_stat(&self, pokemon: &Pokemon, stat: Statistic) -> u32; diff --git a/src/dynamic_data/script_handling/script.rs b/src/dynamic_data/script_handling/script.rs index 0bfbead..289d734 100644 --- a/src/dynamic_data/script_handling/script.rs +++ b/src/dynamic_data/script_handling/script.rs @@ -218,7 +218,7 @@ pub trait Script: Send + Sync { fn on_secondary_effect(&self, _move: &ExecutingMove, _target: &Arc, _hit: u8) {} /// This function triggers on a move or its parents when all hits on a target are finished. fn on_after_hits(&self, _move: &ExecutingMove, _target: &Arc) {} - /// This function prevents the pokemon it is attached to from being able to switch out. + /// This function prevents the Pokemon it is attached to from being able to switch out. fn prevent_self_switch(&self, _choice: &TurnChoice, _prevent: &mut bool) {} /// This function allows the prevention of switching for any opponent. fn prevent_opponent_switch(&self, _choice: &TurnChoice, _prevent: &mut bool) {} @@ -253,7 +253,7 @@ pub trait Script: Send + Sync { /// This function is triggered on a battle and its parents when something attempts to change the /// weather, and allows for blocking the weather change. fn block_weather(&self, _battle: &Battle, _blocked: &mut bool) {} - /// This function is called when a pokeball is thrown at a Pokemon, and allows modifying the catch + /// This function is called when a Pokeball is thrown at a Pokemon, and allows modifying the catch /// rate of this attempt. Pokeball modifier effects should be implemented here, as well as for /// example status effects that change capture rates. fn change_capture_rate_bonus(&self, _target: &Pokemon, _pokeball: &Item, _modifier: &mut u8) {} @@ -270,15 +270,32 @@ impl Debug for dyn Script { } } +/// A script holder defines the underlying type of how we store individual scripts on a script source. +/// The outer [`Arc`] here is so we can take a weak reference to it with dynamic lifetimes, as well as +/// copy the value for use during threading. +/// The [`RwLock`] is so we cannot modify the internal script while we're reading from it. +/// The inner [`Arc`] is the default of Scripts, where there can be multiple owners, and where it can be +/// often copied. type ScriptHolder = Arc>>>; +/// A script container is used to store a exclusive script. This is for example used for non-volatile +/// Pokemon status, weather, ability, etc. It can only hold one script, and that script can be replaced +/// if needed. #[derive(Default, Debug)] pub struct ScriptContainer { + /// The actual place where the script is stored. script: ScriptHolder, + /// The join_handle is a very specific piece of data used in one single specific case; the replacing + /// of a script while the script is actively being read from. The RwLock blocks the write, and + /// as such, this is delayed to a thread. This join handle is this thread. In some very specific + /// cases (mostly test cases), it can be required to make sure that this has been completed before + /// continuing. pub(crate) join_handle: RwLock>>, } impl ScriptContainer { + /// Initialize a script container with a specific script. To initialize with an empty script, use + /// default() instead. pub fn new(script: Arc) -> ScriptContainer { Self { script: Arc::new(RwLock::new(Some(script))), @@ -286,6 +303,7 @@ impl ScriptContainer { } } + /// Get the internal script. Note that this can only be None if the script was marked for deletion. pub fn get(&self) -> Option<&ScriptHolder> { if self.script.read().is_some_and(|a| a.is_marked_for_deletion()) { if !self.script.is_locked() { @@ -297,11 +315,17 @@ impl ScriptContainer { } } + /// Changes the internal script. This has several side effects: primarily that it calls the + /// [`Script::on_remove`] function on itself. Other special cases are that the script is currently read + /// from, and as such can not be replaced yet. In this case, the script will be replaced on a + /// separate thread, and be replaced immediately after the script stops being active. pub fn set(&self, script: Arc) -> Arc { if let Some(v) = self.script.read().deref() { v.on_remove(); v.mark_for_deletion(); } + // If we have a lock on the script, we can't replace it now. Wait until we can get the lock, + // and only replace it then. Don't block in the meantime. if self.script.is_locked() { let holder = self.script.clone(); let new = script.clone(); @@ -315,6 +339,9 @@ impl ScriptContainer { script } + /// Removes the internal script. This calls the [`Script::on_remove`] function on itself. If no + /// locks are held to the script, we also immediately set the internal value to None, otherwise + /// we just mark it as deleted. If we do this we remove the script later on. pub fn clear(&self) { if let Some(v) = self.script.read().deref() { v.on_remove(); @@ -325,10 +352,12 @@ impl ScriptContainer { } } + /// Gets the underlying reference counter to the script. pub fn arc(&self) -> &ScriptHolder { &self.script } + /// Get the underlying script as the downcasted value. pub fn get_as(&self) -> MappedRwLockReadGuard { RwLockReadGuard::map(self.script.read(), |a| unsafe { let ptr = a.as_ref().as_ref().unwrap().as_ref() as *const dyn Script;