Compare commits
	
		
			2 Commits
		
	
	
		
			cb6e602497
			...
			waypoints
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|  | 763eca424e | ||
|  | 3306676910 | 
							
								
								
									
										11
									
								
								.github/workflows/check-release.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						| @@ -1,11 +0,0 @@ | ||||
| on: [push, pull_request] | ||||
| name: Check & Release | ||||
| jobs: | ||||
|   lint: | ||||
|     runs-on: ubuntu-latest | ||||
|     steps: | ||||
|       - uses: actions/checkout@master | ||||
|       - name: lint | ||||
|         uses: Roang-zero1/factorio-mod-luacheck@master | ||||
|         with: | ||||
|           luacheckrc_url: https://raw.githubusercontent.com/minetest-mods/unified_inventory/master/.luacheckrc | ||||
							
								
								
									
										2
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						| @@ -1,2 +0,0 @@ | ||||
| *~ | ||||
|  | ||||
							
								
								
									
										21
									
								
								.luacheckrc
									
									
									
									
									
								
							
							
						
						| @@ -1,21 +0,0 @@ | ||||
| unused_args = false | ||||
| allow_defined_top = true | ||||
| max_line_length = 999 | ||||
|  | ||||
| globals = { | ||||
| 	"unified_inventory", | ||||
| } | ||||
|  | ||||
| read_globals = { | ||||
| 	string = {fields = {"split", "trim"}}, | ||||
| 	table = {fields = {"copy", "getn"}}, | ||||
|  | ||||
| 	"minetest", "vector", | ||||
| 	"ItemStack", "datastorage", | ||||
|  | ||||
| 	"hb", | ||||
| 	"doors", | ||||
| } | ||||
|  | ||||
| files["callbacks.lua"].ignore = { "player", "draw_lite_mode" } | ||||
| files["bags.lua"].ignore = { "player" } | ||||
							
								
								
									
										19
									
								
								LICENSE.txt
									
									
									
									
									
								
							
							
						
						| @@ -1,19 +0,0 @@ | ||||
| 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. | ||||
							
								
								
									
										122
									
								
								README.md
									
									
									
									
									
								
							
							
						
						| @@ -1,120 +1,6 @@ | ||||
