966 lines
35 KiB
Rust
Executable File
966 lines
35 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::{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,
|
|
}
|
|
}
|
|
|
|
/// 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<EffectParameter>>) -> 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::<EffectParameter>::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 target = target;
|
|
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 target = target;
|
|
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 target = target;
|
|
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 target = target;
|
|
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 target = target;
|
|
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 target = target;
|
|
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 target = target;
|
|
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 target = target;
|
|
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 target = target;
|
|
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 target = target;
|
|
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 target = target;
|
|
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 target = target;
|
|
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 target = target;
|
|
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 target = target;
|
|
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 target = target;
|
|
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 target = target;
|
|
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 target = target;
|
|
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) {
|
|
let target = target;
|
|
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) {
|
|
let target = target;
|
|
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 target = target;
|
|
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 target = target;
|
|
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 target = target;
|
|
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) {
|
|
let target = target;
|
|
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) {
|
|
let target = target;
|
|
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
|
|
}
|
|
}
|