Gen7ScriptsRs/pkmn_lib_interface/src/app_interface/static_data/species.rs

280 lines
9.6 KiB
Rust
Executable File

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::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 {
#[cfg(not(feature = "mock_data"))]
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 {
#[cfg(not(feature = "mock_data"))]
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()
}
#[cfg(not(feature = "mock_data"))]
pub fn has_flag(&self, flag: &str) -> 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<hashbrown::HashMap<u32, Option<Form>>>,
}
#[derive(Clone)]
pub struct Species {
inner: Rc<SpeciesInner>,
}
impl Species {
#[cfg(not(feature = "mock_data"))]
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;
}
#[cfg(not(feature = "mock_data"))]
pub fn get_form(&self, form_name: &str) -> Option<Form> {
let hash = get_hash(form_name);
unsafe {
if let Some(v) = self.inner.forms.read().get(&hash) {
v.clone()
} 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
}
}
}
#[cfg(not(feature = "mock_data"))]
pub fn has_flag(&self, flag: &str) -> bool {
let hash = get_hash(flag);
unsafe { species_has_flag_by_hash(self.inner.reference, hash) }
}
}
#[cfg(not(feature = "mock_data"))]
impl ExternalReferenceType for ImmutableStatisticSet {
fn from_extern_value(reference: ExternRef<Self>) -> Self {
Self::new(reference)
}
}
#[cfg(not(feature = "mock_data"))]
impl ExternalReferenceType for Form {
fn from_extern_value(reference: ExternRef<Self>) -> Self {
Self::new(reference)
}
}
#[cfg(not(feature = "mock_data"))]
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);
#[cfg(not(feature = "mock_data"))]
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;
}