| # Unified Inventory | ||||
| unified_inventory | ||||
| ================= | ||||
|  | ||||
| [](https://github.com/minetest-mods/unified_inventory/actions) | ||||
| Replacement for Minetest creative inventory. | ||||
|  | ||||
|  | ||||
|  | ||||
| Unified Inventory replaces the default survival and creative inventory. | ||||
|  | ||||
|  | ||||
| ## 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 and refill slot for creative | ||||
|  * Waypoints to keep track of important locations | ||||
|  * Lite mode: reduces the item browser width | ||||
|     * `minetest.conf` setting `unified_inventory_lite = true` | ||||
|  * Mod API for modders: see [mod_api.txt](doc/mod_api.txt) | ||||
|  * Setting-determinated features: see [settingtypes.txt](settingtypes.txt) | ||||
|  | ||||
|  | ||||
| ## Requirements | ||||
|  | ||||
|  * Minetest 5.4.0+ | ||||
|  * Mod `default` for category filters (contained in Minetest Game) | ||||
|  * Mod `farming` for craftable bags (contained in Minetest Game) | ||||
|  * For waypoint migration: `datastorage` | ||||
|  | ||||
|  | ||||
| # Licenses | ||||
|  | ||||
| Copyright (C) 2012-2014 Maciej Kasatkin (RealBadAngel) | ||||
|  | ||||
| Copyright (C) 2012-? Various minetest-mods contributors | ||||
|  | ||||
|  | ||||
| ## 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) | ||||
|   * [`ui_left_icon.png` / `ui_right_icon.png`](http://commons.wikimedia.org/wiki/File:Media-playback-start.svg) | ||||
|   * [`ui_skip_backward_icon.png`](http://commons.wikimedia.org/wiki/File:Media-skip-backward.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): | ||||
|  | ||||
|   * [`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) | ||||
|   * `ui_trash_icon.png`: <http://www.clker.com/clipart-29090.html> and <http://www.clker.com/clipart-trash.html> | ||||
|   * [`ui_search_icon.png`](http://www.clker.com/clipart-24887.html) | ||||
|   * [`ui_off_icon.png` / `ui_on_icon.png`](http://www.clker.com/clipart-on-off-switches.html) | ||||
|   * [`ui_waypoints_icon.png`](http://www.clker.com/clipart-map-pin-red.html) | ||||
|   * [`ui_circular_arrows_icon.png`](http://www.clker.com/clipart-circular-arrow-pattern.html) | ||||
|   * [`ui_pencil_icon.pnc`](http://www.clker.com/clipart-2256.html) | ||||
|   * [`ui_waypoint_set_icon.png`](http://www.clker.com/clipart-larger-flag.html) | ||||
|  | ||||
| From https://www.svgrepo.com (CC-BY) | ||||
|   * [`ui_teleport.png`](https://www.svgrepo.com/svg/321565/teleport) | ||||
|  | ||||
| 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. | ||||
|  | ||||
|  | ||||
| ## Sounds | ||||
|  | ||||
|  * [`bell.ogg`](https://freesound.org/people/bennstir/sounds/81072/) by bennstir, CC 4.0 | ||||
|  * [`electricity.ogg`](https://freesound.org/people/Halleck/sounds/19486/) by Halleck, CC 4.0 (cut) | ||||
|  * [`pageflip1.ogg`](https://freesound.org/people/themfish/sounds/45823/) by themfish, CC 4.0 (cut, slowed down) | ||||
|  * `pageflip2.ogg` (derived from `pageflip1.ogg`) | ||||
|  * [`trash.ogg`](https://freesound.org/people/OwlStorm/sounds/151231/) by OwlStorm, CC 0 (speed up) | ||||
|  * [`trash_all.ogg`](https://freesound.org/people/abel_K/sounds/68280/) by abel_K, Sampling Plus 1.0 (speed up) | ||||
|  * [`ui_click.ogg`](https://freesound.org/people/lartti/sounds/527569/) by lartti, CC 0 (cut) | ||||
|  * [`ui_morning.ogg`](https://freesound.org/people/InspectorJ/sounds/439472/) by InspectorJ, CC 4.0 | ||||
|  * [`ui_owl.ogg`](https://freesound.org/people/manda_g/sounds/54987/) by manda_g, Sampling Plus 1.0 (cut) | ||||
| Unified Inventory replaces the survival and creative inventory; it also functions as a crafting guide. | ||||
|   | ||||
							
								
								
									
										427
									
								
								api.lua
									
									
									
									
									
								
							
							
						
						| @@ -1,413 +1,102 @@ | ||||
| local S = minetest.get_translator("unified_inventory") | ||||
| local F = minetest.formspec_escape | ||||
| local ui = unified_inventory | ||||
|  | ||||
| local function is_recipe_craftable(recipe) | ||||
| 	-- Ensure the ingedients exist | ||||
| 	for _, itemname in pairs(recipe.items) do | ||||
| 		local groups = string.find(itemname, "group:") | ||||
| 		if groups then | ||||
| 			if not ui.get_group_item(string.sub(groups, 8)).item then | ||||
| 				return false | ||||
| 			end | ||||
| 		else | ||||
| 			-- Possibly an item | ||||
| 			local itemname_cleaned = ItemStack(itemname):get_name() | ||||
| 			if not minetest.registered_items[itemname_cleaned] | ||||
| 					or minetest.get_item_group(itemname_cleaned, "not_in_craft_guide") ~= 0 then | ||||
| 				return false | ||||
| 			end | ||||
| 		end | ||||
| 	end | ||||
| 	return true | ||||
| end | ||||
|  | ||||
| -- Create detached creative inventory after loading all mods | ||||
| minetest.after(0.01, function() | ||||
| 	local rev_aliases = {} | ||||
| 	for original, newname in pairs(minetest.registered_aliases) do | ||||
| 		if not rev_aliases[newname] then | ||||
| 			rev_aliases[newname] = {} | ||||
| 		end | ||||
| 		table.insert(rev_aliases[newname], original) | ||||
| 	end | ||||
|  | ||||
| 	-- Filtered item list | ||||
| 	ui.items_list = {} | ||||
| 	unified_inventory.items_list = {} | ||||
| 	for name, def in pairs(minetest.registered_items) do | ||||
| 		if ui.is_itemdef_listable(def) then | ||||
| 			table.insert(ui.items_list, name) | ||||
|  | ||||
| 			-- Alias processing: Find recipes that belong to the current item name | ||||
| 			local all_names = rev_aliases[name] or {} | ||||
| 			table.insert(all_names, name) | ||||
| 			for _, itemname in ipairs(all_names) do | ||||
| 				local recipes = minetest.get_all_craft_recipes(itemname) | ||||
| 				for _, recipe in ipairs(recipes or {}) do | ||||
| 					if is_recipe_craftable(recipe) then | ||||
| 						ui.register_craft(recipe) | ||||
| 					end | ||||
| 				end | ||||
| 		if (not def.groups.not_in_creative_inventory or | ||||
| 		   def.groups.not_in_creative_inventory == 0) and | ||||
| 		   def.description and def.description ~= "" then | ||||
| 			table.insert(unified_inventory.items_list, name) | ||||
| 			local recipes = minetest.get_all_craft_recipes(name) | ||||
| 			if recipes then | ||||
| 				unified_inventory.crafts_table[name] = recipes | ||||
| 			else | ||||
| 				unified_inventory.crafts_table[name] = {} | ||||
| 			end | ||||
| 		end | ||||
| 	end | ||||
| 	table.sort(ui.items_list) | ||||
| 	ui.items_list_size = #ui.items_list | ||||
| 	print("Unified Inventory. Inventory size: "..ui.items_list_size) | ||||
|  | ||||
| 	-- Analyse dropped items -> custom "digging" recipes | ||||
| 	for _, name in ipairs(ui.items_list) do | ||||
| 		local def = minetest.registered_items[name] | ||||
| 		-- Simple drops | ||||
| 		if type(def.drop) == "string" then | ||||
| 			local dstack = ItemStack(def.drop) | ||||
| 			if not dstack:is_empty() and dstack:get_name() ~= name then | ||||
| 				ui.register_craft({ | ||||
| 					type = "digging", | ||||
| 					items = {name}, | ||||
| 					output = def.drop, | ||||
| 					width = 0, | ||||
| 				}) | ||||
|  | ||||
| 			end | ||||
| 		-- Complex drops. Yes, it's really complex! | ||||
| 		elseif type(def.drop) == "table" then | ||||
| 			--[[ Extract single items from the table and save them into dedicated tables | ||||
| 			to register them later, in order to avoid duplicates. These tables counts | ||||
| 			the total number of guaranteed drops and drops by chance (“maybes”) for each item. | ||||
| 			For “maybes”, the final count is the theoretical maximum number of items, not | ||||
| 			neccessarily the actual drop count. ]] | ||||
| 			local drop_guaranteed = {} | ||||
| 			local drop_maybe = {} | ||||
| 			-- This is for catching an obscure corner case: If the top items table has | ||||
| 			-- only items with rarity = 1, but max_items is set, then only the first | ||||
| 			-- max_items will be part of the drop, any later entries are logically | ||||
| 			-- impossible, so this variable is for keeping track of this | ||||
| 			local max_items_left = def.drop.max_items | ||||
| 			-- For checking whether we still encountered only guaranteed only so far; | ||||
| 			-- for the first “maybe” item it will become false which will cause ALL | ||||
| 			-- later items to be considered “maybes”. | ||||
| 			-- A common idiom is: | ||||
| 			-- { max_items 1, { items = { | ||||
| 			--	{ items={"example:1"}, rarity = 5 }, | ||||
| 			-- 	{ items={"example:2"}, rarity = 1 }, }}} | ||||
| 			-- example:2 must be considered a “maybe” because max_items is set and it | ||||
| 			-- appears after a “maybe” | ||||
| 			local max_start = true | ||||
| 			-- Let's iterate through the items madness! | ||||
| 			-- Handle invalid drop entries gracefully. | ||||
| 			local drop_items = def.drop.items or { } | ||||
| 			for i=1,#drop_items do | ||||
| 				if max_items_left ~= nil and max_items_left <= 0 then break end | ||||
| 				local itit = drop_items[i] | ||||
| 				for j=1,#itit.items do | ||||
| 					local dstack = ItemStack(itit.items[j]) | ||||
| 					if not dstack:is_empty() and dstack:get_name() ~= name then | ||||
| 						local dname = dstack:get_name() | ||||
| 						local dcount = dstack:get_count() | ||||
| 						-- Guaranteed drops AND we are not yet in “maybe mode” | ||||
| 						if #itit.items == 1 and itit.rarity == 1 and max_start then | ||||
| 							if drop_guaranteed[dname] == nil then | ||||
| 								drop_guaranteed[dname] = 0 | ||||
| 							end | ||||
| 							drop_guaranteed[dname] = drop_guaranteed[dname] + dcount | ||||
|  | ||||
| 							if max_items_left ~= nil then | ||||
| 								max_items_left = max_items_left - 1 | ||||
| 								if max_items_left <= 0 then break end | ||||
| 							end | ||||
| 						-- Drop was a “maybe” | ||||
| 						else | ||||
| 							if max_items_left ~= nil then max_start = false end | ||||
| 							if drop_maybe[dname] == nil then | ||||
| 								drop_maybe[dname] = 0 | ||||
| 							end | ||||
| 							drop_maybe[dname] = drop_maybe[dname] + dcount | ||||
| 						end | ||||
| 					end | ||||
| 				end | ||||
| 			end | ||||
| 			for itemstring, count in pairs(drop_guaranteed) do | ||||
| 				ui.register_craft({ | ||||
| 					type = "digging", | ||||
| 					items = {name}, | ||||
| 					output = itemstring .. " " .. count, | ||||
| 					width = 0, | ||||
| 				}) | ||||
| 			end | ||||
| 			for itemstring, count in pairs(drop_maybe) do | ||||
| 				ui.register_craft({ | ||||
| 					type = "digging_chance", | ||||
| 					items = {name}, | ||||
| 					output = itemstring .. " " .. count, | ||||
| 					width = 0, | ||||
| 				}) | ||||
| 			end | ||||
| 		end | ||||
| 	end | ||||
|  | ||||
| 	-- Step 1: Initialize cache for looking up groups | ||||
| 	unified_inventory.init_matching_cache() | ||||
|  | ||||
| 	-- Step 2: Find all matching items for the given spec (groups) | ||||
| 	local get_matching_spec_items = unified_inventory.get_matching_items | ||||
|  | ||||
| 	for outputitemname, recipes in pairs(ui.crafts_for.recipe) do | ||||
| 		-- List of crafts that return this item string (variable "_") | ||||
|  | ||||
| 		-- Problem: The group cache must be initialized after all mods finished loading | ||||
| 		-- thus, invalid recipes might be indexed. Hence perform filtering with `new_recipe_list` | ||||
| 		local new_recipe_list = {} | ||||
| 		for _, recipe in ipairs(recipes) do | ||||
| 			local ingredient_items = {} | ||||
| 			for _, spec in pairs(recipe.items) do | ||||
| 				-- Get items that fit into this spec (group or item name) | ||||
| 				local specname = ItemStack(spec):get_name() | ||||
| 				for item_name, _ in pairs(get_matching_spec_items(specname)) do | ||||
| 					ingredient_items[item_name] = true | ||||
| 				end | ||||
| 			end | ||||
| 			for name, _ in pairs(ingredient_items) do | ||||
| 				if not ui.crafts_for.usage[name] then | ||||
| 					ui.crafts_for.usage[name] = {} | ||||
| 				end | ||||
| 				table.insert(ui.crafts_for.usage[name], recipe) | ||||
| 			end | ||||
|  | ||||
| 			if next(ingredient_items) then | ||||
| 				-- There's at least one known ingredient: mark as good recipe | ||||
| 				-- PS: What whatll be done about partially incomplete recipes? | ||||
| 				table.insert(new_recipe_list, recipe) | ||||
| 			end | ||||
| 		end | ||||
| 		ui.crafts_for.recipe[outputitemname] = new_recipe_list | ||||
| 	end | ||||
|  | ||||
| 	for _, callback in ipairs(ui.initialized_callbacks) do | ||||
| 		callback() | ||||
| 	end | ||||
| 	table.sort(unified_inventory.items_list) | ||||
| 	unified_inventory.items_list_size = #unified_inventory.items_list | ||||
| 	print("Unified Inventory. inventory size: "..unified_inventory.items_list_size) | ||||
| end) | ||||
|  | ||||
| ---------------- Home API ---------------- | ||||
|  | ||||
| -- load_home | ||||
| local function load_home() | ||||
| 	local input = io.open(ui.home_filename, "r") | ||||
| 	if not input then | ||||
| 		ui.home_pos = {} | ||||
| 		return | ||||
| 	local input = io.open(unified_inventory.home_filename, "r") | ||||
| 	if input then | ||||
| 		while true do | ||||
| 			local x = input:read("*n") | ||||
| 			if x == nil then | ||||
| 				break | ||||
| 			end | ||||
| 			local y = input:read("*n") | ||||
| 			local z = input:read("*n") | ||||
| 			local name = input:read("*l") | ||||
| 			unified_inventory.home_pos[name:sub(2)] = {x = x, y = y, z = z} | ||||
| 		end | ||||
| 		io.close(input) | ||||
| 	else | ||||
| 		unified_inventory.home_pos = {} | ||||
| 	end | ||||
| 	while true do | ||||
| 		local x = input:read("*n") | ||||
| 		if not x then break end | ||||
| 		local y = input:read("*n") | ||||
| 		local z = input:read("*n") | ||||
| 		local name = input:read("*l") | ||||
| 		ui.home_pos[name:sub(2)] = {x = x, y = y, z = z} | ||||
| 	end | ||||
| 	io.close(input) | ||||
| end | ||||
|  | ||||
| load_home() | ||||
|  | ||||
| function ui.set_home(player, pos) | ||||
| function unified_inventory.set_home(player, pos) | ||||
| 	local player_name = player:get_player_name() | ||||
| 	ui.home_pos[player_name] = vector.round(pos) | ||||
|  | ||||
| 	unified_inventory.home_pos[player_name] = pos | ||||
| 	-- save the home data from the table to the file | ||||
| 	local output = io.open(ui.home_filename, "w") | ||||
| 	if not output then | ||||
| 		minetest.log("warning", "[unified_inventory] Failed to save file: " | ||||
| 			.. ui.home_filename) | ||||
| 		return | ||||
| 	end | ||||
| 	for k, v in pairs(ui.home_pos) do | ||||
| 		output:write(v.x.." "..v.y.." "..v.z.." "..k.."\n") | ||||
| 	local output = io.open(unified_inventory.home_filename, "w") | ||||
| 	for k, v in pairs(unified_inventory.home_pos) do | ||||
| 		if v ~= nil then | ||||
| 			output:write(math.floor(v.x).." " | ||||
| 					..math.floor(v.y).." " | ||||
| 					..math.floor(v.z).." " | ||||
| 					..k.."\n") | ||||
| 		end | ||||
| 	end | ||||
| 	io.close(output) | ||||
| end | ||||
|  | ||||
| function ui.go_home(player) | ||||
| 	local pos = ui.home_pos[player:get_player_name()] | ||||
| 	if pos then | ||||
| 		player:set_pos(pos) | ||||
| 		return true | ||||
| function unified_inventory.go_home(player) | ||||
| 	local pos = unified_inventory.home_pos[player:get_player_name()] | ||||
| 	if pos ~= nil then | ||||
| 		player:setpos(pos) | ||||
| 	end | ||||
| 	return false | ||||
| end | ||||
|  | ||||
| ---------------- Crafting API ---------------- | ||||
|  | ||||
| function ui.register_craft(options) | ||||
| 	if not options.output then | ||||
| -- register_craft | ||||
| function unified_inventory.register_craft(options) | ||||
| 	if  options.output == nil then | ||||
| 		return | ||||
| 	end | ||||
| 	local itemstack = ItemStack(options.output) | ||||
| 	if itemstack:is_empty() then | ||||
| 		return | ||||
| 	end | ||||
| 	if options.type == "normal" and options.width == 0 then | ||||
| 		options = { type = "shapeless", items = options.items, output = options.output, width = 0 } | ||||
| 	end | ||||
| 	local item_name = itemstack:get_name() | ||||
| 	if not ui.crafts_for.recipe[item_name] then | ||||
| 		ui.crafts_for.recipe[item_name] = {} | ||||
| 	end | ||||
| 	table.insert(ui.crafts_for.recipe[item_name],options) | ||||
|  | ||||
| 	for _, callback in ipairs(ui.craft_registered_callbacks) do | ||||
| 		callback(item_name, options) | ||||
| 	if unified_inventory.crafts_table[itemstack:get_name()] == nil then | ||||
| 		unified_inventory.crafts_table[itemstack:get_name()] = {} | ||||
| 	end | ||||
| 	table.insert(unified_inventory.crafts_table[itemstack:get_name()],options) | ||||
| end | ||||
|  | ||||
| local craft_type_defaults = { | ||||
| 	width = 3, | ||||
| 	height = 3, | ||||
| 	uses_crafting_grid = false, | ||||
| } | ||||
|  | ||||
| function ui.craft_type_defaults(name, options) | ||||
| 	if not options.description then | ||||
| 		options.description = name | ||||
| 	end | ||||
| 	setmetatable(options, {__index = craft_type_defaults}) | ||||
| 	return options | ||||
| function unified_inventory.register_page(name, def) | ||||
| 	unified_inventory.pages[name] = def | ||||
| end | ||||
|  | ||||
|  | ||||
| function ui.register_craft_type(name, options) | ||||
| 	ui.registered_craft_types[name] = ui.craft_type_defaults(name, options) | ||||
| end | ||||
|  | ||||
|  | ||||
| ui.register_craft_type("normal", { | ||||
| 	description = F(S("Crafting")), | ||||
| 	icon = "ui_craftgrid_icon.png", | ||||
| 	width = 3, | ||||
| 	height = 3, | ||||
| 	get_shaped_craft_width = function (craft) return craft.width end, | ||||
| 	dynamic_display_size = function (craft) | ||||
| 		local w = craft.width | ||||
| 		local h = math.ceil(table.maxn(craft.items) / craft.width) | ||||
| 		local g = w < h and h or w | ||||
| 		return { width = g, height = g } | ||||
| 	end, | ||||
| 	uses_crafting_grid = true, | ||||
| }) | ||||
|  | ||||
|  | ||||
| ui.register_craft_type("shapeless", { | ||||
| 	description = F(S("Mixing")), | ||||
| 	icon = "ui_craftgrid_icon.png", | ||||
| 	width = 3, | ||||
| 	height = 3, | ||||
| 	dynamic_display_size = function (craft) | ||||
| 		local maxn = table.maxn(craft.items) | ||||
| 		local g = 1 | ||||
| 		while g*g < maxn do g = g + 1 end | ||||
| 		return { width = g, height = g } | ||||
| 	end, | ||||
| 	uses_crafting_grid = true, | ||||
| }) | ||||
|  | ||||
|  | ||||
| ui.register_craft_type("cooking", { | ||||
| 	description = F(S("Cooking")), | ||||
| 	icon = "default_furnace_front.png", | ||||
| 	width = 1, | ||||
| 	height = 1, | ||||
| }) | ||||
|  | ||||
|  | ||||
| ui.register_craft_type("digging", { | ||||
| 	description = F(S("Digging")), | ||||
| 	icon = "default_tool_steelpick.png", | ||||
| 	width = 1, | ||||
| 	height = 1, | ||||
| }) | ||||
|  | ||||
| ui.register_craft_type("digging_chance", { | ||||
| 	description = "Digging (by chance)", | ||||
| 	icon = "default_tool_steelpick.png^[transformFY.png", | ||||
| 	width = 1, | ||||
| 	height = 1, | ||||
| }) | ||||
|  | ||||
| ---------------- GUI registrations ---------------- | ||||
|  | ||||
| function ui.register_page(name, def) | ||||
| 	ui.pages[name] = def | ||||
| end | ||||
|  | ||||
|  | ||||
| function ui.register_button(name, def) | ||||
| function unified_inventory.register_button(name, def) | ||||
| 	if not def.action then | ||||
| 		def.action = function(player) | ||||
| 			ui.set_inventory_formspec(player, name) | ||||
| 			unified_inventory.set_inventory_formspec(player, name) | ||||
| 		end | ||||
| 	end | ||||
| 	def.name = name | ||||
| 	table.insert(ui.buttons, def) | ||||
| 	table.insert(unified_inventory.buttons, def) | ||||
| end | ||||
|  | ||||
| ---------------- Callback registrations ---------------- | ||||
|  | ||||
| function ui.register_on_initialized(callback) | ||||
| 	if type(callback) ~= "function" then | ||||
| 		error(("Initialized callback must be a function, %s given."):format(type(callback))) | ||||
| function unified_inventory.is_creative(playername) | ||||
| 	if minetest.check_player_privs(playername, {creative=true}) or | ||||
| 	   minetest.setting_getbool("creative_mode") then | ||||
| 		return true | ||||
| 	end | ||||
| 	table.insert(ui.initialized_callbacks, callback) | ||||
| end | ||||
|  | ||||
| function ui.register_on_craft_registered(callback) | ||||
| 	if type(callback) ~= "function" then | ||||
| 		error(("Craft registered callback must be a function, %s given."):format(type(callback))) | ||||
| 	end | ||||
| 	table.insert(ui.craft_registered_callbacks, callback) | ||||
| end | ||||
|  | ||||
| ---------------- List getters ---------------- | ||||
|  | ||||
| function ui.get_recipe_list(output) | ||||
| 	return ui.crafts_for.recipe[output] | ||||
| end | ||||
|  | ||||
| function ui.get_registered_outputs() | ||||
| 	local outputs = {} | ||||
| 	for item_name, _ in pairs(ui.crafts_for.recipe) do | ||||
| 		table.insert(outputs, item_name) | ||||
| 	end | ||||
| 	return outputs | ||||
| end | ||||
|  | ||||
| ---------------- Player utilities ---------------- | ||||
|  | ||||
| function ui.is_creative(playername) | ||||
| 	return minetest.check_player_privs(playername, {creative=true}) | ||||
| 		or minetest.settings:get_bool("creative_mode") | ||||
| end | ||||
|  | ||||
| ---------------- Formspec helpers ---------------- | ||||
|  | ||||
| function ui.single_slot(xpos, ypos, bright) | ||||
| 	return string.format("background9[%f,%f;%f,%f;ui_single_slot%s.png;false;16]", | ||||
| 	xpos, ypos, ui.imgscale, ui.imgscale, (bright and "_bright" or "") ) | ||||
| end | ||||
|  | ||||
| function ui.make_trash_slot(xpos, ypos) | ||||
| 	return | ||||
| 		ui.single_slot(xpos, ypos).. | ||||
| 		"image["..xpos..","..ypos..";1.25,1.25;ui_trash_slot_icon.png]".. | ||||
| 		"list[detached:trash;main;"..(xpos + ui.list_img_offset)..","..(ypos + ui.list_img_offset)..";1,1;]" | ||||
| end | ||||
|  | ||||
| function ui.make_inv_img_grid(xpos, ypos, width, height, bright) | ||||
| 	local tiled = {} | ||||
| 	local n=1 | ||||
| 	for y = 0, (height - 1) do | ||||
| 		for x = 0, (width -1) do | ||||
| 			tiled[n] = ui.single_slot(xpos + (ui.imgscale * x), ypos + (ui.imgscale * y), bright) | ||||
| 			n = n + 1 | ||||
| 		end | ||||
| 	end | ||||
| 	return table.concat(tiled) | ||||
| end | ||||
|   | ||||
							
								
								
									
										327
									
								
								bags.lua
									
									
									
									
									
								
							
							
						
						| @@ -1,114 +1,49 @@ | ||||
| --[[ | ||||
| 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 = minetest.get_translator("unified_inventory") | ||||
| local F = minetest.formspec_escape | ||||
| local ui = unified_inventory | ||||
|  | ||||
| ui.register_page("bags", { | ||||
| 	get_formspec = function(player, perplayer_formspec) | ||||
| unified_inventory.register_page("bags", { | ||||
| 	get_formspec = function(player) | ||||
| 		local player_name = player:get_player_name() | ||||
| 		local std_inv_x = perplayer_formspec.std_inv_x | ||||
| 		local formspec = { | ||||
| 			perplayer_formspec.standard_inv_bg, | ||||
| 			"label[", perplayer_formspec.form_header_x, ",", | ||||
| 				perplayer_formspec.form_header_y, ";", F(S("Bags")), "]", | ||||
| 			"listcolors[#00000000;#00000000]", | ||||
| 		} | ||||
|  | ||||
| 		for i = 1, 4 do | ||||
| 			local x = std_inv_x + i * 2.5 | ||||
| 			formspec[#formspec + 1] = ui.single_slot(x - 1.875, 1.5) | ||||
| 			formspec[#formspec + 1] = string.format("list[detached:%s_bags;bag%i;%.3f,1.65;1,1;]", | ||||
| 				F(player_name), i, x - 1.725) | ||||
| 			formspec[#formspec + 1] = string.format("button[%.4f,2.75;1.875,0.75;bag%i;%s]", | ||||
| 				x - 2.1875, i, F(S("Bag @1", i))) | ||||
| 		end | ||||
|  | ||||
| 		return { formspec = table.concat(formspec) } | ||||
| 		local formspec = "background[0.06,0.99;7.92,7.52;ui_bags_main_form.png]" | ||||
| 		formspec = formspec.."image[0,0;1,1;ui_bags_icon.png]" | ||||
| 		formspec = formspec.."label[1,0;Bags]" | ||||
| 		formspec = formspec.."button[0,2;2,0.5;bag1;Bag 1]" | ||||
| 		formspec = formspec.."button[2,2;2,0.5;bag2;Bag 2]" | ||||
| 		formspec = formspec.."button[4,2;2,0.5;bag3;Bag 3]" | ||||
| 		formspec = formspec.."button[6,2;2,0.5;bag4;Bag 4]" | ||||
| 		formspec = formspec.."listcolors[#00000000;#00000000]" | ||||
| 		formspec = formspec.."list[detached:"..player_name.."_bags;bag1;0.5,1;1,1;]" | ||||
| 		formspec = formspec.."list[detached:"..player_name.."_bags;bag2;2.5,1;1,1;]" | ||||
| 		formspec = formspec.."list[detached:"..player_name.."_bags;bag3;4.5,1;1,1;]" | ||||
| 		formspec = formspec.."list[detached:"..player_name.."_bags;bag4;6.5,1;1,1;]" | ||||
| 		return {formspec=formspec} | ||||
| 	end, | ||||
| }) | ||||
|  | ||||
| ui.register_button("bags", { | ||||
| unified_inventory.register_button("bags", { | ||||
| 	type = "image", | ||||
| 	image = "ui_bags_icon.png", | ||||
| 	tooltip = S("Bags"), | ||||
| }) | ||||
|  | ||||
| local function get_player_bag_stack(player, i) | ||||
| 	return minetest.get_inventory({ | ||||
| 		type = "detached", | ||||
| 		name = player:get_player_name() .. "_bags" | ||||
| 	}):get_stack("bag" .. i, 1) | ||||
| end | ||||
|  | ||||
| for bag_i = 1, 4 do | ||||
| 	ui.register_page("bag" .. bag_i, { | ||||
| 		get_formspec = function(player, perplayer_formspec) | ||||
| 			local stack = get_player_bag_stack(player, bag_i) | ||||
| for i = 1, 4 do | ||||
| 	unified_inventory.register_page("bag"..i, { | ||||
| 		get_formspec = function(player) | ||||
| 			local stack = player:get_inventory():get_stack("bag"..i, 1) | ||||
| 			local image = stack:get_definition().inventory_image | ||||
| 			local formspec = "image[7,0;1,1;"..image.."]" | ||||
| 			formspec = formspec.."listcolors[#00000000;#00000000]" | ||||
| 			formspec = formspec.."list[current_player;bag"..i.."contents;0,1;8,3;]" | ||||
| 			local slots = stack:get_definition().groups.bagslots | ||||
| 			local std_inv_x = perplayer_formspec.std_inv_x | ||||
| 			local lite_mode = perplayer_formspec.is_lite_mode | ||||
|  | ||||
| 			local bag_inv_y, header_x, header_y = 1.5, 0.3, 0.65 | ||||
| 			if lite_mode then | ||||
| 				bag_inv_y = 0.5 | ||||
| 				header_x = perplayer_formspec.form_header_x | ||||
| 				header_y = perplayer_formspec.form_header_y | ||||
| 			if slots == 8 then | ||||
| 				formspec = formspec.."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]" | ||||
| 			elseif slots == 24 then | ||||
| 				formspec = formspec.."background[0.06,0.99;7.92,7.52;ui_bags_lg_form.png]" | ||||
| 			end | ||||
|  | ||||
| 			local formspec = { | ||||
| 				perplayer_formspec.standard_inv_bg, | ||||
| 				ui.make_inv_img_grid(std_inv_x, bag_inv_y, 8, slots/8), | ||||
| 				"label[", header_x, ",", header_y, ";", F(S("Bag @1", bag_i)), "]", | ||||
| 				"listcolors[#00000000;#00000000]", | ||||
| 				"listring[current_player;main]", | ||||
| 				string.format("list[current_player;bag%icontents;%f,%f;8,3;]", | ||||
| 				    bag_i, std_inv_x + ui.list_img_offset, bag_inv_y + ui.list_img_offset), | ||||
| 				"listring[current_name;bag", bag_i, "contents]", | ||||
| 			} | ||||
|  | ||||
| 			if lite_mode then | ||||
| 				return { formspec = table.concat(formspec) } | ||||
| 			end | ||||
|  | ||||
| 			local n = #formspec + 1 | ||||
| 			formspec[n] = "image[" .. std_inv_x + 8.9 .. ",0.4;1,1;" .. image .. "]" | ||||
| 			n = n + 1 | ||||
|  | ||||
| 			local player_name = player:get_player_name() -- For if statement. | ||||
| 			if ui.trash_enabled | ||||
| 				or ui.is_creative(player_name) | ||||
| 				or minetest.get_player_privs(player_name).give then | ||||
| 					formspec[n] = ui.make_trash_slot(7.8, 0.25) | ||||
| 					n = n + 1 | ||||
| 			end | ||||
| 			local inv = player:get_inventory() | ||||
| 			for i = 1, 4 do | ||||
| 				local def = get_player_bag_stack(player, i):get_definition() | ||||
| 				if def.groups.bagslots then | ||||
| 					local list_name = "bag" .. i .. "contents" | ||||
| 					local size = inv:get_size(list_name) | ||||
| 					local used = 0 | ||||
| 					for si = 1, size do | ||||
| 						local stk = inv:get_stack(list_name, si) | ||||
| 						if not stk:is_empty() then | ||||
| 							used = used + 1 | ||||
| 						end | ||||
| 					end | ||||
| 					local img = def.inventory_image | ||||
| 					local label = F(S("Bag @1", i)) .. "\n" .. used .. "/" .. size | ||||
| 					formspec[n] = string.format("image_button[%f,0.4;1,1;%s;bag%i;%s]", | ||||
| 							(i + 1.35)*1.25, img, i, label) | ||||
| 					n = n + 1 | ||||
| 				end | ||||
| 			end | ||||
| 			return { formspec = table.concat(formspec) } | ||||
| 			return {formspec=formspec} | ||||
| 		end, | ||||
| 	}) | ||||
| end | ||||
| @@ -118,182 +53,98 @@ minetest.register_on_player_receive_fields(function(player, formname, fields) | ||||
| 		return | ||||
| 	end | ||||
| 	for i = 1, 4 do | ||||
| 		if fields["bag" .. i] then | ||||
| 			local stack = get_player_bag_stack(player, i) | ||||
| 		if fields["bag"..i] then | ||||
| 			local stack = player:get_inventory():get_stack("bag"..i, 1) | ||||
| 			if not stack:get_definition().groups.bagslots then | ||||
| 				return | ||||
| 			end | ||||
| 			ui.set_inventory_formspec(player, "bag" .. i) | ||||
| 			unified_inventory.set_inventory_formspec(player, "bag"..i) | ||||
| 			return | ||||
| 		end | ||||
| 	end | ||||
| end) | ||||
|  | ||||
| -- Player slots are preserved when unified_inventory is disabled. Do not allow modification. | ||||
| -- Fix: use a detached inventory and store the data separately. | ||||
| local function save_bags_metadata(player, bags_inv) | ||||
| 	local is_empty = true | ||||
| 	local bags = {} | ||||
| 	for i = 1, 4 do | ||||
| 		local bag = "bag" .. i | ||||
| 		if not bags_inv:is_empty(bag) then | ||||
| 			-- Stack limit is 1, otherwise use stack:to_string() | ||||
| 			bags[i] = bags_inv:get_stack(bag, 1):get_name() | ||||
| 			is_empty = false | ||||
| 		end | ||||
| 	end | ||||
| 	local meta = player:get_meta() | ||||
| 	if is_empty then | ||||
| 		meta:set_string("unified_inventory:bags", nil) | ||||
| 	else | ||||
| 		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 meta = player:get_meta() | ||||
| 	local bags_meta = meta:get("unified_inventory:bags") | ||||
| 	local bags = bags_meta and minetest.deserialize(bags_meta) or {} | ||||
| 	local dirty_meta = false | ||||
| 	if not bags_meta then | ||||
| 		-- Backwards compatiblity | ||||
| 		for i = 1, 4 do | ||||
| 			local bag = "bag" .. i | ||||
| 			if not player_inv:is_empty(bag) then | ||||
| 				-- Stack limit is 1, otherwise use stack:to_string() | ||||
| 				bags[i] = player_inv:get_stack(bag, 1):get_name() | ||||
| 				dirty_meta = true | ||||
| 			end | ||||
| 		end | ||||
| 	end | ||||
| 	-- Fill detached slots | ||||
| 	for i = 1, 4 do | ||||
| 		local bag = "bag" .. i | ||||
| 		bags_inv:set_size(bag, 1) | ||||
| 		bags_inv:set_stack(bag, 1, bags[i] or "") | ||||
| 	end | ||||
|  | ||||
| 	if dirty_meta then | ||||
| 		-- Requires detached inventory to be set up | ||||
| 		save_bags_metadata(player, bags_inv) | ||||
| 	end | ||||
|  | ||||
| 	-- Legacy: Clean up old player lists | ||||
| 	for i = 1, 4 do | ||||
| 		local bag = "bag" .. i | ||||
| 		player_inv:set_size(bag, 0) | ||||
| 	end | ||||
| end | ||||
|  | ||||
| minetest.register_on_joinplayer(function(player) | ||||
| 	local player_name = player:get_player_name() | ||||
| 	local bags_inv = minetest.create_detached_inventory(player_name .. "_bags", { | ||||
| 		allow_put = function(inv, listname, index, stack, player) | ||||
| 			local new_slots = stack:get_definition().groups.bagslots | ||||
| 			if not new_slots then | ||||
| 				return 0 -- ItemStack is not a bag. | ||||
| 			end | ||||
|  | ||||
| 			-- The execution order of `allow_put`/`allow_take` is not defined. | ||||
| 			-- We do not know the replacement ItemStack if the items are swapped. | ||||
| 			-- Hence, bag slot upgrades and downgrades are not possible with the | ||||
| 			-- current API. | ||||
|  | ||||
| 			if not player:get_inventory():is_empty(listname .. "contents") then | ||||
| 				-- Legacy: in case `allow_take` is not executed on old Minetest versions. | ||||
| 				return 0 | ||||
| 			end | ||||
| 			return 1 | ||||
| 		end, | ||||
| 	local player_inv = player:get_inventory() | ||||
| 	local bags_inv = minetest.create_detached_inventory(player:get_player_name().."_bags",{ | ||||
| 		on_put = function(inv, listname, index, stack, player) | ||||
| 			player:get_inventory():set_size(listname .. "contents", | ||||
| 			player:get_inventory():set_stack(listname, index, stack) | ||||
| 			player:get_inventory():set_size(listname.."contents", | ||||
| 					stack:get_definition().groups.bagslots) | ||||
| 			save_bags_metadata(player, inv) | ||||
| 		end, | ||||
| 		allow_take = function(inv, listname, index, stack, player) | ||||
| 			if player:get_inventory():is_empty(listname .. "contents") then | ||||
| 				return stack:get_count() | ||||
| 			end | ||||
| 			return 0 | ||||
| 		end, | ||||
| 		on_take = function(inv, listname, index, stack, player) | ||||
| 			player:get_inventory():set_size(listname .. "contents", 0) | ||||
| 			save_bags_metadata(player, inv) | ||||
| 			if listname == ui.current_page[player:get_player_name()] then | ||||
| 				-- Bag is currently open: avoid follow-up issues by navigating back | ||||
| 				-- Trick: the list name is the same as the registered page name | ||||
| 				ui.set_inventory_formspec(player, "bags") | ||||
| 			player:get_inventory():set_stack(listname, index, nil) | ||||
| 		end, | ||||
| 		allow_put = function(inv, listname, index, stack, player) | ||||
| 			if stack:get_definition().groups.bagslots then | ||||
| 				return 1 | ||||
| 			else | ||||
| 				return 0 | ||||
| 			end | ||||
| 		end, | ||||
| 		allow_move = function() | ||||
| 		allow_take = function(inv, listname, index, stack, player) | ||||
| 			if player:get_inventory():is_empty(listname.."contents") then | ||||
| 				return stack:get_count() | ||||
| 			else | ||||
| 				return 0 | ||||
| 			end | ||||
| 		end, | ||||
| 		allow_move = function(inv, from_list, from_index, to_list, to_index, count, player) | ||||
| 			return 0 | ||||
| 		end, | ||||
| 	}, player_name) | ||||
|  | ||||
| 	load_bags_metadata(player, bags_inv) | ||||
| end) | ||||
|  | ||||
|  | ||||
| minetest.register_allow_player_inventory_action(function(player, action, inventory, info) | ||||
| 	-- From detached inventory -> player inventory: put & take callbacks | ||||
| 	if action ~= "put" or not info.listname:find("bag%dcontents") then | ||||
| 		return | ||||
| 	end | ||||
| 	if info.stack:get_definition().groups.bagslots then | ||||
| 		-- Problem 1: empty bags could be moved into their own slots | ||||
| 		-- Problem 2: cannot reliably keep track of ItemStack ownership due to | ||||
| 		--> Disallow all external bag movements into this list | ||||
| 		return 0 | ||||
| 	}) | ||||
| 	for i=1,4 do | ||||
| 		local bag = "bag"..i | ||||
| 		player_inv:set_size(bag, 1) | ||||
| 		bags_inv:set_size(bag, 1) | ||||
| 		bags_inv:set_stack(bag, 1, player_inv:get_stack(bag, 1)) | ||||
| 	end | ||||
| end) | ||||
|  | ||||
| -- register bag tools | ||||
| minetest.register_tool("unified_inventory:bag_small", { | ||||
| 	description = S("Small Bag"), | ||||
| 	description = "Small Bag", | ||||
| 	inventory_image = "bags_small.png", | ||||
| 	groups = {bagslots=8}, | ||||
| }) | ||||
|  | ||||
| minetest.register_tool("unified_inventory:bag_medium", { | ||||
| 	description = S("Medium Bag"), | ||||
| 	description = "Medium Bag", | ||||
| 	inventory_image = "bags_medium.png", | ||||
| 	groups = {bagslots=16}, | ||||
| }) | ||||
|  | ||||
| minetest.register_tool("unified_inventory:bag_large", { | ||||
| 	description = S("Large Bag"), | ||||
| 	description = "Large Bag", | ||||
| 	inventory_image = "bags_large.png", | ||||
| 	groups = {bagslots=24}, | ||||
| }) | ||||
|  | ||||
| -- register bag crafts | ||||
| if minetest.get_modpath("farming") ~= nil then | ||||
| 	minetest.register_craft({ | ||||
| 		output = "unified_inventory:bag_small", | ||||
| 		recipe = { | ||||
| 			{"",           "farming:string", ""}, | ||||
| 			{"group:wool", "group:wool",     "group:wool"}, | ||||
| 			{"group:wool", "group:wool",     "group:wool"}, | ||||
| 		}, | ||||
| 	}) | ||||
| minetest.register_craft({ | ||||
| 	output = "unified_inventory:bag_small", | ||||
| 	recipe = { | ||||
| 		{"",           "default:stick", ""}, | ||||
| 		{"group:wood", "group:wood",    "group:wood"}, | ||||
| 		{"group:wood", "group:wood",    "group:wood"}, | ||||
| 	}, | ||||
| }) | ||||
|  | ||||
| 	minetest.register_craft({ | ||||
| 		output = "unified_inventory:bag_medium", | ||||
| 		recipe = { | ||||
| 			{"",               "",                            ""}, | ||||
| 			{"farming:string", "unified_inventory:bag_small", "farming:string"}, | ||||
| 			{"farming:string", "unified_inventory:bag_small", "farming:string"}, | ||||
| 		}, | ||||
| 	}) | ||||
| minetest.register_craft({ | ||||
| 	output = "unified_inventory:bag_medium", | ||||
| 	recipe = { | ||||
| 		{"",              "",                            ""}, | ||||
| 		{"default:stick", "unified_inventory:bag_small", "default:stick"}, | ||||
| 		{"default:stick", "unified_inventory:bag_small", "default:stick"}, | ||||
| 	}, | ||||
| }) | ||||
|  | ||||
| minetest.register_craft({ | ||||
| 	output = "unified_inventory:bag_large", | ||||
| 	recipe = { | ||||
| 		{"",              "",                             ""}, | ||||
| 		{"default:stick", "unified_inventory:bag_medium", "default:stick"}, | ||||
| 		{"default:stick", "unified_inventory:bag_medium", "default:stick"}, | ||||
|     }, | ||||
| }) | ||||
|  | ||||
| 	minetest.register_craft({ | ||||
| 		output = "unified_inventory:bag_large", | ||||
| 		recipe = { | ||||
| 			{"",               "",                             ""}, | ||||
| 			{"farming:string", "unified_inventory:bag_medium", "farming:string"}, | ||||
| 			{"farming:string", "unified_inventory:bag_medium", "farming:string"}, | ||||
| 	    }, | ||||
| 	}) | ||||
| end | ||||
|   | ||||
							
								
								
									
										252
									
								
								callbacks.lua
									
									
									
									
									
								
							
							
						
						| @@ -1,34 +1,36 @@ | ||||
| local ui = unified_inventory | ||||
|  | ||||
| local function default_refill(stack) | ||||
| 	stack:set_count(stack:get_stack_max()) | ||||
| 	local itemdef = minetest.registered_items[stack:get_name()] | ||||
| 	if itemdef | ||||
| 	and (itemdef.wear_represents or "mechanical_wear") == "mechanical_wear" | ||||
| 	and stack:get_wear() ~= 0 then | ||||
| 		stack:set_wear(0) | ||||
| 	end | ||||
| 	return stack | ||||
| end | ||||
|  | ||||
| minetest.register_on_joinplayer(function(player) | ||||
| 	local player_name = player:get_player_name() | ||||
| 	unified_inventory.players[player_name] = {} | ||||
| 	unified_inventory.current_index[player_name] = 1 -- Item (~page) index | ||||
| 	unified_inventory.current_index[player_name] = 1 | ||||
| 	unified_inventory.filtered_items_list[player_name] = | ||||
| 		unified_inventory.items_list | ||||
| 			unified_inventory.items_list | ||||
| 	unified_inventory.activefilter[player_name] = "" | ||||
| 	unified_inventory.active_search_direction[player_name] = "nochange" | ||||
| 	unified_inventory.current_searchbox[player_name] = "" | ||||
| 	unified_inventory.current_category[player_name] = "all" | ||||
| 	unified_inventory.current_category_scroll[player_name] = 0 | ||||
| 	unified_inventory.apply_filter(player, "") | ||||
| 	unified_inventory.alternate[player_name] = 1 | ||||
| 	unified_inventory.current_item[player_name] = nil | ||||
| 	unified_inventory.current_craft_direction[player_name] = "recipe" | ||||
| 	unified_inventory.set_inventory_formspec(player, | ||||
| 			unified_inventory.default) | ||||
|  | ||||
| 	-- Crafting guide inventories | ||||
| 	local inv = minetest.create_detached_inventory(player_name.."craftrecipe", { | ||||
| 		allow_put = function(inv, listname, index, stack, player) | ||||
| 			return 0 | ||||
| 		end, | ||||
| 		allow_take = function(inv, listname, index, stack, player) | ||||
| 			return 0 | ||||
| 		end, | ||||
| 		allow_move = function(inv, from_list, from_index, to_list, | ||||
| 				to_index, count, player) | ||||
| 			return 0 | ||||
| 		end, | ||||
| 	}) | ||||
| 	inv:set_size("output", 1) | ||||
|  | ||||
| 	-- Refill slot | ||||
| 	local refill = minetest.create_detached_inventory(player_name.."refill", { | ||||
| 		allow_put = function(inv, listname, index, stack, player) | ||||
| 			local player_name = player:get_player_name() | ||||
| 			if unified_inventory.is_creative(player_name) then | ||||
| 				return stack:get_count() | ||||
| 			else | ||||
| @@ -36,102 +38,26 @@ minetest.register_on_joinplayer(function(player) | ||||
| 			end | ||||
| 		end, | ||||
| 		on_put = function(inv, listname, index, stack, player) | ||||
| 			local handle_refill = (minetest.registered_items[stack:get_name()] or {}).on_refill or default_refill | ||||
| 			stack = handle_refill(stack) | ||||
| 			local player_name = player:get_player_name() | ||||
| 			stack:set_count(stack:get_stack_max()) | ||||
| 			inv:set_stack(listname, index, stack) | ||||
| 			minetest.sound_play("electricity", | ||||
| 					{to_player=player_name, gain = 1.0}) | ||||
| 		end, | ||||
| 	}, player_name) | ||||
| 	}) | ||||
| 	refill:set_size("main", 1) | ||||
| end) | ||||
|  | ||||
| minetest.register_on_mods_loaded(function() | ||||
|        minetest.register_on_joinplayer(function(player) | ||||
|                -- After everything is initialized, set up the formspec | ||||
|                ui.apply_filter(player, "", "nochange") | ||||
|                ui.set_inventory_formspec(player, unified_inventory.default) | ||||
|        end) | ||||
| end) | ||||
|  | ||||
| local function apply_new_filter(player, search_text, new_dir) | ||||
| 	local player_name = player:get_player_name() | ||||
|  | ||||
| 	minetest.sound_play("ui_click", {to_player=player_name, gain = 0.1}) | ||||
| 	ui.apply_filter(player, search_text, new_dir) | ||||
| 	ui.current_searchbox[player_name] = search_text | ||||
| 	ui.set_inventory_formspec(player, ui.current_page[player_name]) | ||||
| end | ||||
|  | ||||
| -- Search box handling | ||||
| local function receive_fields_searchbox(player, formname, fields) | ||||
| 	local player_name = player:get_player_name() | ||||
|  | ||||
| 	-- always take new search text, even if not searching on it yet | ||||
| 	if fields.searchbox and fields.searchbox ~= ui.current_searchbox[player_name] then | ||||
| 		ui.current_searchbox[player_name] = fields.searchbox | ||||
| 	end | ||||
|  | ||||
| 	if fields.searchbutton | ||||
| 			or fields.key_enter_field == "searchbox" then | ||||
|  | ||||
| 		if ui.current_searchbox[player_name] ~= ui.activefilter[player_name] then | ||||
| 			ui.apply_filter(player, ui.current_searchbox[player_name], "nochange") | ||||
| 			ui.set_inventory_formspec(player, ui.current_page[player_name]) | ||||
| 			minetest.sound_play("paperflip2", | ||||
| 					{to_player=player_name, gain = 1.0}) | ||||
| 		end | ||||
| 	elseif fields.searchresetbutton then | ||||
| 		if ui.activefilter[player_name] ~= "" then | ||||
| 			apply_new_filter(player, "", "nochange") | ||||
| 		end | ||||
| 	end | ||||
| end | ||||
|  | ||||
| minetest.register_on_player_receive_fields(function(player, formname, fields) | ||||
| 	if formname ~= "" then | ||||
| 		return | ||||
| 	end | ||||
|  | ||||
| 	receive_fields_searchbox(player, formname, fields) | ||||
|  | ||||
| 	local player_name = player:get_player_name() | ||||
|  | ||||
| 	local ui_peruser,draw_lite_mode = unified_inventory.get_per_player_formspec(player_name) | ||||
|  | ||||
| 	local clicked_category | ||||
| 	for name, value in pairs(fields) do | ||||
| 		local category_name = string.match(name, "^category_(.+)$") | ||||
| 		if category_name then | ||||
| 			clicked_category = category_name | ||||
| 			break | ||||
| 		end | ||||
| 	end | ||||
|  | ||||
| 	if clicked_category | ||||
| 	and clicked_category ~= unified_inventory.current_category[player_name] then | ||||
| 		unified_inventory.current_category[player_name] = clicked_category | ||||
| 		unified_inventory.apply_filter(player, unified_inventory.current_searchbox[player_name], "nochange") | ||||
| 		unified_inventory.set_inventory_formspec(player, | ||||
| 				unified_inventory.current_page[player_name]) | ||||
| 	end | ||||
|  | ||||
| 	if fields.next_category or fields.prev_category then | ||||
| 		local step = fields.next_category and 1 or -1 | ||||
| 		local scroll_old = ui.current_category_scroll[player_name] | ||||
| 		local scroll_new = math.max(0, math.min(#ui.category_list - ui_peruser.pagecols, scroll_old + step)) | ||||
|  | ||||
| 		if scroll_old ~= scroll_new then | ||||
| 			ui.current_category_scroll[player_name] = scroll_new | ||||
| 			ui.set_inventory_formspec(player, | ||||
| 					unified_inventory.current_page[player_name]) | ||||
| 		end | ||||
| 	end | ||||
|  | ||||
| 	for i, def in pairs(unified_inventory.buttons) do | ||||
| 		if fields[def.name] then | ||||
| 			def.action(player) | ||||
| 			minetest.sound_play("ui_click", | ||||
| 			minetest.sound_play("click", | ||||
| 					{to_player=player_name, gain = 0.1}) | ||||
| 			return | ||||
| 		end | ||||
| @@ -139,28 +65,40 @@ minetest.register_on_player_receive_fields(function(player, formname, fields) | ||||
|  | ||||
| 	-- Inventory page controls | ||||
| 	local start = math.floor( | ||||
| 		unified_inventory.current_index[player_name] / ui_peruser.items_per_page + 1) | ||||
| 		unified_inventory.current_index[player_name] / 80 + 1) | ||||
| 	local start_i = start | ||||
| 	local pagemax = math.floor( | ||||
| 		(#unified_inventory.filtered_items_list[player_name] - 1) | ||||
| 		/ (ui_peruser.items_per_page) + 1) | ||||
| 		/ (80) + 1) | ||||
|  | ||||
| 	if fields.start_list then | ||||
| 		minetest.sound_play("paperflip1", | ||||
| 				{to_player=player_name, gain = 1.0}) | ||||
| 		start_i = 1 | ||||
| 	end | ||||
| 	if fields.rewind1 then | ||||
| 		minetest.sound_play("paperflip1", | ||||
| 				{to_player=player_name, gain = 1.0}) | ||||
| 		start_i = start_i - 1 | ||||
| 	end | ||||
| 	if fields.forward1 then | ||||
| 		minetest.sound_play("paperflip1", | ||||
| 				{to_player=player_name, gain = 1.0}) | ||||
| 		start_i = start_i + 1 | ||||
| 	end | ||||
| 	if fields.rewind3 then | ||||
| 		minetest.sound_play("paperflip1", | ||||
| 				{to_player=player_name, gain = 1.0}) | ||||
| 		start_i = start_i - 3 | ||||
| 	end | ||||
| 	if fields.forward3 then | ||||
| 		minetest.sound_play("paperflip1", | ||||
| 				{to_player=player_name, gain = 1.0}) | ||||
| 		start_i = start_i + 3 | ||||
| 	end | ||||
| 	if fields.end_list then | ||||
| 		minetest.sound_play("paperflip1", | ||||
| 				{to_player=player_name, gain = 1.0}) | ||||
| 		start_i = pagemax | ||||
| 	end | ||||
| 	if start_i < 1 then | ||||
| @@ -169,92 +107,78 @@ minetest.register_on_player_receive_fields(function(player, formname, fields) | ||||
| 	if start_i > pagemax then | ||||
| 		start_i = pagemax | ||||
| 	end | ||||
| 	if start_i ~= start then | ||||
| 		minetest.sound_play("paperflip1", | ||||
| 				{to_player=player_name, gain = 1.0}) | ||||
| 		unified_inventory.current_index[player_name] = (start_i - 1) * ui_peruser.items_per_page + 1 | ||||
| 	if not (start_i	== start) then | ||||
| 		unified_inventory.current_index[player_name] = (start_i - 1) * 80 + 1 | ||||
| 		unified_inventory.set_inventory_formspec(player, | ||||
| 				unified_inventory.current_page[player_name]) | ||||
| 	end | ||||
|  | ||||
| 	-- Check clicked item image button | ||||
| 	local clicked_item | ||||
| 	local clicked_item = nil | ||||
| 	for name, value in pairs(fields) do | ||||
| 		local new_dir, mangled_item = string.match(name, "^[0-9]*_?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 | ||||
| 				-- Change search filter to this group | ||||
| 				unified_inventory.current_category[player_name] = "all" | ||||
| 				apply_new_filter(player, clicked_item, new_dir) | ||||
| 				return | ||||
| 			end | ||||
| 			if new_dir == "recipe" or new_dir == "usage" then | ||||
| 				unified_inventory.current_craft_direction[player_name] = new_dir | ||||
| 			end | ||||
| 		if string.sub(name, 1, 12) == "item_button_" then | ||||
| 			clicked_item = string.sub(name, 13) | ||||
| 			break | ||||
| 		elseif string.sub(name, 1, 11) == "item_group_" then | ||||
| 			minetest.sound_play("click", | ||||
| 					{to_player=player_name, gain = 0.1}) | ||||
| 			unified_inventory.apply_filter(player, "group:"..string.sub(name, 12)) | ||||
| 			return | ||||
| 		end | ||||
| 	end | ||||
| 	if clicked_item then | ||||
| 		minetest.sound_play("ui_click", | ||||
| 		minetest.sound_play("click", | ||||
| 				{to_player=player_name, gain = 0.1}) | ||||
| 		local page = unified_inventory.current_page[player_name] | ||||
| 		local player_creative = unified_inventory.is_creative(player_name) | ||||
| 		if not player_creative then | ||||
| 		if not unified_inventory.is_creative(player_name) then | ||||
| 			page = "craftguide" | ||||
| 		end | ||||
| 		if page == "craftguide" then | ||||
| 			unified_inventory.current_item[player_name] = clicked_item | ||||
| 			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()) | ||||
| 			if inv:room_for_item("main", stack) then | ||||
| 				inv:add_item("main", stack) | ||||
| 			unified_inventory.set_inventory_formspec(player, | ||||
| 					"craftguide") | ||||
| 		else | ||||
| 			if unified_inventory.is_creative(player_name) then | ||||
| 				local inv = player:get_inventory() | ||||
| 				local stack = ItemStack(clicked_item) | ||||
| 				stack:set_count(stack:get_stack_max()) | ||||
| 				if inv:room_for_item("main", stack) then | ||||
| 					inv:add_item("main", stack) | ||||
| 				end | ||||
| 			end | ||||
| 		end | ||||
| 	end | ||||
|  | ||||
| 	-- alternate buttons | ||||
| 	if not (fields.alternate or fields.alternate_prev) then | ||||
| 		return | ||||
| 	if fields.searchbutton then | ||||
| 		unified_inventory.apply_filter(player, fields.searchbox) | ||||
| 		unified_inventory.set_inventory_formspec(player, | ||||
| 				unified_inventory.current_page[player_name]) | ||||
| 		minetest.sound_play("paperflip2", | ||||
| 				{to_player=player_name, gain = 1.0}) | ||||
| 	end | ||||
| 	minetest.sound_play("ui_click", | ||||
| 			{to_player=player_name, gain = 0.1}) | ||||
| 	local item_name = unified_inventory.current_item[player_name] | ||||
| 	if not item_name then | ||||
| 		return | ||||
| 	end | ||||
| 	local crafts = unified_inventory.crafts_for[unified_inventory.current_craft_direction[player_name]][item_name] | ||||
| 	if not crafts then | ||||
| 		return | ||||
| 	end | ||||
| 	local alternates = #crafts | ||||
| 	if alternates <= 1 then | ||||
| 		return | ||||
| 	end | ||||
| 	local alternate | ||||
|  | ||||
| 	-- alternate button | ||||
| 	if fields.alternate then | ||||
| 		alternate = unified_inventory.alternate[player_name] + 1 | ||||
| 		if alternate > alternates then | ||||
| 			alternate = 1 | ||||
| 		end | ||||
| 	elseif fields.alternate_prev then | ||||
| 		alternate = unified_inventory.alternate[player_name] - 1 | ||||
| 		if alternate < 1 then | ||||
| 			alternate = alternates | ||||
| 		minetest.sound_play("click", | ||||
| 				{to_player=player_name, gain = 0.1}) | ||||
| 		local item_name = unified_inventory.current_item[player_name] | ||||
| 		if item_name then | ||||
| 			local alternates = 0 | ||||
| 			local alternate = unified_inventory.alternate[player_name] | ||||
| 			local crafts = unified_inventory.crafts_table[item_name] | ||||
| 			if crafts ~= nil then | ||||
| 				alternates = #crafts | ||||
| 			end | ||||
| 			if alternates > 1 then | ||||
| 				alternate = alternate + 1 | ||||
| 				if alternate > alternates then | ||||
| 					alternate = 1 | ||||
| 				end | ||||
| 				unified_inventory.alternate[player_name] = alternate | ||||
| 				unified_inventory.set_inventory_formspec(player, | ||||
| 						unified_inventory.current_page[player_name]) | ||||
| 			end | ||||
| 		end | ||||
| 	end | ||||
| 	unified_inventory.alternate[player_name] = alternate | ||||
| 	unified_inventory.set_inventory_formspec(player, | ||||
| 			unified_inventory.current_page[player_name]) | ||||
| end) | ||||
|  | ||||
| minetest.register_on_leaveplayer(function(player) | ||||
| 	local player_name = player:get_player_name() | ||||
| 	minetest.remove_detached_inventory(player_name.."_bags") | ||||
| 	minetest.remove_detached_inventory(player_name.."refill") | ||||
| end) | ||||
|   | ||||
							
								
								
									
										153
									
								
								category.lua
									
									
									
									
									
								
							
							
						
						| @@ -1,153 +0,0 @@ | ||||
| local S = minetest.get_translator("unified_inventory") | ||||
|  | ||||
| unified_inventory.registered_categories = {} | ||||
| unified_inventory.registered_category_items = {} | ||||
| unified_inventory.category_list = {} | ||||
|  | ||||
| local function char_to_sort_index(char_code) | ||||
| 	if char_code <= 32 then | ||||
| 		-- Command codes, no thanks | ||||
| 		return 0 | ||||
| 	end | ||||
| 	if char_code <= 64 then | ||||
| 		-- Sorts numbers, and some punctuation, after letters | ||||
| 		return char_code | ||||
| 	end | ||||
| 	if char_code >= 158 then | ||||
| 		-- Out of sortable range | ||||
| 		return 0 | ||||
| 	end | ||||
| 	if char_code > 122 then | ||||
| 		-- Avoids overlap with {, |, } and ~ | ||||
| 		return char_code - 58 | ||||
| 	end | ||||
| 	if char_code > 96 then | ||||
| 		-- Normalises lowercase with uppercase | ||||
| 		return char_code - 96 | ||||
| 	end | ||||
| 	return char_code - 64 | ||||
| end | ||||
|  | ||||
| local function string_to_sort_index(str) | ||||
| 	local max_chars = 5 | ||||
| 	local power = 100 | ||||
| 	local index = 0 | ||||
| 	for i=1,math.min(#str, max_chars) do | ||||
| 		index = index + (char_to_sort_index(string.byte(str, i))/(power^i)) | ||||
| 	end | ||||
| 	return index | ||||
| end | ||||
|  | ||||
| function update_category_list() | ||||
| 	local category_list = {} | ||||
| 	table.insert(category_list, { | ||||
| 		name = "all", | ||||
| 		label = S("All Items"), | ||||
| 		symbol = "ui_category_all.png", | ||||
| 		index = -2, | ||||
| 	}) | ||||
| 	table.insert(category_list, { | ||||
| 		name = "uncategorized", | ||||
| 		label = S("Misc. Items"), | ||||
| 		symbol = "ui_category_none.png", | ||||
| 		index = -1, | ||||
| 	}) | ||||
| 	for category, def in pairs(unified_inventory.registered_categories) do | ||||
| 		table.insert(category_list, { | ||||
| 			name = category, | ||||
| 			label = def.label or category, | ||||
| 			symbol = def.symbol, | ||||
| 			index = def.index or                    -- sortby defined order | ||||
| 					string_to_sort_index(category)  -- or do a rudimentary alphabetical sort | ||||
| 		}) | ||||
| 	end | ||||
| 	table.sort(category_list, function (a,b) | ||||
| 		return a.index < b.index | ||||
| 	end) | ||||
| 	unified_inventory.category_list = category_list | ||||
| end | ||||
|  | ||||
| local function ensure_category_exists(category_name) | ||||
| 	if not unified_inventory.registered_categories[category_name] then | ||||
| 		unified_inventory.registered_categories[category_name] = { | ||||
| 			symbol = "unknown_item.png", | ||||
| 			label = category_name | ||||
| 		} | ||||
| 	end | ||||
| 	if not unified_inventory.registered_category_items[category_name] then | ||||
| 		unified_inventory.registered_category_items[category_name] = {} | ||||
| 	end | ||||
| end | ||||
|  | ||||
| function unified_inventory.register_category(category_name, config) | ||||
| 	ensure_category_exists(category_name) | ||||
| 	config = config or {} | ||||
| 	if config.symbol then | ||||
| 		unified_inventory.set_category_symbol(category_name, config.symbol) | ||||
| 	end | ||||
| 	if config.label then | ||||
| 		unified_inventory.set_category_label(category_name, config.label) | ||||
| 	end | ||||
| 	if config.index then | ||||
| 		unified_inventory.set_category_index(category_name, config.index) | ||||
| 	end | ||||
| 	if config.items then | ||||
| 		unified_inventory.add_category_items(category_name, config.items) | ||||
| 	end | ||||
| 	update_category_list() | ||||
| end | ||||
|  | ||||
| -- TODO: Mark these for removal. They are pretty much useless | ||||
|  | ||||
| function unified_inventory.set_category_symbol(category_name, symbol) | ||||
| 	ensure_category_exists(category_name) | ||||
| 	unified_inventory.registered_categories[category_name].symbol = symbol | ||||
| 	update_category_list() | ||||
| end | ||||
| function unified_inventory.set_category_label(category_name, label) | ||||
| 	ensure_category_exists(category_name) | ||||
| 	unified_inventory.registered_categories[category_name].label = label | ||||
| 	update_category_list() | ||||
| end | ||||
| function unified_inventory.set_category_index(category_name, index) | ||||
| 	ensure_category_exists(category_name) | ||||
| 	unified_inventory.registered_categories[category_name].index = index | ||||
| 	update_category_list() | ||||
| end | ||||
| function unified_inventory.add_category_item(category_name, item) | ||||
| 	ensure_category_exists(category_name) | ||||
| 	unified_inventory.registered_category_items[category_name][item] = true | ||||
| end | ||||
| function unified_inventory.add_category_items(category_name, items) | ||||
| 	for _,item in ipairs(items) do | ||||
| 		unified_inventory.add_category_item(category_name, item) | ||||
| 	end | ||||
| end | ||||
|  | ||||
| function unified_inventory.remove_category_item(category_name, item) | ||||
| 	unified_inventory.registered_category_items[category_name][item] = nil | ||||
| end | ||||
| function unified_inventory.remove_category(category_name) | ||||
| 	unified_inventory.registered_categories[category_name] = nil | ||||
| 	unified_inventory.registered_category_items[category_name] = nil | ||||
| 	update_category_list() | ||||
| end | ||||
|  | ||||
| function unified_inventory.find_category(item) | ||||
| 	-- Returns the first category the item exists in | ||||
| 	-- Best for checking if an item has any category at all | ||||
| 	for category, items in pairs(unified_inventory.registered_category_items) do | ||||
| 		if items[item] then return category end | ||||
| 	end | ||||
| end | ||||
| function unified_inventory.find_categories(item) | ||||
| 	-- Returns all the categories the item exists in | ||||
| 	-- Best for listing all categories | ||||
| 	local categories = {} | ||||
| 	for category, items in pairs(unified_inventory.registered_category_items) do | ||||
| 		if items[item] then | ||||
| 			table.insert(categories, category) | ||||
| 		end | ||||
| 	end | ||||
| 	return categories | ||||
| end | ||||
							
								
								
									
										83
									
								
								datastorage.lua
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,83 @@ | ||||
| datastorage={} | ||||
| datastorage["!registered_players"]={} | ||||
|  | ||||
| datastorage.save_data = function(table_pointer) | ||||
| 	local data = minetest.serialize( datastorage[table_pointer] ) | ||||
| 	local path = minetest.get_worldpath().."/datastorage_"..table_pointer..".data" | ||||
| 	local file = io.open( path, "w" ) | ||||
| 	if( file ) then | ||||
| 		file:write( data ) | ||||
| 		file:close() | ||||
| 		return true | ||||
| 	else return nil | ||||
| 	end | ||||
| end | ||||
|  | ||||
| datastorage.load_data = function(table_pointer) | ||||
| 	local path = minetest.get_worldpath().."/datastorage_"..table_pointer..".data" | ||||
| 	local file = io.open( path, "r" ) | ||||
| 	if( file ) then | ||||
| 		local data = file:read("*all") | ||||
| 		datastorage[table_pointer] = minetest.deserialize( data ) | ||||
| 		file:close() | ||||
| 	return true | ||||
| 	else return nil | ||||
| 	end | ||||
| end | ||||
|  | ||||
| datastorage.get_container = function (player, key) | ||||
| 	local player_name = player:get_player_name() | ||||
| 	local container = datastorage[player_name] | ||||
| 	if container[key] == nil then | ||||
| 		container[key] = {} | ||||
| 	end | ||||
| 	datastorage.save_data(player_name) | ||||
| 	return container[key] | ||||
| end | ||||
|  | ||||
| -- forced save of all player's data | ||||
| datastorage.save_container = function (player) | ||||
| 	local player_name = player:get_player_name() | ||||
| 	datastorage.save_data(player_name) | ||||
| end | ||||
|  | ||||
|  | ||||
| -- Init | ||||
| if datastorage.load_data("!registered_players") == nil then | ||||
| 	datastorage["!registered_players"]={} | ||||
| 	datastorage.save_data("!registered_players") | ||||
| end | ||||
|  | ||||
| minetest.register_on_joinplayer(function(player) | ||||
| 	local player_name = player:get_player_name() | ||||
| 	local registered = nil | ||||
| 	for __,tab in ipairs(datastorage["!registered_players"]) do | ||||
| 		if tab["player_name"] == player_name then registered = true break end | ||||
| 	end | ||||
| 	if registered == nil then | ||||
| 		local new={} | ||||
| 		new["player_name"]=player_name | ||||
| 		table.insert(datastorage["!registered_players"],new) | ||||
| 		datastorage[player_name]={} | ||||
| 		datastorage.save_data("!registered_players") | ||||
| 		datastorage.save_data(player_name) | ||||
| 	else  | ||||
| 		datastorage.load_data(player_name) | ||||
| 	end | ||||
| end | ||||
| ) | ||||
|  | ||||
| minetest.register_on_leaveplayer(function(player) | ||||
| 	local player_name = player:get_player_name() | ||||
| 	datastorage.save_data(player_name) | ||||
| 	datastorage[player_name] = nil | ||||
| end | ||||
| ) | ||||
|  | ||||
| minetest.register_on_shutdown(function() | ||||
| 	for __,tab in ipairs(datastorage["!registered_players"]) do | ||||
| 		if datastorage[tab["player_name"]] == nil then break end | ||||
| 		datastorage.save_data(tab["player_name"])  | ||||
| 	end | ||||
| end | ||||
| ) | ||||
| @@ -1,704 +0,0 @@ | ||||
| local S = minetest.get_translator("unified_inventory") | ||||
|  | ||||
| unified_inventory.register_category('plants', { | ||||
| 	symbol = "flowers:tulip", | ||||
| 	label = S("Plant Life") | ||||
| }) | ||||
| unified_inventory.register_category('building', { | ||||
| 	symbol = "default:brick", | ||||
| 	label = S("Building Materials") | ||||
| }) | ||||
| unified_inventory.register_category('tools', { | ||||
| 	symbol = "default:pick_diamond", | ||||
| 	label = S("Tools") | ||||
| }) | ||||
| unified_inventory.register_category('minerals', { | ||||
| 	symbol = "default:iron_lump", | ||||
| 	label = S("Minerals and Metals") | ||||
| }) | ||||
| unified_inventory.register_category('environment', { | ||||
| 	symbol = "default:dirt_with_grass", | ||||
| 	label = S("Environment and Worldgen") | ||||
| }) | ||||
| unified_inventory.register_category('lighting', { | ||||
| 	symbol = "default:torch", | ||||
| 	label = S("Lighting") | ||||
| }) | ||||
|  | ||||
|  | ||||
| if unified_inventory.automatic_categorization then | ||||
| 	minetest.register_on_mods_loaded(function() | ||||
|  | ||||
| 		-- Add biome nodes to environment category | ||||
| 		for _,def in pairs(minetest.registered_biomes) do | ||||
| 			local env_nodes = { | ||||
| 				def.node_riverbed, def.node_top, def.node_filler, def.node_dust, | ||||
| 			} | ||||
| 			for i,node in pairs(env_nodes) do | ||||
| 				if node then | ||||
| 					unified_inventory.add_category_item('environment', node) | ||||
| 				end | ||||
| 			end | ||||
| 		end | ||||
|  | ||||
| 		-- Add minable ores to minerals and everything else (pockets of stone & sand variations) to environment | ||||
| 		for _,item in  pairs(minetest.registered_ores) do | ||||
| 			if item.ore_type == "scatter" then | ||||
| 				local drop = minetest.registered_nodes[item.ore].drop | ||||
| 				if drop and drop ~= "" then | ||||
| 					unified_inventory.add_category_item('minerals', item.ore) | ||||
| 					unified_inventory.add_category_item('minerals', drop) | ||||
| 				else | ||||
| 					unified_inventory.add_category_item('environment', item.ore) | ||||
| 				end | ||||
| 			else | ||||
| 				unified_inventory.add_category_item('environment', item.ore) | ||||
| 			end | ||||
| 		end | ||||
|  | ||||
| 		-- Add items by item definition | ||||
| 		for name, def in pairs(minetest.registered_items) do | ||||
| 			local group = def.groups or {} | ||||
| 			if not group.not_in_creative_inventory then | ||||
| 				if group.stair or | ||||
| 				   group.slab or | ||||
| 				   group.wall or | ||||
| 				   group.fence then | ||||
| 					unified_inventory.add_category_item('building', name) | ||||
| 				elseif group.flora or | ||||
| 					   group.flower or | ||||
| 					   group.seed or | ||||
| 					   group.leaves or | ||||
| 					   group.sapling or | ||||
| 					   group.tree then | ||||
| 					unified_inventory.add_category_item('plants', name) | ||||
| 				elseif def.type == 'tool' then | ||||
| 					unified_inventory.add_category_item('tools', name) | ||||
| 				elseif def.liquidtype == 'source' then | ||||
| 					unified_inventory.add_category_item('environment', name) | ||||
| 				elseif def.light_source and def.light_source > 0 then | ||||
| 					unified_inventory.add_category_item('lighting', name) | ||||
| 				elseif group.door or | ||||
| 					   minetest.global_exists("doors") and ( | ||||
| 					     doors.registered_doors and doors.registered_doors[name..'_a'] or | ||||
| 					     doors.registered_trapdoors and doors.registered_trapdoors[name] | ||||
| 					   ) then | ||||
| 					unified_inventory.add_category_item('building', name) | ||||
| 				end | ||||
| 			end | ||||
| 		end | ||||
| 	end) | ||||
| end | ||||
|  | ||||
| -- [[ | ||||
| unified_inventory.add_category_items('plants', { | ||||
| 	"default:dry_grass_5", | ||||
| 	"default:acacia_sapling", | ||||
| 	"default:blueberry_bush_sapling", | ||||
| 	"default:grass_2", | ||||
| 	"default:pine_bush_stem", | ||||
| 	"default:leaves", | ||||
| 	"default:pine_needles", | ||||
| 	"default:cactus", | ||||
| 	"default:junglegrass", | ||||
| 	"default:pine_sapling", | ||||
| 	"default:sapling", | ||||
| 	"default:bush_stem", | ||||
| 	"default:dry_grass_2", | ||||
| 	"default:fern_1", | ||||
| 	"default:grass_3", | ||||
| 	"default:marram_grass_1", | ||||
| 	"default:pine_tree", | ||||
| 	"default:dry_grass_3", | ||||
| 	"default:dry_shrub", | ||||
| 	"default:grass_4", | ||||
| 	"default:marram_grass_2", | ||||
| 	"default:jungleleaves", | ||||
| 	"default:apple", | ||||
| 	"default:tree", | ||||
| 	"default:aspen_tree", | ||||
| 	"default:bush_sapling", | ||||
| 	"default:grass_5", | ||||
| 	"default:blueberry_bush_leaves_with_berries", | ||||
| 	"default:acacia_bush_sapling", | ||||
| 	"default:grass_1", | ||||
| 	"default:aspen_leaves", | ||||
| 	"default:marram_grass_3", | ||||
| 	"default:large_cactus_seedling", | ||||
| 	"default:junglesapling", | ||||
| 	"default:dry_grass_4", | ||||
| 	"default:acacia_bush_stem", | ||||
| 	"default:papyrus", | ||||
| 	"default:pine_bush_needles", | ||||
| 	"default:bush_leaves", | ||||
| 	"default:fern_3", | ||||
| 	"default:aspen_sapling", | ||||
| 	"default:acacia_tree", | ||||
| 	"default:apple_mark", | ||||
| 	"default:acacia_leaves", | ||||
| 	"default:jungletree", | ||||
| 	"default:dry_grass_1", | ||||
| 	"default:acacia_bush_leaves", | ||||
| 	"default:emergent_jungle_sapling", | ||||
| 	"default:fern_2", | ||||
| 	"default:blueberries", | ||||
| 	"default:sand_with_kelp", | ||||
| 	"default:blueberry_bush_leaves", | ||||
| 	"default:pine_bush_sapling", | ||||
|  | ||||
| 	"farming:cotton", | ||||
| 	"farming:cotton_1", | ||||
| 	"farming:cotton_2", | ||||
| 	"farming:cotton_3", | ||||
| 	"farming:cotton_4", | ||||
| 	"farming:cotton_5", | ||||
| 	"farming:cotton_6", | ||||
| 	"farming:cotton_7", | ||||
| 	"farming:cotton_8", | ||||
| 	"farming:cotton_wild", | ||||
| 	"farming:seed_cotton", | ||||
| 	"farming:seed_wheat", | ||||
| 	"farming:straw", | ||||
| 	"farming:wheat", | ||||
| 	"farming:wheat_1", | ||||
| 	"farming:wheat_2", | ||||
| 	"farming:wheat_3", | ||||
| 	"farming:wheat_4", | ||||
| 	"farming:wheat_5", | ||||
| 	"farming:wheat_6", | ||||
| 	"farming:wheat_7", | ||||
| 	"farming:wheat_8", | ||||
|  | ||||
| 	"flowers:chrysanthemum_green", | ||||
| 	"flowers:dandelion_white", | ||||
| 	"flowers:dandelion_yellow", | ||||
| 	"flowers:geranium", | ||||
| 	"flowers:mushroom_brown", | ||||
| 	"flowers:mushroom_red", | ||||
| 	"flowers:rose", | ||||
| 	"flowers:tulip", | ||||
| 	"flowers:tulip_black", | ||||
| 	"flowers:viola", | ||||
| 	"flowers:waterlily", | ||||
| 	"flowers:waterlily_waving", | ||||
| }) | ||||
|  | ||||
| unified_inventory.add_category_items('tools', { | ||||
| 	"default:sword_diamond", | ||||
| 	"default:axe_diamond", | ||||
| 	"default:shovel_diamond", | ||||
| 	"default:axe_steel", | ||||
| 	"default:shovel_mese", | ||||
| 	"default:sword_wood", | ||||
| 	"default:pick_bronze", | ||||
| 	"default:axe_stone", | ||||
| 	"default:sword_stone", | ||||
| 	"default:pick_stone", | ||||
| 	"default:shovel_stone", | ||||
| 	"default:sword_mese", | ||||
| 	"default:shovel_bronze", | ||||
| 	"default:sword_bronze", | ||||
| 	"default:axe_bronze", | ||||
| 	"default:shovel_steel", | ||||
| 	"default:sword_steel", | ||||
| 	"default:axe_mese", | ||||
| 	"default:shovel_wood", | ||||
| 	"default:pick_mese", | ||||
| 	"default:axe_wood", | ||||
| 	"default:pick_diamond", | ||||
| 	"default:pick_wood", | ||||
| 	"default:pick_steel", | ||||
|  | ||||
| 	"farming:hoe_bronze", | ||||
| 	"farming:hoe_diamond", | ||||
| 	"farming:hoe_mese", | ||||
| 	"farming:hoe_steel", | ||||
| 	"farming:hoe_stone", | ||||
| 	"farming:hoe_wood", | ||||
|  | ||||
| 	"fire:flint_and_steel", | ||||
| 	"map:mapping_kit", | ||||
| 	"screwdriver:screwdriver", | ||||
|  | ||||
| 	"fireflies:bug_net", | ||||
| 	"bucket:bucket_empty", | ||||
|  | ||||
| 	"binoculars:binoculars", | ||||
| 	"default:skeleton_key", | ||||
| }) | ||||
|  | ||||
| unified_inventory.add_category_items('minerals', { | ||||
| 	"default:stone_with_copper", | ||||
| 	"default:stone_with_gold", | ||||
| 	"default:stone_with_iron", | ||||
| 	"default:copper_ingot", | ||||
| 	"default:copper_lump", | ||||
| 	"default:gold_lump", | ||||
| 	"default:diamondblock", | ||||
| 	"default:stone_with_diamond", | ||||
| 	"default:stone_with_mese", | ||||
| 	"default:steel_ingot", | ||||
| 	"default:gold_ingot", | ||||
| 	"default:iron_lump", | ||||
| 	"default:tinblock", | ||||
| 	"default:tin_lump", | ||||
| 	"default:stone_with_tin", | ||||
| 	"default:mese_crystal", | ||||
| 	"default:diamond", | ||||
| 	"default:bronze_ingot", | ||||
| 	"default:mese", | ||||
| 	"default:mese_crystal_fragment", | ||||
| 	"default:copperblock", | ||||
| 	"default:stone_with_coal", | ||||
| 	"default:steelblock", | ||||
| 	"default:tin_ingot", | ||||
| 	"default:coalblock", | ||||
| 	"default:coal_lump", | ||||
| 	"default:bronzeblock", | ||||
| 	"default:goldblock", | ||||
|  | ||||
| 	"stairs:slab_bronzeblock", | ||||
| 	"stairs:slab_copperblock", | ||||
| 	"stairs:slab_steelblock", | ||||
| 	"stairs:slab_tinblock", | ||||
| 	"stairs:stair_bronzeblock", | ||||
| 	"stairs:stair_copperblock", | ||||
| 	"stairs:stair_inner_bronzeblock", | ||||
| 	"stairs:stair_inner_copperblock", | ||||
| 	"stairs:stair_inner_steelblock", | ||||
| 	"stairs:stair_inner_tinblock", | ||||
| 	"stairs:stair_outer_bronzeblock", | ||||
| 	"stairs:stair_outer_copperblock", | ||||
| 	"stairs:stair_outer_steelblock", | ||||
| 	"stairs:stair_outer_tinblock", | ||||
| 	"stairs:stair_steelblock", | ||||
| 	"stairs:stair_tinblock", | ||||
| }) | ||||
|  | ||||
| unified_inventory.add_category_items('building', { | ||||
| 	"default:fence_rail_aspen_wood", | ||||
| 	"default:fence_rail_acacia_wood", | ||||
| 	"default:fence_junglewood", | ||||
| 	"default:fence_rail_junglewood", | ||||
| 	"default:fence_aspen_wood", | ||||
| 	"default:fence_pine_wood", | ||||
| 	"default:fence_rail_wood", | ||||
| 	"default:fence_rail_pine_wood", | ||||
| 	"default:fence_acacia_wood", | ||||
| 	"default:junglewood", | ||||
| 	"default:acacia_wood", | ||||
| 	"default:aspen_wood", | ||||
| 	"default:fence_wood", | ||||
| 	"default:pine_wood", | ||||
| 	"default:silver_sandstone", | ||||
| 	"default:desert_sandstone", | ||||
| 	"default:sandstone_block", | ||||
| 	"default:desert_sandstone_brick", | ||||
| 	"default:stone_block", | ||||
| 	"default:stonebrick", | ||||
| 	"default:obsidian_glass", | ||||
| 	"default:desert_sandstone_block", | ||||
| 	"default:silver_sandstone_brick", | ||||
| 	"default:brick", | ||||
| 	"default:obsidianbrick", | ||||
| 	"default:sandstonebrick", | ||||
| 	"default:sandstone", | ||||
| 	"default:desert_stone_block", | ||||
| 	"default:silver_sandstone_block", | ||||
| 	"default:wood", | ||||
| 	"default:obsidian_block", | ||||
| 	"default:glass", | ||||
| 	"default:clay_brick", | ||||
| 	"default:desert_stonebrick", | ||||
| 	"default:desert_cobble", | ||||
| 	"default:cobble", | ||||
| 	"default:mossycobble", | ||||
|  | ||||
| 	"doors:door_glass", | ||||
| 	"doors:door_glass_a", | ||||
| 	"doors:door_glass_b", | ||||
| 	"doors:door_glass_c", | ||||
| 	"doors:door_glass_d", | ||||
| 	"doors:door_obsidian_glass", | ||||
| 	"doors:door_obsidian_glass_a", | ||||
| 	"doors:door_obsidian_glass_b", | ||||
| 	"doors:door_obsidian_glass_c", | ||||
| 	"doors:door_obsidian_glass_d", | ||||
| 	"doors:door_steel", | ||||
| 	"doors:door_steel_a", | ||||
| 	"doors:door_steel_b", | ||||
| 	"doors:door_steel_c", | ||||
| 	"doors:door_steel_d", | ||||
| 	"doors:door_wood", | ||||
| 	"doors:door_wood_a", | ||||
| 	"doors:door_wood_b", | ||||
| 	"doors:door_wood_c", | ||||
| 	"doors:door_wood_d", | ||||
| 	"doors:gate_acacia_wood_closed", | ||||
| 	"doors:gate_acacia_wood_open", | ||||
| 	"doors:gate_aspen_wood_closed", | ||||
| 	"doors:gate_aspen_wood_open", | ||||
| 	"doors:gate_junglewood_closed", | ||||
| 	"doors:gate_junglewood_open", | ||||
| 	"doors:gate_pine_wood_closed", | ||||
| 	"doors:gate_pine_wood_open", | ||||
| 	"doors:gate_wood_closed", | ||||
| 	"doors:gate_wood_open", | ||||
| 	"doors:hidden", | ||||
| 	"doors:trapdoor", | ||||
| 	"doors:trapdoor_open", | ||||
| 	"doors:trapdoor_steel", | ||||
| 	"doors:trapdoor_steel_open", | ||||
|  | ||||
| 	"stairs:slab_bronzeblock", | ||||
| 	"stairs:slab_copperblock", | ||||
| 	"stairs:slab_steelblock", | ||||
| 	"stairs:slab_tinblock", | ||||
| 	"stairs:stair_bronzeblock", | ||||
| 	"stairs:stair_copperblock", | ||||
| 	"stairs:stair_inner_bronzeblock", | ||||
| 	"stairs:stair_inner_copperblock", | ||||
| 	"stairs:stair_inner_steelblock", | ||||
| 	"stairs:stair_inner_tinblock", | ||||
| 	"stairs:stair_outer_bronzeblock", | ||||
| 	"stairs:stair_outer_copperblock", | ||||
| 	"stairs:stair_outer_steelblock", | ||||
| 	"stairs:stair_outer_tinblock", | ||||
| 	"stairs:stair_steelblock", | ||||
| 	"stairs:stair_tinblock", | ||||
|  | ||||
| 	"stairs:slab_acacia_wood", | ||||
| 	"stairs:slab_aspen_wood", | ||||
| 	"stairs:slab_brick", | ||||
| 	"stairs:slab_cobble", | ||||
| 	"stairs:slab_desert_cobble", | ||||
| 	"stairs:slab_desert_sandstone", | ||||
| 	"stairs:slab_desert_sandstone_block", | ||||
| 	"stairs:slab_desert_sandstone_brick", | ||||
| 	"stairs:slab_desert_stone", | ||||
| 	"stairs:slab_desert_stone_block", | ||||
| 	"stairs:slab_desert_stonebrick", | ||||
| 	"stairs:slab_glass", | ||||
| 	"stairs:slab_goldblock", | ||||
| 	"stairs:slab_ice", | ||||
| 	"stairs:slab_junglewood", | ||||
| 	"stairs:slab_mossycobble", | ||||
| 	"stairs:slab_obsidian", | ||||
| 	"stairs:slab_obsidian_block", | ||||
| 	"stairs:slab_obsidian_glass", | ||||
| 	"stairs:slab_obsidianbrick", | ||||
| 	"stairs:slab_pine_wood", | ||||
| 	"stairs:slab_sandstone", | ||||
| 	"stairs:slab_sandstone_block", | ||||
| 	"stairs:slab_sandstonebrick", | ||||
| 	"stairs:slab_silver_sandstone", | ||||
| 	"stairs:slab_silver_sandstone_block", | ||||
| 	"stairs:slab_silver_sandstone_brick", | ||||
| 	"stairs:slab_snowblock", | ||||
| 	"stairs:slab_stone", | ||||
| 	"stairs:slab_stone_block", | ||||
| 	"stairs:slab_stonebrick", | ||||
| 	"stairs:slab_straw", | ||||
| 	"stairs:slab_wood", | ||||
| 	"stairs:stair_acacia_wood", | ||||
| 	"stairs:stair_aspen_wood", | ||||
| 	"stairs:stair_brick", | ||||
| 	"stairs:stair_cobble", | ||||
| 	"stairs:stair_desert_cobble", | ||||
| 	"stairs:stair_desert_sandstone", | ||||
| 	"stairs:stair_desert_sandstone_block", | ||||
| 	"stairs:stair_desert_sandstone_brick", | ||||
| 	"stairs:stair_desert_stone", | ||||
| 	"stairs:stair_desert_stone_block", | ||||
| 	"stairs:stair_desert_stonebrick", | ||||
| 	"stairs:stair_glass", | ||||
| 	"stairs:stair_goldblock", | ||||
| 	"stairs:stair_ice", | ||||
| 	"stairs:stair_inner_acacia_wood", | ||||
| 	"stairs:stair_inner_aspen_wood", | ||||
| 	"stairs:stair_inner_brick", | ||||
| 	"stairs:stair_inner_cobble", | ||||
| 	"stairs:stair_inner_desert_cobble", | ||||
| 	"stairs:stair_inner_desert_sandstone", | ||||
| 	"stairs:stair_inner_desert_sandstone_block", | ||||
| 	"stairs:stair_inner_desert_sandstone_brick", | ||||
| 	"stairs:stair_inner_desert_stone", | ||||
| 	"stairs:stair_inner_desert_stone_block", | ||||
| 	"stairs:stair_inner_desert_stonebrick", | ||||
| 	"stairs:stair_inner_glass", | ||||
| 	"stairs:stair_inner_goldblock", | ||||
| 	"stairs:stair_inner_ice", | ||||
| 	"stairs:stair_inner_junglewood", | ||||
| 	"stairs:stair_inner_mossycobble", | ||||
| 	"stairs:stair_inner_obsidian", | ||||
| 	"stairs:stair_inner_obsidian_block", | ||||
| 	"stairs:stair_inner_obsidian_glass", | ||||
| 	"stairs:stair_inner_obsidianbrick", | ||||
| 	"stairs:stair_inner_pine_wood", | ||||
| 	"stairs:stair_inner_sandstone", | ||||
| 	"stairs:stair_inner_sandstone_block", | ||||
| 	"stairs:stair_inner_sandstonebrick", | ||||
| 	"stairs:stair_inner_silver_sandstone", | ||||
| 	"stairs:stair_inner_silver_sandstone_block", | ||||
| 	"stairs:stair_inner_silver_sandstone_brick", | ||||
| 	"stairs:stair_inner_snowblock", | ||||
| 	"stairs:stair_inner_stone", | ||||
| 	"stairs:stair_inner_stone_block", | ||||
| 	"stairs:stair_inner_stonebrick", | ||||
| 	"stairs:stair_inner_straw", | ||||
| 	"stairs:stair_inner_wood", | ||||
| 	"stairs:stair_junglewood", | ||||
| 	"stairs:stair_mossycobble", | ||||
| 	"stairs:stair_obsidian", | ||||
| 	"stairs:stair_obsidian_block", | ||||
| 	"stairs:stair_obsidian_glass", | ||||
| 	"stairs:stair_obsidianbrick", | ||||
| 	"stairs:stair_outer_acacia_wood", | ||||
| 	"stairs:stair_outer_aspen_wood", | ||||
| 	"stairs:stair_outer_brick", | ||||
| 	"stairs:stair_outer_cobble", | ||||
| 	"stairs:stair_outer_desert_cobble", | ||||
| 	"stairs:stair_outer_desert_sandstone", | ||||
| 	"stairs:stair_outer_desert_sandstone_block", | ||||
| 	"stairs:stair_outer_desert_sandstone_brick", | ||||
| 	"stairs:stair_outer_desert_stone", | ||||
| 	"stairs:stair_outer_desert_stone_block", | ||||
| 	"stairs:stair_outer_desert_stonebrick", | ||||
| 	"stairs:stair_outer_glass", | ||||
| 	"stairs:stair_outer_goldblock", | ||||
| 	"stairs:stair_outer_ice", | ||||
| 	"stairs:stair_outer_junglewood", | ||||
| 	"stairs:stair_outer_mossycobble", | ||||
| 	"stairs:stair_outer_obsidian", | ||||
| 	"stairs:stair_outer_obsidian_block", | ||||
| 	"stairs:stair_outer_obsidian_glass", | ||||
| 	"stairs:stair_outer_obsidianbrick", | ||||
| 	"stairs:stair_outer_pine_wood", | ||||
| 	"stairs:stair_outer_sandstone", | ||||
| 	"stairs:stair_outer_sandstone_block", | ||||
| 	"stairs:stair_outer_sandstonebrick", | ||||
| 	"stairs:stair_outer_silver_sandstone", | ||||
| 	"stairs:stair_outer_silver_sandstone_block", | ||||
| 	"stairs:stair_outer_silver_sandstone_brick", | ||||
| 	"stairs:stair_outer_snowblock", | ||||
| 	"stairs:stair_outer_stone", | ||||
| 	"stairs:stair_outer_stone_block", | ||||
| 	"stairs:stair_outer_stonebrick", | ||||
| 	"stairs:stair_outer_straw", | ||||
| 	"stairs:stair_outer_wood", | ||||
| 	"stairs:stair_pine_wood", | ||||
| 	"stairs:stair_sandstone", | ||||
| 	"stairs:stair_sandstone_block", | ||||
| 	"stairs:stair_sandstonebrick", | ||||
| 	"stairs:stair_silver_sandstone", | ||||
| 	"stairs:stair_silver_sandstone_block", | ||||
| 	"stairs:stair_silver_sandstone_brick", | ||||
| 	"stairs:stair_snowblock", | ||||
| 	"stairs:stair_stone", | ||||
| 	"stairs:stair_stone_block", | ||||
| 	"stairs:stair_stonebrick", | ||||
| 	"stairs:stair_straw", | ||||
| 	"stairs:stair_wood", | ||||
|  | ||||
| 	"xpanes:bar", | ||||
| 	"xpanes:bar_flat", | ||||
| 	"xpanes:door_steel_bar", | ||||
| 	"xpanes:door_steel_bar_a", | ||||
| 	"xpanes:door_steel_bar_b", | ||||
| 	"xpanes:door_steel_bar_c", | ||||
| 	"xpanes:door_steel_bar_d", | ||||
| 	"xpanes:obsidian_pane", | ||||
| 	"xpanes:obsidian_pane_flat", | ||||
| 	"xpanes:pane", | ||||
| 	"xpanes:pane_flat", | ||||
| 	"xpanes:trapdoor_steel_bar", | ||||
| 	"xpanes:trapdoor_steel_bar_open", | ||||
|  | ||||
| 	"walls:cobble", | ||||
| 	"walls:desertcobble", | ||||
| 	"walls:mossycobble", | ||||
| }) | ||||
|  | ||||
| unified_inventory.add_category_items('environment', { | ||||
| 	"air", | ||||
| 	"default:cave_ice", | ||||
| 	"default:dirt_with_rainforest_litter", | ||||
| 	"default:gravel", | ||||
| 	"default:dry_dirt_with_dry_grass", | ||||
| 	"default:permafrost", | ||||
| 	"default:desert_stone", | ||||
| 	"default:ice", | ||||
| 	"default:dry_dirt", | ||||
| 	"default:obsidian", | ||||
| 	"default:sand", | ||||
| 	"default:river_water_source", | ||||
| 	"default:dirt_with_snow", | ||||
| 	"default:dirt_with_grass", | ||||
| 	"default:water_flowing", | ||||
| 	"default:dirt", | ||||
| 	"default:desert_sand", | ||||
| 	"default:permafrost_with_moss", | ||||
| 	"default:dirt_with_coniferous_litter", | ||||
| 	"default:water_source", | ||||
| 	"default:dirt_with_dry_grass", | ||||
| 	"default:river_water_flowing", | ||||
| 	"default:stone", | ||||
| 	"default:snow", | ||||
| 	"default:lava_flowing", | ||||
| 	"default:lava_source", | ||||
| 	"default:permafrost_with_stones", | ||||
| 	"default:dirt_with_grass_footsteps", | ||||
| 	"default:silver_sand", | ||||
| 	"default:snowblock", | ||||
| 	"default:clay", | ||||
|  | ||||
| 	"farming:desert_sand_soil", | ||||
| 	"farming:desert_sand_soil_wet", | ||||
| 	"farming:dry_soil", | ||||
| 	"farming:dry_soil_wet", | ||||
| 	"farming:soil", | ||||
| 	"farming:soil_wet", | ||||
| }) | ||||
|  | ||||
| unified_inventory.add_category_items('lighting', { | ||||
| 	"default:mese_post_light_junglewood", | ||||
| 	"default:torch_ceiling", | ||||
| 	"default:meselamp", | ||||
| 	"default:torch", | ||||
| 	"default:mese_post_light_acacia_wood", | ||||
| 	"default:mese_post_light", | ||||
| 	"default:torch_wall", | ||||
| 	"default:mese_post_light_pine_wood", | ||||
| 	"default:mese_post_light_aspen_wood" | ||||
| }) | ||||
| --]] | ||||
|  | ||||
|  | ||||
| --[[ UNCATEGORISED | ||||
|  | ||||
| 	"farming:string", | ||||
|  | ||||
| 	"beds:bed_bottom", | ||||
| 	"beds:bed_top", | ||||
| 	"beds:fancy_bed_bottom", | ||||
| 	"beds:fancy_bed_top", | ||||
| 	"boats:boat", | ||||
| 	"bones:bones", | ||||
|  | ||||
| 	"bucket:bucket_lava", | ||||
| 	"bucket:bucket_river_water", | ||||
| 	"bucket:bucket_water", | ||||
|  | ||||
| 	"butterflies:butterfly_red", | ||||
| 	"butterflies:butterfly_violet", | ||||
| 	"butterflies:butterfly_white", | ||||
| 	"butterflies:hidden_butterfly_red", | ||||
| 	"butterflies:hidden_butterfly_violet", | ||||
| 	"butterflies:hidden_butterfly_white", | ||||
|  | ||||
| 	"carts:brakerail", | ||||
| 	"carts:cart", | ||||
| 	"carts:powerrail", | ||||
| 	"carts:rail", | ||||
|  | ||||
| 	"default:book", | ||||
| 	"default:book_written", | ||||
| 	"default:bookshelf", | ||||
| 	"default:chest", | ||||
| 	"default:chest_locked", | ||||
| 	"default:chest_locked_open", | ||||
| 	"default:chest_open", | ||||
| 	"default:clay_lump", | ||||
| 	"default:cloud", | ||||
| 	"default:coral_brown", | ||||
| 	"default:coral_cyan", | ||||
| 	"default:coral_green", | ||||
| 	"default:coral_orange", | ||||
| 	"default:coral_pink", | ||||
| 	"default:coral_skeleton", | ||||
| 	"default:flint", | ||||
| 	"default:furnace", | ||||
| 	"default:furnace_active", | ||||
| 	"default:key", | ||||
| 	"default:ladder_steel", | ||||
| 	"default:ladder_wood", | ||||
| 	"default:obsidian_shard", | ||||
| 	"default:paper", | ||||
| 	"default:sign_wall_steel", | ||||
| 	"default:sign_wall_wood", | ||||
| 	"default:stick", | ||||
|  | ||||
| 	"fire:basic_flame", | ||||
| 	"fire:permanent_flame", | ||||
| 	"fireflies:firefly", | ||||
| 	"fireflies:firefly_bottle", | ||||
| 	"fireflies:hidden_firefly", | ||||
|  | ||||
| 	"ignore", | ||||
| 	"unknown", | ||||
|  | ||||
| 	"tnt:boom", | ||||
| 	"tnt:gunpowder", | ||||
| 	"tnt:gunpowder_burning", | ||||
| 	"tnt:tnt", | ||||
| 	"tnt:tnt_burning", | ||||
| 	"tnt:tnt_stick", | ||||
|  | ||||
| 	"vessels:drinking_glass", | ||||
| 	"vessels:glass_bottle", | ||||
| 	"vessels:glass_fragments", | ||||
| 	"vessels:shelf", | ||||
| 	"vessels:steel_bottle", | ||||
|  | ||||
| 	"dye:black", | ||||
| 	"dye:blue", | ||||
| 	"dye:brown", | ||||
| 	"dye:cyan", | ||||
| 	"dye:dark_green", | ||||
| 	"dye:dark_grey", | ||||
| 	"dye:green", | ||||
| 	"dye:grey", | ||||
| 	"dye:magenta", | ||||
| 	"dye:orange", | ||||
| 	"dye:pink", | ||||
| 	"dye:red", | ||||
| 	"dye:violet", | ||||
| 	"dye:white", | ||||
| 	"dye:yellow", | ||||
|  | ||||
| 	"wool:black", | ||||
| 	"wool:blue", | ||||
| 	"wool:brown", | ||||
| 	"wool:cyan", | ||||
| 	"wool:dark_green", | ||||
| 	"wool:dark_grey", | ||||
| 	"wool:green", | ||||
| 	"wool:grey", | ||||
| 	"wool:magenta", | ||||
| 	"wool:orange", | ||||
| 	"wool:pink", | ||||
| 	"wool:red", | ||||
| 	"wool:violet", | ||||
| 	"wool:white", | ||||
| 	"wool:yellow", | ||||
|  | ||||
| 	"unified_inventory:bag_large", | ||||
| 	"unified_inventory:bag_medium", | ||||
| 	"unified_inventory:bag_small", | ||||
| --]] | ||||
|  | ||||
| --[[ LIST UNCATEGORIZED AFTER LOAD | ||||
| minetest.register_on_mods_loaded(function() | ||||
| 	minetest.after(1, function ( ) | ||||
| 		local l = {} | ||||
| 		for name,_ in pairs(minetest.registered_items) do | ||||
| 			if not unified_inventory.find_category(name) then | ||||
| 				-- minetest.log("error", minetest.serialize(minetest.registered_items[name])) | ||||
| 				table.insert(l, name) | ||||
| 			end | ||||
| 		end | ||||
| 		table.sort(l) | ||||
| 		minetest.log(table.concat(l, '",'.."\n"..'"')) | ||||
| 	end) | ||||
| end) | ||||
| --]] | ||||
							
								
								
									
										1
									
								
								depends.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1 @@ | ||||
| creative? | ||||
							
								
								
									
										222
									
								
								doc/mod_api.txt
									
									
									
									
									
								
							
							
						
						| @@ -1,222 +0,0 @@ | ||||
| unified_inventory API | ||||
| ===================== | ||||
|  | ||||
| This file provides information about the API of unified_inventory | ||||
| and can be viewed in Markdown readers. | ||||
|  | ||||
| API revisions within unified_inventory can be checked using: | ||||
|  | ||||
| 	(unified_inventory.version or 1) | ||||
|  | ||||
| **Revision history** | ||||
|  | ||||
| * Version `1`: Classic formspec layout (no real_coordinates) | ||||
| * Version `2`: Force formspec version 4 (includes real_coordinates) | ||||
|  | ||||
| Misc functions | ||||
| -------------- | ||||
| Grouped by use-case, afterwards sorted alphabetically. | ||||
|  | ||||
| * `unified_inventory.is_creative(name)` | ||||
| 	* Checks whether creative is enabled or the player has `creative` | ||||
|  | ||||
|  | ||||
| Callbacks | ||||
| --------- | ||||
|  | ||||
| Register a callback that will be run whenever a craft is registered via unified_inventory.register_craft. | ||||
| This callback is run before any recipe ingredients checks, hence it is also executed on recipes that are | ||||
| purged after all mods finished loading. | ||||
|  | ||||
| 	unified_inventory.register_on_craft_registered( | ||||
| 		function (item_name, options) | ||||
| 			-- item_name (string): name of the output item, equivalent to `ItemStack:get_name()` | ||||
| 			-- options (table): definition table of crafts registered by `unified_inventory.register_craft` | ||||
| 		end | ||||
| 	) | ||||
|  | ||||
| Register a callback that will be run after all mods have loaded and after the unified_inventory mod has initialised all its internal structures: | ||||
|  | ||||
| 	unified_inventory.register_on_initialized(callback) | ||||
| 		-- The callback is passed no arguments | ||||
|  | ||||
|  | ||||
| Accessing Data | ||||
| -------------- | ||||
|  | ||||
| These methods should be used instead of accessing the unified_inventory data structures directly - this will ensure your code survives any potential restructuring of the mod. | ||||
|  | ||||
| Get a list of recipes for a particular output item: | ||||
|  | ||||
| 	unified_inventory.get_recipe_list(output_item) | ||||
|  | ||||
| 	Returns a list of tables, each holding a recipe definition, like: | ||||
| 	{ | ||||
| 		{ | ||||
| 			type = "normal", | ||||
| 			items = { "default:stick", "default:stick", "default:stick", "default:stick" }, | ||||
| 			output = "default:wood", | ||||
| 			width = 2 | ||||
| 		}, | ||||
| 		{ | ||||
| 			type = "shapeless", | ||||
| 			items = { "default:tree" }, | ||||
| 			output = "default:wood 4", | ||||
| 			width = 0 | ||||
| 		}, | ||||
| 		... | ||||
| 	} | ||||
|  | ||||
| Get a list of all the output items crafts have been registered for: | ||||
|  | ||||
| 	unified_inventory.get_registered_outputs() | ||||
|  | ||||
| 	Returns a list of item names, like: | ||||
| 	{ | ||||
| 		"default:stone", | ||||
| 		"default:chest", | ||||
| 		"default:brick", | ||||
| 		"doors:door_wood", | ||||
| 		... | ||||
| 	} | ||||
|  | ||||
|  | ||||
| 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` | ||||
| 	}) | ||||
|  | ||||
|  | ||||
| Categories | ||||
| ---------- | ||||
|  | ||||
|  * `unified_inventory.register_category(name, def)` | ||||
|      * Registers a new category | ||||
|      * `name` (string): internal category name | ||||
|      * `def` (optional, table): also its fields are optional | ||||
|  | ||||
| 	unified_inventory.register_category("category_name", { | ||||
| 		symbol = source, | ||||
| 		-- ^ Can be in the format "mod_name:item_name" or "texture.png", | ||||
| 		label = "Human Readable Label", | ||||
| 		index = 5, | ||||
| 		-- ^ Categories are sorted by index. Lower numbers appear before higher ones. | ||||
| 		--   By default, the name is translated to a number: AA -> 0.0101, ZZ -> 0.2626 | ||||
| 		---  Predefined category indices: "all" = -2, "uncategorized" = -1 | ||||
| 		items = { | ||||
| 			"mod_name:item_name", | ||||
| 			"another_mod:different_item" | ||||
| 		} | ||||
| 		-- ^ List of items within this category | ||||
| 	}) | ||||
|  * `unified_inventory.remove_category(name)` | ||||
|      * Removes an entire category | ||||
|  | ||||
| Modifier functions (to be removed) | ||||
|  | ||||
|  * `unified_inventory.set_category_symbol(name, source)` | ||||
|      * Changes the symbol of the category. The category does not need to exist yet. | ||||
|      * `name` (string): internal category name | ||||
|      * `source` (string, optional): `"mod_name:item_name"` or `"texture.png"`. | ||||
|        Defaults to `"default:stick"` if not specified. | ||||
|  * `unified_inventory.set_category_label(name, label)` | ||||
|      * Changes the human readable label of the category. | ||||
|      * `name` (string): internal category name | ||||
|      * `label` (string): human readable label. Defaults to the category name. | ||||
|  * `unified_inventory.set_category_index(name, index)` | ||||
|      * Changes the sorting index of the category. | ||||
|      * `name` (string): internal category name | ||||
|      * `index` (numeric): any real number | ||||
|  | ||||
| Item management | ||||
|  | ||||
|  * `	unified_inventory.add_category_item(name, itemname)` | ||||
|      * Adds a single item to the category | ||||
|      * `itemname` (string): self-explanatory | ||||
|  * `unified_inventory.add_category_items(name, { itemname1, itemname2, ... }` | ||||
|      * Same as above but with multiple items | ||||
|  * `unified_inventory.remove_category_item(name, itemname)` | ||||
|      * Removes an item from the category | ||||
|  * `unified_inventory.find_category(itemname)` | ||||
|      * Looks up the first category containing this item | ||||
|      * Returns: category name (string) or nil | ||||
|  * `unified_inventory.find_categories(itemname)` | ||||
|      * Looks up the item name within all registered categories | ||||
|      * Returns: array of category names (table) | ||||
|  | ||||
							
								
								
									
										146
									
								
								group.lua
									
									
									
									
									
								
							
							
						
						| @@ -1,146 +0,0 @@ | ||||
| local S = minetest.get_translator("unified_inventory") | ||||
| local ui = unified_inventory | ||||
|  | ||||
| function unified_inventory.extract_groupnames(groupname) | ||||
| 	local specname = ItemStack(groupname):get_name() | ||||
| 	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 | ||||
|  | ||||
|  | ||||
| -- This is used when displaying craft recipes, where an ingredient is | ||||
| -- specified by group rather than as a specific item.  A single-item group | ||||
| -- is represented by that item, with the single-item status signalled | ||||
| -- in the "sole" field.  If the group contains no items at all, the item | ||||
| -- field will be nil. | ||||
| -- | ||||
| -- Within a multiple-item group, we prefer to use an item that has the | ||||
| -- same specific name as the group, and if there are more than one of | ||||
| -- those items we prefer the one registered for the group by a mod. | ||||
| -- Among equally-preferred items, we just pick the one with the | ||||
| -- lexicographically earliest name. | ||||
| -- | ||||
| -- The parameter to this function isn't just a single group name. | ||||
| -- It may be a comma-separated list of group names.  This is really a | ||||
| -- "group:..." ingredient specification, minus the "group:" prefix. | ||||
|  | ||||
| -- TODO Replace this with the more efficient spec matcher (below) | ||||
| local function compute_group_item(group_name_list) | ||||
| 	local group_names = group_name_list:split(",") | ||||
| 	local candidate_items = {} | ||||
| 	for itemname, itemdef in pairs(minetest.registered_items) do | ||||
| 		if (itemdef.groups.not_in_creative_inventory or 0) == 0 then | ||||
| 			local all = true | ||||
| 			for _, group_name in ipairs(group_names) do | ||||
| 				if (itemdef.groups[group_name] or 0) == 0 then | ||||
| 					all = false | ||||
| 				end | ||||
| 			end | ||||
| 			if all then table.insert(candidate_items, itemname) end | ||||
| 		end | ||||
| 	end | ||||
| 	local num_candidates = #candidate_items | ||||
| 	if num_candidates == 0 then | ||||
| 		return {sole = true} | ||||
| 	elseif num_candidates == 1 then | ||||
| 		return {item = candidate_items[1], sole = true} | ||||
| 	end | ||||
| 	local is_group = {} | ||||
| 	local registered_rep = {} | ||||
| 	for _, group_name in ipairs(group_names) do | ||||
| 		is_group[group_name] = true | ||||
| 		local rep = unified_inventory.registered_group_items[group_name] | ||||
| 		if rep then registered_rep[rep] = true end | ||||
| 	end | ||||
| 	local bestitem = "" | ||||
| 	local bestpref = 0 | ||||
| 	for _, item in ipairs(candidate_items) do | ||||
| 		local pref | ||||
| 		if registered_rep[item] then | ||||
| 			pref = 4 | ||||
| 		elseif string.sub(item, 1, 8) == "default:" and is_group[string.sub(item, 9)] then | ||||
| 			pref = 3 | ||||
| 		elseif is_group[item:gsub("^[^:]*:", "")] then | ||||
| 			pref = 2 | ||||
| 		else | ||||
| 			pref = 1 | ||||
| 		end | ||||
| 		if pref > bestpref or (pref == bestpref and item < bestitem) then | ||||
| 			bestitem = item | ||||
| 			bestpref = pref | ||||
| 		end | ||||
| 	end | ||||
| 	return {item = bestitem, sole = false} | ||||
| end | ||||
|  | ||||
|  | ||||
| local group_item_cache = {} | ||||
|  | ||||
| function unified_inventory.get_group_item(group_name) | ||||
| 	if not group_item_cache[group_name] then | ||||
| 		group_item_cache[group_name] = compute_group_item(group_name) | ||||
| 	end | ||||
| 	return group_item_cache[group_name] | ||||
| end | ||||
|  | ||||
|  | ||||
| --[[ | ||||
| This is for filtering known items by groups | ||||
| e.g. find all items that match "group:flower,yellow" (flower AND yellow groups) | ||||
| ]] | ||||
| local spec_matcher = {} | ||||
| function unified_inventory.init_matching_cache() | ||||
| 	for _, name in ipairs(ui.items_list) do | ||||
| 		-- we only need to care about groups, exact items are handled separately | ||||
| 		for group, value in pairs(minetest.registered_items[name].groups) do | ||||
| 			if value and value ~= 0 then | ||||
| 				if not spec_matcher[group] then | ||||
| 					spec_matcher[group] = {} | ||||
| 				end | ||||
| 				spec_matcher[group][name] = true | ||||
| 			end | ||||
| 		end | ||||
| 	end | ||||
| end | ||||
|  | ||||
| --[[ | ||||
| Retrieves all matching items | ||||
|  | ||||
| Arguments: | ||||
| 	specname (string): Item name or group(s) to filter | ||||
|  | ||||
| Output: | ||||
| 	{ | ||||
| 		matchingitem1 = true, | ||||
| 		... | ||||
| 	} | ||||
| ]] | ||||
| function unified_inventory.get_matching_items(specname) | ||||
| 	if specname:sub(1,6) ~= "group:" then | ||||
| 		return { [specname] = true } | ||||
| 	end | ||||
|  | ||||
| 	local accepted = {} | ||||
| 	for i, group in ipairs(specname:sub(7):split(",")) do | ||||
| 		if i == 1 then | ||||
| 			-- First step: Copy all possible item names in this group | ||||
| 			for name, _ in pairs(spec_matcher[group] or {}) do | ||||
| 				accepted[name] = true | ||||
| 			end | ||||
| 		else | ||||
| 			-- Perform filtering | ||||
| 			if spec_matcher[group] then | ||||
| 				for name, _ in pairs(accepted) do | ||||
| 					accepted[name] = spec_matcher[group][name] | ||||
| 				end | ||||
| 			else | ||||
| 				-- No matching items | ||||
| 				return {} | ||||
| 			end | ||||
| 		end | ||||
| 	end | ||||
| 	return accepted | ||||
| end | ||||
| @@ -1,69 +0,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 | ||||
|  | ||||
| ui_craftguide_icon.png / ui_craft_icon.png | ||||
| 	http://commons.wikimedia.org/wiki/File:Advancedsettings.png | ||||
| 	 | ||||
| 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_left_icon.png / ui_right_icon.png | ||||
| 	http://commons.wikimedia.org/wiki/File:Media-playback-start.svg | ||||
|  | ||||
| ui_skip_backward_icon.png | ||||
| 	http://commons.wikimedia.org/wiki/File:Media-skip-backward.svg | ||||
|  | ||||
| ui_skip_forward_icon.png | ||||
| 	http://commons.wikimedia.org/wiki/File:Media-skip-forward.svg | ||||
|  | ||||
| ui_reset_icon.png | ||||
| 	https://commons.wikimedia.org/wiki/File:Edit-clear.svg | ||||
|  | ||||
| ui_gohome_icon.png / ui_home_icon.png / ui_sethome_icon.png | ||||
| 	http://commons.wikimedia.org/wiki/File:Home_256x256.png | ||||
|  | ||||
| ui_moon_icon.png | ||||
| 	http://commons.wikimedia.org/wiki/File:FullMoon2010.jpg | ||||
|  | ||||
| ui_sun_icon.png | ||||
| 	http://commons.wikimedia.org/wiki/File:2012-10-13_15-29-35-sun.jpg | ||||
|  | ||||
| ui_trash_icon.png | ||||
| 	http://www.clker.com/clipart-29090.html | ||||
| 	http://www.clker.com/clipart-trash.html | ||||
|  | ||||
| ui_search_icon.png | ||||
| 	http://www.clker.com/clipart-24887.html | ||||
|  | ||||
| ui_off_icon.png / ui_on_icon.png | ||||
| 	http://www.clker.com/clipart-on-off-switches.html | ||||
|  | ||||
| ui_waypoints_icon.png | ||||
| 	http://www.clker.com/clipart-map-pin-red.html | ||||
|  | ||||
| ui_circular_arrows_icon.png | ||||
| 	http://www.clker.com/clipart-circular-arrow-pattern.html | ||||
|  | ||||
| ui_pencil_icon.pnc | ||||
| 	http://www.clker.com/clipart-2256.html | ||||
|  | ||||
| ui_waypoint_set_icon.png | ||||
| 	http://www.clker.com/clipart-larger-flag.html | ||||
|  | ||||
| ui_xyz_off_icon.png | ||||
| 	http://commons.wikimedia.org/wiki/File:No_sign.svg | ||||
|  | ||||
| ui_ok_icon.png | ||||
| 	http://commons.wikimedia.org/wiki/File:Yes_check.svg | ||||
|  | ||||
| inventory_plus_worldedit_gui.png | ||||
| 	http://commons.wikimedia.org/wiki/File:Erioll_world_2.svg | ||||
							
								
								
									
										214
									
								
								init.lua
									
									
									
									
									
								
							
							
						
						| @@ -1,202 +1,44 @@ | ||||
| -- Unified Inventory | ||||
|  | ||||
| if not minetest.features.formspec_version_element then | ||||
| 	-- At least formspec_version[] is the minimal feature requirement | ||||
| 	error("Unified Inventory requires Minetest version 5.4.0 or newer.\n" .. | ||||
| 		" Please update Minetest or use an older version of Unified Inventory.") | ||||
| end | ||||
| -- Unified Inventory for Minetest 0.4.8+ | ||||
|  | ||||
| local modpath = minetest.get_modpath(minetest.get_current_modname()) | ||||
| local worldpath = minetest.get_worldpath() | ||||
|  | ||||
| -- Data tables definitions | ||||
| unified_inventory = { | ||||
| 	activefilter = {}, | ||||
| 	active_search_direction = {}, | ||||
| 	alternate = {}, | ||||
| 	current_page = {}, | ||||
| 	current_searchbox = {}, | ||||
| 	current_category = {}, | ||||
| 	current_category_scroll = {}, | ||||
| 	current_index = {}, | ||||
| 	current_item = {}, | ||||
| 	current_craft_direction = {}, | ||||
| 	registered_craft_types = {}, | ||||
| 	crafts_for = {usage = {}, recipe = {} }, | ||||
| 	players = {}, | ||||
| 	items_list_size = 0, | ||||
| 	items_list = {}, | ||||
| 	filtered_items_list_size = {}, | ||||
| 	filtered_items_list = {}, | ||||
| 	pages = {}, | ||||
| 	buttons = {}, | ||||
| 	initialized_callbacks = {}, | ||||
| 	craft_registered_callbacks = {}, | ||||
| unified_inventory = {} | ||||
| unified_inventory.activefilter = {} | ||||
| unified_inventory.alternate = {} | ||||
| unified_inventory.current_page = {} | ||||
| unified_inventory.current_index = {} | ||||
| unified_inventory.current_item = {} | ||||
| unified_inventory.crafts_table = {} | ||||
| unified_inventory.crafts_table_count = 0 | ||||
| unified_inventory.players = {} | ||||
| unified_inventory.items_list_size = 0 | ||||
| unified_inventory.items_list = {} | ||||
| unified_inventory.filtered_items_list_size = {} | ||||
| unified_inventory.filtered_items_list = {} | ||||
| unified_inventory.pages = {} | ||||
| unified_inventory.buttons = {} | ||||
|  | ||||
| 	-- Homepos stuff | ||||
| 	home_pos = {}, | ||||
| 	home_filename =	worldpath.."/unified_inventory_home.home", | ||||
| -- Homepos stuff | ||||
| unified_inventory.home_pos = {} | ||||
| unified_inventory.home_filename = | ||||
| 		worldpath.."/unified_inventory_home.home" | ||||
|  | ||||
| 	-- Default inventory page | ||||
| 	default = "craft", | ||||
|  | ||||
| 	-- "Lite" mode | ||||
| 	lite_mode = minetest.settings:get_bool("unified_inventory_lite"), | ||||
|  | ||||
| 	-- Items automatically added to categories based on item definitions | ||||
| 	automatic_categorization = (minetest.settings:get_bool("unified_inventory_automatic_categorization") ~= false), | ||||
|  | ||||
| 	-- Trash enabled | ||||
| 	trash_enabled = (minetest.settings:get_bool("unified_inventory_trash") ~= false), | ||||
| 	imgscale = 1.25, | ||||
| 	list_img_offset = 0.13, | ||||
| 	standard_background = "bgcolor[#0000]background9[0,0;1,1;ui_formbg_9_sliced.png;true;16]", | ||||
|  | ||||
| 	hide_disabled_buttons = minetest.settings:get_bool("unified_inventory_hide_disabled_buttons", false), | ||||
|  | ||||
| 	version = 4 | ||||
| } | ||||
|  | ||||
| local ui = unified_inventory | ||||
|  | ||||
| -- These tables establish position and layout for the two UI styles. | ||||
| -- UI doesn't use formspec_[xy] anymore, but other mods may need them. | ||||
|  | ||||
| ui.style_full = { | ||||
| 	formspec_x = 1, | ||||
| 	formspec_y = 1, | ||||
| 	formw = 17.75, | ||||
| 	formh = 12.25, | ||||
| 	-- Item browser size, pos | ||||
| 	pagecols = 8, | ||||
| 	pagerows = 9, | ||||
| 	page_x = 10.75, | ||||
| 	page_y = 2.30, | ||||
| 	-- Item browser controls | ||||
| 	page_buttons_x = 11.60, | ||||
| 	page_buttons_y = 10.15, | ||||
| 	searchwidth = 3.4, | ||||
| 	-- Crafting grid positions | ||||
| 	craft_x = 2.8, | ||||
| 	craft_y = 1.15, | ||||
| 	craftresult_x = 7.8, | ||||
| 	craft_arrow_x = 6.55, | ||||
| 	craft_guide_x = 3.3, | ||||
| 	craft_guide_y = 1.15, | ||||
| 	craft_guide_arrow_x = 7.05, | ||||
| 	craft_guide_result_x = 8.3, | ||||
| 	craft_guide_resultstr_x = 0.3, | ||||
| 	craft_guide_resultstr_y = 0.6, | ||||
| 	give_btn_x = 0.25, | ||||
| 	-- Tab switching buttons | ||||
| 	main_button_x = 0.4, | ||||
| 	main_button_y = 11.0, | ||||
| 	main_button_cols = 12, | ||||
| 	main_button_rows = 1, | ||||
| 	-- Tab title position | ||||
| 	form_header_x = 0.4, | ||||
| 	form_header_y = 0.4, | ||||
| 	-- Generic sizes | ||||
| 	btn_spc = 0.85, | ||||
| 	btn_size = 0.75, | ||||
| 	std_inv_x = 0.3, | ||||
| 	std_inv_y = 5.75, | ||||
| } | ||||
|  | ||||
| ui.style_lite = { | ||||
| 	formspec_x =  0.6, | ||||
| 	formspec_y =  0.6, | ||||
| 	formw = 14, | ||||
| 	formh = 9.75, | ||||
| 	-- Item browser size, pos | ||||
| 	pagecols = 4, | ||||
| 	pagerows = 5, | ||||
| 	page_x = 10.5, | ||||
| 	page_y = 2.15, | ||||
| 	-- Item browser controls | ||||
| 	page_buttons_x = 10.5, | ||||
| 	page_buttons_y = 6.15, | ||||
| 	searchwidth = 1.6, | ||||
| 	-- Crafting grid positions | ||||
| 	craft_x = 2.6, | ||||
| 	craft_y = 0.75, | ||||
| 	craftresult_x = 5.75, | ||||
| 	craft_arrow_x = 6.35, | ||||
| 	craft_guide_x = 3.1, | ||||
| 	craft_guide_y = 0.75, | ||||
| 	craft_guide_arrow_x = 7.05, | ||||
| 	craft_guide_result_x = 8.3, | ||||
| 	craft_guide_resultstr_x = 0.15, | ||||
| 	craft_guide_resultstr_y = 0.35, | ||||
| 	give_btn_x = 0.15, | ||||
| 	-- Tab switching buttons | ||||
| 	main_button_x = 10.5, | ||||
| 	main_button_y = 8.15, | ||||
| 	main_button_cols = 4, | ||||
| 	main_button_rows = 2, | ||||
| 	-- Tab title position | ||||
| 	form_header_x =  0.2, | ||||
| 	form_header_y =  0.2, | ||||
| 	-- Generic sizes | ||||
| 	btn_spc = 0.8, | ||||
| 	btn_size = 0.7, | ||||
| 	std_inv_x = 0.1, | ||||
| 	std_inv_y = 4.6, | ||||
| } | ||||
|  | ||||
| dofile(modpath.."/api.lua") | ||||
|  | ||||
| for _, style in ipairs({ui.style_full, ui.style_lite}) do | ||||
| 	style.items_per_page =  style.pagecols * style.pagerows | ||||
| 	style.standard_inv = string.format("list[current_player;main;%f,%f;8,4;]", | ||||
| 							style.std_inv_x + ui.list_img_offset, style.std_inv_y + ui.list_img_offset) | ||||
|  | ||||
| 	style.standard_inv_bg = ui.make_inv_img_grid(style.std_inv_x, style.std_inv_y, 8, 1, true).. | ||||
| 							ui.make_inv_img_grid(style.std_inv_x, style.std_inv_y + ui.imgscale, 8, 3) | ||||
|  | ||||
| 	style.craft_grid =	table.concat({ | ||||
| 							ui.make_inv_img_grid(style.craft_x, style.craft_y, 3, 3), | ||||
| 							ui.single_slot(style.craft_x + ui.imgscale*4, style.craft_y), -- the craft result slot | ||||
| 							string.format("image[%f,%f;%f,%f;ui_crafting_arrow.png]", | ||||
| 							style.craft_arrow_x, style.craft_y, ui.imgscale, ui.imgscale), | ||||
| 							string.format("list[current_player;craft;%f,%f;3,3;]", | ||||
| 								style.craft_x + ui.list_img_offset, style.craft_y + ui.list_img_offset), | ||||
| 							string.format("list[current_player;craftpreview;%f,%f;1,1;]", | ||||
| 								style.craftresult_x + ui.list_img_offset, style.craft_y + ui.list_img_offset) | ||||
| 						}) | ||||
| end | ||||
| -- Default inventory page | ||||
| unified_inventory.default = "craft" | ||||
|  | ||||
| -- Disable default creative inventory | ||||
| local creative = rawget(_G, "creative") or rawget(_G, "creative_inventory") | ||||
| if creative then | ||||
| 	function creative.set_creative_formspec(player, start_i, pagenum) | ||||
| if creative_inventory then | ||||
| 	function creative_inventory.set_creative_formspec(player, start_i, pagenum) | ||||
| 		return | ||||
| 	end | ||||
| end | ||||
|  | ||||
| -- Disable sfinv inventory | ||||
| local sfinv = rawget(_G, "sfinv") | ||||
| if sfinv then | ||||
| 	sfinv.enabled = false | ||||
| end | ||||
|  | ||||
| dofile(modpath.."/group.lua") | ||||
| dofile(modpath.."/category.lua") | ||||
| dofile(modpath.."/default-categories.lua") | ||||
| dofile(modpath.."/datastorage.lua") | ||||
| dofile(modpath.."/api.lua") | ||||
| dofile(modpath.."/internal.lua") | ||||
| dofile(modpath.."/callbacks.lua") | ||||
| dofile(modpath.."/match_craft.lua") | ||||
| dofile(modpath.."/register.lua") | ||||
|  | ||||
| if minetest.settings:get_bool("unified_inventory_bags") ~= false then | ||||
| 	dofile(modpath.."/bags.lua") | ||||
| end | ||||
| if minetest.settings:get_bool("unified_inventory_item_names") ~= false then | ||||
| 	dofile(modpath.."/item_names.lua") | ||||
| end | ||||
| if minetest.settings:get_bool("unified_inventory_waypoints") ~= false then | ||||
| 	dofile(modpath.."/waypoints.lua") | ||||
| end | ||||
| dofile(modpath.."/legacy.lua") -- mod compatibility | ||||
|  | ||||
| minetest.log("action", "[unified_inventory] loaded.") | ||||
| dofile(modpath.."/bags.lua") | ||||
| dofile(modpath.."/waypoints.lua") | ||||
|   | ||||
							
								
								
									
										496
									
								
								internal.lua
									
									
									
									
									
								
							
							
						
						| @@ -1,429 +1,149 @@ | ||||
| local S = minetest.get_translator("unified_inventory") | ||||
| local F = minetest.formspec_escape | ||||
| local ui = unified_inventory | ||||
|  | ||||
| -- This pair of encoding functions is used where variable text must go in | ||||
| -- button names, where the text might contain formspec metacharacters. | ||||
| -- We can escape button names for the formspec, to avoid screwing up | ||||
| -- form structure overall, but they then don't get de-escaped, and so | ||||
| -- the input we get back from the button contains the formspec escaping. | ||||
| -- This is a game engine bug, and in the anticipation that it might be | ||||
| -- fixed some day we don't want to rely on it.  So for safety we apply | ||||
| -- an encoding that avoids all formspec metacharacters. | ||||
|  | ||||
| function ui.mangle_for_formspec(str) | ||||
| 	return string.gsub(str, "([^A-Za-z0-9])", function (c) return string.format("_%d_", string.byte(c)) end) | ||||
| end | ||||
| function ui.demangle_for_formspec(str) | ||||
| 	return string.gsub(str, "_([0-9]+)_", function (v) return string.char(v) end) | ||||
| end | ||||
|  | ||||
| -- Get the player-specific unified_inventory style | ||||
| function ui.get_per_player_formspec(player_name) | ||||
| 	local draw_lite_mode = ui.lite_mode and not minetest.check_player_privs(player_name, {ui_full=true}) | ||||
|  | ||||
| 	local style = table.copy(draw_lite_mode and ui.style_lite or ui.style_full) | ||||
| 	style.is_lite_mode = draw_lite_mode | ||||
| 	return style | ||||
| end | ||||
|  | ||||
| -- Creates an item image or regular image button with a tooltip | ||||
| local function formspec_button(ui_peruser, name, image, offset, pos, scale, label) | ||||
| 	local element = 'image_button' | ||||
| 	if minetest.registered_items[image] then | ||||
| 		element = 'item_image_button' | ||||
| 	elseif image:find(":", 1, true) then | ||||
| 		image = "unknown_item.png" | ||||
| 	end | ||||
| 	local spc = (1-scale)*ui_peruser.btn_size/2 | ||||
| 	local size = ui_peruser.btn_size*scale | ||||
| 	return string.format("%s[%f,%f;%f,%f;%s;%s;]", element, | ||||
| 		(offset.x or offset[1]) + ( ui_peruser.btn_spc * (pos.x or pos[1]) ) + spc, | ||||
| 		(offset.y or offset[2]) + ( ui_peruser.btn_spc * (pos.y or pos[2]) ) + spc, | ||||
| 		size, size, image, name) .. | ||||
| 		string.format("tooltip[%s;%s]", name, F(label or name)) | ||||
| end | ||||
|  | ||||
| -- Add registered buttons (tabs) | ||||
| local function formspec_tab_buttons(player, formspec, style) | ||||
| 	local n = #formspec + 1 | ||||
|  | ||||
| 	-- Main buttons | ||||
|  | ||||
| 	local filtered_inv_buttons = {} | ||||
|  | ||||
| 	for _, def in pairs(ui.buttons) do | ||||
| 		if not (style.is_lite_mode and def.hide_lite) then | ||||
| 			if def.condition == nil or def.condition(player) or not ui.hide_disabled_buttons then | ||||
| 				table.insert(filtered_inv_buttons, def) | ||||
| 			end | ||||
| 		end | ||||
| 	end | ||||
|  | ||||
| 	local needs_scrollbar = #filtered_inv_buttons > style.main_button_cols * style.main_button_rows | ||||
|  | ||||
| 	formspec[n] = ("scroll_container[%g,%g;%g,%g;tabbtnscroll;vertical]"):format( | ||||
| 		style.main_button_x, style.main_button_y, -- position | ||||
| 		style.main_button_cols * style.btn_spc, style.main_button_rows -- size | ||||
| 	) | ||||
| 	n = n + 1 | ||||
|  | ||||
| 	for i, def in pairs(filtered_inv_buttons) do | ||||
| 		local pos_x =           ((i - 1) % style.main_button_cols) * style.btn_spc | ||||
| 		local pos_y = math.floor((i - 1) / style.main_button_cols) * style.btn_spc | ||||
|  | ||||
| 		if def.type == "image" then | ||||
| 			if (def.condition == nil or def.condition(player)) then | ||||
| 				formspec[n] = string.format("image_button[%g,%g;%g,%g;%s;%s;]", | ||||
| 					pos_x, pos_y, style.btn_size, style.btn_size, | ||||
| 					F(def.image), | ||||
| 					F(def.name)) | ||||
| 				formspec[n+1] = "tooltip["..F(def.name)..";"..(def.tooltip or "").."]" | ||||
| 				n = n+2 | ||||
|  | ||||
| 			else | ||||
| 				formspec[n] = string.format("image[%g,%g;%g,%g;%s^[colorize:#808080:alpha]", | ||||
| 					pos_x, pos_y, style.btn_size, style.btn_size, | ||||
| 					def.image) | ||||
| 				n = n+1 | ||||
| 			end | ||||
| 		end | ||||
| 	end | ||||
| 	formspec[n] = "scroll_container_end[]" | ||||
| 	if needs_scrollbar then | ||||
| 		local total_rows = math.ceil(#filtered_inv_buttons / style.main_button_cols) | ||||
| 		formspec[n+1] = ("scrollbaroptions[max=%i;arrows=hide]"):format( | ||||
| 			-- This calculation is not 100% accurate but "good enough" | ||||
| 			(total_rows - style.main_button_rows) * style.btn_spc * 10 | ||||
| 		) | ||||
| 		formspec[n+2] = ("scrollbar[%g,%g;0.4,%g;vertical;tabbtnscroll;0]"):format( | ||||
| 			style.main_button_x + style.main_button_cols * style.btn_spc - 0.1, -- x pos | ||||
| 			style.main_button_y, -- y pos | ||||
| 			style.main_button_rows * style.btn_spc -- height | ||||
| 		) | ||||
| 		formspec[n+3] = "scrollbaroptions[max=1000;arrows=default]" | ||||
| 	end | ||||
| end | ||||
|  | ||||
| -- Add category GUI elements (top right) | ||||
| local function formspec_add_categories(player, formspec, ui_peruser) | ||||
| 	local player_name = player:get_player_name() | ||||
| 	local n = #formspec + 1 | ||||
|  | ||||
| 	local categories_pos = { | ||||
| 		ui_peruser.page_x, | ||||
| 		ui_peruser.page_y-ui_peruser.btn_spc-0.5 | ||||
| 	} | ||||
| 	local categories_scroll_pos = { | ||||
| 		ui_peruser.page_x, | ||||
| 		ui_peruser.form_header_y - (ui_peruser.is_lite_mode and 0 or 0.2) | ||||
| 	} | ||||
|  | ||||
| 	formspec[n] = string.format("background9[%f,%f;%f,%f;%s;false;16]", | ||||
| 		ui_peruser.page_x-0.15, categories_scroll_pos[2], | ||||
| 		(ui_peruser.btn_spc * ui_peruser.pagecols) + 0.2, 1.4 + (ui_peruser.is_lite_mode and 0 or 0.2), | ||||
| 		"ui_smallbg_9_sliced.png") | ||||
| 	n = n + 1 | ||||
|  | ||||
| 	formspec[n] = string.format("label[%f,%f;%s]", | ||||
| 		ui_peruser.page_x, | ||||
| 		ui_peruser.form_header_y + (ui_peruser.is_lite_mode and 0.3 or 0.2), F(S("Category:"))) | ||||
| 	n = n + 1 | ||||
|  | ||||
| 	local scroll_offset = 0 | ||||
| 	local category_count = #ui.category_list | ||||
| 	if category_count > ui_peruser.pagecols then | ||||
| 		scroll_offset = ui.current_category_scroll[player_name] | ||||
| 	end | ||||
|  | ||||
| 	for index, category in ipairs(ui.category_list) do | ||||
| 		local column = index - scroll_offset | ||||
| 		if column > 0 and column <= ui_peruser.pagecols then | ||||
| 			local scale = 0.8 | ||||
| 			if ui.current_category[player_name] == category.name then | ||||
| 				scale = 1 | ||||
| 			end | ||||
| 			formspec[n] = formspec_button(ui_peruser, "category_"..category.name, category.symbol, categories_pos, {column-1, 0}, scale, category.label) | ||||
| 			n = n + 1 | ||||
| 		end | ||||
| 	end | ||||
| 	if category_count > ui_peruser.pagecols and scroll_offset > 0 then | ||||
| 		-- prev | ||||
| 		formspec[n] = formspec_button(ui_peruser, "prev_category", "ui_left_icon.png", categories_scroll_pos, {ui_peruser.pagecols - 2, 0}, 0.8, S("Scroll categories left")) | ||||
| 		n = n + 1 | ||||
| 	end | ||||
| 	if category_count > ui_peruser.pagecols and category_count - scroll_offset > ui_peruser.pagecols then | ||||
| 		-- next | ||||
| 		formspec[n] = formspec_button(ui_peruser, "next_category", "ui_right_icon.png", categories_scroll_pos, {ui_peruser.pagecols - 1, 0}, 0.8, S("Scroll categories right")) | ||||
| 	end | ||||
| end | ||||
|  | ||||
| local function formspec_add_search_box(player, formspec, ui_peruser) | ||||
| 	local player_name = player:get_player_name() | ||||
| 	local n = #formspec + 1 | ||||
|  | ||||
| 	formspec[n] = "field_close_on_enter[searchbox;false]" | ||||
|  | ||||
| 	formspec[n+1] = string.format("field[%f,%f;%f,%f;searchbox;;%s]", | ||||
| 		ui_peruser.page_buttons_x, ui_peruser.page_buttons_y, | ||||
| 		ui_peruser.searchwidth - 0.1, ui_peruser.btn_size, | ||||
| 		F(ui.current_searchbox[player_name])) | ||||
| 	formspec[n+2] = string.format("image_button[%f,%f;%f,%f;ui_search_icon.png;searchbutton;]", | ||||
| 		ui_peruser.page_buttons_x + ui_peruser.searchwidth, ui_peruser.page_buttons_y, | ||||
| 		ui_peruser.btn_size,ui_peruser.btn_size) | ||||
| 	formspec[n+3] = "tooltip[searchbutton;" ..F(S("Search")) .. "]" | ||||
| 	formspec[n+4] = string.format("image_button[%f,%f;%f,%f;ui_reset_icon.png;searchresetbutton;]", | ||||
| 		ui_peruser.page_buttons_x + ui_peruser.searchwidth + ui_peruser.btn_spc, | ||||
| 		ui_peruser.page_buttons_y, | ||||
| 		ui_peruser.btn_size, ui_peruser.btn_size) | ||||
| 	formspec[n+5] = "tooltip[searchresetbutton;"..F(S("Reset search and display everything")).."]" | ||||
|  | ||||
| 	if ui.activefilter[player_name] ~= "" then | ||||
| 		formspec[n+6] = string.format("label[%f,%f;%s: %s]", | ||||
| 			ui_peruser.page_x, ui_peruser.page_y - 0.25, | ||||
| 			F(S("Filter")), F(ui.activefilter[player_name])) | ||||
| 	end | ||||
| end | ||||
|  | ||||
| local function formspec_add_item_browser(player, formspec, ui_peruser) | ||||
| 	local player_name = player:get_player_name() | ||||
| 	local n = #formspec + 1 | ||||
|  | ||||
| 	-- Controls to flip items pages | ||||
|  | ||||
| 	local btnlist = { | ||||
| 		{ "ui_skip_backward_icon.png", "start_list", S("First page") }, | ||||
| 		{ "ui_doubleleft_icon.png",    "rewind3",    S("Back three pages") }, | ||||
| 		{ "ui_left_icon.png",          "rewind1",    S("Back one page") }, | ||||
| 		{ "ui_right_icon.png",         "forward1",   S("Forward one page") }, | ||||
| 		{ "ui_doubleright_icon.png",   "forward3",   S("Forward three pages") }, | ||||
| 		{ "ui_skip_forward_icon.png",  "end_list",   S("Last page") }, | ||||
| 	} | ||||
|  | ||||
| 	if ui_peruser.is_lite_mode then | ||||
| 		btnlist[2] = nil | ||||
| 		btnlist[5] = nil | ||||
| 	end | ||||
|  | ||||
| 	local bn = 0 | ||||
| 	for _, b in pairs(btnlist) do | ||||
| 		formspec[n] =  string.format("image_button[%f,%f;%f,%f;%s;%s;]", | ||||
| 			ui_peruser.page_buttons_x + ui_peruser.btn_spc*bn, | ||||
| 			ui_peruser.page_buttons_y + ui_peruser.btn_spc, | ||||
| 			ui_peruser.btn_size, ui_peruser.btn_size, | ||||
| 			b[1],b[2]) | ||||
| 		formspec[n+1] = "tooltip["..b[2]..";"..F(b[3]).."]" | ||||
| 		bn = bn + 1 | ||||
| 		n = n + 2 | ||||
| 	end | ||||
|  | ||||
| 	-- Items list | ||||
| 	if #ui.filtered_items_list[player_name] == 0 then | ||||
| 		local no_matches = S("No matching items") | ||||
| 		if ui_peruser.is_lite_mode then | ||||
| 			no_matches = S("No matches.") | ||||
| 		end | ||||
|  | ||||
| 		formspec[n] = "label["..ui_peruser.page_x..","..(ui_peruser.page_y+0.15)..";" .. F(no_matches) .. "]" | ||||
| 		return | ||||
| 	end | ||||
|  | ||||
| 	local dir = ui.active_search_direction[player_name] | ||||
| 	local list_index = ui.current_index[player_name] | ||||
| 	local page2 = math.floor(list_index / (ui_peruser.items_per_page) + 1) | ||||
| 	local pagemax = math.floor( | ||||
| 		(#ui.filtered_items_list[player_name] - 1) | ||||
| 			/ (ui_peruser.items_per_page) + 1) | ||||
| 	for y = 0, ui_peruser.pagerows - 1 do | ||||
| 		for x = 0, ui_peruser.pagecols - 1 do | ||||
| 			local name = ui.filtered_items_list[player_name][list_index] | ||||
| 			local item = minetest.registered_items[name] | ||||
| 			if item then | ||||
| 				-- Clicked on current item: Flip crafting direction | ||||
| 				if name == ui.current_item[player_name] then | ||||
| 					local cdir = ui.current_craft_direction[player_name] | ||||
| 					if cdir == "recipe" then | ||||
| 						dir = "usage" | ||||
| 					elseif cdir == "usage" then | ||||
| 						dir = "recipe" | ||||
| 					end | ||||
| 				else | ||||
| 				-- Default: use active search direction by default | ||||
| 					dir = ui.active_search_direction[player_name] | ||||
| 				end | ||||
|  | ||||
| 				local button_name = "item_button_" .. dir .. "_" | ||||
| 					.. ui.mangle_for_formspec(name) | ||||
| 				formspec[n] = ("item_image_button[%f,%f;%f,%f;%s;%s;]"):format( | ||||
| 					ui_peruser.page_x + x * ui_peruser.btn_spc, | ||||
| 					ui_peruser.page_y + y * ui_peruser.btn_spc, | ||||
| 					ui_peruser.btn_size, ui_peruser.btn_size, | ||||
| 					name, button_name | ||||
| 				) | ||||
| 				local tooltip = item.description | ||||
| 				if item.mod_origin then | ||||
| 					-- "mod_origin" may not be specified for items that were | ||||
| 					-- registered in a callback (during or before ServerEnv init) | ||||
| 					tooltip = tooltip .. " [" .. item.mod_origin .. "]" | ||||
| 				end | ||||
| 				formspec[n + 1] = ("tooltip[%s;%s]"):format( | ||||
| 					button_name, minetest.formspec_escape(tooltip) | ||||
| 				) | ||||
| 				n = n + 2 | ||||
| 				list_index = list_index + 1 | ||||
| 			end | ||||
| 		end | ||||
| 	end | ||||
| 	formspec[n] = "style[page_number;content_offset=0]" | ||||
| 	formspec[n + 1] = string.format("image_button[%f,%f;%f,0.4;;page_number;%s: %s;false;false;]", | ||||
| 		ui_peruser.page_buttons_x, | ||||
| 		ui_peruser.page_buttons_y + ui_peruser.btn_spc * 2 - 0.1, | ||||
| 		ui_peruser.btn_spc * (bn - 1) + ui_peruser.btn_size, | ||||
| 		F(S("Page")), S("@1 of @2",page2,pagemax)) | ||||
| end | ||||
|  | ||||
| function ui.get_formspec(player, page) | ||||
|  | ||||
| function unified_inventory.get_formspec(player, page) | ||||
| 	if not player then | ||||
| 		return "" | ||||
| 	end | ||||
|  | ||||
| 	local player_name = player:get_player_name() | ||||
| 	local ui_peruser = ui.get_per_player_formspec(player_name) | ||||
| 	unified_inventory.current_page[player_name] = page | ||||
| 	local pagedef = unified_inventory.pages[page] | ||||
|  | ||||
| 	ui.current_page[player_name] = page | ||||
| 	local pagedef = ui.pages[page] | ||||
| 	local formspec = "size[14,10]" | ||||
| 	local fsdata = nil | ||||
|  | ||||
| 	if not pagedef then | ||||
| 	-- Background | ||||
| 	formspec = formspec .. "background[-0.19,-0.25;14.4,10.75;ui_form_bg.png]" | ||||
| 	-- Current page | ||||
| 	if unified_inventory.pages[page] then | ||||
| 		fsdata = pagedef.get_formspec(player) | ||||
| 		formspec = formspec .. fsdata.formspec | ||||
| 	else | ||||
| 		return "" -- Invalid page name | ||||
| 	end | ||||
|  | ||||
| 	local fs = { | ||||
| 		"formspec_version[4]", | ||||
| 		"size["..ui_peruser.formw..","..ui_peruser.formh.."]", | ||||
| 		pagedef.formspec_prepend and "" or "no_prepend[]", | ||||
| 		ui.standard_background | ||||
| 	} | ||||
|  | ||||
| 	local perplayer_formspec = ui.get_per_player_formspec(player_name) | ||||
| 	local fsdata = pagedef.get_formspec(player, perplayer_formspec) | ||||
|  | ||||
| 	fs[#fs + 1] = fsdata.formspec | ||||
|  | ||||
| 	formspec_tab_buttons(player, fs, ui_peruser) | ||||
| 	-- Main buttons | ||||
| 	for i, def in pairs(unified_inventory.buttons) do | ||||
| 		if def.type == "image" then | ||||
| 			formspec = formspec.."image_button[" | ||||
| 					..(0.65 * (i - 1))..",9;0.8,0.8;" | ||||
| 					..minetest.formspec_escape(def.image)..";" | ||||
| 					..minetest.formspec_escape(def.name)..";]" | ||||
| 		end | ||||
| 	end | ||||
|  | ||||
| 	if fsdata.draw_inventory ~= false then | ||||
| 		-- Player inventory | ||||
| 		fs[#fs + 1] = "listcolors[#00000000;#00000000]" | ||||
| 		fs[#fs + 1] = ui_peruser.standard_inv | ||||
| 		formspec = formspec.."listcolors[#00000000;#00000000]" | ||||
| 		formspec = formspec .. "list[current_player;main;0,4.5;8,4;]" | ||||
| 	end | ||||
|  | ||||
| 	if fsdata.draw_item_list == false then | ||||
| 		return table.concat(fs, "") | ||||
| 		return formspec | ||||
| 	end | ||||
|  | ||||
| 	formspec_add_categories(player, fs, ui_peruser) | ||||
| 	formspec_add_search_box(player, fs, ui_peruser) | ||||
| 	formspec_add_item_browser(player, fs, ui_peruser) | ||||
| 	-- Controls to flip items pages | ||||
| 	local start_x = 9.2 | ||||
| 	formspec = formspec .. "image_button["..(start_x + 0.6 * 0)..",9;.8,.8;ui_skip_backward_icon.png;start_list;]" | ||||
| 	formspec = formspec .. "image_button["..(start_x + 0.6 * 1)..",9;.8,.8;ui_doubleleft_icon.png;rewind3;]" | ||||
| 	formspec = formspec .. "image_button["..(start_x + 0.6 * 2)..",9;.8,.8;ui_left_icon.png;rewind1;]" | ||||
| 	formspec = formspec .. "image_button["..(start_x + 0.6 * 3)..",9;.8,.8;ui_right_icon.png;forward1;]" | ||||
| 	formspec = formspec .. "image_button["..(start_x + 0.6 * 4)..",9;.8,.8;ui_doubleright_icon.png;forward3;]" | ||||
| 	formspec = formspec .. "image_button["..(start_x + 0.6 * 5)..",9;.8,.8;ui_skip_forward_icon.png;end_list;]" | ||||
|  | ||||
| 	return table.concat(fs) | ||||
| 	-- Search box | ||||
| 	formspec = formspec .. "field[9.5,8.325;3,1;searchbox;;]" | ||||
| 	formspec = formspec .. "image_button[12.2,8.1;.8,.8;ui_search_icon.png;searchbutton;]" | ||||
|  | ||||
| 	-- Items list | ||||
| 	local list_index = unified_inventory.current_index[player_name] | ||||
| 	local page = math.floor(list_index / (80) + 1) | ||||
| 	local pagemax = math.floor( | ||||
| 		(#unified_inventory.filtered_items_list[player_name] - 1) | ||||
| 			/ (80) + 1) | ||||
| 	local item = {} | ||||
| 	for y = 0, 9 do | ||||
| 	for x = 0, 7 do | ||||
| 		local name = unified_inventory.filtered_items_list[player_name][list_index] | ||||
| 		if minetest.registered_items[name] then | ||||
| 			formspec = formspec.."item_image_button[" | ||||
| 					..(8.2 + x * 0.7).."," | ||||
| 					..(1   + y * 0.7)..";.81,.81;" | ||||
| 					..name..";item_button_" | ||||
| 					..name..";]" | ||||
| 			list_index = list_index + 1 | ||||
| 		end | ||||
| 	end | ||||
| 	end | ||||
| 	formspec = formspec.."label[8.2,0;Page:]" | ||||
| 	formspec = formspec.."label[9,0;"..page.." of "..pagemax.."]" | ||||
| 	formspec = formspec.."label[8.2,0.4;Filter:]" | ||||
| 	formspec = formspec.."label[9,0.4;"..unified_inventory.activefilter[player_name].."]" | ||||
| 	return formspec | ||||
| end | ||||
|  | ||||
| function ui.set_inventory_formspec(player, page) | ||||
| function unified_inventory.set_inventory_formspec(player, page) | ||||
| 	if player then | ||||
| 		player:set_inventory_formspec(ui.get_formspec(player, page)) | ||||
| 		local formspec = unified_inventory.get_formspec(player, page) | ||||
| 		player:set_inventory_formspec(formspec) | ||||
| 	end | ||||
| end | ||||
|  | ||||
| function ui.is_itemdef_listable(def) | ||||
| 	return (not def.groups.not_in_creative_inventory | ||||
| 			or def.groups.not_in_creative_inventory == 0) | ||||
| 		and def.description | ||||
| 		and def.description ~= "" | ||||
| end | ||||
|  | ||||
| --apply filter to the inventory list (create filtered copy of full one) | ||||
| function ui.apply_filter(player, filter, search_dir) | ||||
| 	if not player then | ||||
| 		return false | ||||
| 	end | ||||
| function unified_inventory.apply_filter(player, filter) | ||||
| 	local player_name = player:get_player_name() | ||||
|  | ||||
| 	local size = 0 | ||||
| 	local lfilter = string.lower(filter) | ||||
| 	local ffilter | ||||
| 	if not pcall(function() ("technic:test"):find(lfilter) end) then | ||||
| 		-- Filter is invalid | ||||
| 		lfilter = "" | ||||
| 	end | ||||
| 	unified_inventory.filtered_items_list[player_name]={} | ||||
| 	if lfilter:sub(1, 6) == "group:" then | ||||
| 		-- Group filter: all groups of the item must match | ||||
| 		local groups = lfilter:sub(7):split(",") | ||||
| 		ffilter = function(name, def) | ||||
| 			for _, group in ipairs(groups) do | ||||
| 				if not def.groups[group] | ||||
| 				or def.groups[group] <= 0 then | ||||
| 					return false | ||||
| 		for name, def in pairs(minetest.registered_items) do | ||||
| 			if def.groups then | ||||
| 				local all = true | ||||
| 				for _, group in ipairs(groups) do | ||||
| 					if not (def.groups[group] and (def.groups[group] > 0)) then | ||||
| 						all = false | ||||
| 						break | ||||
| 					end | ||||
| 				end | ||||
| 				if all then | ||||
| 					table.insert(unified_inventory.filtered_items_list[player_name], name) | ||||
| 					size = size + 1 | ||||
| 				end | ||||
| 			end | ||||
| 			return true | ||||
| 		end | ||||
| 	else | ||||
| 		-- Name filter: fuzzy match item names and descriptions | ||||
| 		local player_info = minetest.get_player_information(player_name) | ||||
| 		local lang = player_info and player_info.lang_code or "" | ||||
|  | ||||
| 		ffilter = function(name, def) | ||||
| 			local lname = string.lower(name) | ||||
| 			local ldesc = string.lower(def.description) | ||||
| 			local llocaldesc = minetest.get_translated_string | ||||
| 				and string.lower(minetest.get_translated_string(lang, def.description)) | ||||
| 			return string.find(lname, lfilter, 1, true) or string.find(ldesc, lfilter, 1, true) | ||||
| 				or llocaldesc and string.find(llocaldesc, lfilter, 1, true) | ||||
| 		end | ||||
| 	end | ||||
|  | ||||
| 	local is_itemdef_listable = ui.is_itemdef_listable | ||||
| 	local filtered_items = {} | ||||
|  | ||||
| 	local category = ui.current_category[player_name] or 'all' | ||||
| 	if category == 'all' then | ||||
| 		for name, def in pairs(minetest.registered_items) do | ||||
| 			if is_itemdef_listable(def) | ||||
| 			and ffilter(name, def) then | ||||
| 				table.insert(filtered_items, name) | ||||
| 			end | ||||
| 		end | ||||
| 	elseif category == 'uncategorized' then | ||||
| 		for name, def in pairs(minetest.registered_items) do | ||||
| 			if is_itemdef_listable(def) | ||||
| 			and not ui.find_category(name) | ||||
| 			and ffilter(name, def) then | ||||
| 				table.insert(filtered_items, name) | ||||
| 			end | ||||
| 		end | ||||
| 	else | ||||
| 		-- Any other category is selected | ||||
| 		for name, exists in pairs(ui.registered_category_items[category]) do | ||||
| 			local def = minetest.registered_items[name] | ||||
| 			if exists and def | ||||
| 			and is_itemdef_listable(def) | ||||
| 			and ffilter(name, def) then | ||||
| 				table.insert(filtered_items, name) | ||||
| 			if (not def.groups.not_in_creative_inventory or | ||||
| 			   def.groups.not_in_creative_inventory == 0) | ||||
| 			   and def.description and def.description ~= "" then | ||||
| 				local lname = string.lower(name) | ||||
| 				local ldesc = string.lower(def.description) | ||||
| 				if string.find(lname, lfilter) or string.find(ldesc, lfilter) then | ||||
| 					table.insert(unified_inventory.filtered_items_list[player_name], name) | ||||
| 					size = size + 1 | ||||
| 				end | ||||
| 			end | ||||
| 		end | ||||
| 	end | ||||
| 	table.sort(filtered_items) | ||||
|  | ||||
| 	ui.filtered_items_list_size[player_name] = #filtered_items | ||||
| 	ui.filtered_items_list[player_name] = filtered_items | ||||
| 	ui.current_index[player_name] = 1 | ||||
| 	ui.activefilter[player_name] = filter | ||||
| 	ui.active_search_direction[player_name] = search_dir | ||||
| 	ui.set_inventory_formspec(player, ui.current_page[player_name]) | ||||
| 	table.sort(unified_inventory.filtered_items_list[player_name]) | ||||
| 	unified_inventory.filtered_items_list_size[player_name] = size | ||||
| 	unified_inventory.current_index[player_name] = 1 | ||||
| 	unified_inventory.activefilter[player_name] = filter | ||||
| 	unified_inventory.set_inventory_formspec(player, | ||||
| 			unified_inventory.current_page[player_name]) | ||||
| end | ||||
|  | ||||
| -- Inform players about potential visual issues | ||||
| minetest.register_on_joinplayer(function(player) | ||||
| 	local player_name = player:get_player_name() | ||||
| 	local info = minetest.get_player_information(player_name) | ||||
| 	if info and (info.formspec_version or 0) < 4 then | ||||
| 		minetest.chat_send_player(player_name, S("Unified Inventory: Your game version is too old" | ||||
| 			.. " and does not support the GUI requirements. You might experience visual issues.")) | ||||
| function unified_inventory.items_in_group(groups) | ||||
| 	local items = {} | ||||
| 	for name, item in pairs(minetest.registered_items) do | ||||
| 		for _, group in pairs(groups:split(',')) do | ||||
| 			if item.groups[group] then | ||||
| 				table.insert(items, name) | ||||
| 			end | ||||
| 		end | ||||
| 	end | ||||
| end) | ||||
| 	return items | ||||
| end | ||||
|   | ||||
| @@ -1,87 +0,0 @@ | ||||
| -- Based on 4itemnames mod by 4aiman | ||||
|  | ||||
| local item_names = {} -- [player_name] = { hud, dtime, itemname } | ||||
| local dlimit = 3  -- HUD element will be hidden after this many seconds | ||||
| local hudbars_mod = minetest.get_modpath("hudbars") | ||||
| local only_names = minetest.settings:get_bool("unified_inventory_only_names", true) | ||||
| local max_length = tonumber(minetest.settings:get("unified_inventory_max_item_name_length")) or 80 | ||||
|  | ||||
| local function set_hud(player) | ||||
| 	local player_name = player:get_player_name() | ||||
| 	local off = {x=0, y=-65} | ||||
| 	if hudbars_mod then | ||||
| 		-- Assume no alignment (2 per line) | ||||
| 		off.y = off.y - math.ceil(hb.hudbars_count / 2) * 25 | ||||
| 	else | ||||
| 		off.y = off.y - 25 | ||||
| 	end | ||||
|  | ||||
| 	item_names[player_name] = { | ||||
| 		hud = player:hud_add({ | ||||
| 			hud_elem_type = "text", | ||||
| 			position = {x=0.5, y=1}, | ||||
| 			offset = off, | ||||
| 			alignment = {x=0, y=-1}, | ||||
| 			number = 0xFFFFFF, | ||||
| 			text = "", | ||||
| 		}), | ||||
| 		dtime = dlimit, | ||||
| 		index = 1, | ||||
| 		itemname = "" | ||||
| 	} | ||||
| end | ||||
|  | ||||
| minetest.register_on_joinplayer(function(player) | ||||
| 	minetest.after(0, set_hud, player) | ||||
| end) | ||||
|  | ||||
| minetest.register_on_leaveplayer(function(player) | ||||
| 	item_names[player:get_player_name()] = nil | ||||
| end) | ||||
|  | ||||
| minetest.register_globalstep(function(dtime) | ||||
| 	for _, player in pairs(minetest.get_connected_players()) do | ||||
| 		local data = item_names[player:get_player_name()] | ||||
| 		if not data or not data.hud then | ||||
| 			data = {} -- Update on next step | ||||
| 			set_hud(player) | ||||
| 		end | ||||
|  | ||||
| 		local index = player:get_wield_index() | ||||
| 		local stack = player:get_wielded_item() | ||||
| 		local itemname = stack:get_name() | ||||
|  | ||||
| 		if data.hud and data.dtime < dlimit then | ||||
| 			data.dtime = data.dtime + dtime | ||||
| 			if data.dtime > dlimit then | ||||
| 				player:hud_change(data.hud, 'text', "") | ||||
| 			end | ||||
| 		end | ||||
|  | ||||
| 		if data.hud and (itemname ~= data.itemname or index ~= data.index) then | ||||
| 			data.itemname = itemname | ||||
| 			data.index = index | ||||
| 			data.dtime = 0 | ||||
| 			local lang_code = minetest.get_player_information(player:get_player_name()).lang_code | ||||
|  | ||||
| 			local desc = stack.get_meta | ||||
| 				and stack:get_meta():get_string("description") | ||||
|  | ||||
| 			if not desc or desc == "" then | ||||
| 				-- Try to use default description when none is set in the meta | ||||
| 				local def = minetest.registered_items[itemname] | ||||
| 				desc = def and def.description or "" | ||||
| 			end | ||||
| 			if only_names and desc and string.find(desc, "\n") then | ||||
| 				desc = string.match(desc, "([^\n]*)") | ||||
| 			end | ||||
| 			desc = minetest.get_translated_string(lang_code, desc) | ||||
| 			desc = minetest.strip_colors(desc) | ||||
| 			if string.len(desc) > max_length and max_length > 0 then | ||||
| 				desc = string.sub(desc, 1, max_length) .. " [...]" | ||||
| 			end | ||||
| 			player:hud_change(data.hud, 'text', desc) | ||||
| 		end | ||||
| 	end | ||||
| end) | ||||
|  | ||||
							
								
								
									
										55
									
								
								legacy.lua
									
									
									
									
									
								
							
							
						
						| @@ -1,55 +0,0 @@ | ||||
| -- Inefficient pattern matching | ||||
|  | ||||
| local warned_funcs = {} | ||||
| local function LOG_ONCE(funcname) | ||||
| 	if warned_funcs[funcname] then return end | ||||
| 	warned_funcs[funcname] = true | ||||
| 	minetest.log("error", "Call to undocumented, deprecated API '" .. funcname .. "'." | ||||
| 		.. " In a future version of Unified Inventory this will result in a real error.") | ||||
| end | ||||
|  | ||||
| function unified_inventory.canonical_item_spec_matcher(spec) | ||||
| 	LOG_ONCE("canonical_item_spec_matcher") | ||||
| 	local specname = ItemStack(spec):get_name() | ||||
| 	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] | ||||
| 		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 | ||||
|  | ||||
| function unified_inventory.item_matches_spec(item, spec) | ||||
| 	LOG_ONCE("item_matches_spec") | ||||
| 	local itemname = ItemStack(item):get_name() | ||||
| 	return unified_inventory.canonical_item_spec_matcher(spec)(itemname) | ||||
| end | ||||
|  | ||||
|  | ||||
| unified_inventory.registered_group_items = { | ||||
| 	mesecon_conductor_craftable = "mesecons:wire_00000000_off", | ||||
| 	stone = "default:cobble", | ||||
| 	wood = "default:wood", | ||||
| 	book = "default:book", | ||||
| 	sand = "default:sand", | ||||
| 	leaves = "default:leaves", | ||||
| 	tree = "default:tree", | ||||
| 	vessel = "vessels:glass_bottle", | ||||
| 	wool = "wool:white", | ||||
| } | ||||
|  | ||||
| function unified_inventory.register_group_item(groupname, itemname) | ||||
| 	LOG_ONCE("register_group_item") | ||||
| 	unified_inventory.registered_group_items[groupname] = itemname | ||||
| end | ||||
|  | ||||
| @@ -1,358 +0,0 @@ | ||||
| # LANGUAGE translation for the unified_inventory mod. | ||||
| # Copyright (C) 2018 Maciej Kasatkin (RealBadAngel) | ||||
| # This file is distributed under the same license as the unified_inventory package. | ||||
| # FIRST AUTHOR <EMAIL@ADDRESS>, YEAR. | ||||
| # | ||||
| #, fuzzy | ||||
| msgid "" | ||||
| msgstr "" | ||||
| "Project-Id-Version: unified_inventory\n" | ||||
| "Report-Msgid-Bugs-To: \n" | ||||
| "POT-Creation-Date: 2018-04-02 03:34+0200\n" | ||||
| "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" | ||||
| "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" | ||||
| "Language-Team: LANGUAGE <LL@li.org>\n" | ||||
| "Language: \n" | ||||
| "MIME-Version: 1.0\n" | ||||
| "Content-Type: text/plain; charset=UTF-8\n" | ||||
| "Content-Transfer-Encoding: 8bit\n" | ||||
|  | ||||
| #: api.lua register.lua | ||||
| msgid "Crafting" | ||||
| msgstr "" | ||||
|  | ||||
| #: api.lua | ||||
| msgid "Mixing" | ||||
| msgstr "" | ||||
|  | ||||
| #: api.lua | ||||
| msgid "Cooking" | ||||
| msgstr "" | ||||
|  | ||||
| #: api.lua | ||||
| msgid "Digging" | ||||
| msgstr "" | ||||
|  | ||||
| #: bags.lua | ||||
| msgid "Bags" | ||||
| msgstr "" | ||||
|  | ||||
| #: bags.lua | ||||
| msgid "Bag @1" | ||||
| msgstr "" | ||||
|  | ||||
| #: bags.lua | ||||
| msgid "Small Bag" | ||||
| msgstr "" | ||||
|  | ||||
| #: bags.lua | ||||
| msgid "Medium Bag" | ||||
| msgstr "" | ||||
|  | ||||
| #: bags.lua | ||||
| msgid "Large Bag" | ||||
| msgstr "" | ||||
|  | ||||
| #: group.lua | ||||
| msgid " and " | ||||
| msgstr "" | ||||
|  | ||||
| #: internal.lua | ||||
| msgid "First page" | ||||
| msgstr "" | ||||
|  | ||||
| #: internal.lua | ||||
| msgid "Back three pages" | ||||
| msgstr "" | ||||
|  | ||||
| #: internal.lua | ||||
| msgid "Back one page" | ||||
| msgstr "" | ||||
|  | ||||
| #: internal.lua | ||||
| msgid "Forward one page" | ||||
| msgstr "" | ||||
|  | ||||
| #: internal.lua | ||||
| msgid "Forward three pages" | ||||
| msgstr "" | ||||
|  | ||||
| #: internal.lua | ||||
| msgid "Last page" | ||||
| msgstr "" | ||||
|  | ||||
| #: internal.lua | ||||
| msgid "Search" | ||||
| msgstr "" | ||||
|  | ||||
| #: internal.lua | ||||
| msgid "Reset search and display everything" | ||||
| msgstr "" | ||||
|  | ||||
| #: internal.lua | ||||
| msgid "No matching items" | ||||
| msgstr "" | ||||
|  | ||||
| #: internal.lua | ||||
| msgid "No matches." | ||||
| msgstr "" | ||||
|  | ||||
| #: internal.lua | ||||
| msgid "Page" | ||||
| msgstr "" | ||||
|  | ||||
| #: internal.lua | ||||
| #, lua-format | ||||
| msgid "%s of %s" | ||||
| msgstr "" | ||||
|  | ||||
| #: internal.lua | ||||
| msgid "Filter" | ||||
| msgstr "" | ||||
|  | ||||
| #: register.lua | ||||
| msgid "Can use the creative inventory" | ||||
| msgstr "" | ||||
|  | ||||
| #: register.lua | ||||
| msgid "" | ||||
| "Forces Unified Inventory to be displayed in Full mode if Lite mode is " | ||||
| "configured globally" | ||||
| msgstr "" | ||||
|  | ||||
| #: register.lua | ||||
| msgid "Crafting Grid" | ||||
| msgstr "" | ||||
|  | ||||
| #: register.lua | ||||
| msgid "Crafting Guide" | ||||
| msgstr "" | ||||
|  | ||||
| #: register.lua | ||||
| msgid "Set home position" | ||||
| msgstr "" | ||||
|  | ||||
| #: register.lua | ||||
| #, lua-format | ||||
| msgid "Home position set to: %s" | ||||
| msgstr "" | ||||
|  | ||||
| #: register.lua | ||||
| msgid "You don't have the \"home\" privilege!" | ||||
| msgstr "" | ||||
|  | ||||
| #: register.lua | ||||
| msgid "Go home" | ||||
| msgstr "" | ||||
|  | ||||
| #: register.lua | ||||
| msgid "Set time to day" | ||||
| msgstr "" | ||||
|  | ||||
| #: register.lua | ||||
| msgid "Time of day set to 6am" | ||||
| msgstr "" | ||||
|  | ||||
| #: register.lua | ||||
| msgid "You don't have the settime privilege!" | ||||
| msgstr "" | ||||
|  | ||||
| #: register.lua | ||||
| msgid "Set time to night" | ||||
| msgstr "" | ||||
|  | ||||
| #: register.lua | ||||
| msgid "Time of day set to 9pm" | ||||
| msgstr "" | ||||
|  | ||||
| #: register.lua | ||||
| msgid "Clear inventory" | ||||
| msgstr "" | ||||
|  | ||||
| #: register.lua | ||||
| msgid "" | ||||
| "This button has been disabled outside of creative mode to prevent accidental " | ||||
| "inventory trashing.\n" | ||||
| "Use the trash slot instead." | ||||
| msgstr "" | ||||
|  | ||||
| #: register.lua | ||||
| msgid "Inventory cleared!" | ||||
| msgstr "" | ||||
|  | ||||
| #: register.lua | ||||
| msgid "Trash:" | ||||
| msgstr "" | ||||
|  | ||||
| #: register.lua | ||||
| msgid "Refill:" | ||||
| msgstr "" | ||||
|  | ||||
| #: register.lua | ||||
| #, lua-format | ||||
| msgid "Any item belonging to the %s group" | ||||
| msgstr "" | ||||
|  | ||||
| #: register.lua | ||||
| #, lua-format | ||||
| msgid "Any item belonging to the groups %s" | ||||
| msgstr "" | ||||
|  | ||||
| #: register.lua | ||||
| #, lua-format | ||||
| msgid "Recipe %d of %d" | ||||
| msgstr "" | ||||
|  | ||||
| #: register.lua | ||||
| #, lua-format | ||||
| msgid "Usage %d of %d" | ||||
| msgstr "" | ||||
|  | ||||
| #: register.lua | ||||
| msgid "No recipes" | ||||
| msgstr "" | ||||
|  | ||||
| #: register.lua | ||||
| msgid "No usages" | ||||
| msgstr "" | ||||
|  | ||||
| #: register.lua | ||||
| msgid "Result" | ||||
| msgstr "" | ||||
|  | ||||
| #: register.lua | ||||
| msgid "Ingredient" | ||||
| msgstr "" | ||||
|  | ||||
| #: register.lua | ||||
| msgid "Show next recipe" | ||||
| msgstr "" | ||||
|  | ||||
| #: register.lua | ||||
| msgid "Show next usage" | ||||
| msgstr "" | ||||
|  | ||||
| #: register.lua | ||||
| msgid "Show previous recipe" | ||||
| msgstr "" | ||||
|  | ||||
| #: register.lua | ||||
| msgid "Show previous usage" | ||||
| msgstr "" | ||||
|  | ||||
| #: register.lua | ||||
| #, lua-format | ||||
| msgid "%s (%s)" | ||||
| msgstr "" | ||||
|  | ||||
| #: register.lua | ||||
| msgid "Give me:" | ||||
| msgstr "" | ||||
|  | ||||
| #: register.lua | ||||
| msgid "" | ||||
| "This recipe is too\n" | ||||
| "large to be displayed." | ||||
| msgstr "" | ||||
|  | ||||
| #: register.lua | ||||
| msgid "To craft grid:" | ||||
| msgstr "" | ||||
|  | ||||
| #: register.lua | ||||
| msgid "All" | ||||
| msgstr "" | ||||
|  | ||||
| #: waypoints.lua | ||||
| msgid "White" | ||||
| msgstr "" | ||||
|  | ||||
| #: waypoints.lua | ||||
| msgid "Yellow" | ||||
| msgstr "" | ||||
|  | ||||
| #: waypoints.lua | ||||
| msgid "Red" | ||||
| msgstr "" | ||||
|  | ||||
| #: waypoints.lua | ||||
| msgid "Green" | ||||
| msgstr "" | ||||
|  | ||||
| #: waypoints.lua | ||||
| msgid "Blue" | ||||
| msgstr "" | ||||
|  | ||||
| #: waypoints.lua | ||||
| msgid "Waypoints" | ||||
| msgstr "" | ||||
|  | ||||
| #: waypoints.lua | ||||
| #, lua-format | ||||
| msgid "Select Waypoint #%d" | ||||
| msgstr "" | ||||
|  | ||||
| #: waypoints.lua | ||||
| #, lua-format | ||||
| msgid "Waypoint %d" | ||||
| msgstr "" | ||||
|  | ||||
| #: waypoints.lua | ||||
| msgid "Set waypoint to current location" | ||||
| msgstr "" | ||||
|  | ||||
| #: waypoints.lua | ||||
| msgid "invisible" | ||||
| msgstr "" | ||||
|  | ||||
| #: waypoints.lua | ||||
| msgid "visible" | ||||
| msgstr "" | ||||
|  | ||||
| #: waypoints.lua | ||||
| msgid "Make waypoint @1" | ||||
| msgstr "" | ||||
|  | ||||
| #: waypoints.lua | ||||
| msgid "Disable" | ||||
| msgstr "" | ||||
|  | ||||
| #: waypoints.lua | ||||
| msgid "Enable" | ||||
| msgstr "" | ||||
|  | ||||
| #: waypoints.lua | ||||
| msgid "@1 display of waypoint coordinates" | ||||
| msgstr "" | ||||
|  | ||||
| #: waypoints.lua | ||||
| msgid "Change color of waypoint display" | ||||
| msgstr "" | ||||
|  | ||||
| #: waypoints.lua | ||||
| msgid "Edit waypoint name" | ||||
| msgstr "" | ||||
|  | ||||
| #: waypoints.lua | ||||
| msgid "Waypoint active" | ||||
| msgstr "" | ||||
|  | ||||
| #: waypoints.lua | ||||
| msgid "Waypoint inactive" | ||||
| msgstr "" | ||||
|  | ||||
| #: waypoints.lua | ||||
| msgid "Finish editing" | ||||
| msgstr "" | ||||
|  | ||||
| #: waypoints.lua | ||||
| msgid "World position" | ||||
| msgstr "" | ||||
|  | ||||
| #: waypoints.lua | ||||
| msgid "Name" | ||||
| msgstr "" | ||||
|  | ||||
| #: waypoints.lua | ||||
| msgid "HUD text color" | ||||
| msgstr "" | ||||
| @@ -1,90 +0,0 @@ | ||||
| # textdomain: unified_inventory | ||||
| Mixing= | ||||
| Cooking= | ||||
| Digging= | ||||
| Bags= | ||||
| Bag @1= | ||||
| Small Bag= | ||||
| Medium Bag= | ||||
| Large Bag= | ||||
| All Items= | ||||
| Misc. Items= | ||||
| Plant Life= | ||||
| Building Materials= | ||||
| Tools= | ||||
| Minerals and Metals= | ||||
| Environment and Worldgen= | ||||
| Lighting= | ||||
|  and = | ||||
| Scroll categories left= | ||||
| Scroll categories right= | ||||
| Search= | ||||
| Reset search and display everything= | ||||
| First page= | ||||
| Back three pages= | ||||
| Back one page= | ||||
| Forward one page= | ||||
| Forward three pages= | ||||
| Last page= | ||||
| No matching items= | ||||
| No matches.= | ||||
| Page= | ||||
| @1 of @2= | ||||
| Filter= | ||||
| Can use the creative inventory= | ||||
| Forces Unified Inventory to be displayed in Full mode if Lite mode is configured globally= | ||||
| Crafting Grid= | ||||
| Crafting Guide= | ||||
| Set home position= | ||||
| Home position set to: @1= | ||||
| You don't have the "home" privilege!= | ||||
| Go home= | ||||
| Set time to day= | ||||
| Time of day set to 6am= | ||||
| You don't have the settime privilege!= | ||||
| Set time to night= | ||||
| Time of day set to 9pm= | ||||
| Clear inventory= | ||||
| This button has been disabled outside of creative mode to prevent accidental inventory trashing.@nUse the trash slot instead.= | ||||
| Inventory cleared!= | ||||
| Trash:= | ||||
| Refill:= | ||||
| Any item belonging to the @1 group= | ||||
| Any item belonging to the groups @1= | ||||
| Recipe @1 of @2= | ||||
| Usage @1 of @2= | ||||
| No recipes= | ||||
| No usages= | ||||
| Result= | ||||
| Ingredient= | ||||
| Show next recipe= | ||||
| Show next usage= | ||||
| Show previous recipe= | ||||
| Show previous usage= | ||||
| @1 (@2)= | ||||
| Give me:= | ||||
| This recipe is too@@large to be displayed.= | ||||
| To craft grid:= | ||||
| All= | ||||
| Crafting= | ||||
| White= | ||||
| Yellow= | ||||
| Red= | ||||
| Green= | ||||
| Blue= | ||||
| Waypoints= | ||||
| Select Waypoint #@1= | ||||
| Waypoint @1= | ||||
| Set waypoint to current location= | ||||
| Hide waypoint= | ||||
| Show waypoint= | ||||
| Hide coordinates= | ||||
| Show coordinates= | ||||
| Change color of waypoint display= | ||||
| Edit waypoint name= | ||||
| Waypoint active= | ||||
| Waypoint inactive= | ||||
| Finish editing= | ||||
| World position= | ||||
| Name= | ||||
| HUD text color= | ||||
| @@ -1,100 +0,0 @@ | ||||
| # textdomain: unified_inventory | ||||
| Mixing=Mischen | ||||
| Cooking=Kochen | ||||
| Digging=Graben | ||||
| Bags=Taschen | ||||
| Bag @1=Tasche @1 | ||||
| Small Bag=Kleine Tasche | ||||
| Medium Bag=Mittelgroße Tasche | ||||
| Large Bag=Große Tasche | ||||
| All Items=Alle Gegenstände | ||||
| Misc. Items=Sonstige Gegenstände | ||||
| Plant Life=Pfanzenwelt | ||||
| Building Materials=Baumaterialien | ||||
| Tools=Werkzeuge | ||||
| Minerals and Metals=Minerale und Metalle | ||||
| Environment and Worldgen=Umwelt und Welterstellung | ||||
| Lighting=Beleuchtung | ||||
|  and = und  | ||||
| Scroll categories left=Kategorien nach links blättern | ||||
| Scroll categories right=Kategorien nach rechts blättern | ||||
| Search=Suchen | ||||
| Reset search and display everything=Suche zurücksetzen und alles anzeigen | ||||
| First page=Erste Seite | ||||
| Back three pages=3 Seiten zurückblättern | ||||
| Back one page=1 Seite zurückblättern | ||||
| Forward one page=1 Seite vorblättern | ||||
| Forward three pages=3 Seiten vorblättern | ||||
| Last page=Letzte Seite | ||||
| No matching items=Keine passenden Gegenstände | ||||
| No matches.=Keine Treffer | ||||
| Page=Seite | ||||
| @1 of @2=@1 von @2 | ||||
| Filter=Filter | ||||
| Can use the creative inventory=Kann das Kreativinventar nutzen | ||||
| Forces Unified Inventory to be displayed in Full mode if Lite mode is configured globally=Zwingt Unified Inventory, im Vollmodus angezeigt zu werden, wenn der Minimalmodus global eingestellt ist | ||||
| Crafting Grid=Fertigungsraster | ||||
| Crafting Guide=Fertigungsführer | ||||
| Set home position=Heimatposition setzen | ||||
| Home position set to: @1=Heimatposition nach @1 gesetzt | ||||
| You don't have the "home" privilege!=Du hast das „home“-Privileg nicht! | ||||
| Go home=Nach Hause gehen | ||||
| Set time to day=Zur Tageszeit wechseln | ||||
| Time of day set to 6am=Tageszeit auf 6 Uhr gesetzt | ||||
| You don't have the settime privilege!=Du hast das „settime“-Privileg nicht! | ||||
| Set time to night=Zur Nachtzeit wechseln | ||||
| Time of day set to 9pm=Tageszeit auf 21 Uhr gesetzt | ||||
| Clear inventory=Inventar leeren | ||||
| This button has been disabled outside of creative mode to prevent accidental inventory trashing.@nUse the trash slot instead.= | ||||
| Inventory cleared!=Inventar geleert! | ||||
| Trash:=Müll: | ||||
| Refill:=Nachfüllen: | ||||
| Any item belonging to the @1 group=Irgendein Gegenstand, der zur Gruppe @1 gehört | ||||
| Any item belonging to the groups @1=Irgendein Gegenstand, der zu den Gruppen @1 gehört | ||||
| Recipe @1 of @2=Rezept @1 von @2 | ||||
| Usage @1 of @2=Verwendung @1 von @2 | ||||
| No recipes=Keine Rezepte | ||||
| No usages=Keine Verwendungen | ||||
| Result=Ergebnis | ||||
| Ingredient=Zutat | ||||
| Show next recipe=Nächstes Rezept zeigen | ||||
| Show next usage=Nächste Verwendung zeigen | ||||
| Show previous recipe=Vorheriges Rezept zeigen | ||||
| Show previous usage=Vorherige Verwendung zeigen | ||||
| @1 (@2)= | ||||
| Give me:=Gib mir: | ||||
| This recipe is too@@large to be displayed.= | ||||
| To craft grid:=Ins Fertigungsraster: | ||||
| All=Alles | ||||
| Crafting=Fertigung | ||||
| White=Weiß | ||||
| Yellow=Gelb | ||||
| Red=Rot | ||||
| Green=Grün | ||||
| Blue=Blau | ||||
| Waypoints=Wegpunkte | ||||
| Select Waypoint #@1=Wegpunkt Nr. @1 auswählen | ||||
| Waypoint @1=Wegpunkt Nr. @1 | ||||
| Set waypoint to current location=Setze Wegpunkt zur derzeitigen Position | ||||
| Hide waypoint=Wegpunkt verstecken | ||||
| Show waypoint=Wegpunkt zeigen | ||||
| Hide coordinates=Koordinaten verstecken | ||||
| Show coordinates=Koordinaten zeigen | ||||
| Change color of waypoint display=Farbe der Darstellung der Wegpunkte ändern | ||||
| Edit waypoint name=Name des Wegpunkts ändern | ||||
| Waypoint active=Wegpunkt aktiv | ||||
| Waypoint inactive=Wegpunkt inaktiv | ||||
| Finish editing=Bearbeitung abschließen | ||||
| World position=Weltposition | ||||
| Name=Name | ||||
| HUD text color=HUD-Textfarbe | ||||
|  | ||||
|  | ||||
| ##### not used anymore ##### | ||||
|  | ||||
| invisible=unsichtbar | ||||
| visible=sichtbar | ||||
| Make waypoint @1=Wegpunkt @1 machen | ||||
| Disable=ausschalten | ||||
| Enable=einschalten | ||||
| @1 display of waypoint coordinates=Anzeige der Wegpunktkoordinaten @1 | ||||
| @@ -1,108 +0,0 @@ | ||||
| # textdomain: unified_inventory | ||||
| # api.lua | ||||
| Mixing=Mezclar | ||||
| Cooking=Hornear | ||||
| Digging=Recoger | ||||
| # bags.lua | ||||
| Bags=Bolsos | ||||
| Bag @1=Bolso @1 | ||||
| Small Bag=Bolso Pequeño | ||||
| Medium Bag=Bolso Mediano | ||||
| Large Bag=Bolso Grande | ||||
| All Items= | ||||
| Misc. Items= | ||||
| Plant Life= | ||||
| Building Materials= | ||||
| Tools= | ||||
| Minerals and Metals= | ||||
| Environment and Worldgen= | ||||
| Lighting= | ||||
| # group.lua | ||||
|  and = y | ||||
| Scroll categories left= | ||||
| Scroll categories right= | ||||
| Search=Buscar | ||||
| Reset search and display everything=Limpiar la busqueda y mostrar todo | ||||
| # internal.lua | ||||
| First page=Primera página | ||||
| Back three pages=Volver tres páginas | ||||
| Back one page=Volver una página | ||||
| Forward one page=Avanzar una página | ||||
| Forward three pages=Avanzar tres páginas | ||||
| Last page=Ultima Pagina | ||||
| No matching items=No se encontraron elementos | ||||
| No matches.=No hay resultados. | ||||
| Page=Página | ||||
| @1 of @2=@1 de @2 | ||||
| Filter=Filtro | ||||
| # register.lua | ||||
| Can use the creative inventory=Puede usar el inventario creativo | ||||
| Forces Unified Inventory to be displayed in Full mode if Lite mode is configured globally=Obliga al Inventario Unificado a mostrarse en modo Completo si el modo Simple está configurado globalmente | ||||
| Crafting Grid=Cuadricula de Elaboración | ||||
| Crafting Guide=Guía de Elaboración | ||||
| Set home position=Establecer posición de la casa | ||||
| Home position set to: @1=Posición de la casa cambiada a: @1 | ||||
| You don't have the "home" privilege!= | ||||
| Go home=Ir a casa | ||||
| Set time to day=Cambiar a dia | ||||
| Time of day set to 6am=Hora del día cambiada a 6 AM | ||||
| You don't have the settime privilege!=¡No tienes el privilegio "settime"! | ||||
| Set time to night=Cambiar a noche | ||||
| Time of day set to 9pm=Hora del día cambiada a 9 PM | ||||
| Clear inventory=Limpiar inventario | ||||
| This button has been disabled outside of creative mode to prevent accidental inventory trashing.@nUse the trash slot instead.= | ||||
| Inventory cleared!=¡Inventario limpio! | ||||
| Trash:=Basura: | ||||
| Refill:=Rellenar: | ||||
| Any item belonging to the @1 group=Cualquier elemento que pertenezca al grupo @1 | ||||
| Any item belonging to the groups @1=Cualquier elemento perteneciente a los grupos @1 | ||||
| Recipe @1 of @2=Receta @1 de @2 | ||||
| Usage @1 of @2=Uso @1 de @2 | ||||
| No recipes=No tiene receta | ||||
| No usages=No tiene uso | ||||
| Result=Resultado | ||||
| Ingredient=Ingrediente | ||||
| Show next recipe=Mostrar la siguiente receta | ||||
| Show next usage=Mostrar el siguiente uso | ||||
| Show previous recipe=Mostrar la receta anterior | ||||
| Show previous usage=Mostrar el uso anterior | ||||
| @1 (@2)=@1 (@2) | ||||
| Give me:=Dame: | ||||
| This recipe is too@@large to be displayed.= | ||||
| To craft grid:=Construir: | ||||
| All=Todos | ||||
| Crafting=Elaboración | ||||
| White=Blanco | ||||
| Yellow=Amarillo | ||||
| Red=Rojo | ||||
| Green=Verde | ||||
| Blue=Azul | ||||
| Waypoints=Puntos | ||||
| Select Waypoint #@1=Seleccionar Punto #@1 | ||||
| Waypoint @1=Punto @1 | ||||
| Set waypoint to current location=Establecer el punto a la ubicación actual | ||||
| Hide waypoint= | ||||
| Show waypoint= | ||||
| Hide coordinates= | ||||
| Show coordinates= | ||||
| Change color of waypoint display=Cambiar el color del punto | ||||
| Edit waypoint name=Editar nombre del punto | ||||
| Waypoint active=Punto activo | ||||
| Waypoint inactive=Punto inactivo | ||||
| Finish editing=Terminar edición | ||||
| World position=Posición en el mundo | ||||
| Name=Nombre | ||||
| HUD text color=Color del texto de la Interfaz | ||||
|  | ||||
|  | ||||
| ##### not used anymore ##### | ||||
|  | ||||
| Make waypoint @1=Hacer punto @1 | ||||
| invisible=invisible | ||||
| visible=visible | ||||
| @1 display of waypoint coordinates=Visualizar coordenadas del punto @1 | ||||
| Disable=Deshabilitado | ||||
| Enable=Habilitado | ||||
| You don't have the \"home\" privilege!=¡No tienes el privilegio \"home\"! | ||||
| This button has been disabled outside=Este botón ha sido deshabilitado | ||||
| This recipe is too@nlarge to be displayed.=Esta receta es demasiado@ngrande para ser mostrada. | ||||
| @@ -1,96 +0,0 @@ | ||||
| # textdomain: unified_inventory | ||||
| Mixing= | ||||
| Cooking=Cuisson | ||||
| Digging=Creuser | ||||
| Bags=Sacs | ||||
| Bag @1=Sac @1 | ||||
| Small Bag=Petit sac | ||||
| Medium Bag=Sac moyen | ||||
| Large Bag=Grand sac | ||||
| All Items= | ||||
| Misc. Items= | ||||
| Plant Life= | ||||
| Building Materials= | ||||
| Tools= | ||||
| Minerals and Metals= | ||||
| Environment and Worldgen= | ||||
| Lighting= | ||||
|  and = et  | ||||
| Scroll categories left= | ||||
| Scroll categories right= | ||||
| Search=Rechercher | ||||
| Reset search and display everything= | ||||
| First page=1ère page | ||||
| Back three pages=3 pages en arrière | ||||
| Back one page=Page précédente | ||||
| Forward one page=Page suivante | ||||
| Forward three pages=3 pages en avant | ||||
| Last page=Dernière page | ||||
| No matching items=Aucun élément correspondant | ||||
| No matches.=Aucun match | ||||
| Page=Page | ||||
| @1 of @2=@1 de @2 | ||||
| Filter=Filtre | ||||
| Can use the creative inventory=Vous pouvez utiliser l'inventaire créatif | ||||
| Forces Unified Inventory to be displayed in Full mode if Lite mode is configured globally= | ||||
| Crafting Grid=Grille de création | ||||
| Crafting Guide=Guide de création | ||||
| Set home position=Position dans le monde | ||||
| Home position set to: @1=Position de votre base fixée à: @1 | ||||
| You don't have the "home" privilege!=Vous n'avez pas le privilège "home"! | ||||
| Go home= | ||||
| Set time to day= | ||||
| Time of day set to 6am=Heure fixée à 6h | ||||
| You don't have the settime privilege!=Vous n'avez pas le privilège "settime"! | ||||
| Set time to night= | ||||
| Time of day set to 9pm=Heure fixée à 21h | ||||
| Clear inventory= | ||||
| This button has been disabled outside of creative mode to prevent accidental inventory trashing.@nUse the trash slot instead.= | ||||
| Inventory cleared!=Inventaire vidé ! | ||||
| Trash:=Poubelle : | ||||
| Refill:=Remplir : | ||||
| Any item belonging to the @1 group= | ||||
| Any item belonging to the groups @1= | ||||
| Recipe @1 of @2=Recette @1 de @2 | ||||
| Usage @1 of @2= | ||||
| No recipes= | ||||
| No usages= | ||||
| Result=Résultat | ||||
| Ingredient= | ||||
| Show next recipe= | ||||
| Show next usage= | ||||
| Show previous recipe= | ||||
| Show previous usage= | ||||
| @1 (@2)= | ||||
| Give me:= | ||||
| This recipe is too@@large to be displayed.= | ||||
| To craft grid:=Sur de création: | ||||
| All=Tout | ||||
| Crafting=Création | ||||
| White=Blanc | ||||
| Yellow=Jaune | ||||
| Red=Rouge | ||||
| Green=Vert | ||||
| Blue=Bleu | ||||
| Waypoints=Point de passage | ||||
| Select Waypoint #@1=Choisir un point de passage #@1 | ||||
| Waypoint @1=Point de passage @1 | ||||
| Set waypoint to current location=Marquer un point de passage à la position actuelle | ||||
| Hide waypoint= | ||||
| Show waypoint= | ||||
| Hide coordinates= | ||||
| Show coordinates= | ||||
| Change color of waypoint display=Changer la couleur du point de passage | ||||
| Edit waypoint name=Editer le nom du point de passage | ||||
| Waypoint active=Point de passage actif | ||||
| Waypoint inactive=Point de passage inactif | ||||
| Finish editing=Terminer l'édition | ||||
| World position=Position dans le monde | ||||
| Name=Nom | ||||
| HUD text color=Couleur de texte du HUD | ||||
|  | ||||
|  | ||||
| ##### not used anymore ##### | ||||
|  | ||||
| Make waypoint @1=Rendre @1 le point de passage | ||||
| @1 display of waypoint coordinates=@1 montrer les coordonnées des points de passages | ||||
| @@ -1,100 +0,0 @@ | ||||
| # textdomain: unified_inventory | ||||
| Mixing=Unione | ||||
| Cooking=Cottura | ||||
| Digging=Scavo | ||||
| Bags=Borse | ||||
| Bag @1=Borsa @1 | ||||
| Small Bag=Borsa piccola | ||||
| Medium Bag=Borsa media | ||||
| Large Bag=Borsa grande | ||||
| All Items= | ||||
| Misc. Items= | ||||
| Plant Life= | ||||
| Building Materials= | ||||
| Tools= | ||||
| Minerals and Metals= | ||||
| Environment and Worldgen= | ||||
| Lighting= | ||||
|  and = e  | ||||
| Scroll categories left= | ||||
| Scroll categories right= | ||||
| Search=Cerca | ||||
| Reset search and display everything=Azzera la ricerca e mostra tutto | ||||
| First page=Prima pagina | ||||
| Back three pages=Indietro di tre pagine | ||||
| Back one page=Indietro di una pagina | ||||
| Forward one page=Avanti di una pagina | ||||
| Forward three pages=Avanti di tre pagine | ||||
| Last page=Ultima pagina | ||||
| No matching items=Nessun oggetto corrispondente | ||||
| No matches.=Nessuna corrispondenza. | ||||
| Page=Pagina | ||||
| @1 of @2=@1 di @2 | ||||
| Filter=Filtro | ||||
| Can use the creative inventory=Può usare l'inventario creativo | ||||
| Forces Unified Inventory to be displayed in Full mode if Lite mode is configured globally=Forza la visualizzazione di Unified Inventory in modalità completa se è configurata globalmente la visualizzazione semplice | ||||
| Crafting Grid=Griglia di assemblaggio | ||||
| Crafting Guide=Guida di assemblaggio | ||||
| Set home position=Imposta la residenza | ||||
| Home position set to: @1=Residenza impostata su: @1 | ||||
| You don't have the "home" privilege!=Non hai il privilegio "home"! | ||||
| Go home=Torna a casa | ||||
| Set time to day=Imposta l'orario sul giorno | ||||
| Time of day set to 6am=Orario impostato sulle 6am | ||||
| You don't have the settime privilege!=Non hai il privilegio "time"! | ||||
| Set time to night=Imposta l'orario sulla notte | ||||
| Time of day set to 9pm=Orario impostato sulle 9am | ||||
| Clear inventory=Ripulisci l'inventario | ||||
| This button has been disabled outside of creative mode to prevent accidental inventory trashing.@nUse the trash slot instead.= | ||||
| Inventory cleared!=Inventario ripulito! | ||||
| Trash:=Butta: | ||||
| Refill:=Riempi: | ||||
| Any item belonging to the @1 group=Qualunque oggetto appartenente al gruppo @1 | ||||
| Any item belonging to the groups @1=Qualunque oggetto appartenente ai gruppi @1 | ||||
| Recipe @1 of @2=Ricetta @1 di @2 | ||||
| Usage @1 of @2=Uso @1 di @2 | ||||
| No recipes=Nessuna ricetta | ||||
| No usages=Nessun utilizzo | ||||
| Result=Risultato | ||||
| Ingredient=Ingrediente | ||||
| Show next recipe=Mostra la prossima ricetta | ||||
| Show next usage=Mostra il prossimo utilizzo | ||||
| Show previous recipe=Mostra la ricetta precedente | ||||
| Show previous usage=Mostra l'utilizzo precedente | ||||
| @1 (@2)= | ||||
| Give me:=Dammi: | ||||
| This recipe is too@@large to be displayed.= | ||||
| To craft grid:=Alla griglia di assemblaggio: | ||||
| All=Tutto | ||||
| Crafting=Assemblaggio | ||||
| White=Bianco | ||||
| Yellow=Giallo | ||||
| Red=Rosso | ||||
| Green=Verde | ||||
| Blue=Blu | ||||
| Waypoints=Tappe | ||||
| Select Waypoint #@1=Seleziona tappa n°@1 | ||||
| Waypoint @1=Tappa @1 | ||||
| Set waypoint to current location=Imposta tappa alla posizione attuale | ||||
| Hide waypoint= | ||||
| Show waypoint= | ||||
| Hide coordinates= | ||||
| Show coordinates= | ||||
| Change color of waypoint display=Modifica il colore della visualizzazione della tappa | ||||
| Edit waypoint name=Modifica il nome della tappa | ||||
| Waypoint active=Tappa attiva | ||||
| Waypoint inactive=Tappa inattiva | ||||
| Finish editing=Termina la modifica | ||||
| World position=Posizione del mondo | ||||
| Name=Nome | ||||
| HUD text color=Colore del testo del visore | ||||
|  | ||||
|  | ||||
| ##### not used anymore ##### | ||||
|  | ||||
| invisible=invisibile | ||||
| visible=visibile | ||||
| Make waypoint @1=Crea tappa @1 | ||||
| Disable=Disabilita | ||||
| Enable=Abilita | ||||
| @1 display of waypoint coordinates=@1 la visualizzazione delle coordinate della tappa | ||||
| @@ -1,100 +0,0 @@ | ||||
| # textdomain: unified_inventory | ||||
| Mixing=Pencampuran | ||||
| Cooking=Pemasakan | ||||
| Digging=Penggalian | ||||
| Bags=Beg | ||||
| Bag @1=Beg @1 | ||||
| Small Bag=Beg Kecil | ||||
| Medium Bag=Beg Sederhana | ||||
| Large Bag=Beg Besar | ||||
| All Items= | ||||
| Misc. Items= | ||||
| Plant Life= | ||||
| Building Materials= | ||||
| Tools= | ||||
| Minerals and Metals= | ||||
| Environment and Worldgen= | ||||
| Lighting= | ||||
|  and = dan  | ||||
| Scroll categories left= | ||||
| Scroll categories right= | ||||
| Search=Cari | ||||
| Reset search and display everything=Set semula carian dan tunjukkan semua benda | ||||
| First page=Halaman pertama | ||||
| Back three pages=Tiga halaman sebelumnya | ||||
| Back one page=Halaman sebelumnya | ||||
| Forward one page=Halaman seterusnya | ||||
| Forward three pages=Tiga halaman seterusnya | ||||
| Last page=Halaman terakhir | ||||
| No matching items=Tiada item sepadan | ||||
| No matches.=Tiada padanan. | ||||
| Page=Halaman | ||||
| @1 of @2=@1 drpd @2 | ||||
| Filter=Tapis | ||||
| Can use the creative inventory=Boleh guna inventori kreatif | ||||
| Forces Unified Inventory to be displayed in Full mode if Lite mode is configured globally= | ||||
| Crafting Grid=Grid Pertukangan | ||||
| Crafting Guide=Panduan Pertukangan | ||||
| Set home position=Tetapkan kedudukan rumah | ||||
| Home position set to: @1=Kedudukan rumah ditetapkan ke: @1 | ||||
| You don't have the "home" privilege!=Anda tidak ada keistimewaan "home"! | ||||
| Go home=Balik rumah | ||||
| Set time to day=Tetapkan masa jadi siang | ||||
| Time of day set to 6am=Masa ditetapkan ke 6 pagi | ||||
| You don't have the settime privilege!=Anda tidak ada keistimewaan settime! | ||||
| Set time to night=Tetapkan masa jadi malam | ||||
| Time of day set to 9pm=Masa ditetapkan ke 9 malam | ||||
| Clear inventory=Kosongkan inventori | ||||
| This button has been disabled outside of creative mode to prevent accidental inventory trashing.@nUse the trash slot instead.= | ||||
| Inventory cleared!=Inventori dikosongkan! | ||||
| Trash:=Buang: | ||||
| Refill:=Isi balik: | ||||
| Any item belonging to the @1 group=Sebarang item dari kumpulan @1 | ||||
| Any item belonging to the groups @1=Sebarang item dari kumpulan @1 | ||||
| Recipe @1 of @2=Resipi @1 drpd @2 | ||||
| Usage @1 of @2=Kegunaan @1 drpd @2 | ||||
| No recipes=Tiada resipi | ||||
| No usages=Tiada kegunaan | ||||
| Result=Hasil | ||||
| Ingredient=Bahan | ||||
| Show next recipe=Tunjuk resipi seterusnya | ||||
| Show next usage=Tunjuk kegunaan seterusnya | ||||
| Show previous recipe=Tunjuk resipi sebelumnya | ||||
| Show previous usage=Tunjuk kegunaan sebelumnya | ||||
| @1 (@2)=@1 (@2) | ||||
| Give me:=Beri saya: | ||||
| This recipe is too@@large to be displayed.= | ||||
| To craft grid:=Ke grid pertukangan: | ||||
| All= | ||||
| Crafting=Pertukangan | ||||
| White=Putih | ||||
| Yellow=Kuning | ||||
| Red=Merah | ||||
| Green=Hijau | ||||
| Blue=Biru | ||||
| Waypoints=Titik Arah | ||||
| Select Waypoint #@1=Pilih Titik Arah #@1 | ||||
| Waypoint @1=Titik Arah @1 | ||||
| Set waypoint to current location=Tetapkan titik arah ke lokasi semasa | ||||
| Hide waypoint= | ||||
| Show waypoint= | ||||
| Hide coordinates= | ||||
| Show coordinates= | ||||
| Change color of waypoint display=Tukar warna paparan titik arah | ||||
| Edit waypoint name=Edit nama titik arah | ||||
| Waypoint active=Titik arah aktif | ||||
| Waypoint inactive=Titik arah tidak aktif | ||||
| Finish editing=Selesai edit | ||||
| World position=Kedudukan dunia | ||||
| Name=Nama | ||||
| HUD text color=Warna tulisan HUD | ||||
|  | ||||
|  | ||||
| ##### not used anymore ##### | ||||
|  | ||||
| invisible=Sembunyikan | ||||
| visible=Paparkan | ||||
| Make waypoint @1=@1 titik arah | ||||
| Disable=Sembunyikan | ||||
| Enable=Paparkan | ||||
| @1 display of waypoint coordinates=@1 koordinat untuk titik arah | ||||
| @@ -1,91 +0,0 @@ | ||||
| # textdomain: unified_inventory | ||||
| Category:=Kategorie: | ||||
| Mixing=Miksowanie | ||||
| Cooking=Gotowanie | ||||
| Digging=Kopanie | ||||
| Bags=Plecaki | ||||
| Bag @1=Plecak @1 | ||||
| Small Bag=Mały plecak | ||||
| Medium Bag=Średni plecak | ||||
| Large Bag=Duży plecak | ||||
| All Items=Wszystkie przedmioty | ||||
| Misc. Items=Różne przedmioty | ||||
| Plant Life=Życie roślin | ||||
| Building Materials=Materiały budowlane | ||||
| Tools=Narzędzia | ||||
| Minerals and Metals=Minerały i metale | ||||
| Environment and Worldgen=Otoczenie i generowanie świata | ||||
| Lighting=Oświetlenie | ||||
|  and = i  | ||||
| Scroll categories left=Przewiń kategorię w lewo | ||||
| Scroll categories right=Przewiń kategorię w prawo | ||||
| Search=Szukaj | ||||
| Reset search and display everything=Zresetuj wyszukiwanie i pokaż wszystko | ||||
| First page=Pierwsza strona | ||||
| Back three pages=Trzy strony do tyłu | ||||
| Back one page=Stronę do tyłu | ||||
| Forward one page=Stronę do przodu | ||||
| Forward three pages=Trzy strony do przodu | ||||
| Last page=Ostatnia strona | ||||
| No matching items=Brak pasujących przedmiotów | ||||
| No matches.=Brak wyników | ||||
| Page=Strona | ||||
| @1 of @2=@1 z @2 | ||||
| Filter=Filtr | ||||
| Can use the creative inventory=Może używać kreatywnego ekwipunku | ||||
| Forces Unified Inventory to be displayed in Full mode if Lite mode is configured globally=Wymusza wyświetlanie Unified Inventory w trybie Full jeżeli tryb Lite jest skonfigurowany globalnie | ||||
| Crafting Grid=Siatka craftingu | ||||
| Crafting Guide=Przewodnik craftingu | ||||
| Set home position=Ustaw pozycję domu | ||||
| Home position set to: @1=Pozycja domu ustawiona na: @1 | ||||
| You don't have the "home" privilege!=Brak uprawnień "home"! | ||||
| Go home=Idź do domu | ||||
| Set time to day=Ustaw czas na dzień | ||||
| Time of day set to 6am=Czas ustawiony na 6:00 | ||||
| You don't have the settime privilege!=Brak uprawnień "settime"! | ||||
| Set time to night=Ustaw czas na noc | ||||
| Time of day set to 9pm=Czas ustawiony na 21:00 | ||||
| Clear inventory=Wyczyść ekwipunek | ||||
| This button has been disabled outside of creative mode to prevent accidental inventory trashing.@nUse the trash slot instead.=Aby zapobiec przypadkowemu skasowaniu ekwipunku, ten przycisk został wyłączony poza trybem kreatywnym.@nUżyj zamiast tego ikony śmietnika. | ||||
| Inventory cleared!=Ekwipunek został wyczyszczony! | ||||
| Trash:=Śmietnik: | ||||
| Refill:=Uzupełnianie: | ||||
| Any item belonging to the @1 group=Każdy przedmiot należący do @1 grupy | ||||
| Any item belonging to the groups @1=Każdy przedmiot należacy do grup @1 | ||||
| Recipe @1 of @2=Recepta @1 z @2 | ||||
| Usage @1 of @2=Użycie @1 z @2 | ||||
| No recipes=Brak recepty | ||||
| No usages=Bez użycia | ||||
| Result=Wynik | ||||
| Ingredient=Składnik | ||||
| Show next recipe=Pokaż nastepną recepturę | ||||
| Show next usage=Pokaż następne użycie | ||||
| Show previous recipe=Pokaż poprzednią recepturę | ||||
| Show previous usage=Pokaż poprzednie użycie | ||||
| @1 (@2)=@1 (@2) | ||||
| Give me:=Daj mi: | ||||
| This recipe is too@@large to be displayed.=Receptura jest zbyt@@duża aby ją wyświetlić. | ||||
| To craft grid:=Do siatki craftingu. | ||||
| All=Wszystko | ||||
| Crafting=Crafting | ||||
| White=Biały | ||||
| Yellow=Zółty | ||||
| Red=Czerwony | ||||
| Green=Zielony | ||||
| Blue=Niebieski | ||||
| Waypoints=Punkty orientacyjne | ||||
| Select Waypoint #@1=Wybierz punkt #@1 | ||||
| Waypoint @1=Punkty orientacyjne @1 | ||||
| Set waypoint to current location=Ustaw punkt orientacyjny na bieżacej pozycji | ||||
| Hide waypoint=Ukryj punkt orientacyjny | ||||
| Show waypoint=Pokaż punkt orientacyjny | ||||
| Hide coordinates=Ukryj koordynaty | ||||
| Show coordinates=Pokaż koordynaty | ||||
| Change color of waypoint display=Zmień kolor punktu | ||||
| Edit waypoint name=Edytuj nazwę punktu | ||||
| Waypoint active=Punkt włączony | ||||
| Waypoint inactive=Punkt wyłączony | ||||
| Finish editing=Zakończ edycję | ||||
| World position=Pozycja | ||||
| Name=Nazwa | ||||
| HUD text color=Kolor tekstu HUD | ||||
| @@ -1,98 +0,0 @@ | ||||
| # textdomain: unified_inventory | ||||
| Mixing=Muistura | ||||
| Cooking=Cozimento | ||||
| Digging=Escavação | ||||
| Bags=Bolsas | ||||
| Bag @1=Bolsa @1 | ||||
| Small Bag=Bolsa Pequena | ||||
| Medium Bag=Bolsa Média | ||||
| Large Bag=Bolsa Grande | ||||
| All Items= | ||||
| Misc. Items= | ||||
| Plant Life= | ||||
| Building Materials= | ||||
| Tools= | ||||
| Minerals and Metals= | ||||
| Environment and Worldgen= | ||||
| Lighting= | ||||
|  and = e  | ||||
| Scroll categories left= | ||||
| Scroll categories right= | ||||
| Search=Pesquisar | ||||
| Reset search and display everything=Redefinir pesquisa e exibir tudo | ||||
| First page=Primeira Página | ||||
| Back three pages=Voltar 3 Páginas | ||||
| Back one page=Voltar 1 Página | ||||
| Forward one page=Avançar 1 Página | ||||
| Forward three pages=Avançar 3 Páginas | ||||
| Last page=Ultima Página | ||||
| No matching items=Nenhum item correspondente | ||||
| No matches.=Sem correspondências | ||||
| Page=Página | ||||
| @1 of @2=@1 de @2 | ||||
| Filter=Filtro | ||||
| Can use the creative inventory=Pode usar o inventário do criativo | ||||
| Forces Unified Inventory to be displayed in Full mode if Lite mode is configured globally= | ||||
| Crafting Grid=Grade de Artesanato | ||||
| Crafting Guide=Guia de Artesanato | ||||
| Set home position=Definir posição de casa | ||||
| Home position set to: @1=Posição inicial definida para: @1 | ||||
| You don't have the "home" privilege!=Você não tem o privilégio de "home"! | ||||
| Go home=Transportar para Casa | ||||
| Set time to day=Definir turno para dia | ||||
| Time of day set to 6am=Hora do dia definida para 06h | ||||
| You don't have the settime privilege!=Você não tem o privilégio de "settime"! | ||||
| Set time to night=Definir turno para noite | ||||
| Time of day set to 9pm=Hora do dia ajustada para 21h | ||||
| Clear inventory=Limpar Inventário | ||||
| This button has been disabled outside of creative mode to prevent accidental inventory trashing.@nUse the trash slot instead.= | ||||
| Inventory cleared!=Inventário Apagado! | ||||
| Trash:=Lixo: | ||||
| Refill:=Recarga: | ||||
| Any item belonging to the @1 group=Qualquer item pertencente ao grupo '@1'. | ||||
| Any item belonging to the groups @1=Qualquer item pertencente aos grupos '@1'. | ||||
| Recipe @1 of @2=Receita @1 de @2 | ||||
| Usage @1 of @2=Utilização @1 de @2 | ||||
| No recipes=Sem Receita | ||||
| No usages=Sem Utilização | ||||
| Result=Resultado | ||||
| Ingredient=Ingrediente | ||||
| Show next recipe=Exibir Próxima Receita | ||||
| Show next usage=Mostrar Próxima Utilização | ||||
| Show previous recipe=Exibir Receita Anterior | ||||
| Show previous usage=Exibir Utilização Anterior | ||||
| @1 (@2)= | ||||
| Give me:=Gerado: | ||||
| This recipe is too@@large to be displayed.= | ||||
| To craft grid:=Para Grade de Artesanato | ||||
| All=MAX | ||||
| Crafting=Artesanato | ||||
| White=Branco | ||||
| Yellow=Amarelo | ||||
| Red=Vermelho | ||||
| Green=Verde | ||||
| Blue=Azul | ||||
| Waypoints=Apontador de Direção | ||||
| Select Waypoint #@1=Seleção de Apontador de Direção #@1 | ||||
| Waypoint @1=Apontador de Direção @1 | ||||
| Set waypoint to current location=Configurar localização atual do Apontador de Direção | ||||
| Hide waypoint= | ||||
| Show waypoint= | ||||
| Hide coordinates= | ||||
| Show coordinates= | ||||
| Change color of waypoint display=Mudar cor exibida do Apontador de Direção | ||||
| Edit waypoint name=Editar Nome de Apontador de Direção | ||||
| Waypoint active=Apontador de Direção Ativo | ||||
| Waypoint inactive=Apontador de Direção Inativo | ||||
| Finish editing=Edição Finalizada | ||||
| World position=Posição Mundial | ||||
| Name=Nome | ||||
| HUD text color=Cor de HUD | ||||
|  | ||||
|  | ||||
| ##### not used anymore ##### | ||||
|  | ||||
| invisible=invisível | ||||
| visible=visível | ||||
| Make waypoint @1=Fazer Apontador de Direção @1 | ||||
| @1 display of waypoint coordinates=@1 exibição de coordenadas de Fazer Apontador de Direção | ||||
| @@ -1,100 +0,0 @@ | ||||
| # textdomain: unified_inventory | ||||
| Mixing=Мешать | ||||
| Cooking=Варить | ||||
| Digging=Копать | ||||
| Bags=Сумки | ||||
| Bag @1=Сумка @1 | ||||
| Small Bag=Малая сумка | ||||
| Medium Bag=Средняя сумка | ||||
| Large Bag=Большая сумка | ||||
| All Items= | ||||
| Misc. Items= | ||||
| Plant Life= | ||||
| Building Materials= | ||||
| Tools= | ||||
| Minerals and Metals= | ||||
| Environment and Worldgen= | ||||
| Lighting= | ||||
|  and = и  | ||||
| Scroll categories left= | ||||
| Scroll categories right= | ||||
| Search=Поиск | ||||
| Reset search and display everything=Сброс поиска, показать всё | ||||
| First page=Первая страница | ||||
| Back three pages=3 страницы назад | ||||
| Back one page=1 страницу назад | ||||
| Forward one page=1 страницу вперёд | ||||
| Forward three pages=3 страницы вперёд | ||||
| Last page=Последняя страница | ||||
| No matching items=Нет подходящих элементов | ||||
| No matches.=Ничего не найдено | ||||
| Page=Страница | ||||
| @1 of @2=@1 из @2 | ||||
| Filter=Фильтр | ||||
| Can use the creative inventory=Можно использовать инвентарь творческого режима | ||||
| Forces Unified Inventory to be displayed in Full mode if Lite mode is configured globally= | ||||
| Crafting Grid=Решетка крафта | ||||
| Crafting Guide=Книга рецептов | ||||
| Set home position=Установить позицию дома | ||||
| Home position set to: @1=Дом теперь расположен по коодинатам: @1 | ||||
| You don't have the "home" privilege!=У вас нет привилегии "home"! | ||||
| Go home=Отправиться домой | ||||
| Set time to day=День | ||||
| Time of day set to 6am=Установлено время 6 утра | ||||
| You don't have the settime privilege!=Вам не разрешено устанавливать время! (нет привилегии "settime") | ||||
| Set time to night=Ночь | ||||
| Time of day set to 9pm=Установлено время 9 вечера | ||||
| Clear inventory=Очистить инвентарь | ||||
| This button has been disabled outside of creative mode to prevent accidental inventory trashing.@nUse the trash slot instead.= | ||||
| Inventory cleared!=Инвентарь очищен! | ||||
| Trash:=Мусор: | ||||
| Refill:=Наполнить: | ||||
| Any item belonging to the @1 group=Любой элемент из группы: @1 | ||||
| Any item belonging to the groups @1=Любой элемент из группы: @1 | ||||
| Recipe @1 of @2=Рецепт @1 из @2 | ||||
| Usage @1 of @2=Вариант @1 of @2 | ||||
| No recipes=Рецептов нет | ||||
| No usages=Не используется | ||||
| Result=Результат | ||||
| Ingredient=Состав | ||||
| Show next recipe=Следующий рецепт | ||||
| Show next usage=Следующее использование | ||||
| Show previous recipe=Прошлый рецепт | ||||
| Show previous usage=Прошлая страница | ||||
| @1 (@2)= | ||||
| Give me:=Дай мне: | ||||
| This recipe is too@@large to be displayed.= | ||||
| To craft grid:=На решeтку крафта: | ||||
| All=Все | ||||
| Crafting=Крафт | ||||
| White=Белый | ||||
| Yellow=Желтый | ||||
| Red=Красный | ||||
| Green=Зелёный | ||||
| Blue=Синий | ||||
| Waypoints=Путевые точки | ||||
| Select Waypoint #@1=Выбрать путевую точку №@1 | ||||
| Waypoint @1=Путевая точка @1 | ||||
| Set waypoint to current location=Установить путевую точку по текущей позиции | ||||
| Hide waypoint= | ||||
| Show waypoint= | ||||
| Hide coordinates= | ||||
| Show coordinates= | ||||
| Change color of waypoint display=Поменять цвет путевой точки | ||||
| Edit waypoint name=Переименовать путевую точку | ||||
| Waypoint active=Путевая точка включена | ||||
| Waypoint inactive=Путевая точка выключена | ||||
| Finish editing=Закончить редакцию | ||||
| World position=Позиция мира | ||||
| Name=Имя | ||||
| HUD text color=Цвет текста HUDа | ||||
|  | ||||
|  | ||||
| ##### not used anymore ##### | ||||
|  | ||||
| invisible=невидимой | ||||
| visible=видимой | ||||
| Make waypoint @1=Сделать путевую точку @1 | ||||
| Disable=Выключить | ||||
| Enable=Включить | ||||
| @1 display of waypoint coordinates=@1 показ координат путевых точек | ||||
| @@ -1,99 +0,0 @@ | ||||
| # textdomain: unified_inventory | ||||
| Mixing=Karıştırma | ||||
| Cooking=Pişirme | ||||
| Digging=Kazma | ||||
| Bags=Çantalarım | ||||
| Bag @1=@1. Çanta | ||||
| Small Bag=Küçük Çanta | ||||
| Medium Bag=Çanta | ||||
| Large Bag=Büyük Çanta | ||||
| All Items= | ||||
| Misc. Items= | ||||
| Plant Life= | ||||
| Building Materials= | ||||
| Tools= | ||||
| Minerals and Metals= | ||||
| Environment and Worldgen= | ||||
| Lighting= | ||||
|  and = ve  | ||||
| Scroll categories left= | ||||
| Scroll categories right= | ||||
| Search=Ara | ||||
| Reset search and display everything= | ||||
| First page=İlk Sayfa | ||||
| Back three pages=3 Sayfa Gerile | ||||
| Back one page=Geri | ||||
| Forward one page=İleri | ||||
| Forward three pages=3 Sayfa İlerile | ||||
| Last page=Son Sayfa | ||||
| No matching items=Eşleşme yok | ||||
| No matches.=Eşleşme yok | ||||
| Page=Sayfa | ||||
| @1 of @2=@1 dan @2 | ||||
| Filter=Süzgeç | ||||
| Can use the creative inventory=Yaratıcı envanteri kullanabilir | ||||
| Forces Unified Inventory to be displayed in Full mode if Lite mode is configured globally= | ||||
| Crafting Grid=Üretim tablosu | ||||
| Crafting Guide=Kılavuz | ||||
| Set home position=Set ev pozisyon | ||||
| Home position set to: @1=Yeni eviniz: @1 | ||||
| You don't have the "home" privilege!="home" yetkiniz yok! | ||||
| Go home=Eve git | ||||
| Set time to day=Güne zaman ayarla | ||||
| Time of day set to 6am=Saat 06:00 olarak ayarlandı | ||||
| You don't have the settime privilege!="settime" yetkiniz yok! | ||||
| Set time to night=Geceye zaman ayarla | ||||
| Time of day set to 9pm=Saat 19:00 olarak ayarlandı | ||||
| Clear inventory= | ||||
| This button has been disabled outside of creative mode to prevent accidental inventory trashing.@nUse the trash slot instead.= | ||||
| Inventory cleared!=Envanter temizlendi! | ||||
| Trash:=Çöp | ||||
| Refill:=Doldur | ||||
| Any item belonging to the @1 group= | ||||
| Any item belonging to the groups @1= | ||||
| Recipe @1 of @2=@1 dan @2 tarifi | ||||
| Usage @1 of @2=Kullanım @1/@2 | ||||
| No recipes=Tarifi yok | ||||
| No usages=Kullanım yok | ||||
| Result=Çıktı | ||||
| Ingredient=Bileşen | ||||
| Show next recipe= | ||||
| Show next usage= | ||||
| Show previous recipe= | ||||
| Show previous usage= | ||||
| @1 (@2)= | ||||
| Give me:=Ver bana: | ||||
| This recipe is too@@large to be displayed.= | ||||
| To craft grid:=Üretim tablosuna kopyala | ||||
| All=Tümü | ||||
| Crafting=Üretim | ||||
| White=Beyaz | ||||
| Yellow=Sarı | ||||
| Red=Kırmızı | ||||
| Green=Yeşil | ||||
| Blue=Mavi | ||||
| Waypoints=Konum Noktaları | ||||
| Select Waypoint #@1=#@1 konum noktası seç | ||||
| Waypoint @1=@1 Konum Noktaları | ||||
| Set waypoint to current location=Bulunduğun noktayı işaretle | ||||
| Hide waypoint= | ||||
| Show waypoint= | ||||
| Hide coordinates= | ||||
| Show coordinates= | ||||
| Change color of waypoint display=Konum Gösterge Rengi | ||||
| Edit waypoint name=Konum Noktasını Düzenle | ||||
| Waypoint active=Konum Etkin | ||||
| Waypoint inactive=Konum Devredışı | ||||
| Finish editing=Düzenleme bitti | ||||
| World position=Dünya konumu | ||||
| Name=İsim | ||||
| HUD text color=Metin rengi | ||||
|  | ||||
|  | ||||
| ##### not used anymore ##### | ||||
|  | ||||
| msgid ""=Yaratıcı modu dışında iken bu tuş kullanılamaz. | ||||
| invisible=görünmez | ||||
| visible=görünür | ||||
| Make waypoint @1=Yol noktası @1 | ||||
| @1 display of waypoint coordinates=Yol noktası koordinatlarının görüntülenmesini @1 | ||||
| @@ -1,98 +0,0 @@ | ||||
| # textdomain: unified_inventory | ||||
| Mixing=混合 | ||||
| Cooking=烹饪 | ||||
| Digging=挖出 | ||||
| Bags=背包 | ||||
| Bag @1=背包@1 | ||||
| Small Bag=小背包 | ||||
| Medium Bag=中背包 | ||||
| Large Bag=大背包 | ||||
| All Items=所有物品 | ||||
| Misc. Items=杂项 | ||||
| Plant Life=植物 | ||||
| Building Materials=建材 | ||||
| Tools=工具 | ||||
| Minerals and Metals=矿物与金属 | ||||
| Environment and Worldgen=自然环境 | ||||
| Lighting=光源 | ||||
|  and = 和  | ||||
| Scroll categories left=向左滚动分类栏 | ||||
| Scroll categories right=向右滚动分类栏 | ||||
| Search=搜索 | ||||
| Reset search and display everything=重置搜索并显示所有物品 | ||||
| First page=第一页 | ||||
| Back three pages=后退三页 | ||||
| Back one page=后退一页 | ||||
| Forward one page=前进一页 | ||||
| Forward three pages=前进三页 | ||||
| Last page=最后一页 | ||||
| No matching items=没有匹配物品 | ||||
| No matches.=没有匹配 | ||||
| Page=页面 | ||||
| @1 of @2=第@1页,共@2页 | ||||
| Filter=过滤器 | ||||
| Can use the creative inventory=可以使用创造背包 | ||||
| Forces Unified Inventory to be displayed in Full mode if Lite mode is configured globally=如果轻量模式被全局配置,强迫Unified Inventory以完全模式展现。 | ||||
| Crafting Grid=合成表 | ||||
| Crafting Guide=合成指南 | ||||
| Set home position=设置家的位置 | ||||
| Home position set to: @1=家的位置设置到: @1 | ||||
| You don't have the "home" privilege!=你没有“home”权限! | ||||
| Go home=回家 | ||||
| Set time to day=设置时间到白天 | ||||
| Time of day set to 6am=时间设置到早晨6点 | ||||
| You don't have the settime privilege!=你没有“settime”权限! | ||||
| Set time to night=设置时间到晚上 | ||||
| Time of day set to 9pm=时间设置到晚上9点 | ||||
| Clear inventory=清空背包 | ||||
| This button has been disabled outside of creative mode to prevent accidental inventory trashing.@nUse the trash slot instead.=此按钮已在非创造模式中禁用以防止意外的背包清空。@n请使用垃圾桶栏。 | ||||
| Inventory cleared!=清空背包 | ||||
| Trash:=丢弃: | ||||
| Refill:=填满: | ||||
| Any item belonging to the @1 group=属于@1组的任何项目 | ||||
| Any item belonging to the groups @1=属于组@1的任何项目 | ||||
| Recipe @1 of @2=第@1配方,共@2个 | ||||
| Usage @1 of @2=第@1用法,共@2个 | ||||
| No recipes=没有配方 | ||||
| No usages=没有用法 | ||||
| Result=结果 | ||||
| Ingredient=原料 | ||||
| Show next recipe=显示下一个配方 | ||||
| Show next usage=显示下一个用法 | ||||
| Show previous recipe=显示前一个配方 | ||||
| Show previous usage=显示前一个用法 | ||||
| @1 (@2)=@1 (@2) | ||||
| Give me:=给予: | ||||
| This recipe is too@@large to be displayed.=该配方太@@大,不能显示。 | ||||
| To craft grid:=填充物品到合成表 | ||||
| All=全部 | ||||
| Crafting=合成 | ||||
| White=白 | ||||
| Yellow=黄 | ||||
| Red=红 | ||||
| Green=绿 | ||||
| Blue=蓝 | ||||
| Waypoints=航路点 | ||||
| Select Waypoint #@1=查询航路点 #@1 | ||||
| Waypoint @1=航路点 @1 | ||||
| Set waypoint to current location=将航路点设置到当前位置 | ||||
| Hide waypoint=隐藏航路点 | ||||
| Show waypoint=显示航路点 | ||||
| Hide coordinates=隐藏坐标 | ||||
| Show coordinates=显示坐标 | ||||
| Change color of waypoint display=改变航路点显示的颜色 | ||||
| Edit waypoint name=编辑航路点名称 | ||||
| Waypoint active=航路点已激活 | ||||
| Waypoint inactive=航路点未激活 | ||||
| Finish editing=完成编辑 | ||||
| World position=世界位置 | ||||
| Name=名称 | ||||
| HUD text color=HUD文本颜色 | ||||
|  | ||||
|  | ||||
| ##### not used anymore ##### | ||||
|  | ||||
| invisible=不可见的 | ||||
| visible=可见的 | ||||
| Make waypoint @1=设置航路点 @1 | ||||
| @1 display of waypoint coordinates=显示航路点@1坐标 | ||||
| @@ -1,98 +0,0 @@ | ||||
| # textdomain: unified_inventory | ||||
| Mixing=混合 | ||||
| Cooking=烹飪 | ||||
| Digging=挖出 | ||||
| Bags=揹包 | ||||
| Bag @1=揹包@1 | ||||
| Small Bag=小揹包 | ||||
| Medium Bag=中揹包 | ||||
| Large Bag=大揹包 | ||||
| All Items=所有物品 | ||||
| Misc. Items=雜項 | ||||
| Plant Life=植物 | ||||
| Building Materials=建材 | ||||
| Tools=工具 | ||||
| Minerals and Metals=礦物與金屬 | ||||
| Environment and Worldgen=自然環境 | ||||
| Lighting=光源 | ||||
|  and = 和  | ||||
| Scroll categories left=向左滾動分類欄 | ||||
| Scroll categories right=向右滾動分類欄 | ||||
| Search=搜索 | ||||
| Reset search and display everything=重置搜索並顯示所有物品 | ||||
| First page=第一頁 | ||||
| Back three pages=後退三頁 | ||||
| Back one page=後退一頁 | ||||
| Forward one page=前進一頁 | ||||
| Forward three pages=前進三頁 | ||||
| Last page=最後一頁 | ||||
| No matching items=沒有匹配物品 | ||||
| No matches.=沒有匹配 | ||||
| Page=頁面 | ||||
| @1 of @2=第@1頁,共@2頁 | ||||
| Filter=過濾器 | ||||
| Can use the creative inventory=可以使用創造揹包 | ||||
| Forces Unified Inventory to be displayed in Full mode if Lite mode is configured globally=如果輕量模式被全局配置,強迫Unified Inventory以完全模式展現。 | ||||
| Crafting Grid=合成表 | ||||
| Crafting Guide=合成指南 | ||||
| Set home position=設置家的位置 | ||||
| Home position set to: @1=家的位置設置到: @1 | ||||
| You don't have the "home" privilege!=你沒有“home”權限! | ||||
| Go home=回家 | ||||
| Set time to day=設置時間到白天 | ||||
| Time of day set to 6am=時間設置到早晨6點 | ||||
| You don't have the settime privilege!=你沒有“settime”權限! | ||||
| Set time to night=設置時間到晚上 | ||||
| Time of day set to 9pm=時間設置到晚上9點 | ||||
| Clear inventory=清空揹包 | ||||
| This button has been disabled outside of creative mode to prevent accidental inventory trashing.@nUse the trash slot instead.=此按鈕已在非創造模式中禁用以防止意外的背包清空。@n請使用垃圾桶欄。 | ||||
| Inventory cleared!=清空揹包 | ||||
| Trash:=丟棄: | ||||
| Refill:=填滿: | ||||
| Any item belonging to the @1 group=屬於@1組的任何項目 | ||||
| Any item belonging to the groups @1=屬於組@1的任何項目 | ||||
| Recipe @1 of @2=第@1配方,共@2個 | ||||
| Usage @1 of @2=第@1用法,共@2個 | ||||
| No recipes=沒有配方 | ||||
| No usages=沒有用法 | ||||
| Result=結果 | ||||
| Ingredient=原料 | ||||
| Show next recipe=顯示下一個配方 | ||||
| Show next usage=顯示下一個用法 | ||||
| Show previous recipe=顯示上一個配方 | ||||
| Show previous usage=顯示上一個用法 | ||||
| @1 (@2)=@1 (@2) | ||||
| Give me:=給予: | ||||
| This recipe is too@@large to be displayed.=該配方太@@大,不能顯示。 | ||||
| To craft grid:=填充物品到合成表 | ||||
| All=全部 | ||||
| Crafting=合成 | ||||
| White=白 | ||||
| Yellow=黃 | ||||
| Red=紅 | ||||
| Green=綠 | ||||
| Blue=藍 | ||||
| Waypoints=航路點 | ||||
| Select Waypoint #@1=查詢航路點 #@1 | ||||
| Waypoint @1=航路點 @1 | ||||
| Set waypoint to current location=將航路點設置到當前位置 | ||||
| Hide waypoint=隱藏航路點 | ||||
| Show waypoint=顯示航路點 | ||||
| Hide coordinates=隱藏坐標 | ||||
| Show coordinates=顯示坐標 | ||||
| Change color of waypoint display=改變航路點顯示的顏色 | ||||
| Edit waypoint name=編輯航路點名稱 | ||||
| Waypoint active=航路點已激活 | ||||
| Waypoint inactive=航路點未激活 | ||||
| Finish editing=完成編輯 | ||||
| World position=世界位置 | ||||
| Name=名稱 | ||||
| HUD text color=HUD文本顏色 | ||||
|  | ||||
|  | ||||
| ##### not used anymore ##### | ||||
|  | ||||
| invisible=不可見的 | ||||
| visible=可見的 | ||||
| Make waypoint @1=設置航路點 @1 | ||||
| @1 display of waypoint coordinates=顯示航路點@1座標 | ||||
							
								
								
									
										402
									
								
								match_craft.lua
									
									
									
									
									
								
							
							
						
						| @@ -1,402 +0,0 @@ | ||||
| -- match_craft.lua | ||||
| -- Find and automatically move inventory items to the crafting grid | ||||
| -- according to the recipe. | ||||
|  | ||||
| --[[ | ||||
| Retrieve items from inventory lists and calculate their total count. | ||||
| Return a table of "item name" - "total count" pairs. | ||||
|  | ||||
| Arguments: | ||||
| 	inv: minetest inventory reference | ||||
| 	lists: names of inventory lists to use | ||||
|  | ||||
| Example usage: | ||||
| 	-- Count items in "main" and "craft" lists of player inventory | ||||
| 	unified_inventory.count_items(player_inv_ref, {"main", "craft"}) | ||||
|  | ||||
| Example output: | ||||
| 	{ | ||||
| 		["default:pine_wood"] = 2, | ||||
| 		["default:acacia_wood"] = 4, | ||||
| 		["default:chest"] = 3, | ||||
| 		["default:axe_diamond"] = 2, -- unstackable item are counted too | ||||
| 		["wool:white"] = 6 | ||||
| 	} | ||||
| ]]-- | ||||
| function unified_inventory.count_items(inv, lists) | ||||
| 	local counts = {} | ||||
|  | ||||
| 	for i = 1, #lists do | ||||
| 		local name = lists[i] | ||||
| 		local size = inv:get_size(name) | ||||
| 		local list = inv:get_list(name) | ||||
|  | ||||
| 		for j = 1, size do | ||||
| 			local stack = list[j] | ||||
|  | ||||
| 			if not stack:is_empty() then | ||||
| 				local item = stack:get_name() | ||||
| 				local count = stack:get_count() | ||||
|  | ||||
| 				counts[item] = (counts[item] or 0) + count | ||||
| 			end | ||||
| 		end | ||||
| 	end | ||||
|  | ||||
| 	return counts | ||||
| end | ||||
|  | ||||
| --[[ | ||||
| Retrieve craft recipe items and their positions in the crafting grid. | ||||
| Return a table of "craft item name" - "set of positions" pairs. | ||||
|  | ||||
| Note that if craft width is not 3 then positions are recalculated as | ||||
| if items were placed on a 3x3 grid. Also note that craft can contain | ||||
| groups of items with "group:" prefix. | ||||
|  | ||||
| Arguments: | ||||
| 	craft: minetest craft recipe | ||||
|  | ||||
| Example output: | ||||
| 	-- Bed recipe | ||||
| 	{ | ||||
| 		["wool:white"] = {[1] = true, [2] = true, [3] = true} | ||||
| 		["group:wood"] = {[4] = true, [5] = true, [6] = true} | ||||
| 	} | ||||
| --]] | ||||
| function unified_inventory.count_craft_positions(craft) | ||||
| 	local positions = {} | ||||
| 	local craft_items = craft.items | ||||
| 	local craft_type = unified_inventory.registered_craft_types[craft.type] | ||||
| 	                   or unified_inventory.craft_type_defaults(craft.type, {}) | ||||
| 	local display_width = craft_type.dynamic_display_size | ||||
| 	                      and craft_type.dynamic_display_size(craft).width | ||||
| 	                      or craft_type.width | ||||
| 	local craft_width = craft_type.get_shaped_craft_width | ||||
| 	                    and craft_type.get_shaped_craft_width(craft) | ||||
| 	                    or display_width | ||||
| 	local i = 0 | ||||
|  | ||||
| 	for y = 1, 3 do | ||||
| 		for x = 1, craft_width do | ||||
| 			i = i + 1 | ||||
| 			local item = craft_items[i] | ||||
|  | ||||
| 			if item ~= nil then | ||||
| 				local pos = 3 * (y - 1) + x | ||||
| 				local set = positions[item] | ||||
|  | ||||
| 				if set ~= nil then | ||||
| 					set[pos] = true | ||||
| 				else | ||||
| 					positions[item] = {[pos] = true} | ||||
| 				end | ||||
| 			end | ||||
| 		end | ||||
| 	end | ||||
|  | ||||
| 	return positions | ||||
| end | ||||
|  | ||||
| --[[ | ||||
| For every craft item find all matching inventory items. | ||||
| - If craft item is a group then find all inventory items that matches | ||||
|   this group. | ||||
| - If craft item is not a group (regular item) then find only this item. | ||||
|  | ||||
| If inventory doesn't contain needed item then found set is empty for | ||||
| this item. | ||||
|  | ||||
| Return a table of "craft item name" - "set of matching inventory items" | ||||
| pairs. | ||||
|  | ||||
| Arguments: | ||||
| 	inv_items: table with items names as keys | ||||
| 	craft_items: table with items names or groups as keys | ||||
|  | ||||
| Example output: | ||||
| 	{ | ||||
| 		["group:wood"] = { | ||||
| 			["default:pine_wood"] = true, | ||||
| 			["default:acacia_wood"] = true | ||||
| 		}, | ||||
| 		["wool:white"] = { | ||||
| 			["wool:white"] = true | ||||
| 		} | ||||
| 	} | ||||
| --]] | ||||
| function unified_inventory.find_usable_items(inv_items, craft_items) | ||||
| 	local result = {} | ||||
|  | ||||
| 	for craft_item in pairs(craft_items) do | ||||
| 		-- may specify group:type1,type2 | ||||
| 		local items = unified_inventory.get_matching_items(craft_item) | ||||
|  | ||||
| 		local found = {} | ||||
| 		for itemname, _ in pairs(items) do | ||||
| 			if inv_items[itemname] then | ||||
| 				found[itemname] = true | ||||
| 			end | ||||
| 		end | ||||
| 		result[craft_item] = found | ||||
| 	end | ||||
|  | ||||
| 	return result | ||||
| end | ||||
|  | ||||
| --[[ | ||||
| Match inventory items with craft grid positions. | ||||
| For every position select the matching inventory item with maximum | ||||
| (total_count / (times_matched + 1)) value. | ||||
|  | ||||
| If for some position matching item cannot be found or match count is 0 | ||||
| then return nil. | ||||
|  | ||||
| Return a table of "matched item name" - "set of craft positions" pairs | ||||
| and overall match count. | ||||
|  | ||||
| Arguments: | ||||
| 	inv_counts: table of inventory items counts from "count_items" | ||||
| 	craft_positions: table of craft positions from "count_craft_positions" | ||||
|  | ||||
| Example output: | ||||
| 	match_table = { | ||||
| 		["wool:white"] = {[1] = true, [2] = true, [3] = true} | ||||
| 		["default:acacia_wood"] = {[4] = true, [6] = true} | ||||
| 		["default:pine_wood"] = {[5] = true} | ||||
| 	} | ||||
| 	match_count = 2 | ||||
| --]] | ||||
| function unified_inventory.match_items(inv_counts, craft_positions) | ||||
| 	local usable = unified_inventory.find_usable_items(inv_counts, craft_positions) | ||||
| 	local match_table = {} | ||||
| 	local match_count | ||||
| 	local matches = {} | ||||
|  | ||||
| 	for craft_item, pos_set in pairs(craft_positions) do | ||||
| 		local use_set = usable[craft_item] | ||||
|  | ||||
| 		for pos in pairs(pos_set) do | ||||
| 			local pos_item | ||||
| 			local pos_count | ||||
|  | ||||
| 			for use_item in pairs(use_set) do | ||||
| 				local count = inv_counts[use_item] | ||||
| 				local times_matched = matches[use_item] or 0 | ||||
| 				local new_pos_count = math.floor(count / (times_matched + 1)) | ||||
|  | ||||
| 				if pos_count == nil or pos_count < new_pos_count then | ||||
| 					pos_item = use_item | ||||
| 					pos_count = new_pos_count | ||||
| 				end | ||||
| 			end | ||||
|  | ||||
| 			if pos_item == nil or pos_count == 0 then | ||||
| 				return nil | ||||
| 			end | ||||
|  | ||||
| 			local set = match_table[pos_item] | ||||
|  | ||||
| 			if set ~= nil then | ||||
| 				set[pos] = true | ||||
| 			else | ||||
| 				match_table[pos_item] = {[pos] = true} | ||||
| 			end | ||||
|  | ||||
| 			matches[pos_item] = (matches[pos_item] or 0) + 1 | ||||
| 		end | ||||
| 	end | ||||
|  | ||||
| 	for match_item, times_matched in pairs(matches) do | ||||
| 		local count = inv_counts[match_item] | ||||
| 		local item_count = math.floor(count / times_matched) | ||||
|  | ||||
| 		if match_count == nil or item_count < match_count then | ||||
| 			match_count = item_count | ||||
| 		end | ||||
| 	end | ||||
|  | ||||
| 	return match_table, match_count | ||||
| end | ||||
|  | ||||
| --[[ | ||||
| Remove item from inventory lists. | ||||
| Return stack of actually removed items. | ||||
|  | ||||
| This function replicates the inv:remove_item function but can accept | ||||
| multiple lists. | ||||
|  | ||||
| Arguments: | ||||
| 	inv: minetest inventory reference | ||||
| 	lists: names of inventory lists | ||||
| 	stack: minetest item stack | ||||
| --]] | ||||
| function unified_inventory.remove_item(inv, lists, stack) | ||||
| 	local removed = ItemStack(nil) | ||||
| 	local leftover = ItemStack(stack) | ||||
|  | ||||
| 	for i = 1, #lists do | ||||
| 		if leftover:is_empty() then | ||||
| 			break | ||||
| 		end | ||||
|  | ||||
| 		local cur_removed = inv:remove_item(lists[i], leftover) | ||||
| 		removed:add_item(cur_removed) | ||||
| 		leftover:take_item(cur_removed:get_count()) | ||||
| 	end | ||||
|  | ||||
| 	return removed | ||||
| end | ||||
|  | ||||
| --[[ | ||||
| Add item to inventory lists. | ||||
| Return leftover stack. | ||||
|  | ||||
| This function replicates the inv:add_item function but can accept | ||||
| multiple lists. | ||||
|  | ||||
| Arguments: | ||||
| 	inv: minetest inventory reference | ||||
| 	lists: names of inventory lists | ||||
| 	stack: minetest item stack | ||||
| --]] | ||||
| function unified_inventory.add_item(inv, lists, stack) | ||||
| 	local leftover = ItemStack(stack) | ||||
|  | ||||
| 	for i = 1, #lists do | ||||
| 		if leftover:is_empty() then | ||||
| 			break | ||||
| 		end | ||||
|  | ||||
| 		leftover = inv:add_item(lists[i], leftover) | ||||
| 	end | ||||
|  | ||||
| 	return leftover | ||||
| end | ||||
|  | ||||
| --[[ | ||||
| Move items from source list to destination list if possible. | ||||
| Skip positions specified in exclude set. | ||||
|  | ||||
| Arguments: | ||||
| 	inv: minetest inventory reference | ||||
| 	src_list: name of source list | ||||
| 	dst_list: name of destination list | ||||
| 	exclude: set of positions to skip | ||||
| --]] | ||||
| function unified_inventory.swap_items(inv, src_list, dst_list, exclude) | ||||
| 	local size = inv:get_size(src_list) | ||||
| 	local empty = ItemStack(nil) | ||||
|  | ||||
| 	for i = 1, size do | ||||
| 		if exclude == nil or exclude[i] == nil then | ||||
| 			local stack = inv:get_stack(src_list, i) | ||||
|  | ||||
| 			if not stack:is_empty() then | ||||
| 				inv:set_stack(src_list, i, empty) | ||||
| 				local leftover = inv:add_item(dst_list, stack) | ||||
|  | ||||
| 				if not leftover:is_empty() then | ||||
| 					inv:set_stack(src_list, i, leftover) | ||||
| 				end | ||||
| 			end | ||||
| 		end | ||||
| 	end | ||||
| end | ||||
|  | ||||
| --[[ | ||||
| Move matched items to the destination list. | ||||
|  | ||||
| If destination list position is already occupied with some other item | ||||
| then function tries to (in that order): | ||||
| 1. Move it to the source list | ||||
| 2. Move it to some other unused position in destination list itself | ||||
| 3. Drop it to the ground if nothing else is possible. | ||||
|  | ||||
| Arguments: | ||||
| 	player: minetest player object | ||||
| 	src_list: name of source list | ||||
| 	dst_list: name of destination list | ||||
| 	match_table: table of matched items | ||||
| 	amount: amount of items per every position | ||||
| --]] | ||||
| function unified_inventory.move_match(player, src_list, dst_list, match_table, amount) | ||||
| 	local inv = player:get_inventory() | ||||
| 	local item_drop = minetest.item_drop | ||||
| 	local src_dst_list = {src_list, dst_list} | ||||
| 	local dst_src_list = {dst_list, src_list} | ||||
|  | ||||
| 	local needed = {} | ||||
| 	local moved = {} | ||||
|  | ||||
| 	-- Remove stacks needed for craft | ||||
| 	for item, pos_set in pairs(match_table) do | ||||
| 		local stack = ItemStack(item) | ||||
| 		local stack_max = stack:get_stack_max() | ||||
| 		local bounded_amount = math.min(stack_max, amount) | ||||
| 		stack:set_count(bounded_amount) | ||||
|  | ||||
| 		for pos in pairs(pos_set) do | ||||
| 			needed[pos] = unified_inventory.remove_item(inv, dst_src_list, stack) | ||||
| 		end | ||||
| 	end | ||||
|  | ||||
| 	-- Add already removed stacks | ||||
| 	for pos, stack in pairs(needed) do | ||||
| 		local occupied = inv:get_stack(dst_list, pos) | ||||
| 		inv:set_stack(dst_list, pos, stack) | ||||
|  | ||||
| 		if not occupied:is_empty() then | ||||
| 			local leftover = unified_inventory.add_item(inv, src_dst_list, occupied) | ||||
|  | ||||
| 			if not leftover:is_empty() then | ||||
| 				inv:set_stack(dst_list, pos, leftover) | ||||
| 				local oversize = unified_inventory.add_item(inv, src_dst_list, stack) | ||||
|  | ||||
| 				if not oversize:is_empty() then | ||||
| 					item_drop(oversize, player, player:get_pos()) | ||||
| 				end | ||||
| 			end | ||||
| 		end | ||||
|  | ||||
| 		moved[pos] = true | ||||
| 	end | ||||
|  | ||||
| 	-- Swap items from unused positions to src (moved positions excluded) | ||||
| 	unified_inventory.swap_items(inv, dst_list, src_list, moved) | ||||
| end | ||||
|  | ||||
| --[[ | ||||
| Find craft match and move matched items to the destination list. | ||||
|  | ||||
| If match cannot be found or match count is smaller than the desired | ||||
| amount then do nothing. | ||||
|  | ||||
| If amount passed is -1 then amount is defined by match count itself. | ||||
| This is used to indicate "craft All" case. | ||||
|  | ||||
| Arguments: | ||||
| 	player: minetest player object | ||||
| 	src_list: name of source list | ||||
| 	dst_list: name of destination list | ||||
| 	craft: minetest craft recipe | ||||
| 	amount: desired amount of output items | ||||
| --]] | ||||
| function unified_inventory.craftguide_match_craft(player, src_list, dst_list, craft, amount) | ||||
| 	local inv = player:get_inventory() | ||||
| 	local src_dst_list = {src_list, dst_list} | ||||
|  | ||||
| 	local counts = unified_inventory.count_items(inv, src_dst_list) | ||||
| 	local positions = unified_inventory.count_craft_positions(craft) | ||||
| 	local match_table, match_count = unified_inventory.match_items(counts, positions) | ||||
|  | ||||
| 	if match_table == nil or match_count < amount then | ||||
| 		return | ||||
| 	end | ||||
|  | ||||
| 	if amount == -1 then | ||||
| 		amount = match_count | ||||
| 	end | ||||
|  | ||||
| 	unified_inventory.move_match(player, src_list, dst_list, match_table, amount) | ||||
| end | ||||
							
								
								
									
										8
									
								
								mod.conf
									
									
									
									
									
								
							
							
						
						| @@ -1,8 +0,0 @@ | ||||
| name = unified_inventory | ||||
|  | ||||
| optional_depends = default, creative, sfinv, datastorage | ||||
| 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. | ||||
| """ | ||||
| min_minetest_version = 5.4.0 | ||||
							
								
								
									
										569
									
								
								register.lua
									
									
									
									
									
								
							
							
						
						| @@ -1,21 +1,12 @@ | ||||
| local S = minetest.get_translator("unified_inventory") | ||||
| local NS = function(s) return s end | ||||
| local F = minetest.formspec_escape | ||||
| local ui = unified_inventory | ||||
|  | ||||
| minetest.register_privilege("creative", { | ||||
| 	description = S("Can use the creative inventory"), | ||||
| 	give_to_singleplayer = false, | ||||
| }) | ||||
|  | ||||
| minetest.register_privilege("ui_full", { | ||||
| 	description = S("Forces Unified Inventory to be displayed in Full mode if Lite mode is configured globally"), | ||||
| 	description = "Can use the creative inventory", | ||||
| 	give_to_singleplayer = false, | ||||
| }) | ||||
|  | ||||
| local trash = minetest.create_detached_inventory("trash", { | ||||
| 	--allow_put = function(inv, listname, index, stack, player) | ||||
| 	--	if ui.is_creative(player:get_player_name()) then | ||||
| 	--	if unified_inventory.is_creative(player:get_player_name()) then | ||||
| 	--		return stack:get_count() | ||||
| 	--	else | ||||
| 	--		return 0 | ||||
| @@ -29,456 +20,288 @@ local trash = minetest.create_detached_inventory("trash", { | ||||
| }) | ||||
| trash:set_size("main", 1) | ||||
|  | ||||
| ui.register_button("craft", { | ||||
| unified_inventory.register_button("craft", { | ||||
| 	type = "image", | ||||
| 	image = "ui_craft_icon.png", | ||||
| 	tooltip = S("Crafting Grid") | ||||
| }) | ||||
|  | ||||
| ui.register_button("craftguide", { | ||||
| unified_inventory.register_button("craftguide", { | ||||
| 	type = "image", | ||||
| 	image = "ui_craftguide_icon.png", | ||||
| 	tooltip = S("Crafting Guide") | ||||
| }) | ||||
|  | ||||
| ui.register_button("misc_set_day", { | ||||
| unified_inventory.register_button("home_gui_set", { | ||||
| 	type = "image", | ||||
| 	image = "ui_sethome_icon.png", | ||||
| 	action = function(player) | ||||
| 		local player_name = player:get_player_name() | ||||
| 		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, | ||||
| 					"Home position set to: " | ||||
| 					..minetest.pos_to_string(home)) | ||||
| 		end | ||||
| 	end, | ||||
| }) | ||||
|  | ||||
| unified_inventory.register_button("home_gui_go", { | ||||
| 	type = "image", | ||||
| 	image = "ui_gohome_icon.png", | ||||
| 	action = function(player) | ||||
| 		minetest.sound_play("teleport", | ||||
| 				{to_player=player:get_player_name(), gain = 1.0}) | ||||
| 		unified_inventory.go_home(player) | ||||
| 	end, | ||||
| }) | ||||
|  | ||||
| unified_inventory.register_button("misc_set_day", { | ||||
| 	type = "image", | ||||
| 	image = "ui_sun_icon.png", | ||||
| 	tooltip = S("Set time to day"), | ||||
| 	hide_lite=true, | ||||
| 	action = function(player) | ||||
| 		local player_name = player:get_player_name() | ||||
| 		if minetest.check_player_privs(player_name, {settime=true}) then | ||||
| 			minetest.sound_play("ui_morning", | ||||
| 			minetest.sound_play("birds", | ||||
| 					{to_player=player_name, gain = 1.0}) | ||||
| 			minetest.set_timeofday((6000 % 24000) / 24000) | ||||
| 			minetest.chat_send_player(player_name, | ||||
| 				S("Time of day set to 6am")) | ||||
| 					"Time of day set to 6am") | ||||
| 		else | ||||
| 			minetest.chat_send_player(player_name, | ||||
| 				S("You don't have the settime privilege!")) | ||||
| 			ui.set_inventory_formspec(player, ui.current_page[player_name]) | ||||
| 					"You don't have the" | ||||
| 					.." settime priviledge!") | ||||
| 		end | ||||
| 	end, | ||||
| 	condition = function(player) | ||||
| 		return minetest.check_player_privs(player:get_player_name(), {settime=true}) | ||||
| 	end, | ||||
| }) | ||||
|  | ||||
| ui.register_button("misc_set_night", { | ||||
| unified_inventory.register_button("misc_set_night", { | ||||
| 	type = "image", | ||||
| 	image = "ui_moon_icon.png", | ||||
| 	tooltip = S("Set time to night"), | ||||
| 	hide_lite=true, | ||||
| 	action = function(player) | ||||
| 		local player_name = player:get_player_name() | ||||
| 		if minetest.check_player_privs(player_name, {settime=true}) then | ||||
| 			minetest.sound_play("ui_owl", | ||||
| 			minetest.sound_play("owl", | ||||
| 					{to_player=player_name, gain = 1.0}) | ||||
| 			minetest.set_timeofday((21000 % 24000) / 24000) | ||||
| 			minetest.chat_send_player(player_name, | ||||
| 					S("Time of day set to 9pm")) | ||||
| 					"Time of day set to 9pm") | ||||
| 		else | ||||
| 			minetest.chat_send_player(player_name, | ||||
| 					S("You don't have the settime privilege!")) | ||||
| 			ui.set_inventory_formspec(player, ui.current_page[player_name]) | ||||
| 					"You don't have the" | ||||
| 					.." settime priviledge!") | ||||
| 		end | ||||
| 	end, | ||||
| 	condition = function(player) | ||||
| 		return minetest.check_player_privs(player:get_player_name(), {settime=true}) | ||||
| 	end, | ||||
| }) | ||||
|  | ||||
| ui.register_button("clear_inv", { | ||||
| unified_inventory.register_button("clear_inv", { | ||||
| 	type = "image", | ||||
| 	image = "ui_trash_icon.png", | ||||
| 	tooltip = S("Clear inventory"), | ||||
| 	action = function(player) | ||||
| 		local player_name = player:get_player_name() | ||||
| 		if not ui.is_creative(player_name) then | ||||
| 		if not unified_inventory.is_creative(player_name) then | ||||
| 			minetest.chat_send_player(player_name, | ||||
| 					S("This button has been disabled outside" | ||||
| 					"This button has been disabled outside" | ||||
| 					.." of creative mode to prevent" | ||||
| 					.." accidental inventory trashing." | ||||
| 					.."\nUse the trash slot instead.")) | ||||
| 			ui.set_inventory_formspec(player, ui.current_page[player_name]) | ||||
| 					.." Use the trash slot instead.") | ||||
| 			return | ||||
| 		end | ||||
| 		player:get_inventory():set_list("main", {}) | ||||
| 		minetest.chat_send_player(player_name, S('Inventory cleared!')) | ||||
| 		minetest.chat_send_player(player_name, 'Inventory Cleared!') | ||||
| 		minetest.sound_play("trash_all", | ||||
| 				{to_player=player_name, gain = 1.0}) | ||||
| 	end, | ||||
| 	condition = function(player) | ||||
| 		return ui.is_creative(player:get_player_name()) | ||||
| }) | ||||
|  | ||||
| unified_inventory.register_page("craft", { | ||||
| 	get_formspec = function(player, formspec) | ||||
| 		local player_name = player:get_player_name() | ||||
| 		local formspec = "background[0,1;8,3;ui_crafting_form.png]" | ||||
| 		formspec = formspec.."background[0,4.5;8,4;ui_main_inventory.png]" | ||||
| 		formspec = formspec.."image[0,0;1,1;ui_craft_icon.png]" | ||||
| 		formspec = formspec.."label[1,0;Crafting]" | ||||
| 		formspec = formspec.."listcolors[#00000000;#00000000]" | ||||
| 		formspec = formspec.."list[current_player;craftpreview;6,1;1,1;]" | ||||
| 		formspec = formspec.."list[current_player;craft;2,1;3,3;]" | ||||
| 		formspec = formspec.."label[7,2.5;Trash:]" | ||||
| 		formspec = formspec.."list[detached:trash;main;7,3;1,1;]" | ||||
| 		if unified_inventory.is_creative(player_name) then | ||||
| 			formspec = formspec.."label[0,2.5;Refill:]" | ||||
| 			formspec = formspec.."list[detached:"..player_name.."refill;main;0,3;1,1;]" | ||||
| 		end | ||||
| 		return {formspec=formspec} | ||||
| 	end, | ||||
| }) | ||||
|  | ||||
| ui.register_page("craft", { | ||||
| 	get_formspec = function(player, perplayer_formspec) | ||||
|  | ||||
| 		local formheaderx = perplayer_formspec.form_header_x | ||||
| 		local formheadery = perplayer_formspec.form_header_y | ||||
| 		local craftx = perplayer_formspec.craft_x | ||||
| 		local crafty = perplayer_formspec.craft_y | ||||
|  | ||||
| unified_inventory.register_page("craftguide", { | ||||
| 	get_formspec = function(player) | ||||
| 		local player_name = player:get_player_name() | ||||
| 		local formspec = { | ||||
| 			perplayer_formspec.standard_inv_bg, | ||||
| 			perplayer_formspec.craft_grid, | ||||
| 			"label["..formheaderx..","..formheadery..";" ..F(S("Crafting")).."]", | ||||
| 			"listcolors[#00000000;#00000000]", | ||||
| 			"listring[current_name;craft]", | ||||
| 			"listring[current_player;main]" | ||||
| 		} | ||||
| 		local n=#formspec+1 | ||||
|  | ||||
| 		if ui.trash_enabled or ui.is_creative(player_name) or minetest.get_player_privs(player_name).give then | ||||
| 			formspec[n] = string.format("label[%f,%f;%s]", craftx + 6.35, crafty + 2.3, F(S("Trash:"))) | ||||
| 			formspec[n+1] = ui.make_trash_slot(craftx + 6.25, crafty + 2.5) | ||||
| 			n=n + 2 | ||||
| 		local formspec = "background[0,1;8,3;ui_craftguide_form.png]" | ||||
| 		formspec = formspec.."background[0,4.5;8,4;ui_main_inventory.png]" | ||||
| 		formspec = formspec.."image[0,0;1,1;ui_craftguide_icon.png]" | ||||
| 		formspec = formspec.."label[1,0;Crafting Guide]" | ||||
| 		formspec = formspec.."listcolors[#00000000;#00000000]" | ||||
| 		formspec = formspec.."list[detached:"..player_name.."craftrecipe;output;6,1;1,1;]" | ||||
| 		formspec = formspec.."label[6,3.35;Method:]" | ||||
| 		local item_name = unified_inventory.current_item[player_name] | ||||
| 		local craft = nil | ||||
| 		if item_name then | ||||
| 			formspec = formspec.."textarea[1.3,0.6;10,1;;Result: "..item_name..";]" | ||||
| 			local alternates = 0 | ||||
| 			local alternate = unified_inventory.alternate[player_name] | ||||
| 			local crafts = unified_inventory.crafts_table[item_name] | ||||
| 			if crafts ~= nil and #crafts > 0 then | ||||
| 				alternates = #crafts | ||||
| 				craft = crafts[alternate] | ||||
| 				local method = craft.type | ||||
| 				local allow_auto_craft = ((method == "normal") or (method == "shapeless")) | ||||
| 				if craft.type == "normal" then | ||||
| 					method = "crafting" | ||||
| 				elseif craft.type == "shapeless" then | ||||
| 					method = "shapeless crafting" | ||||
| 				elseif craft.type == "alloy" then | ||||
| 					method = "alloy cooking" | ||||
| 				end | ||||
| 				formspec = formspec.."label[6,3.75;"..method.."]" | ||||
| 				if allow_auto_craft then | ||||
| 					formspec = formspec.."label[6,1.95;Copy to craft grid:]" | ||||
| 							.."button[6,2.5;0.6,0.5;craftguide_craft_1;1]" | ||||
| 							.."button[6.6,2.5;0.6,0.5;craftguide_craft_10;10]" | ||||
| 							.."button[7.2,2.5;0.6,0.5;craftguide_craft_max;All]" | ||||
| 				end | ||||
| 			end | ||||
| 			if alternates > 1 then | ||||
| 				formspec = formspec.."label[0,2.6;Recipe " | ||||
| 						..tostring(alternate).." of " | ||||
| 						..tostring(alternates).."]" | ||||
| 						.."button[0,3.15;2,1;alternate;Alternate]" | ||||
| 			end | ||||
| 		end | ||||
|  | ||||
| 		if ui.is_creative(player_name) then | ||||
| 			formspec[n] = ui.single_slot(craftx - 2.5, crafty + 2.5) | ||||
| 			formspec[n+1] = string.format("label[%f,%f;%s]", craftx - 2.4, crafty + 2.3, F(S("Refill:"))) | ||||
| 			formspec[n+2] = string.format("list[detached:%srefill;main;%f,%f;1,1;]", | ||||
| 				F(player_name), craftx - 2.5 + ui.list_img_offset, crafty + 2.5 + ui.list_img_offset) | ||||
| 		end | ||||
| 		return {formspec=table.concat(formspec)} | ||||
| 	end, | ||||
| }) | ||||
|  | ||||
| -- stack_image_button(): generate a form button displaying a stack of items | ||||
| -- | ||||
| -- The specified item may be a group.  In that case, the group will be | ||||
| -- represented by some item in the group, along with a flag indicating | ||||
| -- that it's a group.  If the group contains only one item, it will be | ||||
| -- treated as if that item had been specified directly. | ||||
|  | ||||
| local function stack_image_button(x, y, w, h, buttonname_prefix, item) | ||||
| 	local name = item:get_name() | ||||
| 	local description = item:get_meta():get_string("description") | ||||
| 	local show_is_group = false | ||||
| 	local displayitem = item:to_string() | ||||
| 	local selectitem = name | ||||
| 	if name:sub(1, 6) == "group:" then | ||||
| 		local group_name = name:sub(7) | ||||
| 		local group_item = ui.get_group_item(group_name) | ||||
| 		show_is_group = not group_item.sole | ||||
| 		displayitem = group_item.item or "unknown" | ||||
| 		selectitem = group_item.sole and displayitem or name | ||||
| 	end | ||||
| 	local label = show_is_group and "G" or "" | ||||
| 	-- Unique id to prevent tooltip being overridden | ||||
| 	local id = string.format("%i%i_", x*10, y*10) | ||||
| 	local buttonname = F(id..buttonname_prefix..ui.mangle_for_formspec(selectitem)) | ||||
| 	local button = string.format("item_image_button[%f,%f;%f,%f;%s;%s;%s]", | ||||
| 			x, y, w, h, | ||||
| 			F(displayitem), buttonname, label) | ||||
| 	if show_is_group then | ||||
| 		local groupstring, andcount = ui.extract_groupnames(name) | ||||
| 		local grouptip | ||||
| 		if andcount == 1 then | ||||
| 			grouptip = S("Any item belonging to the @1 group", groupstring) | ||||
| 		elseif andcount > 1 then | ||||
| 			grouptip = S("Any item belonging to the groups @1", groupstring) | ||||
| 		end | ||||
| 		grouptip = F(grouptip) | ||||
| 		if andcount >= 1 then | ||||
| 			button = button  .. string.format("tooltip[%s;%s]", buttonname, grouptip) | ||||
| 		end | ||||
| 	elseif description ~= "" then | ||||
| 		button = button  .. string.format("tooltip[%s;%s]", buttonname, F(description)) | ||||
| 	end | ||||
| 	return button | ||||
| end | ||||
|  | ||||
| -- The recipe text contains parameters, hence they can yet not be translated. | ||||
| -- Instead, use a dummy translation call so that it can be picked up by the | ||||
| -- static parsing of the translation string update script | ||||
| local recipe_text = { | ||||
| 	recipe = NS("Recipe @1 of @2"), | ||||
| 	usage = NS("Usage @1 of @2"), | ||||
| } | ||||
| local no_recipe_text = { | ||||
| 	recipe = S("No recipes"), | ||||
| 	usage = S("No usages"), | ||||
| } | ||||
| local role_text = { | ||||
| 	recipe = S("Result"), | ||||
| 	usage = S("Ingredient"), | ||||
| } | ||||
| local next_alt_text = { | ||||
| 	recipe = S("Show next recipe"), | ||||
| 	usage = S("Show next usage"), | ||||
| } | ||||
| local prev_alt_text = { | ||||
| 	recipe = S("Show previous recipe"), | ||||
| 	usage = S("Show previous usage"), | ||||
| } | ||||
| local other_dir = { | ||||
| 	recipe = "usage", | ||||
| 	usage = "recipe", | ||||
| } | ||||
|  | ||||
| ui.register_page("craftguide", { | ||||
| 	get_formspec = function(player, perplayer_formspec) | ||||
|  | ||||
| 		local craftguidex =       perplayer_formspec.craft_guide_x | ||||
| 		local craftguidey =       perplayer_formspec.craft_guide_y | ||||
| 		local craftguidearrowx =  perplayer_formspec.craft_guide_arrow_x | ||||
| 		local craftguideresultx = perplayer_formspec.craft_guide_result_x | ||||
| 		local formheaderx =       perplayer_formspec.form_header_x | ||||
| 		local formheadery =       perplayer_formspec.form_header_y | ||||
| 		local give_x =            perplayer_formspec.give_btn_x | ||||
|  | ||||
| 		local player_name = player:get_player_name() | ||||
| 		local player_privs = minetest.get_player_privs(player_name) | ||||
|  | ||||
| 		local formspec = { | ||||
| 			perplayer_formspec.standard_inv_bg, | ||||
| 			"label["..formheaderx..","..formheadery..";" .. F(S("Crafting Guide")) .. "]", | ||||
| 			"listcolors[#00000000;#00000000]" | ||||
| 		} | ||||
|  | ||||
| 		local item_name = ui.current_item[player_name] | ||||
| 		if not item_name then | ||||
| 			return { formspec = table.concat(formspec) } | ||||
| 		end | ||||
|  | ||||
| 		local n = 4 | ||||
|  | ||||
| 		local item_name_shown | ||||
| 		if minetest.registered_items[item_name] | ||||
| 				and minetest.registered_items[item_name].description then | ||||
| 			item_name_shown = S("@1 (@2)", | ||||
| 				minetest.registered_items[item_name].description, item_name) | ||||
| 		else | ||||
| 			item_name_shown = item_name | ||||
| 		end | ||||
|  | ||||
| 		local dir = ui.current_craft_direction[player_name] | ||||
| 		local rdir = dir == "recipe" and "usage" or "recipe" | ||||
|  | ||||
| 		local crafts = ui.crafts_for[dir][item_name] | ||||
| 		local alternate = ui.alternate[player_name] | ||||
| 		local alternates, craft | ||||
| 		if crafts and #crafts > 0 then | ||||
| 			alternates = #crafts | ||||
| 			craft = crafts[alternate] | ||||
| 		end | ||||
| 		local has_give = player_privs.give or ui.is_creative(player_name) | ||||
|  | ||||
| 		formspec[n] = string.format("image[%f,%f;%f,%f;ui_crafting_arrow.png]", | ||||
| 	                            craftguidearrowx, craftguidey, ui.imgscale, ui.imgscale) | ||||
|  | ||||
| 		formspec[n+1] = string.format("textarea[%f,%f;10,1;;%s: %s;]", | ||||
| 				perplayer_formspec.craft_guide_resultstr_x, perplayer_formspec.craft_guide_resultstr_y, | ||||
| 				F(role_text[dir]), item_name_shown) | ||||
| 		n = n + 2 | ||||
|  | ||||
| 		local giveme_form = table.concat({ | ||||
| 			"label[".. (give_x+0.1)..",".. (craftguidey + 2.7) .. ";" .. F(S("Give me:")) .. "]", | ||||
| 			"button["..(give_x)..","..     (craftguidey + 2.9) .. ";0.75,0.5;craftguide_giveme_1;1]", | ||||
| 			"button["..(give_x+0.8)..",".. (craftguidey + 2.9) .. ";0.75,0.5;craftguide_giveme_10;10]", | ||||
| 			"button["..(give_x+1.6)..",".. (craftguidey + 2.9) .. ";0.75,0.5;craftguide_giveme_99;99]" | ||||
| 		local craftinv = minetest.get_inventory({ | ||||
| 			type = "detached", | ||||
| 			name = player_name.."craftrecipe" | ||||
| 		}) | ||||
|  | ||||
| 		-- fake buttons just to make 3x3 grid | ||||
| 		for y = 1, 3 do | ||||
| 		for x = 1, 3 do | ||||
| 			formspec = formspec.."image_button[" | ||||
| 				..(1.0 + x)..","..(0.0 + y)..";1.1,1.1;ui_blank_image.png;;]" | ||||
| 		end | ||||
| 		end | ||||
|  | ||||
| 		if not craft then | ||||
| 			-- No craft recipes available for this item. | ||||
| 			formspec[n] = string.format("label[%f,%f;%s]", craftguidex+2.5, craftguidey+1.5, F(no_recipe_text[dir])) | ||||
| 			local no_pos = dir == "recipe" and (craftguidex+2.5) or craftguideresultx | ||||
| 			local item_pos = dir == "recipe" and craftguideresultx or (craftguidex+2.5) | ||||
| 			formspec[n+1] = "image["..no_pos..","..craftguidey..";1.2,1.2;ui_no.png]" | ||||
| 			formspec[n+2] = stack_image_button(item_pos, craftguidey, 1.2, 1.2, | ||||
| 				"item_button_" .. other_dir[dir] .. "_", ItemStack(item_name)) | ||||
| 			if has_give then | ||||
| 				formspec[n+3] = giveme_form | ||||
| 			end | ||||
| 			return { formspec = table.concat(formspec) } | ||||
| 		else | ||||
| 			formspec[n] = stack_image_button(craftguideresultx, craftguidey, 1.2, 1.2, | ||||
| 					"item_button_" .. rdir .. "_", ItemStack(craft.output)) | ||||
| 			n = n + 1 | ||||
| 			craftinv:set_stack("output", 1, nil) | ||||
| 			return {formspec=formspec} | ||||
| 		end | ||||
|  | ||||
| 		local craft_type = ui.registered_craft_types[craft.type] or | ||||
| 				ui.craft_type_defaults(craft.type, {}) | ||||
| 		if craft_type.icon then | ||||
| 			formspec[n] = string.format("image[%f,%f;%f,%f;%s]", | ||||
| 					craftguidearrowx+0.35, craftguidey, 0.5, 0.5, craft_type.icon) | ||||
| 			n = n + 1 | ||||
| 		end | ||||
| 		formspec[n] = string.format("label[%f,%f;%s]", craftguidearrowx + 0.15, craftguidey + 1.4, F(craft_type.description)) | ||||
| 		n = n + 1 | ||||
| 		craftinv:set_stack("output", 1, 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. | ||||
| 		local xoffset = craftguidex+3.75 | ||||
| 		local bspc = 1.25 | ||||
| 		-- Offset factor for crafting grids with side length > 4 | ||||
| 		local of = (3/math.max(3, math.max(display_size.width, display_size.height))) | ||||
| 		local od = 0 | ||||
| 		-- Minimum grid size at which size optimization measures kick in | ||||
| 		local mini_craft_size = 6 | ||||
| 		if display_size.width >= mini_craft_size then | ||||
| 			od = math.max(1, display_size.width - 2) | ||||
| 			xoffset = xoffset - 0.1 | ||||
| 		local width = craft.width | ||||
| 		if width == 0 then | ||||
| 			-- Shapeless recipe | ||||
| 			width = 3 | ||||
| 		end | ||||
| 		-- Size modifier factor | ||||
| 		local sf = math.min(1, of * (1.05 + 0.05*od)) | ||||
| 		-- Button size | ||||
| 		local bsize = 1.2 * sf | ||||
|  | ||||
| 		if display_size.width >= mini_craft_size then  -- it's not a normal 3x3 grid | ||||
| 			bsize = 0.8 * sf | ||||
| 		end | ||||
| 		if (bsize > 0.35 and display_size.width) then | ||||
| 		for y = 1, display_size.height do | ||||
| 		for x = 1, display_size.width do | ||||
| 			local item | ||||
| 			if craft and x <= craft_width then | ||||
| 				item = craft.items[(y-1) * craft_width + x] | ||||
| 			end | ||||
| 			-- Flipped x, used to build formspec buttons from right to left | ||||
| 			local fx = display_size.width - (x-1) | ||||
| 			-- x offset, y offset | ||||
| 			local xof = ((fx-1) * of + of) * bspc | ||||
| 			local yof = ((y-1) * of + 1) * bspc | ||||
| 		local i = 1 | ||||
| 		for y = 1, 3 do | ||||
| 		for x = 1, width do | ||||
| 			local item = craft.items[i] | ||||
| 			if item then | ||||
| 				formspec[n] = stack_image_button( | ||||
| 						xoffset - xof, craftguidey - 1.25 + yof, bsize, bsize, | ||||
| 						"item_button_recipe_", | ||||
| 						ItemStack(item)) | ||||
| 			else | ||||
| 				-- Fake buttons just to make grid | ||||
| 				formspec[n] = string.format("image_button[%f,%f;%f,%f;ui_blank_image.png;;]", | ||||
| 						xoffset - xof, craftguidey - 1.25 + yof, bsize, bsize) | ||||
| 				if string.sub(item, 1, 6) == "group:" then | ||||
| 					local group = string.sub(item, 7) | ||||
| 					formspec = formspec.."image_button[" | ||||
| 						..(1.0 + x)..","..(0.0 + y)..";1.1,1.1;" | ||||
| 						.."ui_group.png;" | ||||
| 						.."item_group_"..minetest.formspec_escape(group)..";" | ||||
| 						..minetest.formspec_escape(group).."]" | ||||
| 				else | ||||
| 					formspec = formspec.."item_image_button[" | ||||
| 						..(1.0 + x)..","..(0.0 + y)..";1.1,1.1;" | ||||
| 						..minetest.formspec_escape(item)..";" | ||||
| 						.."item_button_" | ||||
| 						..minetest.formspec_escape(item)..";]" | ||||
| 				end | ||||
| 			end | ||||
| 			n = n + 1 | ||||
| 			i = i + 1 | ||||
| 		end | ||||
| 		end | ||||
| 		else | ||||
| 			-- Error | ||||
| 			formspec[n] = string.format("label[2,%f;%s]", | ||||
| 				craftguidey, F(S("This recipe is too@nlarge to be displayed."))) | ||||
| 			n = n + 1 | ||||
| 		end | ||||
|  | ||||
| 		if craft_type.uses_crafting_grid and display_size.width <= 3 then | ||||
| 			formspec[n]   = "label["..(give_x+0.1)..","..    (craftguidey + 1.7) .. ";" .. F(S("To craft grid:")) .. "]" | ||||
| 			formspec[n+1] = "button["..  (give_x)..","..     (craftguidey + 1.9) .. ";0.75,0.5;craftguide_craft_1;1]" | ||||
| 			formspec[n+2] = "button["..  (give_x+0.8)..",".. (craftguidey + 1.9) .. ";0.75,0.5;craftguide_craft_10;10]" | ||||
| 			formspec[n+3] = "button["..  (give_x+1.6)..",".. (craftguidey + 1.9) .. ";0.75,0.5;craftguide_craft_max;" .. F(S("All")) .. "]" | ||||
| 			n = n + 4 | ||||
| 		end | ||||
|  | ||||
| 		if has_give then | ||||
| 			formspec[n] = giveme_form | ||||
| 			n = n + 1 | ||||
| 		end | ||||
|  | ||||
| 		if alternates and alternates > 1 then | ||||
| 			formspec[n] = string.format("label[%f,%f;%s]", | ||||
| 						craftguidex+4, craftguidey + 2.3, F(S(recipe_text[dir], alternate, alternates))) | ||||
| 			formspec[n+1] = string.format("image_button[%f,%f;1.1,1.1;ui_left_icon.png;alternate_prev;]", | ||||
| 						craftguidearrowx+0.2, craftguidey + 2.6) | ||||
| 			formspec[n+2] = string.format("image_button[%f,%f;1.1,1.1;ui_right_icon.png;alternate;]", | ||||
| 						craftguidearrowx+1.35, craftguidey + 2.6) | ||||
| 			formspec[n+3] = "tooltip[alternate_prev;" .. F(prev_alt_text[dir]) .. "]" | ||||
| 			formspec[n+4] = "tooltip[alternate;" .. F(next_alt_text[dir]) .. "]" | ||||
| 		end | ||||
|  | ||||
| 		return { formspec = table.concat(formspec) } | ||||
| 		return {formspec=formspec} | ||||
| 	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 ui.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 | ||||
|  | ||||
| 	amount = tonumber(amount) or 0 | ||||
| 	if amount == 0 then return end | ||||
|  | ||||
| 	local output = ui.current_item[player_name] | ||||
| 	if (not output) or (output == "") then return end | ||||
|  | ||||
| 	local player_inv = player:get_inventory() | ||||
|  | ||||
| 	player_inv:add_item("main", {name = output, count = amount}) | ||||
| end | ||||
|  | ||||
| local function craftguide_craft(player, formname, fields) | ||||
| minetest.register_on_player_receive_fields(function(player, formname, fields) | ||||
| 	local amount | ||||
| 	for k, v in pairs(fields) do | ||||
| 		amount = k:match("craftguide_craft_(.*)") | ||||
| 		if amount then break end | ||||
| 	end | ||||
| 	if not amount then return end | ||||
|  | ||||
| 	amount = tonumber(amount) or -1 -- fallback for "all" | ||||
| 	if amount == 0 or amount < -1 or amount > 99 then return end | ||||
|  | ||||
| 	local player_name = player:get_player_name() | ||||
| 	local recipe_inv = minetest.get_inventory({ | ||||
| 		type="detached", | ||||
| 		name=player_name.."craftrecipe", | ||||
| 	}) | ||||
|  | ||||
| 	local output = ui.current_item[player_name] or "" | ||||
| 	if output == "" then return end | ||||
| 	local output = unified_inventory.current_item[player_name] | ||||
| 	if (not output) or (output == "") then return end | ||||
|  | ||||
| 	local crafts = ui.crafts_for[ | ||||
| 		ui.current_craft_direction[player_name]][output] or {} | ||||
| 	if #crafts == 0 then return end | ||||
| 	local player_inv = player:get_inventory() | ||||
|  | ||||
| 	local alternate = ui.alternate[player_name] | ||||
| 	local crafts = unified_inventory.crafts_table[output] | ||||
| 	if (not crafts) or (#crafts == 0) then return end | ||||
|  | ||||
| 	local alternate = unified_inventory.alternate[player_name] | ||||
|  | ||||
| 	local craft = crafts[alternate] | ||||
| 	if not craft.width then | ||||
| 		if not craft.output then | ||||
| 			minetest.log("warning", "[unified_inventory] Craft has no output.") | ||||
| 		else | ||||
| 			minetest.log("warning", ("[unified_inventory] Craft for '%s' has no width."):format(craft.output)) | ||||
| 		end | ||||
| 		return | ||||
| 	end | ||||
| 	if craft.width > 3 then return end | ||||
|  | ||||
| 	ui.craftguide_match_craft(player, "main", "craft", craft, amount) | ||||
| 	local needed = craft.items | ||||
|  | ||||
| 	ui.set_inventory_formspec(player, "craft") | ||||
| end | ||||
| 	local craft_list = player_inv:get_list("craft") | ||||
|  | ||||
| minetest.register_on_player_receive_fields(function(player, formname, fields) | ||||
| 	if formname ~= "" then | ||||
| 		return | ||||
| 	local width = craft.width | ||||
| 	if width == 0 then | ||||
| 		-- Shapeless recipe | ||||
| 		width = 3 | ||||
| 	end | ||||
|  | ||||
| 	for k, v in pairs(fields) do | ||||
| 		if k:match("craftguide_craft_") then | ||||
| 			craftguide_craft(player, formname, fields) | ||||
| 			return | ||||
| 		end | ||||
| 		if k:match("craftguide_giveme_") then | ||||
| 			craftguide_giveme(player, formname, fields) | ||||
| 			return | ||||
| 	if amount == "max" then | ||||
| 		amount = 99 -- Arbitrary; need better way to do this. | ||||
| 	else | ||||
| 		amount = tonumber(amount) | ||||
| 	end | ||||
|  | ||||
| 	for iter = 1, amount do | ||||
| 		local index = 1 | ||||
| 		for y = 1, 3 do | ||||
| 			for x = 1, width do | ||||
| 				local needed_item = needed[index] | ||||
| 				if needed_item then | ||||
| 					local craft_index = ((y - 1) * 3) + x | ||||
| 					local craft_item = craft_list[craft_index] | ||||
| 					if (not craft_item) or (craft_item:is_empty()) or (craft_item:get_name() == needed_item) then | ||||
| 						itemname = craft_item and craft_item:get_name() or needed_item | ||||
| 						local needed_stack = ItemStack(needed_item) | ||||
| 						if player_inv:contains_item("main", needed_stack) then | ||||
| 							local count = (craft_item and craft_item:get_count() or 0) + 1 | ||||
| 							if count <= needed_stack:get_definition().stack_max then | ||||
| 								local stack = ItemStack({name=needed_item, count=count}) | ||||
| 								craft_list[craft_index] = stack | ||||
| 								player_inv:remove_item("main", needed_stack) | ||||
| 							end | ||||
| 						end | ||||
| 					end | ||||
| 				end | ||||
| 				index = index + 1 | ||||
| 			end | ||||
| 		end | ||||
| 	end | ||||
|  | ||||
| 	player_inv:set_list("craft", craft_list) | ||||
|  | ||||
| 	unified_inventory.set_inventory_formspec(player, "craft") | ||||
| end) | ||||
|   | ||||
							
								
								
									
										
											BIN
										
									
								
								screenshot.png
									
									
									
									
									
								
							
							
						
						| Before Width: | Height: | Size: 220 KiB | 
| @@ -1,32 +0,0 @@ | ||||
| # Reduced formspec layout, optimized for smaller displays. | ||||
| # Note: This may also disable some features to free up visual space. | ||||
| unified_inventory_lite (Lite mode) bool false | ||||
|  | ||||
| # Provides craftable bag items to extend the inventory space. | ||||
| unified_inventory_bags (Enable bags) bool true | ||||
|  | ||||
| # Shows the trash slot to everyone. | ||||
| # When disabled, only players with the privilege "creative" or "give" will | ||||
| # have this slot shown in their inventory. | ||||
| unified_inventory_trash (Enable trash) bool true | ||||
|  | ||||
| # Provides waypoints on a per-player basis to remember positions on the map. | ||||
| unified_inventory_waypoints (Enable waypoints) bool true | ||||
|  | ||||
| # If enabled, disabled buttons will be hidden instead of grayed out. | ||||
| unified_inventory_hide_disabled_buttons (Hide disabled buttons) bool false | ||||
|  | ||||
| # Automatically categorizes registered items based on their | ||||
| # groups. This is based on a fuzzy match, thus is not 100% accurate. | ||||
| unified_inventory_automatic_categorization (Categories: add items automatically) bool true | ||||
|  | ||||
| # Shows the selected wielded item description in the HUD for a few seconds. | ||||
| unified_inventory_item_names (Enable HUD item names) bool true | ||||
|  | ||||
| # Trims the shown wielded item description to the first line. | ||||
| unified_inventory_only_names (HUD item name: first line only) bool true | ||||
|  | ||||
| # Hard character limit of the wielded item description. | ||||
| # Crops the shown description to the specified length. | ||||
| # 0 disables this functionality. | ||||
| unified_inventory_max_item_name_length (HUD item names: character limit) int 80 | ||||
							
								
								
									
										
											BIN
										
									
								
								sounds/birds.ogg
									
									
									
									
									
										Normal file
									
								
							
							
						
						
							
								
								
									
										
											BIN
										
									
								
								sounds/owl.ogg
									
									
									
									
									
										Normal file
									
								
							
							
						
						| Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 572 B | 
| Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 797 B | 
| Before Width: | Height: | Size: 9.1 KiB After Width: | Height: | Size: 572 B | 
| Before Width: | Height: | Size: 456 B After Width: | Height: | Size: 321 B | 
| Before Width: | Height: | Size: 961 B After Width: | Height: | Size: 567 B | 
| Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 647 B | 
| Before Width: | Height: | Size: 658 B After Width: | Height: | Size: 420 B | 
| Before Width: | Height: | Size: 928 B After Width: | Height: | Size: 554 B | 
| Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 4.5 KiB | 
							
								
								
									
										
											BIN
										
									
								
								textures/ui_bags_lg_form.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 14 KiB | 
							
								
								
									
										
											BIN
										
									
								
								textures/ui_bags_main_form.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 10 KiB | 
							
								
								
									
										
											BIN
										
									
								
								textures/ui_bags_med_form.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 12 KiB | 
							
								
								
									
										
											BIN
										
									
								
								textures/ui_bags_sm_form.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 11 KiB | 
| Before Width: | Height: | Size: 71 B After Width: | Height: | Size: 143 B | 
| Before Width: | Height: | Size: 3.3 KiB After Width: | Height: | Size: 2.9 KiB | 
							
								
								
									
										
											BIN
										
									
								
								textures/ui_cancel_icon.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 3.5 KiB | 
| Before Width: | Height: | Size: 1.2 KiB | 
| Before Width: | Height: | Size: 7.8 KiB | 
| Before Width: | Height: | Size: 8.6 KiB After Width: | Height: | Size: 3.0 KiB | 
| Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 3.1 KiB | 
| Before Width: | Height: | Size: 483 B | 
							
								
								
									
										
											BIN
										
									
								
								textures/ui_craftguide_form.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 13 KiB | 
| Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 3.2 KiB | 
| Before Width: | Height: | Size: 788 B | 
							
								
								
									
										
											BIN
										
									
								
								textures/ui_crafting_form.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 12 KiB | 
| Before Width: | Height: | Size: 9.0 KiB After Width: | Height: | Size: 2.3 KiB | 
| Before Width: | Height: | Size: 9.1 KiB After Width: | Height: | Size: 2.3 KiB | 
							
								
								
									
										
											BIN
										
									
								
								textures/ui_form_bg.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 6.3 KiB | 
| Before Width: | Height: | Size: 510 B | 
| Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 2.9 KiB | 
| Before Width: | Height: | Size: 3.6 KiB After Width: | Height: | Size: 2.9 KiB | 
| Before Width: | Height: | Size: 22 KiB After Width: | Height: | Size: 29 KiB | 
| Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 2.8 KiB | 
| Before Width: | Height: | Size: 6.3 KiB After Width: | Height: | Size: 2.0 KiB | 
							
								
								
									
										
											BIN
										
									
								
								textures/ui_main_inventory.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 7.5 KiB | 
							
								
								
									
										
											BIN
										
									
								
								textures/ui_misc_form.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 9.1 KiB | 
| Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 4.3 KiB | 
| Before Width: | Height: | Size: 6.2 KiB | 
| Before Width: | Height: | Size: 5.6 KiB After Width: | Height: | Size: 3.0 KiB | 
| Before Width: | Height: | Size: 3.6 KiB After Width: | Height: | Size: 2.4 KiB | 
| Before Width: | Height: | Size: 5.6 KiB After Width: | Height: | Size: 3.0 KiB | 
| Before Width: | Height: | Size: 5.9 KiB After Width: | Height: | Size: 1.2 KiB | 
| Before Width: | Height: | Size: 3.2 KiB After Width: | Height: | Size: 2.5 KiB | 
| Before Width: | Height: | Size: 10 KiB | 
| Before Width: | Height: | Size: 6.3 KiB After Width: | Height: | Size: 1.9 KiB | 
| Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 3.3 KiB | 
| Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 2.9 KiB | 
| Before Width: | Height: | Size: 648 B | 
| Before Width: | Height: | Size: 1.0 KiB | 
| Before Width: | Height: | Size: 8.1 KiB After Width: | Height: | Size: 2.8 KiB | 
| Before Width: | Height: | Size: 8.0 KiB After Width: | Height: | Size: 2.8 KiB | 
| Before Width: | Height: | Size: 551 B | 
| Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 5.3 KiB | 
| Before Width: | Height: | Size: 2.2 KiB | 
| Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 4.3 KiB | 
| Before Width: | Height: | Size: 697 B | 
| Before Width: | Height: | Size: 3.7 KiB After Width: | Height: | Size: 2.0 KiB | 
| Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 4.0 KiB |