From 25874d6f6d7aeee739f5af1e099441bb2794b4f2 Mon Sep 17 00:00:00 2001 From: Jean-Patrick Guerrero Date: Tue, 8 Dec 2020 16:05:25 +0100 Subject: [PATCH] Done! export & craft recipes --- init.lua | 465 +++++++++++++++++++-------- textures/craftguide_btn9.png | Bin 0 -> 146 bytes textures/craftguide_btn9_hovered.png | Bin 0 -> 146 bytes textures/craftguide_btn9_pressed.png | Bin 0 -> 146 bytes textures/craftguide_export.png | Bin 0 -> 8065 bytes textures/craftguide_export_off.png | Bin 0 -> 4992 bytes textures/craftguide_fav_off.png | Bin 5402 -> 5177 bytes 7 files changed, 329 insertions(+), 136 deletions(-) create mode 100644 textures/craftguide_btn9.png create mode 100644 textures/craftguide_btn9_hovered.png create mode 100644 textures/craftguide_btn9_pressed.png create mode 100644 textures/craftguide_export.png create mode 100644 textures/craftguide_export_off.png diff --git a/init.lua b/init.lua index cc0ad91..52c72e6 100644 --- a/init.lua +++ b/init.lua @@ -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 diff --git a/textures/craftguide_btn9.png b/textures/craftguide_btn9.png new file mode 100644 index 0000000000000000000000000000000000000000..34433ac82a89114e0be99fd1f2a9bd1bfdfd0a2e GIT binary patch literal 146 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnF3?v&v(vJfv{s5m4*Z=?j1DUzm@pGrQ1^S1s zuk85)zhDN3XE)M-979hR$B+ufWCbRUMGS0gZmG#C2`UE;WISnNnc~Rg< zaB^>EX>4U6ba`-PAZ2)IW&i+q+O3&ulH)iIg#Ystdj#>836@*``S*7J;xCq3ToNt0=6vy&YO0}eQm*^2o=<?N`2Km^mFG$*&qU9Kj|rnaIdC%HjbuFBG=&Gn5LWc@I-ljXAl~oBNZ|8|h5LMzbACAv zG3Lh-9P(*-AIIx@chDy%f1J6Wz5hD<$@!r@%2nu67L|pVzoLui>i? zpt7A$e){IOU*|adz{C_*P>vyt5YJeN8fqBPa7y;_J7}zN#sY>TEC*&OhL+poZlk zrqDsai-d`hA(0xvX&_~IHosAS?hO)huwl3fASC9fU{hlQtdxZK(Nu_`CQ*`zWKk(j zsuLTNo z?jhKk+sZO`EGyI<`dUMsk^IVirA`4WRdD^RBbqB?hukQzE0iHYG|W*$65N#AEd82E zN8K@Qm5N1im%jR%QWUr3k#m;@q{C0>F?PQy0k)UswJTO_Z8i7Ox&D(L#s29RyS3pdwggJnUZ*CIh?z?vAAjMTS&rjeGyPzL|L}Mw>h+r9cU+==^*uvx zD-tuSCEfU&CpgTdla?HNtz0)Tu2bQb0sNYyd14qvq;3rTf`> zrZkbkw|BLU$GJjO6Ug1=7>DGUi02Y}yQKM5HfRx_pS-(fG&aFUdSLp260Rd@6@tT^ zw`)7DC3Z3)PuygFTE{3leG)Ho`(yBUkD_3}*KGN-6CT4p2eyPx zJD0++Pj7*~Vg}`u%(LZq7J7)CP{hvKJJixwHoIXebEk{YO8J6l^{9cmfRC6|EC94= zarYi}T!1*1IayiS)y9Gr7Ch9`!qJdSo;WGgDT8bH8cJH3bnCGW-Ckji)*FNzWlJqG zQge+O7lF&fpy-|7@K66OCV;`5EFM>|8X8#JV1>mh_(6N*=!62{NA+T!>YfnVibIQe z)84`)i|}zU3X8X>SeL+GFvLZy5}mP!O`I&403UR2UJdWY3=hg!I#;`L->h|Tr{m;g zal;|n2}7ROyG`h$`pWd2lk8es+ATg)t1Owoyhs|8 zsk~i_F+c!#5vEDK)sE2(f^HqYOS3rve;L=Pmjy!0q#FxA0r+;bB0{v_+@NKp*-vPc z8MgSLweRj4%=r-*$g35amL_&*jFr4ueIQzb5OaDe8nwb=#K1*P4ro$0GdZBn(c9uE z8f|tmZjLy$Od=ai*G(sdS70a{@C_Zc=xP?Kk01G<4?>K?)p-q;EJ6E1zFIJD3S1OujiW|nwWek=;Z*(d&YaSO#H8a#r{y{)uXl!!jL5U75 zw*ifC@yue_G_QjdX6nj-Lm;hGiBa(Fpin7YeM>8Y@1$*oTd6GFU%fh`LFgP;UOvN| z0hr3gpa(=Fj(X7g6=ic@5R^X?G++Boh!0YoXiAZUKXhnO^+AWIr6_rkQ4=;fA?|TU zcl#o2tB?j0MO0(yy~XLRCS&S?T+IuIr@Qg)g0$MiX;f_Sq&yM1kU35X4UAuRb)tf{ zyRxrtHi66%;}41*GkU;?Fi2<=(U@9PR2}Q`=%Xx!3PWhdJa&!e2MSXKDn&zy9E5Cf z@G413O0qCYDE9Up2*FC!q*UFQI%X!4W*`OUG{6J-&?G5Jt=1zIT0AfyeIf}p5K0FX zFAp1-QoPe7-9zWAQ8UYY!Z6(xZkNl+9 zvHNt|5QmuBXyO1c%^{SH=Iw!578RGeR;@5H9ZRoJ$<*drTkVw%cn9u{#Fr$i!K zy@;cK{Sm}YV%6G}(6L0S{qulZRCOx`0o7@S!TW-*sWsr1(OVYacv*Y+r5thPPw1LD zyn{3oEIF=C7lzYz50n*Xn=?Xaocy2~M=`a)Qf`u9aZS$sQI9K-e#Y=nq~yd8aR*6{ z$0P9@1qcvl38h^Jn$a^qXP(bKsPsAQYOF>vb2IgGRSF4F8jJ&tfGTZFMh0N*{l#uV zfL>^7%(5^1dL}8CiIp*(eLFu6sPTU=lbe5NCUWibOb}sz?t-a2~t-?;y; zHTrZ!xJh)yq$WkgipC=7frTs%w2{?z48z~0rK4)YvRz0XAVa(@9Xdc^pK8SQ&NF^R zY}0OWhvFEEwpYa;mG>eQjO1n+Cz!yPWTKgY-AtdiRc8|jo^rhQtt&6LsVkHvnkMU# z)1frlSXgey9uYojA)|EXztG^A;!;0r8S)s3O!%}$J4*&7-Ll<#oPhgcnLH*Qk60wQ zH&V&v{;-b57W^z#t`y&v8nZ8YdOEb4HKn5`6qlouu29b!57A%GS|e-Cr!%e3Vv#eX z1;relW9oh1>fM`2ql28*u^5kAV@wouQ?s@ql@$4J8MRDxfa~&aA!ML_I0cW8A_n1j zTwzy|0gjGAXC`Vch0^D7W!O8hOqRZ>J{Z)@*dAEORuouq3-OCFAzvBA-D0N1u==B( z6B2?phI-%^B?F~`mhUZ?u)>jq*M_7K!y-4<}#$YG^53Z=sCM`0L3CM_R;pjz4- zjNnNKTRIMii|Gb2T#^OcNd@V&dG$HpSD~jhi}CXn4+P>!P$sdxK^Aaq*UM}_{>;@E zG9!2qb9}$5$=&A~+(Uer#IaCtM;)C05ox6fRA@NBgN5$91CFSoEhfA0SY7aLz80PL zpaeIyhb|f>ch>kZQ6AD4e!vHtp1+Zdx;NcQ(^PuS)}_<)Ar{cKDD+Xy9vo`rNLUF& z(G1bYkiF^5@L)5n5#$5|Xj4#-97>^F(RP(n2%W^7rrnr`oS8>&c(qL*6yw=<6z{x%AsMg4uOrw8ij#tbph+};sJ8j-Xqn^rx&Z@Ovdx@m|G zkB$eC=wLnyB<&GMHrr^q22J$#C3owDw~sCRlxHtUb!#j!@o2#sl4W6hT0&P}lAFFZ z_V3^>VURntZFmP2O@k-*_6fGrac=9km7aEzYsTX=dsZ)oZCs$btboYdrW8#+lu{9| z2X9!K3yE6W%9}H2GKqF#({?U~dt#Foc6splRDI$MJL!(`RG+hf_Q0;fqq^lrYz3&b zIdCrYj<`f~IwI(?zJA}~mwUglS^*%(6DFz2Z8vPg8IuTQ0uMJ4!EuFLLZit6x1jJD zMGp3@xZM8h5{z9$)7egoqY}Q$S&7|6{jyH5T%#9``)GA~r3U@LC=Vs6x2{g1vcWe>ZDjm(|*Fo zKj``;aw+60gOOtaRcMf1KlmT~?$#xO5FelhrmdYve$jy9q#Py-!rZLegJb1a;N4DE5`r;00v@9M??Vs0RI60puMM) z00009a7bBm0005I0005I0XppC;s5{u2XskIMF->z2o3-x0N>A-000lzNklfD%b;f^Rch82M1W1qs7f@Wa%aTPY5@lP7Y$eX-O5((+%2s}e{++z#F>k4IDv4vq zl}b5w$u=pOS}2MXNl_Aa2n#XTF?)C4lZU=T4k3^PD9R#ztGZ?Y47%_4o$WiPdt_#O zxvRm?mi~#c@;fx*GR|5uoWPI*3zV~5*vE$MJv_PfTkPeJ@9EW}FBv_*to}2f&K#$a zlyTOS;R3J-Ftapu=3L7bY_9S#?~TXABTXLWFYej(gD(^OarZBb&Ahh~d=VG`>jx_t zE;5UQI9<|0?INeff68fo@Zb|L&g)z)pY(3u6gWwildNB|J-|L-80a!wEP_1$Y?P0_3s}*c4E6mXM^&Zn1WWGn22A+ge~RfApXc&>(d& zhQqk23JHh|dVuZz$N?$fz^(yxv)JNv$rh>?IW_e&@>>e*sZkY5Ks z=H-ngiac_^6A*j%zoQBbfC8}5SBAuULgGDP-f&H4P1lHL?b_lQj)XttoBiFuuKTwP z#w_40y|w*s4uv)egTQ{^dEl$SXci)tH*C*C?v`n^ zD%2W_R2nllm#pXqKu&3Em2L=W7IX zdx@NOctQez~>u<8PANUgUAU_r(w}#jm*7{D7IID^wa~TFEkrtCOY; zoW+=V55=ji0B+cq^DIta|;r-b>xHC6EX=_b(W-wtJqTgD(5DCMSfe61AOP+ z5irABeB3MUu3hfhNr?YldY_4uYF3ZRiF#GXarAZJE^~VFb@E$_?B@4BF9Bm5x1Td!KFeZ#oMt>v;;NX%xa;n0GHYAa0wAyq zn3TN_{O>z09-7hPK^4|PLLac>vz}nnnPg7VI9as$>IF_-`#%c9MYi#cyCYzNUvPTy zC^L)askO=^X%%Npj8tICtWA(v(IUUWya$vA@^<5QIe-12SW=hjESDgKoUQ*X0SyGkorAaxClM40m%vCwa( zfGB!P_WOorz+0-@A6@<^t{|ZeW)#@qf4-9^v?cREhh%PbNak5H*MwHuO6IM+e2%w* zpKy3EPaj`d3jvcHZTvf95g}ePGHehV>S$aD#;#FLChbQD# zcz{+|w8s+^-Uj??By3nAncJQ)XXcuYrfbG?c5U%2Zw3)hY*@NI0S(S_Wbubg&Yz~< znkIEMj6`PE9$dD84|$-w{juE(mW|%>B@Zm@u(mo}Tr1>xxJK|RHA1^@*teoQW_^RX zmZRYs@r+F^oF-1{wdWRW2TqR(u`+Gts!tSbD?Lu$6I!X*XR#>7aaDU(B(Ij z>i~1R61TGEYn|D-O+s5TALvMmZ4wsDT+rA{+(7JW9;|B7Q1KVq)( z5iK{5S==61=Yd`y+XsQCyd2%-8E==ba23}Uzq!>Wq05KiBdd7AvRN8CYu@YuQ@p{k zi61fREpNm^7J?OgcHRj*0UYw+xA_<^uCVxT8uaZ**wP`C+Rf9aU=<@xuM;rGagI&= zh?%7}_?9GVyVFJ=-%tB-b$eply-JMV4{J5aoUV|}6JYfSpvlL)G4)?eFP@{B%wyIP zfeV46&?dwIZ}n$=yl?XCMz_f1_Y(>2vO3bK7A@<>$`Q=*i<$pqYVHh;)+~;uz=eV$ zfd;`2fL>BYz#gCZOF)S3E34nh6MC^sGFw|8n4OP~Ed78_r%zIAmPuVhMjA-uWo(eK zHwg7S*dbqA2Rjm-vL5HYU!4N0&nNBFdq8(|apE|Y`V@()$yst;R!Zzqz_Vs{NYY*p zzPL_-a=((W185;~(Nb-UIH_QkD68|591LlmMoS@N~s z0FOh)IbLB~C=CwLEz8mPy#XW;_daz>FcFggxNk zbsc=gq;VPVgB=B(i?9^10J9RX)!+%RgWeOmek&|*B#0_#5_lhR1b82~78w>`*R8(? z<54q4ynu-AGl6qA1f)PsFoifJaTGX-7zb(*SZJbzu{D#owwoJwWrN=e@ZuWMX~9v@ z31#3bpd>Je!1{nuGY(kRK$N`e^MHeIAj-gpf;W)fLwpJ>gAx?D$d|XxS%+skG5Q{G z*Y5;BBlrmEO~i5Fs$dBeOQ8#tw+O7uvPV)LvKvY-_yRX~r@wukZn6!&iI@|7BIy|7 zUEq?$BB&*WE)0s6j|Pa$yfQM|LN=C;?qTfPD(`JYZC?2~tr(lF=UVLtDdq(iklsSP zjkqAR0BTBs3skT|ZitQDyNM(=nz75Wp~k(i{z`!DjkRApkCf{-H?MaV+0@DIcyC~J z@M2ML8R;E~w}4NC=57YRkbs-n$bm-RQ?#Koe*fG=P>M z1qFy+u$=}&Yb2q4y%@11xPtVq#IJ#KNHah~QYz&wA8lY$?*X3O{RfQlG7+!~v(4Cb z(X*cTYXf&HK(~AnstFc>d88#lH4`LMfF+DYuti^zQb7?his|>j3jS_V?l$}B1ivg8 zLwZl*4d5)OENDQGfe!~5?AgoHdtPOfm%Y1*$9)wjuG8h{aO3viu`W>q7C>dhG%yBS z5zKh-EuW;C+2+(VvzD?(rPqUb3ZuEgvvf=FP!WtHosc++I0H-rbqLby4_x;=#FKko zVIQyFbZczCA9>~1;QpP!T?gnTU=AotngYfQE(xw7W`TL2=Jj}rJaNKdq>>B>B~oD7 zj8=zN-L|;_suB}O?*m7HQ@|9cCX`B%i^4tzx_0x}=r?#Y_|uzC6#1tzyVfw*>x}J$ ztgBiOOd?$tTmUYSNzPfB=7Fk@^&3xe=;nMOT{mx(o!8PkfM2QdrjSknM1 zmopM?AiTs?#j8Avf^O?BjId|xArAL{|CT3>FxuHxw{Wu-P(jQJu7J)di?j2-saQa& z0||!nfGw+Np-B-zkSA1uAjlCYLK21}PODhDjBE{04Bi0Wmbm96{Tgu`aTT;I6r<3h zpv$@oTNvH^3@>l|+uOD^k(sTGeOsZY=LJ`h&H*O{AAzp=q*p_!+0OC!Z@31`(-Cs5E9-s*jPRmGxAdCNL-X*h}1ZBrb!NGKm|wAShZXKg{-_ zr})<9@A>;V+{Ob|2cP)tUIspr^e$O~xd4jB^L#yF4kHsWoGi=YL-tGuF>a+}z;;c;Hx z`sZHXu_gjmD=kyNS?^}=0hcq4tp-w(0S`>dSr~Sa5Bn(P2k9ve(bv71%>z5xRv2ZN zy}rtJth{k0Jk$A<(4CTA>?_ViN$((z3C@G&Gw`7cRIp-hkl}$xIK1Oe=;FYdP9CjD zb_r0Cm;^qM^agMOxFTuMC%IIX0gr+b`CLEUg<&@K?qKWSUUroBGR%S7x?UH(Xl0al}cXqlou`F-c3= z--A?&2vx9L)Ju0^n8ChLMz=i9qq(mVF}lW!=00nE-Bbh2YlawTdWn0SOyYhhsoV)Z z9}O_ryPszsdX??#{LVns5noF_*}X3~>SKOFVi|}<=rUo^Ln$}JK=)2|ZGMcWdS9f- zzI9zRxc#i9bA(+1rrY{na0Y1_sEZ(#a+VAGv+oq{eT6-D@vV`lqlLVr8!Ug2DLks} zx*8}OAoLbT*tYQz9vyz35ni~u99|PUH zd3^WFJaU&`sEmAOy{s&=9u=G+)9_UY5-GGWC|NN##9;4U_Kh6k>B6^t_k4FNN1i|- zQjk44cw-i1m=ejV7?UPV2;PKD;tJJ3Nzj(KrCmI{^J_er`|e%uB@(*emDCa744J&F z$;-(w=(4W-Fk3b}#xpx!S$B-B9s>R3bHz*)A&`&>!%{>Y(cQP5-E#ck{udWx@Y`Ocb4%biyr8~V18 zpY5R@=WwopWeq_L%p05)N`R{vlUZd_EV4cImUggj+Y9_o@Ap6VP9o4xvi6ZVpphk) z$VFiVJ1ujCPE8UvaZ4~J2pMZOZ|U&PxtWu#22_{?iHGV P00000NkvXXu0mjfW*|&1 literal 0 HcmV?d00001 diff --git a/textures/craftguide_export_off.png b/textures/craftguide_export_off.png new file mode 100644 index 0000000000000000000000000000000000000000..75708b71503449080b855cf5b4da9e0211fb5500 GIT binary patch literal 4992 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 KMNUMnLSTX@qKaz( literal 0 HcmV?d00001 diff --git a/textures/craftguide_fav_off.png b/textures/craftguide_fav_off.png index b597b7af4cd3668df56d27c2eaa027acba1bb792..c8d53b1a252ed6f6195b8c2a141868a8eafdeb0a 100644 GIT binary patch delta 4815 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 delta 5049 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