diff --git a/Bucket_Game-base/unified_inventory_recipe_fix-vs-211031/mods/codercore/00README b/Bucket_Game-base/unified_inventory_recipe_fix-vs-211031/mods/codercore/00README new file mode 100644 index 0000000..1aa78a4 --- /dev/null +++ b/Bucket_Game-base/unified_inventory_recipe_fix-vs-211031/mods/codercore/00README @@ -0,0 +1 @@ +See "oldcoder.txt". diff --git a/Bucket_Game-base/unified_inventory_recipe_fix-vs-211031/mods/codercore/LICENSE.txt b/Bucket_Game-base/unified_inventory_recipe_fix-vs-211031/mods/codercore/LICENSE.txt new file mode 100644 index 0000000..32492e4 --- /dev/null +++ b/Bucket_Game-base/unified_inventory_recipe_fix-vs-211031/mods/codercore/LICENSE.txt @@ -0,0 +1,19 @@ +Unified Inventory for Minetest +Copyright (C) 2012-2014 Maciej Kasatkin (RealBadAngel) + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public +License as published by the Free Software Foundation; either +version 2 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +Contact information: + Examine a git patch to get the contributor's email address. diff --git a/Bucket_Game-base/unified_inventory_recipe_fix-vs-211031/mods/codercore/README.md b/Bucket_Game-base/unified_inventory_recipe_fix-vs-211031/mods/codercore/README.md new file mode 100644 index 0000000..15802c6 --- /dev/null +++ b/Bucket_Game-base/unified_inventory_recipe_fix-vs-211031/mods/codercore/README.md @@ -0,0 +1,96 @@ +# Unified Inventory + +Unified Inventory replaces the default survival and creative inventory. + + +## Features + + * Node, item and tool browser + * Crafting guide + * Can copy the recipe to the crafting grid + * Recipe search function by ingredients + * Up to four bags with up to 24 slots each + * Home function to teleport + * Trash slot + * Lite mode: reduces the item browser width + * Mod API for modders: see [mod_api.txt](doc/mod_api.txt) + * Setting-determinated features: see [settingtypes.txt](settingtypes.txt) + + +## Requirements + + * Minetest 5.0.0+ since commit 4403b69 + * Minetest 0.4.16+ prior commit 4403b69 + + +# Licenses + +Copyright (C) 2012-2014 Maciej Kasatkin (RealBadAngel) + +Copyright (C) 2012-? Various minetest-mods contributors + + +## Code + +GNU LGPLv2+, see [license notice](LICENSE.txt) + + +## Textures + +VanessaE: (CC-BY-4.0) + + * `ui_group.png` + +Tango Project: (Public Domain, CC-BY-4.0) + + * [`ui_reset_icon.png`](https://commons.wikimedia.org/wiki/File:Edit-clear.svg) + * [`ui_doubleleft_icon.png`](http://commons.wikimedia.org/wiki/File:Media-seek-backward.svg) + * [`ui_doubleright_icon.png`](http://commons.wikimedia.org/wiki/File:Media-seek-forward.svg) + * [`ui_left_icon.png` / `ui_right_icon.png`](http://commons.wikimedia.org/wiki/File:Media-playback-start.svg) + * [`ui_skip_backward_icon.png`](http://commons.wikimedia.org/wiki/File:Media-skip-backward.svg) + * [`ui_skip_forward_icon.png`](http://commons.wikimedia.org/wiki/File:Media-skip-forward.svg) + +From http://www.clker.com (Public Domain, CC-BY-4.0): + + * [`bags_small.png`](http://www.clker.com/clipart-moneybag-empty.html) + * [`bags_medium.png`](http://www.clker.com/clipart-backpack-1.html) + * [`bags_large.png` / `ui_bags_icon.png`](http://www.clker.com/clipart-backpack-green-brown.html) + * `ui_trash_icon.png`: and + * [`ui_search_icon.png`](http://www.clker.com/clipart-24887.html) + * [`ui_off_icon.png` / `ui_on_icon.png`](http://www.clker.com/clipart-on-off-switches.html) + * [`ui_waypoints_icon.png`](http://www.clker.com/clipart-map-pin-red.html) + * [`ui_circular_arrows_icon.png`](http://www.clker.com/clipart-circular-arrow-pattern.html) + * [`ui_pencil_icon.pnc`](http://www.clker.com/clipart-2256.html) + * [`ui_waypoint_set_icon.png`](http://www.clker.com/clipart-larger-flag.html) + +Everaldo Coelho (YellowIcon) (LGPL v2.1+): + + * [`ui_craftguide_icon.png` / `ui_craft_icon.png`](http://commons.wikimedia.org/wiki/File:Advancedsettings.png) + +Gregory H. Revera: (CC-BY-SA 3.0) + + * [`ui_moon_icon.png`](http://commons.wikimedia.org/wiki/File:FullMoon2010.jpg) + +Thomas Bresson: (CC-BY 3.0) + + * [`ui_sun_icon.png`](http://commons.wikimedia.org/wiki/File:2012-10-13_15-29-35-sun.jpg) + +Fibonacci: (Public domain, CC-BY 4.0) + + * [`ui_xyz_off_icon.png`](http://commons.wikimedia.org/wiki/File:No_sign.svg) + +Gregory Maxwell: (Public domain, CC-BY 4.0) + + * [`ui_ok_icon.png`](http://commons.wikimedia.org/wiki/File:Yes_check.svg) + +Adrien Facélina: (LGPL v2.1+) + + * [`inventory_plus_worldedit_gui.png`](http://commons.wikimedia.org/wiki/File:Erioll_world_2.svg) + +Other files from Wikimedia Commons: + + * [`ui_gohome_icon.png` / `ui_home_icon.png` / `ui_sethome_icon.png`](http://commons.wikimedia.org/wiki/File:Home_256x256.png) (GPL v2+) + +RealBadAngel: (CC-BY-4.0) + + * Everything else. \ No newline at end of file diff --git a/Bucket_Game-base/unified_inventory_recipe_fix-vs-211031/mods/codercore/api.lua b/Bucket_Game-base/unified_inventory_recipe_fix-vs-211031/mods/codercore/api.lua new file mode 100644 index 0000000..c5dee5d --- /dev/null +++ b/Bucket_Game-base/unified_inventory_recipe_fix-vs-211031/mods/codercore/api.lua @@ -0,0 +1,321 @@ +local S = function (str) return str end +local F = minetest.formspec_escape + +-- 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) + end + unified_inventory.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 + table.insert(unified_inventory.items_list, name) + local all_names = rev_aliases[name] or {} + table.insert(all_names, name) + for _, name in ipairs(all_names) do + local recipes = minetest.get_all_craft_recipes(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 unified_inventory.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 + unified_inventory.register_craft(recipe) + end + end + end + end + end + end + table.sort(unified_inventory.items_list) + unified_inventory.items_list_size = #unified_inventory.items_list + print("Unified Inventory. inventory size: "..unified_inventory.items_list_size) + for _, name in ipairs(unified_inventory.items_list) do + local def = minetest.registered_items[name] + -- Simple drops + if type(def.drop) == "string" then + local dstack = ItemStack(def.drop) + if not dstack:is_empty() and dstack:get_name() ~= name then + unified_inventory.register_craft({ + type = "digging", + items = {name}, + output = def.drop, + width = 0, + }) + + end + -- Complex drops. Yes, it's really complex! + elseif type(def.drop) == "table" then + --[[ Extract single items from the table and save them into dedicated tables + to register them later, in order to avoid duplicates. These tables counts + the total number of guaranteed drops and drops by chance (“maybes”) for each item. + For “maybes”, the final count is the theoretical maximum number of items, not + neccessarily the actual drop count. ]] + local drop_guaranteed = {} + local drop_maybe = {} + -- This is for catching an obscure corner case: If the top items table has + -- only items with rarity = 1, but max_items is set, then only the first + -- max_items will be part of the drop, any later entries are logically + -- impossible, so this variable is for keeping track of this + local max_items_left = def.drop.max_items + -- For checking whether we still encountered only guaranteed only so far; + -- for the first “maybe” item it will become false which will cause ALL + -- later items to be considered “maybes”. + -- A common idiom is: + -- { max_items 1, { items = { + -- { items={"example:1"}, rarity = 5 }, + -- { items={"example:2"}, rarity = 1 }, }}} + -- example:2 must be considered a “maybe” because max_items is set and it + -- appears after a “maybe” + local max_start = true + -- Let's iterate through the items madness! + -- Handle invalid drop entries gracefully. + local drop_items = def.drop.items or { } + for i=1,#drop_items do + if max_items_left ~= nil and max_items_left <= 0 then break end + local itit = drop_items[i] + for j=1,#itit.items do + local dstack = ItemStack(itit.items[j]) + if not dstack:is_empty() and dstack:get_name() ~= name then + local dname = dstack:get_name() + local dcount = dstack:get_count() + -- Guaranteed drops AND we are not yet in “maybe mode” + if #itit.items == 1 and itit.rarity == 1 and max_start then + if drop_guaranteed[dname] == nil then + drop_guaranteed[dname] = 0 + end + drop_guaranteed[dname] = drop_guaranteed[dname] + dcount + + if max_items_left ~= nil then + max_items_left = max_items_left - 1 + if max_items_left <= 0 then break end + end + -- Drop was a “maybe” + else + if max_items_left ~= nil then max_start = false end + if drop_maybe[dname] == nil then + drop_maybe[dname] = 0 + end + drop_maybe[dname] = drop_maybe[dname] + dcount + end + end + end + end + for itemstring, count in pairs(drop_guaranteed) do + unified_inventory.register_craft({ + type = "digging", + items = {name}, + output = itemstring .. " " .. count, + width = 0, + }) + end + for itemstring, count in pairs(drop_maybe) do + unified_inventory.register_craft({ + type = "digging_chance", + items = {name}, + output = itemstring .. " " .. count, + width = 0, + }) + end + end + end + for _, recipes in pairs(unified_inventory.crafts_for.recipe) do + for _, recipe in ipairs(recipes) do + local ingredient_items = {} + for _, spec in pairs(recipe.items) do + local matches_spec = unified_inventory.canonical_item_spec_matcher(spec) + for _, name in ipairs(unified_inventory.items_list) do + if matches_spec(name) then + ingredient_items[name] = true + end + end + end + for name, _ in pairs(ingredient_items) do + if unified_inventory.crafts_for.usage[name] == nil then + unified_inventory.crafts_for.usage[name] = {} + end + table.insert(unified_inventory.crafts_for.usage[name], recipe) + end + end + end +end) + + +-- load_home +local function load_home() + local input = io.open(unified_inventory.home_filename, "r") + if not input then + unified_inventory.home_pos = {} + return + end + while true do + local x = input:read("*n") + if not x then break end + local y = input:read("*n") + local z = input:read("*n") + local name = input:read("*l") + unified_inventory.home_pos[name:sub(2)] = {x = x, y = y, z = z} + end + io.close(input) +end +load_home() + +function unified_inventory.set_home(player, pos) + + local ds = unified_inventory.disable_set + if ds ~= nil and ds then return end + + local player_name = player:get_player_name() + unified_inventory.home_pos[player_name] = vector.round(pos) + -- save the home data from the table to the file + local output = io.open(unified_inventory.home_filename, "w") + for k, v in pairs(unified_inventory.home_pos) do + output:write(v.x.." "..v.y.." "..v.z.." "..k.."\n") + end + io.close(output) + + -- RJK: + if _G ["ocsethome"] ~= nil and + ocsethome ~= nil and + ocsethome.sethome ~= nil then + + unified_inventory.disable_set = true + ocsethome.sethome (player_name, "1") + unified_inventory.disable_set = false + end +end + +function unified_inventory.go_home(player) + local pos = unified_inventory.home_pos[player:get_player_name()] + if pos then + player:set_pos(pos) + end +end + +-- register_craft +function unified_inventory.register_craft(options) + if not options.output then + return + end + local itemstack = ItemStack(options.output) + if itemstack:is_empty() then + return + end + if options.type == "normal" and options.width == 0 then + options = { type = "shapeless", items = options.items, output = options.output, width = 0 } + end + if not unified_inventory.crafts_for.recipe[itemstack:get_name()] then + unified_inventory.crafts_for.recipe[itemstack:get_name()] = {} + end + table.insert(unified_inventory.crafts_for.recipe[itemstack:get_name()],options) +end + + +local craft_type_defaults = { + width = 3, + height = 3, + uses_crafting_grid = false, +} + + +function unified_inventory.craft_type_defaults(name, options) + if not options.description then + options.description = name + end + setmetatable(options, {__index = craft_type_defaults}) + return options +end + + +function unified_inventory.register_craft_type(name, options) + unified_inventory.registered_craft_types[name] = + unified_inventory.craft_type_defaults(name, options) +end + + +unified_inventory.register_craft_type("normal", { + description = F(S("Crafting")), + icon = "ui_craftgrid_icon.png", + width = 3, + height = 3, + get_shaped_craft_width = function (craft) return craft.width end, + dynamic_display_size = function (craft) + local w = craft.width + local h = math.ceil(table.maxn(craft.items) / craft.width) + local g = w < h and h or w + return { width = g, height = g } + end, + uses_crafting_grid = true, +}) + + +unified_inventory.register_craft_type("shapeless", { + description = F(S("Mixing")), + icon = "ui_craftgrid_icon.png", + width = 3, + height = 3, + dynamic_display_size = function (craft) + local maxn = table.maxn(craft.items) + local g = 1 + while g*g < maxn do g = g + 1 end + return { width = g, height = g } + end, + uses_crafting_grid = true, +}) + + +unified_inventory.register_craft_type("cooking", { + description = F(S("Cooking")), + icon = "default_furnace_front.png", + width = 1, + height = 1, +}) + + +unified_inventory.register_craft_type("digging", { + description = F(S("Digging")), + icon = "default_tool_steelpick.png", + width = 1, + height = 1, +}) + +unified_inventory.register_craft_type("digging_chance", { + description = "Digging (by chance)", + icon = "default_tool_steelpick.png^[transformFY.png", + width = 1, + height = 1, +}) + +function unified_inventory.register_page(name, def) + unified_inventory.pages[name] = def +end + + +function unified_inventory.register_button(name, def) + if not def.action then + def.action = function(player) + unified_inventory.set_inventory_formspec(player, name) + end + end + def.name = name + table.insert(unified_inventory.buttons, def) +end + + +function unified_inventory.is_creative(playername) + return minetest.check_player_privs(playername, {creative=true}) + or minetest.settings:get_bool("creative_mode") +end diff --git a/Bucket_Game-base/unified_inventory_recipe_fix-vs-211031/mods/codercore/depends.txt b/Bucket_Game-base/unified_inventory_recipe_fix-vs-211031/mods/codercore/depends.txt new file mode 100644 index 0000000..c1c449a --- /dev/null +++ b/Bucket_Game-base/unified_inventory_recipe_fix-vs-211031/mods/codercore/depends.txt @@ -0,0 +1,6 @@ +default +creative? +sfinv? +datastorage? +farming? +ocsethome? diff --git a/Bucket_Game-base/unified_inventory_recipe_fix-vs-211031/mods/codercore/group.lua b/Bucket_Game-base/unified_inventory_recipe_fix-vs-211031/mods/codercore/group.lua new file mode 100644 index 0000000..518652b --- /dev/null +++ b/Bucket_Game-base/unified_inventory_recipe_fix-vs-211031/mods/codercore/group.lua @@ -0,0 +1,127 @@ +local S = function (str) return str end + +function unified_inventory.canonical_item_spec_matcher(spec) + local specname = ItemStack(spec):get_name() + if specname:sub(1, 6) ~= "group:" then + return function (itemname) + return itemname == specname + end + end + + local group_names = specname:sub(7):split(",") + return function (itemname) + local itemdef = minetest.registered_items[itemname] + for _, group_name in ipairs(group_names) do + if (itemdef.groups[group_name] or 0) == 0 then + return false + end + end + return true + end +end + +function unified_inventory.item_matches_spec(item, spec) + local itemname = ItemStack(item):get_name() + return unified_inventory.canonical_item_spec_matcher(spec)(itemname) +end + +function unified_inventory.extract_groupnames(groupname) + local specname = ItemStack(groupname):get_name() + if specname:sub(1, 6) ~= "group:" then + return nil, 0 + end + local group_names = specname:sub(7):split(",") + return table.concat(group_names, S(" and ")), #group_names +end + +unified_inventory.registered_group_items = { + mesecon_conductor_craftable = "mesecons:wire_00000000_off", + stone = "default:cobble", + wood = "default:wood", + book = "default:book", + sand = "default:sand", + leaves = "default:leaves", + tree = "default:tree", + vessel = "vessels:glass_bottle", + wool = "wool:white", +} + +function unified_inventory.register_group_item(groupname, itemname) + unified_inventory.registered_group_items[groupname] = itemname +end + + +-- This is used when displaying craft recipes, where an ingredient is +-- specified by group rather than as a specific item. A single-item group +-- is represented by that item, with the single-item status signalled +-- in the "sole" field. If the group contains no items at all, the item +-- field will be nil. +-- +-- Within a multiple-item group, we prefer to use an item that has the +-- same specific name as the group, and if there are more than one of +-- those items we prefer the one registered for the group by a mod. +-- Among equally-preferred items, we just pick the one with the +-- lexicographically earliest name. +-- +-- The parameter to this function isn't just a single group name. +-- It may be a comma-separated list of group names. This is really a +-- "group:..." ingredient specification, minus the "group:" prefix. + +local function compute_group_item(group_name_list) + local group_names = group_name_list:split(",") + local candidate_items = {} + for itemname, itemdef in pairs(minetest.registered_items) do + if (itemdef.groups.not_in_creative_inventory or 0) == 0 then + local all = true + for _, group_name in ipairs(group_names) do + if (itemdef.groups[group_name] or 0) == 0 then + all = false + end + end + if all then table.insert(candidate_items, itemname) end + end + end + local num_candidates = #candidate_items + if num_candidates == 0 then + return {sole = true} + elseif num_candidates == 1 then + return {item = candidate_items[1], sole = true} + end + local is_group = {} + local registered_rep = {} + for _, group_name in ipairs(group_names) do + is_group[group_name] = true + local rep = unified_inventory.registered_group_items[group_name] + if rep then registered_rep[rep] = true end + end + local bestitem = "" + local bestpref = 0 + for _, item in ipairs(candidate_items) do + local pref + if registered_rep[item] then + pref = 4 + elseif string.sub(item, 1, 8) == "default:" and is_group[string.sub(item, 9)] then + pref = 3 + elseif is_group[item:gsub("^[^:]*:", "")] then + pref = 2 + else + pref = 1 + end + if pref > bestpref or (pref == bestpref and item < bestitem) then + bestitem = item + bestpref = pref + end + end + return {item = bestitem, sole = false} +end + + +local group_item_cache = {} + +function unified_inventory.get_group_item(group_name) + if not group_item_cache[group_name] then + group_item_cache[group_name] = compute_group_item(group_name) + end + return group_item_cache[group_name] +end + diff --git a/Bucket_Game-base/unified_inventory_recipe_fix-vs-211031/mods/codercore/internal.lua b/Bucket_Game-base/unified_inventory_recipe_fix-vs-211031/mods/codercore/internal.lua new file mode 100644 index 0000000..1e17312 --- /dev/null +++ b/Bucket_Game-base/unified_inventory_recipe_fix-vs-211031/mods/codercore/internal.lua @@ -0,0 +1,375 @@ +local S = function (str) return str end +local F = minetest.formspec_escape + +-- This pair of encoding functions is used where variable text must go in +-- button names, where the text might contain formspec metacharacters. +-- We can escape button names for the formspec, to avoid screwing up +-- form structure overall, but they then don't get de-escaped, and so +-- the input we get back from the button contains the formspec escaping. +-- This is a game engine bug, and in the anticipation that it might be +-- fixed some day we don't want to rely on it. So for safety we apply +-- an encoding that avoids all formspec metacharacters. +function unified_inventory.mangle_for_formspec(str) + return string.gsub(str, "([^A-Za-z0-9])", function (c) return string.format("_%d_", string.byte(c)) end) +end +function unified_inventory.demangle_for_formspec(str) + return string.gsub(str, "_([0-9]+)_", function (v) return string.char(v) end) +end + +function unified_inventory.get_per_player_formspec(player_name) + local lite = unified_inventory.lite_mode and not minetest.check_player_privs(player_name, {ui_full=true}) + + local ui = {} + ui.pagecols = unified_inventory.pagecols + ui.pagerows = unified_inventory.pagerows + ui.page_y = unified_inventory.page_y + ui.formspec_y = unified_inventory.formspec_y + ui.main_button_x = unified_inventory.main_button_x + ui.main_button_y = unified_inventory.main_button_y + ui.craft_result_x = unified_inventory.craft_result_x + ui.craft_result_y = unified_inventory.craft_result_y + ui.form_header_y = unified_inventory.form_header_y + + if lite then + ui.pagecols = 4 + ui.pagerows = 6 + ui.page_y = 0.25 + ui.formspec_y = 0.47 + ui.main_button_x = 8.2 + ui.main_button_y = 6.5 + ui.craft_result_x = 2.8 + ui.craft_result_y = 3.4 + ui.form_header_y = -0.1 + end + + ui.items_per_page = ui.pagecols * ui.pagerows + return ui, lite +end + +function unified_inventory.get_formspec(player, page) + + if not player then + return "" + end + + local player_name = player:get_player_name() + local ui_peruser,draw_lite_mode = unified_inventory.get_per_player_formspec(player_name) + + unified_inventory.current_page[player_name] = page + local pagedef = unified_inventory.pages[page] + + if not pagedef then + return "" -- Invalid page name + end + + local formspec = { + "size[14,10]", + pagedef.formspec_prepend and "" or "no_prepend[]", + "background[-0.19,-0.25;14.4,10.75;ui_form_bg.png]" -- Background + } + local n = 4 + + if draw_lite_mode then + formspec[1] = "size[11,7.7]" + formspec[3] = "background[-0.19,-0.2;11.4,8.4;ui_form_bg.png]" + end + + if unified_inventory.is_creative(player_name) + and page == "craft" then + formspec[n] = "background[0,"..(ui_peruser.formspec_y + 2)..";1,1;ui_single_slot.png]" + n = n+1 + end + + local perplayer_formspec = unified_inventory.get_per_player_formspec(player_name) + local fsdata = pagedef.get_formspec(player, perplayer_formspec) + + formspec[n] = fsdata.formspec + n = n+1 + + local button_row = 0 + local button_col = 0 + + -- Main buttons + + local filtered_inv_buttons = {} + + for i, def in pairs(unified_inventory.buttons) do + if not (draw_lite_mode and def.hide_lite) then + table.insert(filtered_inv_buttons, def) + end + end + + for i, def in pairs(filtered_inv_buttons) do + + if draw_lite_mode and i > 4 then + button_row = 1 + button_col = 1 + end + + if def.type == "image" then + if (def.condition == nil or def.condition(player) == true) then + formspec[n] = "image_button[" + formspec[n+1] = ( ui_peruser.main_button_x + 0.65 * (i - 1) - button_col * 0.65 * 4) + formspec[n+2] = ","..(ui_peruser.main_button_y + button_row * 0.7)..";0.8,0.8;" + formspec[n+3] = F(def.image)..";" + formspec[n+4] = F(def.name)..";]" + formspec[n+5] = "tooltip["..F(def.name) + formspec[n+6] = ";"..(def.tooltip or "").."]" + n = n+7 + else + formspec[n] = "image[" + formspec[n+1] = ( ui_peruser.main_button_x + 0.65 * (i - 1) - button_col * 0.65 * 4) + formspec[n+2] = ","..(ui_peruser.main_button_y + button_row * 0.7)..";0.8,0.8;" + formspec[n+3] = F(def.image).."^[colorize:#808080:alpha]" + n = n+4 + + end + end + end + + if fsdata.draw_inventory ~= false then + -- Player inventory + formspec[n] = "listcolors[#00000000;#00000000]" + formspec[n+1] = "list[current_player;main;0,"..(ui_peruser.formspec_y + 3.5)..";8,4;]" + n = n+2 + end + + if fsdata.draw_item_list == false then + return table.concat(formspec, "") + end + + -- Controls to flip items pages + local start_x = 9.2 + + if not draw_lite_mode then + formspec[n] = + "image_button[" .. (start_x + 0.6 * 0) + .. ",9;.8,.8;ui_skip_backward_icon.png;start_list;]" + .. "tooltip[start_list;" .. F(S("First page")) .. "]" + + .. "image_button[" .. (start_x + 0.6 * 1) + .. ",9;.8,.8;ui_doubleleft_icon.png;rewind3;]" + .. "tooltip[rewind3;" .. F(S("Back three pages")) .. "]" + .. "image_button[" .. (start_x + 0.6 * 2) + .. ",9;.8,.8;ui_left_icon.png;rewind1;]" + .. "tooltip[rewind1;" .. F(S("Back one page")) .. "]" + + .. "image_button[" .. (start_x + 0.6 * 3) + .. ",9;.8,.8;ui_right_icon.png;forward1;]" + .. "tooltip[forward1;" .. F(S("Forward one page")) .. "]" + .. "image_button[" .. (start_x + 0.6 * 4) + .. ",9;.8,.8;ui_doubleright_icon.png;forward3;]" + .. "tooltip[forward3;" .. F(S("Forward three pages")) .. "]" + + .. "image_button[" .. (start_x + 0.6 * 5) + .. ",9;.8,.8;ui_skip_forward_icon.png;end_list;]" + .. "tooltip[end_list;" .. F(S("Last page")) .. "]" + else + formspec[n] = + "image_button[" .. (8.2 + 0.65 * 0) + .. ",5.8;.8,.8;ui_skip_backward_icon.png;start_list;]" + .. "tooltip[start_list;" .. F(S("First page")) .. "]" + .. "image_button[" .. (8.2 + 0.65 * 1) + .. ",5.8;.8,.8;ui_left_icon.png;rewind1;]" + .. "tooltip[rewind1;" .. F(S("Back one page")) .. "]" + .. "image_button[" .. (8.2 + 0.65 * 2) + .. ",5.8;.8,.8;ui_right_icon.png;forward1;]" + .. "tooltip[forward1;" .. F(S("Forward one page")) .. "]" + .. "image_button[" .. (8.2 + 0.65 * 3) + .. ",5.8;.8,.8;ui_skip_forward_icon.png;end_list;]" + .. "tooltip[end_list;" .. F(S("Last page")) .. "]" + end + n = n+1 + + -- Search box + formspec[n] = "field_close_on_enter[searchbox;false]" + n = n+1 + + if not draw_lite_mode then + formspec[n] = "field[9.5,8.325;3,1;searchbox;;" + .. F(unified_inventory.current_searchbox[player_name]) .. "]" + formspec[n+1] = "image_button[12.2,8.1;.8,.8;ui_search_icon.png;searchbutton;]" + .. "tooltip[searchbutton;" ..F(S("Search")) .. "]" + formspec[n+2] = "image_button[12.9,8.1;.8,.8;ui_reset_icon.png;searchresetbutton;]" + .. "tooltip[searchbutton;" ..F(S("Search")) .. "]" + .. "tooltip[searchresetbutton;" ..F(S("Reset search and display everything")) .. "]" + else + formspec[n] = "field[8.5,5.225;2.2,1;searchbox;;" + .. F(unified_inventory.current_searchbox[player_name]) .. "]" + formspec[n+1] = "image_button[10.3,5;.8,.8;ui_search_icon.png;searchbutton;]" + .. "tooltip[searchbutton;" ..F(S("Search")) .. "]" + formspec[n+2] = "image_button[11,5;.8,.8;ui_reset_icon.png;searchresetbutton;]" + .. "tooltip[searchbutton;" ..F(S("Search")) .. "]" + .. "tooltip[searchresetbutton;" ..F(S("Reset search and display everything")) .. "]" + end + n = n+3 + + local no_matches = S("No matching items") + if draw_lite_mode then + no_matches = S("No matches.") + end + + -- Items list + if #unified_inventory.filtered_items_list[player_name] == 0 then + formspec[n] = "label[8.2,"..ui_peruser.form_header_y..";" .. F(no_matches) .. "]" + else + local dir = unified_inventory.active_search_direction[player_name] + local list_index = unified_inventory.current_index[player_name] + local page = math.floor(list_index / (ui_peruser.items_per_page) + 1) + local pagemax = math.floor( + (#unified_inventory.filtered_items_list[player_name] - 1) + / (ui_peruser.items_per_page) + 1) + local item = {} + for y = 0, ui_peruser.pagerows - 1 do + for x = 0, ui_peruser.pagecols - 1 do + local name = unified_inventory.filtered_items_list[player_name][list_index] + local item = minetest.registered_items[name] + if item then + -- Clicked on current item: Flip crafting direction + if name == unified_inventory.current_item[player_name] then + local cdir = unified_inventory.current_craft_direction[player_name] + if cdir == "recipe" then + dir = "usage" + elseif cdir == "usage" then + dir = "recipe" + end + else + -- Default: use active search direction by default + dir = unified_inventory.active_search_direction[player_name] + end + + local button_name = "item_button_" .. dir .. "_" + .. unified_inventory.mangle_for_formspec(name) + formspec[n] = ("item_image_button[%f,%f;.81,.81;%s;%s;]"):format( + 8.2 + x * 0.7, ui_peruser.formspec_y + ui_peruser.page_y + y * 0.7, + name, button_name + ) + formspec[n + 1] = ("tooltip[%s;%s \\[%s\\]]"):format( + button_name, minetest.formspec_escape(item.description), + item.mod_origin or "??" + ) + n = n + 2 + list_index = list_index + 1 + end + end + end + + formspec [n] = "label[8.2," .. ui_peruser.form_header_y +.. ";Page " .. page .. " of " .. pagemax .. "]" + end + n = n+1 + + if unified_inventory.activefilter[player_name] ~= "" then + formspec[n] = "label[8.2,"..(ui_peruser.form_header_y + 0.4)..";" .. F(S("Filter")) .. ":]" + formspec[n+1] = "label[9.1,"..(ui_peruser.form_header_y + 0.4)..";"..F(unified_inventory.activefilter[player_name]).."]" + end + return table.concat(formspec, "") +end + +function unified_inventory.set_inventory_formspec(player, page) + if player then + player:set_inventory_formspec(unified_inventory.get_formspec(player, page)) + end +end + +--apply filter to the inventory list (create filtered copy of full one) +function unified_inventory.apply_filter(player, filter, search_dir) + if not player then + return false + end + local player_name = player:get_player_name() + local lfilter = string.lower(filter) + local ffilter + if lfilter:sub(1, 6) == "group:" then + local groups = lfilter:sub(7):split(",") + ffilter = function(name, def) + for _, group in ipairs(groups) do + if not def.groups[group] + or def.groups[group] <= 0 then + return false + end + end + return true + end + else + ffilter = function(name, def) + local lname = string.lower(name) + local ldesc = string.lower(def.description) + return string.find(lname, lfilter, 1, true) or string.find(ldesc, lfilter, 1, true) + end + end + unified_inventory.filtered_items_list[player_name]={} + for name, def in pairs(minetest.registered_items) do + if (not def.groups.not_in_creative_inventory + or def.groups.not_in_creative_inventory == 0) + and def.description + and def.description ~= "" + and ffilter(name, def) then + table.insert(unified_inventory.filtered_items_list[player_name], name) + end + end + table.sort(unified_inventory.filtered_items_list[player_name]) + unified_inventory.filtered_items_list_size[player_name] = #unified_inventory.filtered_items_list[player_name] + unified_inventory.current_index[player_name] = 1 + unified_inventory.activefilter[player_name] = filter + unified_inventory.active_search_direction[player_name] = search_dir + unified_inventory.set_inventory_formspec(player, + unified_inventory.current_page[player_name]) +end + +function unified_inventory.items_in_group(groups) + local items = {} + for name, item in pairs(minetest.registered_items) do + for _, group in pairs(groups:split(',')) do + if item.groups[group] then + table.insert(items, name) + end + end + end + return items +end + +function unified_inventory.sort_inventory(inv) + local inlist = inv:get_list("main") + local typecnt = {} + local typekeys = {} + for _, st in ipairs(inlist) do + if not st:is_empty() then + local n = st:get_name() + local w = st:get_wear() + local m = st:get_metadata() + local k = string.format("%s %05d %s", n, w, m) + if not typecnt[k] then + typecnt[k] = { + name = n, + wear = w, + metadata = m, + stack_max = st:get_stack_max(), + count = 0, + } + table.insert(typekeys, k) + end + typecnt[k].count = typecnt[k].count + st:get_count() + end + end + table.sort(typekeys) + local outlist = {} + for _, k in ipairs(typekeys) do + local tc = typecnt[k] + while tc.count > 0 do + local c = math.min(tc.count, tc.stack_max) + table.insert(outlist, ItemStack({ + name = tc.name, + wear = tc.wear, + metadata = tc.metadata, + count = c, + })) + tc.count = tc.count - c + end + end + if #outlist > #inlist then return end + while #outlist < #inlist do + table.insert(outlist, ItemStack(nil)) + end + inv:set_list("main", outlist) +end diff --git a/Bucket_Game-base/unified_inventory_recipe_fix-vs-211031/mods/codercore/oldcoder.txt b/Bucket_Game-base/unified_inventory_recipe_fix-vs-211031/mods/codercore/oldcoder.txt new file mode 100644 index 0000000..336f8e1 --- /dev/null +++ b/Bucket_Game-base/unified_inventory_recipe_fix-vs-211031/mods/codercore/oldcoder.txt @@ -0,0 +1,27 @@ +Name: unified_inventory +Source: Fork of upstream mod - Do not replace +License: See "LICENSE.txt" + +---------------------------------------------------------------------- + +1. This is a fork of an upstream mod. The starting point was obtained +initially as follows: + + rm -fr unified_inventory + git clone https://github.com/minetest-mods/unified_inventory.git + cd unified_inventory + git reset --hard ca6d9a10df5110fd75d49785adf690ae270d5a31 + +Forked after: commit indicated above + +---------------------------------------------------------------------- + +2. Partial list of changes: + +2a. Fixed a few cases where "@1" or "@2" was printed instead of the +correct output. + +2b. Modified the mod so that it stays synced with "ocsethome". + +2c. Removed "bags" code, which seems to be crashy. "prestibags" mod +has been added to the "_game" as a substitute for the "bags" feature. diff --git a/Bucket_Game-base/unified_inventory_recipe_fix-vs-211031/mods/codercore/register.lua b/Bucket_Game-base/unified_inventory_recipe_fix-vs-211031/mods/codercore/register.lua new file mode 100644 index 0000000..278acfb --- /dev/null +++ b/Bucket_Game-base/unified_inventory_recipe_fix-vs-211031/mods/codercore/register.lua @@ -0,0 +1,489 @@ +local S = function (str) return str end +local NS = function(s) return s end +local F = minetest.formspec_escape + +minetest.register_privilege("creative", { + description = S("Can use the creative inventory"), + give_to_singleplayer = false, +}) + +minetest.register_privilege("ui_full", { + description = S("Forces Unified Inventory to be displayed in Full mode if Lite mode is configured globally"), + give_to_singleplayer = false, +}) + + +local trash = minetest.create_detached_inventory("trash", { + --allow_put = function(inv, listname, index, stack, player) + -- if unified_inventory.is_creative(player:get_player_name()) then + -- return stack:get_count() + -- else + -- return 0 + -- end + --end, + on_put = function(inv, listname, index, stack, player) + inv:set_stack(listname, index, nil) + local player_name = player:get_player_name() + minetest.sound_play("trash", {to_player=player_name, gain = 1.0}) + end, +}) +trash:set_size("main", 1) + +unified_inventory.register_button("craft", { + type = "image", + image = "ui_craft_icon.png", + tooltip = S("Crafting Grid") +}) + +unified_inventory.register_button("craftguide", { + type = "image", + image = "ui_craftguide_icon.png", + tooltip = S("Crafting Guide") +}) + +unified_inventory.register_button("home_gui_set", { + type = "image", + image = "ui_sethome_icon.png", + tooltip = S("Set home position"), + hide_lite=true, + action = function(player) + local player_name = player:get_player_name() + if minetest.check_player_privs(player_name, {home=true}) then + unified_inventory.set_home(player, player:get_pos()) + local home = unified_inventory.home_pos[player_name] + if home ~= nil then + minetest.sound_play("dingdong", + {to_player=player_name, gain = 1.0}) + minetest.chat_send_player(player_name, + "Home position set to: " .. minetest.pos_to_string (home)) + end + else + minetest.chat_send_player(player_name, + S("You don't have the \"home\" privilege!")) + unified_inventory.set_inventory_formspec(player, unified_inventory.current_page[player_name]) + end + end, + condition = function(player) + return minetest.check_player_privs(player:get_player_name(), {home=true}) + end, +}) + +unified_inventory.register_button("home_gui_go", { + type = "image", + image = "ui_gohome_icon.png", + tooltip = S("Go home"), + hide_lite=true, + action = function(player) + local player_name = player:get_player_name() + if minetest.check_player_privs(player_name, {home=true}) then + minetest.sound_play("teleport", + {to_player=player:get_player_name(), gain = 1.0}) + unified_inventory.go_home(player) + else + minetest.chat_send_player(player_name, + S("You don't have the \"home\" privilege!")) + unified_inventory.set_inventory_formspec(player, unified_inventory.current_page[player_name]) + end + end, + condition = function(player) + return minetest.check_player_privs(player:get_player_name(), {home=true}) + end, +}) + +unified_inventory.register_button("misc_set_day", { + type = "image", + image = "ui_sun_icon.png", + tooltip = S("Set time to day"), + hide_lite=true, + action = function(player) + local player_name = player:get_player_name() + if minetest.check_player_privs(player_name, {settime=true}) then + minetest.sound_play("birds", + {to_player=player_name, gain = 1.0}) + minetest.set_timeofday((6000 % 24000) / 24000) + minetest.chat_send_player(player_name, + S("Time of day set to 6am")) + else + minetest.chat_send_player(player_name, + S("You don't have the settime privilege!")) + unified_inventory.set_inventory_formspec(player, unified_inventory.current_page[player_name]) + end + end, + condition = function(player) + return minetest.check_player_privs(player:get_player_name(), {settime=true}) + end, +}) + +unified_inventory.register_button("misc_set_night", { + type = "image", + image = "ui_moon_icon.png", + tooltip = S("Set time to night"), + hide_lite=true, + action = function(player) + local player_name = player:get_player_name() + if minetest.check_player_privs(player_name, {settime=true}) then + minetest.sound_play("owl", + {to_player=player_name, gain = 1.0}) + minetest.set_timeofday((21000 % 24000) / 24000) + minetest.chat_send_player(player_name, + S("Time of day set to 9pm")) + else + minetest.chat_send_player(player_name, + S("You don't have the settime privilege!")) + unified_inventory.set_inventory_formspec(player, unified_inventory.current_page[player_name]) + end + end, + condition = function(player) + return minetest.check_player_privs(player:get_player_name(), {settime=true}) + end, +}) + +unified_inventory.register_button("clear_inv", { + type = "image", + image = "ui_trash_icon.png", + tooltip = S("Clear inventory"), + action = function(player) + local player_name = player:get_player_name() + if not unified_inventory.is_creative(player_name) then + minetest.chat_send_player(player_name, + S("This button has been disabled outside" + .." of creative mode to prevent" + .." accidental inventory trashing." + .."\nUse the trash slot instead.")) + unified_inventory.set_inventory_formspec(player, unified_inventory.current_page[player_name]) + return + end + player:get_inventory():set_list("main", {}) + minetest.chat_send_player(player_name, S('Inventory cleared!')) + minetest.sound_play("trash_all", + {to_player=player_name, gain = 1.0}) + end, + condition = function(player) + return unified_inventory.is_creative(player:get_player_name()) + end, +}) + +unified_inventory.register_page("craft", { + get_formspec = function(player, perplayer_formspec) + + local formspecy = perplayer_formspec.formspec_y + local formheadery = perplayer_formspec.form_header_y + + local player_name = player:get_player_name() + local formspec = "background[2,"..formspecy..";6,3;ui_crafting_form.png]" + formspec = formspec.."background[0,"..(formspecy + 3.5)..";8,4;ui_main_inventory.png]" + formspec = formspec.."label[0,"..formheadery..";" ..F(S("Crafting")).."]" + formspec = formspec.."listcolors[#00000000;#00000000]" + formspec = formspec.."list[current_player;craftpreview;6,"..formspecy..";1,1;]" + formspec = formspec.."list[current_player;craft;2,"..formspecy..";3,3;]" + if unified_inventory.trash_enabled or unified_inventory.is_creative(player_name) or minetest.get_player_privs(player_name).give then + formspec = formspec.."label[7,"..(formspecy + 1.5)..";" .. F(S("Trash:")) .. "]" + formspec = formspec.."background[7,"..(formspecy + 2)..";1,1;ui_single_slot.png]" + formspec = formspec.."list[detached:trash;main;7,"..(formspecy + 2)..";1,1;]" + end + formspec = formspec.."listring[current_name;craft]" + formspec = formspec.."listring[current_player;main]" + if unified_inventory.is_creative(player_name) then + formspec = formspec.."label[0,"..(formspecy + 1.5)..";" .. F(S("Refill:")) .. "]" + formspec = formspec.."list[detached:"..F(player_name).."refill;main;0,"..(formspecy +2)..";1,1;]" + end + return {formspec=formspec} + end, +}) + +-- stack_image_button(): generate a form button displaying a stack of items +-- +-- The specified item may be a group. In that case, the group will be +-- represented by some item in the group, along with a flag indicating +-- that it's a group. If the group contains only one item, it will be +-- treated as if that item had been specified directly. + +local function stack_image_button(x, y, w, h, buttonname_prefix, item) + local name = item:get_name() + local count = item:get_count() + local show_is_group = false + local displayitem = name.." "..count + local selectitem = name + if name:sub(1, 6) == "group:" then + local group_name = name:sub(7) + local group_item = unified_inventory.get_group_item(group_name) + show_is_group = not group_item.sole + displayitem = group_item.item or "unknown" + selectitem = group_item.sole and displayitem or name + end + local label = show_is_group and "G" or "" + local buttonname = F(buttonname_prefix..unified_inventory.mangle_for_formspec(selectitem)) + local button = string.format("item_image_button[%f,%f;%f,%f;%s;%s;%s]", + x, y, w, h, + F(displayitem), buttonname, label) + if show_is_group then + local groupstring, andcount = unified_inventory.extract_groupnames(name) + local grouptip + if andcount == 1 then + grouptip = "Any item belonging to the " .. groupstring .. " group" + elseif andcount > 1 then + grouptip = "Any item belonging to the groups " .. groupstring + end + grouptip = F(grouptip) + if andcount >= 1 then + button = button .. string.format("tooltip[%s;%s]", buttonname, grouptip) + end + end + return button +end + +local recipe_text = { + recipe = NS("Recipe @1 of @2"), + usage = NS("Usage @1 of @2"), +} +local no_recipe_text = { + recipe = S("No recipes"), + usage = S("No usages"), +} +local role_text = { + recipe = S("Result"), + usage = S("Ingredient"), +} +local next_alt_text = { + recipe = S("Show next recipe"), + usage = S("Show next usage"), +} +local prev_alt_text = { + recipe = S("Show previous recipe"), + usage = S("Show previous usage"), +} +local other_dir = { + recipe = "usage", + usage = "recipe", +} + +unified_inventory.register_page("craftguide", { + get_formspec = function(player, perplayer_formspec) + + local formspecy = perplayer_formspec.formspec_y + local formheadery = perplayer_formspec.form_header_y + local craftresultx = perplayer_formspec.craft_result_x + local craftresulty = perplayer_formspec.craft_result_y + + local player_name = player:get_player_name() + local player_privs = minetest.get_player_privs(player_name) + local fs = { + "background[0,"..(formspecy + 3.5)..";8,4;ui_main_inventory.png]", + "label[0,"..formheadery..";" .. F(S("Crafting Guide")) .. "]", + "listcolors[#00000000;#00000000]" + } + local item_name = unified_inventory.current_item[player_name] + if not item_name then + return { formspec = table.concat(fs) } + end + + local item_name_shown + if minetest.registered_items[item_name] + and minetest.registered_items[item_name].description then + item_name_shown = S("@1 (@2)", + minetest.registered_items[item_name].description, item_name) + else + item_name_shown = item_name + end + + local dir = unified_inventory.current_craft_direction[player_name] + local rdir = dir == "recipe" and "usage" or "recipe" + + local crafts = unified_inventory.crafts_for[dir][item_name] + local alternate = unified_inventory.alternate[player_name] + local alternates, craft + if crafts and #crafts > 0 then + alternates = #crafts + craft = crafts[alternate] + end + local has_give = player_privs.give or unified_inventory.is_creative(player_name) + + fs[#fs + 1] = "background[0.5,"..(formspecy + 0.2)..";8,3;ui_craftguide_form.png]" + fs[#fs + 1] = string.format("textarea[%f,%f;10,1;;%s: %s;]", + craftresultx, craftresulty, F(role_text[dir]), item_name_shown) + fs[#fs + 1] = stack_image_button(0, formspecy, 1.1, 1.1, + "item_button_" .. rdir .. "_", ItemStack(item_name)) + + if not craft then + -- No craft recipes available for this item. + fs[#fs + 1] = "label[5.5,"..(formspecy + 2.35)..";" + .. F(no_recipe_text[dir]) .. "]" + local no_pos = dir == "recipe" and 4.5 or 6.5 + local item_pos = dir == "recipe" and 6.5 or 4.5 + fs[#fs + 1] = "image["..no_pos..","..formspecy..";1.1,1.1;ui_no.png]" + fs[#fs + 1] = stack_image_button(item_pos, formspecy, 1.1, 1.1, + "item_button_" .. other_dir[dir] .. "_", ItemStack(item_name)) + if has_give then + fs[#fs + 1] = "label[0," .. (formspecy + 2.10) .. ";" .. F(S("Give me:")) .. "]" + .. "button[0, " .. (formspecy + 2.7) .. ";0.6,0.5;craftguide_giveme_1;1]" + .. "button[0.6," .. (formspecy + 2.7) .. ";0.7,0.5;craftguide_giveme_10;10]" + .. "button[1.3," .. (formspecy + 2.7) .. ";0.8,0.5;craftguide_giveme_99;99]" + end + return { formspec = table.concat(fs) } + end + + local craft_type = unified_inventory.registered_craft_types[craft.type] or + unified_inventory.craft_type_defaults(craft.type, {}) + if craft_type.icon then + fs[#fs + 1] = string.format("image[%f,%f;%f,%f;%s]", + 5.7, (formspecy + 0.05), 0.5, 0.5, craft_type.icon) + end + fs[#fs + 1] = "label[5.5,"..(formspecy + 1)..";" .. F(craft_type.description).."]" + fs[#fs + 1] = stack_image_button(6.5, formspecy, 1.1, 1.1, + "item_button_usage_", ItemStack(craft.output)) + + local display_size = craft_type.dynamic_display_size + and craft_type.dynamic_display_size(craft) + or { width = craft_type.width, height = craft_type.height } + local craft_width = craft_type.get_shaped_craft_width + and craft_type.get_shaped_craft_width(craft) + or display_size.width + + -- This keeps recipes aligned to the right, + -- so that they're close to the arrow. + local xoffset = 5.5 + -- Offset factor for crafting grids with side length > 4 + local of = (3/math.max(3, math.max(display_size.width, display_size.height))) + local od = 0 + -- Minimum grid size at which size optimazation measures kick in + local mini_craft_size = 6 + if display_size.width >= mini_craft_size then + od = math.max(1, display_size.width - 2) + xoffset = xoffset - 0.1 + end + -- Size modifier factor + local sf = math.min(1, of * (1.05 + 0.05*od)) + -- Button size + local bsize_h = 1.1 * sf + local bsize_w = bsize_h + if display_size.width >= mini_craft_size then + bsize_w = 1.175 * sf + end + if (bsize_h > 0.35 and display_size.width) then + for y = 1, display_size.height do + for x = 1, display_size.width do + local item + if craft and x <= craft_width then + item = craft.items[(y-1) * craft_width + x] + end + -- Flipped x, used to build formspec buttons from right to left + local fx = display_size.width - (x-1) + -- x offset, y offset + local xof = (fx-1) * of + of + local yof = (y-1) * of + 1 + if item then + fs[#fs + 1] = stack_image_button( + xoffset - xof, formspecy - 1 + yof, bsize_w, bsize_h, + "item_button_recipe_", + ItemStack(item)) + else + -- Fake buttons just to make grid + fs[#fs + 1] = string.format("image_button[%f,%f;%f,%f;ui_blank_image.png;;]", + xoffset - xof, formspecy - 1 + yof, bsize_w, bsize_h) + end + end + end + else + -- Error + fs[#fs + 1] = string.format("label[2,%f;%s]", + formspecy, F(S("This recipe is too\nlarge to be displayed."))) + end + + if craft_type.uses_crafting_grid and display_size.width <= 3 then + fs[#fs + 1] = "label[0," .. (formspecy + 0.9) .. ";" .. F(S("To craft grid:")) .. "]" + .. "button[0, " .. (formspecy + 1.5) .. ";0.6,0.5;craftguide_craft_1;1]" + .. "button[0.6," .. (formspecy + 1.5) .. ";0.7,0.5;craftguide_craft_10;10]" + .. "button[1.3," .. (formspecy + 1.5) .. ";0.8,0.5;craftguide_craft_max;" .. F(S("All")) .. "]" + end + if has_give then + fs[#fs + 1] = "label[0," .. (formspecy + 2.1) .. ";" .. F(S("Give me:")) .. "]" + .. "button[0, " .. (formspecy + 2.7) .. ";0.6,0.5;craftguide_giveme_1;1]" + .. "button[0.6," .. (formspecy + 2.7) .. ";0.7,0.5;craftguide_giveme_10;10]" + .. "button[1.3," .. (formspecy + 2.7) .. ";0.8,0.5;craftguide_giveme_99;99]" + end + + if alternates and alternates > 1 then + fs[#fs + 1] = "label[5.5," .. (formspecy + 1.6) .. ";" + .. F(S(recipe_text[dir], alternate, alternates)) .. "]" + .. "image_button[5.5," .. (formspecy + 2) .. ";1,1;ui_left_icon.png;alternate_prev;]" + .. "image_button[6.5," .. (formspecy + 2) .. ";1,1;ui_right_icon.png;alternate;]" + .. "tooltip[alternate_prev;" .. F(prev_alt_text[dir]) .. "]" + .. "tooltip[alternate;" .. F(next_alt_text[dir]) .. "]" + end + return { formspec = table.concat(fs) } + end, +}) + +local function craftguide_giveme(player, formname, fields) + local player_name = player:get_player_name() + local player_privs = minetest.get_player_privs(player_name) + if not player_privs.give and + not unified_inventory.is_creative(player_name) then + minetest.log("action", "[unified_inventory] Denied give action to player " .. + player_name) + return + end + + local amount + for k, v in pairs(fields) do + amount = k:match("craftguide_giveme_(.*)") + if amount then break end + end + + amount = tonumber(amount) or 0 + if amount == 0 then return end + + local output = unified_inventory.current_item[player_name] + if (not output) or (output == "") then return end + + local player_inv = player:get_inventory() + + player_inv:add_item("main", {name = output, count = amount}) +end + +local function craftguide_craft(player, formname, fields) + local amount + for k, v in pairs(fields) do + amount = k:match("craftguide_craft_(.*)") + if amount then break end + end + if not amount then return end + + amount = tonumber(amount) or -1 -- fallback for "all" + if amount == 0 or amount < -1 or amount > 99 then return end + + local player_name = player:get_player_name() + + local output = unified_inventory.current_item[player_name] or "" + if output == "" then return end + + local crafts = unified_inventory.crafts_for[ + unified_inventory.current_craft_direction[player_name]][output] or {} + if #crafts == 0 then return end + + local alternate = unified_inventory.alternate[player_name] + + local craft = crafts[alternate] + if craft.width > 3 then return end + + unified_inventory.craftguide_match_craft(player, "main", "craft", craft, amount) + + unified_inventory.set_inventory_formspec(player, "craft") +end + +minetest.register_on_player_receive_fields(function(player, formname, fields) + if formname ~= "" then + return + end + + for k, v in pairs(fields) do + if k:match("craftguide_craft_") then + craftguide_craft(player, formname, fields) + return + end + if k:match("craftguide_giveme_") then + craftguide_giveme(player, formname, fields) + return + end + end +end) diff --git a/Bucket_Game-base/unified_inventory_recipe_fix-vs-211031/mods/codercore/waypoints.lua b/Bucket_Game-base/unified_inventory_recipe_fix-vs-211031/mods/codercore/waypoints.lua new file mode 100644 index 0000000..a448f88 --- /dev/null +++ b/Bucket_Game-base/unified_inventory_recipe_fix-vs-211031/mods/codercore/waypoints.lua @@ -0,0 +1,247 @@ +local S = function (str) return str end +local F = minetest.formspec_escape + +local hud_colors = { + {"#FFFFFF", 0xFFFFFF, S("White")}, + {"#DBBB00", 0xf1d32c, S("Yellow")}, + {"#DD0000", 0xDD0000, S("Red")}, + {"#2cf136", 0x2cf136, S("Green")}, + {"#2c4df1", 0x2c4df1, S("Blue")}, +} + +local hud_colors_max = #hud_colors + +-- Stores temporary player data (persists until player leaves) +local waypoints_temp = {} + +unified_inventory.register_page("waypoints", { + get_formspec = function(player) + local player_name = player:get_player_name() + + -- build a "fake" temp entry if the server took too long + -- during sign-on and returned an empty entry + if not waypoints_temp[player_name] then waypoints_temp[player_name] = {hud = 1} end + + local waypoints = datastorage.get(player_name, "waypoints") + local formspec = "background[0,4.5;8,4;ui_main_inventory.png]" .. + "image[0,0;1,1;ui_waypoints_icon.png]" .. + "label[1,0;" .. F(S("Waypoints")) .. "]" + + -- Tabs buttons: + for i = 1, 5, 1 do + formspec = formspec .. + "image_button[0.0," .. 0.2 + i * 0.7 .. ";.8,.8;" .. + (i == waypoints.selected and "ui_blue_icon_background.png^" or "") .. + "ui_" .. i .. "_icon.png;" .. + "select_waypoint" .. i .. ";]" .. + "tooltip[select_waypoint" .. i .. ";" + .. S("Select Waypoint #@1", i).."]" + end + + local i = waypoints.selected or 1 + local waypoint = waypoints[i] or {} + local temp = waypoints_temp[player_name][i] or {} + local default_name = S("Waypoint @1", i) + + -- Main buttons: + formspec = formspec .. + "image_button[4.5,3.7;.8,.8;".. + "ui_waypoint_set_icon.png;".. + "set_waypoint"..i..";]".. + "tooltip[set_waypoint" .. i .. ";" + .. F(S("Set waypoint to current location")).."]" + + formspec = formspec .. + "image_button[5.2,3.7;.8,.8;".. + (waypoint.active and "ui_on_icon.png" or "ui_off_icon.png")..";".. + "toggle_waypoint"..i..";]".. + "tooltip[toggle_waypoint" .. i .. ";" + .. F(S("Make waypoint @1", + waypoint.active and S("invisible") or S("visible"))).."]" + + formspec = formspec .. + "image_button[5.9,3.7;.8,.8;".. + (waypoint.display_pos and "ui_green_icon_background.png" or "ui_red_icon_background.png").."^ui_xyz_icon.png;".. + "toggle_display_pos" .. i .. ";]".. + "tooltip[toggle_display_pos" .. i .. ";" + .. F(S("@1 display of waypoint coordinates", + waypoint.display_pos and S("Disable") or S("Enable"))) .."]" + + formspec = formspec .. + "image_button[6.6,3.7;.8,.8;".. + "ui_circular_arrows_icon.png;".. + "toggle_color"..i..";]".. + "tooltip[toggle_color" .. i .. ";" + .. F(S("Change color of waypoint display")).."]" + + formspec = formspec .. + "image_button[7.3,3.7;.8,.8;".. + "ui_pencil_icon.png;".. + "rename_waypoint"..i..";]".. + "tooltip[rename_waypoint" .. i .. ";" + .. F(S("Edit waypoint name")).."]" + + -- Waypoint's info: + if waypoint.active then + formspec = formspec .. "label[1,0.8;"..F(S("Waypoint active")).."]" + else + formspec = formspec .. "label[1,0.8;"..F(S("Waypoint inactive")).."]" + end + + if temp.edit then + formspec = formspec .. + "field[1.3,3.2;6,.8;rename_box" .. i .. ";;" + ..(waypoint.name or default_name).."]" .. + "image_button[7.3,2.9;.8,.8;".. + "ui_ok_icon.png;".. + "confirm_rename"..i.. ";]".. + "tooltip[confirm_rename" .. i .. ";" + .. F(S("Finish editing")).."]" + end + + formspec = formspec .. "label[1,1.3;"..F(S("World position"))..": " .. + minetest.pos_to_string(waypoint.world_pos or vector.new()) .. "]" .. + "label[1,1.8;"..F(S("Name"))..": ".. (waypoint.name or default_name) .. "]" .. + "label[1,2.3;"..F(S("HUD text color"))..": " .. + hud_colors[waypoint.color or 1][3] .. "]" + + return {formspec=formspec} + end, +}) + +unified_inventory.register_button("waypoints", { + type = "image", + image = "ui_waypoints_icon.png", + tooltip = S("Waypoints"), + hide_lite=true +}) + +local function update_hud(player, waypoints, temp, i) + local waypoint = waypoints[i] + if not waypoint then return end + temp[i] = temp[i] or {} + temp = temp[i] + local pos = waypoint.world_pos or vector.new() + local name + if waypoint.display_pos then + name = minetest.pos_to_string(pos) + if waypoint.name then + name = name..", "..waypoint.name + end + else + name = waypoint.name or "Waypoint "..i + end + if temp.hud then + player:hud_remove(temp.hud) + end + if waypoint.active then + temp.hud = player:hud_add({ + hud_elem_type = "waypoint", + number = hud_colors[waypoint.color or 1][2] , + name = name, + text = "m", + world_pos = pos + }) + else + temp.hud = nil + end +end + +minetest.register_on_player_receive_fields(function(player, formname, fields) + if formname ~= "" then return end + + local player_name = player:get_player_name() + local update_formspec = false + local need_update_hud = false + local hit = false + + local waypoints = datastorage.get(player_name, "waypoints") + local temp = waypoints_temp[player_name] + for i = 1, 5, 1 do + if fields["select_waypoint"..i] then + hit = true + waypoints.selected = i + update_formspec = true + end + + if fields["toggle_waypoint"..i] then + hit = true + waypoints[i] = waypoints[i] or {} + waypoints[i].active = not (waypoints[i].active) + need_update_hud = true + update_formspec = true + end + + if fields["set_waypoint"..i] then + hit = true + local pos = player:get_pos() + pos.x = math.floor(pos.x) + pos.y = math.floor(pos.y) + pos.z = math.floor(pos.z) + waypoints[i] = waypoints[i] or {} + waypoints[i].world_pos = pos + need_update_hud = true + update_formspec = true + end + + if fields["rename_waypoint"..i] then + hit = true + temp[i] = temp[i] or {} + temp[i].edit = true + update_formspec = true + end + + if fields["toggle_display_pos"..i] then + hit = true + waypoints[i] = waypoints[i] or {} + waypoints[i].display_pos = not waypoints[i].display_pos + need_update_hud = true + update_formspec = true + end + + if fields["toggle_color"..i] then + hit = true + waypoints[i] = waypoints[i] or {} + local color = waypoints[i].color or 1 + color = color + 1 + if color > hud_colors_max then + color = 1 + end + waypoints[i].color = color + need_update_hud = true + update_formspec = true + end + + if fields["confirm_rename"..i] then + hit = true + waypoints[i] = waypoints[i] or {} + temp[i].edit = false + waypoints[i].name = fields["rename_box"..i] + need_update_hud = true + update_formspec = true + end + if need_update_hud then + update_hud(player, waypoints, temp, i) + end + if update_formspec then + unified_inventory.set_inventory_formspec(player, "waypoints") + end + if hit then return end + end +end) + + +minetest.register_on_joinplayer(function(player) + local player_name = player:get_player_name() + local waypoints = datastorage.get(player_name, "waypoints") + local temp = {} + waypoints_temp[player_name] = temp + for i = 1, 5 do + update_hud(player, waypoints, temp, i) + end +end) + +minetest.register_on_leaveplayer(function(player) + waypoints_temp[player:get_player_name()] = nil +end) + diff --git a/Bucket_Game-branches/unified_inventory_recipe_fix-vs-211031/mods/codercore/00README b/Bucket_Game-branches/unified_inventory_recipe_fix-vs-211031/mods/codercore/00README new file mode 100644 index 0000000..1aa78a4 --- /dev/null +++ b/Bucket_Game-branches/unified_inventory_recipe_fix-vs-211031/mods/codercore/00README @@ -0,0 +1 @@ +See "oldcoder.txt". diff --git a/Bucket_Game-branches/unified_inventory_recipe_fix-vs-211031/mods/codercore/LICENSE.txt b/Bucket_Game-branches/unified_inventory_recipe_fix-vs-211031/mods/codercore/LICENSE.txt new file mode 100644 index 0000000..32492e4 --- /dev/null +++ b/Bucket_Game-branches/unified_inventory_recipe_fix-vs-211031/mods/codercore/LICENSE.txt @@ -0,0 +1,19 @@ +Unified Inventory for Minetest +Copyright (C) 2012-2014 Maciej Kasatkin (RealBadAngel) + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public +License as published by the Free Software Foundation; either +version 2 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +Contact information: + Examine a git patch to get the contributor's email address. diff --git a/Bucket_Game-branches/unified_inventory_recipe_fix-vs-211031/mods/codercore/README.md b/Bucket_Game-branches/unified_inventory_recipe_fix-vs-211031/mods/codercore/README.md new file mode 100644 index 0000000..15802c6 --- /dev/null +++ b/Bucket_Game-branches/unified_inventory_recipe_fix-vs-211031/mods/codercore/README.md @@ -0,0 +1,96 @@ +# Unified Inventory + +Unified Inventory replaces the default survival and creative inventory. + + +## Features + + * Node, item and tool browser + * Crafting guide + * Can copy the recipe to the crafting grid + * Recipe search function by ingredients + * Up to four bags with up to 24 slots each + * Home function to teleport + * Trash slot + * Lite mode: reduces the item browser width + * Mod API for modders: see [mod_api.txt](doc/mod_api.txt) + * Setting-determinated features: see [settingtypes.txt](settingtypes.txt) + + +## Requirements + + * Minetest 5.0.0+ since commit 4403b69 + * Minetest 0.4.16+ prior commit 4403b69 + + +# Licenses + +Copyright (C) 2012-2014 Maciej Kasatkin (RealBadAngel) + +Copyright (C) 2012-? Various minetest-mods contributors + + +## Code + +GNU LGPLv2+, see [license notice](LICENSE.txt) + + +## Textures + +VanessaE: (CC-BY-4.0) + + * `ui_group.png` + +Tango Project: (Public Domain, CC-BY-4.0) + + * [`ui_reset_icon.png`](https://commons.wikimedia.org/wiki/File:Edit-clear.svg) + * [`ui_doubleleft_icon.png`](http://commons.wikimedia.org/wiki/File:Media-seek-backward.svg) + * [`ui_doubleright_icon.png`](http://commons.wikimedia.org/wiki/File:Media-seek-forward.svg) + * [`ui_left_icon.png` / `ui_right_icon.png`](http://commons.wikimedia.org/wiki/File:Media-playback-start.svg) + * [`ui_skip_backward_icon.png`](http://commons.wikimedia.org/wiki/File:Media-skip-backward.svg) + * [`ui_skip_forward_icon.png`](http://commons.wikimedia.org/wiki/File:Media-skip-forward.svg) + +From http://www.clker.com (Public Domain, CC-BY-4.0): + + * [`bags_small.png`](http://www.clker.com/clipart-moneybag-empty.html) + * [`bags_medium.png`](http://www.clker.com/clipart-backpack-1.html) + * [`bags_large.png` / `ui_bags_icon.png`](http://www.clker.com/clipart-backpack-green-brown.html) + * `ui_trash_icon.png`: and + * [`ui_search_icon.png`](http://www.clker.com/clipart-24887.html) + * [`ui_off_icon.png` / `ui_on_icon.png`](http://www.clker.com/clipart-on-off-switches.html) + * [`ui_waypoints_icon.png`](http://www.clker.com/clipart-map-pin-red.html) + * [`ui_circular_arrows_icon.png`](http://www.clker.com/clipart-circular-arrow-pattern.html) + * [`ui_pencil_icon.pnc`](http://www.clker.com/clipart-2256.html) + * [`ui_waypoint_set_icon.png`](http://www.clker.com/clipart-larger-flag.html) + +Everaldo Coelho (YellowIcon) (LGPL v2.1+): + + * [`ui_craftguide_icon.png` / `ui_craft_icon.png`](http://commons.wikimedia.org/wiki/File:Advancedsettings.png) + +Gregory H. Revera: (CC-BY-SA 3.0) + + * [`ui_moon_icon.png`](http://commons.wikimedia.org/wiki/File:FullMoon2010.jpg) + +Thomas Bresson: (CC-BY 3.0) + + * [`ui_sun_icon.png`](http://commons.wikimedia.org/wiki/File:2012-10-13_15-29-35-sun.jpg) + +Fibonacci: (Public domain, CC-BY 4.0) + + * [`ui_xyz_off_icon.png`](http://commons.wikimedia.org/wiki/File:No_sign.svg) + +Gregory Maxwell: (Public domain, CC-BY 4.0) + + * [`ui_ok_icon.png`](http://commons.wikimedia.org/wiki/File:Yes_check.svg) + +Adrien Facélina: (LGPL v2.1+) + + * [`inventory_plus_worldedit_gui.png`](http://commons.wikimedia.org/wiki/File:Erioll_world_2.svg) + +Other files from Wikimedia Commons: + + * [`ui_gohome_icon.png` / `ui_home_icon.png` / `ui_sethome_icon.png`](http://commons.wikimedia.org/wiki/File:Home_256x256.png) (GPL v2+) + +RealBadAngel: (CC-BY-4.0) + + * Everything else. \ No newline at end of file diff --git a/Bucket_Game-branches/unified_inventory_recipe_fix-vs-211031/mods/codercore/api.lua b/Bucket_Game-branches/unified_inventory_recipe_fix-vs-211031/mods/codercore/api.lua new file mode 100644 index 0000000..c5dee5d --- /dev/null +++ b/Bucket_Game-branches/unified_inventory_recipe_fix-vs-211031/mods/codercore/api.lua @@ -0,0 +1,321 @@ +local S = function (str) return str end +local F = minetest.formspec_escape + +-- 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) + end + unified_inventory.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 + table.insert(unified_inventory.items_list, name) + local all_names = rev_aliases[name] or {} + table.insert(all_names, name) + for _, name in ipairs(all_names) do + local recipes = minetest.get_all_craft_recipes(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 unified_inventory.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 + unified_inventory.register_craft(recipe) + end + end + end + end + end + end + table.sort(unified_inventory.items_list) + unified_inventory.items_list_size = #unified_inventory.items_list + print("Unified Inventory. inventory size: "..unified_inventory.items_list_size) + for _, name in ipairs(unified_inventory.items_list) do + local def = minetest.registered_items[name] + -- Simple drops + if type(def.drop) == "string" then + local dstack = ItemStack(def.drop) + if not dstack:is_empty() and dstack:get_name() ~= name then + unified_inventory.register_craft({ + type = "digging", + items = {name}, + output = def.drop, + width = 0, + }) + + end + -- Complex drops. Yes, it's really complex! + elseif type(def.drop) == "table" then + --[[ Extract single items from the table and save them into dedicated tables + to register them later, in order to avoid duplicates. These tables counts + the total number of guaranteed drops and drops by chance (“maybes”) for each item. + For “maybes”, the final count is the theoretical maximum number of items, not + neccessarily the actual drop count. ]] + local drop_guaranteed = {} + local drop_maybe = {} + -- This is for catching an obscure corner case: If the top items table has + -- only items with rarity = 1, but max_items is set, then only the first + -- max_items will be part of the drop, any later entries are logically + -- impossible, so this variable is for keeping track of this + local max_items_left = def.drop.max_items + -- For checking whether we still encountered only guaranteed only so far; + -- for the first “maybe” item it will become false which will cause ALL + -- later items to be considered “maybes”. + -- A common idiom is: + -- { max_items 1, { items = { + -- { items={"example:1"}, rarity = 5 }, + -- { items={"example:2"}, rarity = 1 }, }}} + -- example:2 must be considered a “maybe” because max_items is set and it + -- appears after a “maybe” + local max_start = true + -- Let's iterate through the items madness! + -- Handle invalid drop entries gracefully. + local drop_items = def.drop.items or { } + for i=1,#drop_items do + if max_items_left ~= nil and max_items_left <= 0 then break end + local itit = drop_items[i] + for j=1,#itit.items do + local dstack = ItemStack(itit.items[j]) + if not dstack:is_empty() and dstack:get_name() ~= name then + local dname = dstack:get_name() + local dcount = dstack:get_count() + -- Guaranteed drops AND we are not yet in “maybe mode” + if #itit.items == 1 and itit.rarity == 1 and max_start then + if drop_guaranteed[dname] == nil then + drop_guaranteed[dname] = 0 + end + drop_guaranteed[dname] = drop_guaranteed[dname] + dcount + + if max_items_left ~= nil then + max_items_left = max_items_left - 1 + if max_items_left <= 0 then break end + end + -- Drop was a “maybe” + else + if max_items_left ~= nil then max_start = false end + if drop_maybe[dname] == nil then + drop_maybe[dname] = 0 + end + drop_maybe[dname] = drop_maybe[dname] + dcount + end + end + end + end + for itemstring, count in pairs(drop_guaranteed) do + unified_inventory.register_craft({ + type = "digging", + items = {name}, + output = itemstring .. " " .. count, + width = 0, + }) + end + for itemstring, count in pairs(drop_maybe) do + unified_inventory.register_craft({ + type = "digging_chance", + items = {name}, + output = itemstring .. " " .. count, + width = 0, + }) + end + end + end + for _, recipes in pairs(unified_inventory.crafts_for.recipe) do + for _, recipe in ipairs(recipes) do + local ingredient_items = {} + for _, spec in pairs(recipe.items) do + local matches_spec = unified_inventory.canonical_item_spec_matcher(spec) + for _, name in ipairs(unified_inventory.items_list) do + if matches_spec(name) then + ingredient_items[name] = true + end + end + end + for name, _ in pairs(ingredient_items) do + if unified_inventory.crafts_for.usage[name] == nil then + unified_inventory.crafts_for.usage[name] = {} + end + table.insert(unified_inventory.crafts_for.usage[name], recipe) + end + end + end +end) + + +-- load_home +local function load_home() + local input = io.open(unified_inventory.home_filename, "r") + if not input then + unified_inventory.home_pos = {} + return + end + while true do + local x = input:read("*n") + if not x then break end + local y = input:read("*n") + local z = input:read("*n") + local name = input:read("*l") + unified_inventory.home_pos[name:sub(2)] = {x = x, y = y, z = z} + end + io.close(input) +end +load_home() + +function unified_inventory.set_home(player, pos) + + local ds = unified_inventory.disable_set + if ds ~= nil and ds then return end + + local player_name = player:get_player_name() + unified_inventory.home_pos[player_name] = vector.round(pos) + -- save the home data from the table to the file + local output = io.open(unified_inventory.home_filename, "w") + for k, v in pairs(unified_inventory.home_pos) do + output:write(v.x.." "..v.y.." "..v.z.." "..k.."\n") + end + io.close(output) + + -- RJK: + if _G ["ocsethome"] ~= nil and + ocsethome ~= nil and + ocsethome.sethome ~= nil then + + unified_inventory.disable_set = true + ocsethome.sethome (player_name, "1") + unified_inventory.disable_set = false + end +end + +function unified_inventory.go_home(player) + local pos = unified_inventory.home_pos[player:get_player_name()] + if pos then + player:set_pos(pos) + end +end + +-- register_craft +function unified_inventory.register_craft(options) + if not options.output then + return + end + local itemstack = ItemStack(options.output) + if itemstack:is_empty() then + return + end + if options.type == "normal" and options.width == 0 then + options = { type = "shapeless", items = options.items, output = options.output, width = 0 } + end + if not unified_inventory.crafts_for.recipe[itemstack:get_name()] then + unified_inventory.crafts_for.recipe[itemstack:get_name()] = {} + end + table.insert(unified_inventory.crafts_for.recipe[itemstack:get_name()],options) +end + + +local craft_type_defaults = { + width = 3, + height = 3, + uses_crafting_grid = false, +} + + +function unified_inventory.craft_type_defaults(name, options) + if not options.description then + options.description = name + end + setmetatable(options, {__index = craft_type_defaults}) + return options +end + + +function unified_inventory.register_craft_type(name, options) + unified_inventory.registered_craft_types[name] = + unified_inventory.craft_type_defaults(name, options) +end + + +unified_inventory.register_craft_type("normal", { + description = F(S("Crafting")), + icon = "ui_craftgrid_icon.png", + width = 3, + height = 3, + get_shaped_craft_width = function (craft) return craft.width end, + dynamic_display_size = function (craft) + local w = craft.width + local h = math.ceil(table.maxn(craft.items) / craft.width) + local g = w < h and h or w + return { width = g, height = g } + end, + uses_crafting_grid = true, +}) + + +unified_inventory.register_craft_type("shapeless", { + description = F(S("Mixing")), + icon = "ui_craftgrid_icon.png", + width = 3, + height = 3, + dynamic_display_size = function (craft) + local maxn = table.maxn(craft.items) + local g = 1 + while g*g < maxn do g = g + 1 end + return { width = g, height = g } + end, + uses_crafting_grid = true, +}) + + +unified_inventory.register_craft_type("cooking", { + description = F(S("Cooking")), + icon = "default_furnace_front.png", + width = 1, + height = 1, +}) + + +unified_inventory.register_craft_type("digging", { + description = F(S("Digging")), + icon = "default_tool_steelpick.png", + width = 1, + height = 1, +}) + +unified_inventory.register_craft_type("digging_chance", { + description = "Digging (by chance)", + icon = "default_tool_steelpick.png^[transformFY.png", + width = 1, + height = 1, +}) + +function unified_inventory.register_page(name, def) + unified_inventory.pages[name] = def +end + + +function unified_inventory.register_button(name, def) + if not def.action then + def.action = function(player) + unified_inventory.set_inventory_formspec(player, name) + end + end + def.name = name + table.insert(unified_inventory.buttons, def) +end + + +function unified_inventory.is_creative(playername) + return minetest.check_player_privs(playername, {creative=true}) + or minetest.settings:get_bool("creative_mode") +end diff --git a/Bucket_Game-branches/unified_inventory_recipe_fix-vs-211031/mods/codercore/depends.txt b/Bucket_Game-branches/unified_inventory_recipe_fix-vs-211031/mods/codercore/depends.txt new file mode 100644 index 0000000..c1c449a --- /dev/null +++ b/Bucket_Game-branches/unified_inventory_recipe_fix-vs-211031/mods/codercore/depends.txt @@ -0,0 +1,6 @@ +default +creative? +sfinv? +datastorage? +farming? +ocsethome? diff --git a/Bucket_Game-branches/unified_inventory_recipe_fix-vs-211031/mods/codercore/group.lua b/Bucket_Game-branches/unified_inventory_recipe_fix-vs-211031/mods/codercore/group.lua new file mode 100644 index 0000000..518652b --- /dev/null +++ b/Bucket_Game-branches/unified_inventory_recipe_fix-vs-211031/mods/codercore/group.lua @@ -0,0 +1,127 @@ +local S = function (str) return str end + +function unified_inventory.canonical_item_spec_matcher(spec) + local specname = ItemStack(spec):get_name() + if specname:sub(1, 6) ~= "group:" then + return function (itemname) + return itemname == specname + end + end + + local group_names = specname:sub(7):split(",") + return function (itemname) + local itemdef = minetest.registered_items[itemname] + for _, group_name in ipairs(group_names) do + if (itemdef.groups[group_name] or 0) == 0 then + return false + end + end + return true + end +end + +function unified_inventory.item_matches_spec(item, spec) + local itemname = ItemStack(item):get_name() + return unified_inventory.canonical_item_spec_matcher(spec)(itemname) +end + +function unified_inventory.extract_groupnames(groupname) + local specname = ItemStack(groupname):get_name() + if specname:sub(1, 6) ~= "group:" then + return nil, 0 + end + local group_names = specname:sub(7):split(",") + return table.concat(group_names, S(" and ")), #group_names +end + +unified_inventory.registered_group_items = { + mesecon_conductor_craftable = "mesecons:wire_00000000_off", + stone = "default:cobble", + wood = "default:wood", + book = "default:book", + sand = "default:sand", + leaves = "default:leaves", + tree = "default:tree", + vessel = "vessels:glass_bottle", + wool = "wool:white", +} + +function unified_inventory.register_group_item(groupname, itemname) + unified_inventory.registered_group_items[groupname] = itemname +end + + +-- This is used when displaying craft recipes, where an ingredient is +-- specified by group rather than as a specific item. A single-item group +-- is represented by that item, with the single-item status signalled +-- in the "sole" field. If the group contains no items at all, the item +-- field will be nil. +-- +-- Within a multiple-item group, we prefer to use an item that has the +-- same specific name as the group, and if there are more than one of +-- those items we prefer the one registered for the group by a mod. +-- Among equally-preferred items, we just pick the one with the +-- lexicographically earliest name. +-- +-- The parameter to this function isn't just a single group name. +-- It may be a comma-separated list of group names. This is really a +-- "group:..." ingredient specification, minus the "group:" prefix. + +local function compute_group_item(group_name_list) + local group_names = group_name_list:split(",") + local candidate_items = {} + for itemname, itemdef in pairs(minetest.registered_items) do + if (itemdef.groups.not_in_creative_inventory or 0) == 0 then + local all = true + for _, group_name in ipairs(group_names) do + if (itemdef.groups[group_name] or 0) == 0 then + all = false + end + end + if all then table.insert(candidate_items, itemname) end + end + end + local num_candidates = #candidate_items + if num_candidates == 0 then + return {sole = true} + elseif num_candidates == 1 then + return {item = candidate_items[1], sole = true} + end + local is_group = {} + local registered_rep = {} + for _, group_name in ipairs(group_names) do + is_group[group_name] = true + local rep = unified_inventory.registered_group_items[group_name] + if rep then registered_rep[rep] = true end + end + local bestitem = "" + local bestpref = 0 + for _, item in ipairs(candidate_items) do + local pref + if registered_rep[item] then + pref = 4 + elseif string.sub(item, 1, 8) == "default:" and is_group[string.sub(item, 9)] then + pref = 3 + elseif is_group[item:gsub("^[^:]*:", "")] then + pref = 2 + else + pref = 1 + end + if pref > bestpref or (pref == bestpref and item < bestitem) then + bestitem = item + bestpref = pref + end + end + return {item = bestitem, sole = false} +end + + +local group_item_cache = {} + +function unified_inventory.get_group_item(group_name) + if not group_item_cache[group_name] then + group_item_cache[group_name] = compute_group_item(group_name) + end + return group_item_cache[group_name] +end + diff --git a/Bucket_Game-branches/unified_inventory_recipe_fix-vs-211031/mods/codercore/internal.lua b/Bucket_Game-branches/unified_inventory_recipe_fix-vs-211031/mods/codercore/internal.lua new file mode 100644 index 0000000..1e17312 --- /dev/null +++ b/Bucket_Game-branches/unified_inventory_recipe_fix-vs-211031/mods/codercore/internal.lua @@ -0,0 +1,375 @@ +local S = function (str) return str end +local F = minetest.formspec_escape + +-- This pair of encoding functions is used where variable text must go in +-- button names, where the text might contain formspec metacharacters. +-- We can escape button names for the formspec, to avoid screwing up +-- form structure overall, but they then don't get de-escaped, and so +-- the input we get back from the button contains the formspec escaping. +-- This is a game engine bug, and in the anticipation that it might be +-- fixed some day we don't want to rely on it. So for safety we apply +-- an encoding that avoids all formspec metacharacters. +function unified_inventory.mangle_for_formspec(str) + return string.gsub(str, "([^A-Za-z0-9])", function (c) return string.format("_%d_", string.byte(c)) end) +end +function unified_inventory.demangle_for_formspec(str) + return string.gsub(str, "_([0-9]+)_", function (v) return string.char(v) end) +end + +function unified_inventory.get_per_player_formspec(player_name) + local lite = unified_inventory.lite_mode and not minetest.check_player_privs(player_name, {ui_full=true}) + + local ui = {} + ui.pagecols = unified_inventory.pagecols + ui.pagerows = unified_inventory.pagerows + ui.page_y = unified_inventory.page_y + ui.formspec_y = unified_inventory.formspec_y + ui.main_button_x = unified_inventory.main_button_x + ui.main_button_y = unified_inventory.main_button_y + ui.craft_result_x = unified_inventory.craft_result_x + ui.craft_result_y = unified_inventory.craft_result_y + ui.form_header_y = unified_inventory.form_header_y + + if lite then + ui.pagecols = 4 + ui.pagerows = 6 + ui.page_y = 0.25 + ui.formspec_y = 0.47 + ui.main_button_x = 8.2 + ui.main_button_y = 6.5 + ui.craft_result_x = 2.8 + ui.craft_result_y = 3.4 + ui.form_header_y = -0.1 + end + + ui.items_per_page = ui.pagecols * ui.pagerows + return ui, lite +end + +function unified_inventory.get_formspec(player, page) + + if not player then + return "" + end + + local player_name = player:get_player_name() + local ui_peruser,draw_lite_mode = unified_inventory.get_per_player_formspec(player_name) + + unified_inventory.current_page[player_name] = page + local pagedef = unified_inventory.pages[page] + + if not pagedef then + return "" -- Invalid page name + end + + local formspec = { + "size[14,10]", + pagedef.formspec_prepend and "" or "no_prepend[]", + "background[-0.19,-0.25;14.4,10.75;ui_form_bg.png]" -- Background + } + local n = 4 + + if draw_lite_mode then + formspec[1] = "size[11,7.7]" + formspec[3] = "background[-0.19,-0.2;11.4,8.4;ui_form_bg.png]" + end + + if unified_inventory.is_creative(player_name) + and page == "craft" then + formspec[n] = "background[0,"..(ui_peruser.formspec_y + 2)..";1,1;ui_single_slot.png]" + n = n+1 + end + + local perplayer_formspec = unified_inventory.get_per_player_formspec(player_name) + local fsdata = pagedef.get_formspec(player, perplayer_formspec) + + formspec[n] = fsdata.formspec + n = n+1 + + local button_row = 0 + local button_col = 0 + + -- Main buttons + + local filtered_inv_buttons = {} + + for i, def in pairs(unified_inventory.buttons) do + if not (draw_lite_mode and def.hide_lite) then + table.insert(filtered_inv_buttons, def) + end + end + + for i, def in pairs(filtered_inv_buttons) do + + if draw_lite_mode and i > 4 then + button_row = 1 + button_col = 1 + end + + if def.type == "image" then + if (def.condition == nil or def.condition(player) == true) then + formspec[n] = "image_button[" + formspec[n+1] = ( ui_peruser.main_button_x + 0.65 * (i - 1) - button_col * 0.65 * 4) + formspec[n+2] = ","..(ui_peruser.main_button_y + button_row * 0.7)..";0.8,0.8;" + formspec[n+3] = F(def.image)..";" + formspec[n+4] = F(def.name)..";]" + formspec[n+5] = "tooltip["..F(def.name) + formspec[n+6] = ";"..(def.tooltip or "").."]" + n = n+7 + else + formspec[n] = "image[" + formspec[n+1] = ( ui_peruser.main_button_x + 0.65 * (i - 1) - button_col * 0.65 * 4) + formspec[n+2] = ","..(ui_peruser.main_button_y + button_row * 0.7)..";0.8,0.8;" + formspec[n+3] = F(def.image).."^[colorize:#808080:alpha]" + n = n+4 + + end + end + end + + if fsdata.draw_inventory ~= false then + -- Player inventory + formspec[n] = "listcolors[#00000000;#00000000]" + formspec[n+1] = "list[current_player;main;0,"..(ui_peruser.formspec_y + 3.5)..";8,4;]" + n = n+2 + end + + if fsdata.draw_item_list == false then + return table.concat(formspec, "") + end + + -- Controls to flip items pages + local start_x = 9.2 + + if not draw_lite_mode then + formspec[n] = + "image_button[" .. (start_x + 0.6 * 0) + .. ",9;.8,.8;ui_skip_backward_icon.png;start_list;]" + .. "tooltip[start_list;" .. F(S("First page")) .. "]" + + .. "image_button[" .. (start_x + 0.6 * 1) + .. ",9;.8,.8;ui_doubleleft_icon.png;rewind3;]" + .. "tooltip[rewind3;" .. F(S("Back three pages")) .. "]" + .. "image_button[" .. (start_x + 0.6 * 2) + .. ",9;.8,.8;ui_left_icon.png;rewind1;]" + .. "tooltip[rewind1;" .. F(S("Back one page")) .. "]" + + .. "image_button[" .. (start_x + 0.6 * 3) + .. ",9;.8,.8;ui_right_icon.png;forward1;]" + .. "tooltip[forward1;" .. F(S("Forward one page")) .. "]" + .. "image_button[" .. (start_x + 0.6 * 4) + .. ",9;.8,.8;ui_doubleright_icon.png;forward3;]" + .. "tooltip[forward3;" .. F(S("Forward three pages")) .. "]" + + .. "image_button[" .. (start_x + 0.6 * 5) + .. ",9;.8,.8;ui_skip_forward_icon.png;end_list;]" + .. "tooltip[end_list;" .. F(S("Last page")) .. "]" + else + formspec[n] = + "image_button[" .. (8.2 + 0.65 * 0) + .. ",5.8;.8,.8;ui_skip_backward_icon.png;start_list;]" + .. "tooltip[start_list;" .. F(S("First page")) .. "]" + .. "image_button[" .. (8.2 + 0.65 * 1) + .. ",5.8;.8,.8;ui_left_icon.png;rewind1;]" + .. "tooltip[rewind1;" .. F(S("Back one page")) .. "]" + .. "image_button[" .. (8.2 + 0.65 * 2) + .. ",5.8;.8,.8;ui_right_icon.png;forward1;]" + .. "tooltip[forward1;" .. F(S("Forward one page")) .. "]" + .. "image_button[" .. (8.2 + 0.65 * 3) + .. ",5.8;.8,.8;ui_skip_forward_icon.png;end_list;]" + .. "tooltip[end_list;" .. F(S("Last page")) .. "]" + end + n = n+1 + + -- Search box + formspec[n] = "field_close_on_enter[searchbox;false]" + n = n+1 + + if not draw_lite_mode then + formspec[n] = "field[9.5,8.325;3,1;searchbox;;" + .. F(unified_inventory.current_searchbox[player_name]) .. "]" + formspec[n+1] = "image_button[12.2,8.1;.8,.8;ui_search_icon.png;searchbutton;]" + .. "tooltip[searchbutton;" ..F(S("Search")) .. "]" + formspec[n+2] = "image_button[12.9,8.1;.8,.8;ui_reset_icon.png;searchresetbutton;]" + .. "tooltip[searchbutton;" ..F(S("Search")) .. "]" + .. "tooltip[searchresetbutton;" ..F(S("Reset search and display everything")) .. "]" + else + formspec[n] = "field[8.5,5.225;2.2,1;searchbox;;" + .. F(unified_inventory.current_searchbox[player_name]) .. "]" + formspec[n+1] = "image_button[10.3,5;.8,.8;ui_search_icon.png;searchbutton;]" + .. "tooltip[searchbutton;" ..F(S("Search")) .. "]" + formspec[n+2] = "image_button[11,5;.8,.8;ui_reset_icon.png;searchresetbutton;]" + .. "tooltip[searchbutton;" ..F(S("Search")) .. "]" + .. "tooltip[searchresetbutton;" ..F(S("Reset search and display everything")) .. "]" + end + n = n+3 + + local no_matches = S("No matching items") + if draw_lite_mode then + no_matches = S("No matches.") + end + + -- Items list + if #unified_inventory.filtered_items_list[player_name] == 0 then + formspec[n] = "label[8.2,"..ui_peruser.form_header_y..";" .. F(no_matches) .. "]" + else + local dir = unified_inventory.active_search_direction[player_name] + local list_index = unified_inventory.current_index[player_name] + local page = math.floor(list_index / (ui_peruser.items_per_page) + 1) + local pagemax = math.floor( + (#unified_inventory.filtered_items_list[player_name] - 1) + / (ui_peruser.items_per_page) + 1) + local item = {} + for y = 0, ui_peruser.pagerows - 1 do + for x = 0, ui_peruser.pagecols - 1 do + local name = unified_inventory.filtered_items_list[player_name][list_index] + local item = minetest.registered_items[name] + if item then + -- Clicked on current item: Flip crafting direction + if name == unified_inventory.current_item[player_name] then + local cdir = unified_inventory.current_craft_direction[player_name] + if cdir == "recipe" then + dir = "usage" + elseif cdir == "usage" then + dir = "recipe" + end + else + -- Default: use active search direction by default + dir = unified_inventory.active_search_direction[player_name] + end + + local button_name = "item_button_" .. dir .. "_" + .. unified_inventory.mangle_for_formspec(name) + formspec[n] = ("item_image_button[%f,%f;.81,.81;%s;%s;]"):format( + 8.2 + x * 0.7, ui_peruser.formspec_y + ui_peruser.page_y + y * 0.7, + name, button_name + ) + formspec[n + 1] = ("tooltip[%s;%s \\[%s\\]]"):format( + button_name, minetest.formspec_escape(item.description), + item.mod_origin or "??" + ) + n = n + 2 + list_index = list_index + 1 + end + end + end + + formspec [n] = "label[8.2," .. ui_peruser.form_header_y +.. ";Page " .. page .. " of " .. pagemax .. "]" + end + n = n+1 + + if unified_inventory.activefilter[player_name] ~= "" then + formspec[n] = "label[8.2,"..(ui_peruser.form_header_y + 0.4)..";" .. F(S("Filter")) .. ":]" + formspec[n+1] = "label[9.1,"..(ui_peruser.form_header_y + 0.4)..";"..F(unified_inventory.activefilter[player_name]).."]" + end + return table.concat(formspec, "") +end + +function unified_inventory.set_inventory_formspec(player, page) + if player then + player:set_inventory_formspec(unified_inventory.get_formspec(player, page)) + end +end + +--apply filter to the inventory list (create filtered copy of full one) +function unified_inventory.apply_filter(player, filter, search_dir) + if not player then + return false + end + local player_name = player:get_player_name() + local lfilter = string.lower(filter) + local ffilter + if lfilter:sub(1, 6) == "group:" then + local groups = lfilter:sub(7):split(",") + ffilter = function(name, def) + for _, group in ipairs(groups) do + if not def.groups[group] + or def.groups[group] <= 0 then + return false + end + end + return true + end + else + ffilter = function(name, def) + local lname = string.lower(name) + local ldesc = string.lower(def.description) + return string.find(lname, lfilter, 1, true) or string.find(ldesc, lfilter, 1, true) + end + end + unified_inventory.filtered_items_list[player_name]={} + for name, def in pairs(minetest.registered_items) do + if (not def.groups.not_in_creative_inventory + or def.groups.not_in_creative_inventory == 0) + and def.description + and def.description ~= "" + and ffilter(name, def) then + table.insert(unified_inventory.filtered_items_list[player_name], name) + end + end + table.sort(unified_inventory.filtered_items_list[player_name]) + unified_inventory.filtered_items_list_size[player_name] = #unified_inventory.filtered_items_list[player_name] + unified_inventory.current_index[player_name] = 1 + unified_inventory.activefilter[player_name] = filter + unified_inventory.active_search_direction[player_name] = search_dir + unified_inventory.set_inventory_formspec(player, + unified_inventory.current_page[player_name]) +end + +function unified_inventory.items_in_group(groups) + local items = {} + for name, item in pairs(minetest.registered_items) do + for _, group in pairs(groups:split(',')) do + if item.groups[group] then + table.insert(items, name) + end + end + end + return items +end + +function unified_inventory.sort_inventory(inv) + local inlist = inv:get_list("main") + local typecnt = {} + local typekeys = {} + for _, st in ipairs(inlist) do + if not st:is_empty() then + local n = st:get_name() + local w = st:get_wear() + local m = st:get_metadata() + local k = string.format("%s %05d %s", n, w, m) + if not typecnt[k] then + typecnt[k] = { + name = n, + wear = w, + metadata = m, + stack_max = st:get_stack_max(), + count = 0, + } + table.insert(typekeys, k) + end + typecnt[k].count = typecnt[k].count + st:get_count() + end + end + table.sort(typekeys) + local outlist = {} + for _, k in ipairs(typekeys) do + local tc = typecnt[k] + while tc.count > 0 do + local c = math.min(tc.count, tc.stack_max) + table.insert(outlist, ItemStack({ + name = tc.name, + wear = tc.wear, + metadata = tc.metadata, + count = c, + })) + tc.count = tc.count - c + end + end + if #outlist > #inlist then return end + while #outlist < #inlist do + table.insert(outlist, ItemStack(nil)) + end + inv:set_list("main", outlist) +end diff --git a/Bucket_Game-branches/unified_inventory_recipe_fix-vs-211031/mods/codercore/oldcoder.txt b/Bucket_Game-branches/unified_inventory_recipe_fix-vs-211031/mods/codercore/oldcoder.txt new file mode 100644 index 0000000..336f8e1 --- /dev/null +++ b/Bucket_Game-branches/unified_inventory_recipe_fix-vs-211031/mods/codercore/oldcoder.txt @@ -0,0 +1,27 @@ +Name: unified_inventory +Source: Fork of upstream mod - Do not replace +License: See "LICENSE.txt" + +---------------------------------------------------------------------- + +1. This is a fork of an upstream mod. The starting point was obtained +initially as follows: + + rm -fr unified_inventory + git clone https://github.com/minetest-mods/unified_inventory.git + cd unified_inventory + git reset --hard ca6d9a10df5110fd75d49785adf690ae270d5a31 + +Forked after: commit indicated above + +---------------------------------------------------------------------- + +2. Partial list of changes: + +2a. Fixed a few cases where "@1" or "@2" was printed instead of the +correct output. + +2b. Modified the mod so that it stays synced with "ocsethome". + +2c. Removed "bags" code, which seems to be crashy. "prestibags" mod +has been added to the "_game" as a substitute for the "bags" feature. diff --git a/Bucket_Game-branches/unified_inventory_recipe_fix-vs-211031/mods/codercore/register.lua b/Bucket_Game-branches/unified_inventory_recipe_fix-vs-211031/mods/codercore/register.lua new file mode 100644 index 0000000..278acfb --- /dev/null +++ b/Bucket_Game-branches/unified_inventory_recipe_fix-vs-211031/mods/codercore/register.lua @@ -0,0 +1,489 @@ +local S = function (str) return str end +local NS = function(s) return s end +local F = minetest.formspec_escape + +minetest.register_privilege("creative", { + description = S("Can use the creative inventory"), + give_to_singleplayer = false, +}) + +minetest.register_privilege("ui_full", { + description = S("Forces Unified Inventory to be displayed in Full mode if Lite mode is configured globally"), + give_to_singleplayer = false, +}) + + +local trash = minetest.create_detached_inventory("trash", { + --allow_put = function(inv, listname, index, stack, player) + -- if unified_inventory.is_creative(player:get_player_name()) then + -- return stack:get_count() + -- else + -- return 0 + -- end + --end, + on_put = function(inv, listname, index, stack, player) + inv:set_stack(listname, index, nil) + local player_name = player:get_player_name() + minetest.sound_play("trash", {to_player=player_name, gain = 1.0}) + end, +}) +trash:set_size("main", 1) + +unified_inventory.register_button("craft", { + type = "image", + image = "ui_craft_icon.png", + tooltip = S("Crafting Grid") +}) + +unified_inventory.register_button("craftguide", { + type = "image", + image = "ui_craftguide_icon.png", + tooltip = S("Crafting Guide") +}) + +unified_inventory.register_button("home_gui_set", { + type = "image", + image = "ui_sethome_icon.png", + tooltip = S("Set home position"), + hide_lite=true, + action = function(player) + local player_name = player:get_player_name() + if minetest.check_player_privs(player_name, {home=true}) then + unified_inventory.set_home(player, player:get_pos()) + local home = unified_inventory.home_pos[player_name] + if home ~= nil then + minetest.sound_play("dingdong", + {to_player=player_name, gain = 1.0}) + minetest.chat_send_player(player_name, + "Home position set to: " .. minetest.pos_to_string (home)) + end + else + minetest.chat_send_player(player_name, + S("You don't have the \"home\" privilege!")) + unified_inventory.set_inventory_formspec(player, unified_inventory.current_page[player_name]) + end + end, + condition = function(player) + return minetest.check_player_privs(player:get_player_name(), {home=true}) + end, +}) + +unified_inventory.register_button("home_gui_go", { + type = "image", + image = "ui_gohome_icon.png", + tooltip = S("Go home"), + hide_lite=true, + action = function(player) + local player_name = player:get_player_name() + if minetest.check_player_privs(player_name, {home=true}) then + minetest.sound_play("teleport", + {to_player=player:get_player_name(), gain = 1.0}) + unified_inventory.go_home(player) + else + minetest.chat_send_player(player_name, + S("You don't have the \"home\" privilege!")) + unified_inventory.set_inventory_formspec(player, unified_inventory.current_page[player_name]) + end + end, + condition = function(player) + return minetest.check_player_privs(player:get_player_name(), {home=true}) + end, +}) + +unified_inventory.register_button("misc_set_day", { + type = "image", + image = "ui_sun_icon.png", + tooltip = S("Set time to day"), + hide_lite=true, + action = function(player) + local player_name = player:get_player_name() + if minetest.check_player_privs(player_name, {settime=true}) then + minetest.sound_play("birds", + {to_player=player_name, gain = 1.0}) + minetest.set_timeofday((6000 % 24000) / 24000) + minetest.chat_send_player(player_name, + S("Time of day set to 6am")) + else + minetest.chat_send_player(player_name, + S("You don't have the settime privilege!")) + unified_inventory.set_inventory_formspec(player, unified_inventory.current_page[player_name]) + end + end, + condition = function(player) + return minetest.check_player_privs(player:get_player_name(), {settime=true}) + end, +}) + +unified_inventory.register_button("misc_set_night", { + type = "image", + image = "ui_moon_icon.png", + tooltip = S("Set time to night"), + hide_lite=true, + action = function(player) + local player_name = player:get_player_name() + if minetest.check_player_privs(player_name, {settime=true}) then + minetest.sound_play("owl", + {to_player=player_name, gain = 1.0}) + minetest.set_timeofday((21000 % 24000) / 24000) + minetest.chat_send_player(player_name, + S("Time of day set to 9pm")) + else + minetest.chat_send_player(player_name, + S("You don't have the settime privilege!")) + unified_inventory.set_inventory_formspec(player, unified_inventory.current_page[player_name]) + end + end, + condition = function(player) + return minetest.check_player_privs(player:get_player_name(), {settime=true}) + end, +}) + +unified_inventory.register_button("clear_inv", { + type = "image", + image = "ui_trash_icon.png", + tooltip = S("Clear inventory"), + action = function(player) + local player_name = player:get_player_name() + if not unified_inventory.is_creative(player_name) then + minetest.chat_send_player(player_name, + S("This button has been disabled outside" + .." of creative mode to prevent" + .." accidental inventory trashing." + .."\nUse the trash slot instead.")) + unified_inventory.set_inventory_formspec(player, unified_inventory.current_page[player_name]) + return + end + player:get_inventory():set_list("main", {}) + minetest.chat_send_player(player_name, S('Inventory cleared!')) + minetest.sound_play("trash_all", + {to_player=player_name, gain = 1.0}) + end, + condition = function(player) + return unified_inventory.is_creative(player:get_player_name()) + end, +}) + +unified_inventory.register_page("craft", { + get_formspec = function(player, perplayer_formspec) + + local formspecy = perplayer_formspec.formspec_y + local formheadery = perplayer_formspec.form_header_y + + local player_name = player:get_player_name() + local formspec = "background[2,"..formspecy..";6,3;ui_crafting_form.png]" + formspec = formspec.."background[0,"..(formspecy + 3.5)..";8,4;ui_main_inventory.png]" + formspec = formspec.."label[0,"..formheadery..";" ..F(S("Crafting")).."]" + formspec = formspec.."listcolors[#00000000;#00000000]" + formspec = formspec.."list[current_player;craftpreview;6,"..formspecy..";1,1;]" + formspec = formspec.."list[current_player;craft;2,"..formspecy..";3,3;]" + if unified_inventory.trash_enabled or unified_inventory.is_creative(player_name) or minetest.get_player_privs(player_name).give then + formspec = formspec.."label[7,"..(formspecy + 1.5)..";" .. F(S("Trash:")) .. "]" + formspec = formspec.."background[7,"..(formspecy + 2)..";1,1;ui_single_slot.png]" + formspec = formspec.."list[detached:trash;main;7,"..(formspecy + 2)..";1,1;]" + end + formspec = formspec.."listring[current_name;craft]" + formspec = formspec.."listring[current_player;main]" + if unified_inventory.is_creative(player_name) then + formspec = formspec.."label[0,"..(formspecy + 1.5)..";" .. F(S("Refill:")) .. "]" + formspec = formspec.."list[detached:"..F(player_name).."refill;main;0,"..(formspecy +2)..";1,1;]" + end + return {formspec=formspec} + end, +}) + +-- stack_image_button(): generate a form button displaying a stack of items +-- +-- The specified item may be a group. In that case, the group will be +-- represented by some item in the group, along with a flag indicating +-- that it's a group. If the group contains only one item, it will be +-- treated as if that item had been specified directly. + +local function stack_image_button(x, y, w, h, buttonname_prefix, item) + local name = item:get_name() + local count = item:get_count() + local show_is_group = false + local displayitem = name.." "..count + local selectitem = name + if name:sub(1, 6) == "group:" then + local group_name = name:sub(7) + local group_item = unified_inventory.get_group_item(group_name) + show_is_group = not group_item.sole + displayitem = group_item.item or "unknown" + selectitem = group_item.sole and displayitem or name + end + local label = show_is_group and "G" or "" + local buttonname = F(buttonname_prefix..unified_inventory.mangle_for_formspec(selectitem)) + local button = string.format("item_image_button[%f,%f;%f,%f;%s;%s;%s]", + x, y, w, h, + F(displayitem), buttonname, label) + if show_is_group then + local groupstring, andcount = unified_inventory.extract_groupnames(name) + local grouptip + if andcount == 1 then + grouptip = "Any item belonging to the " .. groupstring .. " group" + elseif andcount > 1 then + grouptip = "Any item belonging to the groups " .. groupstring + end + grouptip = F(grouptip) + if andcount >= 1 then + button = button .. string.format("tooltip[%s;%s]", buttonname, grouptip) + end + end + return button +end + +local recipe_text = { + recipe = NS("Recipe @1 of @2"), + usage = NS("Usage @1 of @2"), +} +local no_recipe_text = { + recipe = S("No recipes"), + usage = S("No usages"), +} +local role_text = { + recipe = S("Result"), + usage = S("Ingredient"), +} +local next_alt_text = { + recipe = S("Show next recipe"), + usage = S("Show next usage"), +} +local prev_alt_text = { + recipe = S("Show previous recipe"), + usage = S("Show previous usage"), +} +local other_dir = { + recipe = "usage", + usage = "recipe", +} + +unified_inventory.register_page("craftguide", { + get_formspec = function(player, perplayer_formspec) + + local formspecy = perplayer_formspec.formspec_y + local formheadery = perplayer_formspec.form_header_y + local craftresultx = perplayer_formspec.craft_result_x + local craftresulty = perplayer_formspec.craft_result_y + + local player_name = player:get_player_name() + local player_privs = minetest.get_player_privs(player_name) + local fs = { + "background[0,"..(formspecy + 3.5)..";8,4;ui_main_inventory.png]", + "label[0,"..formheadery..";" .. F(S("Crafting Guide")) .. "]", + "listcolors[#00000000;#00000000]" + } + local item_name = unified_inventory.current_item[player_name] + if not item_name then + return { formspec = table.concat(fs) } + end + + local item_name_shown + if minetest.registered_items[item_name] + and minetest.registered_items[item_name].description then + item_name_shown = S("@1 (@2)", + minetest.registered_items[item_name].description, item_name) + else + item_name_shown = item_name + end + + local dir = unified_inventory.current_craft_direction[player_name] + local rdir = dir == "recipe" and "usage" or "recipe" + + local crafts = unified_inventory.crafts_for[dir][item_name] + local alternate = unified_inventory.alternate[player_name] + local alternates, craft + if crafts and #crafts > 0 then + alternates = #crafts + craft = crafts[alternate] + end + local has_give = player_privs.give or unified_inventory.is_creative(player_name) + + fs[#fs + 1] = "background[0.5,"..(formspecy + 0.2)..";8,3;ui_craftguide_form.png]" + fs[#fs + 1] = string.format("textarea[%f,%f;10,1;;%s: %s;]", + craftresultx, craftresulty, F(role_text[dir]), item_name_shown) + fs[#fs + 1] = stack_image_button(0, formspecy, 1.1, 1.1, + "item_button_" .. rdir .. "_", ItemStack(item_name)) + + if not craft then + -- No craft recipes available for this item. + fs[#fs + 1] = "label[5.5,"..(formspecy + 2.35)..";" + .. F(no_recipe_text[dir]) .. "]" + local no_pos = dir == "recipe" and 4.5 or 6.5 + local item_pos = dir == "recipe" and 6.5 or 4.5 + fs[#fs + 1] = "image["..no_pos..","..formspecy..";1.1,1.1;ui_no.png]" + fs[#fs + 1] = stack_image_button(item_pos, formspecy, 1.1, 1.1, + "item_button_" .. other_dir[dir] .. "_", ItemStack(item_name)) + if has_give then + fs[#fs + 1] = "label[0," .. (formspecy + 2.10) .. ";" .. F(S("Give me:")) .. "]" + .. "button[0, " .. (formspecy + 2.7) .. ";0.6,0.5;craftguide_giveme_1;1]" + .. "button[0.6," .. (formspecy + 2.7) .. ";0.7,0.5;craftguide_giveme_10;10]" + .. "button[1.3," .. (formspecy + 2.7) .. ";0.8,0.5;craftguide_giveme_99;99]" + end + return { formspec = table.concat(fs) } + end + + local craft_type = unified_inventory.registered_craft_types[craft.type] or + unified_inventory.craft_type_defaults(craft.type, {}) + if craft_type.icon then + fs[#fs + 1] = string.format("image[%f,%f;%f,%f;%s]", + 5.7, (formspecy + 0.05), 0.5, 0.5, craft_type.icon) + end + fs[#fs + 1] = "label[5.5,"..(formspecy + 1)..";" .. F(craft_type.description).."]" + fs[#fs + 1] = stack_image_button(6.5, formspecy, 1.1, 1.1, + "item_button_usage_", ItemStack(craft.output)) + + local display_size = craft_type.dynamic_display_size + and craft_type.dynamic_display_size(craft) + or { width = craft_type.width, height = craft_type.height } + local craft_width = craft_type.get_shaped_craft_width + and craft_type.get_shaped_craft_width(craft) + or display_size.width + + -- This keeps recipes aligned to the right, + -- so that they're close to the arrow. + local xoffset = 5.5 + -- Offset factor for crafting grids with side length > 4 + local of = (3/math.max(3, math.max(display_size.width, display_size.height))) + local od = 0 + -- Minimum grid size at which size optimazation measures kick in + local mini_craft_size = 6 + if display_size.width >= mini_craft_size then + od = math.max(1, display_size.width - 2) + xoffset = xoffset - 0.1 + end + -- Size modifier factor + local sf = math.min(1, of * (1.05 + 0.05*od)) + -- Button size + local bsize_h = 1.1 * sf + local bsize_w = bsize_h + if display_size.width >= mini_craft_size then + bsize_w = 1.175 * sf + end + if (bsize_h > 0.35 and display_size.width) then + for y = 1, display_size.height do + for x = 1, display_size.width do + local item + if craft and x <= craft_width then + item = craft.items[(y-1) * craft_width + x] + end + -- Flipped x, used to build formspec buttons from right to left + local fx = display_size.width - (x-1) + -- x offset, y offset + local xof = (fx-1) * of + of + local yof = (y-1) * of + 1 + if item then + fs[#fs + 1] = stack_image_button( + xoffset - xof, formspecy - 1 + yof, bsize_w, bsize_h, + "item_button_recipe_", + ItemStack(item)) + else + -- Fake buttons just to make grid + fs[#fs + 1] = string.format("image_button[%f,%f;%f,%f;ui_blank_image.png;;]", + xoffset - xof, formspecy - 1 + yof, bsize_w, bsize_h) + end + end + end + else + -- Error + fs[#fs + 1] = string.format("label[2,%f;%s]", + formspecy, F(S("This recipe is too\nlarge to be displayed."))) + end + + if craft_type.uses_crafting_grid and display_size.width <= 3 then + fs[#fs + 1] = "label[0," .. (formspecy + 0.9) .. ";" .. F(S("To craft grid:")) .. "]" + .. "button[0, " .. (formspecy + 1.5) .. ";0.6,0.5;craftguide_craft_1;1]" + .. "button[0.6," .. (formspecy + 1.5) .. ";0.7,0.5;craftguide_craft_10;10]" + .. "button[1.3," .. (formspecy + 1.5) .. ";0.8,0.5;craftguide_craft_max;" .. F(S("All")) .. "]" + end + if has_give then + fs[#fs + 1] = "label[0," .. (formspecy + 2.1) .. ";" .. F(S("Give me:")) .. "]" + .. "button[0, " .. (formspecy + 2.7) .. ";0.6,0.5;craftguide_giveme_1;1]" + .. "button[0.6," .. (formspecy + 2.7) .. ";0.7,0.5;craftguide_giveme_10;10]" + .. "button[1.3," .. (formspecy + 2.7) .. ";0.8,0.5;craftguide_giveme_99;99]" + end + + if alternates and alternates > 1 then + fs[#fs + 1] = "label[5.5," .. (formspecy + 1.6) .. ";" + .. F(S(recipe_text[dir], alternate, alternates)) .. "]" + .. "image_button[5.5," .. (formspecy + 2) .. ";1,1;ui_left_icon.png;alternate_prev;]" + .. "image_button[6.5," .. (formspecy + 2) .. ";1,1;ui_right_icon.png;alternate;]" + .. "tooltip[alternate_prev;" .. F(prev_alt_text[dir]) .. "]" + .. "tooltip[alternate;" .. F(next_alt_text[dir]) .. "]" + end + return { formspec = table.concat(fs) } + end, +}) + +local function craftguide_giveme(player, formname, fields) + local player_name = player:get_player_name() + local player_privs = minetest.get_player_privs(player_name) + if not player_privs.give and + not unified_inventory.is_creative(player_name) then + minetest.log("action", "[unified_inventory] Denied give action to player " .. + player_name) + return + end + + local amount + for k, v in pairs(fields) do + amount = k:match("craftguide_giveme_(.*)") + if amount then break end + end + + amount = tonumber(amount) or 0 + if amount == 0 then return end + + local output = unified_inventory.current_item[player_name] + if (not output) or (output == "") then return end + + local player_inv = player:get_inventory() + + player_inv:add_item("main", {name = output, count = amount}) +end + +local function craftguide_craft(player, formname, fields) + local amount + for k, v in pairs(fields) do + amount = k:match("craftguide_craft_(.*)") + if amount then break end + end + if not amount then return end + + amount = tonumber(amount) or -1 -- fallback for "all" + if amount == 0 or amount < -1 or amount > 99 then return end + + local player_name = player:get_player_name() + + local output = unified_inventory.current_item[player_name] or "" + if output == "" then return end + + local crafts = unified_inventory.crafts_for[ + unified_inventory.current_craft_direction[player_name]][output] or {} + if #crafts == 0 then return end + + local alternate = unified_inventory.alternate[player_name] + + local craft = crafts[alternate] + if craft.width > 3 then return end + + unified_inventory.craftguide_match_craft(player, "main", "craft", craft, amount) + + unified_inventory.set_inventory_formspec(player, "craft") +end + +minetest.register_on_player_receive_fields(function(player, formname, fields) + if formname ~= "" then + return + end + + for k, v in pairs(fields) do + if k:match("craftguide_craft_") then + craftguide_craft(player, formname, fields) + return + end + if k:match("craftguide_giveme_") then + craftguide_giveme(player, formname, fields) + return + end + end +end) diff --git a/Bucket_Game-branches/unified_inventory_recipe_fix-vs-211031/mods/codercore/waypoints.lua b/Bucket_Game-branches/unified_inventory_recipe_fix-vs-211031/mods/codercore/waypoints.lua new file mode 100644 index 0000000..a448f88 --- /dev/null +++ b/Bucket_Game-branches/unified_inventory_recipe_fix-vs-211031/mods/codercore/waypoints.lua @@ -0,0 +1,247 @@ +local S = function (str) return str end +local F = minetest.formspec_escape + +local hud_colors = { + {"#FFFFFF", 0xFFFFFF, S("White")}, + {"#DBBB00", 0xf1d32c, S("Yellow")}, + {"#DD0000", 0xDD0000, S("Red")}, + {"#2cf136", 0x2cf136, S("Green")}, + {"#2c4df1", 0x2c4df1, S("Blue")}, +} + +local hud_colors_max = #hud_colors + +-- Stores temporary player data (persists until player leaves) +local waypoints_temp = {} + +unified_inventory.register_page("waypoints", { + get_formspec = function(player) + local player_name = player:get_player_name() + + -- build a "fake" temp entry if the server took too long + -- during sign-on and returned an empty entry + if not waypoints_temp[player_name] then waypoints_temp[player_name] = {hud = 1} end + + local waypoints = datastorage.get(player_name, "waypoints") + local formspec = "background[0,4.5;8,4;ui_main_inventory.png]" .. + "image[0,0;1,1;ui_waypoints_icon.png]" .. + "label[1,0;" .. F(S("Waypoints")) .. "]" + + -- Tabs buttons: + for i = 1, 5, 1 do + formspec = formspec .. + "image_button[0.0," .. 0.2 + i * 0.7 .. ";.8,.8;" .. + (i == waypoints.selected and "ui_blue_icon_background.png^" or "") .. + "ui_" .. i .. "_icon.png;" .. + "select_waypoint" .. i .. ";]" .. + "tooltip[select_waypoint" .. i .. ";" + .. S("Select Waypoint #@1", i).."]" + end + + local i = waypoints.selected or 1 + local waypoint = waypoints[i] or {} + local temp = waypoints_temp[player_name][i] or {} + local default_name = S("Waypoint @1", i) + + -- Main buttons: + formspec = formspec .. + "image_button[4.5,3.7;.8,.8;".. + "ui_waypoint_set_icon.png;".. + "set_waypoint"..i..";]".. + "tooltip[set_waypoint" .. i .. ";" + .. F(S("Set waypoint to current location")).."]" + + formspec = formspec .. + "image_button[5.2,3.7;.8,.8;".. + (waypoint.active and "ui_on_icon.png" or "ui_off_icon.png")..";".. + "toggle_waypoint"..i..";]".. + "tooltip[toggle_waypoint" .. i .. ";" + .. F(S("Make waypoint @1", + waypoint.active and S("invisible") or S("visible"))).."]" + + formspec = formspec .. + "image_button[5.9,3.7;.8,.8;".. + (waypoint.display_pos and "ui_green_icon_background.png" or "ui_red_icon_background.png").."^ui_xyz_icon.png;".. + "toggle_display_pos" .. i .. ";]".. + "tooltip[toggle_display_pos" .. i .. ";" + .. F(S("@1 display of waypoint coordinates", + waypoint.display_pos and S("Disable") or S("Enable"))) .."]" + + formspec = formspec .. + "image_button[6.6,3.7;.8,.8;".. + "ui_circular_arrows_icon.png;".. + "toggle_color"..i..";]".. + "tooltip[toggle_color" .. i .. ";" + .. F(S("Change color of waypoint display")).."]" + + formspec = formspec .. + "image_button[7.3,3.7;.8,.8;".. + "ui_pencil_icon.png;".. + "rename_waypoint"..i..";]".. + "tooltip[rename_waypoint" .. i .. ";" + .. F(S("Edit waypoint name")).."]" + + -- Waypoint's info: + if waypoint.active then + formspec = formspec .. "label[1,0.8;"..F(S("Waypoint active")).."]" + else + formspec = formspec .. "label[1,0.8;"..F(S("Waypoint inactive")).."]" + end + + if temp.edit then + formspec = formspec .. + "field[1.3,3.2;6,.8;rename_box" .. i .. ";;" + ..(waypoint.name or default_name).."]" .. + "image_button[7.3,2.9;.8,.8;".. + "ui_ok_icon.png;".. + "confirm_rename"..i.. ";]".. + "tooltip[confirm_rename" .. i .. ";" + .. F(S("Finish editing")).."]" + end + + formspec = formspec .. "label[1,1.3;"..F(S("World position"))..": " .. + minetest.pos_to_string(waypoint.world_pos or vector.new()) .. "]" .. + "label[1,1.8;"..F(S("Name"))..": ".. (waypoint.name or default_name) .. "]" .. + "label[1,2.3;"..F(S("HUD text color"))..": " .. + hud_colors[waypoint.color or 1][3] .. "]" + + return {formspec=formspec} + end, +}) + +unified_inventory.register_button("waypoints", { + type = "image", + image = "ui_waypoints_icon.png", + tooltip = S("Waypoints"), + hide_lite=true +}) + +local function update_hud(player, waypoints, temp, i) + local waypoint = waypoints[i] + if not waypoint then return end + temp[i] = temp[i] or {} + temp = temp[i] + local pos = waypoint.world_pos or vector.new() + local name + if waypoint.display_pos then + name = minetest.pos_to_string(pos) + if waypoint.name then + name = name..", "..waypoint.name + end + else + name = waypoint.name or "Waypoint "..i + end + if temp.hud then + player:hud_remove(temp.hud) + end + if waypoint.active then + temp.hud = player:hud_add({ + hud_elem_type = "waypoint", + number = hud_colors[waypoint.color or 1][2] , + name = name, + text = "m", + world_pos = pos + }) + else + temp.hud = nil + end +end + +minetest.register_on_player_receive_fields(function(player, formname, fields) + if formname ~= "" then return end + + local player_name = player:get_player_name() + local update_formspec = false + local need_update_hud = false + local hit = false + + local waypoints = datastorage.get(player_name, "waypoints") + local temp = waypoints_temp[player_name] + for i = 1, 5, 1 do + if fields["select_waypoint"..i] then + hit = true + waypoints.selected = i + update_formspec = true + end + + if fields["toggle_waypoint"..i] then + hit = true + waypoints[i] = waypoints[i] or {} + waypoints[i].active = not (waypoints[i].active) + need_update_hud = true + update_formspec = true + end + + if fields["set_waypoint"..i] then + hit = true + local pos = player:get_pos() + pos.x = math.floor(pos.x) + pos.y = math.floor(pos.y) + pos.z = math.floor(pos.z) + waypoints[i] = waypoints[i] or {} + waypoints[i].world_pos = pos + need_update_hud = true + update_formspec = true + end + + if fields["rename_waypoint"..i] then + hit = true + temp[i] = temp[i] or {} + temp[i].edit = true + update_formspec = true + end + + if fields["toggle_display_pos"..i] then + hit = true + waypoints[i] = waypoints[i] or {} + waypoints[i].display_pos = not waypoints[i].display_pos + need_update_hud = true + update_formspec = true + end + + if fields["toggle_color"..i] then + hit = true + waypoints[i] = waypoints[i] or {} + local color = waypoints[i].color or 1 + color = color + 1 + if color > hud_colors_max then + color = 1 + end + waypoints[i].color = color + need_update_hud = true + update_formspec = true + end + + if fields["confirm_rename"..i] then + hit = true + waypoints[i] = waypoints[i] or {} + temp[i].edit = false + waypoints[i].name = fields["rename_box"..i] + need_update_hud = true + update_formspec = true + end + if need_update_hud then + update_hud(player, waypoints, temp, i) + end + if update_formspec then + unified_inventory.set_inventory_formspec(player, "waypoints") + end + if hit then return end + end +end) + + +minetest.register_on_joinplayer(function(player) + local player_name = player:get_player_name() + local waypoints = datastorage.get(player_name, "waypoints") + local temp = {} + waypoints_temp[player_name] = temp + for i = 1, 5 do + update_hud(player, waypoints, temp, i) + end +end) + +minetest.register_on_leaveplayer(function(player) + waypoints_temp[player:get_player_name()] = nil +end) +