forked from minetest-mods/unified_inventory
		
	Compare commits
	
		
			38 Commits
		
	
	
		
			a977ec47fd
			...
			99bdfe9e14
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 99bdfe9e14 | |||
| 
						 | 
					43cf0d8e7e | ||
| 
						 | 
					e132a17523 | ||
| 6f132186ab | |||
| 
						 | 
					e071a01372 | ||
| 
						 | 
					1547ebcdd4 | ||
| 
						 | 
					16265dca2d | ||
| 
						 | 
					235fa841dd | ||
| 
						 | 
					2c9449b6e7 | ||
| 
						 | 
					b5de18b196 | ||
| 
						 | 
					921a6d76ee | ||
| 
						 | 
					004a39aaf7 | ||
| 
						 | 
					eb3bb03ebf | ||
| 
						 | 
					e7d03626b4 | ||
| cb6e602497 | |||
| 
						 | 
					693ca112b8 | ||
| 
						 | 
					380b77d0fb | ||
| 
						 | 
					43c9b50800 | ||
| 
						 | 
					5d233a0f0a | ||
| 
						 | 
					2426b6c912 | ||
| 
						 | 
					d6d4bea819 | ||
| aa04d4539f | |||
| 
						 | 
					15d729c351 | ||
| 
						 | 
					b2cc3d1532 | ||
| 
						 | 
					37969b2a1b | ||
| 
						 | 
					1b074828a6 | ||
| 
						 | 
					de0063835c | ||
| 
						 | 
					bda9f2598f | ||
| 
						 | 
					b590764026 | ||
| 
						 | 
					82cdf24045 | ||
| 
						 | 
					31c35dcd59 | ||
| 
						 | 
					826d5f4683 | ||
| 
						 | 
					db1c3c10b8 | ||
| 
						 | 
					9533200e25 | ||
| 
						 | 
					177debd13c | ||
| 
						 | 
					8e9ea34ae8 | ||
| 
						 | 
					574de91971 | ||
| 
						 | 
					fc562ecaa0 | 
