Compare commits

..

62 Commits
1.5.6 ... 1.8

Author SHA1 Message Date
aa10460886 Bump version 2022-08-07 16:34:41 +02:00
cef11f5301 Update README 2022-08-07 16:34:19 +02:00
2297b47dc0 Minor Fix 2022-08-07 01:40:49 +02:00
a67ef8b08b Some adjusting 2022-08-07 01:23:36 +02:00
48ab26b4c6 Add a font size global change slider 2022-08-07 00:42:52 +02:00
1389027a22 Another UI tweak 2022-08-01 06:43:20 +02:00
629676a975 Bump version 2022-08-01 04:34:06 +02:00
20b8110375 Minor tweak 2022-08-01 04:21:17 +02:00
a3fea93a09 Remove all the legacy code (MT 5.6+ required) 2022-08-01 04:04:14 +02:00
326ee3e098 Improve search bar look 2022-08-01 03:54:35 +02:00
60bdfa34fb Cleaner bg + slot textures 2022-07-04 05:10:31 +02:00
9971b8c3e6 Improve get_desc() 2022-07-04 03:01:30 +02:00
5a14116b69 Improve alphabetical sorting 2022-07-03 19:40:23 +02:00
222e04d2c4 Minor cleaning 2022-07-03 19:21:13 +02:00
8f4c9f28f1 Also for slots 2022-07-03 18:55:13 +02:00
37e0c21ca3 Add support for bgimg_middle (better looking tabs) 2022-07-03 17:27:03 +02:00
057f0cf03f Fix again 2022-07-03 05:07:49 +02:00
dca93b7249 Minor cleaning 2022-07-02 02:21:14 +02:00
1e9c3ce55a Minor cleaning 2022-07-01 17:28:50 +02:00
1627172cce Check string limits correctly 2022-07-01 17:15:10 +02:00
bd356e4a40 Minor QoL 2022-07-01 15:50:04 +02:00
f26c6af9c4 Minor fix 2022-07-01 15:15:21 +02:00
3f2d983091 Minor tweak 2022-07-01 03:46:25 +02:00
6dd95a6a87 Remove the bullshit and fix the sprite once and for all 2022-07-01 03:36:16 +02:00
32779ab56f Add comments 2022-07-01 03:10:37 +02:00
4ccff6621b Minor tweak 2022-07-01 02:43:05 +02:00
7d0f25e8b2 Minor tweak 2022-07-01 00:47:43 +02:00
652c486249 Tweak textures 2022-06-30 16:31:43 +02:00
9ab47fc0f0 Improve UTF-8 string length counting 2022-06-30 15:18:32 +02:00
c635343c9b Add a 404 image when no item found 2022-06-30 03:10:24 +02:00
662c938afb Minor UI improvement 2022-06-30 02:32:03 +02:00
b2c8447971 Some UI improvements + fix bug with custom tabs 2022-06-30 01:15:35 +02:00
c91f787cb2 Correct condition 2022-06-28 01:24:36 +02:00
dcc4068e46 Fix potential crash during sprite creation 2022-06-28 01:03:41 +02:00
c421c49916 Fix bug with group stereotype 2022-06-23 18:23:03 +02:00
3dfcd95c6f Tweak preprocessor to add -- decrement 2022-06-23 15:04:39 +02:00
72d4a5d4b8 Minor cleaning 2022-06-23 14:14:54 +02:00
f2b4c960ad Fix bug with favs 2022-06-23 02:30:54 +02:00
5d6ce3be18 Improve preprocessor a bit 2022-06-23 01:14:45 +02:00
5f413a150b Minor improvement 2022-06-19 15:23:50 +02:00
563dc719d0 Put a upper limit for sprite creation 2022-06-19 14:47:52 +02:00
56cb236025 Fix again 2022-06-19 03:33:21 +02:00
8525633d4c Improve groups caching 2022-06-19 02:54:11 +02:00
cb1dce66f9 Some last fix 2022-06-19 00:36:57 +02:00
2db1e885fc Minor cleanup 2022-06-18 23:40:22 +02:00
354561d54c Finish animation for group buttons (yay) 2022-06-18 23:20:57 +02:00
8e45f303d3 Some fix to previous commit 2022-06-18 22:32:51 +02:00
a6605263f4 Animated image buttons for groups (needs polish) 2022-06-18 21:52:08 +02:00
e17e1080d3 Remove some unessecerary [resize 2022-06-18 19:59:34 +02:00
f0f94017da Cache groups (testing needed) 2022-06-18 19:53:47 +02:00
cf5f18e1c1 Register creative priv in case MTG is not installed 2022-06-17 03:12:55 +02:00
4736b551a8 Fix crash in progressive mode 2022-06-09 12:33:56 +02:00
e1c0f106cc Fix Luacheck warnings on Ubuntu 22.04 2022-04-26 01:50:25 +02:00
46f1136bb7 Empty slots don't make click sound 2022-04-25 19:24:24 +02:00
e88921fe72 Fix crash 2022-04-25 16:00:49 +02:00
7e0feefc89 API doc: minor correction 2022-03-23 03:52:08 +01:00
44a6256589 Fix tab access on priv revoking 2022-03-21 03:55:22 +01:00
1dd742e887 HUD: minor tweak 2022-03-12 04:30:20 +01:00
518ed971ca Hide pagenum when only one page of skins 2022-03-01 12:15:28 +01:00
e9b8085fde Tweak quick crafting 2022-02-27 19:13:27 +01:00
6dc12390db Tweak sorting 2022-02-27 18:53:26 +01:00
44610b879e Skin selection UI overhaul 2022-02-26 02:09:53 +01:00
21 changed files with 965 additions and 781 deletions

4
API.md
View File

@ -17,9 +17,7 @@ i3.new_tab("stuff", {
-- Determine if the tab is visible by a player, `false` or `nil` hide the tab -- Determine if the tab is visible by a player, `false` or `nil` hide the tab
access = function(player, data) access = function(player, data)
local name = player:get_player_name() local name = player:get_player_name()
if name == "singleplayer" then return name == "singleplayer"
return false
end
end, end,
formspec = function(player, data, fs) formspec = function(player, data, fs)

View File

@ -7,7 +7,7 @@
This mod features a modern, powerful inventory menu with a good user experience. This mod features a modern, powerful inventory menu with a good user experience.
**`i3`** provides a rich [**API**](https://github.com/minetest-mods/i3/blob/master/API.md) for mod developers who want to extend it. **`i3`** provides a rich [**API**](https://github.com/minetest-mods/i3/blob/master/API.md) for mod developers who want to extend it.
This mod requires **Minetest 5.4+** This mod requires **Minetest 5.6+**
#### List of features: #### List of features:
- Crafting Guide (survival mode only) - Crafting Guide (survival mode only)
@ -43,6 +43,8 @@ To use this mod in the best conditions:
If the inventory's font size is too big on certain setups (namely Windows 10/11 or 144 DPI display), you should lower the If the inventory's font size is too big on certain setups (namely Windows 10/11 or 144 DPI display), you should lower the
value of the setting `display_density_factor` in your `minetest.conf`. Note that the change is applied after restart. value of the setting `display_density_factor` in your `minetest.conf`. Note that the change is applied after restart.
You can also use the font size slider in the inventory, settings window.
#### Notes #### Notes
`i3` uses a larger inventory than the usual inventories in Minetest games. `i3` uses a larger inventory than the usual inventories in Minetest games.

View File

@ -13,20 +13,21 @@ print[[
local modpath = core.get_modpath"i3" local modpath = core.get_modpath"i3"
local http = core.request_http_api() local http = core.request_http_api()
local storage = core.get_mod_storage() local storage = core.get_mod_storage()
local _loadfile = dofile(modpath .. "/src/operators.lua") local _loadfile = dofile(modpath .. "/src/preprocessor.lua")
local function lf(path) local function lf(path)
return assert(_loadfile(modpath .. path)) return assert(_loadfile(modpath .. path))
end end
i3 = { i3 = {
version = 180,
data = core.deserialize(storage:get_string"data") or {}, data = core.deserialize(storage:get_string"data") or {},
settings = { settings = {
debug_mode = false, debug_mode = false,
max_favs = 6, max_favs = 6,
max_waypoints = 30, max_waypoints = 30,
min_fs_version = 4, min_fs_version = 6,
item_btn_size = 1.1, item_btn_size = 1.1,
drop_bag_on_die = true, drop_bag_on_die = true,
save_interval = 600, -- Player data save interval (in seconds) save_interval = 600, -- Player data save interval (in seconds)
@ -51,9 +52,9 @@ i3 = {
saves = { -- Metadata to save saves = { -- Metadata to save
bag = true, bag = true,
home = true, home = true,
font_size = true,
waypoints = true, waypoints = true,
inv_items = true, inv_items = true,
drop_items = true,
known_recipes = true, known_recipes = true,
}, },
@ -63,7 +64,7 @@ i3 = {
caches = lf"/src/caches.lua", caches = lf"/src/caches.lua",
callbacks = lf"/src/callbacks.lua", callbacks = lf"/src/callbacks.lua",
common = lf"/src/common.lua", common = lf"/src/common.lua",
compress = lf"/src/compress.lua", compress = lf"/src/compression.lua",
detached = lf"/src/detached_inv.lua", detached = lf"/src/detached_inv.lua",
fields = lf"/src/fields.lua", fields = lf"/src/fields.lua",
groups = lf"/src/groups.lua", groups = lf"/src/groups.lua",
@ -82,6 +83,7 @@ i3 = {
tabs = {}, tabs = {},
cubes = {}, cubes = {},
groups = {},
plants = {}, plants = {},
modules = {}, modules = {},
craft_types = {}, craft_types = {},

View File

@ -167,6 +167,13 @@ function i3.set_fs(player)
sort_inventory(player, data) sort_inventory(player, data)
end end
for i, tab in ipairs(i3.tabs) do
if data.tab == i and tab.access and not tab.access(player, data) then
data.tab = 1
break
end
end
local fs = make_fs(player, data) local fs = make_fs(player, data)
player:set_inventory_formspec(fs) player:set_inventory_formspec(fs)
end end
@ -221,8 +228,8 @@ function i3.set_tab(player, tabname)
return return
end end
for i, def in ipairs(i3.tabs) do for i, tab in ipairs(i3.tabs) do
if def.name == tabname then if tab.name == tabname then
data.tab = i data.tab = i
return return
end end
@ -337,7 +344,7 @@ end
i3.add_sorting_method("alphabetical", { i3.add_sorting_method("alphabetical", {
description = S"Sort items by name (A-Z)", description = S"Sort items by name (A-Z)",
func = function(list, data) func = function(list, data)
sorter(list, data.reverse_sorting, 1) sorter(list, data, 1)
return list return list
end end
}) })
@ -345,7 +352,7 @@ i3.add_sorting_method("alphabetical", {
i3.add_sorting_method("numerical", { i3.add_sorting_method("numerical", {
description = S"Sort items by number of items per stack", description = S"Sort items by number of items per stack",
func = function(list, data) func = function(list, data)
sorter(list, data.reverse_sorting, 2) sorter(list, data, 2)
return list return list
end, end,
}) })

View File

@ -1,11 +1,10 @@
local PNG = i3.files.styles()
local replacements = {fuel = {}} local replacements = {fuel = {}}
local http = ... local http = ...
IMPORT("maxn", "copy", "insert", "sort", "match", "sub") IMPORT("maxn", "copy", "insert", "sort", "match", "sub")
IMPORT("is_group", "extract_groups", "item_has_groups", "groups_to_items") IMPORT("true_str", "is_table", "valid_item", "table_merge", "table_replace", "rcp_eq")
IMPORT("fmt", "reg_items", "reg_aliases", "reg_nodes", "draw_cube", "ItemStack") IMPORT("fmt", "reg_items", "reg_aliases", "reg_nodes", "is_cube", "get_cube", "ItemStack")
IMPORT("true_str", "true_table", "is_table", "valid_item", "table_merge", "table_replace", "rcp_eq") IMPORT("is_group", "extract_groups", "item_has_groups", "groups_to_items", "get_group_stereotype")
local function get_burntime(item) local function get_burntime(item)
return core.get_craft_result{method = "fuel", items = {item}}.time return core.get_craft_result{method = "fuel", items = {item}}.time
@ -23,10 +22,56 @@ local function cache_fuel(item)
end end
end end
local function get_item_usages(item, recipe, added) local function cache_groups(group, groups)
local groups = extract_groups(item) i3.groups[group] = {}
i3.groups[group].groups = groups
i3.groups[group].items = groups_to_items(groups)
if #groups == 1 then
i3.groups[group].stereotype = get_group_stereotype(groups[1])
end
local items = i3.groups[group].items
if #items <= 1 then return end
local px, lim, c = 64, 10, 0
local sprite = "[combine:WxH"
for _, item in ipairs(items) do
local def = reg_items[item]
local tiles = def.tiles or def.tile_images
local texture = true_str(def.inventory_image) and def.inventory_image --or tiles[1]
if def.drawtype and is_cube(def.drawtype) then
texture = get_cube(tiles)
end
if texture then
texture = texture:gsub("%^", "\\^"):gsub(":", "\\:") .. fmt("\\^[resize\\:%ux%u", px, px)
sprite = sprite .. fmt(":0,%u=%s", c * px, texture)
c++
if c == lim then break end
end
end
if c > 1 then
sprite = sprite:gsub("WxH", px .. "x" .. px * c)
i3.groups[group].sprite = sprite
i3.groups[group].count = c
end
end
local function get_item_usages(item, recipe, added)
if is_group(item) then
local group = item:sub(7)
local group_cache = i3.groups[group]
local groups = group_cache and group_cache.groups or extract_groups(item)
if not group_cache then
cache_groups(group, groups)
end
if groups then
for name, def in pairs(reg_items) do for name, def in pairs(reg_items) do
if not added[name] and valid_item(def) and item_has_groups(def.groups, groups) then if not added[name] and valid_item(def) and item_has_groups(def.groups, groups) then
local usage = copy(recipe) local usage = copy(recipe)
@ -181,7 +226,7 @@ core.register_craft = function(def)
if is_group(output[1]) then if is_group(output[1]) then
groups = extract_groups(output[1]) groups = extract_groups(output[1])
output = groups_to_items(groups, true) output = groups_to_items(groups)
end end
for i = 1, #output do for i = 1, #output do
@ -242,7 +287,7 @@ local function resolve_aliases(hash)
end end
end end
if newname ~= "" and i3.recipes_cache[oldname] and not hash[newname] then if newname ~= "" and i3.recipes_cache[oldname] and reg_items[newname] and not hash[newname] then
insert(i3.init_items, newname) insert(i3.init_items, newname)
end end
end end
@ -284,40 +329,20 @@ local function init_recipes()
end end
end end
local function get_cube(tiles)
if not true_table(tiles) then
return PNG.blank
end
local top = tiles[1] or PNG.blank
if is_table(top) then
top = top.name or top.image
end
local left = tiles[3] or top or PNG.blank
if is_table(left) then
left = left.name or left.image
end
local right = tiles[5] or left or PNG.blank
if is_table(right) then
right = right.name or right.image
end
return draw_cube(top, left, right)
end
local function init_cubes() local function init_cubes()
for name, def in pairs(reg_nodes) do for name, def in pairs(reg_nodes) do
if def then if def then
local id = core.get_content_id(name) local id = core.get_content_id(name)
local tiles = def.tiles or def.tile_images
if def.drawtype == "normal" or def.drawtype == "liquid" or if is_cube(def.drawtype) then
sub(def.drawtype, 1, 9) == "glasslike" or i3.cubes[id] = get_cube(tiles)
sub(def.drawtype, 1, 8) == "allfaces" then
i3.cubes[id] = get_cube(def.tiles)
elseif sub(def.drawtype, 1, 9) == "plantlike" or sub(def.drawtype, 1, 8) == "firelike" then elseif sub(def.drawtype, 1, 9) == "plantlike" or sub(def.drawtype, 1, 8) == "firelike" then
i3.plants[id] = def.inventory_image .. "^\\[resize:16x16" local texture = true_str(def.inventory_image) and def.inventory_image or tiles[1]
if texture then
i3.plants[id] = texture
end
end end
end end
end end

View File

@ -134,6 +134,7 @@ local function init_data(player, info)
data.player_name = name data.player_name = name
data.filter = "" data.filter = ""
data.pagenum = 1 data.pagenum = 1
data.skin_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 = {}
@ -148,6 +149,7 @@ local function init_data(player, info)
data.itab = 1 data.itab = 1
data.subcat = 1 data.subcat = 1
data.scrbar_inv = 0 data.scrbar_inv = 0
data.font_size = data.font_size or 0
data.lang_code = get_lang_code(info) data.lang_code = get_lang_code(info)
data.fs_version = info.formspec_version data.fs_version = info.formspec_version

View File

@ -9,6 +9,14 @@ local fmt, find, match, gmatch, sub, split, lower, upper =
string.format, string.find, string.match, string.gmatch, string.format, string.find, string.match, string.gmatch,
string.sub, string.split, string.lower, string.upper string.sub, string.split, string.lower, string.upper
if not core.registered_privileges.creative then
core.register_privilege("creative", {
description = "Allow player to use creative inventory",
give_to_singleplayer = false,
give_to_admin = false,
})
end
local old_is_creative_enabled = core.is_creative_enabled local old_is_creative_enabled = core.is_creative_enabled
function core.is_creative_enabled(name) function core.is_creative_enabled(name)
@ -69,6 +77,16 @@ local function toupper(str)
return str:gsub("%f[%w]%l", upper):gsub("_", " ") return str:gsub("%f[%w]%l", upper):gsub("_", " ")
end end
local function utf8_len(str)
local c = 0
for _ in str:gmatch"[%z\1-\127\194-\244][\128-\191]*" do -- Arguably working duct-tape code
c++
end
return c
end
local function get_bag_description(data, stack) local function get_bag_description(data, stack)
local desc = translate(data.lang_code, stack:get_description()) local desc = translate(data.lang_code, stack:get_description())
desc = split(desc, "(")[1] or desc desc = split(desc, "(")[1] or desc
@ -101,7 +119,7 @@ local function search(data)
for i = 1, #data.items_raw do for i = 1, #data.items_raw do
local item = data.items_raw[i] local item = data.items_raw[i]
local def = reg_items[item] local def = reg_items[item]
local desc = lower(translate(data.lang_code, def and def.description)) or "" local desc = lower(translate(data.lang_code, def.description)) or ""
local search_in = fmt("%s %s", item, desc) local search_in = fmt("%s %s", item, desc)
local temp, j, to_add = {}, 1 local temp, j, to_add = {}, 1
@ -228,9 +246,7 @@ local function is_group(item)
end end
local function extract_groups(str) local function extract_groups(str)
if sub(str, 1, 6) == "group:" then return split(sub(str, 7), ",")
return split(sub(str, 7), ",")
end
end end
local function item_has_groups(item_groups, groups) local function item_has_groups(item_groups, groups)
@ -247,30 +263,56 @@ local function valid_item(def)
def.description and def.description ~= "" def.description and def.description ~= ""
end end
local function groups_to_items(groups, get_all) local function get_group_stereotype(group)
if not get_all and #groups == 1 then local stereotype = i3.group_stereotypes[group]
local group = groups[1] local def = reg_items[stereotype]
local stereotype = i3.group_stereotypes[group]
local def = reg_items[stereotype]
if valid_item(def) then if valid_item(def) then
return stereotype return stereotype
end
end end
end
local function groups_to_items(groups)
local names = {} local names = {}
for name, def in pairs(reg_items) do for name, def in pairs(reg_items) do
if valid_item(def) and item_has_groups(def.groups, groups) then if valid_item(def) and item_has_groups(def.groups, groups) then
if get_all then insert(names, name)
insert(names, name)
else
return name
end
end end
end end
return get_all and names or "" sort(names)
return names
end
local function is_cube(drawtype)
return drawtype == "normal" or drawtype == "liquid" or
sub(drawtype, 1, 9) == "glasslike" or
sub(drawtype, 1, 8) == "allfaces"
end
local function get_cube(tiles)
if not true_table(tiles) then
return "i3_blank.png"
end
local top = tiles[1] or "i3_blank.png"
if is_table(top) then
top = top.name or top.image
end
local left = tiles[3] or top or "i3_blank.png"
if is_table(left) then
left = left.name or left.image
end
local right = tiles[5] or left or "i3_blank.png"
if is_table(right) then
right = right.name or right.image
end
return core.inventorycube(top, left, right)
end end
local function apply_recipe_filters(recipes, player) local function apply_recipe_filters(recipes, player)
@ -377,7 +419,8 @@ local function craft_stack(player, data, craft_rcp)
if is_group(name) then if is_group(name) then
items = {} items = {}
local groups = extract_groups(name) local groups = extract_groups(name)
local item_groups = groups_to_items(groups, true) local groupname = name:sub(7)
local item_groups = i3.groups[groupname].items or groups_to_items(groups)
local remaining = count local remaining = count
for _, item in ipairs(item_groups) do for _, item in ipairs(item_groups) do
@ -439,15 +482,16 @@ local function get_sorting_idx(name)
return idx return idx
end end
local function sorter(inv, reverse, mode) local function sorter(inv, data, mode)
sort(inv, function(a, b) sort(inv, function(a, b)
if mode == 1 then if mode == 1 then
a, b = a:get_name(), b:get_name() a = translate(data.lang_code, a:get_short_description())
b = translate(data.lang_code, b:get_short_description())
else else
a, b = a:get_count(), b:get_count() a, b = a:get_count(), b:get_count()
end end
if reverse then if data.reverse_sorting then
return a > b return a > b
end end
@ -514,32 +558,12 @@ local function compress_items(list, start_i)
return new_inv return new_inv
end end
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()
for _, it in ipairs(rej) do
if name == it then
spawn_item(player, stack)
inv:set_stack("main", i, ItemStack(""))
end
end
end
return inv:get_list"main"
end
local function sort_inventory(player, data) local function sort_inventory(player, data)
local inv = player:get_inventory() local inv = player:get_inventory()
local list = inv:get_list"main" local list = inv:get_list"main"
local size = inv:get_size"main" local size = inv:get_size"main"
local start_i = data.ignore_hotbar and (i3.settings.hotbar_len + 1) or 1 local start_i = data.ignore_hotbar and (i3.settings.hotbar_len + 1) or 1
if true_table(data.drop_items) then
list = drop_items(player, inv, list, start_i, data.drop_items)
end
if data.inv_compress then if data.inv_compress then
list = compress_items(list, start_i) list = compress_items(list, start_i)
else else
@ -570,6 +594,7 @@ local function reset_data(data)
data.scrbar_rcp = 1 data.scrbar_rcp = 1
data.scrbar_usg = 1 data.scrbar_usg = 1
data.query_item = nil data.query_item = nil
data.enable_search = nil
data.recipes = nil data.recipes = nil
data.usages = nil data.usages = nil
data.export_rcp = nil data.export_rcp = nil
@ -589,7 +614,7 @@ local function add_hud_waypoint(player, name, pos, color)
return player:hud_add { return player:hud_add {
hud_elem_type = "waypoint", hud_elem_type = "waypoint",
name = name, name = name,
text = " m", text = "m",
world_pos = pos, world_pos = pos,
number = color, number = color,
z_index = -300, z_index = -300,
@ -630,6 +655,7 @@ local _ = {
extract_groups = extract_groups, extract_groups = extract_groups,
item_has_groups = item_has_groups, item_has_groups = item_has_groups,
groups_to_items = groups_to_items, groups_to_items = groups_to_items,
get_group_stereotype = get_group_stereotype,
-- Compression -- Compression
compressible = compressible, compressible = compressible,
@ -657,6 +683,8 @@ local _ = {
msg = msg, msg = msg,
-- Misc. functions -- Misc. functions
is_cube = is_cube,
get_cube = get_cube,
ItemStack = ItemStack, ItemStack = ItemStack,
valid_item = valid_item, valid_item = valid_item,
spawn_item = spawn_item, spawn_item = spawn_item,
@ -709,6 +737,7 @@ local _ = {
match = string.match, match = string.match,
gmatch = string.gmatch, gmatch = string.gmatch,
toupper = toupper, toupper = toupper,
utf8_len = utf8_len,
-- Table -- Table
maxn = table.maxn, maxn = table.maxn,

View File

@ -1,447 +1,466 @@
local set_fs = i3.set_fs local set_fs = i3.set_fs
IMPORT("vec_eq", "vec_round") IMPORT("vec_eq", "vec_round")
IMPORT("reg_items", "reg_aliases") IMPORT("reg_items", "reg_aliases")
IMPORT("S", "random", "translate", "ItemStack") IMPORT("S", "random", "translate", "ItemStack")
IMPORT("sort", "copy", "insert", "remove", "indexof") IMPORT("sort", "copy", "insert", "remove", "indexof")
IMPORT("fmt", "find", "match", "sub", "lower", "split", "toupper") IMPORT("fmt", "find", "match", "sub", "lower", "split", "toupper")
IMPORT("msg", "is_fav", "pos_to_str", "str_to_pos", "add_hud_waypoint", "play_sound", "reset_data") IMPORT("msg", "is_fav", "pos_to_str", "str_to_pos", "add_hud_waypoint", "play_sound", "reset_data")
IMPORT("search", "get_sorting_idx", "sort_inventory", "sort_by_category", "get_recipes", "get_detached_inv") IMPORT("search", "get_sorting_idx", "sort_inventory", "sort_by_category", "get_recipes", "get_detached_inv")
IMPORT("valid_item", "get_stack", "craft_stack", "clean_name", "compressible", "check_privs", "safe_teleport") IMPORT("valid_item", "get_stack", "craft_stack", "clean_name", "compressible", "check_privs", "safe_teleport")
local function inv_fields(player, data, fields) local function inv_fields(player, data, fields)
local name = data.player_name local name = data.player_name
local inv = player:get_inventory() local inv = player:get_inventory()
local sb_inv = fields.scrbar_inv local sb_inv = fields.scrbar_inv
if sb_inv and sub(sb_inv, 1, 3) == "CHG" then if 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+"))
return return
end end
if fields.skins then for field in pairs(fields) do
local id = tonumber(fields.skins) if sub(field, 1, 4) == "btn_" then
local _skins = skins.get_skinlist_for_player(name) data.subcat = indexof(i3.categories, sub(field, 5))
skins.set_player_skin(player, _skins[id]) break
end
elseif sub(field, 1, 3) == "cb_" then
if fields.drop_items then local str = sub(field, 4)
local items = split(fields.drop_items, ",") data[str] = false
data.drop_items = items
end if fields[field] == "true" then
data[str] = true
for field in pairs(fields) do end
if sub(field, 1, 4) == "btn_" then
data.subcat = indexof(i3.categories, sub(field, 5)) elseif sub(field, 1, 8) == "setting_" then
break data.show_setting = match(field, "_(%w+)$")
elseif sub(field, 1, 3) == "cb_" then elseif sub(field, 1, 9) == "skin_btn_" then
local str = sub(field, 4) local id = tonumber(field:match("%d+"))
data[str] = false local _skins = skins.get_skinlist_for_player(name)
skins.set_player_skin(player, _skins[id])
if fields[field] == "true" then
data[str] = true elseif find(field, "waypoint_%d+") then
end local id, action = match(field, "_(%d+)_(%w+)$")
id = tonumber(id)
elseif sub(field, 1, 8) == "setting_" then local waypoint = data.waypoints[id]
data.show_setting = match(field, "_(%w+)$") if not waypoint then return end
elseif find(field, "waypoint_%d+") then if action == "see" then
local id, action = match(field, "_(%d+)_(%w+)$") if data.waypoint_see and data.waypoint_see == id then
id = tonumber(id) data.waypoint_see = nil
local waypoint = data.waypoints[id] else
if not waypoint then return end data.waypoint_see = id
end
if action == "see" then
if data.waypoint_see and data.waypoint_see == id then elseif action == "delete" then
data.waypoint_see = nil player:hud_remove(waypoint.id)
else remove(data.waypoints, id)
data.waypoint_see = id
end elseif action == "teleport" then
local pos = str_to_pos(waypoint.pos)
elseif action == "delete" then safe_teleport(player, pos)
player:hud_remove(waypoint.id) msg(name, S("Teleported to: @1", waypoint.name))
remove(data.waypoints, id)
elseif action == "refresh" then
elseif action == "teleport" then local color = random(0xffffff)
local pos = str_to_pos(waypoint.pos) waypoint.color = color
safe_teleport(player, pos) player:hud_change(waypoint.id, "number", color)
msg(name, S("Teleported to: @1", waypoint.name))
elseif action == "hide" then
elseif action == "refresh" then if waypoint.hide then
local color = random(0xffffff) local new_id = add_hud_waypoint(
waypoint.color = color player, waypoint.name, str_to_pos(waypoint.pos), waypoint.color)
player:hud_change(waypoint.id, "number", color)
waypoint.id = new_id
elseif action == "hide" then waypoint.hide = nil
if waypoint.hide then else
local new_id = add_hud_waypoint( player:hud_remove(waypoint.id)
player, waypoint.name, str_to_pos(waypoint.pos), waypoint.color) waypoint.hide = true
end
waypoint.id = new_id end
waypoint.hide = nil
else break
player:hud_remove(waypoint.id) end
waypoint.hide = true end
end
end if fields.quit then
data.confirm_trash = nil
break data.show_settings = nil
end data.waypoint_see = nil
end data.bag_rename = nil
if fields.quit then if data.filter == "" then
data.confirm_trash = nil data.enable_search = nil
data.show_settings = nil end
data.waypoint_see = nil
data.bag_rename = nil elseif fields.trash then
data.show_settings = nil
elseif fields.trash then data.confirm_trash = true
data.show_settings = nil
data.confirm_trash = true elseif fields.settings then
if not data.show_settings then
elseif fields.settings then data.confirm_trash = nil
if not data.show_settings then data.show_settings = true
data.confirm_trash = nil else
data.show_settings = true data.show_settings = nil
else end
data.show_settings = nil
end elseif fields.confirm_trash_yes or fields.confirm_trash_no then
if fields.confirm_trash_yes then
elseif fields.confirm_trash_yes or fields.confirm_trash_no then inv:set_list("main", {})
if fields.confirm_trash_yes then inv:set_list("craft", {})
inv:set_list("main", {}) end
inv:set_list("craft", {})
end data.confirm_trash = nil
data.confirm_trash = nil elseif fields.close_settings then
data.show_settings = nil
elseif fields.close_settings then
data.show_settings = nil elseif fields.close_preview then
data.waypoint_see = nil
elseif fields.close_preview then
data.waypoint_see = nil elseif fields.sort then
sort_inventory(player, data)
elseif fields.sort then
sort_inventory(player, data) elseif fields.prev_sort or fields.next_sort then
local idx = get_sorting_idx(data.sort)
elseif fields.prev_sort or fields.next_sort then local tot = #i3.sorting_methods
local idx = get_sorting_idx(data.sort)
local tot = #i3.sorting_methods idx -= (fields.prev_sort and 1 or -1)
idx -= (fields.prev_sort and 1 or -1) if idx > tot then
idx = 1
if idx > tot then elseif idx == 0 then
idx = 1 idx = tot
elseif idx == 0 then end
idx = tot
end data.sort = i3.sorting_methods[idx].name
data.sort = i3.sorting_methods[idx].name elseif fields.home then
if not data.home then
elseif fields.home then return msg(name, "No home set")
if not data.home then elseif not check_privs(name, {home = true}) then
return msg(name, "No home set") return msg(name, "'home' privilege missing")
elseif not check_privs(name, {home = true}) then end
return msg(name, "'home' privilege missing")
end safe_teleport(player, str_to_pos(data.home))
msg(name, S"Welcome back home!")
safe_teleport(player, str_to_pos(data.home))
msg(name, S"Welcome back home!") elseif fields.set_home then
data.home = pos_to_str(player:get_pos(), 1)
elseif fields.set_home then
data.home = pos_to_str(player:get_pos(), 1) elseif fields.bag_rename then
data.bag_rename = true
elseif fields.bag_rename then
data.bag_rename = true elseif fields.sb_font_size then
data.font_size = tonumber(fields.sb_font_size:match"-?%d+$")
elseif fields.confirm_rename then
local bag = get_detached_inv("bag", name) elseif fields.confirm_rename then
local bagstack = bag:get_stack("main", 1) local bag = get_detached_inv("bag", name)
local meta = bagstack:get_meta() local bagstack = bag:get_stack("main", 1)
local desc = translate(data.lang_code, bagstack:get_description()) local meta = bagstack:get_meta()
local fill = split(desc, "(")[2] local desc = translate(data.lang_code, bagstack:get_description())
local newname = fields.bag_newname:gsub("([%(%)])", "") local fill = split(desc, "(")[2]
newname = toupper(newname:trim()) local newname = fields.bag_newname:gsub("([%(%)])", "")
newname = toupper(newname:trim())
if fill then
newname = fmt("%s (%s", newname, fill) if fill then
end newname = fmt("%s (%s", newname, fill)
end
meta:set_string("description", newname)
bag:set_stack("main", 1, bagstack) meta:set_string("description", newname)
bag:set_stack("main", 1, bagstack)
data.bag = bagstack:to_string()
data.bag_rename = nil data.bag = bagstack:to_string()
data.bag_rename = nil
elseif fields.waypoint_add then
local max_waypoints = i3.settings.max_waypoints elseif fields.waypoint_add then
local max_waypoints = i3.settings.max_waypoints
if #data.waypoints >= max_waypoints then
play_sound(name, "i3_cannot", 0.8) if #data.waypoints >= max_waypoints then
return msg(name, fmt("Waypoints limit reached (%u)", max_waypoints)) play_sound(name, "i3_cannot", 0.8)
end return msg(name, fmt("Waypoints limit reached (%u)", max_waypoints))
end
local pos = player:get_pos()
local pos = player:get_pos()
for _, v in ipairs(data.waypoints) do
if vec_eq(vec_round(pos), vec_round(str_to_pos(v.pos))) then for _, v in ipairs(data.waypoints) do
play_sound(name, "i3_cannot", 0.8) if vec_eq(vec_round(pos), vec_round(str_to_pos(v.pos))) then
return msg(name, S"You already set a waypoint at this position") play_sound(name, "i3_cannot", 0.8)
end return msg(name, S"You already set a waypoint at this position")
end end
end
local waypoint = fields.waypoint_name
local waypoint = fields.waypoint_name
if fields.waypoint_name == "" then
waypoint = "Waypoint" if fields.waypoint_name == "" then
end waypoint = "Waypoint"
end
local color = random(0xffffff)
local id = add_hud_waypoint(player, waypoint, pos, color) local color = random(0xffffff)
local id = add_hud_waypoint(player, waypoint, pos, color)
insert(data.waypoints, {
name = waypoint, insert(data.waypoints, {
pos = pos_to_str(pos, 1), name = waypoint,
color = color, pos = pos_to_str(pos, 1),
id = id, color = color,
}) id = id,
})
data.scrbar_inv += 1000
data.scrbar_inv += 1000
elseif fields.hide_debug_grid then
data.hide_debug_grid = not data.hide_debug_grid elseif fields.hide_debug_grid then
end data.hide_debug_grid = not data.hide_debug_grid
end
return set_fs(player)
end return set_fs(player)
end
local function select_item(player, data, _f)
local item local function select_item(player, data, fields)
local item
for field in pairs(_f) do
if find(field, ":") then for field in pairs(fields) do
item = field if find(field, ":") then
break item = field
end break
end end
end
if not item then return end
if not item then return end
if compressible(item, data) then
local idx if compressible(item, data) then
local idx
for i = 1, #data.items do
local it = data.items[i] for i = 1, #data.items do
if it == item then local it = data.items[i]
idx = i if it == item then
break idx = i
end break
end end
end
if data.expand ~= "" then
data.alt_items = nil if data.expand ~= "" then
data.alt_items = nil
if item == data.expand then
data.expand = nil if item == data.expand then
return data.expand = nil
end return
end end
end
if idx and item ~= data.expand then
data.alt_items = copy(data.items) if idx and item ~= data.expand then
data.expand = item data.alt_items = copy(data.items)
data.expand = item
if i3.compress_groups[item] then
local items = copy(i3.compress_groups[item]) if i3.compress_groups[item] then
insert(items, fmt("_%s", item)) local items = copy(i3.compress_groups[item])
insert(items, fmt("_%s", item))
sort(items, function(a, b)
if a:sub(1, 1) == "_" then sort(items, function(a, b)
a = a:sub(2) if a:sub(1, 1) == "_" then
end a = a:sub(2)
end
return a < b
end) return a < b
end)
local i = 1
local i = 1
for _, v in ipairs(items) do
if valid_item(reg_items[clean_name(v)]) then for _, v in ipairs(items) do
insert(data.alt_items, idx + i, v) if valid_item(reg_items[clean_name(v)]) then
i++ insert(data.alt_items, idx + i, v)
end i++
end end
end end
end end
else end
if sub(item, 1, 1) == "_" then else
item = sub(item, 2) if sub(item, 1, 1) == "_" then
elseif sub(item, 1, 6) == "group!" then item = sub(item, 2)
item = match(item, "([%w:_]+)$") elseif sub(item, 1, 6) == "group!" then
end item = match(item, "([%w:_]+)$")
end
item = reg_aliases[item] or item
if not reg_items[item] then return end item = reg_aliases[item] or item
if not reg_items[item] then return end
if core.is_creative_enabled(data.player_name) then
local stack = ItemStack(item) if core.is_creative_enabled(data.player_name) then
local stackmax = stack:get_stack_max() local stack = ItemStack(item)
stack = fmt("%s %s", item, stackmax) local stackmax = stack:get_stack_max()
stack = fmt("%s %s", item, stackmax)
return get_stack(player, stack)
end return get_stack(player, stack)
end
if item == data.query_item then return end
local recipes, usages = get_recipes(player, item) if item == data.query_item then return end
local recipes, usages = get_recipes(player, item)
data.query_item = item
data.recipes = recipes data.query_item = item
data.usages = usages data.recipes = recipes
data.rnum = 1 data.usages = usages
data.unum = 1 data.rnum = 1
data.scrbar_rcp = 1 data.unum = 1
data.scrbar_usg = 1 data.scrbar_rcp = 1
data.export_rcp = nil data.scrbar_usg = 1
data.export_usg = nil data.export_rcp = nil
end data.export_usg = nil
end end
end
local function rcp_fields(player, data, fields)
local sb_rcp, sb_usg = fields.scrbar_rcp, fields.scrbar_usg local function rcp_fields(player, data, fields)
local sb_rcp, sb_usg = fields.scrbar_rcp, fields.scrbar_usg
if fields.cancel then
reset_data(data) if fields.filter and fields.filter == "" then
data.enable_search = nil
elseif fields.exit then end
data.query_item = nil
if fields.cancel then
elseif fields.key_enter_field == "filter" or fields.search then reset_data(data)
if fields.filter == "" then
reset_data(data) elseif fields.exit then
return set_fs(player) data.query_item = nil
end
elseif fields.enable_search then
local str = lower(fields.filter) data.enable_search = true
if data.filter == str then return end return set_fs(player)
data.filter = str elseif fields.filter and (fields.key_enter_field == "filter" or fields.search) then
data.pagenum = 1 if fields.filter == "" then
reset_data(data)
search(data) return set_fs(player)
end
if data.itab > 1 then
sort_by_category(data) local str = lower(fields.filter)
end if data.filter == str then return end
elseif fields.prev_page or fields.next_page then data.filter = str
if data.pagemax == 1 then return end data.pagenum = 1
data.pagenum -= (fields.prev_page and 1 or -1)
search(data)
if data.pagenum > data.pagemax then
data.pagenum = 1 if data.itab > 1 then
elseif data.pagenum == 0 then sort_by_category(data)
data.pagenum = data.pagemax end
end
elseif fields.prev_page or fields.next_page then
elseif fields.prev_recipe or fields.next_recipe then if data.pagemax == 1 then return end
local num = data.rnum + (fields.prev_recipe and -1 or 1) data.pagenum -= (fields.prev_page and 1 or -1)
data.rnum = data.recipes[num] and num or (fields.prev_recipe and #data.recipes or 1)
data.export_rcp = nil if data.pagenum > data.pagemax then
data.scrbar_rcp = 1 data.pagenum = 1
elseif data.pagenum == 0 then
elseif fields.prev_usage or fields.next_usage then data.pagenum = data.pagemax
local num = data.unum + (fields.prev_usage and -1 or 1) end
data.unum = data.usages[num] and num or (fields.prev_usage and #data.usages or 1)
data.export_usg = nil elseif fields.prev_skin or fields.next_skin then
data.scrbar_usg = 1 if data.skin_pagemax == 1 then return end
data.skin_pagenum -= (fields.prev_skin and 1 or -1)
elseif fields.fav then
local fav = is_fav(data) if data.skin_pagenum > data.skin_pagemax then
data.skin_pagenum = 1
if #data.favs < i3.settings.max_favs and not fav then elseif data.skin_pagenum == 0 then
insert(data.favs, data.query_item) data.skin_pagenum = data.skin_pagemax
elseif fav then end
remove(data.favs, fav)
end elseif fields.prev_recipe or fields.next_recipe then
local num = data.rnum + (fields.prev_recipe and -1 or 1)
elseif fields.export_rcp or fields.export_usg then data.rnum = data.recipes[num] and num or (fields.prev_recipe and #data.recipes or 1)
if fields.export_rcp then data.export_rcp = nil
data.export_rcp = not data.export_rcp data.scrbar_rcp = 1
if not data.export_rcp then elseif fields.prev_usage or fields.next_usage then
data.scrbar_rcp = 1 local num = data.unum + (fields.prev_usage and -1 or 1)
end data.unum = data.usages[num] and num or (fields.prev_usage and #data.usages or 1)
else data.export_usg = nil
data.export_usg = not data.export_usg data.scrbar_usg = 1
if not data.export_usg then elseif fields.fav then
data.scrbar_usg = 1 local fav = is_fav(data)
end
end if #data.favs < i3.settings.max_favs and not fav then
insert(data.favs, data.query_item)
elseif (sb_rcp and sub(sb_rcp, 1, 3) == "CHG") or (sb_usg and sub(sb_usg, 1, 3) == "CHG") then elseif fav then
data.scrbar_rcp = sb_rcp and tonumber(match(sb_rcp, "%d+")) remove(data.favs, fav)
data.scrbar_usg = sb_usg and tonumber(match(sb_usg, "%d+")) end
elseif fields.craft_rcp or fields.craft_usg then elseif fields.export_rcp or fields.export_usg then
craft_stack(player, data, fields.craft_rcp) if fields.export_rcp then
data.export_rcp = not data.export_rcp
if fields.craft_rcp then
data.export_rcp = nil if not data.export_rcp then
data.scrbar_rcp = 1 data.scrbar_rcp = 1
else end
data.export_usg = nil else
data.scrbar_usg = 1 data.export_usg = not data.export_usg
end
else if not data.export_usg then
select_item(player, data, fields) data.scrbar_usg = 1
end end
end end
core.register_on_player_receive_fields(function(player, formname, fields) elseif (sb_rcp and sub(sb_rcp, 1, 3) == "CHG") or (sb_usg and sub(sb_usg, 1, 3) == "CHG") then
local name = player:get_player_name() data.scrbar_rcp = sb_rcp and tonumber(match(sb_rcp, "%d+"))
data.scrbar_usg = sb_usg and tonumber(match(sb_usg, "%d+"))
if formname == "i3_outdated" then
return false, core.kick_player(name, elseif fields.craft_rcp or fields.craft_usg then
S"Come back when your Minetest client is up-to-date (www.minetest.net).") craft_stack(player, data, fields.craft_rcp)
elseif formname ~= "" then
return false if fields.craft_rcp then
end data.export_rcp = nil
data.scrbar_rcp = 1
-- No-op buttons else
if fields.player_name or fields.awards or fields.home_pos or fields.pagenum or data.export_usg = nil
fields.no_item or fields.no_rcp or fields.select_sorting or fields.sort_method or data.scrbar_usg = 1
fields.bg_content then end
return false else
end select_item(player, data, fields)
end
--print(dump(fields)) end
local data = i3.data[name]
if not data then return end core.register_on_player_receive_fields(function(player, formname, fields)
local name = player:get_player_name()
for f in pairs(fields) do
if sub(f, 1, 4) == "tab_" then if formname == "i3_outdated" then
local tabname = sub(f, 5) return false, core.kick_player(name,
i3.set_tab(player, tabname) S"Come back when your Minetest client is up-to-date (www.minetest.net).")
break elseif formname ~= "" then
elseif sub(f, 1, 5) == "itab_" then return false
data.pagenum = 1 end
data.itab = tonumber(f:sub(-1))
sort_by_category(data) -- No-op buttons
break if fields.player_name or fields.awards or fields.home_pos or fields.pagenum or
end fields.no_item or fields.no_rcp or fields.select_sorting or fields.sort_method or
end fields.bg_content then
return false
rcp_fields(player, data, fields) end
local tab = i3.tabs[data.tab] --print(dump(fields))
local data = i3.data[name]
if tab and tab.fields then if not data then return end
return true, tab.fields(player, data, fields)
end for f in pairs(fields) do
if sub(f, 1, 4) == "tab_" then
return true, set_fs(player) local tabname = sub(f, 5)
end) i3.set_tab(player, tabname)
break
return inv_fields elseif sub(f, 1, 5) == "itab_" then
data.pagenum = 1
data.itab = tonumber(f:sub(-1))
sort_by_category(data)
break
end
end
rcp_fields(player, data, fields)
local tab = i3.tabs[data.tab]
if tab and tab.fields then
return true, tab.fields(player, data, fields)
end
return true, set_fs(player)
end)
return inv_fields

View File

@ -11,6 +11,7 @@ i3.group_stereotypes = {
stone = "default:stone", stone = "default:stone",
leaves = "default:leaves", leaves = "default:leaves",
coal = "default:coal_lump", coal = "default:coal_lump",
fence = "default:fence_wood",
vessel = "vessels:glass_bottle", vessel = "vessels:glass_bottle",
flower = "flowers:dandelion_yellow", flower = "flowers:dandelion_yellow",
water_bucket = "bucket:bucket_water", water_bucket = "bucket:bucket_water",
@ -26,6 +27,7 @@ i3.group_names = {
glass = S"Any glass", glass = S"Any glass",
stick = S"Any stick", stick = S"Any stick",
stone = S"Any stone", stone = S"Any stone",
fence = S"Any fence",
carpet = S"Any carpet", carpet = S"Any carpet",
flower = S"Any flower", flower = S"Any flower",
leaves = S"Any leaves", leaves = S"Any leaves",

File diff suppressed because it is too large Load Diff

View File

@ -3,6 +3,8 @@
local fmt, split = string.format, string.split local fmt, split = string.format, string.split
local var = "[%w%.%[%]\"\'_]" local var = "[%w%.%[%]\"\'_]"
local modpath = core.get_modpath"i3"
local _,_, fs_elements = dofile(modpath .. "/src/styles.lua")
local operators = { local operators = {
["([%+%-%*%^/&|])="] = function(a, b, c) ["([%+%-%*%^/&|])="] = function(a, b, c)
@ -43,6 +45,16 @@ local function compile(data)
return "local " .. a:gsub("\"", "") .. " = i3.get(" .. a .. ")" return "local " .. a:gsub("\"", "") .. " = i3.get(" .. a .. ")"
end) end)
data = data:gsub("([%w_]+)%(", function(a)
if fs_elements[a] then
return fmt("fs('%s',", a)
end
end)
data = data:gsub("([%w_]+)-%-\n", function(a)
return fmt("%s = %s - 1", a, a)
end)
for op, func in pairs(operators) do for op, func in pairs(operators) do
data = data:gsub("(" .. var .. "+)%s?" .. op .. "%s?(" .. var .. "*)", func) data = data:gsub("(" .. var .. "+)%s?" .. op .. "%s?(" .. var .. "*)", func)
end end

View File

@ -32,7 +32,9 @@ local function item_in_inv(item, inv_items)
local inv_items_size = #inv_items local inv_items_size = #inv_items
if is_group(item) then if is_group(item) then
local groups = extract_groups(item) local groupname = item:sub(7)
local group_cache = i3.groups[groupname]
local groups = group_cache and group_cache.groups or extract_groups(item)
for i = 1, inv_items_size do for i = 1, inv_items_size do
local def = core.registered_items[inv_items[i]] local def = core.registered_items[inv_items[i]]
@ -89,6 +91,10 @@ local item_lists = {"main", "craft", "craftpreview"}
local function get_inv_items(player) local function get_inv_items(player)
local inv = player:get_inventory() local inv = player:get_inventory()
if not inv then
return {}
end
local stacks = {} local stacks = {}
for i = 1, #item_lists do for i = 1, #item_lists do

View File

@ -1,3 +1,5 @@
local fmt = string.format
local PNG = { local PNG = {
blank = "i3_blank.png", blank = "i3_blank.png",
bg = "i3_bg.png", bg = "i3_bg.png",
@ -23,7 +25,7 @@ local PNG = {
sign = "i3_sign.png", sign = "i3_sign.png",
cancel = "i3_cancel.png", cancel = "i3_cancel.png",
export = "i3_export.png", export = "i3_export.png",
slot = "i3_slot.png", slot = "i3_slot.png^\\[resize:128x128",
tab = "i3_tab.png", tab = "i3_tab.png",
tab_small = "i3_tab_small.png", tab_small = "i3_tab_small.png",
tab_top = "i3_tab.png^\\[transformFY", tab_top = "i3_tab.png^\\[transformFY",
@ -42,6 +44,9 @@ local PNG = {
home = "i3_home.png", home = "i3_home.png",
flag = "i3_flag.png", flag = "i3_flag.png",
edit = "i3_edit.png", edit = "i3_edit.png",
no_result = "i3_no_result.png",
find_more = "i3_find_more.png",
search_outline = "i3_search_outline.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",
@ -72,19 +77,18 @@ local styles = string.format([[
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,checkbox,dropdown;border=false;sound=i3_click] style_type[image_button,item_image_button,checkbox,dropdown;border=false;sound=i3_click]
style_type[item_image_button;bgimg_hovered=%s] style_type[item_image_button;bgimg_middle=9;padding=-9]
style_type[item_image_button:hovered;bgimg=%s]
style[;sound=]
style[nofav;sound=i3_cannot] style[nofav;sound=i3_cannot]
style[pagenum,no_item,no_rcp;font=bold;font_size=18] style[pagenum,no_item,no_rcp;font=bold;font_size=18]
style[search;fgimg=%s;content_offset=0]
style[enable_search:hovered;bgimg=%s]
style[exit;fgimg=%s;fgimg_hovered=%s;content_offset=0] style[exit;fgimg=%s;fgimg_hovered=%s;content_offset=0]
style[cancel;fgimg=%s;fgimg_hovered=%s;content_offset=0] style[cancel;fgimg=%s;fgimg_hovered=%s;content_offset=0]
style[search;fgimg=%s;fgimg_hovered=%s;content_offset=0] style[prev_page,prev_recipe,prev_usage,prev_sort,prev_skin;fgimg=%s;fgimg_hovered=%s]
style[prev_page;fgimg=%s;fgimg_hovered=%s] style[next_page,next_recipe,next_usage,next_sort,next_skin;fgimg=%s;fgimg_hovered=%s]
style[next_page;fgimg=%s;fgimg_hovered=%s]
style[prev_recipe;fgimg=%s;fgimg_hovered=%s]
style[next_recipe;fgimg=%s;fgimg_hovered=%s]
style[prev_usage;fgimg=%s;fgimg_hovered=%s]
style[next_usage;fgimg=%s;fgimg_hovered=%s]
style[waypoint_add;fgimg=%s;fgimg_hovered=%s;content_offset=0] style[waypoint_add;fgimg=%s;fgimg_hovered=%s;content_offset=0]
style[bag_rename;fgimg=%s;fgimg_hovered=%s;content_offset=0] style[bag_rename;fgimg=%s;fgimg_hovered=%s;content_offset=0]
style[btn_bag,btn_armor,btn_skins;font=bold;font_size=18;content_offset=0;sound=i3_click] style[btn_bag,btn_armor,btn_skins;font=bold;font_size=18;content_offset=0;sound=i3_click]
@ -97,13 +101,10 @@ local styles = string.format([[
style[confirm_trash_yes;sound=i3_trash] style[confirm_trash_yes;sound=i3_trash]
]], ]],
PNG.slot, PNG.slot,
PNG.search_hover,
PNG.search_outline,
PNG.exit, PNG.exit_hover, PNG.exit, PNG.exit_hover,
PNG.cancel, PNG.cancel_hover, PNG.cancel, PNG.cancel_hover,
PNG.search, PNG.search_hover,
PNG.prev, PNG.prev_hover,
PNG.next, PNG.next_hover,
PNG.prev, PNG.prev_hover,
PNG.next, PNG.next_hover,
PNG.prev, PNG.prev_hover, PNG.prev, PNG.prev_hover,
PNG.next, PNG.next_hover, PNG.next, PNG.next_hover,
PNG.add, PNG.add_hover, PNG.add, PNG.add_hover,
@ -116,9 +117,10 @@ local fs_elements = {
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]", checkbox = "checkbox[%f,%f;%s;%s;%s]",
slot = "image[%f,%f;%f,%f;" .. fmt("%s;9]", PNG.slot),
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;12]",
scrollbar = "scrollbar[%f,%f;%f,%f;%s;%s;%u]", scrollbar = "scrollbar[%f,%f;%f,%f;%s;%s;%u]",
model = "model[%f,%f;%f,%f;%s;%s;%s;%s;%s;%s;%s]", model = "model[%f,%f;%f,%f;%s;%s;%s;%s;%s;%s;%s]",
image_button = "image_button[%f,%f;%f,%f;%s;%s;%s]", image_button = "image_button[%f,%f;%f,%f;%s;%s;%s]",

View File

@ -16,30 +16,18 @@ i3.new_tab("test2", {
end, end,
}) })
i3.new_tab("test3", { i3.new_tab("test_creative", {
description = "Test 3", description = "Test creative",
access = function(player, data) access = function(player, data)
local name = player:get_player_name() local name = player:get_player_name()
if name == "singleplayer" then return core.is_creative_enabled(name)
return true
end
end, end,
formspec = function(player, data, fs) formspec = function(player, data, fs)
fs("label[3,1;Test 3]") fs("label[3,1;Creative enabled]")
end, end,
fields = function(player, data, fields) fields = i3.set_fs,
i3.set_fs(player, "label[3,2;Test extra_fs]")
end,
}) })
i3.override_tab("test2", {
description = "Test override",
image = "i3_mesepick.png",
formspec = function(player, data, fs)
fs("label[3,1;Override!]")
end,
})

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 2.0 KiB

BIN
textures/i3_find_more.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

BIN
textures/i3_no_result.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 507 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.7 KiB

After

Width:  |  Height:  |  Size: 2.4 KiB

View File

@ -1,6 +1,7 @@
local exec = os.execute local exec = os.execute
local fmt, find, sub = string.format, string.find, string.sub local fmt, find, sub = string.format, string.find, string.sub
local var = "[%w%.%[%]\"\'_]" local var = "[%w%.%[%]\"\'_]"
local _,_, fs_elements = dofile("../src/styles.lua")
exec "clear" exec "clear"
@ -34,7 +35,7 @@ local files = {
"caches", "caches",
"callbacks", "callbacks",
"common", "common",
"compress", "compression",
"detached_inv", "detached_inv",
"fields", "fields",
"groups", "groups",
@ -84,6 +85,16 @@ local function compile(data)
return "local " .. a:gsub("\"", "") .. " = i3.get(" .. a .. ")" return "local " .. a:gsub("\"", "") .. " = i3.get(" .. a .. ")"
end) end)
data = data:gsub("([%w_]+)%(", function(a)
if fs_elements[a] then
return fmt("fs('%s',", a)
end
end)
data = data:gsub("([%w_]+)-%-\n", function(a)
return fmt("%s = %s - 1", a, a)
end)
for op, func in pairs(operators) do for op, func in pairs(operators) do
data = data:gsub("(" .. var .. "+)%s?" .. op .. "%s?(" .. var .. "*)", func) data = data:gsub("(" .. var .. "+)%s?" .. op .. "%s?(" .. var .. "*)", func)
end end
@ -116,7 +127,7 @@ for _, p in ipairs(files) do
end end
end end
local _file = io.open(path:match("(.*)%.") .. ".l", "w") local _file = io.open(path:match("(.*)%.") .. ".lc", "w")
_file:write(data) _file:write(data)
_file:close() _file:close()
end end
@ -125,6 +136,6 @@ for _, p in ipairs(files) do
end end
exec "luacheck ../init.lua" exec "luacheck ../init.lua"
exec "luacheck ../src/operators.lua" exec "luacheck ../src/preprocessor.lua"
exec "luacheck ../src/*.l" exec "luacheck ../src/*.lc"
exec "rm ../src/*.l" exec "rm ../src/*.lc"