Compare commits

..

28 Commits

Author SHA1 Message Date
36cdcde7ed Bump version 2023-03-05 14:52:55 +01:00
c9e02dfe09 Fix replacements in Quick Crafting 2023-03-05 14:24:16 +01:00
7005794cc3 Merge globalsteps 2023-03-05 13:57:24 +01:00
66b88dec3b Bump version 2023-02-05 19:01:03 +01:00
c207db38a0 Minor tweak 2023-02-02 19:29:35 +01:00
c89cbf700f New crafting sound 2023-02-02 03:17:48 +01:00
a1a4535f26 Quick Crafting: indicate the missing materials when you cannot craft 2023-02-02 02:20:42 +01:00
80b927de1c Improve set home button look 2023-02-01 16:15:37 +01:00
482027d09b Small cleanup 2023-02-01 15:06:36 +01:00
ea7140a7bb Bugfix 2023-02-01 04:23:28 +01:00
84416b130b Minor cleaning 2023-02-01 04:22:03 +01:00
b31e7a48ab API: Add field to toggle slots in custom tabs 2023-02-01 04:08:52 +01:00
7a4f352ce4 Limit HUDCHANGE pkt sending 2023-01-29 21:47:13 +01:00
675349bd40 Bump version 2023-01-22 14:20:04 +01:00
e17f4e4c29 HUD: minor tweak 2023-01-21 19:18:40 +01:00
3b1d569118 Attempt to Quick Crafting replacements (again) 2023-01-21 00:43:38 +01:00
d55994c535 Minor fix 2023-01-20 21:57:27 +01:00
b6b97aa284 Fix group replacements in Quick Crafting 2023-01-20 21:20:12 +01:00
b4482f0acf Update MIT License 2023-01-20 16:07:28 +01:00
e918942439 Minor fix 2023-01-20 16:06:25 +01:00
889259ac5e Fix Quick Crafting bugs 2023-01-20 14:39:34 +01:00
187b0339bd Minor changes to API 2023-01-19 18:57:16 +01:00
74e88acadf Don't allow removing the 'All' tab 2023-01-19 18:34:43 +01:00
9e1f608846 Small fix 2023-01-19 18:03:56 +01:00
8289d290a3 Fix HUD 2023-01-19 17:58:24 +01:00
d833199628 API.md: Add summary 2023-01-19 16:50:01 +01:00
ac7a1fb746 Complete minitabs API 2023-01-19 16:40:31 +01:00
b95b179a5a Add an API to add minitabs 2023-01-19 01:24:45 +01:00
15 changed files with 401 additions and 181 deletions

69
API.md
View File

