A lot of work on type registration
This commit is contained in:
60
pkmn_lib_interface/src/app_interface/static_data/ability.rs
Normal file
60
pkmn_lib_interface/src/app_interface/static_data/ability.rs
Normal file
@@ -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>;
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
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>>,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct ItemLibrary {
|
||||
inner: Rc<ItemLibraryInner>,
|
||||
}
|
||||
|
||||
impl ItemLibrary {
|
||||
pub(crate) fn new(ptr: ExternRef<Self>) -> Self {
|
||||
Self {
|
||||
inner: Rc::new(ItemLibraryInner {
|
||||
ptr,
|
||||
cache: Default::default(),
|
||||
}),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl DataLibrary<Item> for ItemLibrary {
|
||||
fn get_cache(&self) -> &spin::rwlock::RwLock<BTreeMap<u32, Item>> {
|
||||
&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<Item> {
|
||||
unsafe { move_library_get_move(ptr, name) }
|
||||
}
|
||||
|
||||
fn _get_ref_by_hash(ptr: ExternRef<Self>, hash: u32) -> ExternRef<Item> {
|
||||
unsafe { move_library_get_move_by_hash(ptr, hash) }
|
||||
}
|
||||
}
|
||||
|
||||
crate::handling::cacheable::cacheable!(ItemLibrary);
|
||||
|
||||
impl ExternalReferenceType for ItemLibrary {
|
||||
fn from_extern_value(reference: ExternRef<Self>) -> Self {
|
||||
Self::new(reference)
|
||||
}
|
||||
}
|
||||
|
||||
extern "wasm" {
|
||||
fn move_library_get_move(
|
||||
ptr: ExternRef<ItemLibrary>,
|
||||
name: ExternRef<StringKey>,
|
||||
) -> ExternRef<Item>;
|
||||
fn move_library_get_move_by_hash(ptr: ExternRef<ItemLibrary>, hash: u32) -> ExternRef<Item>;
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
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>>,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct MoveLibrary {
|
||||
inner: Rc<MoveLibraryInner>,
|
||||
}
|
||||
|
||||
impl MoveLibrary {
|
||||
pub(crate) fn new(ptr: ExternRef<Self>) -> Self {
|
||||
Self {
|
||||
inner: Rc::new(MoveLibraryInner {
|
||||
ptr,
|
||||
cache: Default::default(),
|
||||
}),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl DataLibrary<MoveData> for MoveLibrary {
|
||||
fn get_cache(&self) -> &spin::rwlock::RwLock<BTreeMap<u32, MoveData>> {
|
||||
&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<MoveData> {
|
||||
unsafe { move_library_get_move(ptr, name) }
|
||||
}
|
||||
|
||||
fn _get_ref_by_hash(ptr: ExternRef<Self>, hash: u32) -> ExternRef<MoveData> {
|
||||
unsafe { move_library_get_move_by_hash(ptr, hash) }
|
||||
}
|
||||
}
|
||||
|
||||
crate::handling::cacheable::cacheable!(MoveLibrary);
|
||||
|
||||
impl ExternalReferenceType for MoveLibrary {
|
||||
fn from_extern_value(reference: ExternRef<Self>) -> Self {
|
||||
Self::new(reference)
|
||||
}
|
||||
}
|
||||
|
||||
extern "wasm" {
|
||||
fn move_library_get_move(
|
||||
ptr: ExternRef<MoveLibrary>,
|
||||
name: ExternRef<StringKey>,
|
||||
) -> ExternRef<MoveData>;
|
||||
fn move_library_get_move_by_hash(ptr: ExternRef<MoveLibrary>, hash: u32)
|
||||
-> ExternRef<MoveData>;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
use crate::app_interface::StringKey;
|
||||
use crate::{ExternRef, ExternalReferenceType};
|
||||
use core::fmt::{Display, Formatter};
|
||||
|
||||
#[repr(u8)]
|
||||
enum EffectParameterType {
|
||||
None,
|
||||
Bool,
|
||||
Int,
|
||||
Float,
|
||||
String,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub enum EffectParameter {
|
||||
None,
|
||||
Bool(bool),
|
||||
Int(i64),
|
||||
Float(f32),
|
||||
String(StringKey),
|
||||
}
|
||||
|
||||
impl EffectParameter {
|
||||
pub(crate) fn create(ptr: ExternRef<Self>) -> Self {
|
||||
unsafe {
|
||||
match effect_parameter_get_type(ptr) {
|
||||
EffectParameterType::None => Self::None,
|
||||
EffectParameterType::Bool => Self::Bool(effect_parameter_as_bool(ptr)),
|
||||
EffectParameterType::Int => Self::Int(effect_parameter_as_int(ptr)),
|
||||
EffectParameterType::Float => Self::Float(effect_parameter_as_float(ptr)),
|
||||
EffectParameterType::String => {
|
||||
Self::String(StringKey::new(effect_parameter_as_string(ptr)))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ExternalReferenceType for EffectParameter {
|
||||
fn from_extern_value(reference: ExternRef<Self>) -> Self
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
EffectParameter::create(reference)
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for EffectParameter {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
|
||||
match self {
|
||||
EffectParameter::None => f.write_str("EffectParameter::None"),
|
||||
EffectParameter::Bool(b) => f.write_fmt(format_args!("EffectParameter::Bool({})", b)),
|
||||
EffectParameter::Int(i) => f.write_fmt(format_args!("EffectParameter::Int({})", i)),
|
||||
EffectParameter::Float(r) => f.write_fmt(format_args!("EffectParameter::Float({})", r)),
|
||||
EffectParameter::String(s) => {
|
||||
f.write_fmt(format_args!("EffectParameter::String(\"{}\")", s))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extern "wasm" {
|
||||
fn effect_parameter_get_type(ptr: ExternRef<EffectParameter>) -> EffectParameterType;
|
||||
fn effect_parameter_as_bool(ptr: ExternRef<EffectParameter>) -> bool;
|
||||
fn effect_parameter_as_int(ptr: ExternRef<EffectParameter>) -> i64;
|
||||
fn effect_parameter_as_float(ptr: ExternRef<EffectParameter>) -> f32;
|
||||
fn effect_parameter_as_string(ptr: ExternRef<EffectParameter>) -> ExternRef<StringKey>;
|
||||
}
|
||||
105
pkmn_lib_interface/src/app_interface/static_data/item.rs
Normal file
105
pkmn_lib_interface/src/app_interface/static_data/item.rs
Normal file
@@ -0,0 +1,105 @@
|
||||
use crate::handling::cached_value::CachedValue;
|
||||
use crate::handling::Cacheable;
|
||||
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.
|
||||
#[repr(u8)]
|
||||
#[derive(Clone)]
|
||||
pub enum ItemCategory {
|
||||
/// This is where most items should go.
|
||||
MiscItem,
|
||||
/// Pokeballs are used for capturing Pokemons.
|
||||
Pokeball,
|
||||
/// Medicine is used for healing HP, PP, and status effects
|
||||
Medicine,
|
||||
/// Berry is used for all berries.
|
||||
Berry,
|
||||
/// TMHM is used for Technical and Hidden Machines.
|
||||
TMHM,
|
||||
/// Form Changer is used for items that change forms, such as mega stones.
|
||||
FormChanger,
|
||||
/// Key Items are single stored items, generally used for story progression.
|
||||
KeyItem,
|
||||
/// Mail is used for mail items.
|
||||
Mail,
|
||||
}
|
||||
|
||||
/// A battle item category defines how the item is categorized when in battle.
|
||||
#[repr(u8)]
|
||||
#[derive(Clone)]
|
||||
pub enum BattleItemCategory {
|
||||
/// This item can't be used in battle.
|
||||
None,
|
||||
/// This item is used for healing Pokemon.
|
||||
Healing,
|
||||
/// This item is used for healing Pokemon from a status.
|
||||
StatusHealing,
|
||||
/// This item is used for capturing Pokemon.
|
||||
Pokeball,
|
||||
/// This item does not belong in above categories, but is still a battle item.
|
||||
MiscBattleItem,
|
||||
}
|
||||
|
||||
struct ItemInner {
|
||||
reference: ExternRef<Item>,
|
||||
name: CachedValue<StringKey>,
|
||||
category: CachedValue<ItemCategory>,
|
||||
battle_category: CachedValue<BattleItemCategory>,
|
||||
price: CachedValue<i32>,
|
||||
}
|
||||
|
||||
/// An item is an object which the player can pick up, keep in their Bag, and use in some manner
|
||||
#[derive(Clone)]
|
||||
pub struct Item {
|
||||
inner: Rc<ItemInner>,
|
||||
}
|
||||
|
||||
impl Item {
|
||||
pub(crate) fn new(reference: ExternRef<Self>) -> Self {
|
||||
Self::from_ref(reference, &|reference| Self {
|
||||
inner: Rc::new(ItemInner {
|
||||
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 reference(&self) -> ExternRef<Self> {
|
||||
self.inner.reference
|
||||
}
|
||||
|
||||
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.inner.reference, flag.ptr()) }
|
||||
}
|
||||
}
|
||||
|
||||
crate::handling::cacheable::cacheable!(Item);
|
||||
|
||||
impl ExternalReferenceType for Item {
|
||||
fn from_extern_value(reference: ExternRef<Self>) -> Self {
|
||||
Item::new(reference)
|
||||
}
|
||||
}
|
||||
|
||||
extern "wasm" {
|
||||
fn item_get_name(ptr: ExternRef<Item>) -> ExternRef<StringKey>;
|
||||
fn item_get_category(ptr: ExternRef<Item>) -> ItemCategory;
|
||||
fn item_get_battle_category(ptr: ExternRef<Item>) -> BattleItemCategory;
|
||||
fn item_get_price(ptr: ExternRef<Item>) -> i32;
|
||||
fn item_has_flag(ptr: ExternRef<Item>, flag: ExternRef<StringKey>) -> bool;
|
||||
}
|
||||
16
pkmn_lib_interface/src/app_interface/static_data/mod.rs
Normal file
16
pkmn_lib_interface/src/app_interface/static_data/mod.rs
Normal file
@@ -0,0 +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;
|
||||
103
pkmn_lib_interface/src/app_interface/static_data/move_data.rs
Normal file
103
pkmn_lib_interface/src/app_interface/static_data/move_data.rs
Normal file
@@ -0,0 +1,103 @@
|
||||
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};
|
||||
use alloc::rc::Rc;
|
||||
|
||||
#[repr(u8)]
|
||||
#[derive(Clone)]
|
||||
pub enum MoveCategory {
|
||||
Physical = 0,
|
||||
Special = 1,
|
||||
Status = 2,
|
||||
}
|
||||
|
||||
#[repr(u8)]
|
||||
#[derive(Clone)]
|
||||
pub enum MoveTarget {
|
||||
Adjacent,
|
||||
AdjacentAlly,
|
||||
AdjacentAllySelf,
|
||||
AdjacentOpponent,
|
||||
|
||||
All,
|
||||
AllAdjacent,
|
||||
AllAdjacentOpponent,
|
||||
AllAlly,
|
||||
AllOpponent,
|
||||
|
||||
Any,
|
||||
|
||||
RandomOpponent,
|
||||
OnSelf,
|
||||
}
|
||||
|
||||
struct MoveDataInner {
|
||||
ptr: ExternRef<MoveData>,
|
||||
name: CachedValue<StringKey>,
|
||||
move_type: CachedValue<u8>,
|
||||
category: CachedValue<MoveCategory>,
|
||||
base_power: CachedValue<u8>,
|
||||
accuracy: CachedValue<u8>,
|
||||
base_usages: CachedValue<u8>,
|
||||
target: CachedValue<MoveTarget>,
|
||||
priority: CachedValue<i8>,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct MoveData {
|
||||
inner: Rc<MoveDataInner>,
|
||||
}
|
||||
|
||||
impl MoveData {
|
||||
pub(crate) fn new(ptr: ExternRef<Self>) -> Self {
|
||||
MoveData::from_ref(ptr, &|ptr| Self {
|
||||
inner: Rc::new(MoveDataInner {
|
||||
ptr,
|
||||
name: cached_value!({ StringKey::new(move_data_get_name(ptr)) }),
|
||||
move_type: cached_value!({ move_data_get_type(ptr) }),
|
||||
category: cached_value!({ move_data_get_category(ptr) }),
|
||||
base_power: cached_value!({ move_data_get_base_power(ptr) }),
|
||||
accuracy: cached_value!({ move_data_get_accuracy(ptr) }),
|
||||
base_usages: cached_value!({ move_data_get_base_power(ptr) }),
|
||||
target: cached_value!({ move_data_get_target(ptr) }),
|
||||
priority: cached_value!({ move_data_get_priority(ptr) }),
|
||||
}),
|
||||
})
|
||||
}
|
||||
|
||||
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 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) }
|
||||
}
|
||||
}
|
||||
|
||||
impl ExternalReferenceType for MoveData {
|
||||
fn from_extern_value(reference: ExternRef<Self>) -> Self {
|
||||
MoveData::new(reference)
|
||||
}
|
||||
}
|
||||
|
||||
crate::handling::cacheable::cacheable!(MoveData);
|
||||
|
||||
extern "wasm" {
|
||||
fn move_data_get_name(ptr: ExternRef<MoveData>) -> ExternRef<StringKey>;
|
||||
fn move_data_get_type(ptr: ExternRef<MoveData>) -> u8;
|
||||
fn move_data_get_category(ptr: ExternRef<MoveData>) -> MoveCategory;
|
||||
fn move_data_get_base_power(ptr: ExternRef<MoveData>) -> u8;
|
||||
fn move_data_get_accuracy(ptr: ExternRef<MoveData>) -> u8;
|
||||
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_by_hash(ptr: ExternRef<MoveData>, flag_hash: u32) -> bool;
|
||||
}
|
||||
52
pkmn_lib_interface/src/app_interface/static_data/nature.rs
Normal file
52
pkmn_lib_interface/src/app_interface/static_data/nature.rs
Normal file
@@ -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;
|
||||
}
|
||||
270
pkmn_lib_interface/src/app_interface/static_data/species.rs
Normal file
270
pkmn_lib_interface/src/app_interface/static_data/species.rs
Normal file
@@ -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;
|
||||
}
|
||||
Reference in New Issue
Block a user