Addressed review

This commit is contained in:
Sam 2023-03-19 21:28:09 -04:00
parent 79812a7326
commit 132f26dbc0
8 changed files with 82 additions and 79 deletions

View File

@ -27,20 +27,19 @@ pub enum ArmorKind {
impl ArmorKind { impl ArmorKind {
pub fn has_durability(self) -> bool { pub fn has_durability(self) -> bool {
use ArmorKind::*;
match self { match self {
Shoulder => true, ArmorKind::Shoulder => true,
Chest => true, ArmorKind::Chest => true,
Belt => true, ArmorKind::Belt => true,
Hand => true, ArmorKind::Hand => true,
Pants => true, ArmorKind::Pants => true,
Foot => true, ArmorKind::Foot => true,
Back => true, ArmorKind::Back => true,
Ring => false, ArmorKind::Ring => false,
Neck => false, ArmorKind::Neck => false,
Head => true, ArmorKind::Head => true,
Tabard => false, ArmorKind::Tabard => false,
Bag => false, ArmorKind::Bag => false,
} }
} }
} }
@ -262,8 +261,7 @@ impl Armor {
set_stats * multiplier set_stats * multiplier
}, },
}; };
let DurabilityMultiplier(mult) = durability_multiplier; base_stats * durability_multiplier.0
base_stats * mult
} }
#[cfg(test)] #[cfg(test)]

View File

