mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Added repair recipes
This commit is contained in:
parent
c3f5bc13f1
commit
0966753699
79
assets/common/repair_recipe_book.ron
Normal file
79
assets/common/repair_recipe_book.ron
Normal file
@ -0,0 +1,79 @@
|
||||
(
|
||||
recipes: {
|
||||
// Weapons
|
||||
ItemDefId("common.items.weapons.sword.starter"): ( inputs: [], ),
|
||||
ItemDefId("common.items.weapons.axe.starter_axe"): ( inputs: [], ),
|
||||
ItemDefId("common.items.weapons.hammer.starter_hammer"): ( inputs: [], ),
|
||||
ItemDefId("common.items.weapons.bow.starter"): ( inputs: [], ),
|
||||
ItemDefId("common.items.weapons.staff.starter_staff"): ( inputs: [], ),
|
||||
ItemDefId("common.items.weapons.sceptre.starter_sceptre"): ( inputs: [], ),
|
||||
ItemDefId("common.items.weapons.sword_1h.starter"): ( inputs: [], ),
|
||||
ModularWeapon(material: "common.items.mineral.ingot.bronze"): (
|
||||
inputs: [
|
||||
(Item("common.items.mineral.ingot.bronze"), 1),
|
||||
],
|
||||
),
|
||||
ModularWeapon(material: "common.items.mineral.ingot.iron"): (
|
||||
inputs: [
|
||||
(Item("common.items.mineral.ingot.iron"), 1),
|
||||
],
|
||||
),
|
||||
ModularWeapon(material: "common.items.mineral.ingot.steel"): (
|
||||
inputs: [
|
||||
(Item("common.items.mineral.ingot.steel"), 1),
|
||||
],
|
||||
),
|
||||
ModularWeapon(material: "common.items.mineral.ingot.cobalt"): (
|
||||
inputs: [
|
||||
(Item("common.items.mineral.ingot.cobalt"), 1),
|
||||
],
|
||||
),
|
||||
ModularWeapon(material: "common.items.mineral.ingot.bloodsteel"): (
|
||||
inputs: [
|
||||
(Item("common.items.mineral.ingot.bloodsteel"), 1),
|
||||
],
|
||||
),
|
||||
ModularWeapon(material: "common.items.mineral.ingot.orichalcum"): (
|
||||
inputs: [
|
||||
(Item("common.items.mineral.ingot.orichalcum"), 1),
|
||||
],
|
||||
),
|
||||
ModularWeapon(material: "common.items.log.wood"): (
|
||||
inputs: [
|
||||
(Item("common.items.log.wood"), 1),
|
||||
],
|
||||
),
|
||||
ModularWeapon(material: "common.items.log.bamboo"): (
|
||||
inputs: [
|
||||
(Item("common.items.log.bamboo"), 1),
|
||||
],
|
||||
),
|
||||
ModularWeapon(material: "common.items.log.hardwood"): (
|
||||
inputs: [
|
||||
(Item("common.items.log.hardwood"), 1),
|
||||
],
|
||||
),
|
||||
ModularWeapon(material: "common.items.log.ironwood"): (
|
||||
inputs: [
|
||||
(Item("common.items.log.ironwood"), 1),
|
||||
],
|
||||
),
|
||||
ModularWeapon(material: "common.items.log.frostwood"): (
|
||||
inputs: [
|
||||
(Item("common.items.log.frostwood"), 1),
|
||||
],
|
||||
),
|
||||
ModularWeapon(material: "common.items.log.eldwood"): (
|
||||
inputs: [
|
||||
(Item("common.items.log.eldwood"), 1),
|
||||
],
|
||||
),
|
||||
// Armor
|
||||
|
||||
},
|
||||
fallback: (
|
||||
inputs: [
|
||||
(Item("common.items.utility.coins"), 1000),
|
||||
],
|
||||
),
|
||||
)
|
@ -38,7 +38,7 @@ use common::{
|
||||
lod,
|
||||
mounting::Rider,
|
||||
outcome::Outcome,
|
||||
recipe::{ComponentRecipeBook, RecipeBook},
|
||||
recipe::{ComponentRecipeBook, RecipeBook, RepairRecipeBook},
|
||||
resources::{GameMode, PlayerEntity, Time, TimeOfDay},
|
||||
shared_server_config::ServerConstants,
|
||||
spiral::Spiral2d,
|
||||
@ -222,6 +222,7 @@ pub struct Client {
|
||||
pub chat_mode: ChatMode,
|
||||
recipe_book: RecipeBook,
|
||||
component_recipe_book: ComponentRecipeBook,
|
||||
repair_recipe_book: RepairRecipeBook,
|
||||
available_recipes: HashMap<String, Option<SpriteKind>>,
|
||||
lod_zones: HashMap<Vec2<i32>, lod::Zone>,
|
||||
lod_last_requested: Option<Instant>,
|
||||
@ -362,6 +363,7 @@ impl Client {
|
||||
material_stats,
|
||||
ability_map,
|
||||
server_constants,
|
||||
repair_recipe_book,
|
||||
} = loop {
|
||||
tokio::select! {
|
||||
// Spawn in a blocking thread (leaving the network thread free). This is mostly
|
||||
@ -655,6 +657,7 @@ impl Client {
|
||||
world_map.pois,
|
||||
recipe_book,
|
||||
component_recipe_book,
|
||||
repair_recipe_book,
|
||||
max_group_size,
|
||||
client_timeout,
|
||||
))
|
||||
@ -670,6 +673,7 @@ impl Client {
|
||||
pois,
|
||||
recipe_book,
|
||||
component_recipe_book,
|
||||
repair_recipe_book,
|
||||
max_group_size,
|
||||
client_timeout,
|
||||
) = loop {
|
||||
@ -708,6 +712,7 @@ impl Client {
|
||||
pois,
|
||||
recipe_book,
|
||||
component_recipe_book,
|
||||
repair_recipe_book,
|
||||
available_recipes: HashMap::default(),
|
||||
chat_mode: ChatMode::default(),
|
||||
|
||||
@ -1146,6 +1151,8 @@ impl Client {
|
||||
|
||||
pub fn component_recipe_book(&self) -> &ComponentRecipeBook { &self.component_recipe_book }
|
||||
|
||||
pub fn repair_recipe_book(&self) -> &RepairRecipeBook { &self.repair_recipe_book }
|
||||
|
||||
pub fn available_recipes(&self) -> &HashMap<String, Option<SpriteKind>> {
|
||||
&self.available_recipes
|
||||
}
|
||||
@ -1291,12 +1298,17 @@ impl Client {
|
||||
|
||||
/// Repairs the item in the given inventory slot. `sprite_pos` should be
|
||||
/// the location of a relevant crafting station within range of the player.
|
||||
pub fn repair_item(&mut self, slot: Slot, sprite_pos: Vec3<i32>) -> bool {
|
||||
pub fn repair_item(
|
||||
&mut self,
|
||||
item: Slot,
|
||||
slots: Vec<(u32, InvSlotId)>,
|
||||
sprite_pos: Vec3<i32>,
|
||||
) -> bool {
|
||||
let is_repairable = {
|
||||
let inventories = self.inventories();
|
||||
let inventory = inventories.get(self.entity());
|
||||
inventory.map_or(false, |inv| {
|
||||
if let Some(item) = match slot {
|
||||
if let Some(item) = match item {
|
||||
Slot::Equip(equip_slot) => inv.equipped(equip_slot),
|
||||
Slot::Inventory(invslot) => inv.get(invslot),
|
||||
} {
|
||||
@ -1309,7 +1321,7 @@ impl Client {
|
||||
if is_repairable {
|
||||
self.send_msg(ClientGeneral::ControlEvent(ControlEvent::InventoryEvent(
|
||||
InventoryEvent::CraftRecipe {
|
||||
craft_event: CraftEvent::Repair(slot),
|
||||
craft_event: CraftEvent::Repair { item, slots },
|
||||
craft_sprite: Some(sprite_pos),
|
||||
},
|
||||
)));
|
||||
|
@ -10,7 +10,7 @@ use common::{
|
||||
event::UpdateCharacterMetadata,
|
||||
lod,
|
||||
outcome::Outcome,
|
||||
recipe::{ComponentRecipeBook, RecipeBook},
|
||||
recipe::{ComponentRecipeBook, RecipeBook, RepairRecipeBook},
|
||||
resources::{Time, TimeOfDay},
|
||||
shared_server_config::ServerConstants,
|
||||
terrain::{Block, TerrainChunk, TerrainChunkMeta, TerrainChunkSize},
|
||||
@ -65,6 +65,7 @@ pub enum ServerInit {
|
||||
world_map: crate::msg::world_msg::WorldMapMsg,
|
||||
recipe_book: RecipeBook,
|
||||
component_recipe_book: ComponentRecipeBook,
|
||||
repair_recipe_book: RepairRecipeBook,
|
||||
material_stats: MaterialStatManifest,
|
||||
ability_map: comp::item::tool::AbilityMap,
|
||||
server_constants: ServerConstants,
|
||||
|
@ -105,7 +105,10 @@ pub enum CraftEvent {
|
||||
modifier: Option<InvSlotId>,
|
||||
slots: Vec<(u32, InvSlotId)>,
|
||||
},
|
||||
Repair(Slot),
|
||||
Repair {
|
||||
item: Slot,
|
||||
slots: Vec<(u32, InvSlotId)>,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
||||
|
@ -1,11 +1,12 @@
|
||||
use crate::{
|
||||
assets::{self, AssetExt, AssetHandle},
|
||||
comp::{
|
||||
inventory::slot::InvSlotId,
|
||||
inventory::slot::{InvSlotId, Slot},
|
||||
item::{
|
||||
modular,
|
||||
tool::{AbilityMap, ToolKind},
|
||||
ItemBase, ItemDef, ItemDefinitionIdOwned, ItemKind, ItemTag, MaterialStatManifest,
|
||||
ItemBase, ItemDef, ItemDefinitionId, ItemDefinitionIdOwned, ItemKind, ItemTag,
|
||||
MaterialStatManifest,
|
||||
},
|
||||
Inventory, Item,
|
||||
},
|
||||
@ -39,6 +40,45 @@ pub enum RecipeInput {
|
||||
ListSameItem(Vec<Arc<ItemDef>>),
|
||||
}
|
||||
|
||||
impl RecipeInput {
|
||||
fn handle_requirement<'a, I: Iterator<Item = InvSlotId>>(
|
||||
&'a self,
|
||||
amount: u32,
|
||||
slot_claims: &mut HashMap<InvSlotId, u32>,
|
||||
unsatisfied_requirements: &mut Vec<(&'a RecipeInput, u32)>,
|
||||
inv: &Inventory,
|
||||
input_slots: I,
|
||||
) {
|
||||
let mut required = amount;
|
||||
// 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
|
||||
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)
|
||||
.filter(|item| item.matches_recipe_input(self, amount))
|
||||
{
|
||||
// Gets the number of items claimed from the slot, or sets to 0 if slot has
|
||||
// not been claimed by another input yet
|
||||
let claimed = slot_claims.entry(slot).or_insert(0);
|
||||
let available = item.amount().saturating_sub(*claimed);
|
||||
let provided = available.min(required);
|
||||
required -= provided;
|
||||
*claimed += provided;
|
||||
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 {
|
||||
unsatisfied_requirements.push((self, required));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
pub struct Recipe {
|
||||
pub output: (Arc<ItemDef>, u32),
|
||||
@ -594,65 +634,26 @@ impl ComponentRecipe {
|
||||
let mut slot_claims = HashMap::new();
|
||||
let mut unsatisfied_requirements = Vec::new();
|
||||
|
||||
fn handle_requirement<'a, I: Iterator<Item = InvSlotId>>(
|
||||
slot_claims: &mut HashMap<InvSlotId, u32>,
|
||||
unsatisfied_requirements: &mut Vec<(&'a RecipeInput, u32)>,
|
||||
inv: &Inventory,
|
||||
input: &'a RecipeInput,
|
||||
amount: u32,
|
||||
input_slots: I,
|
||||
) {
|
||||
let mut required = amount;
|
||||
// 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
|
||||
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)
|
||||
.filter(|item| item.matches_recipe_input(input, amount))
|
||||
{
|
||||
// Gets the number of items claimed from the slot, or sets to 0 if slot has
|
||||
// not been claimed by another input yet
|
||||
let claimed = slot_claims.entry(slot).or_insert(0);
|
||||
let available = item.amount().saturating_sub(*claimed);
|
||||
let provided = available.min(required);
|
||||
required -= provided;
|
||||
*claimed += provided;
|
||||
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 {
|
||||
unsatisfied_requirements.push((input, required));
|
||||
}
|
||||
}
|
||||
|
||||
// Checks each input against slots in the inventory. If the slots contain an
|
||||
// item that fulfills the need of the input, marks some of the item as claimed
|
||||
// up to quantity needed for the crafting input. If the item either
|
||||
// cannot be used, or there is insufficient quantity, adds input and
|
||||
// number of materials needed to unsatisfied requirements.
|
||||
handle_requirement(
|
||||
self.material.0.handle_requirement(
|
||||
self.material.1,
|
||||
&mut slot_claims,
|
||||
&mut unsatisfied_requirements,
|
||||
inv,
|
||||
&self.material.0,
|
||||
self.material.1,
|
||||
core::iter::once(material_slot),
|
||||
);
|
||||
if let Some((modifier_input, modifier_amount)) = &self.modifier {
|
||||
// TODO: Better way to get slot to use that ensures this requirement fails if no
|
||||
// slot provided?
|
||||
handle_requirement(
|
||||
modifier_input.handle_requirement(
|
||||
*modifier_amount,
|
||||
&mut slot_claims,
|
||||
&mut unsatisfied_requirements,
|
||||
inv,
|
||||
modifier_input,
|
||||
*modifier_amount,
|
||||
core::iter::once(modifier_slot.unwrap_or(InvSlotId::new(0, 0))),
|
||||
);
|
||||
}
|
||||
@ -666,12 +667,11 @@ impl ComponentRecipe {
|
||||
.filter_map(|(j, slot)| if i as u32 == *j { Some(slot) } else { None })
|
||||
.copied();
|
||||
// Checks if requirement is met, and if not marks it as unsatisfied
|
||||
handle_requirement(
|
||||
input.handle_requirement(
|
||||
*amount,
|
||||
&mut slot_claims,
|
||||
&mut unsatisfied_requirements,
|
||||
inv,
|
||||
input,
|
||||
*amount,
|
||||
input_slots,
|
||||
);
|
||||
});
|
||||
@ -900,6 +900,199 @@ impl assets::Compound for ComponentRecipeBook {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Hash, PartialEq, Eq, Clone, Debug)]
|
||||
enum RepairKey {
|
||||
ItemDefId(String),
|
||||
ModularWeapon { material: String },
|
||||
}
|
||||
|
||||
impl RepairKey {
|
||||
fn from_item(item: &Item) -> Option<Self> {
|
||||
match item.item_definition_id() {
|
||||
ItemDefinitionId::Simple(item_id) => Some(Self::ItemDefId(String::from(item_id))),
|
||||
ItemDefinitionId::Compound { .. } => None,
|
||||
ItemDefinitionId::Modular { pseudo_base, .. } => match pseudo_base {
|
||||
"veloren.core.pseudo_items.modular.tool" => {
|
||||
if let Some(ItemDefinitionId::Simple(material)) = item
|
||||
.components()
|
||||
.iter()
|
||||
.find(|comp| {
|
||||
matches!(
|
||||
&*comp.kind(),
|
||||
ItemKind::ModularComponent(
|
||||
modular::ModularComponent::ToolPrimaryComponent { .. }
|
||||
)
|
||||
)
|
||||
})
|
||||
.and_then(|comp| {
|
||||
comp.components()
|
||||
.iter()
|
||||
.next()
|
||||
.map(|comp| comp.item_definition_id())
|
||||
})
|
||||
{
|
||||
let material = String::from(material);
|
||||
Some(Self::ModularWeapon { material })
|
||||
} else {
|
||||
None
|
||||
}
|
||||
},
|
||||
_ => None,
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone)]
|
||||
struct RawRepairRecipe {
|
||||
inputs: Vec<(RawRecipeInput, u32)>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone)]
|
||||
struct RawRepairRecipeBook {
|
||||
recipes: HashMap<RepairKey, RawRepairRecipe>,
|
||||
fallback: RawRepairRecipe,
|
||||
}
|
||||
|
||||
impl assets::Asset for RawRepairRecipeBook {
|
||||
type Loader = assets::RonLoader;
|
||||
|
||||
const EXTENSION: &'static str = "ron";
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone, Debug)]
|
||||
pub struct RepairRecipe {
|
||||
inputs: Vec<(RecipeInput, u32)>,
|
||||
}
|
||||
|
||||
impl RepairRecipe {
|
||||
/// Determine whether the inventory contains the ingredients for a repair.
|
||||
/// If it does, return a vec of inventory slots that contain the
|
||||
/// ingredients needed, whose positions correspond to particular repair
|
||||
/// inputs. If items are missing, return the missing items, and how many
|
||||
/// are missing.
|
||||
pub fn inventory_contains_ingredients(
|
||||
&self,
|
||||
inv: &Inventory,
|
||||
) -> Result<Vec<(u32, InvSlotId)>, Vec<(&RecipeInput, u32)>> {
|
||||
inventory_contains_ingredients(self.inputs(), inv, 1)
|
||||
}
|
||||
|
||||
pub fn inputs(&self) -> impl ExactSizeIterator<Item = (&RecipeInput, u32)> {
|
||||
self.inputs.iter().map(|(input, amount)| (input, *amount))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone, Debug)]
|
||||
pub struct RepairRecipeBook {
|
||||
recipes: HashMap<RepairKey, RepairRecipe>,
|
||||
fallback: RepairRecipe,
|
||||
}
|
||||
|
||||
impl RepairRecipeBook {
|
||||
pub fn repair_recipe(&self, item: &Item) -> Option<&RepairRecipe> {
|
||||
RepairKey::from_item(item)
|
||||
.as_ref()
|
||||
.and_then(|key| self.recipes.get(key))
|
||||
.or_else(|| item.has_durability().then_some(&self.fallback))
|
||||
}
|
||||
|
||||
pub fn repair_item(
|
||||
&self,
|
||||
inv: &mut Inventory,
|
||||
item: Slot,
|
||||
slots: Vec<(u32, InvSlotId)>,
|
||||
ability_map: &AbilityMap,
|
||||
msm: &MaterialStatManifest,
|
||||
) -> Result<(), Vec<(&RecipeInput, u32)>> {
|
||||
let mut slot_claims = HashMap::new();
|
||||
let mut unsatisfied_requirements = Vec::new();
|
||||
|
||||
if let Some(item) = match item {
|
||||
Slot::Equip(slot) => inv.equipped(slot),
|
||||
Slot::Inventory(slot) => inv.get(slot),
|
||||
} {
|
||||
if let Some(repair_recipe) = self.repair_recipe(item) {
|
||||
repair_recipe
|
||||
.inputs
|
||||
.iter()
|
||||
.enumerate()
|
||||
.for_each(|(i, (input, amount))| {
|
||||
// Gets all slots provided for this input by the frontend
|
||||
let input_slots = slots
|
||||
.iter()
|
||||
.filter_map(|(j, slot)| if i as u32 == *j { Some(slot) } else { None })
|
||||
.copied();
|
||||
// Checks if requirement is met, and if not marks it as unsatisfied
|
||||
input.handle_requirement(
|
||||
*amount,
|
||||
&mut slot_claims,
|
||||
&mut unsatisfied_requirements,
|
||||
inv,
|
||||
input_slots,
|
||||
);
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
if unsatisfied_requirements.is_empty() {
|
||||
for (slot, to_remove) in slot_claims.iter() {
|
||||
for _ in 0..*to_remove {
|
||||
let _ = inv
|
||||
.take(*slot, ability_map, msm)
|
||||
.expect("Expected item to exist in the inventory");
|
||||
}
|
||||
}
|
||||
|
||||
inv.repair_item_at_slot(item);
|
||||
|
||||
Ok(())
|
||||
} else {
|
||||
Err(unsatisfied_requirements)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl assets::Compound for RepairRecipeBook {
|
||||
fn load(
|
||||
cache: assets::AnyCache,
|
||||
specifier: &assets::SharedString,
|
||||
) -> Result<Self, assets::BoxedError> {
|
||||
#[inline]
|
||||
fn load_recipe_input(
|
||||
(input, amount): &(RawRecipeInput, u32),
|
||||
) -> Result<(RecipeInput, u32), assets::Error> {
|
||||
let input = input.load_recipe_input()?;
|
||||
Ok((input, *amount))
|
||||
}
|
||||
|
||||
let raw = cache.load::<RawRepairRecipeBook>(specifier)?.cloned();
|
||||
|
||||
let recipes = raw
|
||||
.recipes
|
||||
.iter()
|
||||
.map(|(key, RawRepairRecipe { inputs })| {
|
||||
let inputs = inputs
|
||||
.iter()
|
||||
.map(load_recipe_input)
|
||||
.collect::<Result<Vec<_>, _>>()?;
|
||||
Ok((key.clone(), RepairRecipe { inputs }))
|
||||
})
|
||||
.collect::<Result<_, assets::Error>>()?;
|
||||
|
||||
let fallback = RepairRecipe {
|
||||
inputs: raw
|
||||
.fallback
|
||||
.inputs
|
||||
.iter()
|
||||
.map(load_recipe_input)
|
||||
.collect::<Result<Vec<_>, _>>()?,
|
||||
};
|
||||
|
||||
Ok(RepairRecipeBook { recipes, fallback })
|
||||
}
|
||||
}
|
||||
|
||||
pub fn default_recipe_book() -> AssetHandle<RecipeBook> {
|
||||
RecipeBook::load_expect("common.recipe_book")
|
||||
}
|
||||
@ -908,6 +1101,10 @@ pub fn default_component_recipe_book() -> AssetHandle<ComponentRecipeBook> {
|
||||
ComponentRecipeBook::load_expect("common.component_recipe_book")
|
||||
}
|
||||
|
||||
pub fn default_repair_recipe_book() -> AssetHandle<RepairRecipeBook> {
|
||||
RepairRecipeBook::load_expect("common.repair_recipe_book")
|
||||
}
|
||||
|
||||
impl assets::Compound for ReverseComponentRecipeBook {
|
||||
fn load(
|
||||
cache: assets::AnyCache,
|
||||
|
@ -12,7 +12,9 @@ use common::{
|
||||
slot::{self, Slot},
|
||||
},
|
||||
consts::MAX_PICKUP_RANGE,
|
||||
recipe::{self, default_component_recipe_book, default_recipe_book},
|
||||
recipe::{
|
||||
self, default_component_recipe_book, default_recipe_book, default_repair_recipe_book,
|
||||
},
|
||||
terrain::{Block, SpriteKind},
|
||||
trade::Trades,
|
||||
uid::Uid,
|
||||
@ -856,10 +858,17 @@ pub fn handle_inventory(server: &mut Server, entity: EcsEntity, manip: comp::Inv
|
||||
None
|
||||
}
|
||||
},
|
||||
CraftEvent::Repair(slot) => {
|
||||
CraftEvent::Repair { item, slots } => {
|
||||
let repair_recipes = default_repair_recipe_book().read();
|
||||
let sprite = get_craft_sprite(state, craft_sprite);
|
||||
if matches!(sprite, Some(SpriteKind::RepairBench)) {
|
||||
inventory.repair_item_at_slot(slot);
|
||||
let _ = repair_recipes.repair_item(
|
||||
&mut inventory,
|
||||
item,
|
||||
slots,
|
||||
&state.ecs().read_resource::<AbilityMap>(),
|
||||
&state.ecs().read_resource::<item::MaterialStatManifest>(),
|
||||
);
|
||||
}
|
||||
None
|
||||
},
|
||||
|
@ -8,7 +8,7 @@ use crate::{
|
||||
use common::{
|
||||
comp::{self, Admin, Player, Stats},
|
||||
event::{EventBus, ServerEvent},
|
||||
recipe::{default_component_recipe_book, default_recipe_book},
|
||||
recipe::{default_component_recipe_book, default_recipe_book, default_repair_recipe_book},
|
||||
resources::TimeOfDay,
|
||||
shared_server_config::ServerConstants,
|
||||
uid::{Uid, UidAllocator},
|
||||
@ -348,6 +348,7 @@ impl<'a> System<'a> for Sys {
|
||||
world_map: (*read_data.map).clone(),
|
||||
recipe_book: default_recipe_book().cloned(),
|
||||
component_recipe_book: default_component_recipe_book().cloned(),
|
||||
repair_recipe_book: default_repair_recipe_book().cloned(),
|
||||
material_stats: (*read_data.material_stats).clone(),
|
||||
ability_map: (*read_data.ability_map).clone(),
|
||||
server_constants: ServerConstants {
|
||||
|
@ -726,7 +726,7 @@ pub enum Event {
|
||||
craft_sprite: Option<Vec3<i32>>,
|
||||
},
|
||||
RepairItem {
|
||||
slot: Slot,
|
||||
item: Slot,
|
||||
sprite_pos: Vec3<i32>,
|
||||
},
|
||||
InviteMember(Uid),
|
||||
@ -3944,7 +3944,7 @@ impl Hud {
|
||||
self.show.crafting_fields.craft_sprite
|
||||
{
|
||||
events.push(Event::RepairItem {
|
||||
slot: from,
|
||||
item: from,
|
||||
sprite_pos,
|
||||
})
|
||||
}
|
||||
|
@ -1777,8 +1777,27 @@ impl PlayState for SessionState {
|
||||
HudEvent::SalvageItem { slot, salvage_pos } => {
|
||||
self.client.borrow_mut().salvage_item(slot, salvage_pos);
|
||||
},
|
||||
HudEvent::RepairItem { slot, sprite_pos } => {
|
||||
self.client.borrow_mut().repair_item(slot, sprite_pos);
|
||||
HudEvent::RepairItem { item, sprite_pos } => {
|
||||
let slots = {
|
||||
let client = self.client.borrow();
|
||||
let slots = (|| {
|
||||
if let Some(inventory) = client.inventories().get(client.entity()) {
|
||||
let item = match item {
|
||||
Slot::Equip(slot) => inventory.equipped(slot),
|
||||
Slot::Inventory(slot) => inventory.get(slot),
|
||||
}?;
|
||||
let repair_recipe =
|
||||
client.repair_recipe_book().repair_recipe(item)?;
|
||||
repair_recipe.inventory_contains_ingredients(inventory).ok()
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})();
|
||||
slots.unwrap_or_default()
|
||||
};
|
||||
self.client
|
||||
.borrow_mut()
|
||||
.repair_item(item, slots, sprite_pos);
|
||||
},
|
||||
HudEvent::InviteMember(uid) => {
|
||||
self.client.borrow_mut().send_invite(uid, InviteKind::Group);
|
||||
|
Loading…
Reference in New Issue
Block a user