Done! export & craft recipes

This commit is contained in:
Jean-Patrick Guerrero 2020-12-08 16:05:25 +01:00
parent 3bbb014ec0
commit 25874d6f6d
7 changed files with 329 additions and 136 deletions

465
init.lua
View File

@ -58,7 +58,9 @@ local sprintf, find, gmatch, match, sub, split, upper, lower =
string.sub, string.split, string.upper, string.lower
local min, max, floor, ceil, abs = math.min, math.max, math.floor, math.ceil, math.abs
local pairs, ipairs, next, type, setmetatable = pairs, ipairs, next, type, setmetatable
local pairs, ipairs, next, type, setmetatable, tonum =
pairs, ipairs, next, type, setmetatable, tonumber
local vec_add, vec_mul = vector.add, vector.multiply
local ROWS, _ROWS = 9
@ -66,6 +68,7 @@ local LINES = 10
local IPP = ROWS * LINES
local MAX_FAVS = 6
local ITEM_BTN_SIZE = 1.1
local SPACING = 0
-- Progressive mode
local POLL_FREQ = 0.25
@ -106,6 +109,7 @@ local fs_elements = {
model = "model[%f,%f;%f,%f;%s;%s;%s;0,0;true]",
image_button = "image_button[%f,%f;%f,%f;%s;%s;%s]",
animated_image = "animated_image[%f,%f;%f,%f;;%s;%u;%u]",
scrollbar = "scrollbar[%f,%f;%f,%f;horizontal;%s;%u]",
item_image_button = "item_image_button[%f,%f;%f,%f;%s;%s;%s]",
arrow = "image_button[%f,%f;0.7,0.7;%s;%s;;;false;%s]",
}
@ -113,7 +117,6 @@ local fs_elements = {
local styles = sprintf([[
style_type[label,field;font_size=+0]
style_type[image_button;border=false;sound=craftguide_click]
style_type[button;border=false;font=bold;font_size=+2;content_offset=0]
style_type[item_image_button;border=false;bgimg_hovered=%s;bgimg_pressed=%s;sound=craftguide_click]
style[filter;border=false]
@ -125,6 +128,9 @@ local styles = sprintf([[
style[next_recipe;fgimg=%s;fgimg_hovered=%s;fgimg_pressed=%s]
style[prev_usage;fgimg=%s;fgimg_hovered=%s;fgimg_pressed=%s]
style[next_usage;fgimg=%s;fgimg_hovered=%s;fgimg_pressed=%s]
style[pagenum,no_item,no_rcp;border=false;font=bold;font_size=+2;content_offset=0]
style[craft_rcp,craft_usg;border=false;noclip=true;font_size=+0;sound=craftguide_click;bgimg=craftguide_btn9.png;
bgimg_hovered=craftguide_btn9_hovered.png;bgimg_pressed=craftguide_btn9_pressed.png;bgimg_middle=4,6]
]],
PNG.selected, PNG.selected,
PNG.search, PNG.search_hover,
@ -791,6 +797,142 @@ local function groups_to_items(groups, get_all)
return get_all and names or ""
end
local function get_stack_max(data, is_recipe, rcp)
local inv = data.player:get_inventory()
local list = inv:get_list("main")
local size = inv:get_size("main")
local counts_inv, counts_rcp, counts = {}, {}, {}
local rcp_usg = is_recipe and "recipe" or "usage"
for _, it in pairs(rcp.items) do
counts_rcp[it] = (counts_rcp[it] or 0) + 1
end
data.export_counts[rcp_usg] = {}
data.export_counts[rcp_usg].rcp = counts_rcp
for i = 1, size do
local stack = list[i]
if not stack:is_empty() then
local item = stack:get_name()
local count = stack:get_count()
for name in pairs(counts_rcp) do
if is_group(name) then
local def = reg_items[item]
local groups = extract_groups(name)
if item_has_groups(def.groups, groups) then
counts_inv[name] = (counts_inv[name] or 0) + count
end
end
end
counts_inv[item] = (counts_inv[item] or 0) + count
end
end
data.export_counts[rcp_usg].inv = counts_inv
for name in pairs(counts_rcp) do
counts[name] = floor((counts_inv[name] or 0) / (counts_rcp[name] or 0))
end
local max_stacks = math.huge
for _, count in pairs(counts) do
if count < max_stacks then
max_stacks = count
end
end
return max_stacks
end
local function craft_stack(player, pname, data, _f)
local inv = player:get_inventory()
local rcp_usg = _f.craft_rcp and "recipe" or "usage"
local output = _f.craft_rcp and
data.recipes[data.rnum].output or data.usages[data.unum].output
output = ItemStack(output)
local stackname, stackcount = output:get_name(), output:get_count()
local scrbar_val = data[sprintf("scrbar_%s", _f.craft_rcp and "rcp" or "usg")]
for name, count in pairs(data.export_counts[rcp_usg].rcp) do
if is_group(name) then
local groups = extract_groups(name)
local items = groups_to_items(groups, true)
for _, item in ipairs(items) do
for _name, _count in pairs(data.export_counts[rcp_usg].inv) do
if item == _name and _count >= count then
name = _name
break
end
end
end
end
inv:remove_item("main", sprintf("%s %s", name, count * scrbar_val))
end
local count = stackcount * scrbar_val
local stack = ItemStack(sprintf("%s %s", stackname, count))
local message = clr("#ff0", sprintf("%s x %s", count, stackname))
if inv:room_for_item("main", stack) then
inv:add_item("main", stack)
msg(pname, sprintf("%s added to your inventory!", message))
else
local dir = player:get_look_dir()
local ppos = player:get_pos()
ppos.y = ppos.y + 1.625
local look_at = vec_add(ppos, vec_mul(dir, 1))
core.add_item(look_at, stack)
msg(pname, sprintf("%s crafted!", message))
end
end
local function show_recipes(player, data, _f)
local item
for field in pairs(_f) do
if find(field, ":") then
item = field
break
end
end
if not item then
return
elseif sub(item, -4) == "_inv" then
item = sub(item, 1, -5)
elseif sub(item, 1, 1) == "_" then
item = sub(item, 2)
elseif sub(item, 1, 6) == "group|" then
item = match(item, "([%w:_]+)$")
end
item = reg_aliases[item] or item
if item == data.query_item then return end
local recipes, usages = get_recipes(item, data, player)
if not recipes and not usages then return end
if data.show_usages and not usages then return end
data.query_item = item
data.recipes = recipes
data.usages = usages
data.rnum = 1
data.unum = 1
data.scrbar_rcp = 1
data.scrbar_usg = 1
data.export_rcp = nil
data.export_usg = nil
end
local function repairable(tool)
local def = reg_tools[tool]
return toolrepair and def and def.groups and def.groups.disable_repair ~= 1
@ -927,7 +1069,7 @@ local function get_tooltip(item, info)
return sprintf("tooltip[%s;%s]", item, ESC(tooltip))
end
local function get_output_fs(fs, rcp, shapeless, right, btn_size, _btn_size, spacing)
local function get_output_fs(fs, rcp, shapeless, right, btn_size, _btn_size)
local custom_recipe = craft_types[rcp.type]
if custom_recipe or shapeless or rcp.type == "cooking" then
@ -939,7 +1081,7 @@ local function get_output_fs(fs, rcp, shapeless, right, btn_size, _btn_size, spa
end
local pos_x = right + btn_size + 0.42
local pos_y = spacing + 0.9
local pos_y = SPACING + 0.9
if sub(icon, 1, 18) == "craftguide_furnace" then
fs(fmt("animated_image", pos_x, pos_y, 0.5, 0.5, PNG.furnace_anim, 8, 180))
@ -955,7 +1097,7 @@ local function get_output_fs(fs, rcp, shapeless, right, btn_size, _btn_size, spa
local arrow_X = right + 0.2 + (_btn_size or ITEM_BTN_SIZE)
local X = arrow_X + 1.2
local Y = spacing + 1.4
local Y = SPACING + 1.4
fs(fmt("image", arrow_X, Y + 0.06, 1, 1, PNG.arrow))
@ -994,7 +1136,7 @@ local function get_output_fs(fs, rcp, shapeless, right, btn_size, _btn_size, spa
end
end
local function get_grid_fs(fs, rcp, spacing)
local function get_grid_fs(fs, rcp)
local width = rcp.width or 1
local right, btn_size, _btn_size = 0, ITEM_BTN_SIZE
local cooktime, shapeless
@ -1023,7 +1165,7 @@ local function get_grid_fs(fs, rcp, spacing)
X = X + (X * 0.2) + _ROWS + 3.9
local Y = ceil(i / width) - min(2, rows)
Y = Y + (Y * 0.15) + spacing + 1.4
Y = Y + (Y * 0.15) + SPACING + 1.4
if large_recipe then
btn_size = (3 / width) * (3 / rows) + 0.3
@ -1033,7 +1175,7 @@ local function get_grid_fs(fs, rcp, spacing)
local yi = floor((i - 1) / width)
X = btn_size * xi + _ROWS + 0.3 + (xi * 0.05)
Y = btn_size * yi + spacing + 0.2 + (yi * 0.05)
Y = btn_size * yi + SPACING + 0.2 + (yi * 0.05)
end
if X > right then
@ -1104,10 +1246,10 @@ local function get_grid_fs(fs, rcp, spacing)
fs("style_type[item_image_button;border=false]")
end
get_output_fs(fs, rcp, shapeless, right, btn_size, _btn_size, spacing)
get_output_fs(fs, rcp, shapeless, right, btn_size, _btn_size)
end
local function get_rcp_lbl(fs, data, panel, spacing, rn, is_recipe)
local function get_rcp_lbl(fs, data, panel, rn, is_recipe)
local lbl = ES("Usage @1 of @2", data.unum, rn)
if is_recipe then
@ -1118,27 +1260,69 @@ local function get_rcp_lbl(fs, data, panel, spacing, rn, is_recipe)
local lbl_len = #_lbl:gsub("[\128-\191]", "") -- Count chars, not bytes in UTF-8 strings
local shift = min(0.9, abs(12 - max(12, lbl_len)) * 0.15)
fs(fmt("label", _ROWS + 5.65 - shift, spacing + 3.37, lbl))
fs(fmt("label", _ROWS + 5.65 - shift, SPACING + 3.37, lbl))
if rn > 1 then
local btn_suffix = is_recipe and "recipe" or "usage"
local prev_name = sprintf("prev_%s", btn_suffix)
local next_name = sprintf("next_%s", btn_suffix)
local x_arrow = _ROWS + 4.9
local y_arrow = spacing + 3
local y_arrow = SPACING + 3
fs(fmt("arrow", x_arrow - shift, y_arrow, PNG.prev, prev_name, ""),
fmt("arrow", x_arrow + 2.3, y_arrow, PNG.next, next_name, ""))
end
local rcp = is_recipe and panel.rcp[data.rnum] or panel.rcp[data.unum]
get_grid_fs(fs, rcp, spacing)
get_grid_fs(fs, rcp)
end
local function get_title_fs(query_item, favs, lang_code, fs, spacing)
local function get_model_fs(fs, def, model_alias)
if model_alias then
if model_alias.drawtype == "entity" then
def = reg_entities[model_alias.name]
local init_props = def.initial_properties
def.textures = init_props and init_props.textures or def.textures
def.mesh = init_props and init_props.mesh or def.mesh
else
def = reg_items[model_alias.name]
end
end
local tiles = def.tiles or def.textures or {}
local t = {}
for _, v in ipairs(tiles) do
local _name
if v.color then
local hex = sprintf("%02x", v.color)
while #hex < 8 do
hex = "0" .. hex
end
_name = sprintf("%s^[multiply:%s", v.name,
sprintf("#%s%s", sub(hex, 3), sub(hex, 1, 2)))
elseif v.animation then
_name = sprintf("%s^[verticalframe:%u:0", v.name, v.animation.aspect_h)
end
t[#t + 1] = _name or v.name or v
end
while #t < 6 do
t[#t + 1] = t[#t]
end
fs(fmt("model", _ROWS + 6.6, SPACING + 0.05, 1.3, 1.3, "", def.mesh, concat(t, ",")))
end
local function get_title_fs(fs, query_item, favs, lang_code)
local fav = is_fav(favs, query_item)
local nfavs = #favs
local star_x, star_y, star_size = _ROWS + 0.4, spacing + 0.5, 0.4
local star_x, star_y, star_size = _ROWS + 0.4, SPACING + 0.5, 0.4
if nfavs < MAX_FAVS or (nfavs == MAX_FAVS and fav) then
local fav_marked = sprintf("craftguide_fav%s.png", fav and "_off" or "")
@ -1156,62 +1340,97 @@ local function get_title_fs(query_item, favs, lang_code, fs, spacing)
end
fs("style_type[label;font=bold;font_size=+6]",
fmt("label", _ROWS + 1.05, spacing + 0.47, snip(ESC(get_desc(query_item, lang_code)), 32)),
fmt("label", _ROWS + 1.05, SPACING + 0.47, snip(ESC(get_desc(query_item, lang_code)), 32)),
"style_type[label;font=mono;font_size=+0]",
fmt("label", _ROWS + 1.05, spacing + 0.97, clr("#7bf", snip(query_item, 34))),
fmt("label", _ROWS + 1.05, SPACING + 0.97, clr("#7bf", snip(query_item, 34))),
"style_type[label;font=normal]")
local def = reg_items[query_item]
local model_alias = craftguide.model_alias[query_item]
if def.drawtype == "mesh" or model_alias then
if model_alias then
if model_alias.drawtype == "entity" then
def = reg_entities[model_alias.name]
local init_props = def.initial_properties
def.textures = init_props and init_props.textures or def.textures
def.mesh = init_props and init_props.mesh or def.mesh
else
def = reg_items[model_alias.name]
end
end
local tiles = def.tiles or def.textures or {}
local t = {}
for _, v in ipairs(tiles) do
local _name
if v.color then
local hex = sprintf("%02x", v.color)
while #hex < 8 do
hex = "0" .. hex
end
_name = sprintf("%s^[multiply:%s", v.name,
sprintf("#%s%s", sub(hex, 3), sub(hex, 1, 2)))
elseif v.animation then
_name = sprintf("%s^[verticalframe:%u:0", v.name,
v.animation.aspect_h)
end
t[#t + 1] = _name or v.name or v
end
while #t < 6 do
t[#t + 1] = t[#t]
end
--fs("style_type[model;bgcolor=black]")
fs(fmt("model", _ROWS + 6.6, spacing + 0.05, 1.3, 1.3, "", def.mesh, concat(t, ",")))
get_model_fs(fs, def, model_alias)
else
fs(fmt("item_image", _ROWS + 6.8, spacing + 0.17, 1.1, 1.1, query_item))
fs(fmt("item_image", _ROWS + 6.8, SPACING + 0.17, 1.1, 1.1, query_item))
end
end
local function get_panels(data, fs)
local function get_export_fs(fs, data, panel, is_recipe, is_usage, max_stacks_rcp, max_stacks_usg)
local name = is_recipe and "rcp" or "usg"
local show_export = (is_recipe and data.export_rcp) or (is_usage and data.export_usg)
fs(sprintf("style[export_%s;fgimg=%s;fgimg_hovered=%s;fgimg_pressed=%s]",
name, sprintf("craftguide_export%s.png", show_export and "" or "_off"),
"craftguide_export.png", "craftguide_export.png"),
fmt("image_button",
_ROWS + 7.35, SPACING + 0.2, 0.45, 0.45, "", sprintf("export_%s", name), ""),
sprintf("tooltip[export_%s;%s]", name, ES"Craft this item"))
if not show_export then return end
local item = (is_recipe and panel.rcp[data.rnum].output) or
(is_usage and panel.rcp[data.unum].output)
item = clean_name(item)
local _name = match(item, "%S*")
local stack = ItemStack(_name)
local stack_max = stack:get_stack_max()
local stack_fs = (is_recipe and data.scrbar_rcp) or (is_usage and data.scrbar_usg) or 1
fs(sprintf("style[scrbar_%s;noclip=true]", name),
sprintf("scrollbaroptions[min=1;max=%u;smallstep=1]",
min((is_recipe and max_stacks_rcp or max_stacks_usg), stack_max)),
fmt("scrollbar", _ROWS + 8.1, SPACING, 3, 0.35, sprintf("scrbar_%s", name), stack_fs),
fmt("button", _ROWS + 8.1, SPACING + 0.4, 3, 0.7, sprintf("craft_%s", name),
sprintf("%s", stack_fs == 1 and ES"Craft stack" or
sprintf(ES"Craft %u stacks", stack_fs))))
end
local function get_rcp_extra(fs, data, panel, is_recipe, is_usage)
local rn = panel.rcp and #panel.rcp
if rn then
local rcp_normal = is_recipe and panel.rcp[data.rnum].type == "normal"
local usg_normal = is_usage and panel.rcp[data.unum].type == "normal"
local max_stacks_rcp, max_stacks_usg = 0, 0
if rcp_normal then
max_stacks_rcp = get_stack_max(data, is_recipe, panel.rcp[data.rnum])
end
if usg_normal then
max_stacks_usg = get_stack_max(data, is_recipe, panel.rcp[data.unum])
end
if max_stacks_rcp > 0 or max_stacks_usg > 0 then
get_export_fs(fs, data, panel, is_recipe, is_usage, max_stacks_rcp,
max_stacks_usg)
end
get_rcp_lbl(fs, data, panel, rn, is_recipe)
else
local lbl = is_recipe and ES"No recipes" or ES"No usages"
fs(fmt("button",
_ROWS + 0.1, SPACING + (panel.height / 2) - 0.5, 7.8, 1, "no_rcp", lbl))
end
end
local function get_favs(fs, data)
fs(fmt("label", _ROWS + 0.4, SPACING + 0.4, ES"Bookmarks"))
for i = 1, #data.favs do
local item = data.favs[i]
local X = _ROWS - 0.7 + (i * 1.2)
local Y = SPACING + 0.8
if data.query_item == item then
fs(fmt("image", X, Y, ITEM_BTN_SIZE, ITEM_BTN_SIZE, PNG.selected))
end
fs(fmt("item_image_button", X, Y, ITEM_BTN_SIZE, ITEM_BTN_SIZE, item, item, ""))
end
end
local function get_panels(fs, data)
local _title = {name = "title", height = 1.4}
local _favs = {name = "favs", height = 2.2}
local _recipes = {name = "recipes", rcp = data.recipes, height = 3.9}
@ -1219,48 +1438,25 @@ local function get_panels(data, fs)
local panels = {_title, _recipes, _usages, _favs}
for idx = 1, #panels do
local panel, spacing = panels[idx], 0
local panel = panels[idx]
SPACING = 0
if idx > 1 then
for _idx = idx - 1, 1, -1 do
spacing = spacing + panels[_idx].height + 0.1
SPACING = SPACING + panels[_idx].height + 0.1
end
end
local rn = panel.rcp and #panel.rcp
local is_recipe = panel.name == "recipes"
local recipe_or_usage = panel.name == "recipes" or panel.name == "usages"
fs(fmt("bg9", _ROWS + 0.1, SPACING, 7.9, panel.height, PNG.bg_full, 10))
if rn then
get_rcp_lbl(fs, data, panel, spacing, rn, is_recipe)
end
fs(fmt("bg9", _ROWS + 0.1, spacing, 7.9, panel.height, PNG.bg_full, 10))
if recipe_or_usage and not rn then
local lbl = is_recipe and ES"No recipes" or ES"No usages"
fs(fmt("button",
_ROWS + 0.1, spacing + (panel.height / 2) - 0.5, 7.8, 1, "", lbl))
local is_recipe, is_usage = panel.name == "recipes", panel.name == "usages"
if is_recipe or is_usage then
get_rcp_extra(fs, data, panel, is_recipe, is_usage)
elseif panel.name == "title" then
get_title_fs(data.query_item, data.favs, data.lang_code, fs, spacing)
get_title_fs(fs, data.query_item, data.favs, data.lang_code)
elseif panel.name == "favs" then
fs(fmt("label", _ROWS + 0.4, spacing + 0.4, ES"Bookmarks"))
for i = 1, #data.favs do
local item = data.favs[i]
local X = _ROWS - 0.7 + (i * 1.2)
local Y = spacing + 0.8
if data.query_item == item then
fs(fmt("image",
X, Y, ITEM_BTN_SIZE, ITEM_BTN_SIZE, PNG.selected))
end
fs(fmt("item_image_button",
X, Y, ITEM_BTN_SIZE, ITEM_BTN_SIZE, item, item, ""))
end
get_favs(fs, data)
end
end
end
@ -1309,7 +1505,7 @@ local function make_fs(data)
lbl = ES"Collect items to reveal more recipes"
end
fs(fmt("button", 0, 3, _ROWS, 1, "", lbl))
fs(fmt("button", 0, 3, _ROWS, 1, "no_item", lbl))
end
local first_item = (data.pagenum - 1) * IPP
@ -1332,7 +1528,7 @@ local function make_fs(data)
end
if (data.recipes and #data.recipes > 0) or (data.usages and #data.usages > 0) then
get_panels(data, fs)
get_panels(fs, data)
end
return concat(fs)
@ -1562,13 +1758,15 @@ local function init_data(name)
local info = get_player_info(name)
pdata[name] = {
filter = "",
pagenum = 1,
items = init_items,
items_raw = init_items,
favs = {},
lang_code = get_lang_code(info),
fs_version = get_formspec_version(info),
filter = "",
pagenum = 1,
items = init_items,
items_raw = init_items,
favs = {},
export_counts = {},
lang_code = get_lang_code(info),
fs_version = get_formspec_version(info),
player = get_player_by_name(name),
}
end
@ -1577,10 +1775,14 @@ local function reset_data(data)
data.pagenum = 1
data.rnum = 1
data.unum = 1
data.scrbar_rcp = 1
data.scrbar_usg = 1
data.query_item = nil
data.recipes = nil
data.usages = nil
data.show_usages = nil
data.export_rcp = nil
data.export_usg = nil
data.items = data.items_raw
end
@ -1601,16 +1803,23 @@ local function fields(player, _f)
local name = player:get_player_name()
local data = pdata[name]
local scrbar_rcp_CHG = _f.scrbar_rcp and sub(_f.scrbar_rcp, 1, 3) == "CHG"
local scrbar_usg_CHG = _f.scrbar_usg and sub(_f.scrbar_usg, 1, 3) == "CHG"
if _f.clear then
reset_data(data)
elseif _f.prev_recipe or _f.next_recipe then
local num = data.rnum + (_f.prev_recipe and -1 or 1)
data.rnum = data.recipes[num] and num or (_f.prev_recipe and #data.recipes or 1)
data.export_rcp = nil
data.scrbar_rcp = 1
elseif _f.prev_usage or _f.next_usage then
local num = data.unum + (_f.prev_usage and -1 or 1)
data.unum = data.usages[num] and num or (_f.prev_usage and #data.usages or 1)
data.export_usg = nil
data.scrbar_usg = 1
elseif _f.key_enter_field == "filter" or _f.search then
if _f.filter == "" then
@ -1623,6 +1832,7 @@ local function fields(player, _f)
data.filter = str
data.pagenum = 1
search(data)
elseif _f.prev_page or _f.next_page then
@ -1644,38 +1854,22 @@ local function fields(player, _f)
elseif fav then
remove(data.favs, i)
end
elseif _f.export_rcp or _f.export_usg then
if _f.export_rcp then
data.export_rcp = not data.export_rcp
else
data.export_usg = not data.export_usg
end
elseif scrbar_rcp_CHG or scrbar_usg_CHG then
data.scrbar_rcp = _f.scrbar_rcp and tonum(match(_f.scrbar_rcp, "%d+"))
data.scrbar_usg = _f.scrbar_usg and tonum(match(_f.scrbar_usg, "%d+"))
elseif _f.craft_rcp or _f.craft_usg then
craft_stack(player, name, data, _f)
else
local item
for field in pairs(_f) do
if find(field, ":") then
item = field
break
end
end
if not item then
return
elseif sub(item, -4) == "_inv" then
item = sub(item, 1, -5)
elseif sub(item, 1, 1) == "_" then
item = sub(item, 2)
elseif sub(item, 1, 6) == "group|" then
item = match(item, "([%w:_]+)$")
end
item = reg_aliases[item] or item
if item == data.query_item then return end
local recipes, usages = get_recipes(item, data, player)
if not recipes and not usages then return end
if data.show_usages and not usages then return end
data.query_item = item
data.recipes = recipes
data.usages = usages
data.rnum = 1
data.unum = 1
show_recipes(player, data, _f)
end
return true, show_fs(player, name)
@ -1780,8 +1974,7 @@ if progressive_mode then
local def = reg_items[inv_items[i]]
if def then
local item_groups = def.groups
if item_has_groups(item_groups, groups) then
if item_has_groups(def.groups, groups) then
return true
end
end
@ -1795,8 +1988,8 @@ if progressive_mode then
end
end
local function recipe_in_inv(recipe, inv_items)
for _, item in pairs(recipe.items) do
local function recipe_in_inv(rcp, inv_items)
for _, item in pairs(rcp.items) do
if not item_in_inv(item, inv_items) then return end
end

Binary file not shown.

After

Width:  |  Height:  |  Size: 146 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 146 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 146 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.3 KiB

After

Width:  |  Height:  |  Size: 5.1 KiB