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. 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) 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) VanessaE: (CC-BY-4.0)
* `ui_group.png` * `ui_group.png`
Tango Project: (Public Domain, CC-BY-4.0) Tango Project: (Public Domain, CC-BY-4.0)
* [`ui_reset_icon.png`](https://commons.wikimedia.org/wiki/File:Edit-clear.svg) * [`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_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) * [`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) * [`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): From http://www.clker.com (Public Domain, CC-BY-4.0):
* [`bags_small.png`](http://www.clker.com/clipart-moneybag-empty.html) * [`bags_small.png`](http://www.clker.com/clipart-moneybag-empty.html)
* [`bags_medium.png`](http://www.clker.com/clipart-backpack-1.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) * [`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) * [`ui_waypoint_set_icon.png`](http://www.clker.com/clipart-larger-flag.html)
Everaldo Coelho (YellowIcon) (LGPL v2.1+): Everaldo Coelho (YellowIcon) (LGPL v2.1+):
* [`ui_craftguide_icon.png` / `ui_craft_icon.png`](http://commons.wikimedia.org/wiki/File:Advancedsettings.png) * [`ui_craftguide_icon.png` / `ui_craft_icon.png`](http://commons.wikimedia.org/wiki/File:Advancedsettings.png)
Gregory H. Revera: (CC-BY-SA 3.0) Gregory H. Revera: (CC-BY-SA 3.0)
* [`ui_moon_icon.png`](http://commons.wikimedia.org/wiki/File:FullMoon2010.jpg) * [`ui_moon_icon.png`](http://commons.wikimedia.org/wiki/File:FullMoon2010.jpg)
Thomas Bresson: (CC-BY 3.0) Thomas Bresson: (CC-BY 3.0)
* [`ui_sun_icon.png`](http://commons.wikimedia.org/wiki/File:2012-10-13_15-29-35-sun.jpg) * [`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) Fibonacci: (Public domain, CC-BY 4.0)
* [`ui_xyz_off_icon.png`](http://commons.wikimedia.org/wiki/File:No_sign.svg) * [`ui_xyz_off_icon.png`](http://commons.wikimedia.org/wiki/File:No_sign.svg)
Gregory Maxwell: (Public domain, CC-BY 4.0) Gregory Maxwell: (Public domain, CC-BY 4.0)
* [`ui_ok_icon.png`](http://commons.wikimedia.org/wiki/File:Yes_check.svg) * [`ui_ok_icon.png`](http://commons.wikimedia.org/wiki/File:Yes_check.svg)
Adrien Facélina: (LGPL v2.1+) Adrien Facélina: (LGPL v2.1+)
* [`inventory_plus_worldedit_gui.png`](http://commons.wikimedia.org/wiki/File:Erioll_world_2.svg) * [`inventory_plus_worldedit_gui.png`](http://commons.wikimedia.org/wiki/File:Erioll_world_2.svg)
Other files from Wikimedia Commons: 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+) * [`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) RealBadAngel: (CC-BY-4.0)
* Everything else. * Everything else.

View File

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

115
bags.lua
View File

@ -1,7 +1,9 @@
-- Bags for Minetest --[[
Bags for Minetest
-- Copyright (c) 2012 cornernote, Brett O'Donnell <cornernote@gmail.com> Copyright (c) 2012 cornernote, Brett O'Donnell <cornernote@gmail.com>
-- License: GPLv3 License: GPLv3
--]]
local S = unified_inventory.gettext local S = unified_inventory.gettext
local F = minetest.formspec_escape local F = minetest.formspec_escape
@ -9,18 +11,19 @@ local F = minetest.formspec_escape
unified_inventory.register_page("bags", { unified_inventory.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()
local formspec = "background[0.06,0.99;7.92,7.52;ui_bags_main_form.png]" return { formspec = table.concat({
formspec = formspec.."label[0,0;"..F(S("Bags")).."]" "background[0.06,0.99;7.92,7.52;ui_bags_main_form.png]",
formspec = formspec.."button[0,2;2,0.5;bag1;"..F(S("Bag @1", 1)).."]" "label[0,0;" .. F(S("Bags")) .. "]",
formspec = formspec.."button[2,2;2,0.5;bag2;"..F(S("Bag @1", 2)).."]" "button[0,2;2,0.5;bag1;" .. F(S("Bag @1", 1)) .. "]",
formspec = formspec.."button[4,2;2,0.5;bag3;"..F(S("Bag @1", 3)).."]" "button[2,2;2,0.5;bag2;" .. F(S("Bag @1", 2)) .. "]",
formspec = formspec.."button[6,2;2,0.5;bag4;"..F(S("Bag @1", 4)).."]" "button[4,2;2,0.5;bag3;" .. F(S("Bag @1", 3)) .. "]",
formspec = formspec.."listcolors[#00000000;#00000000]" "button[6,2;2,0.5;bag4;" .. F(S("Bag @1", 4)) .. "]",
formspec = formspec.."list[detached:"..F(player_name).."_bags;bag1;0.5,1;1,1;]" "listcolors[#00000000;#00000000]",
formspec = formspec.."list[detached:"..F(player_name).."_bags;bag2;2.5,1;1,1;]" "list[detached:" .. F(player_name) .. "_bags;bag1;0.5,1;1,1;]",
formspec = formspec.."list[detached:"..F(player_name).."_bags;bag3;4.5,1;1,1;]" "list[detached:" .. F(player_name) .. "_bags;bag2;2.5,1;1,1;]",
formspec = formspec.."list[detached:"..F(player_name).."_bags;bag4;6.5,1;1,1;]" "list[detached:" .. F(player_name) .. "_bags;bag3;4.5,1;1,1;]",
return {formspec=formspec} "list[detached:" .. F(player_name) .. "_bags;bag4;6.5,1;1,1;]"
}) }
end, end,
}) })
@ -38,37 +41,39 @@ local function get_player_bag_stack(player, i)
}):get_stack("bag" .. i, 1) }):get_stack("bag" .. i, 1)
end end
for i = 1, 4 do for bag_i = 1, 4 do
local bi = i unified_inventory.register_page("bag" .. bag_i, {
unified_inventory.register_page("bag"..bi, {
get_formspec = function(player) 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 image = stack:get_definition().inventory_image
local formspec = ("image[7,0;1,1;"..image.."]" local fs = {
.."label[0,0;"..F(S("Bag @1", bi)).."]" "image[7,0;1,1;" .. image .. "]",
.."listcolors[#00000000;#00000000]" "label[0,0;" .. F(S("Bag @1", bag_i)) .. "]",
.."list[current_player;bag"..bi.."contents;0,1;8,3;]" "listcolors[#00000000;#00000000]",
.."listring[current_name;bag"..bi.."contents]" "list[current_player;bag" .. bag_i .. "contents;0,1;8,3;]",
.."listring[current_player;main]") "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 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 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 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 end
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 or unified_inventory.is_creative(player_name) or minetest.get_player_privs(player_name).give then if unified_inventory.trash_enabled
formspec = (formspec.."background[6.06,0;0.92,0.92;ui_bags_trash.png]" or unified_inventory.is_creative(player_name)
.."list[detached:trash;main;6,0.1;1,1;]") 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 end
local inv = player:get_inventory() local inv = player:get_inventory()
for i = 1, 4 do for i = 1, 4 do
local def = get_player_bag_stack(player, i):get_definition() local def = get_player_bag_stack(player, i):get_definition()
local button
if def.groups.bagslots then if def.groups.bagslots then
local list_name = "bag"..i.."contents" local list_name = "bag" .. i .. "contents"
local size = inv:get_size(list_name) local size = inv:get_size(list_name)
local used = 0 local used = 0
for si = 1, size do for si = 1, size do
@ -78,14 +83,12 @@ for i = 1, 4 do
end end
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
button = "image_button["..(i+1)..",0;1,1;"..img..";bag"..i..";"..label.."]" fs[#fs + 1] = string.format("image_button[%i,0;1,1;%s;bag%i;%s]",
else i + 1, img, i, label)
button = ""
end end
formspec = formspec..button
end end
return {formspec=formspec} return { formspec = table.concat(fs) }
end, end,
}) })
end end
@ -95,12 +98,12 @@ minetest.register_on_player_receive_fields(function(player, formname, fields)
return return
end end
for i = 1, 4 do for i = 1, 4 do
if fields["bag"..i] then if fields["bag" .. i] then
local stack = get_player_bag_stack(player, i) local stack = get_player_bag_stack(player, i)
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) unified_inventory.set_inventory_formspec(player, "bag" .. i)
return return
end end
end end
@ -110,30 +113,32 @@ local function save_bags_metadata(player, bags_inv)
local is_empty = true local is_empty = true
local bags = {} local bags = {}
for i = 1, 4 do for i = 1, 4 do
local bag = "bag"..i local bag = "bag" .. i
if not bags_inv:is_empty(bag) then if not bags_inv:is_empty(bag) then
-- Stack limit is 1, otherwise use stack:to_string() -- Stack limit is 1, otherwise use stack:to_string()
bags[i] = bags_inv:get_stack(bag, 1):get_name() bags[i] = bags_inv:get_stack(bag, 1):get_name()
is_empty = false is_empty = false
end end
end end
local meta = player:get_meta()
if is_empty then if is_empty then
player:set_attribute("unified_inventory:bags", nil) meta:set_string("unified_inventory:bags", nil)
else else
player:set_attribute("unified_inventory:bags", meta:set_string("unified_inventory:bags",
minetest.serialize(bags)) minetest.serialize(bags))
end end
end end
local function load_bags_metadata(player, bags_inv) local function load_bags_metadata(player, bags_inv)
local player_inv = player:get_inventory() local player_inv = player:get_inventory()
local 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 bags = bags_meta and minetest.deserialize(bags_meta) or {}
local dirty_meta = false local dirty_meta = false
if not bags_meta then if not bags_meta then
-- Backwards compatiblity -- Backwards compatiblity
for i = 1, 4 do for i = 1, 4 do
local bag = "bag"..i local bag = "bag" .. i
if not player_inv:is_empty(bag) then if not player_inv:is_empty(bag) then
-- Stack limit is 1, otherwise use stack:to_string() -- Stack limit is 1, otherwise use stack:to_string()
bags[i] = player_inv:get_stack(bag, 1):get_name() bags[i] = player_inv:get_stack(bag, 1):get_name()
@ -143,7 +148,7 @@ local function load_bags_metadata(player, bags_inv)
end end
-- Fill detached slots -- Fill detached slots
for i = 1, 4 do for i = 1, 4 do
local bag = "bag"..i local bag = "bag" .. i
bags_inv:set_size(bag, 1) bags_inv:set_size(bag, 1)
bags_inv:set_stack(bag, 1, bags[i] or "") bags_inv:set_stack(bag, 1, bags[i] or "")
end end
@ -155,7 +160,7 @@ local function load_bags_metadata(player, bags_inv)
-- Clean up deprecated garbage after saving -- Clean up deprecated garbage after saving
for i = 1, 4 do for i = 1, 4 do
local bag = "bag"..i local bag = "bag" .. i
player_inv:set_size(bag, 0) player_inv:set_size(bag, 0)
end end
end end
@ -163,9 +168,9 @@ end
minetest.register_on_joinplayer(function(player) minetest.register_on_joinplayer(function(player)
local player_inv = player:get_inventory() local player_inv = player:get_inventory()
local player_name = player:get_player_name() local player_name = player:get_player_name()
local bags_inv = minetest.create_detached_inventory(player_name.."_bags",{ local bags_inv = minetest.create_detached_inventory(player_name .. "_bags",{
on_put = function(inv, listname, index, stack, player) on_put = function(inv, listname, index, stack, player)
player:get_inventory():set_size(listname.."contents", player:get_inventory():set_size(listname .. "contents",
stack:get_definition().groups.bagslots) stack:get_definition().groups.bagslots)
save_bags_metadata(player, inv) save_bags_metadata(player, inv)
end, end,
@ -175,14 +180,14 @@ minetest.register_on_joinplayer(function(player)
return 0 return 0
end end
local player_inv = player:get_inventory() local player_inv = player:get_inventory()
local old_slots = player_inv:get_size(listname.."contents") local old_slots = player_inv:get_size(listname .. "contents")
if new_slots >= old_slots then if new_slots >= old_slots then
return 1 return 1
end end
-- using a smaller bag, make sure it fits -- using a smaller bag, make sure it fits
local old_list = player_inv:get_list(listname.."contents") local old_list = player_inv:get_list(listname .. "contents")
local new_list = {} local new_list = {}
local slots_used = 0 local slots_used = 0
local use_new_list = false local use_new_list = false
@ -196,7 +201,7 @@ minetest.register_on_joinplayer(function(player)
end end
if new_slots >= slots_used then if new_slots >= slots_used then
if use_new_list then if use_new_list then
player_inv:set_list(listname.."contents", new_list) player_inv:set_list(listname .. "contents", new_list)
end end
return 1 return 1
end end
@ -204,13 +209,13 @@ minetest.register_on_joinplayer(function(player)
return 0 return 0
end, end,
allow_take = function(inv, listname, index, stack, player) allow_take = function(inv, listname, index, stack, player)
if player:get_inventory():is_empty(listname.."contents") then if player:get_inventory():is_empty(listname .. "contents") then
return stack:get_count() return stack:get_count()
end end
return 0 return 0
end, end,
on_take = function(inv, listname, index, stack, player) on_take = function(inv, listname, index, stack, player)
player:get_inventory():set_size(listname.."contents", 0) player:get_inventory():set_size(listname .. "contents", 0)
save_bags_metadata(player, inv) save_bags_metadata(player, inv)
end, end,
allow_move = function() allow_move = function()

View File

@ -47,6 +47,15 @@ minetest.register_on_joinplayer(function(player)
refill:set_size("main", 1) refill:set_size("main", 1)
end) 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) minetest.register_on_player_receive_fields(function(player, formname, fields)
local player_name = player:get_player_name() local player_name = player:get_player_name()
@ -60,7 +69,6 @@ minetest.register_on_player_receive_fields(function(player, formname, fields)
if fields.searchbox if fields.searchbox
and fields.searchbox ~= unified_inventory.current_searchbox[player_name] then and fields.searchbox ~= unified_inventory.current_searchbox[player_name] then
unified_inventory.current_searchbox[player_name] = fields.searchbox unified_inventory.current_searchbox[player_name] = fields.searchbox
unified_inventory.set_inventory_formspec(player, unified_inventory.current_page[player_name])
end end
for i, def in pairs(unified_inventory.buttons) do for i, def in pairs(unified_inventory.buttons) do
@ -112,21 +120,18 @@ minetest.register_on_player_receive_fields(function(player, formname, fields)
unified_inventory.current_page[player_name]) unified_inventory.current_page[player_name])
end end
-- Check clicked item image button
local clicked_item local clicked_item
for name, value in pairs(fields) do 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]+)_(.*)$")
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) clicked_item = unified_inventory.demangle_for_formspec(mangled_item)
if string.sub(clicked_item, 1, 6) == "group:" then if string.sub(clicked_item, 1, 6) == "group:" then
minetest.sound_play("click", {to_player=player_name, gain = 0.1}) -- Change search filter to this group
unified_inventory.apply_filter(player, clicked_item, new_dir) apply_new_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])
return return
end end
if new_dir == "recipe" if new_dir == "recipe" or new_dir == "usage" then
or new_dir == "usage" then
unified_inventory.current_craft_direction[player_name] = new_dir unified_inventory.current_craft_direction[player_name] = new_dir
end end
break break
@ -145,6 +150,7 @@ minetest.register_on_player_receive_fields(function(player, formname, fields)
unified_inventory.alternate[player_name] = 1 unified_inventory.alternate[player_name] = 1
unified_inventory.set_inventory_formspec(player, "craftguide") unified_inventory.set_inventory_formspec(player, "craftguide")
elseif player_creative then elseif player_creative then
-- Creative page: Add entire stack to inventory
local inv = player:get_inventory() local inv = player:get_inventory()
local stack = ItemStack(clicked_item) local stack = ItemStack(clicked_item)
stack:set_count(stack:get_stack_max()) 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", minetest.sound_play("paperflip2",
{to_player=player_name, gain = 1.0}) {to_player=player_name, gain = 1.0})
elseif fields.searchresetbutton then elseif fields.searchresetbutton then
unified_inventory.apply_filter(player, "", "nochange") apply_new_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})
end end
-- alternate buttons -- 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,19 +2,21 @@ local S = unified_inventory.gettext
function unified_inventory.canonical_item_spec_matcher(spec) function unified_inventory.canonical_item_spec_matcher(spec)
local specname = ItemStack(spec):get_name() local specname = ItemStack(spec):get_name()
if specname:sub(1, 6) == "group:" then if specname:sub(1, 6) ~= "group:" then
local group_names = specname:sub(7):split(",")
return function (itemname) return function (itemname)
local itemdef = minetest.registered_items[itemname] return itemname == specname
for _, group_name in ipairs(group_names) do
if (itemdef.groups[group_name] or 0) == 0 then
return false
end
end
return true
end end
else end
return function (itemname) return itemname == specname end
local group_names = specname:sub(7):split(",")
return function (itemname)
local itemdef = minetest.registered_items[itemname]
for _, group_name in ipairs(group_names) do
if (itemdef.groups[group_name] or 0) == 0 then
return false
end
end
return true
end end
end end
@ -25,23 +27,11 @@ end
function unified_inventory.extract_groupnames(groupname) function unified_inventory.extract_groupnames(groupname)
local specname = ItemStack(groupname):get_name() local specname = ItemStack(groupname):get_name()
if specname:sub(1, 6) == "group:" then 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
return nil, 0 return nil, 0
end end
local group_names = specname:sub(7):split(",")
return table.concat(group_names, S(" and ")), #group_names
end end
unified_inventory.registered_group_items = { 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 unified_inventory.current_page[player_name] = page
local pagedef = unified_inventory.pages[page] local pagedef = unified_inventory.pages[page]
if not pagedef then
return "" -- Invalid page name
end
local formspec = { local formspec = {
"size[14,10]", "size[14,10]",
pagedef.formspec_prepend and "" or "no_prepend[]",
"background[-0.19,-0.25;14.4,10.75;ui_form_bg.png]" -- Background "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 if draw_lite_mode then
formspec[1] = "size[11,7.7]" 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 end
if unified_inventory.is_creative(player_name) if unified_inventory.is_creative(player_name)
@ -75,11 +80,6 @@ function unified_inventory.get_formspec(player, page)
n = n+1 n = n+1
end 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 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)
@ -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) return string.find(lname, lfilter, 1, true) or string.find(ldesc, lfilter, 1, true)
end end
end end
local is_creative = unified_inventory.is_creative(player_name)
unified_inventory.filtered_items_list[player_name]={} unified_inventory.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) and ffilter(name, def) then
and (is_creative or unified_inventory.crafts_for.recipe[def.name]) then
table.insert(unified_inventory.filtered_items_list[player_name], name) table.insert(unified_inventory.filtered_items_list[player_name], name)
end end
end end

View File

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