diff --git a/API.md b/API.md index a3fc9bd..0b0f95a 100644 --- a/API.md +++ b/API.md @@ -7,8 +7,7 @@ Custom tabs can be added to the `i3` inventory as follow (example): ```Lua -i3.new_tab { - name = "stuff", +i3.new_tab("stuff", { description = "Stuff", image = "image.png", -- Optional, adds an image next to the tab description @@ -28,16 +27,16 @@ i3.new_tab { fields = function(player, data, fields) end, -} +}) ``` - `player` is an `ObjectRef` to the user. - `data` are the user data. - `fs` is the formspec table which is callable with a metamethod. Each call adds a new entry. -#### `i3.set_fs(player[, extra_formspec])` +#### `i3.set_fs(player)` -Updates the current formspec. `extra_formspec` adds an additional formspec string. +Updates the current formspec. #### `i3.remove_tab(tabname)` diff --git a/README.md b/README.md index 7275178..293d6cb 100644 --- a/README.md +++ b/README.md @@ -10,20 +10,20 @@ This mod features a modern, powerful inventory menu with a good user experience. This mod requires **Minetest 5.4+** #### List of features: - - Crafting Guide (only in survival mode) + - Crafting Guide (survival mode only) - Progressive Mode¹ - Quick Crafting - - Backpacks - - 3D Player Model Preview - - Inventory Sorting (with optional compression) + - 3D Player Model Real-Time Preview + - Inventory Sorting (+ options: compression, reverse mode, automation, etc.) + - Item List Compression (**`moreblocks`** is supported) - Item Bookmarks - Waypoints - - Item List Compression (**`moreblocks`** is supported) + - Bags + - Home **¹** *This mode is a Terraria-like system that shows recipes you can craft from items you ever had in your inventory. To enable it: `i3_progressive_mode = true` in `minetest.conf`.* - #### This mod officially supports the following mods: - [**`3d_armor`**](https://content.minetest.net/packages/stu/3d_armor/) - [**`skinsdb`**](https://content.minetest.net/packages/bell07/skinsdb/) @@ -46,12 +46,10 @@ value of the setting `display_density_factor` in your `minetest.conf`. Note that `i3` uses a larger inventory than the usual inventories in Minetest games. Thus, most chests will be unadapted to this inventory size. -The `i3` inventory is 9 slots wide by default (without backpack), such as Minecraft. +The `i3` inventory is 9 slots wide by default, such as Minecraft. -Report any bug on the [**Bug Tracker**](https://github.com/minetest-mods/i3/issues). +Report bugs on the [**Bug Tracker**](https://github.com/minetest-mods/i3/issues). Love this mod? Donations are appreciated: https://www.paypal.me/jpg84240 -Demo video (outdated): https://www.youtube.com/watch?v=25nCAaqeacU - ![Preview](https://user-images.githubusercontent.com/7883281/140816791-693a5c8a-a7d1-47d4-a45d-883cc008ae8a.png) diff --git a/init.lua b/init.lua index 5176231..633defc 100644 --- a/init.lua +++ b/init.lua @@ -15,13 +15,6 @@ i3 = { MIN_FORMSPEC_VERSION = 4, SAVE_INTERVAL = 600, -- Player data save interval (in seconds) - BAG_SIZES = { - 4*9 + 3, - 4*9 + 6, - 4*9 + 9, - 4*9 + 25, - }, - SUBCAT = { "bag", "armor", @@ -36,7 +29,7 @@ i3 = { bag_size = true, waypoints = true, inv_items = true, - reject_items = true, + drop_items = true, known_recipes = true, }, @@ -56,18 +49,19 @@ i3 = { files = { api = lf("/src/api.lua"), bags = lf("/src/bags.lua"), + callbacks = lf("/src/callbacks.lua"), common = lf("/src/common.lua"), compress = lf("/src/compress.lua"), + detached = lf("/src/detached_inv.lua"), groups = lf("/src/groups.lua"), gui = lf("/src/gui.lua"), - inventory = lf("/src/inventory.lua"), model_alias = lf("/src/model_aliases.lua"), progressive = lf("/src/progressive.lua"), recipes = lf("/src/recipes.lua"), styles = lf("/src/styles.lua"), }, - progressive_mode = core.settings:get_bool "i3_progressive_mode", + progressive_mode = core.settings:get_bool"i3_progressive_mode", item_compression = core.settings:get_bool("i3_item_compression", true), } @@ -75,14 +69,16 @@ i3.files.common() i3.files.api() i3.files.compress() i3.files.groups() -i3.files.inventory() +i3.files.callbacks() local storage = core.get_mod_storage() -local slz, dslz, str_to_pos, add_hud_waypoint = i3.get("slz", "dslz", "str_to_pos", "add_hud_waypoint") +local slz, dslz, ESC, str_to_pos, add_hud_waypoint = + i3.get("slz", "dslz", "ESC", "str_to_pos", "add_hud_waypoint") i3.data = dslz(storage:get_string "data") or {} -local init_backpack = i3.files.bags() +local init_bags = i3.files.bags() +local init_inventories = i3.files.detached() local init_recipes = i3.files.recipes() local function get_lang_code(info) @@ -146,6 +142,7 @@ local function init_data(player, info) i3.data[name] = i3.data[name] or {} local data = i3.data[name] + data.player_name = ESC(name) data.filter = "" data.pagenum = 1 data.items = i3.init_items @@ -165,6 +162,9 @@ local function init_data(player, info) data.lang_code = get_lang_code(info) data.fs_version = info.formspec_version + local inv = player:get_inventory() + inv:set_size("main", i3.INV_SIZE) + core.after(0, i3.set_fs, player) end @@ -216,12 +216,12 @@ core.register_on_joinplayer(function(player) local info = core.get_player_information and core.get_player_information(name) if not info or get_formspec_version(info) < i3.MIN_FORMSPEC_VERSION then - i3.data[name] = nil return outdated(name) end init_data(player, info) - init_backpack(player) + init_bags(player) + init_inventories(player) init_waypoints(player) init_hudbar(player) end) diff --git a/sounds/i3_cannot.ogg b/sounds/i3_cannot.ogg new file mode 100644 index 0000000..8f97186 Binary files /dev/null and b/sounds/i3_cannot.ogg differ diff --git a/src/api.lua b/src/api.lua index eba7ab4..87c1c1b 100644 --- a/src/api.lua +++ b/src/api.lua @@ -161,7 +161,7 @@ function i3.get_recipes(item) } end -function i3.set_fs(player, _fs) +function i3.set_fs(player) if not player or player.is_fake_player then return end local name = player:get_player_name() local data = i3.data[name] @@ -171,32 +171,34 @@ function i3.set_fs(player, _fs) sort_inventory(player, data) end - local fs = fmt("%s%s", make_fs(player, data), _fs or "") + local fs = make_fs(player, data) player:set_inventory_formspec(fs) end -function i3.new_tab(def) - if not true_table(def) then - return err "i3.new_tab: tab definition missing" - elseif not true_str(def.name) then +function i3.new_tab(name, def) + if not true_str(name) then return err "i3.new_tab: tab name missing" + elseif not true_table(def) then + return err "i3.new_tab: tab definition missing" elseif not true_str(def.description) then return err "i3.new_tab: description missing" elseif #i3.tabs == 6 then return err(fmt("i3.new_tab: cannot add '%s' tab. Limit reached (6).", def.name)) end - i3.tabs[#i3.tabs + 1] = def + def.name = name + insert(i3.tabs, def) end -function i3.remove_tab(tabname) - if not true_str(tabname) then +function i3.remove_tab(name) + if not true_str(name) then return err "i3.remove_tab: tab name missing" end for i, def in ipairs(i3.tabs) do - if tabname == def.name then + if name == def.name then remove(i3.tabs, i) + break end end end @@ -217,32 +219,31 @@ function i3.set_tab(player, tabname) return end - local found - for i, def in ipairs(i3.tabs) do - if not found and def.name == tabname then + if def.name == tabname then data.tab = i - found = true + return end end - if not found then - return err(fmt("i3.set_tab: tab name '%s' does not exist", tabname)) - end + err(fmt("i3.set_tab: tab name '%s' does not exist", tabname)) end -function i3.override_tab(tabname, newdef) - if not true_table(newdef) then - return err "i3.override_tab: tab definition missing" - elseif not true_str(newdef.name) then +function i3.override_tab(name, newdef) + if not true_str(name) then return err "i3.override_tab: tab name missing" + elseif not true_table(newdef) then + return err "i3.override_tab: tab definition missing" elseif not true_str(newdef.description) then return err "i3.override_tab: description missing" end + newdef.name = name + for i, def in ipairs(i3.tabs) do - if def.name == tabname then + if def.name == name then i3.tabs[i] = newdef + break end end end diff --git a/src/bags.lua b/src/bags.lua index 375b490..a7a23b2 100644 --- a/src/bags.lua +++ b/src/bags.lua @@ -1,55 +1,161 @@ -local S, fmt, msg, spawn_item = i3.get("S", "fmt", "msg", "spawn_item") +local S, ES, fmt, clr, msg, slz, dslz, play_sound, create_inventory = + i3.get("S", "ES", "fmt", "clr", "msg", "slz", "dslz", "play_sound", "create_inventory") -local function init_backpack(player) +local function get_content_inv(name) + return core.get_inventory { + type = "detached", + name = fmt("i3_bag_content_%s", name) + } +end + +local function get_content(content) + local t = {} + + for i, v in pairs(content) do + local stack = ItemStack(v.name) + local meta, wear = v.meta, v.wear + + if meta then + local m = stack:get_meta() + m:from_table(meta) + end + + if wear then + stack:set_wear(wear) + end + + t[i] = stack + end + + return t +end + +local function safe_format(stack) + local meta = stack:get_meta():to_table() + local wear = stack:get_wear() + local has_meta = next(meta.fields) + + local info = {} + info.name = fmt("%s %u", stack:get_name(), stack:get_count()) + + if has_meta then + info.meta = meta + end + + if wear > 0 then + info.wear = wear + end + + return info +end + +local function init_bags(player) local name = player:get_player_name() local data = i3.data[name] - local inv = player:get_inventory() - inv:set_size("main", data.bag_size and i3.BAG_SIZES[data.bag_size] or i3.INV_SIZE) + local bag = create_inventory(fmt("i3_bag_%s", name), { + allow_put = function(inv, _, _, stack) + local empty = inv:is_empty"main" + local item_group = core.get_item_group(stack:get_name(), "bag") - data.bag = core.create_detached_inventory(fmt("%s_backpack", name), { - allow_put = function(_inv, listname, _, stack) - local empty = _inv:get_stack(listname, 1):is_empty() - local item_group = minetest.get_item_group(stack:get_name(), "bag") - - if empty and item_group > 0 and item_group <= #i3.BAG_SIZES then + if empty and item_group > 0 and item_group <= 4 then return 1 end - msg(name, S"This is not a backpack") - return 0 + if not empty then + msg(name, S"There is already a bag") + else + msg(name, S"This is not a bag") + end + + return 0, play_sound(name, "i3_cannot", 0.8) end, on_put = function(_, _, _, stack) - local stackname = stack:get_name() - data.bag_item = stackname - data.bag_size = minetest.get_item_group(stackname, "bag") + data.bag_item = safe_format(stack) + data.bag_size = core.get_item_group(stack:get_name(), "bag") + + local meta = stack:get_meta() + local content = dslz(meta:get_string"content") + + if content then + local inv = get_content_inv(name) + inv:set_list("main", get_content(content)) + end - inv:set_size("main", i3.BAG_SIZES[data.bag_size]) i3.set_fs(player) end, on_take = function() - for i = i3.INV_SIZE + 1, i3.BAG_SIZES[data.bag_size] do - local stack = inv:get_stack("main", i) - - if not stack:is_empty() then - spawn_item(player, stack) - end - end - data.bag_item = nil data.bag_size = nil - inv:set_size("main", i3.INV_SIZE) + local content = get_content_inv(name) + content:set_list("main", {}) + i3.set_fs(player) end, - }) + }, name) - data.bag:set_size("main", 1) + bag:set_size("main", 1) if data.bag_item then - data.bag:set_stack("main", 1, data.bag_item) + bag:set_list("main", get_content{data.bag_item}) + end + + local function save_content(inv) + local bagstack = bag:get_stack("main", 1) + local meta = bagstack:get_meta() + + if inv:is_empty("main") then + meta:set_string("description", "") + meta:set_string("content", "") + else + local list = inv:get_list"main" + local t = {} + + for i = 1, #list do + local stack = list[i] + + if not stack:is_empty() then + t[i] = safe_format(stack) + end + end + + local function count_items() + local c = 0 + + for _ in pairs(t) do + c = c + 1 + end + + return c + end + + meta:set_string("description", "") + meta:set_string("description", ES("@1 (contains @2 / @3 stacks)", + bagstack:get_short_description(), clr("#ff0", count_items()), data.bag_size * 4)) + meta:set_string("content", slz(t)) + end + + bag:set_stack("main", 1, bagstack) + data.bag_item = safe_format(bagstack) + + i3.set_fs(player) + end + + local bag_content = create_inventory(fmt("i3_bag_content_%s", name), { + on_move = save_content, + on_put = save_content, + on_take = save_content, + }, name) + + bag_content:set_size("main", 4*4) + + if data.bag_item then + local meta = bag:get_stack("main", 1):get_meta() + local content = dslz(meta:get_string"content") or {} + bag_content:set_list("main", get_content(content)) end end @@ -60,21 +166,21 @@ local bag_recipes = { {"group:wool", "group:wool", "group:wool"}, {"group:wool", "group:wool", "group:wool"}, }, - size = 1, + size = 2, }, medium = { rcp = { {"farming:string", "i3:bag_small", "farming:string"}, {"farming:string", "i3:bag_small", "farming:string"}, }, - size = 2, + size = 3, }, large = { rcp = { {"farming:string", "i3:bag_medium", "farming:string"}, {"farming:string", "i3:bag_medium", "farming:string"}, }, - size = 3, + size = 4, }, } @@ -84,12 +190,12 @@ for size, item in pairs(bag_recipes) do core.register_craftitem(bagname, { description = fmt("%s Backpack", size:gsub("^%l", string.upper)), inventory_image = fmt("i3_bag_%s.png", size), + groups = {bag = item.size}, stack_max = 1, - groups = {bag = item.size} }) - core.register_craft {output = bagname, recipe = item.rcp} - core.register_craft {type = "fuel", recipe = bagname, burntime = 3} + core.register_craft{output = bagname, recipe = item.rcp} + core.register_craft{type = "fuel", recipe = bagname, burntime = 3} end -return init_backpack +return init_bags diff --git a/src/inventory.lua b/src/callbacks.lua similarity index 77% rename from src/inventory.lua rename to src/callbacks.lua index e597286..3bb34fd 100644 --- a/src/inventory.lua +++ b/src/callbacks.lua @@ -1,20 +1,18 @@ local _, get_inventory_fs = i3.files.gui() local S, clr = i3.get("S", "clr") -local min, ceil, random = i3.get("min", "ceil", "random") +local min, random = i3.get("min", "random") local reg_items, reg_aliases = i3.get("reg_items", "reg_aliases") local fmt, find, match, sub, lower, split = i3.get("fmt", "find", "match", "sub", "lower", "split") local vec_new, vec_eq, vec_round = i3.get("vec_new", "vec_eq", "vec_round") local sort, copy, insert, remove, indexof = i3.get("sort", "copy", "insert", "remove", "indexof") -local is_group, extract_groups, groups_to_items = - i3.get("is_group", "extract_groups", "groups_to_items") -local msg, is_fav, pos_to_str, str_to_pos, add_hud_waypoint = - i3.get("msg", "is_fav", "pos_to_str", "str_to_pos", "add_hud_waypoint") +local msg, is_fav, pos_to_str, str_to_pos, add_hud_waypoint, play_sound = + i3.get("msg", "is_fav", "pos_to_str", "str_to_pos", "add_hud_waypoint", "play_sound") local search, get_sorting_idx, sort_inventory, sort_by_category, get_recipes = i3.get("search", "get_sorting_idx", "sort_inventory", "sort_by_category", "get_recipes") -local show_item, get_stack, clean_name, compressible, check_privs, safe_teleport = - i3.get("show_item", "get_stack", "clean_name", "compressible", "check_privs", "safe_teleport") +local show_item, get_stack, craft_stack, clean_name, compressible, check_privs, safe_teleport = + i3.get("show_item", "get_stack", "craft_stack", "clean_name", "compressible", "check_privs", "safe_teleport") local function reset_data(data) data.filter = "" @@ -40,13 +38,12 @@ local function reset_data(data) end end -i3.new_tab { - name = "inventory", +i3.new_tab("inventory", { description = S"Inventory", formspec = get_inventory_fs, fields = function(player, data, fields) - local name = player:get_player_name() + local name = data.player_name local inv = player:get_inventory() local sb_inv = fields.scrbar_inv @@ -56,9 +53,9 @@ i3.new_tab { skins.set_player_skin(player, _skins[id]) end - if fields.reject_items then - local items = split(fields.reject_items, ",") - data.reject_items = items + if fields.drop_items then + local items = split(fields.drop_items, ",") + data.drop_items = items end for field in pairs(fields) do @@ -176,6 +173,7 @@ i3.new_tab { for _, v in ipairs(data.waypoints) do if vec_eq(vec_round(pos), vec_round(str_to_pos(v.pos))) then + play_sound(name, "i3_cannot", 0.8) return msg(name, "You already set a waypoint at this position") end end @@ -201,9 +199,9 @@ i3.new_tab { return i3.set_fs(player) end, -} +}) -local function select_item(player, name, data, _f) +local function select_item(player, data, _f) local item for field in pairs(_f) do @@ -271,7 +269,7 @@ local function select_item(player, name, data, _f) item = reg_aliases[item] or item if not reg_items[item] then return end - if core.is_creative_enabled(name) then + if core.is_creative_enabled(data.player_name) then local stack = ItemStack(item) local stackmax = stack:get_stack_max() stack = fmt("%s %s", item, stackmax) @@ -294,55 +292,7 @@ local function select_item(player, name, data, _f) end end -local function craft_stack(player, data, craft_rcp) - local inv = player:get_inventory() - local rcp_usg = craft_rcp and "recipe" or "usage" - local output = craft_rcp and data.recipes[data.rnum].output or data.usages[data.unum].output - output = ItemStack(output) - local stackname, stackcount, stackmax = output:get_name(), output:get_count(), output:get_stack_max() - local scrbar_val = data[fmt("scrbar_%s", craft_rcp and "rcp" or "usg")] or 1 - - for name, count in pairs(data.export_counts[rcp_usg].rcp) do - local items = {[name] = count} - - if is_group(name) then - items = {} - local groups = extract_groups(name) - local item_groups = groups_to_items(groups, true) - local remaining = count - - for _, item in ipairs(item_groups) do - for _name, _count in pairs(data.export_counts[rcp_usg].inv) do - if item == _name and remaining > 0 then - local c = min(remaining, _count) - items[item] = c - remaining = remaining - c - end - - if remaining == 0 then break end - end - end - end - - for k, v in pairs(items) do - inv:remove_item("main", fmt("%s %s", k, v * scrbar_val)) - end - end - - local count = stackcount * scrbar_val - local iter = ceil(count / stackmax) - local leftover = count - - for _ = 1, iter do - local c = min(stackmax, leftover) - local stack = ItemStack(fmt("%s %s", stackname, c)) - get_stack(player, stack) - leftover = leftover - stackmax - end -end - local function rcp_fields(player, data, fields) - local name = player:get_player_name() local sb_rcp, sb_usg = fields.scrbar_rcp, fields.scrbar_usg if fields.cancel then @@ -431,7 +381,7 @@ local function rcp_fields(player, data, fields) data.scrbar_usg = 1 end else - select_item(player, name, data, fields) + select_item(player, data, fields) end end @@ -439,11 +389,12 @@ core.register_on_player_receive_fields(function(player, formname, fields) local name = player:get_player_name() if formname == "i3_outdated" then - return false, core.kick_player(name, "Come back when your client is up-to-date.") + return false, core.kick_player(name, S"Come back when your client is up-to-date.") elseif formname ~= "" then return false end + --print(dump(fields)) local data = i3.data[name] if not data then return end @@ -456,6 +407,7 @@ core.register_on_player_receive_fields(function(player, formname, fields) data.pagenum = 1 data.itab = tonumber(f:sub(-1)) sort_by_category(data) + break end end @@ -486,15 +438,6 @@ core.register_on_dieplayer(function(player) local data = i3.data[name] if not data then return end - if data.bag_size then - data.bag_item = nil - data.bag_size = nil - data.bag:set_list("main", {}) - - local inv = player:get_inventory() - inv:set_size("main", i3.INV_SIZE) - end - i3.set_fs(player) end) @@ -524,27 +467,3 @@ core.register_on_player_inventory_action(function(player, _, _, info) i3.set_fs(player) end end) - -local trash = core.create_detached_inventory("i3_trash", { - allow_put = function(_, _, _, stack) - return stack:get_count() - end, - on_put = function(inv, listname, _, _, player) - inv:set_list(listname, {}) - - local name = player:get_player_name() - core.sound_play("i3_trash", {to_player = name, gain = 1.0}, true) - - if not core.is_creative_enabled(name) then - i3.set_fs(player) - end - end, -}) - -trash:set_size("main", 1) - -local output_rcp = core.create_detached_inventory("i3_output_rcp", {}) -output_rcp:set_size("main", 1) - -local output_usg = core.create_detached_inventory("i3_output_usg", {}) -output_usg:set_size("main", 1) diff --git a/src/common.lua b/src/common.lua index dad5e69..5ea32f0 100644 --- a/src/common.lua +++ b/src/common.lua @@ -349,9 +349,60 @@ local function get_stack(player, stack) end end +local function craft_stack(player, data, craft_rcp) + local inv = player:get_inventory() + local rcp_usg = craft_rcp and "recipe" or "usage" + local output = craft_rcp and data.recipes[data.rnum].output or data.usages[data.unum].output + output = ItemStack(output) + local stackname, stackcount, stackmax = output:get_name(), output:get_count(), output:get_stack_max() + local scrbar_val = data[fmt("scrbar_%s", craft_rcp and "rcp" or "usg")] or 1 + + for name, count in pairs(data.export_counts[rcp_usg].rcp) do + local items = {[name] = count} + + if is_group(name) then + items = {} + local groups = extract_groups(name) + local item_groups = groups_to_items(groups, true) + local remaining = count + + for _, item in ipairs(item_groups) do + for _name, _count in pairs(data.export_counts[rcp_usg].inv) do + if item == _name and remaining > 0 then + local c = math.min(remaining, _count) + items[item] = c + remaining = remaining - c + end + + if remaining == 0 then break end + end + end + end + + for k, v in pairs(items) do + inv:remove_item("main", fmt("%s %s", k, v * scrbar_val)) + end + end + + local count = stackcount * scrbar_val + local iter = math.ceil(count / stackmax) + local leftover = count + + for _ = 1, iter do + local c = math.min(stackmax, leftover) + local stack = ItemStack(fmt("%s %s", stackname, c)) + get_stack(player, stack) + leftover = leftover - stackmax + end +end + +local function play_sound(name, sound, volume) + core.sound_play(sound, {to_player = name, gain = volume}, true) +end + local function safe_teleport(player, pos) local name = player:get_player_name() - core.sound_play("i3_teleport", {to_player = name, gain = 1.0}, true) + play_sound(name, "i3_teleport", 1.0) pos.y = pos.y + 0.5 local vel = player:get_velocity() @@ -446,7 +497,7 @@ local function compress_items(list, start_i) return new_inv end -local function reject_items(player, inv, list, start_i, rej) +local function drop_items(player, inv, list, start_i, rej) for i = start_i, #list do local stack = list[i] local name = stack:get_name() @@ -459,17 +510,17 @@ local function reject_items(player, inv, list, start_i, rej) end end - return inv:get_list("main") + return inv:get_list"main" end local function sort_inventory(player, data) local inv = player:get_inventory() - local list = inv:get_list("main") - local size = inv:get_size("main") + local list = inv:get_list"main" + local size = inv:get_size"main" local start_i = data.ignore_hotbar and 10 or 1 - if true_table(data.reject_items) then - list = reject_items(player, inv, list, start_i, data.reject_items) + if true_table(data.drop_items) then + list = drop_items(player, inv, list, start_i, data.drop_items) end if data.inv_compress then @@ -540,9 +591,11 @@ local _ = { -- Misc. functions get_stack = get_stack, + craft_stack = craft_stack, show_item = show_item, spawn_item = spawn_item, clean_name = clean_name, + play_sound = play_sound, safe_teleport = safe_teleport, add_hud_waypoint = add_hud_waypoint, @@ -554,6 +607,7 @@ local _ = { pos_to_str = core.pos_to_string, str_to_pos = core.string_to_pos, check_privs = core.check_player_privs, + create_inventory = core.create_detached_inventory, -- Registered items reg_items = core.registered_items, diff --git a/src/detached_inv.lua b/src/detached_inv.lua new file mode 100644 index 0000000..9b4ceb2 --- /dev/null +++ b/src/detached_inv.lua @@ -0,0 +1,32 @@ +local fmt, play_sound, create_inventory = i3.get("fmt", "play_sound", "create_inventory") + +local trash = create_inventory("i3_trash", { + allow_put = function(_, _, _, stack) + return stack:get_count() + end, + + on_put = function(inv, listname, _, _, player) + inv:set_list(listname, {}) + + local name = player:get_player_name() + play_sound(name, "i3_trash", 1.0) + + if not core.is_creative_enabled(name) then + i3.set_fs(player) + end + end, +}) + +trash:set_size("main", 1) + +local function init_inventories(player) + local name = player:get_player_name() + + local output_rcp = create_inventory(fmt("i3_output_rcp_%s", name), {}, name) + output_rcp:set_size("main", 1) + + local output_usg = create_inventory(fmt("i3_output_usg_%s", name), {}, name) + output_usg:set_size("main", 1) +end + +return init_inventories diff --git a/src/gui.lua b/src/gui.lua index b084a17..c979e12 100644 --- a/src/gui.lua +++ b/src/gui.lua @@ -124,10 +124,8 @@ local function get_stack_max(inv, data, is_recipe, rcp) return max_stacks end -local function get_inv_slots(data, fs) - local inv_x, inv_y = 0.22, 6.9 - local width, size, spacing = i3.HOTBAR_LEN, 1, 0.1 - local bag = data.bag_size +local function get_inv_slots(fs) + local inv_x, inv_y, size, spacing = 0.22, 6.9, 1, 0.1 fs("style_type[box;colors=#77777710,#77777710,#777,#777]") @@ -138,14 +136,9 @@ local function get_inv_slots(data, fs) fs(fmt("style_type[list;size=%f;spacing=%f]", size, spacing), fmt("list[current_player;main;%f,%f;%u,1;]", inv_x, inv_y, i3.HOTBAR_LEN)) - if bag then - local params = {{10, 0.892}, {11, 0.8}, {12, 0.726}, {13, 0.663}} - width, size = unpack(params[bag]) - end - fs(fmt("style_type[list;size=%f;spacing=%f]", size, spacing), fmt("list[current_player;main;%f,%f;%u,%u;%u]", inv_x, inv_y + 1.15, - width, (bag and i3.BAG_SIZES[data.bag_size] or i3.INV_SIZE) / width, i3.HOTBAR_LEN), + i3.HOTBAR_LEN, i3.INV_SIZE / i3.HOTBAR_LEN, i3.HOTBAR_LEN), "style_type[list;size=1;spacing=0.15]") fs("listring[current_player;craft]listring[current_player;main]") @@ -294,8 +287,8 @@ local function get_waypoint_fs(fs, data, player, yextra, ctn_len) end local function get_container(fs, data, player, yoffset, ctn_len, award_list, awards_unlocked, award_list_nb) - local name = player:get_player_name() - add_subtitle(fs, "player_name", 0, ctn_len, 22, true, ESC(name)) + local name = data.player_name + add_subtitle(fs, "player_name", 0, ctn_len, 22, true, name) if damage_enabled then local hp = data.hp or player:get_hp() or 20 @@ -342,20 +335,39 @@ local function get_container(fs, data, player, yoffset, ctn_len, award_list, awa local function not_installed(modname) fs("hypertext", 0, yextra + 0.9, ctn_len, 0.6, "not_installed", - fmt("