Add new buttons to main inventory, add inventory sorting methods + API
This commit is contained in:
parent
8d7ca9df18
commit
9276598e3e
34
API.md
34
API.md
|
@ -235,6 +235,40 @@ A map of search filters, indexed by name.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
### Sorting methods
|
||||||
|
|
||||||
|
Sorting methods are used to filter the player's main inventory.
|
||||||
|
|
||||||
|
#### `i3.add_sorting_method(def)`
|
||||||
|
|
||||||
|
Adds a player inventory sorting method.
|
||||||
|
|
||||||
|
- `def` is the method definition.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
```Lua
|
||||||
|
i3.add_sorting_method {
|
||||||
|
name = "test",
|
||||||
|
description = "Cool sorting method",
|
||||||
|
func = function(player, data)
|
||||||
|
local inv = player:get_inventory()
|
||||||
|
local list = inv:get_list("main")
|
||||||
|
table.sort(list)
|
||||||
|
|
||||||
|
-- An array of items must be returned
|
||||||
|
return list
|
||||||
|
end,
|
||||||
|
}
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
#### `i3.sorting_methods`
|
||||||
|
|
||||||
|
A table containing all sorting methods.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
### Item list compression
|
### Item list compression
|
||||||
|
|
||||||
`i3` can reduce the item list size by compressing a group of items.
|
`i3` can reduce the item list size by compressing a group of items.
|
||||||
|
|
|
@ -15,10 +15,10 @@ This mod requires **Minetest 5.4+**
|
||||||
- Quick Crafting
|
- Quick Crafting
|
||||||
- Backpacks
|
- Backpacks
|
||||||
- 3D Player Model Preview
|
- 3D Player Model Preview
|
||||||
- Inventory Sorting (alphabetical + item stack compression)
|
- Inventory Sorting (with optional compression)
|
||||||
- Item Bookmarks
|
- Item Bookmarks
|
||||||
- Waypoints
|
- Waypoints
|
||||||
- Item List Compression (**`moreblocks`** supported)
|
- Item List Compression (**`moreblocks`** is supported)
|
||||||
|
|
||||||
**¹** *This mode is a Terraria-like system that shows recipes you can craft from items you ever had in your inventory.
|
**¹** *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`.*
|
To enable it: `i3_progressive_mode = true` in `minetest.conf`.*
|
||||||
|
|
67
etc/api.lua
67
etc/api.lua
|
@ -2,6 +2,7 @@ local make_fs = i3.files.gui()
|
||||||
|
|
||||||
local gmatch, match, split = i3.get("gmatch", "match", "split")
|
local gmatch, match, split = i3.get("gmatch", "match", "split")
|
||||||
local S, err, fmt, reg_items = i3.get("S", "err", "fmt", "reg_items")
|
local S, err, fmt, reg_items = i3.get("S", "err", "fmt", "reg_items")
|
||||||
|
local name_sort, count_sort, sort_inventory = i3.get("name_sort", "count_sort", "sort_inventory")
|
||||||
local sort, concat, copy, insert, remove = i3.get("sort", "concat", "copy", "insert", "remove")
|
local sort, concat, copy, insert, remove = i3.get("sort", "concat", "copy", "insert", "remove")
|
||||||
local true_str, true_table, is_str, is_func, is_table, clean_name =
|
local true_str, true_table, is_str, is_func, is_table, clean_name =
|
||||||
i3.get("true_str", "true_table", "is_str", "is_func", "is_table", "clean_name")
|
i3.get("true_str", "true_table", "is_str", "is_func", "is_table", "clean_name")
|
||||||
|
@ -166,6 +167,10 @@ function i3.set_fs(player, _fs)
|
||||||
local data = i3.data[name]
|
local data = i3.data[name]
|
||||||
if not data then return end
|
if not data then return end
|
||||||
|
|
||||||
|
if data.auto_sorting then
|
||||||
|
sort_inventory(player, data)
|
||||||
|
end
|
||||||
|
|
||||||
local fs = fmt("%s%s", make_fs(player, data), _fs or "")
|
local fs = fmt("%s%s", make_fs(player, data), _fs or "")
|
||||||
player:set_inventory_formspec(fs)
|
player:set_inventory_formspec(fs)
|
||||||
end
|
end
|
||||||
|
@ -289,3 +294,65 @@ function i3.compress(item, def)
|
||||||
i3.compressed[it] = true
|
i3.compressed[it] = true
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function i3.add_sorting_method(def)
|
||||||
|
if not true_table(def) then
|
||||||
|
return err "i3.add_sorting_method: definition missing"
|
||||||
|
elseif not true_str(def.name) then
|
||||||
|
return err "i3.add_sorting_method: name missing"
|
||||||
|
elseif not is_func(def.func) then
|
||||||
|
return err "i3.add_sorting_method: function missing"
|
||||||
|
end
|
||||||
|
|
||||||
|
insert(i3.sorting_methods, def)
|
||||||
|
end
|
||||||
|
|
||||||
|
local function pre_sorting(player)
|
||||||
|
local inv = player:get_inventory()
|
||||||
|
local list = inv:get_list("main")
|
||||||
|
local size = inv:get_size("main")
|
||||||
|
local new_inv, stack_meta = {}, {}
|
||||||
|
|
||||||
|
for i = 1, size do
|
||||||
|
local stack = list[i]
|
||||||
|
local name = stack:get_name()
|
||||||
|
local count = stack:get_count()
|
||||||
|
local empty = stack:is_empty()
|
||||||
|
local meta = stack:get_meta():to_table()
|
||||||
|
local wear = stack:get_wear() > 0
|
||||||
|
|
||||||
|
if not empty then
|
||||||
|
if next(meta.fields) or wear then
|
||||||
|
stack_meta[#stack_meta + 1] = stack
|
||||||
|
else
|
||||||
|
new_inv[#new_inv + 1] = ItemStack(fmt("%s %u", name, count))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
for i = 1, #stack_meta do
|
||||||
|
new_inv[#new_inv + 1] = stack_meta[i]
|
||||||
|
end
|
||||||
|
|
||||||
|
return new_inv
|
||||||
|
end
|
||||||
|
|
||||||
|
i3.add_sorting_method {
|
||||||
|
name = "alphabetical",
|
||||||
|
description = S"Sort items by name (A-Z)",
|
||||||
|
func = function(player, data)
|
||||||
|
local new_inv = pre_sorting(player)
|
||||||
|
name_sort(new_inv, data.reverse_sorting)
|
||||||
|
return new_inv
|
||||||
|
end
|
||||||
|
}
|
||||||
|
|
||||||
|
i3.add_sorting_method {
|
||||||
|
name = "numerical",
|
||||||
|
description = S"Sort items by number of items per stack",
|
||||||
|
func = function(player, data)
|
||||||
|
local new_inv = pre_sorting(player)
|
||||||
|
count_sort(new_inv, data.reverse_sorting)
|
||||||
|
return new_inv
|
||||||
|
end,
|
||||||
|
}
|
||||||
|
|
112
etc/common.lua
112
etc/common.lua
|
@ -1,6 +1,6 @@
|
||||||
local translate = core.get_translated_string
|
local translate = core.get_translated_string
|
||||||
local insert, remove, floor, vec_add, vec_mul =
|
local insert, remove, sort, vec_add, vec_mul =
|
||||||
table.insert, table.remove, math.floor, vector.add, vector.mul
|
table.insert, table.remove, table.sort, vector.add, vector.mul
|
||||||
local fmt, find, gmatch, match, sub, split, lower =
|
local fmt, find, gmatch, match, sub, split, lower =
|
||||||
string.format, string.find, string.gmatch, string.match, string.sub, string.split, string.lower
|
string.format, string.find, string.gmatch, string.match, string.sub, string.split, string.lower
|
||||||
local reg_items, reg_nodes, reg_craftitems, reg_tools =
|
local reg_items, reg_nodes, reg_craftitems, reg_tools =
|
||||||
|
@ -297,7 +297,7 @@ end
|
||||||
|
|
||||||
local function round(num, decimal)
|
local function round(num, decimal)
|
||||||
local mul = 10 ^ decimal
|
local mul = 10 ^ decimal
|
||||||
return floor(num * mul + 0.5) / mul
|
return math.floor(num * mul + 0.5) / mul
|
||||||
end
|
end
|
||||||
|
|
||||||
local function is_fav(favs, query_item)
|
local function is_fav(favs, query_item)
|
||||||
|
@ -351,9 +351,107 @@ local function spawn_item(player, stack)
|
||||||
core.add_item(look_at, stack)
|
core.add_item(look_at, stack)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local function name_sort(inv, reverse)
|
||||||
|
return sort(inv, function(a, b)
|
||||||
|
a, b = a:get_name(), b:get_name()
|
||||||
|
|
||||||
|
if reverse then
|
||||||
|
return a > b
|
||||||
|
end
|
||||||
|
|
||||||
|
return a < b
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
local function count_sort(inv, reverse)
|
||||||
|
return sort(inv, function(a, b)
|
||||||
|
a, b = a:get_count(), b:get_count()
|
||||||
|
|
||||||
|
if reverse then
|
||||||
|
return a > b
|
||||||
|
end
|
||||||
|
|
||||||
|
return a < b
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
local function get_sorting_idx(name)
|
||||||
|
local idx = 1
|
||||||
|
|
||||||
|
for i, def in ipairs(i3.sorting_methods) do
|
||||||
|
if name == def.name then
|
||||||
|
idx = i
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return idx
|
||||||
|
end
|
||||||
|
|
||||||
|
local function compress_items(player)
|
||||||
|
local inv = player:get_inventory()
|
||||||
|
local list = inv:get_list("main")
|
||||||
|
local size = inv:get_size("main")
|
||||||
|
local new_inv, _new_inv, special = {}, {}, {}
|
||||||
|
|
||||||
|
for i = 1, size do
|
||||||
|
local stack = list[i]
|
||||||
|
local name = stack:get_name()
|
||||||
|
local count = stack:get_count()
|
||||||
|
local stackmax = stack:get_stack_max()
|
||||||
|
local empty = stack:is_empty()
|
||||||
|
local meta = stack:get_meta():to_table()
|
||||||
|
local wear = stack:get_wear() > 0
|
||||||
|
|
||||||
|
if not empty then
|
||||||
|
if next(meta.fields) or wear or count >= stackmax then
|
||||||
|
special[#special + 1] = stack
|
||||||
|
else
|
||||||
|
new_inv[name] = new_inv[name] or 0
|
||||||
|
new_inv[name] = new_inv[name] + count
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
for name, count in pairs(new_inv) do
|
||||||
|
local stackmax = ItemStack(name):get_stack_max()
|
||||||
|
local iter = math.ceil(count / stackmax)
|
||||||
|
local leftover = count
|
||||||
|
|
||||||
|
for _ = 1, iter do
|
||||||
|
_new_inv[#_new_inv + 1] = fmt("%s %u", name, math.min(stackmax, leftover))
|
||||||
|
leftover = leftover - stackmax
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
for i = 1, #special do
|
||||||
|
_new_inv[#_new_inv + 1] = special[i]
|
||||||
|
end
|
||||||
|
|
||||||
|
inv:set_list("main", _new_inv)
|
||||||
|
end
|
||||||
|
|
||||||
|
local function sort_inventory(player, data)
|
||||||
|
if data.inv_compress then
|
||||||
|
compress_items(player)
|
||||||
|
end
|
||||||
|
|
||||||
|
local sorts = {}
|
||||||
|
|
||||||
|
for _, def in ipairs(i3.sorting_methods) do
|
||||||
|
sorts[def.name] = def.func
|
||||||
|
end
|
||||||
|
|
||||||
|
local new_inv = sorts[data.sort](player, data)
|
||||||
|
|
||||||
|
if new_inv then
|
||||||
|
local inv = player:get_inventory()
|
||||||
|
inv:set_list("main", new_inv)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
-------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------
|
||||||
|
|
||||||
local registry = {
|
local _ = {
|
||||||
-- Groups
|
-- Groups
|
||||||
is_group = is_group,
|
is_group = is_group,
|
||||||
extract_groups = extract_groups,
|
extract_groups = extract_groups,
|
||||||
|
@ -366,6 +464,10 @@ local registry = {
|
||||||
|
|
||||||
-- Sorting
|
-- Sorting
|
||||||
search = search,
|
search = search,
|
||||||
|
name_sort = name_sort,
|
||||||
|
count_sort = count_sort,
|
||||||
|
sort_inventory = sort_inventory,
|
||||||
|
get_sorting_idx = get_sorting_idx,
|
||||||
sort_by_category = sort_by_category,
|
sort_by_category = sort_by_category,
|
||||||
apply_recipe_filters = apply_recipe_filters,
|
apply_recipe_filters = apply_recipe_filters,
|
||||||
|
|
||||||
|
@ -446,7 +548,7 @@ function i3.get(...)
|
||||||
local t = {}
|
local t = {}
|
||||||
|
|
||||||
for i, var in ipairs{...} do
|
for i, var in ipairs{...} do
|
||||||
t[i] = registry[var]
|
t[i] = _[var]
|
||||||
end
|
end
|
||||||
|
|
||||||
return unpack(t)
|
return unpack(t)
|
||||||
|
|
107
etc/gui.lua
107
etc/gui.lua
|
@ -8,13 +8,14 @@ local clr, ESC, check_privs = i3.get("clr", "ESC", "check_privs")
|
||||||
local min, max, floor, ceil, round = i3.get("min", "max", "floor", "ceil", "round")
|
local min, max, floor, ceil, round = i3.get("min", "max", "floor", "ceil", "round")
|
||||||
local sprintf, find, match, sub, upper = i3.get("fmt", "find", "match", "sub", "upper")
|
local sprintf, find, match, sub, upper = i3.get("fmt", "find", "match", "sub", "upper")
|
||||||
local reg_items, reg_tools, reg_entities = i3.get("reg_items", "reg_tools", "reg_entities")
|
local reg_items, reg_tools, reg_entities = i3.get("reg_items", "reg_tools", "reg_entities")
|
||||||
local maxn, sort, concat, copy, insert, remove = i3.get("maxn", "sort", "concat", "copy", "insert", "remove")
|
local maxn, sort, concat, copy, insert, remove =
|
||||||
|
i3.get("maxn", "sort", "concat", "copy", "insert", "remove")
|
||||||
|
|
||||||
local true_str, is_fav, is_num = i3.get("true_str", "is_fav", "is_num")
|
local true_str, is_fav, is_num = i3.get("true_str", "is_fav", "is_num")
|
||||||
local is_group, extract_groups, item_has_groups =
|
|
||||||
i3.get("is_group", "extract_groups", "item_has_groups")
|
|
||||||
local groups_to_items, compression_active, compressible =
|
local groups_to_items, compression_active, compressible =
|
||||||
i3.get("groups_to_items", "compression_active", "compressible")
|
i3.get("groups_to_items", "compression_active", "compressible")
|
||||||
|
local get_sorting_idx, is_group, extract_groups, item_has_groups =
|
||||||
|
i3.get("get_sorting_idx", "is_group", "extract_groups", "item_has_groups")
|
||||||
|
|
||||||
local function fmt(elem, ...)
|
local function fmt(elem, ...)
|
||||||
if not fs_elements[elem] then
|
if not fs_elements[elem] then
|
||||||
|
@ -404,6 +405,84 @@ local function get_container(fs, data, player, yoffset, ctn_len, award_list, awa
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local function show_popup(fs, data)
|
||||||
|
if data.confirm_trash then
|
||||||
|
fs("style_type[box;colors=#999,#999,#808080,#808080]")
|
||||||
|
|
||||||
|
for _ = 1, 3 do
|
||||||
|
fs("box", 2.97, 10.75, 4.3, 0.5, "")
|
||||||
|
end
|
||||||
|
|
||||||
|
fs("label", 3.12, 11, "Confirm trash?")
|
||||||
|
fs("image_button", 5.17, 10.75, 1, 0.5, "", "confirm_trash_yes", "Yes")
|
||||||
|
fs("image_button", 6.27, 10.75, 1, 0.5, "", "confirm_trash_no", "No")
|
||||||
|
|
||||||
|
elseif data.show_settings then
|
||||||
|
fs("style_type[box;colors=#999,#999,#808080,#808080]")
|
||||||
|
|
||||||
|
for _ = 1, 3 do
|
||||||
|
fs("box", 2.1, 9.25, 6, 2, "")
|
||||||
|
end
|
||||||
|
|
||||||
|
for _ = 1, 3 do
|
||||||
|
fs("box", 2.1, 9.25, 6, 0.5, "#707070")
|
||||||
|
end
|
||||||
|
|
||||||
|
fs("image_button", 7.75, 9.35, 0.25, 0.25, PNG.cancel_hover .. "^\\[brighten", "close_settings", "")
|
||||||
|
|
||||||
|
local show_home = data.show_setting == "home"
|
||||||
|
local show_sorting = data.show_setting == "sorting"
|
||||||
|
local show_misc = data.show_setting == "misc"
|
||||||
|
|
||||||
|
fs(fmt("style[setting_home;textcolor=%s;sound=i3_click]", show_home and "#ff0" or "#fff"))
|
||||||
|
fs(fmt("style[setting_sorting;textcolor=%s;sound=i3_click]", show_sorting and "#ff0" or "#fff"))
|
||||||
|
fs(fmt("style[setting_misc;textcolor=%s;sound=i3_click]", show_misc and "#ff0" or "#fff"))
|
||||||
|
|
||||||
|
fs("button", 2.2, 9.25, 1.8, 0.55, "setting_home", "Home")
|
||||||
|
fs("button", 4, 9.25, 1.8, 0.55, "setting_sorting", "Sorting")
|
||||||
|
fs("button", 5.8, 9.25, 1.8, 0.55, "setting_misc", "Misc.")
|
||||||
|
|
||||||
|
if show_home then
|
||||||
|
local home_pos = data.home or ""
|
||||||
|
home_pos = home_pos:gsub(",", ", "):gsub("%(", ""):gsub("%)", "")
|
||||||
|
local home_str = fmt("Home position: %s", home_pos)
|
||||||
|
home_str = data.home and home_str or ES"No home set"
|
||||||
|
|
||||||
|
fs("button", 2.1, 9.7, 6, 0.8, "", home_str)
|
||||||
|
fs("image_button", 4.2, 10.4, 1.8, 0.7, "", "set_home", "Set home")
|
||||||
|
|
||||||
|
elseif show_sorting then
|
||||||
|
fs("button", 2.1, 9.7, 6, 0.8, "", ES"Select the inventory sorting method:")
|
||||||
|
|
||||||
|
fs(fmt("style[prev_sort;fgimg=%s;fgimg_hovered=%s]", PNG.prev, PNG.prev_hover))
|
||||||
|
fs(fmt("style[next_sort;fgimg=%s;fgimg_hovered=%s]", PNG.next, PNG.next_hover))
|
||||||
|
|
||||||
|
fs("image_button", 2.2, 10.6, 0.35, 0.35, "", "prev_sort", "")
|
||||||
|
fs("image_button", 7.65, 10.6, 0.35, 0.35, "", "next_sort", "")
|
||||||
|
|
||||||
|
fs("style[sort_method;font=bold;font_size=20]")
|
||||||
|
fs("button", 2.55, 10.35, 5.1, 0.8, "sort_method", data.sort:gsub("^%l", upper))
|
||||||
|
|
||||||
|
local idx = get_sorting_idx(data.sort)
|
||||||
|
local desc = i3.sorting_methods[idx].description
|
||||||
|
|
||||||
|
if desc then
|
||||||
|
fs(fmt("tooltip[%s;%s]", "sort_method", desc))
|
||||||
|
end
|
||||||
|
|
||||||
|
elseif show_misc then
|
||||||
|
fs("checkbox", 2.4, 10.05,
|
||||||
|
"inv_compress", ES"Inventory compression", tostring(data.inv_compress))
|
||||||
|
|
||||||
|
fs("checkbox", 2.4, 10.5,
|
||||||
|
"auto_sorting", ES"Automatic sorting", tostring(data.auto_sorting))
|
||||||
|
|
||||||
|
fs("checkbox", 2.4, 10.95,
|
||||||
|
"reverse_sorting", ES"Reverse sorting", tostring(data.reverse_sorting))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
local function get_inventory_fs(player, data, fs)
|
local function get_inventory_fs(player, data, fs)
|
||||||
fs("listcolors[#bababa50;#bababa99]")
|
fs("listcolors[#bababa50;#bababa99]")
|
||||||
|
|
||||||
|
@ -481,10 +560,10 @@ local function get_inventory_fs(player, data, fs)
|
||||||
fs("scroll_container_end[]")
|
fs("scroll_container_end[]")
|
||||||
|
|
||||||
local btn = {
|
local btn = {
|
||||||
{"trash", ES"Clear inventory"},
|
{"trash", ES"Clear inventory"},
|
||||||
{"sort_az", ES"Sort items (A-Z)"},
|
{"sort", ES"Sort items"},
|
||||||
{"sort_za", ES"Sort items (Z-A)"},
|
{"settings", ES"Settings"},
|
||||||
{"compress", ES"Compress items"},
|
{"home", ES"Go home"},
|
||||||
}
|
}
|
||||||
|
|
||||||
for i, v in ipairs(btn) do
|
for i, v in ipairs(btn) do
|
||||||
|
@ -493,21 +572,11 @@ local function get_inventory_fs(player, data, fs)
|
||||||
fs(fmt("style[%s;fgimg=%s;fgimg_hovered=%s;content_offset=0]",
|
fs(fmt("style[%s;fgimg=%s;fgimg_hovered=%s;content_offset=0]",
|
||||||
btn_name, PNG[btn_name], PNG[fmt("%s_hover", btn_name)]))
|
btn_name, PNG[btn_name], PNG[fmt("%s_hover", btn_name)]))
|
||||||
|
|
||||||
fs("image_button", i + 3.447 - (i * 0.4), 11.43, 0.35, 0.35, "", btn_name, "")
|
fs("image_button", i + 3.43 - (i * 0.4), 11.43, 0.35, 0.35, "", btn_name, "")
|
||||||
fs(fmt("tooltip[%s;%s]", btn_name, tooltip))
|
fs(fmt("tooltip[%s;%s]", btn_name, tooltip))
|
||||||
end
|
end
|
||||||
|
|
||||||
if data.confirm_trash then
|
show_popup(fs, data)
|
||||||
fs("style_type[box;colors=#999,#999,#808080,#808080]")
|
|
||||||
|
|
||||||
for _ = 1, 3 do
|
|
||||||
fs("box", 2.97, 10.75, 4.3, 0.5, "")
|
|
||||||
end
|
|
||||||
|
|
||||||
fs("label", 3.12, 11, "Confirm trash?")
|
|
||||||
fs("image_button", 5.17, 10.75, 1, 0.5, "", "confirm_trash_yes", "Yes")
|
|
||||||
fs("image_button", 6.27, 10.75, 1, 0.5, "", "confirm_trash_no", "No")
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
local function get_tooltip(item, info, pos)
|
local function get_tooltip(item, info, pos)
|
||||||
|
|
|
@ -7,11 +7,11 @@ local fmt, find, match, sub, lower = i3.get("fmt", "find", "match", "sub", "lowe
|
||||||
local vec_new, vec_mul, vec_eq, vec_round = i3.get("vec_new", "vec_mul", "vec_eq", "vec_round")
|
local vec_new, vec_mul, vec_eq, vec_round = i3.get("vec_new", "vec_mul", "vec_eq", "vec_round")
|
||||||
local sort, copy, insert, remove, indexof = i3.get("sort", "copy", "insert", "remove", "indexof")
|
local sort, copy, insert, remove, indexof = i3.get("sort", "copy", "insert", "remove", "indexof")
|
||||||
|
|
||||||
local msg, is_str, is_fav = i3.get("msg", "is_str", "is_fav")
|
local msg, is_fav = i3.get("msg", "is_fav")
|
||||||
local is_group, extract_groups, groups_to_items =
|
local is_group, extract_groups, groups_to_items =
|
||||||
i3.get("is_group", "extract_groups", "groups_to_items")
|
i3.get("is_group", "extract_groups", "groups_to_items")
|
||||||
local search, sort_by_category, apply_recipe_filters =
|
local search, get_sorting_idx, sort_inventory, sort_by_category, apply_recipe_filters =
|
||||||
i3.get("search", "sort_by_category", "apply_recipe_filters")
|
i3.get("search", "get_sorting_idx", "sort_inventory", "sort_by_category", "apply_recipe_filters")
|
||||||
local show_item, spawn_item, clean_name, compressible, check_privs =
|
local show_item, spawn_item, clean_name, compressible, check_privs =
|
||||||
i3.get("show_item", "spawn_item", "clean_name", "compressible", "check_privs")
|
i3.get("show_item", "spawn_item", "clean_name", "compressible", "check_privs")
|
||||||
|
|
||||||
|
@ -40,6 +40,8 @@ local function reset_data(data)
|
||||||
data.export_usg = nil
|
data.export_usg = nil
|
||||||
data.alt_items = nil
|
data.alt_items = nil
|
||||||
data.confirm_trash = nil
|
data.confirm_trash = nil
|
||||||
|
data.show_settings = nil
|
||||||
|
data.show_setting = "home"
|
||||||
data.items = data.items_raw
|
data.items = data.items_raw
|
||||||
|
|
||||||
if data.current_itab > 1 then
|
if data.current_itab > 1 then
|
||||||
|
@ -66,104 +68,6 @@ local function get_recipes(player, item)
|
||||||
not no_usages and usages or nil
|
not no_usages and usages or nil
|
||||||
end
|
end
|
||||||
|
|
||||||
local function __sort(inv, reverse)
|
|
||||||
sort(inv, function(a, b)
|
|
||||||
if not is_str(a) then
|
|
||||||
a = a:get_name()
|
|
||||||
end
|
|
||||||
|
|
||||||
if not is_str(b) then
|
|
||||||
b = b:get_name()
|
|
||||||
end
|
|
||||||
|
|
||||||
if reverse then
|
|
||||||
return a > b
|
|
||||||
end
|
|
||||||
|
|
||||||
return a < b
|
|
||||||
end)
|
|
||||||
end
|
|
||||||
|
|
||||||
local function sort_itemlist(player, az)
|
|
||||||
local inv = player:get_inventory()
|
|
||||||
local list = inv:get_list("main")
|
|
||||||
local size = inv:get_size("main")
|
|
||||||
local new_inv, stack_meta = {}, {}
|
|
||||||
|
|
||||||
for i = 1, size do
|
|
||||||
local stack = list[i]
|
|
||||||
local name = stack:get_name()
|
|
||||||
local count = stack:get_count()
|
|
||||||
local empty = stack:is_empty()
|
|
||||||
local meta = stack:get_meta():to_table()
|
|
||||||
local wear = stack:get_wear() > 0
|
|
||||||
|
|
||||||
if not empty then
|
|
||||||
if next(meta.fields) or wear then
|
|
||||||
stack_meta[#stack_meta + 1] = stack
|
|
||||||
else
|
|
||||||
new_inv[#new_inv + 1] = fmt("%s %u", name, count)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
for i = 1, #stack_meta do
|
|
||||||
new_inv[#new_inv + 1] = stack_meta[i]
|
|
||||||
end
|
|
||||||
|
|
||||||
if az then
|
|
||||||
__sort(new_inv)
|
|
||||||
else
|
|
||||||
__sort(new_inv, true)
|
|
||||||
end
|
|
||||||
|
|
||||||
inv:set_list("main", new_inv)
|
|
||||||
end
|
|
||||||
|
|
||||||
local function compress_items(player)
|
|
||||||
local inv = player:get_inventory()
|
|
||||||
local list = inv:get_list("main")
|
|
||||||
local size = inv:get_size("main")
|
|
||||||
local new_inv, _new_inv, special = {}, {}, {}
|
|
||||||
|
|
||||||
for i = 1, size do
|
|
||||||
local stack = list[i]
|
|
||||||
local name = stack:get_name()
|
|
||||||
local count = stack:get_count()
|
|
||||||
local stackmax = stack:get_stack_max()
|
|
||||||
local empty = stack:is_empty()
|
|
||||||
local meta = stack:get_meta():to_table()
|
|
||||||
local wear = stack:get_wear() > 0
|
|
||||||
|
|
||||||
if not empty then
|
|
||||||
if next(meta.fields) or wear or count >= stackmax then
|
|
||||||
special[#special + 1] = stack
|
|
||||||
else
|
|
||||||
new_inv[name] = new_inv[name] or 0
|
|
||||||
new_inv[name] = new_inv[name] + count
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
for name, count in pairs(new_inv) do
|
|
||||||
local stackmax = ItemStack(name):get_stack_max()
|
|
||||||
local iter = ceil(count / stackmax)
|
|
||||||
local leftover = count
|
|
||||||
|
|
||||||
for _ = 1, iter do
|
|
||||||
_new_inv[#_new_inv + 1] = fmt("%s %u", name, min(stackmax, leftover))
|
|
||||||
leftover = leftover - stackmax
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
for i = 1, #special do
|
|
||||||
_new_inv[#_new_inv + 1] = special[i]
|
|
||||||
end
|
|
||||||
|
|
||||||
__sort(_new_inv)
|
|
||||||
inv:set_list("main", _new_inv)
|
|
||||||
end
|
|
||||||
|
|
||||||
local function get_stack(player, stack)
|
local function get_stack(player, stack)
|
||||||
local inv = player:get_inventory()
|
local inv = player:get_inventory()
|
||||||
|
|
||||||
|
@ -174,6 +78,13 @@ local function get_stack(player, stack)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local function safe_teleport(player, pos)
|
||||||
|
pos.y = pos.y + 0.5
|
||||||
|
local vel = player:get_velocity()
|
||||||
|
player:add_velocity(vec_mul(vel, -1))
|
||||||
|
player:set_pos(pos)
|
||||||
|
end
|
||||||
|
|
||||||
i3.new_tab {
|
i3.new_tab {
|
||||||
name = "inventory",
|
name = "inventory",
|
||||||
description = S"Inventory",
|
description = S"Inventory",
|
||||||
|
@ -181,6 +92,7 @@ i3.new_tab {
|
||||||
|
|
||||||
fields = function(player, data, fields)
|
fields = function(player, data, fields)
|
||||||
local name = player:get_player_name()
|
local name = player:get_player_name()
|
||||||
|
local inv = player:get_inventory()
|
||||||
local sb_inv = fields.scrbar_inv
|
local sb_inv = fields.scrbar_inv
|
||||||
|
|
||||||
if fields.skins then
|
if fields.skins then
|
||||||
|
@ -194,6 +106,9 @@ i3.new_tab {
|
||||||
data.subcat = indexof(i3.SUBCAT, sub(field, 5))
|
data.subcat = indexof(i3.SUBCAT, sub(field, 5))
|
||||||
break
|
break
|
||||||
|
|
||||||
|
elseif sub(field, 1, 8) == "setting_" then
|
||||||
|
data.show_setting = match(field, "_(%w+)$")
|
||||||
|
|
||||||
elseif find(field, "waypoint_%d+") then
|
elseif find(field, "waypoint_%d+") then
|
||||||
local id, action = match(field, "_(%d+)_(%w+)$")
|
local id, action = match(field, "_(%d+)_(%w+)$")
|
||||||
id = tonumber(id)
|
id = tonumber(id)
|
||||||
|
@ -206,12 +121,7 @@ i3.new_tab {
|
||||||
|
|
||||||
elseif action == "teleport" then
|
elseif action == "teleport" then
|
||||||
local pos = vec_new(waypoint.pos)
|
local pos = vec_new(waypoint.pos)
|
||||||
pos.y = pos.y + 0.5
|
safe_teleport(player, pos)
|
||||||
|
|
||||||
local vel = player:get_velocity()
|
|
||||||
player:add_velocity(vec_mul(vel, -1))
|
|
||||||
player:set_pos(pos)
|
|
||||||
|
|
||||||
msg(name, fmt("Teleported to %s", clr("#ff0", waypoint.name)))
|
msg(name, fmt("Teleported to %s", clr("#ff0", waypoint.name)))
|
||||||
|
|
||||||
elseif action == "refresh" then
|
elseif action == "refresh" then
|
||||||
|
@ -242,23 +152,79 @@ i3.new_tab {
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
if fields.trash then
|
if fields.quit then
|
||||||
|
data.confirm_trash = nil
|
||||||
|
data.show_settings = nil
|
||||||
|
|
||||||
|
elseif fields.trash then
|
||||||
|
data.show_settings = nil
|
||||||
data.confirm_trash = true
|
data.confirm_trash = true
|
||||||
|
|
||||||
|
elseif fields.settings then
|
||||||
|
data.confirm_trash = nil
|
||||||
|
data.show_settings = true
|
||||||
|
|
||||||
elseif fields.confirm_trash_yes or fields.confirm_trash_no then
|
elseif fields.confirm_trash_yes or fields.confirm_trash_no then
|
||||||
if fields.confirm_trash_yes then
|
if fields.confirm_trash_yes then
|
||||||
local inv = player:get_inventory()
|
|
||||||
inv:set_list("main", {})
|
inv:set_list("main", {})
|
||||||
inv:set_list("craft", {})
|
inv:set_list("craft", {})
|
||||||
end
|
end
|
||||||
|
|
||||||
data.confirm_trash = nil
|
data.confirm_trash = nil
|
||||||
|
|
||||||
elseif fields.compress then
|
elseif fields.close_settings then
|
||||||
compress_items(player)
|
data.show_settings = nil
|
||||||
|
|
||||||
elseif fields.sort_az or fields.sort_za then
|
elseif fields.sort then
|
||||||
sort_itemlist(player, fields.sort_az)
|
sort_inventory(player, data)
|
||||||
|
|
||||||
|
elseif fields.prev_sort or fields.next_sort then
|
||||||
|
local idx = get_sorting_idx(data.sort)
|
||||||
|
local tot = #i3.sorting_methods
|
||||||
|
|
||||||
|
idx = idx - (fields.prev_sort and 1 or -1)
|
||||||
|
|
||||||
|
if idx > tot then
|
||||||
|
idx = 1
|
||||||
|
elseif idx == 0 then
|
||||||
|
idx = tot
|
||||||
|
end
|
||||||
|
|
||||||
|
data.sort = i3.sorting_methods[idx].name
|
||||||
|
|
||||||
|
elseif fields.inv_compress then
|
||||||
|
data.inv_compress = false
|
||||||
|
|
||||||
|
if fields.inv_compress == "true" then
|
||||||
|
data.inv_compress = true
|
||||||
|
end
|
||||||
|
|
||||||
|
elseif fields.auto_sorting then
|
||||||
|
data.auto_sorting = false
|
||||||
|
|
||||||
|
if fields.auto_sorting == "true" then
|
||||||
|
data.auto_sorting = true
|
||||||
|
end
|
||||||
|
|
||||||
|
elseif fields.reverse_sorting then
|
||||||
|
data.reverse_sorting = false
|
||||||
|
|
||||||
|
if fields.reverse_sorting == "true" then
|
||||||
|
data.reverse_sorting = true
|
||||||
|
end
|
||||||
|
|
||||||
|
elseif fields.home then
|
||||||
|
if not data.home then
|
||||||
|
return msg(name, "No home set")
|
||||||
|
elseif not check_privs(name, {home = true}) then
|
||||||
|
return msg(name, "'home' privilege missing")
|
||||||
|
end
|
||||||
|
|
||||||
|
safe_teleport(player, core.string_to_pos(data.home))
|
||||||
|
msg(name, S"Welcome back home!")
|
||||||
|
|
||||||
|
elseif fields.set_home then
|
||||||
|
data.home = core.pos_to_string(player:get_pos(), 1)
|
||||||
|
|
||||||
elseif sb_inv and sub(sb_inv, 1, 3) == "CHG" then
|
elseif sb_inv and sub(sb_inv, 1, 3) == "CHG" then
|
||||||
data.scrbar_inv = tonumber(match(sb_inv, "%d+"))
|
data.scrbar_inv = tonumber(match(sb_inv, "%d+"))
|
||||||
|
|
|
@ -11,8 +11,8 @@ local PNG = {
|
||||||
next = "i3_next.png",
|
next = "i3_next.png",
|
||||||
arrow = "i3_arrow.png",
|
arrow = "i3_arrow.png",
|
||||||
trash = "i3_trash.png",
|
trash = "i3_trash.png",
|
||||||
sort_az = "i3_sort_az.png",
|
sort = "i3_sort.png",
|
||||||
sort_za = "i3_sort_za.png",
|
settings = "i3_settings.png",
|
||||||
compress = "i3_compress.png",
|
compress = "i3_compress.png",
|
||||||
fire = "i3_fire.png",
|
fire = "i3_fire.png",
|
||||||
fire_anim = "i3_fire_anim.png",
|
fire_anim = "i3_fire_anim.png",
|
||||||
|
@ -36,14 +36,15 @@ local PNG = {
|
||||||
visible = "i3_visible.png^\\[brighten",
|
visible = "i3_visible.png^\\[brighten",
|
||||||
nonvisible = "i3_non_visible.png",
|
nonvisible = "i3_non_visible.png",
|
||||||
exit = "i3_exit.png",
|
exit = "i3_exit.png",
|
||||||
|
home = "i3_home.png",
|
||||||
|
|
||||||
cancel_hover = "i3_cancel.png^\\[brighten",
|
cancel_hover = "i3_cancel.png^\\[brighten",
|
||||||
search_hover = "i3_search.png^\\[brighten",
|
search_hover = "i3_search.png^\\[brighten",
|
||||||
export_hover = "i3_export.png^\\[brighten",
|
export_hover = "i3_export.png^\\[brighten",
|
||||||
trash_hover = "i3_trash.png^\\[brighten^\\[colorize:#f00:100",
|
trash_hover = "i3_trash.png^\\[brighten^\\[colorize:#f00:100",
|
||||||
compress_hover = "i3_compress.png^\\[brighten",
|
compress_hover = "i3_compress.png^\\[brighten",
|
||||||
sort_az_hover = "i3_sort_az.png^\\[brighten",
|
sort_hover = "i3_sort.png^\\[brighten",
|
||||||
sort_za_hover = "i3_sort_za.png^\\[brighten",
|
settings_hover = "i3_settings.png^\\[brighten",
|
||||||
prev_hover = "i3_next_hover.png^\\[transformFX",
|
prev_hover = "i3_next_hover.png^\\[transformFX",
|
||||||
next_hover = "i3_next_hover.png",
|
next_hover = "i3_next_hover.png",
|
||||||
tab_hover = "i3_tab_hover.png",
|
tab_hover = "i3_tab_hover.png",
|
||||||
|
@ -58,13 +59,14 @@ local PNG = {
|
||||||
add_hover = "i3_add.png^\\[brighten",
|
add_hover = "i3_add.png^\\[brighten",
|
||||||
refresh_hover = "i3_refresh.png^\\[brighten",
|
refresh_hover = "i3_refresh.png^\\[brighten",
|
||||||
exit_hover = "i3_exit.png^\\[brighten",
|
exit_hover = "i3_exit.png^\\[brighten",
|
||||||
|
home_hover = "i3_home.png^\\[brighten",
|
||||||
}
|
}
|
||||||
|
|
||||||
local styles = string.format([[
|
local styles = string.format([[
|
||||||
style_type[field;border=false;bgcolor=transparent]
|
style_type[field;border=false;bgcolor=transparent]
|
||||||
style_type[label,field;font_size=16]
|
style_type[label,field;font_size=16]
|
||||||
style_type[button;border=false;content_offset=0]
|
style_type[button;border=false;content_offset=0]
|
||||||
style_type[image_button,item_image_button;border=false;sound=i3_click]
|
style_type[image_button,item_image_button,checkbox;border=false;sound=i3_click]
|
||||||
style_type[item_image_button;bgimg_hovered=%s]
|
style_type[item_image_button;bgimg_hovered=%s]
|
||||||
|
|
||||||
style[pagenum,no_item,no_rcp;font=bold;font_size=18]
|
style[pagenum,no_item,no_rcp;font=bold;font_size=18]
|
||||||
|
@ -82,7 +84,7 @@ local styles = string.format([[
|
||||||
style[craft_rcp,craft_usg;noclip=true;font_size=16;sound=i3_craft;
|
style[craft_rcp,craft_usg;noclip=true;font_size=16;sound=i3_craft;
|
||||||
bgimg=i3_btn9.png;bgimg_hovered=i3_btn9_hovered.png;
|
bgimg=i3_btn9.png;bgimg_hovered=i3_btn9_hovered.png;
|
||||||
bgimg_pressed=i3_btn9_pressed.png;bgimg_middle=4,6]
|
bgimg_pressed=i3_btn9_pressed.png;bgimg_middle=4,6]
|
||||||
style[confirm_trash_yes,confirm_trash_no;noclip=true;font_size=16;
|
style[confirm_trash_yes,confirm_trash_no,set_home;noclip=true;font_size=16;
|
||||||
bgimg=i3_btn9.png;bgimg_hovered=i3_btn9_hovered.png;
|
bgimg=i3_btn9.png;bgimg_hovered=i3_btn9_hovered.png;
|
||||||
bgimg_pressed=i3_btn9_pressed.png;bgimg_middle=4,6]
|
bgimg_pressed=i3_btn9_pressed.png;bgimg_middle=4,6]
|
||||||
]],
|
]],
|
||||||
|
@ -104,6 +106,7 @@ local fs_elements = {
|
||||||
image = "image[%f,%f;%f,%f;%s]",
|
image = "image[%f,%f;%f,%f;%s]",
|
||||||
tooltip = "tooltip[%f,%f;%f,%f;%s]",
|
tooltip = "tooltip[%f,%f;%f,%f;%s]",
|
||||||
button = "button[%f,%f;%f,%f;%s;%s]",
|
button = "button[%f,%f;%f,%f;%s;%s]",
|
||||||
|
checkbox = "checkbox[%f,%f;%s;%s;%s]",
|
||||||
item_image = "item_image[%f,%f;%f,%f;%s]",
|
item_image = "item_image[%f,%f;%f,%f;%s]",
|
||||||
hypertext = "hypertext[%f,%f;%f,%f;%s;%s]",
|
hypertext = "hypertext[%f,%f;%f,%f;%s;%s]",
|
||||||
bg9 = "background9[%f,%f;%f,%f;%s;false;%u]",
|
bg9 = "background9[%f,%f;%f,%f;%s;false;%u]",
|
||||||
|
|
46
init.lua
46
init.lua
|
@ -30,6 +30,7 @@ i3 = {
|
||||||
},
|
},
|
||||||
|
|
||||||
META_SAVES = {
|
META_SAVES = {
|
||||||
|
home = true,
|
||||||
bag_item = true,
|
bag_item = true,
|
||||||
bag_size = true,
|
bag_size = true,
|
||||||
waypoints = true,
|
waypoints = true,
|
||||||
|
@ -38,14 +39,17 @@ i3 = {
|
||||||
},
|
},
|
||||||
|
|
||||||
-- Caches
|
-- Caches
|
||||||
init_items = {},
|
init_items = {},
|
||||||
recipes_cache = {},
|
fuel_cache = {},
|
||||||
usages_cache = {},
|
usages_cache = {},
|
||||||
fuel_cache = {},
|
recipes_cache = {},
|
||||||
|
|
||||||
|
tabs = {},
|
||||||
|
craft_types = {},
|
||||||
|
|
||||||
recipe_filters = {},
|
recipe_filters = {},
|
||||||
search_filters = {},
|
search_filters = {},
|
||||||
craft_types = {},
|
sorting_methods = {},
|
||||||
tabs = {},
|
|
||||||
|
|
||||||
files = {
|
files = {
|
||||||
api = lf("/etc/api.lua"),
|
api = lf("/etc/api.lua"),
|
||||||
|
@ -140,18 +144,24 @@ local function init_data(player, info)
|
||||||
i3.data[name] = i3.data[name] or {}
|
i3.data[name] = i3.data[name] or {}
|
||||||
local data = i3.data[name]
|
local data = i3.data[name]
|
||||||
|
|
||||||
data.filter = ""
|
data.filter = ""
|
||||||
data.pagenum = 1
|
data.pagenum = 1
|
||||||
data.items = i3.init_items
|
data.items = i3.init_items
|
||||||
data.items_raw = i3.init_items
|
data.items_raw = i3.init_items
|
||||||
data.favs = {}
|
data.favs = {}
|
||||||
data.export_counts = {}
|
data.sort = "alphabetical"
|
||||||
data.current_tab = 1
|
data.show_setting = "home"
|
||||||
data.current_itab = 1
|
data.auto_sorting = false
|
||||||
data.subcat = 1
|
data.reverse_sorting = false
|
||||||
data.scrbar_inv = 0
|
data.inv_compress = true
|
||||||
data.lang_code = get_lang_code(info)
|
data.export_counts = {}
|
||||||
data.fs_version = info.formspec_version
|
data.current_tab = 1
|
||||||
|
data.current_itab = 1
|
||||||
|
data.subcat = 1
|
||||||
|
data.scrbar_inv = 0
|
||||||
|
data.compress = true
|
||||||
|
data.lang_code = get_lang_code(info)
|
||||||
|
data.fs_version = info.formspec_version
|
||||||
|
|
||||||
core.after(0, i3.set_fs, player)
|
core.after(0, i3.set_fs, player)
|
||||||
end
|
end
|
||||||
|
|
Binary file not shown.
After Width: | Height: | Size: 6.0 KiB |
Binary file not shown.
After Width: | Height: | Size: 8.2 KiB |
Binary file not shown.
After Width: | Height: | Size: 6.2 KiB |
Binary file not shown.
Before Width: | Height: | Size: 3.1 KiB |
Binary file not shown.
Before Width: | Height: | Size: 3.5 KiB |
Ŝarĝante…
Reference in New Issue