mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Refactored crafting to use ItemDef instead of Item
This commit is contained in:
parent
98c8240879
commit
11fc74642e
@ -119,13 +119,17 @@ pub struct Item {
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct ItemDef {
|
||||
#[serde(skip)]
|
||||
#[serde(default)]
|
||||
item_definition_id: String,
|
||||
pub name: String,
|
||||
pub description: String,
|
||||
pub kind: ItemKind,
|
||||
}
|
||||
|
||||
impl PartialEq for ItemDef {
|
||||
fn eq(&self, other: &Self) -> bool { self.item_definition_id == other.item_definition_id }
|
||||
}
|
||||
|
||||
impl ItemDef {
|
||||
pub fn is_stackable(&self) -> bool {
|
||||
matches!(self.kind, ItemKind::Consumable { .. }
|
||||
@ -264,6 +268,10 @@ impl Item {
|
||||
|
||||
pub fn item_definition_id(&self) -> &str { &self.item_def.item_definition_id }
|
||||
|
||||
pub fn is_same_item_def(&self, item_def: &ItemDef) -> bool {
|
||||
self.item_def.item_definition_id == item_def.item_definition_id
|
||||
}
|
||||
|
||||
pub fn is_stackable(&self) -> bool { self.item_def.is_stackable() }
|
||||
|
||||
pub fn name(&self) -> &str { &self.item_def.name }
|
||||
@ -314,24 +322,30 @@ impl Item {
|
||||
_ => return None,
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
/// Determines whether two items are superficially equivalent to one another
|
||||
/// (i.e: one may be substituted for the other in crafting recipes or
|
||||
/// item possession checks).
|
||||
pub fn superficially_eq(&self, other: &Self) -> bool {
|
||||
match (&self.kind(), &other.kind()) {
|
||||
(ItemKind::Tool(a), ItemKind::Tool(b)) => a.superficially_eq(b),
|
||||
// TODO: Differentiate between lantern colors?
|
||||
(ItemKind::Lantern(_), ItemKind::Lantern(_)) => true,
|
||||
(ItemKind::Glider(_), ItemKind::Glider(_)) => true,
|
||||
(ItemKind::Armor(a), ItemKind::Armor(b)) => a.superficially_eq(b),
|
||||
(ItemKind::Consumable { kind: a, .. }, ItemKind::Consumable { kind: b, .. }) => a == b,
|
||||
(ItemKind::Throwable { kind: a, .. }, ItemKind::Throwable { kind: b, .. }) => a == b,
|
||||
(ItemKind::Utility { kind: a, .. }, ItemKind::Utility { kind: b, .. }) => a == b,
|
||||
(ItemKind::Ingredient { kind: a, .. }, ItemKind::Ingredient { kind: b, .. }) => a == b,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
/// Provides common methods providing details about an item definition
|
||||
/// for either an `Item` containing the definition, or the actual `ItemDef`
|
||||
pub trait ItemDesc {
|
||||
fn description(&self) -> &str;
|
||||
fn name(&self) -> &str;
|
||||
fn kind(&self) -> &ItemKind;
|
||||
}
|
||||
|
||||
impl ItemDesc for Item {
|
||||
fn description(&self) -> &str { &self.item_def.description }
|
||||
|
||||
fn name(&self) -> &str { &self.item_def.name }
|
||||
|
||||
fn kind(&self) -> &ItemKind { &self.item_def.kind }
|
||||
}
|
||||
|
||||
impl ItemDesc for ItemDef {
|
||||
fn description(&self) -> &str { &self.description }
|
||||
|
||||
fn name(&self) -> &str { &self.name }
|
||||
|
||||
fn kind(&self) -> &ItemKind { &self.kind }
|
||||
}
|
||||
|
||||
impl Component for Item {
|
||||
|
@ -1,7 +1,7 @@
|
||||
pub mod item;
|
||||
pub mod slot;
|
||||
|
||||
use crate::recipe::Recipe;
|
||||
use crate::{comp::inventory::item::ItemDef, recipe::Recipe};
|
||||
use core::ops::Not;
|
||||
use item::Item;
|
||||
use serde::{Deserialize, Serialize};
|
||||
@ -211,11 +211,11 @@ impl Inventory {
|
||||
}
|
||||
|
||||
/// Determine how many of a particular item there is in the inventory.
|
||||
pub fn item_count(&self, item: &Item) -> u64 {
|
||||
pub fn item_count(&self, item_def: &ItemDef) -> u64 {
|
||||
self.slots()
|
||||
.iter()
|
||||
.flatten()
|
||||
.filter(|it| it.superficially_eq(item))
|
||||
.filter(|it| it.is_same_item_def(item_def))
|
||||
.map(|it| u64::from(it.amount()))
|
||||
.sum()
|
||||
}
|
||||
@ -228,15 +228,15 @@ impl Inventory {
|
||||
pub fn contains_ingredients<'a>(
|
||||
&self,
|
||||
recipe: &'a Recipe,
|
||||
) -> Result<Vec<u32>, Vec<(&'a Item, u32)>> {
|
||||
) -> Result<Vec<u32>, Vec<(&'a ItemDef, u32)>> {
|
||||
let mut slot_claims = vec![0; self.slots.len()];
|
||||
let mut missing = Vec::new();
|
||||
let mut missing = Vec::<(&ItemDef, u32)>::new();
|
||||
|
||||
for (input, mut needed) in recipe.inputs() {
|
||||
let mut contains_any = false;
|
||||
|
||||
for (i, slot) in self.slots().iter().enumerate() {
|
||||
if let Some(item) = slot.as_ref().filter(|item| item.superficially_eq(input)) {
|
||||
if let Some(item) = slot.as_ref().filter(|item| item.is_same_item_def(&*input)) {
|
||||
let can_claim = (item.amount() - slot_claims[i]).min(needed);
|
||||
slot_claims[i] += can_claim;
|
||||
needed -= can_claim;
|
||||
|
@ -1,6 +1,6 @@
|
||||
use crate::{
|
||||
assets::{self, Asset},
|
||||
comp::{Inventory, Item},
|
||||
comp::{item::ItemDef, Inventory, Item},
|
||||
};
|
||||
use hashbrown::HashMap;
|
||||
use serde::{Deserialize, Serialize};
|
||||
@ -8,14 +8,17 @@ use std::{fs::File, io::BufReader, sync::Arc};
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
pub struct Recipe {
|
||||
pub output: (Item, u32),
|
||||
pub inputs: Vec<(Item, u32)>,
|
||||
pub output: (Arc<ItemDef>, u32),
|
||||
pub inputs: Vec<(Arc<ItemDef>, u32)>,
|
||||
}
|
||||
|
||||
#[allow(clippy::type_complexity)]
|
||||
impl Recipe {
|
||||
/// Perform a recipe, returning a list of missing items on failure
|
||||
pub fn perform(&self, inv: &mut Inventory) -> Result<Option<(Item, u32)>, Vec<(&Item, u32)>> {
|
||||
pub fn perform(
|
||||
&self,
|
||||
inv: &mut Inventory,
|
||||
) -> Result<Option<(Item, u32)>, Vec<(&ItemDef, u32)>> {
|
||||
// Get ingredient cells from inventory,
|
||||
inv.contains_ingredients(self)?
|
||||
.into_iter()
|
||||
@ -27,7 +30,8 @@ impl Recipe {
|
||||
});
|
||||
|
||||
for i in 0..self.output.1 {
|
||||
if let Some(item) = inv.push(self.output.0.duplicate()) {
|
||||
let crafted_item = Item::new(Arc::clone(&self.output.0));
|
||||
if let Some(item) = inv.push(crafted_item) {
|
||||
return Ok(Some((item, self.output.1 - i)));
|
||||
}
|
||||
}
|
||||
@ -35,8 +39,10 @@ impl Recipe {
|
||||
Ok(None)
|
||||
}
|
||||
|
||||
pub fn inputs(&self) -> impl ExactSizeIterator<Item = (&Item, u32)> {
|
||||
self.inputs.iter().map(|(item, amount)| (item, *amount))
|
||||
pub fn inputs(&self) -> impl ExactSizeIterator<Item = (&Arc<ItemDef>, u32)> {
|
||||
self.inputs
|
||||
.iter()
|
||||
.map(|(item_def, amount)| (item_def, *amount))
|
||||
}
|
||||
}
|
||||
|
||||
@ -75,11 +81,11 @@ impl Asset for RecipeBook {
|
||||
.map::<Result<(String, Recipe), assets::Error>, _>(
|
||||
|(name, ((output, amount), inputs))| {
|
||||
Ok((name, Recipe {
|
||||
output: (Item::new_from_asset(&output)?, amount),
|
||||
output: (ItemDef::load(&output)?, amount),
|
||||
inputs: inputs
|
||||
.into_iter()
|
||||
.map::<Result<(Item, u32), assets::Error>, _>(
|
||||
|(name, amount)| Ok((Item::new_from_asset(&name)?, amount)),
|
||||
.map::<Result<(Arc<ItemDef>, u32), assets::Error>, _>(
|
||||
|(name, amount)| Ok((ItemDef::load(&name)?, amount)),
|
||||
)
|
||||
.collect::<Result<_, _>>()?,
|
||||
}))
|
||||
|
@ -8,7 +8,7 @@ use crate::{
|
||||
ui::{fonts::ConrodVoxygenFonts, ImageFrame, Tooltip, TooltipManager, Tooltipable},
|
||||
};
|
||||
use client::{self, Client};
|
||||
use common::comp::Inventory;
|
||||
use common::comp::{item::ItemDesc, Inventory};
|
||||
use conrod_core::{
|
||||
color,
|
||||
widget::{self, Button, Image, Rectangle, Scrollbar, Text},
|
||||
@ -247,10 +247,10 @@ 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);
|
||||
Button::image(
|
||||
self.item_imgs
|
||||
.img_id_or_not_found_img((&recipe.output.0).into()),
|
||||
.img_id_or_not_found_img((&*recipe.output.0.kind()).into()),
|
||||
)
|
||||
.w_h(55.0, 55.0)
|
||||
.middle_of(state.ids.output_img_frame)
|
||||
@ -362,9 +362,9 @@ impl<'a> Widget for Crafting<'a> {
|
||||
});
|
||||
};
|
||||
// Widget generation for every ingredient
|
||||
for (i, (item, amount)) in recipe.inputs.iter().enumerate() {
|
||||
for (i, (item_def, amount)) in recipe.inputs.iter().enumerate() {
|
||||
// Grey color for images and text if their amount is too low to craft the item
|
||||
let item_count_in_inventory = self.inventory.item_count(item);
|
||||
let item_count_in_inventory = self.inventory.item_count(item_def);
|
||||
let col = if item_count_in_inventory >= u64::from(*amount) {
|
||||
TEXT_COLOR
|
||||
} else {
|
||||
@ -393,8 +393,8 @@ impl<'a> Widget for Crafting<'a> {
|
||||
};
|
||||
frame.set(state.ids.ingredient_frame[i], ui);
|
||||
//Item Image
|
||||
let (title, desc) = super::util::item_text(&item);
|
||||
Button::image(self.item_imgs.img_id_or_not_found_img(item.into()))
|
||||
let (title, desc) = super::util::item_text(&**item_def);
|
||||
Button::image(self.item_imgs.img_id_or_not_found_img((&*item_def.kind()).into()))
|
||||
.w_h(22.0, 22.0)
|
||||
.middle_of(state.ids.ingredient_frame[i])
|
||||
//.image_color(col)
|
||||
@ -414,7 +414,7 @@ impl<'a> Widget for Crafting<'a> {
|
||||
.font_size(self.fonts.cyri.scale(14))
|
||||
.color(col)
|
||||
.set(state.ids.req_text[i], ui);
|
||||
Text::new(&item.name())
|
||||
Text::new(&item_def.name())
|
||||
.right_from(state.ids.ingredient_frame[i], 10.0)
|
||||
.font_id(self.fonts.cyri.conrod_id)
|
||||
.font_size(self.fonts.cyri.scale(14))
|
||||
@ -425,7 +425,7 @@ impl<'a> Widget for Crafting<'a> {
|
||||
let input = format!(
|
||||
"{}x {} ({})",
|
||||
amount,
|
||||
&item.name(),
|
||||
&item_def.name(),
|
||||
if item_count_in_inventory > 99 {
|
||||
over9k
|
||||
} else {
|
||||
|
@ -4,7 +4,7 @@ use common::{
|
||||
comp::item::{
|
||||
armor::{Armor, ArmorKind},
|
||||
tool::{Tool, ToolKind},
|
||||
Glider, Item, ItemKind, Lantern, Throwable, Utility,
|
||||
Glider, ItemKind, Lantern, Throwable, Utility,
|
||||
},
|
||||
figure::Segment,
|
||||
};
|
||||
@ -29,9 +29,10 @@ pub enum ItemKey {
|
||||
Ingredient(String),
|
||||
Empty,
|
||||
}
|
||||
impl From<&Item> for ItemKey {
|
||||
fn from(item: &Item) -> Self {
|
||||
match &item.kind() {
|
||||
|
||||
impl From<&ItemKind> for ItemKey {
|
||||
fn from(item_kind: &ItemKind) -> Self {
|
||||
match item_kind {
|
||||
ItemKind::Tool(Tool { kind, .. }) => ItemKey::Tool(kind.clone()),
|
||||
ItemKind::Lantern(Lantern { kind, .. }) => ItemKey::Lantern(kind.clone()),
|
||||
ItemKind::Glider(Glider { kind, .. }) => ItemKey::Glider(kind.clone()),
|
||||
|
@ -32,7 +32,7 @@ impl SlotKey<Inventory, ItemImgs> for InventorySlot {
|
||||
type ImageKey = ItemKey;
|
||||
|
||||
fn image_key(&self, source: &Inventory) -> Option<(Self::ImageKey, Option<Color>)> {
|
||||
source.get(self.0).map(|i| (i.into(), None))
|
||||
source.get(self.0).map(|i| (i.kind().into(), None))
|
||||
}
|
||||
|
||||
fn amount(&self, source: &Inventory) -> Option<u32> {
|
||||
@ -69,7 +69,7 @@ impl SlotKey<Loadout, ItemImgs> for EquipSlot {
|
||||
EquipSlot::Glider => source.glider.as_ref(),
|
||||
};
|
||||
|
||||
item.map(|i| (i.into(), None))
|
||||
item.map(|i| (i.kind().into(), None))
|
||||
}
|
||||
|
||||
fn amount(&self, _: &Loadout) -> Option<u32> { None }
|
||||
@ -100,7 +100,7 @@ impl<'a> SlotKey<HotbarSource<'a>, HotbarImageSource<'a>> for HotbarSlot {
|
||||
hotbar.get(*self).and_then(|contents| match contents {
|
||||
hotbar::SlotContents::Inventory(idx) => inventory
|
||||
.get(idx)
|
||||
.map(|item| HotbarImage::Item(item.into()))
|
||||
.map(|item| HotbarImage::Item(item.kind().into()))
|
||||
.map(|i| (i, None)),
|
||||
hotbar::SlotContents::Ability3 => loadout
|
||||
.active_item
|
||||
|
@ -1,12 +1,12 @@
|
||||
use common::comp::item::{
|
||||
armor::{Armor, ArmorKind, Protection},
|
||||
tool::{Tool, ToolKind},
|
||||
Item, ItemKind,
|
||||
ItemDesc, ItemKind,
|
||||
};
|
||||
use std::borrow::Cow;
|
||||
|
||||
pub fn loadout_slot_text<'a>(
|
||||
item: Option<&'a Item>,
|
||||
item: Option<&'a impl ItemDesc>,
|
||||
mut empty: impl FnMut() -> (&'a str, &'a str),
|
||||
) -> (&'a str, Cow<'a, str>) {
|
||||
item.map_or_else(
|
||||
@ -18,7 +18,7 @@ pub fn loadout_slot_text<'a>(
|
||||
)
|
||||
}
|
||||
|
||||
pub fn item_text<'a>(item: &'a Item) -> (&'_ str, Cow<'a, str>) {
|
||||
pub fn item_text<'a>(item: &'a impl ItemDesc) -> (&'_ str, Cow<'a, str>) {
|
||||
let desc: Cow<str> = match item.kind() {
|
||||
ItemKind::Armor(armor) => Cow::Owned(armor_desc(&armor, item.description())),
|
||||
ItemKind::Tool(tool) => Cow::Owned(tool_desc(&tool, item.description())),
|
||||
@ -34,6 +34,7 @@ pub fn item_text<'a>(item: &'a Item) -> (&'_ str, Cow<'a, str>) {
|
||||
|
||||
(item.name(), desc)
|
||||
}
|
||||
|
||||
// Armor Description
|
||||
fn armor_desc(armor: &Armor, desc: &str) -> String {
|
||||
// TODO: localization
|
||||
|
Loading…
Reference in New Issue
Block a user