Move around some group code and make the craftguide render well without a recipe
This also keeps recipes aligned to the right, close to the arrow. It also calculates the craft's height.
This commit is contained in:
parent
ba956d6838
commit
043f608145
24
api.lua
24
api.lua
@ -107,20 +107,29 @@ function unified_inventory.register_craft(options)
|
|||||||
table.insert(unified_inventory.crafts_table[itemstack:get_name()],options)
|
table.insert(unified_inventory.crafts_table[itemstack:get_name()],options)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
local craft_type_defaults = {
|
local craft_type_defaults = {
|
||||||
width = 3,
|
width = 3,
|
||||||
height = 3,
|
height = 3,
|
||||||
uses_crafting_grid = false,
|
uses_crafting_grid = false,
|
||||||
}
|
}
|
||||||
function unified_inventory.canonicalise_craft_type(name, options)
|
|
||||||
if not options.description then options.description = name end
|
|
||||||
|
function unified_inventory.craft_type_defaults(name, options)
|
||||||
|
if not options.description then
|
||||||
|
options.description = name
|
||||||
|
end
|
||||||
setmetatable(options, {__index = craft_type_defaults})
|
setmetatable(options, {__index = craft_type_defaults})
|
||||||
return options
|
return options
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
function unified_inventory.register_craft_type(name, options)
|
function unified_inventory.register_craft_type(name, options)
|
||||||
unified_inventory.registered_craft_types[name] = unified_inventory.canonicalise_craft_type(name, options)
|
unified_inventory.registered_craft_types[name] =
|
||||||
|
unified_inventory.craft_type_defaults(name, options)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
unified_inventory.register_craft_type("normal", {
|
unified_inventory.register_craft_type("normal", {
|
||||||
description = "Crafting",
|
description = "Crafting",
|
||||||
width = 3,
|
width = 3,
|
||||||
@ -128,6 +137,7 @@ unified_inventory.register_craft_type("normal", {
|
|||||||
uses_crafting_grid = true,
|
uses_crafting_grid = true,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
unified_inventory.register_craft_type("shapeless", {
|
unified_inventory.register_craft_type("shapeless", {
|
||||||
description = "Mixing",
|
description = "Mixing",
|
||||||
width = 3,
|
width = 3,
|
||||||
@ -135,26 +145,26 @@ unified_inventory.register_craft_type("shapeless", {
|
|||||||
uses_crafting_grid = true,
|
uses_crafting_grid = true,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
unified_inventory.register_craft_type("cooking", {
|
unified_inventory.register_craft_type("cooking", {
|
||||||
description = "Cooking",
|
description = "Cooking",
|
||||||
width = 1,
|
width = 1,
|
||||||
height = 1,
|
height = 1,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
unified_inventory.register_craft_type("digging", {
|
unified_inventory.register_craft_type("digging", {
|
||||||
description = "Digging",
|
description = "Digging",
|
||||||
width = 1,
|
width = 1,
|
||||||
height = 1,
|
height = 1,
|
||||||
})
|
})
|
||||||
|
|
||||||
function unified_inventory.register_group_representative_item(groupname, itemname)
|
|
||||||
unified_inventory.registered_group_representative_items[groupname] = itemname
|
|
||||||
end
|
|
||||||
|
|
||||||
function unified_inventory.register_page(name, def)
|
function unified_inventory.register_page(name, def)
|
||||||
unified_inventory.pages[name] = def
|
unified_inventory.pages[name] = def
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
function unified_inventory.register_button(name, def)
|
function unified_inventory.register_button(name, def)
|
||||||
if not def.action then
|
if not def.action then
|
||||||
def.action = function(player)
|
def.action = function(player)
|
||||||
@ -165,9 +175,11 @@ function unified_inventory.register_button(name, def)
|
|||||||
table.insert(unified_inventory.buttons, def)
|
table.insert(unified_inventory.buttons, def)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
function unified_inventory.is_creative(playername)
|
function unified_inventory.is_creative(playername)
|
||||||
if minetest.check_player_privs(playername, {creative=true}) or
|
if minetest.check_player_privs(playername, {creative=true}) or
|
||||||
minetest.setting_getbool("creative_mode") then
|
minetest.setting_getbool("creative_mode") then
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
66
group.lua
Normal file
66
group.lua
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
|
||||||
|
unified_inventory.registered_group_items = {
|
||||||
|
mesecon_conductor_craftable = "mesecons:wire_00000000_off",
|
||||||
|
wool = "wool:white",
|
||||||
|
}
|
||||||
|
|
||||||
|
function unified_inventory.register_group_item(groupname, itemname)
|
||||||
|
unified_inventory.registered_group_items[groupname] = itemname
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
-- This is used when displaying craft recipes, where an ingredient is
|
||||||
|
-- specified by group rather than as a specific item. A single-item group
|
||||||
|
-- is represented by that item, with the single-item status signalled
|
||||||
|
-- in the "sole" field. If the group contains no items at all, the item
|
||||||
|
-- field will be nil.
|
||||||
|
--
|
||||||
|
-- Within a multiple-item group, we prefer to use an item that has the
|
||||||
|
-- same specific name as the group, and if there are more than one of
|
||||||
|
-- those items we prefer the one registered for the group by a mod.
|
||||||
|
-- Among equally-preferred items, we just pick the one with the
|
||||||
|
-- lexicographically earliest name.
|
||||||
|
|
||||||
|
function compute_group_item(group_name)
|
||||||
|
local candidate_items = {}
|
||||||
|
for itemname, itemdef in pairs(minetest.registered_items) do
|
||||||
|
if (itemdef.groups.not_in_creative_inventory or 0) == 0 and
|
||||||
|
(itemdef.groups[group_name] or 0) ~= 0 then
|
||||||
|
table.insert(candidate_items, itemname)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
local num_candidates = #candidate_items
|
||||||
|
if num_candidates == 0 then
|
||||||
|
return {sole = true}
|
||||||
|
elseif num_candidates == 1 then
|
||||||
|
return {item = candidate_items[1], sole = true}
|
||||||
|
end
|
||||||
|
local bestitem = ""
|
||||||
|
local bestpref = 0
|
||||||
|
for _, item in ipairs(candidate_items) do
|
||||||
|
local pref
|
||||||
|
if item == unified_inventory.registered_group_items[group_name] then
|
||||||
|
pref = 3
|
||||||
|
elseif item:gsub("^[^:]+:", "") == group_name then
|
||||||
|
pref = 2
|
||||||
|
else
|
||||||
|
pref = 1
|
||||||
|
end
|
||||||
|
if pref > bestpref or (pref == bestpref and item < bestitem) then
|
||||||
|
bestitem = item
|
||||||
|
bestpref = pref
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return {item = bestitem, sole = false}
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
local group_item_cache = {}
|
||||||
|
|
||||||
|
function unified_inventory.get_group_item(group_name)
|
||||||
|
if not group_item_cache[group_name] then
|
||||||
|
group_item_cache[group_name] = compute_group_item(group_name)
|
||||||
|
end
|
||||||
|
return group_item_cache[group_name]
|
||||||
|
end
|
||||||
|
|
2
init.lua
2
init.lua
@ -12,7 +12,6 @@ unified_inventory.current_searchbox = {}
|
|||||||
unified_inventory.current_index = {}
|
unified_inventory.current_index = {}
|
||||||
unified_inventory.current_item = {}
|
unified_inventory.current_item = {}
|
||||||
unified_inventory.registered_craft_types = {}
|
unified_inventory.registered_craft_types = {}
|
||||||
unified_inventory.registered_group_representative_items = {}
|
|
||||||
unified_inventory.crafts_table = {}
|
unified_inventory.crafts_table = {}
|
||||||
unified_inventory.crafts_table_count = 0
|
unified_inventory.crafts_table_count = 0
|
||||||
unified_inventory.players = {}
|
unified_inventory.players = {}
|
||||||
@ -39,6 +38,7 @@ if creative_inventory then
|
|||||||
end
|
end
|
||||||
|
|
||||||
dofile(modpath.."/datastorage.lua")
|
dofile(modpath.."/datastorage.lua")
|
||||||
|
dofile(modpath.."/group.lua")
|
||||||
dofile(modpath.."/api.lua")
|
dofile(modpath.."/api.lua")
|
||||||
dofile(modpath.."/internal.lua")
|
dofile(modpath.."/internal.lua")
|
||||||
dofile(modpath.."/callbacks.lua")
|
dofile(modpath.."/callbacks.lua")
|
||||||
|
167
register.lua
167
register.lua
@ -134,106 +134,39 @@ unified_inventory.register_page("craft", {
|
|||||||
end,
|
end,
|
||||||
})
|
})
|
||||||
|
|
||||||
-- group_representative_item(): select representative item for a group
|
|
||||||
--
|
|
||||||
-- This is used when displaying craft recipes, where an ingredient is
|
|
||||||
-- specified by group rather than as a specific item. A single-item group
|
|
||||||
-- is represented by that item, with the single-item status signalled
|
|
||||||
-- so that stack_image_button() can treat it as just the item. If the
|
|
||||||
-- group contains no items at all, it will be treated as containing a
|
|
||||||
-- single unknown item.
|
|
||||||
--
|
|
||||||
-- Within a multiple-item group, we prefer to use an item that has the
|
|
||||||
-- same specific name as the group, and if there are more than one of
|
|
||||||
-- those items we prefer the one specified by the default mod if there
|
|
||||||
-- is one. If this produces a bad result, the mod defining a group can
|
|
||||||
-- register its preference for which item should represent the group,
|
|
||||||
-- and we'll use that instead if possible. Also, for a handful of groups
|
|
||||||
-- (predating this registration system) we have built-in preferences
|
|
||||||
-- that are used like registered preferences. Among equally-preferred
|
|
||||||
-- items, we just pick the one with the lexicographically earliest name,
|
|
||||||
-- for determinism.
|
|
||||||
local builtin_group_representative_items = {
|
|
||||||
mesecon_conductor_craftable = "mesecons:wire_00000000_off",
|
|
||||||
stone = "default:cobble",
|
|
||||||
wool = "wool:white",
|
|
||||||
}
|
|
||||||
local function compute_group_representative_item(groupspec)
|
|
||||||
local groupname = string.sub(groupspec, 7)
|
|
||||||
local candidate_items = {}
|
|
||||||
for itemname, itemdef in pairs(minetest.registered_items) do
|
|
||||||
if (itemdef.groups.not_in_creative_inventory or 0) == 0 and (itemdef.groups[groupname] or 0) ~= 0 then
|
|
||||||
table.insert(candidate_items, itemname)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
if #candidate_items == 0 then return { item = "unobtainium!", sole = true } end
|
|
||||||
if #candidate_items == 1 then return { item = candidate_items[1], sole = true } end
|
|
||||||
local bestitem = ""
|
|
||||||
local bestpref = 0
|
|
||||||
for _, item in ipairs(candidate_items) do
|
|
||||||
local pref
|
|
||||||
if item == unified_inventory.registered_group_representative_items[groupname] then
|
|
||||||
pref = 5
|
|
||||||
elseif item == builtin_group_representative_items[groupname] then
|
|
||||||
pref = 4
|
|
||||||
elseif item == "default:"..groupname then
|
|
||||||
pref = 3
|
|
||||||
elseif item:gsub("^[^:]*:", "") == groupname then
|
|
||||||
pref = 2
|
|
||||||
else
|
|
||||||
pref = 1
|
|
||||||
end
|
|
||||||
if pref > bestpref or (pref == bestpref and item < bestitem) then
|
|
||||||
bestitem = item
|
|
||||||
bestpref = pref
|
|
||||||
end
|
|
||||||
end
|
|
||||||
return { item = bestitem, sole = false }
|
|
||||||
end
|
|
||||||
local group_representative_item_cache = {}
|
|
||||||
local function group_representative_item(groupspec)
|
|
||||||
if not group_representative_item_cache[groupspec] then
|
|
||||||
group_representative_item_cache[groupspec] = compute_group_representative_item(groupspec)
|
|
||||||
end
|
|
||||||
return group_representative_item_cache[groupspec]
|
|
||||||
end
|
|
||||||
|
|
||||||
-- stack_image_button(): generate a form button displaying a stack of items
|
-- stack_image_button(): generate a form button displaying a stack of items
|
||||||
--
|
--
|
||||||
-- Normally a simple item_image_button[] is used. If the stack contains
|
-- Normally a simple item_image_button[] is used. If the stack contains
|
||||||
-- more than one item, item_image_button[] doesn't have an option to
|
-- more than one item, item_image_button[] doesn't have an option to
|
||||||
-- display an item count in the way that an inventory slot does, so
|
-- display an item count in the way that an inventory slot does, so
|
||||||
-- we have to fake it using the label facility. This doesn't let us
|
-- we have to fake it using the label facility.
|
||||||
-- specify that the count should appear at bottom right, so we use some
|
|
||||||
-- dodgy whitespace to shift it away from the centre of the button.
|
|
||||||
-- Unfortunately the correct amount of whitespace depends on display
|
|
||||||
-- resolution, so the results from this will be variable. This should be
|
|
||||||
-- replaced as soon as the engine adds support for a proper item count,
|
|
||||||
-- or at least label placement control, on buttons.
|
|
||||||
--
|
--
|
||||||
-- The specified item may be a group. In that case, the group will be
|
-- The specified item may be a group. In that case, the group will be
|
||||||
-- represented by some item in the group, along with a flag indicating
|
-- represented by some item in the group, along with a flag indicating
|
||||||
-- that it's a group. If the group contains only one item, it will be
|
-- that it's a group. If the group contains only one item, it will be
|
||||||
-- treated as if that item had been specified directly.
|
-- treated as if that item had been specified directly.
|
||||||
local function stack_image_button(x, y, w, h, buttonname_prefix, stackstring)
|
|
||||||
local st = ItemStack(stackstring)
|
local function stack_image_button(x, y, w, h, buttonname_prefix, item)
|
||||||
local specitem = st:get_name()
|
local name = item:get_name()
|
||||||
local c = st:get_count()
|
local count = item:get_count()
|
||||||
local clab = c == 1 and " " or string.format("%7d", c)
|
local show_is_group = false
|
||||||
local gflag, displayitem, selectitem
|
local displayitem = name
|
||||||
if string.sub(specitem, 1, 6) == "group:" then
|
local selectitem = name
|
||||||
local gri = group_representative_item(specitem)
|
if name:sub(1, 6) == "group:" then
|
||||||
gflag = not gri.sole
|
local group_name = name:sub(7)
|
||||||
displayitem = gri.item
|
local group_item = unified_inventory.get_group_item(group_name)
|
||||||
selectitem = gri.sole and gri.item or specitem
|
show_group = not group_item.sole
|
||||||
else
|
displayitem = group_item.item or "unknown"
|
||||||
gflag = false
|
selectitem = group_item.sole and displayitem or name
|
||||||
displayitem = specitem
|
|
||||||
selectitem = specitem
|
|
||||||
end
|
end
|
||||||
local label = string.format("\n\n%s%7d", gflag and "G" or " ", c):gsub(" 1$", " .")
|
-- Hackily shift the count to the bottom right
|
||||||
if label == "\n\n ." then label = "" end
|
local shiftstr = "\n\n "
|
||||||
return "item_image_button["..x..","..y..";"..w..","..h..";"..minetest.formspec_escape(displayitem)..";"..minetest.formspec_escape(buttonname_prefix..selectitem)..";"..label.."]"
|
return string.format("item_image_button[%u,%u;%u,%u;%s;%s;%s]",
|
||||||
|
x, y, w, h,
|
||||||
|
minetest.formspec_escape(displayitem),
|
||||||
|
minetest.formspec_escape(buttonname_prefix..selectitem),
|
||||||
|
count ~= 1 and shiftstr..tostring(count) or "")
|
||||||
end
|
end
|
||||||
|
|
||||||
unified_inventory.register_page("craftguide", {
|
unified_inventory.register_page("craftguide", {
|
||||||
@ -241,14 +174,15 @@ unified_inventory.register_page("craftguide", {
|
|||||||
local player_name = player:get_player_name()
|
local player_name = player:get_player_name()
|
||||||
local formspec = ""
|
local formspec = ""
|
||||||
formspec = formspec.."background[0,4.5;8,4;ui_main_inventory.png]"
|
formspec = formspec.."background[0,4.5;8,4;ui_main_inventory.png]"
|
||||||
|
formspec = formspec.."background[0,1;8,3;ui_craftguide_form.png]"
|
||||||
formspec = formspec.."label[0,0;Crafting Guide]"
|
formspec = formspec.."label[0,0;Crafting Guide]"
|
||||||
formspec = formspec.."listcolors[#00000000;#00000000]"
|
formspec = formspec.."listcolors[#00000000;#00000000]"
|
||||||
local craftinv = minetest.get_inventory({
|
local craftinv = minetest.get_inventory({
|
||||||
type = "detached",
|
type = "detached",
|
||||||
name = player_name.."craftrecipe"
|
name = player_name.."craftrecipe"
|
||||||
})
|
})
|
||||||
local item_name = unified_inventory.current_item[player_name]
|
local item_name = unified_inventory.current_item[player_name] or ""
|
||||||
if not item_name then return {formspec=formspec} end
|
|
||||||
formspec = formspec.."textarea[0.3,0.6;10,1;;Result: "..minetest.formspec_escape(item_name)..";]"
|
formspec = formspec.."textarea[0.3,0.6;10,1;;Result: "..minetest.formspec_escape(item_name)..";]"
|
||||||
formspec = formspec.."list[detached:"..minetest.formspec_escape(player_name).."craftrecipe;output;6,1;1,1;]"
|
formspec = formspec.."list[detached:"..minetest.formspec_escape(player_name).."craftrecipe;output;6,1;1,1;]"
|
||||||
|
|
||||||
@ -259,38 +193,47 @@ unified_inventory.register_page("craftguide", {
|
|||||||
alternates = #crafts
|
alternates = #crafts
|
||||||
craft = crafts[alternate]
|
craft = crafts[alternate]
|
||||||
end
|
end
|
||||||
if not craft then
|
|
||||||
|
if craft then
|
||||||
|
craftinv:set_stack("output", 1, craft.output)
|
||||||
|
craft_type = unified_inventory.registered_craft_types[craft.type] or
|
||||||
|
unified_inventory.craft_type_defaults(craft.type, {})
|
||||||
|
formspec = formspec.."label[6,3.35;Method:]"
|
||||||
|
formspec = formspec.."label[6,3.75;"
|
||||||
|
..minetest.formspec_escape(craft_type.description).."]"
|
||||||
|
else
|
||||||
craftinv:set_stack("output", 1, item_name)
|
craftinv:set_stack("output", 1, item_name)
|
||||||
|
craft_type = unified_inventory.craft_type_defaults("", {})
|
||||||
formspec = formspec.."label[6,3.35;No recipes]"
|
formspec = formspec.."label[6,3.35;No recipes]"
|
||||||
return {formspec=formspec}
|
|
||||||
end
|
end
|
||||||
|
|
||||||
formspec = formspec.."background[0,1;8,3;ui_craftguide_form.png]"
|
local width = craft and craft.width or 0
|
||||||
craft_type = unified_inventory.registered_craft_types[craft.type] or unified_inventory.canonicalise_craft_type(craft.type, {})
|
|
||||||
formspec = formspec.."label[6,3.35;Method:]"
|
|
||||||
formspec = formspec.."label[6,3.75;"..minetest.formspec_escape(craft_type.description).."]"
|
|
||||||
craftinv:set_stack("output", 1, craft.output)
|
|
||||||
|
|
||||||
-- fake buttons just to make grid
|
|
||||||
for y = 1, craft_type.height do
|
|
||||||
for x = 1, craft_type.width do
|
|
||||||
formspec = formspec.."image_button["
|
|
||||||
..(1.0 + x)..","..(0.0 + y)..";1.1,1.1;ui_blank_image.png;;]"
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
local width = craft.width
|
|
||||||
if width == 0 then
|
if width == 0 then
|
||||||
-- Shapeless recipe
|
-- Shapeless recipe
|
||||||
width = craft_type.width
|
width = craft_type.width
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local height = craft_type.height
|
||||||
|
if craft then
|
||||||
|
height = math.ceil(table.maxn(craft.items) / width)
|
||||||
|
end
|
||||||
|
|
||||||
local i = 1
|
local i = 1
|
||||||
for y = 1, craft_type.height do
|
-- This keeps recipes aligned to the right,
|
||||||
|
-- so that they're close to the arrow.
|
||||||
|
local xoffset = 1 + (3 - width)
|
||||||
|
for y = 1, height do
|
||||||
for x = 1, width do
|
for x = 1, width do
|
||||||
local item = craft.items[i]
|
local item = craft and craft.items[i]
|
||||||
if item then
|
if item then
|
||||||
formspec = formspec..stack_image_button(1.0+x, 0.0+y, 1.1, 1.1, "item_button_", item)
|
formspec = formspec..stack_image_button(
|
||||||
|
xoffset + x, y, 1.1, 1.1,
|
||||||
|
"item_button_", ItemStack(item))
|
||||||
|
else
|
||||||
|
-- Fake buttons just to make grid
|
||||||
|
formspec = formspec.."image_button["
|
||||||
|
..tostring(xoffset + x)..","..tostring(y)
|
||||||
|
..";1,1;ui_blank_image.png;;]"
|
||||||
end
|
end
|
||||||
i = i + 1
|
i = i + 1
|
||||||
end
|
end
|
||||||
@ -303,13 +246,13 @@ unified_inventory.register_page("craftguide", {
|
|||||||
.."button[7.2,2.5;0.6,0.5;craftguide_craft_max;All]"
|
.."button[7.2,2.5;0.6,0.5;craftguide_craft_max;All]"
|
||||||
end
|
end
|
||||||
|
|
||||||
if alternates > 1 then
|
if alternates and alternates > 1 then
|
||||||
formspec = formspec.."label[0,2.6;Recipe "
|
formspec = formspec.."label[0,2.6;Recipe "
|
||||||
..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]"
|
||||||
end
|
end
|
||||||
return {formspec=formspec}
|
return {formspec = formspec}
|
||||||
end,
|
end,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user