local F = minetest.formspec_escape cg.update_filter = function(player, context, filter) if (filter or "") == (context.cg_filter or "") then return end context.cg_page = 0 context.cg_filter = filter cg.filter_items(player, filter) end local make_item_button = function(formspec, x, y, size, name) if name and name ~= "" then local groups, buttonText if name:sub(1, 6) == "group:" then groups = name:sub(7):split(",") buttonText = #groups > 1 and ("G " .. #groups) or "G" name = name:gsub(",", "/") end formspec[#formspec + 1] = string.format("item_image_button[%.2f,%.2f;%.2f,%.2f;%s;cgitem_%s;%s]", x, y, size, size, groups and (cg.group_stereotypes[groups[1]] or "") or name, name:match("^%S+"), -- Keep only the item name, not the quantity. buttonText or "" ) if groups then formspec[#formspec + 1] = string.format("tooltip[cgitem_%s;%s]", name, #groups > 1 and F(cg.S("Any item in groups: @1", minetest.colorize("#72FF63", table.concat(groups, ", ")))) or F(cg.S("Any item in group: @1", minetest.colorize("#72FF63", groups[1]))) ) end else size = size * 0.8 + 0.2 formspec[#formspec + 1] = string.format("image[%.2f,%.2f;%.2f,%.2f;gui_hb_bg.png]", x, y, size, size) end end local make_item_grid = function(formspec, player, context) local itemList = cg.get_item_list(player) context.cg_page = context.cg_page or 0 formspec[#formspec + 1] = [[ image_button[2.4,3.7;0.8,0.8;cg_plus_icon_search.png;cg_search;] image_button[3.1,3.7;0.8,0.8;cg_plus_icon_clear.png;cg_clear;] image_button[5.1,3.7;0.8,0.8;cg_plus_icon_prev.png;cg_prev;] image_button[7.1,3.7;0.8,0.8;cg_plus_icon_next.png;cg_next;] ]] formspec[#formspec + 1] = string.format("label[0,0;%s]", F(cg.S("Crafting Guide"))) formspec[#formspec + 1] = string.format("field[0.3,3.9;2.5,1;cg_filter;;%s]", F(context.cg_filter or "")) formspec[#formspec + 1] = "field_close_on_enter[cg_filter;false]" formspec[#formspec + 1] = string.format("label[6,3.8;%i / %i]", context.cg_page + 1, itemList.num_pages) local startIdx = context.cg_page * cg.PAGE_ITEMS + 1 local item for itemIdx = 0, cg.PAGE_ITEMS - 1 do item = itemList.list[startIdx + itemIdx] if item then formspec[#formspec + 1] = string.format("item_image_button[%.2f,%.2f;1,1;%s;cgitem_%s;]", itemIdx % cg.PAGE_WIDTH, math.floor(itemIdx / cg.PAGE_WIDTH) + 0.5, item, item ) end end end local make_craft_preview = function(formspec, player, context) formspec[#formspec + 1] = [[ image_button[7.1,0.1;0.8,0.8;cg_plus_icon_prev.png;cg_craft_close;] image[0.1,0.1;0.8,0.8;gui_hb_bg.png] ]] local item = context.cg_selected_item formspec[#formspec + 1] = string.format("item_image[0.1,0.1;0.8,0.8;%s]", item) formspec[#formspec + 1] = string.format("label[1,0;%s]", cg.crafts[item] and minetest.registered_items[item].description or item) local crafts = cg.crafts[item] if not crafts or #crafts == 0 then formspec[#formspec + 1] = string.format("label[1,0.5;%s]", F(cg.S("There are no recipes for this item."))) return end if #crafts > 1 then formspec[#formspec + 1] = [[ image_button[1.85,3.7;0.8,0.8;cg_plus_icon_prev.png;cg_craft_prev;] image_button[3.85,3.7;0.8,0.8;cg_plus_icon_next.png;cg_craft_next;] ]] formspec[#formspec + 1] = string.format("label[2.75,3.8;%i / %i]", context.cg_craft_page + 1, #crafts) end local craft = cg.parse_craft(crafts[context.cg_craft_page + 1]) local template = cg.craft_types[craft.type] or {} if cg.autocrafting and template.uses_crafting_grid then formspec[#formspec + 1] = "image_button[0.1,3.7;0.8,0.8;cg_plus_icon_autocrafting.png;cg_auto_menu;]" formspec[#formspec + 1] = string.format("tooltip[cg_auto_menu;%s]", F(cg.S("Craft this recipe"))) if context.cg_auto_menu then local num = 1 local yPos = 3 while true do num = math.min(num, context.cg_auto_max) formspec[#formspec + 1] = string.format("button[0.1,%.2f;0.8,0.8;cg_auto_%i;%i]", yPos, num, num) formspec[#formspec + 1] = string.format( "tooltip[cg_auto_%i;%s]", num, num == 1 and F(cg.S("Craft @1 item", num)) or F(cg.S("Craft @1 items", num)) ) if num < context.cg_auto_max then num = num * 10 yPos = yPos - 0.7 else break end end end end formspec[#formspec + 1] = string.format("label[5,0.5;%s]", template.description or "") formspec[#formspec + 1] = string.format("label[5,1;%s]", craft.infotext or "") formspec[#formspec + 1] = string.format("image[4.75,1.5;1,1;%s]", template.arrow_icon or "cg_plus_arrow.png") local slotSize = math.min(3 / math.max(craft.grid_size.x, craft.grid_size.y), 1) local xOffset = 4.75 - craft.grid_size.x * slotSize local yOffset = 2 - craft.grid_size.y * slotSize * 0.5 for idx = 1, craft.grid_size.x * craft.grid_size.y do make_item_button(formspec, (idx - 1) % craft.grid_size.x * slotSize + xOffset, math.floor((idx - 1) / craft.grid_size.y) * slotSize + yOffset, slotSize, craft.items[idx] ) end make_item_button(formspec, 5.75, 1.5, 1, craft.output) end sfinv.register_page("cg_plus:crafting_guide", { title = "Crafting Guide", get = function(self, player, context) local formspec = {[[ image[0,4.75;1,1;gui_hb_bg.png] image[1,4.75;1,1;gui_hb_bg.png] image[2,4.75;1,1;gui_hb_bg.png] image[3,4.75;1,1;gui_hb_bg.png] image[4,4.75;1,1;gui_hb_bg.png] image[5,4.75;1,1;gui_hb_bg.png] image[6,4.75;1,1;gui_hb_bg.png] image[7,4.75;1,1;gui_hb_bg.png] ]]} if context.cg_selected_item then make_craft_preview(formspec, player, context) else make_item_grid(formspec, player, context) end return sfinv.make_formspec(player, context, table.concat(formspec), true) end, on_player_receive_fields = function(self, player, context, fields) if fields.cg_craft_close then context.cg_selected_item = nil context.cg_craft_page = nil context.cg_auto_menu = false elseif fields.cg_prev and context.cg_page then context.cg_page = context.cg_page - 1 elseif fields.cg_next and context.cg_page then context.cg_page = context.cg_page + 1 elseif fields.cg_craft_prev and context.cg_craft_page then context.cg_craft_page = context.cg_craft_page - 1 context.cg_auto_menu = false elseif fields.cg_craft_next and context.cg_craft_page then context.cg_craft_page = context.cg_craft_page + 1 context.cg_auto_menu = false elseif fields.cg_search or fields.key_enter_field == "cg_filter" then cg.update_filter(player, context, fields.cg_filter) elseif fields.cg_clear then cg.update_filter(player, context, "") elseif fields.cg_auto_menu and cg.autocrafting then if not context.cg_auto_menu then -- Make sure the craft is valid, in case the client is sending fake formspec fields. local crafts = cg.crafts[context.cg_selected_item] or {} local craft = crafts[context.cg_craft_page + 1] if craft and cg.craft_types[craft.type] and cg.craft_types[craft.type].uses_crafting_grid then context.cg_auto_menu = true context.cg_auto_max = cg.auto_get_craftable(player, craft) end else context.cg_auto_menu = false end else for field, _ in pairs(fields) do if field:sub(1, 7) == "cgitem_" then local item = string.sub(field, 8) if item:sub(1, 6) == "group:" then if cg.group_search then cg.update_filter(player, context, item:gsub("/", ",")) context.cg_selected_item = nil context.cg_auto_menu = false elseif cg.group_stereotypes[item:sub(7)] then context.cg_selected_item = cg.group_stereotypes[item:sub(7)] context.cg_craft_page = 0 context.cg_auto_menu = false end elseif item ~= context.cg_selected_item then context.cg_selected_item = item context.cg_craft_page = 0 context.cg_auto_menu = false end break elseif field:sub(1, 8) == "cg_auto_" and cg.autocrafting and context.cg_auto_menu then -- No need to sanity check, we already did that when showing the autocrafting menu. local num = tonumber(field:sub(9)) if num > 0 and num <= context.cg_auto_max then cg.auto_craft(player, cg.crafts[context.cg_selected_item][context.cg_craft_page + 1], num) sfinv.set_page(player, "sfinv:crafting") end context.cg_auto_menu = false break end end end -- Wrap around when the player presses the next button on the last page, or the previous button on the first. if context.cg_page then context.cg_page = context.cg_page % math.max(cg.get_item_list(player).num_pages, 1) end if context.cg_craft_page then context.cg_craft_page = context.cg_craft_page % math.max(#(cg.crafts[context.cg_selected_item] or {}), 1) end -- Update the formspec. sfinv.set_player_inventory_formspec(player, context) end, })