38 Commits

Author SHA1 Message Date
a7556c5044 update minimum MT version number 2021-03-09 15:09:46 -05:00
3d58befe03 Document the API version 2021-03-09 15:04:11 -05:00
d0deba10c8 pngcrush+optipng the new slot textures
and remove the slot image .xcf project file
2021-03-09 15:04:11 -05:00
97b882ad23 add a version number variable to the main table 2021-03-09 15:04:11 -05:00
44e32df00a translate some strings inside their table 2021-03-09 15:04:11 -05:00
40d862298b replace excessive spaces with tabs 2021-03-09 15:04:11 -05:00
0ebc9402ed minor tweaks to the slot images
to make them better-resemble their pre-9-sliced versions
(going to that mode made them slightly bigger and the corners
slightly less round since they aren't blurry anymore)
2021-03-09 15:04:11 -05:00
2c16805ef9 Get rid of the image button left of the crafting guide
It had the same function as clicking the craft result on the
right (just inverted), making it redundant. Click either one more
than once and UI would alternately show usages or recipes.
2021-03-09 15:04:11 -05:00
dc61d2980a Move craft guide a little to the right to make some room. 2021-03-09 15:04:11 -05:00
21f122336f make craft arrow 128px
(same reason as the trash icon)
2021-03-09 15:04:11 -05:00
8ee0eb9fce swap the craft type icon with its word
(makes it look like it used to)
2021-03-09 15:04:11 -05:00
1210dbfe22 make trash slot icon 128px
MT nearest-neighbor-scales images to about 75px if they're 1x1
slot in size (at least on my screen).  Use the next power of 2
above that, so that MT can scale down instead of up.
2021-03-09 15:04:11 -05:00
b8a568d7eb remove unused var, excess whitespace 2021-03-09 15:04:11 -05:00
9ddea6eced fix missing "XYZ" and "no" icon on waypoints show coordinates button 2021-03-09 15:04:11 -05:00
76c9bb9517 Use 9-slicing to build inventory-type backgrounds
This way the slots are all nice and crisp regardless of GUI scale or
image size, and we only need the single slot and its bright version.

This also makes the standard crafting grid into a style table entry that
can be referenced to insert the crafting grid at its proper
style-specific position in any formspec.

And it also makes the craft grid arrow, its X position, and the crafting
grid's result slot X position into style table entries.

Includes a few public helper functions to do most of the work:

`ui.single_slot(xpos, ypos, bright)`

    Does just what it sounds like: it returns a single slot image.
    `xpos` and `ypos` are normal coordinates in slots, as you'd use in
    `image[]` element.  `bright` is a flag that switches to the brighter
    version of the slot image.

`ui.make_trash_slot(xpos, ypos)`

    Creates a single slot, with a one-item `list[]` and a trash can icon
    overlay.

`ui.make_inv_img_grid(xpos, ypos, width, height, bright)`

    Generates a `width` by `height` grid of slot images, using the
    single_slot function above, starting at (`xpos`,`ypos`) for the
    top-left.  Position is as in any `image[]` element, and dimensions
    are in integer numbers of slots (so 8,4 would be a standard inventory).
    `bright` is as above.

All three return a string that can be directly inserted into a formspec.
2021-03-09 15:04:11 -05:00
60d7a6d213 Draw the trash slot by overlaying the bare trash can icon
over the single slot image instead of baking it in.
2021-03-09 15:04:11 -05:00
8e94d86420 don't display the refill slot image if no creative priv/mode
(leftover from when it was part of the craft grid image)

Also fixed a typo in the corresponding list[] element that
made it not work.
2021-03-09 15:04:11 -05:00
6d892dda5b use local ui=unified_inventory shorthand in init.lua as elsewhere 2021-03-09 15:04:11 -05:00
37546289bc using a table.copy() to pass the style tables around requires
setting-up items_per_page, standard_inv, and standard_inv_bg
for both tables at init time.
2021-03-09 15:04:11 -05:00
3e7f005366 always modify and return a table.copy() of the style table 2021-03-09 15:04:11 -05:00
382219c466 move S() calls into waypoints' button table
instead of inside the loop
2021-03-09 15:04:11 -05:00
5ea0208ffe Multiple related changes to string handling
1) Convert most formspec elements to use string.format(), when the
result would be more readable, or less messy, or at least makes the line
shorter, assuming it looked like it really needed it to begin with.

2) Convert all long `foo..","..bar..";"..baz..bleh..` types of excessive
string concatenation into tables that then get concated only once, when
their containing functions return the final formspec string.

3) In some places in the code, such tables were already being used, and
were named "formspec", while others were named "fs".  I settled on just
one name, "formspec", as it's more readable, if longer.

4) There was a mix of styles of adding items to those tables:

