Compare commits

...

51 Commits
1.13 ... main

Author SHA1 Message Date
Jean-Patrick Guerrero 9437545ddb Bump version 2023-04-02 16:56:20 +02:00
Jean-Patrick Guerrero ff7353392f Fix tooltips 2023-04-02 16:56:18 +02:00
Jean-Patrick Guerrero 45fc03cc26 Bump version 2023-04-02 14:56:14 +02:00
Jean-Patrick Guerrero f26a1c288d New tooltip color + cleaning 2023-04-02 14:49:13 +02:00
Jean-Patrick Guerrero 85fc8219c1 Move notifs to the left 2023-04-02 01:23:11 +02:00
Jean-Patrick Guerrero 83623effbf More HUD improvements 2023-04-02 00:45:39 +02:00
Jean-Patrick Guerrero c64f28a90b Prevent potential crash 2023-04-01 22:51:21 +02:00
Jean-Patrick Guerrero ad08ca56b8 More improvements to notification look 2023-04-01 22:45:18 +02:00
Jean-Patrick Guerrero 1684388851 Ability to stack notifications on top of each other 2023-04-01 22:17:41 +02:00
Jean-Patrick Guerrero 1f43c8fac2 Optimize textures 2023-04-01 18:53:12 +02:00
Jean-Patrick Guerrero 6953a11279 Improve notification look 2023-04-01 18:35:29 +02:00
Jean-Patrick Guerrero 21affdeeba Eventually remove window info 2023-04-01 14:43:02 +02:00
Jean-Patrick Guerrero 7130ea565d Doc 2023-03-08 16:43:35 +01:00
Jean-Patrick Guerrero b7308b4739 Get window info once per second 2023-03-08 16:42:15 +01:00
Jean-Patrick Guerrero d5df9f6f0f Store window info for future work 2023-03-07 14:07:52 +01:00
Jean-Patrick Guerrero 7246249c52 Bump version 2023-03-07 01:24:44 +01:00
Jean-Patrick Guerrero d36d6e67e7 Fix regression 2023-03-07 01:24:27 +01:00
Jean-Patrick Guerrero d5fc865634 Bump version 2023-03-06 22:24:32 +01:00
Jean-Patrick Guerrero fe475747ea Fix crash with some mods 2023-03-06 22:00:49 +01:00
Jean-Patrick Guerrero e2fafbc876 New click sound 2023-03-06 12:38:12 +01:00
Jean-Patrick Guerrero 3b860082b5 Doc 2023-03-05 14:53:36 +01:00
Jean-Patrick Guerrero 36cdcde7ed Bump version 2023-03-05 14:52:55 +01:00
Jean-Patrick Guerrero c9e02dfe09 Fix replacements in Quick Crafting 2023-03-05 14:24:16 +01:00
Jean-Patrick Guerrero 7005794cc3 Merge globalsteps 2023-03-05 13:57:24 +01:00
Jean-Patrick Guerrero 66b88dec3b Bump version 2023-02-05 19:01:03 +01:00
Jean-Patrick Guerrero c207db38a0 Minor tweak 2023-02-02 19:29:35 +01:00
Jean-Patrick Guerrero c89cbf700f New crafting sound 2023-02-02 03:17:48 +01:00
Jean-Patrick Guerrero a1a4535f26 Quick Crafting: indicate the missing materials when you cannot craft 2023-02-02 02:20:42 +01:00
Jean-Patrick Guerrero 80b927de1c Improve set home button look 2023-02-01 16:15:37 +01:00
Jean-Patrick Guerrero 482027d09b Small cleanup 2023-02-01 15:06:36 +01:00
Jean-Patrick Guerrero ea7140a7bb Bugfix 2023-02-01 04:23:28 +01:00
Jean-Patrick Guerrero 84416b130b Minor cleaning 2023-02-01 04:22:03 +01:00
Jean-Patrick Guerrero b31e7a48ab API: Add field to toggle slots in custom tabs 2023-02-01 04:08:52 +01:00
Jean-Patrick Guerrero 7a4f352ce4 Limit HUDCHANGE pkt sending 2023-01-29 21:47:13 +01:00
Jean-Patrick Guerrero 675349bd40 Bump version 2023-01-22 14:20:04 +01:00
Jean-Patrick Guerrero e17f4e4c29 HUD: minor tweak 2023-01-21 19:18:40 +01:00
Jean-Patrick Guerrero 3b1d569118 Attempt to Quick Crafting replacements (again) 2023-01-21 00:43:38 +01:00
Jean-Patrick Guerrero d55994c535 Minor fix 2023-01-20 21:57:27 +01:00
Jean-Patrick Guerrero b6b97aa284 Fix group replacements in Quick Crafting 2023-01-20 21:20:12 +01:00
Jean-Patrick Guerrero b4482f0acf Update MIT License 2023-01-20 16:07:28 +01:00
Jean-Patrick Guerrero e918942439 Minor fix 2023-01-20 16:06:25 +01:00
Jean-Patrick Guerrero 889259ac5e Fix Quick Crafting bugs 2023-01-20 14:39:34 +01:00
Jean-Patrick Guerrero 187b0339bd Minor changes to API 2023-01-19 18:57:16 +01:00
Jean-Patrick Guerrero 74e88acadf Don't allow removing the 'All' tab 2023-01-19 18:34:43 +01:00
Jean-Patrick Guerrero 9e1f608846 Small fix 2023-01-19 18:03:56 +01:00
Jean-Patrick Guerrero 8289d290a3 Fix HUD 2023-01-19 17:58:24 +01:00
Jean-Patrick Guerrero d833199628 API.md: Add summary 2023-01-19 16:50:01 +01:00
Jean-Patrick Guerrero ac7a1fb746 Complete minitabs API 2023-01-19 16:40:31 +01:00
Jean-Patrick Guerrero b95b179a5a Add an API to add minitabs 2023-01-19 01:24:45 +01:00
Jean-Patrick Guerrero 38f1d7c960 Bump version 2023-01-11 00:10:30 +01:00
Jean-Patrick Guerrero 5d4f9b4709 Get rid of Factorio's sounds 2023-01-11 00:07:27 +01:00
20 changed files with 521 additions and 282 deletions

