A lot of work on type registration
This commit is contained in:
parent
174137dcf6
commit
f06d46d854
|
@ -3,3 +3,4 @@
|
|||
Cargo.lock
|
||||
bin/
|
||||
.idea
|
||||
gen7_scripts.wat
|
|
@ -1,5 +1,7 @@
|
|||
use pkmn_lib_interface::app_interface::list::ImmutableList;
|
||||
use pkmn_lib_interface::app_interface::{get_hash, BattleLibrary, DataLibrary, EffectParameter};
|
||||
use pkmn_lib_interface::app_interface::{
|
||||
get_hash, DataLibrary, DynamicLibrary, EffectParameter, TurnChoice,
|
||||
};
|
||||
use pkmn_lib_interface::dbg;
|
||||
use pkmn_lib_interface::handling::{Script, ScriptCapabilities};
|
||||
|
||||
|
@ -16,12 +18,15 @@ impl Script for TestScript {
|
|||
}
|
||||
|
||||
fn get_capabilities(&self) -> &[ScriptCapabilities] {
|
||||
&[ScriptCapabilities::Initialize]
|
||||
&[
|
||||
ScriptCapabilities::Initialize,
|
||||
ScriptCapabilities::OnBeforeTurn,
|
||||
]
|
||||
}
|
||||
|
||||
fn on_initialize(
|
||||
&self,
|
||||
library: &BattleLibrary,
|
||||
library: &DynamicLibrary,
|
||||
parameters: Option<ImmutableList<EffectParameter>>,
|
||||
) {
|
||||
let l = library.data_library();
|
||||
|
@ -32,6 +37,14 @@ impl Script for TestScript {
|
|||
dbg!(
|
||||
"Found a parameter with value: {}",
|
||||
parameters.unwrap().get(0).unwrap()
|
||||
)
|
||||
);
|
||||
if m.has_flag(b"foo") {}
|
||||
}
|
||||
|
||||
fn on_before_turn(&self, choice: TurnChoice) {
|
||||
dbg!(
|
||||
"On before turn for user: {}",
|
||||
choice.user().species().name()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,7 +6,7 @@ edition = "2018"
|
|||
|
||||
[dependencies]
|
||||
wee_alloc = "0.4.5"
|
||||
cstr_core = { version = "0.2.5", features = ["nightly"]}
|
||||
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"] }
|
||||
|
@ -14,6 +14,4 @@ paste = { version = "1.0.7" }
|
|||
|
||||
[dev-dependencies]
|
||||
|
||||
[profile.dev]
|
||||
lto = false
|
||||
|
||||
|
|
|
@ -1,18 +0,0 @@
|
|||
use crate::app_interface::StaticData;
|
||||
use crate::{impl_extern_ctor, ExternRef};
|
||||
|
||||
pub struct BattleLibrary {
|
||||
ptr: ExternRef<BattleLibrary>,
|
||||
}
|
||||
|
||||
impl_extern_ctor!(BattleLibrary);
|
||||
|
||||
impl BattleLibrary {
|
||||
pub fn data_library(&self) -> StaticData {
|
||||
unsafe { StaticData::new(battle_library_get_static_data(self.ptr)) }
|
||||
}
|
||||
}
|
||||
|
||||
extern "wasm" {
|
||||
fn battle_library_get_static_data(ptr: ExternRef<BattleLibrary>) -> ExternRef<StaticData>;
|
||||
}
|
|
@ -1,5 +0,0 @@
|
|||
mod battle_library;
|
||||
mod turn_choices;
|
||||
|
||||
pub use battle_library::BattleLibrary;
|
||||
pub use turn_choices::*;
|
|
@ -1 +0,0 @@
|
|||
pub struct BaseTurnChoice {}
|
|
@ -0,0 +1,72 @@
|
|||
use crate::app_interface::{BattleParty, BattleRandom, BattleSide, Pokemon};
|
||||
use crate::handling::cached_value::CachedValue;
|
||||
use crate::handling::Cacheable;
|
||||
use crate::{
|
||||
cached_value, cached_value_getters, wasm_value_getters, DynamicLibrary, ExternRef,
|
||||
ExternalReferenceType, ImmutableList, VecExternRef,
|
||||
};
|
||||
use alloc::rc::Rc;
|
||||
|
||||
struct BattleInner {
|
||||
reference: ExternRef<Battle>,
|
||||
library: CachedValue<DynamicLibrary>,
|
||||
parties: CachedValue<ImmutableList<BattleParty>>,
|
||||
sides: CachedValue<ImmutableList<BattleSide>>,
|
||||
random: CachedValue<BattleRandom>,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Battle {
|
||||
inner: Rc<BattleInner>,
|
||||
}
|
||||
|
||||
impl Battle {
|
||||
pub fn new(reference: ExternRef<Battle>) -> Self {
|
||||
Self::from_ref(reference, &|reference| Self {
|
||||
inner: Rc::new(BattleInner {
|
||||
reference,
|
||||
library: cached_value!({ battle_get_library(reference).get_value().unwrap() }),
|
||||
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() }),
|
||||
}),
|
||||
})
|
||||
}
|
||||
|
||||
cached_value_getters! {
|
||||
pub fn library(&self) -> DynamicLibrary;
|
||||
pub fn parties(&self) -> ImmutableList<BattleParty>;
|
||||
pub fn sides(&self) -> ImmutableList<BattleSide>;
|
||||
}
|
||||
|
||||
pub fn get_pokemon(&self, side: u8, index: u8) -> Option<Pokemon> {
|
||||
unsafe { battle_get_pokemon(self.inner.reference, side, index).get_value() }
|
||||
}
|
||||
}
|
||||
|
||||
wasm_value_getters! {
|
||||
Battle,
|
||||
pub fn can_flee(&self) -> bool;
|
||||
pub fn number_of_sides(&self) -> u8;
|
||||
pub fn pokemon_per_side(&self) -> u8;
|
||||
pub fn has_ended(&self) -> bool;
|
||||
pub fn has_ended_conclusively(&self) -> bool;
|
||||
pub fn winning_side(&self) -> u8;
|
||||
pub fn current_turn(&self) -> u32;
|
||||
}
|
||||
|
||||
crate::handling::cacheable::cacheable!(Battle);
|
||||
|
||||
impl ExternalReferenceType for Battle {
|
||||
fn from_extern_value(reference: ExternRef<Self>) -> Self {
|
||||
Self::new(reference)
|
||||
}
|
||||
}
|
||||
|
||||
extern "wasm" {
|
||||
fn battle_get_library(r: ExternRef<Battle>) -> ExternRef<DynamicLibrary>;
|
||||
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_pokemon(r: ExternRef<Battle>, side: u8, index: u8) -> ExternRef<Pokemon>;
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
use crate::app_interface::Party;
|
||||
use crate::handling::cached_value::CachedValue;
|
||||
use crate::handling::Cacheable;
|
||||
use crate::{cached_value, cached_value_getters, ExternRef, ExternalReferenceType};
|
||||
use alloc::rc::Rc;
|
||||
|
||||
struct BattlePartyInner {
|
||||
reference: ExternRef<BattleParty>,
|
||||
party: CachedValue<Party>,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct BattleParty {
|
||||
inner: Rc<BattlePartyInner>,
|
||||
}
|
||||
|
||||
impl BattleParty {
|
||||
pub fn new(reference: ExternRef<BattleParty>) -> Self {
|
||||
Self::from_ref(reference, &|reference| Self {
|
||||
inner: Rc::new(BattlePartyInner {
|
||||
reference,
|
||||
party: cached_value!({ battle_party_get_party(reference).get_value().unwrap() }),
|
||||
}),
|
||||
})
|
||||
}
|
||||
|
||||
cached_value_getters! {
|
||||
pub fn party(&self) -> Party;
|
||||
}
|
||||
}
|
||||
|
||||
crate::handling::cacheable::cacheable!(BattleParty);
|
||||
|
||||
impl ExternalReferenceType for BattleParty {
|
||||
fn from_extern_value(reference: ExternRef<Self>) -> Self {
|
||||
Self::new(reference)
|
||||
}
|
||||
}
|
||||
|
||||
extern "wasm" {
|
||||
fn battle_party_get_party(r: ExternRef<BattleParty>) -> ExternRef<Party>;
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
use crate::{ExternRef, ExternalReferenceType};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct BattleRandom {
|
||||
reference: ExternRef<Self>,
|
||||
}
|
||||
|
||||
impl BattleRandom {
|
||||
pub fn get(&self) -> i32 {
|
||||
unsafe { battle_random_get(self.reference) }
|
||||
}
|
||||
pub fn get_max(&self, max: i32) -> i32 {
|
||||
unsafe { battle_random_get_max(self.reference, max) }
|
||||
}
|
||||
pub fn get_between(&self, min: i32, max: i32) -> i32 {
|
||||
unsafe { battle_random_get_between(self.reference, min, max) }
|
||||
}
|
||||
// TODO: effect_chance()
|
||||
}
|
||||
|
||||
impl ExternalReferenceType for BattleRandom {
|
||||
fn from_extern_value(reference: ExternRef<Self>) -> Self {
|
||||
Self { reference }
|
||||
}
|
||||
}
|
||||
|
||||
extern "wasm" {
|
||||
fn battle_random_get(r: ExternRef<BattleRandom>) -> i32;
|
||||
fn battle_random_get_max(r: ExternRef<BattleRandom>, max: i32) -> i32;
|
||||
fn battle_random_get_between(r: ExternRef<BattleRandom>, min: i32, max: i32) -> i32;
|
||||
|
||||
}
|
|
@ -0,0 +1,63 @@
|
|||
use crate::app_interface::{Battle, Pokemon};
|
||||
use crate::handling::cached_value::CachedValue;
|
||||
use crate::handling::Cacheable;
|
||||
use crate::{
|
||||
cached_value, cached_value_getters, wasm_value_getters, ExternRef, ExternalReferenceType,
|
||||
};
|
||||
use alloc::rc::Rc;
|
||||
|
||||
struct BattleSideInner {
|
||||
reference: ExternRef<BattleSide>,
|
||||
side_index: CachedValue<u8>,
|
||||
pokemon_per_side: CachedValue<u8>,
|
||||
battle: CachedValue<Battle>,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct BattleSide {
|
||||
inner: Rc<BattleSideInner>,
|
||||
}
|
||||
|
||||
impl BattleSide {
|
||||
pub fn new(reference: ExternRef<Self>) -> Self {
|
||||
Self::from_ref(reference, &|reference| Self {
|
||||
inner: Rc::new(BattleSideInner {
|
||||
reference,
|
||||
side_index: cached_value!({ battleside_get_side_index(reference) }),
|
||||
pokemon_per_side: cached_value!({ battleside_get_pokemon_per_side(reference) }),
|
||||
battle: cached_value!({ battleside_get_battle(reference).get_value().unwrap() }),
|
||||
}),
|
||||
})
|
||||
}
|
||||
|
||||
cached_value_getters! {
|
||||
pub fn side_index(&self) -> u8;
|
||||
pub fn pokemon_per_side(&self) -> u8;
|
||||
pub fn battle(&self) -> Battle;
|
||||
}
|
||||
|
||||
pub fn get_pokemon(&self, index: usize) -> Option<Pokemon> {
|
||||
unsafe { battleside_get_pokemon(self.inner.reference, index).get_value() }
|
||||
}
|
||||
}
|
||||
|
||||
wasm_value_getters! {
|
||||
BattleSide,
|
||||
pub fn has_fled_battle(&self) -> bool;
|
||||
pub fn is_defeated(&self) -> bool;
|
||||
}
|
||||
|
||||
crate::handling::cacheable::cacheable!(BattleSide);
|
||||
|
||||
impl ExternalReferenceType for BattleSide {
|
||||
fn from_extern_value(reference: ExternRef<Self>) -> Self {
|
||||
Self::new(reference)
|
||||
}
|
||||
}
|
||||
|
||||
extern "wasm" {
|
||||
fn battleside_get_side_index(r: ExternRef<BattleSide>) -> u8;
|
||||
fn battleside_get_pokemon_per_side(r: ExternRef<BattleSide>) -> u8;
|
||||
fn battleside_get_battle(r: ExternRef<BattleSide>) -> ExternRef<Battle>;
|
||||
fn battleside_get_pokemon(r: ExternRef<BattleSide>, index: usize) -> ExternRef<Pokemon>;
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
use crate::app_interface::StaticData;
|
||||
use crate::handling::cached_value::CachedValue;
|
||||
use crate::handling::Cacheable;
|
||||
use crate::{cached_value, ExternRef, ExternalReferenceType};
|
||||
use alloc::rc::Rc;
|
||||
|
||||
struct DynamicLibraryInner {
|
||||
ptr: ExternRef<DynamicLibrary>,
|
||||
static_data: CachedValue<StaticData>,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct DynamicLibrary {
|
||||
inner: Rc<DynamicLibraryInner>,
|
||||
}
|
||||
|
||||
crate::handling::cacheable::cacheable!(DynamicLibrary);
|
||||
|
||||
impl DynamicLibrary {
|
||||
pub(crate) fn new(ptr: ExternRef<Self>) -> Self {
|
||||
Self::from_ref(ptr, &|ptr| Self {
|
||||
inner: Rc::new(DynamicLibraryInner {
|
||||
ptr,
|
||||
static_data: cached_value!({
|
||||
dynamic_library_get_static_data(ptr).get_value().unwrap()
|
||||
}),
|
||||
}),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn data_library(&self) -> StaticData {
|
||||
self.inner.static_data.value()
|
||||
}
|
||||
}
|
||||
|
||||
impl ExternalReferenceType for DynamicLibrary {
|
||||
fn from_extern_value(reference: ExternRef<Self>) -> Self {
|
||||
DynamicLibrary::new(reference)
|
||||
}
|
||||
}
|
||||
|
||||
extern "wasm" {
|
||||
fn dynamic_library_get_static_data(ptr: ExternRef<DynamicLibrary>) -> ExternRef<StaticData>;
|
||||
}
|
|
@ -0,0 +1,81 @@
|
|||
use crate::app_interface::MoveData;
|
||||
use crate::handling::cacheable::Cacheable;
|
||||
use crate::handling::cached_value::CachedValue;
|
||||
use crate::{
|
||||
cached_value, cached_value_getters, wasm_value_getters, ExternRef, ExternalReferenceType,
|
||||
};
|
||||
|
||||
use alloc::rc::Rc;
|
||||
|
||||
struct LearnedMoveInner {
|
||||
reference: ExternRef<LearnedMove>,
|
||||
move_data: CachedValue<MoveData>,
|
||||
learn_method: CachedValue<MoveLearnMethod>,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, Default)]
|
||||
#[repr(u8)]
|
||||
pub enum MoveLearnMethod {
|
||||
/// We do not know the learn method.
|
||||
#[default]
|
||||
Unknown = 0,
|
||||
/// The move was learned through level up.
|
||||
Level = 1,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct LearnedMove {
|
||||
inner: Rc<LearnedMoveInner>,
|
||||
}
|
||||
|
||||
crate::handling::cacheable::cacheable!(LearnedMove);
|
||||
|
||||
impl ExternalReferenceType for LearnedMove {
|
||||
fn from_extern_value(reference: ExternRef<Self>) -> Self {
|
||||
Self::new(reference)
|
||||
}
|
||||
}
|
||||
|
||||
impl LearnedMove {
|
||||
pub fn new(reference: ExternRef<Self>) -> Self {
|
||||
Self::from_ref(reference, &|reference| Self {
|
||||
inner: Rc::new(LearnedMoveInner {
|
||||
reference,
|
||||
move_data: cached_value!({
|
||||
learned_move_get_move_data(reference).get_value().unwrap()
|
||||
}),
|
||||
learn_method: cached_value!({ learned_move_get_learn_method(reference) }),
|
||||
}),
|
||||
})
|
||||
}
|
||||
|
||||
cached_value_getters! {
|
||||
pub fn move_data(&self) -> MoveData;
|
||||
pub fn learn_method(&self) -> MoveLearnMethod;
|
||||
}
|
||||
|
||||
pub fn restore_all_uses(&self) {
|
||||
unsafe {
|
||||
learned_move_restore_all_uses(self.inner.reference);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn restore_uses(&self, uses: u8) {
|
||||
unsafe {
|
||||
learned_move_restore_uses(self.inner.reference, uses);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
wasm_value_getters! {
|
||||
LearnedMove,
|
||||
pub fn max_pp(&self) -> u8;
|
||||
pub fn remaining_pp(&self) -> u8;
|
||||
}
|
||||
|
||||
extern "wasm" {
|
||||
fn learned_move_get_move_data(r: ExternRef<LearnedMove>) -> ExternRef<MoveData>;
|
||||
fn learned_move_get_learn_method(r: ExternRef<LearnedMove>) -> MoveLearnMethod;
|
||||
fn learned_move_restore_uses(r: ExternRef<LearnedMove>, uses: u8);
|
||||
fn learned_move_restore_all_uses(r: ExternRef<LearnedMove>);
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
mod battle;
|
||||
mod battle_party;
|
||||
mod battle_random;
|
||||
mod battle_side;
|
||||
mod dynamic_library;
|
||||
mod learned_move;
|
||||
mod party;
|
||||
mod pokemon;
|
||||
mod statistic_set;
|
||||
mod turn_choices;
|
||||
|
||||
pub use battle::*;
|
||||
pub use battle_party::*;
|
||||
pub use battle_random::*;
|
||||
pub use battle_side::*;
|
||||
pub use dynamic_library::DynamicLibrary;
|
||||
pub use learned_move::*;
|
||||
pub use party::*;
|
||||
pub use pokemon::*;
|
||||
pub use statistic_set::*;
|
||||
pub use turn_choices::*;
|
|
@ -0,0 +1,27 @@
|
|||
use crate::app_interface::Pokemon;
|
||||
use crate::{ExternRef, ExternalReferenceType};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Party {
|
||||
reference: ExternRef<Party>,
|
||||
}
|
||||
|
||||
impl Party {
|
||||
pub fn new(reference: ExternRef<Party>) -> Self {
|
||||
Self { reference }
|
||||
}
|
||||
|
||||
pub fn get_pokemon(&self, index: usize) -> Option<Pokemon> {
|
||||
unsafe { party_get_pokemon(self.reference, index).get_value() }
|
||||
}
|
||||
}
|
||||
|
||||
impl ExternalReferenceType for Party {
|
||||
fn from_extern_value(reference: ExternRef<Self>) -> Self {
|
||||
Self::new(reference)
|
||||
}
|
||||
}
|
||||
|
||||
extern "wasm" {
|
||||
fn party_get_pokemon(r: ExternRef<Party>, index: usize) -> ExternRef<Pokemon>;
|
||||
}
|
|
@ -0,0 +1,236 @@
|
|||
use crate::app_interface::ability::{Ability, AbilityIndex};
|
||||
use crate::app_interface::{
|
||||
Battle, ClampedStatisticSet, Form, Gender, Item, LearnedMove, LevelInt, Nature, Species,
|
||||
Statistic, StatisticSet,
|
||||
};
|
||||
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,
|
||||
};
|
||||
use alloc::boxed::Box;
|
||||
use alloc::rc::Rc;
|
||||
use cstr_core::{c_char, CString};
|
||||
|
||||
struct PokemonInner {
|
||||
reference: ExternRef<Pokemon>,
|
||||
library: CachedValue<DynamicLibrary>,
|
||||
// We cache the reference to the data, not the values stored inside, which are dynamic.
|
||||
flat_stats: CachedValue<StatisticSet<u32>>,
|
||||
// We cache the reference to the data, not the values stored inside, which are dynamic.
|
||||
stat_boosts: CachedValue<ClampedStatisticSet<i8>>,
|
||||
// We cache the reference to the data, not the values stored inside, which are dynamic.
|
||||
boosted_stats: CachedValue<StatisticSet<u32>>,
|
||||
// We cache the reference to the data, not the values stored inside, which are dynamic.
|
||||
individual_values: CachedValue<ClampedStatisticSet<u8>>,
|
||||
// We cache the reference to the data, not the values stored inside, which are dynamic.
|
||||
effort_values: CachedValue<ClampedStatisticSet<u8>>,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Pokemon {
|
||||
inner: Rc<PokemonInner>,
|
||||
}
|
||||
|
||||
impl Pokemon {
|
||||
pub(crate) fn new(reference: ExternRef<Self>) -> Self {
|
||||
Self::from_ref(reference, &|reference| Self {
|
||||
inner: Rc::new(PokemonInner {
|
||||
reference,
|
||||
library: cached_value!({ pokemon_get_library(reference).get_value().unwrap() }),
|
||||
flat_stats: cached_value!({
|
||||
pokemon_get_flat_stats(reference).get_value().unwrap()
|
||||
}),
|
||||
stat_boosts: cached_value!({
|
||||
pokemon_get_stat_boosts(reference).get_value().unwrap()
|
||||
}),
|
||||
boosted_stats: cached_value!({
|
||||
pokemon_get_boosted_stats(reference).get_value().unwrap()
|
||||
}),
|
||||
individual_values: cached_value!({
|
||||
pokemon_get_individual_values(reference)
|
||||
.get_value()
|
||||
.unwrap()
|
||||
}),
|
||||
effort_values: cached_value!({
|
||||
pokemon_get_effort_values(reference).get_value().unwrap()
|
||||
}),
|
||||
}),
|
||||
})
|
||||
}
|
||||
|
||||
cached_value_getters! {
|
||||
pub fn library(&self) -> DynamicLibrary;
|
||||
pub fn flat_stats(&self) -> StatisticSet<u32>;
|
||||
pub fn stat_boosts(&self) -> ClampedStatisticSet<i8>;
|
||||
pub fn boosted_stats(&self) -> StatisticSet<u32>;
|
||||
pub fn individual_values(&self) -> ClampedStatisticSet<u8>;
|
||||
pub fn effort_values(&self) -> ClampedStatisticSet<u8>;
|
||||
}
|
||||
|
||||
pub fn has_held_item(&self, name: &str) -> bool {
|
||||
let cstr = CString::new(name).unwrap();
|
||||
unsafe { pokemon_has_held_item(self.inner.reference, cstr.as_ptr()) }
|
||||
}
|
||||
|
||||
pub fn set_held_item(&self, item: &Item) -> Option<Item> {
|
||||
unsafe { pokemon_set_held_item(self.inner.reference, item.reference()).get_value() }
|
||||
}
|
||||
|
||||
pub fn remove_held_item(&self) -> Option<Item> {
|
||||
unsafe { pokemon_remove_held_item(self.inner.reference).get_value() }
|
||||
}
|
||||
|
||||
pub fn consume_held_item(&self) -> bool {
|
||||
unsafe { pokemon_consume_held_item(self.inner.reference) }
|
||||
}
|
||||
|
||||
pub fn max_health(&self) -> u32 {
|
||||
self.boosted_stats().hp()
|
||||
}
|
||||
|
||||
pub fn get_type(&self, index: usize) -> u8 {
|
||||
unsafe { pokemon_get_type(self.inner.reference, index) }
|
||||
}
|
||||
pub fn has_type(&self, type_identifier: u8) -> bool {
|
||||
unsafe { pokemon_has_type(self.inner.reference, type_identifier) }
|
||||
}
|
||||
pub fn has_type_by_name(&self, type_name: &str) -> bool {
|
||||
let type_identifier = self
|
||||
.library()
|
||||
.data_library()
|
||||
.type_library()
|
||||
.get_type_from_name(type_name);
|
||||
if let Some(type_identifier) = type_identifier {
|
||||
return self.has_type(type_identifier);
|
||||
}
|
||||
false
|
||||
}
|
||||
pub fn get_learned_move(&self, index: usize) -> Option<LearnedMove> {
|
||||
unsafe { pokemon_get_learned_move(self.inner.reference, index).get_value() }
|
||||
}
|
||||
pub fn change_stat_boost(
|
||||
&self,
|
||||
stat: Statistic,
|
||||
diff_amount: i8,
|
||||
self_inflicted: bool,
|
||||
) -> bool {
|
||||
unsafe {
|
||||
pokemon_change_stat_boost(self.inner.reference, stat, diff_amount, self_inflicted)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn ability_script(&self) -> Option<&Box<dyn Script>> {
|
||||
unsafe { pokemon_get_ability_script(self.inner.reference).as_ref() }
|
||||
}
|
||||
|
||||
pub fn change_species(&self, species: Species, form: Form) {
|
||||
unsafe {
|
||||
pokemon_change_species(self.inner.reference, species.reference(), form.reference());
|
||||
}
|
||||
}
|
||||
|
||||
pub fn change_form(&self, form: Form) {
|
||||
unsafe {
|
||||
pokemon_change_form(self.inner.reference, form.reference());
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_fainted(&self) -> bool {
|
||||
self.current_health() == 0
|
||||
}
|
||||
|
||||
pub fn damage(&self, damage: u32, source: DamageSource) {
|
||||
unsafe { pokemon_damage(self.inner.reference, damage, source) }
|
||||
}
|
||||
|
||||
pub fn heal(&self, amount: u32, allow_revive: bool) -> bool {
|
||||
unsafe { pokemon_heal(self.inner.reference, amount, allow_revive) }
|
||||
}
|
||||
}
|
||||
|
||||
wasm_reference_getters! {
|
||||
Pokemon,
|
||||
pub fn species(&self) -> Species;
|
||||
pub fn form(&self) -> Form;
|
||||
pub fn active_ability(&self) -> Ability;
|
||||
pub fn nature(&self) -> Nature;
|
||||
}
|
||||
|
||||
wasm_optional_reference_getters! {
|
||||
Pokemon,
|
||||
pub fn display_species(&self) -> Option<Species>;
|
||||
pub fn display_form(&self) -> Option<Form>;
|
||||
pub fn held_item(&self) -> Option<Item>;
|
||||
pub fn battle(&self) -> Option<Battle>;
|
||||
}
|
||||
|
||||
wasm_value_getters! {
|
||||
Pokemon,
|
||||
pub fn level(&self) -> LevelInt;
|
||||
pub fn experience(&self) -> u32;
|
||||
pub fn unique_identifier(&self) -> u32;
|
||||
pub fn gender(&self) -> Gender;
|
||||
pub fn coloring(&self) -> u8;
|
||||
pub fn current_health(&self) -> u32;
|
||||
pub fn weight(&self) -> f32;
|
||||
pub fn height(&self) -> f32;
|
||||
pub fn nickname(&self) -> *const c_char;
|
||||
pub fn real_ability(&self) -> AbilityIndex;
|
||||
pub fn types_length(&self) -> usize;
|
||||
pub fn battle_side_index(&self) -> u8;
|
||||
pub fn battle_index(&self) -> u8;
|
||||
pub fn is_ability_overriden(&self) -> u8;
|
||||
pub fn allowed_experience_gain(&self) -> bool;
|
||||
pub fn is_usable(&self) -> bool;
|
||||
}
|
||||
|
||||
/// A source of damage. This should be as unique as possible.
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
#[repr(u8)]
|
||||
pub enum DamageSource {
|
||||
/// The damage is done by a move.
|
||||
MoveDamage = 0,
|
||||
/// The damage is done by something else.
|
||||
Misc = 1,
|
||||
}
|
||||
|
||||
crate::handling::cacheable::cacheable!(Pokemon);
|
||||
|
||||
impl ExternalReferenceType for Pokemon {
|
||||
fn from_extern_value(reference: ExternRef<Self>) -> Self {
|
||||
Self::new(reference)
|
||||
}
|
||||
}
|
||||
|
||||
extern "wasm" {
|
||||
fn pokemon_get_library(r: ExternRef<Pokemon>) -> ExternRef<DynamicLibrary>;
|
||||
fn pokemon_get_flat_stats(r: ExternRef<Pokemon>) -> ExternRef<StatisticSet<u32>>;
|
||||
fn pokemon_get_stat_boosts(r: ExternRef<Pokemon>) -> ExternRef<ClampedStatisticSet<i8>>;
|
||||
fn pokemon_get_boosted_stats(r: ExternRef<Pokemon>) -> ExternRef<StatisticSet<u32>>;
|
||||
fn pokemon_get_individual_values(r: ExternRef<Pokemon>) -> ExternRef<ClampedStatisticSet<u8>>;
|
||||
fn pokemon_get_effort_values(r: ExternRef<Pokemon>) -> ExternRef<ClampedStatisticSet<u8>>;
|
||||
fn pokemon_has_held_item(r: ExternRef<Pokemon>, name: *const c_char) -> bool;
|
||||
fn pokemon_set_held_item(r: ExternRef<Pokemon>, item: ExternRef<Item>) -> ExternRef<Item>;
|
||||
fn pokemon_remove_held_item(r: ExternRef<Pokemon>) -> ExternRef<Item>;
|
||||
fn pokemon_consume_held_item(r: ExternRef<Pokemon>) -> bool;
|
||||
fn pokemon_get_type(r: ExternRef<Pokemon>, index: usize) -> u8;
|
||||
fn pokemon_has_type(r: ExternRef<Pokemon>, identifier: u8) -> bool;
|
||||
fn pokemon_get_learned_move(r: ExternRef<Pokemon>, index: usize) -> ExternRef<LearnedMove>;
|
||||
fn pokemon_change_stat_boost(
|
||||
r: ExternRef<Pokemon>,
|
||||
tat: Statistic,
|
||||
diff_amount: i8,
|
||||
self_inflicted: bool,
|
||||
) -> bool;
|
||||
fn pokemon_get_ability_script(r: ExternRef<Pokemon>) -> *const Box<dyn Script>;
|
||||
fn pokemon_change_species(
|
||||
r: ExternRef<Pokemon>,
|
||||
species: ExternRef<Species>,
|
||||
form: ExternRef<Form>,
|
||||
);
|
||||
fn pokemon_change_form(r: ExternRef<Pokemon>, form: ExternRef<Form>);
|
||||
fn pokemon_damage(r: ExternRef<Pokemon>, damage: u32, source: DamageSource);
|
||||
fn pokemon_heal(r: ExternRef<Pokemon>, amount: u32, allow_revive: bool) -> bool;
|
||||
}
|
|
@ -0,0 +1,194 @@
|
|||
use crate::app_interface::Statistic;
|
||||
use crate::{ExternRef, ExternalReferenceType};
|
||||
use core::convert::{TryFrom, TryInto};
|
||||
use core::fmt::Debug;
|
||||
use core::marker::PhantomData;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct StatisticSet<T>
|
||||
where
|
||||
T: TryFrom<i64>,
|
||||
T: TryInto<i64>,
|
||||
{
|
||||
reference: ExternRef<Self>,
|
||||
_p: PhantomData<T>,
|
||||
}
|
||||
|
||||
impl<T> StatisticSet<T>
|
||||
where
|
||||
T: TryFrom<i64>,
|
||||
T: TryInto<i64>,
|
||||
<T as TryFrom<i64>>::Error: Debug,
|
||||
<T as TryInto<i64>>::Error: Debug,
|
||||
{
|
||||
pub(crate) fn new(reference: ExternRef<Self>) -> Self {
|
||||
Self {
|
||||
reference,
|
||||
_p: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn hp(&self) -> T {
|
||||
self.get_stat(Statistic::HP)
|
||||
}
|
||||
pub fn attack(&self) -> T {
|
||||
self.get_stat(Statistic::Attack)
|
||||
}
|
||||
pub fn defense(&self) -> T {
|
||||
self.get_stat(Statistic::Defense)
|
||||
}
|
||||
pub fn special_attack(&self) -> T {
|
||||
self.get_stat(Statistic::SpecialAttack)
|
||||
}
|
||||
pub fn special_defense(&self) -> T {
|
||||
self.get_stat(Statistic::SpecialDefense)
|
||||
}
|
||||
pub fn speed(&self) -> T {
|
||||
self.get_stat(Statistic::Speed)
|
||||
}
|
||||
|
||||
pub fn get_stat(&self, stat: Statistic) -> T {
|
||||
unsafe {
|
||||
statistic_set_get(self.reference.cast(), stat)
|
||||
.try_into()
|
||||
.unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_stat(&self, stat: Statistic, value: T) {
|
||||
unsafe { statistic_set_set(self.reference.cast(), stat, value.try_into().unwrap()) }
|
||||
}
|
||||
|
||||
pub fn increase_stat(&self, stat: Statistic, value: T) {
|
||||
unsafe {
|
||||
statistic_set_increase_stat(self.reference.cast(), stat, value.try_into().unwrap())
|
||||
}
|
||||
}
|
||||
pub fn decrease_stat(&self, stat: Statistic, value: T) {
|
||||
unsafe {
|
||||
statistic_set_decrease_stat(self.reference.cast(), stat, value.try_into().unwrap())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> ExternalReferenceType for StatisticSet<T>
|
||||
where
|
||||
T: TryFrom<i64>,
|
||||
T: TryInto<i64>,
|
||||
<T as TryFrom<i64>>::Error: Debug,
|
||||
<T as TryInto<i64>>::Error: Debug,
|
||||
{
|
||||
fn from_extern_value(reference: ExternRef<Self>) -> Self {
|
||||
StatisticSet::<T>::new(reference)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct ClampedStatisticSet<T>
|
||||
where
|
||||
T: TryFrom<i64>,
|
||||
T: TryInto<i64>,
|
||||
{
|
||||
reference: ExternRef<Self>,
|
||||
_p: PhantomData<T>,
|
||||
}
|
||||
|
||||
impl<T> ClampedStatisticSet<T>
|
||||
where
|
||||
T: TryFrom<i64>,
|
||||
T: TryInto<i64>,
|
||||
<T as TryFrom<i64>>::Error: Debug,
|
||||
<T as TryInto<i64>>::Error: Debug,
|
||||
{
|
||||
pub(crate) fn new(reference: ExternRef<Self>) -> Self {
|
||||
Self {
|
||||
reference,
|
||||
_p: Default::default(),
|
||||
}
|
||||
}
|
||||
pub fn hp(&self) -> T {
|
||||
self.get_stat(Statistic::HP)
|
||||
}
|
||||
pub fn attack(&self) -> T {
|
||||
self.get_stat(Statistic::Attack)
|
||||
}
|
||||
pub fn defense(&self) -> T {
|
||||
self.get_stat(Statistic::Defense)
|
||||
}
|
||||
pub fn special_attack(&self) -> T {
|
||||
self.get_stat(Statistic::SpecialAttack)
|
||||
}
|
||||
pub fn special_defense(&self) -> T {
|
||||
self.get_stat(Statistic::SpecialDefense)
|
||||
}
|
||||
pub fn speed(&self) -> T {
|
||||
self.get_stat(Statistic::Speed)
|
||||
}
|
||||
|
||||
pub fn get_stat(&self, stat: Statistic) -> T {
|
||||
unsafe {
|
||||
clamped_statistic_set_get(self.reference.cast(), stat)
|
||||
.try_into()
|
||||
.unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_stat(&self, stat: Statistic, value: T) {
|
||||
unsafe { clamped_statistic_set_set(self.reference.cast(), stat, value.try_into().unwrap()) }
|
||||
}
|
||||
|
||||
pub fn increase_stat(&self, stat: Statistic, value: T) -> bool {
|
||||
unsafe {
|
||||
clamped_statistic_set_increase_stat(
|
||||
self.reference.cast(),
|
||||
stat,
|
||||
value.try_into().unwrap(),
|
||||
)
|
||||
}
|
||||
}
|
||||
pub fn decrease_stat(&self, stat: Statistic, value: T) -> bool {
|
||||
unsafe {
|
||||
clamped_statistic_set_decrease_stat(
|
||||
self.reference.cast(),
|
||||
stat,
|
||||
value.try_into().unwrap(),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> ExternalReferenceType for ClampedStatisticSet<T>
|
||||
where
|
||||
T: TryFrom<i64>,
|
||||
T: TryInto<i64>,
|
||||
<T as TryFrom<i64>>::Error: Debug,
|
||||
<T as TryInto<i64>>::Error: Debug,
|
||||
{
|
||||
fn from_extern_value(reference: ExternRef<Self>) -> Self {
|
||||
ClampedStatisticSet::<T>::new(reference)
|
||||
}
|
||||
}
|
||||
|
||||
extern "wasm" {
|
||||
fn statistic_set_get(r: ExternRef<StatisticSet<i64>>, stat: Statistic) -> i64;
|
||||
fn statistic_set_set(r: ExternRef<StatisticSet<i64>>, stat: Statistic, value: i64);
|
||||
fn statistic_set_increase_stat(r: ExternRef<StatisticSet<i64>>, stat: Statistic, value: i64);
|
||||
fn statistic_set_decrease_stat(r: ExternRef<StatisticSet<i64>>, stat: Statistic, value: i64);
|
||||
|
||||
fn clamped_statistic_set_get(r: ExternRef<ClampedStatisticSet<i64>>, stat: Statistic) -> i64;
|
||||
fn clamped_statistic_set_set(
|
||||
r: ExternRef<ClampedStatisticSet<i64>>,
|
||||
stat: Statistic,
|
||||
value: i64,
|
||||
);
|
||||
fn clamped_statistic_set_increase_stat(
|
||||
r: ExternRef<ClampedStatisticSet<i64>>,
|
||||
stat: Statistic,
|
||||
value: i64,
|
||||
) -> bool;
|
||||
fn clamped_statistic_set_decrease_stat(
|
||||
r: ExternRef<ClampedStatisticSet<i64>>,
|
||||
stat: Statistic,
|
||||
value: i64,
|
||||
) -> bool;
|
||||
}
|
|
@ -0,0 +1,78 @@
|
|||
use crate::app_interface::Pokemon;
|
||||
use crate::handling::cached_value::CachedValue;
|
||||
use crate::handling::temporary::Temporary;
|
||||
use crate::{cached_value, ExternRef, ExternalReferenceType};
|
||||
use alloc::rc::Rc;
|
||||
|
||||
struct BaseTurnChoiceData {
|
||||
reference: ExternRef<TurnChoice>,
|
||||
user: CachedValue<Pokemon>,
|
||||
}
|
||||
|
||||
struct MoveTurnChoiceDataInner {
|
||||
base: BaseTurnChoiceData,
|
||||
}
|
||||
#[derive(Clone)]
|
||||
struct MoveTurnChoiceDataTemporary {
|
||||
inner: Rc<MoveTurnChoiceDataInner>,
|
||||
}
|
||||
pub struct MoveTurnChoiceData {
|
||||
temp: Temporary<MoveTurnChoiceDataTemporary>,
|
||||
}
|
||||
|
||||
pub enum TurnChoice {
|
||||
Move(MoveTurnChoiceData),
|
||||
Item(),
|
||||
Switch(),
|
||||
Flee,
|
||||
Pass,
|
||||
}
|
||||
|
||||
impl TurnChoice {
|
||||
pub fn user(&self) -> Pokemon {
|
||||
match self {
|
||||
TurnChoice::Move(data) => data.temp.value().inner.base.user.value(),
|
||||
_ => panic!("Unknown turn choice type"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ExternalReferenceType for TurnChoice {
|
||||
fn from_extern_value(reference: ExternRef<Self>) -> Self {
|
||||
let kind = unsafe { turn_choice_get_kind(reference) };
|
||||
match kind {
|
||||
0 => TurnChoice::Move(MoveTurnChoiceData {
|
||||
temp: Temporary::from_reference(reference.cast()),
|
||||
}),
|
||||
_ => panic!("Unknown turn choice type"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ExternalReferenceType for MoveTurnChoiceDataTemporary {
|
||||
fn from_extern_value(reference: ExternRef<Self>) -> Self {
|
||||
Self {
|
||||
inner: Rc::new(MoveTurnChoiceDataInner {
|
||||
base: BaseTurnChoiceData {
|
||||
reference: reference.cast(),
|
||||
user: cached_value!({
|
||||
turn_choice_get_user(reference.cast()).get_value().unwrap()
|
||||
}),
|
||||
},
|
||||
}),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extern "wasm" {
|
||||
fn turn_choice_get_kind(r: ExternRef<TurnChoice>) -> u8;
|
||||
fn turn_choice_get_user(r: ExternRef<TurnChoice>) -> ExternRef<Pokemon>;
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
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"),
|
||||
}
|
||||
}
|
|
@ -1,73 +0,0 @@
|
|||
use crate::{impl_extern_ctor, ExternRef, ExternalReferenceType, StringKey};
|
||||
use alloc::collections::BTreeMap;
|
||||
use move_library::MoveLibrary;
|
||||
use spin::rwlock::RwLock;
|
||||
|
||||
pub mod item_library;
|
||||
pub mod move_library;
|
||||
|
||||
use crate::handling::Cacheable;
|
||||
pub use item_library::*;
|
||||
pub use move_library::*;
|
||||
|
||||
pub struct StaticData {
|
||||
ptr: ExternRef<Self>,
|
||||
}
|
||||
|
||||
impl_extern_ctor!(StaticData);
|
||||
impl StaticData {
|
||||
pub fn move_library(&self) -> MoveLibrary {
|
||||
unsafe { MoveLibrary::new(static_data_get_move_library(self.ptr)) }
|
||||
}
|
||||
}
|
||||
|
||||
extern "wasm" {
|
||||
fn static_data_get_move_library(ptr: ExternRef<StaticData>) -> ExternRef<MoveLibrary>;
|
||||
}
|
||||
|
||||
pub trait DataLibrary<T>: Cacheable
|
||||
where
|
||||
T: ExternalReferenceType,
|
||||
T: Clone,
|
||||
{
|
||||
fn get_cache(&self) -> &RwLock<BTreeMap<u32, T>>;
|
||||
fn get_self_ref(&self) -> ExternRef<Self>
|
||||
where
|
||||
Self: Sized;
|
||||
fn _get_ref_by_name(ptr: ExternRef<Self>, name: ExternRef<StringKey>) -> ExternRef<T>
|
||||
where
|
||||
Self: Sized;
|
||||
fn _get_ref_by_hash(ptr: ExternRef<Self>, hash: u32) -> ExternRef<T>
|
||||
where
|
||||
Self: Sized;
|
||||
|
||||
fn get(&self, name: &StringKey) -> Option<T>
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
if let Some(v) = self.get_cache().read().get(&name.hash()) {
|
||||
return Some(v.clone());
|
||||
}
|
||||
|
||||
let v = Self::_get_ref_by_name(self.get_self_ref(), name.ptr()).get_value();
|
||||
if let Some(v) = &v {
|
||||
self.get_cache().write().insert(name.hash(), v.clone());
|
||||
}
|
||||
v
|
||||
}
|
||||
|
||||
fn get_by_hash(&self, hash: u32) -> Option<T>
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
if let Some(v) = self.get_cache().read().get(&hash) {
|
||||
return Some(v.clone());
|
||||
}
|
||||
|
||||
let v = Self::_get_ref_by_hash(self.get_self_ref(), hash).get_value();
|
||||
if let Some(v) = &v {
|
||||
self.get_cache().write().insert(hash, v.clone());
|
||||
}
|
||||
v
|
||||
}
|
||||
}
|
|
@ -1,149 +0,0 @@
|
|||
use crate::handling::cached_value::CachedValue;
|
||||
use crate::handling::Cacheable;
|
||||
use crate::{
|
||||
cached_value, ExternRef, ExternalReferenceType, FFIArray, ImmutableList, StringKey,
|
||||
VecExternRef,
|
||||
};
|
||||
use alloc::rc::Rc;
|
||||
use alloc::vec::Vec;
|
||||
|
||||
#[repr(u8)]
|
||||
pub enum Gender {
|
||||
Male = 0,
|
||||
Female = 1,
|
||||
Genderless = 2,
|
||||
}
|
||||
|
||||
#[repr(u8)]
|
||||
pub enum Statistic {
|
||||
HP = 0,
|
||||
Attack = 1,
|
||||
Defense = 2,
|
||||
SpecialAttack = 3,
|
||||
SpecialDefense = 4,
|
||||
Speed = 5,
|
||||
}
|
||||
|
||||
pub struct ImmutableStatisticSetInner {
|
||||
ptr: ExternRef<ImmutableStatisticSet>,
|
||||
/// The health point stat value.
|
||||
hp: CachedValue<u16>,
|
||||
/// The physical attack stat value.
|
||||
attack: CachedValue<u16>,
|
||||
/// The physical defense stat value.
|
||||
defense: CachedValue<u16>,
|
||||
/// The special attack stat value.
|
||||
special_attack: CachedValue<u16>,
|
||||
/// The special defense stat value.
|
||||
special_defense: CachedValue<u16>,
|
||||
/// The speed stat value.
|
||||
speed: CachedValue<u16>,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct ImmutableStatisticSet {
|
||||
inner: Rc<ImmutableStatisticSetInner>,
|
||||
}
|
||||
|
||||
impl ImmutableStatisticSet {
|
||||
pub(crate) fn new(ptr: ExternRef<Self>) -> Self {
|
||||
Self::from_ref(ptr, &|ptr| Self {
|
||||
inner: Rc::new(ImmutableStatisticSetInner {
|
||||
ptr,
|
||||
hp: cached_value!({ static_statistics_set_get_hp(ptr) }),
|
||||
attack: cached_value!({ static_statistics_set_get_attack(ptr) }),
|
||||
defense: cached_value!({ static_statistics_set_get_defense(ptr) }),
|
||||
special_attack: cached_value!({ static_statistics_set_get_special_attack(ptr) }),
|
||||
special_defense: cached_value!({ static_statistics_set_get_special_defense(ptr) }),
|
||||
speed: cached_value!({ static_statistics_set_get_speed(ptr) }),
|
||||
}),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn hp(&self) -> u16 {
|
||||
self.inner.hp.value()
|
||||
}
|
||||
pub fn attack(&self) -> u16 {
|
||||
self.inner.attack.value()
|
||||
}
|
||||
pub fn defense(&self) -> u16 {
|
||||
self.inner.defense.value()
|
||||
}
|
||||
pub fn special_attack(&self) -> u16 {
|
||||
self.inner.special_attack.value()
|
||||
}
|
||||
pub fn special_defense(&self) -> u16 {
|
||||
self.inner.special_defense.value()
|
||||
}
|
||||
pub fn speed(&self) -> u16 {
|
||||
self.inner.speed.value()
|
||||
}
|
||||
}
|
||||
|
||||
struct FormInner {
|
||||
ptr: ExternRef<Form>,
|
||||
name: CachedValue<StringKey>,
|
||||
height: CachedValue<f32>,
|
||||
weight: CachedValue<f32>,
|
||||
types: CachedValue<Vec<u8>>,
|
||||
base_experience: CachedValue<u32>,
|
||||
base_stats: CachedValue<ImmutableStatisticSet>,
|
||||
abilities: CachedValue<ImmutableList<StringKey>>,
|
||||
hidden_abilities: CachedValue<ImmutableList<StringKey>>,
|
||||
// moves: CachedValue<LearnableMoves>,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Form {
|
||||
inner: Rc<FormInner>,
|
||||
}
|
||||
|
||||
impl Form {
|
||||
pub(crate) fn new(ptr: ExternRef<Self>) -> Self {
|
||||
Self::from_ref(ptr, &|ptr| Self {
|
||||
inner: Rc::new(FormInner {
|
||||
ptr,
|
||||
name: cached_value!({ form_get_name(ptr).get_value().unwrap() }),
|
||||
height: cached_value!({ form_get_height(ptr) }),
|
||||
weight: cached_value!({ form_get_weight(ptr) }),
|
||||
types: cached_value!({
|
||||
let raw = form_get_types(ptr);
|
||||
Vec::from_raw_parts(raw.ptr(), raw.len(), raw.len())
|
||||
}),
|
||||
base_experience: cached_value!({ form_get_base_experience(ptr) }),
|
||||
base_stats: cached_value!({ form_get_base_stats(ptr).get_value().unwrap() }),
|
||||
abilities: cached_value!({ form_get_abilities(ptr).get_immutable_list() }),
|
||||
hidden_abilities: cached_value!({
|
||||
form_get_hidden_abilities(ptr).get_immutable_list()
|
||||
}),
|
||||
}),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl ExternalReferenceType for ImmutableStatisticSet {
|
||||
fn from_extern_value(reference: ExternRef<Self>) -> Self {
|
||||
ImmutableStatisticSet::new(reference)
|
||||
}
|
||||
}
|
||||
|
||||
crate::handling::cacheable::cacheable!(ImmutableStatisticSet);
|
||||
crate::handling::cacheable::cacheable!(Form);
|
||||
|
||||
extern "wasm" {
|
||||
fn static_statistics_set_get_hp(r: ExternRef<ImmutableStatisticSet>) -> u16;
|
||||
fn static_statistics_set_get_attack(r: ExternRef<ImmutableStatisticSet>) -> u16;
|
||||
fn static_statistics_set_get_defense(r: ExternRef<ImmutableStatisticSet>) -> u16;
|
||||
fn static_statistics_set_get_special_attack(r: ExternRef<ImmutableStatisticSet>) -> u16;
|
||||
fn static_statistics_set_get_special_defense(r: ExternRef<ImmutableStatisticSet>) -> u16;
|
||||
fn static_statistics_set_get_speed(r: ExternRef<ImmutableStatisticSet>) -> u16;
|
||||
|
||||
fn form_get_name(r: ExternRef<Form>) -> ExternRef<StringKey>;
|
||||
fn form_get_height(r: ExternRef<Form>) -> f32;
|
||||
fn form_get_weight(r: ExternRef<Form>) -> f32;
|
||||
fn form_get_types(r: ExternRef<Form>) -> FFIArray<u8>;
|
||||
fn form_get_base_experience(r: ExternRef<Form>) -> u32;
|
||||
fn form_get_base_stats(r: ExternRef<Form>) -> ExternRef<ImmutableStatisticSet>;
|
||||
fn form_get_abilities(r: ExternRef<Form>) -> VecExternRef<StringKey>;
|
||||
fn form_get_hidden_abilities(r: ExternRef<Form>) -> VecExternRef<StringKey>;
|
||||
}
|
|
@ -1,9 +1,9 @@
|
|||
pub mod battling;
|
||||
pub mod library;
|
||||
pub mod dynamic_data;
|
||||
pub mod list;
|
||||
pub mod static_data;
|
||||
pub mod string_key;
|
||||
|
||||
pub use battling::*;
|
||||
pub use library::*;
|
||||
pub use dynamic_data::*;
|
||||
pub use static_data::*;
|
||||
pub use string_key::get_hash;
|
||||
pub use string_key::StringKey;
|
||||
|
|
|
@ -0,0 +1,60 @@
|
|||
use crate::handling::cacheable::Cacheable;
|
||||
use crate::handling::cached_value::CachedValue;
|
||||
use crate::{
|
||||
cached_value, cached_value_getters, EffectParameter, ExternRef, ExternalReferenceType,
|
||||
ImmutableList, StringKey, VecExternRef,
|
||||
};
|
||||
use alloc::rc::Rc;
|
||||
|
||||
struct AbilityInner {
|
||||
reference: ExternRef<Ability>,
|
||||
name: CachedValue<StringKey>,
|
||||
effect: CachedValue<StringKey>,
|
||||
parameters: CachedValue<ImmutableList<EffectParameter>>,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Ability {
|
||||
inner: Rc<AbilityInner>,
|
||||
}
|
||||
|
||||
impl Ability {
|
||||
pub fn new(reference: ExternRef<Self>) -> Self {
|
||||
Self::from_ref(reference, &|reference| Self {
|
||||
inner: Rc::new(AbilityInner {
|
||||
reference,
|
||||
name: cached_value!({ ability_get_name(reference).get_value().unwrap() }),
|
||||
effect: cached_value!({ ability_get_effect(reference).get_value().unwrap() }),
|
||||
parameters: cached_value!({
|
||||
ability_get_parameters(reference).get_immutable_list()
|
||||
}),
|
||||
}),
|
||||
})
|
||||
}
|
||||
|
||||
cached_value_getters! {
|
||||
pub fn name(&self) -> StringKey;
|
||||
pub fn effect(&self) -> StringKey;
|
||||
}
|
||||
}
|
||||
|
||||
impl ExternalReferenceType for Ability {
|
||||
fn from_extern_value(reference: ExternRef<Self>) -> Self {
|
||||
Self::new(reference)
|
||||
}
|
||||
}
|
||||
|
||||
crate::handling::cacheable::cacheable!(Ability);
|
||||
|
||||
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
||||
#[repr(C)]
|
||||
pub struct AbilityIndex {
|
||||
pub hidden: bool,
|
||||
pub index: u8,
|
||||
}
|
||||
|
||||
extern "wasm" {
|
||||
fn ability_get_name(r: ExternRef<Ability>) -> ExternRef<StringKey>;
|
||||
fn ability_get_effect(r: ExternRef<Ability>) -> ExternRef<StringKey>;
|
||||
fn ability_get_parameters(r: ExternRef<Ability>) -> VecExternRef<EffectParameter>;
|
||||
}
|
|
@ -1,6 +1,5 @@
|
|||
use crate::app_interface::{DataLibrary, Item};
|
||||
use crate::handling::Cacheable;
|
||||
use crate::{ExternRef, StringKey};
|
||||
use crate::{ExternRef, ExternalReferenceType, StringKey};
|
||||
use alloc::collections::BTreeMap;
|
||||
use alloc::rc::Rc;
|
||||
use spin::rwlock::RwLock;
|
||||
|
@ -32,7 +31,7 @@ impl DataLibrary<Item> for ItemLibrary {
|
|||
}
|
||||
|
||||
fn get_self_ref(&self) -> ExternRef<Self> {
|
||||
self.inner.ptr.clone()
|
||||
self.inner.ptr
|
||||
}
|
||||
|
||||
fn _get_ref_by_name(ptr: ExternRef<Self>, name: ExternRef<StringKey>) -> ExternRef<Item> {
|
||||
|
@ -44,17 +43,14 @@ impl DataLibrary<Item> for ItemLibrary {
|
|||
}
|
||||
}
|
||||
|
||||
impl Cacheable for ItemLibrary {
|
||||
fn get_cache<'a>() -> &'a mut BTreeMap<ExternRef<Self>, Self>
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
unsafe { &mut CACHE }
|
||||
crate::handling::cacheable::cacheable!(ItemLibrary);
|
||||
|
||||
impl ExternalReferenceType for ItemLibrary {
|
||||
fn from_extern_value(reference: ExternRef<Self>) -> Self {
|
||||
Self::new(reference)
|
||||
}
|
||||
}
|
||||
|
||||
static mut CACHE: BTreeMap<ExternRef<ItemLibrary>, ItemLibrary> = BTreeMap::new();
|
||||
|
||||
extern "wasm" {
|
||||
fn move_library_get_move(
|
||||
ptr: ExternRef<ItemLibrary>,
|
|
@ -0,0 +1,149 @@
|
|||
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;
|
||||
|
||||
pub mod item_library;
|
||||
pub mod move_library;
|
||||
pub mod species_library;
|
||||
pub mod type_library;
|
||||
|
||||
use crate::app_interface::species_library::SpeciesLibrary;
|
||||
use crate::app_interface::type_library::TypeLibrary;
|
||||
use crate::app_interface::LevelInt;
|
||||
use crate::handling::cached_value::CachedValue;
|
||||
use crate::handling::Cacheable;
|
||||
pub use item_library::*;
|
||||
pub use move_library::*;
|
||||
|
||||
struct StaticDataInner {
|
||||
reference: ExternRef<StaticData>,
|
||||
move_library: CachedValue<MoveLibrary>,
|
||||
item_library: CachedValue<ItemLibrary>,
|
||||
species_library: CachedValue<SpeciesLibrary>,
|
||||
type_library: CachedValue<TypeLibrary>,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct StaticData {
|
||||
inner: Rc<StaticDataInner>,
|
||||
}
|
||||
|
||||
impl StaticData {
|
||||
pub(crate) fn new(reference: ExternRef<StaticData>) -> Self {
|
||||
Self::from_ref(reference, &|reference| Self {
|
||||
inner: Rc::new(StaticDataInner {
|
||||
reference,
|
||||
move_library: cached_value!({
|
||||
static_data_get_move_library(reference).get_value().unwrap()
|
||||
}),
|
||||
item_library: cached_value!({
|
||||
static_data_get_item_library(reference).get_value().unwrap()
|
||||
}),
|
||||
species_library: cached_value!({
|
||||
static_data_get_species_library(reference)
|
||||
.get_value()
|
||||
.unwrap()
|
||||
}),
|
||||
type_library: cached_value!({
|
||||
static_data_get_type_library(reference).get_value().unwrap()
|
||||
}),
|
||||
}),
|
||||
})
|
||||
}
|
||||
|
||||
cached_value_getters! {
|
||||
pub fn move_library(&self) -> MoveLibrary;
|
||||
pub fn item_library(&self) -> ItemLibrary;
|
||||
pub fn species_library(&self) -> SpeciesLibrary;
|
||||
pub fn type_library(&self) -> TypeLibrary;
|
||||
}
|
||||
}
|
||||
|
||||
crate::handling::cacheable::cacheable!(StaticData);
|
||||
|
||||
impl ExternalReferenceType for StaticData {
|
||||
fn from_extern_value(reference: ExternRef<Self>) -> Self {
|
||||
StaticData::new(reference)
|
||||
}
|
||||
}
|
||||
|
||||
struct LibrarySettingsInner {
|
||||
maximum_level: CachedValue<LevelInt>,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct LibrarySettings {
|
||||
inner: Rc<LibrarySettingsInner>,
|
||||
}
|
||||
|
||||
impl LibrarySettings {
|
||||
pub(crate) fn new(ptr: ExternRef<LibrarySettings>) -> Self {
|
||||
Self {
|
||||
inner: Rc::new(LibrarySettingsInner {
|
||||
maximum_level: cached_value!({ library_settings_get_maximum_level(ptr) }),
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
cached_value_getters! {
|
||||
pub fn maximum_level(&self) -> LevelInt;
|
||||
}
|
||||
}
|
||||
|
||||
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 library_settings_get_maximum_level(ptr: ExternRef<LibrarySettings>) -> LevelInt;
|
||||
}
|
||||
|
||||
pub trait DataLibrary<T>: Cacheable
|
||||
where
|
||||
T: ExternalReferenceType,
|
||||
T: Clone,
|
||||
{
|
||||
fn get_cache(&self) -> &RwLock<BTreeMap<u32, T>>;
|
||||
fn get_self_ref(&self) -> ExternRef<Self>
|
||||
where
|
||||
Self: Sized;
|
||||
fn _get_ref_by_name(ptr: ExternRef<Self>, name: ExternRef<StringKey>) -> ExternRef<T>
|
||||
where
|
||||
Self: Sized;
|
||||
fn _get_ref_by_hash(ptr: ExternRef<Self>, hash: u32) -> ExternRef<T>
|
||||
where
|
||||
Self: Sized;
|
||||
|
||||
fn get(&self, name: &StringKey) -> Option<T>
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
if let Some(v) = self.get_cache().read().get(&name.hash()) {
|
||||
return Some(v.clone());
|
||||
}
|
||||
|
||||
let v = Self::_get_ref_by_name(self.get_self_ref(), name.ptr()).get_value();
|
||||
if let Some(v) = &v {
|
||||
self.get_cache().write().insert(name.hash(), v.clone());
|
||||
}
|
||||
v
|
||||
}
|
||||
|
||||
fn get_by_hash(&self, hash: u32) -> Option<T>
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
if let Some(v) = self.get_cache().read().get(&hash) {
|
||||
return Some(v.clone());
|
||||
}
|
||||
|
||||
let v = Self::_get_ref_by_hash(self.get_self_ref(), hash).get_value();
|
||||
if let Some(v) = &v {
|
||||
self.get_cache().write().insert(hash, v.clone());
|
||||
}
|
||||
v
|
||||
}
|
||||
}
|
|
@ -1,7 +1,6 @@
|
|||
use crate::app_interface::data_libraries::DataLibrary;
|
||||
use crate::app_interface::{MoveData, StringKey};
|
||||
use crate::handling::Cacheable;
|
||||
use crate::ExternRef;
|
||||
use crate::{ExternRef, ExternalReferenceType};
|
||||
use alloc::collections::BTreeMap;
|
||||
use alloc::rc::Rc;
|
||||
use spin::RwLock;
|
||||
|
@ -33,7 +32,7 @@ impl DataLibrary<MoveData> for MoveLibrary {
|
|||
}
|
||||
|
||||
fn get_self_ref(&self) -> ExternRef<Self> {
|
||||
self.inner.ptr.clone()
|
||||
self.inner.ptr
|
||||
}
|
||||
|
||||
fn _get_ref_by_name(ptr: ExternRef<Self>, name: ExternRef<StringKey>) -> ExternRef<MoveData> {
|
||||
|
@ -45,17 +44,14 @@ impl DataLibrary<MoveData> for MoveLibrary {
|
|||
}
|
||||
}
|
||||
|
||||
impl Cacheable for MoveLibrary {
|
||||
fn get_cache<'a>() -> &'a mut BTreeMap<ExternRef<Self>, Self>
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
unsafe { &mut CACHE }
|
||||
crate::handling::cacheable::cacheable!(MoveLibrary);
|
||||
|
||||
impl ExternalReferenceType for MoveLibrary {
|
||||
fn from_extern_value(reference: ExternRef<Self>) -> Self {
|
||||
Self::new(reference)
|
||||
}
|
||||
}
|
||||
|
||||
static mut CACHE: BTreeMap<ExternRef<MoveLibrary>, MoveLibrary> = BTreeMap::new();
|
||||
|
||||
extern "wasm" {
|
||||
fn move_library_get_move(
|
||||
ptr: ExternRef<MoveLibrary>,
|
|
@ -0,0 +1,63 @@
|
|||
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>>,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct SpeciesLibrary {
|
||||
inner: Rc<SpeciesLibraryInner>,
|
||||
}
|
||||
|
||||
impl SpeciesLibrary {
|
||||
pub(crate) fn new(ptr: ExternRef<SpeciesLibrary>) -> Self {
|
||||
Self {
|
||||
inner: Rc::new(SpeciesLibraryInner {
|
||||
ptr,
|
||||
cache: Default::default(),
|
||||
}),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl DataLibrary<Species> for SpeciesLibrary {
|
||||
fn get_cache(&self) -> &spin::rwlock::RwLock<BTreeMap<u32, Species>> {
|
||||
&self.inner.cache
|
||||
}
|
||||
|
||||
fn get_self_ref(&self) -> ExternRef<Self> {
|
||||
self.inner.ptr
|
||||
}
|
||||
|
||||
fn _get_ref_by_name(ptr: ExternRef<Self>, name: ExternRef<StringKey>) -> ExternRef<Species> {
|
||||
unsafe { species_library_get_species(ptr, name) }
|
||||
}
|
||||
|
||||
fn _get_ref_by_hash(ptr: ExternRef<Self>, hash: u32) -> ExternRef<Species> {
|
||||
unsafe { species_library_get_species_by_hash(ptr, hash) }
|
||||
}
|
||||
}
|
||||
|
||||
crate::handling::cacheable::cacheable!(SpeciesLibrary);
|
||||
|
||||
impl ExternalReferenceType for SpeciesLibrary {
|
||||
fn from_extern_value(reference: ExternRef<Self>) -> Self {
|
||||
Self::new(reference)
|
||||
}
|
||||
}
|
||||
|
||||
extern "wasm" {
|
||||
fn species_library_get_species(
|
||||
ptr: ExternRef<SpeciesLibrary>,
|
||||
name: ExternRef<StringKey>,
|
||||
) -> ExternRef<Species>;
|
||||
fn species_library_get_species_by_hash(
|
||||
ptr: ExternRef<SpeciesLibrary>,
|
||||
hash: u32,
|
||||
) -> ExternRef<Species>;
|
||||
}
|
|
@ -0,0 +1,93 @@
|
|||
use crate::{ExternRef, ExternalReferenceType};
|
||||
use alloc::collections::BTreeMap;
|
||||
use alloc::rc::Rc;
|
||||
use alloc::string::{String, ToString};
|
||||
use cstr_core::{c_char, CString};
|
||||
use spin::RwLock;
|
||||
|
||||
struct TypeLibraryInner {
|
||||
reference: ExternRef<TypeLibrary>,
|
||||
name_to_type_cache: RwLock<BTreeMap<String, u8>>,
|
||||
effectiveness_cache: RwLock<BTreeMap<(u8, u8), f32>>,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct TypeLibrary {
|
||||
inner: Rc<TypeLibraryInner>,
|
||||
}
|
||||
|
||||
impl TypeLibrary {
|
||||
pub(crate) fn new(reference: ExternRef<Self>) -> Self {
|
||||
Self {
|
||||
inner: Rc::new(TypeLibraryInner {
|
||||
reference,
|
||||
name_to_type_cache: Default::default(),
|
||||
effectiveness_cache: Default::default(),
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_type_from_name(&self, name: &str) -> Option<u8> {
|
||||
if let Some(cached) = self.inner.name_to_type_cache.read().get(name) {
|
||||
return Some(*cached);
|
||||
}
|
||||
let cstr = CString::new(name).unwrap();
|
||||
let v = unsafe { type_library_get_type_by_name(self.inner.reference, cstr.as_ptr()) };
|
||||
if v == 255 {
|
||||
return None;
|
||||
}
|
||||
self.inner
|
||||
.name_to_type_cache
|
||||
.write()
|
||||
.insert(name.to_string(), v);
|
||||
Some(v)
|
||||
}
|
||||
|
||||
pub fn get_single_effectiveness(&self, attacking_type: u8, defending_type: u8) -> f32 {
|
||||
if let Some(cached) = self
|
||||
.inner
|
||||
.effectiveness_cache
|
||||
.read()
|
||||
.get(&(attacking_type, defending_type))
|
||||
{
|
||||
return *cached;
|
||||
}
|
||||
let effectiveness = unsafe {
|
||||
type_library_get_single_effectiveness(
|
||||
self.inner.reference,
|
||||
attacking_type,
|
||||
defending_type,
|
||||
)
|
||||
};
|
||||
self.inner
|
||||
.effectiveness_cache
|
||||
.write()
|
||||
.insert((attacking_type, defending_type), effectiveness);
|
||||
effectiveness
|
||||
}
|
||||
|
||||
pub fn get_effectiveness(&self, attacking_type: u8, defending_types: &[u8]) -> f32 {
|
||||
let mut f = 1.0;
|
||||
for defending_type in defending_types {
|
||||
f *= self.get_single_effectiveness(attacking_type, *defending_type);
|
||||
}
|
||||
f
|
||||
}
|
||||
}
|
||||
|
||||
crate::handling::cacheable::cacheable!(TypeLibrary);
|
||||
|
||||
impl ExternalReferenceType for TypeLibrary {
|
||||
fn from_extern_value(reference: ExternRef<Self>) -> Self {
|
||||
Self::new(reference)
|
||||
}
|
||||
}
|
||||
|
||||
extern "wasm" {
|
||||
fn type_library_get_single_effectiveness(
|
||||
r: ExternRef<TypeLibrary>,
|
||||
attacking_type: u8,
|
||||
defending_type: u8,
|
||||
) -> f32;
|
||||
fn type_library_get_type_by_name(r: ExternRef<TypeLibrary>, name: *const c_char) -> u8;
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
use crate::handling::cached_value::CachedValue;
|
||||
use crate::handling::Cacheable;
|
||||
use crate::{cached_value, ExternRef, ExternalReferenceType, StringKey};
|
||||
use crate::{cached_value, cached_value_getters, ExternRef, ExternalReferenceType, StringKey};
|
||||
use alloc::rc::Rc;
|
||||
|
||||
/// An item category defines which bag slot items are stored in.
|
||||
|
@ -42,7 +42,7 @@ pub enum BattleItemCategory {
|
|||
}
|
||||
|
||||
struct ItemInner {
|
||||
ptr: ExternRef<Item>,
|
||||
reference: ExternRef<Item>,
|
||||
name: CachedValue<StringKey>,
|
||||
category: CachedValue<ItemCategory>,
|
||||
battle_category: CachedValue<BattleItemCategory>,
|
||||
|
@ -56,40 +56,35 @@ pub struct Item {
|
|||
}
|
||||
|
||||
impl Item {
|
||||
pub(crate) fn new(ptr: ExternRef<Self>) -> Self {
|
||||
Self::from_ref(ptr, &|ptr| Self {
|
||||
pub(crate) fn new(reference: ExternRef<Self>) -> Self {
|
||||
Self::from_ref(reference, &|reference| Self {
|
||||
inner: Rc::new(ItemInner {
|
||||
ptr,
|
||||
name: cached_value!({ StringKey::new(item_get_name(ptr)) }),
|
||||
category: cached_value!({ item_get_category(ptr) }),
|
||||
battle_category: cached_value!({ item_get_battle_category(ptr) }),
|
||||
price: cached_value!({ item_get_price(ptr) }),
|
||||
reference,
|
||||
name: cached_value!({ StringKey::new(item_get_name(reference)) }),
|
||||
category: cached_value!({ item_get_category(reference) }),
|
||||
battle_category: cached_value!({ item_get_battle_category(reference) }),
|
||||
price: cached_value!({ item_get_price(reference) }),
|
||||
}),
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn ptr(&self) -> ExternRef<Self> {
|
||||
self.inner.ptr
|
||||
pub(crate) fn reference(&self) -> ExternRef<Self> {
|
||||
self.inner.reference
|
||||
}
|
||||
|
||||
/// The name of the item.
|
||||
pub fn name(&self) -> StringKey {
|
||||
self.inner.name.value()
|
||||
}
|
||||
/// Which bag slot items are stored in.
|
||||
pub fn category(&self) -> ItemCategory {
|
||||
self.inner.category.value()
|
||||
}
|
||||
/// How the item is categorized when in battle.
|
||||
pub fn battle_category(&self) -> BattleItemCategory {
|
||||
self.inner.battle_category.value()
|
||||
}
|
||||
/// The buying value of the item.
|
||||
pub fn price(&self) -> i32 {
|
||||
self.inner.price.value()
|
||||
cached_value_getters! {
|
||||
/// The name of the item.
|
||||
pub fn name(&self) -> StringKey;
|
||||
/// Which bag slot items are stored in.
|
||||
pub fn category(&self) -> ItemCategory;
|
||||
/// How the item is categorized when in battle.
|
||||
pub fn battle_category(&self) -> BattleItemCategory;
|
||||
/// The buying value of the item.
|
||||
pub fn price(&self) -> i32;
|
||||
}
|
||||
|
||||
pub fn has_flag(&self, flag: &StringKey) -> bool {
|
||||
unsafe { item_has_flag(self.ptr(), flag.ptr()) }
|
||||
unsafe { item_has_flag(self.inner.reference, flag.ptr()) }
|
||||
}
|
||||
}
|
||||
|
|
@ -1,11 +1,16 @@
|
|||
pub mod ability;
|
||||
pub mod data_libraries;
|
||||
pub mod effect_parameter;
|
||||
pub mod item;
|
||||
pub mod move_data;
|
||||
mod nature;
|
||||
pub mod species;
|
||||
|
||||
pub use data_libraries::*;
|
||||
pub use effect_parameter::EffectParameter;
|
||||
pub use item::*;
|
||||
pub use move_data::*;
|
||||
pub use nature::*;
|
||||
pub use species::*;
|
||||
|
||||
pub type LevelInt = u8;
|
|
@ -1,8 +1,7 @@
|
|||
use crate::app_interface::StringKey;
|
||||
use crate::app_interface::{get_hash, StringKey};
|
||||
use crate::handling::cached_value::CachedValue;
|
||||
use crate::handling::Cacheable;
|
||||
use crate::{cached_value, ExternRef, ExternalReferenceType};
|
||||
use alloc::collections::BTreeMap;
|
||||
use crate::{cached_value, cached_value_getters, ExternRef, ExternalReferenceType};
|
||||
use alloc::rc::Rc;
|
||||
|
||||
#[repr(u8)]
|
||||
|
@ -66,36 +65,20 @@ impl MoveData {
|
|||
}),
|
||||
})
|
||||
}
|
||||
pub(crate) fn ptr(&self) -> ExternRef<Self> {
|
||||
self.inner.ptr
|
||||
}
|
||||
|
||||
pub fn name(&self) -> StringKey {
|
||||
self.inner.name.value()
|
||||
cached_value_getters! {
|
||||
pub fn name(&self) -> StringKey;
|
||||
pub fn move_type(&self) -> u8;
|
||||
pub fn category(&self) -> MoveCategory;
|
||||
pub fn base_power(&self) -> u8;
|
||||
pub fn accuracy(&self) -> u8;
|
||||
pub fn base_usages(&self) -> u8;
|
||||
pub fn target(&self) -> MoveTarget;
|
||||
pub fn priority(&self) -> i8;
|
||||
}
|
||||
pub fn move_type(&self) -> u8 {
|
||||
self.inner.move_type.value()
|
||||
}
|
||||
pub fn category(&self) -> MoveCategory {
|
||||
self.inner.category.value()
|
||||
}
|
||||
pub fn base_power(&self) -> u8 {
|
||||
self.inner.base_power.value()
|
||||
}
|
||||
pub fn accuracy(&self) -> u8 {
|
||||
self.inner.accuracy.value()
|
||||
}
|
||||
pub fn base_usages(&self) -> u8 {
|
||||
self.inner.base_usages.value()
|
||||
}
|
||||
pub fn target(&self) -> MoveTarget {
|
||||
self.inner.target.value()
|
||||
}
|
||||
pub fn priority(&self) -> i8 {
|
||||
self.inner.priority.value()
|
||||
}
|
||||
pub fn has_flag(&self, flag: &StringKey) -> bool {
|
||||
unsafe { move_data_has_flag(self.ptr(), flag.ptr()) }
|
||||
pub fn has_flag<const N: usize>(&self, flag: &[u8; N]) -> bool {
|
||||
let hash = get_hash(flag);
|
||||
unsafe { move_data_has_flag_by_hash(self.inner.ptr, hash) }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -116,5 +99,5 @@ extern "wasm" {
|
|||
fn move_data_get_base_usages(ptr: ExternRef<MoveData>) -> u8;
|
||||
fn move_data_get_target(ptr: ExternRef<MoveData>) -> MoveTarget;
|
||||
fn move_data_get_priority(ptr: ExternRef<MoveData>) -> i8;
|
||||
fn move_data_has_flag(ptr: ExternRef<MoveData>, flag: ExternRef<StringKey>) -> bool;
|
||||
fn move_data_has_flag_by_hash(ptr: ExternRef<MoveData>, flag_hash: u32) -> bool;
|
||||
}
|
|
@ -0,0 +1,52 @@
|
|||
use crate::app_interface::Statistic;
|
||||
use crate::handling::cacheable::Cacheable;
|
||||
use crate::{ExternRef, ExternalReferenceType};
|
||||
use alloc::rc::Rc;
|
||||
|
||||
struct NatureInner {
|
||||
reference: ExternRef<Nature>,
|
||||
/// The stat that should receive the increased modifier.
|
||||
increase_stat: Statistic,
|
||||
/// The stat that should receive the decreased modifier.
|
||||
decrease_stat: Statistic,
|
||||
/// The amount by which the increased stat is multiplied.
|
||||
increase_modifier: f32,
|
||||
/// The amount by which the decreased stat is multiplied.
|
||||
decrease_modifier: f32,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Nature {
|
||||
inner: Rc<NatureInner>,
|
||||
}
|
||||
|
||||
crate::handling::cacheable::cacheable!(Nature);
|
||||
|
||||
impl Nature {
|
||||
pub fn new(reference: ExternRef<Self>) -> Self {
|
||||
Self::from_ref(reference, &|reference| unsafe {
|
||||
Self {
|
||||
inner: Rc::new(NatureInner {
|
||||
reference,
|
||||
increase_stat: nature_get_increase_stat(reference),
|
||||
decrease_stat: nature_get_decrease_stat(reference),
|
||||
increase_modifier: nature_get_increase_modifier(reference),
|
||||
decrease_modifier: nature_get_decrease_modifier(reference),
|
||||
}),
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl ExternalReferenceType for Nature {
|
||||
fn from_extern_value(reference: ExternRef<Self>) -> Self {
|
||||
Self::new(reference)
|
||||
}
|
||||
}
|
||||
|
||||
extern "wasm" {
|
||||
fn nature_get_increase_stat(r: ExternRef<Nature>) -> Statistic;
|
||||
fn nature_get_decrease_stat(r: ExternRef<Nature>) -> Statistic;
|
||||
fn nature_get_increase_modifier(r: ExternRef<Nature>) -> f32;
|
||||
fn nature_get_decrease_modifier(r: ExternRef<Nature>) -> f32;
|
||||
}
|
|
@ -0,0 +1,270 @@
|
|||
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;
|
||||
|
||||
#[repr(u8)]
|
||||
pub enum Gender {
|
||||
Male = 0,
|
||||
Female = 1,
|
||||
Genderless = 2,
|
||||
}
|
||||
|
||||
#[repr(u8)]
|
||||
pub enum Statistic {
|
||||
HP = 0,
|
||||
Attack = 1,
|
||||
Defense = 2,
|
||||
SpecialAttack = 3,
|
||||
SpecialDefense = 4,
|
||||
Speed = 5,
|
||||
}
|
||||
|
||||
pub struct ImmutableStatisticSetInner {
|
||||
reference: ExternRef<ImmutableStatisticSet>,
|
||||
/// The health point stat value.
|
||||
hp: CachedValue<u16>,
|
||||
/// The physical attack stat value.
|
||||
attack: CachedValue<u16>,
|
||||
/// The physical defense stat value.
|
||||
defense: CachedValue<u16>,
|
||||
/// The special attack stat value.
|
||||
special_attack: CachedValue<u16>,
|
||||
/// The special defense stat value.
|
||||
special_defense: CachedValue<u16>,
|
||||
/// The speed stat value.
|
||||
speed: CachedValue<u16>,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct ImmutableStatisticSet {
|
||||
inner: Rc<ImmutableStatisticSetInner>,
|
||||
}
|
||||
|
||||
impl ImmutableStatisticSet {
|
||||
pub(crate) fn new(reference: ExternRef<Self>) -> Self {
|
||||
Self::from_ref(reference, &|reference| Self {
|
||||
inner: Rc::new(ImmutableStatisticSetInner {
|
||||
reference,
|
||||
hp: cached_value!({ static_statistics_set_get_hp(reference) }),
|
||||
attack: cached_value!({ static_statistics_set_get_attack(reference) }),
|
||||
defense: cached_value!({ static_statistics_set_get_defense(reference) }),
|
||||
special_attack: cached_value!({
|
||||
static_statistics_set_get_special_attack(reference)
|
||||
}),
|
||||
special_defense: cached_value!({
|
||||
static_statistics_set_get_special_defense(reference)
|
||||
}),
|
||||
speed: cached_value!({ static_statistics_set_get_speed(reference) }),
|
||||
}),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn hp(&self) -> u16 {
|
||||
self.inner.hp.value()
|
||||
}
|
||||
pub fn attack(&self) -> u16 {
|
||||
self.inner.attack.value()
|
||||
}
|
||||
pub fn defense(&self) -> u16 {
|
||||
self.inner.defense.value()
|
||||
}
|
||||
pub fn special_attack(&self) -> u16 {
|
||||
self.inner.special_attack.value()
|
||||
}
|
||||
pub fn special_defense(&self) -> u16 {
|
||||
self.inner.special_defense.value()
|
||||
}
|
||||
pub fn speed(&self) -> u16 {
|
||||
self.inner.speed.value()
|
||||
}
|
||||
}
|
||||
|
||||
struct FormInner {
|
||||
reference: ExternRef<Form>,
|
||||
name: CachedValue<StringKey>,
|
||||
height: CachedValue<f32>,
|
||||
weight: CachedValue<f32>,
|
||||
types: CachedValue<Vec<u8>>,
|
||||
base_experience: CachedValue<u32>,
|
||||
base_stats: CachedValue<ImmutableStatisticSet>,
|
||||
abilities: CachedValue<ImmutableList<StringKey>>,
|
||||
hidden_abilities: CachedValue<ImmutableList<StringKey>>,
|
||||
// moves: CachedValue<LearnableMoves>,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Form {
|
||||
inner: Rc<FormInner>,
|
||||
}
|
||||
|
||||
impl Form {
|
||||
pub(crate) fn new(reference: ExternRef<Self>) -> Self {
|
||||
Self::from_ref(reference, &|reference| Self {
|
||||
inner: Rc::new(FormInner {
|
||||
reference,
|
||||
name: cached_value!({ form_get_name(reference).get_value().unwrap() }),
|
||||
height: cached_value!({ form_get_height(reference) }),
|
||||
weight: cached_value!({ form_get_weight(reference) }),
|
||||
types: cached_value!({
|
||||
let raw = form_get_types(reference);
|
||||
Vec::from_raw_parts(raw.ptr(), raw.len(), raw.len())
|
||||
}),
|
||||
base_experience: cached_value!({ form_get_base_experience(reference) }),
|
||||
base_stats: cached_value!({ form_get_base_stats(reference).get_value().unwrap() }),
|
||||
abilities: cached_value!({ form_get_abilities(reference).get_immutable_list() }),
|
||||
hidden_abilities: cached_value!({
|
||||
form_get_hidden_abilities(reference).get_immutable_list()
|
||||
}),
|
||||
}),
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn reference(&self) -> ExternRef<Self> {
|
||||
self.inner.reference
|
||||
}
|
||||
|
||||
cached_value_getters! {
|
||||
pub fn name(&self) -> StringKey;
|
||||
pub fn height(&self) -> f32;
|
||||
pub fn weight(&self) -> f32;
|
||||
pub fn base_experience(&self) -> u32;
|
||||
pub fn base_stats(&self) -> ImmutableStatisticSet;
|
||||
pub fn abilities(&self) -> ImmutableList<StringKey>;
|
||||
pub fn hidden_abilities(&self) -> ImmutableList<StringKey>;
|
||||
}
|
||||
pub fn types(&self) -> &Vec<u8> {
|
||||
self.inner.types.value_ref()
|
||||
}
|
||||
|
||||
pub fn has_flag<const N: usize>(&self, flag: &[u8; N]) -> bool {
|
||||
let hash = get_hash(flag);
|
||||
unsafe { form_has_flag_by_hash(self.inner.reference, hash) }
|
||||
}
|
||||
}
|
||||
|
||||
pub struct SpeciesInner {
|
||||
reference: ExternRef<Species>,
|
||||
id: CachedValue<u16>,
|
||||
name: CachedValue<StringKey>,
|
||||
gender_rate: CachedValue<f32>,
|
||||
growth_rate: CachedValue<StringKey>,
|
||||
capture_rate: CachedValue<u8>,
|
||||
forms: RwLock<BTreeMap<u32, Option<Form>>>,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Species {
|
||||
inner: Rc<SpeciesInner>,
|
||||
}
|
||||
|
||||
impl Species {
|
||||
pub(crate) fn new(reference: ExternRef<Species>) -> Self {
|
||||
Self {
|
||||
inner: Rc::new(SpeciesInner {
|
||||
reference,
|
||||
id: cached_value!({ species_get_id(reference) }),
|
||||
name: cached_value!({ species_get_name(reference).get_value().unwrap() }),
|
||||
gender_rate: cached_value!({ species_get_gender_rate(reference) }),
|
||||
growth_rate: cached_value!({
|
||||
species_get_growth_rate(reference).get_value().unwrap()
|
||||
}),
|
||||
capture_rate: cached_value!({ species_get_capture_rate(reference) }),
|
||||
forms: Default::default(),
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn reference(&self) -> ExternRef<Self> {
|
||||
self.inner.reference
|
||||
}
|
||||
|
||||
cached_value_getters! {
|
||||
/// The national dex identifier of the Pokemon.
|
||||
pub fn id(&self) -> u16;
|
||||
/// The name of the Pokemon species.
|
||||
pub fn name(&self) -> StringKey;
|
||||
/// The chance between 0.0 and 1.0 that a Pokemon is female.
|
||||
pub fn gender_rate(&self) -> f32;
|
||||
/// How much experience is required for a level.
|
||||
pub fn growth_rate(&self) -> StringKey;
|
||||
/// How hard it is to capture a Pokemon. 255 means this will be always caught, 0 means this is
|
||||
/// uncatchable.
|
||||
pub fn capture_rate(&self) -> u8;
|
||||
}
|
||||
|
||||
pub fn get_form<const N: usize>(&self, form_name: &[u8; N]) -> Option<Form> {
|
||||
let hash = get_hash(form_name);
|
||||
unsafe {
|
||||
if let Some(v) = self.inner.forms.read().get(&hash) {
|
||||
v.clone()
|
||||
} else {
|
||||
let r = species_get_form_by_hash(self.inner.reference, hash);
|
||||
let value = r.get_value();
|
||||
self.inner.forms.write().insert(hash, value.clone());
|
||||
value
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn has_flag<const N: usize>(&self, flag: &[u8; N]) -> bool {
|
||||
let hash = get_hash(flag);
|
||||
unsafe { species_has_flag_by_hash(self.inner.reference, hash) }
|
||||
}
|
||||
}
|
||||
|
||||
impl ExternalReferenceType for ImmutableStatisticSet {
|
||||
fn from_extern_value(reference: ExternRef<Self>) -> Self {
|
||||
Self::new(reference)
|
||||
}
|
||||
}
|
||||
|
||||
impl ExternalReferenceType for Form {
|
||||
fn from_extern_value(reference: ExternRef<Self>) -> Self {
|
||||
Self::new(reference)
|
||||
}
|
||||
}
|
||||
|
||||
impl ExternalReferenceType for Species {
|
||||
fn from_extern_value(reference: ExternRef<Self>) -> Self {
|
||||
Self::new(reference)
|
||||
}
|
||||
}
|
||||
|
||||
crate::handling::cacheable::cacheable!(ImmutableStatisticSet);
|
||||
crate::handling::cacheable::cacheable!(Form);
|
||||
crate::handling::cacheable::cacheable!(Species);
|
||||
|
||||
extern "wasm" {
|
||||
fn static_statistics_set_get_hp(r: ExternRef<ImmutableStatisticSet>) -> u16;
|
||||
fn static_statistics_set_get_attack(r: ExternRef<ImmutableStatisticSet>) -> u16;
|
||||
fn static_statistics_set_get_defense(r: ExternRef<ImmutableStatisticSet>) -> u16;
|
||||
fn static_statistics_set_get_special_attack(r: ExternRef<ImmutableStatisticSet>) -> u16;
|
||||
fn static_statistics_set_get_special_defense(r: ExternRef<ImmutableStatisticSet>) -> u16;
|
||||
fn static_statistics_set_get_speed(r: ExternRef<ImmutableStatisticSet>) -> u16;
|
||||
|
||||
fn form_get_name(r: ExternRef<Form>) -> ExternRef<StringKey>;
|
||||
fn form_get_height(r: ExternRef<Form>) -> f32;
|
||||
fn form_get_weight(r: ExternRef<Form>) -> f32;
|
||||
fn form_get_types(r: ExternRef<Form>) -> FFIArray<u8>;
|
||||
fn form_get_base_experience(r: ExternRef<Form>) -> u32;
|
||||
fn form_get_base_stats(r: ExternRef<Form>) -> ExternRef<ImmutableStatisticSet>;
|
||||
fn form_get_abilities(r: ExternRef<Form>) -> VecExternRef<StringKey>;
|
||||
fn form_get_hidden_abilities(r: ExternRef<Form>) -> VecExternRef<StringKey>;
|
||||
fn form_has_flag_by_hash(r: ExternRef<Form>, hash: u32) -> bool;
|
||||
|
||||
fn species_get_id(r: ExternRef<Species>) -> u16;
|
||||
fn species_get_name(r: ExternRef<Species>) -> ExternRef<StringKey>;
|
||||
fn species_get_gender_rate(r: ExternRef<Species>) -> f32;
|
||||
fn species_get_growth_rate(r: ExternRef<Species>) -> ExternRef<StringKey>;
|
||||
fn species_get_capture_rate(r: ExternRef<Species>) -> u8;
|
||||
fn species_get_form_by_hash(r: ExternRef<Species>, hash: u32) -> ExternRef<Form>;
|
||||
fn species_has_flag_by_hash(r: ExternRef<Species>, flag_hash: u32) -> bool;
|
||||
}
|
|
@ -21,7 +21,7 @@ pub trait Cacheable {
|
|||
}
|
||||
|
||||
macro_rules! cacheable {
|
||||
($type: ident) => {
|
||||
($type: ty) => {
|
||||
paste::paste!{
|
||||
static mut [<$type:upper _CACHE>]: alloc::collections::BTreeMap<ExternRef<$type>, $type> =
|
||||
alloc::collections::BTreeMap::new();
|
||||
|
|
|
@ -5,10 +5,7 @@ pub struct CachedValue<T> {
|
|||
value: Option<T>,
|
||||
}
|
||||
|
||||
impl<T> CachedValue<T>
|
||||
where
|
||||
T: Clone,
|
||||
{
|
||||
impl<T> CachedValue<T> {
|
||||
pub fn new(init_fn: Box<dyn Fn() -> T>) -> Self {
|
||||
Self {
|
||||
init_fn,
|
||||
|
@ -16,16 +13,30 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn value(&self) -> T {
|
||||
#[inline(always)]
|
||||
fn init_if_empty(&self) {
|
||||
if self.value.is_none() {
|
||||
unsafe {
|
||||
let s = self as *const Self as *mut Self;
|
||||
s.as_mut().unwrap().value.replace((self.init_fn)());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn value(&self) -> T
|
||||
where
|
||||
T: Clone,
|
||||
{
|
||||
self.init_if_empty();
|
||||
self.value.as_ref().unwrap().clone()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn value_ref(&self) -> &T {
|
||||
self.init_if_empty();
|
||||
self.value.as_ref().unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
|
@ -34,3 +45,20 @@ macro_rules! cached_value {
|
|||
CachedValue::new(alloc::boxed::Box::new(move || unsafe { $init }))
|
||||
};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! cached_value_getters {
|
||||
(
|
||||
$(
|
||||
$(#[$attr:meta])*
|
||||
$v:vis fn $name:ident(&self) -> $type:ty;
|
||||
)*
|
||||
) => {
|
||||
$(
|
||||
$(#[$attr])*
|
||||
$v fn $name(&self) -> $type {
|
||||
self.inner.$name.value()
|
||||
}
|
||||
)*
|
||||
};
|
||||
}
|
||||
|
|
|
@ -14,6 +14,10 @@ impl<T> ExternRef<T> {
|
|||
self.p == 0
|
||||
}
|
||||
|
||||
pub(crate) fn get_internal_index(&self) -> u32 {
|
||||
self.p
|
||||
}
|
||||
|
||||
pub fn get_value(&self) -> Option<T>
|
||||
where
|
||||
T: ExternalReferenceType,
|
||||
|
@ -22,6 +26,14 @@ impl<T> ExternRef<T> {
|
|||
{
|
||||
T::instantiate_from_extern_value(*self)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate) fn cast<TCast>(&self) -> ExternRef<TCast> {
|
||||
ExternRef::<TCast> {
|
||||
p: self.p,
|
||||
resource_type: Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Clone for ExternRef<T> {
|
||||
|
@ -71,12 +83,12 @@ impl<T> VecExternRef<T> {
|
|||
v.0
|
||||
}
|
||||
|
||||
pub fn len(&self) -> u32 {
|
||||
pub(crate) fn len(&self) -> u32 {
|
||||
let v: (u32, u32) = unsafe { transmute(self.v) };
|
||||
v.1
|
||||
}
|
||||
|
||||
pub fn at(&self, index: u32) -> ExternRef<T> {
|
||||
pub(crate) fn at(&self, index: u32) -> ExternRef<T> {
|
||||
let p = unsafe { _vec_extern_ref_get_value(self.get_internal_index(), index) };
|
||||
ExternRef {
|
||||
p,
|
||||
|
@ -84,12 +96,12 @@ impl<T> VecExternRef<T> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn get_immutable_list(&self) -> ImmutableList<T>
|
||||
pub(crate) fn get_immutable_list(&self) -> ImmutableList<T>
|
||||
where
|
||||
T: Clone,
|
||||
T: ExternalReferenceType,
|
||||
{
|
||||
ImmutableList::from_ref(self.clone())
|
||||
ImmutableList::from_ref(*self)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@ pub mod capabilities;
|
|||
pub mod extern_ref;
|
||||
pub mod ffi_array;
|
||||
pub mod script;
|
||||
pub(crate) mod temporary;
|
||||
|
||||
pub use capabilities::*;
|
||||
|
||||
|
@ -20,3 +21,102 @@ pub enum ScriptCategory {
|
|||
Side,
|
||||
ItemBattleTrigger,
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! wasm_reference_getters {
|
||||
(
|
||||
$base_type:ty,
|
||||
$(
|
||||
$(#[$attr:meta])*
|
||||
$v:vis fn $name:ident(&self) -> $type:ty;
|
||||
)*
|
||||
) => {
|
||||
impl $base_type {
|
||||
$(
|
||||
$(#[$attr])*
|
||||
$v fn $name(&self) -> $type {
|
||||
paste::paste!{
|
||||
unsafe{
|
||||
[<$base_type:snake _get_ $name>](self.inner.reference).get_value().unwrap()
|
||||
}
|
||||
}
|
||||
}
|
||||
)*
|
||||
|
||||
}
|
||||
|
||||
extern "wasm" {
|
||||
$(
|
||||
paste::paste!{
|
||||
fn [<$base_type:snake _get_ $name>](r: ExternRef<$base_type>) -> ExternRef<$type>;
|
||||
}
|
||||
)*
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! wasm_optional_reference_getters {
|
||||
(
|
||||
$base_type:ty,
|
||||
$(
|
||||
$(#[$attr:meta])*
|
||||
$v:vis fn $name:ident(&self) -> Option<$type:ty>;
|
||||
)*
|
||||
) => {
|
||||
impl $base_type {
|
||||
$(
|
||||
$(#[$attr])*
|
||||
$v fn $name(&self) -> Option<$type> {
|
||||
paste::paste!{
|
||||
unsafe{
|
||||
[<$base_type:snake get_ $name>](self.inner.reference).get_value()
|
||||
}
|
||||
}
|
||||
}
|
||||
)*
|
||||
|
||||
}
|
||||
|
||||
extern "wasm" {
|
||||
$(
|
||||
paste::paste!{
|
||||
fn [<$base_type:snake get_ $name>](r: ExternRef<$base_type>) -> ExternRef<$type>;
|
||||
}
|
||||
)*
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! wasm_value_getters {
|
||||
(
|
||||
$base_type:ty,
|
||||
$(
|
||||
$(#[$attr:meta])*
|
||||
$v:vis fn $name:ident(&self) -> $type:ty;
|
||||
)*
|
||||
) => {
|
||||
impl $base_type {
|
||||
$(
|
||||
$(#[$attr])*
|
||||
$v fn $name(&self) -> $type {
|
||||
paste::paste!{
|
||||
unsafe{
|
||||
[<$base_type:snake get_ $name>](self.inner.reference)
|
||||
}
|
||||
}
|
||||
}
|
||||
)*
|
||||
|
||||
}
|
||||
|
||||
extern "wasm" {
|
||||
$(
|
||||
paste::paste!{
|
||||
fn [<$base_type:snake get_ $name>](r: ExternRef<$base_type>) -> $type;
|
||||
}
|
||||
)*
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use crate::app_interface::list::ImmutableList;
|
||||
use crate::app_interface::{BaseTurnChoice, BattleLibrary, EffectParameter};
|
||||
use crate::app_interface::{DynamicLibrary, EffectParameter};
|
||||
use crate::handling::ScriptCapabilities;
|
||||
use crate::ExternRef;
|
||||
use crate::{ExternRef, TurnChoice};
|
||||
use core::ffi::c_void;
|
||||
use core::fmt::Debug;
|
||||
|
||||
|
@ -15,11 +15,11 @@ pub trait Script {
|
|||
|
||||
fn on_initialize(
|
||||
&self,
|
||||
_library: &BattleLibrary,
|
||||
_library: &DynamicLibrary,
|
||||
_parameters: Option<ImmutableList<EffectParameter>>,
|
||||
) {
|
||||
}
|
||||
fn on_before_turn(&self, _choice: ExternRef<BaseTurnChoice>) {}
|
||||
fn on_before_turn(&self, _choice: TurnChoice) {}
|
||||
}
|
||||
|
||||
impl Debug for dyn Script {
|
||||
|
|
|
@ -0,0 +1,87 @@
|
|||
use crate::{dbg, println, 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,
|
||||
}
|
||||
|
||||
pub struct Temporary<T> {
|
||||
value: *mut TemporaryData<T>,
|
||||
}
|
||||
|
||||
static mut TEMPORARIES: alloc::collections::BTreeMap<u32, *const u8> =
|
||||
alloc::collections::BTreeMap::new();
|
||||
impl<T> Temporary<T>
|
||||
where
|
||||
T: ExternalReferenceType,
|
||||
T: Clone,
|
||||
{
|
||||
pub fn from_reference(reference: ExternRef<T>) -> Self {
|
||||
let temporaries = unsafe { &mut TEMPORARIES };
|
||||
let existing = temporaries.get(&reference.get_internal_index());
|
||||
unsafe {
|
||||
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>,
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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 }
|
||||
}
|
||||
|
||||
pub fn value(&self) -> T {
|
||||
unsafe { self.value.as_ref().unwrap().value.clone() }
|
||||
}
|
||||
|
||||
pub(crate) fn mark_as_deleted(reference: ExternRef<T>) {
|
||||
let temporaries = unsafe { &mut TEMPORARIES };
|
||||
let existing = temporaries.get(&reference.get_internal_index());
|
||||
unsafe {
|
||||
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());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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 }
|
||||
}
|
||||
}
|
||||
|
||||
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))
|
||||
}
|
||||
}
|
||||
}
|
|
@ -23,7 +23,7 @@ extern crate wee_alloc;
|
|||
static ALLOC: wee_alloc::WeeAlloc = wee_alloc::WeeAlloc::INIT;
|
||||
|
||||
use crate::app_interface::list::ImmutableList;
|
||||
use crate::app_interface::{BaseTurnChoice, BattleLibrary, EffectParameter, StringKey};
|
||||
use crate::app_interface::{DynamicLibrary, EffectParameter, StringKey, TurnChoice};
|
||||
pub(crate) use crate::handling::extern_ref::*;
|
||||
use crate::handling::ffi_array::FFIArray;
|
||||
use crate::handling::{Script, ScriptCapabilities, ScriptCategory};
|
||||
|
@ -57,10 +57,10 @@ extern "wasm" fn load_script(category: ScriptCategory, name: ExternRef<StringKey
|
|||
}
|
||||
|
||||
#[no_mangle]
|
||||
unsafe extern "wasm" fn destroy_script(script: *mut u8) {
|
||||
unsafe extern "wasm" 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 as *mut Box<dyn Script>);
|
||||
let boxed_script = Box::from_raw(script);
|
||||
boxed_script.destroy();
|
||||
}
|
||||
|
||||
|
@ -75,10 +75,10 @@ unsafe extern "wasm" fn get_script_capabilities(
|
|||
#[no_mangle]
|
||||
unsafe extern "wasm" fn script_on_initialize(
|
||||
script: *const Box<dyn Script>,
|
||||
library: ExternRef<BattleLibrary>,
|
||||
library: ExternRef<DynamicLibrary>,
|
||||
parameters: VecExternRef<EffectParameter>,
|
||||
) {
|
||||
let lib = BattleLibrary::new(library);
|
||||
let lib = DynamicLibrary::new(library);
|
||||
let parameters = ImmutableList::from_ref(parameters);
|
||||
script
|
||||
.as_ref()
|
||||
|
@ -90,7 +90,11 @@ unsafe extern "wasm" fn script_on_initialize(
|
|||
#[no_mangle]
|
||||
unsafe extern "wasm" fn script_on_before_turn(
|
||||
script: *const Box<dyn Script>,
|
||||
choice: ExternRef<BaseTurnChoice>,
|
||||
choice: ExternRef<TurnChoice>,
|
||||
) {
|
||||
script.as_ref().unwrap().as_ref().on_before_turn(choice)
|
||||
script
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.as_ref()
|
||||
.on_before_turn(choice.get_value().unwrap())
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue