This commit is contained in:
Milan2018 2021-05-16 13:51:22 +02:00
parent ee8e331d9c
commit 96c7e0aa8b
13 changed files with 1518 additions and 442 deletions

View file

@ -14,6 +14,7 @@ read_globals = {
"ItemStack", "datastorage", "ItemStack", "datastorage",
"hb", "hb",
"doors",
} }
files["callbacks.lua"].ignore = { "player", "draw_lite_mode" } files["callbacks.lua"].ignore = { "player", "draw_lite_mode" }

View file

@ -24,7 +24,7 @@ Unified Inventory replaces the default survival and creative inventory.
## Requirements ## Requirements
* Minetest 5.0.0+ * Minetest 5.4.0+
# Licenses # Licenses
@ -96,4 +96,4 @@ Other files from Wikimedia Commons:
RealBadAngel: (CC-BY-4.0) RealBadAngel: (CC-BY-4.0)
* Everything else. * Everything else.

View file

@ -1,5 +1,6 @@
local S = minetest.get_translator("unified_inventory") local S = minetest.get_translator("unified_inventory")
local F = minetest.formspec_escape local F = minetest.formspec_escape
local ui = unified_inventory
-- Create detached creative inventory after loading all mods -- Create detached creative inventory after loading all mods
minetest.after(0.01, function() minetest.after(0.01, function()
@ -8,12 +9,12 @@ minetest.after(0.01, function()
if not rev_aliases[target] then rev_aliases[target] = {} end if not rev_aliases[target] then rev_aliases[target] = {} end
table.insert(rev_aliases[target], source) table.insert(rev_aliases[target], source)
end end
unified_inventory.items_list = {} ui.items_list = {}
for name, def in pairs(minetest.registered_items) do for name, def in pairs(minetest.registered_items) do
if (not def.groups.not_in_creative_inventory or if (not def.groups.not_in_creative_inventory or
def.groups.not_in_creative_inventory == 0) and def.groups.not_in_creative_inventory == 0) and
def.description and def.description ~= "" then def.description and def.description ~= "" then
table.insert(unified_inventory.items_list, name) table.insert(ui.items_list, name)
local all_names = rev_aliases[name] or {} local all_names = rev_aliases[name] or {}
table.insert(all_names, name) table.insert(all_names, name)
for _, player_name in ipairs(all_names) do for _, player_name in ipairs(all_names) do
@ -26,30 +27,30 @@ minetest.after(0.01, function()
for _,chk in pairs(recipe.items) do for _,chk in pairs(recipe.items) do
local groupchk = string.find(chk, "group:") local groupchk = string.find(chk, "group:")
if (not groupchk and not minetest.registered_items[chk]) if (not groupchk and not minetest.registered_items[chk])
or (groupchk and not unified_inventory.get_group_item(string.gsub(chk, "group:", "")).item) or (groupchk and not ui.get_group_item(string.gsub(chk, "group:", "")).item)
or minetest.get_item_group(chk, "not_in_craft_guide") ~= 0 then or minetest.get_item_group(chk, "not_in_craft_guide") ~= 0 then
unknowns = true unknowns = true
end end
end end
if not unknowns then if not unknowns then
unified_inventory.register_craft(recipe) ui.register_craft(recipe)
end end
end end
end end
end end
end end
end end
table.sort(unified_inventory.items_list) table.sort(ui.items_list)
unified_inventory.items_list_size = #unified_inventory.items_list ui.items_list_size = #ui.items_list
print("Unified Inventory. inventory size: "..unified_inventory.items_list_size) print("Unified Inventory. inventory size: "..ui.items_list_size)
for _, name in ipairs(unified_inventory.items_list) do for _, name in ipairs(ui.items_list) do
local def = minetest.registered_items[name] local def = minetest.registered_items[name]
-- Simple drops -- Simple drops
if type(def.drop) == "string" then if type(def.drop) == "string" then
local dstack = ItemStack(def.drop) local dstack = ItemStack(def.drop)
if not dstack:is_empty() and dstack:get_name() ~= name then if not dstack:is_empty() and dstack:get_name() ~= name then
unified_inventory.register_craft({ ui.register_craft({
type = "digging", type = "digging",
items = {name}, items = {name},
output = def.drop, output = def.drop,
@ -115,7 +116,7 @@ minetest.after(0.01, function()
end end
end end
for itemstring, count in pairs(drop_guaranteed) do for itemstring, count in pairs(drop_guaranteed) do
unified_inventory.register_craft({ ui.register_craft({
type = "digging", type = "digging",
items = {name}, items = {name},
output = itemstring .. " " .. count, output = itemstring .. " " .. count,
@ -123,7 +124,7 @@ minetest.after(0.01, function()
}) })
end end
for itemstring, count in pairs(drop_maybe) do for itemstring, count in pairs(drop_maybe) do
unified_inventory.register_craft({ ui.register_craft({
type = "digging_chance", type = "digging_chance",
items = {name}, items = {name},
output = itemstring .. " " .. count, output = itemstring .. " " .. count,
@ -132,22 +133,22 @@ minetest.after(0.01, function()
end end
end end
end end
for _, recipes in pairs(unified_inventory.crafts_for.recipe) do for _, recipes in pairs(ui.crafts_for.recipe) do
for _, recipe in ipairs(recipes) do for _, recipe in ipairs(recipes) do
local ingredient_items = {} local ingredient_items = {}
for _, spec in pairs(recipe.items) do for _, spec in pairs(recipe.items) do
local matches_spec = unified_inventory.canonical_item_spec_matcher(spec) local matches_spec = ui.canonical_item_spec_matcher(spec)
for _, name in ipairs(unified_inventory.items_list) do for _, name in ipairs(ui.items_list) do
if matches_spec(name) then if matches_spec(name) then
ingredient_items[name] = true ingredient_items[name] = true
end end
end end
end end
for name, _ in pairs(ingredient_items) do for name, _ in pairs(ingredient_items) do
if unified_inventory.crafts_for.usage[name] == nil then if ui.crafts_for.usage[name] == nil then
unified_inventory.crafts_for.usage[name] = {} ui.crafts_for.usage[name] = {}
end end
table.insert(unified_inventory.crafts_for.usage[name], recipe) table.insert(ui.crafts_for.usage[name], recipe)
end end
end end
end end
@ -156,9 +157,9 @@ end)
-- load_home -- load_home
local function load_home() local function load_home()
local input = io.open(unified_inventory.home_filename, "r") local input = io.open(ui.home_filename, "r")
if not input then if not input then
unified_inventory.home_pos = {} ui.home_pos = {}
return return
end end
while true do while true do
@ -167,25 +168,31 @@ local function load_home()
local y = input:read("*n") local y = input:read("*n")
local z = input:read("*n") local z = input:read("*n")
local name = input:read("*l") local name = input:read("*l")
unified_inventory.home_pos[name:sub(2)] = {x = x, y = y, z = z} ui.home_pos[name:sub(2)] = {x = x, y = y, z = z}
end end
io.close(input) io.close(input)
end end
load_home() load_home()
function unified_inventory.set_home(player, pos) function ui.set_home(player, pos)
local player_name = player:get_player_name() local player_name = player:get_player_name()
unified_inventory.home_pos[player_name] = vector.round(pos) ui.home_pos[player_name] = vector.round(pos)
-- save the home data from the table to the file -- save the home data from the table to the file
local output = io.open(unified_inventory.home_filename, "w") local output = io.open(ui.home_filename, "w")
for k, v in pairs(unified_inventory.home_pos) do if not output then
minetest.log("warning", "[unified_inventory] Failed to save file: "
.. ui.home_filename)
return
end
for k, v in pairs(ui.home_pos) do
output:write(v.x.." "..v.y.." "..v.z.." "..k.."\n") output:write(v.x.." "..v.y.." "..v.z.." "..k.."\n")
end end
io.close(output) io.close(output)
end end
function unified_inventory.go_home(player) function ui.go_home(player)
local pos = unified_inventory.home_pos[player:get_player_name()] local pos = ui.home_pos[player:get_player_name()]
if pos then if pos then
player:set_pos(pos) player:set_pos(pos)
return true return true
@ -194,7 +201,7 @@ function unified_inventory.go_home(player)
end end
-- register_craft -- register_craft
function unified_inventory.register_craft(options) function ui.register_craft(options)
if not options.output then if not options.output then
return return
end end
@ -205,10 +212,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 not unified_inventory.crafts_for.recipe[itemstack:get_name()] then if not ui.crafts_for.recipe[itemstack:get_name()] then
unified_inventory.crafts_for.recipe[itemstack:get_name()] = {} ui.crafts_for.recipe[itemstack:get_name()] = {}
end end
table.insert(unified_inventory.crafts_for.recipe[itemstack:get_name()],options) table.insert(ui.crafts_for.recipe[itemstack:get_name()],options)
end end
@ -219,7 +226,7 @@ local craft_type_defaults = {
} }
function unified_inventory.craft_type_defaults(name, options) function ui.craft_type_defaults(name, options)
if not options.description then if not options.description then
options.description = name options.description = name
end end
@ -228,13 +235,13 @@ function unified_inventory.craft_type_defaults(name, options)
end end
function unified_inventory.register_craft_type(name, options) function ui.register_craft_type(name, options)
unified_inventory.registered_craft_types[name] = ui.registered_craft_types[name] =
unified_inventory.craft_type_defaults(name, options) ui.craft_type_defaults(name, options)
end end
unified_inventory.register_craft_type("normal", { ui.register_craft_type("normal", {
description = F(S("Crafting")), description = F(S("Crafting")),
icon = "ui_craftgrid_icon.png", icon = "ui_craftgrid_icon.png",
width = 3, width = 3,
@ -250,7 +257,7 @@ unified_inventory.register_craft_type("normal", {
}) })
unified_inventory.register_craft_type("shapeless", { ui.register_craft_type("shapeless", {
description = F(S("Mixing")), description = F(S("Mixing")),
icon = "ui_craftgrid_icon.png", icon = "ui_craftgrid_icon.png",
width = 3, width = 3,
@ -265,7 +272,7 @@ unified_inventory.register_craft_type("shapeless", {
}) })
unified_inventory.register_craft_type("cooking", { ui.register_craft_type("cooking", {
description = F(S("Cooking")), description = F(S("Cooking")),
icon = "default_furnace_front.png", icon = "default_furnace_front.png",
width = 1, width = 1,
@ -273,37 +280,60 @@ unified_inventory.register_craft_type("cooking", {
}) })
unified_inventory.register_craft_type("digging", { ui.register_craft_type("digging", {
description = F(S("Digging")), description = F(S("Digging")),
icon = "default_tool_steelpick.png", icon = "default_tool_steelpick.png",
width = 1, width = 1,
height = 1, height = 1,
}) })
unified_inventory.register_craft_type("digging_chance", { ui.register_craft_type("digging_chance", {
description = "Digging (by chance)", description = "Digging (by chance)",
icon = "default_tool_steelpick.png^[transformFY.png", icon = "default_tool_steelpick.png^[transformFY.png",
width = 1, width = 1,
height = 1, height = 1,
}) })
function unified_inventory.register_page(name, def) function ui.register_page(name, def)
unified_inventory.pages[name] = def ui.pages[name] = def
end end
function unified_inventory.register_button(name, def) function ui.register_button(name, def)
if not def.action then if not def.action then
def.action = function(player) def.action = function(player)
unified_inventory.set_inventory_formspec(player, name) ui.set_inventory_formspec(player, name)
end end
end end
def.name = name def.name = name
table.insert(unified_inventory.buttons, def) table.insert(ui.buttons, def)
end end
function ui.is_creative(playername)
function unified_inventory.is_creative(playername)
return minetest.check_player_privs(playername, {creative=true}) return minetest.check_player_privs(playername, {creative=true})
or minetest.settings:get_bool("creative_mode") or minetest.settings:get_bool("creative_mode")
end end
function ui.single_slot(xpos, ypos, bright)
return string.format("background9[%f,%f;%f,%f;ui_single_slot%s.png;false;16]",
xpos, ypos, ui.imgscale, ui.imgscale, (bright and "_bright" or "") )
end
function ui.make_trash_slot(xpos, ypos)
return
ui.single_slot(xpos, ypos)..
"image["..xpos..","..ypos..";1.25,1.25;ui_trash_slot_icon.png]"..
"list[detached:trash;main;"..(xpos + ui.list_img_offset)..","..(ypos + ui.list_img_offset)..";1,1;]"
end
function ui.make_inv_img_grid(xpos, ypos, width, height, bright)
local tiled = {}
local n=1
for y = 0, (height - 1) do
for x = 0, (width -1) do
tiled[n] = ui.single_slot(xpos + (ui.imgscale * x), ypos + (ui.imgscale * y), bright)
n = n + 1
end
end
return table.concat(tiled)
end

View file

@ -7,29 +7,32 @@ License: GPLv3
local S = minetest.get_translator("unified_inventory") local S = minetest.get_translator("unified_inventory")
local F = minetest.formspec_escape local F = minetest.formspec_escape
local bags_inv_bg_prefix = "image[-0.1,1.0;10.05," local ui = unified_inventory
unified_inventory.register_page("bags", { ui.register_page("bags", {
get_formspec = function(player) get_formspec = function(player)
local player_name = player:get_player_name() local player_name = player:get_player_name()
return { formspec = table.concat({ return { formspec = table.concat({
string.gsub(unified_inventory.standard_inv_bg, "YYY", "4.4"), ui.style_full.standard_inv_bg,
bags_inv_bg_prefix.."1.175;ui_bags_header.png]", ui.single_slot(0.925, 1.5),
"label[0,0;" .. F(S("Bags")) .. "]", ui.single_slot(3.425, 1.5),
"button[0,2.2;2,0.5;bag1;" .. F(S("Bag @1", 1)) .. "]", ui.single_slot(5.925, 1.5),
"button[2,2.2;2,0.5;bag2;" .. F(S("Bag @1", 2)) .. "]", ui.single_slot(8.425, 1.5),
"button[4,2.2;2,0.5;bag3;" .. F(S("Bag @1", 3)) .. "]", "label["..ui.style_full.form_header_x..","..ui.style_full.form_header_y..";" .. F(S("Bags")) .. "]",
"button[6,2.2;2,0.5;bag4;" .. F(S("Bag @1", 4)) .. "]", "button[0.6125,2.75;1.875,0.75;bag1;" .. F(S("Bag @1", 1)) .. "]",
"button[3.1125,2.75;1.875,0.75;bag2;" .. F(S("Bag @1", 2)) .. "]",
"button[5.6125,2.75;1.875,0.75;bag3;" .. F(S("Bag @1", 3)) .. "]",
"button[8.1125,2.75;1.875,0.75;bag4;" .. F(S("Bag @1", 4)) .. "]",
"listcolors[#00000000;#00000000]", "listcolors[#00000000;#00000000]",
"list[detached:" .. F(player_name) .. "_bags;bag1;0.5,1.1;1,1;]", "list[detached:" .. F(player_name) .. "_bags;bag1;1.075,1.65;1,1;]",
"list[detached:" .. F(player_name) .. "_bags;bag2;2.5,1.1;1,1;]", "list[detached:" .. F(player_name) .. "_bags;bag2;3.575,1.65;1,1;]",
"list[detached:" .. F(player_name) .. "_bags;bag3;4.5,1.1;1,1;]", "list[detached:" .. F(player_name) .. "_bags;bag3;6.075,1.65;1,1;]",
"list[detached:" .. F(player_name) .. "_bags;bag4;6.5,1.1;1,1;]" "list[detached:" .. F(player_name) .. "_bags;bag4;8.575,1.65;1,1;]"
}) } }) }
end, end,
}) })
unified_inventory.register_button("bags", { ui.register_button("bags", {
type = "image", type = "image",
image = "ui_bags_icon.png", image = "ui_bags_icon.png",
tooltip = S("Bags"), tooltip = S("Bags"),
@ -44,33 +47,31 @@ local function get_player_bag_stack(player, i)
end end
for bag_i = 1, 4 do for bag_i = 1, 4 do
unified_inventory.register_page("bag" .. bag_i, { ui.register_page("bag" .. bag_i, {
get_formspec = function(player) get_formspec = function(player)
local stack = get_player_bag_stack(player, bag_i) local stack = get_player_bag_stack(player, bag_i)
local image = stack:get_definition().inventory_image local image = stack:get_definition().inventory_image
local fs = {
string.gsub(unified_inventory.standard_inv_bg, "YYY", "4.4"),
"image[7,0;1,1;" .. image .. "]",
"label[0,0;" .. F(S("Bag @1", bag_i)) .. "]",
"listcolors[#00000000;#00000000]",
"list[current_player;bag" .. bag_i .. "contents;0,1.1;8,3;]",
"listring[current_name;bag" .. bag_i .. "contents]",
"listring[current_player;main]",
}
local slots = stack:get_definition().groups.bagslots local slots = stack:get_definition().groups.bagslots
if slots == 8 then
fs[#fs + 1] = bags_inv_bg_prefix.."1.175;ui_bags_inv_small.png]" local formspec = {
elseif slots == 16 then ui.style_full.standard_inv_bg,
fs[#fs + 1] = bags_inv_bg_prefix.."2.35;ui_bags_inv_medium.png]" ui.make_inv_img_grid(0.3, 1.5, 8, slots/8),
elseif slots == 24 then "image[9.2,0.4;1,1;" .. image .. "]",
fs[#fs + 1] = bags_inv_bg_prefix.."3.525;ui_bags_inv_large.png]" "label[0.3,0.65;" .. F(S("Bag @1", bag_i)) .. "]",
end "listcolors[#00000000;#00000000]",
"listring[current_player;main]",
string.format("list[current_player;bag%icontents;%f,%f;8,3;]",
bag_i, 0.3 + ui.list_img_offset, 1.5 + ui.list_img_offset),
"listring[current_name;bag" .. bag_i .. "contents]",
}
local n = #formspec + 1
local player_name = player:get_player_name() -- For if statement. local player_name = player:get_player_name() -- For if statement.
if unified_inventory.trash_enabled if ui.trash_enabled
or unified_inventory.is_creative(player_name) or ui.is_creative(player_name)
or minetest.get_player_privs(player_name).give then or minetest.get_player_privs(player_name).give then
fs[#fs + 1] = "image[5.91,-0.06;1.21,1.15;ui_bags_trash.png]" formspec[n] = ui.make_trash_slot(7.8, 0.25)
.. "list[detached:trash;main;6,0.1;1,1;]" n = n + 1
end end
local inv = player:get_inventory() local inv = player:get_inventory()
for i = 1, 4 do for i = 1, 4 do
@ -87,11 +88,12 @@ for bag_i = 1, 4 do
end end
local img = def.inventory_image local img = def.inventory_image
local label = F(S("Bag @1", i)) .. "\n" .. used .. "/" .. size local label = F(S("Bag @1", i)) .. "\n" .. used .. "/" .. size
fs[#fs + 1] = string.format("image_button[%i,0;1,1;%s;bag%i;%s]", formspec[n] = string.format("image_button[%f,0.4;1,1;%s;bag%i;%s]",
i + 1, img, i, label) (i + 1.35)*1.25, img, i, label)
n = n + 1
end end
end end
return { formspec = table.concat(fs) } return { formspec = table.concat(formspec) }
end, end,
}) })
end end
@ -106,7 +108,7 @@ minetest.register_on_player_receive_fields(function(player, formname, fields)
if not stack:get_definition().groups.bagslots then if not stack:get_definition().groups.bagslots then
return return
end end
unified_inventory.set_inventory_formspec(player, "bag" .. i) ui.set_inventory_formspec(player, "bag" .. i)
return return
end end
end end
@ -135,7 +137,7 @@ end
local function load_bags_metadata(player, bags_inv) local function load_bags_metadata(player, bags_inv)
local player_inv = player:get_inventory() local player_inv = player:get_inventory()
local meta = player:get_meta() local meta = player:get_meta()
local bags_meta = meta:get_string("unified_inventory:bags") local bags_meta = meta:get("unified_inventory:bags")
local bags = bags_meta and minetest.deserialize(bags_meta) or {} local bags = bags_meta and minetest.deserialize(bags_meta) or {}
local dirty_meta = false local dirty_meta = false
if not bags_meta then if not bags_meta then

View file

@ -19,6 +19,8 @@ minetest.register_on_joinplayer(function(player)
unified_inventory.active_search_direction[player_name] = "nochange" unified_inventory.active_search_direction[player_name] = "nochange"
unified_inventory.apply_filter(player, "", "nochange") unified_inventory.apply_filter(player, "", "nochange")
unified_inventory.current_searchbox[player_name] = "" unified_inventory.current_searchbox[player_name] = ""
unified_inventory.current_category[player_name] = "all"
unified_inventory.current_category_scroll[player_name] = 0
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.current_craft_direction[player_name] = "recipe"
@ -69,6 +71,41 @@ minetest.register_on_player_receive_fields(function(player, formname, fields)
unified_inventory.current_searchbox[player_name] = fields.searchbox unified_inventory.current_searchbox[player_name] = fields.searchbox
end end
local clicked_category
for name, value in pairs(fields) do
local category_name = string.match(name, "^category_(.+)$")
if category_name then
clicked_category = category_name
break
end
end
if clicked_category
and clicked_category ~= unified_inventory.current_category[player_name] then
unified_inventory.current_category[player_name] = clicked_category
unified_inventory.apply_filter(player, unified_inventory.current_searchbox[player_name], "nochange")
unified_inventory.set_inventory_formspec(player,
unified_inventory.current_page[player_name])
end
if fields.next_category then
local scroll = math.min(#unified_inventory.category_list-ui_peruser.pagecols, unified_inventory.current_category_scroll[player_name] + 1)
if scroll ~= unified_inventory.current_category_scroll[player_name] then
unified_inventory.current_category_scroll[player_name] = scroll
unified_inventory.set_inventory_formspec(player,
unified_inventory.current_page[player_name])
end
end
if fields.prev_category then
local scroll = math.max(0, unified_inventory.current_category_scroll[player_name] - 1)
if scroll ~= unified_inventory.current_category_scroll[player_name] then
unified_inventory.current_category_scroll[player_name] = scroll
unified_inventory.set_inventory_formspec(player,
unified_inventory.current_page[player_name])
end
end
for i, def in pairs(unified_inventory.buttons) do for i, def in pairs(unified_inventory.buttons) do
if fields[def.name] then if fields[def.name] then
def.action(player) def.action(player)
@ -126,6 +163,7 @@ minetest.register_on_player_receive_fields(function(player, formname, fields)
clicked_item = unified_inventory.demangle_for_formspec(mangled_item) 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
-- Change search filter to this group -- Change search filter to this group
unified_inventory.current_category[player_name] = "all"
apply_new_filter(player, clicked_item, new_dir) apply_new_filter(player, clicked_item, new_dir)
return return
end end

View file

@ -0,0 +1,149 @@
local S = minetest.get_translator("unified_inventory")
unified_inventory.registered_categories = {}
unified_inventory.registered_category_items = {}
unified_inventory.category_list = {}
local function char_to_sort_index(char_code)
if char_code <= 32 then
-- Command codes, no thanks
return 0
end
if char_code <= 64 then
-- Sorts numbers, and some punctuation, after letters
return char_code
end
if char_code >= 158 then
-- Out of sortable range
return 0
end
if char_code > 122 then
-- Avoids overlap with {, |, } and ~
return char_code - 58
end
if char_code > 96 then
-- Normalises lowercase with uppercase
return char_code - 96
end
return char_code - 64
end
local function string_to_sort_index(str)
local max_chars = 5
local power = 100
local index = 0
for i=1,math.min(#str, max_chars) do
index = index + (char_to_sort_index(string.byte(str, i))/(power^i))
end
return index
end
function update_category_list()
local category_list = {}
table.insert(category_list, {
name = "all",
label = S("All Items"),
symbol = "ui_category_all.png",
index = -2,
})
table.insert(category_list, {
name = "uncategorized",
label = S("Misc. Items"),
symbol = "ui_category_none.png",
index = -1,
})
for category, def in pairs(unified_inventory.registered_categories) do
table.insert(category_list, {
name = category,
label = def.label or category,
symbol = def.symbol,
index = def.index or -- sortby defined order
string_to_sort_index(category) -- or do a rudimentary alphabetical sort
})
end
table.sort(category_list, function (a,b)
return a.index < b.index
end)
unified_inventory.category_list = category_list
end
local function ensure_category_exists(category_name)
if not unified_inventory.registered_categories[category_name] then
unified_inventory.registered_categories[category_name] = {
symbol = "default:stick",
label = category_name
}
end
if not unified_inventory.registered_category_items[category_name] then
unified_inventory.registered_category_items[category_name] = {}
end
end
function unified_inventory.register_category(category_name, config)
ensure_category_exists(category_name)
if config and config.symbol then
unified_inventory.set_category_symbol(category_name, config.symbol)
end
if config and config.label then
unified_inventory.set_category_label(category_name, config.label)
end
if config and config.index then
unified_inventory.set_category_index(category_name, config.index)
end
if config and config.items then
unified_inventory.add_category_items(category_name, config.items)
end
update_category_list()
end
function unified_inventory.set_category_symbol(category_name, symbol)
ensure_category_exists(category_name)
unified_inventory.registered_categories[category_name].symbol = symbol
update_category_list()
end
function unified_inventory.set_category_label(category_name, label)
ensure_category_exists(category_name)
unified_inventory.registered_categories[category_name].label = label
update_category_list()
end
function unified_inventory.set_category_index(category_name, index)
ensure_category_exists(category_name)
unified_inventory.registered_categories[category_name].index = index
update_category_list()
end
function unified_inventory.add_category_item(category_name, item)
ensure_category_exists(category_name)
unified_inventory.registered_category_items[category_name][item] = true
end
function unified_inventory.add_category_items(category_name, items)
for _,item in ipairs(items) do
unified_inventory.add_category_item(category_name, item)
end
end
function unified_inventory.remove_category_item(category_name, item)
unified_inventory.registered_category_items[category_name][item] = nil
end
function unified_inventory.remove_category(category_name)
unified_inventory.registered_categories[category_name] = nil
unified_inventory.registered_category_items[category_name] = nil
update_category_list()
end
function unified_inventory.find_category(item)
-- Returns the first category the item exists in
-- Best for checking if an item has any category at all
for category, items in pairs(unified_inventory.registered_category_items) do
if items[item] then return category end
end
end
function unified_inventory.find_categories(item)
-- Returns all the categories the item exists in
-- Best for listing all categories
local categories = {}
for category, items in pairs(unified_inventory.registered_category_items) do
if items[item] then
table.insert(categories, category)
end
end
return categories
end

View file

@ -0,0 +1,704 @@
local S = minetest.get_translator("unified_inventory")
unified_inventory.register_category('plants', {
symbol = "flowers:tulip",
label = S("Plant Life")
})
unified_inventory.register_category('building', {
symbol = "default:brick",
label = S("Building Materials")
})
unified_inventory.register_category('tools', {
symbol = "default:pick_diamond",
label = S("Tools")
})
unified_inventory.register_category('minerals', {
symbol = "default:iron_lump",
label = S("Minerals and Metals")
})
unified_inventory.register_category('environment', {
symbol = "default:dirt_with_grass",
label = S("Environment and Worldgen")
})
unified_inventory.register_category('lighting', {
symbol = "default:torch",
label = S("Lighting")
})
if unified_inventory.automatic_categorization then
minetest.register_on_mods_loaded(function()
-- Add biome nodes to environment category
for _,def in pairs(minetest.registered_biomes) do
local env_nodes = {
def.node_riverbed, def.node_top, def.node_filler, def.node_dust,
}
for i,node in pairs(env_nodes) do
if node then
unified_inventory.add_category_item('environment', node)
end
end
end
-- Add minable ores to minerals and everything else (pockets of stone & sand variations) to environment
for _,item in pairs(minetest.registered_ores) do
if item.ore_type == "scatter" then
local drop = minetest.registered_nodes[item.ore].drop
if drop and drop ~= "" then
unified_inventory.add_category_item('minerals', item.ore)
unified_inventory.add_category_item('minerals', drop)
else
unified_inventory.add_category_item('environment', item.ore)
end
else
unified_inventory.add_category_item('environment', item.ore)
end
end
-- Add items by item definition
for name, def in pairs(minetest.registered_items) do
local group = def.groups or {}
if not group.not_in_creative_inventory then
if group.stair or
group.slab or
group.wall or
group.fence then
unified_inventory.add_category_item('building', name)
elseif group.flora or
group.flower or
group.seed or
group.leaves or
group.sapling or
group.tree then
unified_inventory.add_category_item('plants', name)
elseif def.type == 'tool' then
unified_inventory.add_category_item('tools', name)
elseif def.liquidtype == 'source' then
unified_inventory.add_category_item('environment', name)
elseif def.light_source and def.light_source > 0 then
unified_inventory.add_category_item('lighting', name)
elseif group.door or
minetest.global_exists("doors") and (
doors.registered_doors and doors.registered_doors[name..'_a'] or
doors.registered_trapdoors and doors.registered_trapdoors[name]
) then
unified_inventory.add_category_item('building', name)
end
end
end
end)
end
-- [[
unified_inventory.add_category_items('plants', {
"default:dry_grass_5",
"default:acacia_sapling",
"default:blueberry_bush_sapling",
"default:grass_2",
"default:pine_bush_stem",
"default:leaves",
"default:pine_needles",
"default:cactus",
"default:junglegrass",
"default:pine_sapling",
"default:sapling",
"default:bush_stem",
"default:dry_grass_2",
"default:fern_1",
"default:grass_3",
"default:marram_grass_1",
"default:pine_tree",
"default:dry_grass_3",
"default:dry_shrub",
"default:grass_4",
"default:marram_grass_2",
"default:jungleleaves",
"default:apple",
"default:tree",
"default:aspen_tree",
"default:bush_sapling",
"default:grass_5",
"default:blueberry_bush_leaves_with_berries",
"default:acacia_bush_sapling",
"default:grass_1",
"default:aspen_leaves",
"default:marram_grass_3",
"default:large_cactus_seedling",
"default:junglesapling",
"default:dry_grass_4",
"default:acacia_bush_stem",
"default:papyrus",
"default:pine_bush_needles",
"default:bush_leaves",
"default:fern_3",
"default:aspen_sapling",
"default:acacia_tree",
"default:apple_mark",
"default:acacia_leaves",
"default:jungletree",
"default:dry_grass_1",
"default:acacia_bush_leaves",
"default:emergent_jungle_sapling",
"default:fern_2",
"default:blueberries",
"default:sand_with_kelp",
"default:blueberry_bush_leaves",
"default:pine_bush_sapling",
"farming:cotton",
"farming:cotton_1",
"farming:cotton_2",
"farming:cotton_3",
"farming:cotton_4",
"farming:cotton_5",
"farming:cotton_6",
"farming:cotton_7",
"farming:cotton_8",
"farming:cotton_wild",
"farming:seed_cotton",
"farming:seed_wheat",
"farming:straw",
"farming:wheat",
"farming:wheat_1",
"farming:wheat_2",
"farming:wheat_3",
"farming:wheat_4",
"farming:wheat_5",
"farming:wheat_6",
"farming:wheat_7",
"farming:wheat_8",
"flowers:chrysanthemum_green",
"flowers:dandelion_white",
"flowers:dandelion_yellow",
"flowers:geranium",
"flowers:mushroom_brown",
"flowers:mushroom_red",
"flowers:rose",
"flowers:tulip",
"flowers:tulip_black",
"flowers:viola",
"flowers:waterlily",
"flowers:waterlily_waving",
})
unified_inventory.add_category_items('tools', {
"default:sword_diamond",
"default:axe_diamond",
"default:shovel_diamond",
"default:axe_steel",
"default:shovel_mese",
"default:sword_wood",
"default:pick_bronze",
"default:axe_stone",
"default:sword_stone",
"default:pick_stone",
"default:shovel_stone",
"default:sword_mese",
"default:shovel_bronze",
"default:sword_bronze",
"default:axe_bronze",
"default:shovel_steel",
"default:sword_steel",
"default:axe_mese",
"default:shovel_wood",
"default:pick_mese",
"default:axe_wood",
"default:pick_diamond",
"default:pick_wood",
"default:pick_steel",
"farming:hoe_bronze",
"farming:hoe_diamond",
"farming:hoe_mese",
"farming:hoe_steel",
"farming:hoe_stone",
"farming:hoe_wood",
"fire:flint_and_steel",
"map:mapping_kit",
"screwdriver:screwdriver",
"fireflies:bug_net",
"bucket:bucket_empty",
"binoculars:binoculars",
"default:skeleton_key",
})
unified_inventory.add_category_items('minerals', {
"default:stone_with_copper",
"default:stone_with_gold",
"default:stone_with_iron",
"default:copper_ingot",
"default:copper_lump",
"default:gold_lump",
"default:diamondblock",
"default:stone_with_diamond",
"default:stone_with_mese",
"default:steel_ingot",
"default:gold_ingot",
"default:iron_lump",
"default:tinblock",
"default:tin_lump",
"default:stone_with_tin",
"default:mese_crystal",
"default:diamond",
"default:bronze_ingot",
"default:mese",
"default:mese_crystal_fragment",
"default:copperblock",
"default:stone_with_coal",
"default:steelblock",
"default:tin_ingot",
"default:coalblock",
"default:coal_lump",
"default:bronzeblock",
"default:goldblock",
"stairs:slab_bronzeblock",
"stairs:slab_copperblock",
"stairs:slab_steelblock",
"stairs:slab_tinblock",
"stairs:stair_bronzeblock",
"stairs:stair_copperblock",
"stairs:stair_inner_bronzeblock",
"stairs:stair_inner_copperblock",
"stairs:stair_inner_steelblock",
"stairs:stair_inner_tinblock",
"stairs:stair_outer_bronzeblock",
"stairs:stair_outer_copperblock",
"stairs:stair_outer_steelblock",
"stairs:stair_outer_tinblock",
"stairs:stair_steelblock",
"stairs:stair_tinblock",
})
unified_inventory.add_category_items('building', {
"default:fence_rail_aspen_wood",
"default:fence_rail_acacia_wood",
"default:fence_junglewood",
"default:fence_rail_junglewood",
"default:fence_aspen_wood",
"default:fence_pine_wood",
"default:fence_rail_wood",
"default:fence_rail_pine_wood",
"default:fence_acacia_wood",
"default:junglewood",
"default:acacia_wood",
"default:aspen_wood",
"default:fence_wood",
"default:pine_wood",
"default:silver_sandstone",
"default:desert_sandstone",
"default:sandstone_block",
"default:desert_sandstone_brick",
"default:stone_block",
"default:stonebrick",
"default:obsidian_glass",
"default:desert_sandstone_block",
"default:silver_sandstone_brick",
"default:brick",
"default:obsidianbrick",
"default:sandstonebrick",
"default:sandstone",
"default:desert_stone_block",
"default:silver_sandstone_block",
"default:wood",
"default:obsidian_block",
"default:glass",
"default:clay_brick",
"default:desert_stonebrick",
"default:desert_cobble",
"default:cobble",
"default:mossycobble",
"doors:door_glass",
"doors:door_glass_a",
"doors:door_glass_b",
"doors:door_glass_c",
"doors:door_glass_d",
"doors:door_obsidian_glass",
"doors:door_obsidian_glass_a",
"doors:door_obsidian_glass_b",
"doors:door_obsidian_glass_c",
"doors:door_obsidian_glass_d",
"doors:door_steel",
"doors:door_steel_a",
"doors:door_steel_b",
"doors:door_steel_c",
"doors:door_steel_d",
"doors:door_wood",
"doors:door_wood_a",
"doors:door_wood_b",
"doors:door_wood_c",
"doors:door_wood_d",
"doors:gate_acacia_wood_closed",
"doors:gate_acacia_wood_open",
"doors:gate_aspen_wood_closed",
"doors:gate_aspen_wood_open",
"doors:gate_junglewood_closed",
"doors:gate_junglewood_open",
"doors:gate_pine_wood_closed",
"doors:gate_pine_wood_open",
"doors:gate_wood_closed",
"doors:gate_wood_open",
"doors:hidden",
"doors:trapdoor",
"doors:trapdoor_open",
"doors:trapdoor_steel",
"doors:trapdoor_steel_open",
"stairs:slab_bronzeblock",
"stairs:slab_copperblock",
"stairs:slab_steelblock",
"stairs:slab_tinblock",
"stairs:stair_bronzeblock",
"stairs:stair_copperblock",
"stairs:stair_inner_bronzeblock",
"stairs:stair_inner_copperblock",
"stairs:stair_inner_steelblock",
"stairs:stair_inner_tinblock",
"stairs:stair_outer_bronzeblock",
"stairs:stair_outer_copperblock",
"stairs:stair_outer_steelblock",
"stairs:stair_outer_tinblock",
"stairs:stair_steelblock",
"stairs:stair_tinblock",
"stairs:slab_acacia_wood",
"stairs:slab_aspen_wood",
"stairs:slab_brick",
"stairs:slab_cobble",
"stairs:slab_desert_cobble",
"stairs:slab_desert_sandstone",
"stairs:slab_desert_sandstone_block",
"stairs:slab_desert_sandstone_brick",
"stairs:slab_desert_stone",
"stairs:slab_desert_stone_block",
"stairs:slab_desert_stonebrick",
"stairs:slab_glass",
"stairs:slab_goldblock",
"stairs:slab_ice",
"stairs:slab_junglewood",
"stairs:slab_mossycobble",
"stairs:slab_obsidian",
"stairs:slab_obsidian_block",
"stairs:slab_obsidian_glass",
"stairs:slab_obsidianbrick",
"stairs:slab_pine_wood",
"stairs:slab_sandstone",
"stairs:slab_sandstone_block",
"stairs:slab_sandstonebrick",
"stairs:slab_silver_sandstone",
"stairs:slab_silver_sandstone_block",
"stairs:slab_silver_sandstone_brick",
"stairs:slab_snowblock",
"stairs:slab_stone",
"stairs:slab_stone_block",
"stairs:slab_stonebrick",
"stairs:slab_straw",
"stairs:slab_wood",
"stairs:stair_acacia_wood",
"stairs:stair_aspen_wood",
"stairs:stair_brick",
"stairs:stair_cobble",
"stairs:stair_desert_cobble",
"stairs:stair_desert_sandstone",
"stairs:stair_desert_sandstone_block",
"stairs:stair_desert_sandstone_brick",
"stairs:stair_desert_stone",
"stairs:stair_desert_stone_block",
"stairs:stair_desert_stonebrick",
"stairs:stair_glass",
"stairs:stair_goldblock",
"stairs:stair_ice",
"stairs:stair_inner_acacia_wood",
"stairs:stair_inner_aspen_wood",
"stairs:stair_inner_brick",
"stairs:stair_inner_cobble",
"stairs:stair_inner_desert_cobble",
"stairs:stair_inner_desert_sandstone",
"stairs:stair_inner_desert_sandstone_block",
"stairs:stair_inner_desert_sandstone_brick",
"stairs:stair_inner_desert_stone",
"stairs:stair_inner_desert_stone_block",
"stairs:stair_inner_desert_stonebrick",
"stairs:stair_inner_glass",
"stairs:stair_inner_goldblock",
"stairs:stair_inner_ice",
"stairs:stair_inner_junglewood",
"stairs:stair_inner_mossycobble",
"stairs:stair_inner_obsidian",
"stairs:stair_inner_obsidian_block",
"stairs:stair_inner_obsidian_glass",
"stairs:stair_inner_obsidianbrick",
"stairs:stair_inner_pine_wood",
"stairs:stair_inner_sandstone",
"stairs:stair_inner_sandstone_block",
"stairs:stair_inner_sandstonebrick",
"stairs:stair_inner_silver_sandstone",
"stairs:stair_inner_silver_sandstone_block",
"stairs:stair_inner_silver_sandstone_brick",
"stairs:stair_inner_snowblock",
"stairs:stair_inner_stone",
"stairs:stair_inner_stone_block",
"stairs:stair_inner_stonebrick",
"stairs:stair_inner_straw",
"stairs:stair_inner_wood",
"stairs:stair_junglewood",
"stairs:stair_mossycobble",
"stairs:stair_obsidian",
"stairs:stair_obsidian_block",
"stairs:stair_obsidian_glass",
"stairs:stair_obsidianbrick",
"stairs:stair_outer_acacia_wood",
"stairs:stair_outer_aspen_wood",
"stairs:stair_outer_brick",
"stairs:stair_outer_cobble",
"stairs:stair_outer_desert_cobble",
"stairs:stair_outer_desert_sandstone",
"stairs:stair_outer_desert_sandstone_block",
"stairs:stair_outer_desert_sandstone_brick",
"stairs:stair_outer_desert_stone",
"stairs:stair_outer_desert_stone_block",
"stairs:stair_outer_desert_stonebrick",
"stairs:stair_outer_glass",
"stairs:stair_outer_goldblock",
"stairs:stair_outer_ice",
"stairs:stair_outer_junglewood",
"stairs:stair_outer_mossycobble",
"stairs:stair_outer_obsidian",
"stairs:stair_outer_obsidian_block",
"stairs:stair_outer_obsidian_glass",
"stairs:stair_outer_obsidianbrick",
"stairs:stair_outer_pine_wood",
"stairs:stair_outer_sandstone",
"stairs:stair_outer_sandstone_block",
"stairs:stair_outer_sandstonebrick",
"stairs:stair_outer_silver_sandstone",
"stairs:stair_outer_silver_sandstone_block",
"stairs:stair_outer_silver_sandstone_brick",
"stairs:stair_outer_snowblock",
"stairs:stair_outer_stone",
"stairs:stair_outer_stone_block",
"stairs:stair_outer_stonebrick",
"stairs:stair_outer_straw",
"stairs:stair_outer_wood",
"stairs:stair_pine_wood",
"stairs:stair_sandstone",
"stairs:stair_sandstone_block",
"stairs:stair_sandstonebrick",
"stairs:stair_silver_sandstone",
"stairs:stair_silver_sandstone_block",
"stairs:stair_silver_sandstone_brick",
"stairs:stair_snowblock",
"stairs:stair_stone",
"stairs:stair_stone_block",
"stairs:stair_stonebrick",
"stairs:stair_straw",
"stairs:stair_wood",
"xpanes:bar",
"xpanes:bar_flat",
"xpanes:door_steel_bar",
"xpanes:door_steel_bar_a",
"xpanes:door_steel_bar_b",
"xpanes:door_steel_bar_c",
"xpanes:door_steel_bar_d",
"xpanes:obsidian_pane",
"xpanes:obsidian_pane_flat",
"xpanes:pane",
"xpanes:pane_flat",
"xpanes:trapdoor_steel_bar",
"xpanes:trapdoor_steel_bar_open",
"walls:cobble",
"walls:desertcobble",
"walls:mossycobble",
})
unified_inventory.add_category_items('environment', {
"air",
"default:cave_ice",
"default:dirt_with_rainforest_litter",
"default:gravel",
"default:dry_dirt_with_dry_grass",
"default:permafrost",
"default:desert_stone",
"default:ice",
"default:dry_dirt",
"default:obsidian",
"default:sand",
"default:river_water_source",
"default:dirt_with_snow",
"default:dirt_with_grass",
"default:water_flowing",
"default:dirt",
"default:desert_sand",
"default:permafrost_with_moss",
"default:dirt_with_coniferous_litter",
"default:water_source",
"default:dirt_with_dry_grass",
"default:river_water_flowing",
"default:stone",
"default:snow",
"default:lava_flowing",
"default:lava_source",
"default:permafrost_with_stones",
"default:dirt_with_grass_footsteps",
"default:silver_sand",
"default:snowblock",
"default:clay",
"farming:desert_sand_soil",
"farming:desert_sand_soil_wet",
"farming:dry_soil",
"farming:dry_soil_wet",
"farming:soil",
"farming:soil_wet",
})
unified_inventory.add_category_items('lighting', {
"default:mese_post_light_junglewood",
"default:torch_ceiling",
"default:meselamp",
"default:torch",
"default:mese_post_light_acacia_wood",
"default:mese_post_light",
"default:torch_wall",
"default:mese_post_light_pine_wood",
"default:mese_post_light_aspen_wood"
})
--]]
--[[ UNCATEGORISED
"farming:string",
"beds:bed_bottom",
"beds:bed_top",
"beds:fancy_bed_bottom",
"beds:fancy_bed_top",
"boats:boat",
"bones:bones",
"bucket:bucket_lava",
"bucket:bucket_river_water",
"bucket:bucket_water",
"butterflies:butterfly_red",
"butterflies:butterfly_violet",
"butterflies:butterfly_white",
"butterflies:hidden_butterfly_red",
"butterflies:hidden_butterfly_violet",
"butterflies:hidden_butterfly_white",
"carts:brakerail",
"carts:cart",
"carts:powerrail",
"carts:rail",
"default:book",
"default:book_written",
"default:bookshelf",
"default:chest",
"default:chest_locked",
"default:chest_locked_open",
"default:chest_open",
"default:clay_lump",
"default:cloud",
"default:coral_brown",
"default:coral_cyan",
"default:coral_green",
"default:coral_orange",
"default:coral_pink",
"default:coral_skeleton",
"default:flint",
"default:furnace",
"default:furnace_active",
"default:key",
"default:ladder_steel",
"default:ladder_wood",
"default:obsidian_shard",
"default:paper",
"default:sign_wall_steel",
"default:sign_wall_wood",
"default:stick",
"fire:basic_flame",
"fire:permanent_flame",
"fireflies:firefly",
"fireflies:firefly_bottle",
"fireflies:hidden_firefly",
"ignore",
"unknown",
"tnt:boom",
"tnt:gunpowder",
"tnt:gunpowder_burning",
"tnt:tnt",
"tnt:tnt_burning",
"tnt:tnt_stick",
"vessels:drinking_glass",
"vessels:glass_bottle",
"vessels:glass_fragments",
"vessels:shelf",
"vessels:steel_bottle",
"dye:black",
"dye:blue",
"dye:brown",
"dye:cyan",
"dye:dark_green",
"dye:dark_grey",
"dye:green",
"dye:grey",
"dye:magenta",
"dye:orange",
"dye:pink",
"dye:red",
"dye:violet",
"dye:white",
"dye:yellow",
"wool:black",
"wool:blue",
"wool:brown",
"wool:cyan",
"wool:dark_green",
"wool:dark_grey",
"wool:green",
"wool:grey",
"wool:magenta",
"wool:orange",
"wool:pink",
"wool:red",
"wool:violet",
"wool:white",
"wool:yellow",
"unified_inventory:bag_large",
"unified_inventory:bag_medium",
"unified_inventory:bag_small",
--]]
--[[ LIST UNCATEGORIZED AFTER LOAD
minetest.register_on_mods_loaded(function()
minetest.after(1, function ( )
local l = {}
for name,_ in pairs(minetest.registered_items) do
if not unified_inventory.find_category(name) then
-- minetest.log("error", minetest.serialize(minetest.registered_items[name]))
table.insert(l, name)
end
end
table.sort(l)
minetest.log(table.concat(l, '",'.."\n"..'"'))
end)
end)
--]]

View file

@ -10,6 +10,8 @@ unified_inventory = {
alternate = {}, alternate = {},
current_page = {}, current_page = {},
current_searchbox = {}, current_searchbox = {},
current_category = {},
current_category_scroll = {},
current_index = {}, current_index = {},
current_item = {}, current_item = {},
current_craft_direction = {}, current_craft_direction = {},
@ -33,23 +35,110 @@ unified_inventory = {
-- "Lite" mode -- "Lite" mode
lite_mode = minetest.settings:get_bool("unified_inventory_lite"), lite_mode = minetest.settings:get_bool("unified_inventory_lite"),
-- Items automatically added to categories based on item definitions
automatic_categorization = (minetest.settings:get_bool("unified_inventory_automatic_categorization") ~= false),
-- Trash enabled -- Trash enabled
trash_enabled = (minetest.settings:get_bool("unified_inventory_trash") ~= false), trash_enabled = (minetest.settings:get_bool("unified_inventory_trash") ~= false),
imgscale = 1.25,
pagecols = 8, list_img_offset = 0.13,
pagerows = 10, standard_background = "background9[0,0;1,1;ui_formbg_9_sliced.png;true;16]",
page_y = 0, version = 2
formspec_y = 1,
main_button_x = 0,
main_button_y = 9,
craft_result_x = 0.3,
craft_result_y = 0.5,
form_header_y = 0,
standard_background = "background[-0.2,-0.2;1,1;ui_form_bg.png;true]", -- the 'true' scales to fill, overrides the 1,1
standard_inv = "list[current_player;main;0,YYY;8,4;]", -- the YYY's are placeholders which get
standard_inv_bg = "image[-0.1,YYY;10.05,4.70;ui_main_inventory.png]", -- replaced later by string.gsub()
} }
local ui = unified_inventory
-- These tables establish position and layout for the two UI styles.
-- UI doesn't use formspec_[xy] anymore, but other mods may need them.
ui.style_full = {
formspec_x = 1,
formspec_y = 1,
formw = 17.75,
formh = 12.25,
pagecols = 8,
pagerows = 9,
page_x = 10.75,
page_y = 2.30,
craft_x = 2.8,
craft_y = 1.15,
craftresult_x = 7.8,
craft_arrow_x = 6.55,
craft_guide_x = 3.3,
craft_guide_y = 1.15,
craft_guide_arrow_x = 7.05,
craft_guide_result_x = 8.3,
craft_guide_resultstr_x = 0.3,
craft_guide_resultstr_y = 0.6,
give_btn_x = 0.25,
main_button_x = 0.4,
main_button_y = 11.0,
page_buttons_x = 11.60,
page_buttons_y = 10.15,
searchwidth = 3.4,
form_header_x = 0.4,
form_header_y = 0.4,
btn_spc = 0.85,
btn_size = 0.75,
std_inv_x = 0.3,
std_inv_y = 5.75,
}
ui.style_lite = {
formspec_x = 0.6,
formspec_y = 0.6,
formw = 14,
formh = 9.75,
pagecols = 4,
pagerows = 5,
page_x = 10.5,
page_y = 2.15,
craft_x = 2.6,
craft_y = 0.75,
craftresult_x = 5.75,
craft_arrow_x = 6.35,
craft_guide_x = 3.1,
craft_guide_y = 0.75,
craft_guide_arrow_x = 7.05,
craft_guide_result_x = 8.3,
craft_guide_resultstr_x = 0.15,
craft_guide_resultstr_y = 0.35,
give_btn_x = 0.15,
main_button_x = 10.5,
main_button_y = 8.15,
page_buttons_x = 10.5,
page_buttons_y = 6.15,
searchwidth = 1.6,
form_header_x = 0.2,
form_header_y = 0.2,
btn_spc = 0.8,
btn_size = 0.7,
std_inv_x = 0.1,
std_inv_y = 4.6,
}
dofile(modpath.."/api.lua")
for _, style in ipairs({ui.style_full, ui.style_lite}) do
style.items_per_page = style.pagecols * style.pagerows
style.standard_inv = string.format("list[current_player;main;%f,%f;8,4;]",
style.std_inv_x + ui.list_img_offset, style.std_inv_y + ui.list_img_offset)
style.standard_inv_bg = ui.make_inv_img_grid(style.std_inv_x, style.std_inv_y, 8, 1, true)..
ui.make_inv_img_grid(style.std_inv_x, style.std_inv_y + ui.imgscale, 8, 3)
style.craft_grid = table.concat({
ui.make_inv_img_grid(style.craft_x, style.craft_y, 3, 3),
ui.single_slot(style.craft_x + ui.imgscale*4, style.craft_y), -- the craft result slot
string.format("image[%f,%f;%f,%f;ui_crafting_arrow.png]",
style.craft_arrow_x, style.craft_y, ui.imgscale, ui.imgscale),
string.format("list[current_player;craft;%f,%f;3,3;]",
style.craft_x + ui.list_img_offset, style.craft_y + ui.list_img_offset),
string.format("list[current_player;craftpreview;%f,%f;1,1;]",
style.craftresult_x + ui.list_img_offset, style.craft_y + ui.list_img_offset)
})
end
-- Disable default creative inventory -- Disable default creative inventory
local creative = rawget(_G, "creative") or rawget(_G, "creative_inventory") local creative = rawget(_G, "creative") or rawget(_G, "creative_inventory")
if creative then if creative then
@ -65,7 +154,8 @@ if sfinv then
end end
dofile(modpath.."/group.lua") dofile(modpath.."/group.lua")
dofile(modpath.."/api.lua") dofile(modpath.."/category.lua")
dofile(modpath.."/default-categories.lua")
dofile(modpath.."/internal.lua") dofile(modpath.."/internal.lua")
dofile(modpath.."/callbacks.lua") dofile(modpath.."/callbacks.lua")
dofile(modpath.."/match_craft.lua") dofile(modpath.."/match_craft.lua")

View file

@ -1,5 +1,6 @@
local S = minetest.get_translator("unified_inventory") local S = minetest.get_translator("unified_inventory")
local F = minetest.formspec_escape local F = minetest.formspec_escape
local ui = unified_inventory
-- This pair of encoding functions is used where variable text must go in -- This pair of encoding functions is used where variable text must go in
-- button names, where the text might contain formspec metacharacters. -- button names, where the text might contain formspec metacharacters.
@ -9,78 +10,61 @@ local F = minetest.formspec_escape
-- This is a game engine bug, and in the anticipation that it might be -- This is a game engine bug, and in the anticipation that it might be
-- fixed some day we don't want to rely on it. So for safety we apply -- fixed some day we don't want to rely on it. So for safety we apply
-- an encoding that avoids all formspec metacharacters. -- an encoding that avoids all formspec metacharacters.
function unified_inventory.mangle_for_formspec(str)
function ui.mangle_for_formspec(str)
return string.gsub(str, "([^A-Za-z0-9])", function (c) return string.format("_%d_", string.byte(c)) end) return string.gsub(str, "([^A-Za-z0-9])", function (c) return string.format("_%d_", string.byte(c)) end)
end end
function unified_inventory.demangle_for_formspec(str) function ui.demangle_for_formspec(str)
return string.gsub(str, "_([0-9]+)_", function (v) return string.char(v) end) return string.gsub(str, "_([0-9]+)_", function (v) return string.char(v) end)
end end
function unified_inventory.get_per_player_formspec(player_name)
local lite = unified_inventory.lite_mode and not minetest.check_player_privs(player_name, {ui_full=true})
local ui = {} function ui.get_per_player_formspec(player_name)
ui.pagecols = unified_inventory.pagecols local draw_lite_mode = ui.lite_mode and not minetest.check_player_privs(player_name, {ui_full=true})
ui.pagerows = unified_inventory.pagerows
ui.page_y = unified_inventory.page_y
ui.formspec_y = unified_inventory.formspec_y
ui.main_button_x = unified_inventory.main_button_x
ui.main_button_y = unified_inventory.main_button_y
ui.craft_result_x = unified_inventory.craft_result_x
ui.craft_result_y = unified_inventory.craft_result_y
ui.form_header_y = unified_inventory.form_header_y
if lite then return table.copy(draw_lite_mode and ui.style_lite or ui.style_full), draw_lite_mode
ui.pagecols = 4
ui.pagerows = 6
ui.page_y = 0.25
ui.formspec_y = 0.47
ui.main_button_x = 8.2
ui.main_button_y = 6.5
ui.craft_result_x = 2.8
ui.craft_result_y = 3.4
ui.form_header_y = -0.1
end
ui.items_per_page = ui.pagecols * ui.pagerows
return ui, lite
end end
function unified_inventory.get_formspec(player, page) local function formspec_button(ui_peruser, name, image, offset, pos, scale, label)
local element = 'image_button'
if minetest.registered_items[image] then
element = 'item_image_button'
end
local spc = (1-scale)*ui_peruser.btn_size/2
local size = ui_peruser.btn_size*scale
return string.format("%s[%f,%f;%f,%f;%s;%s;]", element,
(offset.x or offset[1]) + ( ui_peruser.btn_spc * (pos.x or pos[1]) ) + spc,
(offset.y or offset[2]) + ( ui_peruser.btn_spc * (pos.y or pos[2]) ) + spc,
size, size, image, name) ..
string.format("tooltip[%s;%s]", name, F(label or name))
end
function ui.get_formspec(player, page)
if not player then if not player then
return "" return ""
end end
local player_name = player:get_player_name() local player_name = player:get_player_name()
local ui_peruser,draw_lite_mode = unified_inventory.get_per_player_formspec(player_name) local ui_peruser,draw_lite_mode = ui.get_per_player_formspec(player_name)
unified_inventory.current_page[player_name] = page ui.current_page[player_name] = page
local pagedef = unified_inventory.pages[page] local pagedef = ui.pages[page]
if not pagedef then if not pagedef then
return "" -- Invalid page name return "" -- Invalid page name
end end
local formspec = { local formspec = {
"size[14,10]", "formspec_version[4]",
"size["..ui_peruser.formw..","..ui_peruser.formh.."]",
pagedef.formspec_prepend and "" or "no_prepend[]", pagedef.formspec_prepend and "" or "no_prepend[]",
unified_inventory.standard_background -- Background ui.standard_background
} }
local n = 4
if draw_lite_mode then local n = 5
formspec[1] = "size[11,7.7]"
formspec[3] = unified_inventory.standard_background
end
if unified_inventory.is_creative(player_name) local perplayer_formspec = ui.get_per_player_formspec(player_name)
and page == "craft" then
formspec[n] = "background[0,"..(ui_peruser.formspec_y + 2)..";1,1;ui_single_slot.png]"
n = n+1
end
local perplayer_formspec = unified_inventory.get_per_player_formspec(player_name)
local fsdata = pagedef.get_formspec(player, perplayer_formspec) local fsdata = pagedef.get_formspec(player, perplayer_formspec)
formspec[n] = fsdata.formspec formspec[n] = fsdata.formspec
@ -93,7 +77,7 @@ function unified_inventory.get_formspec(player, page)
local filtered_inv_buttons = {} local filtered_inv_buttons = {}
for i, def in pairs(unified_inventory.buttons) do for i, def in pairs(ui.buttons) do
if not (draw_lite_mode and def.hide_lite) then if not (draw_lite_mode and def.hide_lite) then
table.insert(filtered_inv_buttons, def) table.insert(filtered_inv_buttons, def)
end end
@ -108,21 +92,20 @@ function unified_inventory.get_formspec(player, page)
if def.type == "image" then if def.type == "image" then
if (def.condition == nil or def.condition(player) == true) then if (def.condition == nil or def.condition(player) == true) then
formspec[n] = "image_button[" formspec[n] = string.format("image_button[%f,%f;%f,%f;%s;%s;]",
formspec[n+1] = ( ui_peruser.main_button_x + 0.65 * (i - 1) - button_col * 0.65 * 4) ui_peruser.main_button_x + ui_peruser.btn_spc * (i - 1) - button_col * ui_peruser.btn_spc * 4,
formspec[n+2] = ","..(ui_peruser.main_button_y + button_row * 0.7)..";0.8,0.8;" ui_peruser.main_button_y + button_row * ui_peruser.btn_spc,
formspec[n+3] = F(def.image)..";" ui_peruser.btn_size,ui_peruser.btn_size,
formspec[n+4] = F(def.name)..";]" F(def.image),
formspec[n+5] = "tooltip["..F(def.name) F(def.name))
formspec[n+6] = ";"..(def.tooltip or "").."]" formspec[n+1] = "tooltip["..F(def.name)..";"..(def.tooltip or "").."]"
n = n+7 n = n+2
else else
formspec[n] = "image[" formspec[n] = string.format("image[%f,%f;%f,%f;%s^[colorize:#808080:alpha]",
formspec[n+1] = ( ui_peruser.main_button_x + 0.65 * (i - 1) - button_col * 0.65 * 4) ui_peruser.main_button_x + ui_peruser.btn_spc * (i - 1) - button_col * ui_peruser.btn_spc * 4,
formspec[n+2] = ","..(ui_peruser.main_button_y + button_row * 0.7)..";0.8,0.8;" ui_peruser.main_button_y + button_row * ui_peruser.btn_spc,
formspec[n+3] = F(def.image).."^[colorize:#808080:alpha]" ui_peruser.btn_size,ui_peruser.btn_size,def.image)
n = n+4 n = n+1
end end
end end
end end
@ -130,7 +113,7 @@ function unified_inventory.get_formspec(player, page)
if fsdata.draw_inventory ~= false then if fsdata.draw_inventory ~= false then
-- Player inventory -- Player inventory
formspec[n] = "listcolors[#00000000;#00000000]" formspec[n] = "listcolors[#00000000;#00000000]"
formspec[n+1] = string.gsub(unified_inventory.standard_inv, "YYY", ui_peruser.formspec_y + 3.5) formspec[n+1] = ui_peruser.standard_inv
n = n+2 n = n+2
end end
@ -138,71 +121,94 @@ function unified_inventory.get_formspec(player, page)
return table.concat(formspec, "") return table.concat(formspec, "")
end end
-- Controls to flip items pages -- Category filters
local start_x = 9.2
if not draw_lite_mode then local categories_pos = { ui_peruser.page_x, ui_peruser.page_y-ui_peruser.btn_spc-0.5 }
formspec[n] = local categories_scroll_pos = { ui_peruser.page_x, ui_peruser.form_header_y-(draw_lite_mode and 0 or 0.2) }
"image_button[" .. (start_x + 0.6 * 0)
.. ",9;.8,.8;ui_skip_backward_icon.png;start_list;]"
.. "tooltip[start_list;" .. F(S("First page")) .. "]"
.. "image_button[" .. (start_x + 0.6 * 1) formspec[n] = string.format("background9[%f,%f;%f,%f;%s;false;3]",
.. ",9;.8,.8;ui_doubleleft_icon.png;rewind3;]" ui_peruser.page_x-0.1, categories_scroll_pos[2],
.. "tooltip[rewind3;" .. F(S("Back three pages")) .. "]" (ui_peruser.btn_spc * ui_peruser.pagecols) + 0.13, 1.4+(draw_lite_mode and 0 or 0.2),
.. "image_button[" .. (start_x + 0.6 * 2) "ui_smallbg_9_sliced.png")
.. ",9;.8,.8;ui_left_icon.png;rewind1;]" n = n + 1
.. "tooltip[rewind1;" .. F(S("Back one page")) .. "]"
.. "image_button[" .. (start_x + 0.6 * 3) formspec[n] = string.format("label[%f,%f;%s]", ui_peruser.page_x, ui_peruser.form_header_y+(draw_lite_mode and 0.3 or 0.2), "Category:")
.. ",9;.8,.8;ui_right_icon.png;forward1;]" n = n + 1
.. "tooltip[forward1;" .. F(S("Forward one page")) .. "]"
.. "image_button[" .. (start_x + 0.6 * 4)
.. ",9;.8,.8;ui_doubleright_icon.png;forward3;]"
.. "tooltip[forward3;" .. F(S("Forward three pages")) .. "]"
.. "image_button[" .. (start_x + 0.6 * 5) local scroll_offset = 0
.. ",9;.8,.8;ui_skip_forward_icon.png;end_list;]" local category_count = #unified_inventory.category_list
.. "tooltip[end_list;" .. F(S("Last page")) .. "]" if category_count > ui_peruser.pagecols then
else scroll_offset = unified_inventory.current_category_scroll[player_name]
formspec[n] = end
"image_button[" .. (8.2 + 0.65 * 0)
.. ",5.8;.8,.8;ui_skip_backward_icon.png;start_list;]" for index, category in ipairs(unified_inventory.category_list) do
.. "tooltip[start_list;" .. F(S("First page")) .. "]" local column = index - scroll_offset
.. "image_button[" .. (8.2 + 0.65 * 1) if column > 0 and column <= ui_peruser.pagecols then
.. ",5.8;.8,.8;ui_left_icon.png;rewind1;]" local scale = 0.8
.. "tooltip[rewind1;" .. F(S("Back one page")) .. "]" if unified_inventory.current_category[player_name] == category.name then
.. "image_button[" .. (8.2 + 0.65 * 2) scale = 1
.. ",5.8;.8,.8;ui_right_icon.png;forward1;]" end
.. "tooltip[forward1;" .. F(S("Forward one page")) .. "]" formspec[n] = formspec_button(ui_peruser, "category_"..category.name, category.symbol, categories_pos, {column-1, 0}, scale, category.label)
.. "image_button[" .. (8.2 + 0.65 * 3) n = n + 1
.. ",5.8;.8,.8;ui_skip_forward_icon.png;end_list;]" end
.. "tooltip[end_list;" .. F(S("Last page")) .. "]" end
if category_count > ui_peruser.pagecols and scroll_offset > 0 then
-- prev
formspec[n] = formspec_button(ui_peruser, "prev_category", "ui_left_icon.png", categories_scroll_pos, {ui_peruser.pagecols - 2, 0}, 0.8, S("Scroll categories left"))
n = n + 1
end
if category_count > ui_peruser.pagecols and category_count - scroll_offset > ui_peruser.pagecols then
-- next
formspec[n] = formspec_button(ui_peruser, "next_category", "ui_right_icon.png", categories_scroll_pos, {ui_peruser.pagecols - 1, 0}, 0.8, S("Scroll categories right"))
n = n + 1
end end
n = n+1
-- Search box -- Search box
formspec[n] = "field_close_on_enter[searchbox;false]" formspec[n] = "field_close_on_enter[searchbox;false]"
n = n+1
if not draw_lite_mode then formspec[n+1] = string.format("field[%f,%f;%f,%f;searchbox;;%s]",
formspec[n] = "field[9.5,8.325;3,1;searchbox;;" ui_peruser.page_buttons_x, ui_peruser.page_buttons_y,
.. F(unified_inventory.current_searchbox[player_name]) .. "]" ui_peruser.searchwidth - 0.1, ui_peruser.btn_size,
formspec[n+1] = "image_button[12.2,8.1;.8,.8;ui_search_icon.png;searchbutton;]" F(ui.current_searchbox[player_name]))
.. "tooltip[searchbutton;" ..F(S("Search")) .. "]" formspec[n+2] = string.format("image_button[%f,%f;%f,%f;ui_search_icon.png;searchbutton;]",
formspec[n+2] = "image_button[12.9,8.1;.8,.8;ui_reset_icon.png;searchresetbutton;]" ui_peruser.page_buttons_x + ui_peruser.searchwidth, ui_peruser.page_buttons_y,
.. "tooltip[searchbutton;" ..F(S("Search")) .. "]" ui_peruser.btn_size,ui_peruser.btn_size)
.. "tooltip[searchresetbutton;" ..F(S("Reset search and display everything")) .. "]" formspec[n+3] = "tooltip[searchbutton;" ..F(S("Search")) .. "]"
else formspec[n+4] = string.format("image_button[%f,%f;%f,%f;ui_reset_icon.png;searchresetbutton;]",
formspec[n] = "field[8.5,5.225;2.2,1;searchbox;;" ui_peruser.page_buttons_x + ui_peruser.searchwidth + ui_peruser.btn_spc,
.. F(unified_inventory.current_searchbox[player_name]) .. "]" ui_peruser.page_buttons_y,
formspec[n+1] = "image_button[10.3,5;.8,.8;ui_search_icon.png;searchbutton;]" ui_peruser.btn_size, ui_peruser.btn_size)
.. "tooltip[searchbutton;" ..F(S("Search")) .. "]" formspec[n+5] = "tooltip[searchresetbutton;"..F(S("Reset search and display everything")).."]"
formspec[n+2] = "image_button[11,5;.8,.8;ui_reset_icon.png;searchresetbutton;]"
.. "tooltip[searchbutton;" ..F(S("Search")) .. "]" n = n + 6
.. "tooltip[searchresetbutton;" ..F(S("Reset search and display everything")) .. "]"
-- Controls to flip items pages
local btnlist = {
{ "ui_skip_backward_icon.png", "start_list", S("First page") },
{ "ui_doubleleft_icon.png", "rewind3", S("Back three pages") },
{ "ui_left_icon.png", "rewind1", S("Back one page") },
{ "ui_right_icon.png", "forward1", S("Forward one page") },
{ "ui_doubleright_icon.png", "forward3", S("Forward three pages") },
{ "ui_skip_forward_icon.png", "end_list", S("Last page") },
}
if draw_lite_mode then
btnlist[5] = nil
btnlist[2] = nil
end
local bn = 0
for _, b in pairs(btnlist) do
formspec[n] = string.format("image_button[%f,%f;%f,%f;%s;%s;]",
ui_peruser.page_buttons_x + ui_peruser.btn_spc*bn,
ui_peruser.page_buttons_y + ui_peruser.btn_spc,
ui_peruser.btn_size, ui_peruser.btn_size,
b[1],b[2])
formspec[n+1] = "tooltip["..b[2]..";"..F(b[3]).."]"
bn = bn + 1
n = n + 2
end end
n = n+3
local no_matches = S("No matching items") local no_matches = S("No matching items")
if draw_lite_mode then if draw_lite_mode then
@ -210,23 +216,23 @@ function unified_inventory.get_formspec(player, page)
end end
-- Items list -- Items list
if #unified_inventory.filtered_items_list[player_name] == 0 then if #ui.filtered_items_list[player_name] == 0 then
formspec[n] = "label[8.2,"..ui_peruser.form_header_y..";" .. F(no_matches) .. "]" formspec[n] = "label["..ui_peruser.page_x..","..(ui_peruser.page_y+0.15)..";" .. F(no_matches) .. "]"
else else
local dir = unified_inventory.active_search_direction[player_name] local dir = ui.active_search_direction[player_name]
local list_index = unified_inventory.current_index[player_name] local list_index = ui.current_index[player_name]
local page2 = math.floor(list_index / (ui_peruser.items_per_page) + 1) local page2 = math.floor(list_index / (ui_peruser.items_per_page) + 1)
local pagemax = math.floor( local pagemax = math.floor(
(#unified_inventory.filtered_items_list[player_name] - 1) (#ui.filtered_items_list[player_name] - 1)
/ (ui_peruser.items_per_page) + 1) / (ui_peruser.items_per_page) + 1)
for y = 0, ui_peruser.pagerows - 1 do for y = 0, ui_peruser.pagerows - 1 do
for x = 0, ui_peruser.pagecols - 1 do for x = 0, ui_peruser.pagecols - 1 do
local name = unified_inventory.filtered_items_list[player_name][list_index] local name = ui.filtered_items_list[player_name][list_index]
local item = minetest.registered_items[name] local item = minetest.registered_items[name]
if item then if item then
-- Clicked on current item: Flip crafting direction -- Clicked on current item: Flip crafting direction
if name == unified_inventory.current_item[player_name] then if name == ui.current_item[player_name] then
local cdir = unified_inventory.current_craft_direction[player_name] local cdir = ui.current_craft_direction[player_name]
if cdir == "recipe" then if cdir == "recipe" then
dir = "usage" dir = "usage"
elseif cdir == "usage" then elseif cdir == "usage" then
@ -234,13 +240,15 @@ function unified_inventory.get_formspec(player, page)
end end
else else
-- Default: use active search direction by default -- Default: use active search direction by default
dir = unified_inventory.active_search_direction[player_name] dir = ui.active_search_direction[player_name]
end end
local button_name = "item_button_" .. dir .. "_" local button_name = "item_button_" .. dir .. "_"
.. unified_inventory.mangle_for_formspec(name) .. ui.mangle_for_formspec(name)
formspec[n] = ("item_image_button[%f,%f;.81,.81;%s;%s;]"):format( formspec[n] = ("item_image_button[%f,%f;%f,%f;%s;%s;]"):format(
8.2 + x * 0.7, ui_peruser.formspec_y + ui_peruser.page_y + y * 0.7, ui_peruser.page_x + x * ui_peruser.btn_spc,
ui_peruser.page_y + y * ui_peruser.btn_spc,
ui_peruser.btn_size, ui_peruser.btn_size,
name, button_name name, button_name
) )
formspec[n + 1] = ("tooltip[%s;%s \\[%s\\]]"):format( formspec[n + 1] = ("tooltip[%s;%s \\[%s\\]]"):format(
@ -252,26 +260,36 @@ function unified_inventory.get_formspec(player, page)
end end
end end
end end
formspec[n] = "label[8.2,"..ui_peruser.form_header_y..";"..F(S("Page")) .. ": " formspec[n] = string.format("label[%f,%f;%s: %s]",
.. S("@1 of @2",page2,pagemax).."]" ui_peruser.page_buttons_x + ui_peruser.btn_spc * (draw_lite_mode and 1 or 2),
ui_peruser.page_buttons_y + 0.1 + ui_peruser.btn_spc * 2,
F(S("Page")), S("@1 of @2",page2,pagemax))
end end
n= n+1 n= n+1
if unified_inventory.activefilter[player_name] ~= "" then if ui.activefilter[player_name] ~= "" then
formspec[n] = "label[8.2,"..(ui_peruser.form_header_y + 0.4)..";" .. F(S("Filter")) .. ":]" formspec[n] = string.format("label[%f,%f;%s: %s]",
formspec[n+1] = "label[9.1,"..(ui_peruser.form_header_y + 0.4)..";"..F(unified_inventory.activefilter[player_name]).."]" ui_peruser.page_x, ui_peruser.page_y - 0.25,
F(S("Filter")), F(ui.activefilter[player_name]))
end end
return table.concat(formspec, "") return table.concat(formspec, "")
end end
function unified_inventory.set_inventory_formspec(player, page) function ui.set_inventory_formspec(player, page)
if player then if player then
player:set_inventory_formspec(unified_inventory.get_formspec(player, page)) player:set_inventory_formspec(ui.get_formspec(player, page))
end end
end end
local function valid_def(def)
return (not def.groups.not_in_creative_inventory
or def.groups.not_in_creative_inventory == 0)
and def.description
and def.description ~= ""
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, search_dir) function ui.apply_filter(player, filter, search_dir)
if not player then if not player then
return false return false
end end
@ -300,26 +318,43 @@ function unified_inventory.apply_filter(player, filter, search_dir)
or llocaldesc and string.find(llocaldesc, lfilter, 1, true) or llocaldesc and string.find(llocaldesc, lfilter, 1, true)
end end
end end
unified_inventory.filtered_items_list[player_name]={} ui.filtered_items_list[player_name]={}
for name, def in pairs(minetest.registered_items) do local category = ui.current_category[player_name] or 'all'
if (not def.groups.not_in_creative_inventory if category == 'all' then
or def.groups.not_in_creative_inventory == 0) for name, def in pairs(minetest.registered_items) do
and def.description if valid_def(def)
and def.description ~= "" and ffilter(name, def) then
and ffilter(name, def) then table.insert(ui.filtered_items_list[player_name], name)
table.insert(unified_inventory.filtered_items_list[player_name], name) end
end
elseif category == 'uncategorized' then
for name, def in pairs(minetest.registered_items) do
if (not ui.find_category(name))
and valid_def(def)
and ffilter(name, def) then
table.insert(ui.filtered_items_list[player_name], name)
end
end
else
for name,exists in pairs(ui.registered_category_items[category]) do
local def = minetest.registered_items[name]
if exists and def
and valid_def(def)
and ffilter(name, def) then
table.insert(ui.filtered_items_list[player_name], name)
end
end end
end end
table.sort(unified_inventory.filtered_items_list[player_name]) table.sort(ui.filtered_items_list[player_name])
unified_inventory.filtered_items_list_size[player_name] = #unified_inventory.filtered_items_list[player_name] ui.filtered_items_list_size[player_name] = #ui.filtered_items_list[player_name]
unified_inventory.current_index[player_name] = 1 ui.current_index[player_name] = 1
unified_inventory.activefilter[player_name] = filter ui.activefilter[player_name] = filter
unified_inventory.active_search_direction[player_name] = search_dir ui.active_search_direction[player_name] = search_dir
unified_inventory.set_inventory_formspec(player, ui.set_inventory_formspec(player,
unified_inventory.current_page[player_name]) ui.current_page[player_name])
end end
function unified_inventory.items_in_group(groups) function ui.items_in_group(groups)
local items = {} local items = {}
for name, item in pairs(minetest.registered_items) do for name, item in pairs(minetest.registered_items) do
for _, group in pairs(groups:split(',')) do for _, group in pairs(groups:split(',')) do
@ -331,7 +366,7 @@ function unified_inventory.items_in_group(groups)
return items return items
end end
function unified_inventory.sort_inventory(inv) function ui.sort_inventory(inv)
local inlist = inv:get_list("main") local inlist = inv:get_list("main")
local typecnt = {} local typecnt = {}
local typekeys = {} local typekeys = {}

View file

@ -5,6 +5,4 @@ description = """
Unified Inventory replaces the default survival and creative inventory. Unified Inventory replaces the default survival and creative inventory.
It adds a nicer interface and a number of features, such as a crafting guide. It adds a nicer interface and a number of features, such as a crafting guide.
""" """
release = 6744 min_minetest_version = 5.4.0
title = Unified Inventory
author = RealBadAngel

View file

@ -1,6 +1,7 @@
local S = minetest.get_translator("unified_inventory") local S = minetest.get_translator("unified_inventory")
local NS = function(s) return s end local NS = function(s) return s end
local F = minetest.formspec_escape local F = minetest.formspec_escape
local ui = unified_inventory
minetest.register_privilege("creative", { minetest.register_privilege("creative", {
description = S("Can use the creative inventory"), description = S("Can use the creative inventory"),
@ -12,10 +13,9 @@ minetest.register_privilege("ui_full", {
give_to_singleplayer = false, give_to_singleplayer = false,
}) })
local trash = minetest.create_detached_inventory("trash", { local trash = minetest.create_detached_inventory("trash", {
--allow_put = function(inv, listname, index, stack, player) --allow_put = function(inv, listname, index, stack, player)
-- if unified_inventory.is_creative(player:get_player_name()) then -- if ui.is_creative(player:get_player_name()) then
-- return stack:get_count() -- return stack:get_count()
-- else -- else
-- return 0 -- return 0
@ -29,19 +29,19 @@ local trash = minetest.create_detached_inventory("trash", {
}) })
trash:set_size("main", 1) trash:set_size("main", 1)
unified_inventory.register_button("craft", { ui.register_button("craft", {
type = "image", type = "image",
image = "ui_craft_icon.png", image = "ui_craft_icon.png",
tooltip = S("Crafting Grid") tooltip = S("Crafting Grid")
}) })
unified_inventory.register_button("craftguide", { ui.register_button("craftguide", {
type = "image", type = "image",
image = "ui_craftguide_icon.png", image = "ui_craftguide_icon.png",
tooltip = S("Crafting Guide") tooltip = S("Crafting Guide")
}) })
unified_inventory.register_button("home_gui_set", { ui.register_button("home_gui_set", {
type = "image", type = "image",
image = "ui_sethome_icon.png", image = "ui_sethome_icon.png",
tooltip = S("Set home position"), tooltip = S("Set home position"),
@ -49,8 +49,8 @@ unified_inventory.register_button("home_gui_set", {
action = function(player) action = function(player)
local player_name = player:get_player_name() local player_name = player:get_player_name()
if minetest.check_player_privs(player_name, {home=true}) then if minetest.check_player_privs(player_name, {home=true}) then
unified_inventory.set_home(player, player:get_pos()) ui.set_home(player, player:get_pos())
local home = unified_inventory.home_pos[player_name] local home = ui.home_pos[player_name]
if home ~= nil then if home ~= nil then
minetest.sound_play("dingdong", minetest.sound_play("dingdong",
{to_player=player_name, gain = 1.0}) {to_player=player_name, gain = 1.0})
@ -60,7 +60,7 @@ unified_inventory.register_button("home_gui_set", {
else else
minetest.chat_send_player(player_name, minetest.chat_send_player(player_name,
S("You don't have the \"home\" privilege!")) S("You don't have the \"home\" privilege!"))
unified_inventory.set_inventory_formspec(player, unified_inventory.current_page[player_name]) ui.set_inventory_formspec(player, ui.current_page[player_name])
end end
end, end,
condition = function(player) condition = function(player)
@ -68,7 +68,7 @@ unified_inventory.register_button("home_gui_set", {
end, end,
}) })
unified_inventory.register_button("home_gui_go", { ui.register_button("home_gui_go", {
type = "image", type = "image",
image = "ui_gohome_icon.png", image = "ui_gohome_icon.png",
tooltip = S("Go home"), tooltip = S("Go home"),
@ -76,13 +76,13 @@ unified_inventory.register_button("home_gui_go", {
action = function(player) action = function(player)
local player_name = player:get_player_name() local player_name = player:get_player_name()
if minetest.check_player_privs(player_name, {home=true}) then if minetest.check_player_privs(player_name, {home=true}) then
if unified_inventory.go_home(player) then if ui.go_home(player) then
minetest.sound_play("teleport", {to_player = player_name}) minetest.sound_play("teleport", {to_player = player_name})
end end
else else
minetest.chat_send_player(player_name, minetest.chat_send_player(player_name,
S("You don't have the \"home\" privilege!")) S("You don't have the \"home\" privilege!"))
unified_inventory.set_inventory_formspec(player, unified_inventory.current_page[player_name]) ui.set_inventory_formspec(player, ui.current_page[player_name])
end end
end, end,
condition = function(player) condition = function(player)
@ -90,7 +90,7 @@ unified_inventory.register_button("home_gui_go", {
end, end,
}) })
unified_inventory.register_button("misc_set_day", { ui.register_button("misc_set_day", {
type = "image", type = "image",
image = "ui_sun_icon.png", image = "ui_sun_icon.png",
tooltip = S("Set time to day"), tooltip = S("Set time to day"),
@ -106,7 +106,7 @@ unified_inventory.register_button("misc_set_day", {
else else
minetest.chat_send_player(player_name, minetest.chat_send_player(player_name,
S("You don't have the settime privilege!")) S("You don't have the settime privilege!"))
unified_inventory.set_inventory_formspec(player, unified_inventory.current_page[player_name]) ui.set_inventory_formspec(player, ui.current_page[player_name])
end end
end, end,
condition = function(player) condition = function(player)
@ -114,7 +114,7 @@ unified_inventory.register_button("misc_set_day", {
end, end,
}) })
unified_inventory.register_button("misc_set_night", { ui.register_button("misc_set_night", {
type = "image", type = "image",
image = "ui_moon_icon.png", image = "ui_moon_icon.png",
tooltip = S("Set time to night"), tooltip = S("Set time to night"),
@ -130,7 +130,7 @@ unified_inventory.register_button("misc_set_night", {
else else
minetest.chat_send_player(player_name, minetest.chat_send_player(player_name,
S("You don't have the settime privilege!")) S("You don't have the settime privilege!"))
unified_inventory.set_inventory_formspec(player, unified_inventory.current_page[player_name]) ui.set_inventory_formspec(player, ui.current_page[player_name])
end end
end, end,
condition = function(player) condition = function(player)
@ -138,19 +138,19 @@ unified_inventory.register_button("misc_set_night", {
end, end,
}) })
unified_inventory.register_button("clear_inv", { ui.register_button("clear_inv", {
type = "image", type = "image",
image = "ui_trash_icon.png", image = "ui_trash_icon.png",
tooltip = S("Clear inventory"), tooltip = S("Clear inventory"),
action = function(player) action = function(player)
local player_name = player:get_player_name() local player_name = player:get_player_name()
if not unified_inventory.is_creative(player_name) then if not ui.is_creative(player_name) then
minetest.chat_send_player(player_name, minetest.chat_send_player(player_name,
S("This button has been disabled outside" S("This button has been disabled outside"
.." of creative mode to prevent" .." of creative mode to prevent"
.." accidental inventory trashing." .." accidental inventory trashing."
.."\nUse the trash slot instead.")) .."\nUse the trash slot instead."))
unified_inventory.set_inventory_formspec(player, unified_inventory.current_page[player_name]) ui.set_inventory_formspec(player, ui.current_page[player_name])
return return
end end
player:get_inventory():set_list("main", {}) player:get_inventory():set_list("main", {})
@ -159,35 +159,42 @@ unified_inventory.register_button("clear_inv", {
{to_player=player_name, gain = 1.0}) {to_player=player_name, gain = 1.0})
end, end,
condition = function(player) condition = function(player)
return unified_inventory.is_creative(player:get_player_name()) return ui.is_creative(player:get_player_name())
end, end,
}) })
unified_inventory.register_page("craft", { ui.register_page("craft", {
get_formspec = function(player, perplayer_formspec) get_formspec = function(player, perplayer_formspec)
local formspecy = perplayer_formspec.formspec_y local formheaderx = perplayer_formspec.form_header_x
local formheadery = perplayer_formspec.form_header_y local formheadery = perplayer_formspec.form_header_y
local craftx = perplayer_formspec.craft_x
local crafty = perplayer_formspec.craft_y
local player_name = player:get_player_name() local player_name = player:get_player_name()
local formspec = "background[2,"..formspecy..";6,3;ui_crafting_form.png]" local formspec = {
formspec = formspec..string.gsub(unified_inventory.standard_inv_bg, "YYY", (formspecy + 3.4)) perplayer_formspec.standard_inv_bg,
formspec = formspec.."label[0,"..formheadery..";" ..F(S("Crafting")).."]" perplayer_formspec.craft_grid,
formspec = formspec.."listcolors[#00000000;#00000000]" "label["..formheaderx..","..formheadery..";" ..F(S("Crafting")).."]",
formspec = formspec.."list[current_player;craftpreview;6,"..formspecy..";1,1;]" "listcolors[#00000000;#00000000]",
formspec = formspec.."list[current_player;craft;2,"..formspecy..";3,3;]" "listring[current_name;craft]",
if unified_inventory.trash_enabled or unified_inventory.is_creative(player_name) or minetest.get_player_privs(player_name).give then "listring[current_player;main]"
formspec = formspec.."label[7,"..(formspecy + 1.5)..";" .. F(S("Trash:")) .. "]" }
formspec = formspec.."background[7,"..(formspecy + 2)..";1,1;ui_single_slot.png]" local n=#formspec+1
formspec = formspec.."list[detached:trash;main;7,"..(formspecy + 2)..";1,1;]"
if ui.trash_enabled or ui.is_creative(player_name) or minetest.get_player_privs(player_name).give then
formspec[n] = string.format("label[%f,%f;%s]", craftx + 6.45, crafty + 2.4, F(S("Trash:")))
formspec[n+1] = ui.make_trash_slot(craftx + 6.25, crafty + 2.5)
n=n + 2
end end
formspec = formspec.."listring[current_name;craft]"
formspec = formspec.."listring[current_player;main]" if ui.is_creative(player_name) then
if unified_inventory.is_creative(player_name) then formspec[n] = ui.single_slot(craftx - 2.5, crafty + 2.5)
formspec = formspec.."label[0,"..(formspecy + 1.5)..";" .. F(S("Refill:")) .. "]" formspec[n+1] = string.format("label[%f,%f;%s]", craftx - 2.3, crafty + 2.4,F(S("Refill:")))
formspec = formspec.."list[detached:"..F(player_name).."refill;main;0,"..(formspecy +2)..";1,1;]" formspec[n+2] = string.format("list[detached:%srefill;main;%f,%f;1,1;]",
F(player_name), craftx - 2.5 + ui.list_img_offset, crafty + 2.5 + ui.list_img_offset)
end end
return {formspec=formspec} return {formspec=table.concat(formspec)}
end, end,
}) })
@ -206,18 +213,18 @@ local function stack_image_button(x, y, w, h, buttonname_prefix, item)
local selectitem = name local selectitem = name
if name:sub(1, 6) == "group:" then if name:sub(1, 6) == "group:" then
local group_name = name:sub(7) local group_name = name:sub(7)
local group_item = unified_inventory.get_group_item(group_name) local group_item = ui.get_group_item(group_name)
show_is_group = not group_item.sole show_is_group = not group_item.sole
displayitem = group_item.item or "unknown" displayitem = group_item.item or "unknown"
selectitem = group_item.sole and displayitem or name selectitem = group_item.sole and displayitem or name
end end
local label = show_is_group and "G" or "" local label = show_is_group and "G" or ""
local buttonname = F(buttonname_prefix..unified_inventory.mangle_for_formspec(selectitem)) local buttonname = F(buttonname_prefix..ui.mangle_for_formspec(selectitem))
local button = string.format("item_image_button[%f,%f;%f,%f;%s;%s;%s]", local button = string.format("item_image_button[%f,%f;%f,%f;%s;%s;%s]",
x, y, w, h, x, y, w, h,
F(displayitem), buttonname, label) F(displayitem), buttonname, label)
if show_is_group then if show_is_group then
local groupstring, andcount = unified_inventory.extract_groupnames(name) local groupstring, andcount = ui.extract_groupnames(name)
local grouptip local grouptip
if andcount == 1 then if andcount == 1 then
grouptip = S("Any item belonging to the @1 group", groupstring) grouptip = S("Any item belonging to the @1 group", groupstring)
@ -257,26 +264,33 @@ local other_dir = {
usage = "recipe", usage = "recipe",
} }
unified_inventory.register_page("craftguide", { ui.register_page("craftguide", {
get_formspec = function(player, perplayer_formspec) get_formspec = function(player, perplayer_formspec)
local formspecy = perplayer_formspec.formspec_y local craftguidex = perplayer_formspec.craft_guide_x
local formheadery = perplayer_formspec.form_header_y local craftguidey = perplayer_formspec.craft_guide_y
local craftresultx = perplayer_formspec.craft_result_x local craftguidearrowx = perplayer_formspec.craft_guide_arrow_x
local craftresulty = perplayer_formspec.craft_result_y local craftguideresultx = perplayer_formspec.craft_guide_result_x
local formheaderx = perplayer_formspec.form_header_x
local formheadery = perplayer_formspec.form_header_y
local give_x = perplayer_formspec.give_btn_x
local player_name = player:get_player_name() local player_name = player:get_player_name()
local player_privs = minetest.get_player_privs(player_name) local player_privs = minetest.get_player_privs(player_name)
local fs = {
string.gsub(unified_inventory.standard_inv_bg, "YYY", (formspecy + 3.4)), local formspec = {
"label[0,"..formheadery..";" .. F(S("Crafting Guide")) .. "]", perplayer_formspec.standard_inv_bg,
"label["..formheaderx..","..formheadery..";" .. F(S("Crafting Guide")) .. "]",
"listcolors[#00000000;#00000000]" "listcolors[#00000000;#00000000]"
} }
local item_name = unified_inventory.current_item[player_name]
local item_name = ui.current_item[player_name]
if not item_name then if not item_name then
return { formspec = table.concat(fs) } return { formspec = table.concat(formspec) }
end end
local n = 4
local item_name_shown local item_name_shown
if minetest.registered_items[item_name] if minetest.registered_items[item_name]
and minetest.registered_items[item_name].description then and minetest.registered_items[item_name].description then
@ -286,51 +300,60 @@ unified_inventory.register_page("craftguide", {
item_name_shown = item_name item_name_shown = item_name
end end
local dir = unified_inventory.current_craft_direction[player_name] local dir = ui.current_craft_direction[player_name]
local rdir = dir == "recipe" and "usage" or "recipe" local rdir = dir == "recipe" and "usage" or "recipe"
local crafts = unified_inventory.crafts_for[dir][item_name] local crafts = ui.crafts_for[dir][item_name]
local alternate = unified_inventory.alternate[player_name] local alternate = ui.alternate[player_name]
local alternates, craft local alternates, craft
if crafts and #crafts > 0 then if crafts and #crafts > 0 then
alternates = #crafts alternates = #crafts
craft = crafts[alternate] craft = crafts[alternate]
end end
local has_give = player_privs.give or unified_inventory.is_creative(player_name) local has_give = player_privs.give or ui.is_creative(player_name)
fs[#fs + 1] = "background[0.5,"..(formspecy + 0.2)..";8,3;ui_craftguide_form.png]" formspec[n] = string.format("image[%f,%f;%f,%f;ui_crafting_arrow.png]",
fs[#fs + 1] = string.format("textarea[%f,%f;10,1;;%s: %s;]", craftguidearrowx, craftguidey, ui.imgscale, ui.imgscale)
craftresultx, craftresulty, F(role_text[dir]), item_name_shown)
fs[#fs + 1] = stack_image_button(0, formspecy, 1.1, 1.1, formspec[n+1] = string.format("textarea[%f,%f;10,1;;%s: %s;]",
"item_button_" .. rdir .. "_", ItemStack(item_name)) perplayer_formspec.craft_guide_resultstr_x, perplayer_formspec.craft_guide_resultstr_y,
F(role_text[dir]), item_name_shown)
n = n + 2
local giveme_form = table.concat({
"label[".. (give_x+0.1)..",".. (craftguidey + 2.7) .. ";" .. F(S("Give me:")) .. "]",
"button["..(give_x)..",".. (craftguidey + 2.9) .. ";0.75,0.5;craftguide_giveme_1;1]",
"button["..(give_x+0.8)..",".. (craftguidey + 2.9) .. ";0.75,0.5;craftguide_giveme_10;10]",
"button["..(give_x+1.6)..",".. (craftguidey + 2.9) .. ";0.75,0.5;craftguide_giveme_99;99]"
})
if not craft then if not craft then
-- No craft recipes available for this item. -- No craft recipes available for this item.
fs[#fs + 1] = "label[5.5,"..(formspecy + 2.35)..";" formspec[n] = string.format("label[%f,%f;%s]", craftguidex+2.5, craftguidey+1.5, F(no_recipe_text[dir]))
.. F(no_recipe_text[dir]) .. "]" local no_pos = dir == "recipe" and (craftguidex+2.5) or craftguideresultx
local no_pos = dir == "recipe" and 4.5 or 6.5 local item_pos = dir == "recipe" and craftguideresultx or (craftguidex+2.5)
local item_pos = dir == "recipe" and 6.5 or 4.5 formspec[n+1] = "image["..no_pos..","..craftguidey..";1.2,1.2;ui_no.png]"
fs[#fs + 1] = "image["..no_pos..","..formspecy..";1.1,1.1;ui_no.png]" formspec[n+2] = stack_image_button(item_pos, craftguidey, 1.2, 1.2,
fs[#fs + 1] = stack_image_button(item_pos, formspecy, 1.1, 1.1,
"item_button_" .. other_dir[dir] .. "_", ItemStack(item_name)) "item_button_" .. other_dir[dir] .. "_", ItemStack(item_name))
if has_give then if has_give then
fs[#fs + 1] = "label[0," .. (formspecy + 2.10) .. ";" .. F(S("Give me:")) .. "]" formspec[n+3] = giveme_form
.. "button[0, " .. (formspecy + 2.7) .. ";0.6,0.5;craftguide_giveme_1;1]"
.. "button[0.6," .. (formspecy + 2.7) .. ";0.7,0.5;craftguide_giveme_10;10]"
.. "button[1.3," .. (formspecy + 2.7) .. ";0.8,0.5;craftguide_giveme_99;99]"
end end
return { formspec = table.concat(fs) } return { formspec = table.concat(formspec) }
else
formspec[n] = stack_image_button(craftguideresultx, craftguidey, 1.2, 1.2,
"item_button_" .. rdir .. "_", ItemStack(craft.output))
n = n + 1
end end
local craft_type = unified_inventory.registered_craft_types[craft.type] or local craft_type = ui.registered_craft_types[craft.type] or
unified_inventory.craft_type_defaults(craft.type, {}) ui.craft_type_defaults(craft.type, {})
if craft_type.icon then if craft_type.icon then
fs[#fs + 1] = string.format("image[%f,%f;%f,%f;%s]", formspec[n] = string.format("image[%f,%f;%f,%f;%s]",
5.7, (formspecy + 0.05), 0.5, 0.5, craft_type.icon) craftguidearrowx+0.35, craftguidey, 0.5, 0.5, craft_type.icon)
n = n + 1
end end
fs[#fs + 1] = "label[5.5,"..(formspecy + 1)..";" .. F(craft_type.description).."]" formspec[n] = string.format("label[%f,%f;%s]", craftguidearrowx + 0.15, craftguidey + 1.4, F(craft_type.description))
fs[#fs + 1] = stack_image_button(6.5, formspecy, 1.1, 1.1, n = n + 1
"item_button_usage_", ItemStack(craft.output))
local display_size = craft_type.dynamic_display_size local display_size = craft_type.dynamic_display_size
and craft_type.dynamic_display_size(craft) and craft_type.dynamic_display_size(craft)
@ -341,11 +364,12 @@ unified_inventory.register_page("craftguide", {
-- This keeps recipes aligned to the right, -- This keeps recipes aligned to the right,
-- so that they're close to the arrow. -- so that they're close to the arrow.
local xoffset = 5.5 local xoffset = craftguidex+3.75
local bspc = 1.25
-- Offset factor for crafting grids with side length > 4 -- Offset factor for crafting grids with side length > 4
local of = (3/math.max(3, math.max(display_size.width, display_size.height))) local of = (3/math.max(3, math.max(display_size.width, display_size.height)))
local od = 0 local od = 0
-- Minimum grid size at which size optimazation measures kick in -- Minimum grid size at which size optimization measures kick in
local mini_craft_size = 6 local mini_craft_size = 6
if display_size.width >= mini_craft_size then if display_size.width >= mini_craft_size then
od = math.max(1, display_size.width - 2) od = math.max(1, display_size.width - 2)
@ -354,12 +378,12 @@ unified_inventory.register_page("craftguide", {
-- Size modifier factor -- Size modifier factor
local sf = math.min(1, of * (1.05 + 0.05*od)) local sf = math.min(1, of * (1.05 + 0.05*od))
-- Button size -- Button size
local bsize_h = 1.1 * sf local bsize = 1.2 * sf
local bsize_w = bsize_h
if display_size.width >= mini_craft_size then if display_size.width >= mini_craft_size then -- it's not a normal 3x3 grid
bsize_w = 1.175 * sf bsize = 0.8 * sf
end end
if (bsize_h > 0.35 and display_size.width) then if (bsize > 0.35 and display_size.width) then
for y = 1, display_size.height do for y = 1, display_size.height do
for x = 1, display_size.width do for x = 1, display_size.width do
local item local item
@ -369,48 +393,53 @@ unified_inventory.register_page("craftguide", {
-- Flipped x, used to build formspec buttons from right to left -- Flipped x, used to build formspec buttons from right to left
local fx = display_size.width - (x-1) local fx = display_size.width - (x-1)
-- x offset, y offset -- x offset, y offset
local xof = (fx-1) * of + of local xof = ((fx-1) * of + of) * bspc
local yof = (y-1) * of + 1 local yof = ((y-1) * of + 1) * bspc
if item then if item then
fs[#fs + 1] = stack_image_button( formspec[n] = stack_image_button(
xoffset - xof, formspecy - 1 + yof, bsize_w, bsize_h, xoffset - xof, craftguidey - 1.25 + yof, bsize, bsize,
"item_button_recipe_", "item_button_recipe_",
ItemStack(item)) ItemStack(item))
else else
-- Fake buttons just to make grid -- Fake buttons just to make grid
fs[#fs + 1] = string.format("image_button[%f,%f;%f,%f;ui_blank_image.png;;]", formspec[n] = string.format("image_button[%f,%f;%f,%f;ui_blank_image.png;;]",
xoffset - xof, formspecy - 1 + yof, bsize_w, bsize_h) xoffset - xof, craftguidey - 1.25 + yof, bsize, bsize)
end end
n = n + 1
end end
end end
else else
-- Error -- Error
fs[#fs + 1] = string.format("label[2,%f;%s]", formspec[n] = string.format("label[2,%f;%s]",
formspecy, F(S("This recipe is too@nlarge to be displayed."))) craftguidey, F(S("This recipe is too@nlarge to be displayed.")))
n = n + 1
end end
if craft_type.uses_crafting_grid and display_size.width <= 3 then if craft_type.uses_crafting_grid and display_size.width <= 3 then
fs[#fs + 1] = "label[0," .. (formspecy + 0.9) .. ";" .. F(S("To craft grid:")) .. "]" formspec[n] = "label["..(give_x+0.1)..",".. (craftguidey + 1.7) .. ";" .. F(S("To craft grid:")) .. "]"
.. "button[0, " .. (formspecy + 1.5) .. ";0.6,0.5;craftguide_craft_1;1]" formspec[n+1] = "button[".. (give_x)..",".. (craftguidey + 1.9) .. ";0.75,0.5;craftguide_craft_1;1]"
.. "button[0.6," .. (formspecy + 1.5) .. ";0.7,0.5;craftguide_craft_10;10]" formspec[n+2] = "button[".. (give_x+0.8)..",".. (craftguidey + 1.9) .. ";0.75,0.5;craftguide_craft_10;10]"
.. "button[1.3," .. (formspecy + 1.5) .. ";0.8,0.5;craftguide_craft_max;" .. F(S("All")) .. "]" formspec[n+3] = "button[".. (give_x+1.6)..",".. (craftguidey + 1.9) .. ";0.75,0.5;craftguide_craft_max;" .. F(S("All")) .. "]"
n = n + 4
end end
if has_give then if has_give then
fs[#fs + 1] = "label[0," .. (formspecy + 2.1) .. ";" .. F(S("Give me:")) .. "]" formspec[n] = giveme_form
.. "button[0, " .. (formspecy + 2.7) .. ";0.6,0.5;craftguide_giveme_1;1]" n = n + 1
.. "button[0.6," .. (formspecy + 2.7) .. ";0.7,0.5;craftguide_giveme_10;10]"
.. "button[1.3," .. (formspecy + 2.7) .. ";0.8,0.5;craftguide_giveme_99;99]"
end end
if alternates and alternates > 1 then if alternates and alternates > 1 then
fs[#fs + 1] = "label[5.5," .. (formspecy + 1.6) .. ";" formspec[n] = string.format("label[%f,%f;%s]",
.. F(S(recipe_text[dir], alternate, alternates)) .. "]" craftguidex+4, craftguidey + 2.3, F(S(recipe_text[dir], alternate, alternates)))
.. "image_button[5.5," .. (formspecy + 2) .. ";1,1;ui_left_icon.png;alternate_prev;]" formspec[n+1] = string.format("image_button[%f,%f;1.1,1.1;ui_left_icon.png;alternate_prev;]",
.. "image_button[6.5," .. (formspecy + 2) .. ";1,1;ui_right_icon.png;alternate;]" craftguidearrowx+0.2, craftguidey + 2.6)
.. "tooltip[alternate_prev;" .. F(prev_alt_text[dir]) .. "]" formspec[n+2] = string.format("image_button[%f,%f;1.1,1.1;ui_right_icon.png;alternate;]",
.. "tooltip[alternate;" .. F(next_alt_text[dir]) .. "]" craftguidearrowx+1.35, craftguidey + 2.6)
formspec[n+3] = "tooltip[alternate_prev;" .. F(prev_alt_text[dir]) .. "]"
formspec[n+4] = "tooltip[alternate;" .. F(next_alt_text[dir]) .. "]"
end end
return { formspec = table.concat(fs) }
return { formspec = table.concat(formspec) }
end, end,
}) })
@ -418,7 +447,7 @@ local function craftguide_giveme(player, formname, fields)
local player_name = player:get_player_name() local player_name = player:get_player_name()
local player_privs = minetest.get_player_privs(player_name) local player_privs = minetest.get_player_privs(player_name)
if not player_privs.give and if not player_privs.give and
not unified_inventory.is_creative(player_name) then not ui.is_creative(player_name) then
minetest.log("action", "[unified_inventory] Denied give action to player " .. minetest.log("action", "[unified_inventory] Denied give action to player " ..
player_name) player_name)
return return
@ -433,7 +462,7 @@ local function craftguide_giveme(player, formname, fields)
amount = tonumber(amount) or 0 amount = tonumber(amount) or 0
if amount == 0 then return end if amount == 0 then return end
local output = unified_inventory.current_item[player_name] local output = ui.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()
@ -454,21 +483,21 @@ local function craftguide_craft(player, formname, fields)
local player_name = player:get_player_name() local player_name = player:get_player_name()
local output = unified_inventory.current_item[player_name] or "" local output = ui.current_item[player_name] or ""
if output == "" then return end if output == "" then return end
local crafts = unified_inventory.crafts_for[ local crafts = ui.crafts_for[
unified_inventory.current_craft_direction[player_name]][output] or {} ui.current_craft_direction[player_name]][output] or {}
if #crafts == 0 then return end if #crafts == 0 then return end
local alternate = unified_inventory.alternate[player_name] local alternate = ui.alternate[player_name]
local craft = crafts[alternate] local craft = crafts[alternate]
if craft.width > 3 then return end if craft.width > 3 then return end
unified_inventory.craftguide_match_craft(player, "main", "craft", craft, amount) ui.craftguide_match_craft(player, "main", "craft", craft, amount)
unified_inventory.set_inventory_formspec(player, "craft") ui.set_inventory_formspec(player, "craft")
end end
minetest.register_on_player_receive_fields(function(player, formname, fields) minetest.register_on_player_receive_fields(function(player, formname, fields)

View file

@ -9,3 +9,6 @@ unified_inventory_bags (Enable bags) bool true
#If enabled, the trash slot can be used by those without both creative #If enabled, the trash slot can be used by those without both creative
#and the give privilege. #and the give privilege.
unified_inventory_trash (Enable trash) bool true unified_inventory_trash (Enable trash) bool true
unified_inventory_automatic_categorization (Items automatically added to categories) bool true

View file

@ -1,5 +1,6 @@
local S = minetest.get_translator("unified_inventory") local S = minetest.get_translator("unified_inventory")
local F = minetest.formspec_escape local F = minetest.formspec_escape
local ui = unified_inventory
local hud_colors = { local hud_colors = {
{"#FFFFFF", 0xFFFFFF, S("White")}, {"#FFFFFF", 0xFFFFFF, S("White")},
@ -14,28 +15,38 @@ local hud_colors_max = #hud_colors
-- Stores temporary player data (persists until player leaves) -- Stores temporary player data (persists until player leaves)
local waypoints_temp = {} local waypoints_temp = {}
unified_inventory.register_page("waypoints", { ui.register_page("waypoints", {
get_formspec = function(player) get_formspec = function(player)
local player_name = player:get_player_name() local player_name = player:get_player_name()
local wp_info_x = ui.style_full.form_header_x + 1.25
local wp_info_y = ui.style_full.form_header_y + 0.5
local wp_bottom_row = ui.style_full.std_inv_y - 1
local wp_buttons_rj = ui.style_full.std_inv_x + 10.1 - ui.style_full.btn_spc
local wp_edit_w = ui.style_full.btn_spc * 4 - 0.1
-- build a "fake" temp entry if the server took too long -- build a "fake" temp entry if the server took too long
-- during sign-on and returned an empty entry -- during sign-on and returned an empty entry
if not waypoints_temp[player_name] then waypoints_temp[player_name] = {hud = 1} end if not waypoints_temp[player_name] then waypoints_temp[player_name] = {hud = 1} end
local waypoints = datastorage.get(player_name, "waypoints") local waypoints = datastorage.get(player_name, "waypoints")
local formspec = string.gsub(unified_inventory.standard_inv_bg, "YYY", "4.4") .. local formspec = { ui.style_full.standard_inv_bg,
"image[0,0;1,1;ui_waypoints_icon.png]" .. string.format("label[%f,%f;%s]",
"label[1,0;" .. F(S("Waypoints")) .. "]" ui.style_full.form_header_x, ui.style_full.form_header_y,
F(S("Waypoints"))),
"image["..wp_info_x..","..wp_info_y..";1,1;ui_waypoints_icon.png]"
}
local n=4
-- Tabs buttons: -- Tabs buttons:
for i = 1, 5, 1 do for i = 1, 5 do
formspec = formspec .. local sw="select_waypoint"..i
"image_button[0.0," .. 0.2 + i * 0.7 .. ";.8,.8;" .. formspec[n] = string.format("image_button[%f,%f;%f,%f;%sui_%i_icon.png;%s;]",
(i == waypoints.selected and "ui_blue_icon_background.png^" or "") .. ui.style_full.main_button_x, wp_bottom_row - (5-i) * ui.style_full.btn_spc,
"ui_" .. i .. "_icon.png;" .. ui.style_full.btn_size, ui.style_full.btn_size,
"select_waypoint" .. i .. ";]" .. (i == waypoints.selected) and "ui_blue_icon_background.png^" or "",
"tooltip[select_waypoint" .. i .. ";" i, sw)
.. S("Select Waypoint #@1", i).."]" formspec[n+1] = "tooltip["..sw..";"..S("Select Waypoint #@1", i).."]"
n = n + 2
end end
local i = waypoints.selected or 1 local i = waypoints.selected or 1
@ -44,72 +55,58 @@ unified_inventory.register_page("waypoints", {
local default_name = S("Waypoint @1", i) local default_name = S("Waypoint @1", i)
-- Main buttons: -- Main buttons:
formspec = formspec .. local btnlist = {
"image_button[4.5,3.7;.8,.8;".. { "ui_waypoint_set_icon.png", "set_waypoint", S("Set waypoint to current location") },
"ui_waypoint_set_icon.png;".. { waypoint.active and "ui_on_icon.png" or "ui_off_icon.png", "toggle_waypoint", S("Make waypoint @1", waypoint.active and "invisible" or "visible") },
"set_waypoint"..i..";]".. { waypoint.display_pos and "ui_green_icon_background.png^ui_xyz_icon.png" or "ui_red_icon_background.png^ui_xyz_icon.png^(ui_no.png^[transformR90)", "toggle_display_pos", S("@1 display of waypoint coordinates", waypoint.display_pos and "Disable" or "Enable") },
"tooltip[set_waypoint" .. i .. ";" { "ui_circular_arrows_icon.png", "toggle_color", S("Change color of waypoint display") },
.. F(S("Set waypoint to current location")).."]" { "ui_pencil_icon.png", "rename_waypoint", S("Edit waypoint name") }
}
formspec = formspec .. local x = 4
"image_button[5.2,3.7;.8,.8;".. for _, b in pairs(btnlist) do
(waypoint.active and "ui_on_icon.png" or "ui_off_icon.png")..";".. formspec[n] = string.format("image_button[%f,%f;%f,%f;%s;%s%i;]",
"toggle_waypoint"..i..";]".. wp_buttons_rj - ui.style_full.btn_spc * x, wp_bottom_row,
"tooltip[toggle_waypoint" .. i .. ";" ui.style_full.btn_size, ui.style_full.btn_size,
.. F(S("Make waypoint @1", b[1], b[2], i)
waypoint.active and S("invisible") or S("visible"))).."]" formspec[n+1] = "tooltip["..b[2]..i..";"..F(b[3]).."]"
x = x - 1
formspec = formspec .. n = n + 2
"image_button[5.9,3.7;.8,.8;".. end
(waypoint.display_pos and "ui_green_icon_background.png" or "ui_red_icon_background.png").."^ui_xyz_icon.png;"..
"toggle_display_pos" .. i .. ";]"..
"tooltip[toggle_display_pos" .. i .. ";"
.. F(S("@1 display of waypoint coordinates",
waypoint.display_pos and S("Disable") or S("Enable"))) .."]"
formspec = formspec ..
"image_button[6.6,3.7;.8,.8;"..
"ui_circular_arrows_icon.png;"..
"toggle_color"..i..";]"..
"tooltip[toggle_color" .. i .. ";"
.. F(S("Change color of waypoint display")).."]"
formspec = formspec ..
"image_button[7.3,3.7;.8,.8;"..
"ui_pencil_icon.png;"..
"rename_waypoint"..i..";]"..
"tooltip[rename_waypoint" .. i .. ";"
.. F(S("Edit waypoint name")).."]"
-- Waypoint's info: -- Waypoint's info:
formspec[n] = "label["..wp_info_x..","..(wp_info_y+1.1)..";"
if waypoint.active then if waypoint.active then
formspec = formspec .. "label[1,0.8;"..F(S("Waypoint active")).."]" formspec[n+1] = F(S("Waypoint active")).."]"
else else
formspec = formspec .. "label[1,0.8;"..F(S("Waypoint inactive")).."]" formspec[n+1] = F(S("Waypoint inactive")).."]"
end end
n = n + 2
if temp.edit then if temp.edit then
formspec = formspec .. formspec[n] = string.format("field[%f,%f;%f,%f;rename_box%i;;%s]",
"field[1.3,3.2;6,.8;rename_box" .. i .. ";;" wp_buttons_rj - wp_edit_w - 0.1, wp_bottom_row - ui.style_full.btn_spc,
..(waypoint.name or default_name).."]" .. wp_edit_w, ui.style_full.btn_size, i, (waypoint.name or default_name))
"image_button[7.3,2.9;.8,.8;".. formspec[n+1] = string.format("image_button[%f,%f;%f,%f;ui_ok_icon.png;confirm_rename%i;]",
"ui_ok_icon.png;".. wp_buttons_rj, wp_bottom_row - ui.style_full.btn_spc,
"confirm_rename"..i.. ";]".. ui.style_full.btn_size, ui.style_full.btn_size, i)
"tooltip[confirm_rename" .. i .. ";" formspec[n+2] = "tooltip[confirm_rename"..i..";"..F(S("Finish editing")).."]"
.. F(S("Finish editing")).."]" n = n + 3
end end
formspec = formspec .. "label[1,1.3;"..F(S("World position"))..": " .. formspec[n] = string.format("label[%f,%f;%s: %s]",
minetest.pos_to_string(waypoint.world_pos or vector.new()) .. "]" .. wp_info_x, wp_info_y+1.6, F(S("World position")),
"label[1,1.8;"..F(S("Name"))..": ".. (waypoint.name or default_name) .. "]" .. minetest.pos_to_string(waypoint.world_pos or vector.new()))
"label[1,2.3;"..F(S("HUD text color"))..": " .. formspec[n+1] = string.format("label[%f,%f;%s: %s]",
hud_colors[waypoint.color or 1][3] .. "]" wp_info_x, wp_info_y+2.10, F(S("Name")), (waypoint.name or default_name))
formspec[n+2] = string.format("label[%f,%f;%s: %s]",
wp_info_x, wp_info_y+2.60, F(S("HUD text color")), hud_colors[waypoint.color or 1][3])
return {formspec=formspec} return {formspec=table.concat(formspec)}
end, end,
}) })
unified_inventory.register_button("waypoints", { ui.register_button("waypoints", {
type = "image", type = "image",
image = "ui_waypoints_icon.png", image = "ui_waypoints_icon.png",
tooltip = S("Waypoints"), tooltip = S("Waypoints"),
@ -224,7 +221,7 @@ minetest.register_on_player_receive_fields(function(player, formname, fields)
update_hud(player, waypoints, temp, i) update_hud(player, waypoints, temp, i)
end end
if update_formspec then if update_formspec then
unified_inventory.set_inventory_formspec(player, "waypoints") ui.set_inventory_formspec(player, "waypoints")
end end
if hit then return end if hit then return end
end end