Skip to main content

steel_core/inventory/slots/
armor_slot.rs

1use crate::{
2    inventory::{
3        lock::{ContainerLockGuard, ContainerRef},
4        slots::{NormalSlot, Slot, SlotStorage},
5    },
6    player::Player,
7};
8use steel_registry::{
9    enchantment_effect::EnchantmentEffectComponent, equipment::EquipmentSlot, item_stack::ItemStack,
10};
11use steel_utils::{DowncastType, DowncastTypeKey};
12
13/// A [`NormalSlot`] that only accepts items equippable in its equipment slot,
14/// caps at one item, and respects the prevent-armor-change enchantment effect.
15pub struct ArmorSlot {
16    base: NormalSlot,
17    slot: EquipmentSlot,
18}
19
20// SAFETY: This key uniquely identifies Steel's `ArmorSlot`.
21unsafe impl DowncastType for ArmorSlot {
22    const TYPE_KEY: DowncastTypeKey = DowncastTypeKey::new("steel:slot/armor");
23}
24
25impl ArmorSlot {
26    /// Creates a new armor slot.
27    pub fn new(container: impl Into<ContainerRef>, index: usize, slot: EquipmentSlot) -> Self {
28        Self {
29            base: NormalSlot::new(container, index),
30            slot,
31        }
32    }
33
34    /// Returns the equipment slot this armor slot accepts.
35    #[must_use]
36    pub const fn equipment_slot(&self) -> EquipmentSlot {
37        self.slot
38    }
39
40    /// Returns a reference to the container.
41    #[must_use]
42    pub fn container_ref(&self) -> ContainerRef {
43        self.base.container_ref()
44    }
45}
46
47impl Slot for ArmorSlot {
48    fn storage(&self) -> &SlotStorage {
49        self.base.storage()
50    }
51
52    fn get_item<'a>(&self, guard: &'a ContainerLockGuard) -> &'a ItemStack {
53        self.base.get_item(guard)
54    }
55
56    fn get_item_mut<'a>(&self, guard: &'a mut ContainerLockGuard) -> &'a mut ItemStack {
57        self.base.get_item_mut(guard)
58    }
59
60    fn set_item(&self, guard: &mut ContainerLockGuard, stack: ItemStack) {
61        self.base.set_item(guard, stack);
62    }
63
64    fn may_place(&self, stack: &ItemStack) -> bool {
65        stack.is_equippable_in_slot(self.slot)
66    }
67
68    fn may_pickup(&self, guard: &ContainerLockGuard, player: &Player) -> bool {
69        let item = self.get_item(guard);
70        item.is_empty()
71            || player.has_infinite_materials()
72            || !item.has_enchantment_effect(EnchantmentEffectComponent::PreventArmorChange)
73    }
74
75    fn get_max_stack_size(&self, _guard: &ContainerLockGuard) -> i32 {
76        1
77    }
78
79    fn set_changed(&self, guard: &mut ContainerLockGuard) {
80        self.base.set_changed(guard);
81    }
82
83    fn get_container_slot(&self) -> usize {
84        self.base.get_container_slot()
85    }
86}