veloren_voxygen/hud/
hotbar.rs

1use common::comp::{
2    self,
3    inventory::item::{Item, item_key::ItemKey},
4};
5use serde::{Deserialize, Serialize};
6
7use super::HudInfo;
8
9#[derive(Clone, Copy, Debug, PartialEq, Eq, Default)]
10pub enum Slot {
11    #[default]
12    One = 0,
13    Two = 1,
14    Three = 2,
15    Four = 3,
16    Five = 4,
17    Six = 5,
18    Seven = 6,
19    Eight = 7,
20    Nine = 8,
21    Ten = 9,
22}
23
24#[derive(Clone, PartialEq, Eq, Debug, Serialize, Deserialize)]
25pub enum SlotContents {
26    Inventory(u64, ItemKey),
27    Ability(usize),
28}
29
30#[derive(Clone, Default)]
31pub struct State {
32    pub slots: [Option<SlotContents>; 10],
33    inputs: [bool; 10],
34    pub currently_selected_slot: Slot,
35}
36
37impl State {
38    pub fn new(slots: [Option<SlotContents>; 10]) -> Self {
39        Self {
40            slots,
41            inputs: [false; 10],
42            currently_selected_slot: Slot::default(),
43        }
44    }
45
46    /// Returns true if the button was just pressed
47    pub fn process_input(&mut self, slot: Slot, state: bool) -> bool {
48        let slot = slot as usize;
49        let just_pressed = !self.inputs[slot] && state;
50        self.inputs[slot] = state;
51        just_pressed
52    }
53
54    pub fn get(&self, slot: Slot) -> Option<SlotContents> { self.slots[slot as usize].clone() }
55
56    pub fn swap(&mut self, a: Slot, b: Slot) { self.slots.swap(a as usize, b as usize); }
57
58    pub fn clear_slot(&mut self, slot: Slot) { self.slots[slot as usize] = None; }
59
60    pub fn add_inventory_link(&mut self, slot: Slot, item: &Item) {
61        self.slots[slot as usize] = Some(SlotContents::Inventory(
62            item.item_hash(),
63            ItemKey::from(item),
64        ));
65    }
66
67    // TODO: remove pending UI
68    // Adds ability slots if missing and should be present
69    // Removes ability slots if not there and shouldn't be present
70    pub fn maintain_abilities(&mut self, client: &client::Client, info: &HudInfo) {
71        use specs::WorldExt;
72        if let Some(active_abilities) = client
73            .state()
74            .ecs()
75            .read_storage::<comp::ActiveAbilities>()
76            .get(info.viewpoint_entity)
77        {
78            use common::comp::ability::AuxiliaryAbility;
79            for ((i, ability), hotbar_slot) in active_abilities
80                .auxiliary_set(
81                    client.inventories().get(info.viewpoint_entity),
82                    client
83                        .state()
84                        .read_storage::<comp::SkillSet>()
85                        .get(info.viewpoint_entity),
86                )
87                .iter()
88                .enumerate()
89                .zip(self.slots.iter_mut())
90            {
91                if matches!(ability, AuxiliaryAbility::Empty) {
92                    if matches!(hotbar_slot, Some(SlotContents::Ability(_))) {
93                        // If ability is empty but hotbar shows an ability, clear it
94                        *hotbar_slot = None;
95                    }
96                } else {
97                    // If an ability is not empty show it on the hotbar
98                    *hotbar_slot = Some(SlotContents::Ability(i));
99                }
100            }
101        } else {
102            self.slots
103                .iter_mut()
104                .filter(|slot| matches!(slot, Some(SlotContents::Ability(_))))
105                .for_each(|slot| *slot = None)
106        }
107    }
108}
109
110impl Slot {
111    const SLOTS: [Slot; 10] = [
112        Slot::One,
113        Slot::Two,
114        Slot::Three,
115        Slot::Four,
116        Slot::Five,
117        Slot::Six,
118        Slot::Seven,
119        Slot::Eight,
120        Slot::Nine,
121        Slot::Ten,
122    ];
123
124    pub fn next_slot(&mut self) {
125        let current_slot = *self as usize;
126        let next_slot = (current_slot + 1) % 10;
127        *self = Self::SLOTS[next_slot];
128    }
129
130    pub fn previous_slot(&mut self) {
131        let current_slot = *self as usize;
132        let previous_slot = (current_slot + 10 - 1) % 10;
133        *self = Self::SLOTS[previous_slot];
134    }
135}