mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Repairing UI
This commit is contained in:
parent
536d88a2c7
commit
658de93c59
@ -14,6 +14,7 @@ hud-crafting-loom = Loom
|
||||
hud-crafting-spinning_wheel = Spinning Wheel
|
||||
hud-crafting-tanning_rack = Tanning Rack
|
||||
hud-crafting-salvaging_station = Salvaging Bench
|
||||
hud-crafting-repair_bench = Repair Bench
|
||||
hud-crafting-campfire = Campfire
|
||||
hud-crafting-tabs-all = All
|
||||
hud-crafting-tabs-armor = Armor
|
||||
@ -34,11 +35,8 @@ hud-crafting-dismantle_explanation =
|
||||
|
||||
Double-Click them to start dismantling.
|
||||
hud-crafting-repair_title = Repair Items
|
||||
hud-crafting-repair_explanation =
|
||||
Repair your damaged and
|
||||
broken equipment here.
|
||||
|
||||
Double-Click the item to repair it.
|
||||
hud-crafting-repair_slot_title = Damaged Item
|
||||
hud-crafting-repair_slot_desc = Place a damaged item here to repair it.
|
||||
hud-crafting-modular_desc = Drag Item-Parts here to craft a weapon
|
||||
hud-crafting-mod_weap_prim_slot_title = Primary Weapon Component
|
||||
hud-crafting-mod_weap_prim_slot_desc = Place a primary weapon component here (e.g. a sword blade, axe head, or bow limbs).
|
||||
|
@ -39,6 +39,10 @@
|
||||
"voxel.sprite.salvaging_station.salvaging_station-0",
|
||||
(0.0, 0.0, 0.0), (-50.0, 40.0, 30.0), 0.9,
|
||||
),
|
||||
Simple("RepairBench"): VoxTrans(
|
||||
"voxel.sprite.repair_bench.repair_bench-0",
|
||||
(0.0, 0.0, 0.0), (-50.0, 40.0, 30.0), 0.9,
|
||||
),
|
||||
// Weapons
|
||||
// Diary Example Images
|
||||
Simple("example_utility"): VoxTrans(
|
||||
|
@ -22,7 +22,7 @@ use common::{
|
||||
Item, ItemBase, ItemDef, ItemDesc, ItemKind, ItemTag, MaterialStatManifest, Quality,
|
||||
TagExampleInfo,
|
||||
},
|
||||
slot::InvSlotId,
|
||||
slot::{InvSlotId, Slot},
|
||||
Inventory,
|
||||
},
|
||||
recipe::{ComponentKey, Recipe, RecipeInput},
|
||||
@ -86,10 +86,7 @@ widget_ids! {
|
||||
dismantle_title,
|
||||
dismantle_img,
|
||||
dismantle_txt,
|
||||
repair_title,
|
||||
repair_img,
|
||||
repair_txt,
|
||||
modular_inputs[],
|
||||
craft_slots[],
|
||||
modular_art,
|
||||
modular_desc_txt,
|
||||
modular_wep_empty_bg,
|
||||
@ -117,6 +114,9 @@ pub enum Event {
|
||||
Focus(widget::Id),
|
||||
SearchRecipe(Option<String>),
|
||||
ClearRecipeInputs,
|
||||
RepairItem {
|
||||
slot: Slot,
|
||||
},
|
||||
}
|
||||
|
||||
pub struct CraftingShow {
|
||||
@ -126,7 +126,7 @@ pub struct CraftingShow {
|
||||
pub salvage: bool,
|
||||
pub repair: bool,
|
||||
// TODO: Maybe try to do something that doesn't need to allocate?
|
||||
pub recipe_inputs: HashMap<u32, InvSlotId>,
|
||||
pub recipe_inputs: HashMap<u32, Slot>,
|
||||
}
|
||||
|
||||
impl Default for CraftingShow {
|
||||
@ -282,7 +282,7 @@ impl CraftingTab {
|
||||
|
||||
// Tells UI whether tab is an adhoc tab that should only sometimes be present
|
||||
// depending on what station is accessed
|
||||
fn is_adhoc(self) -> bool { matches!(self, CraftingTab::Dismantle | CraftingTab::Repair) }
|
||||
fn is_adhoc(self) -> bool { matches!(self, CraftingTab::Dismantle) }
|
||||
}
|
||||
|
||||
pub struct State {
|
||||
@ -534,40 +534,45 @@ impl<'a> Widget for Crafting<'a> {
|
||||
let weapon_recipe = make_pseudo_recipe(SpriteKind::CraftingBench);
|
||||
let metal_comp_recipe = make_pseudo_recipe(SpriteKind::Anvil);
|
||||
let wood_comp_recipe = make_pseudo_recipe(SpriteKind::CraftingBench);
|
||||
let modular_entries = {
|
||||
let repair_recipe = make_pseudo_recipe(SpriteKind::RepairBench);
|
||||
let pseudo_entries = {
|
||||
// A BTreeMap is used over a HashMap as when a HashMap is used, the UI shuffles
|
||||
// the positions of these every tick, so a BTreeMap is necessary to keep it
|
||||
// ordered.
|
||||
let mut modular_entries = BTreeMap::new();
|
||||
modular_entries.insert(
|
||||
let mut pseudo_entries = BTreeMap::new();
|
||||
pseudo_entries.insert(
|
||||
String::from("veloren.core.pseudo_recipe.modular_weapon"),
|
||||
(&weapon_recipe, "Modular Weapon"),
|
||||
(&weapon_recipe, "Modular Weapon", CraftingTab::Weapon),
|
||||
);
|
||||
modular_entries.insert(
|
||||
pseudo_entries.insert(
|
||||
String::from("veloren.core.pseudo_recipe.modular_weapon_component.sword"),
|
||||
(&metal_comp_recipe, "Sword Blade"),
|
||||
(&metal_comp_recipe, "Sword Blade", CraftingTab::Weapon),
|
||||
);
|
||||
modular_entries.insert(
|
||||
pseudo_entries.insert(
|
||||
String::from("veloren.core.pseudo_recipe.modular_weapon_component.axe"),
|
||||
(&metal_comp_recipe, "Axe Head"),
|
||||
(&metal_comp_recipe, "Axe Head", CraftingTab::Weapon),
|
||||
);
|
||||
modular_entries.insert(
|
||||
pseudo_entries.insert(
|
||||
String::from("veloren.core.pseudo_recipe.modular_weapon_component.hammer"),
|
||||
(&metal_comp_recipe, "Hammer Head"),
|
||||
(&metal_comp_recipe, "Hammer Head", CraftingTab::Weapon),
|
||||
);
|
||||
modular_entries.insert(
|
||||
pseudo_entries.insert(
|
||||
String::from("veloren.core.pseudo_recipe.modular_weapon_component.bow"),
|
||||
(&wood_comp_recipe, "Bow Limbs"),
|
||||
(&wood_comp_recipe, "Bow Limbs", CraftingTab::Weapon),
|
||||
);
|
||||
modular_entries.insert(
|
||||
pseudo_entries.insert(
|
||||
String::from("veloren.core.pseudo_recipe.modular_weapon_component.staff"),
|
||||
(&wood_comp_recipe, "Staff Shaft"),
|
||||
(&wood_comp_recipe, "Staff Shaft", CraftingTab::Weapon),
|
||||
);
|
||||
modular_entries.insert(
|
||||
pseudo_entries.insert(
|
||||
String::from("veloren.core.pseudo_recipe.modular_weapon_component.sceptre"),
|
||||
(&wood_comp_recipe, "Sceptre Shaft"),
|
||||
(&wood_comp_recipe, "Sceptre Shaft", CraftingTab::Weapon),
|
||||
);
|
||||
modular_entries
|
||||
pseudo_entries.insert(
|
||||
String::from("veloren.core.pseudo_recipe.repair"),
|
||||
(&repair_recipe, "Repair Equipment", CraftingTab::Repair),
|
||||
);
|
||||
pseudo_entries
|
||||
};
|
||||
|
||||
// First available recipes, then ones with available materials,
|
||||
@ -618,36 +623,34 @@ impl<'a> Widget for Crafting<'a> {
|
||||
(name, recipe, is_craftable, has_materials)
|
||||
})
|
||||
.chain(
|
||||
matches!(sel_crafting_tab, CraftingTab::Weapon | CraftingTab::All)
|
||||
.then_some(
|
||||
modular_entries
|
||||
.iter()
|
||||
.filter(|(_, (_, output_name))| {
|
||||
match search_filter {
|
||||
SearchFilter::None => {
|
||||
let output_name = output_name.to_lowercase();
|
||||
search_keys
|
||||
.iter()
|
||||
.all(|&substring| output_name.contains(substring))
|
||||
},
|
||||
// TODO: Get input filtering to work here, probably requires
|
||||
// checking component recipe book?
|
||||
SearchFilter::Input => false,
|
||||
SearchFilter::Nonexistent => false,
|
||||
}
|
||||
})
|
||||
.map(|(recipe_name, (recipe, _))| {
|
||||
(
|
||||
recipe_name,
|
||||
*recipe,
|
||||
self.show.crafting_fields.craft_sprite.map(|(_, s)| s)
|
||||
== recipe.craft_sprite,
|
||||
true,
|
||||
)
|
||||
}),
|
||||
)
|
||||
.into_iter()
|
||||
.flatten(),
|
||||
pseudo_entries
|
||||
.iter()
|
||||
// Filter by selected tab
|
||||
.filter(|(_, (_, _, tab))| *sel_crafting_tab == CraftingTab::All || sel_crafting_tab == tab)
|
||||
// Filter by search filter
|
||||
.filter(|(_, (_, output_name, _))| {
|
||||
match search_filter {
|
||||
SearchFilter::None => {
|
||||
let output_name = output_name.to_lowercase();
|
||||
search_keys
|
||||
.iter()
|
||||
.all(|&substring| output_name.contains(substring))
|
||||
},
|
||||
// TODO: Get input filtering to work here, probably requires
|
||||
// checking component recipe book?
|
||||
SearchFilter::Input => false,
|
||||
SearchFilter::Nonexistent => false,
|
||||
}
|
||||
})
|
||||
.map(|(recipe_name, (recipe, _, _))| {
|
||||
(
|
||||
recipe_name,
|
||||
*recipe,
|
||||
self.show.crafting_fields.craft_sprite.map(|(_, s)| s)
|
||||
== recipe.craft_sprite,
|
||||
true,
|
||||
)
|
||||
}),
|
||||
)
|
||||
.collect();
|
||||
ordered_recipes.sort_by_key(|(_, recipe, is_craftable, has_materials)| {
|
||||
@ -660,7 +663,7 @@ impl<'a> Widget for Crafting<'a> {
|
||||
});
|
||||
|
||||
// Recipe list
|
||||
let recipe_list_length = self.client.recipe_book().iter().len() + modular_entries.len();
|
||||
let recipe_list_length = self.client.recipe_book().iter().len() + pseudo_entries.len();
|
||||
if state.ids.recipe_list_btns.len() < recipe_list_length {
|
||||
state.update(|state| {
|
||||
state
|
||||
@ -715,11 +718,12 @@ impl<'a> Widget for Crafting<'a> {
|
||||
.press_image(self.imgs.selection_press)
|
||||
.image_color(color::rgba(1.0, 0.82, 0.27, 1.0));
|
||||
|
||||
let recipe_name = if let Some((_recipe, modular_name)) = modular_entries.get(name) {
|
||||
*modular_name
|
||||
} else {
|
||||
&recipe.output.0.name
|
||||
};
|
||||
let recipe_name =
|
||||
if let Some((_recipe, pseudo_name, _filter_tab)) = pseudo_entries.get(name) {
|
||||
*pseudo_name
|
||||
} else {
|
||||
&recipe.output.0.name
|
||||
};
|
||||
|
||||
let text = Text::new(recipe_name)
|
||||
.color(if is_craftable {
|
||||
@ -821,7 +825,8 @@ impl<'a> Widget for Crafting<'a> {
|
||||
// Selected Recipe
|
||||
if let Some((recipe_name, recipe)) = match state.selected_recipe.as_deref() {
|
||||
Some(selected_recipe) => {
|
||||
if let Some((modular_recipe, _modular_name)) = modular_entries.get(selected_recipe)
|
||||
if let Some((modular_recipe, _pseudo_name, _filter_tab)) =
|
||||
pseudo_entries.get(selected_recipe)
|
||||
{
|
||||
Some((selected_recipe, *modular_recipe))
|
||||
} else {
|
||||
@ -834,8 +839,10 @@ impl<'a> Widget for Crafting<'a> {
|
||||
None => None,
|
||||
} {
|
||||
let recipe_name = String::from(recipe_name);
|
||||
let title = if let Some((_recipe, modular_name)) = modular_entries.get(&recipe_name) {
|
||||
*modular_name
|
||||
let title = if let Some((_recipe, pseudo_name, _filter_tab)) =
|
||||
pseudo_entries.get(&recipe_name)
|
||||
{
|
||||
*pseudo_name
|
||||
} else {
|
||||
&recipe.output.0.name
|
||||
};
|
||||
@ -853,6 +860,7 @@ impl<'a> Widget for Crafting<'a> {
|
||||
ModularWeapon,
|
||||
Component(ToolKind),
|
||||
Simple,
|
||||
Repair,
|
||||
}
|
||||
|
||||
let recipe_kind = match recipe_name.as_str() {
|
||||
@ -875,37 +883,36 @@ impl<'a> Widget for Crafting<'a> {
|
||||
"veloren.core.pseudo_recipe.modular_weapon_component.sceptre" => {
|
||||
RecipeKind::Component(ToolKind::Sceptre)
|
||||
},
|
||||
"veloren.core.pseudo_recipe.repair" => RecipeKind::Repair,
|
||||
_ => RecipeKind::Simple,
|
||||
};
|
||||
|
||||
// Output slot, tags, and modular input slots
|
||||
let (modular_primary_slot, modular_secondary_slot, can_perform) = match recipe_kind {
|
||||
RecipeKind::ModularWeapon | RecipeKind::Component(_) => {
|
||||
let mut slot_maker = SlotMaker {
|
||||
empty_slot: self.imgs.inv_slot,
|
||||
filled_slot: self.imgs.inv_slot,
|
||||
selected_slot: self.imgs.inv_slot_sel,
|
||||
background_color: Some(UI_MAIN),
|
||||
content_size: ContentSize {
|
||||
width_height_ratio: 1.0,
|
||||
max_fraction: 0.75,
|
||||
},
|
||||
selected_content_scale: 1.067,
|
||||
amount_font: self.fonts.cyri.conrod_id,
|
||||
amount_margins: Vec2::new(-4.0, 0.0),
|
||||
amount_font_size: self.fonts.cyri.scale(12),
|
||||
amount_text_color: TEXT_COLOR,
|
||||
content_source: self.inventory,
|
||||
image_source: self.item_imgs,
|
||||
slot_manager: Some(self.slot_manager),
|
||||
pulse: self.pulse,
|
||||
};
|
||||
let mut slot_maker = SlotMaker {
|
||||
empty_slot: self.imgs.inv_slot,
|
||||
filled_slot: self.imgs.inv_slot,
|
||||
selected_slot: self.imgs.inv_slot_sel,
|
||||
background_color: Some(UI_MAIN),
|
||||
content_size: ContentSize {
|
||||
width_height_ratio: 1.0,
|
||||
max_fraction: 0.75,
|
||||
},
|
||||
selected_content_scale: 1.067,
|
||||
amount_font: self.fonts.cyri.conrod_id,
|
||||
amount_margins: Vec2::new(-4.0, 0.0),
|
||||
amount_font_size: self.fonts.cyri.scale(12),
|
||||
amount_text_color: TEXT_COLOR,
|
||||
content_source: self.inventory,
|
||||
image_source: self.item_imgs,
|
||||
slot_manager: Some(self.slot_manager),
|
||||
pulse: self.pulse,
|
||||
};
|
||||
|
||||
if state.ids.modular_inputs.len() < 2 {
|
||||
// Output slot, tags, and modular input slots
|
||||
let (craft_slot_1, craft_slot_2, can_perform) = match recipe_kind {
|
||||
RecipeKind::ModularWeapon | RecipeKind::Component(_) => {
|
||||
if state.ids.craft_slots.len() < 2 {
|
||||
state.update(|s| {
|
||||
s.ids
|
||||
.modular_inputs
|
||||
.resize(2, &mut ui.widget_id_generator());
|
||||
s.ids.craft_slots.resize(2, &mut ui.widget_id_generator());
|
||||
});
|
||||
}
|
||||
// Modular Weapon Crafting BG-Art
|
||||
@ -916,7 +923,7 @@ impl<'a> Widget for Crafting<'a> {
|
||||
|
||||
let primary_slot = CraftSlot {
|
||||
index: 0,
|
||||
invslot: self.show.crafting_fields.recipe_inputs.get(&0).copied(),
|
||||
slot: self.show.crafting_fields.recipe_inputs.get(&0).copied(),
|
||||
requirement: match recipe_kind {
|
||||
RecipeKind::ModularWeapon => |item, _, _| {
|
||||
matches!(
|
||||
@ -939,11 +946,13 @@ impl<'a> Widget for Crafting<'a> {
|
||||
false
|
||||
}
|
||||
},
|
||||
RecipeKind::Simple => |_, _, _| unreachable!(),
|
||||
RecipeKind::Simple | RecipeKind::Repair => |_, _, _| unreachable!(),
|
||||
},
|
||||
info: match recipe_kind {
|
||||
RecipeKind::Component(toolkind) => Some(CraftSlotInfo::Tool(toolkind)),
|
||||
RecipeKind::ModularWeapon | RecipeKind::Simple => None,
|
||||
RecipeKind::ModularWeapon | RecipeKind::Simple | RecipeKind::Repair => {
|
||||
None
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
@ -952,10 +961,7 @@ impl<'a> Widget for Crafting<'a> {
|
||||
.top_left_with_margins_on(state.ids.modular_art, 4.0, 4.0)
|
||||
.parent(state.ids.align_ing);
|
||||
|
||||
if let Some(item) = primary_slot
|
||||
.invslot
|
||||
.and_then(|slot| self.inventory.get(slot))
|
||||
{
|
||||
if let Some(item) = primary_slot.item(self.inventory) {
|
||||
primary_slot_widget
|
||||
.with_item_tooltip(
|
||||
self.item_tooltip_manager,
|
||||
@ -963,7 +969,7 @@ impl<'a> Widget for Crafting<'a> {
|
||||
&None,
|
||||
&item_tooltip,
|
||||
)
|
||||
.set(state.ids.modular_inputs[0], ui);
|
||||
.set(state.ids.craft_slots[0], ui);
|
||||
} else {
|
||||
let (tooltip_title, tooltip_desc) = match recipe_kind {
|
||||
RecipeKind::ModularWeapon => (
|
||||
@ -988,7 +994,7 @@ impl<'a> Widget for Crafting<'a> {
|
||||
self.localized_strings
|
||||
.get_msg("hud-crafting-mod_comp_wood_prim_slot_desc"),
|
||||
),
|
||||
RecipeKind::Component(_) | RecipeKind::Simple => {
|
||||
RecipeKind::Component(_) | RecipeKind::Simple | RecipeKind::Repair => {
|
||||
(Cow::Borrowed(""), Cow::Borrowed(""))
|
||||
},
|
||||
};
|
||||
@ -1000,12 +1006,12 @@ impl<'a> Widget for Crafting<'a> {
|
||||
&tabs_tooltip,
|
||||
TEXT_COLOR,
|
||||
)
|
||||
.set(state.ids.modular_inputs[0], ui);
|
||||
.set(state.ids.craft_slots[0], ui);
|
||||
}
|
||||
|
||||
let secondary_slot = CraftSlot {
|
||||
index: 1,
|
||||
invslot: self.show.crafting_fields.recipe_inputs.get(&1).copied(),
|
||||
slot: self.show.crafting_fields.recipe_inputs.get(&1).copied(),
|
||||
requirement: match recipe_kind {
|
||||
RecipeKind::ModularWeapon => |item, _, _| {
|
||||
matches!(
|
||||
@ -1028,11 +1034,13 @@ impl<'a> Widget for Crafting<'a> {
|
||||
false
|
||||
}
|
||||
},
|
||||
RecipeKind::Simple => |_, _, _| unreachable!(),
|
||||
RecipeKind::Simple | RecipeKind::Repair => |_, _, _| unreachable!(),
|
||||
},
|
||||
info: match recipe_kind {
|
||||
RecipeKind::Component(toolkind) => Some(CraftSlotInfo::Tool(toolkind)),
|
||||
RecipeKind::ModularWeapon | RecipeKind::Simple => None,
|
||||
RecipeKind::ModularWeapon | RecipeKind::Simple | RecipeKind::Repair => {
|
||||
None
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
@ -1041,10 +1049,7 @@ impl<'a> Widget for Crafting<'a> {
|
||||
.top_right_with_margins_on(state.ids.modular_art, 4.0, 4.0)
|
||||
.parent(state.ids.align_ing);
|
||||
|
||||
if let Some(item) = secondary_slot
|
||||
.invslot
|
||||
.and_then(|slot| self.inventory.get(slot))
|
||||
{
|
||||
if let Some(item) = secondary_slot.item(self.inventory) {
|
||||
secondary_slot_widget
|
||||
.with_item_tooltip(
|
||||
self.item_tooltip_manager,
|
||||
@ -1052,7 +1057,7 @@ impl<'a> Widget for Crafting<'a> {
|
||||
&None,
|
||||
&item_tooltip,
|
||||
)
|
||||
.set(state.ids.modular_inputs[1], ui);
|
||||
.set(state.ids.craft_slots[1], ui);
|
||||
} else {
|
||||
let (tooltip_title, tooltip_desc) = match recipe_kind {
|
||||
RecipeKind::ModularWeapon => (
|
||||
@ -1067,7 +1072,9 @@ impl<'a> Widget for Crafting<'a> {
|
||||
self.localized_strings
|
||||
.get_msg("hud-crafting-mod_comp_sec_slot_desc"),
|
||||
),
|
||||
RecipeKind::Simple => (Cow::Borrowed(""), Cow::Borrowed("")),
|
||||
RecipeKind::Simple | RecipeKind::Repair => {
|
||||
(Cow::Borrowed(""), Cow::Borrowed(""))
|
||||
},
|
||||
};
|
||||
secondary_slot_widget
|
||||
.with_tooltip(
|
||||
@ -1077,11 +1084,11 @@ impl<'a> Widget for Crafting<'a> {
|
||||
&tabs_tooltip,
|
||||
TEXT_COLOR,
|
||||
)
|
||||
.set(state.ids.modular_inputs[1], ui);
|
||||
.set(state.ids.craft_slots[1], ui);
|
||||
}
|
||||
|
||||
let prim_item_placed = primary_slot.invslot.is_some();
|
||||
let sec_item_placed = secondary_slot.invslot.is_some();
|
||||
let prim_item_placed = primary_slot.slot.is_some();
|
||||
let sec_item_placed = secondary_slot.slot.is_some();
|
||||
|
||||
let prim_icon = match recipe_kind {
|
||||
RecipeKind::ModularWeapon => self.imgs.icon_primary_comp,
|
||||
@ -1109,18 +1116,18 @@ impl<'a> Widget for Crafting<'a> {
|
||||
let bg_col = Color::Rgba(1.0, 1.0, 1.0, 0.4);
|
||||
if !prim_item_placed {
|
||||
Image::new(prim_icon)
|
||||
.middle_of(state.ids.modular_inputs[0])
|
||||
.middle_of(state.ids.craft_slots[0])
|
||||
.color(Some(bg_col))
|
||||
.w_h(34.0, 34.0)
|
||||
.graphics_for(state.ids.modular_inputs[0])
|
||||
.graphics_for(state.ids.craft_slots[0])
|
||||
.set(state.ids.modular_wep_ing_1_bg, ui);
|
||||
}
|
||||
if !sec_item_placed {
|
||||
Image::new(sec_icon)
|
||||
.middle_of(state.ids.modular_inputs[1])
|
||||
.middle_of(state.ids.craft_slots[1])
|
||||
.color(Some(bg_col))
|
||||
.w_h(50.0, 50.0)
|
||||
.graphics_for(state.ids.modular_inputs[1])
|
||||
.graphics_for(state.ids.craft_slots[1])
|
||||
.set(state.ids.modular_wep_ing_2_bg, ui);
|
||||
}
|
||||
|
||||
@ -1129,10 +1136,8 @@ impl<'a> Widget for Crafting<'a> {
|
||||
|
||||
let output_item = match recipe_kind {
|
||||
RecipeKind::ModularWeapon => {
|
||||
if let Some((primary_comp, toolkind, hand_restriction)) = primary_slot
|
||||
.invslot
|
||||
.and_then(|slot| self.inventory.get(slot))
|
||||
.and_then(|item| {
|
||||
if let Some((primary_comp, toolkind, hand_restriction)) =
|
||||
primary_slot.item(self.inventory).and_then(|item| {
|
||||
if let ItemKind::ModularComponent(
|
||||
ModularComponent::ToolPrimaryComponent {
|
||||
toolkind,
|
||||
@ -1148,8 +1153,7 @@ impl<'a> Widget for Crafting<'a> {
|
||||
})
|
||||
{
|
||||
secondary_slot
|
||||
.invslot
|
||||
.and_then(|slot| self.inventory.get(slot))
|
||||
.item(self.inventory)
|
||||
.filter(|item| {
|
||||
matches!(
|
||||
&*item.kind(),
|
||||
@ -1174,22 +1178,19 @@ impl<'a> Widget for Crafting<'a> {
|
||||
}
|
||||
},
|
||||
RecipeKind::Component(toolkind) => {
|
||||
if let Some(material) = primary_slot
|
||||
.invslot
|
||||
.and_then(|slot| self.inventory.get(slot))
|
||||
.and_then(|item| {
|
||||
if let Some(material) =
|
||||
primary_slot.item(self.inventory).and_then(|item| {
|
||||
item.item_definition_id().itemdef_id().map(String::from)
|
||||
})
|
||||
{
|
||||
let component_key = ComponentKey {
|
||||
toolkind,
|
||||
material,
|
||||
modifier: secondary_slot
|
||||
.invslot
|
||||
.and_then(|slot| self.inventory.get(slot))
|
||||
.and_then(|item| {
|
||||
modifier: secondary_slot.item(self.inventory).and_then(
|
||||
|item| {
|
||||
item.item_definition_id().itemdef_id().map(String::from)
|
||||
}),
|
||||
},
|
||||
),
|
||||
};
|
||||
self.client.component_recipe_book().get(&component_key).map(
|
||||
|component_recipe| {
|
||||
@ -1200,7 +1201,7 @@ impl<'a> Widget for Crafting<'a> {
|
||||
None
|
||||
}
|
||||
},
|
||||
RecipeKind::Simple => None,
|
||||
RecipeKind::Simple | RecipeKind::Repair => None,
|
||||
};
|
||||
|
||||
if let Some(output_item) = output_item {
|
||||
@ -1226,8 +1227,8 @@ impl<'a> Widget for Crafting<'a> {
|
||||
)
|
||||
.set(state.ids.output_img, ui);
|
||||
(
|
||||
primary_slot.invslot,
|
||||
secondary_slot.invslot,
|
||||
primary_slot.slot,
|
||||
secondary_slot.slot,
|
||||
self.show.crafting_fields.craft_sprite.map(|(_, s)| s)
|
||||
== recipe.craft_sprite,
|
||||
)
|
||||
@ -1244,7 +1245,7 @@ impl<'a> Widget for Crafting<'a> {
|
||||
.w_h(70.0, 70.0)
|
||||
.graphics_for(state.ids.output_img)
|
||||
.set(state.ids.modular_wep_empty_bg, ui);
|
||||
(primary_slot.invslot, secondary_slot.invslot, false)
|
||||
(primary_slot.slot, secondary_slot.slot, false)
|
||||
}
|
||||
},
|
||||
RecipeKind::Simple => {
|
||||
@ -1349,6 +1350,64 @@ impl<'a> Widget for Crafting<'a> {
|
||||
}),
|
||||
)
|
||||
},
|
||||
RecipeKind::Repair => {
|
||||
if state.ids.craft_slots.len() < 1 {
|
||||
state.update(|s| {
|
||||
s.ids.craft_slots.resize(1, &mut ui.widget_id_generator());
|
||||
});
|
||||
}
|
||||
|
||||
// Slot for item to be repaired
|
||||
let repair_slot = CraftSlot {
|
||||
index: 0,
|
||||
slot: self.show.crafting_fields.recipe_inputs.get(&0).copied(),
|
||||
requirement: |item, _, _| item.durability().map_or(false, |d| d > 0),
|
||||
info: None,
|
||||
};
|
||||
|
||||
let repair_slot_widget = slot_maker
|
||||
.fabricate(repair_slot, [40.0; 2])
|
||||
.mid_top_with_margin_on(state.ids.align_ing, 20.0)
|
||||
.parent(state.ids.align_ing);
|
||||
|
||||
if let Some(item) = repair_slot.item(self.inventory) {
|
||||
repair_slot_widget
|
||||
.with_item_tooltip(
|
||||
self.item_tooltip_manager,
|
||||
core::iter::once(item as &dyn ItemDesc),
|
||||
&None,
|
||||
&item_tooltip,
|
||||
)
|
||||
.set(state.ids.craft_slots[0], ui);
|
||||
} else {
|
||||
repair_slot_widget
|
||||
.with_tooltip(
|
||||
self.tooltip_manager,
|
||||
&self
|
||||
.localized_strings
|
||||
.get_msg("hud-crafting-repair_slot_title"),
|
||||
&self
|
||||
.localized_strings
|
||||
.get_msg("hud-crafting-repair_slot_desc"),
|
||||
&tabs_tooltip,
|
||||
TEXT_COLOR,
|
||||
)
|
||||
.set(state.ids.craft_slots[0], ui);
|
||||
}
|
||||
|
||||
let can_perform = repair_slot.item(self.inventory).map_or(false, |item| {
|
||||
self.client.repair_recipe_book().repair_recipe(item).map_or(
|
||||
false,
|
||||
|recipe| {
|
||||
recipe
|
||||
.inventory_contains_ingredients(item, self.inventory)
|
||||
.is_ok()
|
||||
},
|
||||
)
|
||||
});
|
||||
|
||||
(repair_slot.slot, None, can_perform)
|
||||
},
|
||||
};
|
||||
|
||||
// Craft button
|
||||
@ -1386,8 +1445,10 @@ impl<'a> Widget for Crafting<'a> {
|
||||
{
|
||||
match recipe_kind {
|
||||
RecipeKind::ModularWeapon => {
|
||||
if let (Some(primary_slot), Some(secondary_slot)) =
|
||||
(modular_primary_slot, modular_secondary_slot)
|
||||
if let (
|
||||
Some(Slot::Inventory(primary_slot)),
|
||||
Some(Slot::Inventory(secondary_slot)),
|
||||
) = (craft_slot_1, craft_slot_2)
|
||||
{
|
||||
events.push(Event::CraftModularWeapon {
|
||||
primary_slot,
|
||||
@ -1396,11 +1457,14 @@ impl<'a> Widget for Crafting<'a> {
|
||||
}
|
||||
},
|
||||
RecipeKind::Component(toolkind) => {
|
||||
if let Some(primary_slot) = modular_primary_slot {
|
||||
if let Some(Slot::Inventory(primary_slot)) = craft_slot_1 {
|
||||
events.push(Event::CraftModularWeaponComponent {
|
||||
toolkind,
|
||||
material: primary_slot,
|
||||
modifier: modular_secondary_slot,
|
||||
modifier: craft_slot_2.and_then(|slot| match slot {
|
||||
Slot::Inventory(slot) => Some(slot),
|
||||
Slot::Equip(_) => None,
|
||||
}),
|
||||
});
|
||||
}
|
||||
},
|
||||
@ -1408,6 +1472,11 @@ impl<'a> Widget for Crafting<'a> {
|
||||
recipe_name,
|
||||
amount: 1,
|
||||
}),
|
||||
RecipeKind::Repair => {
|
||||
if let Some(slot) = craft_slot_1 {
|
||||
events.push(Event::RepairItem { slot });
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@ -1477,6 +1546,9 @@ impl<'a> Widget for Crafting<'a> {
|
||||
RecipeKind::ModularWeapon | RecipeKind::Component(_) => {
|
||||
t.top_left_with_margins_on(state.ids.align_ing, 325.0, 5.0)
|
||||
},
|
||||
RecipeKind::Repair => {
|
||||
t.top_left_with_margins_on(state.ids.align_ing, 80.0, 5.0)
|
||||
},
|
||||
})
|
||||
.set(state.ids.req_station_title, ui);
|
||||
let station_img = match recipe.craft_sprite {
|
||||
@ -1489,6 +1561,7 @@ impl<'a> Widget for Crafting<'a> {
|
||||
Some(SpriteKind::SpinningWheel) => "SpinningWheel",
|
||||
Some(SpriteKind::TanningRack) => "TanningRack",
|
||||
Some(SpriteKind::DismantlingBench) => "DismantlingBench",
|
||||
Some(SpriteKind::RepairBench) => "RepairBench",
|
||||
None => "CraftsmanHammer",
|
||||
_ => "CraftsmanHammer",
|
||||
};
|
||||
@ -1513,6 +1586,7 @@ impl<'a> Widget for Crafting<'a> {
|
||||
Some(SpriteKind::SpinningWheel) => "hud-crafting-spinning_wheel",
|
||||
Some(SpriteKind::TanningRack) => "hud-crafting-tanning_rack",
|
||||
Some(SpriteKind::DismantlingBench) => "hud-crafting-salvaging_station",
|
||||
Some(SpriteKind::RepairBench) => "hud-crafting-repair_bench",
|
||||
_ => "",
|
||||
};
|
||||
Text::new(&self.localized_strings.get_msg(station_name))
|
||||
@ -1532,7 +1606,7 @@ impl<'a> Widget for Crafting<'a> {
|
||||
}
|
||||
// Ingredients Text
|
||||
// Hack from Sharp to account for iterators not having the same type
|
||||
let (mut iter_a, mut iter_b, mut iter_c);
|
||||
let (mut iter_a, mut iter_b, mut iter_c, mut iter_d);
|
||||
let ingredients = match recipe_kind {
|
||||
RecipeKind::Simple => {
|
||||
iter_a = recipe
|
||||
@ -1546,15 +1620,21 @@ impl<'a> Widget for Crafting<'a> {
|
||||
&mut iter_b
|
||||
},
|
||||
RecipeKind::Component(toolkind) => {
|
||||
if let Some(material) = modular_primary_slot
|
||||
.and_then(|slot| self.inventory.get(slot))
|
||||
if let Some(material) = craft_slot_1
|
||||
.and_then(|slot| match slot {
|
||||
Slot::Inventory(slot) => self.inventory.get(slot),
|
||||
Slot::Equip(_) => None,
|
||||
})
|
||||
.and_then(|item| item.item_definition_id().itemdef_id().map(String::from))
|
||||
{
|
||||
let component_key = ComponentKey {
|
||||
toolkind,
|
||||
material,
|
||||
modifier: modular_secondary_slot
|
||||
.and_then(|slot| self.inventory.get(slot))
|
||||
modifier: craft_slot_2
|
||||
.and_then(|slot| match slot {
|
||||
Slot::Inventory(slot) => self.inventory.get(slot),
|
||||
Slot::Equip(_) => None,
|
||||
})
|
||||
.and_then(|item| {
|
||||
item.item_definition_id().itemdef_id().map(String::from)
|
||||
}),
|
||||
@ -1573,6 +1653,24 @@ impl<'a> Widget for Crafting<'a> {
|
||||
&mut iter_b
|
||||
}
|
||||
},
|
||||
RecipeKind::Repair => {
|
||||
if let Some(item) = match craft_slot_1 {
|
||||
Some(Slot::Inventory(slot)) => self.inventory.get(slot),
|
||||
Some(Slot::Equip(slot)) => self.inventory.equipped(slot),
|
||||
None => None,
|
||||
} {
|
||||
if let Some(recipe) = self.client.repair_recipe_book().repair_recipe(item) {
|
||||
iter_d = recipe.inputs(item);
|
||||
&mut iter_d as &mut dyn ExactSizeIterator<Item = _>
|
||||
} else {
|
||||
iter_b = core::iter::empty();
|
||||
&mut iter_b
|
||||
}
|
||||
} else {
|
||||
iter_b = core::iter::empty();
|
||||
&mut iter_b
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
let num_ingredients = ingredients.len();
|
||||
@ -1861,42 +1959,6 @@ impl<'a> Widget for Crafting<'a> {
|
||||
.color(TEXT_COLOR)
|
||||
.parent(state.ids.window)
|
||||
.set(state.ids.dismantle_txt, ui);
|
||||
} else if *sel_crafting_tab == CraftingTab::Repair {
|
||||
// Title
|
||||
Text::new(&self.localized_strings.get_msg("hud-crafting-repair_title"))
|
||||
.mid_top_with_margin_on(state.ids.align_ing, 0.0)
|
||||
.font_id(self.fonts.cyri.conrod_id)
|
||||
.font_size(self.fonts.cyri.scale(24))
|
||||
.color(TEXT_COLOR)
|
||||
.parent(state.ids.window)
|
||||
.set(state.ids.repair_title, ui);
|
||||
|
||||
// Bench Icon
|
||||
let size = 140.0;
|
||||
Image::new(animate_by_pulse(
|
||||
&self
|
||||
.item_imgs
|
||||
.img_ids_or_not_found_img(ItemKey::Simple("RepairBench".to_string())),
|
||||
self.pulse,
|
||||
))
|
||||
.wh([size; 2])
|
||||
.mid_top_with_margin_on(state.ids.align_ing, 50.0)
|
||||
.parent(state.ids.align_ing)
|
||||
.set(state.ids.repair_img, ui);
|
||||
|
||||
// Explanation
|
||||
|
||||
Text::new(
|
||||
&self
|
||||
.localized_strings
|
||||
.get_msg("hud-crafting-repair_explanation"),
|
||||
)
|
||||
.mid_bottom_with_margin_on(state.ids.repair_img, -60.0)
|
||||
.font_id(self.fonts.cyri.conrod_id)
|
||||
.font_size(self.fonts.cyri.scale(14))
|
||||
.color(TEXT_COLOR)
|
||||
.parent(state.ids.window)
|
||||
.set(state.ids.repair_txt, ui);
|
||||
}
|
||||
|
||||
// Search / Title Recipes
|
||||
|
@ -3271,6 +3271,19 @@ impl Hud {
|
||||
crafting::Event::ClearRecipeInputs => {
|
||||
self.show.crafting_fields.recipe_inputs.clear();
|
||||
},
|
||||
crafting::Event::RepairItem { slot } => {
|
||||
if let Some(sprite_pos) = self
|
||||
.show
|
||||
.crafting_fields
|
||||
.craft_sprite
|
||||
.map(|(pos, _sprite)| pos)
|
||||
{
|
||||
events.push(Event::RepairItem {
|
||||
item: slot,
|
||||
sprite_pos,
|
||||
});
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -3805,7 +3818,21 @@ impl Hud {
|
||||
self.show
|
||||
.crafting_fields
|
||||
.recipe_inputs
|
||||
.insert(c.index, i.slot);
|
||||
.insert(c.index, Slot::Inventory(i.slot));
|
||||
}
|
||||
} else if let (Equip(e), Crafting(c)) = (a, b) {
|
||||
// Add item to crafting input
|
||||
if inventories
|
||||
.get(client.entity())
|
||||
.and_then(|inv| inv.equipped(e))
|
||||
.map_or(false, |item| {
|
||||
(c.requirement)(item, client.component_recipe_book(), c.info)
|
||||
})
|
||||
{
|
||||
self.show
|
||||
.crafting_fields
|
||||
.recipe_inputs
|
||||
.insert(c.index, Slot::Equip(e));
|
||||
}
|
||||
} else if let (Crafting(c), Inventory(_)) = (a, b) {
|
||||
// Remove item from crafting input
|
||||
@ -3937,17 +3964,6 @@ impl Hud {
|
||||
{
|
||||
events.push(Event::SalvageItem { slot, salvage_pos })
|
||||
}
|
||||
} else if self.show.crafting_fields.repair
|
||||
&& matches!(self.show.crafting_fields.crafting_tab, CraftingTab::Repair)
|
||||
{
|
||||
if let Some((sprite_pos, _sprite_kind)) =
|
||||
self.show.crafting_fields.craft_sprite
|
||||
{
|
||||
events.push(Event::RepairItem {
|
||||
item: from,
|
||||
sprite_pos,
|
||||
})
|
||||
}
|
||||
} else {
|
||||
events.push(Event::UseSlot {
|
||||
slot: from,
|
||||
|
@ -9,7 +9,7 @@ use common::{
|
||||
comp::{
|
||||
ability::{Ability, AbilityInput, AuxiliaryAbility},
|
||||
item::tool::{AbilityContext, ToolKind},
|
||||
slot::InvSlotId,
|
||||
slot::{InvSlotId, Slot},
|
||||
ActiveAbilities, Body, CharacterState, Combo, Energy, Inventory, Item, ItemKey, SkillSet,
|
||||
Stance,
|
||||
},
|
||||
@ -276,27 +276,35 @@ impl<'a> SlotKey<AbilitiesSource<'a>, img_ids::Imgs> for AbilitySlot {
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct CraftSlot {
|
||||
pub index: u32,
|
||||
pub invslot: Option<InvSlotId>,
|
||||
pub slot: Option<Slot>,
|
||||
pub requirement: fn(&Item, &ComponentRecipeBook, Option<CraftSlotInfo>) -> bool,
|
||||
pub info: Option<CraftSlotInfo>,
|
||||
}
|
||||
|
||||
impl CraftSlot {
|
||||
pub fn item<'a>(&'a self, inv: &'a Inventory) -> Option<&'a Item> {
|
||||
match self.slot {
|
||||
Some(Slot::Inventory(slot)) => inv.get(slot),
|
||||
Some(Slot::Equip(slot)) => inv.equipped(slot),
|
||||
None => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub enum CraftSlotInfo {
|
||||
Tool(ToolKind),
|
||||
}
|
||||
|
||||
impl PartialEq for CraftSlot {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
(self.index, self.invslot) == (other.index, other.invslot)
|
||||
}
|
||||
fn eq(&self, other: &Self) -> bool { (self.index, self.slot) == (other.index, other.slot) }
|
||||
}
|
||||
|
||||
impl Debug for CraftSlot {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> {
|
||||
f.debug_struct("CraftSlot")
|
||||
.field("index", &self.index)
|
||||
.field("invslot", &self.invslot)
|
||||
.field("slot", &self.slot)
|
||||
.field("requirement", &"fn ptr")
|
||||
.finish()
|
||||
}
|
||||
@ -306,14 +314,11 @@ impl SlotKey<Inventory, ItemImgs> for CraftSlot {
|
||||
type ImageKey = ItemKey;
|
||||
|
||||
fn image_key(&self, source: &Inventory) -> Option<(Self::ImageKey, Option<Color>)> {
|
||||
self.invslot
|
||||
.and_then(|invslot| source.get(invslot))
|
||||
.map(|i| (i.into(), None))
|
||||
self.item(source).map(|i| (i.into(), None))
|
||||
}
|
||||
|
||||
fn amount(&self, source: &Inventory) -> Option<u32> {
|
||||
self.invslot
|
||||
.and_then(|invslot| source.get(invslot))
|
||||
self.item(source)
|
||||
.map(|item| item.amount())
|
||||
.filter(|amount| *amount > 1)
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user