* Some places used line after line of `t[#t + 1] = foo/bar/baz`.
* Others places used the form `t[1] = foo, t[2] = bar, ...`.
* Still others used the form `t[n] = foo, t[n+1] = bar...`,
  with `n` being increased or reset every so often.

Most of them should now be of the third form, with a few of the second.
2021-03-09 15:04:11 -05:00
694553e68b use local "ui" to reference "unified_inventory", where practical
(makes code shorter, easier to read and write)
2021-03-09 15:04:11 -05:00
2d200eb9ae Ditto for bags. 2021-03-09 15:04:11 -05:00
b3077898a7 make waypoints explicitly reference full-style vars
(since it does not support lite mode)
2021-03-09 15:04:11 -05:00
5a8a75f43b put style-specific settings in their own tables
and switch between them directly, instead of copy-and-modify.
2021-03-09 15:04:11 -05:00
0c05f06fa8 "Please continue to use string.format here to avoid messy code"
Derp :-)
2021-03-09 15:04:11 -05:00
c3679eaf7b fix indent 2021-03-09 15:04:11 -05:00
23a089f174 remove a used-only-once variable 2021-03-09 15:04:11 -05:00
82bc2d3f95 use string.format() to create the standard_inv variables
do it just once, after the lite mode settings are applied
(if applicable)
2021-03-09 15:04:11 -05:00
603b5d1d4e get rid of uninv global
make all uses of it back into `unified_inventory.`
2021-03-09 15:04:11 -05:00
eb4cf5bf47 increase spacing around the text above the items page
("Filter:" and its search key, and the page or "No matches)
Adjust main and page flipping buttons' positions to compensate
2021-03-09 15:04:11 -05:00
97960c552b increase size and tweak position of "give/to grid" buttons
and make them vary in pos with lite vs full mode
2021-03-09 15:04:11 -05:00
81d6a1e796 shift the craft grid and guide down a bit
to make more room for the result string
(and shift the result string down a hair to follow)
2021-03-09 15:04:11 -05:00
de575a6513 9-slice the background image 2021-03-09 15:04:11 -05:00
7a0a44037a remove a couple of unused variables 2021-03-09 15:04:11 -05:00
cc93288a6b bump minimum version to 5.4.0 2021-03-09 15:04:11 -05:00
167dddaa84 Convert over to formspec version 4
I recreated the original layout as best as practical, but by necessity
there are a few minor positioning changes, since the underlying
hard-wired inventory slots are square now and image positioning is now
scaled by exactly 1.250 in both dimensions (as opposed to roughly 1.25
by 1.16).

Backstage, I also needed to fix the aspect ratios of the various
inventory slot elements.  That meant redesigning the single-slot image
from scratch.  It was already blurry/grainy and a little ugly, and
trying to alter it would have only made it worse.

The slot image is now exactly 56x56 pixels square, set on a 64x64
canvas, so there's a 4 pixel empty space around the edges. The full
256px .xcf workfile is included in the UI folder.

I've re-tiled all slot/inv images from the new single slot.

I also re-rendered the trash can icon from it since it was blurry and
oddly-sized. I couldn't find the original upstream image, so since
they're free, I used one of my Linux system's icons which happens to
resemble it.

I also removed a couple more improper uses of `background[]` where
`image[]` is more appropriate.

There are tons of minor tweaks throughout the code to re-align
everything, and I had to rewrite a few sections to avoid code
duplication and to allow for a little more flexibility (mainly to make
"lite" mode look right).
2021-03-09 15:04:11 -05:00
26 changed files with 529 additions and 431 deletions

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

116
api.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
-- 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,25 @@ 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 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 +195,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 +206,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 +220,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 +229,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 +251,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 +266,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 +274,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^[opacity:95]"..
"list[detached:trash;main;"..xpos..","..ypos..";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

View File

@ -3,6 +3,14 @@ unified_inventory API
This file provides information about the API of unified_inventory. This file provides information about the API of unified_inventory.
API revisions within unified_inventory can be checked using:
(unified_inventory.version or 1)
**Revision history**
* Version `1`: Classic formspec layout (no real_coordinates)
* Version `2`: Force formspec version 4 (includes real_coordinates)
Misc functions Misc functions
-------------- --------------

101
init.lua
View File

@ -35,21 +35,101 @@ unified_inventory = {
-- 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,
list_img_offset = 0.13,
standard_background = "background9[0,0;1,1;ui_formbg_9_sliced.png;true;16]",
version = 2
}
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,
pagecols = 8, pagecols = 8,
pagerows = 10, pagerows = 10,
page_y = 0, page_x = 10.75,
formspec_y = 1, page_y = 1.45,
main_button_x = 0, craft_x = 2.8,
main_button_y = 9, craft_y = 1.15,
craft_result_x = 0.3, craftresult_x = 7.8,
craft_result_y = 0.5, craft_arrow_x = 6.55,
form_header_y = 0, craft_guide_x = 3.3,
standard_background = "background[-0.2,-0.2;1,1;ui_form_bg.png;true]", -- the 'true' scales to fill, overrides the 1,1 craft_guide_y = 1.15,
standard_inv = "list[current_player;main;0,YYY;8,4;]", -- the YYY's are placeholders which get craft_guide_arrow_x = 7.05,
standard_inv_bg = "image[-0.1,YYY;10.05,4.70;ui_main_inventory.png]", -- replaced later by string.gsub() 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,
pagecols = 4,
pagerows = 6,
page_x = 10.5,
page_y = 1.25,
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 = 7.9,
page_buttons_x = 10.5,
page_buttons_y = 6.3,
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+0.13, style.std_inv_y+0.13)
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 +145,6 @@ if sfinv then
end end
dofile(modpath.."/group.lua") dofile(modpath.."/group.lua")
dofile(modpath.."/api.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,50 @@ 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) 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[17.75,12.25]",
pagedef.formspec_prepend and "" or "no_prepend[]", pagedef.formspec_prepend and "" or "no_prepend[]",
unified_inventory.standard_background -- Background ui.standard_background -- Background
} }
local n = 4 local n = 4
if draw_lite_mode then if draw_lite_mode then
formspec[1] = "size[11,7.7]" formspec[1] = "formspec_version[4]size[14,9.75]"
formspec[3] = unified_inventory.standard_background formspec[3] = ui.standard_background
end 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 +66,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 +81,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 +102,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 +110,52 @@ function unified_inventory.get_formspec(player, page)
return table.concat(formspec, "") return table.concat(formspec, "")
end end
-- Controls to flip items pages
local start_x = 9.2
if not draw_lite_mode then
formspec[n] =
"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)
.. ",9;.8,.8;ui_doubleleft_icon.png;rewind3;]"
.. "tooltip[rewind3;" .. F(S("Back three pages")) .. "]"
.. "image_button[" .. (start_x + 0.6 * 2)
.. ",9;.8,.8;ui_left_icon.png;rewind1;]"
.. "tooltip[rewind1;" .. F(S("Back one page")) .. "]"
.. "image_button[" .. (start_x + 0.6 * 3)
.. ",9;.8,.8;ui_right_icon.png;forward1;]"
.. "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)
.. ",9;.8,.8;ui_skip_forward_icon.png;end_list;]"
.. "tooltip[end_list;" .. F(S("Last page")) .. "]"
else
formspec[n] =
"image_button[" .. (8.2 + 0.65 * 0)
.. ",5.8;.8,.8;ui_skip_backward_icon.png;start_list;]"
.. "tooltip[start_list;" .. F(S("First page")) .. "]"
.. "image_button[" .. (8.2 + 0.65 * 1)
.. ",5.8;.8,.8;ui_left_icon.png;rewind1;]"
.. "tooltip[rewind1;" .. F(S("Back one page")) .. "]"
.. "image_button[" .. (8.2 + 0.65 * 2)
.. ",5.8;.8,.8;ui_right_icon.png;forward1;]"
.. "tooltip[forward1;" .. F(S("Forward one page")) .. "]"
.. "image_button[" .. (8.2 + 0.65 * 3)
.. ",5.8;.8,.8;ui_skip_forward_icon.png;end_list;]"
.. "tooltip[end_list;" .. F(S("Last page")) .. "]"
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 +163,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 +187,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 +207,29 @@ 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_x, ui_peruser.form_header_y,
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:]",
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.65, F(S("Filter")))
formspec[n+1] = string.format("label[%f,%f;%s]",
ui_peruser.page_x, ui_peruser.page_y - 0.25, 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
--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 +258,26 @@ 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 for name, def in pairs(minetest.registered_items) do
if (not def.groups.not_in_creative_inventory if (not def.groups.not_in_creative_inventory
or def.groups.not_in_creative_inventory == 0) or def.groups.not_in_creative_inventory == 0)
and def.description and def.description
and def.description ~= "" and def.description ~= ""
and ffilter(name, def) then and ffilter(name, def) then
table.insert(unified_inventory.filtered_items_list[player_name], name) table.insert(ui.filtered_items_list[player_name], name)
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 +289,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,3 +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.
""" """
min_minetest_version = 5.4.0

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.2 - 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 craftguidey = perplayer_formspec.craft_guide_y
local craftguidearrowx = perplayer_formspec.craft_guide_arrow_x
local craftguideresultx = perplayer_formspec.craft_guide_result_x
local formheaderx = perplayer_formspec.form_header_x
local formheadery = perplayer_formspec.form_header_y local formheadery = perplayer_formspec.form_header_y
local craftresultx = perplayer_formspec.craft_result_x local give_x = perplayer_formspec.give_btn_x
local craftresulty = perplayer_formspec.craft_result_y
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)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 962 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 788 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1003 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 240 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 629 B

After

Width:  |  Height:  |  Size: 648 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.1 KiB

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