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 set_by_player(
65        &self,
66        guard: &mut ContainerLockGuard,
67        stack: ItemStack,
68        previous: &ItemStack,
69    ) {
70        // TODO: Call player.onEquipItem(equipmentSlot, previous, stack) here
71        let _ = previous;
72        self.set_item(guard, stack);
73    }
74
75    fn may_place(&self, stack: &ItemStack) -> bool {
76        stack.is_equippable_in_slot(self.slot)
77    }
78
79    fn may_pickup(&self, guard: &ContainerLockGuard, player: &Player) -> bool {
80        let item = self.get_item(guard);
81        if !item.is_empty()
82            && !player.has_infinite_materials()
83            && item.has_enchantment_effect(EnchantmentEffectComponent::PreventArmorChange)
84        {
85            return false;
86        }
87        true
88    }
89
90    fn get_max_stack_size(&self, _guard: &ContainerLockGuard) -> i32 {
91        1
92    }
93
94    fn set_changed(&self, guard: &mut ContainerLockGuard) {
95        self.base.set_changed(guard);
96    }
97
98    fn get_container_slot(&self) -> usize {
99        self.base.get_container_slot()
100    }
101}