Compare commits

..

27 Commits
1.6 ... 1.7.1

Author SHA1 Message Date
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
14 changed files with 793 additions and 678 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

@ -13,7 +13,7 @@ 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))
@ -63,7 +63,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 +82,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

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,57 @@ 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 c, px, lim = 0, 256, 10
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)
elseif texture then
texture = texture:gsub("%^", "\\^"):gsub(":", "\\:") .. "\\^[resize\\:150x150"
end
if texture then
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 +227,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 +288,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 +330,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

@ -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)
@ -101,7 +109,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 +236,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 +253,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 +409,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
@ -592,7 +625,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,
@ -633,6 +666,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,
@ -660,6 +694,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,

View File

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

View File

@ -13,12 +13,12 @@ IMPORT("vec_new", "vec_sub", "vec_round")
IMPORT("clr", "ESC", "msg", "check_privs") IMPORT("clr", "ESC", "msg", "check_privs")
IMPORT("min", "max", "floor", "ceil", "round") IMPORT("min", "max", "floor", "ceil", "round")
IMPORT("reg_items", "reg_tools", "reg_entities") IMPORT("reg_items", "reg_tools", "reg_entities")
IMPORT("get_bag_description", "get_detached_inv") IMPORT("true_str", "is_fav", "is_num", "str_to_pos")
IMPORT("S", "ES", "translate", "ItemStack", "toupper") IMPORT("S", "ES", "translate", "ItemStack", "toupper")
IMPORT("groups_to_items", "compression_active", "compressible") IMPORT("get_sorting_idx", "compression_active", "compressible")
IMPORT("true_str", "is_fav", "is_num", "get_group", "str_to_pos") IMPORT("get_bag_description", "get_detached_inv", "get_recipes")
IMPORT("maxn", "sort", "concat", "copy", "insert", "remove", "unpack") IMPORT("maxn", "sort", "concat", "copy", "insert", "remove", "unpack")
IMPORT("get_sorting_idx", "is_group", "extract_groups", "item_has_groups", "get_recipes") IMPORT("extract_groups", "groups_to_items", "is_group", "item_has_groups", "get_group")
local function fmt(elem, ...) local function fmt(elem, ...)
if not fs_elements[elem] then if not fs_elements[elem] then
@ -93,7 +93,8 @@ local function get_stack_max(inv, data, is_recipe, rcp)
local def = reg_items[item] local def = reg_items[item]
if def then if def then
local groups = extract_groups(name) local group_cache = i3.groups[name:sub(7)]
local groups = group_cache and group_cache.groups or extract_groups(name)
if item_has_groups(def.groups, groups) then if item_has_groups(def.groups, groups) then
counts_inv[name] = (counts_inv[name] or 0) + count counts_inv[name] = (counts_inv[name] or 0) + count
@ -131,7 +132,7 @@ local function get_inv_slots(fs)
fs"style_type[box;colors=#77777710,#77777710,#777,#777]" fs"style_type[box;colors=#77777710,#77777710,#777,#777]"
for i = 0, hotbar_len - 1 do for i = 0, hotbar_len - 1 do
fs("box", i * size + inv_x + (i * spacing), inv_y, size, size, "") box(i * size + inv_x + (i * spacing), inv_y, size, size, "")
end end
fs(fmt("style_type[list;size=%f;spacing=%f]", size, spacing), fs(fmt("style_type[list;size=%f;spacing=%f]", size, spacing),
@ -147,10 +148,10 @@ end
local function add_subtitle(fs, name, y, ctn_len, font_size, sep, label) local function add_subtitle(fs, name, y, ctn_len, font_size, sep, label)
fs(fmt("style[%s;font=bold;font_size=%u]", name, font_size)) fs(fmt("style[%s;font=bold;font_size=%u]", name, font_size))
fs("button", 0, y, ctn_len, 0.5, name, ESC(label)) button(0, y, ctn_len, 0.5, name, ESC(label))
if sep then if sep then
fs("image", 0, y + 0.55, ctn_len, 0.035, PNG.bar) image(0, y + 0.55, ctn_len, 0.035, PNG.bar)
end end
end end
@ -295,14 +296,14 @@ local function get_isometric_view(fs, pos, X, Y, t, cubes, depth, high)
end end
shift += (base_depth and 0.45 or 0.95) shift += (base_depth and 0.45 or 0.95)
fs("image", 2.7, Y + shift, 0.3, 0.3, PNG.flag) image(2.7, Y + shift, 0.3, 0.3, PNG.flag)
end end
local function get_waypoint_fs(fs, data, player, yextra, ctn_len) local function get_waypoint_fs(fs, data, player, yextra, ctn_len)
fs(fmt("box[0,%f;4.9,0.6;#bababa25]", yextra + 1.1)) fs(fmt("box[0,%f;4.9,0.6;#bababa25]", yextra + 1.1))
fs("label", 0, yextra + 0.85, ES"Waypoint name:") label(0, yextra + 0.85, ES"Waypoint name:")
fs(fmt("field[0.1,%f;4.8,0.6;waypoint_name;;]", yextra + 1.1)) fs(fmt("field[0.1,%f;4.8,0.6;waypoint_name;;]", yextra + 1.1))
fs("image_button", 5.1, yextra + 1.15, 0.5, 0.5, "", "waypoint_add", "") image_button(5.1, yextra + 1.15, 0.5, 0.5, "", "waypoint_add", "")
fs(fmt("tooltip[waypoint_add;%s]", ES"Add waypoint")) fs(fmt("tooltip[waypoint_add;%s]", ES"Add waypoint"))
if #data.waypoints == 0 then return end if #data.waypoints == 0 then return end
@ -313,7 +314,7 @@ local function get_waypoint_fs(fs, data, player, yextra, ctn_len)
local icon_size, yi = 0.35, y + 0.12 local icon_size, yi = 0.35, y + 0.12
fs"style_type[box;colors=#bababa30,#bababa30,#bababa05,#bababa05]" fs"style_type[box;colors=#bababa30,#bababa30,#bababa05,#bababa05]"
fs("box", 0, y, ctn_len, 0.6, "") box(0, y, ctn_len, 0.6, "")
local waypoint_name, lim = v.name, 18 local waypoint_name, lim = v.name, 18
@ -330,7 +331,7 @@ local function get_waypoint_fs(fs, data, player, yextra, ctn_len)
local teleport_priv = check_privs(player, {teleport = true}) local teleport_priv = check_privs(player, {teleport = true})
local waypoint_preview = data.waypoint_see and data.waypoint_see == i local waypoint_preview = data.waypoint_see and data.waypoint_see == i
fs("label", 0.15, y + 0.33, clr(fmt("#%s", hex), waypoint_name)) label(0.15, y + 0.33, clr(fmt("#%s", hex), waypoint_name))
local tooltip = fmt("Name: %s\nPosition:%s", clr("#dbeeff", v.name), local tooltip = fmt("Name: %s\nPosition:%s", clr("#dbeeff", v.name),
v.pos:sub(2,-2):gsub("(%-*%d*%.?%d+)", clr("#dbeeff", " %1"))) v.pos:sub(2,-2):gsub("(%-*%d*%.?%d+)", clr("#dbeeff", " %1")))
@ -339,38 +340,38 @@ local function get_waypoint_fs(fs, data, player, yextra, ctn_len)
tooltip = fmt("%s\n%s", tooltip, clr("#ff0", ES"[Click to teleport]")) tooltip = fmt("%s\n%s", tooltip, clr("#ff0", ES"[Click to teleport]"))
end end
fs("tooltip", 0, y, ctn_len - 2.1, 0.65, tooltip) tooltip(0, y, ctn_len - 2.1, 0.65, tooltip)
local del = fmt("waypoint_%u_delete", i) local del = fmt("waypoint_%u_delete", i)
fs(fmt("style[%s;fgimg=%s;fgimg_hovered=%s;content_offset=0]", del, PNG.trash, PNG.trash_hover)) fs(fmt("style[%s;fgimg=%s;fgimg_hovered=%s;content_offset=0]", del, PNG.trash, PNG.trash_hover))
fs("image_button", ctn_len - 0.5, yi, icon_size, icon_size, "", del, "") image_button(ctn_len - 0.5, yi, icon_size, icon_size, "", del, "")
fs(fmt("tooltip[%s;%s]", del, ES"Remove waypoint")) fs(fmt("tooltip[%s;%s]", del, ES"Remove waypoint"))
local rfs = fmt("waypoint_%u_refresh", i) local rfs = fmt("waypoint_%u_refresh", i)
fs(fmt("style[%s;fgimg=%s;fgimg_hovered=%s;content_offset=0]", rfs, PNG.refresh, PNG.refresh_hover)) fs(fmt("style[%s;fgimg=%s;fgimg_hovered=%s;content_offset=0]", rfs, PNG.refresh, PNG.refresh_hover))
fs("image_button", ctn_len - 1, yi, icon_size, icon_size, "", rfs, "") image_button(ctn_len - 1, yi, icon_size, icon_size, "", rfs, "")
fs(fmt("tooltip[%s;%s]", rfs, ES"Change color")) fs(fmt("tooltip[%s;%s]", rfs, ES"Change color"))
local see = fmt("waypoint_%u_see", i) local see = fmt("waypoint_%u_see", i)
fs(fmt("style[%s;fgimg=%s;fgimg_hovered=%s;content_offset=0]", fs(fmt("style[%s;fgimg=%s;fgimg_hovered=%s;content_offset=0]",
see, waypoint_preview and PNG.search_hover or PNG.search, PNG.search, PNG.search_hover)) see, waypoint_preview and PNG.search_hover or PNG.search, PNG.search, PNG.search_hover))
fs("image_button", ctn_len - 1.5, yi, icon_size, icon_size, "", see, "") image_button(ctn_len - 1.5, yi, icon_size, icon_size, "", see, "")
fs(fmt("tooltip[%s;%s]", see, ES"Preview the waypoint area")) fs(fmt("tooltip[%s;%s]", see, ES"Preview the waypoint area"))
local vsb = fmt("waypoint_%u_hide", i) local vsb = fmt("waypoint_%u_hide", i)
fs(fmt("style[%s;fgimg=%s;content_offset=0]", vsb, v.hide and PNG.nonvisible or PNG.visible)) fs(fmt("style[%s;fgimg=%s;content_offset=0]", vsb, v.hide and PNG.nonvisible or PNG.visible))
fs("image_button", ctn_len - 2, yi, icon_size, icon_size, "", vsb, "") image_button(ctn_len - 2, yi, icon_size, icon_size, "", vsb, "")
fs(fmt("tooltip[%s;%s]", vsb, v.hide and ES"Show waypoint" or ES"Hide waypoint")) fs(fmt("tooltip[%s;%s]", vsb, v.hide and ES"Show waypoint" or ES"Hide waypoint"))
if teleport_priv then if teleport_priv then
local tp = fmt("waypoint_%u_teleport", i) local tp = fmt("waypoint_%u_teleport", i)
fs("button", 0, y, ctn_len - 2.1, 0.6, tp, "") button(0, y, ctn_len - 2.1, 0.6, tp, "")
end end
if waypoint_preview then if waypoint_preview then
fs("image", 0.25, y - 3.5, 5, 4, PNG.bg_content) image(0.25, y - 3.5, 5, 4, PNG.bg_content)
fs("button", 0.25, y - 3.35, 5, 0.55, "area_preview", v.name) button(0.25, y - 3.35, 5, 0.55, "area_preview", v.name)
fs("image_button", 4.65, y - 3.25, 0.25, 0.25, image_button(4.65, y - 3.25, 0.25, 0.25,
PNG.cancel_hover .. "^\\[brighten", "close_preview", "") PNG.cancel_hover .. "^\\[brighten", "close_preview", "")
local pos = str_to_pos(data.waypoints[i].pos) local pos = str_to_pos(data.waypoints[i].pos)
@ -392,20 +393,20 @@ local function get_bag_fs(fs, data, name, esc_name, bag_size, yextra)
local bagstack = bag:get_stack("main", 1) local bagstack = bag:get_stack("main", 1)
local desc = ESC(get_bag_description(data, bagstack)) local desc = ESC(get_bag_description(data, bagstack))
fs("image", 0.5, yextra + 1.85, 0.6, 0.6, PNG.arrow_content) image(0.5, yextra + 1.85, 0.6, 0.6, PNG.arrow_content)
fs(fmt("style[bg_content;bgimg=%s;fgimg=i3_blank.png;bgimg_middle=10,%u;sound=]", PNG.bg_content, m)) fs(fmt("style[bg_content;bgimg=%s;fgimg=i3_blank.png;bgimg_middle=10,%u;sound=]", PNG.bg_content, m))
fs("image_button", 1.1, yextra + 0.5 + (yy or 0), 4.75, h, "", "bg_content", "") image_button(1.1, yextra + 0.5 + (yy or 0), 4.75, h, "", "bg_content", "")
if not data.bag_rename then if not data.bag_rename then
fs("hypertext", 1.3, yextra + 0.8, 4.3, 0.6, "content", hypertext(1.3, yextra + 0.8, 4.3, 0.6, "content",
fmt("<global size=16><center><b>%s</b></center>", desc)) fmt("<global size=16><center><b>%s</b></center>", desc))
fs("image_button", 5.22, yextra + 0.835, 0.25, 0.25, "", "bag_rename", "") image_button(5.22, yextra + 0.835, 0.25, 0.25, "", "bag_rename", "")
fs(fmt("tooltip[%s;%s]", "bag_rename", ES"Rename the bag")) fs(fmt("tooltip[%s;%s]", "bag_rename", ES"Rename the bag"))
else else
fs("box", 1.7, yextra + 0.82, 2.6, 0.4, "#707070") box(1.7, yextra + 0.82, 2.6, 0.4, "#707070")
fs(fmt("field[1.8,%f;2.5,0.4;bag_newname;;%s]", yextra + 0.82, desc), fs(fmt("field[1.8,%f;2.5,0.4;bag_newname;;%s]", yextra + 0.82, desc),
"field_close_on_enter[bag_newname;false]") "field_close_on_enter[bag_newname;false]")
fs("hypertext", 4.4, yextra + 0.88, 0.8, 0.6, "confirm_rename", hypertext(4.4, yextra + 0.88, 0.8, 0.6, "confirm_rename",
fmt("<global size=16><tag name=action color=#fff hovercolor=%s>" .. fmt("<global size=16><tag name=action color=#fff hovercolor=%s>" ..
"<center><b><action name=ok>OK</action></b></center>", colors.yellow)) "<center><b><action name=ok>OK</action></b></center>", colors.yellow))
end end
@ -435,12 +436,12 @@ local function get_container(fs, data, player, yoffset, ctn_len, award_list, awa
local heart_x, heart_h = 0.65, yoffset + 0.75 local heart_x, heart_h = 0.65, yoffset + 0.75
for i = 1, 10 do for i = 1, 10 do
fs("image", heart_x + ((i - 1) * (heart_size + 0.1)), heart_h, image(heart_x + ((i - 1) * (heart_size + 0.1)), heart_h,
heart_size, heart_size, PNG.heart_grey) heart_size, heart_size, PNG.heart_grey)
end end
for i = 1, hearts do for i = 1, hearts do
fs("image", heart_x + ((i - 1) * (heart_size + 0.1)), heart_h, image(heart_x + ((i - 1) * (heart_size + 0.1)), heart_h,
heart_size, heart_size, heart_size, heart_size,
(half == 1 and i == floor(hearts)) and PNG.heart_half or PNG.heart) (half == 1 and i == floor(hearts)) and PNG.heart_half or PNG.heart)
end end
@ -449,10 +450,10 @@ local function get_container(fs, data, player, yoffset, ctn_len, award_list, awa
end end
fs(fmt("list[current_player;craft;%f,%f;3,3;]", 0, yoffset + 1.45)) fs(fmt("list[current_player;craft;%f,%f;3,3;]", 0, yoffset + 1.45))
fs("image", 3.47, yoffset + 2.69, 0.85, 0.85, PNG.arrow) image(3.47, yoffset + 2.69, 0.85, 0.85, PNG.arrow)
fs(fmt("list[current_player;craftpreview;%f,%f;1,1;]", 4.45, yoffset + 2.6), fs(fmt("list[current_player;craftpreview;%f,%f;1,1;]", 4.45, yoffset + 2.6),
fmt("list[detached:i3_trash;main;%f,%f;1,1;]", 4.45, yoffset + 3.75)) fmt("list[detached:i3_trash;main;%f,%f;1,1;]", 4.45, yoffset + 3.75))
fs("image", 4.45, yoffset + 3.75, 1, 1, PNG.trash) image(4.45, yoffset + 3.75, 1, 1, PNG.trash)
local yextra = damage_enabled and 5.5 or 5 local yextra = damage_enabled and 5.5 or 5
@ -461,15 +462,15 @@ local function get_container(fs, data, player, yoffset, ctn_len, award_list, awa
fs(fmt("style[btn_%s;fgimg=%s;fgimg_hovered=%s;content_offset=0]", title, fs(fmt("style[btn_%s;fgimg=%s;fgimg_hovered=%s;content_offset=0]", title,
data.subcat == i and PNG[fmt("%s_hover", title)] or PNG[title], data.subcat == i and PNG[fmt("%s_hover", title)] or PNG[title],
PNG[fmt("%s_hover", title)])) PNG[fmt("%s_hover", title)]))
fs("image_button", 0.25 + ((i - 1) * 1.18), yextra - 0.2, 0.5, 0.5, "", btn_name, "") image_button(0.25 + ((i - 1) * 1.18), yextra - 0.2, 0.5, 0.5, "", btn_name, "")
fs(fmt("tooltip[%s;%s]", btn_name, title:gsub("^%l", upper))) fs(fmt("tooltip[%s;%s]", btn_name, title:gsub("^%l", upper)))
end end
fs("box", 0, yextra + 0.45, ctn_len, 0.045, "#bababa50") box(0, yextra + 0.45, ctn_len, 0.045, "#bababa50")
fs("box", (data.subcat - 1) * 1.18, yextra + 0.45, 1, 0.045, "#f9826c") box((data.subcat - 1) * 1.18, yextra + 0.45, 1, 0.045, "#f9826c")
local function not_installed(modname) local function not_installed(modname)
fs("hypertext", 0, yextra + 0.9, ctn_len, 0.6, "not_installed", hypertext(0, yextra + 0.9, ctn_len, 0.6, "not_installed",
fmt("<global size=16><center><style color=%s font=mono>%s</style> not installed</center>", fmt("<global size=16><center><style color=%s font=mono>%s</style> not installed</center>",
colors.blue, modname)) colors.blue, modname))
end end
@ -484,8 +485,8 @@ local function get_container(fs, data, player, yoffset, ctn_len, award_list, awa
local armor_def = armor.def[name] local armor_def = armor.def[name]
fs(fmt("list[detached:%s_armor;armor;0,%f;3,2;]", esc_name, yextra + 0.7)) fs(fmt("list[detached:%s_armor;armor;0,%f;3,2;]", esc_name, yextra + 0.7))
fs("label", 3.65, yextra + 1.55, fmt("%s: %s", ES"Level", armor_def.level)) label(3.65, yextra + 1.55, fmt("%s: %s", ES"Level", armor_def.level))
fs("label", 3.65, yextra + 2.05, fmt("%s: %s", ES"Heal", armor_def.heal)) label(3.65, yextra + 2.05, fmt("%s: %s", ES"Heal", armor_def.heal))
elseif data.subcat == 3 then elseif data.subcat == 3 then
if not i3.modules.skins then if not i3.modules.skins then
@ -494,17 +495,21 @@ local function get_container(fs, data, player, yoffset, ctn_len, award_list, awa
local _skins = skins.get_skinlist_for_player(name) local _skins = skins.get_skinlist_for_player(name)
local skin_name = skins.get_player_skin(player).name local skin_name = skins.get_player_skin(player).name
local btn_y = yextra + 0.75 local spp, add_y = 24, 0
local spp = 24
data.skin_pagemax = max(1, ceil(#_skins / spp)) if #_skins > spp then
local btn_y = yextra + 0.75
add_y += 0.6
fs("image_button", 1.5, btn_y, 0.35, 0.35, "", "prev_skin", "") data.skin_pagemax = max(1, ceil(#_skins / spp))
fs("image_button", 3.85, btn_y, 0.35, 0.35, "", "next_skin", "")
fs"style[skin_page;font=bold;font_size=18]" image_button(1.5, btn_y, 0.35, 0.35, "", "prev_skin", "")
fs("button", 1.85, btn_y - 0.23, 2, 0.8, "skin_page", image_button(3.85, btn_y, 0.35, 0.35, "", "next_skin", "")
fmt("%s / %u", clr(colors.yellow, data.skin_pagenum), data.skin_pagemax))
fs"style[skin_page;font=bold;font_size=18]"
button(1.85, btn_y - 0.23, 2, 0.8, "skin_page",
fmt("%s / %u", clr(colors.yellow, data.skin_pagenum), data.skin_pagemax))
end
local first = (data.skin_pagenum - 1) * spp local first = (data.skin_pagenum - 1) * spp
local last = first + spp - 1 local last = first + spp - 1
@ -523,9 +528,9 @@ local function get_container(fs, data, player, yoffset, ctn_len, award_list, awa
local X = (i % 3) * 1.93 local X = (i % 3) * 1.93
local Y = ceil((i % spp - X) / 3 + 1) local Y = ceil((i % spp - X) / 3 + 1)
Y += (Y * 2.45) + yextra - 2.15 Y += (Y * 2.45) + yextra - 2.75 + add_y
fs("image_button", X, Y, 1.86, 3.4, "", btn_name, "") image_button(X, Y, 1.86, 3.4, "", btn_name, "")
fs(fmt("tooltip[%s;%s]", btn_name, ESC(skin.name))) fs(fmt("tooltip[%s;%s]", btn_name, ESC(skin.name)))
end end
@ -547,25 +552,25 @@ local function show_popup(fs, data)
fs"style_type[box;colors=#999,#999,#808080,#808080]" fs"style_type[box;colors=#999,#999,#808080,#808080]"
for _ = 1, 3 do for _ = 1, 3 do
fs("box", 2.97, 10.75, 4.3, 0.5, "") box(2.97, 10.75, 4.3, 0.5, "")
end end
fs("label", 3.12, 11, "Confirm trash?") label(3.12, 11, "Confirm trash?")
fs("image_button", 5.17, 10.75, 1, 0.5, "", "confirm_trash_yes", "Yes") 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") image_button(6.27, 10.75, 1, 0.5, "", "confirm_trash_no", "No")
elseif data.show_settings then elseif data.show_settings then
fs"style_type[box;colors=#999,#999,#808080,#808080]" fs"style_type[box;colors=#999,#999,#808080,#808080]"
for _ = 1, 3 do for _ = 1, 3 do
fs("box", 2.1, 9.25, 6, 2, "") box(2.1, 9.25, 6, 2, "")
end end
for _ = 1, 3 do for _ = 1, 3 do
fs("box", 2.1, 9.25, 6, 0.5, "#707070") box(2.1, 9.25, 6, 0.5, "#707070")
end end
fs("image_button", 7.75, 9.35, 0.25, 0.25, PNG.cancel_hover .. "^\\[brighten", "close_settings", "") 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_home = data.show_setting == "home"
local show_sorting = data.show_setting == "sorting" local show_sorting = data.show_setting == "sorting"
@ -578,9 +583,9 @@ local function show_popup(fs, data)
fmt("style[setting_misc;textcolor=%s;font=bold;sound=i3_click]", fmt("style[setting_misc;textcolor=%s;font=bold;sound=i3_click]",
show_misc and colors.yellow or "#fff")) show_misc and colors.yellow or "#fff"))
fs("button", 2.2, 9.25, 1.8, 0.55, "setting_home", "Home") button(2.2, 9.25, 1.8, 0.55, "setting_home", "Home")
fs("button", 4, 9.25, 1.8, 0.55, "setting_sorting", "Sorting") button(4, 9.25, 1.8, 0.55, "setting_sorting", "Sorting")
fs("button", 5.8, 9.25, 1.8, 0.55, "setting_misc", "Misc.") button(5.8, 9.25, 1.8, 0.55, "setting_misc", "Misc.")
if show_home then if show_home then
local coords, c, str = {"X", "Y", "Z"}, 0, ES"No home set" local coords, c, str = {"X", "Y", "Z"}, 0, ES"No home set"
@ -594,17 +599,17 @@ local function show_popup(fs, data)
end) end)
end end
fs("hypertext", 2.1, 9.9, 6, 0.6, "home_pos", fmt("<global size=16><center>%s</center>", str)) hypertext(2.1, 9.9, 6, 0.6, "home_pos", fmt("<global size=16><center>%s</center>", str))
fs("image_button", 4.2, 10.4, 1.8, 0.7, "", "set_home", "Set home") image_button(4.2, 10.4, 1.8, 0.7, "", "set_home", "Set home")
elseif show_sorting then elseif show_sorting then
fs("button", 2.1, 9.7, 6, 0.8, "select_sorting", ES"Select the inventory sorting method:") button(2.1, 9.7, 6, 0.8, "select_sorting", ES"Select the inventory sorting method:")
fs("image_button", 2.2, 10.6, 0.35, 0.35, "", "prev_sort", "") 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", "") image_button(7.65, 10.6, 0.35, 0.35, "", "next_sort", "")
fs"style[sort_method;font=bold;font_size=20]" fs"style[sort_method;font=bold;font_size=20]"
fs("button", 2.55, 10.36, 5.1, 0.8, "sort_method", toupper(data.sort)) button(2.55, 10.36, 5.1, 0.8, "sort_method", toupper(data.sort))
local idx = get_sorting_idx(data.sort) local idx = get_sorting_idx(data.sort)
local desc = i3.sorting_methods[idx].description local desc = i3.sorting_methods[idx].description
@ -614,13 +619,13 @@ local function show_popup(fs, data)
end end
elseif show_misc then elseif show_misc then
fs("checkbox", 2.4, 10.05, "cb_inv_compress", "Compression", tostring(data.inv_compress)) checkbox(2.4, 10.05, "cb_inv_compress", "Compression", tostring(data.inv_compress))
fs("checkbox", 2.4, 10.5, "cb_reverse_sorting", "Reverse mode", tostring(data.reverse_sorting)) checkbox(2.4, 10.5, "cb_reverse_sorting", "Reverse mode", tostring(data.reverse_sorting))
fs("checkbox", 2.4, 10.95, "cb_ignore_hotbar", "Ignore hotbar", tostring(data.ignore_hotbar)) checkbox(2.4, 10.95, "cb_ignore_hotbar", "Ignore hotbar", tostring(data.ignore_hotbar))
fs("checkbox", 5.4, 10.05, "cb_auto_sorting", "Automation", tostring(data.auto_sorting)) checkbox(5.4, 10.05, "cb_auto_sorting", "Automation", tostring(data.auto_sorting))
for _ = 1, 3 do for _ = 1, 3 do
fs("box", 5.4, 10.68, 2.4, 0.45, "#707070") box(5.4, 10.68, 2.4, 0.45, "#707070")
end end
fs("style[drop_items;font_size=15;font=mono;textcolor=#dbeeff]", fs("style[drop_items;font_size=15;font=mono;textcolor=#dbeeff]",
@ -663,12 +668,12 @@ local function get_inventory_fs(player, data, fs)
local textures = concat(t, ","):gsub("!", ",") local textures = concat(t, ","):gsub("!", ",")
--fs("style[player_model;bgcolor=black]") --fs("style[player_model;bgcolor=black]")
fs("model", 0.2, 0.2, armor_skin and 4 or 3.4, ctn_hgt, model(0.2, 0.2, armor_skin and 4 or 3.4, ctn_hgt,
"player_model", props.mesh, textures, "0,-150", "false", "false", "player_model", props.mesh, textures, "0,-150", "false", "false",
fmt("%u,%u%s", anim.x, anim.y, data.fs_version >= 5 and ";30" or "")) fmt("%u,%u%s", anim.x, anim.y, data.fs_version >= 5 and ";30" or ""))
else else
local size = 2.5 local size = 2.5
fs("image", 0.7, 0.2, size, size * props.visual_size.y, props.textures[1]) image(0.7, 0.2, size, size * props.visual_size.y, props.textures[1])
end end
local awards_unlocked, award_list, award_list_nb = 0 local awards_unlocked, award_list, award_list_nb = 0
@ -688,9 +693,10 @@ local function get_inventory_fs(player, data, fs)
elseif i3.modules.skins and data.subcat == 3 then elseif i3.modules.skins and data.subcat == 3 then
local spp = 24 local spp = 24
local _skins = skins.get_skinlist_for_player(data.player_name) local _skins = skins.get_skinlist_for_player(data.player_name)
local num = max(1, min(spp, #_skins - ((data.skin_pagenum - 1) * spp))) local nb = #_skins
local num = max(1, min(spp, nb - ((data.skin_pagenum - 1) * spp)))
max_val += ceil(num / 3) * 34 max_val += ceil(num / 3) * (nb > spp and 34 or 31)
elseif i3.modules.awards and data.subcat == 4 then elseif i3.modules.awards and data.subcat == 4 then
award_list = awards.get_award_states(data.player_name) award_list = awards.get_award_states(data.player_name)
@ -737,7 +743,7 @@ local function get_inventory_fs(player, data, fs)
local btn_name, tooltip = unpack(v) local btn_name, tooltip = unpack(v)
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.43 - (i * 0.4), 11.43, 0.35, 0.35, "", btn_name, "") 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
@ -824,7 +830,7 @@ local function get_tooltip(item, info, pos)
return fmt("tooltip[%s;%s]", item, ESC(tooltip)) return fmt("tooltip[%s;%s]", item, ESC(tooltip))
end end
local function get_output_fs(fs, data, rcp, is_recipe, shapeless, right, btn_size, _btn_size) local function get_output_fs(fs, data, rcp, is_recipe, shapeless, right, btn_size, btn_size2)
local custom_recipe = i3.craft_types[rcp.type] local custom_recipe = i3.craft_types[rcp.type]
local cooking = rcp.type == "cooking" local cooking = rcp.type == "cooking"
local fuel = rcp.type == "fuel" local fuel = rcp.type == "fuel"
@ -833,7 +839,7 @@ local function get_output_fs(fs, data, rcp, is_recipe, shapeless, right, btn_siz
local icon, tooltip = PNG.blank local icon, tooltip = PNG.blank
if custom_recipe and true_str(custom_recipe.icon) then if custom_recipe and true_str(custom_recipe.icon) then
icon = fmt("%s^\\[resize:16x16", custom_recipe.icon) icon = custom_recipe.icon
elseif shapeless then elseif shapeless then
icon = PNG.shapeless icon = PNG.shapeless
end end
@ -842,9 +848,9 @@ local function get_output_fs(fs, data, rcp, is_recipe, shapeless, right, btn_siz
local pos_y = data.yoffset + 0.9 local pos_y = data.yoffset + 0.9
if cooking then if cooking then
fs("animated_image", pos_x, pos_y, 0.5, 0.5, PNG.furnace_anim, 8, 180) animated_image(pos_x, pos_y, 0.5, 0.5, PNG.furnace_anim, 8, 180)
else else
fs("image", pos_x, pos_y, 0.5, 0.5, icon) image(pos_x, pos_y, 0.5, 0.5, icon)
end end
if custom_recipe and true_str(custom_recipe.description) then if custom_recipe and true_str(custom_recipe.description) then
@ -856,19 +862,19 @@ local function get_output_fs(fs, data, rcp, is_recipe, shapeless, right, btn_siz
end end
if tooltip then if tooltip then
fs("tooltip", pos_x, pos_y, 0.5, 0.5, ESC(tooltip)) tooltip(pos_x, pos_y, 0.5, 0.5, ESC(tooltip))
end end
end end
local BTN_SIZE = i3.settings.item_btn_size local BTN_SIZE = i3.settings.item_btn_size
local arrow_X = right + 0.2 + (_btn_size or BTN_SIZE) local arrow_X = right + 0.2 + (btn_size2 or BTN_SIZE)
local X = arrow_X + 1.2 local X = arrow_X + 1.2
local Y = data.yoffset + 1.4 local Y = data.yoffset + 1.4
fs("image", arrow_X, Y + 0.06, 1, 1, PNG.arrow) image(arrow_X, Y + 0.06, 1, 1, PNG.arrow)
if fuel then if fuel then
fs("animated_image", X + 0.05, Y, BTN_SIZE, BTN_SIZE, PNG.fire_anim, 8, 180) animated_image(X + 0.05, Y, BTN_SIZE, BTN_SIZE, PNG.fire_anim, 8, 180)
return return
end end
@ -887,14 +893,14 @@ local function get_output_fs(fs, data, rcp, is_recipe, shapeless, right, btn_siz
fs(fmt("style_type[list;size=%f]", BTN_SIZE)) fs(fmt("style_type[list;size=%f]", BTN_SIZE))
fs"listcolors[#bababa50;#bababa99]" fs"listcolors[#bababa50;#bababa99]"
fs(fmt("list[detached:i3_output_%s_%s;main;%f,%f;1,1;]", rcp_usg, data.player_name, X + 0.11, Y)) fs(fmt("list[detached:i3_output_%s_%s;main;%f,%f;1,1;]", rcp_usg, data.player_name, X + 0.11, Y))
fs("button", X + 0.11, Y, BTN_SIZE, BTN_SIZE, _name, "") button(X + 0.11, Y, BTN_SIZE, BTN_SIZE, _name, "")
local inv = get_detached_inv(fmt("output_%s", rcp_usg), data.player_name) local inv = get_detached_inv(fmt("output_%s", rcp_usg), data.player_name)
inv:set_stack("main", 1, item) inv:set_stack("main", 1, item)
pos = {x = X + 0.11, y = Y} pos = {x = X + 0.11, y = Y}
else else
fs("image", X, Y - 0.11, bt_s, bt_s, PNG.slot) image(X, Y - 0.11, bt_s, bt_s, PNG.slot)
fs("item_image_button", item_image_button(
X + 0.11, Y, BTN_SIZE, BTN_SIZE, X + 0.11, Y, BTN_SIZE, BTN_SIZE,
fmt("%s %u %u", name, count * (is_recipe and data.scrbar_rcp or data.scrbar_usg or 1), wear), fmt("%s %u %u", name, count * (is_recipe and data.scrbar_rcp or data.scrbar_usg or 1), wear),
_name, "") _name, "")
@ -987,10 +993,12 @@ local function get_grid_fs(fs, data, rcp, is_recipe)
end end
local groups local groups
local group_cache = i3.groups[name:sub(7)]
if is_group(name) then if is_group(name) then
groups = extract_groups(name) groups = group_cache and group_cache.groups or extract_groups(name)
name = groups_to_items(groups) name = group_cache and (group_cache.stereotype or group_cache.items[1]) or
groups_to_items(groups)[1]
end end
local label = groups and "\nG" or "" local label = groups and "\nG" or ""
@ -1018,14 +1026,25 @@ local function get_grid_fs(fs, data, rcp, is_recipe)
end end
if not large_recipe then if not large_recipe then
fs("image", X, Y, btn_size, btn_size, PNG.slot) image(X, Y, btn_size, btn_size, PNG.slot)
end end
local btn_name = groups and fmt("group!%s!%s", groups[1], name) or name local btn_name = groups and fmt("group!%s!%s", groups[1], name) or name
local _count = count * (is_recipe and data.scrbar_rcp or data.scrbar_usg or 1)
fs("item_image_button", X, Y, btn_size, btn_size, if group_cache and group_cache.sprite and not large_recipe then
fmt("%s %u", name, count * (is_recipe and data.scrbar_rcp or data.scrbar_usg or 1)), local sprite = ESC(group_cache.sprite)
btn_name, label)
item_image_button(X, Y, btn_size, btn_size, "", btn_name, "")
animated_image(X + 0.01, Y + 0.01, 1.89, 1.89, sprite, group_cache.count, 1000)
label(X + 0.45, Y + 0.18, label)
if _count > 1 then
label(X + 0.8, Y + 0.9, _count)
end
else
item_image_button(X, Y, btn_size, btn_size, fmt("%s %u", name, _count), btn_name, label)
end
local def = reg_items[name] local def = reg_items[name]
local unknown = not def or nil local unknown = not def or nil
@ -1064,7 +1083,7 @@ local function get_rcp_lbl(fs, data, panel, rn, is_recipe)
local rcp = is_recipe and panel.rcp[data.rnum] or panel.rcp[data.unum] local rcp = is_recipe and panel.rcp[data.rnum] or panel.rcp[data.unum]
if rcp.custom then if rcp.custom then
fs("hypertext", data.inv_width + 4.8, data.yoffset + 0.12, 3, 0.6, "custom_rcp", hypertext(data.inv_width + 4.8, data.yoffset + 0.12, 3, 0.6, "custom_rcp",
fmt("<global size=16><right><i>%s</i></right>", ES"Custom recipe")) fmt("<global size=16><right><i>%s</i></right>", ES"Custom recipe"))
end end
@ -1077,7 +1096,7 @@ local function get_rcp_lbl(fs, data, panel, rn, is_recipe)
local one = rn == 1 local one = rn == 1
local y = data.yoffset + 3.3 local y = data.yoffset + 3.3
fs("hypertext", data.inv_width + (one and 4.7 or 3.95), y, 3, 0.6, "rcp_num", hypertext(data.inv_width + (one and 4.7 or 3.95), y, 3, 0.6, "rcp_num",
fmt("<global size=16><right>%s</right>", lbl)) fmt("<global size=16><right>%s</right>", lbl))
if not one then if not one then
@ -1086,8 +1105,8 @@ local function get_rcp_lbl(fs, data, panel, rn, is_recipe)
local next_name = fmt("next_%s", btn_suffix) local next_name = fmt("next_%s", btn_suffix)
local size = 0.3 local size = 0.3
fs("image_button", data.inv_width + 7.05, y, size, size, "", prev_name, "") image_button(data.inv_width + 7.05, y, size, size, "", prev_name, "")
fs("image_button", data.inv_width + 7.5, y, size, size, "", next_name, "") image_button(data.inv_width + 7.5, y, size, size, "", next_name, "")
end end
get_grid_fs(fs, data, rcp, is_recipe) get_grid_fs(fs, data, rcp, is_recipe)
@ -1134,7 +1153,7 @@ local function get_model_fs(fs, data, def, model_alias)
insert(t, t[#t]) insert(t, t[#t])
end end
fs("model", data.inv_width + 6.6, data.yoffset + 0.05, 1.3, 1.3, "preview", model(data.inv_width + 6.6, data.yoffset + 0.05, 1.3, 1.3, "preview",
def.mesh, concat(t, ","), "0,0", "true", "true", def.mesh, concat(t, ","), "0,0", "true", "true",
model_alias and model_alias.frames or "") model_alias and model_alias.frames or "")
end end
@ -1149,16 +1168,16 @@ local function get_header(fs, data)
local fav_marked = fmt("i3_fav%s.png", fav and "_off" or "") local fav_marked = fmt("i3_fav%s.png", fav and "_off" or "")
fs(fmt("style[fav;fgimg=%s;fgimg_hovered=%s;fgimg_pressed=%s]", fs(fmt("style[fav;fgimg=%s;fgimg_hovered=%s;fgimg_pressed=%s]",
fmt("i3_fav%s.png", fav and "" or "_off"), fav_marked, fav_marked)) fmt("i3_fav%s.png", fav and "" or "_off"), fav_marked, fav_marked))
fs("image_button", star_x, star_y, size, size, "", "fav", "") image_button(star_x, star_y, size, size, "", "fav", "")
fs(fmt("tooltip[fav;%s]", fav and ES"Unmark this item" or ES"Mark this item")) fs(fmt("tooltip[fav;%s]", fav and ES"Unmark this item" or ES"Mark this item"))
else else
fs(fmt("style[nofav;fgimg=%s;fgimg_hovered=%s;fgimg_pressed=%s]", fs(fmt("style[nofav;fgimg=%s;fgimg_hovered=%s;fgimg_pressed=%s]",
"i3_fav_off.png", PNG.cancel, PNG.cancel)) "i3_fav_off.png", PNG.cancel, PNG.cancel))
fs("image_button", star_x, star_y, size, size, "", "nofav", "") image_button(star_x, star_y, size, size, "", "nofav", "")
fs(fmt("tooltip[nofav;%s]", ES"Cannot mark this item. Bookmark limit reached.")) fs(fmt("tooltip[nofav;%s]", ES"Cannot mark this item. Bookmark limit reached."))
end end
fs("image_button", star_x + 0.05, star_y + 0.6, size, size, "", "exit", "") image_button(star_x + 0.05, star_y + 0.6, size, size, "", "exit", "")
fs(fmt("tooltip[exit;%s]", ES"Back to item list")) fs(fmt("tooltip[exit;%s]", ES"Back to item list"))
local desc_lim, name_lim = 34, 35 local desc_lim, name_lim = 34, 35
@ -1170,19 +1189,19 @@ local function get_header(fs, data)
local Y2 = Y1 + 0.5 local Y2 = Y1 + 0.5
if #desc > desc_lim then if #desc > desc_lim then
fs("tooltip", X, Y1 - 0.1, 5.7, 0.24, desc) tooltip(X, Y1 - 0.1, 5.7, 0.24, desc)
desc = snip(desc, desc_lim) desc = snip(desc, desc_lim)
end end
if #tech_name > name_lim then if #tech_name > name_lim then
fs("tooltip", X, Y2 - 0.1, 5.7, 0.24, tech_name) tooltip(X, Y2 - 0.1, 5.7, 0.24, tech_name)
tech_name = snip(tech_name, name_lim) tech_name = snip(tech_name, name_lim)
end end
fs"style_type[label;font=bold;font_size=20]" fs"style_type[label;font=bold;font_size=20]"
fs("label", X, Y1, desc) label(X, Y1, desc)
fs"style_type[label;font=mono;font_size=16]" fs"style_type[label;font=mono;font_size=16]"
fs("label", X, Y2, clr(colors.blue, tech_name)) label(X, Y2, clr(colors.blue, tech_name))
fs"style_type[label;font=normal;font_size=16]" fs"style_type[label;font=normal;font_size=16]"
local def = reg_items[data.query_item] local def = reg_items[data.query_item]
@ -1191,7 +1210,7 @@ local function get_header(fs, data)
if def.drawtype == "mesh" or model_alias then if def.drawtype == "mesh" or model_alias then
get_model_fs(fs, data, def, model_alias) get_model_fs(fs, data, def, model_alias)
else else
fs("item_image", data.inv_width + 6.8, data.yoffset + 0.17, 1.1, 1.1, data.query_item) item_image(data.inv_width + 6.8, data.yoffset + 0.17, 1.1, 1.1, data.query_item)
end end
end end
@ -1201,7 +1220,7 @@ local function get_export_fs(fs, data, is_recipe, is_usage, max_stacks_rcp, max_
fs(fmt("style[export_%s;fgimg=%s;fgimg_hovered=%s]", fs(fmt("style[export_%s;fgimg=%s;fgimg_hovered=%s]",
name, fmt("%s", show_export and PNG.export_hover or PNG.export), PNG.export_hover)) name, fmt("%s", show_export and PNG.export_hover or PNG.export), PNG.export_hover))
fs("image_button", data.inv_width + 7.35, data.yoffset + 0.2, 0.45, 0.45, "", fmt("export_%s", name), "") image_button(data.inv_width + 7.35, data.yoffset + 0.2, 0.45, 0.45, "", fmt("export_%s", name), "")
fs(fmt("tooltip[export_%s;%s]", name, ES"Quick crafting")) fs(fmt("tooltip[export_%s;%s]", name, ES"Quick crafting"))
if not show_export then return end if not show_export then return end
@ -1223,8 +1242,8 @@ local function get_export_fs(fs, data, is_recipe, is_usage, max_stacks_rcp, max_
fmt("scrollbaroptions[min=1;max=%u;smallstep=1]", craft_max)) fmt("scrollbaroptions[min=1;max=%u;smallstep=1]", craft_max))
local x = data.inv_width + 8.1 local x = data.inv_width + 8.1
fs("scrollbar", x, data.yoffset, 2.5, 0.35, "horizontal", fmt("scrbar_%s", name), stack_fs) scrollbar(x, data.yoffset, 2.5, 0.35, "horizontal", fmt("scrbar_%s", name), stack_fs)
fs("button", x, data.yoffset + 0.4, 2.5, 0.7, fmt("craft_%s", name), ES("Craft (×@1)", stack_fs)) button(x, data.yoffset + 0.4, 2.5, 0.7, fmt("craft_%s", name), ES("Craft (×@1)", stack_fs))
end end
local function get_rcp_extra(fs, data, player, panel, is_recipe, is_usage) local function get_rcp_extra(fs, data, player, panel, is_recipe, is_usage)
@ -1260,7 +1279,7 @@ local function get_rcp_extra(fs, data, player, panel, is_recipe, is_usage)
get_rcp_lbl(fs, data, panel, rn, is_recipe) get_rcp_lbl(fs, data, panel, rn, is_recipe)
else else
local lbl = is_recipe and ES"No recipes" or ES"No usages" local lbl = is_recipe and ES"No recipes" or ES"No usages"
fs("button", data.inv_width + 0.1, data.yoffset + (panel.height / 2) - 0.5, 7.8, 1, "no_rcp", lbl) button(data.inv_width + 0.1, data.yoffset + (panel.height / 2) - 0.5, 7.8, 1, "no_rcp", lbl)
end end
fs"container_end[]" fs"container_end[]"
@ -1304,21 +1323,21 @@ local function get_items_fs(fs, data, player, full_height)
local ipp = rows * lines local ipp = rows * lines
local size = 0.85 local size = 0.85
fs("bg9", data.inv_width + 0.1, 0, 7.9, full_height, PNG.bg_full, 10) bg9(data.inv_width + 0.1, 0, 7.9, full_height, PNG.bg_full, 10)
fs(fmt("box[%f,0.2;4.05,0.6;#bababa25]", data.inv_width + 0.3), fs(fmt("box[%f,0.2;4.05,0.6;#bababa25]", data.inv_width + 0.3),
"set_focus[filter]", "set_focus[filter]",
fmt("field[%f,0.2;2.95,0.6;filter;;%s]", data.inv_width + 0.35, ESC(data.filter)), fmt("field[%f,0.2;2.95,0.6;filter;;%s]", data.inv_width + 0.35, ESC(data.filter)),
"field_close_on_enter[filter;false]") "field_close_on_enter[filter;false]")
fs("image_button", data.inv_width + 3.35, 0.35, 0.3, 0.3, "", "cancel", "") image_button(data.inv_width + 3.35, 0.35, 0.3, 0.3, "", "cancel", "")
fs("image_button", data.inv_width + 3.85, 0.32, 0.35, 0.35, "", "search", "") image_button(data.inv_width + 3.85, 0.32, 0.35, 0.35, "", "search", "")
fs("image_button", data.inv_width + 5.27, 0.3, 0.35, 0.35, "", "prev_page", "") image_button(data.inv_width + 5.27, 0.3, 0.35, 0.35, "", "prev_page", "")
fs("image_button", data.inv_width + 7.45, 0.3, 0.35, 0.35, "", "next_page", "") image_button(data.inv_width + 7.45, 0.3, 0.35, 0.35, "", "next_page", "")
data.pagemax = max(1, ceil(#items / ipp)) data.pagemax = max(1, ceil(#items / ipp))
fs("button", data.inv_width + 5.6, 0.14, 1.88, 0.7, "pagenum", button(data.inv_width + 5.6, 0.14, 1.88, 0.7, "pagenum",
fmt("%s / %u", clr(colors.yellow, data.pagenum), data.pagemax)) fmt("%s / %u", clr(colors.yellow, data.pagenum), data.pagemax))
if #items == 0 then if #items == 0 then
@ -1328,7 +1347,7 @@ local function get_items_fs(fs, data, player, full_height)
lbl = ES"Collect items to reveal more recipes" lbl = ES"Collect items to reveal more recipes"
end end
fs("button", data.inv_width + 0.1, 3, 8, 1, "no_item", lbl) button(data.inv_width + 0.1, 3, 8, 1, "no_item", lbl)
else else
local first_item = (data.pagenum - 1) * ipp local first_item = (data.pagenum - 1) * ipp
@ -1352,7 +1371,7 @@ local function get_items_fs(fs, data, player, full_height)
fs(fmt("tooltip[%s;%s]", item, expand and ES"Click to hide" or ES"Click to expand")) fs(fmt("tooltip[%s;%s]", item, expand and ES"Click to hide" or ES"Click to expand"))
fs"style_type[label;font=bold;font_size=20]" fs"style_type[label;font=bold;font_size=20]"
fs("label", X + 0.65, Y + 0.7, expand and "-" or "+") label(X + 0.65, Y + 0.7, expand and "-" or "+")
fs"style_type[label;font=normal;font_size=16]" fs"style_type[label;font=normal;font_size=16]"
end end
end end
@ -1369,25 +1388,25 @@ local function get_items_fs(fs, data, player, full_height)
PNG.tab_small_hover, selected and "#fff" or "#ddd")) PNG.tab_small_hover, selected and "#fff" or "#ddd"))
fs"style_type[image_button:hovered;textcolor=#fff]" fs"style_type[image_button:hovered;textcolor=#fff]"
fs("image_button", (data.inv_width - 0.65) + (i * (tab_len + 0.1)), image_button((data.inv_width - 0.65) + (i * (tab_len + 0.1)),
full_height, tab_len, tab_hgh, "", fmt("itab_%u", i), title) full_height, tab_len, tab_hgh, "", fmt("itab_%u", i), title)
end end
end end
local function get_favs(fs, data) local function get_favs(fs, data)
local btn_size = i3.settings.item_btn_size local btn_size = i3.settings.item_btn_size
fs("label", data.inv_width + 0.4, data.yoffset + 0.4, ES"Bookmarks") label(data.inv_width + 0.4, data.yoffset + 0.4, ES"Bookmarks")
for i = 1, #data.favs do for i, item in ipairs(data.favs) do
local item = data.favs[i] local name = fmt("_%s", item)
local X = data.inv_width - 0.7 + (i * 1.2) local X = data.inv_width - 0.7 + (i * 1.2)
local Y = data.yoffset + 0.8 local Y = data.yoffset + 0.8
if data.query_item == item then if data.query_item == item then
fs("image", X, Y, btn_size, btn_size, PNG.slot) image(X, Y, btn_size, btn_size, PNG.slot)
end end
fs("item_image_button", X, Y, btn_size, btn_size, item, item, "") item_image_button(X, Y, btn_size, btn_size, item, name, "")
end end
end end
@ -1404,7 +1423,7 @@ local function get_panels(fs, data, player)
data.yoffset += panels[i - 1].height + 0.1 data.yoffset += panels[i - 1].height + 0.1
end end
fs("bg9", data.inv_width + 0.1, data.yoffset, 7.9, panel.height, PNG.bg_full, 10) bg9(data.inv_width + 0.1, data.yoffset, 7.9, panel.height, PNG.bg_full, 10)
local is_recipe, is_usage = panel.name == "recipes", panel.name == "usages" local is_recipe, is_usage = panel.name == "recipes", panel.name == "usages"
panel.func(fs, data, player, panel, is_recipe, is_usage) panel.func(fs, data, player, panel, is_recipe, is_usage)
@ -1446,13 +1465,12 @@ local function get_tabs_fs(fs, player, data, full_height)
local Y = btm and full_height or -tab_hgh local Y = btm and full_height or -tab_hgh
fs"style_type[image_button:hovered;textcolor=#fff]" fs"style_type[image_button:hovered;textcolor=#fff]"
fs("image_button", X, Y, tab_len, tab_hgh, "", fmt("tab_%s", def.name), ESC(def.description)) image_button(X, Y, tab_len, tab_hgh, "", fmt("tab_%s", def.name), ESC(def.description))
if true_str(def.image) then if true_str(def.image) then
local desc = translate(data.lang_code, def.description) local desc = translate(data.lang_code, def.description)
fs("style_type[image;noclip=true]") fs("style_type[image;noclip=true]")
fs("image", X + (tab_len / 2) - ((#desc * 0.1) / 2) - 0.55, image(X + (tab_len / 2) - ((#desc * 0.1) / 2) - 0.55, Y + 0.05, 0.35, 0.35, def.image)
Y + 0.05, 0.35, 0.35, fmt("%s^\\[resize:16x16", def.image))
end end
c++ c++
@ -1461,28 +1479,28 @@ end
local function get_debug_grid(data, fs, full_height) local function get_debug_grid(data, fs, full_height)
fs"style[hide_debug_grid;noclip=true]" fs"style[hide_debug_grid;noclip=true]"
fs("button", -2, full_height - 1, 2, 1, "hide_debug_grid", "Toggle grid") button(-2, full_height - 1, 2, 1, "hide_debug_grid", "Toggle grid")
if data.hide_debug_grid then return end if data.hide_debug_grid then return end
fs("style_type[label;font_size=8;noclip=true]") fs("style_type[label;font_size=8;noclip=true]")
local spacing, i = 0.2, 1 local spacing, i = 0.2, 1
for x = 0, data.inv_width + 8, spacing do for x = 0, data.inv_width + 8, spacing do
fs("box", x, 0, 0.01, full_height, "#ff0") box(x, 0, 0.01, full_height, "#ff0")
fs("label", x, full_height + 0.1, tostring(i)) label(x, full_height + 0.1, tostring(i))
i++ i++
end end
i = 61 i = 61
for y = 0, full_height, spacing do for y = 0, full_height, spacing do
fs("box", 0, y, data.inv_width + 8, 0.01, "#ff0") box(0, y, data.inv_width + 8, 0.01, "#ff0")
fs("label", -0.15, y, tostring(i)) label(-0.15, y, tostring(i))
i -= 1 i -= 1
end end
fs("box", data.inv_width / 2, 0, 0.01, full_height, "#f00") box(data.inv_width / 2, 0, 0.01, full_height, "#f00")
fs("box", 0, full_height / 2, data.inv_width, 0.01, "#f00") box(0, full_height / 2, data.inv_width, 0.01, "#f00")
fs"style_type[label;font_size=16]" fs"style_type[label;font_size=16]"
end end
@ -1508,9 +1526,10 @@ local function make_fs(player, data)
fs(fmt("formspec_version[%u]size[%f,%f]no_prepend[]bgcolor[#0000]", fs(fmt("formspec_version[%u]size[%f,%f]no_prepend[]bgcolor[#0000]",
i3.settings.min_fs_version, data.inv_width + 8, full_height), styles) i3.settings.min_fs_version, data.inv_width + 8, full_height), styles)
fs("bg9", 0, 0, data.inv_width, full_height, PNG.bg_full, 10) bg9(0, 0, data.inv_width, full_height, PNG.bg_full, 10)
local tab = i3.tabs[data.tab] local tab = i3.tabs[data.tab]
if tab then if tab then
tab.formspec(player, data, fs) tab.formspec(player, data, fs)
end end
@ -1521,7 +1540,15 @@ local function make_fs(player, data)
get_items_fs(fs, data, player, full_height) get_items_fs(fs, data, player, full_height)
end end
if #i3.tabs > 1 then local visible_tabs = 1
for _, def in ipairs(i3.tabs) do
if visible_tabs < 2 and def.access and def.access(player, data) then
visible_tabs++
end
end
if visible_tabs > 1 then
get_tabs_fs(fs, player, data, full_height) get_tabs_fs(fs, player, data, full_height)
end end

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

@ -74,6 +74,7 @@ local styles = string.format([[
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_hovered=%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[exit;fgimg=%s;fgimg_hovered=%s;content_offset=0] style[exit;fgimg=%s;fgimg_hovered=%s;content_offset=0]

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,
})

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"