@@ -10,6 +10,7 @@ read_globals = {
 | 
			
		||||
	string = {fields = {"split", "trim"}},
 | 
			
		||||
	table = {fields = {"copy", "getn"}},
 | 
			
		||||
 | 
			
		||||
	"dump",
 | 
			
		||||
	"minetest", "vector",
 | 
			
		||||
	"ItemStack", "datastorage",
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										16
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										16
									
								
								README.md
									
									
									
									
									
								
							@@ -71,6 +71,9 @@ From http://www.clker.com (Public Domain, CC-BY-4.0):
 | 
			
		||||
  * [`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)
 | 
			
		||||
@@ -102,3 +105,16 @@ Other files from Wikimedia Commons:
 | 
			
		||||
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)
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										170
									
								
								api.lua
									
									
									
									
									
								
							
							
						
						
									
										170
									
								
								api.lua
									
									
									
									
									
								
							@@ -2,48 +2,61 @@ 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 source, target in pairs(minetest.registered_aliases) do
 | 
			
		||||
		if not rev_aliases[target] then rev_aliases[target] = {} end
 | 
			
		||||
		table.insert(rev_aliases[target], source)
 | 
			
		||||
	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 = {}
 | 
			
		||||
	for name, def in pairs(minetest.registered_items) do
 | 
			
		||||
		if (not def.groups.not_in_creative_inventory or
 | 
			
		||||
		   def.groups.not_in_creative_inventory == 0) and
 | 
			
		||||
		   def.description and def.description ~= "" then
 | 
			
		||||
		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 _, player_name in ipairs(all_names) do
 | 
			
		||||
				local recipes = minetest.get_all_craft_recipes(player_name)
 | 
			
		||||
				if recipes then
 | 
			
		||||
					for _, recipe in ipairs(recipes) do
 | 
			
		||||
 | 
			
		||||
						local unknowns
 | 
			
		||||
 | 
			
		||||
						for _,chk in pairs(recipe.items) do
 | 
			
		||||
							local groupchk = string.find(chk, "group:")
 | 
			
		||||
							if (not groupchk and not minetest.registered_items[chk])
 | 
			
		||||
							  or (groupchk and not ui.get_group_item(string.gsub(chk, "group:", "")).item)
 | 
			
		||||
							  or minetest.get_item_group(chk, "not_in_craft_guide") ~= 0 then
 | 
			
		||||
								unknowns = true
 | 
			
		||||
							end
 | 
			
		||||
						end
 | 
			
		||||
 | 
			
		||||
						if not unknowns then
 | 
			
		||||
							ui.register_craft(recipe)
 | 
			
		||||
						end
 | 
			
		||||
			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
 | 
			
		||||
			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
 | 
			
		||||
@@ -134,50 +147,18 @@ minetest.after(0.01, function()
 | 
			
		||||
		end
 | 
			
		||||
	end
 | 
			
		||||
 | 
			
		||||
	-- Step 1: group-indexed lookup table for items
 | 
			
		||||
	local spec_matcher = {}
 | 
			
		||||
	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
 | 
			
		||||
	-- 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 function get_matching_spec_items(specname)
 | 
			
		||||
		if specname:sub(1,6) ~= "group:" then
 | 
			
		||||
			return { [specname] = true }
 | 
			
		||||
		end
 | 
			
		||||
	local get_matching_spec_items = unified_inventory.get_matching_items
 | 
			
		||||
 | 
			
		||||
		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
 | 
			
		||||
 | 
			
		||||
	for _, recipes in pairs(ui.crafts_for.recipe) do
 | 
			
		||||
	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
 | 
			
		||||
@@ -193,7 +174,45 @@ minetest.after(0.01, function()
 | 
			
		||||
				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
 | 
			
		||||
 | 
			
		||||
	-- Remove unknown items from all categories
 | 
			
		||||
	local total_removed = 0
 | 
			
		||||
	for cat_name, cat_def in pairs(ui.registered_category_items) do
 | 
			
		||||
		for itemname, _ in pairs(cat_def) do
 | 
			
		||||
			local idef = minetest.registered_items[itemname]
 | 
			
		||||
			if not idef then
 | 
			
		||||
				total_removed = total_removed + 1
 | 
			
		||||
				--[[
 | 
			
		||||
				-- For analysis
 | 
			
		||||
				minetest.log("warning", "[unified_inventory] Removed item '"
 | 
			
		||||
					.. itemname .. "' from category '" .. cat_name
 | 
			
		||||
					.. "'. Reason: item not registered")
 | 
			
		||||
				]]
 | 
			
		||||
				cat_def[itemname] = nil
 | 
			
		||||
			elseif not ui.is_itemdef_listable(idef) then
 | 
			
		||||
				total_removed = total_removed + 1
 | 
			
		||||
				--[[
 | 
			
		||||
				-- For analysis
 | 
			
		||||
				minetest.log("warning", "[unified_inventory] Removed item '"
 | 
			
		||||
					.. itemname .. "' from category '" .. cat_name
 | 
			
		||||
					.. "'. Reason: item is in 'not_in_creative_inventory' group")
 | 
			
		||||
				]]
 | 
			
		||||
				cat_def[itemname] = nil
 | 
			
		||||
			end
 | 
			
		||||
		end
 | 
			
		||||
	end
 | 
			
		||||
	if total_removed > 0 then
 | 
			
		||||
		minetest.log("info", "[unified_inventory] Removed " .. total_removed ..
 | 
			
		||||
			" items from the categories.")
 | 
			
		||||
	end
 | 
			
		||||
 | 
			
		||||
	for _, callback in ipairs(ui.initialized_callbacks) do
 | 
			
		||||
@@ -201,8 +220,8 @@ minetest.after(0.01, function()
 | 
			
		||||
	end
 | 
			
		||||
end)
 | 
			
		||||
 | 
			
		||||
---------------- Home API ----------------
 | 
			
		||||
 | 
			
		||||
-- load_home
 | 
			
		||||
local function load_home()
 | 
			
		||||
	local input = io.open(ui.home_filename, "r")
 | 
			
		||||
	if not input then
 | 
			
		||||
@@ -219,6 +238,7 @@ local function load_home()
 | 
			
		||||
	end
 | 
			
		||||
	io.close(input)
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
load_home()
 | 
			
		||||
 | 
			
		||||
function ui.set_home(player, pos)
 | 
			
		||||
@@ -247,7 +267,8 @@ function ui.go_home(player)
 | 
			
		||||
	return false
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
-- register_craft
 | 
			
		||||
---------------- Crafting API ----------------
 | 
			
		||||
 | 
			
		||||
function ui.register_craft(options)
 | 
			
		||||
	if not options.output then
 | 
			
		||||
		return
 | 
			
		||||
@@ -270,14 +291,12 @@ function ui.register_craft(options)
 | 
			
		||||
	end
 | 
			
		||||
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
 | 
			
		||||
@@ -288,8 +307,7 @@ end
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
function ui.register_craft_type(name, options)
 | 
			
		||||
	ui.registered_craft_types[name] =
 | 
			
		||||
			ui.craft_type_defaults(name, options)
 | 
			
		||||
	ui.registered_craft_types[name] = ui.craft_type_defaults(name, options)
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@@ -346,6 +364,8 @@ ui.register_craft_type("digging_chance", {
 | 
			
		||||
	height = 1,
 | 
			
		||||
})
 | 
			
		||||
 | 
			
		||||
---------------- GUI registrations ----------------
 | 
			
		||||
 | 
			
		||||
function ui.register_page(name, def)
 | 
			
		||||
	ui.pages[name] = def
 | 
			
		||||
end
 | 
			
		||||
@@ -361,6 +381,8 @@ function ui.register_button(name, def)
 | 
			
		||||
	table.insert(ui.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)))
 | 
			
		||||
@@ -375,6 +397,8 @@ function ui.register_on_craft_registered(callback)
 | 
			
		||||
	table.insert(ui.craft_registered_callbacks, callback)
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
---------------- List getters ----------------
 | 
			
		||||
 | 
			
		||||
function ui.get_recipe_list(output)
 | 
			
		||||
	return ui.crafts_for.recipe[output]
 | 
			
		||||
end
 | 
			
		||||
@@ -387,11 +411,15 @@ function ui.get_registered_outputs()
 | 
			
		||||
	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 "") )
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										143
									
								
								bags.lua
									
									
									
									
									
								
							
							
						
						
									
										143
									
								
								bags.lua
									
									
									
									
									
								
							@@ -10,25 +10,26 @@ local F = minetest.formspec_escape
 | 
			
		||||
local ui = unified_inventory
 | 
			
		||||
 | 
			
		||||
ui.register_page("bags", {
 | 
			
		||||
	get_formspec = function(player)
 | 
			
		||||
	get_formspec = function(player, perplayer_formspec)
 | 
			
		||||
		local player_name = player:get_player_name()
 | 
			
		||||
		return { formspec = table.concat({
 | 
			
		||||
			ui.style_full.standard_inv_bg,
 | 
			
		||||
			ui.single_slot(0.925, 1.5),
 | 
			
		||||
			ui.single_slot(3.425, 1.5),
 | 
			
		||||
			ui.single_slot(5.925, 1.5),
 | 
			
		||||
			ui.single_slot(8.425, 1.5),
 | 
			
		||||
			"label["..ui.style_full.form_header_x..","..ui.style_full.form_header_y..";" .. F(S("Bags")) .. "]",
 | 
			
		||||
			"button[0.6125,2.75;1.875,0.75;bag1;" .. F(S("Bag @1", 1)) .. "]",
 | 
			
		||||
			"button[3.1125,2.75;1.875,0.75;bag2;" .. F(S("Bag @1", 2)) .. "]",
 | 
			
		||||
			"button[5.6125,2.75;1.875,0.75;bag3;" .. F(S("Bag @1", 3)) .. "]",
 | 
			
		||||
			"button[8.1125,2.75;1.875,0.75;bag4;" .. F(S("Bag @1", 4)) .. "]",
 | 
			
		||||
		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]",
 | 
			
		||||
			"list[detached:" .. F(player_name) .. "_bags;bag1;1.075,1.65;1,1;]",
 | 
			
		||||
			"list[detached:" .. F(player_name) .. "_bags;bag2;3.575,1.65;1,1;]",
 | 
			
		||||
			"list[detached:" .. F(player_name) .. "_bags;bag3;6.075,1.65;1,1;]",
 | 
			
		||||
			"list[detached:" .. F(player_name) .. "_bags;bag4;8.575,1.65;1,1;]"
 | 
			
		||||
		}) }
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		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) }
 | 
			
		||||
	end,
 | 
			
		||||
})
 | 
			
		||||
 | 
			
		||||
@@ -36,7 +37,6 @@ ui.register_button("bags", {
 | 
			
		||||
	type = "image",
 | 
			
		||||
	image = "ui_bags_icon.png",
 | 
			
		||||
	tooltip = S("Bags"),
 | 
			
		||||
	hide_lite=true
 | 
			
		||||
})
 | 
			
		||||
 | 
			
		||||
local function get_player_bag_stack(player, i)
 | 
			
		||||
@@ -48,23 +48,38 @@ end
 | 
			
		||||
 | 
			
		||||
for bag_i = 1, 4 do
 | 
			
		||||
	ui.register_page("bag" .. bag_i, {
 | 
			
		||||
		get_formspec = function(player)
 | 
			
		||||
		get_formspec = function(player, perplayer_formspec)
 | 
			
		||||
			local stack = get_player_bag_stack(player, bag_i)
 | 
			
		||||
			local image = stack:get_definition().inventory_image
 | 
			
		||||
			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
 | 
			
		||||
			end
 | 
			
		||||
 | 
			
		||||
			local formspec = {
 | 
			
		||||
				ui.style_full.standard_inv_bg,
 | 
			
		||||
				ui.make_inv_img_grid(0.3, 1.5, 8, slots/8),
 | 
			
		||||
				"image[9.2,0.4;1,1;" .. image .. "]",
 | 
			
		||||
				"label[0.3,0.65;" .. F(S("Bag @1", bag_i)) .. "]",
 | 
			
		||||
				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, 0.3 + ui.list_img_offset, 1.5 + ui.list_img_offset),
 | 
			
		||||
				"listring[current_name;bag" .. bag_i .. "contents]",
 | 
			
		||||
				    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
 | 
			
		||||
@@ -114,6 +129,8 @@ minetest.register_on_player_receive_fields(function(player, formname, fields)
 | 
			
		||||
	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 = {}
 | 
			
		||||
@@ -127,7 +144,7 @@ local function save_bags_metadata(player, bags_inv)
 | 
			
		||||
	end
 | 
			
		||||
	local meta = player:get_meta()
 | 
			
		||||
	if is_empty then
 | 
			
		||||
		meta:set_string("unified_inventory:bags", nil)
 | 
			
		||||
		meta:set_string("unified_inventory:bags", "")
 | 
			
		||||
	else
 | 
			
		||||
		meta:set_string("unified_inventory:bags",
 | 
			
		||||
			minetest.serialize(bags))
 | 
			
		||||
@@ -163,7 +180,7 @@ local function load_bags_metadata(player, bags_inv)
 | 
			
		||||
		save_bags_metadata(player, bags_inv)
 | 
			
		||||
	end
 | 
			
		||||
 | 
			
		||||
	-- Clean up deprecated garbage after saving
 | 
			
		||||
	-- Legacy: Clean up old player lists
 | 
			
		||||
	for i = 1, 4 do
 | 
			
		||||
		local bag = "bag" .. i
 | 
			
		||||
		player_inv:set_size(bag, 0)
 | 
			
		||||
@@ -172,46 +189,29 @@ end
 | 
			
		||||
 | 
			
		||||
minetest.register_on_joinplayer(function(player)
 | 
			
		||||
	local player_name = player:get_player_name()
 | 
			
		||||
	local bags_inv = minetest.create_detached_inventory(player_name .. "_bags",{
 | 
			
		||||
	local bags_inv = minetest.create_detached_inventory(player_name .. "_bags", {
 | 
			
		||||
		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,
 | 
			
		||||
		on_put = function(inv, listname, index, stack, player)
 | 
			
		||||
			player:get_inventory():set_size(listname .. "contents",
 | 
			
		||||
					stack:get_definition().groups.bagslots)
 | 
			
		||||
			save_bags_metadata(player, inv)
 | 
			
		||||
		end,
 | 
			
		||||
		allow_put = function(inv, listname, index, stack, player)
 | 
			
		||||
			local new_slots = stack:get_definition().groups.bagslots
 | 
			
		||||
			if not new_slots then
 | 
			
		||||
				return 0
 | 
			
		||||
			end
 | 
			
		||||
			local player_inv = player:get_inventory()
 | 
			
		||||
			local old_slots = player_inv:get_size(listname .. "contents")
 | 
			
		||||
 | 
			
		||||
			if new_slots >= old_slots then
 | 
			
		||||
				return 1
 | 
			
		||||
			end
 | 
			
		||||
 | 
			
		||||
			-- using a smaller bag, make sure it fits
 | 
			
		||||
			local old_list = player_inv:get_list(listname .. "contents")
 | 
			
		||||
			local new_list = {}
 | 
			
		||||
			local slots_used = 0
 | 
			
		||||
			local use_new_list = false
 | 
			
		||||
 | 
			
		||||
			for i, v in ipairs(old_list) do
 | 
			
		||||
				if v and not v:is_empty() then
 | 
			
		||||
					slots_used = slots_used + 1
 | 
			
		||||
					use_new_list = i > new_slots
 | 
			
		||||
					new_list[slots_used] = v
 | 
			
		||||
				end
 | 
			
		||||
			end
 | 
			
		||||
			if new_slots >= slots_used then
 | 
			
		||||
				if use_new_list then
 | 
			
		||||
					player_inv:set_list(listname .. "contents", new_list)
 | 
			
		||||
				end
 | 
			
		||||
				return 1
 | 
			
		||||
			end
 | 
			
		||||
			-- New bag is smaller: Disallow inserting
 | 
			
		||||
			return 0
 | 
			
		||||
		end,
 | 
			
		||||
		allow_take = function(inv, listname, index, stack, player)
 | 
			
		||||
			if player:get_inventory():is_empty(listname .. "contents") then
 | 
			
		||||
				return stack:get_count()
 | 
			
		||||
@@ -221,6 +221,11 @@ minetest.register_on_joinplayer(function(player)
 | 
			
		||||
		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")
 | 
			
		||||
			end
 | 
			
		||||
		end,
 | 
			
		||||
		allow_move = function()
 | 
			
		||||
			return 0
 | 
			
		||||
@@ -230,6 +235,20 @@ minetest.register_on_joinplayer(function(player)
 | 
			
		||||
	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
 | 
			
		||||
	end
 | 
			
		||||
end)
 | 
			
		||||
 | 
			
		||||
-- register bag tools
 | 
			
		||||
minetest.register_tool("unified_inventory:bag_small", {
 | 
			
		||||
	description = S("Small Bag"),
 | 
			
		||||
 
 | 
			
		||||
@@ -57,30 +57,47 @@ end)
 | 
			
		||||
local function apply_new_filter(player, search_text, new_dir)
 | 
			
		||||
	local player_name = player:get_player_name()
 | 
			
		||||
 | 
			
		||||
	minetest.sound_play("click", {to_player=player_name, gain = 0.1})
 | 
			
		||||
	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
 | 
			
		||||
 | 
			
		||||
minetest.register_on_player_receive_fields(function(player, formname, fields)
 | 
			
		||||
-- Search box handling
 | 
			
		||||
local function 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)
 | 
			
		||||
	-- 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
 | 
			
		||||
 | 
			
		||||
	-- always take new search text, even if not searching on it yet
 | 
			
		||||
	local dirty_search_filter = false
 | 
			
		||||
	receive_fields_searchbox(player, formname, fields)
 | 
			
		||||
 | 
			
		||||
	if fields.searchbox
 | 
			
		||||
	and fields.searchbox ~= unified_inventory.current_searchbox[player_name] then
 | 
			
		||||
		unified_inventory.current_searchbox[player_name] = fields.searchbox
 | 
			
		||||
		dirty_search_filter = true
 | 
			
		||||
	end
 | 
			
		||||
	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
 | 
			
		||||
@@ -114,7 +131,7 @@ minetest.register_on_player_receive_fields(function(player, formname, fields)
 | 
			
		||||
	for i, def in pairs(unified_inventory.buttons) do
 | 
			
		||||
		if fields[def.name] then
 | 
			
		||||
			def.action(player)
 | 
			
		||||
			minetest.sound_play("click",
 | 
			
		||||
			minetest.sound_play("ui_click",
 | 
			
		||||
					{to_player=player_name, gain = 0.1})
 | 
			
		||||
			return
 | 
			
		||||
		end
 | 
			
		||||
@@ -179,7 +196,7 @@ minetest.register_on_player_receive_fields(function(player, formname, fields)
 | 
			
		||||
		end
 | 
			
		||||
	end
 | 
			
		||||
	if clicked_item then
 | 
			
		||||
		minetest.sound_play("click",
 | 
			
		||||
		minetest.sound_play("ui_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)
 | 
			
		||||
@@ -201,25 +218,11 @@ minetest.register_on_player_receive_fields(function(player, formname, fields)
 | 
			
		||||
		end
 | 
			
		||||
	end
 | 
			
		||||
 | 
			
		||||
	if fields.searchbutton
 | 
			
		||||
			or fields.key_enter_field == "searchbox" then
 | 
			
		||||
		if dirty_search_filter 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
 | 
			
		||||
 | 
			
		||||
	-- alternate buttons
 | 
			
		||||
	if not (fields.alternate or fields.alternate_prev) then
 | 
			
		||||
		return
 | 
			
		||||
	end
 | 
			
		||||
	minetest.sound_play("click",
 | 
			
		||||
	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
 | 
			
		||||
 
 | 
			
		||||
@@ -96,6 +96,9 @@ function unified_inventory.register_category(category_name, config)
 | 
			
		||||
	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
 | 
			
		||||
@@ -112,6 +115,11 @@ function unified_inventory.set_category_index(category_name, index)
 | 
			
		||||
	update_category_list()
 | 
			
		||||
end
 | 
			
		||||
function unified_inventory.add_category_item(category_name, item)
 | 
			
		||||
	if type(item) ~= "string" then
 | 
			
		||||
		minetest.log("warning", "[unified_inventory] Cannot register category item: " .. dump(item))
 | 
			
		||||
		return
 | 
			
		||||
	end
 | 
			
		||||
 | 
			
		||||
	ensure_category_exists(category_name)
 | 
			
		||||
	unified_inventory.registered_category_items[category_name][item] = true
 | 
			
		||||
end
 | 
			
		||||
 
 | 
			
		||||
@@ -1,4 +1,5 @@
 | 
			
		||||
local S = minetest.get_translator("unified_inventory")
 | 
			
		||||
local ui = unified_inventory
 | 
			
		||||
 | 
			
		||||
unified_inventory.register_category('plants', {
 | 
			
		||||
	symbol = "flowers:tulip",
 | 
			
		||||
@@ -25,71 +26,87 @@ unified_inventory.register_category('lighting', {
 | 
			
		||||
	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
 | 
			
		||||
local function register_automatic_categorization()
 | 
			
		||||
	-- 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)
 | 
			
		||||
	-- Preparation for ore registration: find all possible drops (digging)
 | 
			
		||||
	local possible_node_dig_drops = {
 | 
			
		||||
		-- ["default:stone_with_coal"] = { "default:coal_lump", "mymod:raregem" }
 | 
			
		||||
		-- Ores may be contained multiple times, depending on drop chances.
 | 
			
		||||
	}
 | 
			
		||||
	for itemname, recipes in pairs(ui.crafts_for.usage) do
 | 
			
		||||
		for _, recipe in ipairs(recipes) do
 | 
			
		||||
			if recipe.type == "digging" or recipe.type == "digging_chance" then
 | 
			
		||||
				if not possible_node_dig_drops[itemname] then
 | 
			
		||||
					possible_node_dig_drops[itemname] = {}
 | 
			
		||||
				end
 | 
			
		||||
			else
 | 
			
		||||
				unified_inventory.add_category_item('environment', item.ore)
 | 
			
		||||
				local stack = ItemStack(recipe.output)
 | 
			
		||||
				table.insert(possible_node_dig_drops[itemname], stack:get_name())
 | 
			
		||||
			end
 | 
			
		||||
		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
 | 
			
		||||
	-- Add minable ores to minerals and everything else (pockets of stone & sand variations) to environment
 | 
			
		||||
	for _, odef in pairs(minetest.registered_ores) do
 | 
			
		||||
		local drops = possible_node_dig_drops[odef.ore]
 | 
			
		||||
		if drops and odef.ore_type == "scatter" then
 | 
			
		||||
			ui.add_category_item('minerals', odef.ore)
 | 
			
		||||
			-- Register all possible drops as "minerals"
 | 
			
		||||
			ui.add_category_items('minerals', drops)
 | 
			
		||||
			possible_node_dig_drops[odef.ore] = {} -- mask as handled
 | 
			
		||||
		else
 | 
			
		||||
			ui.add_category_item('environment', odef.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
 | 
			
		||||
 | 
			
		||||
if ui.automatic_categorization then
 | 
			
		||||
	ui.register_on_initialized(register_automatic_categorization)
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
-- [[
 | 
			
		||||
unified_inventory.add_category_items('plants', {
 | 
			
		||||
	"default:dry_grass_5",
 | 
			
		||||
@@ -256,23 +273,6 @@ unified_inventory.add_category_items('minerals', {
 | 
			
		||||
	"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', {
 | 
			
		||||
 
 | 
			
		||||
@@ -1,7 +1,8 @@
 | 
			
		||||
unified_inventory API
 | 
			
		||||
=====================
 | 
			
		||||
 | 
			
		||||
This file provides information about the API of unified_inventory.
 | 
			
		||||
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:
 | 
			
		||||
 | 
			
		||||
@@ -23,7 +24,9 @@ Grouped by use-case, afterwards sorted alphabetically.
 | 
			
		||||
Callbacks
 | 
			
		||||
---------
 | 
			
		||||
 | 
			
		||||
Register a callback that will be run whenever a craft is registered via unified_inventory.register_craft:
 | 
			
		||||
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)
 | 
			
		||||
@@ -163,68 +166,57 @@ Register a non-standard craft recipe:
 | 
			
		||||
Categories
 | 
			
		||||
----------
 | 
			
		||||
 | 
			
		||||
Register a new category:
 | 
			
		||||
	The config table (second argument) is optional, and all its members are optional
 | 
			
		||||
	See the unified_inventory.set_category_* functions for more details on the members of the config table
 | 
			
		||||
 * `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 = "mod_name:item_name" or "texture.png",
 | 
			
		||||
		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
 | 
			
		||||
 | 
			
		||||
Add / override the symbol for a category:
 | 
			
		||||
	The category does not need to exist first
 | 
			
		||||
	The symbol can be an item name or a texture image
 | 
			
		||||
	If unset this will default to "default:stick"
 | 
			
		||||
Modifier functions (to be removed)
 | 
			
		||||
 | 
			
		||||
	unified_inventory.set_category_symbol("category_name", "mod_name:item_name" or "texture.png")
 | 
			
		||||
 * `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
 | 
			
		||||
 | 
			
		||||
Add / override the human readable label for a category:
 | 
			
		||||
	If unset this will default to the category name
 | 
			
		||||
Item management
 | 
			
		||||
 | 
			
		||||
	unified_inventory.set_category_label("category_name", "Human Readable Label")
 | 
			
		||||
 * `	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)
 | 
			
		||||
 | 
			
		||||
Add / override the sorting index of the category:
 | 
			
		||||
	Must be a number, can also be negative (-5) or fractional (2.345)
 | 
			
		||||
	This determines the position the category appears in the list of categories
 | 
			
		||||
	The "all" meta-category has index -2, the "misc"/"uncategorized" meta-category has index -1, use a negative number smaller than these to make a category appear before these in the list
 | 
			
		||||
	By default categories are sorted alphabetically with an index between 0.0101(AA) and 0.2626(ZZ)
 | 
			
		||||
 | 
			
		||||
	unified_inventory.set_category_index("category_name", 5)
 | 
			
		||||
 | 
			
		||||
Add a single item to a category:
 | 
			
		||||
 | 
			
		||||
	unified_inventory.add_category_item("category_name", "mod_name:item_name")
 | 
			
		||||
 | 
			
		||||
Add multiple items to a category:
 | 
			
		||||
 | 
			
		||||
	unified_inventory.add_category_items("category_name", {
 | 
			
		||||
		"mod_name:item_name",
 | 
			
		||||
		"another_mod:different_item"
 | 
			
		||||
	})
 | 
			
		||||
 | 
			
		||||
Remove an item from a category:
 | 
			
		||||
 | 
			
		||||
	unified_inventory.remove_category_item("category_name", "mod_name:item_name")
 | 
			
		||||
 | 
			
		||||
Remove a category entirely:
 | 
			
		||||
 | 
			
		||||
	unified_inventory.remove_category("category_name")
 | 
			
		||||
 | 
			
		||||
Finding existing items in categories:
 | 
			
		||||
	This will find the first category an item exists in
 | 
			
		||||
	It should be used for checking if an item is catgorised
 | 
			
		||||
	Returns "category_name" or nil
 | 
			
		||||
 | 
			
		||||
	unified_inventory.find_category("mod_name:item_name")
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	This will find all the categories an item exists in
 | 
			
		||||
	Returns a number indexed table (list) of category names
 | 
			
		||||
 | 
			
		||||
	unified_inventory.find_categories("mod_name:item_name")
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										60
									
								
								group.lua
									
									
									
									
									
								
							
							
						
						
									
										60
									
								
								group.lua
									
									
									
									
									
								
							@@ -1,4 +1,5 @@
 | 
			
		||||
local S = minetest.get_translator("unified_inventory")
 | 
			
		||||
local ui = unified_inventory
 | 
			
		||||
 | 
			
		||||
function unified_inventory.extract_groupnames(groupname)
 | 
			
		||||
	local specname = ItemStack(groupname):get_name()
 | 
			
		||||
@@ -26,6 +27,7 @@ end
 | 
			
		||||
-- 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 = {}
 | 
			
		||||
@@ -84,3 +86,61 @@ function unified_inventory.get_group_item(group_name)
 | 
			
		||||
	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
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										14
									
								
								init.lua
									
									
									
									
									
								
							
							
						
						
									
										14
									
								
								init.lua
									
									
									
									
									
								
							@@ -52,7 +52,10 @@ unified_inventory = {
 | 
			
		||||
	list_img_offset = 0.13,
 | 
			
		||||
	standard_background = "bgcolor[#0000]background9[0,0;1,1;ui_formbg_9_sliced.png;true;16]",
 | 
			
		||||
 | 
			
		||||
	version = 4
 | 
			
		||||
	hide_disabled_buttons = minetest.settings:get_bool("unified_inventory_hide_disabled_buttons", false),
 | 
			
		||||
	hide_uncraftable_items = minetest.settings:get_bool("unified_inventory_hide_uncraftable_items", false),
 | 
			
		||||
 | 
			
		||||
	version = 5
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
local ui = unified_inventory
 | 
			
		||||
@@ -189,9 +192,12 @@ dofile(modpath.."/register.lua")
 | 
			
		||||
if minetest.settings:get_bool("unified_inventory_bags") ~= false then
 | 
			
		||||
	dofile(modpath.."/bags.lua")
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
dofile(modpath.."/item_names.lua")
 | 
			
		||||
dofile(modpath.."/waypoints.lua")
 | 
			
		||||
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.")
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										92
									
								
								internal.lua
									
									
									
									
									
								
							
							
						
						
									
										92
									
								
								internal.lua
									
									
									
									
									
								
							@@ -52,9 +52,11 @@ local function formspec_tab_buttons(player, formspec, style)
 | 
			
		||||
 | 
			
		||||
	local filtered_inv_buttons = {}
 | 
			
		||||
 | 
			
		||||
	for i, def in pairs(ui.buttons) do
 | 
			
		||||
	for _, def in pairs(ui.buttons) do
 | 
			
		||||
		if not (style.is_lite_mode and def.hide_lite) then
 | 
			
		||||
			table.insert(filtered_inv_buttons, def)
 | 
			
		||||
			if def.condition == nil or def.condition(player) or not ui.hide_disabled_buttons then
 | 
			
		||||
				table.insert(filtered_inv_buttons, def)
 | 
			
		||||
			end
 | 
			
		||||
		end
 | 
			
		||||
	end
 | 
			
		||||
 | 
			
		||||
@@ -71,13 +73,14 @@ local function formspec_tab_buttons(player, formspec, style)
 | 
			
		||||
		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) == true) 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,
 | 
			
		||||
