Add inventory stacking

This commit is contained in:
timokoesters 2020-03-19 14:30:50 +01:00
parent d863e12235
commit 449ae22730
4 changed files with 166 additions and 7 deletions

View File

@ -194,6 +194,8 @@ pub struct ToolData {
// TODO: item specific abilities // TODO: item specific abilities
} }
fn default_amount() -> u32 { 1 }
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] #[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub enum ItemKind { pub enum ItemKind {
/// Something wieldable /// Something wieldable
@ -205,11 +207,19 @@ pub enum ItemKind {
Consumable { Consumable {
kind: Consumable, kind: Consumable,
effect: Effect, effect: Effect,
#[serde(skip, default = "default_amount")]
amount: u32,
}, },
Utility { Utility {
kind: 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)] #[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]

View File

@ -29,9 +29,105 @@ impl Inventory {
pub fn len(&self) -> usize { self.slots.len() } 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<Item> {
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 /// Adds a new item to the first empty slot of the inventory. Returns the
/// item again if no free slot was found. /// item again if no free slot was found.
pub fn push(&mut self, item: Item) -> Option<Item> { fn add_to_first_empty(&mut self, item: Item) -> Option<Item> {
match self.slots.iter_mut().find(|slot| slot.is_none()) { match self.slots.iter_mut().find(|slot| slot.is_none()) {
Some(slot) => { Some(slot) => {
*slot = Some(item); *slot = Some(item);
@ -123,6 +219,59 @@ impl Inventory {
pub fn remove(&mut self, cell: usize) -> Option<Item> { pub fn remove(&mut self, cell: usize) -> Option<Item> {
self.slots.get_mut(cell).and_then(|item| item.take()) 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<Item> {
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 { impl Default for Inventory {

View File

@ -88,7 +88,7 @@ pub fn handle_inventory(server: &mut Server, entity: EcsEntity, manip: comp::Inv
.ecs() .ecs()
.write_storage::<comp::Inventory>() .write_storage::<comp::Inventory>()
.get_mut(entity) .get_mut(entity)
.and_then(|inv| inv.remove(slot_idx)); .and_then(|inv| inv.take(slot_idx));
let mut event = comp::InventoryUpdateEvent::Used; 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); event = comp::InventoryUpdateEvent::Consumed(*kind);
state.apply_effect(entity, *effect); 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 => { comp::item::Utility::Collar => {
let reinsert = if let Some(pos) = let reinsert = if let Some(pos) =
state.read_storage::<comp::Pos>().get(entity) state.read_storage::<comp::Pos>().get(entity)

View File

@ -26,9 +26,9 @@ impl From<&Item> for ItemKey {
match &item.kind { match &item.kind {
ItemKind::Tool(ToolData { kind, .. }) => ItemKey::Tool(kind.clone()), ItemKind::Tool(ToolData { kind, .. }) => ItemKey::Tool(kind.clone()),
ItemKind::Armor { kind, .. } => ItemKey::Armor(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::Consumable { kind, .. } => ItemKey::Consumable(kind.clone()),
ItemKind::Ingredient(kind) => ItemKey::Ingredient(kind.clone()), ItemKind::Ingredient { kind, .. } => ItemKey::Ingredient(kind.clone()),
} }
} }
} }