diff --git a/common/src/comp/inventory/item/armor.rs b/common/src/comp/inventory/item/armor.rs index 1c876e63ce..1c8efe8458 100644 --- a/common/src/comp/inventory/item/armor.rs +++ b/common/src/comp/inventory/item/armor.rs @@ -25,6 +25,26 @@ pub enum ArmorKind { Bag, } +impl ArmorKind { + pub fn has_durability(self) -> bool { + use ArmorKind::*; + match self { + Shoulder => true, + Chest => true, + Belt => true, + Hand => true, + Pants => true, + Foot => true, + Back => true, + Ring => false, + Neck => false, + Head => false, + Tabard => false, + Bag => false, + } + } +} + impl Armor { /// Determines whether two pieces of armour are superficially equivalent to /// one another (i.e: one may be substituted for the other in crafting diff --git a/common/src/comp/inventory/item/mod.rs b/common/src/comp/inventory/item/mod.rs index c401a08d66..9ab56961c9 100644 --- a/common/src/comp/inventory/item/mod.rs +++ b/common/src/comp/inventory/item/mod.rs @@ -5,11 +5,11 @@ pub mod tool; // Reexports pub use modular::{MaterialStatManifest, ModularBase, ModularComponent}; -pub use tool::{AbilitySet, AbilitySpec, Hands, Tool, ToolKind}; +pub use tool::{AbilityMap, AbilitySet, AbilitySpec, Hands, Tool, ToolKind}; use crate::{ assets::{self, AssetExt, BoxedError, Error}, - comp::inventory::{item::tool::AbilityMap, InvSlot}, + comp::inventory::InvSlot, effect::Effect, recipe::RecipeInput, terrain::Block, @@ -793,6 +793,7 @@ impl Item { hash: 0, durability: None, }; + item.durability = item.has_durability().then_some(0); item.update_item_state(ability_map, msm); item } @@ -1199,14 +1200,29 @@ impl Item { const MAX_DURABILITY: u32 = 8; let durability = self.durability.map_or(0, |x| x.clamp(0, MAX_DURABILITY)); const DURABILITY_THRESHOLD: u32 = 4; - const MIN_FRAC: f32 = 0.25; - let mult = durability.saturating_sub(DURABILITY_THRESHOLD) as f32 - / (MAX_DURABILITY - DURABILITY_THRESHOLD) as f32 + const MIN_FRAC: f32 = 0.2; + let mult = (1.0 + - durability.saturating_sub(DURABILITY_THRESHOLD) as f32 + / (MAX_DURABILITY - DURABILITY_THRESHOLD) as f32) * (1.0 - MIN_FRAC) + MIN_FRAC; DurabilityMultiplier(mult) } + pub fn has_durability(&self) -> bool { + match &*self.kind() { + ItemKind::Tool(_) => true, + ItemKind::Armor(armor) => armor.kind.has_durability(), + _ => false, + } + } + + pub fn apply_durability(&mut self) { + if let Some(durability) = &mut self.durability { + *durability += 1; + } + } + #[cfg(test)] pub fn create_test_item_from_kind(kind: ItemKind) -> Self { let ability_map = &AbilityMap::load().read(); diff --git a/common/src/comp/inventory/loadout.rs b/common/src/comp/inventory/loadout.rs index dd2eee1bc8..f52826668a 100644 --- a/common/src/comp/inventory/loadout.rs +++ b/common/src/comp/inventory/loadout.rs @@ -416,6 +416,25 @@ impl Loadout { } }); } + + /// Increments durability by 1 of all valid items + pub(super) fn apply_durability( + &mut self, + ability_map: &item::tool::AbilityMap, + msm: &item::MaterialStatManifest, + ) { + self.slots + .iter_mut() + .filter(|slot| slot.slot.as_ref().map_or(false, |i| i.has_durability())) + .for_each(|slot| { + if let Some(item) = &mut slot.slot { + item.apply_durability(); + // Update item state after applying durability because stats have potential to + // change from different durability + item.update_item_state(ability_map, msm); + } + }) + } } #[cfg(test)] diff --git a/common/src/comp/inventory/mod.rs b/common/src/comp/inventory/mod.rs index 4eff57e20c..26241b6323 100644 --- a/common/src/comp/inventory/mod.rs +++ b/common/src/comp/inventory/mod.rs @@ -878,6 +878,15 @@ impl Inventory { } }); } + + /// Increments durability of all valid items equipped in loaodut by 1 + pub fn apply_durability( + &mut self, + ability_map: &item::tool::AbilityMap, + msm: &item::MaterialStatManifest, + ) { + self.loadout.apply_durability(ability_map, msm) + } } impl Component for Inventory { diff --git a/server/src/events/entity_manipulation.rs b/server/src/events/entity_manipulation.rs index 7efa635355..55976ca2f5 100644 --- a/server/src/events/entity_manipulation.rs +++ b/server/src/events/entity_manipulation.rs @@ -18,7 +18,7 @@ use common::{ comp::{ self, aura, buff, chat::{KillSource, KillType}, - inventory::item::MaterialStatManifest, + inventory::item::{AbilityMap, MaterialStatManifest}, loot_owner::LootOwnerKind, Alignment, Auras, Body, CharacterState, Energy, Group, Health, HealthChange, Inventory, Player, Poise, Pos, SkillSet, Stats, @@ -511,6 +511,13 @@ pub fn handle_destroy(server: &mut Server, entity: EcsEntity, last_change: Healt true }; + // Modify durability on all equipped items + if let Some(mut inventory) = state.ecs().write_storage::().get_mut(entity) { + let ability_map = state.ecs().read_resource::(); + let msm = state.ecs().read_resource::(); + inventory.apply_durability(&ability_map, &msm); + } + if should_delete { if let Some(rtsim_entity) = state .ecs()