2021-01-08 19:12:09 +00:00
|
|
|
use crate::hud::slots::EquipSlot;
|
2021-02-13 00:43:33 +00:00
|
|
|
use common::comp::{
|
|
|
|
item::{tool::Hands, ItemKind},
|
|
|
|
slot::InvSlotId,
|
|
|
|
Inventory,
|
|
|
|
};
|
2020-10-05 08:35:24 +00:00
|
|
|
use serde::{Deserialize, Serialize};
|
2020-06-16 13:55:37 +00:00
|
|
|
|
2021-01-08 19:12:09 +00:00
|
|
|
#[derive(Clone, Copy, Debug, PartialEq)]
|
2020-04-11 06:33:06 +00:00
|
|
|
pub enum Slot {
|
|
|
|
One = 0,
|
|
|
|
Two = 1,
|
|
|
|
Three = 2,
|
|
|
|
Four = 3,
|
|
|
|
Five = 4,
|
|
|
|
Six = 5,
|
|
|
|
Seven = 6,
|
|
|
|
Eight = 7,
|
|
|
|
Nine = 8,
|
|
|
|
Ten = 9,
|
|
|
|
}
|
|
|
|
|
2020-06-16 13:55:37 +00:00
|
|
|
#[derive(Clone, Copy, PartialEq, Debug, Serialize, Deserialize)]
|
2020-04-11 06:33:06 +00:00
|
|
|
pub enum SlotContents {
|
2021-01-08 19:12:09 +00:00
|
|
|
Inventory(InvSlotId),
|
2020-04-11 06:33:06 +00:00
|
|
|
Ability3,
|
2021-02-13 00:43:33 +00:00
|
|
|
Ability4,
|
2020-04-11 06:33:06 +00:00
|
|
|
}
|
|
|
|
|
2020-06-16 13:55:37 +00:00
|
|
|
#[derive(Clone, Debug)]
|
2020-04-11 06:33:06 +00:00
|
|
|
pub struct State {
|
2020-06-16 13:55:37 +00:00
|
|
|
pub slots: [Option<SlotContents>; 10],
|
2020-04-11 06:33:06 +00:00
|
|
|
inputs: [bool; 10],
|
|
|
|
}
|
|
|
|
|
2020-06-16 13:55:37 +00:00
|
|
|
impl Default for State {
|
|
|
|
fn default() -> Self {
|
2020-04-11 06:33:06 +00:00
|
|
|
Self {
|
|
|
|
slots: [None; 10],
|
|
|
|
inputs: [false; 10],
|
|
|
|
}
|
|
|
|
}
|
2020-06-16 13:55:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl State {
|
|
|
|
pub fn new(slots: [Option<SlotContents>; 10]) -> Self {
|
|
|
|
Self {
|
|
|
|
slots,
|
|
|
|
inputs: [false; 10],
|
|
|
|
}
|
|
|
|
}
|
2020-04-11 06:33:06 +00:00
|
|
|
|
2020-04-12 19:45:01 +00:00
|
|
|
/// Returns true if the button was just pressed
|
2020-04-11 06:33:06 +00:00
|
|
|
pub fn process_input(&mut self, slot: Slot, state: bool) -> bool {
|
|
|
|
let slot = slot as usize;
|
|
|
|
let just_pressed = !self.inputs[slot] && state;
|
|
|
|
self.inputs[slot] = state;
|
|
|
|
just_pressed
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn get(&self, slot: Slot) -> Option<SlotContents> { self.slots[slot as usize] }
|
|
|
|
|
|
|
|
pub fn swap(&mut self, a: Slot, b: Slot) { self.slots.swap(a as usize, b as usize); }
|
|
|
|
|
|
|
|
pub fn clear_slot(&mut self, slot: Slot) { self.slots[slot as usize] = None; }
|
|
|
|
|
2021-01-08 19:12:09 +00:00
|
|
|
pub fn add_inventory_link(&mut self, slot: Slot, inventory_pos: InvSlotId) {
|
|
|
|
self.slots[slot as usize] = Some(SlotContents::Inventory(inventory_pos));
|
2020-04-11 06:33:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// TODO: remove
|
|
|
|
// Adds ability3 slot if it is missing and should be present
|
|
|
|
// Removes if it is there and shouldn't be present
|
2020-06-23 06:52:04 +00:00
|
|
|
#[allow(clippy::unnested_or_patterns)] // TODO: Pending review in #587
|
2020-04-11 06:33:06 +00:00
|
|
|
pub fn maintain_ability3(&mut self, client: &client::Client) {
|
|
|
|
use specs::WorldExt;
|
2021-01-08 19:12:09 +00:00
|
|
|
let inventories = client.state().ecs().read_storage::<Inventory>();
|
|
|
|
let inventory = inventories.get(client.entity());
|
2021-01-05 06:03:25 +00:00
|
|
|
let stats = client.state().ecs().read_storage::<common::comp::Stats>();
|
|
|
|
let stat = stats.get(client.entity());
|
2021-03-24 04:54:25 +00:00
|
|
|
|
|
|
|
let hands =
|
|
|
|
|equip_slot| match inventory.and_then(|i| i.equipped(equip_slot).map(|i| i.kind())) {
|
|
|
|
Some(ItemKind::Tool(tool)) => Some(tool.hands),
|
|
|
|
_ => None,
|
|
|
|
};
|
2021-03-24 02:04:21 +00:00
|
|
|
|
|
|
|
let equip_slot = match (hands(EquipSlot::Mainhand), hands(EquipSlot::Offhand)) {
|
|
|
|
(Some(_), _) => Some(EquipSlot::Mainhand),
|
|
|
|
(_, Some(_)) => Some(EquipSlot::Offhand),
|
|
|
|
_ => None,
|
|
|
|
};
|
|
|
|
|
2021-03-24 04:54:25 +00:00
|
|
|
let should_be_present = if let (Some(inventory), Some(stat), Some(equip_slot)) =
|
|
|
|
(inventory, stat, equip_slot)
|
|
|
|
{
|
2021-03-24 02:04:21 +00:00
|
|
|
inventory.equipped(equip_slot).map_or(false, |i| {
|
2021-02-12 20:32:08 +00:00
|
|
|
i.item_config_expect()
|
2021-02-12 23:09:05 +00:00
|
|
|
.abilities
|
2021-02-19 23:45:48 +00:00
|
|
|
.abilities
|
2021-02-12 23:09:05 +00:00
|
|
|
.get(0)
|
2021-02-12 20:32:08 +00:00
|
|
|
.as_ref()
|
|
|
|
.map_or(false, |(s, _)| {
|
|
|
|
s.map_or(true, |s| stat.skill_set.has_skill(s))
|
|
|
|
})
|
|
|
|
})
|
2020-04-11 06:33:06 +00:00
|
|
|
} else {
|
|
|
|
false
|
|
|
|
};
|
|
|
|
|
|
|
|
if should_be_present {
|
|
|
|
if !self
|
|
|
|
.slots
|
|
|
|
.iter()
|
|
|
|
.any(|s| matches!(s, Some(SlotContents::Ability3)))
|
|
|
|
{
|
|
|
|
self.slots[0] = Some(SlotContents::Ability3);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
self.slots
|
|
|
|
.iter_mut()
|
|
|
|
.filter(|s| matches!(s, Some(SlotContents::Ability3)))
|
|
|
|
.for_each(|s| *s = None)
|
|
|
|
}
|
|
|
|
}
|
2021-02-13 00:43:33 +00:00
|
|
|
|
|
|
|
pub fn maintain_ability4(&mut self, client: &client::Client) {
|
|
|
|
use specs::WorldExt;
|
|
|
|
let inventories = client.state().ecs().read_storage::<Inventory>();
|
|
|
|
let inventory = inventories.get(client.entity());
|
|
|
|
let stats = client.state().ecs().read_storage::<common::comp::Stats>();
|
|
|
|
let stat = stats.get(client.entity());
|
|
|
|
let should_be_present = if let (Some(inventory), Some(stat)) = (inventory, stat) {
|
2021-02-19 23:45:48 +00:00
|
|
|
let hands = |equip_slot| match inventory.equipped(equip_slot).map(|i| i.kind()) {
|
2021-02-13 00:43:33 +00:00
|
|
|
Some(ItemKind::Tool(tool)) => Some(tool.hands),
|
|
|
|
_ => None,
|
|
|
|
};
|
|
|
|
|
2021-02-19 23:45:48 +00:00
|
|
|
let active_tool_hands = hands(EquipSlot::Mainhand);
|
|
|
|
let second_tool_hands = hands(EquipSlot::Offhand);
|
2021-02-13 00:43:33 +00:00
|
|
|
|
|
|
|
let (equip_slot, skill_index) = match (active_tool_hands, second_tool_hands) {
|
2021-02-19 23:45:48 +00:00
|
|
|
(Some(Hands::Two), _) => (Some(EquipSlot::Mainhand), 1),
|
2021-03-24 02:04:21 +00:00
|
|
|
(Some(_), Some(Hands::One)) => (Some(EquipSlot::Offhand), 0),
|
2021-02-19 23:45:48 +00:00
|
|
|
(Some(Hands::One), _) => (Some(EquipSlot::Mainhand), 1),
|
2021-03-24 02:04:21 +00:00
|
|
|
(None, Some(_)) => (Some(EquipSlot::Offhand), 1),
|
2021-02-13 00:43:33 +00:00
|
|
|
(_, _) => (None, 0),
|
|
|
|
};
|
|
|
|
|
|
|
|
if let Some(equip_slot) = equip_slot {
|
|
|
|
inventory.equipped(equip_slot).map_or(false, |i| {
|
|
|
|
i.item_config_expect()
|
|
|
|
.abilities
|
2021-02-19 23:45:48 +00:00
|
|
|
.abilities
|
2021-02-13 00:43:33 +00:00
|
|
|
.get(skill_index)
|
|
|
|
.as_ref()
|
|
|
|
.map_or(false, |(s, _)| {
|
|
|
|
s.map_or(true, |s| stat.skill_set.has_skill(s))
|
|
|
|
})
|
|
|
|
})
|
|
|
|
} else {
|
|
|
|
false
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
false
|
|
|
|
};
|
|
|
|
|
|
|
|
if should_be_present {
|
|
|
|
if !self
|
|
|
|
.slots
|
|
|
|
.iter()
|
|
|
|
.any(|s| matches!(s, Some(SlotContents::Ability4)))
|
|
|
|
{
|
|
|
|
self.slots[1] = Some(SlotContents::Ability4);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
self.slots
|
|
|
|
.iter_mut()
|
|
|
|
.filter(|s| matches!(s, Some(SlotContents::Ability4)))
|
|
|
|
.for_each(|s| *s = None)
|
|
|
|
}
|
|
|
|
}
|
2020-04-11 06:33:06 +00:00
|
|
|
}
|