mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Recently unequipped items are now tracked and durability loss on death is applied to them
This commit is contained in:
parent
77785faeec
commit
c1a64e1d69
@ -1,18 +1,26 @@
|
|||||||
use crate::comp::{
|
use crate::{
|
||||||
inventory::{
|
comp::{
|
||||||
item::{self, tool::Tool, Hands, ItemKind},
|
inventory::{
|
||||||
slot::{ArmorSlot, EquipSlot},
|
item::{self, tool::Tool, Hands, ItemDefinitionIdOwned, ItemKind},
|
||||||
InvSlot,
|
slot::{ArmorSlot, EquipSlot},
|
||||||
|
InvSlot,
|
||||||
|
},
|
||||||
|
Item,
|
||||||
},
|
},
|
||||||
Item,
|
resources::Time,
|
||||||
};
|
};
|
||||||
|
use hashbrown::HashMap;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::ops::Range;
|
use std::ops::Range;
|
||||||
use tracing::warn;
|
use tracing::warn;
|
||||||
|
|
||||||
|
pub(super) const UNEQUIP_TRACKING_DURATION: f64 = 60.0;
|
||||||
|
|
||||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||||
pub struct Loadout {
|
pub struct Loadout {
|
||||||
slots: Vec<LoadoutSlot>,
|
slots: Vec<LoadoutSlot>,
|
||||||
|
// Includes time that item was unequipped at
|
||||||
|
pub(super) recently_unequipped_items: HashMap<ItemDefinitionIdOwned, Time>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// NOTE: Please don't derive a PartialEq Instance for this; that's broken!
|
/// NOTE: Please don't derive a PartialEq Instance for this; that's broken!
|
||||||
@ -83,16 +91,36 @@ impl Loadout {
|
|||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|(equip_slot, persistence_key)| LoadoutSlot::new(equip_slot, persistence_key))
|
.map(|(equip_slot, persistence_key)| LoadoutSlot::new(equip_slot, persistence_key))
|
||||||
.collect(),
|
.collect(),
|
||||||
|
recently_unequipped_items: HashMap::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Replaces the item in the Loadout slot that corresponds to the given
|
/// Replaces the item in the Loadout slot that corresponds to the given
|
||||||
/// EquipSlot and returns the previous item if any
|
/// EquipSlot and returns the previous item if any
|
||||||
pub(super) fn swap(&mut self, equip_slot: EquipSlot, item: Option<Item>) -> Option<Item> {
|
pub(super) fn swap(
|
||||||
self.slots
|
&mut self,
|
||||||
|
equip_slot: EquipSlot,
|
||||||
|
item: Option<Item>,
|
||||||
|
time: Time,
|
||||||
|
) -> Option<Item> {
|
||||||
|
self.recently_unequipped_items.retain(|def, unequip_time| {
|
||||||
|
let item_reequipped = item
|
||||||
|
.as_ref()
|
||||||
|
.map_or(false, |i| def.as_ref() == i.item_definition_id());
|
||||||
|
let old_unequip = time.0 - unequip_time.0 > UNEQUIP_TRACKING_DURATION;
|
||||||
|
// Stop tracking item if it is re-equipped or if was unequipped a while ago
|
||||||
|
!(item_reequipped || old_unequip)
|
||||||
|
});
|
||||||
|
let unequipped_item = self
|
||||||
|
.slots
|
||||||
.iter_mut()
|
.iter_mut()
|
||||||
.find(|x| x.equip_slot == equip_slot)
|
.find(|x| x.equip_slot == equip_slot)
|
||||||
.and_then(|x| core::mem::replace(&mut x.slot, item))
|
.and_then(|x| core::mem::replace(&mut x.slot, item));
|
||||||
|
if let Some(unequipped_item) = unequipped_item.as_ref() {
|
||||||
|
self.recently_unequipped_items
|
||||||
|
.insert(unequipped_item.item_definition_id().to_owned(), time);
|
||||||
|
}
|
||||||
|
unequipped_item
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns a reference to the item (if any) equipped in the given EquipSlot
|
/// Returns a reference to the item (if any) equipped in the given EquipSlot
|
||||||
@ -154,7 +182,12 @@ impl Loadout {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Swaps the contents of two loadout slots
|
/// Swaps the contents of two loadout slots
|
||||||
pub(super) fn swap_slots(&mut self, equip_slot_a: EquipSlot, equip_slot_b: EquipSlot) {
|
pub(super) fn swap_slots(
|
||||||
|
&mut self,
|
||||||
|
equip_slot_a: EquipSlot,
|
||||||
|
equip_slot_b: EquipSlot,
|
||||||
|
time: Time,
|
||||||
|
) {
|
||||||
if self.slot(equip_slot_b).is_none() || self.slot(equip_slot_b).is_none() {
|
if self.slot(equip_slot_b).is_none() || self.slot(equip_slot_b).is_none() {
|
||||||
// Currently all loadouts contain slots for all EquipSlots so this can never
|
// Currently all loadouts contain slots for all EquipSlots so this can never
|
||||||
// happen, but if loadouts with alternate slot combinations are
|
// happen, but if loadouts with alternate slot combinations are
|
||||||
@ -163,9 +196,9 @@ impl Loadout {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let item_a = self.swap(equip_slot_a, None);
|
let item_a = self.swap(equip_slot_a, None, time);
|
||||||
let item_b = self.swap(equip_slot_b, item_a);
|
let item_b = self.swap(equip_slot_b, item_a, time);
|
||||||
assert_eq!(self.swap(equip_slot_a, item_b), None);
|
assert_eq!(self.swap(equip_slot_a, item_b, time), None);
|
||||||
|
|
||||||
// Check if items are valid in their new positions
|
// Check if items are valid in their new positions
|
||||||
if !self.slot_can_hold(
|
if !self.slot_can_hold(
|
||||||
@ -176,9 +209,9 @@ impl Loadout {
|
|||||||
self.equipped(equip_slot_b).map(|x| x.kind()).as_deref(),
|
self.equipped(equip_slot_b).map(|x| x.kind()).as_deref(),
|
||||||
) {
|
) {
|
||||||
// If not, revert the swap
|
// If not, revert the swap
|
||||||
let item_a = self.swap(equip_slot_a, None);
|
let item_a = self.swap(equip_slot_a, None, time);
|
||||||
let item_b = self.swap(equip_slot_b, item_a);
|
let item_b = self.swap(equip_slot_b, item_a, time);
|
||||||
assert_eq!(self.swap(equip_slot_a, item_b), None);
|
assert_eq!(self.swap(equip_slot_a, item_b, time), None);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -367,7 +400,7 @@ impl Loadout {
|
|||||||
(None, None))
|
(None, None))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn swap_equipped_weapons(&mut self) {
|
pub(super) fn swap_equipped_weapons(&mut self, time: Time) {
|
||||||
// Checks if a given slot can hold an item right now, defaults to true if
|
// Checks if a given slot can hold an item right now, defaults to true if
|
||||||
// nothing is equipped in slot
|
// nothing is equipped in slot
|
||||||
let valid_slot = |equip_slot| {
|
let valid_slot = |equip_slot| {
|
||||||
@ -385,25 +418,25 @@ impl Loadout {
|
|||||||
&& valid_slot(EquipSlot::InactiveOffhand)
|
&& valid_slot(EquipSlot::InactiveOffhand)
|
||||||
{
|
{
|
||||||
// Get weapons from each slot
|
// Get weapons from each slot
|
||||||
let active_mainhand = self.swap(EquipSlot::ActiveMainhand, None);
|
let active_mainhand = self.swap(EquipSlot::ActiveMainhand, None, time);
|
||||||
let active_offhand = self.swap(EquipSlot::ActiveOffhand, None);
|
let active_offhand = self.swap(EquipSlot::ActiveOffhand, None, time);
|
||||||
let inactive_mainhand = self.swap(EquipSlot::InactiveMainhand, None);
|
let inactive_mainhand = self.swap(EquipSlot::InactiveMainhand, None, time);
|
||||||
let inactive_offhand = self.swap(EquipSlot::InactiveOffhand, None);
|
let inactive_offhand = self.swap(EquipSlot::InactiveOffhand, None, time);
|
||||||
// Equip weapons into new slots
|
// Equip weapons into new slots
|
||||||
assert!(
|
assert!(
|
||||||
self.swap(EquipSlot::ActiveMainhand, inactive_mainhand)
|
self.swap(EquipSlot::ActiveMainhand, inactive_mainhand, time)
|
||||||
.is_none()
|
.is_none()
|
||||||
);
|
);
|
||||||
assert!(
|
assert!(
|
||||||
self.swap(EquipSlot::ActiveOffhand, inactive_offhand)
|
self.swap(EquipSlot::ActiveOffhand, inactive_offhand, time)
|
||||||
.is_none()
|
.is_none()
|
||||||
);
|
);
|
||||||
assert!(
|
assert!(
|
||||||
self.swap(EquipSlot::InactiveMainhand, active_mainhand)
|
self.swap(EquipSlot::InactiveMainhand, active_mainhand, time)
|
||||||
.is_none()
|
.is_none()
|
||||||
);
|
);
|
||||||
assert!(
|
assert!(
|
||||||
self.swap(EquipSlot::InactiveOffhand, active_offhand)
|
self.swap(EquipSlot::InactiveOffhand, active_offhand, time)
|
||||||
.is_none()
|
.is_none()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -9,6 +9,7 @@ use crate::{
|
|||||||
item::{self, Item},
|
item::{self, Item},
|
||||||
object, quadruped_low, quadruped_medium, theropod, Body,
|
object, quadruped_low, quadruped_medium, theropod, Body,
|
||||||
},
|
},
|
||||||
|
resources::Time,
|
||||||
trade::SiteInformation,
|
trade::SiteInformation,
|
||||||
};
|
};
|
||||||
use rand::{self, distributions::WeightedError, seq::SliceRandom, Rng};
|
use rand::{self, distributions::WeightedError, seq::SliceRandom, Rng};
|
||||||
@ -1148,7 +1149,11 @@ impl LoadoutBuilder {
|
|||||||
.map_or(true, |item| equip_slot.can_hold(&item.kind()))
|
.map_or(true, |item| equip_slot.can_hold(&item.kind()))
|
||||||
);
|
);
|
||||||
|
|
||||||
self.0.swap(equip_slot, item);
|
// Used when creating a loadout, so time not needed as it is used to check when
|
||||||
|
// stuff gets unequipped. A new loadout has never unequipped an item.
|
||||||
|
let time = Time(0.0);
|
||||||
|
|
||||||
|
self.0.swap(equip_slot, item, time);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -17,6 +17,7 @@ use crate::{
|
|||||||
slot::{InvSlotId, SlotId},
|
slot::{InvSlotId, SlotId},
|
||||||
Item,
|
Item,
|
||||||
},
|
},
|
||||||
|
resources::Time,
|
||||||
uid::Uid,
|
uid::Uid,
|
||||||
LoadoutBuilder,
|
LoadoutBuilder,
|
||||||
};
|
};
|
||||||
@ -615,18 +616,19 @@ impl Inventory {
|
|||||||
&mut self,
|
&mut self,
|
||||||
equip_slot: EquipSlot,
|
equip_slot: EquipSlot,
|
||||||
replacement_item: Option<Item>,
|
replacement_item: Option<Item>,
|
||||||
|
time: Time,
|
||||||
) -> Option<Item> {
|
) -> Option<Item> {
|
||||||
self.loadout.swap(equip_slot, replacement_item)
|
self.loadout.swap(equip_slot, replacement_item, time)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Equip an item from a slot in inventory. The currently equipped item will
|
/// Equip an item from a slot in inventory. The currently equipped item will
|
||||||
/// go into inventory. If the item is going to mainhand, put mainhand in
|
/// go into inventory. If the item is going to mainhand, put mainhand in
|
||||||
/// offhand and place offhand into inventory.
|
/// offhand and place offhand into inventory.
|
||||||
#[must_use = "Returned items will be lost if not used"]
|
#[must_use = "Returned items will be lost if not used"]
|
||||||
pub fn equip(&mut self, inv_slot: InvSlotId) -> Vec<Item> {
|
pub fn equip(&mut self, inv_slot: InvSlotId, time: Time) -> Vec<Item> {
|
||||||
self.get(inv_slot)
|
self.get(inv_slot)
|
||||||
.and_then(|item| self.loadout.get_slot_to_equip_into(&item.kind()))
|
.and_then(|item| self.loadout.get_slot_to_equip_into(&item.kind()))
|
||||||
.map(|equip_slot| self.swap_inventory_loadout(inv_slot, equip_slot))
|
.map(|equip_slot| self.swap_inventory_loadout(inv_slot, equip_slot, time))
|
||||||
.unwrap_or_else(Vec::new)
|
.unwrap_or_else(Vec::new)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -680,7 +682,11 @@ impl Inventory {
|
|||||||
/// equipped if inventory has no slots available.
|
/// equipped if inventory has no slots available.
|
||||||
#[must_use = "Returned items will be lost if not used"]
|
#[must_use = "Returned items will be lost if not used"]
|
||||||
#[allow(clippy::needless_collect)] // This is a false positive, the collect is needed
|
#[allow(clippy::needless_collect)] // This is a false positive, the collect is needed
|
||||||
pub fn unequip(&mut self, equip_slot: EquipSlot) -> Result<Option<Vec<Item>>, SlotError> {
|
pub fn unequip(
|
||||||
|
&mut self,
|
||||||
|
equip_slot: EquipSlot,
|
||||||
|
time: Time,
|
||||||
|
) -> Result<Option<Vec<Item>>, SlotError> {
|
||||||
// Ensure there is enough space in the inventory to place the unequipped item
|
// Ensure there is enough space in the inventory to place the unequipped item
|
||||||
if self.free_slots_minus_equipped_item(equip_slot) == 0 {
|
if self.free_slots_minus_equipped_item(equip_slot) == 0 {
|
||||||
return Err(SlotError::InventoryFull);
|
return Err(SlotError::InventoryFull);
|
||||||
@ -688,7 +694,7 @@ impl Inventory {
|
|||||||
|
|
||||||
Ok(self
|
Ok(self
|
||||||
.loadout
|
.loadout
|
||||||
.swap(equip_slot, None)
|
.swap(equip_slot, None, time)
|
||||||
.and_then(|mut unequipped_item| {
|
.and_then(|mut unequipped_item| {
|
||||||
let unloaded_items: Vec<Item> = unequipped_item.drain().collect();
|
let unloaded_items: Vec<Item> = unequipped_item.drain().collect();
|
||||||
self.push(unequipped_item)
|
self.push(unequipped_item)
|
||||||
@ -721,7 +727,7 @@ impl Inventory {
|
|||||||
/// Swaps items from two slots, regardless of if either is inventory or
|
/// Swaps items from two slots, regardless of if either is inventory or
|
||||||
/// loadout.
|
/// loadout.
|
||||||
#[must_use = "Returned items will be lost if not used"]
|
#[must_use = "Returned items will be lost if not used"]
|
||||||
pub fn swap(&mut self, slot_a: Slot, slot_b: Slot) -> Vec<Item> {
|
pub fn swap(&mut self, slot_a: Slot, slot_b: Slot, time: Time) -> Vec<Item> {
|
||||||
match (slot_a, slot_b) {
|
match (slot_a, slot_b) {
|
||||||
(Slot::Inventory(slot_a), Slot::Inventory(slot_b)) => {
|
(Slot::Inventory(slot_a), Slot::Inventory(slot_b)) => {
|
||||||
self.swap_slots(slot_a, slot_b);
|
self.swap_slots(slot_a, slot_b);
|
||||||
@ -729,10 +735,10 @@ impl Inventory {
|
|||||||
},
|
},
|
||||||
(Slot::Inventory(inv_slot), Slot::Equip(equip_slot))
|
(Slot::Inventory(inv_slot), Slot::Equip(equip_slot))
|
||||||
| (Slot::Equip(equip_slot), Slot::Inventory(inv_slot)) => {
|
| (Slot::Equip(equip_slot), Slot::Inventory(inv_slot)) => {
|
||||||
self.swap_inventory_loadout(inv_slot, equip_slot)
|
self.swap_inventory_loadout(inv_slot, equip_slot, time)
|
||||||
},
|
},
|
||||||
(Slot::Equip(slot_a), Slot::Equip(slot_b)) => {
|
(Slot::Equip(slot_a), Slot::Equip(slot_b)) => {
|
||||||
self.loadout.swap_slots(slot_a, slot_b);
|
self.loadout.swap_slots(slot_a, slot_b, time);
|
||||||
Vec::new()
|
Vec::new()
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@ -768,6 +774,7 @@ impl Inventory {
|
|||||||
&mut self,
|
&mut self,
|
||||||
inv_slot_id: InvSlotId,
|
inv_slot_id: InvSlotId,
|
||||||
equip_slot: EquipSlot,
|
equip_slot: EquipSlot,
|
||||||
|
time: Time,
|
||||||
) -> Vec<Item> {
|
) -> Vec<Item> {
|
||||||
if !self.can_swap(inv_slot_id, equip_slot) {
|
if !self.can_swap(inv_slot_id, equip_slot) {
|
||||||
return Vec::new();
|
return Vec::new();
|
||||||
@ -777,7 +784,7 @@ impl Inventory {
|
|||||||
let from_inv = self.remove(inv_slot_id);
|
let from_inv = self.remove(inv_slot_id);
|
||||||
|
|
||||||
// Swap the equipped item for the item from the inventory
|
// Swap the equipped item for the item from the inventory
|
||||||
let from_equip = self.loadout.swap(equip_slot, from_inv);
|
let from_equip = self.loadout.swap(equip_slot, from_inv, time);
|
||||||
|
|
||||||
let unloaded_items = from_equip
|
let unloaded_items = from_equip
|
||||||
.map(|mut from_equip| {
|
.map(|mut from_equip| {
|
||||||
@ -803,10 +810,10 @@ impl Inventory {
|
|||||||
if self.loadout.equipped(EquipSlot::ActiveMainhand).is_none()
|
if self.loadout.equipped(EquipSlot::ActiveMainhand).is_none()
|
||||||
&& self.loadout.equipped(EquipSlot::ActiveOffhand).is_some()
|
&& self.loadout.equipped(EquipSlot::ActiveOffhand).is_some()
|
||||||
{
|
{
|
||||||
let offhand = self.loadout.swap(EquipSlot::ActiveOffhand, None);
|
let offhand = self.loadout.swap(EquipSlot::ActiveOffhand, None, time);
|
||||||
assert!(
|
assert!(
|
||||||
self.loadout
|
self.loadout
|
||||||
.swap(EquipSlot::ActiveMainhand, offhand)
|
.swap(EquipSlot::ActiveMainhand, offhand, time)
|
||||||
.is_none()
|
.is_none()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -815,10 +822,10 @@ impl Inventory {
|
|||||||
if self.loadout.equipped(EquipSlot::InactiveMainhand).is_none()
|
if self.loadout.equipped(EquipSlot::InactiveMainhand).is_none()
|
||||||
&& self.loadout.equipped(EquipSlot::InactiveOffhand).is_some()
|
&& self.loadout.equipped(EquipSlot::InactiveOffhand).is_some()
|
||||||
{
|
{
|
||||||
let offhand = self.loadout.swap(EquipSlot::InactiveOffhand, None);
|
let offhand = self.loadout.swap(EquipSlot::InactiveOffhand, None, time);
|
||||||
assert!(
|
assert!(
|
||||||
self.loadout
|
self.loadout
|
||||||
.swap(EquipSlot::InactiveMainhand, offhand)
|
.swap(EquipSlot::InactiveMainhand, offhand, time)
|
||||||
.is_none()
|
.is_none()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -867,7 +874,7 @@ impl Inventory {
|
|||||||
self.loadout.equipped_items_replaceable_by(item_kind)
|
self.loadout.equipped_items_replaceable_by(item_kind)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn swap_equipped_weapons(&mut self) { self.loadout.swap_equipped_weapons() }
|
pub fn swap_equipped_weapons(&mut self, time: Time) { self.loadout.swap_equipped_weapons(time) }
|
||||||
|
|
||||||
/// Update internal computed state of all top level items in this loadout.
|
/// Update internal computed state of all top level items in this loadout.
|
||||||
/// Used only when loading in persistence code.
|
/// Used only when loading in persistence code.
|
||||||
@ -883,13 +890,48 @@ impl Inventory {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Increments durability of all valid items equipped in loaodut by 1
|
/// Increments durability of all valid items equipped in loaodut and
|
||||||
|
/// recently unequipped from loadout by 1
|
||||||
pub fn damage_items(
|
pub fn damage_items(
|
||||||
&mut self,
|
&mut self,
|
||||||
ability_map: &item::tool::AbilityMap,
|
ability_map: &item::tool::AbilityMap,
|
||||||
msm: &item::MaterialStatManifest,
|
msm: &item::MaterialStatManifest,
|
||||||
|
time: Time,
|
||||||
) {
|
) {
|
||||||
self.loadout.damage_items(ability_map, msm)
|
self.loadout.damage_items(ability_map, msm);
|
||||||
|
self.loadout
|
||||||
|
.recently_unequipped_items
|
||||||
|
.retain(|_item, unequip_time| {
|
||||||
|
time.0 - unequip_time.0 <= loadout::UNEQUIP_TRACKING_DURATION
|
||||||
|
});
|
||||||
|
let inv_slots = self
|
||||||
|
.loadout
|
||||||
|
.recently_unequipped_items
|
||||||
|
.keys()
|
||||||
|
.filter_map(|item_def_id| {
|
||||||
|
self.slots_with_id()
|
||||||
|
.find(|&(_, item)| {
|
||||||
|
if let Some(item) = item {
|
||||||
|
// Find an item with the matching item definition id and that is not yet
|
||||||
|
// at maximum durability lost
|
||||||
|
item.item_definition_id() == *item_def_id
|
||||||
|
&& item
|
||||||
|
.durability()
|
||||||
|
.map_or(true, |dur| dur < Item::MAX_DURABILITY)
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.map(|(slot, _)| slot)
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
for inv_slot in inv_slots.iter() {
|
||||||
|
if let Some(Some(item)) = self.slot_mut(*inv_slot) {
|
||||||
|
if item.has_durability() {
|
||||||
|
item.increment_damage(ability_map, msm);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Resets durability of item in specified slot
|
/// Resets durability of item in specified slot
|
||||||
|
@ -508,9 +508,11 @@ pub fn handle_destroy(server: &mut Server, entity: EcsEntity, last_change: Healt
|
|||||||
|
|
||||||
// Modify durability on all equipped items
|
// Modify durability on all equipped items
|
||||||
if let Some(mut inventory) = state.ecs().write_storage::<Inventory>().get_mut(entity) {
|
if let Some(mut inventory) = state.ecs().write_storage::<Inventory>().get_mut(entity) {
|
||||||
let ability_map = state.ecs().read_resource::<AbilityMap>();
|
let ecs = state.ecs();
|
||||||
let msm = state.ecs().read_resource::<MaterialStatManifest>();
|
let ability_map = ecs.read_resource::<AbilityMap>();
|
||||||
inventory.damage_items(&ability_map, &msm);
|
let msm = ecs.read_resource::<MaterialStatManifest>();
|
||||||
|
let time = ecs.read_resource::<Time>();
|
||||||
|
inventory.damage_items(&ability_map, &msm, *time);
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(actor) = state.entity_as_actor(entity) {
|
if let Some(actor) = state.entity_as_actor(entity) {
|
||||||
|
@ -15,6 +15,7 @@ use common::{
|
|||||||
recipe::{
|
recipe::{
|
||||||
self, default_component_recipe_book, default_recipe_book, default_repair_recipe_book,
|
self, default_component_recipe_book, default_recipe_book, default_repair_recipe_book,
|
||||||
},
|
},
|
||||||
|
resources::Time,
|
||||||
terrain::{Block, SpriteKind},
|
terrain::{Block, SpriteKind},
|
||||||
trade::Trades,
|
trade::Trades,
|
||||||
uid::Uid,
|
uid::Uid,
|
||||||
@ -113,6 +114,8 @@ pub fn handle_inventory(server: &mut Server, entity: EcsEntity, manip: comp::Inv
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let time = *state.ecs().read_resource::<Time>();
|
||||||
|
|
||||||
match manip {
|
match manip {
|
||||||
comp::InventoryManip::Pickup(pickup_uid) => {
|
comp::InventoryManip::Pickup(pickup_uid) => {
|
||||||
let item_entity =
|
let item_entity =
|
||||||
@ -405,15 +408,17 @@ pub fn handle_inventory(server: &mut Server, entity: EcsEntity, manip: comp::Inv
|
|||||||
swap_lantern(&mut state.ecs().write_storage(), entity, lantern_info);
|
swap_lantern(&mut state.ecs().write_storage(), entity, lantern_info);
|
||||||
}
|
}
|
||||||
if let Some(pos) = state.ecs().read_storage::<comp::Pos>().get(entity) {
|
if let Some(pos) = state.ecs().read_storage::<comp::Pos>().get(entity) {
|
||||||
dropped_items.extend(inventory.equip(slot).into_iter().map(|x| {
|
dropped_items.extend(inventory.equip(slot, time).into_iter().map(
|
||||||
(
|
|x| {
|
||||||
*pos,
|
(
|
||||||
state
|
*pos,
|
||||||
.read_component_copied::<comp::Ori>(entity)
|
state
|
||||||
.unwrap_or_default(),
|
.read_component_copied::<comp::Ori>(entity)
|
||||||
x,
|
.unwrap_or_default(),
|
||||||
)
|
x,
|
||||||
}));
|
)
|
||||||
|
},
|
||||||
|
));
|
||||||
}
|
}
|
||||||
Some(InventoryUpdateEvent::Used)
|
Some(InventoryUpdateEvent::Used)
|
||||||
} else if let Some(item) = inventory.take(
|
} else if let Some(item) = inventory.take(
|
||||||
@ -525,7 +530,7 @@ pub fn handle_inventory(server: &mut Server, entity: EcsEntity, manip: comp::Inv
|
|||||||
if let Some(pos) = state.ecs().read_storage::<comp::Pos>().get(entity) {
|
if let Some(pos) = state.ecs().read_storage::<comp::Pos>().get(entity) {
|
||||||
// Unequip the item, any items that no longer fit within the inventory (due
|
// Unequip the item, any items that no longer fit within the inventory (due
|
||||||
// to unequipping a bag for example) will be dropped on the floor
|
// to unequipping a bag for example) will be dropped on the floor
|
||||||
if let Ok(Some(leftover_items)) = inventory.unequip(slot) {
|
if let Ok(Some(leftover_items)) = inventory.unequip(slot, time) {
|
||||||
dropped_items.extend(leftover_items.into_iter().map(|x| {
|
dropped_items.extend(leftover_items.into_iter().map(|x| {
|
||||||
(
|
(
|
||||||
*pos,
|
*pos,
|
||||||
@ -598,7 +603,7 @@ pub fn handle_inventory(server: &mut Server, entity: EcsEntity, manip: comp::Inv
|
|||||||
|
|
||||||
// If the stacks weren't mergable carry out a swap.
|
// If the stacks weren't mergable carry out a swap.
|
||||||
if !merged_stacks {
|
if !merged_stacks {
|
||||||
dropped_items.extend(inventory.swap(a, b).into_iter().map(|x| {
|
dropped_items.extend(inventory.swap(a, b, time).into_iter().map(|x| {
|
||||||
(
|
(
|
||||||
*pos,
|
*pos,
|
||||||
state
|
state
|
||||||
@ -665,7 +670,7 @@ pub fn handle_inventory(server: &mut Server, entity: EcsEntity, manip: comp::Inv
|
|||||||
comp::InventoryManip::Drop(slot) => {
|
comp::InventoryManip::Drop(slot) => {
|
||||||
let item = match slot {
|
let item = match slot {
|
||||||
Slot::Inventory(slot) => inventory.remove(slot),
|
Slot::Inventory(slot) => inventory.remove(slot),
|
||||||
Slot::Equip(slot) => inventory.replace_loadout_item(slot, None),
|
Slot::Equip(slot) => inventory.replace_loadout_item(slot, None, time),
|
||||||
};
|
};
|
||||||
|
|
||||||
// FIXME: We should really require the drop and write to be atomic!
|
// FIXME: We should really require the drop and write to be atomic!
|
||||||
@ -910,7 +915,7 @@ pub fn handle_inventory(server: &mut Server, entity: EcsEntity, manip: comp::Inv
|
|||||||
drop(inventories);
|
drop(inventories);
|
||||||
},
|
},
|
||||||
comp::InventoryManip::SwapEquippedWeapons => {
|
comp::InventoryManip::SwapEquippedWeapons => {
|
||||||
inventory.swap_equipped_weapons();
|
inventory.swap_equipped_weapons(time);
|
||||||
drop(inventories);
|
drop(inventories);
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -7,6 +7,7 @@ use common::{
|
|||||||
character::CharacterId,
|
character::CharacterId,
|
||||||
comp,
|
comp,
|
||||||
comp::{group, pet::is_tameable, Presence, PresenceKind},
|
comp::{group, pet::is_tameable, Presence, PresenceKind},
|
||||||
|
resources::Time,
|
||||||
uid::{Uid, UidAllocator},
|
uid::{Uid, UidAllocator},
|
||||||
};
|
};
|
||||||
use common_base::span;
|
use common_base::span;
|
||||||
@ -482,6 +483,7 @@ pub fn handle_possess(server: &mut Server, possessor_uid: Uid, possessee_uid: Ui
|
|||||||
drop(admins);
|
drop(admins);
|
||||||
|
|
||||||
// Put possess item into loadout
|
// Put possess item into loadout
|
||||||
|
let time = ecs.read_resource::<Time>();
|
||||||
let mut inventories = ecs.write_storage::<Inventory>();
|
let mut inventories = ecs.write_storage::<Inventory>();
|
||||||
let mut inventory = inventories
|
let mut inventory = inventories
|
||||||
.entry(possessee)
|
.entry(possessee)
|
||||||
@ -493,12 +495,13 @@ pub fn handle_possess(server: &mut Server, possessor_uid: Uid, possessee_uid: Ui
|
|||||||
let leftover_items = inventory.swap(
|
let leftover_items = inventory.swap(
|
||||||
Slot::Equip(EquipSlot::ActiveMainhand),
|
Slot::Equip(EquipSlot::ActiveMainhand),
|
||||||
Slot::Equip(EquipSlot::InactiveMainhand),
|
Slot::Equip(EquipSlot::InactiveMainhand),
|
||||||
|
*time,
|
||||||
);
|
);
|
||||||
assert!(
|
assert!(
|
||||||
leftover_items.is_empty(),
|
leftover_items.is_empty(),
|
||||||
"Swapping active and inactive mainhands never results in leftover items"
|
"Swapping active and inactive mainhands never results in leftover items"
|
||||||
);
|
);
|
||||||
inventory.replace_loadout_item(EquipSlot::ActiveMainhand, Some(debug_item));
|
inventory.replace_loadout_item(EquipSlot::ActiveMainhand, Some(debug_item), *time);
|
||||||
}
|
}
|
||||||
drop(inventories);
|
drop(inventories);
|
||||||
|
|
||||||
|
@ -25,6 +25,7 @@ use client::{Client, ServerInfo};
|
|||||||
use common::{
|
use common::{
|
||||||
character::{CharacterId, CharacterItem, MAX_CHARACTERS_PER_PLAYER, MAX_NAME_LENGTH},
|
character::{CharacterId, CharacterItem, MAX_CHARACTERS_PER_PLAYER, MAX_NAME_LENGTH},
|
||||||
comp::{self, humanoid, inventory::slot::EquipSlot, Inventory, Item},
|
comp::{self, humanoid, inventory::slot::EquipSlot, Inventory, Item},
|
||||||
|
resources::Time,
|
||||||
terrain::TerrainChunkSize,
|
terrain::TerrainChunkSize,
|
||||||
vol::RectVolSize,
|
vol::RectVolSize,
|
||||||
LoadoutBuilder,
|
LoadoutBuilder,
|
||||||
@ -1812,10 +1813,16 @@ impl Controls {
|
|||||||
inventory.replace_loadout_item(
|
inventory.replace_loadout_item(
|
||||||
EquipSlot::ActiveMainhand,
|
EquipSlot::ActiveMainhand,
|
||||||
mainhand.map(Item::new_from_asset_expect),
|
mainhand.map(Item::new_from_asset_expect),
|
||||||
|
// Voxygen is not authoritative on inventory so we don't care if fake time
|
||||||
|
// is supplied
|
||||||
|
Time(0.0),
|
||||||
);
|
);
|
||||||
inventory.replace_loadout_item(
|
inventory.replace_loadout_item(
|
||||||
EquipSlot::ActiveOffhand,
|
EquipSlot::ActiveOffhand,
|
||||||
offhand.map(Item::new_from_asset_expect),
|
offhand.map(Item::new_from_asset_expect),
|
||||||
|
// Voxygen is not authoritative on inventory so we don't care if fake time
|
||||||
|
// is supplied
|
||||||
|
Time(0.0),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
Loading…
Reference in New Issue
Block a user