More documentation for script hooks, reworks stat changes to only be changeable through a function that allows for script hooks, and events.
continuous-integration/drone/push Build is passing Details

This commit is contained in:
Deukhoofd 2022-06-27 18:26:27 +02:00
parent 1c9edd4d9c
commit cf4d74d898
Signed by: Deukhoofd
GPG Key ID: F63E044490819F6F
5 changed files with 119 additions and 9 deletions

View File

@ -3,8 +3,8 @@ use std::fmt::{Debug, Formatter};
use crate::dynamic_data::DamageSource; use crate::dynamic_data::DamageSource;
use crate::dynamic_data::ExecutingMove; use crate::dynamic_data::ExecutingMove;
use crate::dynamic_data::Pokemon; use crate::dynamic_data::Pokemon;
use crate::static_data::Form;
use crate::static_data::Species; use crate::static_data::Species;
use crate::static_data::{Form, Statistic};
/// The event hook is used to store external functions that listen to events. /// The event hook is used to store external functions that listen to events.
/// ///
@ -108,4 +108,15 @@ pub enum Event<'own, 'battle, 'library> {
}, },
/// The turn is finished running, waiting for new input. /// The turn is finished running, waiting for new input.
EndTurn, EndTurn,
/// A pokemon had its stat boost changed
StatBoostChange {
/// The pokemon that had its stat boosts changed.
user: &'own Pokemon<'battle, 'library>,
/// The statistic that changed.
stat: Statistic,
/// The value of the stat before the change.
old_value: i8,
/// The value of the stat after the change.
new_value: i8,
},
} }

View File

