PkmnLib_rs/src/script_implementations/wasm/script.rs

942 lines
34 KiB
Rust
Executable File

use anyhow_ext::Result;
use std::any::Any;
use std::sync::atomic::{AtomicBool, AtomicUsize};
use std::sync::Arc;
use hashbrown::HashSet;
use crate::dynamic_data::{
Battle, DamageSource, DynamicLibrary, ExecutingMove, Pokemon, Script, ScriptOwnerData, TurnChoice,
};
use crate::script_implementations::wasm::export_registry::WasmVoidResultExtension;
use crate::script_implementations::wasm::extern_ref::ExternRef;
use crate::script_implementations::wasm::script_resolver::WebAssemblyEnvironmentData;
use crate::script_implementations::wasm::WebAssemblyScriptCapabilities;
use crate::static_data::{Item, Parameter, Statistic, TypeIdentifier};
use crate::StringKey;
/// A WebAssemblyScript is there to implement the Script trait within WebAssemblyScript.
pub struct WebAssemblyScript {
/// The unique identifier of the script.
name: StringKey,
/// Returns an atomic bool for internal marking of deletion. This is currently only specifically
/// used for deletion of a script while we are holding a reference to it (i.e. executing a script
/// hook on it).
marked_for_deletion: AtomicBool,
/// A script can be suppressed by other scripts. If a script is suppressed by at least one script
/// we will not execute its methods. This holds the number of suppressions on the script.
suppressed_count: AtomicUsize,
/// The owner of this script (where the script is attached to)
owner: ScriptOwnerData,
/// Pointer inside WebAssembly memory where the data is for this script.
self_ptr: u32,
/// Capabilities define which functions we actually implement.
capabilities: Arc<HashSet<WebAssemblyScriptCapabilities>>,
/// The global runtime environment data.
environment: Arc<WebAssemblyEnvironmentData>,
}
impl WebAssemblyScript {
/// Instantiates a new WebAssemblyScript.
pub fn new(
owner: ScriptOwnerData,
self_ptr: u32,
capabilities: Arc<HashSet<WebAssemblyScriptCapabilities>>,
environment: Arc<WebAssemblyEnvironmentData>,
name: StringKey,
) -> Self {
Self {
name,
marked_for_deletion: Default::default(),
suppressed_count: Default::default(),
owner,
self_ptr,
capabilities,
environment,
}
}
/// Get a pointer inside the WASM memory.
pub(crate) fn get_wasm_pointer(&self) -> u32 {
self.self_ptr
}
/// Check if this script implements a certain capability.
#[inline(always)]
fn has_capability(&self, cap: &WebAssemblyScriptCapabilities) -> bool {
self.capabilities.contains(cap)
}
/// Gets the thing the script is owned by.
pub fn get_owner(&self) -> &ScriptOwnerData {
&self.owner
}
}
/// Util macro to reduce function call verbosity.
macro_rules! call_func {
($func:ident, $env:ident, $self:ident $(, $par_name:expr)*) => {
match $func.call(&mut $env.store_mut(), $self.self_ptr $(, $par_name)*) {
Ok(res) => res.into_result_env($env)?,
Err(e) => return Err(e.into()),
};
}
}
/// Util macro to reduce extern ref instantiation verbosity.
macro_rules! ex_ref {
($env:ident, $value:expr) => {
ExternRef::new($env.as_ref(), $value.into())
};
}
impl Script for WebAssemblyScript {
fn name(&self) -> Result<&StringKey> {
Ok(&self.name)
}
fn get_marked_for_deletion(&self) -> &AtomicBool {
&self.marked_for_deletion
}
fn get_suppressed_count(&self) -> &AtomicUsize {
&self.suppressed_count
}
fn stack(&self) -> Result<()> {
if !self.has_capability(&WebAssemblyScriptCapabilities::OnStack) {
return Ok(());
}
let env = &self.environment;
if let Some(func) = env.script_function_cache().stack(env) {
call_func!(func, env, self);
}
Ok(())
}
fn on_remove(&self) -> Result<()> {
if !self.has_capability(&WebAssemblyScriptCapabilities::OnRemove) {
return Ok(());
}
let env = &self.environment;
if let Some(func) = env.script_function_cache().on_remove(env) {
call_func!(func, env, self);
}
Ok(())
}
fn on_initialize(&self, library: &Arc<dyn DynamicLibrary>, pars: Vec<Arc<Parameter>>) -> Result<()> {
if !self.has_capability(&WebAssemblyScriptCapabilities::Initialize) {
return Ok(());
}
let env = &self.environment;
if let Some(func) = env.script_function_cache().on_initialize(env) {
let pars = pars
.into_iter()
.map(|p| ExternRef::<Parameter>::new(env, (&p).into()).index() as u32)
.collect::<Vec<_>>();
let wasm_ptr = env.copy_value_vec_to_wasm(&pars)?;
let r: u64 = unsafe { std::mem::transmute((wasm_ptr, pars.len() as u32)) };
call_func!(func, env, self, ex_ref!(env, library), r);
}
Ok(())
}
fn on_before_turn(&self, choice: &Arc<TurnChoice>) -> Result<()> {
if !self.has_capability(&WebAssemblyScriptCapabilities::OnBeforeTurn) {
return Ok(());
}
let env = &self.environment;
if let Some(func) = env.script_function_cache().on_before_turn(env) {
call_func!(func, env, self, ex_ref!(env, choice));
}
Ok(())
}
fn change_speed(&self, choice: &Arc<TurnChoice>, speed: &mut u32) -> Result<()> {
if !self.has_capability(&WebAssemblyScriptCapabilities::ChangeSpeed) {
return Ok(());
}
let env = &self.environment;
if let Some(func) = env.script_function_cache().change_speed(env) {
let ptr = env.allocate_temp::<u32>(*speed);
call_func!(func, env, self, ex_ref!(env, choice), ptr.wasm_ptr);
*speed = *ptr.value();
}
Ok(())
}
fn change_priority(&self, choice: &Arc<TurnChoice>, priority: &mut i8) -> Result<()> {
if !self.has_capability(&WebAssemblyScriptCapabilities::ChangePriority) {
return Ok(());
}
let env = &self.environment;
if let Some(func) = env.script_function_cache().change_priority(env) {
let ptr = env.allocate_temp::<i8>(*priority);
call_func!(func, env, self, ex_ref!(env, choice), ptr.wasm_ptr);
*priority = *ptr.value();
}
Ok(())
}
fn change_move(&self, choice: &Arc<TurnChoice>, move_name: &mut StringKey) -> Result<()> {
if !self.has_capability(&WebAssemblyScriptCapabilities::ChangeMove) {
return Ok(());
}
let env = &self.environment;
if let Some(func) = env.script_function_cache().change_move(env) {
let move_ref = ex_ref!(env, move_name.clone());
let ptr = env.allocate_temp::<ExternRef<StringKey>>(move_ref);
call_func!(func, env, self, ex_ref!(env, choice), ptr.wasm_ptr);
*move_name = ptr.value().value(env)?;
}
Ok(())
}
fn change_number_of_hits(&self, choice: &Arc<TurnChoice>, number_of_hits: &mut u8) -> Result<()> {
if !self.has_capability(&WebAssemblyScriptCapabilities::ChangeNumberOfHits) {
return Ok(());
}
let env = &self.environment;
if let Some(func) = env.script_function_cache().change_number_of_hits(env) {
let ptr = env.allocate_temp::<u8>(*number_of_hits);
call_func!(func, env, self, ex_ref!(env, choice), ptr.wasm_ptr);
*number_of_hits = *ptr.value();
}
Ok(())
}
fn prevent_move(&self, mv: &Arc<ExecutingMove>, prevent: &mut bool) -> Result<()> {
if !self.has_capability(&WebAssemblyScriptCapabilities::PreventMove) {
return Ok(());
}
let env = &self.environment;
if let Some(func) = env.script_function_cache().prevent_move(env) {
let ptr = env.allocate_temp::<bool>(*prevent);
call_func!(func, env, self, ex_ref!(env, mv), ptr.wasm_ptr);
*prevent = *ptr.value();
}
Ok(())
}
fn fail_move(&self, mv: &Arc<ExecutingMove>, fail: &mut bool) -> Result<()> {
if !self.has_capability(&WebAssemblyScriptCapabilities::FailMove) {
return Ok(());
}
let env = &self.environment;
if let Some(func) = env.script_function_cache().fail_move(env) {
let ptr = env.allocate_temp::<bool>(*fail);
call_func!(func, env, self, ex_ref!(env, mv), ptr.wasm_ptr);
*fail = *ptr.value();
}
Ok(())
}
fn stop_before_move(&self, mv: &Arc<ExecutingMove>, stop: &mut bool) -> Result<()> {
if !self.has_capability(&WebAssemblyScriptCapabilities::StopBeforeMove) {
return Ok(());
}
let env = &self.environment;
if let Some(func) = env.script_function_cache().stop_before_move(env) {
let ptr = env.allocate_temp::<bool>(*stop);
call_func!(func, env, self, ex_ref!(env, mv), ptr.wasm_ptr);
*stop = *ptr.value();
}
Ok(())
}
fn on_before_move(&self, mv: &Arc<ExecutingMove>) -> Result<()> {
if !self.has_capability(&WebAssemblyScriptCapabilities::OnBeforeMove) {
return Ok(());
}
let env = &self.environment;
if let Some(func) = env.script_function_cache().on_before_move(env) {
call_func!(func, env, self, ex_ref!(env, mv));
}
Ok(())
}
fn fail_incoming_move(&self, mv: &Arc<ExecutingMove>, target: &Pokemon, fail: &mut bool) -> Result<()> {
if !self.has_capability(&WebAssemblyScriptCapabilities::FailIncomingMove) {
return Ok(());
}
let env = &self.environment;
if let Some(func) = env.script_function_cache().fail_incoming_move(env) {
let ptr = env.allocate_temp::<bool>(*fail);
call_func!(func, env, self, ex_ref!(env, mv), ex_ref!(env, target), ptr.wasm_ptr);
*fail = *ptr.value();
}
Ok(())
}
fn is_invulnerable(&self, mv: &Arc<ExecutingMove>, target: &Pokemon, invulnerable: &mut bool) -> Result<()> {
if !self.has_capability(&WebAssemblyScriptCapabilities::IsInvulnerable) {
return Ok(());
}
let env = &self.environment;
if let Some(func) = env.script_function_cache().is_invulnerable(env) {
let ptr = env.allocate_temp::<bool>(*invulnerable);
call_func!(func, env, self, ex_ref!(env, mv), ex_ref!(env, target), ptr.wasm_ptr);
*invulnerable = *ptr.value();
}
Ok(())
}
fn on_move_miss(&self, mv: &Arc<ExecutingMove>, target: &Pokemon) -> Result<()> {
if !self.has_capability(&WebAssemblyScriptCapabilities::OnMoveMiss) {
return Ok(());
}
let env = &self.environment;
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));
}
Ok(())
}
fn change_move_type(
&self,
mv: &Arc<ExecutingMove>,
target: &Pokemon,
hit: u8,
move_type: &mut TypeIdentifier,
) -> Result<()> {
if !self.has_capability(&WebAssemblyScriptCapabilities::ChangeMoveType) {
return Ok(());
}
let env = &self.environment;
if let Some(func) = env.script_function_cache().change_move_type(env) {
let ptr = env.allocate_temp::<TypeIdentifier>(*move_type);
let w_ptr = ptr.wasm_ptr;
call_func!(func, env, self, ex_ref!(env, mv), ex_ref!(env, target), hit, w_ptr);
*move_type = *ptr.value();
}
Ok(())
}
fn change_effectiveness(
&self,
mv: &Arc<ExecutingMove>,
target: &Pokemon,
hit: u8,
effectiveness: &mut f32,
) -> Result<()> {
if !self.has_capability(&WebAssemblyScriptCapabilities::ChangeEffectiveness) {
return Ok(());
}
let env = &self.environment;
if let Some(func) = env.script_function_cache().change_effectiveness(env) {
let ptr = env.allocate_temp(*effectiveness);
let w_ptr = ptr.wasm_ptr;
call_func!(func, env, self, ex_ref!(env, mv), ex_ref!(env, target), hit, w_ptr);
*effectiveness = *ptr.value();
}
Ok(())
}
fn block_critical(
&self,
mv: &Arc<ExecutingMove>,
target: &Pokemon,
hit: u8,
block_critical: &mut bool,
) -> Result<()> {
if !self.has_capability(&WebAssemblyScriptCapabilities::BlockCritical) {
return Ok(());
}
let env = &self.environment;
if let Some(func) = env.script_function_cache().block_critical(env) {
let ptr = env.allocate_temp(*block_critical);
let w_ptr = ptr.wasm_ptr;
call_func!(func, env, self, ex_ref!(env, mv), ex_ref!(env, target), hit, w_ptr);
*block_critical = *ptr.value();
}
Ok(())
}
fn block_incoming_critical(
&self,
mv: &Arc<ExecutingMove>,
target: &Pokemon,
hit: u8,
block_critical: &mut bool,
) -> Result<()> {
if !self.has_capability(&WebAssemblyScriptCapabilities::BlockIncomingCritical) {
return Ok(());
}
let env = &self.environment;
if let Some(func) = env.script_function_cache().block_incoming_critical(env) {
let ptr = env.allocate_temp(*block_critical);
let w_ptr = ptr.wasm_ptr;
call_func!(func, env, self, ex_ref!(env, mv), ex_ref!(env, target), hit, w_ptr);
*block_critical = *ptr.value();
}
Ok(())
}
fn change_accuracy(&self, mv: &Arc<ExecutingMove>, target: &Pokemon, hit: u8, accuracy: &mut u8) -> Result<()> {
if !self.has_capability(&WebAssemblyScriptCapabilities::ChangeAccuracy) {
return Ok(());
}
let env = &self.environment;
if let Some(func) = env.script_function_cache().change_accuracy(env) {
let ptr = env.allocate_temp(*accuracy);
let w_ptr = ptr.wasm_ptr;
call_func!(func, env, self, ex_ref!(env, mv), ex_ref!(env, target), hit, w_ptr);
*accuracy = *ptr.value();
}
Ok(())
}
fn change_critical_stage(&self, mv: &Arc<ExecutingMove>, target: &Pokemon, hit: u8, stage: &mut u8) -> Result<()> {
if !self.has_capability(&WebAssemblyScriptCapabilities::ChangeCriticalStage) {
return Ok(());
}
let env = &self.environment;
if let Some(func) = env.script_function_cache().change_critical_stage(env) {
let ptr = env.allocate_temp(*stage);
let w_ptr = ptr.wasm_ptr;
call_func!(func, env, self, ex_ref!(env, mv), ex_ref!(env, target), hit, w_ptr);
*stage = *ptr.value();
}
Ok(())
}
fn change_critical_modifier(
&self,
mv: &Arc<ExecutingMove>,
target: &Pokemon,
hit: u8,
modifier: &mut f32,
) -> Result<()> {
if !self.has_capability(&WebAssemblyScriptCapabilities::ChangeCriticalModifier) {
return Ok(());
}
let env = &self.environment;
if let Some(func) = env.script_function_cache().change_critical_modifier(env) {
let ptr = env.allocate_temp(*modifier);
let w_ptr = ptr.wasm_ptr;
call_func!(func, env, self, ex_ref!(env, mv), ex_ref!(env, target), hit, w_ptr);
*modifier = *ptr.value();
}
Ok(())
}
fn change_stab_modifier(
&self,
mv: &Arc<ExecutingMove>,
target: &Pokemon,
hit: u8,
modifier: &mut f32,
) -> Result<()> {
if !self.has_capability(&WebAssemblyScriptCapabilities::ChangeSTABModifier) {
return Ok(());
}
let env = &self.environment;
if let Some(func) = env.script_function_cache().change_stab_modifier(env) {
let ptr = env.allocate_temp(*modifier);
let w_ptr = ptr.wasm_ptr;
call_func!(func, env, self, ex_ref!(env, mv), ex_ref!(env, target), hit, w_ptr);
*modifier = *ptr.value();
}
Ok(())
}
fn change_base_power(&self, mv: &Arc<ExecutingMove>, target: &Pokemon, hit: u8, base_power: &mut u8) -> Result<()> {
if !self.has_capability(&WebAssemblyScriptCapabilities::ChangeBasePower) {
return Ok(());
}
let env = &self.environment;
if let Some(func) = env.script_function_cache().change_base_power(env) {
let ptr = env.allocate_temp(*base_power);
let w_ptr = ptr.wasm_ptr;
call_func!(func, env, self, ex_ref!(env, mv), ex_ref!(env, target), hit, w_ptr);
*base_power = *ptr.value();
}
Ok(())
}
fn bypass_defensive_stat_boost(
&self,
mv: &Arc<ExecutingMove>,
target: &Pokemon,
hit: u8,
bypass: &mut bool,
) -> Result<()> {
if !self.has_capability(&WebAssemblyScriptCapabilities::BypassDefensiveStat) {
return Ok(());
}
let env = &self.environment;
if let Some(func) = env.script_function_cache().bypass_defensive_stat_boost(env) {
let ptr = env.allocate_temp(*bypass);
let w_ptr = ptr.wasm_ptr;
call_func!(func, env, self, ex_ref!(env, mv), ex_ref!(env, target), hit, w_ptr);
*bypass = *ptr.value();
}
Ok(())
}
fn bypass_offensive_stat_boost(
&self,
mv: &Arc<ExecutingMove>,
target: &Pokemon,
hit: u8,
bypass: &mut bool,
) -> Result<()> {
if !self.has_capability(&WebAssemblyScriptCapabilities::BypassOffensiveStat) {
return Ok(());
}
let env = &self.environment;
if let Some(func) = env.script_function_cache().bypass_offensive_stat_boost(env) {
let ptr = env.allocate_temp(*bypass);
let w_ptr = ptr.wasm_ptr;
call_func!(func, env, self, ex_ref!(env, mv), ex_ref!(env, target), hit, w_ptr);
*bypass = *ptr.value();
}
Ok(())
}
fn change_offensive_stat_value(
&self,
mv: &Arc<ExecutingMove>,
target: &Pokemon,
hit: u8,
amount: &mut u32,
) -> Result<()> {
if !self.has_capability(&WebAssemblyScriptCapabilities::ChangeOffensiveStatValue) {
return Ok(());
}
let env = &self.environment;
if let Some(func) = env.script_function_cache().change_offensive_stat_value(env) {
let ptr = env.allocate_temp(*amount);
let w_ptr = ptr.wasm_ptr;
call_func!(func, env, self, ex_ref!(env, mv), ex_ref!(env, target), hit, w_ptr);
*amount = *ptr.value();
}
Ok(())
}
fn change_defensive_stat_value(
&self,
mv: &Arc<ExecutingMove>,
target: &Pokemon,
hit: u8,
amount: &mut u32,
) -> Result<()> {
if !self.has_capability(&WebAssemblyScriptCapabilities::ChangeOffensiveStatValue) {
return Ok(());
}
let env = &self.environment;
if let Some(func) = env.script_function_cache().change_defensive_stat_value(env) {
let ptr = env.allocate_temp(*amount);
let w_ptr = ptr.wasm_ptr;
call_func!(func, env, self, ex_ref!(env, mv), ex_ref!(env, target), hit, w_ptr);
*amount = *ptr.value();
}
Ok(())
}
fn change_damage_stat_modifier(
&self,
mv: &Arc<ExecutingMove>,
target: &Pokemon,
hit: u8,
modifier: &mut f32,
) -> Result<()> {
if !self.has_capability(&WebAssemblyScriptCapabilities::ChangeStatModifier) {
return Ok(());
}
let env = &self.environment;
if let Some(func) = env.script_function_cache().change_damage_stat_modifier(env) {
let ptr = env.allocate_temp(*modifier);
let w_ptr = ptr.wasm_ptr;
call_func!(func, env, self, ex_ref!(env, mv), ex_ref!(env, target), hit, w_ptr);
*modifier = *ptr.value();
}
Ok(())
}
fn change_damage_modifier(
&self,
mv: &Arc<ExecutingMove>,
target: &Pokemon,
hit: u8,
modifier: &mut f32,
) -> Result<()> {
if !self.has_capability(&WebAssemblyScriptCapabilities::ChangeDamageModifier) {
return Ok(());
}
let env = &self.environment;
if let Some(func) = env.script_function_cache().change_damage_modifier(env) {
let ptr = env.allocate_temp(*modifier);
let w_ptr = ptr.wasm_ptr;
call_func!(func, env, self, ex_ref!(env, mv), ex_ref!(env, target), hit, w_ptr);
*modifier = *ptr.value();
}
Ok(())
}
fn change_damage(&self, mv: &Arc<ExecutingMove>, target: &Pokemon, hit: u8, damage: &mut u32) -> Result<()> {
if !self.has_capability(&WebAssemblyScriptCapabilities::ChangeDamage) {
return Ok(());
}
let env = &self.environment;
if let Some(func) = env.script_function_cache().change_damage(env) {
let ptr = env.allocate_temp(*damage);
let w_ptr = ptr.wasm_ptr;
call_func!(func, env, self, ex_ref!(env, mv), ex_ref!(env, target), hit, w_ptr);
*damage = *ptr.value();
}
Ok(())
}
fn change_incoming_damage(
&self,
mv: &Arc<ExecutingMove>,
target: &Pokemon,
hit: u8,
damage: &mut u32,
) -> Result<()> {
if !self.has_capability(&WebAssemblyScriptCapabilities::ChangeIncomingDamage) {
return Ok(());
}
let env = &self.environment;
if let Some(func) = env.script_function_cache().change_incoming_damage(env) {
let ptr = env.allocate_temp(*damage);
let w_ptr = ptr.wasm_ptr;
call_func!(func, env, self, ex_ref!(env, mv), ex_ref!(env, target), hit, w_ptr);
*damage = *ptr.value();
}
Ok(())
}
fn on_incoming_hit(&self, mv: &Arc<ExecutingMove>, target: &Pokemon, hit: u8) -> Result<()> {
if !self.has_capability(&WebAssemblyScriptCapabilities::OnIncomingHit) {
return Ok(());
}
let env = &self.environment;
if let Some(func) = env.script_function_cache().on_incoming_hit(env) {
call_func!(func, env, self, ex_ref!(env, mv), ex_ref!(env, target), hit);
}
Ok(())
}
fn on_opponent_faints(&self, mv: &Arc<ExecutingMove>, target: &Pokemon, hit: u8) -> Result<()> {
if !self.has_capability(&WebAssemblyScriptCapabilities::OnFaintingOpponent) {
return Ok(());
}
let env = &self.environment;
if let Some(func) = env.script_function_cache().on_opponent_faints(env) {
call_func!(func, env, self, ex_ref!(env, mv), ex_ref!(env, target), hit);
}
Ok(())
}
fn prevent_stat_boost_change(
&self,
target: &Pokemon,
stat: Statistic,
amount: i8,
self_inflicted: bool,
prevent: &mut bool,
) -> Result<()> {
if !self.has_capability(&WebAssemblyScriptCapabilities::PreventStatBoostChange) {
return Ok(());
}
let env = &self.environment;
if let Some(func) = env.script_function_cache().prevent_stat_boost_change(env) {
let ptr = env.allocate_temp(*prevent);
let self_inflicted = u8::from(self_inflicted);
call_func!(
func,
env,
self,
ex_ref!(env, target),
stat as u8,
amount,
self_inflicted,
ptr.wasm_ptr
);
*prevent = *ptr.value();
}
Ok(())
}
fn prevent_secondary_effect(
&self,
mv: &Arc<ExecutingMove>,
target: &Pokemon,
hit: u8,
prevent: &mut bool,
) -> Result<()> {
if !self.has_capability(&WebAssemblyScriptCapabilities::PreventSecondaryEffects) {
return Ok(());
}
let env = &self.environment;
if let Some(func) = env.script_function_cache().prevent_secondary_effect(env) {
let ptr = env.allocate_temp(*prevent);
let w_ptr = ptr.wasm_ptr;
call_func!(func, env, self, ex_ref!(env, mv), ex_ref!(env, target), hit, w_ptr);
*prevent = *ptr.value();
}
Ok(())
}
fn change_effect_chance(&self, mv: &Arc<ExecutingMove>, target: &Pokemon, hit: u8, chance: &mut f32) -> Result<()> {
if !self.has_capability(&WebAssemblyScriptCapabilities::ChangeEffectChance) {
return Ok(());
}
let env = &self.environment;
if let Some(func) = env.script_function_cache().change_effect_chance(env) {
let ptr = env.allocate_temp(*chance);
let w_ptr = ptr.wasm_ptr;
call_func!(func, env, self, ex_ref!(env, mv), ex_ref!(env, target), hit, w_ptr);
*chance = *ptr.value();
}
Ok(())
}
fn change_incoming_effect_chance(
&self,
mv: &Arc<ExecutingMove>,
target: &Pokemon,
hit: u8,
chance: &mut f32,
) -> Result<()> {
if !self.has_capability(&WebAssemblyScriptCapabilities::ChangeIncomingEffectChance) {
return Ok(());
}
let env = &self.environment;
if let Some(func) = env.script_function_cache().change_incoming_effect_chance(env) {
let ptr = env.allocate_temp(*chance);
let w_ptr = ptr.wasm_ptr;
call_func!(func, env, self, ex_ref!(env, mv), ex_ref!(env, target), hit, w_ptr);
*chance = *ptr.value();
}
Ok(())
}
fn on_secondary_effect(&self, mv: &Arc<ExecutingMove>, target: &Pokemon, hit: u8) -> Result<()> {
if !self.has_capability(&WebAssemblyScriptCapabilities::OnFaintingOpponent) {
return Ok(());
}
let env = &self.environment;
if let Some(func) = env.script_function_cache().on_secondary_effect(env) {
call_func!(func, env, self, ex_ref!(env, mv), ex_ref!(env, target), hit);
}
Ok(())
}
fn on_after_hits(&self, mv: &Arc<ExecutingMove>, target: &Pokemon) -> Result<()> {
if !self.has_capability(&WebAssemblyScriptCapabilities::OnAfterHits) {
return Ok(());
}
let env = &self.environment;
if let Some(func) = env.script_function_cache().on_after_hits(env) {
call_func!(func, env, self, ex_ref!(env, mv), ex_ref!(env, target));
}
Ok(())
}
fn prevent_self_switch(&self, choice: &Arc<TurnChoice>, prevent: &mut bool) -> Result<()> {
if !self.has_capability(&WebAssemblyScriptCapabilities::PreventSelfSwitch) {
return Ok(());
}
let env = &self.environment;
if let Some(func) = env.script_function_cache().prevent_self_switch(env) {
let ptr = env.allocate_temp(*prevent);
call_func!(func, env, self, ex_ref!(env, choice), ptr.wasm_ptr);
*prevent = *ptr.value();
}
Ok(())
}
fn prevent_opponent_switch(&self, choice: &Arc<TurnChoice>, prevent: &mut bool) -> Result<()> {
if !self.has_capability(&WebAssemblyScriptCapabilities::PreventSelfSwitch) {
return Ok(());
}
let env = &self.environment;
if let Some(func) = env.script_function_cache().prevent_opponent_switch(env) {
let ptr = env.allocate_temp(*prevent);
call_func!(func, env, self, ex_ref!(env, choice), ptr.wasm_ptr);
*prevent = *ptr.value();
}
Ok(())
}
fn on_fail(&self, pokemon: &Pokemon) -> Result<()> {
if !self.has_capability(&WebAssemblyScriptCapabilities::OnFail) {
return Ok(());
}
let env = &self.environment;
if let Some(func) = env.script_function_cache().on_fail(env) {
call_func!(func, env, self, ex_ref!(env, pokemon));
}
Ok(())
}
fn on_opponent_fail(&self, pokemon: &Pokemon) -> Result<()> {
if !self.has_capability(&WebAssemblyScriptCapabilities::OnFail) {
return Ok(());
}
let env = &self.environment;
if let Some(func) = env.script_function_cache().on_opponent_fail(env) {
call_func!(func, env, self, ex_ref!(env, pokemon));
}
Ok(())
}
fn prevent_self_run_away(&self, choice: &Arc<TurnChoice>, prevent: &mut bool) -> Result<()> {
if !self.has_capability(&WebAssemblyScriptCapabilities::PreventSelfRunAway) {
return Ok(());
}
let env = &self.environment;
if let Some(func) = env.script_function_cache().prevent_self_run_away(env) {
let ptr = env.allocate_temp(*prevent);
call_func!(func, env, self, ex_ref!(env, choice), ptr.wasm_ptr);
*prevent = *ptr.value();
}
Ok(())
}
fn prevent_opponent_run_away(&self, choice: &Arc<TurnChoice>, prevent: &mut bool) -> Result<()> {
if !self.has_capability(&WebAssemblyScriptCapabilities::PreventOpponentRunAway) {
return Ok(());
}
let env = &self.environment;
if let Some(func) = env.script_function_cache().prevent_opponent_run_away(env) {
let ptr = env.allocate_temp(*prevent);
call_func!(func, env, self, ex_ref!(env, choice), ptr.wasm_ptr);
*prevent = *ptr.value();
}
Ok(())
}
fn on_end_turn(&self) -> Result<()> {
if !self.has_capability(&WebAssemblyScriptCapabilities::OnEndTurn) {
return Ok(());
}
let env = &self.environment;
if let Some(func) = env.script_function_cache().on_end_turn(env) {
call_func!(func, env, self);
}
Ok(())
}
fn on_damage(&self, pokemon: &Pokemon, source: DamageSource, old_health: u32, new_health: u32) -> Result<()> {
if !self.has_capability(&WebAssemblyScriptCapabilities::OnDamage) {
return Ok(());
}
let env = &self.environment;
if let Some(func) = env.script_function_cache().on_damage(env) {
let r = ex_ref!(env, pokemon);
call_func!(func, env, self, r, source as u8, old_health, new_health);
}
Ok(())
}
fn on_faint(&self, pokemon: &Pokemon, source: DamageSource) -> Result<()> {
if !self.has_capability(&WebAssemblyScriptCapabilities::OnFaint) {
return Ok(());
}
let env = &self.environment;
if let Some(func) = env.script_function_cache().on_faint(env) {
call_func!(func, env, self, ex_ref!(env, pokemon), source as u8);
}
Ok(())
}
fn on_switch_in(&self, pokemon: &Pokemon) -> Result<()> {
if !self.has_capability(&WebAssemblyScriptCapabilities::OnSwitchIn) {
return Ok(());
}
let env = &self.environment;
if let Some(func) = env.script_function_cache().on_switch_in(env) {
call_func!(func, env, self, ex_ref!(env, pokemon));
}
Ok(())
}
fn on_after_held_item_consume(&self, pokemon: &Pokemon, item: &Arc<dyn Item>) -> Result<()> {
if !self.has_capability(&WebAssemblyScriptCapabilities::OnAfterHeldItemConsume) {
return Ok(());
}
let env = &self.environment;
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));
}
Ok(())
}
fn change_experience_gained(&self, fainted_mon: &Pokemon, winning_mon: &Pokemon, amount: &mut u32) -> Result<()> {
if !self.has_capability(&WebAssemblyScriptCapabilities::ChangeExperienceGain) {
return Ok(());
}
let env = &self.environment;
if let Some(func) = env.script_function_cache().change_experience_gained(env) {
let ptr = env.allocate_temp(*amount);
let fainted_mon = ex_ref!(env, fainted_mon);
let winning_mon = ex_ref!(env, winning_mon);
call_func!(func, env, self, fainted_mon, winning_mon, ptr.wasm_ptr);
*amount = *ptr.value();
}
Ok(())
}
fn share_experience(&self, fainted_mon: &Pokemon, winning_mon: &Pokemon, shares: &mut bool) -> Result<()> {
if !self.has_capability(&WebAssemblyScriptCapabilities::DoesShareExperience) {
return Ok(());
}
let env = &self.environment;
if let Some(func) = env.script_function_cache().share_experience(env) {
let ptr = env.allocate_temp(*shares);
let fainted_mon = ex_ref!(env, fainted_mon);
let winning_mon = ex_ref!(env, winning_mon);
call_func!(func, env, self, fainted_mon, winning_mon, ptr.wasm_ptr);
*shares = *ptr.value();
}
Ok(())
}
fn block_weather(&self, battle: &Battle, blocked: &mut bool) -> Result<()> {
if !self.has_capability(&WebAssemblyScriptCapabilities::BlockWeather) {
return Ok(());
}
let env = &self.environment;
if let Some(func) = env.script_function_cache().block_weather(env) {
let ptr = env.allocate_temp(*blocked);
call_func!(func, env, self, ex_ref!(env, battle), ptr.wasm_ptr);
*blocked = *ptr.value();
}
Ok(())
}
fn change_capture_rate_bonus(&self, target: &Pokemon, pokeball: &Arc<dyn Item>, modifier: &mut u8) -> Result<()> {
if !self.has_capability(&WebAssemblyScriptCapabilities::ChangeCaptureRate) {
return Ok(());
}
let env = &self.environment;
if let Some(func) = env.script_function_cache().change_capture_rate_bonus(env) {
let ptr = env.allocate_temp(*modifier);
let target = ex_ref!(env, target);
let pokeball = ex_ref!(env, pokeball);
call_func!(func, env, self, target, pokeball, ptr.wasm_ptr);
*modifier = *ptr.value();
}
Ok(())
}
fn as_any(&self) -> &dyn Any {
self
}
fn as_any_mut(&mut self) -> &mut dyn Any {
self
}
}