Compare commits

..

56 Commits
1.10.1 ... 1.14

Author SHA1 Message Date
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
38f1d7c960 Bump version 2023-01-11 00:10:30 +01:00
5d4f9b4709 Get rid of Factorio's sounds 2023-01-11 00:07:27 +01:00
a0a3394e18 Add API to manage waypoints 2023-01-07 12:47:45 +01:00
d9a16bf39d Bump version 2022-12-05 03:08:19 +01:00
2a2837dd0c Minor cleaning 2022-12-01 20:28:44 +01:00
080579b2a4 Show player name based on nametag 2022-12-01 20:23:53 +01:00
b711f8f195 API doc clarification 2022-11-12 19:54:17 +01:00
00a258afea Show colored itemstacks the right way 2022-10-02 14:38:49 +02:00
dd8657ab56 Waypoint viewer: use an animate flag 2022-10-02 13:49:06 +02:00
34fa63519e Minor tweak 2022-09-28 15:31:39 +02:00
066e0a5d9d Improve wording 2022-09-26 03:17:34 +02:00
8fc01b7ece Minor cleaning 2022-09-25 18:57:27 +02:00
a1af79a870 Minor cleaning 2022-09-25 18:16:17 +02:00
a5ceae07d7 Oopsie 2022-09-25 17:43:07 +02:00
7f437b21f4 Bump version 2022-09-25 17:22:38 +02:00
e8a811f72c Save more settings accross restarts 2022-09-25 17:22:36 +02:00
4c4911eb4f Fix 2022-09-25 16:55:41 +02:00
325d6f30be 🚀 Greatly improve Progressive Mode look 2022-09-25 16:23:11 +02:00
05995a22df Add sound for skins 2022-09-24 16:24:01 +02:00
32594e7552 Small fix 2022-09-24 14:30:45 +02:00
27ed1f02e6 More cleaning 2022-09-24 14:23:47 +02:00
916e80f2c3 Cleanup vectors 2022-09-24 13:46:50 +02:00
c42ea6c005 Minor tweak 2022-09-20 01:12:07 +02:00
da91223c4d Bump version 2022-09-18 14:24:45 +02:00
408267754c API.md: rewrite some parts 2022-09-15 12:28:23 +02:00
b4de48370a HUD: small tweak 2022-09-14 15:37:29 +02:00
477efe56d3 Bump version 2022-09-04 19:17:42 +02:00
8afb51dae8 Some cleaning 2022-09-04 19:12:57 +02:00
734b09b69f Minor cleaning 2022-08-29 11:29:09 +02:00
1560d59d4a Bump version 2022-08-28 16:36:30 +02:00
e4e175a775 Minor tweak 2022-08-28 16:36:08 +02:00
7a40f36611 Bump version 2022-08-28 15:36:44 +02:00
2467e8bb0b Fix sound play 2022-08-28 15:34:37 +02:00
9666834aed Minor tweak 2022-08-28 15:21:20 +02:00
7670356c8c Bump version (again) 2022-08-28 14:46:03 +02:00
646d16afd8 Hotfix HUD 2022-08-28 14:45:37 +02:00
6b54dbc934 Bump version 2022-08-28 14:23:36 +02:00
911bed3911 Add option in Style settings to show wielditem descriptions in HUD 2022-08-28 14:18:05 +02:00
75fdd57f2a Integrate Legacy Inventory option per-player in Settings popup 2022-08-28 13:31:01 +02:00
c8d6312772 Minor cleaning 2022-08-21 23:47:15 +02:00
a4e8fac0e6 Update preview screenshot 2022-08-20 17:45:44 +02:00
32 changed files with 905 additions and 444 deletions

View File

