mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Changed item definition id to better handle modular items.
This commit is contained in:
parent
efc0189548
commit
64d07d02c4
@ -2,7 +2,8 @@ use crate::{
|
||||
assets::AssetExt,
|
||||
comp::inventory::item::{
|
||||
armor::{Armor, ArmorKind},
|
||||
modular, Glider, ItemDef, ItemDesc, ItemKind, Lantern, Throwable, Utility,
|
||||
modular, Glider, ItemDef, ItemDefinitionId, ItemDesc, ItemKind, Lantern, Throwable,
|
||||
Utility,
|
||||
},
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
@ -29,29 +30,33 @@ impl<T: ItemDesc> From<&T> for ItemKey {
|
||||
let item_definition_id = item_desc.item_definition_id();
|
||||
|
||||
match &*item_desc.kind() {
|
||||
ItemKind::Tool(_) => {
|
||||
if item_desc.is_modular() {
|
||||
ItemKind::Tool(_) => match item_definition_id {
|
||||
ItemDefinitionId::Simple(id) => ItemKey::Tool(id.to_string()),
|
||||
ItemDefinitionId::Modular { .. } => {
|
||||
ItemKey::ModularWeapon(modular::weapon_to_key(item_desc))
|
||||
} else {
|
||||
ItemKey::Tool(item_definition_id.to_owned())
|
||||
}
|
||||
},
|
||||
},
|
||||
ItemKind::ModularComponent(mod_comp) => {
|
||||
use modular::ModularComponent;
|
||||
match mod_comp {
|
||||
ModularComponent::ToolPrimaryComponent { .. } => {
|
||||
match modular::weapon_component_to_key(
|
||||
item_definition_id,
|
||||
item_desc.components(),
|
||||
) {
|
||||
Ok(key) => ItemKey::ModularWeaponComponent(key),
|
||||
// TODO: Maybe use a different ItemKey?
|
||||
Err(_) => ItemKey::Tool(item_definition_id.to_owned()),
|
||||
if let Some(id) = item_definition_id.raw() {
|
||||
match modular::weapon_component_to_key(id, item_desc.components()) {
|
||||
Ok(key) => ItemKey::ModularWeaponComponent(key),
|
||||
// TODO: Maybe use a different ItemKey?
|
||||
Err(_) => ItemKey::Tool(id.to_owned()),
|
||||
}
|
||||
} else {
|
||||
ItemKey::Empty
|
||||
}
|
||||
},
|
||||
ModularComponent::ToolSecondaryComponent { .. } => {
|
||||
// TODO: Maybe use a different ItemKey?
|
||||
ItemKey::Tool(item_definition_id.to_owned())
|
||||
if let Some(id) = item_definition_id.raw() {
|
||||
// TODO: Maybe use a different ItemKey?
|
||||
ItemKey::Tool(id.to_owned())
|
||||
} else {
|
||||
ItemKey::Empty
|
||||
}
|
||||
},
|
||||
}
|
||||
},
|
||||
@ -59,7 +64,13 @@ impl<T: ItemDesc> From<&T> for ItemKey {
|
||||
ItemKind::Glider(Glider { kind, .. }) => ItemKey::Glider(kind.clone()),
|
||||
ItemKind::Armor(Armor { kind, .. }) => ItemKey::Armor(kind.clone()),
|
||||
ItemKind::Utility { kind, .. } => ItemKey::Utility(*kind),
|
||||
ItemKind::Consumable { .. } => ItemKey::Consumable(item_definition_id.to_owned()),
|
||||
ItemKind::Consumable { .. } => {
|
||||
if let Some(id) = item_definition_id.raw() {
|
||||
ItemKey::Consumable(id.to_owned())
|
||||
} else {
|
||||
ItemKey::Empty
|
||||
}
|
||||
},
|
||||
ItemKind::Throwable { kind, .. } => ItemKey::Throwable(*kind),
|
||||
ItemKind::Ingredient { kind, .. } => ItemKey::Ingredient(kind.clone()),
|
||||
ItemKind::TagExamples { item_ids } => ItemKey::TagExamples(
|
||||
|
@ -379,7 +379,7 @@ pub enum ItemName {
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum ItemBase {
|
||||
Raw(Arc<ItemDef>),
|
||||
Simple(Arc<ItemDef>),
|
||||
Modular(modular::ModularBase),
|
||||
}
|
||||
|
||||
@ -392,7 +392,7 @@ impl Serialize for ItemBase {
|
||||
S: Serializer,
|
||||
{
|
||||
serializer.serialize_str(match self {
|
||||
ItemBase::Raw(item_def) => &item_def.item_definition_id,
|
||||
ItemBase::Simple(item_def) => &item_def.item_definition_id,
|
||||
ItemBase::Modular(mod_base) => mod_base.pseudo_item_id(),
|
||||
})
|
||||
}
|
||||
@ -422,7 +422,7 @@ impl<'de> Deserialize<'de> for ItemBase {
|
||||
if serialized_item_base.starts_with(crate::modular_item_id_prefix!()) {
|
||||
ItemBase::Modular(ModularBase::load_from_pseudo_id(serialized_item_base))
|
||||
} else {
|
||||
ItemBase::Raw(Arc::<ItemDef>::load_expect_cloned(serialized_item_base))
|
||||
ItemBase::Simple(Arc::<ItemDef>::load_expect_cloned(serialized_item_base))
|
||||
},
|
||||
)
|
||||
}
|
||||
@ -435,19 +435,71 @@ impl<'de> Deserialize<'de> for ItemBase {
|
||||
impl ItemBase {
|
||||
fn num_slots(&self) -> u16 {
|
||||
match self {
|
||||
ItemBase::Raw(item_def) => item_def.num_slots(),
|
||||
ItemBase::Simple(item_def) => item_def.num_slots(),
|
||||
ItemBase::Modular(_) => 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn item_definition_id(&self) -> &str {
|
||||
match &self {
|
||||
ItemBase::Raw(item_def) => &item_def.item_definition_id,
|
||||
ItemBase::Modular(mod_base) => mod_base.pseudo_item_id(),
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq, Hash)]
|
||||
pub enum ItemDefinitionId<'a> {
|
||||
Simple(&'a str),
|
||||
Modular {
|
||||
pseudo_base: &'a str,
|
||||
components: Vec<ItemDefinitionId<'a>>,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
|
||||
pub enum ItemDefinitionIdOwned {
|
||||
Simple(String),
|
||||
Modular {
|
||||
pseudo_base: String,
|
||||
components: Vec<ItemDefinitionIdOwned>,
|
||||
},
|
||||
}
|
||||
|
||||
impl ItemDefinitionIdOwned {
|
||||
pub fn as_ref(&self) -> ItemDefinitionId<'_> {
|
||||
match *self {
|
||||
Self::Simple(ref id) => ItemDefinitionId::Simple(id),
|
||||
Self::Modular {
|
||||
ref pseudo_base,
|
||||
ref components,
|
||||
} => ItemDefinitionId::Modular {
|
||||
pseudo_base,
|
||||
components: components.iter().map(|comp| comp.as_ref()).collect(),
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> ItemDefinitionId<'a> {
|
||||
pub fn raw(&self) -> Option<&str> {
|
||||
match self {
|
||||
Self::Simple(id) => Some(id),
|
||||
Self::Modular { .. } => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn to_owned(&self) -> ItemDefinitionIdOwned {
|
||||
match self {
|
||||
Self::Simple(id) => ItemDefinitionIdOwned::Simple(String::from(*id)),
|
||||
Self::Modular {
|
||||
pseudo_base,
|
||||
components,
|
||||
} => ItemDefinitionIdOwned::Modular {
|
||||
pseudo_base: String::from(*pseudo_base),
|
||||
components: components.iter().map(|comp| comp.to_owned()).collect(),
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for ItemDefinitionIdOwned {
|
||||
fn default() -> Self { Self::Simple(String::new()) }
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct ItemDef {
|
||||
#[serde(default)]
|
||||
@ -580,7 +632,7 @@ impl ItemDef {
|
||||
/// please don't rely on this for anything!
|
||||
impl PartialEq for Item {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
if let (ItemBase::Raw(self_def), ItemBase::Raw(other_def)) =
|
||||
if let (ItemBase::Simple(self_def), ItemBase::Simple(other_def)) =
|
||||
(&self.item_base, &other.item_base)
|
||||
{
|
||||
self_def.item_definition_id == other_def.item_definition_id
|
||||
@ -706,7 +758,7 @@ impl Item {
|
||||
let inner_item = if asset.starts_with("veloren.core.pseudo_items.modular") {
|
||||
ItemBase::Modular(ModularBase::load_from_pseudo_id(asset))
|
||||
} else {
|
||||
ItemBase::Raw(Arc::<ItemDef>::load_cloned(asset)?)
|
||||
ItemBase::Simple(Arc::<ItemDef>::load_cloned(asset)?)
|
||||
};
|
||||
// TODO: Get msm and ability_map less hackily
|
||||
let msm = &MaterialStatManifest::load().read();
|
||||
@ -729,7 +781,7 @@ impl Item {
|
||||
.collect();
|
||||
let mut new_item = Item::new_from_item_base(
|
||||
match &self.item_base {
|
||||
ItemBase::Raw(item_def) => ItemBase::Raw(Arc::clone(item_def)),
|
||||
ItemBase::Simple(item_def) => ItemBase::Simple(Arc::clone(item_def)),
|
||||
ItemBase::Modular(mod_base) => ItemBase::Modular(mod_base.clone()),
|
||||
},
|
||||
duplicated_components,
|
||||
@ -844,10 +896,22 @@ impl Item {
|
||||
self.slots.iter_mut().filter_map(mem::take)
|
||||
}
|
||||
|
||||
pub fn item_definition_id(&self) -> &str { self.item_base.item_definition_id() }
|
||||
pub fn item_definition_id(&self) -> ItemDefinitionId<'_> {
|
||||
match &self.item_base {
|
||||
ItemBase::Simple(item_def) => ItemDefinitionId::Simple(&item_def.item_definition_id),
|
||||
ItemBase::Modular(mod_base) => ItemDefinitionId::Modular {
|
||||
pseudo_base: mod_base.pseudo_item_id(),
|
||||
components: self
|
||||
.components
|
||||
.iter()
|
||||
.map(|item| item.item_definition_id())
|
||||
.collect(),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_same_item_def(&self, item_def: &ItemDef) -> bool {
|
||||
if let ItemBase::Raw(self_def) = &self.item_base {
|
||||
if let ItemBase::Simple(self_def) = &self.item_base {
|
||||
self_def.item_definition_id == item_def.item_definition_id
|
||||
} else {
|
||||
false
|
||||
@ -885,7 +949,7 @@ impl Item {
|
||||
|
||||
pub fn name(&self) -> Cow<str> {
|
||||
match &self.item_base {
|
||||
ItemBase::Raw(item_def) => {
|
||||
ItemBase::Simple(item_def) => {
|
||||
if self.components.is_empty() {
|
||||
Cow::Borrowed(&item_def.name)
|
||||
} else {
|
||||
@ -898,7 +962,7 @@ impl Item {
|
||||
|
||||
pub fn description(&self) -> &str {
|
||||
match &self.item_base {
|
||||
ItemBase::Raw(item_def) => &item_def.description,
|
||||
ItemBase::Simple(item_def) => &item_def.description,
|
||||
// TODO: See if James wanted to make description, else leave with none
|
||||
ItemBase::Modular(_) => "",
|
||||
}
|
||||
@ -906,7 +970,7 @@ impl Item {
|
||||
|
||||
pub fn kind(&self) -> Cow<ItemKind> {
|
||||
match &self.item_base {
|
||||
ItemBase::Raw(item_def) => Cow::Borrowed(&item_def.kind),
|
||||
ItemBase::Simple(item_def) => Cow::Borrowed(&item_def.kind),
|
||||
ItemBase::Modular(mod_base) => {
|
||||
// TODO: Try to move further upward
|
||||
let msm = MaterialStatManifest::load().read();
|
||||
@ -919,7 +983,7 @@ impl Item {
|
||||
|
||||
pub fn is_stackable(&self) -> bool {
|
||||
match &self.item_base {
|
||||
ItemBase::Raw(item_def) => item_def.is_stackable(),
|
||||
ItemBase::Simple(item_def) => item_def.is_stackable(),
|
||||
// TODO: Let whoever implements stackable modular items deal with this
|
||||
ItemBase::Modular(_) => false,
|
||||
}
|
||||
@ -933,7 +997,7 @@ impl Item {
|
||||
|
||||
pub fn quality(&self) -> Quality {
|
||||
match &self.item_base {
|
||||
ItemBase::Raw(item_def) => item_def.quality,
|
||||
ItemBase::Simple(item_def) => item_def.quality,
|
||||
ItemBase::Modular(mod_base) => mod_base.compute_quality(self.components()),
|
||||
}
|
||||
}
|
||||
@ -964,7 +1028,7 @@ impl Item {
|
||||
|
||||
pub fn ability_spec(&self) -> Option<Cow<AbilitySpec>> {
|
||||
match &self.item_base {
|
||||
ItemBase::Raw(item_def) => {
|
||||
ItemBase::Simple(item_def) => {
|
||||
item_def.ability_spec.as_ref().map(Cow::Borrowed).or({
|
||||
// If no custom ability set is specified, fall back to abilityset of tool
|
||||
// kind.
|
||||
@ -983,7 +1047,7 @@ impl Item {
|
||||
// iterator?
|
||||
pub fn tags(&self) -> Vec<ItemTag> {
|
||||
match &self.item_base {
|
||||
ItemBase::Raw(item_def) => item_def.tags.to_vec(),
|
||||
ItemBase::Simple(item_def) => item_def.tags.to_vec(),
|
||||
// TODO: Do this properly. It'll probably be important at some point.
|
||||
ItemBase::Modular(mod_base) => mod_base.generate_tags(self.components()),
|
||||
}
|
||||
@ -991,7 +1055,7 @@ impl Item {
|
||||
|
||||
pub fn is_modular(&self) -> bool {
|
||||
match &self.item_base {
|
||||
ItemBase::Raw(_) => false,
|
||||
ItemBase::Simple(_) => false,
|
||||
ItemBase::Modular(_) => true,
|
||||
}
|
||||
}
|
||||
@ -1003,7 +1067,7 @@ impl Item {
|
||||
let ability_map = &AbilityMap::load().read();
|
||||
let msm = &MaterialStatManifest::load().read();
|
||||
Self::new_from_item_base(
|
||||
ItemBase::Raw(Arc::new(ItemDef::create_test_itemdef_from_kind(kind))),
|
||||
ItemBase::Simple(Arc::new(ItemDef::create_test_itemdef_from_kind(kind))),
|
||||
Vec::new(),
|
||||
ability_map,
|
||||
msm,
|
||||
@ -1019,7 +1083,7 @@ pub trait ItemDesc {
|
||||
fn kind(&self) -> Cow<ItemKind>;
|
||||
fn quality(&self) -> Quality;
|
||||
fn num_slots(&self) -> u16;
|
||||
fn item_definition_id(&self) -> &str;
|
||||
fn item_definition_id(&self) -> ItemDefinitionId<'_>;
|
||||
fn tags(&self) -> Vec<ItemTag>;
|
||||
|
||||
fn is_modular(&self) -> bool;
|
||||
@ -1046,7 +1110,7 @@ impl ItemDesc for Item {
|
||||
|
||||
fn num_slots(&self) -> u16 { self.num_slots() }
|
||||
|
||||
fn item_definition_id(&self) -> &str { self.item_definition_id() }
|
||||
fn item_definition_id(&self) -> ItemDefinitionId<'_> { self.item_definition_id() }
|
||||
|
||||
fn tags(&self) -> Vec<ItemTag> { self.tags() }
|
||||
|
||||
@ -1066,7 +1130,9 @@ impl ItemDesc for ItemDef {
|
||||
|
||||
fn num_slots(&self) -> u16 { self.slots }
|
||||
|
||||
fn item_definition_id(&self) -> &str { &self.item_definition_id }
|
||||
fn item_definition_id(&self) -> ItemDefinitionId<'_> {
|
||||
ItemDefinitionId::Simple(&self.item_definition_id)
|
||||
}
|
||||
|
||||
fn tags(&self) -> Vec<ItemTag> { self.tags.to_vec() }
|
||||
|
||||
@ -1097,7 +1163,7 @@ impl<'a, T: ItemDesc + ?Sized> ItemDesc for &'a T {
|
||||
|
||||
fn num_slots(&self) -> u16 { (*self).num_slots() }
|
||||
|
||||
fn item_definition_id(&self) -> &str { (*self).item_definition_id() }
|
||||
fn item_definition_id(&self) -> ItemDefinitionId<'_> { (*self).item_definition_id() }
|
||||
|
||||
fn components(&self) -> &[Item] { (*self).components() }
|
||||
|
||||
|
@ -238,7 +238,13 @@ impl ModularComponent {
|
||||
Self::ToolPrimaryComponent { stats, .. } => {
|
||||
let average_material_mult = components
|
||||
.iter()
|
||||
.filter_map(|comp| msm.0.get(comp.item_definition_id()).copied().zip(Some(1)))
|
||||
.filter_map(|comp| {
|
||||
comp.item_definition_id()
|
||||
.raw()
|
||||
.and_then(|id| msm.0.get(id))
|
||||
.copied()
|
||||
.zip(Some(1))
|
||||
})
|
||||
.reduce(|(stats_a, count_a), (stats_b, count_b)| {
|
||||
(stats_a + stats_b, count_a + count_b)
|
||||
})
|
||||
@ -308,7 +314,7 @@ lazy_static! {
|
||||
if let Ok(items) = Item::new_from_asset_glob(&directory) {
|
||||
items
|
||||
.into_iter()
|
||||
.map(|comp| comp.item_definition_id().to_owned())
|
||||
.filter_map(|comp| Some(comp.item_definition_id().raw()?.to_owned()))
|
||||
.filter_map(|id| Arc::<ItemDef>::load_cloned(&id).ok())
|
||||
.for_each(|comp_def| {
|
||||
if let ItemKind::ModularComponent(ModularComponent::ToolSecondaryComponent { hand_restriction, .. }) = comp_def.kind {
|
||||
@ -378,7 +384,7 @@ pub fn random_weapon(
|
||||
.ok_or(ModularWeaponCreationError::SecondaryComponentNotFound)?
|
||||
.0;
|
||||
Item::new_from_item_base(
|
||||
ItemBase::Raw(Arc::clone(def)),
|
||||
ItemBase::Simple(Arc::clone(def)),
|
||||
Vec::new(),
|
||||
ability_map,
|
||||
msm,
|
||||
@ -441,9 +447,9 @@ pub fn weapon_to_key(mod_weap: impl ItemDesc) -> ModularWeaponKey {
|
||||
.iter()
|
||||
.find_map(|comp| match &*comp.kind() {
|
||||
ItemKind::ModularComponent(ModularComponent::ToolPrimaryComponent { .. }) => {
|
||||
let component_id = comp.item_definition_id().to_owned();
|
||||
let component_id = comp.item_definition_id().raw()?.to_owned();
|
||||
let material_id = comp.components().iter().find_map(|mat| match &*mat.kind() {
|
||||
ItemKind::Ingredient { .. } => Some(mat.item_definition_id().to_owned()),
|
||||
ItemKind::Ingredient { .. } => Some(mat.item_definition_id().raw()?.to_owned()),
|
||||
_ => None,
|
||||
});
|
||||
Some((component_id, material_id))
|
||||
@ -469,7 +475,7 @@ pub fn weapon_component_to_key(
|
||||
components: &[Item],
|
||||
) -> Result<ModularWeaponComponentKey, ModularWeaponComponentKeyError> {
|
||||
match components.iter().find_map(|mat| match &*mat.kind() {
|
||||
ItemKind::Ingredient { .. } => Some(mat.item_definition_id().to_owned()),
|
||||
ItemKind::Ingredient { .. } => Some(mat.item_definition_id().raw()?.to_owned()),
|
||||
_ => None,
|
||||
}) {
|
||||
Some(material_id) => Ok((item_def_id.to_owned(), material_id)),
|
||||
|
@ -23,7 +23,7 @@ pub(super) fn get_test_bag(slots: u16) -> Item {
|
||||
);
|
||||
|
||||
Item::new_from_item_base(
|
||||
ItemBase::Raw(Arc::new(item_def)),
|
||||
ItemBase::Simple(Arc::new(item_def)),
|
||||
Vec::new(),
|
||||
&AbilityMap::load().read(),
|
||||
&MaterialStatManifest::load().read(),
|
||||
|
@ -135,7 +135,7 @@ impl Recipe {
|
||||
let (item_def, quantity) = &self.output;
|
||||
|
||||
let crafted_item = Item::new_from_item_base(
|
||||
ItemBase::Raw(Arc::clone(item_def)),
|
||||
ItemBase::Simple(Arc::clone(item_def)),
|
||||
components,
|
||||
ability_map,
|
||||
msm,
|
||||
@ -659,7 +659,7 @@ impl ComponentRecipe {
|
||||
.iter()
|
||||
.map(|item_def| {
|
||||
Item::new_from_item_base(
|
||||
ItemBase::Raw(Arc::clone(item_def)),
|
||||
ItemBase::Simple(Arc::clone(item_def)),
|
||||
Vec::new(),
|
||||
ability_map,
|
||||
msm,
|
||||
@ -667,7 +667,7 @@ impl ComponentRecipe {
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
Item::new_from_item_base(
|
||||
ItemBase::Raw(Arc::clone(item_def)),
|
||||
ItemBase::Simple(Arc::clone(item_def)),
|
||||
components,
|
||||
ability_map,
|
||||
msm,
|
||||
|
@ -29,8 +29,8 @@ pub struct StaticData {
|
||||
pub recover_duration: Duration,
|
||||
/// Inventory slot to use item from
|
||||
pub inv_slot: InvSlotId,
|
||||
/// Item definition id, used to verify that slot still has the correct item
|
||||
pub item_definition_id: String,
|
||||
/// Item hash, used to verify that slot still has the correct item
|
||||
pub item_hash: u64,
|
||||
/// Kind of item used
|
||||
pub item_kind: ItemUseKind,
|
||||
/// Had weapon wielded
|
||||
@ -213,7 +213,7 @@ fn use_item(data: &JoinData, output_events: &mut OutputEvents, state: &Data) {
|
||||
.inventory
|
||||
.and_then(|inv| inv.get(state.static_data.inv_slot))
|
||||
.map_or(false, |item| {
|
||||
item.item_definition_id() == state.static_data.item_definition_id
|
||||
item.item_hash() == state.static_data.item_hash
|
||||
});
|
||||
if item_is_same {
|
||||
// Create inventory manipulation event
|
||||
|
@ -714,7 +714,7 @@ pub fn handle_manipulate_loadout(
|
||||
recover_duration,
|
||||
inv_slot,
|
||||
item_kind,
|
||||
item_definition_id: item.item_definition_id().to_string(),
|
||||
item_hash: item.item_hash(),
|
||||
was_wielded: matches!(data.character, CharacterState::Wielding(_)),
|
||||
was_sneak: data.character.is_stealthy(),
|
||||
},
|
||||
|
@ -1,7 +1,9 @@
|
||||
use std::cmp::Ordering;
|
||||
|
||||
use crate::{
|
||||
comp::inventory::{slot::InvSlotId, trade_pricing::TradePricing, Inventory},
|
||||
comp::inventory::{
|
||||
item::ItemDefinitionIdOwned, slot::InvSlotId, trade_pricing::TradePricing, Inventory,
|
||||
},
|
||||
terrain::BiomeKind,
|
||||
uid::Uid,
|
||||
};
|
||||
@ -387,7 +389,12 @@ impl SitePrices {
|
||||
.as_ref()
|
||||
.and_then(|ri| {
|
||||
ri.inventory.get(slot).map(|item| {
|
||||
if let Some(vec) = TradePricing::get_materials(&item.name) {
|
||||
if let Some(vec) = item
|
||||
.name
|
||||
.as_ref()
|
||||
.raw()
|
||||
.and_then(TradePricing::get_materials)
|
||||
{
|
||||
vec.iter()
|
||||
.map(|(amount2, material)| {
|
||||
self.values.get(material).copied().unwrap_or_default()
|
||||
@ -409,7 +416,7 @@ impl SitePrices {
|
||||
|
||||
#[derive(Clone, Debug, Default)]
|
||||
pub struct ReducedInventoryItem {
|
||||
pub name: String,
|
||||
pub name: ItemDefinitionIdOwned,
|
||||
pub amount: u32,
|
||||
}
|
||||
|
||||
@ -425,7 +432,7 @@ impl ReducedInventory {
|
||||
.filter(|(_, it)| it.is_some())
|
||||
.map(|(sl, it)| {
|
||||
(sl, ReducedInventoryItem {
|
||||
name: it.as_ref().unwrap().item_definition_id().to_string(),
|
||||
name: it.as_ref().unwrap().item_definition_id().to_owned(),
|
||||
amount: it.as_ref().unwrap().amount(),
|
||||
})
|
||||
})
|
||||
|
@ -177,16 +177,15 @@ pub fn handle_mine_block(
|
||||
if let (Some(tool), Some(uid), Some(exp_reward)) = (
|
||||
tool,
|
||||
state.ecs().uid_from_entity(entity),
|
||||
RESOURCE_EXPERIENCE_MANIFEST
|
||||
.read()
|
||||
.0
|
||||
.get(item.item_definition_id()),
|
||||
item.item_definition_id()
|
||||
.raw()
|
||||
.and_then(|id| RESOURCE_EXPERIENCE_MANIFEST.read().0.get(id).copied()),
|
||||
) {
|
||||
let skill_group = SkillGroupKind::Weapon(tool);
|
||||
let outcome_bus = state.ecs().read_resource::<EventBus<Outcome>>();
|
||||
let positions = state.ecs().read_component::<comp::Pos>();
|
||||
if let (Some(level_outcome), Some(pos)) = (
|
||||
skillset.add_experience(skill_group, *exp_reward),
|
||||
skillset.add_experience(skill_group, exp_reward),
|
||||
positions.get(entity),
|
||||
) {
|
||||
outcome_bus.emit_now(Outcome::SkillPointGain {
|
||||
@ -198,7 +197,7 @@ pub fn handle_mine_block(
|
||||
}
|
||||
outcome_bus.emit_now(Outcome::ExpChange {
|
||||
uid,
|
||||
exp: *exp_reward,
|
||||
exp: exp_reward,
|
||||
xp_pools: HashSet::from_iter(vec![skill_group]),
|
||||
});
|
||||
}
|
||||
@ -223,10 +222,10 @@ pub fn handle_mine_block(
|
||||
rng.gen_bool(chance_mod * f64::from(skill_level))
|
||||
};
|
||||
|
||||
let double_gain = (item.item_definition_id().contains("mineral.ore.")
|
||||
&& need_double_ore(&mut rng))
|
||||
|| (item.item_definition_id().contains("mineral.gem.")
|
||||
&& need_double_gem(&mut rng));
|
||||
let double_gain = item.item_definition_id().raw().map_or(false, |id| {
|
||||
(id.contains("mineral.ore.") && need_double_ore(&mut rng))
|
||||
|| (id.contains("mineral.gem.") && need_double_gem(&mut rng))
|
||||
});
|
||||
|
||||
if double_gain {
|
||||
// Ignore non-stackable errors
|
||||
|
@ -678,13 +678,17 @@ pub fn handle_inventory(server: &mut Server, entity: EcsEntity, manip: comp::Inv
|
||||
slots,
|
||||
} => {
|
||||
let component_recipes = default_component_recipe_book().read();
|
||||
let item_id = |slot| inventory.get(slot).map(|item| item.item_definition_id());
|
||||
let item_id = |slot| {
|
||||
inventory
|
||||
.get(slot)
|
||||
.and_then(|item| item.item_definition_id().raw().map(String::from))
|
||||
};
|
||||
if let Some(material_item_id) = item_id(material) {
|
||||
component_recipes
|
||||
.get(&ComponentKey {
|
||||
toolkind,
|
||||
material: String::from(material_item_id),
|
||||
modifier: modifier.and_then(item_id).map(String::from),
|
||||
material: material_item_id,
|
||||
modifier: modifier.and_then(item_id),
|
||||
})
|
||||
.filter(|r| {
|
||||
if let Some(needed_sprite) = r.craft_sprite {
|
||||
|
@ -3,7 +3,7 @@ use common::{
|
||||
comp::{
|
||||
agent::{Agent, AgentEvent},
|
||||
inventory::{
|
||||
item::{tool::AbilityMap, MaterialStatManifest},
|
||||
item::{tool::AbilityMap, ItemDefinitionIdOwned, MaterialStatManifest},
|
||||
Inventory,
|
||||
},
|
||||
},
|
||||
@ -239,7 +239,7 @@ fn commit_trade(ecs: &specs::World, trade: &PendingTrade) -> TradeResult {
|
||||
|
||||
// Hashmap to compute merged stackable stacks, including overflow checks
|
||||
// TODO: add a ComponentKey struct to compare items properly, see issue #1226
|
||||
let mut stackable_items: HashMap<String, TradeQuantities> = HashMap::new();
|
||||
let mut stackable_items: HashMap<ItemDefinitionIdOwned, TradeQuantities> = HashMap::new();
|
||||
for who in [0, 1].iter().cloned() {
|
||||
for (slot, quantity) in trade.offers[who].iter() {
|
||||
let inventory = inventories.get_mut(entities[who]).expect(invmsg);
|
||||
@ -274,7 +274,7 @@ fn commit_trade(ecs: &specs::World, trade: &PendingTrade) -> TradeResult {
|
||||
max_stack_size,
|
||||
trade_quantities,
|
||||
} = stackable_items
|
||||
.entry(item.item_definition_id().to_string())
|
||||
.entry(item.item_definition_id().to_owned())
|
||||
.or_insert_with(|| TradeQuantities::new(item.max_amount()));
|
||||
|
||||
trade_quantities[who].full_stacks += 1;
|
||||
@ -295,7 +295,7 @@ fn commit_trade(ecs: &specs::World, trade: &PendingTrade) -> TradeResult {
|
||||
max_stack_size: _,
|
||||
trade_quantities,
|
||||
} = stackable_items
|
||||
.entry(item.item_definition_id().to_string())
|
||||
.entry(item.item_definition_id().to_owned())
|
||||
.or_insert_with(|| TradeQuantities::new(item.max_amount()));
|
||||
|
||||
trade_quantities[who].quantity_sold += *quantity as u128;
|
||||
@ -338,7 +338,7 @@ fn commit_trade(ecs: &specs::World, trade: &PendingTrade) -> TradeResult {
|
||||
.slots()
|
||||
.flatten()
|
||||
.filter_map(|it| {
|
||||
if it.item_definition_id() == item_id {
|
||||
if it.item_definition_id() == item_id.as_ref() {
|
||||
Some(*max_stack_size as u128 - it.amount() as u128)
|
||||
} else {
|
||||
None
|
||||
|
@ -11,7 +11,7 @@ use common::{
|
||||
character::CharacterId,
|
||||
comp::{
|
||||
inventory::{
|
||||
item::{tool::AbilityMap, Item as VelorenItem, MaterialStatManifest},
|
||||
item::{tool::AbilityMap, Item as VelorenItem, ItemDefinitionId, MaterialStatManifest},
|
||||
loadout::{Loadout, LoadoutError},
|
||||
loadout_builder::LoadoutBuilder,
|
||||
slot::InvSlotId,
|
||||
@ -165,9 +165,14 @@ pub fn convert_items_to_database_items(
|
||||
bfs_queue.push_back((format!("component_{}", i), Some(component), item_id));
|
||||
}
|
||||
|
||||
let persistence_item_id = match item.item_definition_id() {
|
||||
ItemDefinitionId::Simple(id) => id.to_owned(),
|
||||
ItemDefinitionId::Modular { pseudo_base, .. } => pseudo_base.to_owned(),
|
||||
};
|
||||
|
||||
let upsert = ItemModelPair {
|
||||
model: Item {
|
||||
item_definition_id: item.item_definition_id().to_owned(),
|
||||
item_definition_id: persistence_item_id,
|
||||
position,
|
||||
parent_container_item_id,
|
||||
item_id,
|
||||
|
@ -977,8 +977,9 @@ impl<'a> Widget for Crafting<'a> {
|
||||
// }) },
|
||||
RecipeKind::Component(_) => |item| {
|
||||
item.map_or(false, |item| {
|
||||
item.item_definition_id()
|
||||
.starts_with("common.items.crafting_ing.animal_misc")
|
||||
item.item_definition_id().raw().map_or(false, |id| {
|
||||
id.starts_with("common.items.crafting_ing.animal_misc")
|
||||
})
|
||||
})
|
||||
},
|
||||
RecipeKind::Simple => |_| unreachable!(),
|
||||
@ -1099,7 +1100,7 @@ impl<'a> Widget for Crafting<'a> {
|
||||
if let Some(material) = primary_slot
|
||||
.invslot
|
||||
.and_then(|slot| self.inventory.get(slot))
|
||||
.map(|item| String::from(item.item_definition_id()))
|
||||
.and_then(|item| item.item_definition_id().raw().map(String::from))
|
||||
{
|
||||
let component_key = ComponentKey {
|
||||
toolkind,
|
||||
@ -1107,7 +1108,9 @@ impl<'a> Widget for Crafting<'a> {
|
||||
modifier: secondary_slot
|
||||
.invslot
|
||||
.and_then(|slot| self.inventory.get(slot))
|
||||
.map(|item| String::from(item.item_definition_id())),
|
||||
.and_then(|item| {
|
||||
item.item_definition_id().raw().map(String::from)
|
||||
}),
|
||||
};
|
||||
self.client.component_recipe_book().get(&component_key).map(
|
||||
|component_recipe| {
|
||||
@ -1405,14 +1408,14 @@ impl<'a> Widget for Crafting<'a> {
|
||||
RecipeKind::Component(toolkind) => {
|
||||
if let Some(material) = modular_primary_slot
|
||||
.and_then(|slot| self.inventory.get(slot))
|
||||
.map(|item| String::from(item.item_definition_id()))
|
||||
.and_then(|item| item.item_definition_id().raw().map(String::from))
|
||||
{
|
||||
let component_key = ComponentKey {
|
||||
toolkind,
|
||||
material,
|
||||
modifier: modular_secondary_slot
|
||||
.and_then(|slot| self.inventory.get(slot))
|
||||
.map(|item| String::from(item.item_definition_id())),
|
||||
.and_then(|item| item.item_definition_id().raw().map(String::from)),
|
||||
};
|
||||
if let Some(comp_recipe) =
|
||||
self.client.component_recipe_book().get(&component_key)
|
||||
@ -1491,42 +1494,54 @@ impl<'a> Widget for Crafting<'a> {
|
||||
for (i, (recipe_input, amount)) in ingredients.enumerate() {
|
||||
let item_def = match recipe_input {
|
||||
RecipeInput::Item(item_def) => Arc::clone(item_def),
|
||||
RecipeInput::Tag(tag) | RecipeInput::TagSameItem(tag) => {
|
||||
Arc::<ItemDef>::load_expect_cloned(
|
||||
self.inventory
|
||||
.slots()
|
||||
.find_map(|slot| {
|
||||
slot.as_ref().and_then(|item| {
|
||||
if item.matches_recipe_input(recipe_input, amount) {
|
||||
Some(item.item_definition_id())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
})
|
||||
.or_else(|| tag.exemplar_identifier())
|
||||
.unwrap_or("common.items.weapons.empty.empty"),
|
||||
)
|
||||
},
|
||||
RecipeInput::ListSameItem(item_defs) => Arc::<ItemDef>::load_expect_cloned(
|
||||
self.inventory
|
||||
.slots()
|
||||
.find_map(|slot| {
|
||||
slot.as_ref().and_then(|item| {
|
||||
if item.matches_recipe_input(recipe_input, amount) {
|
||||
Some(item.item_definition_id())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
RecipeInput::Tag(tag) | RecipeInput::TagSameItem(tag) => self
|
||||
.inventory
|
||||
.slots()
|
||||
.find_map(|slot| {
|
||||
slot.as_ref().and_then(|item| {
|
||||
if item.matches_recipe_input(recipe_input, amount) {
|
||||
item.item_definition_id()
|
||||
.raw()
|
||||
.map(Arc::<ItemDef>::load_expect_cloned)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.unwrap_or_else(|| {
|
||||
item_defs
|
||||
.first()
|
||||
.map(|i| i.item_definition_id())
|
||||
.unwrap_or_else(|| "common.items.weapons.empty.empty")
|
||||
}),
|
||||
),
|
||||
})
|
||||
.unwrap_or_else(|| {
|
||||
Arc::<ItemDef>::load_expect_cloned(
|
||||
tag.exemplar_identifier()
|
||||
.unwrap_or("common.items.weapons.empty.empty"),
|
||||
)
|
||||
}),
|
||||
RecipeInput::ListSameItem(item_defs) => self
|
||||
.inventory
|
||||
.slots()
|
||||
.find_map(|slot| {
|
||||
slot.as_ref().and_then(|item| {
|
||||
if item.matches_recipe_input(recipe_input, amount) {
|
||||
item.item_definition_id()
|
||||
.raw()
|
||||
.map(Arc::<ItemDef>::load_expect_cloned)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
})
|
||||
.unwrap_or_else(|| {
|
||||
item_defs
|
||||
.first()
|
||||
.and_then(|i| {
|
||||
i.item_definition_id()
|
||||
.raw()
|
||||
.map(Arc::<ItemDef>::load_expect_cloned)
|
||||
})
|
||||
.unwrap_or_else(|| {
|
||||
Arc::<ItemDef>::load_expect_cloned(
|
||||
"common.items.weapons.empty.empty",
|
||||
)
|
||||
})
|
||||
}),
|
||||
};
|
||||
|
||||
// Grey color for images and text if their amount is too low to craft the
|
||||
|
@ -3689,8 +3689,10 @@ impl Hud {
|
||||
false,
|
||||
);
|
||||
if let Some(item) = inventory.get(slot) {
|
||||
if let Some(materials) =
|
||||
TradePricing::get_materials(item.item_definition_id())
|
||||
if let Some(materials) = item
|
||||
.item_definition_id()
|
||||
.raw()
|
||||
.and_then(TradePricing::get_materials)
|
||||
{
|
||||
let unit_price: f32 = materials
|
||||
.iter()
|
||||
|
@ -15,7 +15,7 @@ use common::{
|
||||
item::{
|
||||
armor::{Armor, ArmorKind},
|
||||
item_key::ItemKey,
|
||||
modular, Item, ItemKind,
|
||||
modular, Item, ItemDefinitionId, ItemKind,
|
||||
},
|
||||
CharacterState,
|
||||
},
|
||||
@ -221,12 +221,11 @@ impl CharacterCacheKey {
|
||||
})
|
||||
},
|
||||
tool: if are_tools_visible {
|
||||
let tool_key_from_item = |item: &Item| {
|
||||
if item.is_modular() {
|
||||
let tool_key_from_item = |item: &Item| match item.item_definition_id() {
|
||||
ItemDefinitionId::Simple(id) => ToolKey::Tool(String::from(id)),
|
||||
ItemDefinitionId::Modular { .. } => {
|
||||
ToolKey::Modular(modular::weapon_to_key(item))
|
||||
} else {
|
||||
ToolKey::Tool(item.item_definition_id().to_owned())
|
||||
}
|
||||
},
|
||||
};
|
||||
Some(CharacterToolKey {
|
||||
active: inventory
|
||||
|
@ -8,7 +8,7 @@ use std::{cell::RefCell, collections::HashSet, rc::Rc, result::Result, sync::Arc
|
||||
use mumble_link::SharedLink;
|
||||
use ordered_float::OrderedFloat;
|
||||
use specs::{Join, WorldExt};
|
||||
use tracing::{error, info, warn};
|
||||
use tracing::{error, info, trace, warn};
|
||||
use vek::*;
|
||||
|
||||
use client::{self, Client};
|
||||
@ -18,7 +18,7 @@ use common::{
|
||||
comp::{
|
||||
inventory::slot::{EquipSlot, Slot},
|
||||
invite::InviteKind,
|
||||
item::{tool::ToolKind, ItemDef, ItemDesc},
|
||||
item::{tool::ToolKind, ItemDef, ItemDefinitionId, ItemDesc},
|
||||
ChatMsg, ChatType, InputKind, InventoryUpdateEvent, Pos, Stats, UtteranceKind, Vel,
|
||||
},
|
||||
consts::MAX_MOUNT_RANGE,
|
||||
@ -250,8 +250,8 @@ impl SessionState {
|
||||
self.hud.add_failed_entity_pickup(entity);
|
||||
}
|
||||
},
|
||||
InventoryUpdateEvent::Collected(item) => {
|
||||
match Arc::<ItemDef>::load_cloned(item.item_definition_id()) {
|
||||
InventoryUpdateEvent::Collected(item) => match item.item_definition_id() {
|
||||
ItemDefinitionId::Simple(id) => match Arc::<ItemDef>::load_cloned(id) {
|
||||
Result::Ok(item_def) => {
|
||||
self.hud.new_loot_message(LootMessage {
|
||||
item: item_def,
|
||||
@ -261,11 +261,14 @@ impl SessionState {
|
||||
Result::Err(e) => {
|
||||
warn!(
|
||||
?e,
|
||||
"Item not present on client: {}",
|
||||
"Item not present on client: {:?}",
|
||||
item.item_definition_id()
|
||||
);
|
||||
},
|
||||
}
|
||||
},
|
||||
ItemDefinitionId::Modular { .. } => {
|
||||
trace!("Modular items not currently supported for loot messages.")
|
||||
},
|
||||
},
|
||||
_ => {},
|
||||
};
|
||||
@ -1445,7 +1448,9 @@ impl PlayState for SessionState {
|
||||
.inventories()
|
||||
.get(client.entity())
|
||||
.and_then(|inv| inv.get(slot))
|
||||
.map(|item| String::from(item.item_definition_id()))
|
||||
.and_then(|item| {
|
||||
item.item_definition_id().raw().map(String::from)
|
||||
})
|
||||
};
|
||||
if let Some(material_id) = item_id(material) {
|
||||
let key = recipe::ComponentKey {
|
||||
|
@ -1316,8 +1316,10 @@ impl<'a> Widget for ItemTooltip<'a> {
|
||||
}
|
||||
|
||||
// Price display
|
||||
if let Some((buy, sell, factor)) =
|
||||
util::price_desc(self.prices, item.item_definition_id(), i18n)
|
||||
if let Some((buy, sell, factor)) = item
|
||||
.item_definition_id()
|
||||
.raw()
|
||||
.and_then(|id| util::price_desc(self.prices, id, i18n))
|
||||
{
|
||||
widget::Text::new(&buy)
|
||||
.x_align_to(state.ids.item_frame, conrod_core::position::Align::Start)
|
||||
@ -1413,11 +1415,11 @@ impl<'a> Widget for ItemTooltip<'a> {
|
||||
};
|
||||
|
||||
// Price
|
||||
let price_h: f64 = if let Some((buy, sell, _)) = util::price_desc(
|
||||
self.prices,
|
||||
item.item_definition_id(),
|
||||
self.localized_strings,
|
||||
) {
|
||||
let price_h: f64 = if let Some((buy, sell, _)) = item
|
||||
.item_definition_id()
|
||||
.raw()
|
||||
.and_then(|id| util::price_desc(self.prices, 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)
|
||||
let tt_hint_1 = self.localized_strings.get("hud.trade.tooltip_hint_1");
|
||||
|
Loading…
Reference in New Issue
Block a user