Merge branch 'minetest-mods-main' into main

This commit is contained in:
Daretmavi
2021-07-01 10:26:50 +02:00
13 changed files with 795 additions and 340 deletions

21
API.md
View File

@ -38,7 +38,7 @@ i3.new_tab {
Updates the current formspec. `extra_formspec` adds an additional formspec string. Updates the current formspec. `extra_formspec` adds an additional formspec string.
#### `i3.delete_tab(tabname)` #### `i3.remove_tab(tabname)`
Deletes a tab by name. Deletes a tab by name.
@ -141,7 +141,7 @@ Recipes can be registered from a given URL containing a JSON file (HTTP support
```Lua ```Lua
i3.register_craft({ i3.register_craft({
url = "https://raw.githubusercontent.com/minetest-mods/i3/main/test_online_recipe.json" url = "https://raw.githubusercontent.com/minetest-mods/i3/main/tests/test_online_recipe.json"
}) })
``` ```
@ -178,7 +178,7 @@ end)
Removes all recipe filters and adds a new one. Removes all recipe filters and adds a new one.
#### `i3.delete_recipe_filter(name)` #### `i3.remove_recipe_filter(name)`
Removes the recipe filter with the given `name`. Removes the recipe filter with the given `name`.
@ -197,12 +197,12 @@ They can be used like so: `<optional_name> +<filter name>=<value1>,<value2>,<...
Example usages: Example usages:
- `+groups=cracky,crumbly`: search for groups `cracky` and `crumbly` in all items. - `+groups=cracky,crumbly`: search for groups `cracky` and `crumbly` in all items.
- `wood +groups=flammable +types=node`: search for group `flammable` amongst items which contain - `wood +groups=flammable`: search for group `flammable` amongst items which contain
`wood` in their names AND have a `node` drawtype. `wood` in their names.
Notes: Notes:
- If `optional_name` is omitted, the search filter will apply to all items, without pre-filtering. - If `optional_name` is omitted, the search filter will apply to all items, without pre-filtering.
- The `+groups` and `+types` filters are currently implemented by default. - The `+groups` filter is currently implemented by default.
#### `i3.add_search_filter(name, function(item, values))` #### `i3.add_search_filter(name, function(item, values))`
@ -237,15 +237,6 @@ Returns a map of search filters, indexed by name.
### Miscellaneous ### Miscellaneous
#### `i3.group_stereotypes`
This is the table indexing the item groups by stereotypes.
You can add a stereotype like so:
```Lua
i3.group_stereotypes.radioactive = "mod:item"
```
#### `i3.export_url` #### `i3.export_url`
If set, the mod will export all the cached recipes and usages in a JSON format If set, the mod will export all the cached recipes and usages in a JSON format

View File

@ -18,6 +18,7 @@ This mod requires **Minetest 5.4+**
- Inventory Sorting (alphabetical + item stack compression) - Inventory Sorting (alphabetical + item stack compression)
- Item Bookmarks - Item Bookmarks
- Waypoints - Waypoints
- Item List Compression (**`moreblocks`** supported)
**¹** *This mode is a Terraria-like system that shows recipes you can craft from items you ever had in your inventory. **¹** *This mode is a Terraria-like system that shows recipes you can craft from items you ever had in your inventory.
To enable it: `i3_progressive_mode = true` in `minetest.conf`.* To enable it: `i3_progressive_mode = true` in `minetest.conf`.*
@ -48,4 +49,4 @@ Love this mod? Donations are appreciated: https://www.paypal.me/jpg84240
Demo video (outdated): https://www.youtube.com/watch?v=25nCAaqeacU Demo video (outdated): https://www.youtube.com/watch?v=25nCAaqeacU
![Preview](https://user-images.githubusercontent.com/7883281/116791813-0edf7b00-aabd-11eb-90b3-11c604af34dc.png) ![Preview](https://user-images.githubusercontent.com/7883281/123561657-10ba7780-d7aa-11eb-8bbe-dcec348bb28c.png)

319
etc/compress.lua Normal file
View File

@ -0,0 +1,319 @@
local fmt, insert = string.format, table.insert
local wood_types = {
"acacia_wood", "aspen_wood", "junglewood", "pine_wood",
}
local material_tools = {
"bronze", "diamond", "mese", "stone", "wood",
}
local material_stairs = {
"acacia_wood", "aspen_wood", "brick", "bronzeblock", "cobble", "copperblock",
"desert_cobble", "desert_sandstone", "desert_sandstone_block", "desert_sandstone_brick",
"desert_stone", "desert_stone_block", "desert_stonebrick",
"glass", "goldblock", "ice", "junglewood", "mossycobble", "obsidian",
"obsidian_block", "obsidian_glass", "obsidianbrick", "pine_wood",
"sandstone", "sandstone_block", "sandstonebrick",
"silver_sandstone", "silver_sandstone_block", "silver_sandstone_brick",
"snowblock", "steelblock", "stone", "stone_block", "stonebrick",
"straw", "tinblock",
}
local colors = {
"black", "blue", "brown", "cyan", "dark_green", "dark_grey", "green",
"grey", "magenta", "orange", "pink", "red", "violet", "yellow",
}
local to_compress = {
["default:wood"] = {
replace = "wood",
by = wood_types,
},
["default:fence_wood"] = {
replace = "wood",
by = wood_types,
},
["default:fence_rail_wood"] = {
replace = "wood",
by = wood_types,
},
["default:mese_post_light"] = {
replace = "mese_post_light",
by = {
"mese_post_light_acacia",
"mese_post_light_aspen_wood",
"mese_post_light_junglewood",
"mese_post_light_pine_wood",
}
},
["doors:gate_wood_closed"] = {
replace = "wood",
by = wood_types,
},
["wool:white"] = {
replace = "white",
by = colors
},
["dye:white"] = {
replace = "white",
by = colors
},
["default:axe_steel"] = {
replace = "steel",
by = material_tools
},
["default:pick_steel"] = {
replace = "steel",
by = material_tools
},
["default:shovel_steel"] = {
replace = "steel",
by = material_tools
},
["default:sword_steel"] = {
replace = "steel",
by = material_tools
},
["farming:hoe_steel"] = {
replace = "steel",
by = {"wood", "stone"}
},
["stairs:slab_wood"] = {
replace = "wood",
by = material_stairs
},
["stairs:stair_wood"] = {
replace = "wood",
by = material_stairs
},
["stairs:stair_inner_wood"] = {
replace = "wood",
by = material_stairs
},
["stairs:stair_outer_wood"] = {
replace = "wood",
by = material_stairs
},
["walls:cobble"] = {
replace = "cobble",
by = {"desertcobble", "mossycobble"}
},
}
local circular_saw_names = {
{"micro", "_1"},
{"panel", "_1"},
{"micro", "_2"},
{"panel", "_2"},
{"micro", "_4"},
{"panel", "_4"},
{"micro", ""},
{"panel", ""},
{"micro", "_12"},
{"panel", "_12"},
{"micro", "_14"},
{"panel", "_14"},
{"micro", "_15"},
{"panel", "_15"},
{"stair", "_outer"},
{"stair", ""},
{"stair", "_inner"},
{"slab", "_1"},
{"slab", "_2"},
{"slab", "_quarter"},
{"slab", ""},
{"slab", "_three_quarter"},
{"slab", "_14"},
{"slab", "_15"},
{"slab", "_two_sides"},
{"slab", "_three_sides"},
{"slab", "_three_sides_u"},
{"stair", "_half"},
{"stair", "_alt_1"},
{"stair", "_alt_2"},
{"stair", "_alt_4"},
{"stair", "_alt"},
{"stair", "_right_half"},
{"slope", ""},
{"slope", "_half"},
{"slope", "_half_raised"},
{"slope", "_inner"},
{"slope", "_inner_half"},
{"slope", "_inner_half_raised"},
{"slope", "_inner_cut"},
{"slope", "_inner_cut_half"},
{"slope", "_inner_cut_half_raised"},
{"slope", "_outer"},
{"slope", "_outer_half"},
{"slope", "_outer_half_raised"},
{"slope", "_outer_cut"},
{"slope", "_outer_cut_half"},
{"slope", "_outer_cut_half_raised"},
{"slope", "_cut"},
}
local moreblocks_nodes = {
"coal_stone",
"wood_tile",
"iron_checker",
"circle_stone_bricks",
"cobble_compressed",
"plankstone",
"clean_glass",
"split_stone_tile",
"all_faces_tree",
"dirt_compressed",
"coal_checker",
"clean_glow_glass",
"tar",
"clean_super_glow_glass",
"stone_tile",
"cactus_brick",
"super_glow_glass",
"desert_cobble_compressed",
"copperpatina",
"coal_stone_bricks",
"glow_glass",
"cactus_checker",
"all_faces_pine_tree",
"all_faces_aspen_tree",
"all_faces_acacia_tree",
"all_faces_jungle_tree",
"iron_stone",
"grey_bricks",
"wood_tile_left",
"wood_tile_down",
"wood_tile_center",
"wood_tile_right",
"wood_tile_full",
"checker_stone_tile",
"iron_glass",
"iron_stone_bricks",
"wood_tile_flipped",
"wood_tile_offset",
"coal_glass",
"straw",
"stone",
"stone_block",
"cobble",
"mossycobble",
"brick",
"sandstone",
"steelblock",
"goldblock",
"copperblock",
"bronzeblock",
"diamondblock",
"tinblock",
"desert_stone",
"desert_stone_block",
"desert_cobble",
"meselamp",
"glass",
"tree",
"wood",
"jungletree",
"junglewood",
"pine_tree",
"pine_wood",
"acacia_tree",
"acacia_wood",
"aspen_tree",
"aspen_wood",
"obsidian",
"obsidian_block",
"obsidianbrick",
"obsidian_glass",
"stonebrick",
"desert_stonebrick",
"sandstonebrick",
"silver_sandstone",
"silver_sandstone_brick",
"silver_sandstone_block",
"desert_sandstone",
"desert_sandstone_brick",
"desert_sandstone_block",
"sandstone_block",
"coral_skeleton",
"ice",
}
local colors_moreblocks = table.copy(colors)
insert(colors_moreblocks, "white")
local moreblocks_mods = {
wool = colors_moreblocks,
moreblocks = moreblocks_nodes,
}
local t = {}
for mod, v in pairs(moreblocks_mods) do
for _, nodename in ipairs(v) do
t[nodename] = {}
for _, shape in ipairs(circular_saw_names) do
local to_add = true
if shape[1] == "slope" and shape[2] == "" then
to_add = nil
end
if to_add then
insert(t[nodename], fmt("%s_%s%s", shape[1], nodename, shape[2]))
end
end
local slope_name = fmt("slope_%s", nodename)
to_compress[fmt("%s:%s", mod, slope_name)] = {
replace = slope_name,
by = t[nodename]
}
end
end
local compressed = {}
for k, v in pairs(to_compress) do
compressed[k] = compressed[k] or {}
for _, str in ipairs(v.by) do
local it = k:gsub(v.replace, str)
insert(compressed[k], it)
end
end
local _compressed = {}
for _, v in pairs(compressed) do
for _, v2 in ipairs(v) do
_compressed[v2] = true
end
end
return compressed, _compressed

62
etc/groups.lua Normal file
View File

@ -0,0 +1,62 @@
local S = core.get_translator "i3"
local group_stereotypes = {
dye = "dye:white",
wool = "wool:white",
wood = "default:wood",
tree = "default:tree",
sand = "default:sand",
glass = "default:glass",
stick = "default:stick",
stone = "default:stone",
leaves = "default:leaves",
coal = "default:coal_lump",
vessel = "vessels:glass_bottle",
flower = "flowers:dandelion_yellow",
water_bucket = "bucket:bucket_water",
mesecon_conductor_craftable = "mesecons:wire_00000000_off",
}
local group_names = {
dye = S"Any dye",
coal = S"Any coal",
sand = S"Any sand",
tree = S"Any tree",
wool = S"Any wool",
glass = S"Any glass",
stick = S"Any stick",
stone = S"Any stone",
carpet = S"Any carpet",
flower = S"Any flower",
leaves = S"Any leaves",
vessel = S"Any vessel",
wood = S"Any wood planks",
mushroom = S"Any mushroom",
["color_red,flower"] = S"Any red flower",
["color_blue,flower"] = S"Any blue flower",
["color_black,flower"] = S"Any black flower",
["color_white,flower"] = S"Any white flower",
["color_green,flower"] = S"Any green flower",
["color_orange,flower"] = S"Any orange flower",
["color_yellow,flower"] = S"Any yellow flower",
["color_violet,flower"] = S"Any violet flower",
["color_red,dye"] = S"Any red dye",
["color_blue,dye"] = S"Any blue dye",
["color_grey,dye"] = S"Any grey dye",
["color_pink,dye"] = S"Any pink dye",
["color_cyan,dye"] = S"Any cyan dye",
["color_black,dye"] = S"Any black dye",
["color_white,dye"] = S"Any white dye",
["color_brown,dye"] = S"Any brown dye",
["color_green,dye"] = S"Any green dye",
["color_orange,dye"] = S"Any orange dye",
["color_yellow,dye"] = S"Any yellow dye",
["color_violet,dye"] = S"Any violet dye",
["color_magenta,dye"] = S"Any magenta dye",
["color_dark_grey,dye"] = S"Any dark grey dye",
["color_dark_green,dye"] = S"Any dark green dye",
}
return group_stereotypes, group_names

13
etc/model_aliases.lua Normal file
View File

@ -0,0 +1,13 @@
local model_alias = {
["boats:boat"] = {name = "boats:boat", drawtype = "entity"},
["carts:cart"] = {name = "carts:cart", drawtype = "entity", frames = "0,0"},
["default:chest"] = {name = "default:chest_open"},
["default:chest_locked"] = {name = "default:chest_locked_open"},
["doors:door_wood"] = {name = "doors:door_wood_a"},
["doors:door_glass"] = {name = "doors:door_glass_a"},
["doors:door_obsidian_glass"] = {name = "doors:door_obsidian_glass_a"},
["doors:door_steel"] = {name = "doors:door_steel_a"},
["xpanes:door_steel_bar"] = {name = "xpanes:door_steel_bar_a"},
}
return model_alias

116
etc/styles.lua Normal file
View File

@ -0,0 +1,116 @@
local fmt = string.format
local PNG = {
bg = "i3_bg.png",
bg_full = "i3_bg_full.png",
bar = "i3_bar.png",
hotbar = "i3_hotbar.png",
search = "i3_search.png",
heart = "i3_heart.png",
heart_half = "i3_heart_half.png",
heart_grey = "i3_heart_grey.png",
prev = "i3_next.png^\\[transformFX",
next = "i3_next.png",
arrow = "i3_arrow.png",
trash = "i3_trash.png",
sort_az = "i3_sort_az.png",
sort_za = "i3_sort_za.png",
compress = "i3_compress.png",
fire = "i3_fire.png",
fire_anim = "i3_fire_anim.png",
book = "i3_book.png",
sign = "i3_sign.png",
cancel = "i3_cancel.png",
export = "i3_export.png",
slot = "i3_slot.png",
tab = "i3_tab.png",
tab_small = "i3_tab_small.png",
tab_top = "i3_tab.png^\\[transformFY",
furnace_anim = "i3_furnace_anim.png",
bag = "i3_bag.png",
armor = "i3_armor.png",
awards = "i3_award.png",
skins = "i3_skin.png",
waypoints = "i3_waypoint.png",
teleport = "i3_teleport.png",
add = "i3_add.png",
refresh = "i3_refresh.png",
visible = "i3_visible.png^\\[brighten",
nonvisible = "i3_non_visible.png",
exit = "i3_exit.png",
cancel_hover = "i3_cancel.png^\\[brighten",
search_hover = "i3_search.png^\\[brighten",
export_hover = "i3_export.png^\\[brighten",
trash_hover = "i3_trash.png^\\[brighten^\\[colorize:#f00:100",
compress_hover = "i3_compress.png^\\[brighten",
sort_az_hover = "i3_sort_az.png^\\[brighten",
sort_za_hover = "i3_sort_za.png^\\[brighten",
prev_hover = "i3_next_hover.png^\\[transformFX",
next_hover = "i3_next_hover.png",
tab_hover = "i3_tab_hover.png",
tab_small_hover = "i3_tab_small_hover.png",
tab_hover_top = "i3_tab_hover.png^\\[transformFY",
bag_hover = "i3_bag_hover.png",
armor_hover = "i3_armor_hover.png",
awards_hover = "i3_award_hover.png",
skins_hover = "i3_skin_hover.png",
waypoints_hover = "i3_waypoint_hover.png",
teleport_hover = "i3_teleport.png^\\[brighten",
add_hover = "i3_add.png^\\[brighten",
refresh_hover = "i3_refresh.png^\\[brighten",
exit_hover = "i3_exit.png^\\[brighten",
}
local styles = fmt([[
style_type[field;border=false;bgcolor=transparent]
style_type[label,field;font_size=16]
style_type[button;border=false;content_offset=0]
style_type[image_button,item_image_button;border=false;sound=i3_click]
style_type[item_image_button;bgimg_hovered=%s]
style[pagenum,no_item,no_rcp;font=bold;font_size=18]
style[exit;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;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[btn_bag,btn_armor,btn_skins;font=bold;font_size=18;content_offset=0;sound=i3_click]
style[craft_rcp,craft_usg;noclip=true;font_size=16;sound=i3_craft;
bgimg=i3_btn9.png;bgimg_hovered=i3_btn9_hovered.png;
bgimg_pressed=i3_btn9_pressed.png;bgimg_middle=4,6]
]],
PNG.slot,
PNG.exit, PNG.exit_hover,
PNG.cancel, PNG.cancel_hover,
PNG.search, PNG.search_hover,
PNG.prev, PNG.prev_hover,
PNG.next, PNG.next_hover,
PNG.prev, PNG.prev_hover,
PNG.next, PNG.next_hover,
PNG.prev, PNG.prev_hover,
PNG.next, PNG.next_hover,
PNG.add, PNG.add_hover)
local fs_elements = {
label = "label[%f,%f;%s]",
box = "box[%f,%f;%f,%f;%s]",
image = "image[%f,%f;%f,%f;%s]",
tooltip = "tooltip[%f,%f;%f,%f;%s]",
button = "button[%f,%f;%f,%f;%s;%s]",
item_image = "item_image[%f,%f;%f,%f;%s]",
hypertext = "hypertext[%f,%f;%f,%f;%s;%s]",
bg9 = "background9[%f,%f;%f,%f;%s;false;%u]",
scrollbar = "scrollbar[%f,%f;%f,%f;%s;%s;%u]",
model = "model[%f,%f;%f,%f;%s;%s;%s;%s;%s;%s;%s]",
image_button = "image_button[%f,%f;%f,%f;%s;%s;%s]",
animated_image = "animated_image[%f,%f;%f,%f;;%s;%u;%u]",
item_image_button = "item_image_button[%f,%f;%f,%f;%s;%s;%s]",
}
return PNG, styles, fs_elements

524
init.lua
View File

@ -1,12 +1,12 @@
i3 = {} i3 = {}
local modpath = core.get_modpath "i3"
local storage = core.get_mod_storage() local storage = core.get_mod_storage()
local slz, dslz = core.serialize, core.deserialize local slz, dslz = core.serialize, core.deserialize
local pdata = dslz(storage:get_string "pdata") or {} local pdata = dslz(storage:get_string "pdata") or {}
-- Caches -- Caches
local init_items = {} local init_items = {}
local searches = {}
local recipes_cache = {} local recipes_cache = {}
local usages_cache = {} local usages_cache = {}
local fuel_cache = {} local fuel_cache = {}
@ -15,7 +15,13 @@ local toolrepair
local tabs = {} local tabs = {}
local model_aliases = loadfile(modpath .. "/etc/model_aliases.lua")()
local PNG, styles, fs_elements = loadfile(modpath .. "/etc/styles.lua")()
local compress_groups, compressed = loadfile(modpath .. "/etc/compress.lua")()
local group_stereotypes, group_names = loadfile(modpath .. "/etc/groups.lua")()
local progressive_mode = core.settings:get_bool "i3_progressive_mode" and not(core.is_creative_enabled()) local progressive_mode = core.settings:get_bool "i3_progressive_mode" and not(core.is_creative_enabled())
local item_compression = core.settings:get_bool "i3_item_compression"
local damage_enabled = core.settings:get_bool "enable_damage" local damage_enabled = core.settings:get_bool "enable_damage"
local __3darmor, __skinsdb, __awards local __3darmor, __skinsdb, __awards
@ -25,6 +31,9 @@ local __unified_inventory, old_unified_inventory_fn
local http = core.request_http_api() local http = core.request_http_api()
local singleplayer = core.is_singleplayer() local singleplayer = core.is_singleplayer()
local after = core.after
local clr = core.colorize
local reg_items = core.registered_items local reg_items = core.registered_items
local reg_nodes = core.registered_nodes local reg_nodes = core.registered_nodes
local reg_craftitems = core.registered_craftitems local reg_craftitems = core.registered_craftitems
@ -32,29 +41,9 @@ local reg_tools = core.registered_tools
local reg_entities = core.registered_entities local reg_entities = core.registered_entities
local reg_aliases = core.registered_aliases local reg_aliases = core.registered_aliases
local log = core.log
local after = core.after
local clr = core.colorize
local parse_json = core.parse_json
local write_json = core.write_json
local get_inv = core.get_inventory
local chat_send = core.chat_send_player
local show_formspec = core.show_formspec
local pos_to_string = core.pos_to_string
local check_privs = core.check_player_privs local check_privs = core.check_player_privs
local globalstep = core.register_globalstep local translate = core.get_translated_string
local on_shutdown = core.register_on_shutdown
local get_players = core.get_connected_players
local get_craft_result = core.get_craft_result
local translate = minetest.get_translated_string
local on_joinplayer = core.register_on_joinplayer
local get_all_recipes = core.get_all_craft_recipes
local on_leaveplayer = core.register_on_leaveplayer
local on_mods_loaded = core.register_on_mods_loaded
local get_player_info = core.get_player_information
local create_inventory = core.create_detached_inventory local create_inventory = core.create_detached_inventory
local on_receive_fields = core.register_on_player_receive_fields
local ESC = core.formspec_escape local ESC = core.formspec_escape
local S = core.get_translator "i3" local S = core.get_translator "i3"
@ -109,117 +98,6 @@ local SUBCAT = {
"waypoints", "waypoints",
} }
local PNG = {
bg = "i3_bg.png",
bg_full = "i3_bg_full.png",
bar = "i3_bar.png",
hotbar = "i3_hotbar.png",
search = "i3_search.png",
heart = "i3_heart.png",
heart_half = "i3_heart_half.png",
heart_grey = "i3_heart_grey.png",
prev = "i3_next.png^\\[transformFX",
next = "i3_next.png",
arrow = "i3_arrow.png",
trash = "i3_trash.png",
sort_az = "i3_sort_az.png",
sort_za = "i3_sort_za.png",
compress = "i3_compress.png",
fire = "i3_fire.png",
fire_anim = "i3_fire_anim.png",
book = "i3_book.png",
sign = "i3_sign.png",
cancel = "i3_cancel.png",
export = "i3_export.png",
slot = "i3_slot.png",
tab = "i3_tab.png",
tab_top = "i3_tab.png^\\[transformFY",
furnace_anim = "i3_furnace_anim.png",
bag = "i3_bag.png",
armor = "i3_armor.png",
awards = "i3_award.png",
skins = "i3_skin.png",
waypoints = "i3_waypoint.png",
teleport = "i3_teleport.png",
add = "i3_add.png",
refresh = "i3_refresh.png",
visible = "i3_visible.png^\\[brighten",
nonvisible = "i3_non_visible.png",
exit = "i3_exit.png",
cancel_hover = "i3_cancel.png^\\[brighten",
search_hover = "i3_search.png^\\[brighten",
export_hover = "i3_export.png^\\[brighten",
trash_hover = "i3_trash.png^\\[brighten^\\[colorize:#f00:100",
compress_hover = "i3_compress.png^\\[brighten",
sort_az_hover = "i3_sort_az.png^\\[brighten",
sort_za_hover = "i3_sort_za.png^\\[brighten",
prev_hover = "i3_next_hover.png^\\[transformFX",
next_hover = "i3_next_hover.png",
tab_hover = "i3_tab_hover.png",
tab_hover_top = "i3_tab_hover.png^\\[transformFY",
bag_hover = "i3_bag_hover.png",
armor_hover = "i3_armor_hover.png",
awards_hover = "i3_award_hover.png",
skins_hover = "i3_skin_hover.png",
waypoints_hover = "i3_waypoint_hover.png",
teleport_hover = "i3_teleport.png^\\[brighten",
add_hover = "i3_add.png^\\[brighten",
refresh_hover = "i3_refresh.png^\\[brighten",
exit_hover = "i3_exit.png^\\[brighten",
}
local fs_elements = {
label = "label[%f,%f;%s]",
box = "box[%f,%f;%f,%f;%s]",
image = "image[%f,%f;%f,%f;%s]",
tooltip = "tooltip[%f,%f;%f,%f;%s]",
button = "button[%f,%f;%f,%f;%s;%s]",
item_image = "item_image[%f,%f;%f,%f;%s]",
hypertext = "hypertext[%f,%f;%f,%f;%s;%s]",
bg9 = "background9[%f,%f;%f,%f;%s;false;%u]",
scrollbar = "scrollbar[%f,%f;%f,%f;%s;%s;%u]",
model = "model[%f,%f;%f,%f;%s;%s;%s;%s;%s;%s;%s]",
image_button = "image_button[%f,%f;%f,%f;%s;%s;%s]",
animated_image = "animated_image[%f,%f;%f,%f;;%s;%u;%u]",
item_image_button = "item_image_button[%f,%f;%f,%f;%s;%s;%s]",
}
local styles = sprintf([[
style_type[field;border=false;bgcolor=transparent]
style_type[label,field;font_size=16]
style_type[button;border=false;content_offset=0]
style_type[image_button,item_image_button;border=false;sound=i3_click]
style_type[item_image_button;bgimg_hovered=%s]
style[pagenum,no_item,no_rcp;font=bold;font_size=18]
style[exit;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;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[btn_bag,btn_armor,btn_skins;font=bold;font_size=18;content_offset=0;sound=i3_click]
style[craft_rcp,craft_usg;noclip=true;font_size=16;sound=i3_craft;
bgimg=i3_btn9.png;bgimg_hovered=i3_btn9_hovered.png;
bgimg_pressed=i3_btn9_pressed.png;bgimg_middle=4,6]
]],
PNG.slot,
PNG.exit, PNG.exit_hover,
PNG.cancel, PNG.cancel_hover,
PNG.search, PNG.search_hover,
PNG.prev, PNG.prev_hover,
PNG.next, PNG.next_hover,
PNG.prev, PNG.prev_hover,
PNG.next, PNG.next_hover,
PNG.prev, PNG.prev_hover,
PNG.next, PNG.next_hover,
PNG.add, PNG.add_hover)
local function get_lang_code(info) local function get_lang_code(info)
return info and info.lang_code return info and info.lang_code
end end
@ -233,92 +111,25 @@ local function outdated(name)
PNG.book, PNG.book,
"Your Minetest client is outdated.\nGet the latest version on minetest.net to use i3") "Your Minetest client is outdated.\nGet the latest version on minetest.net to use i3")
show_formspec(name, "i3", fs) core.show_formspec(name, "i3", fs)
end 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)
if name == "" then
return old_is_creative_enabled(name)
end
return check_privs(name, {creative = true}) or old_is_creative_enabled(name) return check_privs(name, {creative = true}) or old_is_creative_enabled(name)
end end
i3.group_stereotypes = {
dye = "dye:white",
wool = "wool:white",
wood = "default:wood",
tree = "default:tree",
sand = "default:sand",
glass = "default:glass",
stick = "default:stick",
stone = "default:stone",
leaves = "default:leaves",
coal = "default:coal_lump",
vessel = "vessels:glass_bottle",
flower = "flowers:dandelion_yellow",
water_bucket = "bucket:bucket_water",
mesecon_conductor_craftable = "mesecons:wire_00000000_off",
}
local group_names = {
dye = S"Any dye",
coal = S"Any coal",
sand = S"Any sand",
tree = S"Any tree",
wool = S"Any wool",
glass = S"Any glass",
stick = S"Any stick",
stone = S"Any stone",
carpet = S"Any carpet",
flower = S"Any flower",
leaves = S"Any leaves",
vessel = S"Any vessel",
wood = S"Any wood planks",
mushroom = S"Any mushroom",
["color_red,flower"] = S"Any red flower",
["color_blue,flower"] = S"Any blue flower",
["color_black,flower"] = S"Any black flower",
["color_white,flower"] = S"Any white flower",
["color_green,flower"] = S"Any green flower",
["color_orange,flower"] = S"Any orange flower",
["color_yellow,flower"] = S"Any yellow flower",
["color_violet,flower"] = S"Any violet flower",
["color_red,dye"] = S"Any red dye",
["color_blue,dye"] = S"Any blue dye",
["color_grey,dye"] = S"Any grey dye",
["color_pink,dye"] = S"Any pink dye",
["color_cyan,dye"] = S"Any cyan dye",
["color_black,dye"] = S"Any black dye",
["color_white,dye"] = S"Any white dye",
["color_brown,dye"] = S"Any brown dye",
["color_green,dye"] = S"Any green dye",
["color_orange,dye"] = S"Any orange dye",
["color_yellow,dye"] = S"Any yellow dye",
["color_violet,dye"] = S"Any violet dye",
["color_magenta,dye"] = S"Any magenta dye",
["color_dark_grey,dye"] = S"Any dark grey dye",
["color_dark_green,dye"] = S"Any dark green dye",
}
i3.model_alias = {
["boats:boat"] = {name = "boats:boat", drawtype = "entity"},
["carts:cart"] = {name = "carts:cart", drawtype = "entity", frames = "0,0"},
["default:chest"] = {name = "default:chest_open"},
["default:chest_locked"] = {name = "default:chest_locked_open"},
["doors:door_wood"] = {name = "doors:door_wood_a"},
["doors:door_glass"] = {name = "doors:door_glass_a"},
["doors:door_obsidian_glass"] = {name = "doors:door_obsidian_glass_a"},
["doors:door_steel"] = {name = "doors:door_steel_a"},
["xpanes:door_steel_bar"] = {name = "xpanes:door_steel_bar_a"},
}
local function err(str) local function err(str)
return log("error", str) return core.log("error", str)
end end
local function msg(name, str) local function msg(name, str)
return chat_send(name, sprintf("[i3] %s", str)) return core.chat_send_player(name, sprintf("[i3] %s", str))
end end
local function is_num(x) local function is_num(x)
@ -354,7 +165,7 @@ local function fmt(elem, ...)
end end
local function clean_name(item) local function clean_name(item)
if sub(item, 1, 1) == ":" or sub(item, 1, 1) == " " then if sub(item, 1, 1) == ":" or sub(item, 1, 1) == " " or sub(item, 1, 1) == "_" then
item = sub(item, 2) item = sub(item, 2)
end end
@ -500,7 +311,7 @@ function i3.register_craft(def)
http.fetch({url = def.url}, function(result) http.fetch({url = def.url}, function(result)
if result.succeeded then if result.succeeded then
local t = parse_json(result.data) local t = core.parse_json(result.data)
if is_table(t) then if is_table(t) then
return i3.register_craft(t) return i3.register_craft(t)
end end
@ -615,7 +426,7 @@ function i3.set_recipe_filter(name, f)
recipe_filters = {[name] = f} recipe_filters = {[name] = f}
end end
function i3.delete_recipe_filter(name) function i3.remove_recipe_filter(name)
recipe_filters[name] = nil recipe_filters[name] = nil
end end
@ -651,6 +462,14 @@ function i3.get_search_filters()
return search_filters return search_filters
end end
local function compression_active(data)
return item_compression and not next(recipe_filters) and data.filter == ""
end
local function compressible(item, data)
return compression_active(data) and compress_groups[item]
end
local function weird_desc(str) local function weird_desc(str)
return not true_str(str) or find(str, "\n") or not find(str, "%u") return not true_str(str) or find(str, "\n") or not find(str, "%u")
end end
@ -734,7 +553,7 @@ local function get_filtered_items(player, data)
end end
local function get_burntime(item) local function get_burntime(item)
return get_craft_result{method = "fuel", items = {item}}.time return core.get_craft_result{method = "fuel", items = {item}}.time
end end
local function cache_fuel(item) local function cache_fuel(item)
@ -754,19 +573,22 @@ local function show_item(def)
def.description and def.description ~= "" def.description and def.description ~= ""
end end
local function search(data) local function reset_compression(data)
local filter = data.filter data.alt_items = nil
data.expand = ""
if searches[filter] then
data.items = searches[filter]
return
end end
local function search(data)
reset_compression(data)
local filter = data.filter
local opt = "^(.-)%+([%w_]+)=([%w_,]+)" local opt = "^(.-)%+([%w_]+)=([%w_,]+)"
local search_filter = next(search_filters) and match(filter, opt) local search_filter = next(search_filters) and match(filter, opt)
local filters = {} local filters = {}
if search_filter then if search_filter then
search_filter = search_filter:trim()
for filter_name, values in gmatch(filter, sub(opt, 6)) do for filter_name, values in gmatch(filter, sub(opt, 6)) do
if search_filters[filter_name] then if search_filters[filter_name] then
values = split(values, ",") values = split(values, ",")
@ -800,7 +622,18 @@ local function search(data)
end end
end end
else else
to_add = find(search_in, filter, 1, true) local ok = true
for keyword in gmatch(filter, "%S+") do
if not find(search_in, keyword, 1, true) then
ok = nil
break
end
end
if ok then
to_add = true
end
end end
if to_add then if to_add then
@ -809,16 +642,36 @@ local function search(data)
end end
end end
if not next(recipe_filters) then data.items = filtered_list
-- Cache the results only if searched 2 times end
if searches[filter] == nil then
searches[filter] = false local function sort_by_category(data)
else reset_compression(data)
searches[filter] = filtered_list local items = data.items_raw
if data.filter ~= "" then
search(data)
items = data.items
end
local new = {}
for i = 1, #items do
local item = items[i]
local to_add = true
if data.current_itab == 2 then
to_add = reg_nodes[item]
elseif data.current_itab == 3 then
to_add = reg_craftitems[item] or reg_tools[item]
end
if to_add then
new[#new + 1] = item
end end
end end
data.items = filtered_list data.items = new
end end
local function get_item_usages(item, recipe, added) local function get_item_usages(item, recipe, added)
@ -923,7 +776,7 @@ local function cache_drops(name, drop)
end end
local function cache_recipes(item) local function cache_recipes(item)
local recipes = get_all_recipes(item) local recipes = core.get_all_craft_recipes(item)
if replacements[item] then if replacements[item] then
local _recipes = {} local _recipes = {}
@ -978,15 +831,16 @@ end
local function groups_to_items(groups, get_all) local function groups_to_items(groups, get_all)
if not get_all and #groups == 1 then if not get_all and #groups == 1 then
local group = groups[1] local group = groups[1]
local stereotype = i3.group_stereotypes[group] local stereotype = group_stereotypes[group]
local def = reg_items[stereotype] local def = reg_items[stereotype]
if def and show_item(def) then if show_item(def) then
return stereotype return stereotype
end end
end end
local names = {} local names = {}
for name, def in pairs(reg_items) do for name, def in pairs(reg_items) do
if show_item(def) and item_has_groups(def.groups, groups) then if show_item(def) and item_has_groups(def.groups, groups) then
if get_all then if get_all then
@ -1241,9 +1095,56 @@ local function select_item(player, name, data, _f)
end end
end end
if not item then if not item then return end
if compressible(item, data) then
local idx
for i = 1, #data.items do
local it = data.items[i]
if it == item then
idx = i
break
end
end
if data.expand ~= "" then
data.alt_items = nil
if item == data.expand then
data.expand = nil
return return
elseif sub(item, 1, 1) == "_" then end
end
if idx and item ~= data.expand then
data.alt_items = copy(data.items)
data.expand = item
if compress_groups[item] then
local items = copy(compress_groups[item])
insert(items, fmt("_%s", item))
sort(items, function(a, b)
if a:sub(1, 1) == "_" then
a = a:sub(2)
end
return a < b
end)
local i = 1
for _, v in ipairs(items) do
if show_item(reg_items[clean_name(v)]) then
insert(data.alt_items, idx + i, v)
i = i + 1
end
end
end
end
else
if sub(item, 1, 1) == "_" then
item = sub(item, 2) item = sub(item, 2)
elseif sub(item, 1, 6) == "group|" then elseif sub(item, 1, 6) == "group|" then
item = match(item, "([%w:_]+)$") item = match(item, "([%w:_]+)$")
@ -1272,6 +1173,7 @@ local function select_item(player, name, data, _f)
data.export_rcp = nil data.export_rcp = nil
data.export_usg = nil data.export_usg = nil
end end
end
local function repairable(tool) local function repairable(tool)
local def = reg_tools[tool] local def = reg_tools[tool]
@ -1421,7 +1323,11 @@ local function get_output_fs(fs, data, rcp, is_recipe, shapeless, right, btn_siz
fs(fmt("list[detached:i3_output_%s;main;%f,%f;1,1;]", rcp_usg, X + 0.11, Y)) fs(fmt("list[detached:i3_output_%s;main;%f,%f;1,1;]", rcp_usg, X + 0.11, Y))
fs("button", X + 0.11, Y, ITEM_BTN_SIZE, ITEM_BTN_SIZE, _name, "") fs("button", X + 0.11, Y, ITEM_BTN_SIZE, ITEM_BTN_SIZE, _name, "")
local inv = get_inv {type = "detached", name = fmt("i3_output_%s", rcp_usg)} local inv = core.get_inventory {
type = "detached",
name = fmt("i3_output_%s", rcp_usg)
}
inv:set_stack("main", 1, item) inv:set_stack("main", 1, item)
pos = {x = X + 0.11, y = Y} pos = {x = X + 0.11, y = Y}
else else
@ -1708,7 +1614,7 @@ local function get_header(fs, data)
fs("style_type[label;font=normal;font_size=16]") fs("style_type[label;font=normal;font_size=16]")
local def = reg_items[data.query_item] local def = reg_items[data.query_item]
local model_alias = i3.model_alias[data.query_item] local model_alias = model_aliases[data.query_item]
if def.drawtype == "mesh" or model_alias then if def.drawtype == "mesh" or model_alias then
get_model_fs(fs, data, def, model_alias) get_model_fs(fs, data, def, model_alias)
@ -1788,9 +1694,22 @@ local function get_rcp_extra(player, fs, data, panel, is_recipe, is_usage)
fs("container_end[]") fs("container_end[]")
end end
local function get_items_fs(fs, data, extend) local function get_items_fs(fs, data, full_height)
local rows = 8 if compression_active(data) then
local lines = extend and 12 or 9 local new = {}
for i = 1, #data.items do
local item = data.items[i]
if not compressed[item] then
new[#new + 1] = item
end
end
data.items = new
end
local items = data.alt_items or data.items
local rows, lines = 8, 12
local ipp = rows * lines local ipp = rows * lines
local size = 0.85 local size = 0.85
@ -1804,12 +1723,12 @@ local function get_items_fs(fs, data, extend)
fs("image_button", data.inv_width + 5.27, 0.3, 0.35, 0.35, "", "prev_page", "") fs("image_button", data.inv_width + 5.27, 0.3, 0.35, 0.35, "", "prev_page", "")
fs("image_button", data.inv_width + 7.45, 0.3, 0.35, 0.35, "", "next_page", "") fs("image_button", data.inv_width + 7.45, 0.3, 0.35, 0.35, "", "next_page", "")
data.pagemax = max(1, ceil(#data.items / ipp)) data.pagemax = max(1, ceil(#items / ipp))
fs("button", data.inv_width + 5.6, 0.14, 1.88, 0.7, "pagenum", fs("button", data.inv_width + 5.6, 0.14, 1.88, 0.7, "pagenum",
fmt("%s / %u", clr("#ff0", data.pagenum), data.pagemax)) fmt("%s / %u", clr("#ff0", data.pagenum), data.pagemax))
if #data.items == 0 then if #items == 0 then
local lbl = ES"No item to show" local lbl = ES"No item to show"
if next(recipe_filters) and #init_items > 0 and data.filter == "" then if next(recipe_filters) and #init_items > 0 and data.filter == "" then
@ -1817,21 +1736,49 @@ local function get_items_fs(fs, data, extend)
end end
fs("button", data.inv_width + 0.1, 3, 8, 1, "no_item", lbl) fs("button", data.inv_width + 0.1, 3, 8, 1, "no_item", lbl)
end else
local first_item = (data.pagenum - 1) * ipp local first_item = (data.pagenum - 1) * ipp
for i = first_item, first_item + ipp - 1 do for i = first_item, first_item + ipp - 1 do
local item = data.items[i + 1] local item = items[i + 1]
if not item then break end if not item then break end
local _compressed = item:sub(1, 1) == "_"
local name = _compressed and item:sub(2) or item
local X = i % rows local X = i % rows
X = X - (X * 0.045) + data.inv_width + 0.28 X = X - (X * 0.045) + data.inv_width + 0.28
local Y = round((i % ipp - X) / rows + 1, 0) local Y = round((i % ipp - X) / rows + 1, 0)
Y = Y - (Y * (extend and 0.085 or 0.035)) + 0.95 Y = Y - (Y * 0.085) + 0.95
fs[#fs + 1] = fmt("item_image_button", X, Y, size, size, item, item, "") fs[#fs + 1] = fmt("item_image_button", X, Y, size, size, name, item, "")
if compressible(item, data) then
local expand = data.expand == name
fs(fmt("tooltip[%s;%s]", item, expand and ES"Click to hide" or ES"Click to expand"))
fs("style_type[label;font=bold;font_size=20]")
fs("label", X + 0.65, Y + 0.7, expand and "-" or "+")
fs("style_type[label;font=normal;font_size=16]")
end
end
end
local _tabs = {"All", "Nodes", "Items"}
local tab_len, tab_hgh = 1.8, 0.5
for i, title in ipairs(_tabs) do
local selected = i == data.current_itab
fs(fmt([[style_type[image_button;fgimg=%s;fgimg_hovered=%s;noclip=true;
font_size=16;textcolor=%s;content_offset=0;sound=i3_tab] ]],
selected and PNG.tab_small_hover or PNG.tab_small,
PNG.tab_small_hover, selected and "#fff" or "#ddd"))
fs("style_type[image_button:hovered;textcolor=#fff]")
fs("image_button", (data.inv_width - 0.65) + (i * (tab_len + 0.1)),
full_height, tab_len, tab_hgh, "", fmt("itab_%u", i), title)
end end
end end
@ -1854,21 +1801,15 @@ end
local function get_panels(player, data, fs, full_height) local function get_panels(player, data, fs, full_height)
local _title = {name = "title", height = 1.4} local _title = {name = "title", height = 1.4}
local _favs = {name = "favs", height = 2.23} local _favs = {name = "favs", height = 2.23}
local _items = {name = "items", height = 9.69} local _items = {name = "items", height = full_height}
local _recipes = {name = "recipes", rcp = data.recipes, height = 4.045} local _recipes = {name = "recipes", rcp = data.recipes, height = 4.045}
local _usages = {name = "usages", rcp = data.usages, height = 4.045} local _usages = {name = "usages", rcp = data.usages, height = 4.045}
local panels, extend local panels
if data.query_item then if data.query_item then
panels = {_title, _recipes, _usages, _favs} panels = {_title, _recipes, _usages, _favs}
else else
panels = {_items, _favs} panels = {_items}
if #data.favs == 0 then
extend = true
remove(panels, 2)
_items.height = full_height
end
end end
for idx = 1, #panels do for idx = 1, #panels do
@ -1888,7 +1829,7 @@ local function get_panels(player, data, fs, full_height)
if is_recipe or is_usage then if is_recipe or is_usage then
get_rcp_extra(player, fs, data, panel, is_recipe, is_usage) get_rcp_extra(player, fs, data, panel, is_recipe, is_usage)
elseif panel.name == "items" then elseif panel.name == "items" then
get_items_fs(fs, data, extend) get_items_fs(fs, data, full_height)
elseif panel.name == "title" then elseif panel.name == "title" then
get_header(fs, data) get_header(fs, data)
elseif panel.name == "favs" then elseif panel.name == "favs" then
@ -2008,7 +1949,7 @@ local function get_waypoint_fs(fs, data, player, yextra, ctn_len)
fs("tooltip", 0, y, ctn_len - 2.5, 0.65, fs("tooltip", 0, y, ctn_len - 2.5, 0.65,
fmt("Name: %s\nPosition:%s", clr("#ff0", v.name), fmt("Name: %s\nPosition:%s", clr("#ff0", v.name),
pos_to_string(v.pos, 0):sub(2,-2):gsub("(%-*%d+)", clr("#ff0", " %1")))) core.pos_to_string(v.pos, 0):sub(2,-2):gsub("(%-*%d+)", clr("#ff0", " %1"))))
local del = fmt("waypoint_%u_delete", i) local del = fmt("waypoint_%u_delete", i)
fs(fmt("style[%s;fgimg=%s;fgimg_hovered=%s;content_offset=0]", del, PNG.trash, PNG.trash_hover)) fs(fmt("style[%s;fgimg=%s;fgimg_hovered=%s;content_offset=0]", del, PNG.trash, PNG.trash_hover))
@ -2287,9 +2228,9 @@ function i3.get_tabs()
return tabs return tabs
end end
function i3.delete_tab(tabname) function i3.remove_tab(tabname)
if not true_str(tabname) then if not true_str(tabname) then
return err "i3.delete_tab: tab name missing" return err "i3.remove_tab: tab name missing"
end end
for i, def in ipairs(tabs) do for i, def in ipairs(tabs) do
@ -2356,15 +2297,18 @@ local function init_data(player, info)
data.favs = {} data.favs = {}
data.export_counts = {} data.export_counts = {}
data.current_tab = 1 data.current_tab = 1
data.current_itab = 1
data.subcat = 1 data.subcat = 1
data.scrbar_inv = 0 data.scrbar_inv = 0
data.lang_code = get_lang_code(info) data.lang_code = get_lang_code(info)
data.fs_version = info.formspec_version
after(0, set_fs, player) after(0, set_fs, player)
end end
local function reset_data(data) local function reset_data(data)
data.filter = "" data.filter = ""
data.expand = ""
data.pagenum = 1 data.pagenum = 1
data.rnum = 1 data.rnum = 1
data.unum = 1 data.unum = 1
@ -2375,7 +2319,12 @@ local function reset_data(data)
data.usages = nil data.usages = nil
data.export_rcp = nil data.export_rcp = nil
data.export_usg = nil data.export_usg = nil
data.alt_items = nil
data.items = data.items_raw data.items = data.items_raw
if data.current_itab > 1 then
sort_by_category(data)
end
end end
local function rcp_fields(player, data, fields) local function rcp_fields(player, data, fields)
@ -2402,6 +2351,10 @@ local function rcp_fields(player, data, fields)
search(data) search(data)
if data.current_itab > 1 then
sort_by_category(data)
end
elseif fields.prev_page or fields.next_page then elseif fields.prev_page or fields.next_page then
if data.pagemax == 1 then return end if data.pagemax == 1 then return end
data.pagenum = data.pagenum - (fields.prev_page and 1 or -1) data.pagenum = data.pagenum - (fields.prev_page and 1 or -1)
@ -2515,9 +2468,9 @@ local function get_inventory_fs(player, data, fs)
local textures = concat(t, ","):gsub("!", ",") local textures = concat(t, ","):gsub("!", ",")
--fs("style[player_model;bgcolor=black]") --fs("style[player_model;bgcolor=black]")
fs("model", 0.2, 0.2, armor_skin and 4 or 3.4, armor_skin and ctn_hgt or 6.1, fs("model", 0.2, 0.2, armor_skin and 4 or 3.4, ctn_hgt,
"player_model", props.mesh, textures, "0,-150", "false", "false", "player_model", props.mesh, textures, "0,-150", "false", "false",
fmt("%u,%u", anim.x, anim.y)) fmt("%u,%u%s", anim.x, anim.y, data.fs_version >= 5 and ";30" or ""))
else else
local size = 2.5 local size = 2.5
fs("image", 0.7, 0.2, size, size * props.visual_size.y, props.textures[1]) fs("image", 0.7, 0.2, size, size * props.visual_size.y, props.textures[1])
@ -2565,9 +2518,7 @@ local function get_inventory_fs(player, data, fs)
(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(fmt("scroll_container[3.9,0.2;%f,%f;scrbar_inv;vertical]", ctn_len, ctn_hgt))
get_ctn_content(fs, data, player, yoffset, ctn_len, award_list, awards_unlocked, award_list_nb) get_ctn_content(fs, data, player, yoffset, ctn_len, award_list, awards_unlocked, award_list_nb)
fs("scroll_container_end[]") fs("scroll_container_end[]")
local btn = { local btn = {
@ -2812,18 +2763,6 @@ i3.add_search_filter("groups", function(item, groups)
return has_groups return has_groups
end) end)
i3.add_search_filter("types", function(item, drawtypes)
local t = {}
for i, dt in ipairs(drawtypes) do
t[i] = (dt == "node" and reg_nodes[item] and 1) or
(dt == "item" and reg_craftitems[item] and 1) or
(dt == "tool" and reg_tools[item] and 1) or nil
end
return #t > 0
end)
--[[ As `core.get_craft_recipe` and `core.get_all_craft_recipes` do not --[[ As `core.get_craft_recipe` and `core.get_all_craft_recipes` do not
return the fuel, replacements and toolrepair recipes, we have to return the fuel, replacements and toolrepair recipes, we have to
override `core.register_craft` and do some reverse engineering. override `core.register_craft` and do some reverse engineering.
@ -2945,12 +2884,12 @@ local function get_init_items()
http.fetch_async { http.fetch_async {
url = i3.export_url, url = i3.export_url,
post_data = write_json(post_data), post_data = core.write_json(post_data),
} }
end end
end end
on_mods_loaded(function() core.register_on_mods_loaded(function()
get_init_items() get_init_items()
__sfinv = rawget(_G, "sfinv") __sfinv = rawget(_G, "sfinv")
@ -2974,7 +2913,7 @@ local function init_backpack(player)
local data = pdata[name] local data = pdata[name]
local inv = player:get_inventory() local inv = player:get_inventory()
inv:set_size("main", INV_SIZE) inv:set_size("main", data.bag_size and BAG_SIZES[data.bag_size] or INV_SIZE)
data.bag = create_inventory(fmt("%s_backpack", name), { data.bag = create_inventory(fmt("%s_backpack", name), {
allow_put = function(_inv, listname, _, stack) allow_put = function(_inv, listname, _, stack)
@ -3015,7 +2954,6 @@ local function init_backpack(player)
if data.bag_size then if data.bag_size then
data.bag:set_stack("main", 1, fmt("i3:bag_%s", data.bag_size)) data.bag:set_stack("main", 1, fmt("i3:bag_%s", data.bag_size))
inv:set_size("main", BAG_SIZES[data.bag_size])
end end
end end
@ -3040,11 +2978,11 @@ local function init_waypoints(player)
end end
end end
on_joinplayer(function(player) core.register_on_joinplayer(function(player)
local name = player:get_player_name() local name = player:get_player_name()
local info = get_player_info(name) local info = core.get_player_information and core.get_player_information(name)
if get_formspec_version(info) < MIN_FORMSPEC_VERSION then if not info or get_formspec_version(info) < MIN_FORMSPEC_VERSION then
if __sfinv then if __sfinv then
sfinv.set_player_inventory_formspec = old_sfinv_fn sfinv.set_player_inventory_formspec = old_sfinv_fn
sfinv.enabled = true sfinv.enabled = true
@ -3058,6 +2996,8 @@ on_joinplayer(function(player)
end end
end end
pdata[name] = nil
return outdated(name) return outdated(name)
end end
@ -3111,12 +3051,12 @@ local function save_data(player_name)
storage:set_string("pdata", slz(_pdata)) storage:set_string("pdata", slz(_pdata))
end end
on_leaveplayer(function(player) core.register_on_leaveplayer(function(player)
local name = player:get_player_name() local name = player:get_player_name()
save_data(name) save_data(name)
end) end)
on_shutdown(save_data) core.register_on_shutdown(save_data)
local function routine() local function routine()
save_data() save_data()
@ -3125,7 +3065,7 @@ end
after(SAVE_INTERVAL, routine) after(SAVE_INTERVAL, routine)
on_receive_fields(function(player, formname, fields) core.register_on_player_receive_fields(function(player, formname, fields)
if formname ~= "" then if formname ~= "" then
return false return false
end end
@ -3139,6 +3079,10 @@ on_receive_fields(function(player, formname, fields)
local tabname = sub(f, 5) local tabname = sub(f, 5)
set_tab(player, tabname) set_tab(player, tabname)
break break
elseif sub(f, 1, 5) == "itab_" then
data.pagenum = 1
data.current_itab = tonum(f:sub(-1))
sort_by_category(data)
end end
end end
@ -3170,6 +3114,7 @@ if progressive_mode then
if is_group(item) then if is_group(item) then
local groups = extract_groups(item) local groups = extract_groups(item)
for i = 1, inv_items_size do for i = 1, inv_items_size do
local def = reg_items[inv_items[i]] local def = reg_items[inv_items[i]]
@ -3236,6 +3181,7 @@ if progressive_mode then
for i = 1, #stacks do for i = 1, #stacks do
local stack = stacks[i] local stack = stacks[i]
if not stack:is_empty() then if not stack:is_empty() then
local name = stack:get_name() local name = stack:get_name()
if reg_items[name] then if reg_items[name] then
@ -3326,7 +3272,8 @@ if progressive_mode then
-- Workaround. Need an engine call to detect when the contents of -- Workaround. Need an engine call to detect when the contents of
-- the player inventory changed, instead. -- the player inventory changed, instead.
local function poll_new_items() local function poll_new_items()
local players = get_players() local players = core.get_connected_players()
for i = 1, #players do for i = 1, #players do
local player = players[i] local player = players[i]
local name = player:get_player_name() local name = player:get_player_name()
@ -3346,6 +3293,8 @@ if progressive_mode then
end end
data.items_raw = items data.items_raw = items
data.current_itab = 1
search(data) search(data)
set_fs(player) set_fs(player)
end end
@ -3356,8 +3305,9 @@ if progressive_mode then
poll_new_items() poll_new_items()
globalstep(function() core.register_globalstep(function()
local players = get_players() local players = core.get_connected_players()
for i = 1, #players do for i = 1, #players do
local player = players[i] local player = players[i]
local name = player:get_player_name() local name = player:get_player_name()
@ -3371,7 +3321,7 @@ if progressive_mode then
i3.add_recipe_filter("Default progressive filter", progressive_filter) i3.add_recipe_filter("Default progressive filter", progressive_filter)
on_joinplayer(function(player) core.register_on_joinplayer(function(player)
local name = player:get_player_name() local name = player:get_player_name()
local data = pdata[name] local data = pdata[name]
@ -3417,5 +3367,5 @@ for size, rcp in pairs(bag_recipes) do
core.register_craft {type = "fuel", recipe = bagname, burntime = 3} core.register_craft {type = "fuel", recipe = bagname, burntime = 3}
end end
--dofile(core.get_modpath("i3") .. "/test_tabs.lua") --dofile(modpath .. "/tests/test_tabs.lua")
--dofile(core.get_modpath("i3") .. "/test_custom_recipes.lua") --dofile(modpath .. "/tests/test_custom_recipes.lua")

View File

@ -1,2 +1,5 @@
# 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

BIN
textures/i3_tab_small.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB