Finish plumbing MaterialStatsManifest. Fix issue with speed clamping when recursing through components. Improve statblocks in item tooltips.

This commit is contained in:
Avi Weinstock 2021-02-25 14:04:09 -05:00
parent 78014d7d3b
commit e1484c28c0
10 changed files with 156 additions and 84 deletions

View File

@ -5,5 +5,5 @@ ItemDef(
kind: "TinIngot",
),
quality: Common,
tags: [MetalIngot(0.25)],
tags: [MetalIngot],
)

View File

@ -363,11 +363,11 @@
(Item("common.items.crafting_tools.sewing_set"), 0),
],
),
"metal_blade": (
("common.items.crafting_ing.modular.damage.sword.metal_blade", 1),
[
(Tag(MetalIngot), 5),
(Item("common.items.crafting_tools.craftsman_hammer"), 0),
],
),
//"metal_blade": (
// ("common.items.crafting_ing.modular.damage.sword.metal_blade", 1),
// [
// (Tag(MetalIngot), 5),
// (Item("common.items.crafting_tools.craftsman_hammer"), 0),
// ],
//),
}

View File

@ -72,6 +72,13 @@ impl Stats {
speed: 0.0,
}
}
pub fn clamp_speed(mut self) -> Stats {
// if a tool has 0.0 speed, that panics due to being infinite duration, so
// enforce speed >= 0.1 on the final product (but not the intermediates)
self.speed = self.speed.max(0.1);
self
}
}
impl Asset for Stats {
@ -112,7 +119,7 @@ impl DivAssign<usize> for Stats {
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct MaterialStatManifest(HashMap<String, Stats>);
pub struct MaterialStatManifest(pub HashMap<String, Stats>);
// This could be a Compound that also loads the keys, but the RecipeBook
// Compound impl already does that, so checking for existence here is redundant.
@ -166,16 +173,13 @@ impl StatKind {
average_mult /= multipliers.len();
stats *= average_mult;
}
// if an item has 0.0 speed, that panics due to being infinite duration, so
// enforce speed >= 0.1
stats.speed = stats.speed.max(0.1);
stats
}
}
impl From<(&MaterialStatManifest, &[Item], &Tool)> for Stats {
fn from((msm, components, tool): (&MaterialStatManifest, &[Item], &Tool)) -> Self {
let raw_stats = tool.stats.resolve_stats(msm, components);
let raw_stats = tool.stats.resolve_stats(msm, components).clamp_speed();
let (power, speed) = match tool.hands {
Hands::One => (0.67, 1.33),
// TODO: Restore this when one-handed weapons are made accessible
@ -245,7 +249,10 @@ impl Tool {
}
pub fn base_speed(&self, msm: &MaterialStatManifest, components: &[Item]) -> f32 {
self.stats.resolve_stats(msm, components).speed
self.stats
.resolve_stats(msm, components)
.clamp_speed()
.speed
}
pub fn equip_time(&self, msm: &MaterialStatManifest, components: &[Item]) -> Duration {

View File

@ -509,6 +509,7 @@ impl<'a> Widget for Bag<'a> {
let (title, desc) = loadout_slot_text(
inventory.equipped(EquipSlot::Armor(ArmorSlot::Head)),
|| (i18n.get("hud.bag.head"), ""),
&self.msm,
);
let head_q_col = inventory
.equipped(EquipSlot::Armor(ArmorSlot::Head))
@ -531,6 +532,7 @@ impl<'a> Widget for Bag<'a> {
let (title, desc) = loadout_slot_text(
inventory.equipped(EquipSlot::Armor(ArmorSlot::Neck)),
|| (i18n.get("hud.bag.neck"), ""),
&self.msm,
);
let neck_q_col = inventory
.equipped(EquipSlot::Armor(ArmorSlot::Neck))
@ -554,6 +556,7 @@ impl<'a> Widget for Bag<'a> {
let (title, desc) = loadout_slot_text(
inventory.equipped(EquipSlot::Armor(ArmorSlot::Chest)),
|| (i18n.get("hud.bag.chest"), ""),
&self.msm,
);
let chest_q_col = inventory
.equipped(EquipSlot::Armor(ArmorSlot::Chest))
@ -576,6 +579,7 @@ impl<'a> Widget for Bag<'a> {
let (title, desc) = loadout_slot_text(
inventory.equipped(EquipSlot::Armor(ArmorSlot::Shoulders)),
|| (i18n.get("hud.bag.shoulders"), ""),
&self.msm,
);
let shoulder_q_col = inventory
.equipped(EquipSlot::Armor(ArmorSlot::Shoulders))
@ -598,6 +602,7 @@ impl<'a> Widget for Bag<'a> {
let (title, desc) = loadout_slot_text(
inventory.equipped(EquipSlot::Armor(ArmorSlot::Hands)),
|| (i18n.get("hud.bag.hands"), ""),
&self.msm,
);
let chest_q_col = inventory
.equipped(EquipSlot::Armor(ArmorSlot::Hands))
@ -620,6 +625,7 @@ impl<'a> Widget for Bag<'a> {
let (title, desc) = loadout_slot_text(
inventory.equipped(EquipSlot::Armor(ArmorSlot::Belt)),
|| (i18n.get("hud.bag.belt"), ""),
&self.msm,
);
let belt_q_col = inventory
.equipped(EquipSlot::Armor(ArmorSlot::Belt))
@ -642,6 +648,7 @@ impl<'a> Widget for Bag<'a> {
let (title, desc) = loadout_slot_text(
inventory.equipped(EquipSlot::Armor(ArmorSlot::Legs)),
|| (i18n.get("hud.bag.legs"), ""),
&self.msm,
);
let legs_q_col = inventory
.equipped(EquipSlot::Armor(ArmorSlot::Legs))
@ -664,6 +671,7 @@ impl<'a> Widget for Bag<'a> {
let (title, desc) = loadout_slot_text(
inventory.equipped(EquipSlot::Armor(ArmorSlot::Ring1)),
|| (i18n.get("hud.bag.ring"), ""),
&self.msm,
);
let ring_q_col = inventory
.equipped(EquipSlot::Armor(ArmorSlot::Ring1))
@ -686,6 +694,7 @@ impl<'a> Widget for Bag<'a> {
let (title, desc) = loadout_slot_text(
inventory.equipped(EquipSlot::Armor(ArmorSlot::Ring2)),
|| (i18n.get("hud.bag.ring"), ""),
&self.msm,
);
let ring2_q_col = inventory
.equipped(EquipSlot::Armor(ArmorSlot::Ring2))
@ -708,6 +717,7 @@ impl<'a> Widget for Bag<'a> {
let (title, desc) = loadout_slot_text(
inventory.equipped(EquipSlot::Armor(ArmorSlot::Back)),
|| (i18n.get("hud.bag.back"), ""),
&self.msm,
);
let back_q_col = inventory
.equipped(EquipSlot::Armor(ArmorSlot::Back))
@ -730,6 +740,7 @@ impl<'a> Widget for Bag<'a> {
let (title, desc) = loadout_slot_text(
inventory.equipped(EquipSlot::Armor(ArmorSlot::Feet)),
|| (i18n.get("hud.bag.feet"), ""),
&self.msm,
);
let foot_q_col = inventory
.equipped(EquipSlot::Armor(ArmorSlot::Feet))
@ -749,9 +760,11 @@ impl<'a> Widget for Bag<'a> {
)
.set(state.ids.feet_slot, ui);
// Lantern
let (title, desc) = loadout_slot_text(inventory.equipped(EquipSlot::Lantern), || {
(i18n.get("hud.bag.lantern"), "")
});
let (title, desc) = loadout_slot_text(
inventory.equipped(EquipSlot::Lantern),
|| (i18n.get("hud.bag.lantern"), ""),
&self.msm,
);
let lantern_q_col = inventory
.equipped(EquipSlot::Lantern)
.map(|item| get_quality_col(item))
@ -770,9 +783,11 @@ impl<'a> Widget for Bag<'a> {
)
.set(state.ids.lantern_slot, ui);
// Glider
let (title, desc) = loadout_slot_text(inventory.equipped(EquipSlot::Glider), || {
(i18n.get("hud.bag.glider"), "")
});
let (title, desc) = loadout_slot_text(
inventory.equipped(EquipSlot::Glider),
|| (i18n.get("hud.bag.glider"), ""),
&self.msm,
);
let glider_q_col = inventory
.equipped(EquipSlot::Glider)
.map(|item| get_quality_col(item))
@ -794,6 +809,7 @@ impl<'a> Widget for Bag<'a> {
let (title, desc) = loadout_slot_text(
inventory.equipped(EquipSlot::Armor(ArmorSlot::Tabard)),
|| (i18n.get("hud.bag.tabard"), ""),
&self.msm,
);
let tabard_q_col = inventory
.equipped(EquipSlot::Armor(ArmorSlot::Tabard))
@ -813,9 +829,11 @@ impl<'a> Widget for Bag<'a> {
)
.set(state.ids.tabard_slot, ui);
// Mainhand/Left-Slot
let (title, desc) = loadout_slot_text(inventory.equipped(EquipSlot::Mainhand), || {
(i18n.get("hud.bag.mainhand"), "")
});
let (title, desc) = loadout_slot_text(
inventory.equipped(EquipSlot::Mainhand),
|| (i18n.get("hud.bag.mainhand"), ""),
&self.msm,
);
let mainhand_q_col = inventory
.equipped(EquipSlot::Mainhand)
.map(|item| get_quality_col(item))
@ -834,9 +852,11 @@ impl<'a> Widget for Bag<'a> {
)
.set(state.ids.mainhand_slot, ui);
// Offhand/Right-Slot
let (title, desc) = loadout_slot_text(inventory.equipped(EquipSlot::Offhand), || {
(i18n.get("hud.bag.offhand"), "")
});
let (title, desc) = loadout_slot_text(
inventory.equipped(EquipSlot::Offhand),
|| (i18n.get("hud.bag.offhand"), ""),
&self.msm,
);
let offhand_q_col = inventory
.equipped(EquipSlot::Offhand)
.map(|item| get_quality_col(item))
@ -859,6 +879,7 @@ impl<'a> Widget for Bag<'a> {
let (title, desc) = loadout_slot_text(
inventory.equipped(EquipSlot::Armor(ArmorSlot::Bag1)),
|| (i18n.get("hud.bag.bag"), ""),
&self.msm,
);
let bag1_q_col = inventory
.equipped(EquipSlot::Armor(ArmorSlot::Bag1))
@ -885,6 +906,7 @@ impl<'a> Widget for Bag<'a> {
let (title, desc) = loadout_slot_text(
inventory.equipped(EquipSlot::Armor(ArmorSlot::Bag2)),
|| (i18n.get("hud.bag.bag"), ""),
&self.msm,
);
let bag2_q_col = inventory
.equipped(EquipSlot::Armor(ArmorSlot::Bag2))
@ -907,6 +929,7 @@ impl<'a> Widget for Bag<'a> {
let (title, desc) = loadout_slot_text(
inventory.equipped(EquipSlot::Armor(ArmorSlot::Bag3)),
|| (i18n.get("hud.bag.bag"), ""),
&self.msm,
);
let bag3_q_col = inventory
.equipped(EquipSlot::Armor(ArmorSlot::Bag3))
@ -929,6 +952,7 @@ impl<'a> Widget for Bag<'a> {
let (title, desc) = loadout_slot_text(
inventory.equipped(EquipSlot::Armor(ArmorSlot::Bag4)),
|| (i18n.get("hud.bag.bag"), ""),
&self.msm,
);
let bag4_q_col = inventory
.equipped(EquipSlot::Armor(ArmorSlot::Bag4))
@ -1011,7 +1035,7 @@ impl<'a> Widget for Bag<'a> {
}
if let Some(item) = item {
let (title, desc) = super::util::item_text(item);
let (title, desc) = super::util::item_text(item, &self.msm);
let quality_col = get_quality_col(item);
let quality_col_img = match item.quality() {
Quality::Low => self.imgs.inv_slot_grey,

View File

@ -12,7 +12,7 @@ use client::{self, Client};
use common::{
assets::AssetExt,
comp::{
item::{ItemDef, ItemDesc, Quality, TagExampleInfo},
item::{ItemDef, ItemDesc, MaterialStatManifest, Quality, TagExampleInfo},
Inventory,
},
recipe::RecipeInput,
@ -68,6 +68,7 @@ pub struct Crafting<'a> {
tooltip_manager: &'a mut TooltipManager,
item_imgs: &'a ItemImgs,
inventory: &'a Inventory,
msm: &'a MaterialStatManifest,
#[conrod(common_builder)]
common: widget::CommonBuilder,
}
@ -83,6 +84,7 @@ impl<'a> Crafting<'a> {
tooltip_manager: &'a mut TooltipManager,
item_imgs: &'a ItemImgs,
inventory: &'a Inventory,
msm: &'a MaterialStatManifest,
) -> Self {
Self {
client,
@ -94,6 +96,7 @@ impl<'a> Crafting<'a> {
tooltip_manager,
item_imgs,
inventory,
msm,
common: widget::CommonBuilder::default(),
}
}
@ -297,7 +300,7 @@ impl<'a> Widget for Crafting<'a> {
{
let output_text = format!("x{}", &recipe.output.1.to_string());
// Output Image
let (title, desc) = super::util::item_text(&*recipe.output.0);
let (title, desc) = super::util::item_text(&*recipe.output.0, self.msm);
let quality_col = get_quality_col(&*recipe.output.0);
Button::image(animate_by_pulse(
&self
@ -488,7 +491,7 @@ impl<'a> Widget for Crafting<'a> {
};
frame.set(state.ids.ingredient_frame[i], ui);
//Item Image
let (title, desc) = super::util::item_text(&*item_def);
let (title, desc) = super::util::item_text(&*item_def, self.msm);
Button::image(animate_by_pulse(
&self.item_imgs.img_ids_or_not_found_img((&*item_def).into()),
self.pulse,

View File

@ -2143,6 +2143,7 @@ impl Hud {
tooltip_manager,
&mut self.slot_manager,
i18n,
&msm,
self.pulse,
)
.set(self.ids.trade, ui_widgets)
@ -2207,6 +2208,7 @@ impl Hud {
tooltip_manager,
&self.item_imgs,
&inventory,
&msm,
)
.set(self.ids.crafting_window, ui_widgets)
{

View File

@ -400,7 +400,13 @@ impl<'a> Widget for Skillbar<'a> {
.set(state.ids.stamina_txt, ui);
}
// Slots
let content_source = (self.hotbar, self.inventory, self.energy, self.ability_map); // TODO: avoid this
let content_source = (
self.hotbar,
self.inventory,
self.energy,
self.ability_map,
self.msm,
); // TODO: avoid this
let image_source = (self.item_imgs, self.imgs);
let mut slot_maker = SlotMaker {
// TODO: is a separate image needed for the frame?

View File

@ -2,13 +2,12 @@ use super::{
hotbar::{self, Slot as HotbarSlot},
img_ids,
item_imgs::{ItemImgs, ItemKey},
util::MATERIAL_STATS_MANIFEST,
};
use crate::ui::slot::{self, SlotKey, SumSlot};
use common::comp::{
item::{
tool::{AbilityMap, Hands, ToolKind},
ItemKind,
ItemKind, MaterialStatManifest,
},
slot::InvSlotId,
Energy, Inventory,
@ -102,7 +101,13 @@ pub enum HotbarImage {
BowJumpBurst,
}
type HotbarSource<'a> = (&'a hotbar::State, &'a Inventory, &'a Energy, &'a AbilityMap);
type HotbarSource<'a> = (
&'a hotbar::State,
&'a Inventory,
&'a Energy,
&'a AbilityMap,
&'a MaterialStatManifest,
);
type HotbarImageSource<'a> = (&'a ItemImgs, &'a img_ids::Imgs);
impl<'a> SlotKey<HotbarSource<'a>, HotbarImageSource<'a>> for HotbarSlot {
@ -110,7 +115,7 @@ impl<'a> SlotKey<HotbarSource<'a>, HotbarImageSource<'a>> for HotbarSlot {
fn image_key(
&self,
(hotbar, inventory, energy, ability_map): &HotbarSource<'a>,
(hotbar, inventory, energy, ability_map, msm): &HotbarSource<'a>,
) -> Option<(Self::ImageKey, Option<Color>)> {
hotbar.get(*self).and_then(|contents| match contents {
hotbar::SlotContents::Inventory(idx) => inventory
@ -131,11 +136,7 @@ impl<'a> SlotKey<HotbarSource<'a>, HotbarImageSource<'a>> for HotbarSlot {
(
i,
if let Some(skill) = tool
.get_abilities(
&MATERIAL_STATS_MANIFEST,
item.components(),
ability_map,
)
.get_abilities(&msm, item.components(), ability_map)
.abilities
.get(0)
{
@ -178,11 +179,7 @@ impl<'a> SlotKey<HotbarSource<'a>, HotbarImageSource<'a>> for HotbarSlot {
(
i,
if let Some(skill) = tool
.get_abilities(
&MATERIAL_STATS_MANIFEST,
item.components(),
ability_map,
)
.get_abilities(&msm, item.components(), ability_map)
.abilities
.get(skill_index)
{
@ -201,7 +198,7 @@ impl<'a> SlotKey<HotbarSource<'a>, HotbarImageSource<'a>> for HotbarSlot {
})
}
fn amount(&self, (hotbar, inventory, _, _): &HotbarSource<'a>) -> Option<u32> {
fn amount(&self, (hotbar, inventory, _, _, _): &HotbarSource<'a>) -> Option<u32> {
hotbar
.get(*self)
.and_then(|content| match content {

View File

@ -15,7 +15,10 @@ use crate::{
};
use client::Client;
use common::{
comp::{inventory::item::Quality, Inventory},
comp::{
inventory::item::{MaterialStatManifest, Quality},
Inventory,
},
trade::{PendingTrade, TradeAction, TradePhase},
};
use common_net::sync::WorldSyncExt;
@ -61,6 +64,7 @@ pub struct Trade<'a> {
common: widget::CommonBuilder,
slot_manager: &'a mut SlotManager,
localized_strings: &'a Localization,
msm: &'a MaterialStatManifest,
pulse: f32,
}
@ -74,6 +78,7 @@ impl<'a> Trade<'a> {
tooltip_manager: &'a mut TooltipManager,
slot_manager: &'a mut SlotManager,
localized_strings: &'a Localization,
msm: &'a MaterialStatManifest,
pulse: f32,
) -> Self {
Self {
@ -84,9 +89,9 @@ impl<'a> Trade<'a> {
rot_imgs,
tooltip_manager,
common: widget::CommonBuilder::default(),
//tooltip_manager,
slot_manager,
localized_strings,
msm,
pulse,
}
}
@ -295,7 +300,7 @@ impl<'a> Trade<'a> {
);
let slot_id = state.ids.inv_slots[i + who * MAX_TRADE_SLOTS];
if let Some(Some(item)) = slot.invslot.and_then(|slotid| inventory.slot(slotid)) {
let (title, desc) = super::util::item_text(item);
let (title, desc) = super::util::item_text(item, self.msm);
let quality_col = get_quality_col(item);
let quality_col_img = match item.quality() {
Quality::Low => self.imgs.inv_slot_grey,

View File

@ -1,30 +1,28 @@
use common::comp::item::{
armor::{Armor, ArmorKind, Protection},
tool::{Hands, StatKind, Tool, ToolKind},
tool::{Hands, StatKind, Stats, Tool, ToolKind},
Item, ItemDesc, ItemKind, MaterialStatManifest, ModularComponent,
};
use lazy_static::lazy_static;
use std::{borrow::Cow, fmt::Write};
lazy_static! {
// TODO: even more plumbing
pub static ref MATERIAL_STATS_MANIFEST: MaterialStatManifest = MaterialStatManifest::default();
}
pub fn loadout_slot_text<'a>(
item: Option<&'a impl ItemDesc>,
mut empty: impl FnMut() -> (&'a str, &'a str),
msm: &'a MaterialStatManifest,
) -> (&'a str, Cow<'a, str>) {
item.map_or_else(
|| {
let (title, desc) = empty();
(title, Cow::Borrowed(desc))
},
item_text,
|item| item_text(item, msm),
)
}
pub fn item_text<'a>(item: &'a impl ItemDesc) -> (&'_ str, Cow<'a, str>) {
pub fn item_text<'a>(
item: &'a impl ItemDesc,
msm: &'a MaterialStatManifest,
) -> (&'a str, Cow<'a, str>) {
let desc: Cow<str> = match item.kind() {
ItemKind::Armor(armor) => {
Cow::Owned(armor_desc(armor, item.description(), item.num_slots()))
@ -32,20 +30,24 @@ pub fn item_text<'a>(item: &'a impl ItemDesc) -> (&'_ str, Cow<'a, str>) {
ItemKind::Tool(tool) => Cow::Owned(tool_desc(
&tool,
item.components(),
&MATERIAL_STATS_MANIFEST,
&msm,
item.description(),
)),
ItemKind::ModularComponent(mc) => Cow::Owned(modular_component_desc(
mc,
item.components(),
&MATERIAL_STATS_MANIFEST,
&msm,
item.description(),
)),
ItemKind::Glider(_glider) => Cow::Owned(glider_desc(item.description())),
ItemKind::Consumable { .. } => Cow::Owned(consumable_desc(item.description())),
ItemKind::Throwable { .. } => Cow::Owned(throwable_desc(item.description())),
ItemKind::Utility { .. } => Cow::Owned(utility_desc(item.description())),
ItemKind::Ingredient { .. } => Cow::Owned(ingredient_desc(item.description())),
ItemKind::Ingredient { .. } => Cow::Owned(ingredient_desc(
item.description(),
item.item_definition_id(),
msm,
)),
ItemKind::Lantern { .. } => Cow::Owned(lantern_desc(item.description())),
ItemKind::TagExamples { .. } => Cow::Borrowed(item.description()),
//_ => Cow::Borrowed(item.description()),
@ -61,13 +63,11 @@ fn modular_component_desc(
msm: &MaterialStatManifest,
description: &str,
) -> String {
let mut result = format!(
"Modular Component\n\n{:?}\n\n{}",
StatKind::Direct(mc.stats).resolve_stats(msm, components),
description
);
let stats = StatKind::Direct(mc.stats).resolve_stats(msm, components);
let statblock = statblock_desc(&stats);
let mut result = format!("Modular Component\n\n{}\n\n{}", statblock, description);
if !components.is_empty() {
result += "Made from:\n";
result += "\n\nMade from:\n";
for component in components {
result += component.name();
result += "\n"
@ -88,7 +88,14 @@ fn throwable_desc(desc: &str) -> String {
fn utility_desc(desc: &str) -> String { format!("{}\n\n<Right-Click to use>", desc) }
fn ingredient_desc(desc: &str) -> String { format!("Crafting Ingredient\n\n{}", desc) }
fn ingredient_desc(desc: &str, item_id: &str, msm: &MaterialStatManifest) -> String {
let mut result = format!("Crafting Ingredient\n\n{}", desc);
if let Some(stats) = msm.0.get(item_id) {
result += "\n\nStat multipliers:\n";
result += &statblock_desc(stats);
}
result
}
fn lantern_desc(desc: &str) -> String { format!("Lantern\n\n{}\n\n<Right-Click to use>", desc) }
@ -153,26 +160,16 @@ fn tool_desc(tool: &Tool, components: &[Item], msm: &MaterialStatManifest, desc:
};
// Get tool stats
let power = tool.base_power(msm, components);
let stats = tool.stats.resolve_stats(msm, components).clamp_speed();
//let poise_strength = tool.base_poise_strength();
let hands = match tool.hands {
Hands::One => "One",
Hands::Two => "Two",
};
let speed = tool.base_speed(msm, components);
let mut result = format!(
"{}-Handed {}\n\nDPS: {:0.1}\n\nPower: {:0.1}\n\nSpeed: {:0.1}\n\n",
// add back when ready for poise
//"{}\n\nDPS: {:0.1}\n\nPower: {:0.1}\n\nPoise Strength: {:0.1}\n\nSpeed: \
// {:0.1}\n\n{}\n\n<Right-Click to use>",
hands,
kind,
speed * power * 10.0, // Damage per second
power * 10.0,
//poise_strength * 10.0,
speed
);
let mut result = format!("{}-Handed {}\n\n", hands, kind);
result += &statblock_desc(&stats);
if !components.is_empty() {
result += "Made from:\n";
for component in components {
@ -188,6 +185,19 @@ fn tool_desc(tool: &Tool, components: &[Item], msm: &MaterialStatManifest, desc:
result
}
fn statblock_desc(stats: &Stats) -> String {
format!(
"DPS: {:0.1}\n\nPower: {:0.1}\n\nSpeed: {:0.1}\n\n",
// add back when ready for poise
//"{}\n\nDPS: {:0.1}\n\nPower: {:0.1}\n\nPoise Strength: {:0.1}\n\nSpeed: \
// {:0.1}\n\n{}\n\n<Right-Click to use>",
stats.speed * stats.power * 10.0, // Damage per second
stats.power * 10.0,
//stats.poise_strength * 10.0,
stats.speed
)
}
#[cfg(test)]
mod tests {
use super::*;
@ -234,11 +244,29 @@ mod tests {
#[test]
fn test_ingredient_desc() {
let item_description = "mushrooms";
let mut testmsm = MaterialStatManifest(hashbrown::HashMap::new());
testmsm.0.insert(
"common.items.crafting_ing.bronze_ingot".to_string(),
Stats {
equip_time_millis: 0,
power: 3.0,
poise_strength: 5.0,
speed: 7.0,
},
);
assert_eq!(
"Crafting Ingredient\n\nmushrooms",
ingredient_desc(item_description)
ingredient_desc("mushrooms", "common.items.food.mushroom", &testmsm)
);
assert_eq!(
"Crafting Ingredient\n\nA bronze ingot.\n\nStat multipliers:\nDPS: 210.0\n\nPower: \
30.0\n\nSpeed: 7.0\n\n",
ingredient_desc(
"A bronze ingot.",
"common.items.crafting_ing.bronze_ingot",
&testmsm
)
);
}