Show item usages in craft guide
When the craft guide is showing a craft, the output slot is now a button, which causes the craft guide to show ways in which that output can be used. This mirrors the way input slots are buttons that show recipes for the selected ingredient. Usages of an item can be iterated through in the same way as recipes for the item. This incidentally offers some ability to retrace one's steps through a crafting chain, without storing actual history.
This commit is contained in:
parent
c33efe8631
commit
87f502a259
25
api.lua
25
api.lua
@ -42,6 +42,25 @@ minetest.after(0.01, function()
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
for _, recipes in pairs(unified_inventory.crafts_for.recipe) do
|
||||||
|
for _, recipe in ipairs(recipes) do
|
||||||
|
local ingredient_items = {}
|
||||||
|
for _, spec in ipairs(recipe.items) do
|
||||||
|
local matches_spec = unified_inventory.canonical_item_spec_matcher(spec)
|
||||||
|
for _, name in ipairs(unified_inventory.items_list) do
|
||||||
|
if matches_spec(name) then
|
||||||
|
ingredient_items[name] = true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
for name, _ in pairs(ingredient_items) do
|
||||||
|
if unified_inventory.crafts_for.usage[name] == nil then
|
||||||
|
unified_inventory.crafts_for.usage[name] = {}
|
||||||
|
end
|
||||||
|
table.insert(unified_inventory.crafts_for.usage[name], recipe)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
|
||||||
@ -101,10 +120,10 @@ function unified_inventory.register_craft(options)
|
|||||||
if options.type == "normal" and options.width == 0 then
|
if options.type == "normal" and options.width == 0 then
|
||||||
options = { type = "shapeless", items = options.items, output = options.output, width = 0 }
|
options = { type = "shapeless", items = options.items, output = options.output, width = 0 }
|
||||||
end
|
end
|
||||||
if unified_inventory.crafts_table[itemstack:get_name()] == nil then
|
if unified_inventory.crafts_for.recipe[itemstack:get_name()] == nil then
|
||||||
unified_inventory.crafts_table[itemstack:get_name()] = {}
|
unified_inventory.crafts_for.recipe[itemstack:get_name()] = {}
|
||||||
end
|
end
|
||||||
table.insert(unified_inventory.crafts_table[itemstack:get_name()],options)
|
table.insert(unified_inventory.crafts_for.recipe[itemstack:get_name()],options)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
@ -14,28 +14,15 @@ minetest.register_on_joinplayer(function(player)
|
|||||||
unified_inventory.filtered_items_list[player_name] =
|
unified_inventory.filtered_items_list[player_name] =
|
||||||
unified_inventory.items_list
|
unified_inventory.items_list
|
||||||
unified_inventory.activefilter[player_name] = ""
|
unified_inventory.activefilter[player_name] = ""
|
||||||
unified_inventory.apply_filter(player, "")
|
unified_inventory.active_search_direction[player_name] = "nochange"
|
||||||
|
unified_inventory.apply_filter(player, "", "nochange")
|
||||||
unified_inventory.current_searchbox[player_name] = ""
|
unified_inventory.current_searchbox[player_name] = ""
|
||||||
unified_inventory.alternate[player_name] = 1
|
unified_inventory.alternate[player_name] = 1
|
||||||
unified_inventory.current_item[player_name] = nil
|
unified_inventory.current_item[player_name] = nil
|
||||||
|
unified_inventory.current_craft_direction[player_name] = "recipe"
|
||||||
unified_inventory.set_inventory_formspec(player,
|
unified_inventory.set_inventory_formspec(player,
|
||||||
unified_inventory.default)
|
unified_inventory.default)
|
||||||
|
|
||||||
-- Crafting guide inventories
|
|
||||||
local inv = minetest.create_detached_inventory(player_name.."craftrecipe", {
|
|
||||||
allow_put = function(inv, listname, index, stack, player)
|
|
||||||
return 0
|
|
||||||
end,
|
|
||||||
allow_take = function(inv, listname, index, stack, player)
|
|
||||||
return 0
|
|
||||||
end,
|
|
||||||
allow_move = function(inv, from_list, from_index, to_list,
|
|
||||||
to_index, count, player)
|
|
||||||
return 0
|
|
||||||
end,
|
|
||||||
})
|
|
||||||
inv:set_size("output", 1)
|
|
||||||
|
|
||||||
-- Refill slot
|
-- Refill slot
|
||||||
local refill = minetest.create_detached_inventory(player_name.."refill", {
|
local refill = minetest.create_detached_inventory(player_name.."refill", {
|
||||||
allow_put = function(inv, listname, index, stack, player)
|
allow_put = function(inv, listname, index, stack, player)
|
||||||
@ -122,12 +109,16 @@ minetest.register_on_player_receive_fields(function(player, formname, fields)
|
|||||||
local clicked_item = nil
|
local clicked_item = nil
|
||||||
for name, value in pairs(fields) do
|
for name, value in pairs(fields) do
|
||||||
if string.sub(name, 1, 12) == "item_button_" then
|
if string.sub(name, 1, 12) == "item_button_" then
|
||||||
clicked_item = unified_inventory.demangle_for_formspec(string.sub(name, 13))
|
local new_dir, mangled_item = string.match(name, "^item_button_([a-z]+)_(.*)$")
|
||||||
|
clicked_item = unified_inventory.demangle_for_formspec(mangled_item)
|
||||||
if string.sub(clicked_item, 1, 6) == "group:" then
|
if string.sub(clicked_item, 1, 6) == "group:" then
|
||||||
minetest.sound_play("click", {to_player=player_name, gain = 0.1})
|
minetest.sound_play("click", {to_player=player_name, gain = 0.1})
|
||||||
unified_inventory.apply_filter(player, clicked_item)
|
unified_inventory.apply_filter(player, clicked_item, new_dir)
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
if new_dir == "recipe" or new_dir == "usage" then
|
||||||
|
unified_inventory.current_craft_direction[player_name] = new_dir
|
||||||
|
end
|
||||||
break
|
break
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@ -156,7 +147,7 @@ minetest.register_on_player_receive_fields(function(player, formname, fields)
|
|||||||
end
|
end
|
||||||
|
|
||||||
if fields.searchbutton then
|
if fields.searchbutton then
|
||||||
unified_inventory.apply_filter(player, unified_inventory.current_searchbox[player_name])
|
unified_inventory.apply_filter(player, unified_inventory.current_searchbox[player_name], "nochange")
|
||||||
unified_inventory.current_searchbox[player_name] = ""
|
unified_inventory.current_searchbox[player_name] = ""
|
||||||
unified_inventory.set_inventory_formspec(player,
|
unified_inventory.set_inventory_formspec(player,
|
||||||
unified_inventory.current_page[player_name])
|
unified_inventory.current_page[player_name])
|
||||||
@ -172,7 +163,7 @@ minetest.register_on_player_receive_fields(function(player, formname, fields)
|
|||||||
if item_name then
|
if item_name then
|
||||||
local alternates = 0
|
local alternates = 0
|
||||||
local alternate = unified_inventory.alternate[player_name]
|
local alternate = unified_inventory.alternate[player_name]
|
||||||
local crafts = unified_inventory.crafts_table[item_name]
|
local crafts = unified_inventory.crafts_for[unified_inventory.current_craft_direction[player_name]][item_name]
|
||||||
if crafts ~= nil then
|
if crafts ~= nil then
|
||||||
alternates = #crafts
|
alternates = #crafts
|
||||||
end
|
end
|
||||||
|
22
group.lua
22
group.lua
@ -1,3 +1,25 @@
|
|||||||
|
function unified_inventory.canonical_item_spec_matcher(spec)
|
||||||
|
local specname = ItemStack(spec):get_name()
|
||||||
|
if specname:sub(1, 6) == "group:" then
|
||||||
|
local group_names = specname:sub(7):split(",")
|
||||||
|
return function (itemname)
|
||||||
|
local itemdef = minetest.registered_items[itemname]
|
||||||
|
for _, group_name in ipairs(group_names) do
|
||||||
|
if (itemdef.groups[group_name] or 0) == 0 then
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
else
|
||||||
|
return function (itemname) return itemname == specname end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function unified_inventory.item_matches_spec(item, spec)
|
||||||
|
local itemname = ItemStack(item):get_name()
|
||||||
|
return unified_inventory.canonical_item_spec_matcher(spec)(itemname)
|
||||||
|
end
|
||||||
|
|
||||||
unified_inventory.registered_group_items = {
|
unified_inventory.registered_group_items = {
|
||||||
mesecon_conductor_craftable = "mesecons:wire_00000000_off",
|
mesecon_conductor_craftable = "mesecons:wire_00000000_off",
|
||||||
|
5
init.lua
5
init.lua
@ -6,14 +6,15 @@ local worldpath = minetest.get_worldpath()
|
|||||||
-- Data tables definitions
|
-- Data tables definitions
|
||||||
unified_inventory = {}
|
unified_inventory = {}
|
||||||
unified_inventory.activefilter = {}
|
unified_inventory.activefilter = {}
|
||||||
|
unified_inventory.active_search_direction = {}
|
||||||
unified_inventory.alternate = {}
|
unified_inventory.alternate = {}
|
||||||
unified_inventory.current_page = {}
|
unified_inventory.current_page = {}
|
||||||
unified_inventory.current_searchbox = {}
|
unified_inventory.current_searchbox = {}
|
||||||
unified_inventory.current_index = {}
|
unified_inventory.current_index = {}
|
||||||
unified_inventory.current_item = {}
|
unified_inventory.current_item = {}
|
||||||
|
unified_inventory.current_craft_direction = {}
|
||||||
unified_inventory.registered_craft_types = {}
|
unified_inventory.registered_craft_types = {}
|
||||||
unified_inventory.crafts_table = {}
|
unified_inventory.crafts_for = { usage = {}, recipe = {} }
|
||||||
unified_inventory.crafts_table_count = 0
|
|
||||||
unified_inventory.players = {}
|
unified_inventory.players = {}
|
||||||
unified_inventory.items_list_size = 0
|
unified_inventory.items_list_size = 0
|
||||||
unified_inventory.items_list = {}
|
unified_inventory.items_list = {}
|
||||||
|
@ -71,6 +71,7 @@ function unified_inventory.get_formspec(player, page)
|
|||||||
if #unified_inventory.filtered_items_list[player_name] == 0 then
|
if #unified_inventory.filtered_items_list[player_name] == 0 then
|
||||||
formspec = formspec.."label[8.2,0;No matching items]"
|
formspec = formspec.."label[8.2,0;No matching items]"
|
||||||
else
|
else
|
||||||
|
local dir = unified_inventory.active_search_direction[player_name]
|
||||||
local list_index = unified_inventory.current_index[player_name]
|
local list_index = unified_inventory.current_index[player_name]
|
||||||
local page = math.floor(list_index / (80) + 1)
|
local page = math.floor(list_index / (80) + 1)
|
||||||
local pagemax = math.floor(
|
local pagemax = math.floor(
|
||||||
@ -84,7 +85,7 @@ function unified_inventory.get_formspec(player, page)
|
|||||||
formspec = formspec.."item_image_button["
|
formspec = formspec.."item_image_button["
|
||||||
..(8.2 + x * 0.7)..","
|
..(8.2 + x * 0.7)..","
|
||||||
..(1 + y * 0.7)..";.81,.81;"
|
..(1 + y * 0.7)..";.81,.81;"
|
||||||
..name..";item_button_"
|
..name..";item_button_"..dir.."_"
|
||||||
..unified_inventory.mangle_for_formspec(name)..";]"
|
..unified_inventory.mangle_for_formspec(name)..";]"
|
||||||
list_index = list_index + 1
|
list_index = list_index + 1
|
||||||
end
|
end
|
||||||
@ -108,7 +109,7 @@ function unified_inventory.set_inventory_formspec(player, page)
|
|||||||
end
|
end
|
||||||
|
|
||||||
--apply filter to the inventory list (create filtered copy of full one)
|
--apply filter to the inventory list (create filtered copy of full one)
|
||||||
function unified_inventory.apply_filter(player, filter)
|
function unified_inventory.apply_filter(player, filter, search_dir)
|
||||||
local player_name = player:get_player_name()
|
local player_name = player:get_player_name()
|
||||||
local lfilter = string.lower(filter)
|
local lfilter = string.lower(filter)
|
||||||
local ffilter
|
local ffilter
|
||||||
@ -139,6 +140,7 @@ function unified_inventory.apply_filter(player, filter)
|
|||||||
unified_inventory.filtered_items_list_size[player_name] = #unified_inventory.filtered_items_list[player_name]
|
unified_inventory.filtered_items_list_size[player_name] = #unified_inventory.filtered_items_list[player_name]
|
||||||
unified_inventory.current_index[player_name] = 1
|
unified_inventory.current_index[player_name] = 1
|
||||||
unified_inventory.activefilter[player_name] = filter
|
unified_inventory.activefilter[player_name] = filter
|
||||||
|
unified_inventory.active_search_direction[player_name] = search_dir
|
||||||
unified_inventory.set_inventory_formspec(player,
|
unified_inventory.set_inventory_formspec(player,
|
||||||
unified_inventory.current_page[player_name])
|
unified_inventory.current_page[player_name])
|
||||||
end
|
end
|
||||||
|
59
register.lua
59
register.lua
@ -169,6 +169,23 @@ local function stack_image_button(x, y, w, h, buttonname_prefix, item)
|
|||||||
label)
|
label)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local recipe_text = {
|
||||||
|
recipe = "Recipe",
|
||||||
|
usage = "Usage",
|
||||||
|
}
|
||||||
|
local no_recipe_text = {
|
||||||
|
recipe = "No recipes",
|
||||||
|
usage = "No usages",
|
||||||
|
}
|
||||||
|
local role_text = {
|
||||||
|
recipe = "Result",
|
||||||
|
usage = "Ingredient",
|
||||||
|
}
|
||||||
|
local other_dir = {
|
||||||
|
recipe = "usage",
|
||||||
|
usage = "recipe",
|
||||||
|
}
|
||||||
|
|
||||||
unified_inventory.register_page("craftguide", {
|
unified_inventory.register_page("craftguide", {
|
||||||
get_formspec = function(player)
|
get_formspec = function(player)
|
||||||
local player_name = player:get_player_name()
|
local player_name = player:get_player_name()
|
||||||
@ -179,36 +196,33 @@ unified_inventory.register_page("craftguide", {
|
|||||||
local item_name = unified_inventory.current_item[player_name]
|
local item_name = unified_inventory.current_item[player_name]
|
||||||
if not item_name then return {formspec=formspec} end
|
if not item_name then return {formspec=formspec} end
|
||||||
|
|
||||||
formspec = formspec.."background[0,1;8,3;ui_craftguide_form.png]"
|
local dir = unified_inventory.current_craft_direction[player_name]
|
||||||
formspec = formspec.."textarea[0.3,0.6;10,1;;Result: "..minetest.formspec_escape(item_name)..";]"
|
local crafts = unified_inventory.crafts_for[dir][item_name]
|
||||||
formspec = formspec.."list[detached:"..minetest.formspec_escape(player_name).."craftrecipe;output;6,1;1,1;]"
|
local alternate = unified_inventory.alternate[player_name]
|
||||||
local craftinv = minetest.get_inventory({
|
local alternates, craft
|
||||||
type = "detached",
|
|
||||||
name = player_name.."craftrecipe"
|
|
||||||
})
|
|
||||||
|
|
||||||
local alternate, alternates, craft, craft_type
|
|
||||||
alternate = unified_inventory.alternate[player_name]
|
|
||||||
local crafts = unified_inventory.crafts_table[item_name]
|
|
||||||
if crafts ~= nil and #crafts > 0 then
|
if crafts ~= nil and #crafts > 0 then
|
||||||
alternates = #crafts
|
alternates = #crafts
|
||||||
craft = crafts[alternate]
|
craft = crafts[alternate]
|
||||||
end
|
end
|
||||||
|
|
||||||
|
formspec = formspec.."background[0,1;8,3;ui_craftguide_form.png]"
|
||||||
|
formspec = formspec.."textarea[0.3,0.6;10,1;;"..minetest.formspec_escape(role_text[dir]..": "..item_name)..";]"
|
||||||
|
|
||||||
if not craft then
|
if not craft then
|
||||||
craftinv:set_stack("output", 1, item_name)
|
formspec = formspec.."label[6,3.35;"..minetest.formspec_escape(no_recipe_text[dir]).."]"
|
||||||
craft_type = unified_inventory.craft_type_defaults("", {})
|
local no_pos = dir == "recipe" and 4 or 6
|
||||||
formspec = formspec.."label[6,3.35;No recipes]"
|
local item_pos = dir == "recipe" and 6 or 4
|
||||||
formspec = formspec.."image[4,1;1.1,1.1;ui_no.png]"
|
formspec = formspec.."image["..no_pos..",1;1.1,1.1;ui_no.png]"
|
||||||
|
formspec = formspec..stack_image_button(item_pos, 1, 1.1, 1.1, "item_button_"..other_dir[dir].."_", ItemStack(item_name))
|
||||||
return {formspec = formspec}
|
return {formspec = formspec}
|
||||||
end
|
end
|
||||||
|
|
||||||
craftinv:set_stack("output", 1, craft.output)
|
local craft_type = unified_inventory.registered_craft_types[craft.type] or
|
||||||
craft_type = unified_inventory.registered_craft_types[craft.type] or
|
|
||||||
unified_inventory.craft_type_defaults(craft.type, {})
|
unified_inventory.craft_type_defaults(craft.type, {})
|
||||||
formspec = formspec.."label[6,3.35;Method:]"
|
formspec = formspec.."label[6,3.35;Method:]"
|
||||||
formspec = formspec.."label[6,3.75;"
|
formspec = formspec.."label[6,3.75;"
|
||||||
..minetest.formspec_escape(craft_type.description).."]"
|
..minetest.formspec_escape(craft_type.description).."]"
|
||||||
|
formspec = formspec..stack_image_button(6, 1, 1.1, 1.1, "item_button_usage_", ItemStack(craft.output))
|
||||||
local display_size = craft_type.dynamic_display_size and craft_type.dynamic_display_size(craft) or { width = craft_type.width, height = craft_type.height }
|
local display_size = craft_type.dynamic_display_size and craft_type.dynamic_display_size(craft) or { width = craft_type.width, height = craft_type.height }
|
||||||
local craft_width = craft_type.get_shaped_craft_width and craft_type.get_shaped_craft_width(craft) or display_size.width
|
local craft_width = craft_type.get_shaped_craft_width and craft_type.get_shaped_craft_width(craft) or display_size.width
|
||||||
|
|
||||||
@ -224,7 +238,8 @@ unified_inventory.register_page("craftguide", {
|
|||||||
if item then
|
if item then
|
||||||
formspec = formspec..stack_image_button(
|
formspec = formspec..stack_image_button(
|
||||||
xoffset + x, y, 1.1, 1.1,
|
xoffset + x, y, 1.1, 1.1,
|
||||||
"item_button_", ItemStack(item))
|
"item_button_recipe_",
|
||||||
|
ItemStack(item))
|
||||||
else
|
else
|
||||||
-- Fake buttons just to make grid
|
-- Fake buttons just to make grid
|
||||||
formspec = formspec.."image_button["
|
formspec = formspec.."image_button["
|
||||||
@ -242,7 +257,7 @@ unified_inventory.register_page("craftguide", {
|
|||||||
end
|
end
|
||||||
|
|
||||||
if alternates and alternates > 1 then
|
if alternates and alternates > 1 then
|
||||||
formspec = formspec.."label[0,2.6;Recipe "
|
formspec = formspec.."label[0,2.6;"..recipe_text[dir].." "
|
||||||
..tostring(alternate).." of "
|
..tostring(alternate).." of "
|
||||||
..tostring(alternates).."]"
|
..tostring(alternates).."]"
|
||||||
.."button[0,3.15;2,1;alternate;Alternate]"
|
.."button[0,3.15;2,1;alternate;Alternate]"
|
||||||
@ -259,17 +274,13 @@ minetest.register_on_player_receive_fields(function(player, formname, fields)
|
|||||||
end
|
end
|
||||||
if not amount then return end
|
if not amount then return end
|
||||||
local player_name = player:get_player_name()
|
local player_name = player:get_player_name()
|
||||||
local recipe_inv = minetest.get_inventory({
|
|
||||||
type="detached",
|
|
||||||
name=player_name.."craftrecipe",
|
|
||||||
})
|
|
||||||
|
|
||||||
local output = unified_inventory.current_item[player_name]
|
local output = unified_inventory.current_item[player_name]
|
||||||
if (not output) or (output == "") then return end
|
if (not output) or (output == "") then return end
|
||||||
|
|
||||||
local player_inv = player:get_inventory()
|
local player_inv = player:get_inventory()
|
||||||
|
|
||||||
local crafts = unified_inventory.crafts_table[output]
|
local crafts = unified_inventory.crafts_for[unified_inventory.current_craft_direction[player_name]][output]
|
||||||
if (not crafts) or (#crafts == 0) then return end
|
if (not crafts) or (#crafts == 0) then return end
|
||||||
|
|
||||||
local alternate = unified_inventory.alternate[player_name]
|
local alternate = unified_inventory.alternate[player_name]
|
||||||
|
Binary file not shown.
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 13 KiB |
Loading…
Reference in New Issue
Block a user