79
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
@ -24,6 +38,7 @@ i3.new_tab("stuff", {
return name == "singleplayer"
end,
-- Build the formspec
formspec = function(player, data, fs)
fs("label", 3, 1, "Just a test")
fs"label[3,2;Lorem Ipsum]"
@ -36,7 +51,8 @@ i3.new_tab("stuff", {
-- Do things
end
i3.set_fs(player) -- Update the formspec, mandatory
-- To prevent a formspec update, return false.
-- Otherwise: no need to return anything, it's automatic.
end,
})
```
@ -59,7 +75,7 @@ Return the current player tab. `player` is an `ObjectRef` to the user.
#### `i3.set_tab(player[, tabname])`
Sets the current tab by name. `player` is an `ObjectRef` to the user.
Set the current tab by name. `player` is an `ObjectRef` to the user.
`tabname` can be omitted to get an empty tab.
#### `i3.override_tab(tabname, def)`
@ -72,7 +88,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.
@ -130,7 +146,7 @@ i3.register_craft {
}
```
Multiples recipes can also be registered:
Multiple recipes can also be registered at once:
```Lua
i3.register_craft {
@ -164,6 +180,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.minitabs`
A list of registered minitabs.
---
### Recipe filters
Recipe filters can be used to filter the recipes shown to players. Progressive
@ -356,7 +419,7 @@ Return a table of all waypoints of a specific player.
#### `i3.hud_notif(name, msg[, img])`
Show a Steam-like HUD notification on the bottom-right corner of the screen (experimental).
Show a Steam-like HUD notification on the bottom-left corner of the screen.
- `name` is the player name.
- `msg` is the HUD message to show.
@ -378,4 +441,4 @@ given a number between 1 and 4.
---
**¹** Add `i3` to the `secure.http_mods` or `secure.trusted_mods` setting in `minetest.conf`.
**[1]** Add `i3` to the `secure.http_mods` or `secure.trusted_mods` setting in `minetest.conf`.

12
LICENSE
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
@ -23,6 +23,16 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
Licenses of media (sounds)
--------------------------
Lone_Wolf (CC0):
i3_tab.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

@ -35,7 +35,6 @@ To enable it: `i3_progressive_mode = true` in `minetest.conf`.*
To use this mod in the best conditions:
- Use LuaJIT
- Use a HiDPI widescreen display
- Use the default Freetype font style
#### Troubleshooting

View File

@ -20,7 +20,7 @@ local function lf(path)
end
i3 = {
version = 113,
version = 1161,
data = core.deserialize(storage:get_string"data") or {},
settings = {
@ -33,8 +33,8 @@ i3 = {
wielditem_fade_after = 3,
save_interval = 600, -- Player data save interval (in seconds)
hud_speed = 1,
hud_timer_max = 1.5,
hud_speed = 3,
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.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -2,8 +2,8 @@ local http = ...
local make_fs, get_inventory_fs = i3.files.gui()
IMPORT("sorter", "sort_inventory", "play_sound")
IMPORT("get_player_by_name", "add_hud_waypoint")
IMPORT("sort", "concat", "copy", "insert", "remove")
IMPORT("get_player_by_name", "add_hud_waypoint", "init_hud_notif")
IMPORT("gmatch", "split", "S", "err", "fmt", "reg_items", "pos_to_str")
IMPORT("true_str", "true_table", "is_str", "is_func", "is_table", "clean_name")
@ -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)
@ -319,13 +319,30 @@ function i3.hud_notif(name, msg, img)
return err "i3.hud_notif: no player data initialized"
end
data.show_hud = true
data.hud_msg = msg
local player = get_player_by_name(name)
if not player then return end
local max_y = -125
local def = {
show = true,
max = {x = -330, y = max_y},
hud_msg = msg,
hud_img = img and fmt("%s^[resize:64x64", img) or nil,
hud_timer = 0,
elems = init_hud_notif(player),
}
insert(data.hud.notifs, def)
play_sound(name, "i3_achievement", 1.0)
if img then
data.hud_img = fmt("%s^[resize:64x64", img)
local nb_notifs = #data.hud.notifs
for i = 1, nb_notifs - 1 do
local notif = data.hud.notifs[i]
if notif then
notif.show = true
notif.max.y = ((nb_notifs - i) + 1) * max_y
notif.hud_timer = 0.5 * (nb_notifs - i)
end
end
end
@ -430,3 +447,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
@ -567,11 +577,7 @@ local function sort_inventory(player, data)
local size = inv:get_size"main"
local start_i = data.ignore_hotbar and (data.hotbar_len + 1) or 1
if data.inv_compress then
list = compress_items(list, start_i)
else
list = pre_sorting(list, start_i)
end
list = data.inv_compress and compress_items(list, start_i) or pre_sorting(list, start_i)
local new_inv = i3.sorting_methods[data.sort].func(list, data)
if not new_inv then return end
@ -626,6 +632,41 @@ local function add_hud_waypoint(player, name, pos, color, image)
}
end
local function init_hud_notif(player)
return {
bg = player:hud_add {
hud_elem_type = "image",
position = {x = 0, y = 1},
offset = {x = 10, y = 0},
alignment = {x = 1, y = 1},
scale = {x = 0.6, y = 0.6},
text = "i3_bg_notif.png",
z_index = 0xDEAD,
},
img = player:hud_add {
hud_elem_type = "image",
position = {x = 0, y = 1},
offset = {x = 20, y = 20},
alignment = {x = 1, y = 1},
scale = {x = 1, y = 1},
text = "",
z_index = 0xDEAD,
},
text = player:hud_add {
hud_elem_type = "text",
position = {x = 0, y = 1},
offset = {x = 100, y = 40},
alignment = {x = 1, y = 1},
number = 0xffffff,
text = "",
z_index = 0xDEAD,
style = 1,
}
}
end
local function get_detached_inv(name, player_name)
return core.get_inventory {
type = "detached",
@ -643,11 +684,7 @@ local function update_inv_size(player, data)
player:hud_set_hotbar_itemcount(data.hotbar_len)
core.after(0, function()
if data.legacy_inventory then
player:hud_set_hotbar_image"gui_hotbar.png"
else
player:hud_set_hotbar_image"i3_hotbar.png"
end
player:hud_set_hotbar_image(data.legacy_inventory and "gui_hotbar.png" or "i3_hotbar.png")
end)
end
@ -715,6 +752,7 @@ local _ = {
play_sound = play_sound,
reset_data = reset_data,
safe_teleport = safe_teleport,
init_hud_notif = init_hud_notif,
add_hud_waypoint = add_hud_waypoint,
-- Core functions
@ -780,6 +818,7 @@ local _ = {
-- Math
round = round,
abs = math.abs,
min = math.min,
max = math.max,
ceil = math.ceil,

View File

@ -12,12 +12,6 @@ IMPORT("search", "sort_inventory", "sort_by_category", "get_recipes", "get_detac
local function inv_fields(player, data, fields)
local name = data.player_name
local inv = player:get_inventory()
local sb_inv = fields.scrbar_inv
if sb_inv and sub(sb_inv, 1, 3) == "CHG" then
data.scrbar_inv = tonumber(match(sb_inv, "%d+"))
return
end
if fields.dd_sorting_method then
data.sort = tonumber(fields.dd_sorting_method)
@ -211,8 +205,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)
@ -431,8 +423,7 @@ core.register_on_player_receive_fields(function(player, formname, fields)
local name = player:get_player_name()
if formname == "i3_outdated" then
return false, core.kick_player(name,
S"Your Minetest client needs updating (www.minetest.net)")
return false, core.kick_player(name, S"Your Minetest client needs updating (www.minetest.net)")
elseif formname ~= "" then
return false
end
@ -448,6 +439,12 @@ core.register_on_player_receive_fields(function(player, formname, fields)
local data = i3.data[name]
if not data then return end
local sb_inv = fields.scrbar_inv
if sb_inv and sub(sb_inv, 1, 3) == "CHG" then
data.scrbar_inv = tonumber(match(sb_inv, "%d+"))
return
end
for f in pairs(fields) do
if sub(f, 1, 4) == "tab_" then
local tabname = sub(f, 5)
@ -464,12 +461,16 @@ core.register_on_player_receive_fields(function(player, formname, fields)
rcp_fields(player, data, fields)
local tab = i3.tabs[data.tab]
if tab then
if tab.slots then
inv_fields(player, data, fields)
end
if tab and tab.fields then
return true, tab.fields(player, data, fields)
if tab.fields then
local ret = tab.fields(player, data, fields)
if ret == false then return end
end
end
return true, set_fs(player)
end)
return inv_fields

View File

@ -11,11 +11,11 @@ IMPORT("vec", "vec_round")
IMPORT("find", "match", "sub", "upper")
IMPORT("clr", "ESC", "msg", "check_privs")
IMPORT("min", "max", "floor", "ceil", "round")
IMPORT("true_str", "is_fav", "is_num", "str_to_pos")
IMPORT("reg_items", "reg_nodes", "reg_tools", "reg_entities")
IMPORT("get_bag_description", "get_detached_inv", "get_recipes")
IMPORT("compression_active", "compressible", "recipe_filter_set")
IMPORT("S", "ES", "translate", "ItemStack", "toupper", "utf8_len")
IMPORT("true_str", "true_table", "is_fav", "is_num", "str_to_pos")
IMPORT("maxn", "sort", "concat", "copy", "insert", "remove", "unpack")
IMPORT("extract_groups", "groups_to_items", "is_group", "item_has_groups", "get_group")
@ -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)
@ -305,7 +285,7 @@ local function get_waypoint_fs(fs, data, player, yextra, ctn_len)
label(0, yextra + 0.85, ES"New waypoint" .. ":")
fs("field[0.1,%f;4.8,0.6;waypoint_name;;]", yextra + 1.1)
image_button(5.1, yextra + 1.15, 0.5, 0.5, "", "waypoint_add", "")
fs("tooltip[waypoint_add;%s]", ES"Add waypoint")
fs("tooltip[waypoint_add;%s;#32333899;#fff]", ES"Add waypoint")
if #data.waypoints == 0 then return end
fs"style_type[label;font=bold;font_size=17]"
@ -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]"))
@ -343,23 +323,23 @@ local function get_waypoint_fs(fs, data, player, yextra, ctn_len)
local del = fmt("waypoint_%u_delete", i)
fs("style[%s;fgimg=%s;fgimg_hovered=%s;content_offset=0]", del, PNG.trash, PNG.trash_hover)
image_button(ctn_len - 0.5, yi, icon_size, icon_size, "", del, "")
fs("tooltip[%s;%s]", del, ES"Remove waypoint")
fs("tooltip[%s;%s;#32333899;#fff]", del, ES"Remove waypoint")
local rfs = fmt("waypoint_%u_refresh", i)
fs("style[%s;fgimg=%s;fgimg_hovered=%s;content_offset=0]", rfs, PNG.refresh, PNG.refresh_hover)
image_button(ctn_len - 1, yi, icon_size, icon_size, "", rfs, "")
fs("tooltip[%s;%s]", rfs, ES"Change color")
fs("tooltip[%s;%s;#32333899;#fff]", rfs, ES"Change color")
local see = fmt("waypoint_%u_see", i)
fs("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)
image_button(ctn_len - 1.5, yi, icon_size, icon_size, "", see, "")
fs("tooltip[%s;%s]", see, ES"Preview the waypoint area")
fs("tooltip[%s;%s;#32333899;#fff]", see, ES"Preview the waypoint area")
local vsb = fmt("waypoint_%u_hide", i)
fs("style[%s;fgimg=%s;content_offset=0]", vsb, v.hide and PNG.nonvisible or PNG.visible)
image_button(ctn_len - 2, yi, icon_size, icon_size, "", vsb, "")
fs("tooltip[%s;%s]", vsb, v.hide and ES"Show waypoint" or ES"Hide waypoint")
fs("tooltip[%s;%s;#32333899;#fff]", vsb, v.hide and ES"Show waypoint" or ES"Hide waypoint")
if teleport_priv then
local tp = fmt("waypoint_%u_teleport", i)
@ -399,7 +379,7 @@ local function get_bag_fs(fs, data, bag_size, yextra)
hypertext(1.3, yextra + 0.8, 4.3, 0.6, "content",
fmt("<global size=16><center><b>%s</b></center>", desc))
image_button(5.22, yextra + 0.835, 0.25, 0.25, "", "bag_rename", "")
fs("tooltip[bag_rename;%s]", ES"Rename the bag")
fs("tooltip[bag_rename;%s;#32333899;#fff]", ES"Rename the bag")
else
box(1.7, yextra + 0.82, 2.6, 0.4, "#707070")
fs("field[1.8,%f;2.5,0.4;bag_newname;;%s]", yextra + 0.82, desc)
@ -462,7 +442,7 @@ local function get_container(fs, data, player, yoffset, ctn_len, award_list, awa
data.subcat == i and PNG[fmt("%s_hover", title)] or PNG[title],
PNG[fmt("%s_hover", title)])
image_button(0.25 + ((i - 1) * 1.18), yextra - 0.2, 0.5, 0.5, "", btn_name, "")
fs("tooltip[%s;%s]", btn_name, title:gsub("^%l", upper))
fs("tooltip[%s;%s;#32333899;#fff]", btn_name, title:gsub("^%l", upper))
end
box(0, yextra + 0.45, ctn_len, 0.045, "#bababa50")
@ -560,7 +540,7 @@ local function get_container(fs, data, player, yoffset, ctn_len, award_list, awa
Y += (Y * 2.45) + yextra - 2.75 + add_y
image_button(X, Y, 1.86, 3.4, "", btn_name, "")
fs("tooltip[%s;%s]", btn_name, ESC(skin.name))
fs("tooltip[%s;%s;#32333899;#fff]", btn_name, ESC(skin.name))
end
elseif data.subcat == 4 then
@ -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))
@ -639,17 +621,17 @@ local function show_settings(fs, data)
local sign = (data.font_size > 0 and "+") or (data.font_size > 0 and "-") or ""
label(5.3, 9.95, ES"Font size" .. fmt(": %s", sign .. data.font_size))
local range = 5
local range = 8
fs("scrollbaroptions[min=-%u;max=%u;smallstep=1;largestep=1;thumbsize=2]", range, range)
fs("scrollbar[5.3,10.2;2.55,0.3;horizontal;sb_font_size;%d]", data.font_size)
fs("scrollbar[5.3,10.2;2.55,0.3;horizontal;sb_font_size;%d+]", data.font_size)
fs("tooltip[cb_hide_tabs;%s;#707070;#fff]",
fs("tooltip[cb_hide_tabs;%s;#32333899;#fff]",
ES"Enable this option to change the style of the right panel")
fs("tooltip[cb_legacy_inventory;%s;#707070;#fff]",
fs("tooltip[cb_legacy_inventory;%s;#32333899;#fff]",
ES"Enable this option to set the classic inventory size in Minetest")
fs("tooltip[cb_wielditem_hud;%s;#707070;#fff]",
fs("tooltip[cb_wielditem_hud;%s;#32333899;#fff]",
ES"Enable this option to show the wielded item description in your HUD")
fs("tooltip[cb_collapse;%s;#707070;#fff]",
fs("tooltip[cb_collapse;%s;#32333899;#fff]",
ES"Enable this option to collapse the inventory list by grouping some items")
elseif show_sorting then
@ -666,21 +648,20 @@ local function show_settings(fs, data)
end
label(5.3, 10.4, ES"Sorting method:")
fs("dropdown[%f,%f;2.6,0.5;dd_sorting_method;%s;%u;true]",
5.3, 10.6, concat(methods, ","), data.sort)
fs("dropdown[%f,%f;2.6,0.5;dd_sorting_method;%s;%u;true]", 5.3, 10.6, concat(methods, ","), data.sort)
local desc = i3.sorting_methods[data.sort].description
if desc then
tooltip(5.3, 10.6, 2.4, 0.5, ESC(desc))
end
fs("tooltip[cb_inv_compress;%s;#707070;#fff]",
fs("tooltip[cb_inv_compress;%s;#32333899;#fff]",
ES"Enable this option to compress your inventory")
fs("tooltip[cb_reverse_sorting;%s;#707070;#fff]",
fs("tooltip[cb_reverse_sorting;%s;#32333899;#fff]",
ES"Enable this option to sort your inventory in reverse order")
fs("tooltip[cb_ignore_hotbar;%s;#707070;#fff]",
fs("tooltip[cb_ignore_hotbar;%s;#32333899;#fff]",
ES"Enable this option to sort your inventory except the hotbar slots")
fs("tooltip[cb_auto_sorting;%s;#707070;#fff]",
fs("tooltip[cb_auto_sorting;%s;#32333899;#fff]",
ES"Enable this option to sort your inventory automatically")
end
@ -688,11 +669,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;#32333899;#fff]", 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
@ -712,7 +735,7 @@ local function get_inventory_fs(player, data, fs)
-- fs"style[player_model;bgcolor=black]"
model(0.2, 0.2, armor_skin and 4 or 3.4, ctn_hgt,
"player_model", props.mesh, textures, "0,-150", "false", "false",
fmt("%u,%u;30", anim.x, anim.y))
true_table(anim) and fmt("%u,%u;30", anim.x, anim.y) or "")
else
local size = 2.5
image(0.7, 0.2, size, size * props.visual_size.y, props.textures[1])
@ -747,7 +770,6 @@ local function get_inventory_fs(player, data, fs)
for i = 1, award_list_nb do
local award = award_list[i]
if award.unlocked then
awards_unlocked++
end
@ -757,7 +779,6 @@ local function get_inventory_fs(player, data, fs)
elseif data.subcat == 5 then
local wp = #data.waypoints
if wp > 0 then
local mul = (wp > 8 and 7) or (wp > 4 and 6) or 5
max_val += 11 + (wp * mul)
@ -772,23 +793,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)
@ -864,7 +868,7 @@ local function get_tooltip(item, info, lang_code)
end
end
return fmt("tooltip[%s;%s]", item, ESC(tooltip))
return fmt("tooltip[%s;%s;#32333899;#fff]", item, ESC(tooltip))
end
local function get_true_count(data, count, is_recipe, is_usage)
@ -946,6 +950,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 +1054,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 +1067,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 +1100,13 @@ 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]
@ -1111,9 +1130,7 @@ local function get_grid_fs(fs, data, rcp, is_recipe, is_usage)
meta_desc = meta_desc,
}
if next(infos) then
fs(get_tooltip(btn_name, infos, data.lang_code))
end
fs(get_tooltip(btn_name, infos, data.lang_code))
end
if large_recipe then
@ -1214,20 +1231,18 @@ local function get_header(fs, data)
local star_x, star_y, size = data.inv_width + 0.3, data.yoffset + 0.2, 0.4
if nfavs < max_favs or (nfavs == max_favs and fav) then
local fav_marked = fmt("i3_fav%s.png", fav and "_off" or "")
fs("style[fav;fgimg=%s;fgimg_hovered=%s;fgimg_pressed=%s]",
fmt("i3_fav%s.png", fav and "" or "_off"), fav_marked, fav_marked)
fs("style[fav;fgimg=i3_fav%s.png;fgimg_hovered=i3_fav%s.png]", fav and "" or "_off", fav and "" or "_off")
image_button(star_x, star_y, size, size, "", "fav", "")
fs("tooltip[fav;%s]", fav and ES"Unmark this item" or ES"Mark this item")
fs("tooltip[fav;%s;#32333899;#fff]", fav and ES"Unbookmark this item" or ES"Bookmark this item")
else
fs("style[nofav;fgimg=%s;fgimg_hovered=%s;fgimg_pressed=%s]",
"i3_fav_off.png", PNG.cancel, PNG.cancel)
image_button(star_x, star_y, size, size, "", "nofav", "")
fs("tooltip[nofav;%s]", ES"Cannot mark this item. Bookmark limit reached.")
fs("tooltip[nofav;%s;#32333899;#fff]", ES"Unable to bookmark this item, limit reached")
end
image_button(star_x + 0.05, star_y + 0.6, size, size, "", "exit", "")
fs("tooltip[exit;%s]", ES"Back to item list")
fs("tooltip[exit;%s;#32333899;#fff]", ES"Back to item list")
local desc_lim, name_lim = 34, 35
local desc = get_desc(data.query_item, data.lang_code)
@ -1270,7 +1285,7 @@ local function get_crafting_fs(fs, data, is_recipe, is_usage, max_stacks_rcp, ma
fs("style[crafting_%s;fgimg=%s;fgimg_hovered=%s;content_offset=0]",
name, fmt("%s", show_crafting and PNG.crafting_hover or PNG.crafting), PNG.crafting_hover)
image_button(data.inv_width + 7.35, data.yoffset + 0.2, 0.45, 0.45, "", fmt("crafting_%s", name), "")
fs("tooltip[crafting_%s;%s]", name, ES"Quick crafting")
fs("tooltip[crafting_%s;%s;#32333899;#fff]", name, ES"Quick crafting")
if not show_crafting then return end
@ -1298,9 +1313,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 +1326,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 +1347,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)
@ -1380,7 +1413,7 @@ local function get_header_items_fs(fs, data)
fs("style[enable_search;bgimg=%s;bgimg_hovered=%s;bgimg_pressed=%s]",
data.enable_search and PNG.search_hover or PNG.search, PNG.search_hover, PNG.search_hover)
image_button(X + 0.3, 0.2, 0.5, 0.5, "", "enable_search", "")
fs("tooltip[enable_search;%s]", ES"Search")
fs("tooltip[enable_search;%s;#32333899;#fff]", ES"Search")
if data.enable_search then
image(X + 0.4, 0.75, 3.4, 0.8, PNG.bg_goto)
@ -1391,7 +1424,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])
@ -1400,12 +1446,12 @@ local function get_header_items_fs(fs, data)
fs("style[itab_%u;bgimg=%s;bgimg_hovered=%s;bgimg_pressed=%s;sound=i3_tab]",
i, data.itab == i and active or PNG[name], active, active)
image_button(X + 1.25 + ((i - 1) * 0.7), 0.2, 0.5, 0.5, "", fmt("itab_%s", i), "")
fs("tooltip[itab_%u;Show %s]", i, desc)
fs("tooltip[itab_%u;Show %s;#32333899;#fff]", i, desc)
end
else
fs("style[search;bgimg=%s]", PNG.search_hover)
image_button(X + 0.35, 0.32, 0.35, 0.35, "", "search", "")
fs("tooltip[search;%s]", ES"Search")
fs("tooltip[search;%s;#32333899;#fff]", ES"Search")
if data.enable_search then
fs"style[filter;font_size=18]"
@ -1424,7 +1470,7 @@ local function get_header_items_fs(fs, data)
if true_str(data.filter) then
image_button(X + 4.3, 0.4, 0.2, 0.2, "", "cancel", "")
fs("tooltip[cancel;%s]", ES"Clear")
fs("tooltip[cancel;%s;#32333899;#fff]", ES"Clear")
box(X + 0.85, 0.75, 3.74, 0.01, "#f9826c")
end
end
@ -1452,22 +1498,35 @@ 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 +1574,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
@ -1536,10 +1595,12 @@ local function get_items_fs(fs, data, player, full_height)
if compressible(item, data) then
local expand = data.expand == name
fs("tooltip[%s;%s]", item, expand and ES"Click to hide" or ES"Click to expand")
fs("tooltip[%s;%s;#32333899;#fff]", item, expand and ES"Click to hide" or ES"Click to expand")
fs"style_type[label;font=bold;font_size=20]"
label(X + 0.65, Y + 0.7, expand and "-" or "+")
fs"style_type[label;font=normal;font_size=16]"
elseif true_str(name) then
fs(get_tooltip(name, {}, data.lang_code))
end
end
end
@ -1616,17 +1677,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 +1695,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 +1758,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 +1774,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

@ -1,9 +1,9 @@
IMPORT("ceil", "get_connected_players", "str_to_pos", "add_hud_waypoint")
IMPORT("max", "ceil", "remove", "str_to_pos")
IMPORT("get_connected_players", "add_hud_waypoint")
local function init_hud(player)
local name = player:get_player_name()
local data = i3.data[name]
local wdesc_y = -90
if core.global_exists"hb" then
@ -13,33 +13,7 @@ local function init_hud(player)
end
data.hud = {
bg = player:hud_add {
hud_elem_type = "image",
position = {x = 0.78, y = 1},
alignment = {x = 1, y = 1},
scale = {x = 370, y = 112},
text = "i3_bg.png",
z_index = 0xDEAD,
},
img = player:hud_add {
hud_elem_type = "image",
position = {x = 0.79, y = 1.02},
alignment = {x = 1, y = 1},
scale = {x = 1, y = 1},
text = "",
z_index = 0xDEAD,
},
text = player:hud_add {
hud_elem_type = "text",
position = {x = 0.84, y = 1.04},
alignment = {x = 1, y = 1},
number = 0xffffff,
text = "",
z_index = 0xDEAD,
style = 1,
},
notifs = {},
wielditem = player:hud_add {
hud_elem_type = "text",
@ -50,54 +24,55 @@ local function init_hud(player)
text = "",
z_index = 0xDEAD,
style = 1,
},
}
}
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 function get_progress(offset, max_val)
local progress = offset * (1 / (max_val - 5))
return 1 - (progress ^ 4)
end
local hud_info_bg = player:hud_get(data.hud.bg)
local dt = 0.025
local function show_hud(player, data, notif, idx, dt)
local hud_info_bg = player:hud_get(notif.elems.bg)
local offset = hud_info_bg.offset
if hud_info_bg.position.y <= 0.9 then
data.show_hud = false
data.hud_timer = (data.hud_timer or 0) + dt
if offset.y < notif.max.y then
notif.show = false
notif.hud_timer += dt
end
player:hud_change(data.hud.text, "text", data.hud_msg)
player:hud_change(notif.elems.text, "text", notif.hud_msg)
if data.hud_img then
player:hud_change(data.hud.img, "text", data.hud_img)
if notif.hud_img then
player:hud_change(notif.elems.img, "text", notif.hud_img)
end
if data.show_hud then
for _, def in pairs(data.hud) do
if notif.show then
local speed = i3.settings.hud_speed * (100 * get_progress(offset.y, notif.max.y)) * dt
for _, def in pairs(notif.elems) 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)
player:hud_change(def, "offset", {
x = hud_info.offset.x,
y = hud_info.offset.y - (speed * max(1, (#data.hud.notifs - idx + 1) / 1.45))
})
end
elseif notif.show == false and notif.hud_timer >= i3.settings.hud_timer_max then
local speed = (i3.settings.hud_speed * 2.6) * (100 * get_progress(offset.x, notif.max.x)) * dt
elseif data.show_hud == false then
if data.hud_timer >= i3.settings.hud_timer_max then
for _, def in pairs(data.hud) do
local hud_info = player:hud_get(def)
for _, def in pairs(notif.elems) 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
player:hud_change(def, "offset", {
x = hud_info.offset.x - speed,
y = hud_info.offset.y
})
if hud_info_bg.position.y >= 1 then
data.show_hud = nil
data.hud_timer = nil
data.hud_msg = nil
data.hud_img = nil
if hud_info.offset.x < notif.max.x then
player:hud_remove(def)
remove(data.hud.notifs, idx)
end
end
end
@ -113,8 +88,18 @@ core.register_globalstep(function(dt)
local data = i3.data[name]
if not data then return end
for idx, notif in ipairs(data.hud.notifs) do
if notif.show ~= nil then
show_hud(player, data, notif, idx, dt)
end
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 +107,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 +128,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]
@ -123,7 +128,7 @@ local fs_elements = {
label = "label[%f,%f;%s]",
box = "box[%f,%f;%f,%f;%s]",
image = "image[%f,%f;%f,%f;%s]",
tooltip = "tooltip[%f,%f;%f,%f;%s]",
tooltip = "tooltip[%f,%f;%f,%f;%s;#32333899;#fff]",
button = "button[%f,%f;%f,%f;%s;%s]",
checkbox = "checkbox[%f,%f;%s;%s;%s]",
slot = "image[%f,%f;%f,%f;" .. fmt("%s;9]", PNG.slot),

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_bg_notif.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

BIN
textures/i3_home_px.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 171 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 171 B