Addressed more comments on MR.

This commit is contained in:
Sam 2021-11-22 19:47:24 -05:00
parent 259db56ca6
commit 524845b661
17 changed files with 344 additions and 229 deletions

View File

@ -12,12 +12,36 @@
(1, Asset("common.loadout.world.traveler0.rawhide")),
]),
active_hands: ([
(1, "common.items.weapons.sword.bronze-0"),
(1, "common.items.weapons.axe.bronze_axe-0"),
(1, "common.items.weapons.hammer.bronze_hammer-0"),
(1, "common.items.weapons.bow.bone-0"),
(1, "common.items.weapons.staff.fiery_wishing_rod"),
(1, "common.items.weapons.sceptre.root_green0"),
(1, (
tool: Sword,
material: Bronze,
hands: None,
)),
(1, (
tool: Axe,
material: Bronze,
hands: None,
)),
(1, (
tool: Hammer,
material: Bronze,
hands: None,
)),
(1, (
tool: Bow,
material: Wood,
hands: None,
)),
(1, (
tool: Staff,
material: Wood,
hands: None,
)),
(1, (
tool: Sceptre,
material: Wood,
hands: None,
)),
], None),
)),
items: [

View File

@ -12,12 +12,36 @@
(1, Asset("common.loadout.world.traveler1.wool")),
]),
active_hands: ([
(1, "common.items.weapons.sword.iron-0"),
(1, "common.items.weapons.axe.iron_axe-0"),
(1, "common.items.weapons.hammer.iron_hammer-0"),
(1, "common.items.weapons.bow.hardwood-0"),
(1, "common.items.weapons.staff.heated_arm"),
(1, "common.items.weapons.sceptre.staff_nature"),
(1, (
tool: Sword,
material: Iron,
hands: None,
)),
(1, (
tool: Axe,
material: Iron,
hands: None,
)),
(1, (
tool: Hammer,
material: Iron,
hands: None,
)),
(1, (
tool: Bow,
material: Bamboo,
hands: None,
)),
(1, (
tool: Staff,
material: Bamboo,
hands: None,
)),
(1, (
tool: Sceptre,
material: Bamboo,
hands: None,
)),
], None),
)),
items: [

View File

@ -17,18 +17,66 @@
(1, Asset("common.loadout.world.traveler2.carapace")),
]),
active_hands: ([
(1, "common.items.weapons.sword.steel-0"),
(1, "common.items.weapons.axe.steel_axe-0"),
(1, "common.items.weapons.hammer.steel_hammer-0"),
(1, "common.items.weapons.bow.metal-0"),
(1, "common.items.weapons.staff.golden_khakkara"),
(1, "common.items.weapons.sceptre.totem_green"),
(1, "common.items.weapons.sword.cobalt-0"),
(1, "common.items.weapons.axe.cobalt_axe-0"),
(1, "common.items.weapons.hammer.cobalt_hammer-0"),
(1, "common.items.weapons.bow.frostwood-0"),
(1, "common.items.weapons.staff.aurora"),
(1, "common.items.weapons.sceptre.loops0"),
(1, (
tool: Sword,
material: Steel,
hands: None,
)),
(1, (
tool: Axe,
material: Steel,
hands: None,
)),
(1, (
tool: Hammer,
material: Steel,
hands: None,
)),
(1, (
tool: Bow,
material: Hardwood,
hands: None,
)),
(1, (
tool: Staff,
material: Hardwood,
hands: None,
)),
(1, (
tool: Sceptre,
material: Hardwood,
hands: None,
)),
(1, (
tool: Sword,
material: Cobalt,
hands: None,
)),
(1, (
tool: Axe,
material: Cobalt,
hands: None,
)),
(1, (
tool: Hammer,
material: Cobalt,
hands: None,
)),
(1, (
tool: Bow,
material: Ironwood,
hands: None,
)),
(1, (
tool: Staff,
material: Ironwood,
hands: None,
)),
(1, (
tool: Sceptre,
material: Ironwood,
hands: None,
)),
], None),
)),
items: [

View File

@ -17,18 +17,41 @@
(1, Asset("common.loadout.world.traveler3.dragonscale")),
]),
active_hands: ([
(2, "common.items.weapons.sword.bloodsteel-0"),
(2, "common.items.weapons.axe.bloodsteel_axe-0"),
(2, "common.items.weapons.hammer.runic_hammer"),
(2, "common.items.weapons.bow.eldwood-0"),
(2, "common.items.weapons.staff.ruby_rod"),
(2, "common.items.weapons.sceptre.emerald"),
(2, (
tool: Sword,
material: Orichalcum,
hands: None,
)),
(2, (
tool: Axe,
material: Orichalcum,
hands: None,
)),
(2, (
tool: Hammer,
material: Orichalcum,
hands: None,
)),
(2, (
tool: Bow,
material: Eldwood,
hands: None,
)),
(2, (
tool: Staff,
material: Eldwood,
hands: None,
)),
(2, (
tool: Sceptre,
material: Eldwood,
hands: None,
)),
(2, "common.items.weapons.sword.caladbolg"),
(2, "common.items.weapons.hammer.mjolnir"),
(2, "common.items.weapons.axe.parashu"),
(2, "common.items.weapons.bow.sagitta"),
(1, "common.items.weapons.staff.phoenix"),
(1, "common.items.weapons.staff.laevateinn"),
(2, "common.items.weapons.staff.laevateinn"),
(1, "common.items.weapons.sceptre.root_evil"),
(1, "common.items.weapons.sceptre.caduceus"),
], None),

