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, name: CachedValue, category: CachedValue, battle_category: CachedValue, price: CachedValue, } /// 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, } impl Item { #[cfg(not(feature = "mock_data"))] pub(crate) fn new(reference: ExternRef) -> 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) }), }), }) } #[cfg(not(feature = "mock_data"))] pub(crate) fn reference(&self) -> ExternRef { 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; } #[cfg(not(feature = "mock_data"))] pub fn has_flag(&self, flag: &StringKey) -> bool { unsafe { item_has_flag(self.inner.reference, flag.ptr()) } } } crate::handling::cacheable::cacheable!(Item); #[cfg(not(feature = "mock_data"))] impl ExternalReferenceType for Item { fn from_extern_value(reference: ExternRef) -> Self { Item::new(reference) } } #[cfg(not(feature = "mock_data"))] extern "wasm" { fn item_get_name(ptr: ExternRef) -> ExternRef; fn item_get_category(ptr: ExternRef) -> ItemCategory; fn item_get_battle_category(ptr: ExternRef) -> BattleItemCategory; fn item_get_price(ptr: ExternRef) -> i32; fn item_has_flag(ptr: ExternRef, flag: ExternRef) -> bool; } #[cfg(feature = "mock_data")] mod test { use super::Item; use super::ItemInner; use crate::app_interface::{BattleItemCategory, ItemCategory}; use crate::{cached_value, ExternRef, StringKey}; use alloc::rc::Rc; impl Item { pub fn mock() -> Self { Self { inner: Rc::new(ItemInner { reference: ExternRef::mock(), name: StringKey::new("test").into(), category: ItemCategory::MiscItem.into(), battle_category: BattleItemCategory::None.into(), price: 0.into(), }), } } pub fn has_flag(&self) -> bool { unimplemented!() } } }