Implements first few actual move effects.

This commit is contained in:
Deukhoofd 2022-08-28 15:50:12 +02:00
parent 98130706fb
commit 05430c5e84
Signed by: Deukhoofd
GPG Key ID: F63E044490819F6F
38 changed files with 1539 additions and 355 deletions

View File

@ -1,5 +1,6 @@
[workspace]
edition = "2021"
resolver = "2"
members = [
"pkmn_lib_interface",

View File

@ -12,7 +12,8 @@ use pkmn_lib_interface::set_load_script_fn;
#[macro_use]
pub mod registered_scripts;
pub mod test_script;
pub mod moves;
pub mod util_scripts;
#[no_mangle]
#[cfg(not(test))]

View File

@ -0,0 +1,40 @@
use pkmn_lib_interface::app_interface::{ExecutingMove, Pokemon};
use pkmn_lib_interface::handling::{Script, ScriptCapabilities};
pub struct Acrobatics {}
impl Acrobatics {
pub const fn get_const_name() -> &'static str {
"acrobatics"
}
}
impl Script for Acrobatics {
fn new() -> Self {
Self {}
}
fn get_name() -> &'static str {
Self::get_const_name()
}
fn get_capabilities(&self) -> &[ScriptCapabilities] {
&[ScriptCapabilities::ChangeBasePower]
}
fn change_base_power(
&self,
mv: ExecutingMove,
_target: Pokemon,
_hit: u8,
base_power: &mut u8,
) {
if mv.user().held_item().is_none() {
if *base_power >= 128_u8 {
*base_power = 255
} else {
*base_power *= 2;
}
}
}
}

View File

@ -0,0 +1,35 @@
use core::mem::transmute;
use pkmn_lib_interface::app_interface::{ExecutingMove, Pokemon, Statistic};
use pkmn_lib_interface::handling::{Script, ScriptCapabilities};
pub struct Acupressure {}
impl Acupressure {
pub const fn get_const_name() -> &'static str {
"acupressure"
}
}
impl Script for Acupressure {
fn new() -> Self {
Self {}
}
fn get_name() -> &'static str {
Self::get_const_name()
}
fn get_capabilities(&self) -> &[ScriptCapabilities] {
&[ScriptCapabilities::OnSecondaryEffect]
}
fn on_secondary_effect(&self, mv: ExecutingMove, target: Pokemon, hit: u8) {
if target == mv.user() {
mv.get_hit_data(&target, hit).fail();
return;
}
let rand_stat: Statistic =
unsafe { transmute(target.battle().unwrap().random().get_between(1, 6) as u8) };
target.change_stat_boost(rand_stat, 2, false);
}
}

View File

@ -0,0 +1,35 @@
use pkmn_lib_interface::app_interface::{ExecutingMove, Pokemon};
use pkmn_lib_interface::handling::{Script, ScriptCapabilities};
pub struct AfterYou {}
impl AfterYou {
pub const fn get_const_name() -> &'static str {
"after_you"
}
}
impl Script for AfterYou {
fn new() -> Self {
Self {}
}
fn get_name() -> &'static str {
Self::get_const_name()
}
fn get_capabilities(&self) -> &[ScriptCapabilities] {
&[ScriptCapabilities::OnSecondaryEffect]
}
fn on_secondary_effect(&self, mv: ExecutingMove, target: Pokemon, hit: u8) {
if !target
.battle()
.unwrap()
.choice_queue()
.move_pokemon_choice_next(&target)
{
mv.get_hit_data(&target, hit).fail()
}
}
}

View File

@ -0,0 +1,4 @@
pub mod acrobatics;
pub mod acupressure;
pub mod after_you;
pub mod multi_hit_move;

View File

@ -0,0 +1,37 @@
use pkmn_lib_interface::app_interface::TurnChoice;
use pkmn_lib_interface::handling::{Script, ScriptCapabilities};
pub struct MultiHitMove {}
impl MultiHitMove {
pub const fn get_const_name() -> &'static str {
"2_5_hit_move"
}
}
impl Script for MultiHitMove {
fn new() -> Self {
Self {}
}
fn get_name() -> &'static str {
Self::get_const_name()
}
fn get_capabilities(&self) -> &[ScriptCapabilities] {
&[ScriptCapabilities::ChangeNumberOfHits]
}
fn change_number_of_hits(&self, choice: TurnChoice, number_of_hits: &mut u8) {
// 35% chance that it will hit 2 times, a 35% chance it will hit 3 times, a 15% chance it
// will hit 4 times, and a 15% chance it will hit 5 times.
let rand_value = choice.user().battle().unwrap().random().get_between(0, 100);
*number_of_hits = match rand_value {
0..=34 => 2,
35..=69 => 3,
70..=84 => 4,
85..=100 => 5,
_ => *number_of_hits,
}
}
}

View File

@ -1,19 +1,19 @@
use crate::test_script::TestScript;
use crate::moves::*;
use alloc::boxed::Box;
use pkmn_lib_interface::app_interface::{get_hash_const, StringKey};
use pkmn_lib_interface::app_interface::{get_hash, StringKey};
use pkmn_lib_interface::handling::{Script, ScriptCategory};
macro_rules! resolve_match {
(
$mid:expr,
$(
$key:expr => $script:ident,
$script:ty,
)*
) => (
match $mid {
$(
const { get_hash_const($key) } => {
return Some(Box::new($script {}))
const { get_hash(<$script>::get_const_name()) } => {
return Some(Box::new(<$script>::new()))
}
)*
_ => {}
@ -26,13 +26,18 @@ pub fn get_script(category: ScriptCategory, name: &StringKey) -> Option<Box<dyn
ScriptCategory::Move => {
resolve_match!(
name.hash(),
b"test" => TestScript,
acrobatics::Acrobatics,
acupressure::Acupressure,
after_you::AfterYou,
multi_hit_move::MultiHitMove,
);
}
ScriptCategory::Ability => {}
ScriptCategory::Status => {}
ScriptCategory::Pokemon => {}
ScriptCategory::Battle => {}
ScriptCategory::Battle => {
resolve_match!(name.hash(), crate::util_scripts::ForceEffectTriggerScript,)
}
ScriptCategory::Side => {}
ScriptCategory::ItemBattleTrigger => {}
}

View File

@ -1,102 +0,0 @@
use pkmn_lib_interface::app_interface::list::ImmutableList;
use pkmn_lib_interface::app_interface::{
get_hash_const, DamageSource, DataLibrary, DynamicLibrary, EffectParameter, TurnChoice,
};
use pkmn_lib_interface::dbg;
use pkmn_lib_interface::handling::{Script, ScriptCapabilities};
pub struct TestScript {}
impl Script for TestScript {
fn new() -> Self {
TestScript {}
}
fn destroy(&self) {}
fn get_name(&self) -> &str {
"TestScript"
}
fn get_capabilities(&self) -> &[ScriptCapabilities] {
&[
ScriptCapabilities::Initialize,
ScriptCapabilities::OnBeforeTurn,
]
}
fn on_initialize(
&self,
library: &DynamicLibrary,
parameters: Option<ImmutableList<EffectParameter>>,
) {
let l = library.data_library();
let ml = l.move_library();
let m = ml.get_by_hash(const { get_hash_const(b"tackle") }).unwrap();
dbg!("found move!");
dbg!("{:?} has {} base power", m.name().str(), m.base_power());
dbg!(
"Found a parameter with value: {}",
parameters.unwrap().get(0).unwrap()
);
}
fn on_before_turn(&self, choice: TurnChoice) {
dbg!(
"On before turn for user: {}",
choice.user().species().name()
);
// choice.user().damage(50, DamageSource::Misc);
if let TurnChoice::Move(d) = choice {
dbg!(
"On before turn for move choice: {}",
d.used_move().move_data().name()
);
}
}
}
#[cfg(test)]
mod test {
use super::*;
use pkmn_lib_interface::app_interface::move_library::MoveLibrary;
use pkmn_lib_interface::app_interface::species_library::SpeciesLibrary;
use pkmn_lib_interface::app_interface::type_library::TypeLibrary;
use pkmn_lib_interface::app_interface::{
Item, ItemLibrary, LibrarySettings, MoveCategory, MoveData, MoveTarget, StaticData,
};
use pkmn_lib_interface::handling::Script;
#[test]
fn test_foo() {
let item = Item::mock();
assert_eq!(item.name().str().to_str().unwrap(), "test");
let script = TestScript::new();
assert_eq!(script.get_name(), "TestScript");
let lib = DynamicLibrary::new(StaticData::mock(
MoveLibrary::mock(),
ItemLibrary::mock(),
SpeciesLibrary::mock(),
TypeLibrary::mock(),
LibrarySettings::mock(100),
));
lib.data_library().move_library().insert(
const { get_hash_const(b"tackle") },
MoveData::mock(
"tackle",
0,
MoveCategory::Physical,
60,
100,
10,
MoveTarget::Adjacent,
0,
),
);
script.on_initialize(
&lib,
Some(ImmutableList::mock((&[EffectParameter::Int(100)]).to_vec())),
);
}
}

View File

@ -0,0 +1,35 @@
use pkmn_lib_interface::app_interface::{ExecutingMove, Pokemon};
use pkmn_lib_interface::handling::{Script, ScriptCapabilities};
pub struct ForceEffectTriggerScript {}
impl ForceEffectTriggerScript {
pub const fn get_const_name() -> &'static str {
"force_effect_trigger"
}
}
impl Script for ForceEffectTriggerScript {
fn new() -> Self {
Self {}
}
fn get_name() -> &'static str {
Self::get_const_name()
}
fn get_capabilities(&self) -> &[ScriptCapabilities] {
&[ScriptCapabilities::ChangeEffectChance]
}
fn change_effect_chance(
&self,
_mv: ExecutingMove,
_target: Pokemon,
_hit: u8,
chance: &mut f32,
) {
// Set to 50_000% chance.
*chance = 50_000.0;
}
}

View File

@ -0,0 +1,3 @@
mod force_effect_trigger;
pub use force_effect_trigger::*;

View File

@ -10,10 +10,10 @@ mock_data = []
[dependencies]
wee_alloc = "0.4.5"
cstr_core = { version = "0.2.6", features = ["nightly"]}
lazy_static = { version = "1.4.0", features = ["spin_no_std"] }
enumflags2 = { version = "0.7.5", default-features = false }
spin = { version = "0.9.4", default-features = false, features = ["rwlock"] }
paste = { version = "1.0.7" }
hashbrown = { version = "0.12.3" }
[dev-dependencies]

View File

@ -1,4 +1,4 @@
use crate::app_interface::{BattleParty, BattleRandom, BattleSide, Pokemon};
use crate::app_interface::{BattleParty, BattleRandom, BattleSide, ChoiceQueue, Pokemon};
use crate::handling::cached_value::CachedValue;
use crate::handling::Cacheable;
use crate::{
@ -13,6 +13,7 @@ struct BattleInner {
parties: CachedValue<ImmutableList<BattleParty>>,
sides: CachedValue<ImmutableList<BattleSide>>,
random: CachedValue<BattleRandom>,
choice_queue: CachedValue<ChoiceQueue>,
}
#[derive(Clone)]
@ -30,6 +31,9 @@ impl Battle {
parties: cached_value!({ battle_get_parties(reference).get_immutable_list() }),
sides: cached_value!({ battle_get_sides(reference).get_immutable_list() }),
random: cached_value!({ battle_get_random(reference).get_value().unwrap() }),
choice_queue: cached_value!({
battle_get_choice_queue(reference).get_value().unwrap()
}),
}),
})
}
@ -38,6 +42,8 @@ impl Battle {
pub fn library(&self) -> DynamicLibrary;
pub fn parties(&self) -> ImmutableList<BattleParty>;
pub fn sides(&self) -> ImmutableList<BattleSide>;
pub fn random(&self) -> BattleRandom;
pub fn choice_queue(&self) -> ChoiceQueue;
}
#[cfg(not(feature = "mock_data"))]
@ -72,5 +78,6 @@ extern "wasm" {
fn battle_get_parties(r: ExternRef<Battle>) -> VecExternRef<BattleParty>;
fn battle_get_sides(r: ExternRef<Battle>) -> VecExternRef<BattleSide>;
fn battle_get_random(r: ExternRef<Battle>) -> ExternRef<BattleRandom>;
fn battle_get_choice_queue(r: ExternRef<Battle>) -> ExternRef<ChoiceQueue>;
fn battle_get_pokemon(r: ExternRef<Battle>, side: u8, index: u8) -> ExternRef<Pokemon>;
}