@@ -88,9 +91,10 @@ local function formspec_tab_buttons(player, formspec, style)
 | 
			
		||||
	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"
 | 
			
		||||
			math.ceil((#filtered_inv_buttons - 1) / style.main_button_cols) * style.btn_spc * 5
 | 
			
		||||
			(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
 | 
			
		||||
@@ -266,13 +270,15 @@ local function formspec_add_item_browser(player, formspec, ui_peruser)
 | 
			
		||||
					button_name, minetest.formspec_escape(tooltip)
 | 
			
		||||
				)
 | 
			
		||||
				n = n + 2
 | 
			
		||||
				list_index = list_index + 1
 | 
			
		||||
			end
 | 
			
		||||
			list_index = list_index + 1
 | 
			
		||||
		end
 | 
			
		||||
	end
 | 
			
		||||
	formspec[n] = string.format("label[%f,%f;%s: %s]",
 | 
			
		||||
		ui_peruser.page_buttons_x + ui_peruser.btn_spc * (ui_peruser.is_lite_mode and 1 or 2),
 | 
			
		||||
		ui_peruser.page_buttons_y + 0.1 + ui_peruser.btn_spc * 2,
 | 
			
		||||
	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
 | 
			
		||||
 | 
			
		||||
@@ -329,7 +335,7 @@ function ui.set_inventory_formspec(player, page)
 | 
			
		||||
	end
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
local function valid_def(def)
 | 
			
		||||
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
 | 
			
		||||
@@ -342,11 +348,30 @@ function ui.apply_filter(player, filter, search_dir)
 | 
			
		||||
		return false
 | 
			
		||||
	end
 | 
			
		||||
	local player_name = player:get_player_name()
 | 
			
		||||
 | 
			
		||||
	-- Whether to show uncraftable items
 | 
			
		||||
	local fprefilter = function(_)
 | 
			
		||||
		return true
 | 
			
		||||
	end
 | 
			
		||||
	if ui.hide_uncraftable_items and not ui.is_creative(player_name) then
 | 
			
		||||
		fprefilter = function(name)
 | 
			
		||||
			return ui.get_recipe_list(name)
 | 
			
		||||
		end
 | 
			
		||||
	end
 | 
			
		||||
 | 
			
		||||
	local registered_items = minetest.registered_items
 | 
			
		||||
	local lfilter = string.lower(filter)
 | 
			
		||||
	local ffilter
 | 
			
		||||
 | 
			
		||||
	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)
 | 
			
		||||
		ffilter = function(name)
 | 
			
		||||
			local def = registered_items[name]
 | 
			
		||||
			if not def then
 | 
			
		||||
				return false
 | 
			
		||||
			end
 | 
			
		||||
 | 
			
		||||
			for _, group in ipairs(groups) do
 | 
			
		||||
				if not def.groups[group]
 | 
			
		||||
				or def.groups[group] <= 0 then
 | 
			
		||||
@@ -356,10 +381,16 @@ function ui.apply_filter(player, filter, search_dir)
 | 
			
		||||
			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)
 | 
			
		||||
		ffilter = function(name)
 | 
			
		||||
			local def = registered_items[name]
 | 
			
		||||
			if not def then
 | 
			
		||||
				return false
 | 
			
		||||
			end
 | 
			
		||||
 | 
			
		||||
			local lname = string.lower(name)
 | 
			
		||||
			local ldesc = string.lower(def.description)
 | 
			
		||||
			local llocaldesc = minetest.get_translated_string
 | 
			
		||||
@@ -368,35 +399,38 @@ function ui.apply_filter(player, filter, search_dir)
 | 
			
		||||
				or llocaldesc and string.find(llocaldesc, lfilter, 1, true)
 | 
			
		||||
		end
 | 
			
		||||
	end
 | 
			
		||||
	ui.filtered_items_list[player_name]={}
 | 
			
		||||
 | 
			
		||||
	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 valid_def(def)
 | 
			
		||||
			and ffilter(name, def) then
 | 
			
		||||
				table.insert(ui.filtered_items_list[player_name], name)
 | 
			
		||||
		for _, name in ipairs(ui.items_list) do
 | 
			
		||||
			if fprefilter(name) and ffilter(name) then
 | 
			
		||||
				table.insert(filtered_items, name)
 | 
			
		||||
			end
 | 
			
		||||
		end
 | 
			
		||||
	elseif category == 'uncategorized' then
 | 
			
		||||
		for name, def in pairs(minetest.registered_items) do
 | 
			
		||||
			if (not ui.find_category(name))
 | 
			
		||||
			and valid_def(def)
 | 
			
		||||
			and ffilter(name, def) then
 | 
			
		||||
				table.insert(ui.filtered_items_list[player_name], name)
 | 
			
		||||
		for _, name in ipairs(ui.items_list) do
 | 
			
		||||
			if not ui.find_category(name)
 | 
			
		||||
					and fprefilter(name)
 | 
			
		||||
					and ffilter(name) then
 | 
			
		||||
				table.insert(filtered_items, name)
 | 
			
		||||
			end
 | 
			
		||||
		end
 | 
			
		||||
	else
 | 
			
		||||
		for name,exists in pairs(ui.registered_category_items[category]) do
 | 
			
		||||
			local def = minetest.registered_items[name]
 | 
			
		||||
			if exists and def
 | 
			
		||||
			and valid_def(def)
 | 
			
		||||
			and ffilter(name, def) then
 | 
			
		||||
				table.insert(ui.filtered_items_list[player_name], name)
 | 
			
		||||
		-- Any other category is selected
 | 
			
		||||
		for name, exists in pairs(ui.registered_category_items[category]) do
 | 
			
		||||
			if exists
 | 
			
		||||
					and fprefilter(name)
 | 
			
		||||
					and ffilter(name) then
 | 
			
		||||
				table.insert(filtered_items, name)
 | 
			
		||||
			end
 | 
			
		||||
		end
 | 
			
		||||
	end
 | 
			
		||||
	table.sort(ui.filtered_items_list[player_name])
 | 
			
		||||
	ui.filtered_items_list_size[player_name] = #ui.filtered_items_list[player_name]
 | 
			
		||||
	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
 | 
			
		||||
 
 | 
			
		||||
@@ -3,6 +3,8 @@
 | 
			
		||||
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()
 | 
			
		||||
@@ -16,7 +18,8 @@ local function set_hud(player)
 | 
			
		||||
 | 
			
		||||
	item_names[player_name] = {
 | 
			
		||||
		hud = player:hud_add({
 | 
			
		||||
			hud_elem_type = "text",
 | 
			
		||||
			-- TODO: remove compatibility code when 5.8.0 is no longer used
 | 
			
		||||
			[minetest.features.hud_def_type_field and "type" or "hud_elem_type"] = "text",
 | 
			
		||||
			position = {x=0.5, y=1},
 | 
			
		||||
			offset = off,
 | 
			
		||||
			alignment = {x=0, y=-1},
 | 
			
		||||
@@ -60,6 +63,7 @@ minetest.register_globalstep(function(dtime)
 | 
			
		||||
			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")
 | 
			
		||||
@@ -69,6 +73,14 @@ minetest.register_globalstep(function(dtime)
 | 
			
		||||
				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
 | 
			
		||||
 
 | 
			
		||||
@@ -7,17 +7,17 @@ Bag @1=Tasche @1
 | 
			
		||||
Small Bag=Kleine Tasche
 | 
			
		||||
Medium Bag=Mittelgroße Tasche
 | 
			
		||||
Large Bag=Große Tasche
 | 
			
		||||
All Items=
 | 
			
		||||
Misc. Items=
 | 
			
		||||
Plant Life=
 | 
			
		||||
Building Materials=
 | 
			
		||||
Tools=
 | 
			
		||||
Minerals and Metals=
 | 
			
		||||
Environment and Worldgen=
 | 
			
		||||
Lighting=
 | 
			
		||||
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=
 | 
			
		||||
Scroll categories right=
 | 
			
		||||
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
 | 
			
		||||
@@ -76,10 +76,10 @@ 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=
 | 
			
		||||
Show waypoint=
 | 
			
		||||
Hide coordinates=
 | 
			
		||||
Show coordinates=
 | 
			
		||||
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
 | 
			
		||||
 
 | 
			
		||||
@@ -1,98 +1,91 @@
 | 
			
		||||
# textdomain: unified_inventory
 | 
			
		||||
Mixing=
 | 
			
		||||
Cooking=
 | 
			
		||||
Digging=
 | 
			
		||||
Category:=Kategorie:
 | 
			
		||||
Mixing=Miksowanie
 | 
			
		||||
Cooking=Gotowanie
 | 
			
		||||
Digging=Kopanie
 | 
			
		||||
Bags=Plecaki
 | 
			
		||||
Bag @1=Plecak @1
 | 
			
		||||
Small Bag=Maly plecak
 | 
			
		||||
Medium Bag=Sredni plecak
 | 
			
		||||
Large Bag=Duzy plecak
 | 
			
		||||
All Items=
 | 
			
		||||
Misc. Items=
 | 
			
		||||
Plant Life=
 | 
			
		||||
Building Materials=
 | 
			
		||||
Tools=
 | 
			
		||||
Minerals and Metals=
 | 
			
		||||
Environment and Worldgen=
 | 
			
		||||
Lighting=
 | 
			
		||||
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=
 | 
			
		||||
Scroll categories right=
 | 
			
		||||
Scroll categories left=Przewiń kategorię w lewo
 | 
			
		||||
Scroll categories right=Przewiń kategorię w prawo
 | 
			
		||||
Search=Szukaj
 | 
			
		||||
Reset search and display everything=
 | 
			
		||||
Reset search and display everything=Zresetuj wyszukiwanie i pokaż wszystko
 | 
			
		||||
First page=Pierwsza strona
 | 
			
		||||
Back three pages=3 strony w tyl
 | 
			
		||||
Back one page=1 strona w tyl
 | 
			
		||||
Forward one page=1 strona do przodu
 | 
			
		||||
Forward three pages=3 strony do przodu
 | 
			
		||||
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 pasujacych przedmiotow
 | 
			
		||||
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=
 | 
			
		||||
Forces Unified Inventory to be displayed in Full mode if Lite mode is configured globally=
 | 
			
		||||
Crafting Grid=
 | 
			
		||||
Crafting Guide=
 | 
			
		||||
Set home position=Ustaw pozycję wyjściową
 | 
			
		||||
Home position set to: @1=Pozycja domowa ustawiona na: @1
 | 
			
		||||
You don't have the "home" privilege!=Nie masz uprawnien do zmiany czasu "home"!
 | 
			
		||||
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!=Nie masz uprawnien do zmiany czasu "settime"!
 | 
			
		||||
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ść zapasy
 | 
			
		||||
This button has been disabled outside of creative mode to prevent accidental inventory trashing.@nUse the trash slot instead.=
 | 
			
		||||
Inventory cleared!=Zapasy zostały wyczyszczone!
 | 
			
		||||
Trash:=Smietnik:
 | 
			
		||||
Refill:=Uzupelnianie:
 | 
			
		||||
Any item belonging to the @1 group=
 | 
			
		||||
Any item belonging to the groups @1=
 | 
			
		||||
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=
 | 
			
		||||
Show next usage=
 | 
			
		||||
Show previous recipe=
 | 
			
		||||
Show previous usage=
 | 
			
		||||
@1 (@2)=
 | 
			
		||||
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.=
 | 
			
		||||
To craft grid:=
 | 
			
		||||
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=
 | 
			
		||||
White=Bialy
 | 
			
		||||
Yellow=Zolty
 | 
			
		||||
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 biezacej pozycji
 | 
			
		||||
Hide waypoint=
 | 
			
		||||
Show waypoint=
 | 
			
		||||
Hide coordinates=
 | 
			
		||||
Show coordinates=
 | 
			
		||||
Change color of waypoint display=Zmien kolor punktu
 | 
			
		||||
Edit waypoint name=Edytuj nazwe punktu
 | 
			
		||||
Waypoint active=Punkt wlaczony
 | 
			
		||||
Waypoint inactive=Punkt wylaczony
 | 
			
		||||
Finish editing=Zakoncz edycje
 | 
			
		||||
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
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
##### not used anymore #####
 | 
			
		||||
 | 
			
		||||
invisible=niewidzialny
 | 
			
		||||
visible=widomy
 | 
			
		||||
Make waypoint @1=Robić punkt @1
 | 
			
		||||
@1 display of waypoint coordinates=@1 koordynatow punktu
 | 
			
		||||
 
 | 
			
		||||
@@ -1,23 +1,23 @@
 | 
			
		||||
# textdomain: unified_inventory
 | 
			
		||||
Mixing=Мешать
 | 
			
		||||
Cooking=Варить
 | 
			
		||||
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=
 | 
			
		||||
All Items=Все предметы
 | 
			
		||||
Misc. Items=Разн. предметы
 | 
			
		||||
Plant Life=Растения
 | 
			
		||||
Building Materials=Стройматериалы
 | 
			
		||||
Tools=Инструменты
 | 
			
		||||
Minerals and Metals=Металлы и минералы
 | 
			
		||||
Environment and Worldgen=Окружение и генер.мира
 | 
			
		||||
Lighting=Освещение
 | 
			
		||||
 and = и 
 | 
			
		||||
Scroll categories left=
 | 
			
		||||
Scroll categories right=
 | 
			
		||||
Scroll categories left=Листать влево
 | 
			
		||||
Scroll categories right=Листать вправо
 | 
			
		||||
Search=Поиск
 | 
			
		||||
Reset search and display everything=Сброс поиска, показать всё
 | 
			
		||||
First page=Первая страница
 | 
			
		||||
@@ -32,7 +32,7 @@ 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=
 | 
			
		||||
Forces Unified Inventory to be displayed in Full mode if Lite mode is configured globally=Отображает инвентарь в полном режиме, если простой режим установлен глобально
 | 
			
		||||
Crafting Grid=Решетка крафта
 | 
			
		||||
Crafting Guide=Книга рецептов
 | 
			
		||||
Set home position=Установить позицию дома
 | 
			
		||||
@@ -59,11 +59,11 @@ Result=Результат
 | 
			
		||||
Ingredient=Состав
 | 
			
		||||
Show next recipe=Следующий рецепт
 | 
			
		||||
Show next usage=Следующее использование
 | 
			
		||||
Show previous recipe=Прошлый рецепт
 | 
			
		||||
Show previous usage=Прошлая страница
 | 
			
		||||
Show previous recipe=Предыдущий рецепт
 | 
			
		||||
Show previous usage=Предыдущая страница
 | 
			
		||||
@1 (@2)=
 | 
			
		||||
Give me:=Дай мне:
 | 
			
		||||
This recipe is too@@large to be displayed.=
 | 
			
		||||
This recipe is too@@large to be displayed.=Этот рецепт слишком большой
 | 
			
		||||
To craft grid:=На решeтку крафта:
 | 
			
		||||
All=Все
 | 
			
		||||
Crafting=Крафт
 | 
			
		||||
@@ -76,10 +76,10 @@ Waypoints=Путевые точки
 | 
			
		||||
Select Waypoint #@1=Выбрать путевую точку №@1
 | 
			
		||||
Waypoint @1=Путевая точка @1
 | 
			
		||||
Set waypoint to current location=Установить путевую точку по текущей позиции
 | 
			
		||||
Hide waypoint=
 | 
			
		||||
Show waypoint=
 | 
			
		||||
Hide coordinates=
 | 
			
		||||
Show coordinates=
 | 
			
		||||
Hide waypoint=Скрыть точку
 | 
			
		||||
Show waypoint=Показать точку
 | 
			
		||||
Hide coordinates=Скрыть координаты
 | 
			
		||||
Show coordinates=Показать координаты
 | 
			
		||||
Change color of waypoint display=Поменять цвет путевой точки
 | 
			
		||||
Edit waypoint name=Переименовать путевую точку
 | 
			
		||||
Waypoint active=Путевая точка включена
 | 
			
		||||
@@ -88,13 +88,4 @@ 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 показ координат путевых точек
 | 
			
		||||
Category:=Категории:
 | 
			
		||||
 
 | 
			
		||||
@@ -126,25 +126,18 @@ Example output:
 | 
			
		||||
	}
 | 
			
		||||
--]]
 | 
			
		||||
function unified_inventory.find_usable_items(inv_items, craft_items)
 | 
			
		||||
	local get_group = minetest.get_item_group
 | 
			
		||||
	local result = {}
 | 
			
		||||
 | 
			
		||||
	for craft_item in pairs(craft_items) do
 | 
			
		||||
		local group = craft_item:match("^group:(.+)")
 | 
			
		||||
		local found = {}
 | 
			
		||||
		-- may specify group:type1,type2
 | 
			
		||||
		local items = unified_inventory.get_matching_items(craft_item)
 | 
			
		||||
 | 
			
		||||
		if group ~= nil then
 | 
			
		||||
			for inv_item in pairs(inv_items) do
 | 
			
		||||
				if get_group(inv_item, group) > 0 then
 | 
			
		||||
					found[inv_item] = true
 | 
			
		||||
				end
 | 
			
		||||
			end
 | 
			
		||||
		else
 | 
			
		||||
			if inv_items[craft_item] ~= nil then
 | 
			
		||||
				found[craft_item] = true
 | 
			
		||||
		local found = {}
 | 
			
		||||
		for itemname, _ in pairs(items) do
 | 
			
		||||
			if inv_items[itemname] then
 | 
			
		||||
				found[itemname] = true
 | 
			
		||||
			end
 | 
			
		||||
		end
 | 
			
		||||
 | 
			
		||||
		result[craft_item] = found
 | 
			
		||||
	end
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										2
									
								
								mod.conf
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								mod.conf
									
									
									
									
									
								
							@@ -1,6 +1,6 @@
 | 
			
		||||
name = unified_inventory
 | 
			
		||||
 | 
			
		||||
optional_depends = default, creative, sfinv, datastorage, farming
 | 
			
		||||
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.
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										38
									
								
								register.lua
									
									
									
									
									
								
							
							
						
						
									
										38
									
								
								register.lua
									
									
									
									
									
								
							@@ -49,7 +49,7 @@ ui.register_button("misc_set_day", {
 | 
			
		||||
	action = function(player)
 | 
			
		||||
		local player_name = player:get_player_name()
 | 
			
		||||
		if minetest.check_player_privs(player_name, {settime=true}) then
 | 
			
		||||
			minetest.sound_play("birds",
 | 
			
		||||
			minetest.sound_play("ui_morning",
 | 
			
		||||
					{to_player=player_name, gain = 1.0})
 | 
			
		||||
			minetest.set_timeofday((6000 % 24000) / 24000)
 | 
			
		||||
			minetest.chat_send_player(player_name,
 | 
			
		||||
@@ -73,7 +73,7 @@ ui.register_button("misc_set_night", {
 | 
			
		||||
	action = function(player)
 | 
			
		||||
		local player_name = player:get_player_name()
 | 
			
		||||
		if minetest.check_player_privs(player_name, {settime=true}) then
 | 
			
		||||
			minetest.sound_play("owl",
 | 
			
		||||
			minetest.sound_play("ui_owl",
 | 
			
		||||
					{to_player=player_name, gain = 1.0})
 | 
			
		||||
			minetest.set_timeofday((21000 % 24000) / 24000)
 | 
			
		||||
			minetest.chat_send_player(player_name,
 | 
			
		||||
@@ -134,14 +134,14 @@ ui.register_page("craft", {
 | 
			
		||||
		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.45, crafty + 2.4, F(S("Trash:")))
 | 
			
		||||
			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
 | 
			
		||||
		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.3, crafty + 2.4,F(S("Refill:")))
 | 
			
		||||
			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
 | 
			
		||||
@@ -158,17 +158,15 @@ ui.register_page("craft", {
 | 
			
		||||
 | 
			
		||||
local function stack_image_button(x, y, w, h, buttonname_prefix, item)
 | 
			
		||||
	local name = item:get_name()
 | 
			
		||||
	local count = item:get_count()
 | 
			
		||||
	local wear = item:get_wear()
 | 
			
		||||
	local description = item:get_meta():get_string("description")
 | 
			
		||||
	local show_is_group = false
 | 
			
		||||
	local displayitem = name.." "..count.." "..wear
 | 
			
		||||
	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"
 | 
			
		||||
		displayitem = group_item.item or name
 | 
			
		||||
		selectitem = group_item.sole and displayitem or name
 | 
			
		||||
	end
 | 
			
		||||
	local label = show_is_group and "G" or ""
 | 
			
		||||
@@ -196,6 +194,9 @@ local function stack_image_button(x, y, w, h, buttonname_prefix, item)
 | 
			
		||||
	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"),
 | 
			
		||||
@@ -248,11 +249,10 @@ ui.register_page("craftguide", {
 | 
			
		||||
 | 
			
		||||
		local n = 4
 | 
			
		||||
 | 
			
		||||
		local item_def = minetest.registered_items[item_name]
 | 
			
		||||
		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)
 | 
			
		||||
		if item_def and item_def.description then
 | 
			
		||||
			item_name_shown = S("@1 (@2)", item_def.description, item_name)
 | 
			
		||||
		else
 | 
			
		||||
			item_name_shown = item_name
 | 
			
		||||
		end
 | 
			
		||||
@@ -277,12 +277,14 @@ ui.register_page("craftguide", {
 | 
			
		||||
				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 giveme_form =
 | 
			
		||||
			"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]"
 | 
			
		||||
		if item_def and item_def.type ~= "tool" then
 | 
			
		||||
			giveme_form = giveme_form ..
 | 
			
		||||
				"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]"
 | 
			
		||||
		end
 | 
			
		||||
 | 
			
		||||
		if not craft then
 | 
			
		||||
			-- No craft recipes available for this item.
 | 
			
		||||
 
 | 
			
		||||
@@ -1,14 +1,36 @@
 | 
			
		||||
#Enabling lite mode enables a smaller and simpler version of the Unified
 | 
			
		||||
#Inventory, optimized for small displays.
 | 
			
		||||
# 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
 | 
			
		||||
 | 
			
		||||
#If enabled, bags will be made available which can be used to extend
 | 
			
		||||
#inventory storage size.
 | 
			
		||||
# Provides craftable bag items to extend the inventory space.
 | 
			
		||||
unified_inventory_bags (Enable bags) bool true
 | 
			
		||||
 | 
			
		||||
#If enabled, the trash slot can be used by those without both creative
 | 
			
		||||
#and the give privilege.
 | 
			
		||||
# 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
 | 
			
		||||
 | 
			
		||||
unified_inventory_automatic_categorization (Items automatically added to categories) bool true
 | 
			
		||||
# If enabled, disabled buttons will be hidden instead of grayed out.
 | 
			
		||||
unified_inventory_hide_disabled_buttons (Hide disabled buttons) bool false
 | 
			
		||||
 | 
			
		||||
# Hides items with no known craft recipe from the category "all" (default).
 | 
			
		||||
# This setting has no effect on players in creative mode.
 | 
			
		||||
unified_inventory_hide_uncraftable_items (Hide uncraftable items) 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
									
									
									
									
									
								
							
							
						
						
									
										
											BIN
										
									
								
								sounds/birds.ogg
									
									
									
									
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								sounds/owl.ogg
									
									
									
									
									
								
							
							
						
						
									
										
											BIN
										
									
								
								sounds/owl.ogg
									
									
									
									
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								sounds/ui_click.ogg
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								sounds/ui_click.ogg
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								sounds/ui_morning.ogg
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								sounds/ui_morning.ogg
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								sounds/ui_owl.ogg
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								sounds/ui_owl.ogg
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								textures/ui_teleport.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								textures/ui_teleport.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| 
		 After Width: | Height: | Size: 2.2 KiB  | 
@@ -103,7 +103,7 @@ local function get_waypoint_data(player)
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
ui.register_page("waypoints", {
 | 
			
		||||
	get_formspec = function(player)
 | 
			
		||||
	get_formspec = function(player, perplayer_formspec)
 | 
			
		||||
		local player_name = player:get_player_name()
 | 
			
		||||
		local wp_info_x = ui.style_full.form_header_x + 1.25
 | 
			
		||||
		local wp_info_y = ui.style_full.form_header_y + 0.5
 | 
			
		||||
@@ -115,12 +115,16 @@ ui.register_page("waypoints", {
 | 
			
		||||
		local sel = waypoints.selected or 1
 | 
			
		||||
 | 
			
		||||
		local formspec = {
 | 
			
		||||
			ui.style_full.standard_inv_bg,
 | 
			
		||||
			string.format("label[%f,%f;%s]",
 | 
			
		||||
				ui.style_full.form_header_x, ui.style_full.form_header_y, F(S("Waypoints"))),
 | 
			
		||||
			"image["..wp_info_x..","..wp_info_y..";1,1;ui_waypoints_icon.png]"
 | 
			
		||||
		}
 | 
			
		||||
		local n=4
 | 
			
		||||
		local n=3
 | 
			
		||||
 | 
			
		||||
		if not perplayer_formspec.is_lite_mode then
 | 
			
		||||
			formspec[n] = ui.style_full.standard_inv_bg
 | 
			
		||||
			n = n + 1
 | 
			
		||||
		end
 | 
			
		||||
 | 
			
		||||
		-- Tabs buttons:
 | 
			
		||||
		for i = 1, COUNT do
 | 
			
		||||
@@ -140,36 +144,49 @@ ui.register_page("waypoints", {
 | 
			
		||||
 | 
			
		||||
		-- Main buttons:
 | 
			
		||||
		local btnlist = {
 | 
			
		||||
			set_waypoint = {
 | 
			
		||||
				"ui_waypoint_set_icon.png",
 | 
			
		||||
				S("Set waypoint to current location")
 | 
			
		||||
			},
 | 
			
		||||
			toggle_waypoint = {
 | 
			
		||||
			-- 1. formspec name
 | 
			
		||||
			-- 2. button image
 | 
			
		||||
			-- 3. translation text
 | 
			
		||||
			{
 | 
			
		||||
				"toggle_waypoint",
 | 
			
		||||
				waypoint.active and "ui_on_icon.png" or "ui_off_icon.png",
 | 
			
		||||
				waypoint.active and S("Hide waypoint") or S("Show waypoint")
 | 
			
		||||
			},
 | 
			
		||||
			toggle_display_pos = {
 | 
			
		||||
			{
 | 
			
		||||
				"rename_waypoint",
 | 
			
		||||
				"ui_pencil_icon.png",
 | 
			
		||||
				S("Edit waypoint name")
 | 
			
		||||
			},
 | 
			
		||||
			{
 | 
			
		||||
				"set_waypoint",
 | 
			
		||||
				"ui_waypoint_set_icon.png",
 | 
			
		||||
				S("Set waypoint to current location")
 | 
			
		||||
			},
 | 
			
		||||
			{
 | 
			
		||||
				"toggle_display_pos",
 | 
			
		||||
				waypoint.display_pos and "ui_green_icon_background.png^ui_xyz_icon.png" or "ui_red_icon_background.png^ui_xyz_icon.png^(ui_no.png^[transformR90)",
 | 
			
		||||
				waypoint.display_pos and S("Hide coordinates") or S("Show coordinates")
 | 
			
		||||
			},
 | 
			
		||||
			toggle_color = {
 | 
			
		||||
			{
 | 
			
		||||
				"toggle_color",
 | 
			
		||||
				"ui_circular_arrows_icon.png",
 | 
			
		||||
				S("Change color of waypoint display")
 | 
			
		||||
			},
 | 
			
		||||
			rename_waypoint = {
 | 
			
		||||
				"ui_pencil_icon.png",
 | 
			
		||||
				S("Edit waypoint name")
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		if minetest.get_player_privs(player_name).teleport then
 | 
			
		||||
			table.insert(btnlist, {
 | 
			
		||||
				"teleport_waypoint",
 | 
			
		||||
				"ui_teleport.png",
 | 
			
		||||
				S("Teleport to waypoint")
 | 
			
		||||
			})
 | 
			
		||||
		end
 | 
			
		||||
 | 
			
		||||
		local x = 4
 | 
			
		||||
		for name, def in pairs(btnlist) do
 | 
			
		||||
		for i, def in pairs(btnlist) do
 | 
			
		||||
			formspec[n] = string.format("image_button[%f,%f;%f,%f;%s;%s%i;]",
 | 
			
		||||
				wp_buttons_rj - ui.style_full.btn_spc * x, wp_bottom_row,
 | 
			
		||||
				wp_buttons_rj + ui.style_full.btn_spc * (i - #btnlist), wp_bottom_row,
 | 
			
		||||
				ui.style_full.btn_size, ui.style_full.btn_size,
 | 
			
		||||
				def[1], name, sel)
 | 
			
		||||
			formspec[n+1] = "tooltip["..name..sel..";"..F(def[2]).."]"
 | 
			
		||||
			x = x - 1
 | 
			
		||||
				def[2], def[1], sel)
 | 
			
		||||
			formspec[n+1] = "tooltip["..def[1]..sel..";"..F(def[3]).."]"
 | 
			
		||||
			n = n + 2
 | 
			
		||||
		end
 | 
			
		||||
 | 
			
		||||
@@ -199,7 +216,10 @@ ui.register_page("waypoints", {
 | 
			
		||||
		formspec[n+2] = string.format("label[%f,%f;%s: %s]",
 | 
			
		||||
			wp_info_x, wp_info_y+2.60, F(S("HUD text color")), hud_colors[waypoint.color or 1][3])
 | 
			
		||||
 | 
			
		||||
		return {formspec=table.concat(formspec)}
 | 
			
		||||
		return {
 | 
			
		||||
			formspec = table.concat(formspec),
 | 
			
		||||
			draw_inventory = not perplayer_formspec.is_lite_mode,
 | 
			
		||||
		}
 | 
			
		||||
	end,
 | 
			
		||||
})
 | 
			
		||||
 | 
			
		||||
@@ -207,7 +227,6 @@ ui.register_button("waypoints", {
 | 
			
		||||
	type = "image",
 | 
			
		||||
	image = "ui_waypoints_icon.png",
 | 
			
		||||
	tooltip = S("Waypoints"),
 | 
			
		||||
	hide_lite=true
 | 
			
		||||
})
 | 
			
		||||
 | 
			
		||||
local function update_hud(player, waypoints, temp, i)
 | 
			
		||||
@@ -313,6 +332,13 @@ minetest.register_on_player_receive_fields(function(player, formname, fields)
 | 
			
		||||
			update_formspec = true
 | 
			
		||||
		end
 | 
			
		||||
 | 
			
		||||
		if fields["teleport_waypoint" .. i] and waypoint.world_pos then
 | 
			
		||||
			if minetest.get_player_privs(player_name).teleport then
 | 
			
		||||
				minetest.sound_play("teleport", {to_player = player_name})
 | 
			
		||||
				player:set_pos(waypoint.world_pos)
 | 
			
		||||
			end
 | 
			
		||||
		end
 | 
			
		||||
 | 
			
		||||
		if hit then
 | 
			
		||||
			-- Save first
 | 
			
		||||
			waypoints.data[i] = waypoint
 | 
			
		||||
@@ -323,6 +349,7 @@ minetest.register_on_player_receive_fields(function(player, formname, fields)
 | 
			
		||||
			update_hud(player, waypoints, temp, i)
 | 
			
		||||
		end
 | 
			
		||||
		if update_formspec then
 | 
			
		||||
			minetest.sound_play("ui_click", {to_player=player_name, gain = 0.1})
 | 
			
		||||
			ui.set_inventory_formspec(player, "waypoints")
 | 
			
		||||
		end
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user