View File

@ -1864,7 +1864,7 @@
craft_sprite: Some(CraftingBench),
),
"winged coronet": (
output: ("common.items.armor.misc.head.winged_coronet", 1, false),
output: ("common.items.armor.misc.head.winged_coronet", 1),
inputs: [
(Item("common.items.mineral.gem.emerald"), 1, false),
(Item("common.items.mineral.ingot.gold"), 4, false),

View File

@ -36,11 +36,22 @@ impl<T: ItemDesc> From<&T> for ItemKey {
ItemKey::Tool(item_definition_id.to_owned())
}
},
ItemKind::ModularComponent(_) => {
match modular::weapon_component_to_key(item_desc) {
Ok(key) => ItemKey::ModularWeaponComponent(key),
// TODO: Maybe use a different ItemKey?
Err(_) => 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()),
}
},
ModularComponent::ToolSecondaryComponent { .. } => {
ItemKey::Tool(item_definition_id.to_owned())
},
}
},
ItemKind::Lantern(Lantern { kind, .. }) => ItemKey::Lantern(kind.clone()),

View File

@ -82,6 +82,10 @@ pub enum Quality {
Debug, // Red
}
impl Quality {
pub const MIN: Self = Self::Low;
}
pub trait TagExampleInfo {
fn name(&self) -> &str;
/// What item to show in the crafting hud if the player has nothing with the
@ -379,20 +383,19 @@ where
{
serializer.serialize_str(match field {
ItemBase::Raw(item_def) => &item_def.item_definition_id,
// TODO: Encode this data somehow
ItemBase::Modular(mod_base) => mod_base.pseudo_item_id(),
})
}
// Custom de-serialization for ItemDef to retrieve the ItemDef from assets using
// its asset specifier (item_definition_id)
// Custom de-serialization for ItemBase to retrieve the ItemBase from assets
// using its asset specifier (item_definition_id)
fn deserialize_item_base<'de, D>(deserializer: D) -> Result<ItemBase, D::Error>
where
D: de::Deserializer<'de>,
{
struct ItemDefStringVisitor;
struct ItemBaseStringVisitor;
impl<'de> de::Visitor<'de> for ItemDefStringVisitor {
impl<'de> de::Visitor<'de> for ItemBaseStringVisitor {
type Value = ItemBase;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
@ -413,7 +416,7 @@ where
}
}
deserializer.deserialize_str(ItemDefStringVisitor)
deserializer.deserialize_str(ItemBaseStringVisitor)
}
#[derive(Clone, Debug, Serialize, Deserialize)]
@ -581,6 +584,7 @@ impl PartialEq for Item {
(&self.item_base, &other.item_base)
{
self_def.item_definition_id == other_def.item_definition_id
&& self.components == other.components
} else {
false
}
@ -592,6 +596,15 @@ impl assets::Compound for ItemDef {
cache: &assets::AssetCache<S>,
specifier: &str,
) -> Result<Self, BoxedError> {
if specifier.starts_with("veloren.core.") {
return Err(format!(
"Attempted to load an asset from a specifier reserved for core veloren functions. \
Specifier: {}",
specifier
)
.into());
}
let RawItemDef {
name,
description,
@ -650,17 +663,10 @@ impl Item {
pub fn new_from_item_base(
inner_item: ItemBase,
input_components: &[Item],
components: Vec<Item>,
ability_map: &AbilityMap,
msm: &MaterialStatManifest,
) -> Self {
let mut components = Vec::new();
components.extend(
input_components
.iter()
.map(|comp| comp.duplicate(ability_map, msm)),
);
let item_hash = {
let mut s = DefaultHasher::new();
inner_item.item_definition_id().hash(&mut s);
@ -684,8 +690,12 @@ impl Item {
/// Creates a new instance of an `Item` from the provided asset identifier
/// Panics if the asset does not exist.
pub fn new_from_asset_expect(asset_specifier: &str) -> Self {
let err_string = format!("Expected asset to exist: {}", asset_specifier);
Item::new_from_asset(asset_specifier).expect(&err_string)
Item::new_from_asset(asset_specifier).unwrap_or_else(|err| {
panic!(
"Expected asset to exist: {}, instead got error {:?}",
asset_specifier, err
);
})
}
/// Creates a Vec containing one of each item that matches the provided
@ -709,7 +719,7 @@ impl Item {
let ability_map = AbilityMap::default();
Ok(Item::new_from_item_base(
inner_item,
&[],
Vec::new(),
&ability_map,
&msm,
))
@ -718,12 +728,17 @@ impl Item {
/// Duplicates an item, creating an exact copy but with a new item ID
#[must_use]
pub fn duplicate(&self, ability_map: &AbilityMap, msm: &MaterialStatManifest) -> Self {
let duplicated_components = self
.components
.iter()
.map(|comp| comp.duplicate(ability_map, msm))
.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::Modular(mod_base) => ItemBase::Modular(mod_base.duplicate()),
ItemBase::Modular(mod_base) => ItemBase::Modular(mod_base.clone()),
},
&self.components,
duplicated_components,
ability_map,
msm,
);
@ -812,9 +827,6 @@ impl Item {
ability_map: &AbilityMap,
msm: &MaterialStatManifest,
) {
// TODO: hook for typechecking (not needed atm if this is only used by DB
// persistence, but will definitely be needed once enhancement slots are
// added to prevent putting a sword into another sword)
self.components.push(component);
// adding a component changes the stats, so recalculate the ItemConfig
self.update_item_config(ability_map, msm);
@ -981,7 +993,7 @@ impl Item {
pub fn create_test_item_from_kind(kind: ItemKind) -> Self {
Self::new_from_item_base(
ItemBase::Raw(Arc::new(ItemDef::create_test_itemdef_from_kind(kind))),
&[],
Vec::new(),
&Default::default(),
&Default::default(),
)
@ -1056,7 +1068,7 @@ impl Component for Item {
type Storage = DerefFlaggedStorage<Self, IdvStorage<Self>>;
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct ItemDrop(pub Item);
impl Component for ItemDrop {

View File

@ -15,12 +15,6 @@ pub enum ModularBase {
}
impl ModularBase {
pub(super) fn duplicate(&self) -> Self {
match self {
ModularBase::Tool => ModularBase::Tool,
}
}
// DO NOT CHANGE. THIS IS A PERSISTENCE RELATED FUNCTION. MUST MATCH THE
// FUNCTION BELOW.
pub fn pseudo_item_id(&self) -> &str {
@ -106,13 +100,16 @@ impl ModularBase {
let material_name = comp
.components()
.iter()
.find_map(|mat| match &*mat.kind() {
ItemKind::Ingredient { descriptor, .. } => {
Some(descriptor.to_owned())
.find_map(|mat| match mat.kind() {
Cow::Owned(ItemKind::Ingredient { descriptor, .. }) => {
Some(Cow::Owned(descriptor))
},
Cow::Borrowed(ItemKind::Ingredient { descriptor, .. }) => {
Some(Cow::Borrowed(descriptor.as_str()))
},
_ => None,
})
.unwrap_or_else(|| "Modular".to_owned());
.unwrap_or_else(|| "Modular".into());
Some(format!("{} {}", material_name, weapon_name))
},
_ => None,
@ -126,7 +123,7 @@ impl ModularBase {
pub fn compute_quality(&self, components: &[Item]) -> Quality {
components
.iter()
.fold(Quality::Low, |a, b| a.max(b.quality()))
.fold(Quality::MIN, |a, b| a.max(b.quality()))
}
pub fn ability_spec(&self, components: &[Item]) -> Option<Cow<AbilitySpec>> {
@ -165,26 +162,15 @@ impl ModularComponent {
) -> Option<tool::Stats> {
match self {
Self::ToolPrimaryComponent { stats, .. } => {
let mut material_multipliers = Vec::new();
for component in components.iter() {
if let Some(tool_stats) = msm.0.get(component.item_definition_id()) {
material_multipliers.push(*tool_stats);
}
}
let average_material_mult = components
.iter()
.filter_map(|comp| msm.0.get(comp.item_definition_id()).copied().zip(Some(1)))
.reduce(|(stats_a, count_a), (stats_b, count_b)| {
(stats_a + stats_b, count_a + count_b)
})
.map_or_else(tool::Stats::one, |(stats_sum, count)| stats_sum / count);
// Take the average of the material multipliers
let material_mult = if !material_multipliers.is_empty() {
let mut average_mult = tool::Stats::zero();
for stat in material_multipliers.iter() {
average_mult += *stat;
}
average_mult /= material_multipliers.len();
average_mult
} else {
tool::Stats::one()
};
Some(*stats * material_mult)
Some(*stats * average_material_mult)
},
Self::ToolSecondaryComponent { stats, .. } => Some(*stats),
}
@ -208,8 +194,8 @@ lazy_static! {
let mut component_pool = HashMap::new();
// Load recipe book (done to check that material is valid for a particular component)
let recipe::RawRecipeBook(recipes) =
recipe::RawRecipeBook::load_expect_cloned("common.recipe_book");
let recipe_book = recipe::RawRecipeBook::load_expect("common.recipe_book");
let recipes = &recipe_book.read().0;
const ASSET_PREFIX: &str = "common.items.crafting_ing.modular.primary";
@ -309,59 +295,54 @@ pub fn random_weapon(
let material = Item::new_from_asset_expect(material_id);
let primary_components = PRIMARY_COMPONENT_POOL
.get(&(tool, material_id.to_owned()))
.map_or(Vec::new(), |components| {
components
.iter()
.filter(|(_def, hand)| match (hand_restriction, hand) {
(Some(restriction), Some(hand)) => restriction == *hand,
(None, _) | (_, None) => true,
})
.map(|entry| (1.0, entry))
.collect::<Vec<_>>()
});
.into_iter()
.flatten()
.filter(|(_def, hand)| match (hand_restriction, hand) {
(Some(restriction), Some(hand)) => restriction == *hand,
(None, _) | (_, None) => true,
})
.collect::<Vec<_>>();
let (primary_component, hand_restriction) = {
let (def, hand) = primary_components
.choose(&mut rng)
.ok_or(ModularWeaponCreationError::PrimaryComponentNotFound)?
.1;
.ok_or(ModularWeaponCreationError::PrimaryComponentNotFound)?;
let comp = Item::new_from_item_base(
ItemBase::Raw(Arc::clone(def)),
&[material],
vec![material],
&ability_map,
&msm,
);
(comp, hand_restriction.or(*hand))
};
let secondary_components =
SECONDARY_COMPONENT_POOL
.get(&tool)
.map_or(Vec::new(), |components| {
components
.iter()
.filter(|(_def, hand)| match (hand_restriction, hand) {
(Some(restriction), Some(hand)) => restriction == *hand,
(None, _) | (_, None) => true,
})
.map(|entry| (1.0, entry))
.collect::<Vec<_>>()
});
let secondary_components = SECONDARY_COMPONENT_POOL
.get(&tool)
.into_iter()
.flatten()
.filter(|(_def, hand)| match (hand_restriction, hand) {
(Some(restriction), Some(hand)) => restriction == *hand,
(None, _) | (_, None) => true,
})
.collect::<Vec<_>>();
let secondary_component = {
let def = &secondary_components
.choose(&mut rng)
.ok_or(ModularWeaponCreationError::SecondaryComponentNotFound)?
.1
.0;
Item::new_from_item_base(ItemBase::Raw(Arc::clone(def)), &[], &ability_map, &msm)
Item::new_from_item_base(
ItemBase::Raw(Arc::clone(def)),
Vec::new(),
&ability_map,
&msm,
)
};
// Create modular weapon
let components = vec![primary_component, secondary_component];
Ok(Item::new_from_item_base(
ItemBase::Modular(ModularBase::Tool),
&components,
vec![primary_component, secondary_component],
&ability_map,
&msm,
))
@ -407,29 +388,17 @@ pub type ModularWeaponComponentKey = (String, String);
pub enum ModularWeaponComponentKeyError {
MaterialNotFound,
NotMainComponent,
}
pub fn weapon_component_to_key(
mod_weap_comp: &dyn ItemDesc,
item_def_id: &str,
components: &[Item],
) -> Result<ModularWeaponComponentKey, ModularWeaponComponentKeyError> {
match if let ItemKind::ModularComponent(ModularComponent::ToolPrimaryComponent { .. }) =
&*mod_weap_comp.kind()
{
let component_id = mod_weap_comp.item_definition_id().to_owned();
let material_id = mod_weap_comp
.components()
.iter()
.find_map(|mat| match &*mat.kind() {
ItemKind::Ingredient { .. } => Some(mat.item_definition_id().to_owned()),
_ => None,
});
Some((component_id, material_id))
} else {
None
} {
Some((component_id, Some(material_id))) => Ok((component_id, material_id)),
Some((_component_id, None)) => Err(ModularWeaponComponentKeyError::MaterialNotFound),
None => Err(ModularWeaponComponentKeyError::NotMainComponent),
match components.iter().find_map(|mat| match &*mat.kind() {
ItemKind::Ingredient { .. } => Some(mat.item_definition_id().to_owned()),
_ => None,
}) {
Some(material_id) => Ok((item_def_id.to_owned(), material_id)),
None => Err(ModularWeaponComponentKeyError::MaterialNotFound),
}
}

View File

@ -8,7 +8,7 @@ use crate::{
use hashbrown::HashMap;
use serde::{Deserialize, Serialize};
use std::{
ops::{AddAssign, DivAssign, Mul, MulAssign, Sub},
ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Sub},
time::Duration,
};
@ -139,28 +139,39 @@ impl Asset for Stats {
const EXTENSION: &'static str = "ron";
}
impl AddAssign<Stats> for Stats {
fn add_assign(&mut self, other: Stats) {
self.equip_time_secs += other.equip_time_secs;
self.power += other.power;
self.effect_power += other.effect_power;
self.speed += other.speed;
self.crit_chance += other.crit_chance;
self.range += other.range;
self.energy_efficiency += other.energy_efficiency;
self.buff_strength += other.buff_strength;
impl Add<Stats> for Stats {
type Output = Self;
fn add(self, other: Self) -> Self {
Self {
equip_time_secs: self.equip_time_secs + other.equip_time_secs,
power: self.power + other.power,
effect_power: self.effect_power + other.effect_power,
speed: self.speed + other.speed,
crit_chance: self.crit_chance + other.crit_chance,
range: self.range + other.range,
energy_efficiency: self.energy_efficiency + other.energy_efficiency,
buff_strength: self.buff_strength + other.buff_strength,
}
}
}
impl MulAssign<Stats> for Stats {
fn mul_assign(&mut self, other: Stats) {
self.equip_time_secs *= other.equip_time_secs;
self.power *= other.power;
self.effect_power *= other.effect_power;
self.speed *= other.speed;
self.crit_chance *= other.crit_chance;
self.range *= other.range;
self.energy_efficiency *= other.energy_efficiency;
self.buff_strength *= other.buff_strength;
impl AddAssign<Stats> for Stats {
fn add_assign(&mut self, other: Stats) { *self = *self + other; }
}
impl Sub<Stats> for Stats {
type Output = Self;
fn sub(self, other: Self) -> Self::Output {
Self {
equip_time_secs: self.equip_time_secs - other.equip_time_secs,
power: self.power - other.power,
effect_power: self.effect_power - other.effect_power,
speed: self.speed - other.speed,
crit_chance: self.crit_chance - other.crit_chance,
range: self.range - other.range,
energy_efficiency: self.range - other.energy_efficiency,
buff_strength: self.buff_strength - other.buff_strength,
}
}
}
impl Mul<Stats> for Stats {
@ -179,35 +190,29 @@ impl Mul<Stats> for Stats {
}
}
}
impl DivAssign<usize> for Stats {
fn div_assign(&mut self, scalar: usize) {
self.equip_time_secs /= scalar as f32;
self.power /= scalar as f32;
self.effect_power /= scalar as f32;
self.speed /= scalar as f32;
self.crit_chance /= scalar as f32;
self.range /= scalar as f32;
self.energy_efficiency /= scalar as f32;
self.buff_strength /= scalar as f32;
}
impl MulAssign<Stats> for Stats {
fn mul_assign(&mut self, other: Stats) { *self = *self * other; }
}
impl Sub<Stats> for Stats {
impl Div<usize> for Stats {
type Output = Self;
fn sub(self, other: Self) -> Self::Output {
fn div(self, scalar: usize) -> Self {
let scalar = scalar as f32;
Self {
equip_time_secs: self.equip_time_secs - other.equip_time_secs,
power: self.power - other.power,
effect_power: self.effect_power - other.effect_power,
speed: self.speed - other.speed,
crit_chance: self.crit_chance - other.crit_chance,
range: self.range - other.range,
energy_efficiency: self.range - other.energy_efficiency,
buff_strength: self.buff_strength - other.buff_strength,
equip_time_secs: self.equip_time_secs / scalar,
power: self.power / scalar,
effect_power: self.effect_power / scalar,
speed: self.speed / scalar,
crit_chance: self.crit_chance / scalar,
range: self.range / scalar,
energy_efficiency: self.energy_efficiency / scalar,
buff_strength: self.buff_strength / scalar,
}
}
}
impl DivAssign<usize> for Stats {
fn div_assign(&mut self, scalar: usize) { *self = *self / scalar; }
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct MaterialStatManifest(pub HashMap<String, Stats>);
@ -262,11 +267,9 @@ impl Tool {
pub fn base_effect_power(&self) -> f32 { self.stats.effect_power }
pub fn base_speed(&self) -> f32 {
// Has floor to prevent infinite durations being created later down due to a
// divide by zero
self.stats.speed.max(0.1)
}
/// Has floor to prevent infinite durations being created later down due to
/// a divide by zero
pub fn base_speed(&self) -> f32 { self.stats.speed.max(0.1) }
pub fn base_crit_chance(&self) -> f32 { self.stats.crit_chance }

View File

@ -205,7 +205,7 @@ impl Loadout {
/// Returns all items currently equipped that an item of the given ItemKind
/// could replace
pub(super) fn equipped_items_of_kind<'a>(
pub(super) fn equipped_items_replaceable_by<'a>(
&'a self,
item_kind: &'a ItemKind,
) -> impl Iterator<Item = &'a Item> {

View File

@ -72,6 +72,13 @@ impl ItemSpec {
};
Ok(item)
},
ItemSpec::ModularWeapon {
tool,
material,
hands,
} => {
item::modular::random_weapon(*tool, *material, *hands)
},
}
}
@ -157,20 +164,6 @@ impl Hands {
}
Ok(())
},
ItemSpec::ModularWeapon {
tool,
material,
hands,
} => {
let item = item::modular::random_weapon(*tool, *material, *hands)
.expect("Invalid modular weapon");
if !equip_slot.can_hold(&*item.kind()) {
panic!(
"Tried to place {:?} handed {:?} {:?} into {:?}",
hands, material, tool, equip_slot
);
}
},
}
}
}

View File

@ -775,11 +775,11 @@ impl Inventory {
true
}
pub fn equipped_items_of_kind<'a>(
pub fn equipped_items_replaceable_by<'a>(
&'a self,
item_kind: &'a ItemKind,
) -> impl Iterator<Item = &'a Item> {
self.loadout.equipped_items_of_kind(item_kind)
self.loadout.equipped_items_replaceable_by(item_kind)
}
pub fn swap_equipped_weapons(&mut self) { self.loadout.swap_equipped_weapons() }

View File

@ -24,7 +24,7 @@ pub(super) fn get_test_bag(slots: u16) -> Item {
Item::new_from_item_base(
ItemBase::Raw(Arc::new(item_def)),
&[],
Vec::new(),
&AbilityMap::default(),
&MaterialStatManifest::default(),
)

View File

@ -130,7 +130,20 @@ impl<T: AsRef<str>> LootSpec<T> {
tool,
material,
hands,
} => item::modular::random_weapon(*tool, *material, *hands).ok(),
} => item::modular::random_weapon(*tool, *material, *hands).map_or_else(
|e| {
warn!(
?e,
"error while creating modular weapon. Toolkind: {:?}, Material: {:?}, \
Hands: {:?}",
tool,
material,
hands
);
None
},
Option::Some,
),
}
}
}

View File

@ -11,7 +11,7 @@ use crate::{
};
use hashbrown::HashMap;
use serde::{Deserialize, Serialize};
use std::sync::Arc;
use std::{borrow::Cow, sync::Arc};
#[derive(Clone, Debug, Serialize, Deserialize)]
pub enum RecipeInput {
@ -127,7 +127,7 @@ impl Recipe {
let crafted_item = Item::new_from_item_base(
ItemBase::Raw(Arc::clone(item_def)),
&components,
components,
ability_map,
msm,
);
@ -247,15 +247,12 @@ pub fn modular_weapon(
) -> Result<Item, ModularWeaponError> {
use modular::ModularComponent;
// Closure to get inner modular component info from item in a given slot
fn unwrap_modular(inv: &Inventory, slot: InvSlotId) -> Option<ModularComponent> {
if let Some(ItemKind::ModularComponent(mod_comp)) =
inv.get(slot).map(|item| item.kind()).as_deref()
{
// TODO: Remove
Some(mod_comp.clone())
} else {
None
}
fn unwrap_modular(inv: &Inventory, slot: InvSlotId) -> Option<Cow<ModularComponent>> {
inv.get(slot).and_then(|item| match item.kind() {
Cow::Owned(ItemKind::ModularComponent(mod_comp)) => Some(Cow::Owned(mod_comp)),
Cow::Borrowed(ItemKind::ModularComponent(mod_comp)) => Some(Cow::Borrowed(mod_comp)),
_ => None,
})
}
// Checks if both components are comptabile, and if so returns the toolkind to
@ -277,13 +274,12 @@ pub fn modular_weapon(
hand_restriction: hands_b,
..
},
) = (primary_component, secondary_component)
) = (&*primary_component, &*secondary_component)
{
// Checks that both components are of the same tool kind
if tool_a == tool_b {
// Checks that if both components have a hand restriction, they are the same
let hands_check =
hands_a.map_or(true, |hands| hands_b.map_or(true, |hands2| hands == hands2));
let hands_check = hands_a.zip(*hands_b).map_or(true, |(a, b)| a == b);
if hands_check {
Ok(())
} else {
@ -310,10 +306,9 @@ pub fn modular_weapon(
.expect("Expected component to exist");
// Create modular weapon
let components = vec![primary_component, secondary_component];
Ok(Item::new_from_item_base(
ItemBase::Modular(modular::ModularBase::Tool),
&components,
vec![primary_component, secondary_component],
ability_map,
msm,
))

View File

@ -942,7 +942,7 @@ impl<'a> Widget for Crafting<'a> {
}
})
})
.unwrap_or({
.unwrap_or_else(|| {
item_defs
.first()
.map(|i| i.item_definition_id())

View File

@ -464,7 +464,7 @@ impl<'a> Widget for ItemTooltip<'a> {
let item_kind = &*item.kind();
let equip_slot = inventory.equipped_items_of_kind(item_kind);
let equip_slot = inventory.equipped_items_replaceable_by(item_kind);
let (title, desc) = (item.name().to_string(), item.description().to_string());