Support for errors from scripts through separate script error handling.
continuous-integration/drone/push Build is passing Details

This commit is contained in:
Deukhoofd 2023-04-21 10:35:46 +02:00
parent a6f4b1d5c5
commit eb68977290
Signed by: Deukhoofd
GPG Key ID: F63E044490819F6F
9 changed files with 677 additions and 222 deletions

View File

@ -353,7 +353,7 @@ impl Battle {
if let Some(script) = self.weather.get() { if let Some(script) = self.weather.get() {
let lock = script.read(); let lock = script.read();
Ok(Some( Ok(Some(
lock.as_ref().ok_or(PkmnError::UnableToAcquireLock)?.name().clone(), lock.as_ref().ok_or(PkmnError::UnableToAcquireLock)?.name()?.clone(),
)) ))
} else { } else {
Ok(None) Ok(None)

View File

@ -535,11 +535,18 @@ impl Pokemon {
.library .library
.load_script(self.into(), ScriptCategory::Ability, ability.name())?; .load_script(self.into(), ScriptCategory::Ability, ability.name())?;
if let Some(ability_script) = ability_script { if let Some(ability_script) = ability_script {
self.ability_script let script_result = self
.ability_script
.set(ability_script) .set(ability_script)
.as_ref() .as_ref()
// Ensure the ability script gets initialized with the parameters for the ability. // Ensure the ability script gets initialized with the parameters for the ability.
.on_initialize(&self.library, ability.parameters().to_vec()) .on_initialize(&self.library, ability.parameters().to_vec());
match script_result {
Ok(_) => (),
Err(e) => {
crate::dynamic_data::script_handling::handle_script_error(&e);
}
}
} else { } else {
self.ability_script.clear(); self.ability_script.clear();
} }

View File

@ -1,5 +1,5 @@
use anyhow::{anyhow, Result}; use anyhow::{anyhow, Result};
use std::sync::{Arc, Weak}; use std::sync::{Arc, LazyLock, Weak};
use parking_lot::RwLock; use parking_lot::RwLock;
@ -33,7 +33,12 @@ macro_rules! script_hook {
if let Some(script) = script { if let Some(script) = script {
if let Some(script) = script.read().as_deref() { if let Some(script) = script.read().as_deref() {
if !script.is_suppressed() { if !script.is_suppressed() {
script.$hook_name($($parameters),*); match script.$hook_name($($parameters),*) {
Ok(_) => {}
Err(e) => {
$crate::dynamic_data::script_handling::handle_script_error(&e);
}
}
} }
} }
} }
@ -53,7 +58,12 @@ macro_rules! run_scripts {
let s = s.read(); let s = s.read();
if let Some(s) = s.deref() { if let Some(s) = s.deref() {
if !s.is_suppressed() { if !s.is_suppressed() {
s.$hook_name($($parameters),*); match s.$hook_name($($parameters),*) {
Ok(_) => {}
Err(e) => {
$crate::dynamic_data::script_handling::handle_script_error(&e);
}
}
} }
} }
} }
@ -65,8 +75,13 @@ macro_rules! run_scripts {
if let Some(s) = s.get() { if let Some(s) = s.get() {
let s = s.read(); let s = s.read();
if let Some(s) = s.deref() { if let Some(s) = s.deref() {
if !s.is_suppressed() && set.has(s.name()) { if !s.is_suppressed() && set.has(s.name()?) {
s.$hook_name($($parameters),*); match s.$hook_name($($parameters),*) {
Ok(_) => {}
Err(e) => {
$crate::dynamic_data::script_handling::handle_script_error(&e);
}
}
} }
} }
} }
@ -78,6 +93,35 @@ macro_rules! run_scripts {
}; };
} }
/// When a script encounters an error, this function should be called. This allows the implementation
/// to define how to handle script errors.
pub(crate) fn handle_script_error(e: &anyhow_ext::Error) {
unsafe {
(HANDLE_SCRIPT_ERROR_IMPL.read())(e);
}
}
/// The type of the function that is called when a script encounters an error.
type ScriptErrorFunction = Box<dyn Fn(&anyhow_ext::Error)>;
/// The currently set script error handler.
static mut HANDLE_SCRIPT_ERROR_IMPL: LazyLock<RwLock<ScriptErrorFunction>> =
LazyLock::new(|| RwLock::new(Box::new(default_script_error_handler)));
/// The default script error handler. This will panic with the error message. As this can (and should)
/// be changed by the implementation, we allow panics here.
#[allow(clippy::panic)]
fn default_script_error_handler(e: &anyhow_ext::Error) {
panic!("Script error: {}", e);
}
/// Sets the script error handler to the given function.
pub fn set_script_error_handler(f: ScriptErrorFunction) {
unsafe {
*HANDLE_SCRIPT_ERROR_IMPL.write() = f;
}
}
/// The script source data is the basic data required for any script source. /// The script source data is the basic data required for any script source.
#[derive(Default, Debug)] #[derive(Default, Debug)]
pub struct ScriptSourceData { pub struct ScriptSourceData {
@ -279,8 +323,8 @@ mod tests {
} }
impl Script for TestScript { impl Script for TestScript {
fn name(&self) -> &StringKey { fn name(&self) -> Result<&StringKey> {
&self.name Ok(&self.name)
} }
fn get_marked_for_deletion(&self) -> &AtomicBool { fn get_marked_for_deletion(&self) -> &AtomicBool {
@ -295,8 +339,9 @@ mod tests {
fn remove_suppression(&self) {} fn remove_suppression(&self) {}
fn stack(&self) { fn stack(&self) -> Result<()> {
self.test_count.fetch_add(1, Ordering::SeqCst); self.test_count.fetch_add(1, Ordering::SeqCst);
Ok(())
} }
fn as_any(&self) -> &dyn Any { fn as_any(&self) -> &dyn Any {
@ -314,7 +359,7 @@ mod tests {
let scripts = vec![ScriptWrapper::from(&script)]; let scripts = vec![ScriptWrapper::from(&script)];
let mut aggregator = ScriptIterator::new(&scripts as *const Vec<ScriptWrapper>); let mut aggregator = ScriptIterator::new(&scripts as *const Vec<ScriptWrapper>);
while let Some(v) = aggregator.get_next().unwrap() { while let Some(v) = aggregator.get_next().unwrap() {
v.get().unwrap().read().as_ref().unwrap().stack(); v.get().unwrap().read().as_ref().unwrap().stack().unwrap();
} }
let a = script.get_as::<TestScript>().unwrap(); let a = script.get_as::<TestScript>().unwrap();
assert_eq!(a.test_count.load(Ordering::Relaxed), 1); assert_eq!(a.test_count.load(Ordering::Relaxed), 1);
@ -328,7 +373,7 @@ mod tests {
for i in 1..11 { for i in 1..11 {
aggregator.reset(); aggregator.reset();
while let Some(v) = aggregator.get_next().unwrap() { while let Some(v) = aggregator.get_next().unwrap() {
v.get().unwrap().read().as_ref().unwrap().stack(); v.get().unwrap().read().as_ref().unwrap().stack().unwrap();
} }
let a = script.get_as::<TestScript>().unwrap(); let a = script.get_as::<TestScript>().unwrap();
assert_eq!(a.test_count.load(Ordering::Relaxed), i); assert_eq!(a.test_count.load(Ordering::Relaxed), i);
@ -347,7 +392,7 @@ mod tests {
]; ];
let mut aggregator = ScriptIterator::new(&scripts as *const Vec<ScriptWrapper>); let mut aggregator = ScriptIterator::new(&scripts as *const Vec<ScriptWrapper>);
while let Some(v) = aggregator.get_next().unwrap() { while let Some(v) = aggregator.get_next().unwrap() {
v.get().unwrap().read().as_ref().unwrap().stack(); v.get().unwrap().read().as_ref().unwrap().stack().unwrap();
} }
let a = script1.get_as::<TestScript>().unwrap(); let a = script1.get_as::<TestScript>().unwrap();
assert_eq!(a.test_count.load(Ordering::Relaxed), 1); assert_eq!(a.test_count.load(Ordering::Relaxed), 1);
@ -371,7 +416,7 @@ mod tests {
for i in 1..11 { for i in 1..11 {
aggregator.reset(); aggregator.reset();
while let Some(v) = aggregator.get_next().unwrap() { while let Some(v) = aggregator.get_next().unwrap() {
v.get().unwrap().read().as_ref().unwrap().stack(); v.get().unwrap().read().as_ref().unwrap().stack().unwrap();
} }
let a = script1.get_as::<TestScript>().unwrap(); let a = script1.get_as::<TestScript>().unwrap();
assert_eq!(a.test_count.load(Ordering::Relaxed), i); assert_eq!(a.test_count.load(Ordering::Relaxed), i);
@ -385,38 +430,38 @@ mod tests {
#[test] #[test]
fn script_aggregator_property_iterates_script_set() { fn script_aggregator_property_iterates_script_set() {
let set = Arc::new(ScriptSet::default()); let set = Arc::new(ScriptSet::default());
set.add(Arc::new(TestScript::new_with_name("test_a"))); set.add(Arc::new(TestScript::new_with_name("test_a"))).unwrap();
set.add(Arc::new(TestScript::new_with_name("test_b"))); set.add(Arc::new(TestScript::new_with_name("test_b"))).unwrap();
set.add(Arc::new(TestScript::new_with_name("test_c"))); set.add(Arc::new(TestScript::new_with_name("test_c"))).unwrap();
let scripts = vec![ScriptWrapper::from(&set)]; let scripts = vec![ScriptWrapper::from(&set)];
let mut aggregator = ScriptIterator::new(&scripts as *const Vec<ScriptWrapper>); let mut aggregator = ScriptIterator::new(&scripts as *const Vec<ScriptWrapper>);
for i in 1..11 { for i in 1..11 {
aggregator.reset(); aggregator.reset();
while let Some(v) = aggregator.get_next().unwrap() { while let Some(v) = aggregator.get_next().unwrap() {
v.get().unwrap().read().as_ref().unwrap().stack(); v.get().unwrap().read().as_ref().unwrap().stack().unwrap();
} }
let s = set.at(0).unwrap(); let s = set.at(0).unwrap();
let s = s.get_as::<TestScript>().unwrap(); let s = s.get_as::<TestScript>().unwrap();
assert_eq!(s.test_count.load(Ordering::Relaxed), i); assert_eq!(s.test_count.load(Ordering::Relaxed), i);
assert_eq!(s.name().str(), "test_a"); assert_eq!(s.name().unwrap().str(), "test_a");
let s = set.at(1).unwrap(); let s = set.at(1).unwrap();
let s = s.get_as::<TestScript>().unwrap(); let s = s.get_as::<TestScript>().unwrap();
assert_eq!(s.test_count.load(Ordering::Relaxed), i); assert_eq!(s.test_count.load(Ordering::Relaxed), i);
assert_eq!(s.name().str(), "test_b"); assert_eq!(s.name().unwrap().str(), "test_b");
let s = set.at(2).unwrap(); let s = set.at(2).unwrap();
let s = s.get_as::<TestScript>().unwrap(); let s = s.get_as::<TestScript>().unwrap();
assert_eq!(s.test_count.load(Ordering::Relaxed), i); assert_eq!(s.test_count.load(Ordering::Relaxed), i);
assert_eq!(s.name().str(), "test_c"); assert_eq!(s.name().unwrap().str(), "test_c");
} }
} }
#[test] #[test]
fn script_aggregator_property_iterates_script_set_when_removing_last() { fn script_aggregator_property_iterates_script_set_when_removing_last() {
let set = Arc::new(ScriptSet::default()); let set = Arc::new(ScriptSet::default());
set.add(Arc::new(TestScript::new_with_name("test_a"))); set.add(Arc::new(TestScript::new_with_name("test_a"))).unwrap();
set.add(Arc::new(TestScript::new_with_name("test_b"))); set.add(Arc::new(TestScript::new_with_name("test_b"))).unwrap();
set.add(Arc::new(TestScript::new_with_name("test_c"))); set.add(Arc::new(TestScript::new_with_name("test_c"))).unwrap();
let scripts = vec![ScriptWrapper::from(&set)]; let scripts = vec![ScriptWrapper::from(&set)];
let mut aggregator = ScriptIterator::new(&scripts as *const Vec<ScriptWrapper>); let mut aggregator = ScriptIterator::new(&scripts as *const Vec<ScriptWrapper>);
@ -431,6 +476,7 @@ mod tests {
.as_ref() .as_ref()
.unwrap() .unwrap()
.name() .name()
.unwrap()
.str(), .str(),
"test_a" "test_a"
); );
@ -445,6 +491,7 @@ mod tests {
.as_ref() .as_ref()
.unwrap() .unwrap()
.name() .name()
.unwrap()
.str(), .str(),
"test_b" "test_b"
); );
@ -456,9 +503,9 @@ mod tests {
#[test] #[test]
fn script_aggregator_property_iterates_script_set_when_removing_middle() { fn script_aggregator_property_iterates_script_set_when_removing_middle() {
let set = Arc::new(ScriptSet::default()); let set = Arc::new(ScriptSet::default());
set.add(Arc::new(TestScript::new_with_name("test_a"))); set.add(Arc::new(TestScript::new_with_name("test_a"))).unwrap();
set.add(Arc::new(TestScript::new_with_name("test_b"))); set.add(Arc::new(TestScript::new_with_name("test_b"))).unwrap();
set.add(Arc::new(TestScript::new_with_name("test_c"))); set.add(Arc::new(TestScript::new_with_name("test_c"))).unwrap();
let scripts = vec![ScriptWrapper::from(&set)]; let scripts = vec![ScriptWrapper::from(&set)];
let mut aggregator = ScriptIterator::new(&scripts as *const Vec<ScriptWrapper>); let mut aggregator = ScriptIterator::new(&scripts as *const Vec<ScriptWrapper>);
@ -473,6 +520,7 @@ mod tests {
.as_ref() .as_ref()
.unwrap() .unwrap()
.name() .name()
.unwrap()
.str(), .str(),
"test_a" "test_a"
); );
@ -490,6 +538,7 @@ mod tests {
.as_ref() .as_ref()
.unwrap() .unwrap()
.name() .name()
.unwrap()
.str(), .str(),
"test_c" "test_c"
); );

View File

@ -23,7 +23,7 @@ use crate::StringKey;
pub trait Script: Send + Sync { pub trait Script: Send + Sync {
/// The name of a script is its unique identifier. This should generally be set on load, and be /// 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. /// the same as the key that was used to load it.
fn name(&self) -> &StringKey; fn name(&self) -> Result<&StringKey>;
/// Returns an atomic bool for internal marking of deletion. This is currently only specifically /// 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 /// used for deletion of a script while we are holding a reference to it (i.e. executing a script
///hook on it). ///hook on it).
@ -61,50 +61,80 @@ pub trait Script: Send + Sync {
/// This function is ran when a volatile effect is added while that volatile effect already is /// 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. /// in place. Instead of adding the volatile effect twice, it will execute this function instead.
fn stack(&self) {} fn stack(&self) -> Result<()> {
Ok(())
}
/// This function is ran when this script stops being in effect, and is removed from its owner. /// This function is ran when this script stops being in effect, and is removed from its owner.
fn on_remove(&self) {} fn on_remove(&self) -> Result<()> {
Ok(())
}
/// This function is ran when this script starts being in effect. /// This function is ran when this script starts being in effect.
fn on_initialize(&self, _library: &Arc<dyn DynamicLibrary>, _pars: Vec<EffectParameter>) {} fn on_initialize(&self, _library: &Arc<dyn DynamicLibrary>, _pars: Vec<EffectParameter>) -> Result<()> {
Ok(())
}
/// This function is ran just before the start of the turn. Everyone has made its choices here, /// 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 /// 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. /// something has happened during a turn.
fn on_before_turn(&self, _choice: &TurnChoice) {} fn on_before_turn(&self, _choice: &TurnChoice) -> Result<()> {
Ok(())
}
/// This function allows you to modify the effective speed of the Pokemon. This is ran before /// 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. /// turn ordering, so overriding here will allow you to put certain Pokemon before others.
fn change_speed(&self, _choice: &TurnChoice, _speed: &mut u32) {} fn change_speed(&self, _choice: &TurnChoice, _speed: &mut u32) -> Result<()> {
Ok(())
}
/// This function allows you to modify the effective priority of the Pokemon. This is ran before /// 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 /// 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. /// that this is only relevant on move choices, as other turn choice types do not have a priority.
fn change_priority(&self, _choice: &TurnChoice, _priority: &mut i8) {} fn change_priority(&self, _choice: &TurnChoice, _priority: &mut i8) -> Result<()> {
Ok(())
}
/// This function allows you to change the move that is used during execution. This is useful for /// 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. /// moves such as metronome, where the move chosen actually differs from the move used.
fn change_move(&self, _choice: &TurnChoice, _move_name: &mut StringKey) {} fn change_move(&self, _choice: &TurnChoice, _move_name: &mut StringKey) -> Result<()> {
Ok(())
}
/// This function allows you to change a move into a multi-hit move. The number of hits set here /// 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 /// gets used as the number of hits. If set to 0, this will behave as if the move missed on its
/// first hit. /// first hit.
fn change_number_of_hits(&self, _choice: &TurnChoice, _number_of_hits: &mut u8) {} fn change_number_of_hits(&self, _choice: &TurnChoice, _number_of_hits: &mut u8) -> Result<()> {
Ok(())
}
/// This function allows you to prevent a move from running. If this gets set to true, the move /// 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. /// ends execution here. No PP will be decreased in this case.
fn prevent_move(&self, _move: &ExecutingMove, _prevent: &mut bool) {} fn prevent_move(&self, _move: &ExecutingMove, _prevent: &mut bool) -> Result<()> {
Ok(())
}
/// This function makes the move fail. If the fail field gets set to true, the move ends execution, /// This function makes the move fail. If the fail field gets set to true, the move ends execution,
/// and fail events get triggered. /// and fail events get triggered.
fn fail_move(&self, _move: &ExecutingMove, _fail: &mut bool) {} fn fail_move(&self, _move: &ExecutingMove, _fail: &mut bool) -> Result<()> {
Ok(())
}
/// Similar to [`Self::prevent_move`]. This function will also stop execution, but PP will be /// Similar to [`Self::prevent_move`]. This function will also stop execution, but PP will be
/// decreased. /// decreased.
fn stop_before_move(&self, _move: &ExecutingMove, _stop: &mut bool) {} fn stop_before_move(&self, _move: &ExecutingMove, _stop: &mut bool) -> Result<()> {
Ok(())
}
/// This function runs just before the move starts its execution. /// This function runs just before the move starts its execution.
fn on_before_move(&self, _move: &ExecutingMove) {} fn on_before_move(&self, _move: &ExecutingMove) -> Result<()> {
Ok(())
}
/// This function allows a script to prevent a move that is targeted at its owner. If set to true /// 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. /// the move fails, and fail events get triggered.
fn fail_incoming_move(&self, _move: &ExecutingMove, _target: &Arc<Pokemon>, _fail: &mut bool) {} fn fail_incoming_move(&self, _move: &ExecutingMove, _target: &Arc<Pokemon>, _fail: &mut bool) -> Result<()> {
Ok(())
}
/// This function allows a script to make its owner invulnerable to an incoming move. /// This function allows a script to make its owner invulnerable to an incoming move.
fn is_invulnerable(&self, _move: &ExecutingMove, _target: &Arc<Pokemon>, _invulnerable: &mut bool) {} fn is_invulnerable(&self, _move: &ExecutingMove, _target: &Arc<Pokemon>, _invulnerable: &mut bool) -> Result<()> {
Ok(())
}
/// This function occurs when a move gets missed. This runs on the scripts belonging to the executing /// 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. /// move, which include the scripts that are attached to the owner of the script.
fn on_move_miss(&self, _move: &ExecutingMove, _target: &Arc<Pokemon>) {} fn on_move_miss(&self, _move: &ExecutingMove, _target: &Arc<Pokemon>) -> Result<()> {
Ok(())
}
/// This function allows the script to change the actual type that is used for the move on a target. /// This function allows the script to change the actual type that is used for the move on a target.
fn change_move_type( fn change_move_type(
&self, &self,
@ -112,12 +142,29 @@ pub trait Script: Send + Sync {
_target: &Arc<Pokemon>, _target: &Arc<Pokemon>,
_hit: u8, _hit: u8,
_move_type: &mut TypeIdentifier, _move_type: &mut TypeIdentifier,
) { ) -> Result<()> {
Ok(())
} }
/// This function allows the script to change how effective a move is on a target. /// This function allows the script to change how effective a move is on a target.
fn change_effectiveness(&self, _move: &ExecutingMove, _target: &Arc<Pokemon>, _hit: u8, _effectiveness: &mut f32) {} fn change_effectiveness(
&self,
_move: &ExecutingMove,
_target: &Arc<Pokemon>,
_hit: u8,
_effectiveness: &mut f32,
) -> Result<()> {
Ok(())
}
/// This function allows a script to block an outgoing move from being critical. /// This function allows a script to block an outgoing move from being critical.
fn block_critical(&self, _move: &ExecutingMove, _target: &Arc<Pokemon>, _hit: u8, _block_critical: &mut bool) {} fn block_critical(
&self,
_move: &ExecutingMove,
_target: &Arc<Pokemon>,
_hit: u8,
_block_critical: &mut bool,
) -> Result<()> {
Ok(())
}
/// This function allows a script to block an incoming move from being critical. /// This function allows a script to block an incoming move from being critical.
fn block_incoming_critical( fn block_incoming_critical(
&self, &self,
@ -125,33 +172,104 @@ pub trait Script: Send + Sync {
_target: &Arc<Pokemon>, _target: &Arc<Pokemon>,
_hit: u8, _hit: u8,
_block_critical: &mut bool, _block_critical: &mut bool,
) { ) -> Result<()> {
Ok(())
} }
/// This function allows a script to modify the accuracy of a move used. This value represents /// 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. /// 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) {} fn change_accuracy(
&self,
_move: &ExecutingMove,
_target: &Arc<Pokemon>,
_hit: u8,
_accuracy: &mut u8,
) -> Result<()> {
Ok(())
}
/// This function allows a script to change the critical stage of the move used. /// This function allows a script to change the critical stage of the move used.
fn change_critical_stage(&self, _move: &ExecutingMove, _target: &Arc<Pokemon>, _hit: u8, _stage: &mut u8) {} fn change_critical_stage(
&self,
_move: &ExecutingMove,
_target: &Arc<Pokemon>,
_hit: u8,
_stage: &mut u8,
) -> Result<()> {
Ok(())
}
/// This function allows a script to change the damage modifier of a critical hit. This will only /// This function allows a script to change the damage modifier of a critical hit. This will only
/// run when a hit is critical. /// run when a hit is critical.
fn change_critical_modifier(&self, _move: &ExecutingMove, _target: &Arc<Pokemon>, _hit: u8, _modifier: &mut f32) {} fn change_critical_modifier(
&self,
_move: &ExecutingMove,
_target: &Arc<Pokemon>,
_hit: u8,
_modifier: &mut f32,
) -> Result<()> {
Ok(())
}
/// This function allows a script to change the damage modifier of a Same Type Attack Bonus, which /// 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. /// occurs when the user has the move type as one of its own types.
fn change_stab_modifier(&self, _move: &ExecutingMove, _target: &Arc<Pokemon>, _hit: u8, _modifier: &mut f32) {} fn change_stab_modifier(
&self,
_move: &ExecutingMove,
_target: &Arc<Pokemon>,
_hit: u8,
_modifier: &mut f32,
) -> Result<()> {
Ok(())
}
/// This function allows a script to change the effective base power of a move hit. /// This function allows a script to change the effective base power of a move hit.
fn change_base_power(&self, _move: &ExecutingMove, _target: &Arc<Pokemon>, _hit: u8, _base_power: &mut u8) {} fn change_base_power(
&self,
_move: &ExecutingMove,
_target: &Arc<Pokemon>,
_hit: u8,
_base_power: &mut u8,
) -> Result<()> {
Ok(())
}
/// This function allows a script to bypass defensive stat boosts for a move hit. /// This function allows a script to bypass defensive stat boosts for a move hit.
fn bypass_defensive_stat_boost(&self, _move: &ExecutingMove, _target: &Arc<Pokemon>, _hit: u8, _bypass: &mut bool) { fn bypass_defensive_stat_boost(
&self,
_move: &ExecutingMove,
_target: &Arc<Pokemon>,
_hit: u8,
_bypass: &mut bool,
) -> Result<()> {
Ok(())
} }
/// This function allows a script to bypass offensive stat boosts for a move hit. /// This function allows a script to bypass offensive stat boosts for a move hit.
fn bypass_offensive_stat_boost(&self, _move: &ExecutingMove, _target: &Arc<Pokemon>, _hit: u8, _bypass: &mut bool) { fn bypass_offensive_stat_boost(
&self,
_move: &ExecutingMove,
_target: &Arc<Pokemon>,
_hit: u8,
_bypass: &mut bool,
) -> Result<()> {
Ok(())
} }
/// This function allows a script to change the actual offensive stat values used when calculating damage /// This function allows a script to change the actual offensive stat values used when calculating damage
fn change_offensive_stat_value(&self, _move: &ExecutingMove, _target: &Arc<Pokemon>, _hit: u8, _amount: &mut u32) {} fn change_offensive_stat_value(
&self,
_move: &ExecutingMove,
_target: &Arc<Pokemon>,
_hit: u8,
_amount: &mut u32,
) -> Result<()> {
Ok(())
}
/// This function allows a script to change the actual defensive stat values used when calculating damage. /// This function allows a script to change the actual defensive stat values used when calculating damage.
fn change_defensive_stat_value(&self, _move: &ExecutingMove, _target: &Arc<Pokemon>, _hit: u8, _amount: &mut u32) {} fn change_defensive_stat_value(
&self,
_move: &ExecutingMove,
_target: &Arc<Pokemon>,
_hit: u8,
_amount: &mut u32,
) -> Result<()> {
Ok(())
}
/// This function allows a script to change the raw modifier we retrieved from the stats of the /// This function allows a script to change the raw modifier we retrieved from the stats of the
/// defender and attacker. /// defender and attacker.
@ -161,19 +279,42 @@ pub trait Script: Send + Sync {
_target: &Arc<Pokemon>, _target: &Arc<Pokemon>,
_hit: u8, _hit: u8,
_modifier: &mut f32, _modifier: &mut f32,
) { ) -> Result<()> {
Ok(())
} }
/// This function allows a script to apply a raw multiplier to the damage done by a move. /// 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,
) -> Result<()> {
Ok(())
}
/// This function allows a script to modify the outgoing damage done by a move. /// 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) -> Result<()> {
Ok(())
}
/// This function allows a script to modify the incoming damage done by a move. /// 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,
) -> Result<()> {
Ok(())
}
/// This function triggers when an incoming hit happens. This triggers after the damage is done, /// This function triggers when an incoming hit happens. This triggers after the damage is done,
/// but before the secondary effect of the move happens. /// 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) -> Result<()> {
Ok(())
}
/// This function triggers when an opponent on the field faints. /// 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) -> Result<()> {
Ok(())
}
/// This function allows a script attached to a Pokemon or its parents to prevent stat boost /// This function allows a script attached to a Pokemon or its parents to prevent stat boost
/// changes on that Pokemon. /// changes on that Pokemon.
fn prevent_stat_boost_change( fn prevent_stat_boost_change(
@ -183,21 +324,46 @@ pub trait Script: Send + Sync {
_amount: i8, _amount: i8,
_self_inflicted: bool, _self_inflicted: bool,
_prevent: &mut bool, _prevent: &mut bool,
) { ) -> Result<()> {
Ok(())
} }
/// This function allows a script attached to a Pokemon or its parents to modify the amount by /// 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 /// 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. /// 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) {} fn change_stat_boost_change(
&self,
_target: &Pokemon,
_stat: Statistic,
_self_inflicted: bool,
_amount: &mut i8,
) -> Result<()> {
Ok(())
}
/// This function allows a script attached to a Pokemon or its parents to prevent an incoming /// 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. 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. /// 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,
) -> Result<()> {
Ok(())
}
/// This function allows a script attached to a move or its parents to change the chance the /// 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 /// 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 /// 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. /// 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,
) -> Result<()> {
Ok(())
}
/// This function allows a script attached to a Pokemon or its parents to change the chance the /// 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, /// 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 /// so changing this to above or equal to 100 will make it always hit, while setting it to equal
@ -208,53 +374,93 @@ pub trait Script: Send + Sync {
_target: &Arc<Pokemon>, _target: &Arc<Pokemon>,
_hit: u8, _hit: u8,
_chance: &mut f32, _chance: &mut f32,
) { ) -> Result<()> {
Ok(())
} }
/// This function triggers when the move uses its secondary effect. Moves should implement their /// 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 /// 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. /// 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) -> Result<()> {
Ok(())
}
/// This function triggers on a move or its parents when all hits on a target are finished. /// 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>) -> Result<()> {
Ok(())
}
/// 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) {} fn prevent_self_switch(&self, _choice: &TurnChoice, _prevent: &mut bool) -> Result<()> {
Ok(())
}
/// This function allows the prevention of switching for any opponent. /// 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) -> Result<()> {
Ok(())
}
/// This function is called on a move and its parents when the move fails. /// 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) -> Result<()> {
Ok(())
}
/// This function is called on a script when an opponent fails. /// 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) -> Result<()> {
Ok(())
}
/// This function allows preventing the running away of the Pokemon its attached to /// 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) -> Result<()> {
Ok(())
}
/// This function prevents a Pokemon on another side than where its attached to from running away. /// 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) -> Result<()> {
Ok(())
}
/// This function id triggered on all scripts active in the battle after all choices have finished /// 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 /// running. Note that choices are not active anymore here, so their scripts do not call this
/// function. /// function.
fn on_end_turn(&self) {} fn on_end_turn(&self) -> Result<()> {
Ok(())
}
/// This function is triggered on a Pokemon and its parents when the given Pokemon takes damage. /// 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) -> Result<()> {
Ok(())
}
/// This function is triggered on a Pokemon and its parents when the given Pokemon faints. /// 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) -> Result<()> {
Ok(())
}
/// This function is triggered on a Pokemon and its parents when the given Pokemon is switched into /// This function is triggered on a Pokemon and its parents when the given Pokemon is switched into
/// the battlefield. /// the battlefield.
fn on_switch_in(&self, _pokemon: &Pokemon) {} fn on_switch_in(&self, _pokemon: &Pokemon) -> Result<()> {
Ok(())
}
/// This function is triggered on a Pokemon and its parents when the given Pokemon consumes the /// This function is triggered on a Pokemon and its parents when the given Pokemon consumes the
/// held item it had. /// held item it had.
fn on_after_held_item_consume(&self, _pokemon: &Pokemon, _item: &dyn Item) {} fn on_after_held_item_consume(&self, _pokemon: &Pokemon, _item: &dyn Item) -> Result<()> {
Ok(())
}
/// This function is triggered on a Pokemon and its parents when the given Pokemon gains experience, /// This function is triggered on a Pokemon and its parents when the given Pokemon gains experience,
/// and allows for changing this amount of 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,
) -> Result<()> {
Ok(())
}
/// This function is triggered on a Pokemon and its parents when the given Pokemon gains experience, /// 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. /// 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) -> Result<()> {
Ok(())
}
/// This function is triggered on a battle and its parents when something attempts to change the /// This function is triggered on a battle and its parents when something attempts to change the
/// weather, and allows for blocking the weather change. /// 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) -> Result<()> {
Ok(())
}
/// 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 /// rate of this attempt. Pokeball modifier effects should be implemented here, as well as for
/// example status effects that change capture rates. /// example status effects that change capture rates.
fn change_capture_rate_bonus(&self, _target: &Pokemon, _pokeball: &dyn Item, _modifier: &mut u8) {} fn change_capture_rate_bonus(&self, _target: &Pokemon, _pokeball: &dyn Item, _modifier: &mut u8) -> Result<()> {
Ok(())
}
/// Helper function to turn the self into an Any for downcasting. /// Helper function to turn the self into an Any for downcasting.
fn as_any(&self) -> &dyn Any; fn as_any(&self) -> &dyn Any;
@ -319,7 +525,13 @@ impl ScriptContainer {
/// separate thread, and be replaced immediately after the script stops being active. /// separate thread, and be replaced immediately after the script stops being active.
pub fn set(&self, script: Arc<dyn Script>) -> Arc<dyn Script> { pub fn set(&self, script: Arc<dyn Script>) -> Arc<dyn Script> {
if let Some(v) = self.script.read().deref() { if let Some(v) = self.script.read().deref() {
v.on_remove(); let script_result = v.on_remove();
match script_result {
Ok(_) => {}
Err(e) => {
crate::dynamic_data::script_handling::handle_script_error(&e);
}
}
v.mark_for_deletion(); 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, // If we have a lock on the script, we can't replace it now. Wait until we can get the lock,
@ -342,7 +554,13 @@ impl ScriptContainer {
/// we just mark it as deleted. If we do this we remove the script later on. /// we just mark it as deleted. If we do this we remove the script later on.
pub fn clear(&self) { pub fn clear(&self) {
if let Some(v) = self.script.read().deref() { if let Some(v) = self.script.read().deref() {
v.on_remove(); let script_result = v.on_remove();
match script_result {
Ok(_) => {}
Err(e) => {
crate::dynamic_data::script_handling::handle_script_error(&e);
}
}
v.mark_for_deletion(); v.mark_for_deletion();
} }
if !self.script.is_locked() { if !self.script.is_locked() {
@ -418,8 +636,8 @@ mod tests {
unsafe impl Send for TestScript {} unsafe impl Send for TestScript {}
impl Script for TestScript { impl Script for TestScript {
fn name(&self) -> &StringKey { fn name(&self) -> Result<&StringKey> {
&self.name Ok(&self.name)
} }
fn get_marked_for_deletion(&self) -> &AtomicBool { fn get_marked_for_deletion(&self) -> &AtomicBool {
@ -430,8 +648,9 @@ mod tests {
&self.suppressed_count &self.suppressed_count
} }
fn stack(&self) { fn stack(&self) -> Result<()> {
unsafe { self.container.load(Ordering::Relaxed).as_ref().unwrap().clear() } unsafe { self.container.load(Ordering::Relaxed).as_ref().unwrap().clear() }
Ok(())
} }
fn as_any(&self) -> &dyn Any { fn as_any(&self) -> &dyn Any {
@ -458,7 +677,7 @@ mod tests {
drop(w); drop(w);
// Initialize with the script being taken as read lock. This prevents the script from actually // Initialize with the script being taken as read lock. This prevents the script from actually
// removing itself, as it's still doing things. // removing itself, as it's still doing things.
container.script.read().as_ref().unwrap().stack(); container.script.read().as_ref().unwrap().stack().unwrap();
// If we now try and get the script, it will be none the first time. This has the side effect // 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. // of actually disposing of the script.
assert!(container.get().is_none()); assert!(container.get().is_none());
@ -497,8 +716,8 @@ mod tests {
unsafe impl Send for ReplaceTestScript {} unsafe impl Send for ReplaceTestScript {}
impl Script for ReplaceTestScript { impl Script for ReplaceTestScript {
fn name(&self) -> &StringKey { fn name(&self) -> Result<&StringKey> {
&self.name Ok(&self.name)
} }
fn get_marked_for_deletion(&self) -> &AtomicBool { fn get_marked_for_deletion(&self) -> &AtomicBool {
@ -544,7 +763,10 @@ mod tests {
h.join().unwrap(); h.join().unwrap();
} }
assert_eq!(container.script.read().as_ref().unwrap().name(), &"script2".into()); assert_eq!(
container.script.read().as_ref().unwrap().name().unwrap(),
&"script2".into()
);
} }
} }

View File

@ -19,22 +19,22 @@ pub struct ScriptSet {
impl ScriptSet { impl ScriptSet {
/// Adds a script to the set. If the script with that name already exists in this set, this /// Adds a script to the set. If the script with that name already exists in this set, this
/// makes that script stack instead. The return value here is that script. /// makes that script stack instead. The return value here is that script.
pub fn add(&self, script: Arc<dyn Script>) -> ScriptContainer { pub fn add(&self, script: Arc<dyn Script>) -> Result<ScriptContainer> {
if let Some(lock) = self.scripts.read().get(script.name()) { if let Some(lock) = self.scripts.read().get(script.name()?) {
if let Some(existing) = lock.get() { if let Some(existing) = lock.get() {
let existing = existing.read(); let existing = existing.read();
if let Some(v) = &*existing { if let Some(v) = &*existing {
v.stack(); v.stack()?;
return lock.clone(); return Ok(lock.clone());
} }
} }
} }
// If the existing script does not exist, or is not a script, we can just add the new one. // If the existing script does not exist, or is not a script, we can just add the new one.
let name = script.name().clone(); let name = script.name()?.clone();
let container = ScriptContainer::new(script); let container = ScriptContainer::new(script);
self.scripts.write().insert(name, container.clone()); self.scripts.write().insert(name, container.clone());
container Ok(container)
} }
/// Adds a script with a name to the set. If the script with that name already exists in this /// Adds a script with a name to the set. If the script with that name already exists in this
@ -47,14 +47,20 @@ impl ScriptSet {
if let Some(existing) = lock.get() { if let Some(existing) = lock.get() {
let existing = existing.read(); let existing = existing.read();
if let Some(v) = &*existing { if let Some(v) = &*existing {
v.stack(); let script_result = v.stack();
match script_result {
Ok(_) => (),
Err(e) => {
crate::dynamic_data::script_handling::handle_script_error(&e);
}
}
return Ok(Some(lock.clone())); return Ok(Some(lock.clone()));
} }
} }
} }
let script = instantiation()?; let script = instantiation()?;
if let Some(script) = script { if let Some(script) = script {
let name = script.name().clone(); let name = script.name()?.clone();
let arc = ScriptContainer::new(script); let arc = ScriptContainer::new(script);
self.scripts.write().insert(name, arc.clone()); self.scripts.write().insert(name, arc.clone());
Ok(Some(arc)) Ok(Some(arc))
@ -74,7 +80,14 @@ impl ScriptSet {
if let Some(script) = value { if let Some(script) = value {
if let Some(script) = script.get() { if let Some(script) = script.get() {
let script = script.read(); let script = script.read();
script.as_ref().ok_or(PkmnError::UnableToAcquireLock)?.on_remove(); let script_result = script.as_ref().ok_or(PkmnError::UnableToAcquireLock)?.on_remove();
match script_result {
Ok(_) => (),
Err(e) => {
crate::dynamic_data::script_handling::handle_script_error(&e);
}
}
script script
.as_ref() .as_ref()
.ok_or(PkmnError::UnableToAcquireLock)? .ok_or(PkmnError::UnableToAcquireLock)?
@ -90,7 +103,14 @@ impl ScriptSet {
if let Some(script) = script.1.get() { if let Some(script) = script.1.get() {
let script = script.read(); let script = script.read();
if let Some(script) = &*script { if let Some(script) = &*script {
script.on_remove(); let script_result = script.on_remove();
match script_result {
Ok(_) => (),
Err(e) => {
crate::dynamic_data::script_handling::handle_script_error(&e);
}
}
script.mark_for_deletion(); script.mark_for_deletion();
} }
} }

View File

@ -31,7 +31,7 @@ pub trait VolatileScriptsOwner {
/// Adds a volatile script by name. /// Adds a volatile script by name.
fn add_volatile_script_with_script(&self, script: Arc<dyn Script>) -> Result<Option<ScriptContainer>> { fn add_volatile_script_with_script(&self, script: Arc<dyn Script>) -> Result<Option<ScriptContainer>> {
self.volatile_scripts() self.volatile_scripts()
.stack_or_add(&script.name().clone(), &|| Ok(Some(script.clone()))) .stack_or_add(&script.name()?.clone(), &|| Ok(Some(script.clone())))
} }
/// Removes a volatile script by name. /// Removes a volatile script by name.

View File

@ -1,6 +1,17 @@
use std::ffi::{c_char, CString};
/// The foreign function interfaces for the turn choices /// The foreign function interfaces for the turn choices
mod choices; mod choices;
/// The foreign function interfaces for the dynamic data libraries /// The foreign function interfaces for the dynamic data libraries
mod libraries; mod libraries;
/// The foreign function interfaces for the dynamic data models /// The foreign function interfaces for the dynamic data models
mod models; mod models;
/// The library the battle uses for handling.
#[no_mangle]
#[allow(clippy::unwrap_used)]
extern "C" fn set_script_error_handler(func: unsafe extern "C" fn(*mut c_char)) {
crate::dynamic_data::set_script_error_handler(Box::new(move |e: &anyhow_ext::Error| unsafe {
func(CString::new(e.to_string()).unwrap().into_raw())
}));
}

View File

@ -1,3 +1,4 @@
use anyhow_ext::Result;
use std::any::Any; use std::any::Any;
use std::sync::atomic::{AtomicBool, AtomicUsize}; use std::sync::atomic::{AtomicBool, AtomicUsize};
use std::sync::Arc; use std::sync::Arc;
@ -93,8 +94,8 @@ macro_rules! vec_ex_ref {
} }
impl Script for WebAssemblyScript { impl Script for WebAssemblyScript {
fn name(&self) -> &StringKey { fn name(&self) -> Result<&StringKey> {
&self.name Ok(&self.name)
} }
fn get_marked_for_deletion(&self) -> &AtomicBool { fn get_marked_for_deletion(&self) -> &AtomicBool {
@ -105,50 +106,54 @@ impl Script for WebAssemblyScript {
&self.suppressed_count &self.suppressed_count
} }
fn stack(&self) { fn stack(&self) -> Result<()> {
if !self.has_capability(&WebAssemblyScriptCapabilities::OnStack) { if !self.has_capability(&WebAssemblyScriptCapabilities::OnStack) {
return; return Ok(());
} }
let env = &self.environment; let env = &self.environment;
if let Some(func) = env.script_function_cache().stack(env) { if let Some(func) = env.script_function_cache().stack(env) {
call_func!(func, env, self); call_func!(func, env, self);
} }
Ok(())
} }
fn on_remove(&self) { fn on_remove(&self) -> Result<()> {
if !self.has_capability(&WebAssemblyScriptCapabilities::OnRemove) { if !self.has_capability(&WebAssemblyScriptCapabilities::OnRemove) {
return; return Ok(());
} }
let env = &self.environment; let env = &self.environment;
if let Some(func) = env.script_function_cache().on_remove(env) { if let Some(func) = env.script_function_cache().on_remove(env) {
call_func!(func, env, self); call_func!(func, env, self);
} }
Ok(())
} }
fn on_initialize(&self, library: &Arc<dyn DynamicLibrary>, pars: Vec<EffectParameter>) { fn on_initialize(&self, library: &Arc<dyn DynamicLibrary>, pars: Vec<EffectParameter>) -> Result<()> {
if !self.has_capability(&WebAssemblyScriptCapabilities::Initialize) { if !self.has_capability(&WebAssemblyScriptCapabilities::Initialize) {
return; return Ok(());
} }
let env = &self.environment; let env = &self.environment;
if let Some(func) = env.script_function_cache().on_initialize(env) { if let Some(func) = env.script_function_cache().on_initialize(env) {
call_func!(func, env, self, ex_ref!(env, library), vec_ex_ref!(env, &pars)); call_func!(func, env, self, ex_ref!(env, library), vec_ex_ref!(env, &pars));
} }
Ok(())
} }
fn on_before_turn(&self, choice: &TurnChoice) { fn on_before_turn(&self, choice: &TurnChoice) -> Result<()> {
if !self.has_capability(&WebAssemblyScriptCapabilities::OnBeforeTurn) { if !self.has_capability(&WebAssemblyScriptCapabilities::OnBeforeTurn) {
return; return Ok(());
} }
let env = &self.environment; let env = &self.environment;
if let Some(func) = env.script_function_cache().on_before_turn(env) { if let Some(func) = env.script_function_cache().on_before_turn(env) {
call_func!(func, env, self, ex_ref!(env, choice)); call_func!(func, env, self, ex_ref!(env, choice));
} }
Ok(())
} }
fn change_speed(&self, choice: &TurnChoice, speed: &mut u32) { fn change_speed(&self, choice: &TurnChoice, speed: &mut u32) -> Result<()> {
if !self.has_capability(&WebAssemblyScriptCapabilities::ChangeSpeed) { if !self.has_capability(&WebAssemblyScriptCapabilities::ChangeSpeed) {
return; return Ok(());
} }
let env = &self.environment; let env = &self.environment;
@ -157,11 +162,12 @@ impl Script for WebAssemblyScript {
call_func!(func, env, self, ex_ref!(env, choice), ptr.wasm_ptr); call_func!(func, env, self, ex_ref!(env, choice), ptr.wasm_ptr);
*speed = *ptr.value(); *speed = *ptr.value();
} }
Ok(())
} }
fn change_priority(&self, choice: &TurnChoice, priority: &mut i8) { fn change_priority(&self, choice: &TurnChoice, priority: &mut i8) -> Result<()> {
if !self.has_capability(&WebAssemblyScriptCapabilities::ChangePriority) { if !self.has_capability(&WebAssemblyScriptCapabilities::ChangePriority) {
return; return Ok(());
} }
let env = &self.environment; let env = &self.environment;
@ -170,11 +176,12 @@ impl Script for WebAssemblyScript {
call_func!(func, env, self, ex_ref!(env, choice), ptr.wasm_ptr); call_func!(func, env, self, ex_ref!(env, choice), ptr.wasm_ptr);
*priority = *ptr.value(); *priority = *ptr.value();
} }
Ok(())
} }
fn change_move(&self, choice: &TurnChoice, move_name: &mut StringKey) { fn change_move(&self, choice: &TurnChoice, move_name: &mut StringKey) -> Result<()> {
if !self.has_capability(&WebAssemblyScriptCapabilities::ChangeMove) { if !self.has_capability(&WebAssemblyScriptCapabilities::ChangeMove) {
return; return Ok(());
} }
let env = &self.environment; let env = &self.environment;
@ -184,11 +191,12 @@ impl Script for WebAssemblyScript {
call_func!(func, env, self, ex_ref!(env, choice), ptr.wasm_ptr); call_func!(func, env, self, ex_ref!(env, choice), ptr.wasm_ptr);
*move_name = ptr.value().value(env).unwrap().clone(); *move_name = ptr.value().value(env).unwrap().clone();
} }
Ok(())
} }
fn change_number_of_hits(&self, choice: &TurnChoice, number_of_hits: &mut u8) { fn change_number_of_hits(&self, choice: &TurnChoice, number_of_hits: &mut u8) -> Result<()> {
if !self.has_capability(&WebAssemblyScriptCapabilities::ChangeNumberOfHits) { if !self.has_capability(&WebAssemblyScriptCapabilities::ChangeNumberOfHits) {
return; return Ok(());
} }
let env = &self.environment; let env = &self.environment;
@ -197,11 +205,12 @@ impl Script for WebAssemblyScript {
call_func!(func, env, self, ex_ref!(env, choice), ptr.wasm_ptr); call_func!(func, env, self, ex_ref!(env, choice), ptr.wasm_ptr);
*number_of_hits = *ptr.value(); *number_of_hits = *ptr.value();
} }
Ok(())
} }
fn prevent_move(&self, mv: &ExecutingMove, prevent: &mut bool) { fn prevent_move(&self, mv: &ExecutingMove, prevent: &mut bool) -> Result<()> {
if !self.has_capability(&WebAssemblyScriptCapabilities::PreventMove) { if !self.has_capability(&WebAssemblyScriptCapabilities::PreventMove) {
return; return Ok(());
} }
let env = &self.environment; let env = &self.environment;
@ -210,11 +219,12 @@ impl Script for WebAssemblyScript {
call_func!(func, env, self, ex_ref!(env, mv), ptr.wasm_ptr); call_func!(func, env, self, ex_ref!(env, mv), ptr.wasm_ptr);
*prevent = *ptr.value(); *prevent = *ptr.value();
} }
Ok(())
} }
fn fail_move(&self, mv: &ExecutingMove, fail: &mut bool) { fn fail_move(&self, mv: &ExecutingMove, fail: &mut bool) -> Result<()> {
if !self.has_capability(&WebAssemblyScriptCapabilities::FailMove) { if !self.has_capability(&WebAssemblyScriptCapabilities::FailMove) {
return; return Ok(());
} }
let env = &self.environment; let env = &self.environment;
@ -223,11 +233,12 @@ impl Script for WebAssemblyScript {
call_func!(func, env, self, ex_ref!(env, mv), ptr.wasm_ptr); call_func!(func, env, self, ex_ref!(env, mv), ptr.wasm_ptr);
*fail = *ptr.value(); *fail = *ptr.value();
} }
Ok(())
} }
fn stop_before_move(&self, mv: &ExecutingMove, stop: &mut bool) { fn stop_before_move(&self, mv: &ExecutingMove, stop: &mut bool) -> Result<()> {
if !self.has_capability(&WebAssemblyScriptCapabilities::StopBeforeMove) { if !self.has_capability(&WebAssemblyScriptCapabilities::StopBeforeMove) {
return; return Ok(());
} }
let env = &self.environment; let env = &self.environment;
@ -236,21 +247,23 @@ impl Script for WebAssemblyScript {
call_func!(func, env, self, ex_ref!(env, mv), ptr.wasm_ptr); call_func!(func, env, self, ex_ref!(env, mv), ptr.wasm_ptr);
*stop = *ptr.value(); *stop = *ptr.value();
} }
Ok(())
} }
fn on_before_move(&self, mv: &ExecutingMove) { fn on_before_move(&self, mv: &ExecutingMove) -> Result<()> {
if !self.has_capability(&WebAssemblyScriptCapabilities::OnBeforeMove) { if !self.has_capability(&WebAssemblyScriptCapabilities::OnBeforeMove) {
return; return Ok(());
} }
let env = &self.environment; let env = &self.environment;
if let Some(func) = env.script_function_cache().on_before_move(env) { if let Some(func) = env.script_function_cache().on_before_move(env) {
call_func!(func, env, self, ex_ref!(env, mv)); call_func!(func, env, self, ex_ref!(env, mv));
} }
Ok(())
} }
fn fail_incoming_move(&self, mv: &ExecutingMove, target: &Arc<Pokemon>, fail: &mut bool) { fn fail_incoming_move(&self, mv: &ExecutingMove, target: &Arc<Pokemon>, fail: &mut bool) -> Result<()> {
if !self.has_capability(&WebAssemblyScriptCapabilities::FailIncomingMove) { if !self.has_capability(&WebAssemblyScriptCapabilities::FailIncomingMove) {
return; return Ok(());
} }
let env = &self.environment; let env = &self.environment;
if let Some(func) = env.script_function_cache().fail_incoming_move(env) { if let Some(func) = env.script_function_cache().fail_incoming_move(env) {
@ -265,11 +278,12 @@ impl Script for WebAssemblyScript {
); );
*fail = *ptr.value(); *fail = *ptr.value();
} }
Ok(())
} }
fn is_invulnerable(&self, mv: &ExecutingMove, target: &Arc<Pokemon>, invulnerable: &mut bool) { fn is_invulnerable(&self, mv: &ExecutingMove, target: &Arc<Pokemon>, invulnerable: &mut bool) -> Result<()> {
if !self.has_capability(&WebAssemblyScriptCapabilities::IsInvulnerable) { if !self.has_capability(&WebAssemblyScriptCapabilities::IsInvulnerable) {
return; return Ok(());
} }
let env = &self.environment; let env = &self.environment;
if let Some(func) = env.script_function_cache().is_invulnerable(env) { if let Some(func) = env.script_function_cache().is_invulnerable(env) {
@ -284,21 +298,29 @@ impl Script for WebAssemblyScript {
); );
*invulnerable = *ptr.value(); *invulnerable = *ptr.value();
} }
Ok(())
} }
fn on_move_miss(&self, mv: &ExecutingMove, target: &Arc<Pokemon>) { fn on_move_miss(&self, mv: &ExecutingMove, target: &Arc<Pokemon>) -> Result<()> {
if !self.has_capability(&WebAssemblyScriptCapabilities::OnMoveMiss) { if !self.has_capability(&WebAssemblyScriptCapabilities::OnMoveMiss) {
return; return Ok(());
} }
let env = &self.environment; let env = &self.environment;
if let Some(func) = env.script_function_cache().on_move_miss(env) { if let Some(func) = env.script_function_cache().on_move_miss(env) {
call_func!(func, env, self, ex_ref!(env, mv), ex_ref!(env, target.as_ref())); call_func!(func, env, self, ex_ref!(env, mv), ex_ref!(env, target.as_ref()));
} }
Ok(())
} }
fn change_move_type(&self, mv: &ExecutingMove, target: &Arc<Pokemon>, hit: u8, move_type: &mut TypeIdentifier) { fn change_move_type(
&self,
mv: &ExecutingMove,
target: &Arc<Pokemon>,
hit: u8,
move_type: &mut TypeIdentifier,
) -> Result<()> {
if !self.has_capability(&WebAssemblyScriptCapabilities::ChangeMoveType) { if !self.has_capability(&WebAssemblyScriptCapabilities::ChangeMoveType) {
return; return Ok(());
} }
let env = &self.environment; let env = &self.environment;
if let Some(func) = env.script_function_cache().change_move_type(env) { if let Some(func) = env.script_function_cache().change_move_type(env) {
@ -308,11 +330,18 @@ impl Script for WebAssemblyScript {
call_func!(func, env, self, ex_ref!(env, mv), ex_ref!(env, target), hit, w_ptr); call_func!(func, env, self, ex_ref!(env, mv), ex_ref!(env, target), hit, w_ptr);
*move_type = *ptr.value(); *move_type = *ptr.value();
} }
Ok(())
} }
fn change_effectiveness(&self, mv: &ExecutingMove, target: &Arc<Pokemon>, hit: u8, effectiveness: &mut f32) { fn change_effectiveness(
&self,
mv: &ExecutingMove,
target: &Arc<Pokemon>,
hit: u8,
effectiveness: &mut f32,
) -> Result<()> {
if !self.has_capability(&WebAssemblyScriptCapabilities::ChangeEffectiveness) { if !self.has_capability(&WebAssemblyScriptCapabilities::ChangeEffectiveness) {
return; return Ok(());
} }
let env = &self.environment; let env = &self.environment;
if let Some(func) = env.script_function_cache().change_effectiveness(env) { if let Some(func) = env.script_function_cache().change_effectiveness(env) {
@ -322,11 +351,18 @@ impl Script for WebAssemblyScript {
call_func!(func, env, self, ex_ref!(env, mv), ex_ref!(env, target), hit, w_ptr); call_func!(func, env, self, ex_ref!(env, mv), ex_ref!(env, target), hit, w_ptr);
*effectiveness = *ptr.value(); *effectiveness = *ptr.value();
} }
Ok(())
} }
fn block_critical(&self, mv: &ExecutingMove, target: &Arc<Pokemon>, hit: u8, block_critical: &mut bool) { fn block_critical(
&self,
mv: &ExecutingMove,
target: &Arc<Pokemon>,
hit: u8,
block_critical: &mut bool,
) -> Result<()> {
if !self.has_capability(&WebAssemblyScriptCapabilities::BlockCritical) { if !self.has_capability(&WebAssemblyScriptCapabilities::BlockCritical) {
return; return Ok(());
} }
let env = &self.environment; let env = &self.environment;
if let Some(func) = env.script_function_cache().block_critical(env) { if let Some(func) = env.script_function_cache().block_critical(env) {
@ -336,11 +372,18 @@ impl Script for WebAssemblyScript {
call_func!(func, env, self, ex_ref!(env, mv), ex_ref!(env, target), hit, w_ptr); call_func!(func, env, self, ex_ref!(env, mv), ex_ref!(env, target), hit, w_ptr);
*block_critical = *ptr.value(); *block_critical = *ptr.value();
} }
Ok(())
} }
fn block_incoming_critical(&self, mv: &ExecutingMove, target: &Arc<Pokemon>, hit: u8, block_critical: &mut bool) { fn block_incoming_critical(
&self,
mv: &ExecutingMove,
target: &Arc<Pokemon>,
hit: u8,
block_critical: &mut bool,
) -> Result<()> {
if !self.has_capability(&WebAssemblyScriptCapabilities::BlockIncomingCritical) { if !self.has_capability(&WebAssemblyScriptCapabilities::BlockIncomingCritical) {
return; return Ok(());
} }
let env = &self.environment; let env = &self.environment;
if let Some(func) = env.script_function_cache().block_incoming_critical(env) { if let Some(func) = env.script_function_cache().block_incoming_critical(env) {
@ -350,11 +393,12 @@ impl Script for WebAssemblyScript {
call_func!(func, env, self, ex_ref!(env, mv), ex_ref!(env, target), hit, w_ptr); call_func!(func, env, self, ex_ref!(env, mv), ex_ref!(env, target), hit, w_ptr);
*block_critical = *ptr.value(); *block_critical = *ptr.value();
} }
Ok(())
} }
fn change_accuracy(&self, mv: &ExecutingMove, target: &Arc<Pokemon>, hit: u8, accuracy: &mut u8) { fn change_accuracy(&self, mv: &ExecutingMove, target: &Arc<Pokemon>, hit: u8, accuracy: &mut u8) -> Result<()> {
if !self.has_capability(&WebAssemblyScriptCapabilities::ChangeAccuracy) { if !self.has_capability(&WebAssemblyScriptCapabilities::ChangeAccuracy) {
return; return Ok(());
} }
let env = &self.environment; let env = &self.environment;
if let Some(func) = env.script_function_cache().change_accuracy(env) { if let Some(func) = env.script_function_cache().change_accuracy(env) {
@ -364,11 +408,12 @@ impl Script for WebAssemblyScript {
call_func!(func, env, self, ex_ref!(env, mv), ex_ref!(env, target), hit, w_ptr); call_func!(func, env, self, ex_ref!(env, mv), ex_ref!(env, target), hit, w_ptr);
*accuracy = *ptr.value(); *accuracy = *ptr.value();
} }
Ok(())
} }
fn change_critical_stage(&self, mv: &ExecutingMove, target: &Arc<Pokemon>, hit: u8, stage: &mut u8) { fn change_critical_stage(&self, mv: &ExecutingMove, target: &Arc<Pokemon>, hit: u8, stage: &mut u8) -> Result<()> {
if !self.has_capability(&WebAssemblyScriptCapabilities::ChangeCriticalStage) { if !self.has_capability(&WebAssemblyScriptCapabilities::ChangeCriticalStage) {
return; return Ok(());
} }
let env = &self.environment; let env = &self.environment;
if let Some(func) = env.script_function_cache().change_critical_stage(env) { if let Some(func) = env.script_function_cache().change_critical_stage(env) {
@ -378,11 +423,18 @@ impl Script for WebAssemblyScript {
call_func!(func, env, self, ex_ref!(env, mv), ex_ref!(env, target), hit, w_ptr); call_func!(func, env, self, ex_ref!(env, mv), ex_ref!(env, target), hit, w_ptr);
*stage = *ptr.value(); *stage = *ptr.value();
} }
Ok(())
} }
fn change_critical_modifier(&self, mv: &ExecutingMove, target: &Arc<Pokemon>, hit: u8, modifier: &mut f32) { fn change_critical_modifier(
&self,
mv: &ExecutingMove,
target: &Arc<Pokemon>,
hit: u8,
modifier: &mut f32,
) -> Result<()> {
if !self.has_capability(&WebAssemblyScriptCapabilities::ChangeCriticalModifier) { if !self.has_capability(&WebAssemblyScriptCapabilities::ChangeCriticalModifier) {
return; return Ok(());
} }
let env = &self.environment; let env = &self.environment;
if let Some(func) = env.script_function_cache().change_critical_modifier(env) { if let Some(func) = env.script_function_cache().change_critical_modifier(env) {
@ -392,11 +444,18 @@ impl Script for WebAssemblyScript {
call_func!(func, env, self, ex_ref!(env, mv), ex_ref!(env, target), hit, w_ptr); call_func!(func, env, self, ex_ref!(env, mv), ex_ref!(env, target), hit, w_ptr);
*modifier = *ptr.value(); *modifier = *ptr.value();
} }
Ok(())
} }
fn change_stab_modifier(&self, mv: &ExecutingMove, target: &Arc<Pokemon>, hit: u8, modifier: &mut f32) { fn change_stab_modifier(
&self,
mv: &ExecutingMove,
target: &Arc<Pokemon>,
hit: u8,
modifier: &mut f32,
) -> Result<()> {
if !self.has_capability(&WebAssemblyScriptCapabilities::ChangeSTABModifier) { if !self.has_capability(&WebAssemblyScriptCapabilities::ChangeSTABModifier) {
return; return Ok(());
} }
let env = &self.environment; let env = &self.environment;
if let Some(func) = env.script_function_cache().change_stab_modifier(env) { if let Some(func) = env.script_function_cache().change_stab_modifier(env) {
@ -406,11 +465,12 @@ impl Script for WebAssemblyScript {
call_func!(func, env, self, ex_ref!(env, mv), ex_ref!(env, target), hit, w_ptr); call_func!(func, env, self, ex_ref!(env, mv), ex_ref!(env, target), hit, w_ptr);
*modifier = *ptr.value(); *modifier = *ptr.value();
} }
Ok(())
} }
fn change_base_power(&self, mv: &ExecutingMove, target: &Arc<Pokemon>, hit: u8, base_power: &mut u8) { fn change_base_power(&self, mv: &ExecutingMove, target: &Arc<Pokemon>, hit: u8, base_power: &mut u8) -> Result<()> {
if !self.has_capability(&WebAssemblyScriptCapabilities::ChangeBasePower) { if !self.has_capability(&WebAssemblyScriptCapabilities::ChangeBasePower) {
return; return Ok(());
} }
let env = &self.environment; let env = &self.environment;
if let Some(func) = env.script_function_cache().change_base_power(env) { if let Some(func) = env.script_function_cache().change_base_power(env) {
@ -420,11 +480,18 @@ impl Script for WebAssemblyScript {
call_func!(func, env, self, ex_ref!(env, mv), ex_ref!(env, target), hit, w_ptr); call_func!(func, env, self, ex_ref!(env, mv), ex_ref!(env, target), hit, w_ptr);
*base_power = *ptr.value(); *base_power = *ptr.value();
} }
Ok(())
} }
fn bypass_defensive_stat_boost(&self, mv: &ExecutingMove, target: &Arc<Pokemon>, hit: u8, bypass: &mut bool) { fn bypass_defensive_stat_boost(
&self,
mv: &ExecutingMove,
target: &Arc<Pokemon>,
hit: u8,
bypass: &mut bool,
) -> Result<()> {
if !self.has_capability(&WebAssemblyScriptCapabilities::BypassDefensiveStat) { if !self.has_capability(&WebAssemblyScriptCapabilities::BypassDefensiveStat) {
return; return Ok(());
} }
let env = &self.environment; let env = &self.environment;
if let Some(func) = env.script_function_cache().bypass_defensive_stat_boost(env) { if let Some(func) = env.script_function_cache().bypass_defensive_stat_boost(env) {
@ -434,11 +501,18 @@ impl Script for WebAssemblyScript {
call_func!(func, env, self, ex_ref!(env, mv), ex_ref!(env, target), hit, w_ptr); call_func!(func, env, self, ex_ref!(env, mv), ex_ref!(env, target), hit, w_ptr);
*bypass = *ptr.value(); *bypass = *ptr.value();
} }
Ok(())
} }
fn bypass_offensive_stat_boost(&self, mv: &ExecutingMove, target: &Arc<Pokemon>, hit: u8, bypass: &mut bool) { fn bypass_offensive_stat_boost(
&self,
mv: &ExecutingMove,
target: &Arc<Pokemon>,
hit: u8,
bypass: &mut bool,
) -> Result<()> {
if !self.has_capability(&WebAssemblyScriptCapabilities::BypassOffensiveStat) { if !self.has_capability(&WebAssemblyScriptCapabilities::BypassOffensiveStat) {
return; return Ok(());
} }
let env = &self.environment; let env = &self.environment;
if let Some(func) = env.script_function_cache().bypass_offensive_stat_boost(env) { if let Some(func) = env.script_function_cache().bypass_offensive_stat_boost(env) {
@ -448,11 +522,18 @@ impl Script for WebAssemblyScript {
call_func!(func, env, self, ex_ref!(env, mv), ex_ref!(env, target), hit, w_ptr); call_func!(func, env, self, ex_ref!(env, mv), ex_ref!(env, target), hit, w_ptr);
*bypass = *ptr.value(); *bypass = *ptr.value();
} }
Ok(())
} }
fn change_offensive_stat_value(&self, mv: &ExecutingMove, target: &Arc<Pokemon>, hit: u8, amount: &mut u32) { fn change_offensive_stat_value(
&self,
mv: &ExecutingMove,
target: &Arc<Pokemon>,
hit: u8,
amount: &mut u32,
) -> Result<()> {
if !self.has_capability(&WebAssemblyScriptCapabilities::ChangeOffensiveStatValue) { if !self.has_capability(&WebAssemblyScriptCapabilities::ChangeOffensiveStatValue) {
return; return Ok(());
} }
let env = &self.environment; let env = &self.environment;
if let Some(func) = env.script_function_cache().change_offensive_stat_value(env) { if let Some(func) = env.script_function_cache().change_offensive_stat_value(env) {
@ -462,11 +543,18 @@ impl Script for WebAssemblyScript {
call_func!(func, env, self, ex_ref!(env, mv), ex_ref!(env, target), hit, w_ptr); call_func!(func, env, self, ex_ref!(env, mv), ex_ref!(env, target), hit, w_ptr);
*amount = *ptr.value(); *amount = *ptr.value();
} }
Ok(())
} }
fn change_defensive_stat_value(&self, mv: &ExecutingMove, target: &Arc<Pokemon>, hit: u8, amount: &mut u32) { fn change_defensive_stat_value(
&self,
mv: &ExecutingMove,
target: &Arc<Pokemon>,
hit: u8,
amount: &mut u32,
) -> Result<()> {
if !self.has_capability(&WebAssemblyScriptCapabilities::ChangeOffensiveStatValue) { if !self.has_capability(&WebAssemblyScriptCapabilities::ChangeOffensiveStatValue) {
return; return Ok(());
} }
let env = &self.environment; let env = &self.environment;
if let Some(func) = env.script_function_cache().change_defensive_stat_value(env) { if let Some(func) = env.script_function_cache().change_defensive_stat_value(env) {
@ -476,11 +564,18 @@ impl Script for WebAssemblyScript {
call_func!(func, env, self, ex_ref!(env, mv), ex_ref!(env, target), hit, w_ptr); call_func!(func, env, self, ex_ref!(env, mv), ex_ref!(env, target), hit, w_ptr);
*amount = *ptr.value(); *amount = *ptr.value();
} }
Ok(())
} }
fn change_damage_stat_modifier(&self, mv: &ExecutingMove, target: &Arc<Pokemon>, hit: u8, modifier: &mut f32) { fn change_damage_stat_modifier(
&self,
mv: &ExecutingMove,
target: &Arc<Pokemon>,
hit: u8,
modifier: &mut f32,
) -> Result<()> {
if !self.has_capability(&WebAssemblyScriptCapabilities::ChangeStatModifier) { if !self.has_capability(&WebAssemblyScriptCapabilities::ChangeStatModifier) {
return; return Ok(());
} }
let env = &self.environment; let env = &self.environment;
if let Some(func) = env.script_function_cache().change_damage_stat_modifier(env) { if let Some(func) = env.script_function_cache().change_damage_stat_modifier(env) {
@ -490,11 +585,18 @@ impl Script for WebAssemblyScript {
call_func!(func, env, self, ex_ref!(env, mv), ex_ref!(env, target), hit, w_ptr); call_func!(func, env, self, ex_ref!(env, mv), ex_ref!(env, target), hit, w_ptr);
*modifier = *ptr.value(); *modifier = *ptr.value();
} }
Ok(())
} }
fn change_damage_modifier(&self, mv: &ExecutingMove, target: &Arc<Pokemon>, hit: u8, modifier: &mut f32) { fn change_damage_modifier(
&self,
mv: &ExecutingMove,
target: &Arc<Pokemon>,
hit: u8,
modifier: &mut f32,
) -> Result<()> {
if !self.has_capability(&WebAssemblyScriptCapabilities::ChangeDamageModifier) { if !self.has_capability(&WebAssemblyScriptCapabilities::ChangeDamageModifier) {
return; return Ok(());
} }
let env = &self.environment; let env = &self.environment;
if let Some(func) = env.script_function_cache().change_damage_modifier(env) { if let Some(func) = env.script_function_cache().change_damage_modifier(env) {
@ -504,11 +606,12 @@ impl Script for WebAssemblyScript {
call_func!(func, env, self, ex_ref!(env, mv), ex_ref!(env, target), hit, w_ptr); call_func!(func, env, self, ex_ref!(env, mv), ex_ref!(env, target), hit, w_ptr);
*modifier = *ptr.value(); *modifier = *ptr.value();
} }
Ok(())
} }
fn change_damage(&self, mv: &ExecutingMove, target: &Arc<Pokemon>, hit: u8, damage: &mut u32) { fn change_damage(&self, mv: &ExecutingMove, target: &Arc<Pokemon>, hit: u8, damage: &mut u32) -> Result<()> {
if !self.has_capability(&WebAssemblyScriptCapabilities::ChangeDamage) { if !self.has_capability(&WebAssemblyScriptCapabilities::ChangeDamage) {
return; return Ok(());
} }
let env = &self.environment; let env = &self.environment;
if let Some(func) = env.script_function_cache().change_damage(env) { if let Some(func) = env.script_function_cache().change_damage(env) {
@ -518,11 +621,18 @@ impl Script for WebAssemblyScript {
call_func!(func, env, self, ex_ref!(env, mv), ex_ref!(env, target), hit, w_ptr); call_func!(func, env, self, ex_ref!(env, mv), ex_ref!(env, target), hit, w_ptr);
*damage = *ptr.value(); *damage = *ptr.value();
} }
Ok(())
} }
fn change_incoming_damage(&self, mv: &ExecutingMove, target: &Arc<Pokemon>, hit: u8, damage: &mut u32) { fn change_incoming_damage(
&self,
mv: &ExecutingMove,
target: &Arc<Pokemon>,
hit: u8,
damage: &mut u32,
) -> Result<()> {
if !self.has_capability(&WebAssemblyScriptCapabilities::ChangeIncomingDamage) { if !self.has_capability(&WebAssemblyScriptCapabilities::ChangeIncomingDamage) {
return; return Ok(());
} }
let env = &self.environment; let env = &self.environment;
if let Some(func) = env.script_function_cache().change_incoming_damage(env) { if let Some(func) = env.script_function_cache().change_incoming_damage(env) {
@ -532,28 +642,31 @@ impl Script for WebAssemblyScript {
call_func!(func, env, self, ex_ref!(env, mv), ex_ref!(env, target), hit, w_ptr); call_func!(func, env, self, ex_ref!(env, mv), ex_ref!(env, target), hit, w_ptr);
*damage = *ptr.value(); *damage = *ptr.value();
} }
Ok(())
} }
fn on_incoming_hit(&self, mv: &ExecutingMove, target: &Arc<Pokemon>, hit: u8) { fn on_incoming_hit(&self, mv: &ExecutingMove, target: &Arc<Pokemon>, hit: u8) -> Result<()> {
if !self.has_capability(&WebAssemblyScriptCapabilities::OnIncomingHit) { if !self.has_capability(&WebAssemblyScriptCapabilities::OnIncomingHit) {
return; return Ok(());
} }
let env = &self.environment; let env = &self.environment;
if let Some(func) = env.script_function_cache().on_incoming_hit(env) { if let Some(func) = env.script_function_cache().on_incoming_hit(env) {
let target = target.as_ref(); let target = target.as_ref();
call_func!(func, env, self, ex_ref!(env, mv), ex_ref!(env, target), hit); call_func!(func, env, self, ex_ref!(env, mv), ex_ref!(env, target), hit);
} }
Ok(())
} }
fn on_opponent_faints(&self, mv: &ExecutingMove, target: &Arc<Pokemon>, hit: u8) { fn on_opponent_faints(&self, mv: &ExecutingMove, target: &Arc<Pokemon>, hit: u8) -> Result<()> {
if !self.has_capability(&WebAssemblyScriptCapabilities::OnFaintingOpponent) { if !self.has_capability(&WebAssemblyScriptCapabilities::OnFaintingOpponent) {
return; return Ok(());
} }
let env = &self.environment; let env = &self.environment;
if let Some(func) = env.script_function_cache().on_opponent_faints(env) { if let Some(func) = env.script_function_cache().on_opponent_faints(env) {
let target = target.as_ref(); let target = target.as_ref();
call_func!(func, env, self, ex_ref!(env, mv), ex_ref!(env, target), hit); call_func!(func, env, self, ex_ref!(env, mv), ex_ref!(env, target), hit);
} }
Ok(())
} }
fn prevent_stat_boost_change( fn prevent_stat_boost_change(
@ -563,9 +676,9 @@ impl Script for WebAssemblyScript {
amount: i8, amount: i8,
self_inflicted: bool, self_inflicted: bool,
prevent: &mut bool, prevent: &mut bool,
) { ) -> Result<()> {
if !self.has_capability(&WebAssemblyScriptCapabilities::PreventStatBoostChange) { if !self.has_capability(&WebAssemblyScriptCapabilities::PreventStatBoostChange) {
return; return Ok(());
} }
let env = &self.environment; let env = &self.environment;
if let Some(func) = env.script_function_cache().prevent_stat_boost_change(env) { if let Some(func) = env.script_function_cache().prevent_stat_boost_change(env) {
@ -583,11 +696,18 @@ impl Script for WebAssemblyScript {
); );
*prevent = *ptr.value(); *prevent = *ptr.value();
} }
Ok(())
} }
fn prevent_secondary_effect(&self, mv: &ExecutingMove, target: &Arc<Pokemon>, hit: u8, prevent: &mut bool) { fn prevent_secondary_effect(
&self,
mv: &ExecutingMove,
target: &Arc<Pokemon>,
hit: u8,
prevent: &mut bool,
) -> Result<()> {
if !self.has_capability(&WebAssemblyScriptCapabilities::PreventSecondaryEffects) { if !self.has_capability(&WebAssemblyScriptCapabilities::PreventSecondaryEffects) {
return; return Ok(());
} }
let env = &self.environment; let env = &self.environment;
if let Some(func) = env.script_function_cache().prevent_secondary_effect(env) { if let Some(func) = env.script_function_cache().prevent_secondary_effect(env) {
@ -597,11 +717,12 @@ impl Script for WebAssemblyScript {
call_func!(func, env, self, ex_ref!(env, mv), ex_ref!(env, target), hit, w_ptr); call_func!(func, env, self, ex_ref!(env, mv), ex_ref!(env, target), hit, w_ptr);
*prevent = *ptr.value(); *prevent = *ptr.value();
} }
Ok(())
} }
fn change_effect_chance(&self, mv: &ExecutingMove, target: &Arc<Pokemon>, hit: u8, chance: &mut f32) { fn change_effect_chance(&self, mv: &ExecutingMove, target: &Arc<Pokemon>, hit: u8, chance: &mut f32) -> Result<()> {
if !self.has_capability(&WebAssemblyScriptCapabilities::ChangeEffectChance) { if !self.has_capability(&WebAssemblyScriptCapabilities::ChangeEffectChance) {
return; return Ok(());
} }
let env = &self.environment; let env = &self.environment;
if let Some(func) = env.script_function_cache().change_effect_chance(env) { if let Some(func) = env.script_function_cache().change_effect_chance(env) {
@ -611,11 +732,18 @@ impl Script for WebAssemblyScript {
call_func!(func, env, self, ex_ref!(env, mv), ex_ref!(env, target), hit, w_ptr); call_func!(func, env, self, ex_ref!(env, mv), ex_ref!(env, target), hit, w_ptr);
*chance = *ptr.value(); *chance = *ptr.value();
} }
Ok(())
} }
fn change_incoming_effect_chance(&self, mv: &ExecutingMove, target: &Arc<Pokemon>, hit: u8, chance: &mut f32) { fn change_incoming_effect_chance(
&self,
mv: &ExecutingMove,
target: &Arc<Pokemon>,
hit: u8,
chance: &mut f32,
) -> Result<()> {
if !self.has_capability(&WebAssemblyScriptCapabilities::ChangeIncomingEffectChance) { if !self.has_capability(&WebAssemblyScriptCapabilities::ChangeIncomingEffectChance) {
return; return Ok(());
} }
let env = &self.environment; let env = &self.environment;
if let Some(func) = env.script_function_cache().change_incoming_effect_chance(env) { if let Some(func) = env.script_function_cache().change_incoming_effect_chance(env) {
@ -625,33 +753,36 @@ impl Script for WebAssemblyScript {
call_func!(func, env, self, ex_ref!(env, mv), ex_ref!(env, target), hit, w_ptr); call_func!(func, env, self, ex_ref!(env, mv), ex_ref!(env, target), hit, w_ptr);
*chance = *ptr.value(); *chance = *ptr.value();
} }
Ok(())
} }
fn on_secondary_effect(&self, mv: &ExecutingMove, target: &Arc<Pokemon>, hit: u8) { fn on_secondary_effect(&self, mv: &ExecutingMove, target: &Arc<Pokemon>, hit: u8) -> Result<()> {
if !self.has_capability(&WebAssemblyScriptCapabilities::OnFaintingOpponent) { if !self.has_capability(&WebAssemblyScriptCapabilities::OnFaintingOpponent) {
return; return Ok(());
} }
let env = &self.environment; let env = &self.environment;
if let Some(func) = env.script_function_cache().on_secondary_effect(env) { if let Some(func) = env.script_function_cache().on_secondary_effect(env) {
let target = target.as_ref(); let target = target.as_ref();
call_func!(func, env, self, ex_ref!(env, mv), ex_ref!(env, target), hit); call_func!(func, env, self, ex_ref!(env, mv), ex_ref!(env, target), hit);
} }
Ok(())
} }
fn on_after_hits(&self, mv: &ExecutingMove, target: &Arc<Pokemon>) { fn on_after_hits(&self, mv: &ExecutingMove, target: &Arc<Pokemon>) -> Result<()> {
if !self.has_capability(&WebAssemblyScriptCapabilities::OnAfterHits) { if !self.has_capability(&WebAssemblyScriptCapabilities::OnAfterHits) {
return; return Ok(());
} }
let env = &self.environment; let env = &self.environment;
if let Some(func) = env.script_function_cache().on_after_hits(env) { if let Some(func) = env.script_function_cache().on_after_hits(env) {
let target = target.as_ref(); let target = target.as_ref();
call_func!(func, env, self, ex_ref!(env, mv), ex_ref!(env, target)); call_func!(func, env, self, ex_ref!(env, mv), ex_ref!(env, target));
} }
Ok(())
} }
fn prevent_self_switch(&self, choice: &TurnChoice, prevent: &mut bool) { fn prevent_self_switch(&self, choice: &TurnChoice, prevent: &mut bool) -> Result<()> {
if !self.has_capability(&WebAssemblyScriptCapabilities::PreventSelfSwitch) { if !self.has_capability(&WebAssemblyScriptCapabilities::PreventSelfSwitch) {
return; return Ok(());
} }
let env = &self.environment; let env = &self.environment;
if let Some(func) = env.script_function_cache().prevent_self_switch(env) { if let Some(func) = env.script_function_cache().prevent_self_switch(env) {
@ -659,11 +790,12 @@ impl Script for WebAssemblyScript {
call_func!(func, env, self, ex_ref!(env, choice), ptr.wasm_ptr); call_func!(func, env, self, ex_ref!(env, choice), ptr.wasm_ptr);
*prevent = *ptr.value(); *prevent = *ptr.value();
} }
Ok(())
} }
fn prevent_opponent_switch(&self, choice: &TurnChoice, prevent: &mut bool) { fn prevent_opponent_switch(&self, choice: &TurnChoice, prevent: &mut bool) -> Result<()> {
if !self.has_capability(&WebAssemblyScriptCapabilities::PreventSelfSwitch) { if !self.has_capability(&WebAssemblyScriptCapabilities::PreventSelfSwitch) {
return; return Ok(());
} }
let env = &self.environment; let env = &self.environment;
if let Some(func) = env.script_function_cache().prevent_opponent_switch(env) { if let Some(func) = env.script_function_cache().prevent_opponent_switch(env) {
@ -671,31 +803,34 @@ impl Script for WebAssemblyScript {
call_func!(func, env, self, ex_ref!(env, choice), ptr.wasm_ptr); call_func!(func, env, self, ex_ref!(env, choice), ptr.wasm_ptr);
*prevent = *ptr.value(); *prevent = *ptr.value();
} }
Ok(())
} }
fn on_fail(&self, pokemon: &Pokemon) { fn on_fail(&self, pokemon: &Pokemon) -> Result<()> {
if !self.has_capability(&WebAssemblyScriptCapabilities::OnFail) { if !self.has_capability(&WebAssemblyScriptCapabilities::OnFail) {
return; return Ok(());
} }
let env = &self.environment; let env = &self.environment;
if let Some(func) = env.script_function_cache().on_fail(env) { if let Some(func) = env.script_function_cache().on_fail(env) {
call_func!(func, env, self, ex_ref!(env, pokemon)); call_func!(func, env, self, ex_ref!(env, pokemon));
} }
Ok(())
} }
fn on_opponent_fail(&self, pokemon: &Pokemon) { fn on_opponent_fail(&self, pokemon: &Pokemon) -> Result<()> {
if !self.has_capability(&WebAssemblyScriptCapabilities::OnFail) { if !self.has_capability(&WebAssemblyScriptCapabilities::OnFail) {
return; return Ok(());
} }
let env = &self.environment; let env = &self.environment;
if let Some(func) = env.script_function_cache().on_opponent_fail(env) { if let Some(func) = env.script_function_cache().on_opponent_fail(env) {
call_func!(func, env, self, ex_ref!(env, pokemon)); call_func!(func, env, self, ex_ref!(env, pokemon));
} }
Ok(())
} }
fn prevent_self_run_away(&self, choice: &TurnChoice, prevent: &mut bool) { fn prevent_self_run_away(&self, choice: &TurnChoice, prevent: &mut bool) -> Result<()> {
if !self.has_capability(&WebAssemblyScriptCapabilities::PreventSelfRunAway) { if !self.has_capability(&WebAssemblyScriptCapabilities::PreventSelfRunAway) {
return; return Ok(());
} }
let env = &self.environment; let env = &self.environment;
if let Some(func) = env.script_function_cache().prevent_self_run_away(env) { if let Some(func) = env.script_function_cache().prevent_self_run_away(env) {
@ -703,11 +838,12 @@ impl Script for WebAssemblyScript {
call_func!(func, env, self, ex_ref!(env, choice), ptr.wasm_ptr); call_func!(func, env, self, ex_ref!(env, choice), ptr.wasm_ptr);
*prevent = *ptr.value(); *prevent = *ptr.value();
} }
Ok(())
} }
fn prevent_opponent_run_away(&self, choice: &TurnChoice, prevent: &mut bool) { fn prevent_opponent_run_away(&self, choice: &TurnChoice, prevent: &mut bool) -> Result<()> {
if !self.has_capability(&WebAssemblyScriptCapabilities::PreventOpponentRunAway) { if !self.has_capability(&WebAssemblyScriptCapabilities::PreventOpponentRunAway) {
return; return Ok(());
} }
let env = &self.environment; let env = &self.environment;
if let Some(func) = env.script_function_cache().prevent_opponent_run_away(env) { if let Some(func) = env.script_function_cache().prevent_opponent_run_away(env) {
@ -715,61 +851,67 @@ impl Script for WebAssemblyScript {
call_func!(func, env, self, ex_ref!(env, choice), ptr.wasm_ptr); call_func!(func, env, self, ex_ref!(env, choice), ptr.wasm_ptr);
*prevent = *ptr.value(); *prevent = *ptr.value();
} }
Ok(())
} }
fn on_end_turn(&self) { fn on_end_turn(&self) -> Result<()> {
if !self.has_capability(&WebAssemblyScriptCapabilities::OnEndTurn) { if !self.has_capability(&WebAssemblyScriptCapabilities::OnEndTurn) {
return; return Ok(());
} }
let env = &self.environment; let env = &self.environment;
if let Some(func) = env.script_function_cache().on_end_turn(env) { if let Some(func) = env.script_function_cache().on_end_turn(env) {
call_func!(func, env, self); call_func!(func, env, self);
} }
Ok(())
} }
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) -> Result<()> {
if !self.has_capability(&WebAssemblyScriptCapabilities::OnDamage) { if !self.has_capability(&WebAssemblyScriptCapabilities::OnDamage) {
return; return Ok(());
} }
let env = &self.environment; let env = &self.environment;
if let Some(func) = env.script_function_cache().on_damage(env) { if let Some(func) = env.script_function_cache().on_damage(env) {
let r = ex_ref!(env, pokemon); let r = ex_ref!(env, pokemon);
call_func!(func, env, self, r, source as u8, old_health, new_health); call_func!(func, env, self, r, source as u8, old_health, new_health);
} }
Ok(())
} }
fn on_faint(&self, pokemon: &Pokemon, source: DamageSource) { fn on_faint(&self, pokemon: &Pokemon, source: DamageSource) -> Result<()> {
if !self.has_capability(&WebAssemblyScriptCapabilities::OnFaint) { if !self.has_capability(&WebAssemblyScriptCapabilities::OnFaint) {
return; return Ok(());
} }
let env = &self.environment; let env = &self.environment;
if let Some(func) = env.script_function_cache().on_faint(env) { if let Some(func) = env.script_function_cache().on_faint(env) {
call_func!(func, env, self, ex_ref!(env, pokemon), source as u8); call_func!(func, env, self, ex_ref!(env, pokemon), source as u8);
} }
Ok(())
} }
fn on_switch_in(&self, pokemon: &Pokemon) { fn on_switch_in(&self, pokemon: &Pokemon) -> Result<()> {
if !self.has_capability(&WebAssemblyScriptCapabilities::OnSwitchIn) { if !self.has_capability(&WebAssemblyScriptCapabilities::OnSwitchIn) {
return; return Ok(());
} }
let env = &self.environment; let env = &self.environment;
if let Some(func) = env.script_function_cache().on_switch_in(env) { if let Some(func) = env.script_function_cache().on_switch_in(env) {
call_func!(func, env, self, ex_ref!(env, pokemon)); call_func!(func, env, self, ex_ref!(env, pokemon));
} }
Ok(())
} }
fn on_after_held_item_consume(&self, pokemon: &Pokemon, item: &dyn Item) { fn on_after_held_item_consume(&self, pokemon: &Pokemon, item: &dyn Item) -> Result<()> {
if !self.has_capability(&WebAssemblyScriptCapabilities::OnAfterHeldItemConsume) { if !self.has_capability(&WebAssemblyScriptCapabilities::OnAfterHeldItemConsume) {
return; return Ok(());
} }
let env = &self.environment; let env = &self.environment;
if let Some(func) = env.script_function_cache().on_after_held_item_consume(env) { if let Some(func) = env.script_function_cache().on_after_held_item_consume(env) {
call_func!(func, env, self, ex_ref!(env, pokemon), ex_ref!(env, item)); call_func!(func, env, self, ex_ref!(env, pokemon), ex_ref!(env, item));
} }
Ok(())
} }
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) -> Result<()> {
if !self.has_capability(&WebAssemblyScriptCapabilities::ChangeExperienceGain) { if !self.has_capability(&WebAssemblyScriptCapabilities::ChangeExperienceGain) {
return; return Ok(());
} }
let env = &self.environment; let env = &self.environment;
if let Some(func) = env.script_function_cache().change_experience_gained(env) { if let Some(func) = env.script_function_cache().change_experience_gained(env) {
@ -779,11 +921,12 @@ impl Script for WebAssemblyScript {
call_func!(func, env, self, fainted_mon, winning_mon, ptr.wasm_ptr); call_func!(func, env, self, fainted_mon, winning_mon, ptr.wasm_ptr);
*amount = *ptr.value(); *amount = *ptr.value();
} }
Ok(())
} }
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) -> Result<()> {
if !self.has_capability(&WebAssemblyScriptCapabilities::DoesShareExperience) { if !self.has_capability(&WebAssemblyScriptCapabilities::DoesShareExperience) {
return; return Ok(());
} }
let env = &self.environment; let env = &self.environment;
if let Some(func) = env.script_function_cache().share_experience(env) { if let Some(func) = env.script_function_cache().share_experience(env) {
@ -793,11 +936,12 @@ impl Script for WebAssemblyScript {
call_func!(func, env, self, fainted_mon, winning_mon, ptr.wasm_ptr); call_func!(func, env, self, fainted_mon, winning_mon, ptr.wasm_ptr);
*shares = *ptr.value(); *shares = *ptr.value();
} }
Ok(())
} }
fn block_weather(&self, battle: &Battle, blocked: &mut bool) { fn block_weather(&self, battle: &Battle, blocked: &mut bool) -> Result<()> {
if !self.has_capability(&WebAssemblyScriptCapabilities::BlockWeather) { if !self.has_capability(&WebAssemblyScriptCapabilities::BlockWeather) {
return; return Ok(());
} }
let env = &self.environment; let env = &self.environment;
if let Some(func) = env.script_function_cache().block_weather(env) { if let Some(func) = env.script_function_cache().block_weather(env) {
@ -805,11 +949,12 @@ impl Script for WebAssemblyScript {
call_func!(func, env, self, ex_ref!(env, battle), ptr.wasm_ptr); call_func!(func, env, self, ex_ref!(env, battle), ptr.wasm_ptr);
*blocked = *ptr.value(); *blocked = *ptr.value();
} }
Ok(())
} }
fn change_capture_rate_bonus(&self, target: &Pokemon, pokeball: &dyn Item, modifier: &mut u8) { fn change_capture_rate_bonus(&self, target: &Pokemon, pokeball: &dyn Item, modifier: &mut u8) -> Result<()> {
if !self.has_capability(&WebAssemblyScriptCapabilities::ChangeCaptureRate) { if !self.has_capability(&WebAssemblyScriptCapabilities::ChangeCaptureRate) {
return; return Ok(());
} }
let env = &self.environment; let env = &self.environment;
if let Some(func) = env.script_function_cache().change_capture_rate_bonus(env) { if let Some(func) = env.script_function_cache().change_capture_rate_bonus(env) {
@ -819,6 +964,7 @@ impl Script for WebAssemblyScript {
call_func!(func, env, self, target, pokeball, ptr.wasm_ptr); call_func!(func, env, self, target, pokeball, ptr.wasm_ptr);
*modifier = *ptr.value(); *modifier = *ptr.value();
} }
Ok(())
} }
fn as_any(&self) -> &dyn Any { fn as_any(&self) -> &dyn Any {

View File

@ -119,7 +119,7 @@ fn validate_assurance() {
let mv = p1.learned_moves().read()[0].as_ref().unwrap().clone(); let mv = p1.learned_moves().read()[0].as_ref().unwrap().clone();
let choice = TurnChoice::Move(MoveChoice::new(p1.clone(), mv.clone(), 1, 0)); let choice = TurnChoice::Move(MoveChoice::new(p1.clone(), mv.clone(), 1, 0));
script.on_before_turn(&choice); script.on_before_turn(&choice).unwrap();
assert!(battle.sides()[1].has_volatile_script(&"assurance_data".into())); assert!(battle.sides()[1].has_volatile_script(&"assurance_data".into()));
let executing_move = ExecutingMove::new( let executing_move = ExecutingMove::new(
@ -131,19 +131,19 @@ fn validate_assurance() {
ScriptContainer::default(), ScriptContainer::default(),
); );
let mut v = 20_u8; let mut v = 20_u8;
script.change_base_power(&executing_move, &p2, 0, &mut v); script.change_base_power(&executing_move, &p2, 0, &mut v).unwrap();
assert_eq!(v, 20_u8); assert_eq!(v, 20_u8);
let s = battle.sides()[1].get_volatile_script(&"assurance_data".into()); let s = battle.sides()[1].get_volatile_script(&"assurance_data".into());
let binding = s.as_ref().unwrap().get().unwrap().read(); let binding = s.as_ref().unwrap().get().unwrap().read();
let data_script = binding.as_ref().unwrap(); let data_script = binding.as_ref().unwrap();
data_script.on_damage(&p2, DamageSource::Misc, 100, 50); data_script.on_damage(&p2, DamageSource::Misc, 100, 50).unwrap();
let mut v = 20_u8; let mut v = 20_u8;
script.change_base_power(&executing_move, &p2, 0, &mut v); script.change_base_power(&executing_move, &p2, 0, &mut v).unwrap();
assert_eq!(v, 40_u8); assert_eq!(v, 40_u8);
data_script.on_end_turn(); data_script.on_end_turn().unwrap();
assert!(!battle.sides()[1].has_volatile_script(&"assurance_data".into())); assert!(!battle.sides()[1].has_volatile_script(&"assurance_data".into()));
} }