use crate::app_interface::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, } #[cfg_attr(feature = "mock_data", mockall::automock)] pub trait ItemTrait { fn reference(&self) -> u32; /// The name of the item. fn name(&self) -> StringKey; /// Which bag slot items are stored in. fn category(&self) -> ItemCategory; /// How the item is categorized when in battle. fn battle_category(&self) -> BattleItemCategory; /// The buying value of the item. fn price(&self) -> i32; fn has_flag(&self, flag: &StringKey) -> bool; } pub type Item = Rc; #[cfg(feature = "mock_data")] pub type MockItem = MockItemTrait; #[cfg(not(feature = "mock_data"))] mod implementation { use crate::app_interface::{BattleItemCategory, ItemCategory, ItemTrait, StringKey}; use crate::handling::cached_value::CachedValue; use crate::handling::extern_ref::{ExternRef, ExternalReferenceType}; use crate::handling::Cacheable; use crate::{cached_value, cached_value_getters}; use alloc::rc::Rc; 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 ItemImpl { inner: Rc, } #[cfg(not(feature = "mock_data"))] impl ItemImpl { 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) }), }), }) } pub(crate) fn reference(&self) -> ExternRef { self.inner.reference } } #[cfg(not(feature = "mock_data"))] impl ItemTrait for ItemImpl { fn reference(&self) -> u32 { self.inner.reference.get_internal_index() } cached_value_getters! { /// The name of the item. fn name(&self) -> StringKey; /// Which bag slot items are stored in. fn category(&self) -> ItemCategory; /// How the item is categorized when in battle. fn battle_category(&self) -> BattleItemCategory; /// The buying value of the item. fn price(&self) -> i32; } fn has_flag(&self, flag: &StringKey) -> bool { unsafe { item_has_flag(self.inner.reference, flag.ptr()) } } } crate::handling::cacheable::cacheable!(ItemImpl); #[cfg(not(feature = "mock_data"))] impl ExternalReferenceType for ItemImpl { fn from_extern_value(reference: ExternRef) -> Self { ItemImpl::new(reference) } } 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(not(feature = "mock_data"))] pub use implementation::*;