@ -1,6 +1,19 @@
## API
# API :screwdriver:
### Custom tabs
### Table of Contents
1. [**Tabs**](https://github.com/minetest-mods/i3/blob/main/API.md#tabs)
2. [**Recipes**](https://github.com/minetest-mods/i3/blob/main/API.md#recipes)
3. [**Minitabs**](https://github.com/minetest-mods/i3/blob/main/API.md#minitabs)
4. [**Recipe filters**](https://github.com/minetest-mods/i3/blob/main/API.md#recipe-filters)
5. [**Search filters**](https://github.com/minetest-mods/i3/blob/main/API.md#search-filters)
6. [**Sorting methods**](https://github.com/minetest-mods/i3/blob/main/API.md#sorting-methods)
7. [**Item list compression**](https://github.com/minetest-mods/i3/blob/main/API.md#item-list-compression)
8. [**Waypoints**](https://github.com/minetest-mods/i3/blob/main/API.md#waypoints)
9. [**Miscellaneous**](https://github.com/minetest-mods/i3/blob/main/API.md#miscellaneous)
---
### Tabs
#### `i3.new_tab(name, def)`
@ -13,6 +26,7 @@ Custom tabs can be added to the `i3` inventory as follow (example):
i3.new_tab("stuff", {
description = "Stuff",
image = "image.png", -- Optional, add an image next to the tab description
slots = true -- Optional, whether the inventory slots are shown or not. Disabled by default.
--
-- The functions below are all optional
@ -36,7 +50,7 @@ i3.new_tab("stuff", {
-- Do things
end
i3.set_fs(player) -- Update the formspec, mandatory
-- No need to update the formspec, it's automatic
end,
})
```
@ -72,7 +86,7 @@ A list of registered tabs.
---
### Custom recipes
### Recipes
Custom recipes are nonconventional crafts outside the main crafting grid.
They can be registered in-game dynamically and have a size beyond 3x3 items.
@ -164,6 +178,53 @@ i3.register_craft {
---
### Minitabs
Manage the tabs on the right panel of the inventory.
Allow to make a sensible list sorted by specific groups of items.
#### `i3.new_minitab(name, def)`
Add a new minitab (limited to 6).
- `name` is the tab name.
- `def` is the definition table.
Example:
```Lua
i3.new_minitab("test", {
description = "Test",
-- Whether this tab is visible or not. Optional.
access = function(player, data)
return player:get_player_name() == "singleplayer"
end,
-- Whether a specific item is shown in the list or not.
sorter = function(item, data)
return item:find"wood"
end
})
```
- `player` is an `ObjectRef` to the user.
- `data` are the user data.
- `item` is an item name string.
#### `i3.remove_minitab(name)`
Remove a minitab by name.
- `name` is the name of the tab to remove.
#### `i3.minimap`
A list of registered minitabs.
---
### Recipe filters
Recipe filters can be used to filter the recipes shown to players. Progressive

View File

@ -3,7 +3,7 @@ License of source code
The MIT License (MIT)
Copyright (c) 2020-2021 Jean-Patrick Guerrero and contributors.
Copyright (c) 2020-2023 Jean-Patrick Guerrero and contributors.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
@ -28,10 +28,12 @@ Licenses of media (sounds)
Lone_Wolf (CC0):
i3_tab.ogg
i3_craft.ogg
i3_click.ogg
i3_cannot.ogg
MadPanCake (CC0):
i3_craft.ogg (https://freesound.org/people/MadPanCake/sounds/567849/)
Licenses of media (textures)
----------------------------

View File

@ -20,7 +20,7 @@ local function lf(path)
end
i3 = {
version = 1131,
version = 1151,
data = core.deserialize(storage:get_string"data") or {},
settings = {
@ -34,7 +34,7 @@ i3 = {
save_interval = 600, -- Player data save interval (in seconds)
hud_speed = 1,
hud_timer_max = 1.5,
hud_timer_max = 3,
damage_enabled = core.settings:get_bool"enable_damage",
progressive_mode = core.settings:get_bool"i3_progressive_mode",
@ -101,6 +101,7 @@ i3 = {
groups = {},
plants = {},
modules = {},
minitabs = {},
craft_types = {},
recipe_filters = {},
@ -112,6 +113,7 @@ i3.files.common()
i3.files.api(http)
i3.files.compress()
i3.files.detached()
i3.files.fields()
i3.files.groups()
i3.files.callbacks(http, storage)

Binary file not shown.

View File

@ -196,7 +196,7 @@ end
i3.new_tab("inventory", {
description = S"Inventory",
formspec = get_inventory_fs,
fields = i3.files.fields(),
slots = true,
})
function i3.remove_tab(name)
@ -204,7 +204,7 @@ function i3.remove_tab(name)
return err "i3.remove_tab: tab name missing"
end
for i = #i3.tabs, 1, -1 do
for i = #i3.tabs, 2, -1 do
local def = i3.tabs[i]
if def and name == def.name then
remove(i3.tabs, i)
@ -430,3 +430,53 @@ function i3.get_waypoints(player_name)
return data.waypoints
end
function i3.new_minitab(name, def)
if #i3.minitabs == 6 then
return err "i3.new_minitab: limit reached (6)"
elseif not true_str(name) then
return err "i3.new_minitab: name missing"
elseif not true_table(def) then
return err "i3.new_minitab: definition missing"
end
def.name = name
insert(i3.minitabs, def)
end
function i3.remove_minitab(name)
if not true_str(name) then
return err "i3.remove_minitab: name missing"
end
for i = #i3.minitabs, 2, -1 do
local v = i3.minitabs[i]
if v and v.name == name then
remove(i3.minitabs, i)
end
end
end
i3.new_minitab("all", {
description = "All",
sorter = function()
return true
end
})
i3.new_minitab("nodes", {
description = "Nodes",
sorter = function(item)
return core.registered_nodes[item]
end
})
i3.new_minitab("items", {
description = "Items",
sorter = function(item)
return core.registered_craftitems[item] or core.registered_tools[item]
end
})

View File

@ -1,7 +1,7 @@
local replacements = {fuel = {}}
local http = ...
IMPORT("maxn", "copy", "insert", "sort", "match", "sub")
IMPORT("copy", "insert", "sort", "match", "sub")
IMPORT("true_str", "is_table", "valid_item", "table_merge", "table_replace", "table_eq")
IMPORT("fmt", "reg_items", "reg_aliases", "reg_nodes", "is_cube", "get_cube", "ItemStack")
IMPORT("is_group", "extract_groups", "item_has_groups", "groups_to_items", "get_group_stereotype")
@ -178,17 +178,7 @@ local function cache_recipes(item)
_recipes[#recipes + 1 - k] = v
end
local shift = 0
local size_rpl = maxn(replacements[item])
local size_rcp = #_recipes
if size_rpl > size_rcp then
shift = size_rcp - size_rpl
end
for k, v in pairs(replacements[item]) do
k += shift
if _recipes[k] then
_recipes[k].replacements = v
end

View File

@ -360,13 +360,8 @@ local function sort_by_category(data)
for i = 1, #items do
local item = items[i]
local to_add = true
if data.itab == 2 then
to_add = core.registered_nodes[item]
elseif data.itab == 3 then
to_add = core.registered_craftitems[item] or core.registered_tools[item]
end
local tab = i3.minitabs[data.itab]
local to_add = tab.sorter(item, data)
if to_add then
insert(new, item)
@ -413,6 +408,11 @@ local function get_stack(player, stack)
end
end
local function get_group_items(name)
local groups = extract_groups(name)
return i3.groups[name:sub(7)].items or groups_to_items(groups)
end
local function craft_stack(player, data, craft_rcp)
local inv = player:get_inventory()
local rcp_usg = craft_rcp and "recipe" or "usage"
@ -427,32 +427,42 @@ local function craft_stack(player, data, craft_rcp)
if is_group(name) then
items = {}
local groups = extract_groups(name)
local groupname = name:sub(7)
local item_groups = i3.groups[groupname].items or groups_to_items(groups)
local item_groups = get_group_items(name)
local remaining = count
for _, item in ipairs(item_groups) do
for _name, _count in pairs(data.crafting_counts[rcp_usg].inv) do
if item == _name and remaining > 0 then
local c = min(remaining, _count)
items[item] = c
remaining -= c
for _name, _count in pairs(data.crafting_counts[rcp_usg].inv) do
if item == _name and remaining > 0 then
local c = min(remaining, _count)
items[item] = c
remaining -= c
end
if remaining == 0 then break end
end
if remaining == 0 then break end
end
end
end
for k, v in pairs(items) do
inv:remove_item("main", fmt("%s %s", k, v * scrbar_val))
end
end
for item, v in pairs(items) do
for _ = 1, v * scrbar_val do
inv:remove_item("main", item)
if rcp_def.replacements then
for _, pair in ipairs(rcp_def.replacements) do
get_stack(player, ItemStack(pair[2]))
for _, pair in ipairs(rcp_def.replacements or {}) do
local old_name, new_name = unpack(pair)
if is_group(old_name) then
local item_groups = get_group_items(old_name)
for _, it in ipairs(item_groups) do
if item == it then
get_stack(player, ItemStack(new_name))
end
end
elseif item == old_name then
get_stack(player, ItemStack(new_name))
end
end
end
end
end

View File

@ -211,8 +211,6 @@ local function inv_fields(player, data, fields)
elseif fields.hide_debug_grid then
data.hide_debug_grid = not data.hide_debug_grid
end
return set_fs(player)
end
local function select_item(player, data, fields)
@ -465,11 +463,15 @@ core.register_on_player_receive_fields(function(player, formname, fields)
local tab = i3.tabs[data.tab]
if tab and tab.fields then
return true, tab.fields(player, data, fields)
if tab then
if tab.slots then
inv_fields(player, data, fields)
end
if tab.fields then
tab.fields(player, data, fields)
end
end
return true, set_fs(player)
end)
return inv_fields

View File

@ -124,33 +124,13 @@ local function get_stack_max(inv, data, is_recipe, rcp)
end
end
return max_stacks
end
local missing = {}
local function get_inv_slots(data, fs)
local legacy_inventory = data.legacy_inventory
local hotbar_len = data.hotbar_len
local inv_x = legacy_inventory and 0.23 or 0.22
local inv_y = legacy_inventory and 6.7 or 6.9
local spacing = legacy_inventory and 0.25 or 0.1
local size = 1
fs"style_type[box;colors=#77777710,#77777710,#777,#777]"
for i = 0, hotbar_len - 1 do
box(i * size + inv_x + (i * spacing), inv_y, size, size, "")
for item, count in pairs(counts_rcp) do
missing[item] = max(0, count - (counts_inv[item] or 0))
end
fs("style_type[list;size=%f;spacing=%f]", size, spacing)
fs("list[current_player;main;%f,%f;%u,1;]", inv_x, inv_y, hotbar_len)
fs("style_type[list;size=%f;spacing=%f,%f]", size, spacing, legacy_inventory and 0.15 or spacing)
fs("list[current_player;main;%f,%f;%u,%u;%u]", inv_x, inv_y + (legacy_inventory and 1.25 or 1.15),
hotbar_len, data.inv_size / hotbar_len, hotbar_len)
fs"style_type[list;size=1;spacing=0.15]"
fs"listring[current_player;craft]listring[current_player;main]"
return max_stacks, missing
end
local function add_subtitle(fs, name, y, ctn_len, font_size, sep, label)
@ -332,7 +312,7 @@ local function get_waypoint_fs(fs, data, player, yextra, ctn_len)
label(0.15, y + 0.33, clr(fmt("#%s", hex), waypoint_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")))
if teleport_priv then
tooltip = fmt("%s\n%s", tooltip, clr("#ff0", ES"[Click to teleport]"))
@ -625,7 +605,9 @@ local function show_settings(fs, data)
end
hypertext(2.2, 9.9, 6, 0.6, "home_pos", fmt("<global size=16><center>%s</center>", str))
image_button(4.3, 10.4, 1.8, 0.7, "", "set_home", "Set home")
fs("style[set_home;padding=20,10,-210,-10;fgimg=%s;fgimg_hovered=%s]", PNG.home_px, PNG.home_px_hover)
image_button(4.1, 10.4, 2.2, 0.7, "", "set_home", "")
label(4.9, 10.75, "Set home")
elseif show_style then
checkbox(2.6, 9.95, "cb_hide_tabs", "Hide tabs", tostring(data.hide_tabs))
@ -688,11 +670,53 @@ local function show_settings(fs, data)
end
end
local function get_footer(fs, data)
local btn = {
{"trash", ES"Clear inventory"},
{"sort", ES"Sort inventory"},
{"settings", ES"Settings"},
{"home", ES"Go home"},
}
for i, v in ipairs(btn) do
local btn_name, tooltip = unpack(v)
fs("style[%s;fgimg=%s;fgimg_hovered=%s;content_offset=0]",
btn_name, PNG[btn_name], PNG[fmt("%s_hover", btn_name)])
image_button(i + 3.43 - (i * 0.4), 11.43, 0.35, 0.35, "", btn_name, "")
fs("tooltip[%s;%s]", btn_name, tooltip)
end
show_settings(fs, data)
end
local function get_slots(fs, data)
local legacy_inventory = data.legacy_inventory
local hotbar_len = data.hotbar_len
local inv_x = legacy_inventory and 0.23 or 0.22
local inv_y = legacy_inventory and 6.7 or 6.9
local spacing = legacy_inventory and 0.25 or 0.1
local size = 1
fs"style_type[box;colors=#77777710,#77777710,#777,#777]"
for i = 0, hotbar_len - 1 do
box(i * size + inv_x + (i * spacing), inv_y, size, size, "")
end
fs("style_type[list;size=%f;spacing=%f]", size, spacing)
fs("list[current_player;main;%f,%f;%u,1;]", inv_x, inv_y, hotbar_len)
fs("style_type[list;size=%f;spacing=%f,%f]", size, spacing, legacy_inventory and 0.15 or spacing)
fs("list[current_player;main;%f,%f;%u,%u;%u]", inv_x, inv_y + (legacy_inventory and 1.25 or 1.15),
hotbar_len, data.inv_size / hotbar_len, hotbar_len)
fs"listring[current_player;craft]listring[current_player;main]"
get_footer(fs, data)
end
local function get_inventory_fs(player, data, fs)
fs"listcolors[#bababa50;#bababa99]"
get_inv_slots(data, fs)
local props = player:get_properties()
local ctn_len = 5.7
local ctn_hgt = data.legacy_inventory and 6.1 or 6.3
@ -772,23 +796,6 @@ local function get_inventory_fs(player, data, fs)
fs("scroll_container[3.9,0.2;%f,%f;scrbar_inv;vertical]", ctn_len, ctn_hgt)
get_container(fs, data, player, yoffset, ctn_len, award_list, awards_unlocked, award_list_nb, bag_size)
fs"scroll_container_end[]"
local btn = {
{"trash", ES"Clear inventory"},
{"sort", ES"Sort inventory"},
{"settings", ES"Settings"},
{"home", ES"Go home"},
}
for i, v in ipairs(btn) do
local btn_name, tooltip = unpack(v)
fs("style[%s;fgimg=%s;fgimg_hovered=%s;content_offset=0]",
btn_name, PNG[btn_name], PNG[fmt("%s_hover", btn_name)])
image_button(i + 3.43 - (i * 0.4), 11.43, 0.35, 0.35, "", btn_name, "")
fs("tooltip[%s;%s]", btn_name, tooltip)
end
show_settings(fs, data)
end
local function get_tooltip(item, info, lang_code)
@ -946,6 +953,12 @@ local function get_output_fs(fs, data, rcp, is_recipe, is_usage, shapeless, righ
local itemstr = ESC(item:to_string())
item_image_button(X + 0.11, Y, BTN_SIZE, BTN_SIZE, itemstr, _name, "")
local stackmax = item:get_stack_max()
if stackmax == 1 and count > 1 then
label(X + 1.05, Y + 1, count)
end
local def = reg_items[name]
local unknown = not def or nil
local desc = def and def.description
@ -1044,11 +1057,9 @@ local function get_grid_fs(fs, data, rcp, is_recipe, is_usage)
local label = groups and "\nG" or ""
local replace
for j = 1, #(rcp.replacements or {}) do
local replacement = rcp.replacements[j]
for _, replacement in ipairs(rcp.replacements or {}) do
if replacement[1] == name then
replace = replace or {type = rcp.type, items = {}}
local added
for _, v in ipairs(replace.items) do
@ -1059,12 +1070,17 @@ local function get_grid_fs(fs, data, rcp, is_recipe, is_usage)
end
if not added then
label = fmt("%s%s\nR", label ~= "" and "\n" or "", label)
label = fmt("%s\nR", label)
insert(replace.items, replacement[2])
end
end
end
local _, count_sub = label:gsub("\n", "")
if count_sub == 2 then
label = label:sub(2)
end
if not large_recipe then
slot(X, Y, btn_size, btn_size)
end
@ -1087,7 +1103,14 @@ local function get_grid_fs(fs, data, rcp, is_recipe, is_usage)
item:set_name(name)
item:set_count(count)
local itemstr = ESC(item:to_string())
item_image_button(X, Y, btn_size, btn_size, itemstr, btn_name, label)
local stackmax = item:get_stack_max()
if stackmax == 1 and count > 1 then
label(X + 0.95, Y + 0.95, count)
end
end
local def = reg_items[name]
@ -1298,9 +1321,10 @@ local function get_crafting_fs(fs, data, is_recipe, is_usage, max_stacks_rcp, ma
fs("scrollbaroptions[min=1;max=%u;smallstep=1]", craft_max)
scrollbar(x + 0.2, data.yoffset + 1.45, 2.5, 0.35, "horizontal", fmt("scrbar_%s", name), stack_fs)
button(x + 0.2, data.yoffset + 1.85, 2.5, 0.7, fmt("craft_%s", name), ES("Craft (×@1)", stack_fs))
button(x + 0.2, data.yoffset + 1.9, 2.5, 0.7, fmt("craft_%s", name), ES("Craft (×@1)", stack_fs))
fs"style_type[label;font_size=16;textcolor=#fff]"
fs"style_type[image,button,image_button;noclip=false]"
end
local function get_rcp_extra(fs, data, player, panel, is_recipe, is_usage)
@ -1310,15 +1334,15 @@ local function get_rcp_extra(fs, data, player, panel, is_recipe, is_usage)
if rn then
local rcp_ok = is_recipe and panel.rcp[data.rnum].type == "normal"
local usg_ok = is_usage and panel.rcp[data.unum].type == "normal"
local max_stacks_rcp, max_stacks_usg = 0, 0
local max_stacks_rcp, max_stacks_usg, missing_rcp, missing_usg = 0, 0
local inv = player:get_inventory()
if rcp_ok then
max_stacks_rcp = get_stack_max(inv, data, is_recipe, panel.rcp[data.rnum])
max_stacks_rcp, missing_rcp = get_stack_max(inv, data, is_recipe, panel.rcp[data.rnum])
end
if usg_ok then
max_stacks_usg = get_stack_max(inv, data, is_recipe, panel.rcp[data.unum])
max_stacks_usg, missing_usg = get_stack_max(inv, data, is_recipe, panel.rcp[data.unum])
end
if is_recipe and max_stacks_rcp == 0 then
@ -1331,6 +1355,23 @@ local function get_rcp_extra(fs, data, player, panel, is_recipe, is_usage)
if max_stacks_rcp > 0 or max_stacks_usg > 0 then
get_crafting_fs(fs, data, is_recipe, is_usage, max_stacks_rcp, max_stacks_usg)
elseif rcp_ok or usg_ok then
local X = data.inv_width + 7.35
local Y = data.yoffset + 0.2
local missing = is_recipe and missing_rcp or missing_usg
local str = ""
for item, count in pairs(missing) do
if count > 0 then
local name = is_group(item) and (i3.group_names[item:sub(7)] or item) or
get_desc(item, data.lang_code)
str = fmt("%s\n%s %s", str, clr("#ff0", count .. '×'), name)
end
end
image(X, Y, 0.45, 0.45, PNG.crafting .. "^\\[opacity:100")
tooltip(X, Y, 0.45, 0.45, fmt("%s:%s", ES"Missing materials for crafting", str))
end
get_rcp_lbl(fs, data, panel, rn, is_recipe, is_usage)
@ -1391,7 +1432,20 @@ local function get_header_items_fs(fs, data)
end
box(X + 1, 0.2, 0.01, 0.5, "#bababa50")
local cat = {{"all", "all items"}, {"node", "nodes only"}, {"item", "items only"}}
local cat = {{"all", "all items"}}
if not recipe_filter_set() then
for _, v in ipairs(i3.minitabs) do
if v.name == "nodes" then
insert(cat, {"node", "nodes only"})
end
if v.name == "items" then
insert(cat, {"item", "items only"})
end
end
end
for i in ipairs(cat) do
local name, desc = unpack(cat[i])
@ -1452,22 +1506,36 @@ local function get_header_items_fs(fs, data)
end
end
local function get_minitabs(fs, data, full_height)
local _tabs = {"All", "Nodes", "Items"}
local tab_len, tab_hgh = 1.8, 0.5
local function get_minitabs(fs, data, player, full_height)
local minitabs = {}
for i, title in ipairs(_tabs) do
local selected = i == data.itab
for i, v in ipairs(i3.minitabs) do
local access = v.access
if access == nil or access(player, data) then
minitabs[i] = v.description
end
end
local tab_len, tab_hgh, i = 1.8, 0.5, 0
for id, title in pairs(minitabs) do
i++
local top = i > 3
local X = top and i - 3 or i
local selected = id == data.itab
local hover_texture = selected and PNG.tab_small_hover or PNG.tab_small
local flip = top and "^[transformFY" or ""
local tabname = fmt("itab_%u", id)
fs([[ style_type[image_button;bgimg=%s;bgimg_hovered=%s;
bgimg_middle=14,0,-14,-14;padding=-14,0,14,14] ]], hover_texture, PNG.tab_small_hover)
fs([[ style[%s;bgimg=%s%s;bgimg_hovered=%s%s;noclip=true;font=bold;font_size=16;
textcolor=%s;content_offset=0;sound=i3_tab;bgimg_middle=14,0,-14,-14;padding=-14,0,14,14] ]],
tabname, hover_texture, flip, PNG.tab_small_hover, flip, selected and "#fff" or "#bbb")
fs([[ style_type[image_button;noclip=true;font=bold;font_size=16;
textcolor=%s;content_offset=0;sound=i3_tab] ]], selected and "#fff" or "#bbb")
fs"style_type[image_button:hovered;textcolor=#fff]"
image_button((data.inv_width - 0.65) + (i * (tab_len + 0.1)),
full_height, tab_len, tab_hgh, "", fmt("itab_%u", i), title)
fs("style[%s:hovered;textcolor=#fff]", tabname)
image_button((data.inv_width - 0.65) + (X * (tab_len + 0.1)),
top and -tab_hgh or full_height, tab_len, tab_hgh, "", tabname, title)
end
end
@ -1515,7 +1583,7 @@ local function get_items_fs(fs, data, player, full_height)
local item_btn = fmt("item_image_button", X, Y, size, size, name, item, "")
if recipe_filter_set() then
if recipe_filter_set() and data.itab == 1 then
if data.items_progress[item] then
insert(fs, item_btn)
else
@ -1616,17 +1684,17 @@ local function get_tabs_fs(fs, player, data, full_height)
local middle = btm and "16,0,-16,-16" or "16,16,-16,-16"
local padding = btm and "-16,0,16,16" or "-16,-16,16,16"
fs([[ style_type[image_button;bgimg=%s;bgimg_hovered=%s;bgimg_middle=%s;padding=%s] ]],
bgimg, bgimg_hover, middle, padding)
local tabname = fmt("tab_%s", def.name)
fs("style_type[image_button;noclip=true;font_size=16;textcolor=%s;content_offset=0;sound=i3_tab]",
selected and "#fff" or "#ddd")
fs([[ style[%s;bgimg=%s;bgimg_hovered=%s;bgimg_middle=%s;padding=%s;noclip=true;
font=bold;font_size=16;textcolor=%s;content_offset=0;sound=i3_tab] ]],
tabname, bgimg, bgimg_hover, middle, padding, selected and "#fff" or "#bbb")
local X = (data.inv_width / 2) + (c * (tab_len + 0.1)) - ((tab_len + 0.05) * (shift / 2))
local Y = btm and full_height or -tab_hgh
fs"style_type[image_button:hovered;textcolor=#fff]"
image_button(X, Y, tab_len, tab_hgh, "", fmt("tab_%s", def.name), ESC(def.description))
fs("style[%s:hovered;textcolor=#fff]", tabname)
image_button(X, Y, tab_len, tab_hgh, "", tabname, ESC(def.description))
if true_str(def.image) then
local desc = translate(data.lang_code, def.description)
@ -1634,6 +1702,7 @@ local function get_tabs_fs(fs, player, data, full_height)
fs"style_type[image;noclip=true]"
image(X + (tab_len / 2) - ((desc_len * 0.1) / 2) - 0.55, Y + 0.05, 0.35, 0.35, def.image)
fs"style_type[image;noclip=false]"
end
c++
@ -1696,8 +1765,14 @@ local function make_fs(player, data)
local tab = i3.tabs[data.tab]
if tab and tab.formspec then
tab.formspec(player, data, fs)
if tab then
if tab.formspec then
tab.formspec(player, data, fs)
end
if tab.slots then
get_slots(fs, data)
end
end
if data.query_item then
@ -1706,7 +1781,7 @@ local function make_fs(player, data)
get_items_fs(fs, data, player, full_height)
if not data.hide_tabs then
get_minitabs(fs, data, full_height)
get_minitabs(fs, data, player, full_height)
end
end

View File

@ -15,16 +15,18 @@ local function init_hud(player)
data.hud = {
bg = player:hud_add {
hud_elem_type = "image",
position = {x = 0.78, y = 1},
position = {x = 1, y = 1},
offset = {x = -320, y = 0},
alignment = {x = 1, y = 1},
scale = {x = 370, y = 112},
scale = {x = 300, y = 105},
text = "i3_bg.png",
z_index = 0xDEAD,
},
img = player:hud_add {
hud_elem_type = "image",
position = {x = 0.79, y = 1.02},
position = {x = 1, y = 1},
offset = {x = -310, y = 20},
alignment = {x = 1, y = 1},
scale = {x = 1, y = 1},
text = "",
@ -33,7 +35,8 @@ local function init_hud(player)
text = player:hud_add {
hud_elem_type = "text",
position = {x = 0.84, y = 1.04},
position = {x = 1, y = 1},
offset = {x = -235, y = 40},
alignment = {x = 1, y = 1},
number = 0xffffff,
text = "",
@ -55,13 +58,12 @@ local function init_hud(player)
end
local function show_hud(player, data)
-- It would better to have an engine function `hud_move` to only need
-- 2 calls for the notification's back and forth.
local hud_info_bg = player:hud_get(data.hud.bg)
local dt = 0.025
local dt = 0.016
local offset_y = hud_info_bg.offset.y
local speed = 5 * i3.settings.hud_speed
if hud_info_bg.position.y <= 0.9 then
if offset_y < -100 then
data.show_hud = false
data.hud_timer = (data.hud_timer or 0) + dt
end
@ -73,31 +75,34 @@ local function show_hud(player, data)
end
if data.show_hud then
for _, def in pairs(data.hud) do
local hud_info = player:hud_get(def)
player:hud_change(def, "position", {
x = hud_info.position.x,
y = hud_info.position.y - ((dt / 5) * i3.settings.hud_speed)
})
end
elseif data.show_hud == false then
if data.hud_timer >= i3.settings.hud_timer_max then
for _, def in pairs(data.hud) do
for name, def in pairs(data.hud) do
if name ~= "wielditem" then
local hud_info = player:hud_get(def)
player:hud_change(def, "position", {
x = hud_info.position.x,
y = hud_info.position.y + ((dt / 5) * i3.settings.hud_speed)
player:hud_change(def, "offset", {
x = hud_info.offset.x,
y = hud_info.offset.y - speed
})
end
end
elseif data.show_hud == false then
if data.hud_timer >= i3.settings.hud_timer_max then
for name, def in pairs(data.hud) do
if name ~= "wielditem" then
local hud_info = player:hud_get(def)
if hud_info_bg.position.y >= 1 then
data.show_hud = nil
player:hud_change(def, "offset", {
x = hud_info.offset.x,
y = hud_info.offset.y + speed
})
end
end
if offset_y > 0 then
data.show_hud = nil
data.hud_timer = nil
data.hud_msg = nil
data.hud_img = nil
data.hud_msg = nil
data.hud_img = nil
end
end
end
@ -113,8 +118,16 @@ core.register_globalstep(function(dt)
local data = i3.data[name]
if not data then return end
if data.show_hud ~= nil then
show_hud(player, data)
end
local has_text = player:hud_get(data.hud.wielditem).text ~= ""
if not data.wielditem_hud then
player:hud_change(data.hud.wielditem, "text", "")
if has_text then
player:hud_change(data.hud.wielditem, "text", "")
end
return
end
@ -122,7 +135,7 @@ core.register_globalstep(function(dt)
local wieldidx = player:get_wield_index()
if wieldidx == data.old_wieldidx then
if data.timer >= i3.settings.wielditem_fade_after then
if data.timer >= i3.settings.wielditem_fade_after and has_text then
player:hud_change(data.hud.wielditem, "text", "")
end
return
@ -143,21 +156,6 @@ core.register_globalstep(function(dt)
end
end)
core.register_globalstep(function()
local players = get_connected_players()
players[0] = #players
for i = 1, players[0] do
local player = players[i]
local name = player:get_player_name()
local data = i3.data[name]
if data and data.show_hud ~= nil then
show_hud(player, data)
end
end
end)
local function init_waypoints(player)
local name = player:get_player_name()
local data = i3.data[name]

View File

@ -2,9 +2,19 @@ local set_fs = i3.set_fs
local hud_notif = i3.hud_notif
local POLL_FREQ = 0.25
IMPORT("reg_items", "reg_nodes")
IMPORT("fmt", "search", "table_merge", "array_diff")
IMPORT("is_group", "extract_groups", "item_has_groups", "apply_recipe_filters")
IMPORT("reg_items", "reg_nodes", "fmt", "table_merge", "array_diff")
IMPORT("is_group", "extract_groups", "item_has_groups", "apply_recipe_filters", "sort_by_category")
i3.remove_minitab"nodes"
i3.remove_minitab"items"
i3.new_minitab("unlocked", {
description = "Unlocked",
sorter = function(item, data)
return data.items_progress[item]
end
})
local function get_filtered_items(player, data)
local items, known = {}, 0
@ -145,9 +155,8 @@ local function poll_new_items(player, data, join)
end
data.items_progress = items
data.itab = 1
search(data)
sort_by_category(data)
set_fs(player)
end

View File

@ -54,6 +54,8 @@ local PNG = {
node = "i3_node.png",
item = "i3_item.png",
cube = "i3_cube.png",
home_px = "i3_home_px.png",
home_px_hover = "i3_home_px_hover.png",
cancel_hover = "i3_cancel.png^\\[brighten",
search_hover = "i3_search.png^\\[brighten",
@ -83,6 +85,9 @@ local PNG = {
}
local styles = string.format([[
listcolors[#bababa50;#bababa99]
style_type[list;size=1;spacing=0.15]
style_type[field;border=false;bgcolor=transparent]
style_type[label,field;font_size=16]
style_type[button;border=false;content_offset=0]

View File

@ -1,16 +1,32 @@
local SWITCH
i3.new_tab("test1", {
description = "Test 1 Test 1",
image = "i3_heart.png",
formspec = function(player, data, fs)
fs("button", 3, 4, 3, 0.8, "test", "Click here")
fs("label", 3, 1, "Just a test")
fs"label[3,2;Lorem Ipsum]"
if SWITCH then
fs"label[3,2;Button clicked]"
else
fs"label[3,2;Lorem Ipsum]"
end
end,
fields = function(player, data, fields)
if fields.test then
SWITCH = true
end
end
})
i3.new_tab("test2", {
description = "Test 2",
image = "i3_mesepick.png",
slots = true,
formspec = function(player, data, fs)
fs("label[3,1;Test 2]")

BIN
textures/i3_home_px.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 KiB