PkmnLib_rs/src/script_implementations/wasm/script.rs

830 lines
32 KiB
Rust
Executable File

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::extern_ref::{ExternRef, VecExternRef};
use crate::script_implementations::wasm::script_resolver::WebAssemblyEnvironmentData;
use crate::script_implementations::wasm::WebAssemblyScriptCapabilities;
use crate::static_data::{EffectParameter, Item, 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,
}
}
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)*) => {
$func.call(&mut $env.store_mut(), $self.self_ptr $(, $par_name)*).unwrap();
}
}
/// Util macro to reduce extern ref instantiation verbosity.
macro_rules! ex_ref {
($env:ident, $value:expr) => {
ExternRef::new($env.as_ref(), $value)
};
}
/// Util macro to reduce vec extern ref instantiation verbosity.
macro_rules! vec_ex_ref {
($env:ident, $value:expr) => {
VecExternRef::new($env.as_ref(), $value)
};
}
impl Script for WebAssemblyScript {
fn name(&self) -> &StringKey {
&self.name
}
fn get_marked_for_deletion(&self) -> &AtomicBool {
&self.marked_for_deletion
}
fn get_suppressed_count(&self) -> &AtomicUsize {
&self.suppressed_count
}
fn stack(&self) {
if !self.has_capability(&WebAssemblyScriptCapabilities::OnStack) {
return;
}
let env = &self.environment;
if let Some(func) = env.script_function_cache().stack(env) {
call_func!(func, env, self);
}
}
fn on_remove(&self) {
if !self.has_capability(&WebAssemblyScriptCapabilities::OnRemove) {
return;
}
let env = &self.environment;
if let Some(func) = env.script_function_cache().on_remove(env) {
call_func!(func, env, self);
}
}
fn on_initialize(&self, library: &DynamicLibrary, pars: &[EffectParameter]) {
if !self.has_capability(&WebAssemblyScriptCapabilities::Initialize) {
return;
}
let env = &self.environment;
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));
}
}
fn on_before_turn(&self, choice: &TurnChoice) {
if !self.has_capability(&WebAssemblyScriptCapabilities::OnBeforeTurn) {
return;
}
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));
}
}
fn change_speed(&self, choice: &TurnChoice, speed: &mut u32) {
if !self.has_capability(&WebAssemblyScriptCapabilities::ChangeSpeed) {
return;
}
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();
}
}
fn change_priority(&self, choice: &TurnChoice, priority: &mut i8) {
if !self.has_capability(&WebAssemblyScriptCapabilities::ChangePriority) {
return;
}
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();
}
}
fn change_move(&self, choice: &TurnChoice, move_name: &mut StringKey) {
if !self.has_capability(&WebAssemblyScriptCapabilities::ChangeMove) {
return;
}
let env = &self.environment;
if let Some(func) = env.script_function_cache().change_move(env) {
let move_ref = ex_ref!(env, move_name);
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).unwrap().clone();
}
}
fn change_number_of_hits(&self, choice: &TurnChoice, number_of_hits: &mut u8) {
if !self.has_capability(&WebAssemblyScriptCapabilities::ChangeNumberOfHits) {
return;
}
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();
}
}
fn prevent_move(&self, mv: &ExecutingMove, prevent: &mut bool) {
if !self.has_capability(&WebAssemblyScriptCapabilities::PreventMove) {
return;
}
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();
}
}
fn fail_move(&self, mv: &ExecutingMove, fail: &mut bool) {
if !self.has_capability(&WebAssemblyScriptCapabilities::FailMove) {
return;
}
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();
}
}
fn stop_before_move(&self, mv: &ExecutingMove, stop: &mut bool) {
if !self.has_capability(&WebAssemblyScriptCapabilities::StopBeforeMove) {
return;
}
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();
}
}
fn on_before_move(&self, mv: &ExecutingMove) {
if !self.has_capability(&WebAssemblyScriptCapabilities::OnBeforeMove) {
return;
}
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));
}
}
fn fail_incoming_move(&self, mv: &ExecutingMove, target: &Arc<Pokemon>, fail: &mut bool) {
if !self.has_capability(&WebAssemblyScriptCapabilities::FailIncomingMove) {
return;
}
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.as_ref()),
ptr.wasm_ptr
);
*fail = *ptr.value();
}
}
fn is_invulnerable(&self, mv: &ExecutingMove, target: &Arc<Pokemon>, invulnerable: &mut bool) {
if !self.has_capability(&WebAssemblyScriptCapabilities::IsInvulnerable) {
return;
}
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.as_ref()),
ptr.wasm_ptr
);
*invulnerable = *ptr.value();
}
}
fn on_move_miss(&self, mv: &ExecutingMove, target: &Arc<Pokemon>) {
if !self.has_capability(&WebAssemblyScriptCapabilities::OnMoveMiss) {
return;
}
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.as_ref()));
}
}
fn change_move_type(&self, mv: &ExecutingMove, target: &Arc<Pokemon>, hit: u8, move_type: &mut TypeIdentifier) {
if !self.has_capability(&WebAssemblyScriptCapabilities::ChangeMoveType) {
return;
}
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 target = target.as_ref();
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();
}
}
fn change_effectiveness(&self, mv: &ExecutingMove, target: &Arc<Pokemon>, hit: u8, effectiveness: &mut f32) {
if !self.has_capability(&WebAssemblyScriptCapabilities::ChangeEffectiveness) {
return;
}
let env = &self.environment;
if let Some(func) = env.script_function_cache().change_effectiveness(env) {
let ptr = env.allocate_temp(*effectiveness);
let target = target.as_ref();
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();
}
}
fn block_critical(&self, mv: &ExecutingMove, target: &Arc<Pokemon>, hit: u8, block_critical: &mut bool) {
if !self.has_capability(&WebAssemblyScriptCapabilities::BlockCritical) {
return;
}
let env = &self.environment;
if let Some(func) = env.script_function_cache().block_critical(env) {
let ptr = env.allocate_temp(*block_critical);
let target = target.as_ref();
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();
}
}
fn block_incoming_critical(&self, mv: &ExecutingMove, target: &Arc<Pokemon>, hit: u8, block_critical: &mut bool) {
if !self.has_capability(&WebAssemblyScriptCapabilities::BlockIncomingCritical) {
return;
}
let env = &self.environment;
if let Some(func) = env.script_function_cache().block_incoming_critical(env) {
let ptr = env.allocate_temp(*block_critical);
let target = target.as_ref();
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();
}
}
fn change_accuracy(&self, mv: &ExecutingMove, target: &Arc<Pokemon>, hit: u8, accuracy: &mut u8) {
if !self.has_capability(&WebAssemblyScriptCapabilities::ChangeAccuracy) {
return;
}
let env = &self.environment;
if let Some(func) = env.script_function_cache().change_accuracy(env) {
let ptr = env.allocate_temp(*accuracy);
let target = target.as_ref();
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();
}
}
fn change_critical_stage(&self, mv: &ExecutingMove, target: &Arc<Pokemon>, hit: u8, stage: &mut u8) {
if !self.has_capability(&WebAssemblyScriptCapabilities::ChangeCriticalStage) {
return;
}
let env = &self.environment;
if let Some(func) = env.script_function_cache().change_critical_stage(env) {
let ptr = env.allocate_temp(*stage);
let target = target.as_ref();
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();
}
}
fn change_critical_modifier(&self, mv: &ExecutingMove, target: &Arc<Pokemon>, hit: u8, modifier: &mut f32) {
if !self.has_capability(&WebAssemblyScriptCapabilities::ChangeCriticalModifier) {
return;
}
let env = &self.environment;
if let Some(func) = env.script_function_cache().change_critical_modifier(env) {
let ptr = env.allocate_temp(*modifier);
let target = target.as_ref();
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();
}
}
fn change_stab_modifier(&self, mv: &ExecutingMove, target: &Arc<Pokemon>, hit: u8, modifier: &mut f32) {
if !self.has_capability(&WebAssemblyScriptCapabilities::ChangeSTABModifier) {
return;
}
let env = &self.environment;
if let Some(func) = env.script_function_cache().change_stab_modifier(env) {
let ptr = env.allocate_temp(*modifier);
let target = target.as_ref();
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();
}
}
fn change_base_power(&self, mv: &ExecutingMove, target: &Arc<Pokemon>, hit: u8, base_power: &mut u8) {
if !self.has_capability(&WebAssemblyScriptCapabilities::ChangeBasePower) {
return;
}
let env = &self.environment;
if let Some(func) = env.script_function_cache().change_base_power(env) {
let ptr = env.allocate_temp(*base_power);
let target = target.as_ref();
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();
}
}
fn bypass_defensive_stat_boost(&self, mv: &ExecutingMove, target: &Arc<Pokemon>, hit: u8, bypass: &mut bool) {
if !self.has_capability(&WebAssemblyScriptCapabilities::BypassDefensiveStat) {
return;
}
let env = &self.environment;
if let Some(func) = env.script_function_cache().bypass_defensive_stat_boost(env) {
let ptr = env.allocate_temp(*bypass);
let target = target.as_ref();
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();
}
}
fn bypass_offensive_stat_boost(&self, mv: &ExecutingMove, target: &Arc<Pokemon>, hit: u8, bypass: &mut bool) {
if !self.has_capability(&WebAssemblyScriptCapabilities::BypassOffensiveStat) {
return;
}
let env = &self.environment;
if let Some(func) = env.script_function_cache().bypass_offensive_stat_boost(env) {
let ptr = env.allocate_temp(*bypass);
let target = target.as_ref();
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();
}
}
fn change_offensive_stat_value(&self, mv: &ExecutingMove, target: &Arc<Pokemon>, hit: u8, amount: &mut u32) {
if !self.has_capability(&WebAssemblyScriptCapabilities::ChangeOffensiveStatValue) {
return;
}
let env = &self.environment;
if let Some(func) = env.script_function_cache().change_offensive_stat_value(env) {
let ptr = env.allocate_temp(*amount);
let target = target.as_ref();
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();
}
}
fn change_defensive_stat_value(&self, mv: &ExecutingMove, target: &Arc<Pokemon>, hit: u8, amount: &mut u32) {
if !self.has_capability(&WebAssemblyScriptCapabilities::ChangeOffensiveStatValue) {
return;
}
let env = &self.environment;
if let Some(func) = env.script_function_cache().change_defensive_stat_value(env) {
let ptr = env.allocate_temp(*amount);
let target = target.as_ref();
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();
}
}
fn change_damage_stat_modifier(&self, mv: &ExecutingMove, target: &Arc<Pokemon>, hit: u8, modifier: &mut f32) {
if !self.has_capability(&WebAssemblyScriptCapabilities::ChangeStatModifier) {
return;
}
let env = &self.environment;
if let Some(func) = env.script_function_cache().change_damage_stat_modifier(env) {
let ptr = env.allocate_temp(*modifier);
let target = target.as_ref();
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();
}
}
fn change_damage_modifier(&self, mv: &ExecutingMove, target: &Arc<Pokemon>, hit: u8, modifier: &mut f32) {
if !self.has_capability(&WebAssemblyScriptCapabilities::ChangeDamageModifier) {
return;
}
let env = &self.environment;
if let Some(func) = env.script_function_cache().change_damage_modifier(env) {
let ptr = env.allocate_temp(*modifier);
let target = target.as_ref();
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();
}
}
fn change_damage(&self, mv: &ExecutingMove, target: &Arc<Pokemon>, hit: u8, damage: &mut u32) {
if !self.has_capability(&WebAssemblyScriptCapabilities::ChangeDamage) {
return;
}
let env = &self.environment;
if let Some(func) = env.script_function_cache().change_damage(env) {
let ptr = env.allocate_temp(*damage);
let target = target.as_ref();
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();
}
}
fn change_incoming_damage(&self, mv: &ExecutingMove, target: &Arc<Pokemon>, hit: u8, damage: &mut u32) {
if !self.has_capability(&WebAssemblyScriptCapabilities::ChangeIncomingDamage) {
return;
}
let env = &self.environment;
if let Some(func) = env.script_function_cache().change_incoming_damage(env) {
let ptr = env.allocate_temp(*damage);
let target = target.as_ref();
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();
}
}
fn on_incoming_hit(&self, mv: &ExecutingMove, target: &Arc<Pokemon>, hit: u8) {
if !self.has_capability(&WebAssemblyScriptCapabilities::OnIncomingHit) {
return;
}
let env = &self.environment;
if let Some(func) = env.script_function_cache().on_incoming_hit(env) {
let target = target.as_ref();
call_func!(func, env, self, ex_ref!(env, mv), ex_ref!(env, target), hit);
}
}
fn on_opponent_faints(&self, mv: &ExecutingMove, target: &Arc<Pokemon>, hit: u8) {
if !self.has_capability(&WebAssemblyScriptCapabilities::OnFaintingOpponent) {
return;
}
let env = &self.environment;
if let Some(func) = env.script_function_cache().on_opponent_faints(env) {
let target = target.as_ref();
call_func!(func, env, self, ex_ref!(env, mv), ex_ref!(env, target), hit);
}
}
fn prevent_stat_boost_change(
&self,
target: &Pokemon,
stat: Statistic,
amount: i8,
self_inflicted: bool,
prevent: &mut bool,
) {
if !self.has_capability(&WebAssemblyScriptCapabilities::PreventStatBoostChange) {
return;
}
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 = if self_inflicted { 1_u8 } else { 0_u8 };
call_func!(
func,
env,
self,
ex_ref!(env, target),
stat as u8,
amount,
self_inflicted,
ptr.wasm_ptr
);
*prevent = *ptr.value();
}
}
fn prevent_secondary_effect(&self, mv: &ExecutingMove, target: &Arc<Pokemon>, hit: u8, prevent: &mut bool) {
if !self.has_capability(&WebAssemblyScriptCapabilities::PreventSecondaryEffects) {
return;
}
let env = &self.environment;
if let Some(func) = env.script_function_cache().prevent_secondary_effect(env) {
let ptr = env.allocate_temp(*prevent);
let target = target.as_ref();
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();
}
}
fn change_effect_chance(&self, mv: &ExecutingMove, target: &Arc<Pokemon>, hit: u8, chance: &mut f32) {
if !self.has_capability(&WebAssemblyScriptCapabilities::ChangeEffectChance) {
return;
}
let env = &self.environment;
if let Some(func) = env.script_function_cache().change_effect_chance(env) {
let ptr = env.allocate_temp(*chance);
let target = target.as_ref();
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();
}
}
fn change_incoming_effect_chance(&self, mv: &ExecutingMove, target: &Arc<Pokemon>, hit: u8, chance: &mut f32) {
if !self.has_capability(&WebAssemblyScriptCapabilities::ChangeIncomingEffectChance) {
return;
}
let env = &self.environment;
if let Some(func) = env.script_function_cache().change_incoming_effect_chance(env) {
let ptr = env.allocate_temp(*chance);
let target = target.as_ref();
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();
}
}
fn on_secondary_effect(&self, mv: &ExecutingMove, target: &Arc<Pokemon>, hit: u8) {
if !self.has_capability(&WebAssemblyScriptCapabilities::OnFaintingOpponent) {
return;
}
let env = &self.environment;
if let Some(func) = env.script_function_cache().on_secondary_effect(env) {
let target = target.as_ref();
call_func!(func, env, self, ex_ref!(env, mv), ex_ref!(env, target), hit);
}
}
fn on_after_hits(&self, mv: &ExecutingMove, target: &Arc<Pokemon>) {
if !self.has_capability(&WebAssemblyScriptCapabilities::OnAfterHits) {
return;
}
let env = &self.environment;
if let Some(func) = env.script_function_cache().on_after_hits(env) {
let target = target.as_ref();
call_func!(func, env, self, ex_ref!(env, mv), ex_ref!(env, target));
}
}
fn prevent_self_switch(&self, choice: &TurnChoice, prevent: &mut bool) {
if !self.has_capability(&WebAssemblyScriptCapabilities::PreventSelfSwitch) {
return;
}
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();
}
}
fn prevent_opponent_switch(&self, choice: &TurnChoice, prevent: &mut bool) {
if !self.has_capability(&WebAssemblyScriptCapabilities::PreventSelfSwitch) {
return;
}
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();
}
}
fn on_fail(&self, pokemon: &Pokemon) {
if !self.has_capability(&WebAssemblyScriptCapabilities::OnFail) {
return;
}
let env = &self.environment;
if let Some(func) = env.script_function_cache().on_fail(env) {
call_func!(func, env, self, ex_ref!(env, pokemon));
}
}
fn on_opponent_fail(&self, pokemon: &Pokemon) {
if !self.has_capability(&WebAssemblyScriptCapabilities::OnFail) {
return;
}
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));
}
}
fn prevent_self_run_away(&self, choice: &TurnChoice, prevent: &mut bool) {
if !self.has_capability(&WebAssemblyScriptCapabilities::PreventSelfRunAway) {
return;
}
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();
}
}
fn prevent_opponent_run_away(&self, choice: &TurnChoice, prevent: &mut bool) {
if !self.has_capability(&WebAssemblyScriptCapabilities::PreventOpponentRunAway) {
return;
}
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();
}
}
fn on_end_turn(&self) {
if !self.has_capability(&WebAssemblyScriptCapabilities::OnEndTurn) {
return;
}
let env = &self.environment;
if let Some(func) = env.script_function_cache().on_end_turn(env) {
call_func!(func, env, self);
}
}
fn on_damage(&self, pokemon: &Pokemon, source: DamageSource, old_health: u32, new_health: u32) {
if !self.has_capability(&WebAssemblyScriptCapabilities::OnDamage) {
return;
}
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);
}
}
fn on_faint(&self, pokemon: &Pokemon, source: DamageSource) {
if !self.has_capability(&WebAssemblyScriptCapabilities::OnFaint) {
return;
}
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);
}
}
fn on_switch_in(&self, pokemon: &Pokemon) {
if !self.has_capability(&WebAssemblyScriptCapabilities::OnSwitchIn) {
return;
}
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));
}
}
fn on_after_held_item_consume(&self, pokemon: &Pokemon, item: &Item) {
if !self.has_capability(&WebAssemblyScriptCapabilities::OnAfterHeldItemConsume) {
return;
}
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));
}
}
fn change_experience_gained(&self, fainted_mon: &Pokemon, winning_mon: &Pokemon, amount: &mut u32) {
if !self.has_capability(&WebAssemblyScriptCapabilities::ChangeExperienceGain) {
return;
}
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();
}
}
fn share_experience(&self, fainted_mon: &Pokemon, winning_mon: &Pokemon, shares: &mut bool) {
if !self.has_capability(&WebAssemblyScriptCapabilities::DoesShareExperience) {
return;
}
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();
}
}
fn block_weather(&self, battle: &Battle, blocked: &mut bool) {
if !self.has_capability(&WebAssemblyScriptCapabilities::BlockWeather) {
return;
}
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();
}
}
fn change_capture_rate_bonus(&self, target: &Pokemon, pokeball: &Item, modifier: &mut u8) {
if !self.has_capability(&WebAssemblyScriptCapabilities::ChangeCaptureRate) {
return;
}
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();
}
}
fn as_any(&self) -> &dyn Any {
self
}
fn as_any_mut(&mut self) -> &mut dyn Any {
self
}
}