View File

@ -39,7 +39,6 @@ impl ExternalReferenceType for BattleParty {
}
}
#[cfg(not(feature = "mock_data"))]
extern "wasm" {
fn battle_party_get_party(r: ExternRef<BattleParty>) -> ExternRef<Party>;

View File

@ -0,0 +1,31 @@
use crate::{ExternRef, ExternalReferenceType, Pokemon};
#[derive(Clone)]
pub struct ChoiceQueue {
reference: ExternRef<ChoiceQueue>,
}
impl ChoiceQueue {
#[cfg(not(feature = "mock_data"))]
pub fn new(reference: ExternRef<ChoiceQueue>) -> Self {
Self { reference }
}
pub fn move_pokemon_choice_next(&self, pokemon: &Pokemon) -> bool {
unsafe { choice_queue_move_pokemon_choice_next(self.reference, pokemon.reference()) }
}
}
#[cfg(not(feature = "mock_data"))]
impl ExternalReferenceType for ChoiceQueue {
fn from_extern_value(reference: ExternRef<Self>) -> Self {
Self::new(reference)
}
}
extern "wasm" {
fn choice_queue_move_pokemon_choice_next(
r: ExternRef<ChoiceQueue>,
pokemon: ExternRef<Pokemon>,
) -> bool;
}

View File

@ -0,0 +1,161 @@
use crate::app_interface::{LearnedMove, MoveData, Pokemon};
use crate::handling::cached_value::CachedValue;
use crate::handling::temporary::Temporary;
use crate::{cached_value, ExternRef, ExternalReferenceType, Script};
struct ExecutingMoveInner {
reference: ExternRef<ExecutingMove>,
number_of_hits: CachedValue<u8>,
user: CachedValue<Pokemon>,
chosen_move: CachedValue<LearnedMove>,
use_move: CachedValue<MoveData>,
}
#[derive(Clone)]
pub struct ExecutingMove {
inner: Temporary<ExecutingMoveInner>,
}
impl ExecutingMove {
pub(crate) fn new(reference: ExternRef<ExecutingMove>) -> Self {
Self {
inner: Temporary::new(
reference.get_internal_index(),
ExecutingMoveInner {
reference,
number_of_hits: cached_value!({ executing_move_get_number_of_hits(reference) }),
user: cached_value!({
executing_move_get_user(reference).get_value().unwrap()
}),
chosen_move: cached_value!({
executing_move_get_chosen_move(reference)
.get_value()
.unwrap()
}),
use_move: cached_value!({
executing_move_get_use_move(reference).get_value().unwrap()
}),
},
),
}
}
pub fn number_of_hits(&self) -> u8 {
self.inner.value().number_of_hits.value()
}
pub fn user(&self) -> Pokemon {
self.inner.value().user.value()
}
pub fn chosen_move(&self) -> LearnedMove {
self.inner.value().chosen_move.value()
}
pub fn use_move(&self) -> MoveData {
self.inner.value().use_move.value()
}
pub fn move_script(&self) -> Option<&dyn Script> {
unsafe { executing_move_get_script(self.inner.value().reference).as_ref() }
}
pub fn number_of_targets(&self) -> usize {
unsafe { executing_move_get_number_of_targets(self.inner.value().reference) }
}
pub fn is_pokemon_target(&self, pokemon: &Pokemon) -> bool {
unsafe {
executing_move_is_pokemon_target(self.inner.value().reference, pokemon.reference())
}
}
pub fn get_hit_data(&self, pokemon: &Pokemon, hit: u8) -> HitData {
unsafe {
executing_move_get_hit_data(self.inner.value().reference, pokemon.reference(), hit)
.get_value()
.unwrap()
}
}
}
#[derive(Clone)]
pub struct HitData {
reference: ExternRef<HitData>,
}
impl HitData {
pub fn is_critical(&self) -> bool {
unsafe { hit_data_is_critical(self.reference) }
}
pub fn base_power(&self) -> u8 {
unsafe { hit_data_get_base_power(self.reference) }
}
pub fn effectiveness(&self) -> f32 {
unsafe { hit_data_get_effectiveness(self.reference) }
}
pub fn damage(&self) -> u32 {
unsafe { hit_data_get_damage(self.reference) }
}
pub fn move_type(&self) -> u8 {
unsafe { hit_data_get_move_type(self.reference) }
}
pub fn has_failed(&self) -> bool {
unsafe { hit_data_is_critical(self.reference) }
}
pub fn set_critical(&self, critical: bool) {
unsafe { hit_data_set_critical(self.reference, critical) }
}
pub fn set_effectiveness(&self, effectiveness: f32) {
unsafe { hit_data_set_effectiveness(self.reference, effectiveness) }
}
pub fn set_damage(&self, damage: u32) {
unsafe { hit_data_set_damage(self.reference, damage) }
}
pub fn set_move_type(&self, move_type: u8) {
unsafe { hit_data_set_move_type(self.reference, move_type) }
}
pub fn fail(&self) {
unsafe { hit_data_fail(self.reference) }
}
}
impl ExternalReferenceType for ExecutingMove {
fn from_extern_value(reference: ExternRef<Self>) -> Self {
Self::new(reference)
}
}
impl ExternalReferenceType for HitData {
fn from_extern_value(reference: ExternRef<Self>) -> Self {
Self { reference }
}
}
extern "wasm" {
fn executing_move_get_number_of_targets(r: ExternRef<ExecutingMove>) -> usize;
fn executing_move_get_number_of_hits(r: ExternRef<ExecutingMove>) -> u8;
fn executing_move_get_user(r: ExternRef<ExecutingMove>) -> ExternRef<Pokemon>;
fn executing_move_get_chosen_move(r: ExternRef<ExecutingMove>) -> ExternRef<LearnedMove>;
fn executing_move_get_use_move(r: ExternRef<ExecutingMove>) -> ExternRef<MoveData>;
#[allow(improper_ctypes)]
fn executing_move_get_script(r: ExternRef<ExecutingMove>) -> *const dyn Script;
fn executing_move_is_pokemon_target(
r: ExternRef<ExecutingMove>,
pokemon: ExternRef<Pokemon>,
) -> bool;
fn executing_move_get_hit_data(
r: ExternRef<ExecutingMove>,
target: ExternRef<Pokemon>,
hit: u8,
) -> ExternRef<HitData>;
fn hit_data_is_critical(r: ExternRef<HitData>) -> bool;
fn hit_data_get_base_power(r: ExternRef<HitData>) -> u8;
fn hit_data_get_effectiveness(r: ExternRef<HitData>) -> f32;
fn hit_data_get_damage(r: ExternRef<HitData>) -> u32;
fn hit_data_get_move_type(r: ExternRef<HitData>) -> u8;
fn hit_data_has_failed(r: ExternRef<HitData>) -> bool;
fn hit_data_set_critical(r: ExternRef<HitData>, critical: bool);
fn hit_data_set_base_power(r: ExternRef<HitData>, power: u8);
fn hit_data_set_effectiveness(r: ExternRef<HitData>, effectiveness: f32);
fn hit_data_set_damage(r: ExternRef<HitData>, damage: u32);
fn hit_data_set_move_type(r: ExternRef<HitData>, move_type: u8);
fn hit_data_fail(r: ExternRef<HitData>);
}

View File

@ -2,7 +2,9 @@ mod battle;
mod battle_party;
mod battle_random;
mod battle_side;
mod choice_queue;
mod dynamic_library;
mod executing_move;
mod learned_move;
mod party;
mod pokemon;
@ -13,7 +15,9 @@ pub use battle::*;
pub use battle_party::*;
pub use battle_random::*;
pub use battle_side::*;
pub use choice_queue::*;
pub use dynamic_library::DynamicLibrary;
pub use executing_move::*;
pub use learned_move::*;
pub use party::*;
pub use pokemon::*;

View File

@ -7,7 +7,7 @@ use crate::handling::cached_value::CachedValue;
use crate::handling::Cacheable;
use crate::{
cached_value, cached_value_getters, wasm_optional_reference_getters, wasm_reference_getters,
wasm_value_getters, DynamicLibrary, ExternRef, ExternalReferenceType, Script,
wasm_value_getters, DynamicLibrary, ExternRef, ExternalReferenceType, Script, TypeIdentifier,
};
use alloc::boxed::Box;
use alloc::rc::Rc;
@ -61,6 +61,10 @@ impl Pokemon {
})
}
pub(crate) fn reference(&self) -> ExternRef<Self> {
self.inner.reference
}
cached_value_getters! {
pub fn library(&self) -> DynamicLibrary;
pub fn flat_stats(&self) -> StatisticSet<u32>;
@ -101,8 +105,8 @@ impl Pokemon {
unsafe { pokemon_get_type(self.inner.reference, index) }
}
#[cfg(not(feature = "mock_data"))]
pub fn has_type(&self, type_identifier: u8) -> bool {
unsafe { pokemon_has_type(self.inner.reference, type_identifier) }
pub fn has_type(&self, type_identifier: TypeIdentifier) -> bool {
unsafe { pokemon_has_type(self.inner.reference, type_identifier.into()) }
}
#[cfg(not(feature = "mock_data"))]
pub fn has_type_by_name(&self, type_name: &str) -> bool {
@ -206,6 +210,12 @@ wasm_value_getters! {
pub fn is_usable(&self) -> bool;
}
impl PartialEq for Pokemon {
fn eq(&self, other: &Self) -> bool {
self.inner.reference == other.inner.reference
}
}
/// A source of damage. This should be as unique as possible.
#[derive(Debug, Clone, Copy)]
#[repr(u8)]
@ -246,6 +256,7 @@ extern "wasm" {
diff_amount: i8,
self_inflicted: bool,
) -> bool;
#[allow(improper_ctypes)]
fn pokemon_get_ability_script(r: ExternRef<Pokemon>) -> *const Box<dyn Script>;
fn pokemon_change_species(
r: ExternRef<Pokemon>,

View File

@ -3,10 +3,9 @@ use crate::handling::cached_value::CachedValue;
use crate::handling::temporary::Temporary;
use crate::ExternRef;
#[cfg(not(feature = "mock_data"))]
use crate::{cached_value, wasm_value_getters, ExternalReferenceType, Script};
use crate::{cached_value, ExternalReferenceType, Script};
#[cfg(not(feature = "mock_data"))]
use alloc::boxed::Box;
use alloc::rc::Rc;
struct BaseTurnChoiceData {
reference: ExternRef<TurnChoice>,
@ -19,12 +18,10 @@ struct MoveTurnChoiceDataInner {
target_side: CachedValue<u8>,
target_index: CachedValue<u8>,
}
#[derive(Clone)]
struct MoveTurnChoiceDataTemporary {
inner: Rc<MoveTurnChoiceDataInner>,
}
pub struct MoveTurnChoiceData {
temp: Temporary<MoveTurnChoiceDataTemporary>,
inner: Temporary<MoveTurnChoiceDataInner>,
}
pub enum TurnChoice {
@ -38,7 +35,7 @@ pub enum TurnChoice {
impl TurnChoice {
fn base(&self) -> &BaseTurnChoiceData {
match self {
TurnChoice::Move(d) => &d.temp.value_ref().inner.base,
TurnChoice::Move(d) => &d.inner.value_ref().base,
TurnChoice::Item() => unimplemented!(),
TurnChoice::Switch() => unimplemented!(),
TurnChoice::Flee => unimplemented!(),
@ -68,22 +65,22 @@ impl TurnChoice {
impl MoveTurnChoiceData {
pub fn used_move(&self) -> LearnedMove {
self.temp.value().inner.used_move.value()
self.inner.value().used_move.value()
}
pub fn target_side(&self) -> u8 {
self.temp.value().inner.target_side.value()
self.inner.value().target_side.value()
}
pub fn target_index(&self) -> u8 {
self.temp.value().inner.target_index.value()
self.inner.value().target_index.value()
}
#[cfg(not(feature = "mock_data"))]
pub fn priority(&self) -> i8 {
unsafe { turn_choice_move_priority(self.temp.value().inner.base.reference.cast()) }
unsafe { turn_choice_move_priority(self.inner.value().base.reference.cast()) }
}
#[cfg(not(feature = "mock_data"))]
pub fn move_script(&self) -> Option<&Box<dyn Script>> {
unsafe { turn_choice_move_script(self.temp.value().inner.base.reference.cast()).as_ref() }
unsafe { turn_choice_move_script(self.inner.value().base.reference.cast()).as_ref() }
}
}
@ -93,7 +90,10 @@ impl ExternalReferenceType for TurnChoice {
let kind = unsafe { turn_choice_get_kind(reference) };
match kind {
0 => TurnChoice::Move(MoveTurnChoiceData {
temp: Temporary::from_reference(reference.cast()),
inner: Temporary::new(
reference.get_internal_index(),
MoveTurnChoiceDataInner::from_reference(reference.cast()),
),
}),
_ => panic!("Unknown turn choice type"),
}
@ -101,10 +101,9 @@ impl ExternalReferenceType for TurnChoice {
}
#[cfg(not(feature = "mock_data"))]
impl ExternalReferenceType for MoveTurnChoiceDataTemporary {
fn from_extern_value(reference: ExternRef<Self>) -> Self {
impl MoveTurnChoiceDataInner {
fn from_reference(reference: ExternRef<MoveTurnChoiceData>) -> Self {
Self {
inner: Rc::new(MoveTurnChoiceDataInner {
base: BaseTurnChoiceData {
reference: reference.cast(),
user: cached_value!({
@ -118,7 +117,6 @@ impl ExternalReferenceType for MoveTurnChoiceDataTemporary {
}),
target_side: cached_value!({ turn_choice_move_target_side(reference.cast()) }),
target_index: cached_value!({ turn_choice_move_target_index(reference.cast()) }),
}),
}
}
}
@ -135,14 +133,6 @@ extern "wasm" {
fn turn_choice_move_target_side(r: ExternRef<MoveTurnChoiceData>) -> u8;
fn turn_choice_move_target_index(r: ExternRef<MoveTurnChoiceData>) -> u8;
fn turn_choice_move_priority(r: ExternRef<MoveTurnChoiceData>) -> i8;
#[allow(improper_ctypes)]
fn turn_choice_move_script(r: ExternRef<MoveTurnChoiceData>) -> *const Box<dyn Script>;
}
#[no_mangle]
#[cfg(not(feature = "mock_data"))]
unsafe extern "wasm" fn turn_choice_mark_deleted(r: ExternRef<TurnChoice>, kind: u8) {
match kind {
0 => Temporary::<MoveTurnChoiceDataTemporary>::mark_as_deleted(r.cast()),
_ => panic!("Unknown turn choice type"),
}
}

View File

@ -1,6 +1,6 @@
use crate::{ExternalReferenceType, VecExternRef};
use alloc::boxed::Box;
use alloc::collections::BTreeMap;
#[cfg(feature = "mock_data")]
use alloc::rc::Rc;
use alloc::vec::Vec;
use core::marker::PhantomData;
@ -44,13 +44,22 @@ where
pub(crate) fn from_ref(extern_ref: VecExternRef<T>) -> Self {
unsafe {
let existing = CACHE.get(&extern_ref.get_internal_index());
if let None = CACHE {
CACHE = Some(hashbrown::HashMap::new());
}
let existing = CACHE
.as_ref()
.unwrap()
.get(&extern_ref.get_internal_index());
if let Some(v) = existing {
let inner = *v as *const ImmutableListInner<T>;
ImmutableList { inner }
} else {
let v = Self::new(extern_ref);
CACHE.insert(extern_ref.get_internal_index(), v.inner as *const u8);
CACHE
.as_mut()
.unwrap()
.insert(extern_ref.get_internal_index(), v.inner as *const u8);
v
}
}
@ -102,4 +111,4 @@ where
}
}
static mut CACHE: BTreeMap<u32, *const u8> = BTreeMap::new();
static mut CACHE: Option<hashbrown::HashMap<u32, *const u8>> = None;

View File

@ -5,5 +5,4 @@ pub mod string_key;
pub use dynamic_data::*;
pub use static_data::*;
pub use string_key::get_hash_const;
pub use string_key::StringKey;
pub use string_key::*;

View File

@ -1,12 +1,11 @@
use crate::app_interface::{DataLibrary, Item};
use crate::{ExternRef, ExternalReferenceType, StringKey};
use alloc::collections::BTreeMap;
use alloc::rc::Rc;
use spin::rwlock::RwLock;
struct ItemLibraryInner {
ptr: ExternRef<ItemLibrary>,
cache: RwLock<BTreeMap<u32, Item>>,
cache: RwLock<hashbrown::HashMap<u32, Item>>,
}
#[derive(Clone)]
@ -27,7 +26,7 @@ impl ItemLibrary {
}
impl DataLibrary<Item> for ItemLibrary {
fn get_cache(&self) -> &spin::rwlock::RwLock<BTreeMap<u32, Item>> {
fn get_cache(&self) -> &spin::rwlock::RwLock<hashbrown::HashMap<u32, Item>> {
&self.inner.cache
}

View File

@ -1,5 +1,4 @@
use crate::{cached_value, cached_value_getters, ExternRef, ExternalReferenceType, StringKey};
use alloc::collections::BTreeMap;
use alloc::rc::Rc;
use move_library::MoveLibrary;
use spin::rwlock::RwLock;
@ -51,6 +50,11 @@ impl StaticData {
type_library: cached_value!({
static_data_get_type_library(reference).get_value().unwrap()
}),
settings: cached_value!({
static_data_get_library_settings(reference)
.get_value()
.unwrap()
}),
}),
})
}
@ -88,7 +92,7 @@ crate::handling::cacheable::cacheable!(StaticData);
#[cfg(not(feature = "mock_data"))]
impl ExternalReferenceType for StaticData {
fn from_extern_value(reference: ExternRef<Self>) -> Self {
StaticData::mock(reference)
StaticData::new(reference)
}
}
@ -125,12 +129,20 @@ impl LibrarySettings {
}
}
#[cfg(not(feature = "mock_data"))]
impl ExternalReferenceType for LibrarySettings {
fn from_extern_value(reference: ExternRef<Self>) -> Self {
LibrarySettings::new(reference)
}
}
#[cfg(not(feature = "mock_data"))]
extern "wasm" {
fn static_data_get_move_library(ptr: ExternRef<StaticData>) -> ExternRef<MoveLibrary>;
fn static_data_get_item_library(ptr: ExternRef<StaticData>) -> ExternRef<ItemLibrary>;
fn static_data_get_species_library(ptr: ExternRef<StaticData>) -> ExternRef<SpeciesLibrary>;
fn static_data_get_type_library(ptr: ExternRef<StaticData>) -> ExternRef<TypeLibrary>;
fn static_data_get_library_settings(ptr: ExternRef<StaticData>) -> ExternRef<LibrarySettings>;
fn library_settings_get_maximum_level(ptr: ExternRef<LibrarySettings>) -> LevelInt;
}
@ -141,7 +153,7 @@ where
T: ExternalReferenceType,
T: Clone,
{
fn get_cache(&self) -> &RwLock<BTreeMap<u32, T>>;
fn get_cache(&self) -> &RwLock<hashbrown::HashMap<u32, T>>;
fn get_self_ref(&self) -> ExternRef<Self>
where
Self: Sized;
@ -188,7 +200,7 @@ pub trait DataLibrary<T>: Cacheable
where
T: Clone,
{
fn get_cache(&self) -> &RwLock<BTreeMap<u32, T>>;
fn get_cache(&self) -> &RwLock<hashbrown::HashMap<u32, T>>;
fn get_self_ref(&self) -> ExternRef<Self>
where
Self: Sized;

View File

@ -1,13 +1,12 @@
use crate::app_interface::data_libraries::DataLibrary;
use crate::app_interface::{MoveData, StringKey};
use crate::{ExternRef, ExternalReferenceType};
use alloc::collections::BTreeMap;
use alloc::rc::Rc;
use spin::RwLock;
struct MoveLibraryInner {
ptr: ExternRef<MoveLibrary>,
cache: RwLock<BTreeMap<u32, MoveData>>,
cache: RwLock<hashbrown::HashMap<u32, MoveData>>,
}
#[derive(Clone)]
@ -38,7 +37,7 @@ impl MoveLibrary {
}
impl DataLibrary<MoveData> for MoveLibrary {
fn get_cache(&self) -> &spin::rwlock::RwLock<BTreeMap<u32, MoveData>> {
fn get_cache(&self) -> &spin::rwlock::RwLock<hashbrown::HashMap<u32, MoveData>> {
&self.inner.cache
}

View File

@ -1,12 +1,11 @@
use crate::app_interface::{DataLibrary, Species};
use crate::{ExternRef, ExternalReferenceType, StringKey};
use alloc::collections::BTreeMap;
use alloc::rc::Rc;
use spin::RwLock;
struct SpeciesLibraryInner {
ptr: ExternRef<SpeciesLibrary>,
cache: RwLock<BTreeMap<u32, Species>>,
cache: RwLock<hashbrown::HashMap<u32, Species>>,
}
#[derive(Clone)]
@ -37,7 +36,7 @@ impl SpeciesLibrary {
}
impl DataLibrary<Species> for SpeciesLibrary {
fn get_cache(&self) -> &spin::rwlock::RwLock<BTreeMap<u32, Species>> {
fn get_cache(&self) -> &spin::rwlock::RwLock<hashbrown::HashMap<u32, Species>> {
&self.inner.cache
}

View File

@ -1,5 +1,4 @@
use crate::{ExternRef, ExternalReferenceType};
use alloc::collections::BTreeMap;
use crate::{ExternRef, ExternalReferenceType, TypeIdentifier};
use alloc::rc::Rc;
use alloc::string::{String, ToString};
use cstr_core::{c_char, CString};
@ -7,8 +6,8 @@ use spin::RwLock;
struct TypeLibraryInner {
reference: ExternRef<TypeLibrary>,
name_to_type_cache: RwLock<BTreeMap<String, u8>>,
effectiveness_cache: RwLock<BTreeMap<(u8, u8), f32>>,
name_to_type_cache: RwLock<hashbrown::HashMap<String, TypeIdentifier>>,
effectiveness_cache: RwLock<hashbrown::HashMap<(TypeIdentifier, TypeIdentifier), f32>>,
}
#[derive(Clone)]
@ -39,7 +38,7 @@ impl TypeLibrary {
}
#[cfg(not(feature = "mock_data"))]
pub fn get_type_from_name(&self, name: &str) -> Option<u8> {
pub fn get_type_from_name(&self, name: &str) -> Option<TypeIdentifier> {
if let Some(cached) = self.inner.name_to_type_cache.read().get(name) {
return Some(*cached);
}
@ -48,6 +47,7 @@ impl TypeLibrary {
if v == 255 {
return None;
}
let v = v.into();
self.inner
.name_to_type_cache
.write()
@ -56,7 +56,11 @@ impl TypeLibrary {
}
#[cfg(not(feature = "mock_data"))]
pub fn get_single_effectiveness(&self, attacking_type: u8, defending_type: u8) -> f32 {
pub fn get_single_effectiveness(
&self,
attacking_type: TypeIdentifier,
defending_type: TypeIdentifier,
) -> f32 {
if let Some(cached) = self
.inner
.effectiveness_cache
@ -68,8 +72,8 @@ impl TypeLibrary {
let effectiveness = unsafe {
type_library_get_single_effectiveness(
self.inner.reference,
attacking_type,
defending_type,
attacking_type.into(),
defending_type.into(),
)
};
self.inner
@ -80,7 +84,11 @@ impl TypeLibrary {
}
#[cfg(not(feature = "mock_data"))]
pub fn get_effectiveness(&self, attacking_type: u8, defending_types: &[u8]) -> f32 {
pub fn get_effectiveness(
&self,
attacking_type: TypeIdentifier,
defending_types: &[TypeIdentifier],
) -> f32 {
let mut f = 1.0;
for defending_type in defending_types {
f *= self.get_single_effectiveness(attacking_type, *defending_type);

View File

@ -96,7 +96,7 @@ crate::handling::cacheable::cacheable!(Item);
#[cfg(not(feature = "mock_data"))]
impl ExternalReferenceType for Item {
fn from_extern_value(reference: ExternRef<Self>) -> Self {
Item::mock(reference)
Item::new(reference)
}
}

View File

@ -14,3 +14,23 @@ pub use nature::*;
pub use species::*;
pub type LevelInt = u8;
/// A unique key that can be used to store a reference to a type. Opaque reference to a byte
/// internally.
#[derive(Debug, Copy, Clone, Eq, PartialEq, Default, Hash)]
pub struct TypeIdentifier {
/// The unique internal value.
val: u8,
}
impl From<u8> for TypeIdentifier {
fn from(val: u8) -> Self {
Self { val }
}
}
impl From<TypeIdentifier> for u8 {
fn from(id: TypeIdentifier) -> Self {
id.val
}
}

View File

@ -1,4 +1,4 @@
use crate::app_interface::{get_hash_const, StringKey};
use crate::app_interface::{get_hash, StringKey};
use crate::handling::cached_value::CachedValue;
use crate::handling::Cacheable;
use crate::{cached_value, cached_value_getters, ExternRef, ExternalReferenceType};
@ -104,8 +104,8 @@ impl MoveData {
}
#[cfg(not(feature = "mock_data"))]
pub fn has_flag<const N: usize>(&self, flag: &[u8; N]) -> bool {
let hash = get_hash_const(flag);
pub fn has_flag(&self, flag: &str) -> bool {
let hash = get_hash(flag);
unsafe { move_data_has_flag_by_hash(self.inner.ptr, hash) }
}
}

View File

@ -1,11 +1,10 @@
use crate::app_interface::get_hash_const;
use crate::app_interface::get_hash;
use crate::handling::cached_value::CachedValue;
use crate::handling::Cacheable;
use crate::{
cached_value, cached_value_getters, ExternRef, ExternalReferenceType, FFIArray, ImmutableList,
StringKey, VecExternRef,
};
use alloc::collections::BTreeMap;
use alloc::rc::Rc;
use alloc::vec::Vec;
use spin::RwLock;
@ -147,8 +146,8 @@ impl Form {
}
#[cfg(not(feature = "mock_data"))]
pub fn has_flag<const N: usize>(&self, flag: &[u8; N]) -> bool {
let hash = get_hash_const(flag);
pub fn has_flag(&self, flag: &str) -> bool {
let hash = get_hash(flag);
unsafe { form_has_flag_by_hash(self.inner.reference, hash) }
}
}
@ -160,7 +159,7 @@ pub struct SpeciesInner {
gender_rate: CachedValue<f32>,
growth_rate: CachedValue<StringKey>,
capture_rate: CachedValue<u8>,
forms: RwLock<BTreeMap<u32, Option<Form>>>,
forms: RwLock<hashbrown::HashMap<u32, Option<Form>>>,
}
#[derive(Clone)]
@ -205,8 +204,8 @@ impl Species {
}
#[cfg(not(feature = "mock_data"))]
pub fn get_form<const N: usize>(&self, form_name: &[u8; N]) -> Option<Form> {
let hash = get_hash_const(form_name);
pub fn get_form(&self, form_name: &str) -> Option<Form> {
let hash = get_hash(form_name);
unsafe {
if let Some(v) = self.inner.forms.read().get(&hash) {
v.clone()
@ -220,8 +219,8 @@ impl Species {
}
#[cfg(not(feature = "mock_data"))]
pub fn has_flag<const N: usize>(&self, flag: &[u8; N]) -> bool {
let hash = get_hash_const(flag);
pub fn has_flag(&self, flag: &str) -> bool {
let hash = get_hash(flag);
unsafe { species_has_flag_by_hash(self.inner.reference, hash) }
}
}

View File

@ -31,7 +31,7 @@ impl StringKey {
}
#[cfg(not(feature = "mock_data"))]
pub(super) fn ptr(&self) -> ExternRef<Self> {
pub(crate) fn ptr(&self) -> ExternRef<Self> {
self.data.ptr
}
@ -70,6 +70,12 @@ impl StringKey {
}
}
impl PartialEq for StringKey {
fn eq(&self, other: &Self) -> bool {
self.data.ptr == other.data.ptr
}
}
crate::handling::cacheable::cacheable!(StringKey);
#[cfg(not(feature = "mock_data"))]
@ -134,23 +140,12 @@ const fn to_lower(c: u8) -> u8 {
c
}
pub const fn get_hash_const<const N: usize>(s: &[u8; N]) -> u32 {
let mut crc: u32 = 0xffffffff;
let mut i: usize = 0;
while i < N {
crc = (crc >> 8) ^ CRC_TABLE[((crc ^ (to_lower(s[i]) as u32)) & 0xff) as usize];
i += 1;
}
crc ^ 0xffffffff
}
pub const fn get_hash(s: &[u8]) -> u32 {
pub const fn get_hash(s: &str) -> u32 {
let mut crc: u32 = 0xffffffff;
let mut i: usize = 0;
while i < s.len() {
crc = (crc >> 8) ^ CRC_TABLE[((crc ^ (to_lower(s[i]) as u32)) & 0xff) as usize];
crc = (crc >> 8) ^ CRC_TABLE[((crc ^ (to_lower(s.as_bytes()[i]) as u32)) & 0xff) as usize];
i += 1;
}
crc ^ 0xffffffff

View File

@ -1,11 +1,9 @@
#[cfg(not(feature = "mock_data"))]
use crate::ExternRef;
#[cfg(not(feature = "mock_data"))]
use alloc::collections::BTreeMap;
pub trait Cacheable {
#[cfg(not(feature = "mock_data"))]
fn get_cache<'a>() -> &'a mut BTreeMap<ExternRef<Self>, Self>
fn get_cache<'a>() -> &'a mut hashbrown::HashMap<ExternRef<Self>, Self>
where
Self: Sized;
@ -19,8 +17,9 @@ pub trait Cacheable {
if let Some(v) = opt {
return v.clone();
}
Self::get_cache().insert(ptr, ctor(ptr));
return Self::get_cache().get(&ptr).unwrap().clone();
let value = ctor(ptr);
Self::get_cache().insert(ptr, value.clone());
value
}
}
@ -28,12 +27,18 @@ macro_rules! cacheable {
($type: ty) => {
paste::paste! {
#[cfg(not(feature = "mock_data"))]
static mut [<$type:upper _CACHE>]: alloc::collections::BTreeMap<ExternRef<$type>, $type> =
alloc::collections::BTreeMap::new();
static mut [<$type:upper _CACHE>]: Option<hashbrown::HashMap<ExternRef<$type>, $type>> =
None;
impl crate::handling::Cacheable for $type {
#[cfg(not(feature = "mock_data"))]
fn get_cache<'a>() -> &'a mut alloc::collections::BTreeMap<ExternRef<$type>, $type> {
unsafe { &mut [<$type:upper _CACHE>] }
fn get_cache<'a>() -> &'a mut hashbrown::HashMap<ExternRef<$type>, $type> {
unsafe {
if let None = [<$type:upper _CACHE>] {
[<$type:upper _CACHE>] = Some(hashbrown::HashMap::new());
}
[<$type:upper _CACHE>].as_mut().unwrap()
}
}
}
}

View File

@ -1,59 +1,62 @@
#[repr(u8)]
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum ScriptCapabilities {
None = 0,
Initialize = 1,
OnStack,
OnRemove,
OnBeforeTurn,
ChangeAttack,
ModifyNumberOfHits,
PreventAttack,
FailAttack,
StopBeforeAttack,
OnBeforeAttack,
FailIncomingAttack,
ChangeMove,
ChangeNumberOfHits,
PreventMove,
FailMove,
StopBeforeMove,
OnBeforeMove,
FailIncomingMove,
IsInvulnerable,
OnAttackMiss,
ChangeAttackType,
OnMoveMiss,
ChangeMoveType,
ChangeEffectiveness,
BlockCritical,
OnIncomingHit,
OnFaintingOpponent,
PreventStatBoostChange,
ModifyStatBoostChange,
ChangeStatBoostChange,
PreventSecondaryEffects,
OnSecondaryEffect,
OnAfterHits,
PreventSelfSwitch,
ModifyEffectChance,
ModifyIncomingEffectChance,
OverrideBasePower,
ChangeEffectChance,
ChangeIncomingEffectChance,
ChangeBasePower,
ChangeDamageStatsUser,
BypassDefensiveStat,
BypassOffensiveStat,
ModifyStatModifier,
ModifyDamageModifier,
OverrideDamage,
OverrideIncomingDamage,
ChangeStatModifier,
ChangeDamageModifier,
ChangeDamage,
ChangeIncomingDamage,
ChangeSpeed,
ChangePriority,
OnFail,
OnOpponentFail,
PreventRunAway,
PreventSelfRunAway,
PreventOpponentRunAway,
PreventOpponentSwitch,
OnEndTurn,
OnDamage,
OnFaint,
OnAfterHeldItemConsume,
PreventIncomingCritical,
ModifyCriticalStage,
OverrideCriticalModifier,
OverrideSTABModifier,
ModifyExperienceGain,
BlockIncomingCritical,
ChangeAccuracy,
ChangeCriticalStage,
ChangeCriticalModifier,
ChangeSTABModifier,
ChangeExperienceGain,
DoesShareExperience,
BlockWeather,
OnSwitchIn,
ModifyOffensiveStatValue,
ModifyDefensiveStatValue,
ChangeOffensiveStatValue,
ChangeDefensiveStatValue,
ChangeCaptureRate,
}

View File

@ -1,5 +1,6 @@
use crate::ImmutableList;
use core::cmp::Ordering;
use core::hash::{Hash, Hasher};
use core::intrinsics::transmute;
use core::marker::PhantomData;
@ -28,6 +29,16 @@ impl<T> ExternRef<T> {
T::instantiate_from_extern_value(*self)
}
#[inline]
pub fn not_null(&self) -> T
where
T: ExternalReferenceType,
T: Sized,
T:,
{
T::instantiate_from_extern_value(*self).unwrap()
}
#[inline]
pub(crate) fn cast<TCast>(&self) -> ExternRef<TCast> {
ExternRef::<TCast> {
@ -76,6 +87,12 @@ impl<T> Ord for ExternRef<T> {
}
}
impl<T> Hash for ExternRef<T> {
fn hash<H: Hasher>(&self, state: &mut H) {
self.p.hash(state)
}
}
#[repr(C)]
pub struct VecExternRef<T> {
v: u64,

View File

@ -1,7 +1,9 @@
use crate::app_interface::list::ImmutableList;
use crate::app_interface::{DynamicLibrary, EffectParameter};
use crate::app_interface::{
Battle, DamageSource, DynamicLibrary, EffectParameter, ExecutingMove, Item, Pokemon, Statistic,
};
use crate::handling::ScriptCapabilities;
use crate::{ExternRef, TurnChoice};
use crate::{ExternRef, StringKey, TurnChoice, TypeIdentifier};
use core::ffi::c_void;
use core::fmt::Debug;
@ -9,17 +11,338 @@ pub trait Script {
fn new() -> Self
where
Self: Sized;
fn destroy(&self);
fn get_name(&self) -> &str;
fn get_name() -> &'static str
where
Self: Sized;
fn get_capabilities(&self) -> &[ScriptCapabilities];
/// 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.
fn stack(&self) {}
/// This function is ran when this script stops being in effect, and is removed from its owner.
fn on_remove(&self) {}
/// This function is ran when this script starts being in effect.
fn on_initialize(
&self,
_library: &DynamicLibrary,
_parameters: Option<ImmutableList<EffectParameter>>,
) {
}
/// 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
/// something has happened during a turn.
fn on_before_turn(&self, _choice: TurnChoice) {}
/// 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.
fn change_speed(&self, _choice: TurnChoice, _speed: &mut u32) {}
/// 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
/// 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) {}
/// 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.
fn change_move(&self, _choice: TurnChoice, _move_name: &mut StringKey) {}
/// 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
/// first hit.
fn change_number_of_hits(&self, _choice: TurnChoice, _number_of_hits: &mut u8) {}
/// 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.
fn prevent_move(&self, _move: ExecutingMove, _prevent: &mut bool) {}
/// This function makes the move fail. If the fail field gets set to true, the move ends execution,
/// and fail events get triggered.
fn fail_move(&self, _move: ExecutingMove, _fail: &mut bool) {}
/// Similar to [`Self::prevent_move`]. This function will also stop execution, but PP will be
/// decreased.
fn stop_before_move(&self, _move: ExecutingMove, _stop: &mut bool) {}
/// This function runs just before the move starts its execution.
fn on_before_move(&self, _move: ExecutingMove) {}
/// 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.
fn fail_incoming_move(&self, _move: ExecutingMove, _target: Pokemon, _fail: &mut bool) {}
/// This function allows a script to make its owner invulnerable to an incoming move.
fn is_invulnerable(&self, _move: ExecutingMove, _target: Pokemon, _invulnerable: &mut bool) {}
/// 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.
fn on_move_miss(&self, _move: ExecutingMove, _target: Pokemon) {}
/// This function allows the script to change the actual type that is used for the move on a target.
fn change_move_type(
&self,
_move: ExecutingMove,
_target: Pokemon,
_hit: u8,
_move_type: &mut TypeIdentifier,
) {
}
/// This function allows the script to change how effective a move is on a target.
fn change_effectiveness(
&self,
_move: ExecutingMove,
_target: Pokemon,
_hit: u8,
_effectiveness: &mut f32,
) {
}
/// This function allows a script to block an outgoing move from being critical.
fn block_critical(
&self,
_move: ExecutingMove,
_target: Pokemon,
_hit: u8,
_block_critical: &mut bool,
) {
}
/// This function allows a script to block an incoming move from being critical.
fn block_incoming_critical(
&self,
_move: ExecutingMove,
_target: Pokemon,
_hit: u8,
_block_critical: &mut bool,
) {
}
/// 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.
fn change_accuracy(
&self,
_move: ExecutingMove,
_target: Pokemon,
_hit: u8,
_accuracy: &mut u8,
) {
}
/// This function allows a script to change the critical stage of the move used.
fn change_critical_stage(
&self,
_move: ExecutingMove,
_target: Pokemon,
_hit: u8,
_stage: &mut u8,
) {
}
/// This function allows a script to change the damage modifier of a critical hit. This will only
/// run when a hit is critical.
fn change_critical_modifier(
&self,
_move: ExecutingMove,
_target: Pokemon,
_hit: u8,
_modifier: &mut f32,
) {
}
/// 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.
fn change_stab_modifier(
&self,
_move: ExecutingMove,
_target: Pokemon,
_hit: u8,
_modifier: &mut f32,
) {
}
/// This function allows a script to change the effective base power of a move hit.
fn change_base_power(
&self,
_move: ExecutingMove,
_target: Pokemon,
_hit: u8,
_base_power: &mut u8,
) {
}
/// This function allows a script to bypass defensive stat boosts for a move hit.
fn bypass_defensive_stat_boost(
&self,
_move: ExecutingMove,
_target: Pokemon,
_hit: u8,
_bypass: &mut bool,
) {
}
/// This function allows a script to bypass offensive stat boosts for a move hit.
fn bypass_offensive_stat_boost(
&self,
_move: ExecutingMove,
_target: Pokemon,
_hit: u8,
_bypass: &mut bool,
) {
}
/// 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: Pokemon,
_hit: u8,
_amount: &mut u32,
) {
}
/// 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: Pokemon,
_hit: u8,
_amount: &mut u32,
) {
}
/// This function allows a script to change the raw modifier we retrieved from the stats of the
/// defender and attacker.
fn change_damage_stat_modifier(
&self,
_move: ExecutingMove,
_target: Pokemon,
_hit: u8,
_modifier: &mut f32,
) {
}
/// This function allows a script to apply a raw multiplier to the damage done by a move.
fn change_damage_modifier(
&self,
_move: ExecutingMove,
_target: Pokemon,
_hit: u8,
_modifier: &mut f32,
) {
}
/// This function allows a script to modify the outgoing damage done by a move.
fn change_damage(&self, _move: ExecutingMove, _target: Pokemon, _hit: u8, _damage: &mut u32) {}
/// This function allows a script to modify the incoming damage done by a move.
fn change_incoming_damage(
&self,
_move: ExecutingMove,
_target: Pokemon,
_hit: u8,
_damage: &mut u32,
) {
}
/// This function triggers when an incoming hit happens. This triggers after the damage is done,
/// but before the secondary effect of the move happens.
fn on_incoming_hit(&self, _move: ExecutingMove, _target: Pokemon, _hit: u8) {}
/// This function triggers when an opponent on the field faints.
fn on_opponent_faints(&self, _move: ExecutingMove, _target: Pokemon, _hit: u8) {}
/// This function allows a script attached to a Pokemon or its parents to prevent stat boost
/// changes on that Pokemon.
fn prevent_stat_boost_change(
&self,
_target: Pokemon,
_stat: Statistic,
_amount: i8,
_self_inflicted: bool,
_prevent: &mut bool,
) {
}
/// This function allows a script attached to a Pokemon or its parents to modify the amount by
/// which the stat boost will change. If the stat boost is done by the user itself, self
/// inflicted will be true, otherwise it will be false.
fn change_stat_boost_change(
&self,
_target: Pokemon,
_stat: Statistic,
_self_inflicted: bool,
_amount: &mut i8,
) {
}
/// This function allows a script attached to a Pokemon or its parents to prevent an incoming
/// secondary effect. This means the move will still hit and do damage, but not trigger its
/// secondary effect. Note that this function is not called for status moves.
fn prevent_secondary_effect(
&self,
_move: ExecutingMove,
_target: Pokemon,
_hit: u8,
_prevent: &mut bool,
) {
}
/// This function allows a script attached to a move or its parents to change the chance the
/// secondary effect of a move will trigger. The chance is depicted in percentage here, so
/// changing this to above or equal to 100 will make it always hit, while setting it to equal or
/// below 0 will make it never hit.
fn change_effect_chance(
&self,
_move: ExecutingMove,
_target: Pokemon,
_hit: u8,
_chance: &mut f32,
) {
}
/// This function allows a script attached to a Pokemon or its parents to change the chance the
/// secondary effect of an incoming move will trigger. The chance is depicted in percentage here,
/// so changing this to above or equal to 100 will make it always hit, while setting it to equal
/// or below 0 will make it never hit.
fn change_incoming_effect_chance(
&self,
_move: ExecutingMove,
_target: Pokemon,
_hit: u8,
_chance: &mut f32,
) {
}
/// This function triggers when the move uses its secondary effect. Moves should implement their
/// secondary effects here. Status moves should implement their actual functionality in this
/// function as well, as status moves effects are defined as secondary effects for simplicity.
fn on_secondary_effect(&self, _move: ExecutingMove, _target: Pokemon, _hit: u8) {}
/// This function triggers on a move or its parents when all hits on a target are finished.
fn on_after_hits(&self, _move: ExecutingMove, _target: Pokemon) {}
/// This function prevents the Pokemon it is attached to from being able to switch out.
fn prevent_self_switch(&self, _choice: TurnChoice, _prevent: &mut bool) {}
/// This function allows the prevention of switching for any opponent.
fn prevent_opponent_switch(&self, _choice: TurnChoice, _prevent: &mut bool) {}
/// This function is called on a move and its parents when the move fails.
fn on_fail(&self, _target: Pokemon) {}
/// This function is called on a script when an opponent fails.
fn on_opponent_fail(&self, _target: Pokemon) {}
/// This function allows preventing the running away of the Pokemon its attached to
fn prevent_self_run_away(&self, _choice: TurnChoice, _prevent: &mut bool) {}
/// 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) {}
/// This function id triggered on all scripts active in the battle after all choices have finished
/// running. Note that choices are not active anymore here, so their scripts do not call this
/// function.
fn on_end_turn(&self) {}
/// 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,
) {
}
/// This function is triggered on a Pokemon and its parents when the given Pokemon faints.
fn on_faint(&self, _pokemon: Pokemon, _source: DamageSource) {}
/// This function is triggered on a Pokemon and its parents when the given Pokemon is switched into
/// the battlefield.
fn on_switch_in(&self, _pokemon: Pokemon) {}
/// This function is triggered on a Pokemon and its parents when the given Pokemon consumes the
/// held item it had.
fn on_after_held_item_consume(&self, _pokemon: Pokemon, _item: &Item) {}
/// This function is triggered on a Pokemon and its parents when the given Pokemon gains experience,
/// and allows for changing this amount of experience.
fn change_experience_gained(
&self,
_fainted_mon: Pokemon,
_winning_mon: Pokemon,
_amount: &mut u32,
) {
}
/// This function is triggered on a Pokemon and its parents when the given Pokemon gains experience,
/// and allows for making the experience be shared across multiple Pokemon.
fn share_experience(&self, _fainted_mon: Pokemon, _winning_mon: Pokemon, _shares: &mut bool) {}
/// This function is triggered on a battle and its parents when something attempts to change the
/// weather, and allows for blocking the weather change.
fn block_weather(&self, _battle: Battle, _blocked: &mut bool) {}
/// This function is called when a Pokeball is thrown at a Pokemon, and allows modifying the catch
/// rate of this attempt. Pokeball modifier effects should be implemented here, as well as for
/// example status effects that change capture rates.
fn change_capture_rate_bonus(&self, _target: Pokemon, _pokeball: Item, _modifier: &mut u8) {}
}
impl Debug for dyn Script {

View File

@ -1,80 +1,63 @@
use crate::{ExternRef, ExternalReferenceType};
use alloc::boxed::Box;
use core::cell::Cell;
use core::mem::forget;
struct TemporaryData<T> {
use_count: Cell<usize>,
is_deleted: bool,
value: T,
}
use alloc::rc::Rc;
use core::sync::atomic::{AtomicBool, Ordering};
#[cfg(not(feature = "mock_data"))]
pub struct Temporary<T> {
value: *mut TemporaryData<T>,
is_deleted: Rc<AtomicBool>,
value: Rc<T>,
}
#[cfg(not(feature = "mock_data"))]
static mut TEMPORARIES: alloc::collections::BTreeMap<u32, *const u8> =
alloc::collections::BTreeMap::new();
static mut TEMPORARIES: Option<hashbrown::HashMap<u32, Rc<AtomicBool>>> = None;
#[cfg(not(feature = "mock_data"))]
impl<T> Temporary<T>
where
T: ExternalReferenceType,
T: Clone,
{
impl<T> Temporary<T> {
#[inline]
pub fn from_reference(reference: ExternRef<T>) -> Self {
let temporaries = unsafe { &mut TEMPORARIES };
let existing = temporaries.get(&reference.get_internal_index());
pub fn new(reference: u32, value: T) -> Self {
unsafe {
if let None = TEMPORARIES {
TEMPORARIES = Some(hashbrown::HashMap::new());
}
}
let temporaries = unsafe { &mut TEMPORARIES }.as_mut().unwrap();
let existing = temporaries.get(&reference);
if let Some(v) = existing {
let rc = (*v as *mut TemporaryData<T>).as_mut().unwrap();
if !rc.is_deleted {
*rc.use_count.get_mut() += 1;
return Self {
value: rc as *mut TemporaryData<T>,
is_deleted: v.clone(),
value: Rc::new(value),
};
}
}
}
let value = reference.get_value().unwrap();
let mut reference_counter = TemporaryData {
use_count: Cell::new(1),
is_deleted: false,
value,
};
let ptr = &mut reference_counter as *mut TemporaryData<T>;
forget(reference_counter);
temporaries.insert(reference.get_internal_index(), ptr as *const u8);
Self { value: ptr }
let value = Rc::new(value);
let is_deleted = Rc::new(AtomicBool::new(false));
temporaries.insert(reference, is_deleted.clone());
Self { is_deleted, value }
}
#[inline]
pub fn value(&self) -> T {
unsafe { self.value.as_ref().unwrap().value.clone() }
pub fn value(&self) -> Rc<T> {
if self.is_deleted.load(Ordering::SeqCst) {
panic!("Accessed value after it had been deleted");
}
self.value.clone()
}
#[inline]
pub fn value_ref(&self) -> &T {
unsafe { &self.value.as_ref().unwrap().value }
if self.is_deleted.load(Ordering::SeqCst) {
panic!("Accessed value after it had been deleted");
}
self.value.as_ref()
}
}
pub(crate) fn mark_as_deleted(reference: ExternRef<T>) {
#[cfg(not(feature = "mock_data"))]
impl Temporary<u8> {
pub(crate) fn mark_as_deleted(reference: u32) {
let temporaries = unsafe { &mut TEMPORARIES };
let existing = temporaries.get(&reference.get_internal_index());
unsafe {
let existing = temporaries.as_mut().unwrap().get_mut(&reference);
if let Some(v) = existing {
crate::utils::print_raw(b"Dropping temporary");
let rc = (*v as *mut TemporaryData<T>).as_mut().unwrap();
rc.is_deleted = true;
if rc.use_count.get() == 0 {
drop(Box::from(*v as *mut TemporaryData<T>))
}
temporaries.remove(&reference.get_internal_index());
}
v.store(false, Ordering::SeqCst);
}
}
}
@ -82,32 +65,28 @@ where
#[cfg(not(feature = "mock_data"))]
impl<T> Clone for Temporary<T> {
fn clone(&self) -> Self {
*unsafe { self.value.as_mut() }.unwrap().use_count.get_mut() += 1;
Self { value: self.value }
Self {
is_deleted: self.is_deleted.clone(),
value: self.value.clone(),
}
}
}
#[no_mangle]
#[cfg(not(feature = "mock_data"))]
impl<T> Drop for Temporary<T> {
fn drop(&mut self) {
let data = unsafe { self.value.as_mut() }.unwrap();
let v = data.use_count.get_mut();
*v -= 1;
if *v == 0 && data.is_deleted {
drop(Box::from(self.value))
}
}
unsafe extern "wasm" fn _mark_deleted(r: u32) {
Temporary::<u8>::mark_as_deleted(r)
}
#[cfg(feature = "mock_data")]
pub struct Temporary<T: Clone> {
value: T,
pub struct Temporary<T> {
value: Rc<T>,
}
#[cfg(feature = "mock_data")]
impl<T: Clone> Temporary<T> {
impl<T> Temporary<T> {
#[inline]
pub fn value(&self) -> T {
pub fn value(&self) -> Rc<T> {
self.value.clone()
}
@ -116,3 +95,12 @@ impl<T: Clone> Temporary<T> {
&self.value
}
}
#[cfg(feature = "mock_data")]
impl<T> Clone for Temporary<T> {
fn clone(&self) -> Self {
Self {
value: self.value.clone(),
}
}
}

View File

@ -12,6 +12,7 @@
#![feature(wasm_abi)]
#![feature(thread_local)]
#![feature(build_hasher_simple_hash_one)]
#![feature(adt_const_params)]
#![cfg_attr(not(feature = "mock_data"), no_std)]
#![allow(incomplete_features)]
@ -23,7 +24,12 @@ extern crate wee_alloc;
static ALLOC: wee_alloc::WeeAlloc = wee_alloc::WeeAlloc::INIT;
use crate::app_interface::list::ImmutableList;
use crate::app_interface::{DynamicLibrary, EffectParameter, StringKey, TurnChoice};
use crate::app_interface::Statistic;
use crate::app_interface::{
Battle, DamageSource, DynamicLibrary, EffectParameter, ExecutingMove, Item, StringKey,
TurnChoice,
};
use crate::app_interface::{Pokemon, TypeIdentifier};
pub(crate) use crate::handling::extern_ref::*;
use crate::handling::ffi_array::FFIArray;
#[cfg(not(feature = "mock_data"))]
@ -47,61 +53,565 @@ pub fn set_load_script_fn(f: LoadScriptFnType) {
}
}
macro_rules! exported_functions {
(
$(
fn $func_name:ident($($par_name:ident: $par_type:ty),*$(,)?) $(-> $return_type:ty)? $func_body:block
)*
) => {
$(
#[no_mangle]
#[cfg(not(feature = "mock_data"))]
extern "wasm" fn load_script(category: ScriptCategory, name: ExternRef<StringKey>) -> u32 {
unsafe extern "wasm" fn $func_name(
$(
$par_name: $par_type,
)*
) $(-> $return_type)* $func_body
)*
};
}
#[repr(C)]
pub struct ScriptPtr {
ptr: *const Box<dyn Script>,
}
impl ScriptPtr {
pub fn new(ptr: *const Box<dyn Script>) -> Self {
Self { ptr }
}
pub fn val(&self) -> &dyn Script {
unsafe { self.ptr.as_ref().unwrap().as_ref() }
}
pub fn ptr(&self) -> *const Box<dyn Script> {
self.ptr
}
}
exported_functions! {
fn load_script(category: ScriptCategory, name: ExternRef<StringKey>) -> ScriptPtr {
let name_c = StringKey::new(name);
let boxed_script = unsafe { &LOAD_SCRIPT_FN }.as_ref().unwrap()(category, &name_c);
if boxed_script.is_none() {
return 0;
return ScriptPtr::new(core::ptr::null());
}
let b = Box::new(boxed_script.unwrap());
Box::into_raw(b) as u32
ScriptPtr::new(Box::into_raw(b))
}
#[no_mangle]
#[cfg(not(feature = "mock_data"))]
unsafe extern "wasm" fn destroy_script(script: *mut Box<dyn Script>) {
fn destroy_script(script: *mut Box<dyn Script>) {
// By turning it from a raw pointer back into a Box with from_raw, we give ownership back to rust.
// This lets Rust do the cleanup.
let boxed_script = Box::from_raw(script);
boxed_script.destroy();
drop(boxed_script);
}
#[no_mangle]
#[cfg(not(feature = "mock_data"))]
unsafe extern "wasm" fn get_script_capabilities(
script: *const Box<dyn Script>,
) -> FFIArray<ScriptCapabilities> {
let c = script.as_ref().unwrap().get_capabilities();
fn get_script_capabilities(script: ScriptPtr) -> FFIArray<ScriptCapabilities> {
let c = script.val().get_capabilities();
FFIArray::new(c)
}
#[no_mangle]
#[cfg(not(feature = "mock_data"))]
unsafe extern "wasm" fn script_on_initialize(
script: *const Box<dyn Script>,
fn script_stack(script: ScriptPtr) {
script.val().stack();
}
fn script_on_remove(script: ScriptPtr) {
script.val().on_remove();
}
fn script_on_initialize(
script: ScriptPtr,
library: ExternRef<DynamicLibrary>,
parameters: VecExternRef<EffectParameter>,
) {
let lib = DynamicLibrary::new(library);
let parameters = ImmutableList::from_ref(parameters);
script
.as_ref()
.unwrap()
.as_ref()
.on_initialize(&lib, Some(parameters));
script.val().on_initialize(&library.not_null(), Some(parameters));
}
#[no_mangle]
#[cfg(not(feature = "mock_data"))]
unsafe extern "wasm" fn script_on_before_turn(
script: *const Box<dyn Script>,
fn script_on_before_turn(
script: ScriptPtr,
choice: ExternRef<TurnChoice>,
) {
script
.as_ref()
.unwrap()
.as_ref()
.on_before_turn(choice.get_value().unwrap())
script.val().on_before_turn(choice.not_null())
}
fn script_change_speed(
script:ScriptPtr,
choice: ExternRef<TurnChoice>,
speed: *mut u32,
) {
script.val().change_speed(choice.not_null(), speed.as_mut().unwrap())
}
fn script_change_priority(
script: ScriptPtr,
choice: ExternRef<TurnChoice>,
priority: *mut i8,
) {
script.val().change_priority(choice.not_null(), priority.as_mut().unwrap())
}
fn script_change_move(
script: ScriptPtr,
choice: ExternRef<TurnChoice>,
mv: *mut ExternRef<StringKey>,
) {
let old = mv.as_ref().unwrap().not_null();
let mut new = old.clone();
script.val().change_move(choice.not_null(), &mut new);
if old != new {
*mv = new.ptr();
}
}
fn script_change_number_of_hits(
script: ScriptPtr,
choice: ExternRef<TurnChoice>,
out: *mut u8,
) {
script.val().change_number_of_hits(choice.not_null(), out.as_mut().unwrap());
}
fn script_prevent_move(
script: ScriptPtr,
mv: ExternRef<ExecutingMove>,
out: *mut bool,
) {
script.val().prevent_move(mv.not_null(), out.as_mut().unwrap());
}
fn script_fail_move(
script: ScriptPtr,
mv: ExternRef<ExecutingMove>,
out: *mut bool,
) {
script.val().fail_move(mv.not_null(), out.as_mut().unwrap());
}
fn script_stop_before_move(
script: ScriptPtr,
mv: ExternRef<ExecutingMove>,
out: *mut bool,
) {
script.val().stop_before_move(mv.not_null(), out.as_mut().unwrap());
}
fn script_on_before_move(
script: ScriptPtr,
mv: ExternRef<ExecutingMove>,
) {
script.val().on_before_move(mv.not_null());
}
fn script_fail_incoming_move(
script: ScriptPtr,
mv: ExternRef<ExecutingMove>,
target: ExternRef<Pokemon>,
out: *mut bool,
) {
script.val().fail_incoming_move(mv.not_null(), target.not_null(), out.as_mut().unwrap());
}
fn script_is_invulnerable(
script: ScriptPtr,
mv: ExternRef<ExecutingMove>,
target: ExternRef<Pokemon>,
out: *mut bool,
) {
script.val().is_invulnerable(mv.not_null(), target.not_null(), out.as_mut().unwrap());
}
fn script_on_move_miss(
script: ScriptPtr,
mv: ExternRef<ExecutingMove>,
target: ExternRef<Pokemon>,
) {
script.val().on_move_miss(mv.not_null(), target.not_null());
}
fn script_change_move_type(
script: ScriptPtr,
mv: ExternRef<ExecutingMove>,
target: ExternRef<Pokemon>,
hit: u8,
out: *mut TypeIdentifier,
) {
script.val().change_move_type(mv.not_null(), target.not_null(), hit, out.as_mut().unwrap());
}
fn script_change_effectiveness(
script: ScriptPtr,
mv: ExternRef<ExecutingMove>,
target: ExternRef<Pokemon>,
hit: u8,
out: *mut f32,
) {
script.val().change_effectiveness(mv.not_null(), target.not_null(), hit, out.as_mut().unwrap());
}
fn script_block_critical(
script: ScriptPtr,
mv: ExternRef<ExecutingMove>,
target: ExternRef<Pokemon>,
hit: u8,
out: *mut bool,
) {
script.val().block_critical(mv.not_null(), target.not_null(), hit, out.as_mut().unwrap());
}
fn script_block_incoming_critical(
script: ScriptPtr,
mv: ExternRef<ExecutingMove>,
target: ExternRef<Pokemon>,
hit: u8,
out: *mut bool,
) {
script.val().block_incoming_critical(mv.not_null(), target.not_null(), hit, out.as_mut().unwrap());
}
fn script_change_accuracy(
script: ScriptPtr,
mv: ExternRef<ExecutingMove>,
target: ExternRef<Pokemon>,
hit: u8,
out: *mut u8,
) {
script.val().change_accuracy(mv.not_null(), target.not_null(), hit, out.as_mut().unwrap());
}
fn script_change_critical_stage(
script: ScriptPtr,
mv: ExternRef<ExecutingMove>,
target: ExternRef<Pokemon>,
hit: u8,
out: *mut u8,
) {
script.val().change_critical_stage(mv.not_null(), target.not_null(), hit, out.as_mut().unwrap());
}
fn script_change_critical_modifier(
script: ScriptPtr,
mv: ExternRef<ExecutingMove>,
target: ExternRef<Pokemon>,
hit: u8,
out: *mut f32,
) {
script.val().change_critical_modifier(mv.not_null(), target.not_null(), hit, out.as_mut().unwrap());
}
fn script_change_stab_modifier(
script: ScriptPtr,
mv: ExternRef<ExecutingMove>,
target: ExternRef<Pokemon>,
hit: u8,
out: *mut f32,
) {
script.val().change_stab_modifier(mv.not_null(), target.not_null(), hit, out.as_mut().unwrap());
}
fn script_change_base_power(
script: ScriptPtr,
mv: ExternRef<ExecutingMove>,
target: ExternRef<Pokemon>,
hit: u8,
out: *mut u8,
) {
script.val().change_base_power(mv.not_null(), target.not_null(), hit, out.as_mut().unwrap());
}
fn script_bypass_defensive_stat_boost(
script: ScriptPtr,
mv: ExternRef<ExecutingMove>,
target: ExternRef<Pokemon>,
hit: u8,
out: *mut bool,
) {
script.val().bypass_defensive_stat_boost(mv.not_null(), target.not_null(), hit, out.as_mut().unwrap());
}
fn script_bypass_offensive_stat_boost(
script: ScriptPtr,
mv: ExternRef<ExecutingMove>,
target: ExternRef<Pokemon>,
hit: u8,
out: *mut bool,
) {
script.val().bypass_offensive_stat_boost(mv.not_null(), target.not_null(), hit, out.as_mut().unwrap());
}
fn script_change_defensive_stat_value(
script: ScriptPtr,
mv: ExternRef<ExecutingMove>,
target: ExternRef<Pokemon>,
hit: u8,
out: *mut u32,
) {
script.val().change_defensive_stat_value(mv.not_null(), target.not_null(), hit, out.as_mut().unwrap());
}
fn script_change_offensive_stat_value(
script: ScriptPtr,
mv: ExternRef<ExecutingMove>,
target: ExternRef<Pokemon>,
hit: u8,
out: *mut u32,
) {
script.val().change_offensive_stat_value(mv.not_null(), target.not_null(), hit, out.as_mut().unwrap());
}
fn script_change_damage_stat_modifier(
script: ScriptPtr,
mv: ExternRef<ExecutingMove>,
target: ExternRef<Pokemon>,
hit: u8,
out: *mut f32,
) {
script.val().change_damage_stat_modifier(mv.not_null(), target.not_null(), hit, out.as_mut().unwrap());
}
fn script_change_damage_modifier(
script: ScriptPtr,
mv: ExternRef<ExecutingMove>,
target: ExternRef<Pokemon>,
hit: u8,
out: *mut f32,
) {
script.val().change_damage_modifier(mv.not_null(), target.not_null(), hit, out.as_mut().unwrap());
}
fn script_change_damage(
script: ScriptPtr,
mv: ExternRef<ExecutingMove>,
target: ExternRef<Pokemon>,
hit: u8,
out: *mut u32,
) {
script.val().change_damage(mv.not_null(), target.not_null(), hit, out.as_mut().unwrap());
}
fn script_change_incoming_damage(
script: ScriptPtr,
mv: ExternRef<ExecutingMove>,
target: ExternRef<Pokemon>,
hit: u8,
out: *mut u32,
) {
script.val().change_incoming_damage(mv.not_null(), target.not_null(), hit, out.as_mut().unwrap());
}
fn script_on_incoming_hit(
script: ScriptPtr,
mv: ExternRef<ExecutingMove>,
target: ExternRef<Pokemon>,
hit: u8,
) {
script.val().on_incoming_hit(mv.not_null(), target.not_null(), hit);
}
fn script_on_opponent_faints(
script: ScriptPtr,
mv: ExternRef<ExecutingMove>,
target: ExternRef<Pokemon>,
hit: u8,
) {
script.val().on_opponent_faints(mv.not_null(), target.not_null(), hit);
}
fn script_prevent_stat_boost_change(
script: ScriptPtr,
target: ExternRef<Pokemon>,
stat: Statistic,
amount: i8,
self_inflicted: u8,
out: *mut bool,
) {
script.val().prevent_stat_boost_change(target.not_null(), stat, amount, self_inflicted == 1, out.as_mut().unwrap());
}
fn script_prevent_secondary_effect(
script: ScriptPtr,
mv: ExternRef<ExecutingMove>,
target: ExternRef<Pokemon>,
hit: u8,
out: *mut bool,
) {
script.val().prevent_secondary_effect(mv.not_null(), target.not_null(), hit, out.as_mut().unwrap());
}
fn script_change_effect_chance(
script: ScriptPtr,
mv: ExternRef<ExecutingMove>,
target: ExternRef<Pokemon>,
hit: u8,
out: *mut f32,
) {
script.val().change_effect_chance(mv.not_null(), target.not_null(), hit, out.as_mut().unwrap());
}
fn script_change_incoming_effect_chance(
script: ScriptPtr,
mv: ExternRef<ExecutingMove>,
target: ExternRef<Pokemon>,
hit: u8,
out: *mut f32,
) {
script.val().change_incoming_effect_chance(mv.not_null(), target.not_null(), hit, out.as_mut().unwrap());
}
fn script_on_secondary_effect(
script: ScriptPtr,
mv: ExternRef<ExecutingMove>,
target: ExternRef<Pokemon>,
hit: u8,
) {
script.val().on_secondary_effect(mv.not_null(), target.not_null(), hit);
}
fn script_on_after_hits(
script: ScriptPtr,
mv: ExternRef<ExecutingMove>,
target: ExternRef<Pokemon>,
) {
script.val().on_after_hits(mv.not_null(), target.not_null());
}
fn script_prevent_self_switch(
script: ScriptPtr,
choice: ExternRef<TurnChoice>,
out: *mut bool,
) {
script.val().prevent_self_switch(choice.not_null(), out.as_mut().unwrap());
}
fn script_prevent_opponent_switch(
script: ScriptPtr,
choice: ExternRef<TurnChoice>,
out: *mut bool,
) {
script.val().prevent_opponent_switch(choice.not_null(), out.as_mut().unwrap());
}
fn script_on_fail(
script: ScriptPtr,
pokemon: ExternRef<Pokemon>,
) {
script.val().on_fail(pokemon.not_null());
}
fn script_on_opponent_fail(
script: ScriptPtr,
pokemon: ExternRef<Pokemon>,
) {
script.val().on_opponent_fail(pokemon.not_null());
}
fn script_prevent_self_run_away(
script: ScriptPtr,
choice: ExternRef<TurnChoice>,
out: *mut bool,
) {
script.val().prevent_self_run_away(choice.not_null(), out.as_mut().unwrap());
}
fn script_prevent_opponent_run_away(
script: ScriptPtr,
choice: ExternRef<TurnChoice>,
out: *mut bool,
) {
script.val().prevent_opponent_run_away(choice.not_null(), out.as_mut().unwrap());
}
fn script_on_end_turn(
script: ScriptPtr,
) {
script.val().on_end_turn();
}
fn script_on_damage(
script: ScriptPtr,
pokemon: ExternRef<Pokemon>,
source: DamageSource,
old_health: u32,
new_health: u32,
) {
script.val().on_damage(pokemon.not_null(), source, old_health, new_health);
}
fn script_on_faint(
script: ScriptPtr,
pokemon: ExternRef<Pokemon>,
source: DamageSource,
) {
script.val().on_faint(pokemon.not_null(), source);
}
fn script_on_switch_in(
script: ScriptPtr,
pokemon: ExternRef<Pokemon>,
) {
script.val().on_switch_in(pokemon.not_null());
}
fn script_on_after_held_item_consume(
script: ScriptPtr,
pokemon: ExternRef<Pokemon>,
item: ExternRef<Item>
) {
script.val().on_after_held_item_consume(pokemon.not_null(), &item.not_null());
}
fn script_change_experience_gained(
script: ScriptPtr,
fainted_pokemon: ExternRef<Pokemon>,
winning_pokemon: ExternRef<Pokemon>,
out: *mut u32
) {
script.val().change_experience_gained(fainted_pokemon.not_null(), winning_pokemon.not_null(), out.as_mut().unwrap());
}
fn script_share_experience(
script: ScriptPtr,
fainted_pokemon: ExternRef<Pokemon>,
winning_pokemon: ExternRef<Pokemon>,
out: *mut bool,
) {
script.val().share_experience(fainted_pokemon.not_null(), winning_pokemon.not_null(), out.as_mut().unwrap());
}
fn script_block_weather(
script: ScriptPtr,
battle: ExternRef<Battle>,
out: *mut bool,
) {
script.val().block_weather(battle.not_null(), out.as_mut().unwrap());
}
fn script_change_capture_rate_bonus(
script: ScriptPtr,
target: ExternRef<Pokemon>,
pokeball: ExternRef<Item>,
out: *mut u8,
) {
script.val().change_capture_rate_bonus(target.not_null(), pokeball.not_null(), out.as_mut().unwrap());
}
}

View File

@ -2,7 +2,9 @@ use alloc::alloc::alloc;
use core::alloc::Layout;
#[cfg(not(feature = "mock_data"))]
use core::panic::PanicInfo;
use cstr_core::{c_char, CStr, CString};
use cstr_core::c_char;
#[cfg(feature = "mock_data")]
use cstr_core::{CStr, CString};
#[cfg(not(feature = "mock_data"))]
#[cfg(not(feature = "mock_data"))]