2022-06-12 15:57:39 +00:00
|
|
|
use std::any::Any;
|
2022-06-03 14:35:18 +00:00
|
|
|
use std::fmt::{Debug, Formatter};
|
2022-06-18 16:08:25 +00:00
|
|
|
use std::ops::Deref;
|
2022-09-07 16:01:26 +00:00
|
|
|
use std::sync::atomic::{AtomicBool, AtomicPtr, AtomicUsize, Ordering};
|
2022-06-12 15:57:39 +00:00
|
|
|
use std::sync::Arc;
|
2022-06-18 17:44:13 +00:00
|
|
|
use std::thread::JoinHandle;
|
2022-06-03 14:35:18 +00:00
|
|
|
|
2022-06-19 19:34:08 +00:00
|
|
|
use parking_lot::{MappedRwLockReadGuard, RwLock, RwLockReadGuard};
|
|
|
|
|
2022-08-27 16:04:56 +00:00
|
|
|
use crate::dynamic_data::choices::TurnChoice;
|
2022-06-19 19:34:08 +00:00
|
|
|
use crate::dynamic_data::ExecutingMove;
|
|
|
|
use crate::dynamic_data::Pokemon;
|
2022-07-18 13:36:03 +00:00
|
|
|
use crate::dynamic_data::{Battle, DynamicLibrary};
|
2022-09-07 16:01:26 +00:00
|
|
|
use crate::dynamic_data::{BattleSide, DamageSource};
|
2022-07-01 15:07:22 +00:00
|
|
|
use crate::static_data::{EffectParameter, TypeIdentifier};
|
2022-06-19 19:34:08 +00:00
|
|
|
use crate::static_data::{Item, Statistic};
|
|
|
|
use crate::StringKey;
|
|
|
|
|
2022-06-20 17:26:33 +00:00
|
|
|
/// The script trait is used to make changes to how a battle executes, without requiring hardcoded
|
|
|
|
/// changes. This allows for easily defining generational differences, and add effects that the
|
|
|
|
/// developer might require.
|
2022-06-18 16:08:25 +00:00
|
|
|
pub trait Script: Send + Sync {
|
2022-06-20 17:26:33 +00:00
|
|
|
/// The name of a script is its unique identifier. This should generally be set on load, and be
|
|
|
|
/// the same as the key that was used to load it.
|
2022-06-11 15:22:46 +00:00
|
|
|
fn name(&self) -> &StringKey;
|
2022-06-20 17:26:33 +00:00
|
|
|
/// Returns an atomic bool for internal marking of deletion. This is currently only specifically
|
|
|
|
/// used for deletion of a script while we are holding a reference to it (i.e. executing a script
|
|
|
|
///hook on it).
|
2022-06-18 16:08:25 +00:00
|
|
|
fn get_marked_for_deletion(&self) -> &AtomicBool;
|
2022-06-06 11:54:59 +00:00
|
|
|
|
2022-06-20 17:26:33 +00:00
|
|
|
/// This marks the script for deletion, which will dispose of it as soon as possible.
|
2022-06-18 16:08:25 +00:00
|
|
|
fn mark_for_deletion(&self) {
|
|
|
|
self.get_marked_for_deletion().store(true, Ordering::SeqCst);
|
|
|
|
}
|
2022-06-20 17:26:33 +00:00
|
|
|
/// Helper function to get the value of the marked for deletion bool.
|
2022-06-18 16:08:25 +00:00
|
|
|
fn is_marked_for_deletion(&self) -> bool {
|
|
|
|
self.get_marked_for_deletion().load(Ordering::SeqCst)
|
|
|
|
}
|
|
|
|
|
2022-06-20 17:26:33 +00:00
|
|
|
/// A script can be suppressed by other scripts. If a script is suppressed by at least one script
|
|
|
|
/// we will not execute its methods. This should return the number of suppressions on the script.
|
2022-06-18 16:08:25 +00:00
|
|
|
fn get_suppressed_count(&self) -> &AtomicUsize;
|
2022-06-20 17:26:33 +00:00
|
|
|
/// Helper function to check if there is at least one suppression on the script
|
2022-06-03 14:35:18 +00:00
|
|
|
fn is_suppressed(&self) -> bool {
|
2022-06-18 16:08:25 +00:00
|
|
|
self.get_suppressed_count().load(Ordering::SeqCst) > 0
|
|
|
|
}
|
2022-06-20 17:26:33 +00:00
|
|
|
/// Adds a suppression. This makes the script not run anymore. Note that adding this should also
|
|
|
|
/// remove the suppression later.
|
|
|
|
///
|
|
|
|
/// A common pattern for this is to run this in the [`Self::on_initialize`] function, and run the
|
|
|
|
/// remove in the [`Self::on_remove`] function.
|
2022-06-18 16:08:25 +00:00
|
|
|
fn add_suppression(&self) {
|
|
|
|
self.get_suppressed_count().fetch_add(1, Ordering::SeqCst);
|
|
|
|
}
|
2022-06-20 17:26:33 +00:00
|
|
|
/// Removes a suppression. This allows the script to run again (provided other scripts are not
|
|
|
|
/// suppressing it). Note that running this should only occur if an add was run before.
|
2022-06-18 16:08:25 +00:00
|
|
|
fn remove_suppression(&self) {
|
|
|
|
self.get_suppressed_count().fetch_sub(1, Ordering::SeqCst);
|
2022-06-13 19:25:30 +00:00
|
|
|
}
|
2022-06-18 16:08:25 +00:00
|
|
|
|
2022-06-20 17:26:33 +00:00
|
|
|
/// This function is ran when a volatile effect is added while that volatile effect already is
|
|
|
|
/// in place. Instead of adding the volatile effect twice, it will execute this function instead.
|
2022-06-18 16:08:25 +00:00
|
|
|
fn stack(&self) {}
|
2022-06-20 17:26:33 +00:00
|
|
|
/// This function is ran when this script stops being in effect, and is removed from its owner.
|
2022-06-18 16:08:25 +00:00
|
|
|
fn on_remove(&self) {}
|
2022-06-20 17:26:33 +00:00
|
|
|
/// This function is ran when this script starts being in effect.
|
2022-12-24 11:00:50 +00:00
|
|
|
fn on_initialize(&self, _library: &Arc<dyn DynamicLibrary>, _pars: Vec<EffectParameter>) {}
|
2022-06-20 17:26:33 +00:00
|
|
|
/// This function is ran just before the start of the turn. Everyone has made its choices here,
|
|
|
|
/// and the turn is about to start. This is a great place to initialize data if you need to know
|
|
|
|
/// something has happened during a turn.
|
2022-06-18 16:08:25 +00:00
|
|
|
fn on_before_turn(&self, _choice: &TurnChoice) {}
|
2022-06-20 17:26:33 +00:00
|
|
|
/// This function allows you to modify the effective speed of the Pokemon. This is ran before
|
|
|
|
/// turn ordering, so overriding here will allow you to put certain Pokemon before others.
|
2022-06-18 16:08:25 +00:00
|
|
|
fn change_speed(&self, _choice: &TurnChoice, _speed: &mut u32) {}
|
2022-06-20 17:26:33 +00:00
|
|
|
/// This function allows you to modify the effective priority of the Pokemon. This is ran before
|
|
|
|
/// turn ordering, so overriding here will allow you to put certain Pokemon before others. Note
|
|
|
|
/// that this is only relevant on move choices, as other turn choice types do not have a priority.
|
2022-06-18 16:08:25 +00:00
|
|
|
fn change_priority(&self, _choice: &TurnChoice, _priority: &mut i8) {}
|
2022-06-20 17:26:33 +00:00
|
|
|
|
|
|
|
/// This function allows you to change the move that is used during execution. This is useful for
|
|
|
|
/// moves such as metronome, where the move chosen actually differs from the move used.
|
2022-08-27 16:04:56 +00:00
|
|
|
fn change_move(&self, _choice: &TurnChoice, _move_name: &mut StringKey) {}
|
2022-06-20 17:26:33 +00:00
|
|
|
/// This function allows you to change a move into a multi-hit move. The number of hits set here
|
|
|
|
/// gets used as the number of hits. If set to 0, this will behave as if the move missed on its
|
|
|
|
/// first hit.
|
2022-08-27 16:04:56 +00:00
|
|
|
fn change_number_of_hits(&self, _choice: &TurnChoice, _number_of_hits: &mut u8) {}
|
2022-06-20 17:26:33 +00:00
|
|
|
|
|
|
|
/// This function allows you to prevent a move from running. If this gets set to true, the move
|
|
|
|
/// ends execution here. No PP will be decreased in this case.
|
2022-06-18 16:08:25 +00:00
|
|
|
fn prevent_move(&self, _move: &ExecutingMove, _prevent: &mut bool) {}
|
2022-06-20 17:26:33 +00:00
|
|
|
/// This function makes the move fail. If the fail field gets set to true, the move ends execution,
|
|
|
|
/// and fail events get triggered.
|
2022-06-18 16:08:25 +00:00
|
|
|
fn fail_move(&self, _move: &ExecutingMove, _fail: &mut bool) {}
|
2022-06-20 17:26:33 +00:00
|
|
|
/// Similar to [`Self::prevent_move`]. This function will also stop execution, but PP will be
|
|
|
|
/// decreased.
|
2022-06-18 16:08:25 +00:00
|
|
|
fn stop_before_move(&self, _move: &ExecutingMove, _stop: &mut bool) {}
|
2022-06-20 17:26:33 +00:00
|
|
|
/// This function runs just before the move starts its execution.
|
2022-06-18 16:08:25 +00:00
|
|
|
fn on_before_move(&self, _move: &ExecutingMove) {}
|
2022-06-20 17:26:33 +00:00
|
|
|
/// This function allows a script to prevent a move that is targeted at its owner. If set to true
|
|
|
|
/// the move fails, and fail events get triggered.
|
2022-06-18 16:08:25 +00:00
|
|
|
fn fail_incoming_move(&self, _move: &ExecutingMove, _target: &Arc<Pokemon>, _fail: &mut bool) {}
|
2022-06-20 17:26:33 +00:00
|
|
|
/// This function allows a script to make its owner invulnerable to an incoming move.
|
2022-06-18 16:08:25 +00:00
|
|
|
fn is_invulnerable(&self, _move: &ExecutingMove, _target: &Arc<Pokemon>, _invulnerable: &mut bool) {}
|
2022-06-20 17:26:33 +00:00
|
|
|
/// This function occurs when a move gets missed. This runs on the scripts belonging to the executing
|
|
|
|
/// move, which include the scripts that are attached to the owner of the script.
|
2022-06-18 16:08:25 +00:00
|
|
|
fn on_move_miss(&self, _move: &ExecutingMove, _target: &Arc<Pokemon>) {}
|
2022-06-20 17:26:33 +00:00
|
|
|
/// This function allows the script to change the actual type that is used for the move on a target.
|
2022-07-01 15:07:22 +00:00
|
|
|
fn change_move_type(
|
|
|
|
&self,
|
|
|
|
_move: &ExecutingMove,
|
|
|
|
_target: &Arc<Pokemon>,
|
|
|
|
_hit: u8,
|
|
|
|
_move_type: &mut TypeIdentifier,
|
|
|
|
) {
|
|
|
|
}
|
2022-06-20 17:26:33 +00:00
|
|
|
/// This function allows the script to change how effective a move is on a target.
|
2022-06-18 16:08:25 +00:00
|
|
|
fn change_effectiveness(&self, _move: &ExecutingMove, _target: &Arc<Pokemon>, _hit: u8, _effectiveness: &mut f32) {}
|
2022-06-20 17:26:33 +00:00
|
|
|
/// This function allows a script to block an outgoing move from being critical.
|
2022-06-18 16:08:25 +00:00
|
|
|
fn block_critical(&self, _move: &ExecutingMove, _target: &Arc<Pokemon>, _hit: u8, _block_critical: &mut bool) {}
|
2022-06-20 17:26:33 +00:00
|
|
|
/// This function allows a script to block an incoming move from being critical.
|
2022-06-13 19:25:30 +00:00
|
|
|
fn block_incoming_critical(
|
2022-06-18 16:08:25 +00:00
|
|
|
&self,
|
2022-06-13 19:25:30 +00:00
|
|
|
_move: &ExecutingMove,
|
2022-06-18 13:52:39 +00:00
|
|
|
_target: &Arc<Pokemon>,
|
2022-06-13 19:25:30 +00:00
|
|
|
_hit: u8,
|
|
|
|
_block_critical: &mut bool,
|
|
|
|
) {
|
|
|
|
}
|
2022-06-20 17:26:33 +00:00
|
|
|
/// This function allows a script to modify the accuracy of a move used. This value represents
|
|
|
|
/// the percentage accuracy, so anything above 100% will make it always hit.
|
|
|
|
fn change_accuracy(&self, _move: &ExecutingMove, _target: &Arc<Pokemon>, _hit: u8, _accuracy: &mut u8) {}
|
|
|
|
|
|
|
|
/// This function allows a script to change the critical stage of the move used.
|
2022-06-18 16:08:25 +00:00
|
|
|
fn change_critical_stage(&self, _move: &ExecutingMove, _target: &Arc<Pokemon>, _hit: u8, _stage: &mut u8) {}
|
2022-06-20 17:26:33 +00:00
|
|
|
/// This function allows a script to change the damage modifier of a critical hit. This will only
|
|
|
|
/// run when a hit is critical.
|
2022-06-18 16:08:25 +00:00
|
|
|
fn change_critical_modifier(&self, _move: &ExecutingMove, _target: &Arc<Pokemon>, _hit: u8, _modifier: &mut f32) {}
|
2022-06-20 17:26:33 +00:00
|
|
|
/// This function allows a script to change the damage modifier of a Same Type Attack Bonus, which
|
|
|
|
/// occurs when the user has the move type as one of its own types.
|
2022-06-18 16:08:25 +00:00
|
|
|
fn change_stab_modifier(&self, _move: &ExecutingMove, _target: &Arc<Pokemon>, _hit: u8, _modifier: &mut f32) {}
|
2022-06-13 19:25:30 +00:00
|
|
|
|
2022-06-20 17:26:33 +00:00
|
|
|
/// This function allows a script to change the effective base power of a move hit.
|
2022-06-18 16:08:25 +00:00
|
|
|
fn change_base_power(&self, _move: &ExecutingMove, _target: &Arc<Pokemon>, _hit: u8, _base_power: &mut u8) {}
|
2022-06-20 17:26:33 +00:00
|
|
|
/// This function allows a script to bypass defensive stat boosts for a move hit.
|
2022-06-18 16:08:25 +00:00
|
|
|
fn bypass_defensive_stat_boost(&self, _move: &ExecutingMove, _target: &Arc<Pokemon>, _hit: u8, _bypass: &mut bool) {
|
2022-06-13 19:25:30 +00:00
|
|
|
}
|
2022-06-20 17:26:33 +00:00
|
|
|
/// This function allows a script to bypass offensive stat boosts for a move hit.
|
2022-06-18 16:08:25 +00:00
|
|
|
fn bypass_offensive_stat_boost(&self, _move: &ExecutingMove, _target: &Arc<Pokemon>, _hit: u8, _bypass: &mut bool) {
|
2022-06-13 19:25:30 +00:00
|
|
|
}
|
2022-06-20 17:26:33 +00:00
|
|
|
/// This function allows a script to change the actual offensive stat values used when calculating damage
|
2022-06-18 16:08:25 +00:00
|
|
|
fn change_offensive_stat_value(&self, _move: &ExecutingMove, _target: &Arc<Pokemon>, _hit: u8, _amount: &mut u32) {}
|
2022-06-20 17:26:33 +00:00
|
|
|
/// This function allows a script to change the actual defensive stat values used when calculating damage.
|
2022-06-18 16:08:25 +00:00
|
|
|
fn change_defensive_stat_value(&self, _move: &ExecutingMove, _target: &Arc<Pokemon>, _hit: u8, _amount: &mut u32) {}
|
2022-06-13 19:25:30 +00:00
|
|
|
|
2022-06-20 17:26:33 +00:00
|
|
|
/// This function allows a script to change the raw modifier we retrieved from the stats of the
|
|
|
|
/// defender and attacker.
|
2022-06-16 15:59:33 +00:00
|
|
|
fn change_damage_stat_modifier(
|
2022-06-18 16:08:25 +00:00
|
|
|
&self,
|
2022-06-13 19:25:30 +00:00
|
|
|
_move: &ExecutingMove,
|
2022-06-18 13:52:39 +00:00
|
|
|
_target: &Arc<Pokemon>,
|
2022-06-13 19:25:30 +00:00
|
|
|
_hit: u8,
|
|
|
|
_modifier: &mut f32,
|
|
|
|
) {
|
|
|
|
}
|
2022-06-27 16:26:27 +00:00
|
|
|
/// This function allows a script to apply a raw multiplier to the damage done by a move.
|
2022-06-18 16:08:25 +00:00
|
|
|
fn change_damage_modifier(&self, _move: &ExecutingMove, _target: &Arc<Pokemon>, _hit: u8, _modifier: &mut f32) {}
|
2022-06-27 16:26:27 +00:00
|
|
|
/// This function allows a script to modify the outgoing damage done by a move.
|
2022-06-18 16:08:25 +00:00
|
|
|
fn change_damage(&self, _move: &ExecutingMove, _target: &Arc<Pokemon>, _hit: u8, _damage: &mut u32) {}
|
2022-06-27 16:26:27 +00:00
|
|
|
/// This function allows a script to modify the incoming damage done by a move.
|
2022-06-18 16:08:25 +00:00
|
|
|
fn change_incoming_damage(&self, _move: &ExecutingMove, _target: &Arc<Pokemon>, _hit: u8, _damage: &mut u32) {}
|
2022-06-27 16:26:27 +00:00
|
|
|
/// This function triggers when an incoming hit happens. This triggers after the damage is done,
|
|
|
|
/// but before the secondary effect of the move happens.
|
2022-06-18 16:08:25 +00:00
|
|
|
fn on_incoming_hit(&self, _move: &ExecutingMove, _target: &Arc<Pokemon>, _hit: u8) {}
|
2022-06-27 16:26:27 +00:00
|
|
|
/// This function triggers when an opponent on the field faints.
|
2022-06-18 16:08:25 +00:00
|
|
|
fn on_opponent_faints(&self, _move: &ExecutingMove, _target: &Arc<Pokemon>, _hit: u8) {}
|
2022-06-27 16:26:27 +00:00
|
|
|
/// This function allows a script attached to a Pokemon or its parents to prevent stat boost
|
|
|
|
/// changes on that Pokemon.
|
2022-06-13 19:25:30 +00:00
|
|
|
fn prevent_stat_boost_change(
|
2022-06-18 16:08:25 +00:00
|
|
|
&self,
|
2022-06-13 19:25:30 +00:00
|
|
|
_target: &Pokemon,
|
|
|
|
_stat: Statistic,
|
|
|
|
_amount: i8,
|
|
|
|
_self_inflicted: bool,
|
|
|
|
_prevent: &mut bool,
|
|
|
|
) {
|
|
|
|
}
|
2022-06-27 16:26:27 +00:00
|
|
|
/// This function allows a script attached to a Pokemon or its parents to modify the amount by
|
|
|
|
/// which the stat boost will change. If the stat boost is done by the user itself, self
|
|
|
|
/// inflicted will be true, otherwise it will be false.
|
|
|
|
fn change_stat_boost_change(&self, _target: &Pokemon, _stat: Statistic, _self_inflicted: bool, _amount: &mut i8) {}
|
|
|
|
/// This function allows a script attached to a Pokemon or its parents to prevent an incoming
|
|
|
|
/// secondary effect. This means the move will still hit and do damage, but not trigger its
|
|
|
|
/// secondary effect. Note that this function is not called for status moves.
|
2022-06-18 16:08:25 +00:00
|
|
|
fn prevent_secondary_effect(&self, _move: &ExecutingMove, _target: &Arc<Pokemon>, _hit: u8, _prevent: &mut bool) {}
|
2022-06-27 16:26:27 +00:00
|
|
|
/// This function allows a script attached to a move or its parents to change the chance the
|
|
|
|
/// secondary effect of a move will trigger. The chance is depicted in percentage here, so
|
|
|
|
/// changing this to above or equal to 100 will make it always hit, while setting it to equal or
|
|
|
|
/// below 0 will make it never hit.
|
2022-06-18 16:08:25 +00:00
|
|
|
fn change_effect_chance(&self, _move: &ExecutingMove, _target: &Arc<Pokemon>, _hit: u8, _chance: &mut f32) {}
|
2022-06-27 16:26:27 +00:00
|
|
|
/// This function allows a script attached to a Pokemon or its parents to change the chance the
|
|
|
|
/// secondary effect of an incoming move will trigger. The chance is depicted in percentage here,
|
|
|
|
/// so changing this to above or equal to 100 will make it always hit, while setting it to equal
|
|
|
|
/// or below 0 will make it never hit.
|
2022-06-16 15:59:33 +00:00
|
|
|
fn change_incoming_effect_chance(
|
2022-06-18 16:08:25 +00:00
|
|
|
&self,
|
2022-06-13 19:25:30 +00:00
|
|
|
_move: &ExecutingMove,
|
2022-06-18 13:52:39 +00:00
|
|
|
_target: &Arc<Pokemon>,
|
2022-06-13 19:25:30 +00:00
|
|
|
_hit: u8,
|
|
|
|
_chance: &mut f32,
|
|
|
|
) {
|
|
|
|
}
|
2022-06-27 16:26:27 +00:00
|
|
|
/// This function triggers when the move uses its secondary effect. Moves should implement their
|
|
|
|
/// secondary effects here. Status moves should implement their actual functionality in this
|
|
|
|
/// function as well, as status moves effects are defined as secondary effects for simplicity.
|
2022-06-18 16:08:25 +00:00
|
|
|
fn on_secondary_effect(&self, _move: &ExecutingMove, _target: &Arc<Pokemon>, _hit: u8) {}
|
2022-06-27 16:26:27 +00:00
|
|
|
/// This function triggers on a move or its parents when all hits on a target are finished.
|
2022-06-18 16:08:25 +00:00
|
|
|
fn on_after_hits(&self, _move: &ExecutingMove, _target: &Arc<Pokemon>) {}
|
2022-06-27 17:21:50 +00:00
|
|
|
/// This function prevents the Pokemon it is attached to from being able to switch out.
|
2022-06-18 16:08:25 +00:00
|
|
|
fn prevent_self_switch(&self, _choice: &TurnChoice, _prevent: &mut bool) {}
|
2022-06-27 16:26:27 +00:00
|
|
|
/// This function allows the prevention of switching for any opponent.
|
2022-06-18 16:08:25 +00:00
|
|
|
fn prevent_opponent_switch(&self, _choice: &TurnChoice, _prevent: &mut bool) {}
|
2022-06-27 16:26:27 +00:00
|
|
|
/// This function is called on a move and its parents when the move fails.
|
2022-06-18 16:08:25 +00:00
|
|
|
fn on_fail(&self, _target: &Pokemon) {}
|
2022-06-27 16:26:27 +00:00
|
|
|
/// This function is called on a script when an opponent fails.
|
2022-06-18 16:08:25 +00:00
|
|
|
fn on_opponent_fail(&self, _target: &Pokemon) {}
|
2022-06-27 16:26:27 +00:00
|
|
|
/// This function allows preventing the running away of the Pokemon its attached to
|
2022-06-18 16:08:25 +00:00
|
|
|
fn prevent_self_run_away(&self, _choice: &TurnChoice, _prevent: &mut bool) {}
|
2022-06-27 16:26:27 +00:00
|
|
|
/// This function prevents a Pokemon on another side than where its attached to from running away.
|
2022-06-18 16:08:25 +00:00
|
|
|
fn prevent_opponent_run_away(&self, _choice: &TurnChoice, _prevent: &mut bool) {}
|
2022-06-27 16:26:27 +00:00
|
|
|
/// This function id triggered on all scripts active in the battle after all choices have finished
|
|
|
|
/// running. Note that choices are not active anymore here, so their scripts do not call this
|
|
|
|
/// function.
|
2022-06-18 16:08:25 +00:00
|
|
|
fn on_end_turn(&self) {}
|
2022-06-27 16:26:27 +00:00
|
|
|
/// This function is triggered on a Pokemon and its parents when the given Pokemon takes damage.
|
2022-06-18 16:08:25 +00:00
|
|
|
fn on_damage(&self, _pokemon: &Pokemon, _source: DamageSource, _old_health: u32, _new_health: u32) {}
|
2022-06-27 16:26:27 +00:00
|
|
|
/// This function is triggered on a Pokemon and its parents when the given Pokemon faints.
|
2022-06-18 16:08:25 +00:00
|
|
|
fn on_faint(&self, _pokemon: &Pokemon, _source: DamageSource) {}
|
2022-06-27 16:26:27 +00:00
|
|
|
/// This function is triggered on a Pokemon and its parents when the given Pokemon is switched into
|
|
|
|
/// the battlefield.
|
2022-06-18 16:08:25 +00:00
|
|
|
fn on_switch_in(&self, _pokemon: &Pokemon) {}
|
2022-06-27 16:26:27 +00:00
|
|
|
/// This function is triggered on a Pokemon and its parents when the given Pokemon consumes the
|
|
|
|
/// held item it had.
|
2022-11-27 16:29:29 +00:00
|
|
|
fn on_after_held_item_consume(&self, _pokemon: &Pokemon, _item: &dyn Item) {}
|
2022-06-27 16:26:27 +00:00
|
|
|
/// This function is triggered on a Pokemon and its parents when the given Pokemon gains experience,
|
|
|
|
/// and allows for changing this amount of experience.
|
2022-06-18 16:08:25 +00:00
|
|
|
fn change_experience_gained(&self, _fainted_mon: &Pokemon, _winning_mon: &Pokemon, _amount: &mut u32) {}
|
2022-06-27 16:26:27 +00:00
|
|
|
/// This function is triggered on a Pokemon and its parents when the given Pokemon gains experience,
|
|
|
|
/// and allows for making the experience be shared across multiple Pokemon.
|
2022-06-18 16:08:25 +00:00
|
|
|
fn share_experience(&self, _fainted_mon: &Pokemon, _winning_mon: &Pokemon, _shares: &mut bool) {}
|
2022-06-27 16:26:27 +00:00
|
|
|
/// This function is triggered on a battle and its parents when something attempts to change the
|
|
|
|
/// weather, and allows for blocking the weather change.
|
2022-06-18 16:08:25 +00:00
|
|
|
fn block_weather(&self, _battle: &Battle, _blocked: &mut bool) {}
|
2022-06-27 17:21:50 +00:00
|
|
|
/// This function is called when a Pokeball is thrown at a Pokemon, and allows modifying the catch
|
2022-06-27 16:26:27 +00:00
|
|
|
/// rate of this attempt. Pokeball modifier effects should be implemented here, as well as for
|
|
|
|
/// example status effects that change capture rates.
|
2022-11-27 16:29:29 +00:00
|
|
|
fn change_capture_rate_bonus(&self, _target: &Pokemon, _pokeball: &dyn Item, _modifier: &mut u8) {}
|
2022-06-12 15:57:39 +00:00
|
|
|
|
2022-06-27 16:26:27 +00:00
|
|
|
/// Helper function to turn the self into an Any for downcasting.
|
2022-06-12 15:57:39 +00:00
|
|
|
fn as_any(&self) -> &dyn Any;
|
2022-06-27 16:26:27 +00:00
|
|
|
/// Helper function to turn the self into an Any for downcasting.
|
2022-06-18 16:08:25 +00:00
|
|
|
fn as_any_mut(&mut self) -> &mut dyn Any;
|
2022-06-03 14:35:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl Debug for dyn Script {
|
|
|
|
fn fmt(&self, _f: &mut Formatter<'_>) -> std::fmt::Result {
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
}
|
2022-06-12 15:57:39 +00:00
|
|
|
|
2022-06-27 17:21:50 +00:00
|
|
|
/// 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.
|
2022-06-18 16:41:23 +00:00
|
|
|
type ScriptHolder = Arc<RwLock<Option<Arc<dyn Script>>>>;
|
2022-06-12 15:57:39 +00:00
|
|
|
|
2022-06-27 17:21:50 +00:00
|
|
|
/// 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.
|
2022-06-18 17:44:13 +00:00
|
|
|
#[derive(Default, Debug)]
|
2022-06-12 15:57:39 +00:00
|
|
|
pub struct ScriptContainer {
|
2022-06-27 17:21:50 +00:00
|
|
|
/// The actual place where the script is stored.
|
2022-06-12 15:57:39 +00:00
|
|
|
script: ScriptHolder,
|
2022-06-27 17:21:50 +00:00
|
|
|
/// 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.
|
2022-06-18 17:44:13 +00:00
|
|
|
pub(crate) join_handle: RwLock<Option<JoinHandle<()>>>,
|
2022-06-12 15:57:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl ScriptContainer {
|
2022-06-27 17:21:50 +00:00
|
|
|
/// Initialize a script container with a specific script. To initialize with an empty script, use
|
|
|
|
/// default() instead.
|
2022-06-18 16:41:23 +00:00
|
|
|
pub fn new(script: Arc<dyn Script>) -> ScriptContainer {
|
2022-06-12 15:57:39 +00:00
|
|
|
Self {
|
|
|
|
script: Arc::new(RwLock::new(Some(script))),
|
2022-06-18 17:44:13 +00:00
|
|
|
join_handle: RwLock::new(None),
|
2022-06-12 15:57:39 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-06-27 17:21:50 +00:00
|
|
|
/// Get the internal script. Note that this can only be None if the script was marked for deletion.
|
2022-06-18 16:08:25 +00:00
|
|
|
pub fn get(&self) -> Option<&ScriptHolder> {
|
2023-01-02 09:41:57 +00:00
|
|
|
if self.script.read().as_ref().is_some_and(|a| a.is_marked_for_deletion()) {
|
2022-06-18 16:08:25 +00:00
|
|
|
if !self.script.is_locked() {
|
|
|
|
self.script.write().take();
|
|
|
|
}
|
|
|
|
None
|
|
|
|
} else {
|
|
|
|
Some(&self.script)
|
|
|
|
}
|
2022-06-12 15:57:39 +00:00
|
|
|
}
|
|
|
|
|
2022-06-27 17:21:50 +00:00
|
|
|
/// 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.
|
2022-06-18 16:41:23 +00:00
|
|
|
pub fn set(&self, script: Arc<dyn Script>) -> Arc<dyn Script> {
|
2022-06-18 16:08:25 +00:00
|
|
|
if let Some(v) = self.script.read().deref() {
|
2022-06-18 17:44:13 +00:00
|
|
|
v.on_remove();
|
2022-06-18 16:08:25 +00:00
|
|
|
v.mark_for_deletion();
|
|
|
|
}
|
2022-06-27 17:21:50 +00:00
|
|
|
// 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.
|
2022-06-18 16:08:25 +00:00
|
|
|
if self.script.is_locked() {
|
2022-06-18 16:41:23 +00:00
|
|
|
let holder = self.script.clone();
|
|
|
|
let new = script.clone();
|
2022-06-18 17:44:13 +00:00
|
|
|
let handle = std::thread::spawn(move || {
|
2022-06-18 16:41:23 +00:00
|
|
|
holder.write().replace(new);
|
|
|
|
});
|
2022-06-18 17:44:13 +00:00
|
|
|
self.join_handle.write().replace(handle);
|
2022-06-18 16:08:25 +00:00
|
|
|
} else {
|
2022-06-18 16:41:23 +00:00
|
|
|
self.script.write().replace(script.clone());
|
|
|
|
};
|
|
|
|
script
|
2022-06-12 15:57:39 +00:00
|
|
|
}
|
|
|
|
|
2022-06-27 17:21:50 +00:00
|
|
|
/// 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.
|
2022-06-12 15:57:39 +00:00
|
|
|
pub fn clear(&self) {
|
2022-06-18 16:08:25 +00:00
|
|
|
if let Some(v) = self.script.read().deref() {
|
2022-06-18 17:44:13 +00:00
|
|
|
v.on_remove();
|
2022-06-18 16:08:25 +00:00
|
|
|
v.mark_for_deletion();
|
|
|
|
}
|
|
|
|
if !self.script.is_locked() {
|
|
|
|
self.script.write().take();
|
|
|
|
}
|
2022-06-12 15:57:39 +00:00
|
|
|
}
|
|
|
|
|
2022-06-27 17:21:50 +00:00
|
|
|
/// Gets the underlying reference counter to the script.
|
2022-06-12 15:57:39 +00:00
|
|
|
pub fn arc(&self) -> &ScriptHolder {
|
|
|
|
&self.script
|
|
|
|
}
|
|
|
|
|
2022-06-27 17:21:50 +00:00
|
|
|
/// Get the underlying script as the downcasted value.
|
2022-06-12 15:57:39 +00:00
|
|
|
pub fn get_as<T: 'static>(&self) -> MappedRwLockReadGuard<T> {
|
|
|
|
RwLockReadGuard::map(self.script.read(), |a| unsafe {
|
|
|
|
let ptr = a.as_ref().as_ref().unwrap().as_ref() as *const dyn Script;
|
|
|
|
let any = ptr.as_ref().unwrap().as_any();
|
|
|
|
any.downcast_ref::<T>().unwrap()
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl From<ScriptHolder> for ScriptContainer {
|
|
|
|
fn from(a: ScriptHolder) -> Self {
|
2022-06-18 17:44:13 +00:00
|
|
|
Self {
|
|
|
|
script: a,
|
|
|
|
join_handle: RwLock::new(None),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Clone for ScriptContainer {
|
|
|
|
fn clone(&self) -> Self {
|
|
|
|
Self {
|
|
|
|
script: self.script.clone(),
|
|
|
|
join_handle: RwLock::new(None),
|
|
|
|
}
|
2022-06-12 15:57:39 +00:00
|
|
|
}
|
|
|
|
}
|
2022-06-18 16:08:25 +00:00
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
mod tests {
|
2022-06-18 16:41:23 +00:00
|
|
|
use std::sync::atomic::{AtomicBool, AtomicPtr};
|
2022-06-18 16:08:25 +00:00
|
|
|
|
2022-06-19 19:34:08 +00:00
|
|
|
use super::*;
|
|
|
|
|
2022-06-18 16:08:25 +00:00
|
|
|
pub struct TestScript {
|
|
|
|
name: StringKey,
|
2022-06-18 16:41:23 +00:00
|
|
|
container: AtomicPtr<ScriptContainer>,
|
2022-06-18 16:08:25 +00:00
|
|
|
suppressed_count: AtomicUsize,
|
|
|
|
marked_for_deletion: AtomicBool,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl TestScript {
|
|
|
|
fn new() -> Self {
|
|
|
|
Self {
|
2022-10-14 14:53:30 +00:00
|
|
|
name: "test".into(),
|
2022-06-18 16:41:23 +00:00
|
|
|
container: AtomicPtr::<ScriptContainer>::default(),
|
2022-06-18 16:08:25 +00:00
|
|
|
suppressed_count: AtomicUsize::new(0),
|
|
|
|
marked_for_deletion: Default::default(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
unsafe impl Sync for TestScript {}
|
|
|
|
|
|
|
|
unsafe impl Send for TestScript {}
|
|
|
|
|
|
|
|
impl Script for TestScript {
|
|
|
|
fn name(&self) -> &StringKey {
|
|
|
|
&self.name
|
|
|
|
}
|
|
|
|
|
|
|
|
fn get_marked_for_deletion(&self) -> &AtomicBool {
|
|
|
|
&self.marked_for_deletion
|
|
|
|
}
|
|
|
|
|
|
|
|
fn get_suppressed_count(&self) -> &AtomicUsize {
|
|
|
|
&self.suppressed_count
|
|
|
|
}
|
|
|
|
|
2022-07-18 13:36:03 +00:00
|
|
|
fn stack(&self) {
|
2022-06-18 16:41:23 +00:00
|
|
|
unsafe { self.container.load(Ordering::Relaxed).as_ref().unwrap().clear() }
|
2022-06-18 16:08:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
fn as_any(&self) -> &dyn Any {
|
|
|
|
self
|
|
|
|
}
|
|
|
|
fn as_any_mut(&mut self) -> &mut dyn Any {
|
|
|
|
self
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Removing yourself while active should be completely valid for a script. Consider for example
|
|
|
|
// a status effect such as sleep clearing itself in a script hook. As the script is actively
|
|
|
|
// being read from at that time, we should wait until the script hook is finished reading, and
|
|
|
|
// then dispose of the script.
|
|
|
|
#[test]
|
|
|
|
fn clear_self_while_active() {
|
2022-06-18 16:41:23 +00:00
|
|
|
let script = Arc::new(TestScript::new());
|
|
|
|
let mut container = ScriptContainer::new(script);
|
|
|
|
let c = &mut container as *mut ScriptContainer;
|
|
|
|
|
|
|
|
let w = container.script.read();
|
|
|
|
let script: &TestScript = w.as_ref().unwrap().as_any().downcast_ref().unwrap();
|
|
|
|
script.container.store(c, Ordering::SeqCst);
|
2022-06-18 16:08:25 +00:00
|
|
|
drop(w);
|
|
|
|
// Initialize with the script being taken as read lock. This prevents the script from actually
|
|
|
|
// removing itself, as it's still doing things.
|
2022-07-18 13:36:03 +00:00
|
|
|
container.script.read().as_ref().unwrap().stack();
|
2022-06-18 16:08:25 +00:00
|
|
|
// If we now try and get the script, it will be none the first time. This has the side effect
|
|
|
|
// of actually disposing of the script.
|
|
|
|
assert!(container.get().is_none());
|
|
|
|
// As we've properly disposed of the script now, the next fetch will return something.
|
|
|
|
assert!(container.get().is_some());
|
|
|
|
// But the value it returns shows that it is empty.
|
|
|
|
assert!(container.get().unwrap().read().is_none());
|
|
|
|
}
|
|
|
|
|
|
|
|
pub struct ReplaceTestScript {
|
|
|
|
name: StringKey,
|
2022-06-18 16:41:23 +00:00
|
|
|
container: AtomicPtr<ScriptContainer>,
|
2022-06-18 16:08:25 +00:00
|
|
|
suppressed_count: AtomicUsize,
|
|
|
|
marked_for_deletion: AtomicBool,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl ReplaceTestScript {
|
|
|
|
fn new(name: StringKey) -> Self {
|
|
|
|
Self {
|
|
|
|
name,
|
2022-06-18 16:41:23 +00:00
|
|
|
container: AtomicPtr::<ScriptContainer>::default(),
|
2022-06-18 16:08:25 +00:00
|
|
|
suppressed_count: AtomicUsize::new(0),
|
|
|
|
marked_for_deletion: Default::default(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-06-18 16:41:23 +00:00
|
|
|
fn test(&self, script: Arc<dyn Script>) {
|
2022-06-18 16:08:25 +00:00
|
|
|
unsafe {
|
2022-06-18 16:41:23 +00:00
|
|
|
self.container.load(Ordering::Relaxed).as_ref().unwrap().set(script);
|
2022-06-18 16:08:25 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
unsafe impl Sync for ReplaceTestScript {}
|
|
|
|
|
|
|
|
unsafe impl Send for ReplaceTestScript {}
|
|
|
|
|
|
|
|
impl Script for ReplaceTestScript {
|
|
|
|
fn name(&self) -> &StringKey {
|
|
|
|
&self.name
|
|
|
|
}
|
|
|
|
|
|
|
|
fn get_marked_for_deletion(&self) -> &AtomicBool {
|
|
|
|
&self.marked_for_deletion
|
|
|
|
}
|
|
|
|
|
|
|
|
fn get_suppressed_count(&self) -> &AtomicUsize {
|
|
|
|
&self.suppressed_count
|
|
|
|
}
|
|
|
|
|
|
|
|
fn as_any(&self) -> &dyn Any {
|
|
|
|
self
|
|
|
|
}
|
|
|
|
fn as_any_mut(&mut self) -> &mut dyn Any {
|
|
|
|
self
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn replace_self_while_active() {
|
2022-06-18 16:41:23 +00:00
|
|
|
let script = Arc::new(ReplaceTestScript::new("script1".into()));
|
|
|
|
let mut container = ScriptContainer::new(script);
|
|
|
|
let c = &mut container as *mut ScriptContainer;
|
|
|
|
|
|
|
|
let w = container.script.read();
|
|
|
|
let script: &ReplaceTestScript = w.as_ref().unwrap().as_any().downcast_ref().unwrap();
|
|
|
|
script.container.store(c, Ordering::SeqCst);
|
2022-06-18 16:08:25 +00:00
|
|
|
drop(w);
|
|
|
|
|
2022-06-18 16:41:23 +00:00
|
|
|
let script2 = Arc::new(ReplaceTestScript::new("script2".into()));
|
2022-06-18 16:08:25 +00:00
|
|
|
container
|
|
|
|
.script
|
|
|
|
.read()
|
|
|
|
.as_ref()
|
|
|
|
.unwrap()
|
|
|
|
.as_any()
|
|
|
|
.downcast_ref::<ReplaceTestScript>()
|
|
|
|
.unwrap()
|
|
|
|
.test(script2);
|
2022-06-18 17:44:13 +00:00
|
|
|
let mut jh = container.join_handle.write();
|
|
|
|
if jh.is_some() {
|
|
|
|
let h = jh.take().unwrap();
|
|
|
|
h.join().unwrap();
|
|
|
|
}
|
|
|
|
|
2022-10-14 14:53:30 +00:00
|
|
|
assert_eq!(container.script.read().as_ref().unwrap().name(), &"script2".into());
|
2022-06-18 16:08:25 +00:00
|
|
|
}
|
|
|
|
}
|
2022-09-07 16:01:26 +00:00
|
|
|
|
|
|
|
/// Data to store references to their owning objects on scripts.
|
|
|
|
pub enum ScriptOwnerData {
|
|
|
|
/// A script attached to a Pokemon has a reference to that Pokemon.
|
|
|
|
Pokemon(AtomicPtr<Pokemon>),
|
|
|
|
/// A script attached to a Battle Side has a reference to that Battle Side.
|
|
|
|
BattleSide(AtomicPtr<BattleSide>),
|
|
|
|
/// A script attached to a Battle has a reference to that Battle.
|
|
|
|
Battle(AtomicPtr<Battle>),
|
|
|
|
/// A script also can have no owner.
|
|
|
|
None,
|
|
|
|
}
|
|
|
|
|
2022-10-14 14:53:30 +00:00
|
|
|
impl From<&Pokemon> for ScriptOwnerData {
|
|
|
|
fn from(p: &Pokemon) -> Self {
|
|
|
|
ScriptOwnerData::Pokemon(AtomicPtr::new(p as *const Pokemon as *mut Pokemon))
|
2022-09-07 16:01:26 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-10-14 14:53:30 +00:00
|
|
|
impl From<&BattleSide> for ScriptOwnerData {
|
|
|
|
fn from(p: &BattleSide) -> Self {
|
|
|
|
ScriptOwnerData::BattleSide(AtomicPtr::new(p as *const BattleSide as *mut BattleSide))
|
2022-09-07 16:01:26 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-10-14 14:53:30 +00:00
|
|
|
impl From<&Battle> for ScriptOwnerData {
|
|
|
|
fn from(p: &Battle) -> Self {
|
|
|
|
ScriptOwnerData::Battle(AtomicPtr::new(p as *const Battle as *mut Battle))
|
2022-09-07 16:01:26 +00:00
|
|
|
}
|
|
|
|
}
|