diff --git a/common/src/comp/inventory/trade_pricing.rs b/common/src/comp/inventory/trade_pricing.rs index e1f73c0ce6..a6038b8de7 100644 --- a/common/src/comp/inventory/trade_pricing.rs +++ b/common/src/comp/inventory/trade_pricing.rs @@ -1,6 +1,6 @@ use crate::{ assets::{self, AssetExt}, - comp::item::Item, + comp::item::{Item, ItemDefinitionId}, lottery::LootSpec, recipe::{default_recipe_book, RecipeInput}, trade::Good, @@ -61,6 +61,22 @@ impl std::ops::Add for MaterialUse { } } +impl std::ops::AddAssign for MaterialUse { + fn add_assign(&mut self, rhs: Self) { + vector_add_eq(&mut self.0, &rhs.0); + } +} + +impl std::iter::Sum for MaterialUse { + fn sum(iter: I) -> Self where I: Iterator { + let mut ret = Self::default(); + for i in iter { + ret += i; + } + ret + } +} + impl std::ops::Deref for MaterialUse { type Target = [(f32, Good)]; @@ -362,6 +378,7 @@ impl TradePricing { _ if name.starts_with("common.items.armor.") => Good::Armor, _ if name.starts_with("common.items.weapons.") => Good::Tools, + _ if name.starts_with("common.items.modular.weapon.") => Good::Tools, _ if name.starts_with("common.items.tool.") => Good::Tools, _ if name.starts_with("common.items.crafting_ing.") => Good::Ingredients, @@ -663,7 +680,16 @@ impl TradePricing { result } - fn get_materials_impl(&self, item: &str) -> Option<&MaterialUse> { self.price_lookup(item) } + fn get_materials_impl(&self, item: ItemDefinitionId<'_>) -> Option { + let tmp = format!("{:?}", item); + let ret = match item { + ItemDefinitionId::Simple(id) => self.price_lookup(id).cloned(), + ItemDefinitionId::Modular { components, .. } => Some(components.into_iter().filter_map(|comp| self.get_materials_impl(comp)).sum()), + ItemDefinitionId::Compound { simple_base, components } => Some(self.price_lookup(simple_base).cloned().unwrap_or_else(MaterialUse::default) + components.into_iter().filter_map(|comp| self.get_materials_impl(comp)).sum()), + }; + println!("{} -> {:?}", tmp, ret); + ret + } #[must_use] pub fn random_items( @@ -677,7 +703,7 @@ impl TradePricing { } #[must_use] - pub fn get_materials(item: &str) -> Option<&MaterialUse> { + pub fn get_materials(item: ItemDefinitionId<'_>) -> Option { TRADE_PRICING.get_materials_impl(item) } diff --git a/common/src/recipe.rs b/common/src/recipe.rs index 6f2da5a81d..265e80df41 100644 --- a/common/src/recipe.rs +++ b/common/src/recipe.rs @@ -5,7 +5,7 @@ use crate::{ item::{ modular, tool::{AbilityMap, ToolKind}, - ItemBase, ItemDef, ItemKind, ItemTag, MaterialStatManifest, + ItemBase, ItemDef, ItemDefinitionIdOwned, ItemKind, ItemTag, MaterialStatManifest, }, Inventory, Item, }, @@ -472,6 +472,11 @@ pub struct ComponentRecipeBook { recipes: HashMap, } +#[derive(Clone, Debug)] +pub struct ReverseComponentRecipeBook { + recipes: HashMap, +} + impl ComponentRecipeBook { pub fn get(&self, key: &ComponentKey) -> Option<&ComponentRecipe> { self.recipes.get(key) } @@ -480,6 +485,10 @@ impl ComponentRecipeBook { } } +impl ReverseComponentRecipeBook { + pub fn get(&self, key: &ItemDefinitionIdOwned) -> Option<&ComponentRecipe> { self.recipes.get(key) } +} + #[derive(Clone, Deserialize)] #[serde(transparent)] struct RawComponentRecipeBook(Vec); @@ -646,6 +655,26 @@ impl ComponentRecipe { ) } + pub fn itemdef_output(&self) -> ItemDefinitionIdOwned { + match &self.output { + ComponentOutput::ItemComponents { + item: item_def, + components, + } => { + let components = components + .iter() + .map(|item_def| { + ItemDefinitionIdOwned::Simple(item_def.id().to_owned()) + }) + .collect::>(); + ItemDefinitionIdOwned::Compound { + simple_base: item_def.id().to_owned(), + components, + } + }, + } + } + pub fn item_output(&self, ability_map: &AbilityMap, msm: &MaterialStatManifest) -> Item { match &self.output { ComponentOutput::ItemComponents { @@ -818,3 +847,14 @@ pub fn default_recipe_book() -> AssetHandle { pub fn default_component_recipe_book() -> AssetHandle { ComponentRecipeBook::load_expect("common.component_recipe_book") } + +impl assets::Compound for ReverseComponentRecipeBook { + fn load(cache: assets::AnyCache, specifier: &str) -> Result { + let forward = cache.load::(specifier)?.cloned(); + let mut recipes = HashMap::new(); + for (_, recipe) in forward.iter() { + recipes.insert(recipe.itemdef_output(), recipe.clone()); + } + Ok(ReverseComponentRecipeBook { recipes }) + } +} diff --git a/common/src/trade.rs b/common/src/trade.rs index 535f062786..9b34281209 100644 --- a/common/src/trade.rs +++ b/common/src/trade.rs @@ -389,12 +389,7 @@ impl SitePrices { .as_ref() .and_then(|ri| { ri.inventory.get(slot).map(|item| { - if let Some(vec) = item - .name - .as_ref() - // TODO: This won't handle compound items with components well, or pure modular items at all - .itemdef_id() - .and_then(TradePricing::get_materials) + if let Some(vec) = TradePricing::get_materials(item.name.as_ref()) { vec.iter() .map(|(amount2, material)| { diff --git a/voxygen/src/hud/mod.rs b/voxygen/src/hud/mod.rs index ecc917f839..edcb9c7cf4 100644 --- a/voxygen/src/hud/mod.rs +++ b/voxygen/src/hud/mod.rs @@ -3644,11 +3644,7 @@ impl Hud { false, ); if let Some(item) = inventory.get(slot) { - if let Some(materials) = item - .item_definition_id() - .itemdef_id() - .and_then(TradePricing::get_materials) - { + if let Some(materials) = TradePricing::get_materials(item.item_definition_id()) { let unit_price: f32 = materials .iter() .map(|e| { diff --git a/voxygen/src/hud/util.rs b/voxygen/src/hud/util.rs index f934aea939..25249d97f4 100644 --- a/voxygen/src/hud/util.rs +++ b/voxygen/src/hud/util.rs @@ -5,7 +5,7 @@ use common::{ item::{ armor::{Armor, ArmorKind, Protection}, tool::{Hands, Tool, ToolKind}, - ItemDesc, ItemKind, MaterialKind, MaterialStatManifest, + ItemDefinitionId, ItemDesc, ItemKind, MaterialKind, MaterialStatManifest, }, BuffKind, }, @@ -18,7 +18,7 @@ use std::{borrow::Cow, fmt::Write}; pub fn price_desc( prices: &Option, - item_definition_id: &str, + item_definition_id: ItemDefinitionId<'_>, i18n: &Localization, ) -> Option<(String, String, f32)> { if let Some(prices) = prices { diff --git a/voxygen/src/ui/widgets/item_tooltip.rs b/voxygen/src/ui/widgets/item_tooltip.rs index 67bf7bd4cc..0951758ff1 100644 --- a/voxygen/src/ui/widgets/item_tooltip.rs +++ b/voxygen/src/ui/widgets/item_tooltip.rs @@ -1357,11 +1357,7 @@ impl<'a> Widget for ItemTooltip<'a> { } // Price display - if let Some((buy, sell, factor)) = item - .item_definition_id() - .itemdef_id() - .and_then(|id| util::price_desc(self.prices, id, i18n)) - { + if let Some((buy, sell, factor)) = util::price_desc(self.prices, item.item_definition_id(), i18n) { widget::Text::new(&buy) .x_align_to(state.ids.item_frame, conrod_core::position::Align::Start) .graphics_for(id) @@ -1393,9 +1389,10 @@ impl<'a> Widget for ItemTooltip<'a> { //Tooltips for trade mini-tutorial widget::Text::new(&format!( - "{}\n{}", + "{}\n{}\n{:?}", i18n.get("hud.trade.tooltip_hint_1"), - i18n.get("hud.trade.tooltip_hint_2") + i18n.get("hud.trade.tooltip_hint_2"), + item.item_definition_id() )) .x_align_to(state.ids.item_frame, conrod_core::position::Align::Start) .graphics_for(id) @@ -1457,10 +1454,7 @@ impl<'a> Widget for ItemTooltip<'a> { }; // Price - let price_h: f64 = if let Some((buy, sell, _)) = item - .item_definition_id() - .itemdef_id() - .and_then(|id| util::price_desc(self.prices, id, self.localized_strings)) + let price_h: f64 = if let Some((buy, sell, _)) = util::price_desc(self.prices, item.item_definition_id(), self.localized_strings) { //Get localized tooltip strings (gotten here because these should only show if // in a trade- aka if buy/sell prices are present)