]> git.lizzy.rs Git - minetest.git/commitdiff
DevTest: `chest_of_everything` mod: Add search, bag, improve formspec (#13064)
authorWuzzy <Wuzzy@disroot.org>
Mon, 9 Jan 2023 20:40:41 +0000 (21:40 +0100)
committerGitHub <noreply@github.com>
Mon, 9 Jan 2023 20:40:41 +0000 (21:40 +0100)
games/devtest/mods/chest_of_everything/init.lua
games/devtest/mods/chest_of_everything/mod.conf
games/devtest/mods/chest_of_everything/textures/chest_of_everything_bag.png [new file with mode: 0644]
games/devtest/mods/give_initial_stuff/init.lua

index 11bc93d212b25f5f18e1dc01828e44e6169d6428..ece236f224beed435a9d84204b1aba113d5b6b21 100644 (file)
 local F = minetest.formspec_escape
+local S = minetest.get_translator("chest_of_everything")
 
--- Create a detached inventory
-local inv_everything = minetest.create_detached_inventory("everything", {
-       allow_move = function(inv, from_list, from_index, to_list, to_index, count, player)
-               return 0
-       end,
-       allow_put = function(inv, listname, index, stack, player)
-               return 0
-       end,
-       allow_take = function(inv, listname, index, stack, player)
-               return -1
-       end,
-})
-local inv_trash = minetest.create_detached_inventory("trash", {
-       allow_take = function(inv, listname, index, stack, player)
-               return 0
-       end,
-       allow_move = function(inv, from_list, from_index, to_list, to_index, count, player)
-               return 0
-       end,
-       on_put = function(inv, listname, index, stack, player)
-               inv:set_list("main", {})
-       end,
-})
-inv_trash:set_size("main", 1)
-
-local max_page = 1
-
-local function get_chest_formspec(page)
-       local start = 0 + (page-1)*32
-       return "size[8,9]"..
-       "list[detached:everything;main;0,0;8,4;"..start.."]"..
-       "list[current_player;main;0,5;8,4;]" ..
-       "label[6,4;Trash:]" ..
-       "list[detached:trash;main;7,4;1,1]" ..
-       "button[0,4;1,1;chest_of_everything_prev;"..F("<").."]"..
-       "button[1,4;1,1;chest_of_everything_next;"..F(">").."]"..
-       "label[2,4;"..F("Page: "..page).."]"..
-       "listring[detached:everything;main]"..
+local detached_inventories = {}
+
+-- Per-player lists (indexed by player name)
+local current_pages = {} -- current page number
+local current_max_pages = {} -- current max. page number
+local current_searches = {} -- current search string
+
+local SLOTS_W = 10
+local SLOTS_H = 5
+local SLOTS = SLOTS_W * SLOTS_H
+
+-- This determines how the items are sorted
+-- "by_type": Sort by item type (tool/craftitem/node/"chest_of_everything" items), then alphabetically by itemstring
+-- "abc": Alphabetically by itemstring
+local SORT_MODE = "by_type"
+
+local all_items_list -- cached list of all items
+
+-- Create detached inventories
+local function add_detached_inventories(player)
+       local name = player:get_player_name()
+       local inv_items = minetest.create_detached_inventory("chest_of_everything_items_"..name, {
+               allow_move = function(inv, from_list, from_index, to_list, to_index, count, player)
+                       return 0
+               end,
+               allow_put = function(inv, listname, index, stack, player)
+                       return 0
+               end,
+               allow_take = function(inv, listname, index, stack, player)
+                       return -1
+               end,
+       }, name)
+       local inv_trash = minetest.create_detached_inventory("chest_of_everything_trash_"..name, {
+               allow_take = function(inv, listname, index, stack, player)
+                       return 0
+               end,
+               allow_move = function(inv, from_list, from_index, to_list, to_index, count, player)
+                       return 0
+               end,
+               on_put = function(inv, listname, index, stack, player)
+                       inv:set_list(listname, {})
+               end,
+       }, name)
+       inv_trash:set_size("main", 1)
+       detached_inventories[name] = { items = inv_items, trash = inv_trash }
+end
+
+local sort_items_by_type = function(item1, item2)
+       --[[ Sort items in this order:
+       * Bag of Everything
+       * Chest of Everything
+       * Test tools
+       * Other tools
+       * Craftitems
+       * Other items
+       * Items from the 'broken' mod
+       * Dummy items ]]
+       local def1 = minetest.registered_items[item1]
+       local def2 = minetest.registered_items[item2]
+       local tool1 = def1.type == "tool"
+       local tool2 = def2.type == "tool"
+       local testtool1 = minetest.get_item_group(item1, "testtool") == 1
+       local testtool2 = minetest.get_item_group(item2, "testtool") == 1
+       local dummy1 = minetest.get_item_group(item1, "dummy") == 1
+       local dummy2 = minetest.get_item_group(item2, "dummy") == 1
+       local broken1 = def1.mod_origin == "broken"
+       local broken2 = def2.mod_origin == "broken"
+       local craftitem1 = def1.type == "craft"
+       local craftitem2 = def2.type == "craft"
+       if item1 == "chest_of_everything:bag" then
+               return true
+       elseif item2 == "chest_of_everything:bag" then
+               return false
+       elseif item1 == "chest_of_everything:chest" then
+               return true
+       elseif item2 == "chest_of_everything:chest" then
+               return false
+       elseif dummy1 and not dummy2 then
+               return false
+       elseif not dummy1 and dummy2 then
+               return true
+       elseif broken1 and not broken2 then
+               return false
+       elseif not broken1 and broken2 then
+               return true
+       elseif testtool1 and not testtool2 then
+               return true
+       elseif not testtool1 and testtool2 then
+               return false
+       elseif tool1 and not tool2 then
+               return true
+       elseif not tool1 and tool2 then
+               return false
+       elseif craftitem1 and not craftitem2 then
+               return true
+       elseif not craftitem1 and craftitem2 then
+               return false
+       else
+               return item1 < item2
+       end
+end
+
+local sort_items_alphabetically = function(item1, item2)
+       return item1 < item2
+end
+
+local collect_items = function(filter, lang_code)
+       local items = {}
+       if filter then
+               filter = string.trim(filter)
+               filter = string.lower(filter) -- to make sure the search is case-insensitive
+       end
+       for itemstring, def in pairs(minetest.registered_items) do
+               if itemstring ~= "" and itemstring ~= "unknown" and itemstring ~= "ignore" then
+                       if filter and lang_code then
+                               local desc = ItemStack(itemstring):get_description()
+                               local matches
+                               -- First, try to match original description
+                               if desc ~= "" then
+                                       local ldesc = string.lower(desc)
+                                       matches = string.match(ldesc, filter) ~= nil
+                                       -- Second, try to match translated description
+                                       if not matches then
+                                               local tdesc = minetest.get_translated_string(lang_code, desc)
+                                               if tdesc ~= "" then
+                                                       tdesc = string.lower(tdesc)
+                                                       matches = string.match(tdesc, filter) ~= nil
+                                               end
+                                       end
+                                       -- Third, try to match translated short description
+                                       if not matches then
+                                               local sdesc = ItemStack(itemstring):get_short_description()
+                                               if sdesc ~= "" then
+                                                       sdesc = minetest.get_translated_string(lang_code, sdesc)
+                                                       sdesc = string.lower(sdesc)
+                                                       matches = string.match(sdesc, filter) ~= nil
+                                               end
+                                       end
+
+                               end
+                               -- Fourth, try to match itemstring
+                               if not matches then
+                                       matches = string.match(itemstring, filter) ~= nil
+                               end
+
+                               -- If item was matched, add to item list
+                               if matches then
+                                       table.insert(items, itemstring)
+                               end
+                       else
+                               table.insert(items, itemstring)
+                       end
+               end
+       end
+       local compare
+       if SORT_MODE == "by_type" then
+               compare = sort_items_by_type
+       elseif SORT_MODE == "abc" then
+               compare = sort_items_alphabetically
+       end
+       table.sort(items, compare)
+
+       return items
+end
+
+local function update_inventory(name)
+       local search = current_searches[name] or ""
+       local items
+       if search == "" then
+               items = all_items_list
+       else
+               local lang_code = minetest.get_player_information(name).lang_code
+               items = collect_items(search, lang_code)
+       end
+       local max_page = math.ceil(#items / SLOTS)
+       current_max_pages[name] = max_page
+
+       local inv = detached_inventories[name].items
+       inv:set_size("main", #items)
+       inv:set_list("main", items)
+       if not current_pages[name] then
+               current_pages[name] = 1
+       end
+       if current_pages[name] > max_page then
+               current_pages[name] = max_page
+       end
+       if current_pages[name] < 1 then
+               current_pages[name] = 1
+       end
+end
+
+local function get_formspec(page, name)
+       local start = 0 + (page-1)*SLOTS
+       if not name then
+               return ""
+       end
+       local player = minetest.get_player_by_name(name)
+       local playerinvsize = player:get_inventory():get_size("main")
+       local hotbarsize = player:hud_get_hotbar_itemcount()
+       local pinv_w, pinv_h, pinv_x
+       pinv_w = hotbarsize
+       pinv_h = math.ceil(playerinvsize / pinv_w)
+       pinv_w = math.min(pinv_w, 10)
+       pinv_h = math.min(pinv_w, 4)
+       pinv_x = 0
+       if pinv_w < 9 then
+               pinv_x = 1
+       end
+
+       local pagestr = ""
+       local max_page = current_max_pages[name]
+       if max_page > 1 then
+               pagestr = "button[0,5.45;1,1;chest_of_everything_prev;"..F(S("<")).."]"..
+               "button[1,5.45;1,1;chest_of_everything_next;"..F(S(">")).."]"..
+               "label[0,5.1;"..F(S("Page: @1/@2", page, max_page)).."]"
+       end
+
+       local search_text = current_searches[name] or ""
+
+       local inventory_list
+       if current_max_pages[name] > 0 then
+               inventory_list = "list[detached:chest_of_everything_items_"..name..";main;0,0;"..SLOTS_W..","..SLOTS_H..";"..start.."]"
+       else
+               inventory_list = "label[2.5,2.5;"..F(S("No items found.")).."]"
+               if search_text ~= "" then
+                       inventory_list = inventory_list .. "button[2.5,3.25;3,0.8;search_button_reset_big;"..F(S("Reset search")).."]"
+               end
+       end
+
+       return "size[10,10.5]"..
+       inventory_list ..
+       "list[current_player;main;"..pinv_x..",6.75;"..pinv_w..","..pinv_h..";]" ..
+       "label[9,5.1;"..F(S("Trash:")).."]" ..
+       "list[detached:chest_of_everything_trash_"..name..";main;9,5.5;1,1]" ..
+       "field[2.2,5.75;4,1;search;;"..F(search_text).."]" ..
+       "field_close_on_enter[search;false]" ..
+       "button[6,5.45;1.6,1;search_button_start;"..F(S("Search")).."]" ..
+       "button[7.6,5.45;0.8,1;search_button_reset;"..F(S("X")).."]" ..
+       "tooltip[search_button_reset;"..F(S("Reset search")).."]" ..
+       pagestr ..
+       "listring[detached:chest_of_everything_items_"..name..";main]"..
        "listring[current_player;main]"..
-       "listring[detached:trash;main]"
+       "listring[detached:chest_of_everything_trash_"..name..";main]"
 end
 
+local show_formspec = function(name)
+       local page = current_pages[name]
+       local form = get_formspec(page, name)
+       minetest.show_formspec(name, "chest_of_everything:getitem", form)
+       return true
+end
+
+minetest.register_on_player_receive_fields(function(player, formname, fields)
+       if formname ~= "chest_of_everything:getitem" then
+               return
+       end
+       local name = player:get_player_name()
+       local page = current_pages[name]
+       local old_page = page
+       -- Next page or previous page
+       if fields.chest_of_everything_next or fields.chest_of_everything_prev then
+               if fields.chest_of_everything_next then
+                       page = page + 1
+               elseif fields.chest_of_everything_prev then
+                       page = page - 1
+               end
+               -- Handle page change
+               if page < 1 then
+                       page = 1
+               end
+               local max_page = current_max_pages[name]
+               if page > max_page then
+                       page = max_page
+               end
+               if page ~= old_page then
+                       current_pages[name] = page
+                       show_formspec(name)
+               end
+               return
+       -- Search
+       elseif (fields.search_button_start or (fields.key_enter and fields.key_enter_field == "search")) and fields.search then
+               current_searches[name] = fields.search
+               update_inventory(name)
+               show_formspec(name, fields.search)
+               return
+       -- Reset search
+       elseif (fields.search_button_reset or fields.search_button_reset_big) then
+               current_searches[name] = ""
+               update_inventory(name)
+               show_formspec(name)
+               return
+       end
+end)
+
+minetest.register_tool("chest_of_everything:bag", {
+       description = S("Bag of Everything") .. "\n" ..
+               S("Grants access to all items"),
+       inventory_image = "chest_of_everything_bag.png",
+       wield_image = "chest_of_everything_bag.png",
+       groups = { disable_repair = 1 },
+       on_use = function(itemstack, user)
+               if user and user:is_player() then
+                       local name = user:get_player_name()
+                       show_formspec(name)
+               end
+       end,
+})
+
 minetest.register_node("chest_of_everything:chest", {
-       description = "Chest of Everything" .. "\n" ..
-               "Grants access to all items",
+       description = S("Chest of Everything") .. "\n" ..
+               S("Grants access to all items"),
        tiles ={"chest_of_everything_chest.png^[sheet:2x2:0,0", "chest_of_everything_chest.png^[sheet:2x2:0,0",
                "chest_of_everything_chest.png^[sheet:2x2:1,0", "chest_of_everything_chest.png^[sheet:2x2:1,0",
                "chest_of_everything_chest.png^[sheet:2x2:1,0", "chest_of_everything_chest.png^[sheet:2x2:0,1"},
        paramtype2 = "4dir",
-       groups = {dig_immediate=2,choppy=3},
+       groups = { dig_immediate=2, choppy=3 },
        is_ground_content = false,
        on_construct = function(pos)
                local meta = minetest.get_meta(pos)
-               meta:set_string("infotext", "Chest of Everything")
-               meta:set_int("page", 1)
-               meta:set_string("formspec", get_chest_formspec(1))
+               meta:set_string("infotext", S("Chest of Everything"))
        end,
-       on_receive_fields = function(pos, formname, fields, sender)
-               if formname == "" then
-                       local meta = minetest.get_meta(pos)
-                       local page = meta:get_int("page")
-                       if fields.chest_of_everything_prev then
-                               page = page - 1
-                       elseif fields.chest_of_everything_next then
-                               page = page + 1
-                       end
-                       if page < 1 then
-                               page = 1
-                       end
-                       if page > max_page then
-                               page = max_page
-                       end
-                       meta:set_int("page", page)
-                       meta:set_string("formspec", get_chest_formspec(page))
+       on_rightclick = function(pos, node, clicker)
+               if clicker and clicker:is_player() then
+                       local name = clicker:get_player_name()
+                       show_formspec(name)
                end
        end,
 })
 
+
 minetest.register_on_mods_loaded(function()
-       local items = {}
-       for itemstring,_ in pairs(minetest.registered_items) do
-               if itemstring ~= "" and itemstring ~= "unknown" and itemstring ~= "ignore" then
-                       table.insert(items, itemstring)
-               end
-       end
-       --[[ Sort items in this order:
-       * Chest of Everything
-       * Test tools
-       * Other tools
-       * Craftitems
-       * Other items
-       * Items from the 'broken' mod
-       * Dummy items ]]
-       local function compare(item1, item2)
-               local def1 = minetest.registered_items[item1]
-               local def2 = minetest.registered_items[item2]
-               local tool1 = def1.type == "tool"
-               local tool2 = def2.type == "tool"
-               local testtool1 = minetest.get_item_group(item1, "testtool") == 1
-               local testtool2 = minetest.get_item_group(item2, "testtool") == 1
-               local dummy1 = minetest.get_item_group(item1, "dummy") == 1
-               local dummy2 = minetest.get_item_group(item2, "dummy") == 1
-               local broken1 = def1.mod_origin == "broken"
-               local broken2 = def2.mod_origin == "broken"
-               local craftitem1 = def1.type == "craft"
-               local craftitem2 = def2.type == "craft"
-               if item1 == "chest_of_everything:chest" then
-                       return true
-               elseif item2 == "chest_of_everything:chest" then
-                       return false
-               elseif dummy1 and not dummy2 then
-                       return false
-               elseif not dummy1 and dummy2 then
-                       return true
-               elseif broken1 and not broken2 then
-                       return false
-               elseif not broken1 and broken2 then
-                       return true
-               elseif testtool1 and not testtool2 then
-                       return true
-               elseif not testtool1 and testtool2 then
-                       return false
-               elseif tool1 and not tool2 then
-                       return true
-               elseif not tool1 and tool2 then
-                       return false
-               elseif craftitem1 and not craftitem2 then
-                       return true
-               elseif not craftitem1 and craftitem2 then
-                       return false
-               else
-                       return item1 < item2
-               end
-       end
-       table.sort(items, compare)
-       inv_everything:set_size("main", #items)
-       max_page = math.ceil(#items / 32)
-       for i=1, #items do
-               inv_everything:add_item("main", items[i])
-       end
+       all_items_list = collect_items()
+end)
+
+minetest.register_on_joinplayer(function(player)
+       local name = player:get_player_name()
+       current_searches[name] = ""
+       current_pages[name] = 1
+       current_max_pages[name] = 0
+       add_detached_inventories(player)
+       update_inventory(name)
+end)
+
+minetest.register_on_leaveplayer(function(player)
+       local name = player:get_player_name()
+       current_pages[name] = nil
+       current_max_pages[name] = nil
+       current_searches[name] = nil
 end)
index 4a4425e05f8830ea9bb8d9a8c6b04874cba03ffa..50dc2d547ca6b676caa6a5f2a255ce7837ca5fe6 100644 (file)
@@ -1,2 +1,2 @@
 name = chest_of_everything
-description = Adds the chest of everything from which you can take all items
+description = Adds the chest of everything and bag of everything from which you can take all items
diff --git a/games/devtest/mods/chest_of_everything/textures/chest_of_everything_bag.png b/games/devtest/mods/chest_of_everything/textures/chest_of_everything_bag.png
new file mode 100644 (file)
index 0000000..7c18907
Binary files /dev/null and b/games/devtest/mods/chest_of_everything/textures/chest_of_everything_bag.png differ
index 491a531e42c4f1245dd509fb6066d7ba0959d3c9..055ae8976888a40b358a0e53526ad8264400dd5e 100644 (file)
@@ -11,7 +11,7 @@ local give_initial_stuff = function(player)
        give_if_not_gotten_already(inv, "main", "basetools:shovel_steel")
        give_if_not_gotten_already(inv, "main", "bucket:bucket")
        give_if_not_gotten_already(inv, "main", "testnodes:light14")
-       give_if_not_gotten_already(inv, "main", "chest_of_everything:chest")
+       give_if_not_gotten_already(inv, "main", "chest_of_everything:bag")
        minetest.log("action", "[give_initial_stuff] Giving initial stuff to "..player:get_player_name())
 end