mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Fixed random generation of modular weapons.
This commit is contained in:
parent
e86d2ab46a
commit
6fa7852a8c
@ -3,6 +3,7 @@ use super::{
|
||||
Item, ItemBase, ItemDef, ItemDesc, ItemKind, ItemTag, Material, Quality, ToolKind,
|
||||
};
|
||||
use crate::{assets::AssetExt, recipe};
|
||||
use common_base::dev_panic;
|
||||
use hashbrown::HashMap;
|
||||
use lazy_static::lazy_static;
|
||||
use rand::{prelude::SliceRandom, thread_rng};
|
||||
@ -247,7 +248,7 @@ const SUPPORTED_TOOLKINDS: [ToolKind; 6] = [
|
||||
ToolKind::Sceptre,
|
||||
];
|
||||
|
||||
type PrimaryComponentPool = HashMap<(ToolKind, String), Vec<(Arc<ItemDef>, Option<Hands>)>>;
|
||||
type PrimaryComponentPool = HashMap<(ToolKind, String), Vec<(Item, Option<Hands>)>>;
|
||||
type SecondaryComponentPool = HashMap<ToolKind, Vec<(Arc<ItemDef>, Option<Hands>)>>;
|
||||
|
||||
// TODO: Fix this. It broke when changes were made to component recipes
|
||||
@ -256,54 +257,23 @@ lazy_static! {
|
||||
let mut component_pool = HashMap::new();
|
||||
|
||||
// Load recipe book (done to check that material is valid for a particular component)
|
||||
let recipe_book = recipe::RawRecipeBook::load_expect("common.recipe_book");
|
||||
let recipes = &recipe_book.read().0;
|
||||
use crate::recipe::ComponentKey;
|
||||
let recipes = recipe::default_component_recipe_book().read();
|
||||
let ability_map = &AbilityMap::load().read();
|
||||
let msm = &MaterialStatManifest::load().read();
|
||||
|
||||
const ASSET_PREFIX: &str = "common.items.crafting_ing.modular.primary";
|
||||
|
||||
// Closure to check that an Item has a recipe that uses the provided material
|
||||
let valid_materials = |item: &str| {
|
||||
// Iterate over all recipes in the raw recipe book
|
||||
recipes
|
||||
.values()
|
||||
// Filter by recipes that have an output of the item of interest
|
||||
.filter(|recipe| recipe.output.0.eq(item))
|
||||
// Check that item is composed of material, uses heuristic that assumes all modular components use the ListSameItem recipe input
|
||||
.find_map(|recipe| {
|
||||
recipe
|
||||
.inputs
|
||||
.iter()
|
||||
.find_map(|input| {
|
||||
match &input.0 {
|
||||
recipe::RawRecipeInput::ListSameItem(items) => {
|
||||
Some(recipe::ItemList::load_expect_cloned(items).0)
|
||||
},
|
||||
_ => None,
|
||||
}
|
||||
})
|
||||
})
|
||||
};
|
||||
|
||||
for toolkind in SUPPORTED_TOOLKINDS {
|
||||
let directory = format!("{}.{}", ASSET_PREFIX, toolkind.identifier_name());
|
||||
if let Ok(items) = Item::new_from_asset_glob(&directory) {
|
||||
items
|
||||
.into_iter()
|
||||
.map(|comp| comp.item_definition_id().to_owned())
|
||||
.filter_map(|id| Arc::<ItemDef>::load_cloned(&id).ok())
|
||||
.for_each(|comp_def| {
|
||||
if let ItemKind::ModularComponent(ModularComponent::ToolPrimaryComponent { hand_restriction, .. }) = comp_def.kind {
|
||||
if let Some(material_ids) = valid_materials(comp_def.id()) {
|
||||
for material in material_ids {
|
||||
let entry = component_pool.entry((toolkind, material)).or_insert(Vec::new());
|
||||
entry.push((Arc::clone(&comp_def), hand_restriction));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
recipes
|
||||
.iter()
|
||||
.for_each(|(ComponentKey { toolkind, material, .. }, recipe)| {
|
||||
let component = recipe.item_output(ability_map, msm);
|
||||
let hand_restriction = if let ItemKind::ModularComponent(ModularComponent::ToolPrimaryComponent { hand_restriction, .. }) = &*component.kind() {
|
||||
*hand_restriction
|
||||
} else {
|
||||
return;
|
||||
};
|
||||
let entry = component_pool.entry((*toolkind, String::from(material))).or_insert(Vec::new());
|
||||
entry.push((component, hand_restriction));
|
||||
});
|
||||
|
||||
component_pool
|
||||
};
|
||||
@ -347,65 +317,74 @@ pub fn random_weapon(
|
||||
material: Material,
|
||||
hand_restriction: Option<Hands>,
|
||||
) -> Result<Item, ModularWeaponCreationError> {
|
||||
if let Some(material_id) = material.asset_identifier() {
|
||||
// Loads default ability map and material stat manifest for later use
|
||||
let ability_map = &AbilityMap::load().read();
|
||||
let msm = &MaterialStatManifest::load().read();
|
||||
let result = (|| {
|
||||
if let Some(material_id) = material.asset_identifier() {
|
||||
// Loads default ability map and material stat manifest for later use
|
||||
let ability_map = &AbilityMap::load().read();
|
||||
let msm = &MaterialStatManifest::load().read();
|
||||
|
||||
let mut rng = thread_rng();
|
||||
let mut rng = thread_rng();
|
||||
|
||||
let material = Item::new_from_asset_expect(material_id);
|
||||
let primary_components = PRIMARY_COMPONENT_POOL
|
||||
.get(&(tool, material_id.to_owned()))
|
||||
.into_iter()
|
||||
.flatten()
|
||||
.filter(|(_def, hand)| match (hand_restriction, hand) {
|
||||
(Some(restriction), Some(hand)) => restriction == *hand,
|
||||
(None, _) | (_, None) => true,
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
let primary_components = PRIMARY_COMPONENT_POOL
|
||||
.get(&(tool, material_id.to_owned()))
|
||||
.into_iter()
|
||||
.flatten()
|
||||
.filter(|(_comp, 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)?;
|
||||
let comp = Item::new_from_item_base(
|
||||
ItemBase::Raw(Arc::clone(def)),
|
||||
vec![material],
|
||||
let (primary_component, hand_restriction) = {
|
||||
let (comp, hand) = primary_components
|
||||
.choose(&mut rng)
|
||||
.ok_or(ModularWeaponCreationError::PrimaryComponentNotFound)?;
|
||||
let comp = comp.duplicate(ability_map, msm);
|
||||
(comp, hand_restriction.or(*hand))
|
||||
};
|
||||
|
||||
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)?
|
||||
.0;
|
||||
Item::new_from_item_base(
|
||||
ItemBase::Raw(Arc::clone(def)),
|
||||
Vec::new(),
|
||||
ability_map,
|
||||
msm,
|
||||
)
|
||||
};
|
||||
|
||||
// Create modular weapon
|
||||
Ok(Item::new_from_item_base(
|
||||
ItemBase::Modular(ModularBase::Tool),
|
||||
vec![primary_component, secondary_component],
|
||||
ability_map,
|
||||
msm,
|
||||
);
|
||||
(comp, hand_restriction.or(*hand))
|
||||
};
|
||||
|
||||
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)?
|
||||
.0;
|
||||
Item::new_from_item_base(ItemBase::Raw(Arc::clone(def)), Vec::new(), ability_map, msm)
|
||||
};
|
||||
|
||||
// Create modular weapon
|
||||
Ok(Item::new_from_item_base(
|
||||
ItemBase::Modular(ModularBase::Tool),
|
||||
vec![primary_component, secondary_component],
|
||||
ability_map,
|
||||
msm,
|
||||
))
|
||||
} else {
|
||||
Err(ModularWeaponCreationError::MaterialNotFound)
|
||||
))
|
||||
} else {
|
||||
Err(ModularWeaponCreationError::MaterialNotFound)
|
||||
}
|
||||
})();
|
||||
if result.is_err() {
|
||||
let error_str = format!(
|
||||
"Failed to synthesize a modular {tool:?} made of {material:?} that had a hand \
|
||||
restriction of {hand_restriction:?}."
|
||||
);
|
||||
dev_panic!(error_str)
|
||||
}
|
||||
result
|
||||
}
|
||||
|
||||
pub fn modify_name<'a>(item_name: &'a str, item: &'a Item) -> Cow<'a, str> {
|
||||
|
@ -527,11 +527,10 @@ impl ComponentRecipe {
|
||||
input_slots: I,
|
||||
) {
|
||||
let mut required = amount;
|
||||
// Check used for recipes that have an input that is not consumed, e.g.
|
||||
// craftsman hammer
|
||||
let mut contains_any = false;
|
||||
// contains_any check used for recipes that have an input that is not consumed,
|
||||
// e.g. craftsman hammer
|
||||
// Goes through each slot and marks some amount from each slot as claimed
|
||||
for slot in input_slots {
|
||||
let contains_any = input_slots.into_iter().all(|slot| {
|
||||
// Checks that the item in the slot can be used for the input
|
||||
if let Some(item) = inv
|
||||
.get(slot)
|
||||
@ -544,9 +543,11 @@ impl ComponentRecipe {
|
||||
let provided = available.min(required);
|
||||
required -= provided;
|
||||
*claimed += provided;
|
||||
contains_any = true;
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
});
|
||||
// If there were not sufficient items to cover requirement between all provided
|
||||
// slots, or if non-consumed item was not present, mark input as not satisfied
|
||||
if required > 0 || !contains_any {
|
||||
|
Loading…
Reference in New Issue
Block a user