@ -43,7 +43,7 @@ impl Gen7BattleStatCalculator {
/// This functions returns the modifier we need to do to a stat for a given stat boost. /// 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(stat);
match boost { match boost {
-6 => 2.0 / 8.0, -6 => 2.0 / 8.0,
-5 => 2.0 / 7.0, -5 => 2.0 / 7.0,

View File

@ -191,8 +191,7 @@ impl DamageLibrary for Gen7DamageLibrary {
offensive_stat = Statistic::SpecialAttack; offensive_stat = Statistic::SpecialAttack;
defensive_stat = Statistic::SpecialDefense; defensive_stat = Statistic::SpecialDefense;
} }
let mut bypass_defensive_stat_boost = let mut bypass_defensive_stat_boost = hit_data.is_critical() && target.stat_boost(defensive_stat) > 0;
hit_data.is_critical() && target.stat_boost().get_stat(defensive_stat) > 0;
script_hook!( script_hook!(
bypass_defensive_stat_boost, bypass_defensive_stat_boost,
executing_move, executing_move,
@ -201,7 +200,7 @@ impl DamageLibrary for Gen7DamageLibrary {
hit_number, hit_number,
&mut bypass_defensive_stat_boost &mut bypass_defensive_stat_boost
); );
let mut bypass_offensive_stat_boost = hit_data.is_critical() && user.stat_boost().get_stat(offensive_stat) > 0; let mut bypass_offensive_stat_boost = hit_data.is_critical() && user.stat_boost(offensive_stat) > 0;
script_hook!( script_hook!(
bypass_offensive_stat_boost, bypass_offensive_stat_boost,
executing_move, executing_move,

View File

@ -12,7 +12,6 @@ use crate::dynamic_data::models::damage_source::DamageSource;
use crate::dynamic_data::models::learned_move::{LearnedMove, MoveLearnMethod}; use crate::dynamic_data::models::learned_move::{LearnedMove, MoveLearnMethod};
use crate::dynamic_data::script_handling::{ScriptSource, ScriptSourceData, ScriptWrapper}; use crate::dynamic_data::script_handling::{ScriptSource, ScriptSourceData, ScriptWrapper};
use crate::dynamic_data::{DynamicLibrary, Script, ScriptCategory, ScriptContainer, ScriptSet, VolatileScripts}; use crate::dynamic_data::{DynamicLibrary, Script, ScriptCategory, ScriptContainer, ScriptSet, VolatileScripts};
use crate::static_data::Ability;
use crate::static_data::AbilityIndex; use crate::static_data::AbilityIndex;
use crate::static_data::DataLibrary; use crate::static_data::DataLibrary;
use crate::static_data::Form; use crate::static_data::Form;
@ -20,6 +19,7 @@ use crate::static_data::Gender;
use crate::static_data::Item; use crate::static_data::Item;
use crate::static_data::Nature; use crate::static_data::Nature;
use crate::static_data::Species; use crate::static_data::Species;
use crate::static_data::{Ability, Statistic};
use crate::static_data::{ClampedStatisticSet, StatisticSet}; use crate::static_data::{ClampedStatisticSet, StatisticSet};
use crate::utils::Random; use crate::utils::Random;
use crate::{script_hook, PkmnResult, StringKey}; use crate::{script_hook, PkmnResult, StringKey};
@ -277,9 +277,57 @@ impl<'own, 'library> Pokemon<'own, 'library> {
pub fn boosted_stats(&self) -> &StatisticSet<AtomicU32> { pub fn boosted_stats(&self) -> &StatisticSet<AtomicU32> {
&self.boosted_stats &self.boosted_stats
} }
pub fn stat_boost(&self) -> &ClampedStatisticSet<AtomicI8, -6, 6> { pub fn stat_boost(&self, stat: Statistic) -> i8 {
&self.stat_boost self.stat_boost.get_stat(stat)
} }
pub fn change_stat_boost(&self, stat: Statistic, mut diff_amount: i8, self_inflicted: bool) -> bool {
let mut prevent = false;
script_hook!(
prevent_stat_boost_change,
self,
self,
stat,
diff_amount,
self_inflicted,
&mut prevent
);
if prevent {
return false;
}
script_hook!(
change_stat_boost_change,
self,
self,
stat,
self_inflicted,
&mut diff_amount
);
if diff_amount == 0 {
return false;
}
let mut changed = false;
let old_value = self.stat_boost.get_stat(stat);
if diff_amount > 0 {
changed = self.stat_boost.increase_stat(stat, diff_amount);
} else if diff_amount < 0 {
changed = self.stat_boost.decrease_stat(stat, -diff_amount);
}
if changed {
if let Some(battle) = self.get_battle() {
let new_value = self.stat_boost(stat);
battle.event_hook().trigger(Event::StatBoostChange {
user: self,
stat,
old_value,
new_value,
})
}
self.recalculate_boosted_stats();
}
return changed;
}
pub fn individual_values(&self) -> &ClampedStatisticSet<AtomicU8, 0, 31> { pub fn individual_values(&self) -> &ClampedStatisticSet<AtomicU8, 0, 31> {
&self.individual_values &self.individual_values
} }

View File

@ -165,11 +165,19 @@ pub trait Script: Send + Sync {
_modifier: &mut f32, _modifier: &mut f32,
) { ) {
} }
/// This function allows a script to apply a raw multiplier to the damage done by a move.
fn change_damage_modifier(&self, _move: &ExecutingMove, _target: &Arc<Pokemon>, _hit: u8, _modifier: &mut f32) {} fn change_damage_modifier(&self, _move: &ExecutingMove, _target: &Arc<Pokemon>, _hit: u8, _modifier: &mut f32) {}
/// This function allows a script to modify the outgoing damage done by a move.
fn change_damage(&self, _move: &ExecutingMove, _target: &Arc<Pokemon>, _hit: u8, _damage: &mut u32) {} fn change_damage(&self, _move: &ExecutingMove, _target: &Arc<Pokemon>, _hit: u8, _damage: &mut u32) {}
/// This function allows a script to modify the incoming damage done by a move.
fn change_incoming_damage(&self, _move: &ExecutingMove, _target: &Arc<Pokemon>, _hit: u8, _damage: &mut u32) {} fn change_incoming_damage(&self, _move: &ExecutingMove, _target: &Arc<Pokemon>, _hit: u8, _damage: &mut u32) {}
/// This function triggers when an incoming hit happens. This triggers after the damage is done,
/// but before the secondary effect of the move happens.
fn on_incoming_hit(&self, _move: &ExecutingMove, _target: &Arc<Pokemon>, _hit: u8) {} fn on_incoming_hit(&self, _move: &ExecutingMove, _target: &Arc<Pokemon>, _hit: u8) {}
/// This function triggers when an opponent on the field faints.
fn on_opponent_faints(&self, _move: &ExecutingMove, _target: &Arc<Pokemon>, _hit: u8) {} fn on_opponent_faints(&self, _move: &ExecutingMove, _target: &Arc<Pokemon>, _hit: u8) {}
/// This function allows a script attached to a Pokemon or its parents to prevent stat boost
/// changes on that Pokemon.
fn prevent_stat_boost_change( fn prevent_stat_boost_change(
&self, &self,
_target: &Pokemon, _target: &Pokemon,
@ -179,9 +187,23 @@ pub trait Script: Send + Sync {
_prevent: &mut bool, _prevent: &mut bool,
) { ) {
} }
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 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.
fn prevent_secondary_effect(&self, _move: &ExecutingMove, _target: &Arc<Pokemon>, _hit: u8, _prevent: &mut bool) {} fn prevent_secondary_effect(&self, _move: &ExecutingMove, _target: &Arc<Pokemon>, _hit: u8, _prevent: &mut bool) {}
/// 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.
fn change_effect_chance(&self, _move: &ExecutingMove, _target: &Arc<Pokemon>, _hit: u8, _chance: &mut f32) {} fn change_effect_chance(&self, _move: &ExecutingMove, _target: &Arc<Pokemon>, _hit: u8, _chance: &mut f32) {}
/// 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.
fn change_incoming_effect_chance( fn change_incoming_effect_chance(
&self, &self,
_move: &ExecutingMove, _move: &ExecutingMove,
@ -190,25 +212,55 @@ pub trait Script: Send + Sync {
_chance: &mut f32, _chance: &mut f32,
) { ) {
} }
/// 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.
fn on_secondary_effect(&self, _move: &ExecutingMove, _target: &Arc<Pokemon>, _hit: u8) {} fn on_secondary_effect(&self, _move: &ExecutingMove, _target: &Arc<Pokemon>, _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<Pokemon>) {} fn on_after_hits(&self, _move: &ExecutingMove, _target: &Arc<Pokemon>) {}
/// 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) {} 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) {} fn prevent_opponent_switch(&self, _choice: &TurnChoice, _prevent: &mut bool) {}
/// This function is called on a move and its parents when the move fails.
fn on_fail(&self, _target: &Pokemon) {} fn on_fail(&self, _target: &Pokemon) {}
/// This function is called on a script when an opponent fails.
fn on_opponent_fail(&self, _target: &Pokemon) {} fn on_opponent_fail(&self, _target: &Pokemon) {}
/// This function allows preventing the running away of the Pokemon its attached to
fn prevent_self_run_away(&self, _choice: &TurnChoice, _prevent: &mut bool) {} fn prevent_self_run_away(&self, _choice: &TurnChoice, _prevent: &mut bool) {}
/// This function prevents a Pokemon on another side than where its attached to from running away.
fn prevent_opponent_run_away(&self, _choice: &TurnChoice, _prevent: &mut bool) {} fn prevent_opponent_run_away(&self, _choice: &TurnChoice, _prevent: &mut bool) {}
/// 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.
fn on_end_turn(&self) {} fn on_end_turn(&self) {}
/// This function is triggered on a Pokemon and its parents when the given Pokemon takes damage.
fn on_damage(&self, _pokemon: &Pokemon, _source: DamageSource, _old_health: u32, _new_health: u32) {} fn on_damage(&self, _pokemon: &Pokemon, _source: DamageSource, _old_health: u32, _new_health: u32) {}
/// This function is triggered on a Pokemon and its parents when the given Pokemon faints.
fn on_faint(&self, _pokemon: &Pokemon, _source: DamageSource) {} fn on_faint(&self, _pokemon: &Pokemon, _source: DamageSource) {}
/// This function is triggered on a Pokemon and its parents when the given Pokemon is switched into
/// the battlefield.
fn on_switch_in(&self, _pokemon: &Pokemon) {} fn on_switch_in(&self, _pokemon: &Pokemon) {}
/// This function is triggered on a Pokemon and its parents when the given Pokemon consumes the
/// held item it had.
fn on_after_held_item_consume(&self, _pokemon: &Pokemon, _item: &Item) {} fn on_after_held_item_consume(&self, _pokemon: &Pokemon, _item: &Item) {}
/// This function is triggered on a Pokemon and its parents when the given Pokemon gains experience,
/// and allows for changing this amount of experience.
fn change_experience_gained(&self, _fainted_mon: &Pokemon, _winning_mon: &Pokemon, _amount: &mut u32) {} fn change_experience_gained(&self, _fainted_mon: &Pokemon, _winning_mon: &Pokemon, _amount: &mut u32) {}
/// 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.
fn share_experience(&self, _fainted_mon: &Pokemon, _winning_mon: &Pokemon, _shares: &mut bool) {} fn share_experience(&self, _fainted_mon: &Pokemon, _winning_mon: &Pokemon, _shares: &mut bool) {}
/// 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) {} 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
/// 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) {} fn change_capture_rate_bonus(&self, _target: &Pokemon, _pokeball: &Item, _modifier: &mut u8) {}
/// Helper function to turn the self into an Any for downcasting.
fn as_any(&self) -> &dyn Any; fn as_any(&self) -> &dyn Any;
/// Helper function to turn the self into an Any for downcasting.
fn as_any_mut(&mut self) -> &mut dyn Any; fn as_any_mut(&mut self) -> &mut dyn Any;
} }