@ -10,6 +10,7 @@ read_globals = {
"armor", "armor",
"skins", "skins",
"awards", "awards",
"hb",
"vector", "vector",
"string", "string",
"table", "table",
@ -30,6 +31,7 @@ exclude_files = {
"tests/test_custom_recipes.lua", "tests/test_custom_recipes.lua",
"tests/test_operators.lua", "tests/test_operators.lua",
"tests/test_tabs.lua", "tests/test_tabs.lua",
"tests/test_waypoints.lua",
".install", ".install",
".luarocks", ".luarocks",

159
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)` #### `i3.new_tab(name, def)`
@ -12,40 +25,50 @@ Custom tabs can be added to the `i3` inventory as follow (example):
```Lua ```Lua
i3.new_tab("stuff", { i3.new_tab("stuff", {
description = "Stuff", description = "Stuff",
image = "image.png", -- Optional, adds an image next to the tab description image = "image.png", -- Optional, add an image next to the tab description
-- Determine if the tab is visible by a player, `false` or `nil` hide the tab --
-- The functions below are all optional
--
-- Determine if the tab is visible by a player, return false to hide the tab
access = function(player, data) access = function(player, data)
local name = player:get_player_name() local name = player:get_player_name()
return name == "singleplayer" return name == "singleplayer"
end, end,
formspec = function(player, data, fs) formspec = function(player, data, fs)
fs("label[3,1;This is just a test]") fs("label", 3, 1, "Just a test")
fs"label[3,2;Lorem Ipsum]"
-- No need to return anything
end, end,
-- Events handling happens here -- Events handling happens here
fields = function(player, data, fields) fields = function(player, data, fields)
if fields.mybutton then
-- Do things
end
i3.set_fs(player) -- Update the formspec
end, end,
}) })
``` ```
- `player` is an `ObjectRef` to the user. - `player` is an `ObjectRef` to the user.
- `data` are the user data. - `data` are the user data.
- `fs` is the formspec table which is callable with a metamethod. Each call adds a new entry. - `fs` is the formspec table which is callable with a metamethod. Every call adds a new entry.
#### `i3.set_fs(player)` #### `i3.set_fs(player)`
Updates the current formspec. Update the current formspec.
#### `i3.remove_tab(tabname)` #### `i3.remove_tab(tabname)`
Deletes a tab by name. Delete a tab by name.
#### `i3.get_current_tab(player)` #### `i3.get_current_tab(player)`
Returns the current player tab. `player` is an `ObjectRef` to the user. Return the current player tab. `player` is an `ObjectRef` to the user.
#### `i3.set_tab(player[, tabname])` #### `i3.set_tab(player[, tabname])`
@ -54,7 +77,7 @@ Sets the current tab by name. `player` is an `ObjectRef` to the user.
#### `i3.override_tab(tabname, def)` #### `i3.override_tab(tabname, def)`
Overrides a tab by name. `def` is the tab definition like seen in `i3.set_tab`. Override a tab by name. `def` is the tab definition like seen in `i3.set_tab`
#### `i3.tabs` #### `i3.tabs`
@ -62,15 +85,17 @@ A list of registered tabs.
--- ---
### Custom recipes ### Recipes
Custom recipes are nonconventional crafts outside the main crafting grid. Custom recipes are nonconventional crafts outside the main crafting grid.
They can be registered in-game dynamically and have a size beyond 3x3 items. They can be registered in-game dynamically and have a size beyond 3x3 items.
**Note:** the registration format differs from the default registration format in everything. **Note:** the registration format differs from the default registration format in everything.
The width is automatically calculated depending where you place the commas. Look at the examples attentively. The width is automatically calculated depending where you place the commas.
#### Registering a custom crafting type (example) Examples:
#### Registering a custom crafting type
```Lua ```Lua
i3.register_craft_type("digging", { i3.register_craft_type("digging", {
@ -79,7 +104,7 @@ i3.register_craft_type("digging", {
}) })
``` ```
#### Registering a custom crafting recipe (examples) #### Registering a custom crafting recipe
```Lua ```Lua
i3.register_craft { i3.register_craft {
@ -152,6 +177,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
Recipe filters can be used to filter the recipes shown to players. Progressive Recipe filters can be used to filter the recipes shown to players. Progressive
@ -159,7 +231,7 @@ mode is implemented as a recipe filter.
#### `i3.add_recipe_filter(name, function(recipes, player))` #### `i3.add_recipe_filter(name, function(recipes, player))`
Adds a recipe filter with the given `name`. The filter function returns the Add a recipe filter with the given `name`. The filter function returns the
recipes to be displayed, given the available recipes and an `ObjectRef` to the recipes to be displayed, given the available recipes and an `ObjectRef` to the
user. Each recipe is a table of the form returned by user. Each recipe is a table of the form returned by
`minetest.get_craft_recipe`. `minetest.get_craft_recipe`.
@ -181,7 +253,7 @@ end)
#### `i3.set_recipe_filter(name, function(recipe, player))` #### `i3.set_recipe_filter(name, function(recipe, player))`
Removes all recipe filters and adds a new one. Remove all recipe filters and add a new one.
#### `i3.recipe_filters` #### `i3.recipe_filters`
@ -207,7 +279,7 @@ Notes:
#### `i3.add_search_filter(name, function(item, values))` #### `i3.add_search_filter(name, function(item, values))`
Adds a search filter. Add a search filter.
The search function must return a boolean value (whether the given item should be listed or not). The search function must return a boolean value (whether the given item should be listed or not).
- `name` is the filter name. - `name` is the filter name.
@ -241,7 +313,7 @@ Sorting methods are used to filter the player's main inventory.
#### `i3.add_sorting_method(name, def)` #### `i3.add_sorting_method(name, def)`
Adds a player inventory sorting method. Add a player inventory sorting method.
- `name` is the method name. - `name` is the method name.
- `def` is the method definition. - `def` is the method definition.
@ -276,7 +348,7 @@ A table containing all sorting methods.
#### `i3.compress(item, def)` #### `i3.compress(item, def)`
Adds a new group of items to compress. Add a new group of items to compress.
- `item` is the item which represent the group of compressed items. - `item` is the item which represent the group of compressed items.
- `def` is a table specifying the substring replace patterns to be used. - `def` is a table specifying the substring replace patterns to be used.
@ -297,11 +369,54 @@ A map of all compressed item groups, indexed by stereotypes.
--- ---
### Waypoints
`i3` allows you to manage the waypoints of a specific player.
#### `i3.add_waypoint(player_name, def)`
Add a waypoint to specific player.
- `player_name` is the player name.
- `def` is the waypoint definition table.
Example:
```Lua
i3.add_waypoint("Test", {
player = "singleplayer",
pos = {x = 0, y = 2, z = 0},
color = 0xffff00,
-- image = "heart.png" (optional)
})
```
#### `i3.remove_waypoint(player_name, waypoint_name)`
Remove a waypoint for specific player.
- `player_name` is the player name.
- `waypoint_name` is the waypoint name.
Example:
```Lua
i3.remove_waypoint("singleplayer", "Test")
```
#### `i3.get_waypoints(player_name)`
Return a table of all waypoints of a specific player.
- `player_name` is the player name.
---
### Miscellaneous ### Miscellaneous
#### `i3.hud_notif(name, msg[, img])` #### `i3.hud_notif(name, msg[, img])`
Shows a Steam-like HUD notification on the bottom-right corner of the screen (experimental). Show a Steam-like HUD notification on the bottom-right corner of the screen (experimental).
- `name` is the player name. - `name` is the player name.
- `msg` is the HUD message to show. - `msg` is the HUD message to show.
@ -309,7 +424,7 @@ Shows a Steam-like HUD notification on the bottom-right corner of the screen (ex
#### `i3.get_recipes(item)` #### `i3.get_recipes(item)`
Returns a table of recipes and usages of `item`. Return a table of recipes and usages of `item`.
#### `i3.export_url` #### `i3.export_url`

10
LICENSE
View File

@ -3,7 +3,7 @@ License of source code
The MIT License (MIT) 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 Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal
@ -23,6 +23,14 @@ 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 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE. THE SOFTWARE.
Licenses of media (sounds)
--------------------------
Lone_Wolf (CC0):
i3_tab.ogg
i3_craft.ogg
i3_click.ogg
i3_cannot.ogg
Licenses of media (textures) Licenses of media (textures)
---------------------------- ----------------------------

View File

@ -1,6 +1,6 @@
![logo](https://user-images.githubusercontent.com/7883281/145490041-d91d6bd6-a654-438d-b208-4d5736845ab7.png) ![logo](https://user-images.githubusercontent.com/7883281/145490041-d91d6bd6-a654-438d-b208-4d5736845ab7.png)
[![MIT License](https://img.shields.io/apm/l/atomic-design-ui.svg?)](https://github.com/tterb/atomic-design-ui/blob/master/LICENSEs) [![GitHub Release](https://img.shields.io/github/release/minetest-mods/i3.svg?style=flat)]() ![workflow](https://github.com/minetest-mods/i3/actions/workflows/luacheck.yml/badge.svg) [![ContentDB](https://content.minetest.net/packages/jp/i3/shields/downloads/)](https://content.minetest.net/packages/jp/i3/) [![PayPal](https://img.shields.io/badge/paypal-donate-yellow.svg)](https://www.paypal.me/jpg84240) [![GitHub Release](https://img.shields.io/github/release/minetest-mods/i3.svg?style=flat)]() ![workflow](https://github.com/minetest-mods/i3/actions/workflows/luacheck.yml/badge.svg) [![ContentDB](https://content.minetest.net/packages/jp/i3/shields/downloads/)](https://content.minetest.net/packages/jp/i3/) [![PayPal](https://img.shields.io/badge/paypal-donate-yellow.svg)](https://www.paypal.me/jpg84240)
#### **`i3`** is a next-generation inventory for Minetest. #### **`i3`** is a next-generation inventory for Minetest.
@ -55,4 +55,4 @@ Report bugs on the [**Bug Tracker**](https://github.com/minetest-mods/i3/issues)
**Video review on YouTube:** https://www.youtube.com/watch?v=Xd14BCdEZ3o **Video review on YouTube:** https://www.youtube.com/watch?v=Xd14BCdEZ3o
![Preview](https://content.minetest.net/uploads/3abf3755de.png) ![Preview](https://user-images.githubusercontent.com/7883281/185755315-23c2fffa-203d-4115-9dc3-576c92615733.png)

View File

@ -20,7 +20,7 @@ local function lf(path)
end end
i3 = { i3 = {
version = 1100, version = 114,
data = core.deserialize(storage:get_string"data") or {}, data = core.deserialize(storage:get_string"data") or {},
settings = { settings = {
@ -30,15 +30,14 @@ i3 = {
min_fs_version = 6, min_fs_version = 6,
item_btn_size = 1.1, item_btn_size = 1.1,
drop_bag_on_die = true, drop_bag_on_die = true,
wielditem_fade_after = 3,
save_interval = 600, -- Player data save interval (in seconds) save_interval = 600, -- Player data save interval (in seconds)
hud_speed = 1, hud_speed = 1,
hud_timer_max = 1.5, hud_timer_max = 3,
damage_enabled = core.settings:get_bool"enable_damage", damage_enabled = core.settings:get_bool"enable_damage",
progressive_mode = core.settings:get_bool"i3_progressive_mode", progressive_mode = core.settings:get_bool"i3_progressive_mode",
legacy_inventory = core.settings:get_bool"i3_legacy_inventory",
item_compression = core.settings:get_bool("i3_item_compression", true),
}, },
categories = { categories = {
@ -52,11 +51,26 @@ i3 = {
saves = { -- Metadata to save saves = { -- Metadata to save
bag = true, bag = true,
home = true, home = true,
sort = true,
collapse = true,
font_size = true, font_size = true,
hide_tabs = true, hide_tabs = true,
waypoints = true, waypoints = true,
inv_items = true, inv_items = true,
auto_sorting = true,
inv_compress = true,
known_recipes = true, known_recipes = true,
wielditem_hud = true,
ignore_hotbar = true,
reverse_sorting = true,
legacy_inventory = true,
},
default_data = {
sort = 1,
font_size = 0,
collapse = true,
inv_compress = true,
}, },
files = { files = {
@ -87,6 +101,7 @@ i3 = {
groups = {}, groups = {},
plants = {}, plants = {},
modules = {}, modules = {},
minitabs = {},
craft_types = {}, craft_types = {},
recipe_filters = {}, recipe_filters = {},
@ -94,12 +109,10 @@ i3 = {
sorting_methods = {}, sorting_methods = {},
} }
i3.settings.hotbar_len = i3.settings.legacy_inventory and 8 or 9
i3.settings.inv_size = 4 * i3.settings.hotbar_len
i3.files.common() i3.files.common()
i3.files.api(http) i3.files.api(http)
i3.files.compress() i3.files.compress()
i3.files.detached()
i3.files.groups() i3.files.groups()
i3.files.callbacks(http, storage) i3.files.callbacks(http, storage)
@ -109,7 +122,8 @@ end
if i3.settings.debug_mode then if i3.settings.debug_mode then
lf("/tests/test_tabs.lua")() lf("/tests/test_tabs.lua")()
lf("/tests/test_operators.lua")() lf("/tests/test_waypoints.lua")()
-- lf("/tests/test_operators.lua")()
lf("/tests/test_compression.lua")() lf("/tests/test_compression.lua")()
lf("/tests/test_custom_recipes.lua")() lf("/tests/test_custom_recipes.lua")()
end end

View File

@ -1,4 +1,4 @@
name = i3 name = i3
description = Next-generation inventory description = Next-generation inventory
optional_depends = 3d_armor, skinsdb, awards optional_depends = 3d_armor, skinsdb, awards
min_minetest_version = 5.4 min_minetest_version = 5.6

View File

@ -1,8 +1,2 @@
# The progressive mode shows recipes you can craft from items you ever had in your inventory. # The progressive mode shows recipes you can craft from items you ever had in your inventory.
i3_progressive_mode (Learn crafting recipes progressively) bool false i3_progressive_mode (Learn crafting recipes progressively) bool false
# Regroup the items of the same type in the item list.
i3_item_compression (Regroup items of the same type) bool true
# Set the inventory size to common chests size (8*4).
i3_legacy_inventory (Legacy inventory size) bool false

BIN
sounds/i3_achievement.ogg Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
sounds/i3_skin_change.ogg Normal file

Binary file not shown.

Binary file not shown.

View File

@ -1,10 +1,10 @@
local http = ... local http = ...
local make_fs, get_inventory_fs = i3.files.gui() local make_fs, get_inventory_fs = i3.files.gui()
IMPORT("gmatch", "split") IMPORT("sorter", "sort_inventory", "play_sound")
IMPORT("S", "err", "fmt", "reg_items") IMPORT("get_player_by_name", "add_hud_waypoint")
IMPORT("sorter", "sort_inventory")
IMPORT("sort", "concat", "copy", "insert", "remove") IMPORT("sort", "concat", "copy", "insert", "remove")
IMPORT("gmatch", "split", "S", "err", "fmt", "reg_items", "pos_to_str")
IMPORT("true_str", "true_table", "is_str", "is_func", "is_table", "clean_name") IMPORT("true_str", "true_table", "is_str", "is_func", "is_table", "clean_name")
function i3.register_craft_type(name, def) function i3.register_craft_type(name, def)
@ -204,10 +204,10 @@ function i3.remove_tab(name)
return err "i3.remove_tab: tab name missing" return err "i3.remove_tab: tab name missing"
end end
for i, def in ipairs(i3.tabs) do for i = #i3.tabs, 1, -1 do
if name == def.name then local def = i3.tabs[i]
if def and name == def.name then
remove(i3.tabs, i) remove(i3.tabs, i)
break
end end
end end
end end
@ -315,7 +315,6 @@ function i3.hud_notif(name, msg, img)
end end
local data = i3.data[name] local data = i3.data[name]
if not data then if not data then
return err "i3.hud_notif: no player data initialized" return err "i3.hud_notif: no player data initialized"
end end
@ -323,8 +322,10 @@ function i3.hud_notif(name, msg, img)
data.show_hud = true data.show_hud = true
data.hud_msg = msg data.hud_msg = msg
play_sound(name, "i3_achievement", 1.0)
if img then if img then
data.hud_img = fmt("%s^[resize:16x16", img) data.hud_img = fmt("%s^[resize:64x64", img)
end end
end end
@ -356,3 +357,128 @@ i3.add_sorting_method("numerical", {
return list return list
end, end,
}) })
function i3.add_waypoint(name, def)
if not true_str(name) then
return err "i3.add_waypoint: name missing"
elseif not true_table(def) then
return err "i3.add_waypoint: definition missing"
elseif not true_str(def.player) then
return err "i3.add_waypoint: player name missing"
end
local data = i3.data[def.player]
if not data then
return err "i3.add_waypoint: no player data initialized"
end
local player = get_player_by_name(def.player)
local id = player and add_hud_waypoint(player, name, def.pos, def.color, def.image) or nil
insert(data.waypoints, {
name = name,
pos = pos_to_str(def.pos, 1),
color = def.color,
image = def.image,
id = id,
})
if data.subcat == 5 then
data.scrbar_inv += 1000
end
i3.set_fs(player)
end
function i3.remove_waypoint(player_name, name)
if not true_str(player_name) then
return err "i3.remove_waypoint: player name missing"
elseif not true_str(name) then
return err "i3.remove_waypoint: waypoint name missing"
end
local data = i3.data[player_name]
if not data then
return err "i3.remove_waypoint: no player data initialized"
end
local player = get_player_by_name(player_name)
for i = #data.waypoints, 1, -1 do
local waypoint = data.waypoints[i]
if waypoint and name == waypoint.name then
if player then
player:hud_remove(waypoint.id)
end
remove(data.waypoints, i)
end
end
i3.set_fs(player)
end
function i3.get_waypoints(player_name)
if not true_str(player_name) then
return err "i3.get_waypoints: player name missing"
end
local data = i3.data[player_name]
if not data then
return err "i3.get_waypoints: no player data initialized"
end
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"
elseif name == "all" then
return err "i3.remove_minitab: removing the 'All' tab is not allowed"
end
for i = #i3.minitabs, 1, -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

@ -2,7 +2,7 @@ local replacements = {fuel = {}}
local http = ... local http = ...
IMPORT("maxn", "copy", "insert", "sort", "match", "sub") IMPORT("maxn", "copy", "insert", "sort", "match", "sub")
IMPORT("true_str", "is_table", "valid_item", "table_merge", "table_replace", "rcp_eq") 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("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") IMPORT("is_group", "extract_groups", "item_has_groups", "groups_to_items", "get_group_stereotype")
@ -178,13 +178,9 @@ local function cache_recipes(item)
_recipes[#recipes + 1 - k] = v _recipes[#recipes + 1 - k] = v
end end
local shift = 0
local size_rpl = maxn(replacements[item]) local size_rpl = maxn(replacements[item])
local size_rcp = #_recipes local size_rcp = #_recipes
local shift = size_rcp - size_rpl
if size_rpl > size_rcp then
shift = size_rcp - size_rpl
end
for k, v in pairs(replacements[item]) do for k, v in pairs(replacements[item]) do
k += shift k += shift
@ -248,11 +244,7 @@ local old_clear_craft = core.clear_craft
core.clear_craft = function(def) core.clear_craft = function(def)
old_clear_craft(def) old_clear_craft(def)
if true_str(def) then -- TODO: hide in crafting guide
return -- TODO
elseif is_table(def) then
return -- TODO
end
end end
local function resolve_aliases(hash) local function resolve_aliases(hash)
@ -274,7 +266,7 @@ local function resolve_aliases(hash)
local rcp_new = copy(i3.recipes_cache[newname][j]) local rcp_new = copy(i3.recipes_cache[newname][j])
rcp_new.output = oldname rcp_new.output = oldname
if rcp_eq(rcp_old, rcp_new) then if table_eq(rcp_old, rcp_new) then
similar = true similar = true
break break
end end

View File

@ -1,12 +1,11 @@
local http, storage = ... local http, storage = ...
local init_bags = i3.files.bags() local init_bags = i3.files.bags()
local fill_caches = i3.files.caches(http) local fill_caches = i3.files.caches(http)
local init_detached = i3.files.detached()
local init_hud = i3.files.hud() local init_hud = i3.files.hud()
local set_fs = i3.set_fs local set_fs = i3.set_fs
IMPORT("slz", "min", "insert", "copy", "ItemStack") IMPORT("slz", "min", "insert", "copy", "ItemStack")
IMPORT("spawn_item", "reset_data", "get_detached_inv", "play_sound") IMPORT("spawn_item", "reset_data", "get_detached_inv", "play_sound", "update_inv_size")
core.register_on_player_hpchange(function(player, hpchange) core.register_on_player_hpchange(function(player, hpchange)
local name = player:get_player_name() local name = player:get_player_name()
@ -204,6 +203,15 @@ local function init_data(player, info)
i3.data[name] = i3.data[name] or {} i3.data[name] = i3.data[name] or {}
local data = i3.data[name] local data = i3.data[name]
for k, v in pairs(i3.default_data) do
local val = data[k]
if val == nil then
val = v
end
data[k] = val
end
data.player_name = name data.player_name = name
data.filter = "" data.filter = ""
data.pagenum = 1 data.pagenum = 1
@ -212,22 +220,15 @@ local function init_data(player, info)
data.items_raw = i3.init_items data.items_raw = i3.init_items
data.favs = {} data.favs = {}
data.show_setting = "home" data.show_setting = "home"
data.ignore_hotbar = false
data.auto_sorting = false
data.reverse_sorting = false
data.inv_compress = true
data.crafting_counts = {} data.crafting_counts = {}
data.sort = 1
data.tab = 1 data.tab = 1
data.itab = 1 data.itab = 1
data.subcat = 1 data.subcat = 1
data.scrbar_inv = 0 data.scrbar_inv = 0
data.font_size = data.font_size or 0
data.lang_code = get_lang_code(info) data.lang_code = get_lang_code(info)
data.fs_version = info.formspec_version data.fs_version = info.formspec_version
local inv = player:get_inventory() update_inv_size(player, data)
inv:set_size("main", i3.settings.inv_size)
core.after(0, set_fs, player) core.after(0, set_fs, player)
end end
@ -260,7 +261,6 @@ insert(core.registered_on_joinplayers, 1, function(player)
init_data(player, info) init_data(player, info)
init_bags(player) init_bags(player)
init_detached(player)
init_hud(player) init_hud(player)
end) end)

View File

@ -1,8 +1,8 @@
local vec = vector.new
local ItemStack = ItemStack local ItemStack = ItemStack
local loadstring = loadstring local loadstring = loadstring
local reg_items = core.registered_items local reg_items = core.registered_items
local translate = core.get_translated_string local translate = core.get_translated_string
local vec_new, vec_add, vec_mul = vector.new, vector.add, vector.multiply
local sort, concat, insert = table.sort, table.concat, table.insert local sort, concat, insert = table.sort, table.concat, table.insert
local min, floor, ceil = math.min, math.floor, math.ceil local min, floor, ceil = math.min, math.floor, math.ceil
local fmt, find, match, gmatch, sub, split, lower, upper = local fmt, find, match, gmatch, sub, split, lower, upper =
@ -216,18 +216,22 @@ local function array_diff(t1, t2)
return diff return diff
end end
local function rcp_eq(rcp, rcp2) local function table_eq(t1, t2)
if rcp.type ~= rcp2.type then return end local ty1, ty2 = type(t1), type(t2)
if rcp.width ~= rcp2.width then return end if ty1 ~= ty2 then return end
if #rcp.items ~= #rcp2.items then return end
if rcp.output ~= rcp2.output then return end
for i, item in pairs(rcp.items) do if ty1 ~= "table" and ty2 ~= "table" then
if item ~= rcp2.items[i] then return end return t1 == t2
end end
for i, item in pairs(rcp2.items) do for k, v in pairs(t1) do
if item ~= rcp.items[i] then return end local v2 = t2[k]
if v2 == nil or not table_eq(v, v2) then return end
end
for k, v in pairs(t2) do
local v1 = t1[k]
if v1 == nil or not table_eq(v1, v) then return end
end end
return true return true
@ -323,8 +327,12 @@ local function apply_recipe_filters(recipes, player)
return recipes return recipes
end end
local function recipe_filter_set()
return next(i3.recipe_filters)
end
local function compression_active(data) local function compression_active(data)
return i3.settings.item_compression and not next(i3.recipe_filters) and data.filter == "" return data.collapse and not recipe_filter_set() and data.filter == ""
end end
local function compressible(item, data) local function compressible(item, data)
@ -352,13 +360,8 @@ local function sort_by_category(data)
for i = 1, #items do for i = 1, #items do
local item = items[i] local item = items[i]
local to_add = true local tab = i3.minitabs[data.itab]
local to_add = tab.sorter(item, data)
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
if to_add then if to_add then
insert(new, item) insert(new, item)
@ -372,7 +375,7 @@ local function spawn_item(player, stack)
local dir = player:get_look_dir() local dir = player:get_look_dir()
local ppos = player:get_pos() local ppos = player:get_pos()
ppos.y = ppos.y + player:get_properties().eye_height ppos.y = ppos.y + player:get_properties().eye_height
local look_at = vec_add(ppos, vec_mul(dir, 1)) local look_at = ppos + dir
core.add_item(look_at, stack) core.add_item(look_at, stack)
end end
@ -405,6 +408,11 @@ local function get_stack(player, stack)
end end
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 function craft_stack(player, data, craft_rcp)
local inv = player:get_inventory() local inv = player:get_inventory()
local rcp_usg = craft_rcp and "recipe" or "usage" local rcp_usg = craft_rcp and "recipe" or "usage"
@ -419,32 +427,42 @@ 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 item_groups = get_group_items(name)
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
for _name, _count in pairs(data.crafting_counts[rcp_usg].inv) do for _name, _count in pairs(data.crafting_counts[rcp_usg].inv) do
if item == _name and remaining > 0 then if item == _name and remaining > 0 then
local c = min(remaining, _count) local c = min(remaining, _count)
items[item] = c items[item] = c
remaining -= c remaining -= c
end
if remaining == 0 then break end
end end
if remaining == 0 then break end
end
end end
end end
for k, v in pairs(items) do for item, v in pairs(items) do
inv:remove_item("main", fmt("%s %s", k, v * scrbar_val)) for _ = 1, v * scrbar_val do
end inv:remove_item("main", item)
end
if rcp_def.replacements then for _, pair in ipairs(rcp_def.replacements or {}) do
for _, pair in ipairs(rcp_def.replacements) do local old_name, new_name = unpack(pair)
get_stack(player, ItemStack(pair[2]))
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
end end
@ -469,9 +487,9 @@ local function safe_teleport(player, pos)
play_sound(name, "i3_teleport", 0.8) play_sound(name, "i3_teleport", 0.8)
local vel = player:get_velocity() local vel = player:get_velocity()
player:add_velocity(vec_mul(vel, -1)) player:add_velocity(-vel)
local p = vec_new(pos) local p = vec(pos)
p.y += 0.25 p.y += 0.25
player:set_pos(p) player:set_pos(p)
@ -557,7 +575,7 @@ local function sort_inventory(player, data)
local inv = player:get_inventory() local inv = player:get_inventory()
local list = inv:get_list"main" local list = inv:get_list"main"
local size = inv:get_size"main" local size = inv:get_size"main"
local start_i = data.ignore_hotbar and (i3.settings.hotbar_len + 1) or 1 local start_i = data.ignore_hotbar and (data.hotbar_len + 1) or 1
if data.inv_compress then if data.inv_compress then
list = compress_items(list, start_i) list = compress_items(list, start_i)
@ -592,8 +610,8 @@ local function reset_data(data)
data.goto_page = nil data.goto_page = nil
data.recipes = nil data.recipes = nil
data.usages = nil data.usages = nil
data.crafting_rcp = nil data.crafting_rcp = nil
data.crafting_usg = nil data.crafting_usg = nil
data.alt_items = nil data.alt_items = nil
data.confirm_trash = nil data.confirm_trash = nil
data.show_settings = nil data.show_settings = nil
@ -605,13 +623,15 @@ local function reset_data(data)
end end
end end
local function add_hud_waypoint(player, name, pos, color) local function add_hud_waypoint(player, name, pos, color, image)
return player:hud_add { return player:hud_add {
hud_elem_type = "waypoint", hud_elem_type = image and "image_waypoint" or "waypoint",
name = name, name = name,
text = "m", text = image or "m",
scale = {x = 5, y = 5},
world_pos = pos, world_pos = pos,
number = color, number = color,
image = image,
z_index = -300, z_index = -300,
} }
end end
@ -623,6 +643,24 @@ local function get_detached_inv(name, player_name)
} }
end end
local function update_inv_size(player, data)
data.hotbar_len = data.legacy_inventory and 8 or 9
data.inv_size = 4 * data.hotbar_len
local inv = player:get_inventory()
inv:set_size("main", data.inv_size)
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
end)
end
-- Much faster implementation of `unpack` -- Much faster implementation of `unpack`
local function createunpack(n) local function createunpack(n)
local ret = {"local t = ... return "} local ret = {"local t = ... return "}
@ -662,6 +700,7 @@ local _ = {
get_recipes = get_recipes, get_recipes = get_recipes,
sort_inventory = sort_inventory, sort_inventory = sort_inventory,
sort_by_category = sort_by_category, sort_by_category = sort_by_category,
recipe_filter_set = recipe_filter_set,
apply_recipe_filters = apply_recipe_filters, apply_recipe_filters = apply_recipe_filters,
-- Type checks -- Type checks
@ -704,6 +743,7 @@ local _ = {
-- Inventory -- Inventory
get_stack = get_stack, get_stack = get_stack,
craft_stack = craft_stack, craft_stack = craft_stack,
update_inv_size = update_inv_size,
get_detached_inv = get_detached_inv, get_detached_inv = get_detached_inv,
get_bag_description = get_bag_description, get_bag_description = get_bag_description,
create_inventory = core.create_detached_inventory, create_inventory = core.create_detached_inventory,
@ -745,7 +785,7 @@ local _ = {
is_table = is_table, is_table = is_table,
table_merge = table_merge, table_merge = table_merge,
table_replace = table_replace, table_replace = table_replace,
rcp_eq = rcp_eq, table_eq = table_eq,
array_diff = array_diff, array_diff = array_diff,
-- Math -- Math
@ -757,12 +797,8 @@ local _ = {
random = math.random, random = math.random,
-- Vectors -- Vectors
vec_new = vector.new, vec = vector.new,
vec_add = vector.add,
vec_sub = vector.subtract,
vec_mul = vector.multiply,
vec_round = vector.round, vec_round = vector.round,
vec_eq = vector.equals,
} }
function i3.get(...) function i3.get(...)

View File

@ -1,5 +1,5 @@
local set_fs = i3.set_fs local set_fs = i3.set_fs
IMPORT("fmt", "play_sound", "create_inventory") IMPORT("play_sound", "create_inventory")
local trash = create_inventory("i3_trash", { local trash = create_inventory("i3_trash", {
allow_put = function(_, _, _, stack) allow_put = function(_, _, _, stack)
@ -10,6 +10,9 @@ local trash = create_inventory("i3_trash", {
inv:set_list(listname, {}) inv:set_list(listname, {})
local name = player:get_player_name() local name = player:get_player_name()
local data = i3.data[name]
data.armor_allow = nil
play_sound(name, "i3_trash", 1.0) play_sound(name, "i3_trash", 1.0)
if not core.is_creative_enabled(name) then if not core.is_creative_enabled(name) then
@ -19,15 +22,3 @@ local trash = create_inventory("i3_trash", {
}) })
trash:set_size("main", 1) trash:set_size("main", 1)
local function init_detached(player)
local name = player:get_player_name()
local output_rcp = create_inventory(fmt("i3_output_rcp_%s", name), {}, name)
output_rcp:set_size("main", 1)
local output_usg = create_inventory(fmt("i3_output_usg_%s", name), {}, name)
output_usg:set_size("main", 1)
end
return init_detached

View File

@ -1,13 +1,13 @@
local set_fs = i3.set_fs local set_fs = i3.set_fs
IMPORT("min", "max", "vec_round")
IMPORT("reg_items", "reg_aliases") IMPORT("reg_items", "reg_aliases")
IMPORT("min", "max", "vec_eq", "vec_round")
IMPORT("S", "random", "translate", "ItemStack")
IMPORT("sort", "copy", "insert", "remove", "indexof") IMPORT("sort", "copy", "insert", "remove", "indexof")
IMPORT("S", "random", "translate", "compressible", "ItemStack")
IMPORT("fmt", "find", "match", "sub", "lower", "split", "toupper") IMPORT("fmt", "find", "match", "sub", "lower", "split", "toupper")
IMPORT("search", "sort_inventory", "sort_by_category", "get_recipes", "get_detached_inv") IMPORT("valid_item", "get_stack", "craft_stack", "clean_name", "check_privs", "safe_teleport")
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("valid_item", "get_stack", "craft_stack", "clean_name", "compressible", "check_privs", "safe_teleport") IMPORT("search", "sort_inventory", "sort_by_category", "get_recipes", "get_detached_inv", "update_inv_size")
local function inv_fields(player, data, fields) local function inv_fields(player, data, fields)
local name = data.player_name local name = data.player_name
@ -19,6 +19,12 @@ local function inv_fields(player, data, fields)
return return
end end
if fields.dd_sorting_method then
data.sort = tonumber(fields.dd_sorting_method)
elseif fields.sb_font_size then
data.font_size = tonumber(fields.sb_font_size:match"-?%d+$")
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))
@ -32,12 +38,20 @@ local function inv_fields(player, data, fields)
data[str] = true data[str] = true
end end
if str == "legacy_inventory" then
update_inv_size(player, data)
elseif str == "collapse" then
search(data)
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)
play_sound(name, "i3_skin_change", 0.6)
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
@ -124,9 +138,6 @@ local function inv_fields(player, data, fields)
elseif fields.sort then elseif fields.sort then
sort_inventory(player, data) sort_inventory(player, data)
elseif fields.dd_sorting_method then
data.sort = tonumber(fields.dd_sorting_method)
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")
@ -143,9 +154,6 @@ local function inv_fields(player, data, fields)
elseif fields.bag_rename then elseif fields.bag_rename then
data.bag_rename = true data.bag_rename = true
elseif fields.sb_font_size then
data.font_size = tonumber(fields.sb_font_size:match"-?%d+$")
elseif fields.confirm_rename then 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)
@ -176,7 +184,7 @@ local function inv_fields(player, data, fields)
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_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 have set a waypoint at this position") return msg(name, S"You already have set a waypoint at this position")
end end
@ -286,13 +294,13 @@ local function select_item(player, data, fields)
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.crafting_rcp = nil data.crafting_rcp = nil
data.crafting_usg = nil data.crafting_usg = nil
end end
@ -424,7 +432,7 @@ core.register_on_player_receive_fields(function(player, formname, fields)
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"Your Minetest client needs updating (www.minetest.net)")
elseif formname ~= "" then elseif formname ~= "" then
return false return false
end end

View File

@ -1,5 +1,4 @@
local damage_enabled = i3.settings.damage_enabled local damage_enabled = i3.settings.damage_enabled
local hotbar_len = i3.settings.hotbar_len
local debug_mode = i3.settings.debug_mode local debug_mode = i3.settings.debug_mode
local model_aliases = i3.files.model_alias() local model_aliases = i3.files.model_alias()
@ -8,14 +7,14 @@ local PNG, styles, fs_elements, colors = i3.files.styles()
local sprintf = string.format local sprintf = string.format
local VoxelArea, VoxelManip = VoxelArea, VoxelManip local VoxelArea, VoxelManip = VoxelArea, VoxelManip
IMPORT("vec", "vec_round")
IMPORT("find", "match", "sub", "upper") IMPORT("find", "match", "sub", "upper")
IMPORT("vec_new", "vec_sub", "vec_round")
IMPORT("clr", "ESC", "msg", "check_privs") IMPORT("clr", "ESC", "msg", "check_privs")
IMPORT("compression_active", "compressible")
IMPORT("min", "max", "floor", "ceil", "round") IMPORT("min", "max", "floor", "ceil", "round")
IMPORT("reg_items", "reg_tools", "reg_entities")
IMPORT("true_str", "is_fav", "is_num", "str_to_pos") 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("get_bag_description", "get_detached_inv", "get_recipes")
IMPORT("compression_active", "compressible", "recipe_filter_set")
IMPORT("S", "ES", "translate", "ItemStack", "toupper", "utf8_len") IMPORT("S", "ES", "translate", "ItemStack", "toupper", "utf8_len")
IMPORT("maxn", "sort", "concat", "copy", "insert", "remove", "unpack") IMPORT("maxn", "sort", "concat", "copy", "insert", "remove", "unpack")
IMPORT("extract_groups", "groups_to_items", "is_group", "item_has_groups", "get_group") IMPORT("extract_groups", "groups_to_items", "is_group", "item_has_groups", "get_group")
@ -128,10 +127,13 @@ local function get_stack_max(inv, data, is_recipe, rcp)
return max_stacks return max_stacks
end end
local function get_inv_slots(fs) local function get_inv_slots(data, fs)
local inv_x = i3.settings.legacy_inventory and 0.75 or 0.22 local legacy_inventory = data.legacy_inventory
local inv_y = 6.9 local hotbar_len = data.hotbar_len
local size, spacing = 1, 0.1 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]" fs"style_type[box;colors=#77777710,#77777710,#777,#777]"
@ -139,19 +141,20 @@ local function get_inv_slots(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("style_type[list;size=%f;spacing=%f]", size, spacing)
fmt("list[current_player;main;%f,%f;%u,1;]", inv_x, inv_y, hotbar_len)) fs("list[current_player;main;%f,%f;%u,1;]", inv_x, inv_y, hotbar_len)
fs(fmt("style_type[list;size=%f;spacing=%f]", size, spacing), fs("style_type[list;size=%f;spacing=%f,%f]", size, spacing, legacy_inventory and 0.15 or spacing)
fmt("list[current_player;main;%f,%f;%u,%u;%u]", inv_x, inv_y + 1.15,
hotbar_len, i3.settings.inv_size / hotbar_len, hotbar_len),
"style_type[list;size=1;spacing=0.15]")
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]" fs"listring[current_player;craft]listring[current_player;main]"
end 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("style[%s;font=bold;font_size=%u]", name, font_size)
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
@ -237,8 +240,8 @@ local function get_isometric_view(fs, pos, X, Y, t, cubes, depth, high)
local max_depth = -7 local max_depth = -7
local height = base_depth and (base_height - 1) or depth local height = base_depth and (base_height - 1) or depth
local pos1 = vec_new(pos.x - width, pos.y + depth, pos.z - width) local pos1 = vec(pos.x - width, pos.y + depth, pos.z - width)
local pos2 = vec_new(pos.x + width, pos.y + height, pos.z + width) local pos2 = vec(pos.x + width, pos.y + height, pos.z + width)
local vm = VoxelManip(pos1, pos2) local vm = VoxelManip(pos1, pos2)
local emin, emax = vm:get_emerged_area() local emin, emax = vm:get_emerged_area()
@ -252,7 +255,7 @@ local function get_isometric_view(fs, pos, X, Y, t, cubes, depth, high)
if img then if img then
local p = area:position(idx) local p = area:position(idx)
p = vec_sub(p, pos) p -= pos
local size = 0.25 local size = 0.25
local x = 2 + (size / 2 * (p.z - p.x)) local x = 2 + (size / 2 * (p.z - p.x))
@ -294,15 +297,15 @@ 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)
image(2.7, Y + shift, 0.3, 0.3, PNG.flag) animated_image(2.75, Y + shift, 3/14, 0.3, "i3_flag_anim.png", 4, 150)
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("box[0,%f;4.9,0.6;#bababa25]", yextra + 1.1)
label(0, yextra + 0.85, ES"New waypoint" .. ":") label(0, yextra + 0.85, ES"New waypoint" .. ":")
fs(fmt("field[0.1,%f;4.8,0.6;waypoint_name;;]", yextra + 1.1)) 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", "") image_button(5.1, yextra + 1.15, 0.5, 0.5, "", "waypoint_add", "")
fs(fmt("tooltip[waypoint_add;%s]", ES"Add waypoint")) fs("tooltip[waypoint_add;%s]", ES"Add waypoint")
if #data.waypoints == 0 then return end if #data.waypoints == 0 then return end
fs"style_type[label;font=bold;font_size=17]" fs"style_type[label;font=bold;font_size=17]"
@ -329,7 +332,7 @@ local function get_waypoint_fs(fs, data, player, yextra, ctn_len)
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")))
if teleport_priv then if teleport_priv then
tooltip = fmt("%s\n%s", tooltip, clr("#ff0", ES"[Click to teleport]")) tooltip = fmt("%s\n%s", tooltip, clr("#ff0", ES"[Click to teleport]"))
@ -338,25 +341,25 @@ local function get_waypoint_fs(fs, data, player, yextra, ctn_len)
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("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, "") image_button(ctn_len - 0.5, yi, icon_size, icon_size, "", del, "")
fs(fmt("tooltip[%s;%s]", del, ES"Remove waypoint")) fs("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("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, "") image_button(ctn_len - 1, yi, icon_size, icon_size, "", rfs, "")
fs(fmt("tooltip[%s;%s]", rfs, ES"Change color")) fs("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("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)
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("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("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, "") 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("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)
@ -377,9 +380,9 @@ local function get_waypoint_fs(fs, data, player, yextra, ctn_len)
fs"style_type[label;font=normal;font_size=16;textcolor=#fff]" fs"style_type[label;font=normal;font_size=16;textcolor=#fff]"
end end
local function get_bag_fs(fs, data, name, esc_name, bag_size, yextra) local function get_bag_fs(fs, data, bag_size, yextra)
fs(fmt("list[detached:i3_bag_%s;main;0,%f;1,1;]", esc_name, yextra + 0.7)) fs("list[detached:i3_bag_%s;main;0,%f;1,1;]", data.player_name, yextra + 0.7)
local bag = get_detached_inv("bag", name) local bag = get_detached_inv("bag", data.player_name)
if bag:is_empty"main" then return end if bag:is_empty"main" then return end
local v = {{1.9, 2, 0.12}, {3.05, 5, 0.06}, {4.2, 10}, {4.75, 10}} local v = {{1.9, 2, 0.12}, {3.05, 5, 0.06}, {4.2, 10}, {4.75, 10}}
@ -389,18 +392,18 @@ local function get_bag_fs(fs, data, name, esc_name, bag_size, yextra)
local desc = ESC(get_bag_description(data, bagstack)) local desc = ESC(get_bag_description(data, bagstack))
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("style[bg_content;bgimg=%s;fgimg=i3_blank.png;bgimg_middle=10,%u;sound=]", PNG.bg_content, m)
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
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))
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("tooltip[bag_rename;%s]", ES"Rename the bag")
else else
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("field[1.8,%f;2.5,0.4;bag_newname;;%s]", yextra + 0.82, desc)
"field_close_on_enter[bag_newname;false]") fs"field_close_on_enter[bag_newname;false]"
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))
@ -412,13 +415,14 @@ local function get_bag_fs(fs, data, name, esc_name, bag_size, yextra)
x, size, spacing = 1.7, 0.8, 0.1 x, size, spacing = 1.7, 0.8, 0.1
end end
fs(fmt("style_type[list;size=%f;spacing=%f]", size, spacing)) fs("style_type[list;size=%f;spacing=%f]", size, spacing)
fs(fmt("list[detached:i3_bag_content_%s;main;%f,%f;4,%u;]", esc_name, x, yextra + 1.3, bag_size)) fs("list[detached:i3_bag_content_%s;main;%f,%f;4,%u;]", data.player_name, x, yextra + 1.3, bag_size)
fs"style_type[list;size=1;spacing=0.15]" fs"style_type[list;size=1;spacing=0.15]"
end end
local function get_container(fs, data, player, yoffset, ctn_len, award_list, awards_unlocked, award_list_nb, bag_size) local function get_container(fs, data, player, yoffset, ctn_len, award_list, awards_unlocked, award_list_nb, bag_size)
local name = data.player_name local nametag = player:get_nametag_attributes()
local name = true_str(nametag.text) and nametag.text or data.player_name
local esc_name = ESC(name) local esc_name = ESC(name)
add_subtitle(fs, "player_name", 0, ctn_len, 22, true, esc_name) add_subtitle(fs, "player_name", 0, ctn_len, 22, true, esc_name)
@ -432,7 +436,7 @@ local function get_container(fs, data, player, yoffset, ctn_len, award_list, awa
for i = 1, 10 do for i = 1, 10 do
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 .. "^[colorize:#232428")
end end
for i = 1, hearts do for i = 1, hearts do
@ -444,21 +448,21 @@ local function get_container(fs, data, player, yoffset, ctn_len, award_list, awa
yoffset -= 0.5 yoffset -= 0.5
end end
fs(fmt("list[current_player;craft;%f,%f;3,3;]", 0, yoffset + 1.45)) fs("list[current_player;craft;%f,%f;3,3;]", 0, yoffset + 1.45)
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("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)) fs("list[detached:i3_trash;main;%f,%f;1,1;]", 4.45, yoffset + 3.75)
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
for i, title in ipairs(i3.categories) do for i, title in ipairs(i3.categories) do
local btn_name = fmt("btn_%s", title) local btn_name = fmt("btn_%s", title)
fs(fmt("style[btn_%s;fgimg=%s;fgimg_hovered=%s;content_offset=0]", title, fs("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)])
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("tooltip[%s;%s]", btn_name, title:gsub("^%l", upper))
end end
box(0, yextra + 0.45, ctn_len, 0.045, "#bababa50") box(0, yextra + 0.45, ctn_len, 0.045, "#bababa50")
@ -471,18 +475,19 @@ local function get_container(fs, data, player, yoffset, ctn_len, award_list, awa
end end
if data.subcat == 1 then if data.subcat == 1 then
get_bag_fs(fs, data, name, esc_name, bag_size, yextra) get_bag_fs(fs, data, bag_size, yextra)
elseif data.subcat == 2 then elseif data.subcat == 2 then
if not i3.modules.armor then if not i3.modules.armor then
return not_installed "3d_armor" return not_installed "3d_armor"
end end
local armor_def = armor.def[name] local armor_def = armor.def[data.player_name]
fs(fmt("list[detached:%s_armor;armor;0,%f;5,1;]", esc_name, yextra + 0.7)) local _, armor_inv = armor:get_valid_player(player, "3d_armor")
fs("list[detached:%s_armor;armor;0,%f;5,1;]", esc_name, yextra + 0.7)
for i = 1, 5 do for i = 1, 5 do
local _, armor_inv = armor:get_valid_player(player, "3d_armor")
local stack = armor_inv:get_stack("armor", i) local stack = armor_inv:get_stack("armor", i)
if stack:is_empty() then if stack:is_empty() then
@ -518,7 +523,7 @@ local function get_container(fs, data, player, yoffset, ctn_len, award_list, awa
return not_installed "skinsdb" return not_installed "skinsdb"
end end
local _skins = skins.get_skinlist_for_player(name) local _skins = skins.get_skinlist_for_player(data.player_name)
local skin_name = skins.get_player_skin(player).name local skin_name = skins.get_player_skin(player).name
local spp, add_y = 24, 0 local spp, add_y = 24, 0
@ -544,11 +549,10 @@ local function get_container(fs, data, player, yoffset, ctn_len, award_list, awa
if not skin then break end if not skin then break end
local btn_name = fmt("skin_btn_%u", i + 1) local btn_name = fmt("skin_btn_%u", i + 1)
fs(fmt([[ style[%s;padding=10; fs([[ style[%s;padding=10;fgimg=%s;bgimg=%s;bgimg_hovered=i3_btn9_hovered.png;
fgimg=%s;bgimg=%s;bgimg_hovered=i3_btn9_hovered.png; bgimg_pressed=i3_btn9_pressed.png;bgimg_middle=4,6;sound=] ]],
bgimg_pressed=i3_btn9_pressed.png;bgimg_middle=4,6] ]],
btn_name, skin:get_preview(), btn_name, skin:get_preview(),
skin.name == skin_name and "i3_btn9_hovered.png" or "i3_btn9.png")) skin.name == skin_name and "i3_btn9_hovered.png" or "i3_btn9.png")
local X = (i % 3) * 1.93 local X = (i % 3) * 1.93
@ -556,7 +560,7 @@ local function get_container(fs, data, player, yoffset, ctn_len, award_list, awa
Y += (Y * 2.45) + yextra - 2.75 + add_y Y += (Y * 2.45) + yextra - 2.75 + add_y
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("tooltip[%s;%s]", btn_name, ESC(skin.name))
end end
elseif data.subcat == 4 then elseif data.subcat == 4 then
@ -580,32 +584,33 @@ local function show_settings(fs, data)
image_button(6.17, 10.75, 1, 0.5, "", "confirm_trash_no", "No") image_button(6.17, 10.75, 1, 0.5, "", "confirm_trash_no", "No")
elseif data.show_settings then elseif data.show_settings then
image(2.2, 9, 6, 2.35, PNG.bg_content) fs"container[-0.06,0]"
image(2.2, 9, 6.1, 2.35, PNG.bg_content)
local show_home = data.show_setting == "home" local show_home = data.show_setting == "home"
local show_style = data.show_setting == "style" local show_style = data.show_setting == "style"
local show_sorting = data.show_setting == "sorting" local show_sorting = data.show_setting == "sorting"
fs"style[setting_home,setting_style,setting_sorting;font=bold;font_size=16;sound=i3_click]" fs"style[setting_home,setting_style,setting_sorting;font=bold;font_size=16;sound=i3_click]"
fs(fmt("style[setting_home:hovered;textcolor=%s]", show_home and colors.yellow or "#fff")) fs("style[setting_home:hovered;textcolor=%s]", show_home and colors.yellow or "#fff")
fs(fmt("style[setting_style:hovered;textcolor=%s]", show_style and colors.yellow or "#fff")) fs("style[setting_style:hovered;textcolor=%s]", show_style and colors.yellow or "#fff")
fs(fmt("style[setting_sorting:hovered;textcolor=%s]", show_sorting and colors.yellow or "#fff")) fs("style[setting_sorting:hovered;textcolor=%s]", show_sorting and colors.yellow or "#fff")
fs(fmt("style[setting_home;bgimg=%s;bgimg_hovered=%s;bgimg_middle=9;padding=-9;textcolor=%s]", fs("style[setting_home;bgimg=%s;bgimg_hovered=%s;bgimg_middle=9;padding=-9;textcolor=%s]",
show_home and PNG.pagenum_hover or "", PNG.pagenum_hover, show_home and PNG.pagenum_hover or "", PNG.pagenum_hover,
show_home and colors.yellow or "#ddd"), show_home and colors.yellow or "#ddd")
fmt("style[setting_style;bgimg=%s;bgimg_hovered=%s;bgimg_middle=9;padding=-9;textcolor=%s]", fs("style[setting_style;bgimg=%s;bgimg_hovered=%s;bgimg_middle=9;padding=-9;textcolor=%s]",
show_style and PNG.pagenum_hover or "", PNG.pagenum_hover, show_style and PNG.pagenum_hover or "", PNG.pagenum_hover,
show_style and colors.yellow or "#ddd"), show_style and colors.yellow or "#ddd")
fmt("style[setting_sorting;bgimg=%s;bgimg_hovered=%s;bgimg_middle=9;padding=-9;textcolor=%s]", fs("style[setting_sorting;bgimg=%s;bgimg_hovered=%s;bgimg_middle=9;padding=-9;textcolor=%s]",
show_sorting and PNG.pagenum_hover or "", PNG.pagenum_hover, show_sorting and PNG.pagenum_hover or "", PNG.pagenum_hover,
show_sorting and colors.yellow or "#ddd")) show_sorting and colors.yellow or "#ddd")
local X = 2.5 local X = 2.5
button(X, 9.1, 1.6, 0.55, "setting_home", "Home") button(X, 9.1, 1.6, 0.55, "setting_home", "Home")
button(X + 1.6, 9.1, 1.6, 0.55, "setting_style", "Style") button(X + 1.7, 9.1, 1.6, 0.55, "setting_style", "Style")
button(X + 3.2, 9.1, 1.6, 0.55, "setting_sorting", "Sorting") button(X + 3.4, 9.1, 1.6, 0.55, "setting_sorting", "Sorting")
image_button(X + 5, 9.2, 0.25, 0.25, PNG.cancel_hover .. "^\\[brighten", "close_settings", "") image_button(X + 5.12, 9.2, 0.25, 0.25, PNG.cancel_hover .. "^\\[brighten", "close_settings", "")
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"
@ -619,24 +624,39 @@ local function show_settings(fs, data)
end) end)
end end
hypertext(2.1, 9.9, 6, 0.6, "home_pos", fmt("<global size=16><center>%s</center>", str)) hypertext(2.2, 9.9, 6, 0.6, "home_pos", fmt("<global size=16><center>%s</center>", str))
image_button(4.2, 10.4, 1.8, 0.7, "", "set_home", "Set home") image_button(4.3, 10.4, 1.8, 0.7, "", "set_home", "Set home")
elseif show_style then elseif show_style then
checkbox(2.6, 9.95, "cb_hide_tabs", "Hide tabs", tostring(data.hide_tabs)) checkbox(2.6, 9.95, "cb_hide_tabs", "Hide tabs", tostring(data.hide_tabs))
checkbox(2.6, 10.4, "cb_legacy_inventory", "Legacy inventory", tostring(data.legacy_inventory))
checkbox(2.6, 10.85, "cb_wielditem_hud", "HUD description", tostring(data.wielditem_hud))
if not recipe_filter_set() then
checkbox(5.3, 10.85, "cb_collapse", "Collapse list", tostring(data.collapse))
end
local sign = (data.font_size > 0 and "+") or (data.font_size > 0 and "-") or "" local sign = (data.font_size > 0 and "+") or (data.font_size > 0 and "-") or ""
label(2.6, 10.45, ES"Font size" .. fmt(": %s", sign .. data.font_size)) label(5.3, 9.95, ES"Font size" .. fmt(": %s", sign .. data.font_size))
local range = 5 local range = 5
fs(fmt("scrollbaroptions[min=-%u;max=%u;smallstep=1;largestep=1;thumbsize=2]", range, range)) fs("scrollbaroptions[min=-%u;max=%u;smallstep=1;largestep=1;thumbsize=2]", range, range)
fs(fmt("scrollbar[2.6,10.65;2.5,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]",
ES"Enable this option to change the style of the right panel")
fs("tooltip[cb_legacy_inventory;%s;#707070;#fff]",
ES"Enable this option to set the classic inventory size in Minetest")
fs("tooltip[cb_wielditem_hud;%s;#707070;#fff]",
ES"Enable this option to show the wielded item description in your HUD")
fs("tooltip[cb_collapse;%s;#707070;#fff]",
ES"Enable this option to collapse the inventory list by grouping some items")
elseif show_sorting then elseif show_sorting then
checkbox(2.6, 9.95, "cb_inv_compress", "Compression", tostring(data.inv_compress)) checkbox(2.6, 9.95, "cb_inv_compress", "Compression", tostring(data.inv_compress))
checkbox(2.6, 10.4, "cb_reverse_sorting", "Reverse mode", tostring(data.reverse_sorting)) checkbox(2.6, 10.4, "cb_reverse_sorting", "Reverse mode", tostring(data.reverse_sorting))
checkbox(2.6, 10.85, "cb_ignore_hotbar", "Ignore hotbar", tostring(data.ignore_hotbar)) checkbox(2.6, 10.85, "cb_ignore_hotbar", "Ignore hotbar", tostring(data.ignore_hotbar))
checkbox(5.5, 9.95, "cb_auto_sorting", "Automation", tostring(data.auto_sorting)) checkbox(5.3, 9.95, "cb_auto_sorting", "Automation", tostring(data.auto_sorting))
local methods = {} local methods = {}
@ -645,34 +665,38 @@ local function show_settings(fs, data)
insert(methods, name) insert(methods, name)
end end
label(5.5, 10.4, ES"Sorting method:") label(5.3, 10.4, ES"Sorting method:")
fs(fmt("dropdown[%f,%f;2.3,0.5;dd_sorting_method;%s;%u;true]", fs("dropdown[%f,%f;2.6,0.5;dd_sorting_method;%s;%u;true]",
5.5, 10.6, concat(methods, ","), data.sort)) 5.3, 10.6, concat(methods, ","), data.sort)
local desc = i3.sorting_methods[data.sort].description local desc = i3.sorting_methods[data.sort].description
if desc then if desc then
tooltip(5.5, 10.6, 2.3, 0.5, ESC(desc)) tooltip(5.3, 10.6, 2.4, 0.5, ESC(desc))
end end
fs(fmt("tooltip[cb_inv_compress;%s;#707070;#fff]", fs("tooltip[cb_inv_compress;%s;#707070;#fff]",
ES"Enable this option to compress your inventory"), ES"Enable this option to compress your inventory")
fmt("tooltip[cb_reverse_sorting;%s;#707070;#fff]", fs("tooltip[cb_reverse_sorting;%s;#707070;#fff]",
ES"Enable this option to sort your inventory in reverse order"), ES"Enable this option to sort your inventory in reverse order")
fmt("tooltip[cb_ignore_hotbar;%s;#707070;#fff]", fs("tooltip[cb_ignore_hotbar;%s;#707070;#fff]",
ES"Enable this option to sort your inventory except the hotbar slots"), ES"Enable this option to sort your inventory except the hotbar slots")
fmt("tooltip[cb_auto_sorting;%s;#707070;#fff]", fs("tooltip[cb_auto_sorting;%s;#707070;#fff]",
ES"Enable this option to sort your inventory automatically")) ES"Enable this option to sort your inventory automatically")
end end
fs"container_end[]"
end end
end end
local function get_inventory_fs(player, data, fs) local function get_inventory_fs(player, data, fs)
fs"listcolors[#bababa50;#bababa99]" fs"listcolors[#bababa50;#bababa99]"
get_inv_slots(fs) get_inv_slots(data, fs)
local props = player:get_properties() local props = player:get_properties()
local ctn_len, ctn_hgt, yoffset = 5.7, 6.3, 0 local ctn_len = 5.7
local ctn_hgt = data.legacy_inventory and 6.1 or 6.3
local yoffset = 0
if props.mesh ~= "" then if props.mesh ~= "" then
local anim = player:get_local_animation() local anim = player:get_local_animation()
@ -696,6 +720,7 @@ local function get_inventory_fs(player, data, fs)
local awards_unlocked, award_list, award_list_nb = 0 local awards_unlocked, award_list, award_list_nb = 0
local max_val = damage_enabled and 12 or 7 local max_val = damage_enabled and 12 or 7
max_val += (data.legacy_inventory and 2 or 0)
local bag_size = get_group(ItemStack(data.bag):get_name(), "bag") local bag_size = get_group(ItemStack(data.bag):get_name(), "bag")
if data.subcat == 1 and bag_size > 0 then if data.subcat == 1 and bag_size > 0 then
@ -739,14 +764,12 @@ local function get_inventory_fs(player, data, fs)
end end
end end
fs(fmt([[ fs([[ scrollbaroptions[arrows=hide;thumbsize=%d;max=%d]
scrollbaroptions[arrows=hide;thumbsize=%d;max=%d]
scrollbar[%f,0.2;0.2,%f;vertical;scrbar_inv;%u] scrollbar[%f,0.2;0.2,%f;vertical;scrbar_inv;%u]
scrollbaroptions[arrows=default;thumbsize=0;max=1000] scrollbaroptions[arrows=default;thumbsize=0;max=1000] ]],
]], (max_val * 4) / 12, max_val, 9.8, ctn_hgt, data.scrbar_inv)
(max_val * 4) / 12, max_val, 9.8, ctn_hgt, data.scrbar_inv))
fs(fmt("scroll_container[3.9,0.2;%f,%f;scrbar_inv;vertical]", ctn_len, ctn_hgt)) 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) get_container(fs, data, player, yoffset, ctn_len, award_list, awards_unlocked, award_list_nb, bag_size)
fs"scroll_container_end[]" fs"scroll_container_end[]"
@ -759,16 +782,16 @@ local function get_inventory_fs(player, data, fs)
for i, v in ipairs(btn) do for i, v in ipairs(btn) do
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("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)])
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("tooltip[%s;%s]", btn_name, tooltip)
end end
show_settings(fs, data) show_settings(fs, data)
end end
local function get_tooltip(item, info, pos, lang_code) local function get_tooltip(item, info, lang_code)
local tooltip local tooltip
if info.groups then if info.groups then
@ -841,11 +864,6 @@ local function get_tooltip(item, info, pos, lang_code)
end end
end end
if pos then
local btn_size = i3.settings.item_btn_size
return fmt("tooltip", pos.x, pos.y, btn_size, btn_size, ESC(tooltip))
end
return fmt("tooltip[%s;%s]", item, ESC(tooltip)) return fmt("tooltip[%s;%s]", item, ESC(tooltip))
end end
@ -917,27 +935,19 @@ local function get_output_fs(fs, data, rcp, is_recipe, is_usage, shapeless, righ
local meta = item:get_meta() local meta = item:get_meta()
local name = item:get_name() local name = item:get_name()
local count = item:get_count() local count = item:get_count()
local wear = item:get_wear()
local _name = fmt("_%s", name) local _name = fmt("_%s", name)
local pos
if meta:get_string"color" ~= "" or meta:get_string"palette_index" ~= "" then local size = BTN_SIZE * 1.2
local rcp_usg = is_recipe and "rcp" or "usg" slot(X, Y - 0.11, size, size)
fs(fmt("style_type[list;size=%f]", BTN_SIZE)) count = get_true_count(data, count, is_recipe, is_usage)
fs"listcolors[#bababa50;#bababa99]" item:set_count(count)
fs(fmt("list[detached:i3_output_%s_%s;main;%f,%f;1,1;]", rcp_usg, data.player_name, X + 0.11, Y))
button(X + 0.11, Y, BTN_SIZE, BTN_SIZE, _name, "")
local inv = get_detached_inv(fmt("output_%s", rcp_usg), data.player_name) local itemstr = ESC(item:to_string())
inv:set_stack("main", 1, item) item_image_button(X + 0.11, Y, BTN_SIZE, BTN_SIZE, itemstr, _name, "")
pos = {x = X + 0.11, y = Y}
else
local size = BTN_SIZE * 1.2
slot(X, Y - 0.11, size, size)
count = get_true_count(data, count, is_recipe, is_usage) if item:get_stack_max() < count then
item_image_button(X + 0.11, Y, BTN_SIZE, BTN_SIZE, fmt("%s %u %u", name, count, wear), _name, "") label(X + 1.05, Y + 1, count)
end end
local def = reg_items[name] local def = reg_items[name]
@ -961,7 +971,7 @@ local function get_output_fs(fs, data, rcp, is_recipe, is_usage, shapeless, righ
} }
if next(infos) then if next(infos) then
fs(get_tooltip(_name, infos, pos, data.lang_code)) fs(get_tooltip(_name, infos, data.lang_code))
end end
end end
@ -1038,11 +1048,9 @@ local function get_grid_fs(fs, data, rcp, is_recipe, is_usage)
local label = groups and "\nG" or "" local label = groups and "\nG" or ""
local replace local replace
for j = 1, #(rcp.replacements or {}) do for _, replacement in ipairs(rcp.replacements or {}) do
local replacement = rcp.replacements[j]
if replacement[1] == name then if replacement[1] == name then
replace = replace or {type = rcp.type, items = {}} replace = replace or {type = rcp.type, items = {}}
local added local added
for _, v in ipairs(replace.items) do for _, v in ipairs(replace.items) do
@ -1053,12 +1061,17 @@ local function get_grid_fs(fs, data, rcp, is_recipe, is_usage)
end end
if not added then if not added then
label = fmt("%s%s\nR", label ~= "" and "\n" or "", label) label = fmt("%s\nR", label)
insert(replace.items, replacement[2]) insert(replace.items, replacement[2])
end end
end end
end end
local _, count_sub = label:gsub("\n", "")
if count_sub == 2 then
label = label:sub(2)
end
if not large_recipe then if not large_recipe then
slot(X, Y, btn_size, btn_size) slot(X, Y, btn_size, btn_size)
end end
@ -1078,7 +1091,15 @@ local function get_grid_fs(fs, data, rcp, is_recipe, is_usage)
label(X + 0.8, Y + 0.9, count) label(X + 0.8, Y + 0.9, count)
end end
else else
item_image_button(X, Y, btn_size, btn_size, fmt("%s %u", name, count), btn_name, label) 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)
if item:get_stack_max() < count then
label(X + 0.95, Y + 0.95, count)
end
end end
local def = reg_items[name] local def = reg_items[name]
@ -1103,7 +1124,7 @@ local function get_grid_fs(fs, data, rcp, is_recipe, is_usage)
} }
if next(infos) then if next(infos) then
fs(get_tooltip(btn_name, infos, nil, data.lang_code)) fs(get_tooltip(btn_name, infos, data.lang_code))
end end
end end
@ -1118,9 +1139,13 @@ local function get_rcp_lbl(fs, data, panel, rn, is_recipe, is_usage)
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
local desc = i3.craft_types[rcp.type].description local craft_type = i3.craft_types[rcp.type]
hypertext(data.inv_width + 4.8, data.yoffset + 0.12, 3, 1, "custom_rcp", if craft_type then
fmt("<right><i><global size=16>%s\n<global size=15>%s</i></right>", ES"Custom recipe", desc)) local desc = craft_type.description
hypertext(data.inv_width + 4.8, data.yoffset + 0.12, 3, 1, "custom_rcp",
fmt("<right><i><global size=16>%s\n<global size=15>%s</i></right>",
ES"Custom recipe", ESC(desc)))
end
end end
local lbl = ES("Usage @1 of @2", data.unum, rn) local lbl = ES("Usage @1 of @2", data.unum, rn)
@ -1202,19 +1227,19 @@ local function get_header(fs, data)
if nfavs < max_favs or (nfavs == max_favs and fav) then if nfavs < max_favs or (nfavs == max_favs and fav) then
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("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)
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("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("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)
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("tooltip[nofav;%s]", ES"Cannot mark this item. Bookmark limit reached.")
end end
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("tooltip[exit;%s]", ES"Back to item list")
local desc_lim, name_lim = 34, 35 local desc_lim, name_lim = 34, 35
local desc = get_desc(data.query_item, data.lang_code) local desc = get_desc(data.query_item, data.lang_code)
@ -1254,10 +1279,10 @@ local function get_crafting_fs(fs, data, is_recipe, is_usage, max_stacks_rcp, ma
local name = is_recipe and "rcp" or "usg" local name = is_recipe and "rcp" or "usg"
local show_crafting = (is_recipe and data.crafting_rcp) or (is_usage and data.crafting_usg) local show_crafting = (is_recipe and data.crafting_rcp) or (is_usage and data.crafting_usg)
fs(fmt("style[crafting_%s;fgimg=%s;fgimg_hovered=%s;content_offset=0]", 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)) 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), "") image_button(data.inv_width + 7.35, data.yoffset + 0.2, 0.45, 0.45, "", fmt("crafting_%s", name), "")
fs(fmt("tooltip[crafting_%s;%s]", name, ES"Quick crafting")) fs("tooltip[crafting_%s;%s]", name, ES"Quick crafting")
if not show_crafting then return end if not show_crafting then return end
@ -1281,8 +1306,8 @@ local function get_crafting_fs(fs, data, is_recipe, is_usage, max_stacks_rcp, ma
fs"style[quick_crafting;font_size=16;textcolor=#ddd]" fs"style[quick_crafting;font_size=16;textcolor=#ddd]"
button(x, data.yoffset + 0.85, 3.05, 0.55, "quick_crafting", ES"Quick Crafting") button(x, data.yoffset + 0.85, 3.05, 0.55, "quick_crafting", ES"Quick Crafting")
fs(fmt("style[scrbar_%s;noclip=true]", name), fs("style[scrbar_%s;noclip=true]", name)
fmt("scrollbaroptions[min=1;max=%u;smallstep=1]", craft_max)) 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) 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.85, 2.5, 0.7, fmt("craft_%s", name), ES("Craft (×@1)", stack_fs))
@ -1343,7 +1368,7 @@ local function hide_items(player, data)
data.items = new data.items = new
end end
if not core.is_creative_enabled(data.player_name) then if not core.is_creative_enabled(data.player_name) and not recipe_filter_set() then
local new = {} local new = {}
for i = 1, #data.items do for i = 1, #data.items do
@ -1364,40 +1389,53 @@ local function get_header_items_fs(fs, data)
fs"set_focus[filter;true]" fs"set_focus[filter;true]"
if data.hide_tabs then if data.hide_tabs then
fs(fmt("style[enable_search;bgimg=%s;bgimg_hovered=%s;bgimg_pressed=%s]", 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)) 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", "") image_button(X + 0.3, 0.2, 0.5, 0.5, "", "enable_search", "")
fs(fmt("tooltip[enable_search;%s]", ES"Search")) fs("tooltip[enable_search;%s]", ES"Search")
if data.enable_search then if data.enable_search then
image(X + 0.4, 0.75, 3.4, 0.8, PNG.bg_goto) image(X + 0.4, 0.75, 3.4, 0.8, PNG.bg_goto)
fs("style[filter;font_size=16]", fs"style[filter;font_size=16]"
fmt("field[%f,%f;3,0.45;filter;;%s]", X + 0.6, 0.95, data.filter), fs("field[%f,%f;3,0.45;filter;;%s]", X + 0.6, 0.95, data.filter)
"field_close_on_enter[filter;false]") fs"field_close_on_enter[filter;false]"
end end
box(X + 1, 0.2, 0.01, 0.5, "#bababa50") 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 for i in ipairs(cat) do
local name, desc = unpack(cat[i]) local name, desc = unpack(cat[i])
local active = PNG[name .. "_hover"] local active = PNG[name .. "_hover"]
fs(fmt("style[itab_%u;bgimg=%s;bgimg_hovered=%s;bgimg_pressed=%s;sound=i3_tab]", 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)) 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), "") image_button(X + 1.25 + ((i - 1) * 0.7), 0.2, 0.5, 0.5, "", fmt("itab_%s", i), "")
fs(fmt("tooltip[itab_%u;Show %s]", i, desc)) fs("tooltip[itab_%u;Show %s]", i, desc)
end end
else else
fs(fmt("style[search;bgimg=%s]", PNG.search_hover)) fs("style[search;bgimg=%s]", PNG.search_hover)
image_button(X + 0.35, 0.32, 0.35, 0.35, "", "search", "") image_button(X + 0.35, 0.32, 0.35, 0.35, "", "search", "")
fs(fmt("tooltip[search;%s]", ES"Search")) fs("tooltip[search;%s]", ES"Search")
if data.enable_search then if data.enable_search then
fs("style[filter;font_size=18]", fs"style[filter;font_size=18]"
fmt("field[%f,0.2;3.35,0.6;filter;;%s]", X + 0.85, ESC(data.filter)), fs("field[%f,0.2;3.35,0.6;filter;;%s]", X + 0.85, ESC(data.filter))
"field_close_on_enter[filter;false]") fs"field_close_on_enter[filter;false]"
if not true_str(data.filter) then if not true_str(data.filter) then
image(X + 0.85, 0.75, 4, 0.01, PNG.search_outline_trim .. "^[opacity:100") image(X + 0.85, 0.75, 4, 0.01, PNG.search_outline_trim .. "^[opacity:100")
@ -1411,7 +1449,7 @@ local function get_header_items_fs(fs, data)
if true_str(data.filter) then if true_str(data.filter) then
image_button(X + 4.3, 0.4, 0.2, 0.2, "", "cancel", "") image_button(X + 4.3, 0.4, 0.2, 0.2, "", "cancel", "")
fs(fmt("tooltip[cancel;%s]", ES"Clear")) fs("tooltip[cancel;%s]", ES"Clear")
box(X + 0.85, 0.75, 3.74, 0.01, "#f9826c") box(X + 0.85, 0.75, 3.74, 0.01, "#f9826c")
end end
end end
@ -1419,8 +1457,8 @@ local function get_header_items_fs(fs, data)
image_button(X + 5.27, 0.3, 0.35, 0.35, "", "prev_page", "") image_button(X + 5.27, 0.3, 0.35, 0.35, "", "prev_page", "")
image_button(X + 7.45, 0.3, 0.35, 0.35, "", "next_page", "") image_button(X + 7.45, 0.3, 0.35, 0.35, "", "next_page", "")
fs(fmt("style[pagenum;bgimg=%s;bgimg_hovered=%s;bgimg_middle=9;padding=-9;sound=i3_click]", fs("style[pagenum;bgimg=%s;bgimg_hovered=%s;bgimg_middle=9;padding=-9;sound=i3_click]",
data.goto_page and PNG.pagenum_hover or "", PNG.pagenum_hover)) data.goto_page and PNG.pagenum_hover or "", PNG.pagenum_hover)
button(X + 5.8, 0.14, 1.48, 0.7, "pagenum", button(X + 5.8, 0.14, 1.48, 0.7, "pagenum",
fmt("%s / %u", clr(colors.yellow, data.pagenum), data.pagemax)) fmt("%s / %u", clr(colors.yellow, data.pagenum), data.pagemax))
@ -1431,30 +1469,45 @@ local function get_header_items_fs(fs, data)
label(X + 5, 1.25, ES"Go to page" .. ":") label(X + 5, 1.25, ES"Go to page" .. ":")
box(X + 6.5, 1, 1, 0.45, "#bababa10") box(X + 6.5, 1, 1, 0.45, "#bababa10")
fs(fmt("style[goto_page;font=mono,bold;font_size=16;textcolor=%s]", colors.yellow), fs("style[goto_page;font=mono,bold;font_size=16;textcolor=%s]", colors.yellow)
fmt("field[%f,%f;1,0.45;goto_page;;%s]", X + 6.55, 1.05, data.pagenum), fs("field[%f,%f;1,0.45;goto_page;;%s]", X + 6.55, 1.05, data.pagenum)
"field_close_on_enter[goto_page;false]") fs"field_close_on_enter[goto_page;false]"
fs"style_type[label;font_size=16;textcolor=#fff]" fs"style_type[label;font_size=16;textcolor=#fff]"
end end
end end
local function get_minitabs(fs, data, full_height) local function get_minitabs(fs, data, player, full_height)
local _tabs = {"All", "Nodes", "Items"} local minitabs = {}
local tab_len, tab_hgh = 1.8, 0.5
for i, title in ipairs(_tabs) do for i, v in ipairs(i3.minitabs) do
local selected = i == data.itab 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 hover_texture = selected and PNG.tab_small_hover or PNG.tab_small
local flip = top and "^[transformFY" or ""
fs(fmt([[style_type[image_button;bgimg=%s;bgimg_hovered=%s; fs([[ style_type[image_button;bgimg=%s%s;bgimg_hovered=%s%s;
bgimg_middle=14,0,-14,-14;padding=-14,0,14,14] ]], hover_texture, PNG.tab_small_hover)) bgimg_middle=14,0,-14,-14;padding=-14,0,14,14] ]],
hover_texture, flip, PNG.tab_small_hover, flip)
fs(fmt([[style_type[image_button;noclip=true;font=bold;font_size=16; 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")) textcolor=%s;content_offset=0;sound=i3_tab] ]], selected and "#fff" or "#bbb")
fs"style_type[image_button:hovered;textcolor=#fff]" 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) image_button((data.inv_width - 0.65) + (X * (tab_len + 0.1)),
top and -tab_hgh or full_height, tab_len, tab_hgh, "", fmt("itab_%u", id), title)
end end
end end
@ -1469,11 +1522,15 @@ local function get_items_fs(fs, data, player, full_height)
data.pagemax = max(1, ceil(#items / ipp)) data.pagemax = max(1, ceil(#items / ipp))
if data.pagenum > data.pagemax then
data.pagenum = data.pagemax
end
if #items == 0 then if #items == 0 then
local lbl = ES"No item to show" local lbl = ES"No item to show"
local icon, width, offset = PNG.no_result, 4, 2 local icon, width, offset = PNG.no_result, 4, 2
if next(i3.recipe_filters) and #i3.init_items > 0 and data.filter == "" then if recipe_filter_set() and #i3.init_items > 0 and data.filter == "" then
lbl = ES"Collect items to reveal more recipes" -- Progressive mode, etc. lbl = ES"Collect items to reveal more recipes" -- Progressive mode, etc.
icon, width, offset = PNG.find_more, 2.5, 2.75 icon, width, offset = PNG.find_more, 2.5, 2.75
end end
@ -1496,12 +1553,30 @@ local function get_items_fs(fs, data, player, full_height)
local Y = round((i % ipp - X) / rows + 1, 0) local Y = round((i % ipp - X) / rows + 1, 0)
Y -= (Y * 0.085) + 0.92 Y -= (Y * 0.085) + 0.92
insert(fs, fmt("item_image_button", X, Y, size, size, name, item, "")) local item_btn = fmt("item_image_button", X, Y, size, size, name, item, "")
if recipe_filter_set() and data.itab == 1 then
if data.items_progress[item] then
insert(fs, item_btn)
else
local col = "^\\[colorize:#232428^\\[opacity:245"
local img = reg_items[item].inventory_image .. col
local nodedef = reg_nodes[item]
if nodedef and not true_str(nodedef.inventory_image) then
img = PNG.cube .. col
end
insert(fs, fmt("image", X, Y, size, size, img))
end
else
insert(fs, item_btn)
end
if compressible(item, data) then if compressible(item, data) then
local expand = data.expand == name local expand = data.expand == name
fs(fmt("tooltip[%s;%s]", item, expand and ES"Click to hide" or ES"Click to expand")) fs("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]"
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]"
@ -1581,11 +1656,11 @@ local function get_tabs_fs(fs, player, data, full_height)
local middle = btm and "16,0,-16,-16" or "16,16,-16,-16" 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" local padding = btm and "-16,0,16,16" or "-16,-16,16,16"
fs(fmt([[style_type[image_button;bgimg=%s;bgimg_hovered=%s;bgimg_middle=%s;padding=%s] ]], fs([[ style_type[image_button;bgimg=%s;bgimg_hovered=%s;bgimg_middle=%s;padding=%s] ]],
bgimg, bgimg_hover, middle, padding)) bgimg, bgimg_hover, middle, padding)
fs(fmt("style_type[image_button;noclip=true;font_size=16;textcolor=%s;content_offset=0;sound=i3_tab]", fs("style_type[image_button;noclip=true;font_size=16;textcolor=%s;content_offset=0;sound=i3_tab]",
selected and "#fff" or "#ddd")) selected and "#fff" or "#ddd")
local X = (data.inv_width / 2) + (c * (tab_len + 0.1)) - ((tab_len + 0.05) * (shift / 2)) 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 local Y = btm and full_height or -tab_hgh
@ -1638,10 +1713,11 @@ local function make_fs(player, data)
local fs = setmetatable({}, { local fs = setmetatable({}, {
__call = function(t, ...) __call = function(t, ...)
local args = {...} local args = {...}
local elem = fs_elements[args[1]]
if elem then if #args > 1 then
insert(t, fmt(elem, select(2, ...))) local arg1 = args[1]
local elem = fs_elements[arg1]
insert(t, fmt(elem or arg1, select(2, ...)))
else else
insert(t, concat(args)) insert(t, concat(args))
end end
@ -1651,14 +1727,16 @@ local function make_fs(player, data)
data.inv_width = 10.23 data.inv_width = 10.23
local full_height = 12 local full_height = 12
fs(fmt("formspec_version[%u]size[%f,%f]no_prepend[]bgcolor[#0000]", fs("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)
fs(styles)
bg9(0, 0, data.inv_width, full_height, PNG.bg_full) bg9(0, 0, data.inv_width, full_height, PNG.bg_full)
local tab = i3.tabs[data.tab] local tab = i3.tabs[data.tab]
if tab then if tab and tab.formspec then
tab.formspec(player, data, fs) tab.formspec(player, data, fs)
end end
@ -1668,7 +1746,7 @@ local function make_fs(player, data)
get_items_fs(fs, data, player, full_height) get_items_fs(fs, data, player, full_height)
if not data.hide_tabs then if not data.hide_tabs then
get_minitabs(fs, data, full_height) get_minitabs(fs, data, player, full_height)
end end
end end

View File

@ -1,55 +1,69 @@
IMPORT("get_connected_players", "str_to_pos", "add_hud_waypoint") IMPORT("ceil", "get_connected_players", "str_to_pos", "add_hud_waypoint")
local function init_hud(player) local function init_hud(player)
local name = player:get_player_name() local name = player:get_player_name()
local data = i3.data[name] local data = i3.data[name]
local wdesc_y = -90
if core.global_exists"hb" then
wdesc_y -= ceil(hb.hudbars_count / 2) * 5
elseif not i3.settings.damage_enabled then
wdesc_y += 15
end
data.hud = { data.hud = {
bg = player:hud_add { bg = player:hud_add {
hud_elem_type = "image", 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}, alignment = {x = 1, y = 1},
scale = {x = 370, y = 112}, scale = {x = 300, y = 105},
text = "i3_bg.png", text = "i3_bg.png",
z_index = 0xDEAD, z_index = 0xDEAD,
}, },
img = player:hud_add { img = player:hud_add {
hud_elem_type = "image", 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}, alignment = {x = 1, y = 1},
scale = {x = 4, y = 4}, scale = {x = 1, y = 1},
text = "", text = "",
z_index = 0xDEAD, z_index = 0xDEAD,
}, },
text = player:hud_add { text = player:hud_add {
hud_elem_type = "text", 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}, alignment = {x = 1, y = 1},
number = 0xffffff, number = 0xffffff,
text = "", text = "",
z_index = 0xDEAD, z_index = 0xDEAD,
style = 1, style = 1,
}, },
}
if not i3.settings.legacy_inventory then wielditem = player:hud_add {
core.after(0, function() hud_elem_type = "text",
player:hud_set_hotbar_itemcount(i3.settings.hotbar_len) position = {x = 0.5, y = 1},
player:hud_set_hotbar_image"i3_hotbar.png" offset = {x = 0, y = wdesc_y},
end) alignment = {x = 0, y = -1},
end number = 0xffffff,
text = "",
z_index = 0xDEAD,
style = 1,
},
}
end end
local function show_hud(player, data) 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 hud_info_bg = player:hud_get(data.hud.bg)
local dt = 0.016 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.show_hud = false
data.hud_timer = (data.hud_timer or 0) + dt data.hud_timer = (data.hud_timer or 0) + dt
end end
@ -61,36 +75,79 @@ local function show_hud(player, data)
end end
if data.show_hud then if data.show_hud then
for _, def in pairs(data.hud) do for name, def in pairs(data.hud) do
local hud_info = player:hud_get(def) if name ~= "wielditem" then
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
local hud_info = player:hud_get(def) local hud_info = player:hud_get(def)
player:hud_change(def, "position", { player:hud_change(def, "offset", {
x = hud_info.position.x, x = hud_info.offset.x,
y = hud_info.position.y + ((dt / 5) * i3.settings.hud_speed) y = hud_info.offset.y - speed
}) })
end 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 player:hud_change(def, "offset", {
data.show_hud = nil 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_timer = nil
data.hud_msg = nil data.hud_msg = nil
data.hud_img = nil data.hud_img = nil
end end
end end
end end
end end
core.register_globalstep(function(dt)
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 not data then return end
if not data.wielditem_hud then
player:hud_change(data.hud.wielditem, "text", "")
return
end
data.timer = (data.timer or 0) + dt
local wieldidx = player:get_wield_index()
if wieldidx == data.old_wieldidx then
if data.timer >= i3.settings.wielditem_fade_after then
player:hud_change(data.hud.wielditem, "text", "")
end
return
end
data.timer = 0
data.old_wieldidx = wieldidx
local wielditem = player:get_wielded_item()
local meta = wielditem:get_meta()
local meta_desc = meta:get_string"short_description"
meta_desc = meta_desc:gsub("\27", "")
meta_desc = core.strip_colors(meta_desc)
local desc = meta_desc ~= "" and meta_desc or wielditem:get_short_description()
player:hud_change(data.hud.wielditem, "text", desc:trim())
end
end)
core.register_globalstep(function() core.register_globalstep(function()
local players = get_connected_players() local players = get_connected_players()
players[0] = #players players[0] = #players
@ -113,7 +170,7 @@ local function init_waypoints(player)
for _, v in ipairs(data.waypoints) do for _, v in ipairs(data.waypoints) do
if not v.hide then if not v.hide then
local id = add_hud_waypoint(player, v.name, str_to_pos(v.pos), v.color) local id = add_hud_waypoint(player, v.name, str_to_pos(v.pos), v.color, v.image)
v.id = id v.id = id
end end
end end

View File

@ -81,6 +81,10 @@ local function _load(path, line, data, t)
if not l then if not l then
local err_line = tonumber(err:match(":(%d+):")) local err_line = tonumber(err:match(":(%d+):"))
if t then
print("err_line", err_line, t[err_line])
end
if line ~= err_line then if line ~= err_line then
return _load(path, err_line, data, t) return _load(path, err_line, data, t)
end end

View File

@ -2,11 +2,22 @@ local set_fs = i3.set_fs
local hud_notif = i3.hud_notif local hud_notif = i3.hud_notif
local POLL_FREQ = 0.25 local POLL_FREQ = 0.25
IMPORT("fmt", "search", "table_merge", "array_diff") IMPORT("reg_items", "reg_nodes", "fmt", "table_merge", "array_diff")
IMPORT("is_group", "extract_groups", "item_has_groups", "apply_recipe_filters") 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 function get_filtered_items(player, data)
local items, known, c = {}, 0, 0 local items, known = {}, 0
for i = 1, #i3.init_items do for i = 1, #i3.init_items do
local item = i3.init_items[i] local item = i3.init_items[i]
@ -17,8 +28,7 @@ local function get_filtered_items(player, data)
usages = #apply_recipe_filters(usages or {}, player) usages = #apply_recipe_filters(usages or {}, player)
if recipes > 0 or usages > 0 then if recipes > 0 or usages > 0 then
c++ items[item] = true
items[c] = item
known += recipes + usages known += recipes + usages
end end
end end
@ -133,13 +143,20 @@ local function poll_new_items(player, data, join)
if data.discovered > 0 then if data.discovered > 0 then
local msg = fmt("%u new recipe%s unlocked!", data.discovered, data.discovered > 1 and "s" or "") local msg = fmt("%u new recipe%s unlocked!", data.discovered, data.discovered > 1 and "s" or "")
hud_notif(data.player_name, msg, "i3_book.png") local last_discovered = diff[1]
local img = reg_items[last_discovered].inventory_image
if reg_nodes[last_discovered] then
local id = core.get_content_id(last_discovered)
img = i3.cubes[id] or img
end
hud_notif(data.player_name, msg, img)
end end
data.items_raw = items data.items_progress = items
data.itab = 1
search(data) sort_by_category(data)
set_fs(player) set_fs(player)
end end

View File

@ -12,7 +12,6 @@ local PNG = {
search = "i3_search.png", search = "i3_search.png",
heart = "i3_heart.png", heart = "i3_heart.png",
heart_half = "i3_heart_half.png", heart_half = "i3_heart_half.png",
heart_grey = "i3_heart_grey.png",
prev = "i3_next.png^\\[transformFX", prev = "i3_next.png^\\[transformFX",
next = "i3_next.png", next = "i3_next.png",
arrow = "i3_arrow.png", arrow = "i3_arrow.png",
@ -45,7 +44,7 @@ local PNG = {
nonvisible = "i3_non_visible.png", nonvisible = "i3_non_visible.png",
exit = "i3_exit.png", exit = "i3_exit.png",
home = "i3_home.png", home = "i3_home.png",
flag = "i3_flag.png", flag = "i3_flag_anim.png",
edit = "i3_edit.png", edit = "i3_edit.png",
no_result = "i3_no_result.png", no_result = "i3_no_result.png",
find_more = "i3_find_more.png", find_more = "i3_find_more.png",
@ -54,6 +53,7 @@ local PNG = {
all = "i3_all.png", all = "i3_all.png",
node = "i3_node.png", node = "i3_node.png",
item = "i3_item.png", item = "i3_item.png",
cube = "i3_cube.png",
cancel_hover = "i3_cancel.png^\\[brighten", cancel_hover = "i3_cancel.png^\\[brighten",
search_hover = "i3_search.png^\\[brighten", search_hover = "i3_search.png^\\[brighten",
@ -95,7 +95,6 @@ local styles = string.format([[
style[search;content_offset=0] style[search;content_offset=0]
style[pagenum,no_item,no_rcp;font=bold;font_size=18] style[pagenum,no_item,no_rcp;font=bold;font_size=18]
style[enable_search:hovered;bgimg=%s] style[enable_search:hovered;bgimg=%s]
style[enable_search:pressed;bgimg=%s^[opacity:178]
style[exit;fgimg=%s;fgimg_hovered=%s;content_offset=0] style[exit;fgimg=%s;fgimg_hovered=%s;content_offset=0]
style[cancel;fgimg=%s;fgimg_hovered=%s;content_offset=0] style[cancel;fgimg=%s;fgimg_hovered=%s;content_offset=0]
style[prev_page,prev_recipe,prev_usage,prev_sort,prev_skin;fgimg=%s;fgimg_hovered=%s] style[prev_page,prev_recipe,prev_usage,prev_sort,prev_skin;fgimg=%s;fgimg_hovered=%s]
@ -112,7 +111,7 @@ local styles = string.format([[
style[confirm_trash_yes;sound=i3_trash] style[confirm_trash_yes;sound=i3_trash]
]], ]],
PNG.slot, PNG.slot,
PNG.search_outline, PNG.search_outline, PNG.search_outline,
PNG.exit, PNG.exit_hover, PNG.exit, PNG.exit_hover,
PNG.cancel, PNG.cancel_hover, PNG.cancel, PNG.cancel_hover,
PNG.prev, PNG.prev_hover, PNG.prev, PNG.prev_hover,

View File

@ -11,32 +11,39 @@ mt3:get_meta():set_string("description", "Worn Pick")
mt3:get_meta():set_string("color", "yellow") mt3:get_meta():set_string("color", "yellow")
mt3:set_wear(10000) mt3:set_wear(10000)
minetest.register_craft({ minetest.register_craft {
output = mt:to_string(), output = mt:to_string(),
type = "shapeless", type = "shapeless",
recipe = { recipe = {
"default:wood", "default:wood",
mt2:to_string(), mt2:to_string(),
}, },
}) }
minetest.register_craft({ minetest.register_craft {
output = mt3:to_string(), output = mt3:to_string(),
type = "shapeless", type = "shapeless",
recipe = { recipe = {
"default:pick_mese", "default:pick_mese",
"default:diamond", "default:diamond",
}, },
}) }
minetest.clear_craft {
recipe = {
{"default:sand", "default:sand"},
{"default:sand", "default:sand"},
},
}
i3.register_craft { i3.register_craft {
url = "https://raw.githubusercontent.com/minetest-mods/i3/main/tests/test_online_recipe.json" url = "https://raw.githubusercontent.com/minetest-mods/i3/main/tests/test_online_recipe.json"
} }
i3.register_craft({ i3.register_craft {
result = "default:ladder_wood 2", result = "default:ladder_wood 2",
items = {"default:copper_ingot 7, default:tin_ingot, default:steel_ingot 2"}, items = {"default:copper_ingot 7, default:tin_ingot, default:steel_ingot 2"},
}) }
i3.register_craft { i3.register_craft {
result = "default:tree", result = "default:tree",
@ -56,7 +63,7 @@ i3.register_craft {
} }
} }
i3.register_craft({ i3.register_craft {
grid = { grid = {
"X", "X",
"#", "#",
@ -68,9 +75,9 @@ i3.register_craft({
['X'] = "default:glass 2", ['X'] = "default:glass 2",
}, },
result = "default:mese 3", result = "default:mese 3",
}) }
i3.register_craft({ i3.register_craft {
grid = { grid = {
"X", "X",
"#X", "#X",
@ -82,9 +89,9 @@ i3.register_craft({
['X'] = "default:glass 2", ['X'] = "default:glass 2",
}, },
result = "default:mese 3", result = "default:mese 3",
}) }
i3.register_craft({ i3.register_craft {
grid = { grid = {
"X", "X",
}, },
@ -93,10 +100,10 @@ i3.register_craft({
['X'] = "default:glass 2", ['X'] = "default:glass 2",
}, },
result = "default:mese 3", result = "default:mese 3",
}) }
i3.register_craft({ i3.register_craft {
grid = { grid = {
"X#", "X#",
}, },
@ -105,9 +112,9 @@ i3.register_craft({
['X'] = "default:glass 2", ['X'] = "default:glass 2",
}, },
result = "default:mese 3", result = "default:mese 3",
}) }
i3.register_craft({ i3.register_craft {
grid = { grid = {
"X#X", "X#X",
}, },
@ -116,9 +123,9 @@ i3.register_craft({
['X'] = "default:glass 2", ['X'] = "default:glass 2",
}, },
result = "default:mese 3", result = "default:mese 3",
}) }
i3.register_craft({ i3.register_craft {
grid = { grid = {
"X#XX", "X#XX",
}, },
@ -127,9 +134,9 @@ i3.register_craft({
['X'] = "default:glass 2", ['X'] = "default:glass 2",
}, },
result = "default:mese 3", result = "default:mese 3",
}) }
i3.register_craft({ i3.register_craft {
grid = { grid = {
"X#XX", "X#XX",
"X#X", "X#X",
@ -139,9 +146,9 @@ i3.register_craft({
['X'] = "default:glass 2", ['X'] = "default:glass 2",
}, },
result = "default:mese 3", result = "default:mese 3",
}) }
i3.register_craft({ i3.register_craft {
grid = { grid = {
"X#XX", "X#XX",
"X#X", "X#X",
@ -152,9 +159,9 @@ i3.register_craft({
['X'] = "default:glass 2", ['X'] = "default:glass 2",
}, },
result = "default:mese 3", result = "default:mese 3",
}) }
i3.register_craft({ i3.register_craft {
grid = { grid = {
"X##XX", "X##XX",
}, },
@ -163,9 +170,9 @@ i3.register_craft({
['X'] = "default:glass 2", ['X'] = "default:glass 2",
}, },
result = "default:mese 3", result = "default:mese 3",
}) }
i3.register_craft({ i3.register_craft {
grid = { grid = {
"X##X#X", "X##X#X",
}, },
@ -174,9 +181,9 @@ i3.register_craft({
['X'] = "default:glass 2", ['X'] = "default:glass 2",
}, },
result = "default:mese 3", result = "default:mese 3",
}) }
i3.register_craft({ i3.register_craft {
grid = { grid = {
"X##X#X", "X##X#X",
"", "",
@ -187,9 +194,9 @@ i3.register_craft({
['X'] = "default:glass 2", ['X'] = "default:glass 2",
}, },
result = "default:mese 3", result = "default:mese 3",
}) }
i3.register_craft({ i3.register_craft {
grid = { grid = {
"X #", "X #",
" ## ", " ## ",
@ -201,9 +208,9 @@ i3.register_craft({
['X'] = "default:glass 2", ['X'] = "default:glass 2",
}, },
result = "default:mese 3", result = "default:mese 3",
}) }
i3.register_craft({ i3.register_craft {
grid = { grid = {
"X #", "X #",
" ## ", " ## ",
@ -215,9 +222,9 @@ i3.register_craft({
['X'] = "default:glass", ['X'] = "default:glass",
}, },
result = "default:mese 3", result = "default:mese 3",
}) }
i3.register_craft({ i3.register_craft {
grid = { grid = {
"X #", "X #",
" ## ", " ## ",
@ -230,9 +237,9 @@ i3.register_craft({
['X'] = "default:glass", ['X'] = "default:glass",
}, },
result = "default:mese 3", result = "default:mese 3",
}) }
i3.register_craft({ i3.register_craft {
grid = { grid = {
"X #", "X #",
" ## ", " ## ",
@ -245,10 +252,10 @@ i3.register_craft({
['X'] = "default:glass", ['X'] = "default:glass",
}, },
result = "default:mese 3", result = "default:mese 3",
}) }
i3.register_craft({ i3.register_craft {
grid = { grid = {
"X #", "X #",
" ## ", " ## ",
@ -262,9 +269,9 @@ i3.register_craft({
['X'] = "default:glass", ['X'] = "default:glass",
}, },
result = "default:mese 3", result = "default:mese 3",
}) }
i3.register_craft({ i3.register_craft {
grid = { grid = {
"X #", "X #",
" ## ", " ## ",
@ -278,9 +285,9 @@ i3.register_craft({
['X'] = "default:glass", ['X'] = "default:glass",
}, },
result = "default:mese 3", result = "default:mese 3",
}) }
i3.register_craft({ i3.register_craft {
grid = { grid = {
"X #", "X #",
" ## ", " ## ",
@ -294,9 +301,9 @@ i3.register_craft({
['X'] = "default:glass", ['X'] = "default:glass",
}, },
result = "default:mese 3", result = "default:mese 3",
}) }
i3.register_craft({ i3.register_craft {
grid = { grid = {
"X #", "X #",
" ## ", " ## ",
@ -310,9 +317,9 @@ i3.register_craft({
['X'] = "default:glass", ['X'] = "default:glass",
}, },
result = "default:mese 3", result = "default:mese 3",
}) }
i3.register_craft({ i3.register_craft {
grid = { grid = {
"X #", "X #",
" ## ", " ## ",
@ -328,4 +335,4 @@ i3.register_craft({
['X'] = "default:glass", ['X'] = "default:glass",
}, },
result = "default:mese 3", result = "default:mese 3",
}) }

View File

@ -3,7 +3,8 @@ i3.new_tab("test1", {
image = "i3_heart.png", image = "i3_heart.png",
formspec = function(player, data, fs) formspec = function(player, data, fs)
fs("label[3,1;Test 1]") fs("label", 3, 1, "Just a test")
fs"label[3,2;Lorem Ipsum]"
end, end,
}) })

12
tests/test_waypoints.lua Normal file
View File

@ -0,0 +1,12 @@
core.after(5, function()
i3.add_waypoint("Test", {
player = "singleplayer",
pos = {x = 0, y = 2, z = 0},
color = 0xffff00,
-- image = "heart.png",
})
core.after(5, function()
i3.remove_waypoint("singleplayer", "Test")
end)
end)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 262 B

BIN
textures/i3_cube.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 404 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 745 B

BIN
textures/i3_flag_anim.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 227 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 147 B