Compare commits

...

99 Commits

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

View File

@ -10,6 +10,7 @@ read_globals = {
"armor", "armor",
"skins", "skins",
"awards", "awards",
"hb",
"vector", "vector",
"string", "string",
"table", "table",

42
API.md
View File

@ -17,37 +17,37 @@ i3.new_tab("stuff", {
-- Determine if the tab is visible by a player, `false` or `nil` hide the tab -- Determine if the tab is visible by a player, `false` or `nil` hide the tab
access = function(player, data) access = function(player, data)
local name = player:get_player_name() local name = player:get_player_name()
if name == "singleplayer" then return name == "singleplayer"
return false
end
end, end,
formspec = function(player, data, fs) formspec = function(player, data, fs)
fs("label[3,1;This is just a test]") fs"label[3,1;This is just a test]"
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
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])`
@ -56,7 +56,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`
@ -70,9 +70,11 @@ 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", {
@ -81,7 +83,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 {
@ -161,7 +163,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`.
@ -183,7 +185,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`
@ -209,7 +211,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.
@ -243,7 +245,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.
@ -278,7 +280,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.
@ -303,7 +305,7 @@ A map of all compressed item groups, indexed by stereotypes.
#### `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.
@ -311,7 +313,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`

View File

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

@ -13,22 +13,24 @@ print[[
local modpath = core.get_modpath"i3" local modpath = core.get_modpath"i3"
local http = core.request_http_api() local http = core.request_http_api()
local storage = core.get_mod_storage() local storage = core.get_mod_storage()
local _loadfile = dofile(modpath .. "/src/operators.lua") local _loadfile = dofile(modpath .. "/src/preprocessor.lua")
local function lf(path) local function lf(path)
return assert(_loadfile(modpath .. path)) return assert(_loadfile(modpath .. path))
end end
i3 = { i3 = {
version = 1115,
data = core.deserialize(storage:get_string"data") or {}, data = core.deserialize(storage:get_string"data") or {},
settings = { settings = {
debug_mode = false, debug_mode = false,
max_favs = 6, max_favs = 6,
max_waypoints = 30, max_waypoints = 30,
min_fs_version = 4, min_fs_version = 6,
item_btn_size = 1.1, item_btn_size = 1.1,
drop_bag_on_die = true, drop_bag_on_die = true,
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,
@ -36,7 +38,6 @@ i3 = {
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), item_compression = core.settings:get_bool("i3_item_compression", true),
}, },
@ -51,10 +52,13 @@ i3 = {
saves = { -- Metadata to save saves = { -- Metadata to save
bag = true, bag = true,
home = true, home = true,
font_size = true,
hide_tabs = true,
waypoints = true, waypoints = true,
inv_items = true, inv_items = true,
drop_items = true,
known_recipes = true, known_recipes = true,
wielditem_hud = true,
legacy_inventory = true,
}, },
files = { files = {
@ -63,7 +67,7 @@ i3 = {
caches = lf"/src/caches.lua", caches = lf"/src/caches.lua",
callbacks = lf"/src/callbacks.lua", callbacks = lf"/src/callbacks.lua",
common = lf"/src/common.lua", common = lf"/src/common.lua",
compress = lf"/src/compress.lua", compress = lf"/src/compression.lua",
detached = lf"/src/detached_inv.lua", detached = lf"/src/detached_inv.lua",
fields = lf"/src/fields.lua", fields = lf"/src/fields.lua",
groups = lf"/src/groups.lua", groups = lf"/src/groups.lua",
@ -82,6 +86,7 @@ i3 = {
tabs = {}, tabs = {},
cubes = {}, cubes = {},
groups = {},
plants = {}, plants = {},
modules = {}, modules = {},
craft_types = {}, craft_types = {},
@ -91,9 +96,6 @@ 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()

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

@ -3,6 +3,3 @@ i3_progressive_mode (Learn crafting recipes progressively) bool false
# Regroup the items of the same type in the item list. # Regroup the items of the same type in the item list.
i3_item_compression (Regroup items of the same type) bool true 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_heavy_armor.ogg Normal file

Binary file not shown.

BIN
sounds/i3_heavy_boots.ogg Normal file

Binary file not shown.

BIN
sounds/i3_heavy_helmet.ogg Normal file

Binary file not shown.

Binary file not shown.

BIN
sounds/i3_heavy_shield.ogg Normal file

Binary file not shown.

BIN
sounds/i3_light_armor.ogg Normal file

Binary file not shown.

BIN
sounds/i3_light_boots.ogg Normal file

Binary file not shown.

BIN
sounds/i3_light_helmet.ogg Normal file

Binary file not shown.

Binary file not shown.

BIN
sounds/i3_light_shield.ogg Normal file

Binary file not shown.

View File

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

View File

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

View File

@ -6,7 +6,7 @@ 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") 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()
@ -66,16 +66,89 @@ core.register_on_player_inventory_action(function(player, _, _, info)
end end
end) end)
if core.global_exists("armor") then if core.global_exists"armor" then
i3.modules.armor = true i3.modules.armor = true
armor:register_on_update(set_fs)
local group_indexes = {
{"armor_head", "i3_heavy_helmet"},
{"armor_torso", "i3_heavy_armor"},
{"armor_legs", "i3_heavy_leggings"},
{"armor_feet", "i3_heavy_boots"},
{"armor_shield", "i3_heavy_shield"},
}
local function check_group(def, group)
return def.groups[group] and def.groups[group] > 0
end
armor:register_on_equip(function(player, idx, stack)
local _, armor_inv = armor:get_valid_player(player, "3d_armor")
local def = stack:get_definition()
local name = player:get_player_name()
local data = i3.data[name]
for i, v in ipairs(group_indexes) do
local group, sound = unpack(v)
local stackname = stack:get_name()
if stackname:find"wood" or stackname:find"stone" or stackname:find"cactus" then
sound = sound:gsub("heavy", "light")
end
if i == idx and check_group(def, group) then
data.armor_allow = sound
return armor:register_on_update(set_fs)
end
end
data.armor_disallow = true
armor_inv:remove_item("armor", stack)
end)
armor:register_on_update(function(player)
local _, armor_inv = armor:get_valid_player(player, "3d_armor")
if not armor_inv then return end
for i = 1, 5 do
local stack = armor_inv:get_stack("armor", i)
local def = stack:get_definition()
for j, v in ipairs(group_indexes) do
local group = v[1]
if check_group(def, group) and i ~= j then
armor_inv:set_stack("armor", i, armor_inv:get_stack("armor", j))
armor_inv:set_stack("armor", j, stack)
return play_sound(player:get_player_name(), "i3_cannot", 0.8)
end
end
end
end)
core.register_on_player_inventory_action(function(player, action, _, info)
if action ~= "take" then return end
local name = player:get_player_name()
local data = i3.data[name]
if data.armor_disallow then
local inv = player:get_inventory()
inv:set_stack("main", info.index, info.stack)
data.armor_disallow = nil
play_sound(name, "i3_cannot", 0.8)
elseif data.armor_allow then
play_sound(name, data.armor_allow, 0.8)
data.armor_allow = nil
end
end)
end end
if core.global_exists("skins") then if core.global_exists"skins" then
i3.modules.skins = true i3.modules.skins = true
end end
if core.global_exists("awards") then if core.global_exists"awards" then
i3.modules.awards = true i3.modules.awards = true
core.register_on_craft(function(_, player) core.register_on_craft(function(_, player)
@ -134,25 +207,26 @@ local function init_data(player, info)
data.player_name = name data.player_name = name
data.filter = "" data.filter = ""
data.pagenum = 1 data.pagenum = 1
data.skin_pagenum = 1
data.items = i3.init_items data.items = i3.init_items
data.items_raw = i3.init_items data.items_raw = i3.init_items
data.favs = {} data.favs = {}
data.sort = "alphabetical"
data.show_setting = "home" data.show_setting = "home"
data.ignore_hotbar = false data.ignore_hotbar = false
data.auto_sorting = false data.auto_sorting = false
data.reverse_sorting = false data.reverse_sorting = false
data.inv_compress = true data.inv_compress = true
data.export_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

View File

@ -9,6 +9,14 @@ local fmt, find, match, gmatch, sub, split, lower, upper =
string.format, string.find, string.match, string.gmatch, string.format, string.find, string.match, string.gmatch,
string.sub, string.split, string.lower, string.upper string.sub, string.split, string.lower, string.upper
if not core.registered_privileges.creative then
core.register_privilege("creative", {
description = "Allow player to use creative inventory",
give_to_singleplayer = false,
give_to_admin = false,
})
end
local old_is_creative_enabled = core.is_creative_enabled local old_is_creative_enabled = core.is_creative_enabled
function core.is_creative_enabled(name) function core.is_creative_enabled(name)
@ -69,6 +77,16 @@ local function toupper(str)
return str:gsub("%f[%w]%l", upper):gsub("_", " ") return str:gsub("%f[%w]%l", upper):gsub("_", " ")
end end
local function utf8_len(str)
local c = 0
for _ in str:gmatch"[%z\1-\127\194-\244][\128-\191]*" do -- Arguably working duct-tape code
c++
end
return c
end
local function get_bag_description(data, stack) local function get_bag_description(data, stack)
local desc = translate(data.lang_code, stack:get_description()) local desc = translate(data.lang_code, stack:get_description())
desc = split(desc, "(")[1] or desc desc = split(desc, "(")[1] or desc
@ -101,7 +119,7 @@ local function search(data)
for i = 1, #data.items_raw do for i = 1, #data.items_raw do
local item = data.items_raw[i] local item = data.items_raw[i]
local def = reg_items[item] local def = reg_items[item]
local desc = lower(translate(data.lang_code, def and def.description)) or "" local desc = lower(translate(data.lang_code, def.description)) or ""
local search_in = fmt("%s %s", item, desc) local search_in = fmt("%s %s", item, desc)
local temp, j, to_add = {}, 1 local temp, j, to_add = {}, 1
@ -198,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
@ -228,9 +250,7 @@ local function is_group(item)
end end
local function extract_groups(str) local function extract_groups(str)
if sub(str, 1, 6) == "group:" then return split(sub(str, 7), ",")
return split(sub(str, 7), ",")
end
end end
local function item_has_groups(item_groups, groups) local function item_has_groups(item_groups, groups)
@ -247,30 +267,56 @@ local function valid_item(def)
def.description and def.description ~= "" def.description and def.description ~= ""
end end
local function groups_to_items(groups, get_all) local function get_group_stereotype(group)
if not get_all and #groups == 1 then local stereotype = i3.group_stereotypes[group]
local group = groups[1] local def = reg_items[stereotype]
local stereotype = i3.group_stereotypes[group]
local def = reg_items[stereotype]
if valid_item(def) then if valid_item(def) then
return stereotype return stereotype
end
end end
end
local function groups_to_items(groups)
local names = {} local names = {}
for name, def in pairs(reg_items) do for name, def in pairs(reg_items) do
if valid_item(def) and item_has_groups(def.groups, groups) then if valid_item(def) and item_has_groups(def.groups, groups) then
if get_all then insert(names, name)
insert(names, name)
else
return name
end
end end
end end
return get_all and names or "" sort(names)
return names
end
local function is_cube(drawtype)
return drawtype == "normal" or drawtype == "liquid" or
sub(drawtype, 1, 9) == "glasslike" or
sub(drawtype, 1, 8) == "allfaces"
end
local function get_cube(tiles)
if not true_table(tiles) then
return "i3_blank.png"
end
local top = tiles[1] or "i3_blank.png"
if is_table(top) then
top = top.name or top.image
end
local left = tiles[3] or top or "i3_blank.png"
if is_table(left) then
left = left.name or left.image
end
local right = tiles[5] or left or "i3_blank.png"
if is_table(right) then
right = right.name or right.image
end
return core.inventorycube(top, left, right)
end end
local function apply_recipe_filters(recipes, player) local function apply_recipe_filters(recipes, player)
@ -366,22 +412,24 @@ 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"
local rcp_def = rcp_usg == "recipe" and data.recipes[data.rnum] or data.usages[data.unum]
local output = craft_rcp and data.recipes[data.rnum].output or data.usages[data.unum].output local output = craft_rcp and data.recipes[data.rnum].output or data.usages[data.unum].output
output = ItemStack(output) output = ItemStack(output)
local stackname, stackcount, stackmax = output:get_name(), output:get_count(), output:get_stack_max() local stackname, stackcount, stackmax = output:get_name(), output:get_count(), output:get_stack_max()
local scrbar_val = data[fmt("scrbar_%s", craft_rcp and "rcp" or "usg")] or 1 local scrbar_val = data[fmt("scrbar_%s", craft_rcp and "rcp" or "usg")] or 1
for name, count in pairs(data.export_counts[rcp_usg].rcp) do for name, count in pairs(data.crafting_counts[rcp_usg].rcp) do
local items = {[name] = count} local items = {[name] = count}
if is_group(name) then if is_group(name) then
items = {} items = {}
local groups = extract_groups(name) local groups = extract_groups(name)
local item_groups = groups_to_items(groups, true) local groupname = name:sub(7)
local item_groups = i3.groups[groupname].items or groups_to_items(groups)
local remaining = count local remaining = count
for _, item in ipairs(item_groups) do for _, item in ipairs(item_groups) do
for _name, _count in pairs(data.export_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
@ -398,6 +446,12 @@ local function craft_stack(player, data, craft_rcp)
end end
end end
if rcp_def.replacements then
for _, pair in ipairs(rcp_def.replacements) do
get_stack(player, ItemStack(pair[2]))
end
end
local count = stackcount * scrbar_val local count = stackcount * scrbar_val
local iter = ceil(count / stackmax) local iter = ceil(count / stackmax)
local leftover = count local leftover = count
@ -427,27 +481,16 @@ local function safe_teleport(player, pos)
player:set_pos(p) player:set_pos(p)
end end
local function get_sorting_idx(name) local function sorter(inv, data, mode)
local idx = 1
for i, def in ipairs(i3.sorting_methods) do
if name == def.name then
idx = i
end
end
return idx
end
local function sorter(inv, reverse, mode)
sort(inv, function(a, b) sort(inv, function(a, b)
if mode == 1 then if mode == 1 then
a, b = a:get_name(), b:get_name() a = translate(data.lang_code, a:get_short_description())
b = translate(data.lang_code, b:get_short_description())
else else
a, b = a:get_count(), b:get_count() a, b = a:get_count(), b:get_count()
end end
if reverse then if data.reverse_sorting then
return a > b return a > b
end end
@ -514,31 +557,11 @@ local function compress_items(list, start_i)
return new_inv return new_inv
end end
local function drop_items(player, inv, list, start_i, rej)
for i = start_i, #list do
local stack = list[i]
local name = stack:get_name()
for _, it in ipairs(rej) do
if name == it then
spawn_item(player, stack)
inv:set_stack("main", i, ItemStack(""))
end
end
end
return inv:get_list"main"
end
local function sort_inventory(player, data) local function sort_inventory(player, data)
local inv = player:get_inventory() local inv = player:get_inventory()
local list = inv:get_list"main" local list = inv:get_list"main"
local size = inv:get_size"main" local size = inv:get_size"main"
local start_i = data.ignore_hotbar and (i3.settings.hotbar_len + 1) or 1 local start_i = data.ignore_hotbar and (data.hotbar_len + 1) or 1
if true_table(data.drop_items) then
list = drop_items(player, inv, list, start_i, data.drop_items)
end
if data.inv_compress then if data.inv_compress then
list = compress_items(list, start_i) list = compress_items(list, start_i)
@ -546,8 +569,7 @@ local function sort_inventory(player, data)
list = pre_sorting(list, start_i) list = pre_sorting(list, start_i)
end end
local idx = get_sorting_idx(data.sort) local new_inv = i3.sorting_methods[data.sort].func(list, data)
local new_inv = i3.sorting_methods[idx].func(list, data)
if not new_inv then return end if not new_inv then return end
if not data.ignore_hotbar then if not data.ignore_hotbar then
@ -570,10 +592,12 @@ local function reset_data(data)
data.scrbar_rcp = 1 data.scrbar_rcp = 1
data.scrbar_usg = 1 data.scrbar_usg = 1
data.query_item = nil data.query_item = nil
data.enable_search = nil
data.goto_page = nil
data.recipes = nil data.recipes = nil
data.usages = nil data.usages = nil
data.export_rcp = nil data.crafting_rcp = nil
data.export_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
@ -589,7 +613,7 @@ local function add_hud_waypoint(player, name, pos, color)
return player:hud_add { return player:hud_add {
hud_elem_type = "waypoint", hud_elem_type = "waypoint",
name = name, name = name,
text = " m", text = "m",
world_pos = pos, world_pos = pos,
number = color, number = color,
z_index = -300, z_index = -300,
@ -603,6 +627,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 "}
@ -630,6 +672,7 @@ local _ = {
extract_groups = extract_groups, extract_groups = extract_groups,
item_has_groups = item_has_groups, item_has_groups = item_has_groups,
groups_to_items = groups_to_items, groups_to_items = groups_to_items,
get_group_stereotype = get_group_stereotype,
-- Compression -- Compression
compressible = compressible, compressible = compressible,
@ -640,7 +683,6 @@ local _ = {
sorter = sorter, sorter = sorter,
get_recipes = get_recipes, get_recipes = get_recipes,
sort_inventory = sort_inventory, sort_inventory = sort_inventory,
get_sorting_idx = get_sorting_idx,
sort_by_category = sort_by_category, sort_by_category = sort_by_category,
apply_recipe_filters = apply_recipe_filters, apply_recipe_filters = apply_recipe_filters,
@ -657,6 +699,8 @@ local _ = {
msg = msg, msg = msg,
-- Misc. functions -- Misc. functions
is_cube = is_cube,
get_cube = get_cube,
ItemStack = ItemStack, ItemStack = ItemStack,
valid_item = valid_item, valid_item = valid_item,
spawn_item = spawn_item, spawn_item = spawn_item,
@ -682,6 +726,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,
@ -709,6 +754,7 @@ local _ = {
match = string.match, match = string.match,
gmatch = string.gmatch, gmatch = string.gmatch,
toupper = toupper, toupper = toupper,
utf8_len = utf8_len,
-- Table -- Table
maxn = table.maxn, maxn = table.maxn,
@ -722,7 +768,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

View File

@ -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

View File

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

View File

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

File diff suppressed because it is too large Load Diff

View File

@ -1,9 +1,17 @@
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",
@ -32,14 +40,18 @@ local function init_hud(player)
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)
@ -91,6 +103,46 @@ local function show_hud(player, data)
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

View File

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

View File

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

View File

@ -1,10 +1,14 @@
local fmt = string.format
local PNG = { local PNG = {
blank = "i3_blank.png", blank = "i3_blank.png",
bg = "i3_bg.png", bg = "i3_bg.png",
bg_full = "i3_bg_full.png", bg_full = "i3_bg_full.png",
bg_goto = "i3_bg_goto.png",
bg_content = "i3_bg_content.png", bg_content = "i3_bg_content.png",
bar = "i3_bar.png", bar = "i3_bar.png",
hotbar = "i3_hotbar.png", hotbar = "i3_hotbar.png",
highlight = "i3_highlight.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",
@ -22,8 +26,9 @@ local PNG = {
book = "i3_book.png", book = "i3_book.png",
sign = "i3_sign.png", sign = "i3_sign.png",
cancel = "i3_cancel.png", cancel = "i3_cancel.png",
export = "i3_export.png", crafting = "i3_crafting.png",
slot = "i3_slot.png", slot = "i3_slot.png^\\[resize:128x128",
pagenum_hover = "i3_slot.png^\\[resize:128x128^\\[opacity:130",
tab = "i3_tab.png", tab = "i3_tab.png",
tab_small = "i3_tab_small.png", tab_small = "i3_tab_small.png",
tab_top = "i3_tab.png^\\[transformFY", tab_top = "i3_tab.png^\\[transformFY",
@ -42,10 +47,17 @@ local PNG = {
home = "i3_home.png", home = "i3_home.png",
flag = "i3_flag.png", flag = "i3_flag.png",
edit = "i3_edit.png", edit = "i3_edit.png",
no_result = "i3_no_result.png",
find_more = "i3_find_more.png",
search_outline = "i3_search_outline.png",
search_outline_trim = "i3_search_outline_trim.png",
all = "i3_all.png",
node = "i3_node.png",
item = "i3_item.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",
export_hover = "i3_export.png^\\[brighten", crafting_hover = "i3_crafting.png^\\[brighten",
trash_hover = "i3_trash.png^\\[brighten^\\[colorize:#f00:100", trash_hover = "i3_trash.png^\\[brighten^\\[colorize:#f00:100",
compress_hover = "i3_compress.png^\\[brighten", compress_hover = "i3_compress.png^\\[brighten",
sort_hover = "i3_sort.png^\\[brighten", sort_hover = "i3_sort.png^\\[brighten",
@ -65,6 +77,9 @@ local PNG = {
exit_hover = "i3_exit.png^\\[brighten", exit_hover = "i3_exit.png^\\[brighten",
home_hover = "i3_home.png^\\[brighten", home_hover = "i3_home.png^\\[brighten",
edit_hover = "i3_edit.png^\\[brighten", edit_hover = "i3_edit.png^\\[brighten",
all_hover = "i3_all_on.png^\\[brighten",
node_hover = "i3_node_on.png^\\[brighten",
item_hover = "i3_item_on.png^\\[brighten",
} }
local styles = string.format([[ local styles = string.format([[
@ -72,19 +87,19 @@ local styles = string.format([[
style_type[label,field;font_size=16] style_type[label,field;font_size=16]
style_type[button;border=false;content_offset=0] style_type[button;border=false;content_offset=0]
style_type[image_button,item_image_button,checkbox,dropdown;border=false;sound=i3_click] style_type[image_button,item_image_button,checkbox,dropdown;border=false;sound=i3_click]
style_type[item_image_button;bgimg_hovered=%s] style_type[item_image_button;bgimg_middle=9;padding=-9]
style_type[item_image_button:hovered;bgimg=%s]
style[;sound=]
style[nofav;sound=i3_cannot] style[nofav;sound=i3_cannot]
style[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: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[search;fgimg=%s;fgimg_hovered=%s;content_offset=0] style[prev_page,prev_recipe,prev_usage,prev_sort,prev_skin;fgimg=%s;fgimg_hovered=%s]
style[prev_page;fgimg=%s;fgimg_hovered=%s] style[next_page,next_recipe,next_usage,next_sort,next_skin;fgimg=%s;fgimg_hovered=%s]
style[next_page;fgimg=%s;fgimg_hovered=%s]
style[prev_recipe;fgimg=%s;fgimg_hovered=%s]
style[next_recipe;fgimg=%s;fgimg_hovered=%s]
style[prev_usage;fgimg=%s;fgimg_hovered=%s]
style[next_usage;fgimg=%s;fgimg_hovered=%s]
style[waypoint_add;fgimg=%s;fgimg_hovered=%s;content_offset=0] style[waypoint_add;fgimg=%s;fgimg_hovered=%s;content_offset=0]
style[bag_rename;fgimg=%s;fgimg_hovered=%s;content_offset=0] style[bag_rename;fgimg=%s;fgimg_hovered=%s;content_offset=0]
style[btn_bag,btn_armor,btn_skins;font=bold;font_size=18;content_offset=0;sound=i3_click] style[btn_bag,btn_armor,btn_skins;font=bold;font_size=18;content_offset=0;sound=i3_click]
@ -97,17 +112,13 @@ local styles = string.format([[
style[confirm_trash_yes;sound=i3_trash] style[confirm_trash_yes;sound=i3_trash]
]], ]],
PNG.slot, PNG.slot,
PNG.exit, PNG.exit_hover, PNG.search_outline, PNG.search_outline,
PNG.cancel, PNG.cancel_hover, PNG.exit, PNG.exit_hover,
PNG.search, PNG.search_hover, PNG.cancel, PNG.cancel_hover,
PNG.prev, PNG.prev_hover, PNG.prev, PNG.prev_hover,
PNG.next, PNG.next_hover, PNG.next, PNG.next_hover,
PNG.prev, PNG.prev_hover, PNG.add, PNG.add_hover,
PNG.next, PNG.next_hover, PNG.edit, PNG.edit_hover)
PNG.prev, PNG.prev_hover,
PNG.next, PNG.next_hover,
PNG.add, PNG.add_hover,
PNG.edit, PNG.edit_hover)
local fs_elements = { local fs_elements = {
label = "label[%f,%f;%s]", label = "label[%f,%f;%s]",
@ -116,9 +127,10 @@ local fs_elements = {
tooltip = "tooltip[%f,%f;%f,%f;%s]", tooltip = "tooltip[%f,%f;%f,%f;%s]",
button = "button[%f,%f;%f,%f;%s;%s]", button = "button[%f,%f;%f,%f;%s;%s]",
checkbox = "checkbox[%f,%f;%s;%s;%s]", checkbox = "checkbox[%f,%f;%s;%s;%s]",
slot = "image[%f,%f;%f,%f;" .. fmt("%s;9]", PNG.slot),
item_image = "item_image[%f,%f;%f,%f;%s]", item_image = "item_image[%f,%f;%f,%f;%s]",
hypertext = "hypertext[%f,%f;%f,%f;%s;%s]", hypertext = "hypertext[%f,%f;%f,%f;%s;%s]",
bg9 = "background9[%f,%f;%f,%f;%s;false;%u]", bg9 = "background9[%f,%f;%f,%f;%s;false;12]",
scrollbar = "scrollbar[%f,%f;%f,%f;%s;%s;%u]", scrollbar = "scrollbar[%f,%f;%f,%f;%s;%s;%u]",
model = "model[%f,%f;%f,%f;%s;%s;%s;%s;%s;%s;%s]", model = "model[%f,%f;%f,%f;%s;%s;%s;%s;%s;%s;%s]",
image_button = "image_button[%f,%f;%f,%f;%s;%s;%s]", image_button = "image_button[%f,%f;%f,%f;%s;%s;%s]",

View File

@ -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

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

BIN
textures/i3_all.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

BIN
textures/i3_all_on.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

BIN
textures/i3_armor_1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 186 B

BIN
textures/i3_armor_2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 191 B

BIN
textures/i3_armor_3.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 175 B

BIN
textures/i3_armor_4.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 167 B

BIN
textures/i3_armor_5.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 141 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 2.0 KiB

BIN
textures/i3_bg_goto.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

BIN
textures/i3_crafting.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.1 KiB

BIN
textures/i3_find_more.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

BIN
textures/i3_highlight.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 70 B

BIN
textures/i3_item.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

BIN
textures/i3_item_on.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

BIN
textures/i3_no_result.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

BIN
textures/i3_node.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

BIN
textures/i3_node_on.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 507 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 304 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.7 KiB

After

Width:  |  Height:  |  Size: 2.4 KiB

View File

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