craftguide/init.lua

989 lines
23 KiB
Lua
Raw Normal View History

2018-12-17 00:38:58 +01:00
craftguide = {
2018-12-16 23:20:54 +01:00
custom_crafts = {},
craft_types = {},
}
local mt = minetest
2019-01-08 20:28:53 +01:00
local player_data = {}
local init_items = {}
local searches = {}
2018-11-11 22:24:48 +01:00
local progressive_mode = mt.settings:get_bool("craftguide_progressive_mode")
2018-11-11 22:24:48 +01:00
local sfinv_only = mt.settings:get_bool("craftguide_sfinv_only")
2016-12-24 19:20:10 +01:00
local reg_items = mt.registered_items
local get_result = mt.get_craft_result
local show_formspec = mt.show_formspec
-- Intllib
local S = dofile(mt.get_modpath("craftguide") .. "/intllib.lua")
2016-12-17 13:15:02 +01:00
-- Lua 5.3 removed `table.maxn`, use this alternative in case of breakage:
-- https://github.com/kilbith/xdecor/blob/master/handlers/helpers.lua#L1
local maxn, sort, concat = table.maxn, table.sort, table.concat
local vector_add, vector_mul = vector.add, vector.multiply
local min, max, floor, ceil = math.min, math.max, math.floor, math.ceil
2019-01-02 18:57:35 +01:00
local fmt = string.format
2016-12-17 13:15:02 +01:00
2018-04-17 13:30:51 +02:00
local DEFAULT_SIZE = 10
2018-11-18 20:06:45 +01:00
local MIN_LIMIT, MAX_LIMIT = 10, 12
2018-04-17 13:30:51 +02:00
DEFAULT_SIZE = min(MAX_LIMIT, max(MIN_LIMIT, DEFAULT_SIZE))
2018-04-27 22:18:18 +02:00
local GRID_LIMIT = 5
local group_stereotypes = {
wool = "wool:white",
dye = "dye:white",
water_bucket = "bucket:bucket_water",
vessel = "vessels:glass_bottle",
coal = "default:coal_lump",
flower = "flowers:dandelion_yellow",
mesecon_conductor_craftable = "mesecons:wire_00000000_off",
}
2018-12-30 21:32:36 +01:00
local function __func()
return debug.getinfo(2, "n").name
end
2018-12-16 23:20:54 +01:00
function craftguide.register_craft_type(name, def)
2018-12-30 21:32:36 +01:00
local func = "craftguide." .. __func() .. "(): "
assert(name, func .. "'name' field missing")
assert(def.description, func .. "'description' field missing")
assert(def.icon, func .. "'icon' field missing")
2018-12-16 23:20:54 +01:00
if not craftguide.craft_types[name] then
craftguide.craft_types[name] = def
end
end
craftguide.register_craft_type("digging", {
description = S("Digging"),
icon = "default_tool_steelpick.png",
2018-12-16 23:20:54 +01:00
})
function craftguide.register_craft(def)
2018-12-30 21:32:36 +01:00
local func = "craftguide." .. __func() .. "(): "
assert(def.type, func .. "'type' field missing")
2018-12-30 21:32:36 +01:00
assert(def.width, func .. "'width' field missing")
2019-01-02 18:57:35 +01:00
assert(def.output, func .. "'output' field missing")
assert(def.items, func .. "'items' field missing")
2018-12-30 21:32:36 +01:00
2018-12-16 23:20:54 +01:00
craftguide.custom_crafts[#craftguide.custom_crafts + 1] = def
end
craftguide.register_craft({
type = "digging",
width = 1,
2018-12-16 23:20:54 +01:00
output = "default:cobble",
items = {"default:stone"},
})
local function get_recipe(output)
local recipe = mt.get_craft_recipe(output)
if recipe.items then
return recipe
end
for i = 1, #craftguide.custom_crafts do
local custom_craft = craftguide.custom_crafts[i]
if custom_craft.output:match("%S*") == output then
return custom_craft
end
end
return {}
end
local function get_recipes(output)
local recipes = mt.get_all_craft_recipes(output) or {}
for i = 1, #craftguide.custom_crafts do
local custom_craft = craftguide.custom_crafts[i]
if custom_craft.output:match("%S*") == output then
recipes[#recipes + 1] = custom_craft
end
end
return recipes
end
2018-12-30 21:10:39 +01:00
local color_codes = {
red = "#FF0000",
yellow = "#FFFF00",
}
local function colorize(str, color)
color = color or "yellow"
return mt.colorize(color_codes[color], str)
2018-12-16 23:20:54 +01:00
end
local function get_fueltime(item)
return get_result({method = "fuel", width = 1, items = {item}}).time
end
local function extract_groups(str)
return str:sub(7):split(",")
end
local function item_has_groups(item_groups, groups)
for i = 1, #groups do
local group = groups[i]
if not item_groups[group] then
return
end
end
return true
end
local function groups_to_item(groups)
if #groups == 1 then
local group = groups[1]
if group_stereotypes[group] then
return group_stereotypes[group]
elseif reg_items["default:" .. group] then
return "default:" .. group
end
end
for name, def in pairs(reg_items) do
if item_has_groups(def.groups, groups) then
return name
2016-02-21 00:42:52 +01:00
end
end
return ""
2016-02-21 00:42:52 +01:00
end
2018-12-17 01:02:19 +01:00
local function get_tooltip(item, recipe_type, cooktime, groups)
2017-03-21 14:26:58 +01:00
local tooltip, item_desc = "tooltip[" .. item .. ";", ""
2016-12-24 17:59:42 +01:00
local fueltime = get_fueltime(item)
2016-12-10 17:17:05 +01:00
local has_extras = groups or recipe_type == "cooking" or fueltime > 0
2016-12-15 01:59:05 +01:00
2016-12-24 17:59:42 +01:00
if reg_items[item] then
if not groups then
2016-12-24 17:59:42 +01:00
item_desc = reg_items[item].description
end
else
return tooltip .. S("Unknown Item (@1)", item) .. "]"
end
2017-03-21 14:26:58 +01:00
if groups then
local groupstr = ""
2018-03-08 17:06:53 +01:00
for i = 1, #groups do
2018-04-17 13:30:51 +02:00
groupstr = groupstr ..
colorize(groups[i]) .. (groups[i + 1] and ", " or "")
end
2018-04-17 13:30:51 +02:00
2018-11-11 14:19:19 +01:00
tooltip = tooltip ..
S("Any item belonging to the group(s)") .. ": " .. groupstr
end
2017-03-21 14:26:58 +01:00
if recipe_type == "cooking" then
2018-11-11 14:19:19 +01:00
tooltip = tooltip .. item_desc .. "\n" ..
S("Cooking time") .. ": " .. colorize(cooktime)
end
2017-03-21 14:26:58 +01:00
2016-12-10 17:17:05 +01:00
if fueltime > 0 then
2018-11-11 14:19:19 +01:00
tooltip = tooltip .. item_desc .. "\n" ..
S("Burning time") .. ": " .. colorize(fueltime)
2016-12-10 17:17:05 +01:00
end
2017-03-21 14:26:58 +01:00
return has_extras and tooltip .. "]" or ""
end
local function get_recipe_fs(iX, iY, xoffset, recipe_num, recipes, show_usage)
if not recipes[1] then
return ""
2016-12-10 23:15:02 +01:00
end
2017-03-21 14:26:58 +01:00
2018-12-30 21:17:21 +01:00
local fs = {}
2019-01-02 18:57:35 +01:00
fs[#fs + 1] = fmt("button[%f,%f;%f,%f;%s;%s %u %s %u]",
iX - (sfinv_only and 2.2 or 2.6),
iY + (sfinv_only and 3.9 or 3.3),
2.2,
1,
"alternate",
show_usage and S("Usage") or S("Recipe"),
recipe_num,
S("of"),
#recipes)
2018-12-30 21:17:21 +01:00
2016-12-17 19:15:02 +01:00
local recipe_type = recipes[recipe_num].type
2017-02-06 04:45:25 +01:00
local items = recipes[recipe_num].items
local width = recipes[recipe_num].width
2018-11-18 18:24:32 +01:00
local cooktime = width
2018-11-17 17:48:47 +01:00
if recipe_type == "cooking" then
width = 1
elseif width == 0 then
2018-03-08 17:06:53 +01:00
width = min(3, #items)
end
2016-12-17 13:15:02 +01:00
local rows = ceil(maxn(items) / width)
2019-01-09 21:11:06 +01:00
local rightest, btn_size, s_btn_size = 0, 1.1
2016-12-10 23:15:02 +01:00
if width > GRID_LIMIT or rows > GRID_LIMIT then
2019-01-02 18:57:35 +01:00
fs[#fs + 1] = fmt("label[%f,%f;%s]",
(iX / 2) - 2,
iY + 2.2,
S("Recipe is too big to be displayed (@1x@2)", width, rows))
2018-12-19 18:36:09 +01:00
return concat(fs)
end
2016-12-17 18:51:04 +01:00
for i, item in pairs(items) do
local X = ceil((i - 1) % width + xoffset - width) -
(sfinv_only and 0 or 0.2)
local Y = ceil(i / width + (iY + 2) - min(2, rows))
2018-11-18 20:06:45 +01:00
if width > 3 or rows > 3 then
2019-01-09 21:11:06 +01:00
btn_size = width > 3 and 3 / width or 3 / rows
s_btn_size = btn_size
X = btn_size * (i % width) + xoffset - 2.65
Y = btn_size * floor((i - 1) / width) + (iY + 3) - min(2, rows)
2016-12-17 18:51:04 +01:00
end
2018-11-17 17:48:47 +01:00
if X > rightest then
rightest = X
end
local groups
if item:sub(1,6) == "group:" then
groups = extract_groups(item)
item = groups_to_item(groups)
end
local label = groups and "\nG" or ""
local tltp = get_tooltip(item, recipe_type, cooktime, groups)
fs[#fs + 1] = fmt("item_image_button[%f,%f;%f,%f;%s;%s;%s]",
X,
Y + (sfinv_only and 0.7 or 0.2),
2019-01-09 21:11:06 +01:00
btn_size,
btn_size,
item,
item:match("%S*"),
label)
fs[#fs + 1] = tltp
2016-12-10 23:15:02 +01:00
end
2018-03-08 17:06:53 +01:00
2018-12-17 01:02:19 +01:00
local custom_recipe = craftguide.craft_types[recipe_type]
if recipe_type == "cooking" or custom_recipe or
(recipe_type == "normal" and width == 0) then
2019-01-02 18:57:35 +01:00
local icon = recipe_type == "cooking" and "furnace" or "shapeless"
2018-12-16 23:20:54 +01:00
2019-01-02 18:57:35 +01:00
fs[#fs + 1] = fmt("image[%f,%f;%f,%f;%s]",
rightest + 1.2,
iY + (sfinv_only and 2.2 or 1.7),
0.5,
0.5,
custom_recipe and custom_recipe.icon or
"craftguide_" .. icon .. ".png^[resize:16x16")
2018-12-19 18:36:09 +01:00
2019-01-02 18:57:35 +01:00
fs[#fs + 1] = fmt("tooltip[%f,%f;%f,%f;%s]",
rightest + 1.2,
iY + (sfinv_only and 2.2 or 1.7),
0.5,
0.5,
custom_recipe and custom_recipe.description or
recipe_type:gsub("^%l", string.upper))
2018-11-18 20:06:45 +01:00
end
local output = recipes[recipe_num].output
2018-12-16 23:20:54 +01:00
local output_s = output:match("%S+")
2018-11-17 17:48:47 +01:00
2019-01-09 21:11:06 +01:00
local arrow_X = rightest + (s_btn_size or 1.1)
2018-11-18 20:52:00 +01:00
local output_X = arrow_X + 0.9
2019-01-02 18:57:35 +01:00
fs[#fs + 1] = fmt("image[%f,%f;%f,%f;%s]",
arrow_X,
iY + (sfinv_only and 2.85 or 2.35),
0.9,
0.7,
"craftguide_arrow.png")
2018-11-17 17:48:47 +01:00
if output == "BURN" then
2019-01-02 18:57:35 +01:00
fs[#fs + 1] = fmt("image[%f,%f;%f,%f;%s]",
output_X,
iY + (sfinv_only and 2.68 or 2.18),
1.1,
1.1,
"craftguide_fire.png")
else
2019-01-02 18:57:35 +01:00
fs[#fs + 1] = fmt("item_image_button[%f,%f;%f,%f;%s;%s;]",
output_X,
iY + (sfinv_only and 2.7 or 2.2),
2019-01-09 21:11:06 +01:00
1.1,
1.1,
2019-01-02 18:57:35 +01:00
output,
output_s)
end
2018-11-17 17:48:47 +01:00
2018-12-19 18:36:09 +01:00
fs[#fs + 1] = get_tooltip(output_s)
2018-11-17 17:48:47 +01:00
local output_is_fuel = get_fueltime(output) > 0
2018-11-17 17:48:47 +01:00
if output_is_fuel then
2019-01-02 18:57:35 +01:00
fs[#fs + 1] = fmt("image[%f,%f;%f,%f;%s]",
output_X + 1,
iY + (sfinv_only and 2.83 or 2.33),
0.6,
0.4,
"craftguide_arrow.png")
2018-11-17 17:48:47 +01:00
2019-01-02 18:57:35 +01:00
fs[#fs + 1] = fmt("image[%f,%f;%f,%f;%s]",
output_X + 1.6,
iY + (sfinv_only and 2.68 or 2.18),
0.6,
0.6,
"craftguide_fire.png")
2018-11-17 17:48:47 +01:00
end
2018-12-19 18:36:09 +01:00
return concat(fs)
2016-12-10 23:15:02 +01:00
end
2019-01-13 01:48:14 +01:00
local function make_formspec(player_name)
2019-01-08 20:28:53 +01:00
local data = player_data[player_name]
2018-11-11 22:24:48 +01:00
local iY = sfinv_only and 4 or data.iX - 5
local ipp = data.iX * iY
2016-12-24 21:17:32 +01:00
2016-12-17 23:03:46 +01:00
data.pagemax = max(1, ceil(#data.items / ipp))
2016-12-17 21:16:10 +01:00
2018-12-19 18:36:09 +01:00
local fs = {}
2018-11-11 22:24:48 +01:00
if not sfinv_only then
2018-12-19 18:36:09 +01:00
fs[#fs + 1] = "size[" .. (data.iX - 0.35) .. "," .. (iY + 4) .. ";]"
2019-01-13 01:18:41 +01:00
fs[#fs + 1] = "no_prepend[]"
2019-01-13 02:31:55 +01:00
fs[#fs + 1] = "background[1,1;1,1;craftguide_bg.png;true]"
2018-12-19 18:36:09 +01:00
fs[#fs + 1] = "tooltip[size_inc;" .. S("Increase window size") .. "]"
fs[#fs + 1] = "tooltip[size_dec;" .. S("Decrease window size") .. "]"
fs[#fs + 1] = "image_button[" .. (data.iX * 0.47) ..
",0.12;0.8,0.8;craftguide_zoomin_icon.png;size_inc;]"
fs[#fs + 1] = "image_button[" .. ((data.iX * 0.47) + 0.6) ..
2018-11-25 15:51:01 +01:00
",0.12;0.8,0.8;craftguide_zoomout_icon.png;size_dec;]"
2018-11-11 22:24:48 +01:00
end
2018-12-19 18:36:09 +01:00
fs[#fs + 1] = [[
image_button[2.4,0.12;0.8,0.8;craftguide_search_icon.png;search;]
image_button[3.05,0.12;0.8,0.8;craftguide_clear_icon.png;clear;]
field_close_on_enter[filter;false]
]]
fs[#fs + 1] = "tooltip[search;" .. S("Search") .. "]"
fs[#fs + 1] = "tooltip[clear;" .. S("Reset") .. "]"
fs[#fs + 1] = "tooltip[prev;" .. S("Previous page") .. "]"
fs[#fs + 1] = "tooltip[next;" .. S("Next page") .. "]"
fs[#fs + 1] = "image_button[" .. (data.iX - (sfinv_only and 2.6 or 3.1)) ..
",0.12;0.8,0.8;craftguide_prev_icon.png;prev;]"
2019-01-02 18:57:35 +01:00
fs[#fs + 1] = "label[" .. (data.iX - (sfinv_only and 1.7 or 2.2)) ..
",0.22;" .. colorize(data.pagenum) .. " / " .. data.pagemax .. "]"
2018-12-19 18:36:09 +01:00
fs[#fs + 1] = "image_button[" .. (data.iX - (sfinv_only and 0.7 or 1.2) -
(data.iX >= 11 and 0.08 or 0)) ..
",0.12;0.8,0.8;craftguide_next_icon.png;next;]"
fs[#fs + 1] = "field[0.3,0.32;2.5,1;filter;;" .. mt.formspec_escape(data.filter) .. "]"
2016-02-21 00:42:52 +01:00
2018-11-17 17:48:47 +01:00
local xoffset = data.iX / 2.15
2016-12-24 19:20:10 +01:00
if not next(data.items) then
2019-01-02 18:57:35 +01:00
fs[#fs + 1] = fmt("label[%f,%f;%s]",
(data.iX / 2) - 1,
2,
S("No item to show"))
end
local first_item = (data.pagenum - 1) * ipp
for i = first_item, first_item + ipp - 1 do
2017-03-21 14:26:58 +01:00
local name = data.items[i + 1]
2018-12-30 21:17:21 +01:00
if not name then
break
end
local X = i % data.iX
local Y = (i % ipp - X) / data.iX + 1
2019-01-15 14:38:15 +01:00
fs[#fs + 1] = fmt("item_image_button[%f,%f;%f,%f;%s;%s_inv;]",
2019-01-02 18:57:35 +01:00
X - (sfinv_only and 0 or (X * 0.05)),
Y,
2019-01-09 21:11:06 +01:00
1.1,
1.1,
2019-01-02 18:57:35 +01:00
name,
name)
2016-02-21 00:42:52 +01:00
end
2018-12-30 21:17:21 +01:00
if data.input and reg_items[data.input] then
local usage = data.show_usage
fs[#fs + 1] = get_recipe_fs(data.iX,
iY,
xoffset,
data.rnum,
(usage and data.usages or data.recipes_item),
usage)
2016-02-21 00:42:52 +01:00
end
2016-03-17 01:10:34 +01:00
2018-12-19 18:36:09 +01:00
fs = concat(fs)
2018-11-11 22:24:48 +01:00
if sfinv_only then
2018-12-19 18:36:09 +01:00
return fs
2018-11-11 22:24:48 +01:00
else
data.formspec = fs
2018-11-11 22:24:48 +01:00
end
2016-02-21 00:42:52 +01:00
end
2018-12-17 01:02:19 +01:00
local show_fs = function(player, player_name)
if sfinv_only then
local context = sfinv.get_or_create_context(player)
sfinv.set_player_inventory_formspec(player, context)
else
2019-01-13 01:48:14 +01:00
make_formspec(player_name)
local data = player_data[player_name]
show_formspec(player_name, "craftguide", data.formspec)
2018-12-17 01:02:19 +01:00
end
end
local function filter_items(data)
local filter = data.filter
2019-01-08 20:28:53 +01:00
if searches[filter] then
data.items = searches[filter]
return
end
local items_list = progressive_mode and data.progressive_items or init_items
2019-01-11 01:54:17 +01:00
local filtered_list, c = {}, 0
2016-12-17 17:39:22 +01:00
2018-03-08 17:06:53 +01:00
for i = 1, #items_list do
2016-12-17 21:16:10 +01:00
local item = items_list[i]
2016-12-24 17:59:42 +01:00
local item_desc = reg_items[item].description:lower()
if item:find(filter, 1, true) or item_desc:find(filter, 1, true) then
c = c + 1
filtered_list[c] = item
2016-12-17 17:39:22 +01:00
end
end
2016-12-24 21:17:32 +01:00
if not progressive_mode then
-- Cache the results only if searched 2 times
2019-01-08 20:28:53 +01:00
if searches[filter] == nil then
searches[filter] = false
else
2019-01-08 20:28:53 +01:00
searches[filter] = filtered_list
end
2016-12-24 21:17:32 +01:00
end
2016-12-17 21:16:10 +01:00
data.items = filtered_list
2016-02-21 00:42:52 +01:00
end
local function item_in_recipe(item, recipe)
local item_groups = reg_items[item].groups
for _, recipe_item in pairs(recipe.items) do
if recipe_item == item then
return true
elseif recipe_item:sub(1,6) == "group:" then
local groups = extract_groups(recipe_item)
if item_has_groups(item_groups, groups) then
return true
end
end
end
end
2018-12-17 01:02:19 +01:00
local function get_item_usages(item)
local usages = {}
for name, def in pairs(reg_items) do
2018-11-11 14:19:19 +01:00
if not (def.groups.not_in_craft_guide == 1 or
def.groups.not_in_creative_inventory == 1) and
get_recipe(name).items and
def.description and def.description ~= "" then
local recipes = get_recipes(name)
for i = 1, #recipes do
local recipe = recipes[i]
if item_in_recipe(item, recipe) then
usages[#usages + 1] = recipe
end
end
end
end
return usages
end
local function get_inv_items(player)
local invlist = player:get_inventory():get_list("main")
local inv_items = {}
for i = 1, #invlist do
local stack = invlist[i]
if not stack:is_empty() then
inv_items[#inv_items + 1] = stack:get_name()
end
end
return inv_items
end
local function progressive_show_recipe(recipe, inv_items)
local inv_items_size = #inv_items
for _, item in pairs(recipe.items) do
local item_in_inv
if item:sub(1,6) == "group:" then
local groups = extract_groups(item)
for i = 1, inv_items_size do
local item_def = reg_items[inv_items[i]]
if item_def then
local item_groups = item_def.groups
if item_has_groups(item_groups, groups) then
item_in_inv = true
end
end
end
else
for i = 1, inv_items_size do
if inv_items[i] == item then
item_in_inv = true
end
end
end
if not item_in_inv then
return
end
end
return true
end
local function progressive_default_filter(recipes, player)
local inv_items = get_inv_items(player)
if #inv_items == 0 then
return {}
end
local filtered = {}
for i = 1, #recipes do
local recipe = recipes[i]
if progressive_show_recipe(recipe, inv_items) then
filtered[#filtered + 1] = recipe
end
end
return filtered
end
local progressive_filters = {{
name = "Default filter",
func = progressive_default_filter,
}}
function craftguide.add_progressive_filter(name, func)
progressive_filters[#progressive_filters + 1] = {
name = name,
func = func,
}
end
function craftguide.set_progressive_filter(name, func)
progressive_filters = {{
name = name,
func = func,
}}
end
function craftguide.get_progressive_filters()
return progressive_filters
end
local function apply_progressive_filters(recipes, player)
for i = 1, #progressive_filters do
local func = progressive_filters[i].func
recipes = func(recipes, player)
end
return recipes
end
local function get_progressive_items(player)
local items = {}
for i = 1, #init_items do
local item = init_items[i]
local recipes = get_recipes(item)
recipes = apply_progressive_filters(recipes, player)
if #recipes > 0 then
items[#items + 1] = item
end
end
return items
end
local function init_data(player, name)
local p_items = progressive_mode and get_progressive_items(player) or nil
player_data[name] = {
filter = "",
pagenum = 1,
iX = sfinv_only and 8 or DEFAULT_SIZE,
items = p_items or init_items,
progressive_items = p_items,
}
end
local function reset_data(data)
data.show_usage = nil
data.filter = ""
data.input = nil
data.pagenum = 1
data.rnum = 1
data.items = progressive_mode and data.progressive_items or init_items
end
local function get_init_items()
local c = 0
for name, def in pairs(reg_items) do
local is_fuel = get_fueltime(name) > 0
if not (def.groups.not_in_craft_guide == 1 or
def.groups.not_in_creative_inventory == 1) and
(get_recipe(name).items or is_fuel) and
def.description and def.description ~= "" then
c = c + 1
init_items[c] = name
end
end
sort(init_items)
end
mt.register_on_mods_loaded(get_init_items)
2018-11-11 22:24:48 +01:00
local function get_fields(player, ...)
2018-11-12 12:51:18 +01:00
local args, formname, fields = {...}
if sfinv_only then
2018-11-11 22:24:48 +01:00
fields = args[1]
else
2018-11-12 12:51:18 +01:00
formname, fields = args[1], args[2]
2018-11-11 22:24:48 +01:00
end
2018-12-30 21:00:04 +01:00
if not sfinv_only and formname ~= "craftguide" then
return
end
2016-02-21 00:42:52 +01:00
local player_name = player:get_player_name()
2019-01-08 20:28:53 +01:00
local data = player_data[player_name]
2016-02-21 00:42:52 +01:00
if fields.clear then
2019-01-08 20:28:53 +01:00
reset_data(data)
show_fs(player, player_name)
2017-03-21 14:26:58 +01:00
2016-02-21 00:42:52 +01:00
elseif fields.alternate then
if #(data.show_usage and data.usages or data.recipes_item) == 1 then
2018-12-30 21:00:04 +01:00
return
end
local next_i
if data.show_usage then
2018-12-30 21:00:04 +01:00
next_i = data.usages[data.rnum + 1]
else
2018-12-30 21:00:04 +01:00
next_i = data.recipes_item[data.rnum + 1]
end
2018-12-30 21:00:04 +01:00
data.rnum = next_i and data.rnum + 1 or 1
show_fs(player, player_name)
2017-03-21 14:26:58 +01:00
2016-12-24 03:27:41 +01:00
elseif (fields.key_enter_field == "filter" or fields.search) and
fields.filter ~= "" then
2019-01-11 01:54:17 +01:00
local fltr = fields.filter:lower()
if not progressive_mode and data.filter == fltr then
2019-01-11 01:54:17 +01:00
return
end
data.filter = fltr
data.pagenum = 1
filter_items(data)
show_fs(player, player_name)
2017-03-21 14:26:58 +01:00
2016-02-21 00:42:52 +01:00
elseif fields.prev or fields.next then
data.pagenum = data.pagenum - (fields.prev and 1 or -1)
2016-12-17 23:03:46 +01:00
if data.pagenum > data.pagemax then
data.pagenum = 1
elseif data.pagenum == 0 then
2016-12-17 23:03:46 +01:00
data.pagenum = data.pagemax
end
show_fs(player, player_name)
2017-03-21 14:26:58 +01:00
elseif (fields.size_inc and data.iX < MAX_LIMIT) or
(fields.size_dec and data.iX > MIN_LIMIT) then
data.pagenum = 1
data.iX = data.iX - (fields.size_dec and 1 or -1)
show_fs(player, player_name)
2017-03-21 14:26:58 +01:00
2016-12-22 21:47:07 +01:00
else for item in pairs(fields) do
if item:find(":") then
2019-01-15 14:38:15 +01:00
if item:sub(-4) == "_inv" then
item = item:sub(1,-5)
end
2016-12-24 17:59:42 +01:00
local is_fuel = get_fueltime(item) > 0
local recipes = get_recipes(item)
2019-01-15 14:38:15 +01:00
if progressive_mode then
recipes = apply_progressive_filters(recipes, player)
end
2016-12-11 20:41:37 +01:00
local no_recipes = not next(recipes)
if no_recipes and (progressive_mode or not is_fuel) then
2018-12-30 21:00:04 +01:00
return
end
2018-12-30 21:17:21 +01:00
if item ~= data.input then
2019-01-02 18:57:35 +01:00
data.show_usage = nil
else
data.show_usage = not data.show_usage
end
2019-01-02 18:57:35 +01:00
if not progressive_mode and is_fuel and no_recipes then
data.show_usage = true
end
if data.show_usage then
2018-12-17 01:02:19 +01:00
data.usages = get_item_usages(item)
if is_fuel then
data.usages[#data.usages + 1] = {
width = 1,
type = "normal",
items = {item},
output = "BURN",
}
end
if progressive_mode and next(data.usages) then
data.usages =
apply_progressive_filters(data.usages, player)
end
if not next(data.usages) then
data.show_usage = nil
2018-12-30 21:00:04 +01:00
end
end
2018-12-30 21:17:21 +01:00
data.input = item
data.recipes_item = recipes
data.rnum = 1
show_fs(player, player_name)
end
2016-12-22 21:47:07 +01:00
end
2016-02-21 00:42:52 +01:00
end
2018-11-11 22:24:48 +01:00
end
2016-02-21 00:42:52 +01:00
2018-11-11 22:24:48 +01:00
if sfinv_only then
sfinv.register_page("craftguide:craftguide", {
title = "Craft Guide",
2019-01-02 18:57:35 +01:00
2018-11-11 22:24:48 +01:00
get = function(self, player, context)
local player_name = player:get_player_name()
return sfinv.make_formspec(
player,
context,
2019-01-13 01:48:14 +01:00
make_formspec(player_name)
2018-11-11 22:24:48 +01:00
)
end,
2019-01-02 18:57:35 +01:00
2018-11-11 22:24:48 +01:00
on_enter = function(self, player, context)
local player_name = player:get_player_name()
2019-01-08 20:28:53 +01:00
local data = player_data[player_name]
2017-01-30 05:24:03 +01:00
if not data then
2019-01-08 20:28:53 +01:00
init_data(player, player_name)
elseif progressive_mode then
data.progressive_items = get_progressive_items(player)
filter_items(data)
2018-11-11 22:24:48 +01:00
end
end,
2019-01-02 18:57:35 +01:00
2018-11-11 22:24:48 +01:00
on_player_receive_fields = function(self, player, context, fields)
get_fields(player, fields)
end,
})
else
mt.register_on_player_receive_fields(get_fields)
2018-12-17 01:02:19 +01:00
local function on_use(itemstack, user)
2018-11-11 22:24:48 +01:00
local player_name = user:get_player_name()
2019-01-08 20:28:53 +01:00
local data = player_data[player_name]
2017-01-30 05:24:03 +01:00
if not data then
2019-01-08 20:28:53 +01:00
init_data(user, player_name)
2019-01-13 01:48:14 +01:00
make_formspec(player_name)
data = player_data[player_name]
elseif progressive_mode then
data.progressive_items = get_progressive_items(user)
filter_items(data)
2019-01-13 01:48:14 +01:00
make_formspec(player_name)
2018-11-11 22:24:48 +01:00
end
show_formspec(player_name, "craftguide", data.formspec)
2016-02-21 00:42:52 +01:00
end
2018-11-11 22:24:48 +01:00
mt.register_craftitem("craftguide:book", {
description = S("Crafting Guide"),
inventory_image = "craftguide_book.png",
wield_image = "craftguide_book.png",
stack_max = 1,
groups = {book = 1},
on_use = function(itemstack, user)
2018-12-17 01:02:19 +01:00
on_use(itemstack, user)
2018-11-11 22:24:48 +01:00
end
})
2016-02-21 00:42:52 +01:00
2018-11-11 22:24:48 +01:00
mt.register_node("craftguide:sign", {
description = S("Crafting Guide Sign"),
drawtype = "nodebox",
tiles = {"craftguide_sign.png"},
inventory_image = "craftguide_sign_inv.png",
wield_image = "craftguide_sign_inv.png",
paramtype = "light",
paramtype2 = "wallmounted",
sunlight_propagates = true,
2019-01-18 15:56:52 +01:00
groups = {oddly_breakable_by_hand = 1, flammable = 3},
2018-11-11 22:24:48 +01:00
node_box = {
type = "wallmounted",
wall_top = {-0.4375, 0.4375, -0.3125, 0.4375, 0.5, 0.3125},
wall_bottom = {-0.4375, -0.5, -0.3125, 0.4375, -0.4375, 0.3125},
wall_side = {-0.5, -0.3125, -0.4375, -0.4375, 0.3125, 0.4375}
},
2019-01-02 18:57:35 +01:00
2018-11-11 22:24:48 +01:00
on_construct = function(pos)
2018-12-16 23:20:54 +01:00
local meta = mt.get_meta(pos)
2018-11-11 22:24:48 +01:00
meta:set_string("infotext", S("Crafting Guide Sign"))
end,
2019-01-02 18:57:35 +01:00
2018-11-11 22:24:48 +01:00
on_rightclick = function(pos, node, user, itemstack)
2018-12-17 01:02:19 +01:00
on_use(itemstack, user)
2018-11-11 22:24:48 +01:00
end
})
2016-12-13 17:30:43 +01:00
2018-11-11 22:24:48 +01:00
mt.register_craft({
output = "craftguide:book",
type = "shapeless",
recipe = {"default:book"}
})
2017-01-30 05:24:03 +01:00
2018-11-11 22:24:48 +01:00
mt.register_craft({
type = "fuel",
recipe = "craftguide:book",
burntime = 3
})
mt.register_craft({
output = "craftguide:sign",
type = "shapeless",
recipe = {"default:sign_wall_wood"}
})
mt.register_craft({
type = "fuel",
recipe = "craftguide:sign",
burntime = 10
})
2017-01-30 05:24:03 +01:00
2018-12-17 01:02:19 +01:00
if rawget(_G, "sfinv_buttons") then
sfinv_buttons.register_button("craftguide", {
title = S("Crafting Guide"),
tooltip = S("Shows a list of available crafting recipes, cooking recipes and fuels"),
2019-01-02 18:57:35 +01:00
image = "craftguide_book.png",
2018-12-17 01:02:19 +01:00
action = function(player)
on_use(nil, player)
end,
})
end
2017-03-19 21:12:49 +01:00
end
if not progressive_mode then
2018-12-16 23:20:54 +01:00
mt.register_chatcommand("craft", {
description = S("Show recipe(s) of the pointed node"),
func = function(name)
2018-12-16 23:20:54 +01:00
local player = mt.get_player_by_name(name)
local ppos = player:get_pos()
local dir = player:get_look_dir()
local eye_h = {x = ppos.x, y = ppos.y + 1.625, z = ppos.z}
local node_name
for i = 1, 10 do
local look_at = vector_add(eye_h, vector_mul(dir, i))
2018-12-16 23:20:54 +01:00
local node = mt.get_node(look_at)
if node.name ~= "air" then
node_name = node.name
break
end
end
if not node_name then
2019-01-02 18:57:35 +01:00
return false, colorize("[craftguide] ", "red") ..
S("No node pointed")
2019-01-08 20:28:53 +01:00
elseif not player_data[name] then
init_data(player, name)
end
2019-01-08 20:28:53 +01:00
local data = player_data[name]
reset_data(data)
local is_fuel = get_fueltime(node_name) > 0
local recipes = get_recipes(node_name)
local no_recipes = not next(recipes)
if no_recipes and not is_fuel then
2018-12-30 21:10:39 +01:00
return false, colorize("[craftguide] ", "red") ..
S("No recipe for this node:") .. " " ..
colorize(node_name)
end
if is_fuel and no_recipes then
data.usages = get_item_usages(node_name)
if is_fuel then
data.usages[#data.usages + 1] = {
width = 1,
type = "normal",
items = {node_name},
output = "BURN",
}
end
if next(data.usages) then
data.show_usage = true
end
end
2019-01-02 18:57:35 +01:00
data.input = node_name
data.recipes_item = recipes
2018-12-16 23:20:54 +01:00
return true, show_fs(player, name)
end,
})
end
2018-04-27 22:18:18 +02:00
--[[ Custom recipes (>3x3) test code
mt.register_craftitem(":secretstuff:custom_recipe_test", {
2018-04-27 22:18:18 +02:00
description = "Custom Recipe Test",
})
local cr = {}
for x = 1, 6 do
cr[x] = {}
for i = 1, 10 - x do
cr[x][i] = {}
for j = 1, 10 - x do
cr[x][i][j] = "group:sand"
2018-04-27 22:18:18 +02:00
end
end
mt.register_craft({
output = "secretstuff:custom_recipe_test",
2018-04-27 22:18:18 +02:00
recipe = cr[x]
})
end
]]