WIP modular weapon pricing.

This commit is contained in:
Avi Weinstock 2022-07-02 12:20:10 -04:00 committed by Christof Petig
parent 80d491f003
commit 27d2cdeb79
6 changed files with 79 additions and 28 deletions

View File

@ -1,6 +1,6 @@
use crate::{ use crate::{
assets::{self, AssetExt}, assets::{self, AssetExt},
comp::item::Item, comp::item::{Item, ItemDefinitionId},
lottery::LootSpec, lottery::LootSpec,
recipe::{default_recipe_book, RecipeInput}, recipe::{default_recipe_book, RecipeInput},
trade::Good, 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<MaterialUse> for MaterialUse {
fn sum<I>(iter: I) -> Self where I: Iterator<Item=Self> {
let mut ret = Self::default();
for i in iter {
ret += i;
}
ret
}
}
impl std::ops::Deref for MaterialUse { impl std::ops::Deref for MaterialUse {
type Target = [(f32, Good)]; 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.armor.") => Good::Armor,
_ if name.starts_with("common.items.weapons.") => Good::Tools, _ 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.tool.") => Good::Tools,
_ if name.starts_with("common.items.crafting_ing.") => Good::Ingredients, _ if name.starts_with("common.items.crafting_ing.") => Good::Ingredients,
@ -663,7 +680,16 @@ impl TradePricing {
result result
} }
fn get_materials_impl(&self, item: &str) -> Option<&MaterialUse> { self.price_lookup(item) } fn get_materials_impl(&self, item: ItemDefinitionId<'_>) -> Option<MaterialUse> {
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] #[must_use]
pub fn random_items( pub fn random_items(
@ -677,7 +703,7 @@ impl TradePricing {
} }
#[must_use] #[must_use]
pub fn get_materials(item: &str) -> Option<&MaterialUse> { pub fn get_materials(item: ItemDefinitionId<'_>) -> Option<MaterialUse> {
TRADE_PRICING.get_materials_impl(item) TRADE_PRICING.get_materials_impl(item)
} }

View File

@ -5,7 +5,7 @@ use crate::{
item::{ item::{
modular, modular,
tool::{AbilityMap, ToolKind}, tool::{AbilityMap, ToolKind},
ItemBase, ItemDef, ItemKind, ItemTag, MaterialStatManifest, ItemBase, ItemDef, ItemDefinitionIdOwned, ItemKind, ItemTag, MaterialStatManifest,
}, },
Inventory, Item, Inventory, Item,
}, },
@ -472,6 +472,11 @@ pub struct ComponentRecipeBook {
recipes: HashMap<ComponentKey, ComponentRecipe>, recipes: HashMap<ComponentKey, ComponentRecipe>,
} }
#[derive(Clone, Debug)]
pub struct ReverseComponentRecipeBook {
recipes: HashMap<ItemDefinitionIdOwned, ComponentRecipe>,
}
impl ComponentRecipeBook { impl ComponentRecipeBook {
pub fn get(&self, key: &ComponentKey) -> Option<&ComponentRecipe> { self.recipes.get(key) } 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)] #[derive(Clone, Deserialize)]
#[serde(transparent)] #[serde(transparent)]
struct RawComponentRecipeBook(Vec<RawComponentRecipe>); struct RawComponentRecipeBook(Vec<RawComponentRecipe>);
@ -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::<Vec<_>>();
ItemDefinitionIdOwned::Compound {
simple_base: item_def.id().to_owned(),
components,
}
},
}
}
pub fn item_output(&self, ability_map: &AbilityMap, msm: &MaterialStatManifest) -> Item { pub fn item_output(&self, ability_map: &AbilityMap, msm: &MaterialStatManifest) -> Item {
match &self.output { match &self.output {
ComponentOutput::ItemComponents { ComponentOutput::ItemComponents {
@ -818,3 +847,14 @@ pub fn default_recipe_book() -> AssetHandle<RecipeBook> {
pub fn default_component_recipe_book() -> AssetHandle<ComponentRecipeBook> { pub fn default_component_recipe_book() -> AssetHandle<ComponentRecipeBook> {
ComponentRecipeBook::load_expect("common.component_recipe_book") ComponentRecipeBook::load_expect("common.component_recipe_book")
} }
impl assets::Compound for ReverseComponentRecipeBook {
fn load(cache: assets::AnyCache, specifier: &str) -> Result<Self, assets::BoxedError> {
let forward = cache.load::<ComponentRecipeBook>(specifier)?.cloned();
let mut recipes = HashMap::new();
for (_, recipe) in forward.iter() {
recipes.insert(recipe.itemdef_output(), recipe.clone());
}
Ok(ReverseComponentRecipeBook { recipes })
}
}

View File

@ -389,12 +389,7 @@ impl SitePrices {
.as_ref() .as_ref()
.and_then(|ri| { .and_then(|ri| {
ri.inventory.get(slot).map(|item| { ri.inventory.get(slot).map(|item| {
if let Some(vec) = item if let Some(vec) = TradePricing::get_materials(item.name.as_ref())
.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)
{ {
vec.iter() vec.iter()
.map(|(amount2, material)| { .map(|(amount2, material)| {

View File

@ -3644,11 +3644,7 @@ impl Hud {
false, false,
); );
if let Some(item) = inventory.get(slot) { if let Some(item) = inventory.get(slot) {
if let Some(materials) = item if let Some(materials) = TradePricing::get_materials(item.item_definition_id()) {
.item_definition_id()
.itemdef_id()
.and_then(TradePricing::get_materials)
{
let unit_price: f32 = materials let unit_price: f32 = materials
.iter() .iter()
.map(|e| { .map(|e| {

View File

@ -5,7 +5,7 @@ use common::{
item::{ item::{
armor::{Armor, ArmorKind, Protection}, armor::{Armor, ArmorKind, Protection},
tool::{Hands, Tool, ToolKind}, tool::{Hands, Tool, ToolKind},
ItemDesc, ItemKind, MaterialKind, MaterialStatManifest, ItemDefinitionId, ItemDesc, ItemKind, MaterialKind, MaterialStatManifest,
}, },
BuffKind, BuffKind,
}, },
@ -18,7 +18,7 @@ use std::{borrow::Cow, fmt::Write};
pub fn price_desc( pub fn price_desc(
prices: &Option<SitePrices>, prices: &Option<SitePrices>,
item_definition_id: &str, item_definition_id: ItemDefinitionId<'_>,
i18n: &Localization, i18n: &Localization,
) -> Option<(String, String, f32)> { ) -> Option<(String, String, f32)> {
if let Some(prices) = prices { if let Some(prices) = prices {

View File

@ -1357,11 +1357,7 @@ impl<'a> Widget for ItemTooltip<'a> {
} }
// Price display // Price display
if let Some((buy, sell, factor)) = item if let Some((buy, sell, factor)) = util::price_desc(self.prices, item.item_definition_id(), i18n) {
.item_definition_id()
.itemdef_id()
.and_then(|id| util::price_desc(self.prices, id, i18n))
{
widget::Text::new(&buy) widget::Text::new(&buy)
.x_align_to(state.ids.item_frame, conrod_core::position::Align::Start) .x_align_to(state.ids.item_frame, conrod_core::position::Align::Start)
.graphics_for(id) .graphics_for(id)
@ -1393,9 +1389,10 @@ impl<'a> Widget for ItemTooltip<'a> {
//Tooltips for trade mini-tutorial //Tooltips for trade mini-tutorial
widget::Text::new(&format!( widget::Text::new(&format!(
"{}\n{}", "{}\n{}\n{:?}",
i18n.get("hud.trade.tooltip_hint_1"), 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) .x_align_to(state.ids.item_frame, conrod_core::position::Align::Start)
.graphics_for(id) .graphics_for(id)
@ -1457,10 +1454,7 @@ impl<'a> Widget for ItemTooltip<'a> {
}; };
// Price // Price
let price_h: f64 = if let Some((buy, sell, _)) = item let price_h: f64 = if let Some((buy, sell, _)) = util::price_desc(self.prices, item.item_definition_id(), self.localized_strings)
.item_definition_id()
.itemdef_id()
.and_then(|id| util::price_desc(self.prices, id, self.localized_strings))
{ {
//Get localized tooltip strings (gotten here because these should only show if //Get localized tooltip strings (gotten here because these should only show if
// in a trade- aka if buy/sell prices are present) // in a trade- aka if buy/sell prices are present)