@ -399,7 +399,7 @@ pub struct Item {
/// Tracks how many deaths occurred while item was equipped, which is /// Tracks how many deaths occurred while item was equipped, which is
/// converted into the items durability. Only tracked for tools and armor /// converted into the items durability. Only tracked for tools and armor
/// currently. /// currently.
durability: Option<u32>, durability_lost: Option<u32>,
} }
use std::hash::{Hash, Hasher}; use std::hash::{Hash, Hasher};
@ -793,9 +793,9 @@ impl Item {
// These fields are updated immediately below // These fields are updated immediately below
item_config: None, item_config: None,
hash: 0, hash: 0,
durability: None, durability_lost: None,
}; };
item.durability = item.has_durability().then_some(0); item.durability_lost = item.has_durability().then_some(0);
item.update_item_state(ability_map, msm); item.update_item_state(ability_map, msm);
item item
} }
@ -1198,16 +1198,17 @@ impl Item {
} }
} }
pub fn durability(&self) -> Option<u32> { self.durability.map(|x| x.min(Self::MAX_DURABILITY)) } pub fn durability(&self) -> Option<u32> {
self.durability_lost.map(|x| x.min(Self::MAX_DURABILITY))
}
pub fn stats_durability_multiplier(&self) -> DurabilityMultiplier { pub fn stats_durability_multiplier(&self) -> DurabilityMultiplier {
let durability = self let durability_lost = self.durability_lost.unwrap_or(0);
.durability debug_assert!(durability_lost <= Self::MAX_DURABILITY);
.map_or(0, |x| x.clamp(0, Self::MAX_DURABILITY));
const DURABILITY_THRESHOLD: u32 = 4; const DURABILITY_THRESHOLD: u32 = 4;
const MIN_FRAC: f32 = 0.2; const MIN_FRAC: f32 = 0.2;
let mult = (1.0 let mult = (1.0
- durability.saturating_sub(DURABILITY_THRESHOLD) as f32 - durability_lost.saturating_sub(DURABILITY_THRESHOLD) as f32
/ (Self::MAX_DURABILITY - DURABILITY_THRESHOLD) as f32) / (Self::MAX_DURABILITY - DURABILITY_THRESHOLD) as f32)
* (1.0 - MIN_FRAC) * (1.0 - MIN_FRAC)
+ MIN_FRAC; + MIN_FRAC;
@ -1218,13 +1219,22 @@ impl Item {
match &*self.kind() { match &*self.kind() {
ItemKind::Tool(_) => true, ItemKind::Tool(_) => true,
ItemKind::Armor(armor) => armor.kind.has_durability(), ItemKind::Armor(armor) => armor.kind.has_durability(),
_ => false, ItemKind::ModularComponent(_)
| ItemKind::Lantern(_)
| ItemKind::Glider
| ItemKind::Consumable { .. }
| ItemKind::Throwable { .. }
| ItemKind::Utility { .. }
| ItemKind::Ingredient { .. }
| ItemKind::TagExamples { .. } => false,
} }
} }
pub fn apply_durability(&mut self, ability_map: &AbilityMap, msm: &MaterialStatManifest) { pub fn increment_damage(&mut self, ability_map: &AbilityMap, msm: &MaterialStatManifest) {
if let Some(durability) = &mut self.durability { if let Some(durability_lost) = &mut self.durability_lost {
*durability += 1; if *durability_lost < Self::MAX_DURABILITY {
*durability_lost += 1;
}
} }
// Update item state after applying durability because stats have potential to // Update item state after applying durability because stats have potential to
// change from different durability // change from different durability
@ -1232,23 +1242,23 @@ impl Item {
} }
pub fn persistence_durability(&self) -> Option<NonZeroU32> { pub fn persistence_durability(&self) -> Option<NonZeroU32> {
self.durability.and_then(NonZeroU32::new) self.durability_lost.and_then(NonZeroU32::new)
} }
pub fn persistence_set_durability(&mut self, value: Option<NonZeroU32>) { pub fn persistence_set_durability(&mut self, value: Option<NonZeroU32>) {
// If changes have been made so that item no longer needs to track durability, // If changes have been made so that item no longer needs to track durability,
// set to None // set to None
if !self.has_durability() { if !self.has_durability() {
self.durability = None; self.durability_lost = None;
} else { } else {
// Set durability to persisted value, and if item previously had no durability, // Set durability to persisted value, and if item previously had no durability,
// set to Some(0) so that durability will be tracked // set to Some(0) so that durability will be tracked
self.durability = Some(value.map_or(0, NonZeroU32::get)); self.durability_lost = Some(value.map_or(0, NonZeroU32::get));
} }
} }
pub fn reset_durability(&mut self, ability_map: &AbilityMap, msm: &MaterialStatManifest) { pub fn reset_durability(&mut self, ability_map: &AbilityMap, msm: &MaterialStatManifest) {
self.durability = self.durability.map(|_| 0); self.durability_lost = self.has_durability().then_some(0);
// Update item state after applying durability because stats have potential to // Update item state after applying durability because stats have potential to
// change from different durability // change from different durability
self.update_item_state(ability_map, msm); self.update_item_state(ability_map, msm);

View File

@ -146,6 +146,20 @@ impl Stats {
let diminished = (self.buff_strength - base + 1.0).log(5.0); let diminished = (self.buff_strength - base + 1.0).log(5.0);
base + diminished base + diminished
} }
pub fn with_durability_mult(&self, dur_mult: DurabilityMultiplier) -> Self {
let less_scaled = dur_mult.0 * 0.5 + 0.5;
Self {
equip_time_secs: self.equip_time_secs / less_scaled.max(0.01),
power: self.power * dur_mult.0,
effect_power: self.effect_power * dur_mult.0,
speed: self.speed * less_scaled,
crit_chance: self.crit_chance * dur_mult.0,
range: self.range * dur_mult.0,
energy_efficiency: self.energy_efficiency * dur_mult.0,
buff_strength: self.buff_strength * dur_mult.0,
}
}
} }
impl Asset for Stats { impl Asset for Stats {
@ -213,25 +227,6 @@ impl MulAssign<Stats> for Stats {
fn mul_assign(&mut self, other: Stats) { *self = *self * other; } fn mul_assign(&mut self, other: Stats) { *self = *self * other; }
} }
impl Mul<DurabilityMultiplier> for Stats {
type Output = Self;
fn mul(self, value: DurabilityMultiplier) -> Self {
let DurabilityMultiplier(value) = value;
let less_scaled = value * 0.5 + 0.5;
Self {
equip_time_secs: self.equip_time_secs / less_scaled.max(0.01),
power: self.power * value,
effect_power: self.effect_power * value,
speed: self.speed * less_scaled,
crit_chance: self.crit_chance * value,
range: self.range * value,
energy_efficiency: self.energy_efficiency * value,
buff_strength: self.buff_strength * value,
}
}
}
impl Div<f32> for Stats { impl Div<f32> for Stats {
type Output = Self; type Output = Self;
@ -249,6 +244,12 @@ impl Div<f32> for Stats {
} }
} }
impl Mul<DurabilityMultiplier> for Stats {
type Output = Self;
fn mul(self, value: DurabilityMultiplier) -> Self { self.with_durability_mult(value) }
}
#[derive(Clone, Debug, Serialize, Deserialize)] #[derive(Clone, Debug, Serialize, Deserialize)]
pub struct Tool { pub struct Tool {
pub kind: ToolKind, pub kind: ToolKind,

View File

@ -424,19 +424,16 @@ impl Loadout {
} }
/// Increments durability by 1 of all valid items /// Increments durability by 1 of all valid items
pub(super) fn apply_durability( pub(super) fn damage_items(
&mut self, &mut self,
ability_map: &item::tool::AbilityMap, ability_map: &item::tool::AbilityMap,
msm: &item::MaterialStatManifest, msm: &item::MaterialStatManifest,
) { ) {
self.slots self.slots
.iter_mut() .iter_mut()
.filter(|slot| slot.slot.as_ref().map_or(false, |i| i.has_durability())) .filter_map(|slot| slot.slot.as_mut())
.for_each(|slot| { .filter(|item| item.has_durability())
if let Some(item) = &mut slot.slot { .for_each(|item| item.increment_damage(ability_map, msm));
item.apply_durability(ability_map, msm);
}
})
} }
/// Resets durability of item in specified slot /// Resets durability of item in specified slot

View File

@ -884,12 +884,12 @@ impl Inventory {
} }
/// Increments durability of all valid items equipped in loaodut by 1 /// Increments durability of all valid items equipped in loaodut by 1
pub fn apply_durability( pub fn damage_items(
&mut self, &mut self,
ability_map: &item::tool::AbilityMap, ability_map: &item::tool::AbilityMap,
msm: &item::MaterialStatManifest, msm: &item::MaterialStatManifest,
) { ) {
self.loadout.apply_durability(ability_map, msm) self.loadout.damage_items(ability_map, msm)
} }
/// Resets durability of item in specified slot /// Resets durability of item in specified slot
@ -901,7 +901,7 @@ impl Inventory {
) { ) {
match slot { match slot {
Slot::Inventory(invslot) => { Slot::Inventory(invslot) => {
if let Some(Some(item)) = self.slot_mut(invslot).map(Option::as_mut) { if let Some(Some(item)) = self.slot_mut(invslot) {
item.reset_durability(ability_map, msm); item.reset_durability(ability_map, msm);
} }
}, },

View File

@ -14,7 +14,7 @@ use crate::{
}; };
use hashbrown::HashMap; use hashbrown::HashMap;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::{borrow::Cow, ops::Mul, sync::Arc}; use std::{borrow::Cow, sync::Arc};
#[derive(Clone, Debug, Serialize, Deserialize)] #[derive(Clone, Debug, Serialize, Deserialize)]
pub enum RecipeInput { pub enum RecipeInput {
@ -517,13 +517,11 @@ impl assets::Compound for RecipeBook {
cache: assets::AnyCache, cache: assets::AnyCache,
specifier: &assets::SharedString, specifier: &assets::SharedString,
) -> Result<Self, assets::BoxedError> { ) -> Result<Self, assets::BoxedError> {
#[inline]
fn load_item_def(spec: &(String, u32)) -> Result<(Arc<ItemDef>, u32), assets::Error> { fn load_item_def(spec: &(String, u32)) -> Result<(Arc<ItemDef>, u32), assets::Error> {
let def = Arc::<ItemDef>::load_cloned(&spec.0)?; let def = Arc::<ItemDef>::load_cloned(&spec.0)?;
Ok((def, spec.1)) Ok((def, spec.1))
} }
#[inline]
fn load_recipe_input( fn load_recipe_input(
(input, amount, is_mod_comp): &(RawRecipeInput, u32, bool), (input, amount, is_mod_comp): &(RawRecipeInput, u32, bool),
) -> Result<(RecipeInput, u32, bool), assets::Error> { ) -> Result<(RecipeInput, u32, bool), assets::Error> {
@ -835,7 +833,6 @@ impl assets::Compound for ComponentRecipeBook {
cache: assets::AnyCache, cache: assets::AnyCache,
specifier: &assets::SharedString, specifier: &assets::SharedString,
) -> Result<Self, assets::BoxedError> { ) -> Result<Self, assets::BoxedError> {
#[inline]
fn create_recipe_key(raw_recipe: &RawComponentRecipe) -> ComponentKey { fn create_recipe_key(raw_recipe: &RawComponentRecipe) -> ComponentKey {
match &raw_recipe.output { match &raw_recipe.output {
RawComponentOutput::ToolPrimaryComponent { toolkind, item: _ } => { RawComponentOutput::ToolPrimaryComponent { toolkind, item: _ } => {
@ -853,7 +850,6 @@ impl assets::Compound for ComponentRecipeBook {
} }
} }
#[inline]
fn load_recipe(raw_recipe: &RawComponentRecipe) -> Result<ComponentRecipe, assets::Error> { fn load_recipe(raw_recipe: &RawComponentRecipe) -> Result<ComponentRecipe, assets::Error> {
let output = match &raw_recipe.output { let output = match &raw_recipe.output {
RawComponentOutput::ToolPrimaryComponent { toolkind: _, item } => { RawComponentOutput::ToolPrimaryComponent { toolkind: _, item } => {
@ -979,18 +975,20 @@ impl RepairRecipe {
inventory_contains_ingredients(self.inputs(item), inv, 1) inventory_contains_ingredients(self.inputs(item), inv, 1)
} }
pub fn inputs(&self, item: &Item) -> impl ExactSizeIterator<Item = (&RecipeInput, u32)> { pub fn inputs(&self, item: &Item) -> impl Iterator<Item = (&RecipeInput, u32)> {
let item_durability = item.durability().unwrap_or(0); let item_durability = item.durability().unwrap_or(0);
// TODO: Figure out how to avoid vec collection to maintain exact size iterator self.inputs
self.inputs.iter().filter_map(move |(input, original_amount)| { .iter()
let amount = original_amount.mul(item_durability).div_floor(Item::MAX_DURABILITY); .filter_map(move |(input, original_amount)| {
// If original repair recipe consumed ingredients, but item not damaged enough to actually need to consume item, remove item as requirement. let amount = (original_amount * item_durability) / Item::MAX_DURABILITY;
if *original_amount > 0 && amount == 0 { // If original repair recipe consumed ingredients, but item not damaged enough
None // to actually need to consume item, remove item as requirement.
} else { if *original_amount > 0 && amount == 0 {
Some((input, amount)) None
} } else {
}).collect::<Vec<_>>().into_iter() Some((input, amount))
}
})
} }
} }
@ -1068,7 +1066,6 @@ impl assets::Compound for RepairRecipeBook {
cache: assets::AnyCache, cache: assets::AnyCache,
specifier: &assets::SharedString, specifier: &assets::SharedString,
) -> Result<Self, assets::BoxedError> { ) -> Result<Self, assets::BoxedError> {
#[inline]
fn load_recipe_input( fn load_recipe_input(
(input, amount): &(RawRecipeInput, u32), (input, amount): &(RawRecipeInput, u32),
) -> Result<(RecipeInput, u32), assets::Error> { ) -> Result<(RecipeInput, u32), assets::Error> {

View File

@ -515,7 +515,7 @@ pub fn handle_destroy(server: &mut Server, entity: EcsEntity, last_change: Healt
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 ability_map = state.ecs().read_resource::<AbilityMap>();
let msm = state.ecs().read_resource::<MaterialStatManifest>(); let msm = state.ecs().read_resource::<MaterialStatManifest>();
inventory.apply_durability(&ability_map, &msm); inventory.damage_items(&ability_map, &msm);
} }
if should_delete { if should_delete {

View File

@ -1747,7 +1747,7 @@ impl<'a> Widget for Crafting<'a> {
None => None, None => None,
} { } {
if let Some(recipe) = self.client.repair_recipe_book().repair_recipe(item) { if let Some(recipe) = self.client.repair_recipe_book().repair_recipe(item) {
iter_d = recipe.inputs(item); iter_d = recipe.inputs(item).collect::<Vec<_>>().into_iter();
&mut iter_d as &mut dyn ExactSizeIterator<Item = _> &mut iter_d as &mut dyn ExactSizeIterator<Item = _>
} else { } else {
iter_b = core::iter::empty(); iter_b = core::iter::empty();