From 449ae227303b4b536f2f64e3f9db63334ac88fcf Mon Sep 17 00:00:00 2001 From: timokoesters Date: Thu, 19 Mar 2020 14:30:50 +0100 Subject: [PATCH] Add inventory stacking --- common/src/comp/inventory/item.rs | 12 ++- common/src/comp/inventory/mod.rs | 151 ++++++++++++++++++++++++++- server/src/events/inventory_manip.rs | 6 +- voxygen/src/hud/item_imgs.rs | 4 +- 4 files changed, 166 insertions(+), 7 deletions(-) diff --git a/common/src/comp/inventory/item.rs b/common/src/comp/inventory/item.rs index d4e7c7ff4b..b65a8d2adb 100644 --- a/common/src/comp/inventory/item.rs +++ b/common/src/comp/inventory/item.rs @@ -194,6 +194,8 @@ pub struct ToolData { // TODO: item specific abilities } +fn default_amount() -> u32 { 1 } + #[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] pub enum ItemKind { /// Something wieldable @@ -205,11 +207,19 @@ pub enum ItemKind { Consumable { kind: Consumable, effect: Effect, + #[serde(skip, default = "default_amount")] + amount: u32, }, Utility { kind: Utility, + #[serde(skip, default = "default_amount")] + amount: u32, + }, + Ingredient { + kind: Ingredient, + #[serde(skip, default = "default_amount")] + amount: u32, }, - Ingredient(Ingredient), } #[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] diff --git a/common/src/comp/inventory/mod.rs b/common/src/comp/inventory/mod.rs index 78e818affb..5a724fff05 100644 --- a/common/src/comp/inventory/mod.rs +++ b/common/src/comp/inventory/mod.rs @@ -29,9 +29,105 @@ impl Inventory { pub fn len(&self) -> usize { self.slots.len() } + /// Adds a new item to the first fitting group of the inventory or starts a + /// new group. Returns the item again if no space was found. + pub fn push(&mut self, item: Item) -> Option { + match item.kind { + ItemKind::Tool(_) | ItemKind::Armor { .. } => self.add_to_first_empty(item), + ItemKind::Utility { + kind: item_kind, + amount: new_amount, + } => { + for slot in &mut self.slots { + if slot + .as_ref() + .map(|s| s.name() == item.name()) + .unwrap_or(false) + && slot + .as_ref() + .map(|s| s.description() == item.description()) + .unwrap_or(false) + { + if let Some(Item { + kind: ItemKind::Utility { kind, amount }, + .. + }) = slot + { + if item_kind == *kind { + *amount += new_amount; + return None; + } + } + } + } + // It didn't work + self.add_to_first_empty(item) + }, + ItemKind::Consumable { + kind: item_kind, + amount: new_amount, + .. + } => { + for slot in &mut self.slots { + if slot + .as_ref() + .map(|s| s.name() == item.name()) + .unwrap_or(false) + && slot + .as_ref() + .map(|s| s.description() == item.description()) + .unwrap_or(false) + { + if let Some(Item { + kind: ItemKind::Consumable { kind, amount, .. }, + .. + }) = slot + { + if item_kind == *kind { + *amount += new_amount; + return None; + } + } + } + } + // It didn't work + self.add_to_first_empty(item) + }, + ItemKind::Ingredient { + kind: item_kind, + amount: new_amount, + } => { + for slot in &mut self.slots { + if slot + .as_ref() + .map(|s| s.name() == item.name()) + .unwrap_or(false) + && slot + .as_ref() + .map(|s| s.description() == item.description()) + .unwrap_or(false) + { + if let Some(Item { + kind: ItemKind::Ingredient { kind, amount }, + .. + }) = slot + { + if item_kind == *kind { + *amount += new_amount; + return None; + } + } + } + } + // It didn't work + self.add_to_first_empty(item) + }, + } + } + /// Adds a new item to the first empty slot of the inventory. Returns the /// item again if no free slot was found. - pub fn push(&mut self, item: Item) -> Option { + fn add_to_first_empty(&mut self, item: Item) -> Option { match self.slots.iter_mut().find(|slot| slot.is_none()) { Some(slot) => { *slot = Some(item); @@ -123,6 +219,59 @@ impl Inventory { pub fn remove(&mut self, cell: usize) -> Option { self.slots.get_mut(cell).and_then(|item| item.take()) } + + /// Remove just one item from the slot + pub fn take(&mut self, cell: usize) -> Option { + if let Some(Some(item)) = self.slots.get_mut(cell) { + let mut return_item = item.clone(); + match &mut item.kind { + ItemKind::Tool(_) | ItemKind::Armor { .. } => self.remove(cell), + ItemKind::Utility { kind, amount } => { + if *amount <= 1 { + self.remove(cell) + } else { + *amount -= 1; + return_item.kind = ItemKind::Utility { + kind: *kind, + amount: 1, + }; + Some(return_item) + } + }, + ItemKind::Consumable { + kind, + amount, + effect, + } => { + if *amount <= 1 { + self.remove(cell) + } else { + *amount -= 1; + return_item.kind = ItemKind::Consumable { + kind: *kind, + effect: *effect, + amount: 1, + }; + Some(return_item) + } + }, + ItemKind::Ingredient { kind, amount } => { + if *amount <= 1 { + self.remove(cell) + } else { + *amount -= 1; + return_item.kind = ItemKind::Ingredient { + kind: *kind, + amount: 1, + }; + Some(return_item) + } + }, + } + } else { + None + } + } } impl Default for Inventory { diff --git a/server/src/events/inventory_manip.rs b/server/src/events/inventory_manip.rs index 7ac4795e93..2bf1fa0e6f 100644 --- a/server/src/events/inventory_manip.rs +++ b/server/src/events/inventory_manip.rs @@ -88,7 +88,7 @@ pub fn handle_inventory(server: &mut Server, entity: EcsEntity, manip: comp::Inv .ecs() .write_storage::() .get_mut(entity) - .and_then(|inv| inv.remove(slot_idx)); + .and_then(|inv| inv.take(slot_idx)); let mut event = comp::InventoryUpdateEvent::Used; @@ -120,7 +120,7 @@ pub fn handle_inventory(server: &mut Server, entity: EcsEntity, manip: comp::Inv } }, - comp::ItemKind::Consumable { kind, effect } => { + comp::ItemKind::Consumable { kind, effect, .. } => { event = comp::InventoryUpdateEvent::Consumed(*kind); state.apply_effect(entity, *effect); }, @@ -152,7 +152,7 @@ pub fn handle_inventory(server: &mut Server, entity: EcsEntity, manip: comp::Inv } }, - comp::ItemKind::Utility { kind } => match kind { + comp::ItemKind::Utility { kind, .. } => match kind { comp::item::Utility::Collar => { let reinsert = if let Some(pos) = state.read_storage::().get(entity) diff --git a/voxygen/src/hud/item_imgs.rs b/voxygen/src/hud/item_imgs.rs index 863a5b4e8c..3344633615 100644 --- a/voxygen/src/hud/item_imgs.rs +++ b/voxygen/src/hud/item_imgs.rs @@ -26,9 +26,9 @@ impl From<&Item> for ItemKey { match &item.kind { ItemKind::Tool(ToolData { kind, .. }) => ItemKey::Tool(kind.clone()), ItemKind::Armor { kind, .. } => ItemKey::Armor(kind.clone()), - ItemKind::Utility { kind } => ItemKey::Utility(kind.clone()), + ItemKind::Utility { kind, .. } => ItemKey::Utility(kind.clone()), ItemKind::Consumable { kind, .. } => ItemKey::Consumable(kind.clone()), - ItemKind::Ingredient(kind) => ItemKey::Ingredient(kind.clone()), + ItemKind::Ingredient { kind, .. } => ItemKey::Ingredient(kind.clone()), } } }