mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Backend stuff for salvaging.
This commit is contained in:
parent
05c2bb5e35
commit
ed5cf8ebf9
@ -1927,15 +1927,15 @@
|
||||
craft_sprite: Some(Anvil),
|
||||
is_recycling: false,
|
||||
),
|
||||
"linen": (
|
||||
output: ("common.items.crafting_ing.cloth.linen", 1),
|
||||
inputs: [
|
||||
(Tag(Material(Linen)), 1),
|
||||
(Item("common.items.crafting_tools.sewing_set"), 0),
|
||||
],
|
||||
craft_sprite: None,
|
||||
is_recycling: true,
|
||||
),
|
||||
// "linen": (
|
||||
// output: ("common.items.crafting_ing.cloth.linen", 1),
|
||||
// inputs: [
|
||||
// (Tag(Material(Linen)), 1),
|
||||
// (Item("common.items.crafting_tools.sewing_set"), 0),
|
||||
// ],
|
||||
// craft_sprite: None,
|
||||
// is_recycling: true,
|
||||
// ),
|
||||
"wool": (
|
||||
output: ("common.items.crafting_ing.cloth.wool", 1),
|
||||
inputs: [
|
||||
|
@ -23,6 +23,7 @@ use common::{
|
||||
comp::{
|
||||
self,
|
||||
chat::{KillSource, KillType},
|
||||
controller::CraftEvent,
|
||||
group,
|
||||
invite::{InviteKind, InviteResponse},
|
||||
skills::Skill,
|
||||
@ -1004,7 +1005,7 @@ impl Client {
|
||||
if can_craft && has_sprite {
|
||||
self.send_msg(ClientGeneral::ControlEvent(ControlEvent::InventoryEvent(
|
||||
InventoryEvent::CraftRecipe {
|
||||
recipe: recipe.to_string(),
|
||||
craft_event: CraftEvent::Simple(recipe.to_string()),
|
||||
craft_sprite: craft_sprite.map(|(pos, _)| pos),
|
||||
},
|
||||
)));
|
||||
|
@ -23,7 +23,7 @@ pub enum InventoryEvent {
|
||||
SplitDrop(InvSlotId),
|
||||
Sort,
|
||||
CraftRecipe {
|
||||
recipe: String,
|
||||
craft_event: CraftEvent,
|
||||
craft_sprite: Option<Vec3<i32>>,
|
||||
},
|
||||
}
|
||||
@ -48,7 +48,7 @@ pub enum InventoryManip {
|
||||
SplitDrop(Slot),
|
||||
Sort,
|
||||
CraftRecipe {
|
||||
recipe: String,
|
||||
craft_event: CraftEvent,
|
||||
craft_sprite: Option<Vec3<i32>>,
|
||||
},
|
||||
SwapEquippedWeapons,
|
||||
@ -80,16 +80,22 @@ impl From<InventoryEvent> for InventoryManip {
|
||||
InventoryEvent::SplitDrop(inv) => Self::SplitDrop(Slot::Inventory(inv)),
|
||||
InventoryEvent::Sort => Self::Sort,
|
||||
InventoryEvent::CraftRecipe {
|
||||
recipe,
|
||||
craft_event,
|
||||
craft_sprite,
|
||||
} => Self::CraftRecipe {
|
||||
recipe,
|
||||
craft_event,
|
||||
craft_sprite,
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub enum CraftEvent {
|
||||
Simple(String),
|
||||
Salvage(InvSlotId),
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub enum GroupManip {
|
||||
Leave,
|
||||
|
@ -170,6 +170,41 @@ impl Material {
|
||||
| Material::Dragonscale => MaterialKind::Hide,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn asset_identifier(&self) -> &'static str {
|
||||
match self {
|
||||
Material::Bronze => "common.items.mineral.ingot.bronze",
|
||||
Material::Iron => "common.items.mineral.ingot.iron",
|
||||
Material::Steel => "common.items.mineral.ingot.steel",
|
||||
Material::Cobalt => "common.items.mineral.ingot.cobalt",
|
||||
Material::Bloodsteel => "common.items.mineral.ingot.bloodsteel",
|
||||
Material::Orichalcum => "common.items.mineral.ingot.orichalcum",
|
||||
Material::Wood
|
||||
| Material::Bamboo
|
||||
| Material::Hardwood
|
||||
| Material::Ironwood
|
||||
| Material::Frostwood
|
||||
| Material::Eldwood => unreachable!(),
|
||||
Material::Rock
|
||||
| Material::Granite
|
||||
| Material::Bone
|
||||
| Material::Basalt
|
||||
| Material::Obsidian
|
||||
| Material::Velorite => unreachable!(),
|
||||
Material::Linen => "common.items.crafting_ing.cloth.linen",
|
||||
Material::Wool => "common.items.crafting_ing.cloth.wool",
|
||||
Material::Silk => "common.items.crafting_ing.cloth.silk",
|
||||
Material::Lifecloth => "common.items.crafting_ing.cloth.lifecloth",
|
||||
Material::Moonweave => "common.items.crafting_ing.cloth.moonweave",
|
||||
Material::Sunsilk => "common.items.crafting_ing.cloth.sunsilk",
|
||||
Material::Rawhide => "common.items.crafting_ing.leather.simple_leather",
|
||||
Material::Leather => "common.items.crafting_ing.leather.thick_leather",
|
||||
Material::Scale => "common.items.crafting_ing.leather.scales",
|
||||
Material::Carapace => "common.items.crafting_ing.leather.carapace",
|
||||
Material::Plate => "common.items.crafting_ing.leather.plate",
|
||||
Material::Dragonscale => "common.items.crafting_ing.leather.dragon_scale",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
||||
@ -202,6 +237,7 @@ pub enum ItemTag {
|
||||
CraftingTool, // Pickaxe, Craftsman-Hammer, Sewing-Set
|
||||
Utility,
|
||||
Bag,
|
||||
SalvageInto(Material),
|
||||
}
|
||||
|
||||
impl TagExampleInfo for ItemTag {
|
||||
@ -219,6 +255,7 @@ impl TagExampleInfo for ItemTag {
|
||||
ItemTag::CraftingTool => "tool",
|
||||
ItemTag::Utility => "utility",
|
||||
ItemTag::Bag => "bag",
|
||||
ItemTag::SalvageInto(_) => "salvage",
|
||||
}
|
||||
}
|
||||
|
||||
@ -237,6 +274,7 @@ impl TagExampleInfo for ItemTag {
|
||||
ItemTag::CraftingTool => "common.items.tag_examples.placeholder",
|
||||
ItemTag::Utility => "common.items.tag_examples.placeholder",
|
||||
ItemTag::Bag => "common.items.tag_examples.placeholder",
|
||||
ItemTag::SalvageInto(_) => "common.items.tag_examples.placeholder",
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -759,6 +797,43 @@ impl Item {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_salvageable(&self) -> bool {
|
||||
self.item_def
|
||||
.tags
|
||||
.iter()
|
||||
.any(|tag| matches!(tag, ItemTag::SalvageInto(_)))
|
||||
}
|
||||
|
||||
// Attempts to salvage an item, returning the salvaged items if salvageable,
|
||||
// else the original item is not Theoretically supports returning multiple
|
||||
// items, only returns one per tag in the item for now
|
||||
pub fn try_salvage(self) -> Result<Vec<Item>, Item> {
|
||||
if !self.is_salvageable() {
|
||||
return Err(self);
|
||||
}
|
||||
|
||||
let salvaged_items: Vec<_> = self
|
||||
.item_def
|
||||
.tags
|
||||
.iter()
|
||||
.filter_map(|tag| {
|
||||
if let ItemTag::SalvageInto(material) = tag {
|
||||
Some(material)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.map(|material| material.asset_identifier())
|
||||
.map(|asset| Item::new_from_asset_expect(asset))
|
||||
.collect();
|
||||
|
||||
if salvaged_items.is_empty() {
|
||||
Err(self)
|
||||
} else {
|
||||
Ok(salvaged_items)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn name(&self) -> &str { &self.item_def.name }
|
||||
|
||||
pub fn description(&self) -> &str { &self.item_def.description }
|
||||
|
@ -13,7 +13,7 @@ pub mod character_state;
|
||||
#[cfg(not(target_arch = "wasm32"))] pub mod combo;
|
||||
pub mod compass;
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
mod controller;
|
||||
pub mod controller;
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
pub mod dialogue;
|
||||
#[cfg(not(target_arch = "wasm32"))] mod energy;
|
||||
|
@ -1,6 +1,7 @@
|
||||
use crate::{
|
||||
assets::{self, AssetExt, AssetHandle},
|
||||
comp::{
|
||||
inventory::slot::InvSlotId,
|
||||
item::{modular, tool::AbilityMap, ItemDef, ItemTag, MaterialStatManifest},
|
||||
Inventory, Item,
|
||||
},
|
||||
@ -32,7 +33,7 @@ impl Recipe {
|
||||
inv: &mut Inventory,
|
||||
ability_map: &AbilityMap,
|
||||
msm: &MaterialStatManifest,
|
||||
) -> Result<Option<(Item, u32)>, Vec<(&RecipeInput, u32)>> {
|
||||
) -> Result<(Item, u32), Vec<(&RecipeInput, u32)>> {
|
||||
// Get ingredient cells from inventory,
|
||||
let mut components = Vec::new();
|
||||
|
||||
@ -47,15 +48,18 @@ impl Recipe {
|
||||
})
|
||||
});
|
||||
|
||||
for i in 0..self.output.1 {
|
||||
let crafted_item =
|
||||
Item::new_from_item_def(Arc::clone(&self.output.0), &components, ability_map, msm);
|
||||
if let Err(item) = inv.push(crafted_item) {
|
||||
return Ok(Some((item, self.output.1 - i)));
|
||||
}
|
||||
}
|
||||
let crafted_item =
|
||||
Item::new_from_item_def(Arc::clone(&self.output.0), &components, ability_map, msm);
|
||||
|
||||
Ok(None)
|
||||
Ok((crafted_item, self.output.1))
|
||||
|
||||
// for i in 0..self.output.1 {
|
||||
// if let Err(item) = inv.push(crafted_item) {
|
||||
// return Ok(Some((item, self.output.1 - i)));
|
||||
// }
|
||||
// }
|
||||
|
||||
// Ok(None)
|
||||
}
|
||||
|
||||
pub fn inputs(&self) -> impl ExactSizeIterator<Item = (&RecipeInput, u32)> {
|
||||
@ -65,6 +69,33 @@ impl Recipe {
|
||||
}
|
||||
}
|
||||
|
||||
pub enum SalvageError {
|
||||
NotSalvageable,
|
||||
}
|
||||
|
||||
pub fn try_salvage(
|
||||
inv: &mut Inventory,
|
||||
slot: InvSlotId,
|
||||
ability_map: &AbilityMap,
|
||||
msm: &MaterialStatManifest,
|
||||
) -> Result<Vec<Item>, SalvageError> {
|
||||
if inv.get(slot).map_or(false, |item| item.is_salvageable()) {
|
||||
let salvage_item = inv
|
||||
.take(slot, ability_map, msm)
|
||||
.expect("Expected item to exist in inventory");
|
||||
match salvage_item.try_salvage() {
|
||||
Ok(items) => Ok(items),
|
||||
Err(item) => {
|
||||
inv.push(item)
|
||||
.expect("Item taken from inventory just before");
|
||||
Err(SalvageError::NotSalvageable)
|
||||
},
|
||||
}
|
||||
} else {
|
||||
Err(SalvageError::NotSalvageable)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
pub struct RecipeBook {
|
||||
recipes: HashMap<String, Recipe>,
|
||||
|
@ -11,7 +11,7 @@ use common::{
|
||||
slot::{self, Slot},
|
||||
},
|
||||
consts::MAX_PICKUP_RANGE,
|
||||
recipe::default_recipe_book,
|
||||
recipe::{self, default_recipe_book},
|
||||
trade::Trades,
|
||||
uid::Uid,
|
||||
util::find_dist::{self, FindDist},
|
||||
@ -563,53 +563,91 @@ pub fn handle_inventory(server: &mut Server, entity: EcsEntity, manip: comp::Inv
|
||||
drop(inventories);
|
||||
},
|
||||
comp::InventoryManip::CraftRecipe {
|
||||
recipe,
|
||||
craft_event,
|
||||
craft_sprite,
|
||||
} => {
|
||||
use comp::controller::CraftEvent;
|
||||
let recipe_book = default_recipe_book().read();
|
||||
let craft_result = recipe_book
|
||||
.get(&recipe)
|
||||
.filter(|r| {
|
||||
if let Some(needed_sprite) = r.craft_sprite {
|
||||
let sprite = craft_sprite
|
||||
.filter(|pos| {
|
||||
let entity_cylinder = get_cylinder(state, entity);
|
||||
if !within_pickup_range(entity_cylinder, || {
|
||||
Some(find_dist::Cube {
|
||||
min: pos.as_(),
|
||||
side_length: 1.0,
|
||||
})
|
||||
}) {
|
||||
debug!(
|
||||
?entity_cylinder,
|
||||
"Failed to craft recipe as not within range of required \
|
||||
sprite, sprite pos: {}",
|
||||
pos
|
||||
);
|
||||
false
|
||||
} else {
|
||||
true
|
||||
}
|
||||
})
|
||||
.and_then(|pos| state.terrain().get(pos).ok().copied())
|
||||
.and_then(|block| block.get_sprite());
|
||||
Some(needed_sprite) == sprite
|
||||
} else {
|
||||
true
|
||||
let ability_map = &state.ecs().read_resource::<AbilityMap>();
|
||||
let msm = state.ecs().read_resource::<MaterialStatManifest>();
|
||||
|
||||
let crafted_items = match craft_event {
|
||||
CraftEvent::Simple(recipe) => recipe_book
|
||||
.get(&recipe)
|
||||
.filter(|r| {
|
||||
if let Some(needed_sprite) = r.craft_sprite {
|
||||
let sprite = craft_sprite
|
||||
.filter(|pos| {
|
||||
let entity_cylinder = get_cylinder(state, entity);
|
||||
if !within_pickup_range(entity_cylinder, || {
|
||||
Some(find_dist::Cube {
|
||||
min: pos.as_(),
|
||||
side_length: 1.0,
|
||||
})
|
||||
}) {
|
||||
debug!(
|
||||
?entity_cylinder,
|
||||
"Failed to craft recipe as not within range of \
|
||||
required sprite, sprite pos: {}",
|
||||
pos
|
||||
);
|
||||
false
|
||||
} else {
|
||||
true
|
||||
}
|
||||
})
|
||||
.and_then(|pos| state.terrain().get(pos).ok().copied())
|
||||
.and_then(|block| block.get_sprite());
|
||||
Some(needed_sprite) == sprite
|
||||
} else {
|
||||
true
|
||||
}
|
||||
})
|
||||
.and_then(|r| {
|
||||
r.perform(
|
||||
&mut inventory,
|
||||
&state.ecs().read_resource::<AbilityMap>(),
|
||||
&state.ecs().read_resource::<item::MaterialStatManifest>(),
|
||||
)
|
||||
.ok()
|
||||
})
|
||||
.map(|(crafted_item, amount)| {
|
||||
let mut crafted_items = Vec::with_capacity(amount as usize);
|
||||
for _ in 0..amount {
|
||||
crafted_items.push(crafted_item.duplicate(ability_map, &msm));
|
||||
}
|
||||
crafted_items
|
||||
}),
|
||||
CraftEvent::Salvage(slot) => {
|
||||
recipe::try_salvage(&mut inventory, slot, ability_map, &msm).ok()
|
||||
},
|
||||
};
|
||||
|
||||
// Attempt to insert items into inventory, dropping them if there is not enough
|
||||
// space
|
||||
let items_were_crafted = if let Some(crafted_items) = crafted_items {
|
||||
for item in crafted_items {
|
||||
if let Err(item) = inventory.push(item) {
|
||||
dropped_items.push((
|
||||
state
|
||||
.read_component_copied::<comp::Pos>(entity)
|
||||
.unwrap_or_default(),
|
||||
state
|
||||
.read_component_copied::<comp::Ori>(entity)
|
||||
.unwrap_or_default(),
|
||||
item.duplicate(ability_map, &msm),
|
||||
));
|
||||
}
|
||||
})
|
||||
.and_then(|r| {
|
||||
r.perform(
|
||||
&mut inventory,
|
||||
&state.ecs().read_resource::<AbilityMap>(),
|
||||
&state.ecs().read_resource::<item::MaterialStatManifest>(),
|
||||
)
|
||||
.ok()
|
||||
});
|
||||
}
|
||||
true
|
||||
} else {
|
||||
false
|
||||
};
|
||||
|
||||
drop(inventories);
|
||||
|
||||
// FIXME: We should really require the drop and write to be atomic!
|
||||
if craft_result.is_some() {
|
||||
if items_were_crafted {
|
||||
let _ = state.ecs().write_storage().insert(
|
||||
entity,
|
||||
comp::InventoryUpdate::new(comp::InventoryUpdateEvent::Craft),
|
||||
@ -617,21 +655,22 @@ pub fn handle_inventory(server: &mut Server, entity: EcsEntity, manip: comp::Inv
|
||||
}
|
||||
|
||||
// Drop the item if there wasn't enough space
|
||||
if let Some(Some((item, amount))) = craft_result {
|
||||
let ability_map = &state.ecs().read_resource::<AbilityMap>();
|
||||
let msm = state.ecs().read_resource::<MaterialStatManifest>();
|
||||
for _ in 0..amount {
|
||||
dropped_items.push((
|
||||
state
|
||||
.read_component_copied::<comp::Pos>(entity)
|
||||
.unwrap_or_default(),
|
||||
state
|
||||
.read_component_copied::<comp::Ori>(entity)
|
||||
.unwrap_or_default(),
|
||||
item.duplicate(ability_map, &msm),
|
||||
));
|
||||
}
|
||||
}
|
||||
// if let Some(Some((item, amount))) = craft_result {
|
||||
// let ability_map = &state.ecs().read_resource::<AbilityMap>();
|
||||
// let msm =
|
||||
// state.ecs().read_resource::<MaterialStatManifest>();
|
||||
// for _ in 0..amount {
|
||||
// dropped_items.push((
|
||||
// state
|
||||
// .read_component_copied::<comp::Pos>(entity)
|
||||
// .unwrap_or_default(),
|
||||
// state
|
||||
// .read_component_copied::<comp::Ori>(entity)
|
||||
// .unwrap_or_default(),
|
||||
// item.duplicate(ability_map, &msm),
|
||||
// ));
|
||||
// }
|
||||
// }
|
||||
},
|
||||
comp::InventoryManip::Sort => {
|
||||
inventory.sort();
|
||||
|
Loading…
Reference in New Issue
Block a user