14 Commits

Author SHA1 Message Date
c6cc6ab83c Merge branch 'master' of yunohost:nalc/unified_inventory 2019-09-29 01:11:56 +02:00
04b1cb9e7d Fix error on invalid item_button_ fields
Also reduce the player inventory sending by one. If a formspec is sent, it'll also take the newest known search text
2019-08-02 16:39:43 +02:00
774674d0f5 README: Add features and link to mod contents
+LICENSE.txt
2019-06-16 11:14:08 +02:00
4403b696be Replace deprecated functions with newer ones (#131)
These commits makes more compatibility with MT/MTG 5.0.0+ versions.
However, these commits breaks compatibility with the 0.4-series.
2019-06-16 10:26:40 +02:00
a70ffb1509 Compress textures (-61 KB!) 2019-05-31 17:30:24 +02:00
86d2a11643 Allow all players to view items regardless of 'creative' priv
This allows any player to see usages of items found
even if item does not have explicit
recipies themselves.
(ex: default:papyrus, found/grown in wild, can be made into paper)
2019-05-28 21:30:55 +02:00
1fd87f5c51 Suppression des icônes set_home et home_go 2019-05-01 17:28:36 +02:00
e5dc9ed53a Merge branch 'master' into nalc-1.1 2019-05-01 17:15:35 +02:00
16babc54f3 Add no_prepend[] by default 2019-03-31 12:19:08 +02:00
4d5e883629 Add mod_api.txt documentation 2019-03-31 11:30:22 +02:00
b871ccfc41 Use table.concat to build formspecs, style cleanups 2019-03-31 11:29:10 +02:00
e9b4b52dc1 Biggest stacks first, smallest as late as possible
Split stacks ~evenly
Fast skip occupied slots
2019-03-30 22:53:36 +01:00
bcb96d6caf Improve craftguide_craft() speed: Move stacks 2019-03-30 22:53:36 +01:00
850ee9cbc0 Improve callback execution, add giveme guards 2019-02-17 15:14:38 +01:00
62 changed files with 407 additions and 304 deletions

19
LICENSE.txt Normal file
View File

@ -0,0 +1,19 @@
Unified Inventory for Minetest
Copyright (C) 2012-2014 Maciej Kasatkin (RealBadAngel)
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Contact information:
Examine a git patch to get the contributor's email address.

View File

@ -1,22 +1,48 @@
Unified inventory
=================
# Unified 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.
License
=======
## Features
* Node, item and tool browser
* Crafting guide
* Can copy the recipe to the crafting grid
* Recipe search function by ingredients
* Up to four bags with up to 24 slots each
* Home function to teleport
* Trash slot
* Lite mode: reduces the item browser width
* Mod API for modders: see [mod_api.txt](doc/mod_api.txt)
* Setting-determinated features: see [settingtypes.txt](settingtypes.txt)
## Requirements
* Minetest 5.0.0+ since commit 4403b69
* Minetest 0.4.16+ prior commit 4403b69
# Licenses
Copyright (C) 2012-2014 Maciej Kasatkin (RealBadAngel)
Unified inventory code is licensed under the GNU LGPLv2+.
Copyright (C) 2012-? Various minetest-mods contributors
Licenses for textures:
## Code
GNU LGPLv2+, see [license notice](LICENSE.txt)
## Textures
VanessaE: (CC-BY-4.0)
* `ui_group.png`
Tango Project: (Public Domain, CC-BY-4.0)
* [`ui_reset_icon.png`](https://commons.wikimedia.org/wiki/File:Edit-clear.svg)
* [`ui_doubleleft_icon.png`](http://commons.wikimedia.org/wiki/File:Media-seek-backward.svg)
* [`ui_doubleright_icon.png`](http://commons.wikimedia.org/wiki/File:Media-seek-forward.svg)
@ -25,6 +51,7 @@ Tango Project: (Public Domain, CC-BY-4.0)
* [`ui_skip_forward_icon.png`](http://commons.wikimedia.org/wiki/File:Media-skip-forward.svg)
From http://www.clker.com (Public Domain, CC-BY-4.0):
* [`bags_small.png`](http://www.clker.com/clipart-moneybag-empty.html)
* [`bags_medium.png`](http://www.clker.com/clipart-backpack-1.html)
* [`bags_large.png` / `ui_bags_icon.png`](http://www.clker.com/clipart-backpack-green-brown.html)
@ -37,25 +64,33 @@ From http://www.clker.com (Public Domain, CC-BY-4.0):
* [`ui_waypoint_set_icon.png`](http://www.clker.com/clipart-larger-flag.html)
Everaldo Coelho (YellowIcon) (LGPL v2.1+):
* [`ui_craftguide_icon.png` / `ui_craft_icon.png`](http://commons.wikimedia.org/wiki/File:Advancedsettings.png)
Gregory H. Revera: (CC-BY-SA 3.0)
* [`ui_moon_icon.png`](http://commons.wikimedia.org/wiki/File:FullMoon2010.jpg)
Thomas Bresson: (CC-BY 3.0)
* [`ui_sun_icon.png`](http://commons.wikimedia.org/wiki/File:2012-10-13_15-29-35-sun.jpg)
Fibonacci: (Public domain, CC-BY 4.0)
* [`ui_xyz_off_icon.png`](http://commons.wikimedia.org/wiki/File:No_sign.svg)
Gregory Maxwell: (Public domain, CC-BY 4.0)
* [`ui_ok_icon.png`](http://commons.wikimedia.org/wiki/File:Yes_check.svg)
Adrien Facélina: (LGPL v2.1+)
* [`inventory_plus_worldedit_gui.png`](http://commons.wikimedia.org/wiki/File:Erioll_world_2.svg)
Other files from Wikimedia Commons:
* [`ui_gohome_icon.png` / `ui_home_icon.png` / `ui_sethome_icon.png`](http://commons.wikimedia.org/wiki/File:Home_256x256.png) (GPL v2+)
RealBadAngel: (CC-BY-4.0)
* Everything else.

View File

@ -187,7 +187,7 @@ end
function unified_inventory.go_home(player)
local pos = unified_inventory.home_pos[player:get_player_name()]
if pos then
player:setpos(pos)
player:set_pos(pos)
end
end

View File

@ -1,7 +1,9 @@
-- Bags for Minetest
--[[
Bags for Minetest
-- Copyright (c) 2012 cornernote, Brett O'Donnell <cornernote@gmail.com>
-- License: GPLv3
Copyright (c) 2012 cornernote, Brett O'Donnell <cornernote@gmail.com>
License: GPLv3
--]]
local S = unified_inventory.gettext
local F = minetest.formspec_escape
@ -9,18 +11,19 @@ local F = minetest.formspec_escape
unified_inventory.register_page("bags", {
get_formspec = function(player)
local player_name = player:get_player_name()
local formspec = "background[0.06,0.99;7.92,7.52;ui_bags_main_form.png]"
formspec = formspec.."label[0,0;"..F(S("Bags")).."]"
formspec = formspec.."button[0,2;2,0.5;bag1;"..F(S("Bag @1", 1)).."]"
formspec = formspec.."button[2,2;2,0.5;bag2;"..F(S("Bag @1", 2)).."]"
formspec = formspec.."button[4,2;2,0.5;bag3;"..F(S("Bag @1", 3)).."]"
formspec = formspec.."button[6,2;2,0.5;bag4;"..F(S("Bag @1", 4)).."]"
formspec = formspec.."listcolors[#00000000;#00000000]"
formspec = formspec.."list[detached:"..F(player_name).."_bags;bag1;0.5,1;1,1;]"
formspec = formspec.."list[detached:"..F(player_name).."_bags;bag2;2.5,1;1,1;]"
formspec = formspec.."list[detached:"..F(player_name).."_bags;bag3;4.5,1;1,1;]"
formspec = formspec.."list[detached:"..F(player_name).."_bags;bag4;6.5,1;1,1;]"
return {formspec=formspec}
return { formspec = table.concat({
"background[0.06,0.99;7.92,7.52;ui_bags_main_form.png]",
"label[0,0;" .. F(S("Bags")) .. "]",
"button[0,2;2,0.5;bag1;" .. F(S("Bag @1", 1)) .. "]",
"button[2,2;2,0.5;bag2;" .. F(S("Bag @1", 2)) .. "]",
"button[4,2;2,0.5;bag3;" .. F(S("Bag @1", 3)) .. "]",
"button[6,2;2,0.5;bag4;" .. F(S("Bag @1", 4)) .. "]",
"listcolors[#00000000;#00000000]",
"list[detached:" .. F(player_name) .. "_bags;bag1;0.5,1;1,1;]",
"list[detached:" .. F(player_name) .. "_bags;bag2;2.5,1;1,1;]",
"list[detached:" .. F(player_name) .. "_bags;bag3;4.5,1;1,1;]",
"list[detached:" .. F(player_name) .. "_bags;bag4;6.5,1;1,1;]"
}) }
end,
})
@ -38,35 +41,37 @@ local function get_player_bag_stack(player, i)
}):get_stack("bag" .. i, 1)
end
for i = 1, 4 do
local bi = i
unified_inventory.register_page("bag"..bi, {
for bag_i = 1, 4 do
unified_inventory.register_page("bag" .. bag_i, {
get_formspec = function(player)
local stack = get_player_bag_stack(player, bi)
local stack = get_player_bag_stack(player, bag_i)
local image = stack:get_definition().inventory_image
local formspec = ("image[7,0;1,1;"..image.."]"
.."label[0,0;"..F(S("Bag @1", bi)).."]"
.."listcolors[#00000000;#00000000]"
.."list[current_player;bag"..bi.."contents;0,1;8,3;]"
.."listring[current_name;bag"..bi.."contents]"
.."listring[current_player;main]")
local fs = {
"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;8,3;]",
"listring[current_name;bag" .. bag_i .. "contents]",
"listring[current_player;main]"
}
local slots = stack:get_definition().groups.bagslots
if slots == 8 then
formspec = formspec.."background[0.06,0.99;7.92,7.52;ui_bags_sm_form.png]"
fs[#fs + 1] = "background[0.06,0.99;7.92,7.52;ui_bags_sm_form.png]"
elseif slots == 16 then
formspec = formspec.."background[0.06,0.99;7.92,7.52;ui_bags_med_form.png]"
fs[#fs + 1] = "background[0.06,0.99;7.92,7.52;ui_bags_med_form.png]"
elseif slots == 24 then
formspec = formspec.."background[0.06,0.99;7.92,7.52;ui_bags_lg_form.png]"
fs[#fs + 1] = "background[0.06,0.99;7.92,7.52;ui_bags_lg_form.png]"
end
local player_name = player:get_player_name() -- For if statement.
if unified_inventory.trash_enabled or unified_inventory.is_creative(player_name) or minetest.get_player_privs(player_name).give then
formspec = (formspec.."background[6.06,0;0.92,0.92;ui_bags_trash.png]"
.."list[detached:trash;main;6,0.1;1,1;]")
if unified_inventory.trash_enabled
or unified_inventory.is_creative(player_name)
or minetest.get_player_privs(player_name).give then
fs[#fs + 1] = "background[6.06,0;0.92,0.92;ui_bags_trash.png]"
.. "list[detached:trash;main;6,0.1;1,1;]"
end
local inv = player:get_inventory()
for i = 1, 4 do
local def = get_player_bag_stack(player, i):get_definition()
local button
if def.groups.bagslots then
local list_name = "bag" .. i .. "contents"
local size = inv:get_size(list_name)
@ -79,13 +84,11 @@ for i = 1, 4 do
end
local img = def.inventory_image
local label = F(S("Bag @1", i)) .. "\n" .. used .. "/" .. size
button = "image_button["..(i+1)..",0;1,1;"..img..";bag"..i..";"..label.."]"
else
button = ""
fs[#fs + 1] = string.format("image_button[%i,0;1,1;%s;bag%i;%s]",
i + 1, img, i, label)
end
formspec = formspec..button
end
return {formspec=formspec}
return { formspec = table.concat(fs) }
end,
})
end
@ -117,17 +120,19 @@ local function save_bags_metadata(player, bags_inv)
is_empty = false
end
end
local meta = player:get_meta()
if is_empty then
player:set_attribute("unified_inventory:bags", nil)
meta:set_string("unified_inventory:bags", nil)
else
player:set_attribute("unified_inventory:bags",
meta:set_string("unified_inventory:bags",
minetest.serialize(bags))
end
end
local function load_bags_metadata(player, bags_inv)
local player_inv = player:get_inventory()
local bags_meta = player:get_attribute("unified_inventory:bags")
local meta = player:get_meta()
local bags_meta = meta:get_string("unified_inventory:bags")
local bags = bags_meta and minetest.deserialize(bags_meta) or {}
local dirty_meta = false
if not bags_meta then

View File

@ -47,6 +47,15 @@ minetest.register_on_joinplayer(function(player)
refill:set_size("main", 1)
end)
local function apply_new_filter(player, search_text, new_dir)
local player_name = player:get_player_name()
minetest.sound_play("click", {to_player=player_name, gain = 0.1})
unified_inventory.apply_filter(player, search_text, new_dir)
unified_inventory.current_searchbox[player_name] = search_text
unified_inventory.set_inventory_formspec(player,
unified_inventory.current_page[player_name])
end
minetest.register_on_player_receive_fields(function(player, formname, fields)
local player_name = player:get_player_name()
@ -60,7 +69,6 @@ minetest.register_on_player_receive_fields(function(player, formname, fields)
if fields.searchbox
and fields.searchbox ~= unified_inventory.current_searchbox[player_name] then
unified_inventory.current_searchbox[player_name] = fields.searchbox
unified_inventory.set_inventory_formspec(player, unified_inventory.current_page[player_name])
end
for i, def in pairs(unified_inventory.buttons) do
@ -112,21 +120,18 @@ minetest.register_on_player_receive_fields(function(player, formname, fields)
unified_inventory.current_page[player_name])
end
-- Check clicked item image button
local clicked_item
for name, value in pairs(fields) do
if string.sub(name, 1, 12) == "item_button_" then
local new_dir, mangled_item = string.match(name, "^item_button_([a-z]+)_(.*)$")
if new_dir and mangled_item then
clicked_item = unified_inventory.demangle_for_formspec(mangled_item)
if string.sub(clicked_item, 1, 6) == "group:" then
minetest.sound_play("click", {to_player=player_name, gain = 0.1})
unified_inventory.apply_filter(player, clicked_item, new_dir)
unified_inventory.current_searchbox[player_name] = clicked_item
unified_inventory.set_inventory_formspec(player,
unified_inventory.current_page[player_name])
-- Change search filter to this group
apply_new_filter(player, clicked_item, new_dir)
return
end
if new_dir == "recipe"
or new_dir == "usage" then
if new_dir == "recipe" or new_dir == "usage" then
unified_inventory.current_craft_direction[player_name] = new_dir
end
break
@ -145,6 +150,7 @@ minetest.register_on_player_receive_fields(function(player, formname, fields)
unified_inventory.alternate[player_name] = 1
unified_inventory.set_inventory_formspec(player, "craftguide")
elseif player_creative then
-- Creative page: Add entire stack to inventory
local inv = player:get_inventory()
local stack = ItemStack(clicked_item)
stack:set_count(stack:get_stack_max())
@ -162,12 +168,7 @@ minetest.register_on_player_receive_fields(function(player, formname, fields)
minetest.sound_play("paperflip2",
{to_player=player_name, gain = 1.0})
elseif fields.searchresetbutton then
unified_inventory.apply_filter(player, "", "nochange")
unified_inventory.current_searchbox[player_name] = ""
unified_inventory.set_inventory_formspec(player,
unified_inventory.current_page[player_name])
minetest.sound_play("click",
{to_player=player_name, gain = 0.1})
apply_new_filter(player, "", "nochange")
end
-- alternate buttons

95
doc/mod_api.txt Normal file
View File

@ -0,0 +1,95 @@
unified_inventory API
=====================
This file provides information about the API of unified_inventory.
Misc functions
--------------
Grouped by use-case, afterwards sorted alphabetically.
* `unified_inventory.is_creative(name)`
* Checks whether creative is enabled or the player has `creative`
Pages
-----
Register a new page: The callback inside this function is called on user input.
unified_inventory.register_page("pagename", {
get_formspec = function(player)
-- ^ `player` is an `ObjectRef`
-- Compute the formspec string here
return {
formspec = "button[2,2;2,1;mybutton;Press me]",
-- ^ Final form of the formspec to display
draw_inventory = false, -- default `true`
-- ^ Optional. Hides the player's `main` inventory list
draw_item_list = false, -- default `true`
-- ^ Optional. Hides the item list on the right side
formspec_prepend = false, -- default `false`
-- ^ Optional. When `false`: Disables the formspec prepend
}
end,
})
Buttons
-------
Register a new button for the bottom row:
unified_inventory.register_button("skins", {
type = "image",
image = "skins_skin_button.png",
tooltip = "Skins",
hide_lite = true
-- ^ Button is hidden when following two conditions are met:
-- Configuration line `unified_inventory_lite = true`
-- Player does not have the privilege `ui_full`
})
Crafting
--------
The code blocks below document each possible parameter using exemplary values.
Provide information to display custom craft types:
unified_inventory.register_craft_type("mytype", {
-- ^ Unique identifier for `register_craft`
description = "Sample Craft",
-- ^ Text shown below the crafting arrow
icon = "dummy.png",
-- ^ Image shown above the crafting arrow
width = 3,
height = 3,
-- ^ Maximal input dimensions of the recipes
dynamic_display_size = function(craft)
-- ^ `craft` is the definition from `register_craft`
return {
width = 2,
height = 3
}
end,
-- ^ Optional callback to change the displayed recipe size
uses_crafting_grid = true,
})
Register a non-standard craft recipe:
unified_inventory.register_craft({
output = "default:foobar",
type = "mytype",
-- ^ Standard craft type or custom (see `register_craft_type`)
items = {
{ "default:foo" },
{ "default:bar" }
},
width = 3,
-- ^ Same as `minetest.register_recipe`
})

View File

@ -2,7 +2,12 @@ local S = unified_inventory.gettext
function unified_inventory.canonical_item_spec_matcher(spec)
local specname = ItemStack(spec):get_name()
if specname:sub(1, 6) == "group:" then
if specname:sub(1, 6) ~= "group:" then
return function (itemname)
return itemname == specname
end
end
local group_names = specname:sub(7):split(",")
return function (itemname)
local itemdef = minetest.registered_items[itemname]
@ -13,9 +18,6 @@ function unified_inventory.canonical_item_spec_matcher(spec)
end
return true
end
else
return function (itemname) return itemname == specname end
end
end
function unified_inventory.item_matches_spec(item, spec)
@ -25,23 +27,11 @@ end
function unified_inventory.extract_groupnames(groupname)
local specname = ItemStack(groupname):get_name()
if specname:sub(1, 6) == "group:" then
local group_names = specname:sub(7):split(",")
if #group_names == 1 then
return group_names[1], 1
end
local s = ""
for g=1,#group_names do
if g > 1 then
-- List connector
s = s .. S(" and ")
end
s = s .. group_names[g]
end
return s, #group_names
else
if specname:sub(1, 6) ~= "group:" then
return nil, 0
end
local group_names = specname:sub(7):split(",")
return table.concat(group_names, S(" and ")), #group_names
end
unified_inventory.registered_group_items = {

View File

@ -58,15 +58,20 @@ function unified_inventory.get_formspec(player, page)
unified_inventory.current_page[player_name] = page
local pagedef = unified_inventory.pages[page]
if not pagedef then
return "" -- Invalid page name
end
local formspec = {
"size[14,10]",
pagedef.formspec_prepend and "" or "no_prepend[]",
"background[-0.19,-0.25;14.4,10.75;ui_form_bg.png]" -- Background
}
local n = 3
local n = 4
if draw_lite_mode then
formspec[1] = "size[11,7.7]"
formspec[2] = "background[-0.19,-0.2;11.4,8.4;ui_form_bg.png]"
formspec[3] = "background[-0.19,-0.2;11.4,8.4;ui_form_bg.png]"
end
if unified_inventory.is_creative(player_name)
@ -75,11 +80,6 @@ function unified_inventory.get_formspec(player, page)
n = n+1
end
-- Current page
if not unified_inventory.pages[page] then
return "" -- Invalid page name
end
local perplayer_formspec = unified_inventory.get_per_player_formspec(player_name)
local fsdata = pagedef.get_formspec(player, perplayer_formspec)
@ -302,15 +302,13 @@ function unified_inventory.apply_filter(player, filter, search_dir)
return string.find(lname, lfilter, 1, true) or string.find(ldesc, lfilter, 1, true)
end
end
local is_creative = unified_inventory.is_creative(player_name)
unified_inventory.filtered_items_list[player_name]={}
for name, def in pairs(minetest.registered_items) do
if (not def.groups.not_in_creative_inventory
or def.groups.not_in_creative_inventory == 0)
and def.description
and def.description ~= ""
and ffilter(name, def)
and (is_creative or unified_inventory.crafts_for.recipe[def.name]) then
and ffilter(name, def) then
table.insert(unified_inventory.filtered_items_list[player_name], name)
end
end

View File

@ -1 +1,4 @@
name = unified_inventory
depends = default
optional_depends = creative, sfinv, intllib, datastorage, farming
description = Unified Inventory replaces the default survival and creative inventory. It adds a nicer interface and a number of features, such as a crafting guide.

View File

@ -40,55 +40,6 @@ unified_inventory.register_button("craftguide", {
tooltip = S("Crafting Guide")
})
unified_inventory.register_button("home_gui_set", {
type = "image",
image = "ui_sethome_icon.png",
tooltip = S("Set home position"),
hide_lite=true,
action = function(player)
local player_name = player:get_player_name()
if minetest.check_player_privs(player_name, {home=true}) then
unified_inventory.set_home(player, player:getpos())
local home = unified_inventory.home_pos[player_name]
if home ~= nil then
minetest.sound_play("dingdong",
{to_player=player_name, gain = 1.0})
minetest.chat_send_player(player_name,
S("Home position set to: %s"):format(minetest.pos_to_string(home)))
end
else
minetest.chat_send_player(player_name,
S("You don't have the \"home\" privilege!"))
unified_inventory.set_inventory_formspec(player, unified_inventory.current_page[player_name])
end
end,
condition = function(player)
return minetest.check_player_privs(player:get_player_name(), {home=true})
end,
})
unified_inventory.register_button("home_gui_go", {
type = "image",
image = "ui_gohome_icon.png",
tooltip = S("Go home"),
hide_lite=true,
action = function(player)
local player_name = player:get_player_name()
if minetest.check_player_privs(player_name, {home=true}) then
minetest.sound_play("teleport",
{to_player=player:get_player_name(), gain = 1.0})
unified_inventory.go_home(player)
else
minetest.chat_send_player(player_name,
S("You don't have the \"home\" privilege!"))
unified_inventory.set_inventory_formspec(player, unified_inventory.current_page[player_name])
end
end,
condition = function(player)
return minetest.check_player_privs(player:get_player_name(), {home=true})
end,
})
unified_inventory.register_button("misc_set_day", {
type = "image",
image = "ui_sun_icon.png",
@ -266,65 +217,77 @@ unified_inventory.register_page("craftguide", {
local player_name = player:get_player_name()
local player_privs = minetest.get_player_privs(player_name)
local formspec = ""
formspec = formspec.."background[0,"..(formspecy + 3.5)..";8,4;ui_main_inventory.png]"
formspec = formspec.."label[0,"..formheadery..";" .. F(S("Crafting Guide")) .. "]"
formspec = formspec.."listcolors[#00000000;#00000000]"
local fs = {
"background[0,"..(formspecy + 3.5)..";8,4;ui_main_inventory.png]",
"label[0,"..formheadery..";" .. F(S("Crafting Guide")) .. "]",
"listcolors[#00000000;#00000000]"
}
local item_name = unified_inventory.current_item[player_name]
if not item_name then return {formspec=formspec} end
if not item_name then
return { formspec = table.concat(fs) }
end
local item_name_shown
if minetest.registered_items[item_name] and minetest.registered_items[item_name].description then
item_name_shown = string.format(S("%s (%s)"), minetest.registered_items[item_name].description, item_name)
if minetest.registered_items[item_name]
and minetest.registered_items[item_name].description then
item_name_shown = string.format(S("%s (%s)"),
minetest.registered_items[item_name].description, item_name)
else
item_name_shown = item_name
end
local dir = unified_inventory.current_craft_direction[player_name]
local rdir
if dir == "recipe" then rdir = "usage" end
if dir == "usage" then rdir = "recipe" end
local rdir = dir == "recipe" and "usage" or "recipe"
local crafts = unified_inventory.crafts_for[dir][item_name]
local alternate = unified_inventory.alternate[player_name]
local alternates, craft
if crafts ~= nil and #crafts > 0 then
if crafts and #crafts > 0 then
alternates = #crafts
craft = crafts[alternate]
end
local has_creative = player_privs.give or player_privs.creative or
minetest.settings:get_bool("creative_mode")
local has_give = player_privs.give or unified_inventory.is_creative(player_name)
formspec = formspec.."background[0.5,"..(formspecy + 0.2)..";8,3;ui_craftguide_form.png]"
formspec = formspec.."textarea["..craftresultx..","..craftresulty
..";10,1;;"..F(role_text[dir])..": "..item_name_shown..";]"
formspec = formspec..stack_image_button(0, formspecy, 1.1, 1.1, "item_button_"
.. rdir .. "_", ItemStack(item_name))
fs[#fs + 1] = "background[0.5,"..(formspecy + 0.2)..";8,3;ui_craftguide_form.png]"
fs[#fs + 1] = string.format("textarea[%f,%f;10,1;;%s: %s;]",
craftresultx, craftresulty, F(role_text[dir]), item_name_shown)
fs[#fs + 1] = stack_image_button(0, formspecy, 1.1, 1.1,
"item_button_" .. rdir .. "_", ItemStack(item_name))
if not craft then
formspec = formspec.."label[5.5,"..(formspecy + 2.35)..";"
-- No craft recipes available for this item.
fs[#fs + 1] = "label[5.5,"..(formspecy + 2.35)..";"
.. F(no_recipe_text[dir]) .. "]"
local no_pos = dir == "recipe" and 4.5 or 6.5
local item_pos = dir == "recipe" and 6.5 or 4.5
formspec = formspec.."image["..no_pos..","..formspecy..";1.1,1.1;ui_no.png]"
formspec = formspec..stack_image_button(item_pos, formspecy, 1.1, 1.1, "item_button_"
..other_dir[dir].."_", ItemStack(item_name))
if has_creative then
formspec = formspec.."label[0,"..(formspecy + 2.10)..";" .. F(S("Give me:")) .. "]"
fs[#fs + 1] = "image["..no_pos..","..formspecy..";1.1,1.1;ui_no.png]"
fs[#fs + 1] = stack_image_button(item_pos, formspecy, 1.1, 1.1,
"item_button_" .. other_dir[dir] .. "_", ItemStack(item_name))
if has_give then
fs[#fs + 1] = "label[0," .. (formspecy + 2.10) .. ";" .. F(S("Give me:")) .. "]"
.. "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
return {formspec = formspec}
return { formspec = table.concat(fs) }
end
local craft_type = unified_inventory.registered_craft_types[craft.type] or
unified_inventory.craft_type_defaults(craft.type, {})
if craft_type.icon then
formspec = formspec..string.format(" image[%f,%f;%f,%f;%s]",5.7,(formspecy + 0.05),0.5,0.5,craft_type.icon)
fs[#fs + 1] = string.format("image[%f,%f;%f,%f;%s]",
5.7, (formspecy + 0.05), 0.5, 0.5, craft_type.icon)
end
formspec = formspec.."label[5.5,"..(formspecy + 1)..";" .. F(craft_type.description).."]"
formspec = formspec..stack_image_button(6.5, formspecy, 1.1, 1.1, "item_button_usage_", ItemStack(craft.output))
local display_size = craft_type.dynamic_display_size and craft_type.dynamic_display_size(craft) or { width = craft_type.width, height = craft_type.height }
local craft_width = craft_type.get_shaped_craft_width and craft_type.get_shaped_craft_width(craft) or display_size.width
fs[#fs + 1] = "label[5.5,"..(formspecy + 1)..";" .. F(craft_type.description).."]"
fs[#fs + 1] = stack_image_button(6.5, formspecy, 1.1, 1.1,
"item_button_usage_", ItemStack(craft.output))
local display_size = craft_type.dynamic_display_size
and craft_type.dynamic_display_size(craft)
or { width = craft_type.width, height = craft_type.height }
local craft_width = craft_type.get_shaped_craft_width
and craft_type.get_shaped_craft_width(craft)
or display_size.width
-- This keeps recipes aligned to the right,
-- so that they're close to the arrow.
@ -359,63 +322,67 @@ unified_inventory.register_page("craftguide", {
local xof = (fx-1) * of + of
local yof = (y-1) * of + 1
if item then
formspec = formspec..stack_image_button(
fs[#fs + 1] = stack_image_button(
xoffset - xof, formspecy - 1 + yof, bsize_w, bsize_h,
"item_button_recipe_",
ItemStack(item))
else
-- Fake buttons just to make grid
formspec = formspec.."image_button["
..tostring(xoffset - xof)..","..tostring(formspecy - 1 + yof)
..";"..bsize_w..","..bsize_h..";ui_blank_image.png;;]"
fs[#fs + 1] = string.format("image_button[%f,%f;%f,%f;ui_blank_image.png;;]",
xoffset - xof, formspecy - 1 + yof, bsize_w, bsize_h)
end
end
end
else
-- Error
formspec = formspec.."label["
..tostring(2)..","..tostring(formspecy)
..";"..F(S("This recipe is too\nlarge to be displayed.")).."]"
fs[#fs + 1] = string.format("label[2,%f;%s]",
formspecy, F(S("This recipe is too\nlarge to be displayed.")))
end
if craft_type.uses_crafting_grid and display_size.width <= 3 then
formspec = formspec.."label[0,"..(formspecy + 0.9)..";" .. F(S("To craft grid:")) .. "]"
fs[#fs + 1] = "label[0," .. (formspecy + 0.9) .. ";" .. F(S("To craft grid:")) .. "]"
.. "button[0, " .. (formspecy + 1.5) .. ";0.6,0.5;craftguide_craft_1;1]"
.. "button[0.6," .. (formspecy + 1.5) .. ";0.7,0.5;craftguide_craft_10;10]"
.. "button[1.3," .. (formspecy + 1.5) .. ";0.8,0.5;craftguide_craft_max;" .. F(S("All")) .. "]"
end
if has_creative then
formspec = formspec.."label[0,"..(formspecy + 2.1)..";" .. F(S("Give me:")) .. "]"
if has_give then
fs[#fs + 1] = "label[0," .. (formspecy + 2.1) .. ";" .. F(S("Give me:")) .. "]"
.. "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
if alternates and alternates > 1 then
formspec = formspec.."label[5.5,"..(formspecy + 1.6)..";"
fs[#fs + 1] = "label[5.5," .. (formspecy + 1.6) .. ";"
.. string.format(F(recipe_text[dir]), alternate, alternates) .. "]"
.. "image_button[5.5," .. (formspecy + 2) .. ";1,1;ui_left_icon.png;alternate_prev;]"
.. "image_button[6.5," .. (formspecy + 2) .. ";1,1;ui_right_icon.png;alternate;]"
.. "tooltip[alternate_prev;" .. F(prev_alt_text[dir]) .. "]"
.. "tooltip[alternate;" .. F(next_alt_text[dir]) .. "]"
end
return {formspec = formspec}
return { formspec = table.concat(fs) }
end,
})
local function craftguide_giveme(player, formname, fields)
local player_name = player:get_player_name()
local player_privs = minetest.get_player_privs(player_name)
if not player_privs.give and
not unified_inventory.is_creative(player_name) then
minetest.log("action", "[unified_inventory] Denied give action to player " ..
player_name)
return
end
local amount
for k, v in pairs(fields) do
amount = k:match("craftguide_giveme_(.*)")
if amount then break end
end
if not amount then return end
amount = tonumber(amount)
amount = tonumber(amount) or 0
if amount == 0 then return end
local player_name = player:get_player_name()
local output = unified_inventory.current_item[player_name]
if (not output) or (output == "") then return end
@ -424,78 +391,63 @@ local function craftguide_giveme(player, formname, fields)
player_inv:add_item("main", {name = output, count = amount})
end
-- tells if an item can be moved and returns an index if so
local function item_fits(player_inv, craft_item, needed_item)
local need_group = string.sub(needed_item, 1, 6) == "group:"
if need_group then
need_group = string.sub(needed_item, 7)
end
if craft_item
and not craft_item:is_empty() then
local ciname = craft_item:get_name()
-- abort if the item there isn't usable
if ciname ~= needed_item
and not need_group then
-- Takes any stack from "main" where the `amount` of `needed_item` may fit
-- into the given crafting stack (`craft_item`)
local function craftguide_move_stacks(inv, craft_item, needed_item, amount)
if craft_item:get_count() >= amount then
return
end
-- abort if no item fits onto it
if craft_item:get_count() >= craft_item:get_definition().stack_max then
local get_item_group = minetest.get_item_group
local group = needed_item:match("^group:(.+)")
if group then
if not craft_item:is_empty() then
-- Source item must be the same to fill
if get_item_group(craft_item:get_name(), group) ~= 0 then
needed_item = craft_item:get_name()
else
-- TODO: Maybe swap unmatching "craft" items
-- !! Would conflict with recursive function call
return
end
-- use the item there if it's in the right group and a group item is needed
if need_group then
if minetest.get_item_group(ciname, need_group) == 0 then
return
else
-- Take matching group from the inventory (biggest stack)
local main = inv:get_list("main")
local max_found = 0
for i, stack in ipairs(main) do
if stack:get_count() > max_found and
get_item_group(stack:get_name(), group) ~= 0 then
needed_item = stack:get_name()
max_found = stack:get_count()
if max_found >= amount then
break
end
needed_item = ciname
need_group = false
end
end
end
else
if not craft_item:is_empty() and
craft_item:get_name() ~= needed_item then
return -- Item must be identical
end
end
if need_group then
-- search an item of the specific group
for i,item in pairs(player_inv:get_list("main")) do
if not item:is_empty()
and minetest.get_item_group(item:get_name(), need_group) > 0 then
return i
end
needed_item = ItemStack(needed_item)
local to_take = math.min(amount, needed_item:get_stack_max())
to_take = to_take - craft_item:get_count()
if to_take <= 0 then
return -- Nothing to do
end
needed_item:set_count(to_take)
-- no index found
return
local taken = inv:remove_item("main", needed_item)
local leftover = taken:add_item(craft_item)
if not leftover:is_empty() then
-- Somehow failed to add the existing "craft" item. Undo the action.
inv:add_item("main", leftover)
return taken
end
-- search an item with a the name needed_item
for i,item in pairs(player_inv:get_list("main")) do
if not item:is_empty()
and item:get_name() == needed_item then
return i
end
end
-- no index found
end
-- modifies the player inventory and returns the changed craft_item if possible
local function move_item(player_inv, craft_item, needed_item)
local stackid = item_fits(player_inv, craft_item, needed_item)
if not stackid then
return
end
local wanted_stack = player_inv:get_stack("main", stackid)
local taken_item = wanted_stack:take_item()
player_inv:set_stack("main", stackid, wanted_stack)
if not craft_item
or craft_item:is_empty() then
return taken_item
end
craft_item:add_item(taken_item)
return craft_item
return taken
end
local function craftguide_craft(player, formname, fields)
@ -505,15 +457,21 @@ local function craftguide_craft(player, formname, fields)
if amount then break end
end
if not amount then return end
amount = tonumber(amount) or 99 -- fallback for "all"
if amount <= 0 or amount > 99 then return end
local player_name = player:get_player_name()
local output = unified_inventory.current_item[player_name]
if (not output) or (output == "") then return end
local output = unified_inventory.current_item[player_name] or ""
if output == "" then return end
local player_inv = player:get_inventory()
local craft_list = player_inv:get_list("craft")
local crafts = unified_inventory.crafts_for[unified_inventory.current_craft_direction[player_name]][output]
if (not crafts) or (#crafts == 0) then return end
local crafts = unified_inventory.crafts_for[
unified_inventory.current_craft_direction[player_name]][output] or {}
if #crafts == 0 then return end
local alternate = unified_inventory.alternate[player_name]
@ -521,24 +479,17 @@ local function craftguide_craft(player, formname, fields)
if craft.width > 3 then return end
local needed = craft.items
local craft_list = player_inv:get_list("craft")
local width = craft.width
if width == 0 then
-- Shapeless recipe
width = 3
end
amount = tonumber(amount) or 99
--[[
if amount == "max" then
amount = 99 -- Arbitrary; need better way to do this.
else
amount = tonumber(amount)
end--]]
for iter = 1, amount do
-- To spread the items evenly
local STEPSIZE = math.ceil(math.sqrt(amount) / 5) * 5
local current_count = 0
repeat
current_count = math.min(current_count + STEPSIZE, amount)
local index = 1
for y = 1, 3 do
for x = 1, width do
@ -546,7 +497,9 @@ local function craftguide_craft(player, formname, fields)
if needed_item then
local craft_index = ((y - 1) * 3) + x
local craft_item = craft_list[craft_index]
local newitem = move_item(player_inv, craft_item, needed_item)
local newitem = craftguide_move_stacks(player_inv,
craft_item, needed_item, current_count)
if newitem then
craft_list[craft_index] = newitem
end
@ -554,7 +507,7 @@ local function craftguide_craft(player, formname, fields)
index = index + 1
end
end
end
until current_count == amount
player_inv:set_list("craft", craft_list)
@ -562,6 +515,10 @@ local function craftguide_craft(player, formname, fields)
end
minetest.register_on_player_receive_fields(function(player, formname, fields)
if formname ~= "" then
return
end
for k, v in pairs(fields) do
if k:match("craftguide_craft_") then
craftguide_craft(player, formname, fields)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 9.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 546 B

After

Width:  |  Height:  |  Size: 456 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 961 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 777 B

After

Width:  |  Height:  |  Size: 658 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 928 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 7.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.7 KiB

After

Width:  |  Height:  |  Size: 5.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 7.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 81 B

After

Width:  |  Height:  |  Size: 71 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.8 KiB

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 8.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 896 B

After

Width:  |  Height:  |  Size: 483 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 962 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.9 KiB

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 9.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 9.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.2 KiB

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 23 KiB

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.0 KiB

After

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.6 KiB

After

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.7 KiB

After

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.8 KiB

After

Width:  |  Height:  |  Size: 5.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.8 KiB

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.9 KiB

After

Width:  |  Height:  |  Size: 5.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.3 KiB

After

Width:  |  Height:  |  Size: 5.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.8 KiB

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.1 KiB

After

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 988 B

After

Width:  |  Height:  |  Size: 629 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.3 KiB

After

Width:  |  Height:  |  Size: 8.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.2 KiB

After

Width:  |  Height:  |  Size: 8.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.5 KiB

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.4 KiB

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.4 KiB

After

Width:  |  Height:  |  Size: 2.1 KiB

View File

@ -174,7 +174,7 @@ minetest.register_on_player_receive_fields(function(player, formname, fields)
if fields["set_waypoint"..i] then
hit = true
local pos = player:getpos()
local pos = player:get_pos()
pos.x = math.floor(pos.x)
pos.y = math.floor(pos.y)
pos.z = math.floor(pos.z)