Compare commits

...

14 Commits
1.2 ... 1.3.1

14 changed files with 543 additions and 236 deletions

View File

@ -4,5 +4,7 @@ allow_defined_top = true
read_globals = { read_globals = {
"minetest", "minetest",
"default", "default",
"sfinv",
"sfinv_buttons", "sfinv_buttons",
"vector",
} }

38
LICENSE
View File

@ -1,4 +1,7 @@
« Copyright © 2015-2017, Jean-Patrick Guerrero <jeanpatrick.guerrero@gmail.com> License of source code
----------------------
« Copyright © 2015-2018, Jean-Patrick Guerrero <jeanpatrick.guerrero@gmail.com>
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
@ -7,3 +10,36 @@ The above copyright notice and this permission notice shall be included in all c
The Software is provided “as is”, without warranty of any kind, express or implied, including but not limited to the warranties of merchantability, fitness for a particular purpose and noninfringement. In no event shall the authors or copyright holders X be liable for any claim, damages or other liability, whether in an action of contract, tort or otherwise, arising from, out of or in connection with the software or the use or other dealings in the Software. The Software is provided “as is”, without warranty of any kind, express or implied, including but not limited to the warranties of merchantability, fitness for a particular purpose and noninfringement. In no event shall the authors or copyright holders X be liable for any claim, damages or other liability, whether in an action of contract, tort or otherwise, arising from, out of or in connection with the software or the use or other dealings in the Software.
Except as contained in this notice, the name of the <copyright holders> shall not be used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from the <copyright holders>. » Except as contained in this notice, the name of the <copyright holders> shall not be used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from the <copyright holders>. »
Licenses of media (textures)
----------------------------
Copyright © Diego Martínez (kaeza): craftguide_*_icon.png (CC BY-SA 3.0)
You are free to:
Share — copy and redistribute the material in any medium or format.
Adapt — remix, transform, and build upon the material for any purpose, even commercially.
The licensor cannot revoke these freedoms as long as you follow the license terms.
Under the following terms:
Attribution — You must give appropriate credit, provide a link to the license, and
indicate if changes were made. You may do so in any reasonable manner, but not in any way
that suggests the licensor endorses you or your use.
ShareAlike — If you remix, transform, or build upon the material, you must distribute
your contributions under the same license as the original.
No additional restrictions — You may not apply legal terms or technological measures that
legally restrict others from doing anything the license permits.
Notices:
You do not have to comply with the license for elements of the material in the public
domain or where your use is permitted by an applicable exception or limitation.
No warranties are given. The license may not give you all of the permissions necessary
for your intended use. For example, other rights such as publicity, privacy, or moral
rights may limit how you use the material.
For more details:
http://creativecommons.org/licenses/by-sa/3.0/

View File

@ -1,14 +1,38 @@
## ![Preview1](http://i.imgur.com/fIPNYkb.png) Crafting Guide ## ## ![Preview1](http://i.imgur.com/fIPNYkb.png) Crafting Guide ##
#### A Crafting Guide for Minetest that doesn't suck. #### #### `craftguide` is the most comprehensive crafting guide on Minetest. ####
#### Consult the [Minetest Wiki](http://wiki.minetest.net/Crafting_guide) for more details. ####
#### `craftguide` is the most comprehensive mod of its category. #### This crafting guide is a blue book named *"Crafting Guide"* or a wooden sign.
#### Consult the [Minetest Wiki](http://wiki.minetest.net/Crafting_guide) for more details and comparisons. ####
#### This crafting guide is usable with a blue book named *"Crafting Guide"*. #### This crafting guide features a **progressive mode**.
The progressive mode is a Terraria-like system that only shows recipes you can craft from items in inventory.
#### This crafting guide features two modes : Standard and Progressive. ####
The Progressive mode is a Terraria-like system that only shows recipes you can craft from items in inventory.
The progressive mode can be enabled with `craftguide_progressive_mode = true` in `minetest.conf`. The progressive mode can be enabled with `craftguide_progressive_mode = true` in `minetest.conf`.
![Preview2](http://i.imgur.com/3q7rVSo.png) `craftguide` is also integrated in `sfinv` (Minetest Game inventory) when you enable it with
`craftguide_sfinv_only = true` in `minetest.conf`.
Use the command `/craft` to show the recipe(s) of the pointed node.
---
`craftguide` has an API to register **custom recipes**. Demos:
#### Registering a custom crafting type ####
```Lua
craftguide.register_craft_type("digging", {
description = S("Digging"),
icon = "default_tool_steelpick.png",
width = 1,
})
```
#### Registering a custom crafting recipe ####
```Lua
craftguide.register_craft({
type = "digging",
output = "default:cobble 2",
items = {"default:stone"},
})
```
![Preview2](https://i.imgur.com/bToFH38.png)

View File

@ -1,2 +1,3 @@
sfinv?
sfinv_buttons? sfinv_buttons?
intllib? intllib?

692
init.lua
View File

@ -1,10 +1,19 @@
local craftguide, datas, mt = {}, {searches = {}}, minetest craftguide = {
custom_crafts = {},
craft_types = {},
}
local mt = minetest
local datas = {searches = {}}
local progressive_mode = mt.settings:get_bool("craftguide_progressive_mode") local progressive_mode = mt.settings:get_bool("craftguide_progressive_mode")
local sfinv_only = mt.settings:get_bool("craftguide_sfinv_only")
local get_recipe, get_recipes = mt.get_craft_recipe, mt.get_all_craft_recipes local get_recipe, get_recipes = mt.get_craft_recipe, mt.get_all_craft_recipes
local get_result, show_formspec = mt.get_craft_result, mt.show_formspec local get_result, show_formspec = mt.get_craft_result, mt.show_formspec
local reg_items = mt.registered_items local reg_items = mt.registered_items
craftguide.path = minetest.get_modpath("craftguide") craftguide.path = mt.get_modpath("craftguide")
-- Intllib -- Intllib
local S = dofile(craftguide.path .. "/intllib.lua") local S = dofile(craftguide.path .. "/intllib.lua")
@ -13,13 +22,15 @@ craftguide.intllib = S
-- Lua 5.3 removed `table.maxn`, use this alternative in case of breakage: -- Lua 5.3 removed `table.maxn`, use this alternative in case of breakage:
-- https://github.com/kilbith/xdecor/blob/master/handlers/helpers.lua#L1 -- https://github.com/kilbith/xdecor/blob/master/handlers/helpers.lua#L1
local remove, maxn, sort = table.remove, table.maxn, table.sort local remove, maxn, sort = table.remove, table.maxn, table.sort
local vector_add, vector_mul = vector.add, vector.multiply
local min, max, floor, ceil = math.min, math.max, math.floor, math.ceil local min, max, floor, ceil = math.min, math.max, math.floor, math.ceil
local DEFAULT_SIZE = 10 local DEFAULT_SIZE = 10
local MIN_LIMIT, MAX_LIMIT = 9, 12 local MIN_LIMIT, MAX_LIMIT = 10, 12
DEFAULT_SIZE = min(MAX_LIMIT, max(MIN_LIMIT, DEFAULT_SIZE)) DEFAULT_SIZE = min(MAX_LIMIT, max(MIN_LIMIT, DEFAULT_SIZE))
local GRID_LIMIT = 5 local GRID_LIMIT = 5
local BUTTON_SIZE = 1.1
local group_stereotypes = { local group_stereotypes = {
wool = "wool:white", wool = "wool:white",
@ -31,7 +42,75 @@ local group_stereotypes = {
mesecon_conductor_craftable = "mesecons:wire_00000000_off", mesecon_conductor_craftable = "mesecons:wire_00000000_off",
} }
function craftguide:group_to_item(item) local function extract_groups(str)
if str:sub(1,6) ~= "group:" then return end
return str:sub(7):split(",")
end
function craftguide.register_craft_type(name, def)
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",
width = 1,
})
function craftguide.register_craft(def)
craftguide.custom_crafts[#craftguide.custom_crafts + 1] = def
end
craftguide.register_craft({
type = "digging",
output = "default:cobble",
items = {"default:stone"},
})
local function colorize(str)
return mt.colorize("#FFFF00", str)
end
local function get_fueltime(item)
return get_result({method = "fuel", width = 1, items = {item}}).time
end
local function reset_datas(data)
data.show_usage = nil
data.filter = ""
data.item = nil
data.pagenum = 1
data.rnum = 1
data.fuel = nil
end
local function in_table(T)
for i = 1, #T do
if T[i] then
return true
end
end
end
local function group_to_items(group)
local items_with_group, counter = {}, 0
for name, def in pairs(reg_items) do
if def.groups[group:sub(7)] then
counter = counter + 1
items_with_group[counter] = name
end
end
return items_with_group
end
local function item_in_inv(inv, item)
return inv:contains_item("main", item)
end
local function group_to_item(item)
if item:sub(1,6) == "group:" then if item:sub(1,6) == "group:" then
local itemsub = item:sub(7) local itemsub = item:sub(7)
if group_stereotypes[itemsub] then if group_stereotypes[itemsub] then
@ -50,21 +129,7 @@ function craftguide:group_to_item(item)
return item:sub(1,6) == "group:" and "" or item return item:sub(1,6) == "group:" and "" or item
end end
local function extract_groups(str) local function get_tooltip(item, recipe_type, cooktime, groups)
if str:sub(1,6) ~= "group:" then return end
return str:sub(7):split(",")
end
local function colorize(str)
-- If client <= 0.4.14, don't colorize for compatibility.
return mt.colorize and mt.colorize("#FFFF00", str) or str
end
local function get_fueltime(item)
return get_result({method = "fuel", width = 1, items = {item}}).time
end
function craftguide:get_tooltip(item, recipe_type, cooktime, groups)
local tooltip, item_desc = "tooltip[" .. item .. ";", "" local tooltip, item_desc = "tooltip[" .. item .. ";", ""
local fueltime = get_fueltime(item) local fueltime = get_fueltime(item)
local has_extras = groups or recipe_type == "cooking" or fueltime > 0 local has_extras = groups or recipe_type == "cooking" or fueltime > 0
@ -101,73 +166,120 @@ function craftguide:get_tooltip(item, recipe_type, cooktime, groups)
return has_extras and tooltip .. "]" or "" return has_extras and tooltip .. "]" or ""
end end
function craftguide:get_recipe(iY, xoffset, recipe_num, recipes, show_usage) local function _get_recipe(iX, iY, xoffset, recipe_num, recipes, show_usage)
local formspec, recipes_total = "", #recipes local formspec, recipes_total = "", #recipes
if recipes_total > 1 then if recipes_total > 1 then
formspec = formspec .. formspec = formspec ..
"button[0," .. (iY + 3.3) .. ";2,1;alternate;" .. S("Alternate") .. "]" .. "button[" .. (iX - (sfinv_only and 2.2 or 2.6)) .. "," ..
"label[0," .. (iY + 2.8) .. ";" .. (iY + (sfinv_only and 3.9 or 3.3)) .. ";2.2,1;alternate;" ..
(show_usage and S("Usage") or S("Recipe")) .. " " .. (show_usage and S("Usage") or S("Recipe")) .. " " ..
S("@1 of @2", recipe_num, recipes_total) .. "]" S("@1 of @2", recipe_num, recipes_total) .. "]"
end end
local recipe_type = recipes[recipe_num].type local recipe_type = recipes[recipe_num].type
local items = recipes[recipe_num].items local items = recipes[recipe_num].items
local width = recipes[recipe_num].width local width = recipes[recipe_num].width
if recipe_type == "cooking" or (recipe_type == "normal" and width == 0) then local cooktime = width
local icon = recipe_type == "cooking" and "furnace" or "shapeless" if recipe_type == "cooking" then
formspec = formspec .. width = 1
"image[" .. (xoffset - 0.8) .. "," .. (iY + 1.7) .. elseif width == 0 then
";0.5,0.5;craftguide_" .. icon .. ".png]"
end
if width == 0 then
width = min(3, #items) width = min(3, #items)
end end
local rows = ceil(maxn(items) / width) local rows = ceil(maxn(items) / width)
local rightest, s_btn_size = 0
if recipe_type == "normal" and (width > GRID_LIMIT or rows > GRID_LIMIT) then if recipe_type ~= "fuel" and (width > GRID_LIMIT or rows > GRID_LIMIT) then
formspec = formspec .. formspec = formspec ..
"label[" .. xoffset .. "," .. (iY + 2) .. ";" .. "label[" .. ((iX / 2) - 2) .. "," .. (iY + 2.2) .. ";" ..
S("Recipe is too big to\nbe displayed (@1x@2)", width, rows) .. "]" S("Recipe is too big to be displayed (@1x@2)", width, rows) .. "]"
return formspec
else else
local btn_size = 1
for i, v in pairs(items) do for i, v in pairs(items) do
local X = (i - 1) % width + xoffset 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)) local Y = ceil(i / width + (iY + 2) - min(2, rows))
if recipe_type == "normal" and (width > 3 or rows > 3) then if recipe_type ~= "fuel" and (width > 3 or rows > 3) then
btn_size = width > 3 and 3 / width or 3 / rows BUTTON_SIZE = width > 3 and 3 / width or 3 / rows
X = btn_size * (i % width) + xoffset s_btn_size = BUTTON_SIZE
Y = btn_size * floor((i - 1) / width) + (iY + 3) - min(2, rows) X = BUTTON_SIZE * (i % width) + xoffset - 2.65
Y = BUTTON_SIZE * floor((i - 1) / width) + (iY + 3) - min(2, rows)
end
if X > rightest then
rightest = X
end end
local groups = extract_groups(v) local groups = extract_groups(v)
local label = groups and "\nG" or "" local label = groups and "\nG" or ""
local item_r = self:group_to_item(v) local item_r = group_to_item(v)
local tltip = self:get_tooltip(item_r, recipe_type, width, groups) local tltip = get_tooltip(item_r, recipe_type, cooktime, groups)
formspec = formspec .. formspec = formspec ..
"item_image_button[" .. X .. "," .. (Y + 0.2) .. ";" .. "item_image_button[" .. X .. "," ..
btn_size .. "," .. btn_size .. ";" .. item_r .. (Y + (sfinv_only and 0.7 or 0.2)) .. ";" ..
";" .. item_r .. ";" .. label .. "]" .. tltip BUTTON_SIZE .. "," .. BUTTON_SIZE .. ";" .. item_r ..
";" .. item_r:match("%S*") .. ";" .. label .. "]" .. tltip
end end
BUTTON_SIZE = 1.1
end end
local output = recipes[recipe_num].output local custom_recipe = craftguide.craft_types[recipe_type]
return formspec .. if recipe_type == "cooking" or (recipe_type == "normal" and width == 0) or
"image[" .. (xoffset - 1) .. "," .. (iY + 2.35) .. custom_recipe then
local icon = recipe_type == "cooking" and "furnace" or "shapeless"
local coords = (rightest + 1.2) .. "," ..
(iY + (sfinv_only and 2.2 or 1.7)) ..
";0.5,0.5;"
formspec = formspec ..
"image[" .. coords ..
(custom_recipe and custom_recipe.icon or
"craftguide_" .. icon .. ".png^[resize:16x16") .. "]" ..
"tooltip[" .. coords ..
(custom_recipe and custom_recipe.description or
recipe_type:gsub("^%l", string.upper)) .. "]"
end
local output = recipes[recipe_num].output
local output_s = output:match("%S+")
local output_is_fuel = get_fueltime(output) > 0
local arrow_X = rightest + (s_btn_size or BUTTON_SIZE)
local output_X = arrow_X + 0.9
formspec = formspec ..
"image[" .. arrow_X .. "," ..
(iY + (sfinv_only and 2.85 or 2.35)) ..
";0.9,0.7;craftguide_arrow.png]" .. ";0.9,0.7;craftguide_arrow.png]" ..
"item_image_button[" .. (xoffset - 2) .. "," .. (iY + 2.2) .. ";1,1;" ..
output .. ";" .. output .. ";]" .. "item_image_button[" .. output_X .. "," ..
self:get_tooltip(output:match("%S+")) (iY + (sfinv_only and 2.7 or 2.2)) .. ";" ..
BUTTON_SIZE .. "," .. BUTTON_SIZE .. ";" ..
output .. ";" .. output_s .. ";]" ..
get_tooltip(output_s)
if output_is_fuel then
formspec = formspec ..
"image[" .. (output_X + 1) .. "," ..
(iY + (sfinv_only and 2.83 or 2.33)) ..
";0.6,0.4;craftguide_arrow.png]" ..
"image[" .. (output_X + 1.6) .. "," ..
(iY + (sfinv_only and 2.68 or 2.18)) ..
";0.6,0.6;craftguide_fire.png]"
end
return formspec
end end
function craftguide:get_formspec(player_name, is_fuel) local function get_formspec(player_name)
local data = datas[player_name] local data = datas[player_name]
local iY = data.iX - 5 local iY = sfinv_only and 4 or data.iX - 5
local ipp = data.iX * iY local ipp = data.iX * iY
if not data.items then if not data.items then
@ -176,35 +288,42 @@ function craftguide:get_formspec(player_name, is_fuel)
data.pagemax = max(1, ceil(#data.items / ipp)) data.pagemax = max(1, ceil(#data.items / ipp))
local formspec = "size[" .. (data.iX - 0.35) .. "," .. (iY + 4) .. ";]" .. [[ local formspec = ""
background[1,1;1,1;craftguide_bg.png;true] if not sfinv_only then
button[2.4,0.23;0.8,0.5;search;?] formspec = formspec ..
button[3.05,0.23;0.8,0.5;clear;X] "size[" .. (data.iX - 0.35) .. "," .. (iY + 4) .. ";]" ..
"background[1,1;1,1;craftguide_bg.png;true]" ..
"tooltip[size_inc;" .. S("Increase window size") .. "]" ..
"tooltip[size_dec;" .. S("Decrease window size") .. "]" ..
"image_button[" .. (data.iX * 0.47) ..
",0.12;0.8,0.8;craftguide_zoomin_icon.png;size_inc;]" ..
"image_button[" .. ((data.iX * 0.47) + 0.6) ..
",0.12;0.8,0.8;craftguide_zoomout_icon.png;size_dec;]"
end
formspec = formspec .. [[
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] field_close_on_enter[filter;false]
]] .. ]] ..
"tooltip[search;" .. S("Search") .. "]" .. "tooltip[search;" .. S("Search") .. "]" ..
"tooltip[clear;" .. S("Reset") .. "]" .. "tooltip[clear;" .. S("Reset") .. "]" ..
"tooltip[size_inc;" .. S("Increase window size") .. "]" ..
"tooltip[size_dec;" .. S("Decrease window size") .. "]" ..
"tooltip[prev;" .. S("Previous page") .. "]" .. "tooltip[prev;" .. S("Previous page") .. "]" ..
"tooltip[next;" .. S("Next page") .. "]" .. "tooltip[next;" .. S("Next page") .. "]" ..
"button[" .. (data.iX * 0.48) .. ",-0.02;0.7,1;size_inc;+]" .. "image_button[" .. (data.iX - (sfinv_only and 2.6 or 3.1)) ..
"button[" .. ((data.iX * 0.48) + 0.5) .. ",0.12;0.8,0.8;craftguide_prev_icon.png;prev;]" ..
",-0.02;0.7,1;size_dec;-]" .. "label[" .. (data.iX - (sfinv_only and 1.7 or 2.2)) .. ",0.22;" ..
"button[" .. (data.iX - 3.1) .. ",0;0.8,0.95;prev;<]" ..
"label[" .. (data.iX - 2.2) .. ",0.18;" ..
colorize(data.pagenum) .. " / " .. data.pagemax .. "]" .. colorize(data.pagenum) .. " / " .. data.pagemax .. "]" ..
"button[" .. (data.iX - 1.2) .. ",0;0.8,0.95;next;>]" .. "image_button[" .. (data.iX - (sfinv_only and 0.7 or 1.2) -
"field[0.3,0.32;2.5,1;filter;;" .. (data.iX >= 11 and 0.08 or 0)) ..
mt.formspec_escape(data.filter) .. "]" ",0.12;0.8,0.8;craftguide_next_icon.png;next;]" ..
"field[0.3,0.32;2.5,1;filter;;" .. mt.formspec_escape(data.filter) .. "]"
local even_num = data.iX % 2 == 0 local xoffset = data.iX / 2.15
local xoffset = data.iX / 2 + (even_num and 0.5 or 0)
if not next(data.items) then if not next(data.items) then
formspec = formspec .. formspec = formspec ..
"label[" .. (xoffset - (even_num and 1.5 or 1)) .. ",2;" .. "label[" .. ((data.iX / 2) - 1) .. ",2;" .. S("No item to show") .. "]"
S("No item to show") .. "]"
end end
local first_item = (data.pagenum - 1) * ipp local first_item = (data.pagenum - 1) * ipp
@ -215,24 +334,36 @@ function craftguide:get_formspec(player_name, is_fuel)
local Y = (i % ipp - X) / data.iX + 1 local Y = (i % ipp - X) / data.iX + 1
formspec = formspec .. formspec = formspec ..
"item_image_button[" .. (X - (X * 0.05)) .. "," .. Y .. ";1.1,1.1;" .. "item_image_button[" ..
(X - (sfinv_only and 0 or (X * 0.05))) .. "," ..
Y .. ";" .. BUTTON_SIZE .. "," .. BUTTON_SIZE .. ";" ..
name .. ";" .. name .. "_inv;]" name .. ";" .. name .. "_inv;]"
end end
if data.item and reg_items[data.item] then if data.item and reg_items[data.item] then
if not data.recipes_item or (is_fuel and not get_recipe(data.item).items) then if not data.recipes_item or (data.fuel and not get_recipe(data.item).items) then
local X = floor(xoffset) - (sfinv_only and 0 or 0.2)
formspec = formspec .. formspec = formspec ..
"image[" .. (xoffset - 1) .. "," .. (iY + 2.35) .. "item_image_button[" .. X .. "," ..
(iY + (sfinv_only and 2.7 or 2.2)) ..
";" .. BUTTON_SIZE .. "," .. BUTTON_SIZE ..
";" .. data.item .. ";" .. data.item .. ";]" ..
"image[" .. (X + 1.1) .. "," ..
(iY + (sfinv_only and 2.85 or 2.35)) ..
";0.9,0.7;craftguide_arrow.png]" .. ";0.9,0.7;craftguide_arrow.png]" ..
"item_image_button[" .. xoffset .. "," .. (iY + 2.2) ..
";1,1;" .. data.item .. ";" .. data.item .. ";]" .. get_tooltip(data.item) ..
self:get_tooltip(data.item) ..
"image[" .. (xoffset - 2) .. "," .. "image[" .. (X + 2.1) .. "," ..
(iY + 2.18) .. ";1,1;craftguide_fire.png]" (iY + (sfinv_only and 2.68 or 2.18)) ..
";1.1,1.1;craftguide_fire.png]"
else else
local show_usage = data.show_usage local show_usage = data.show_usage
formspec = formspec .. formspec = formspec ..
self:get_recipe(iY, xoffset, _get_recipe(data.iX,
iY,
xoffset,
data.rnum, data.rnum,
(show_usage and data.usages or data.recipes_item), (show_usage and data.usages or data.recipes_item),
show_usage) show_usage)
@ -240,34 +371,24 @@ function craftguide:get_formspec(player_name, is_fuel)
end end
data.formspec = formspec data.formspec = formspec
show_formspec(player_name, "craftguide", formspec)
end
local function player_has_item(T) if sfinv_only then
for i = 1, #T do return formspec
if T[i] then else
return true show_formspec(player_name, "craftguide", formspec)
end
end end
end end
local function group_to_items(group) local show_fs = function(player, player_name)
local items_with_group, counter = {}, 0 if sfinv_only then
for name, def in pairs(reg_items) do local context = sfinv.get_or_create_context(player)
if def.groups[group:sub(7)] then sfinv.set_player_inventory_formspec(player, context)
counter = counter + 1 else
items_with_group[counter] = name get_formspec(player_name)
end
end end
return items_with_group
end end
local function item_in_inv(inv, item) local function recipe_in_inv(inv, item_name, recipes_f)
return inv:contains_item("main", item)
end
function craftguide:recipe_in_inv(inv, item_name, recipes_f)
local recipes = recipes_f or get_recipes(item_name) or {} local recipes = recipes_f or get_recipes(item_name) or {}
local show_item_recipes = {} local show_item_recipes = {}
@ -295,28 +416,10 @@ function craftguide:recipe_in_inv(inv, item_name, recipes_f)
end end
end end
return recipes, player_has_item(show_item_recipes) return recipes, in_table(show_item_recipes)
end end
function craftguide:get_init_items() local function get_filter_items(data, player)
local items_list, counter = {}, 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
counter = counter + 1
items_list[counter] = name
end
end
sort(items_list)
datas.init_items = items_list
end
function craftguide:get_filter_items(data, player)
local filter = data.filter local filter = data.filter
if datas.searches[filter] then if datas.searches[filter] then
data.items = datas.searches[filter] data.items = datas.searches[filter]
@ -337,7 +440,7 @@ function craftguide:get_filter_items(data, player)
filtered_list[counter] = item filtered_list[counter] = item
end end
elseif progressive_mode then elseif progressive_mode then
local _, has_item = self:recipe_in_inv(inv, item) local _, has_item = recipe_in_inv(inv, item)
if has_item then if has_item then
counter = counter + 1 counter = counter + 1
filtered_list[counter] = item filtered_list[counter] = item
@ -361,7 +464,73 @@ function craftguide:get_filter_items(data, player)
data.items = filtered_list data.items = filtered_list
end end
function craftguide:get_item_usages(item) local function init_datas(user, name)
datas[name] = {filter = "", pagenum = 1, iX = sfinv_only and 8 or DEFAULT_SIZE}
if progressive_mode then
get_filter_items(datas[name], user)
end
end
local function add_custom_recipes(item, recipes)
for j = 1, #craftguide.custom_crafts do
local craft = craftguide.custom_crafts[j]
if craft.output:match("%S*") == item then
recipes[#recipes + 1] = {
width = craftguide.craft_types[craft.type].width,
type = craft.type,
items = craft.items,
output = craft.output,
}
end
end
return recipes
end
local function get_init_items()
local items_list, c = {}, 0
local function list(name)
c = c + 1
items_list[c] = name
end
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
list(name)
end
end
for i = 1, #craftguide.custom_crafts do
local craft = craftguide.custom_crafts[i]
local output = craft.output:match("%S*")
local listed
for j = 1, #items_list do
local listed_item = items_list[j]
if output == listed_item then
listed = true
break
end
end
if not listed then
list(output)
end
end
sort(items_list)
datas.init_items = items_list
end
mt.register_on_mods_loaded(function()
get_init_items()
end)
local function get_item_usages(item)
local usages = {} local usages = {}
for name, def in pairs(reg_items) do for name, def in pairs(reg_items) do
if not (def.groups.not_in_craft_guide == 1 or if not (def.groups.not_in_craft_guide == 1 or
@ -390,20 +559,22 @@ function craftguide:get_item_usages(item)
return usages return usages
end end
mt.register_on_player_receive_fields(function(player, formname, fields) local function get_fields(player, ...)
if formname ~= "craftguide" then return end local args, formname, fields = {...}
if sfinv_only then
fields = args[1]
else
formname, fields = args[1], args[2]
end
if not sfinv_only and formname ~= "craftguide" then return end
local player_name = player:get_player_name() local player_name = player:get_player_name()
local data = datas[player_name] local data = datas[player_name]
if fields.clear then if fields.clear then
data.show_usage = nil reset_datas(data)
data.filter = ""
data.item = nil
data.pagenum = 1
data.rnum = 1
data.items = progressive_mode and data.init_filter_items or datas.init_items data.items = progressive_mode and data.init_filter_items or datas.init_items
craftguide:get_formspec(player_name) show_fs(player, player_name)
elseif fields.alternate then elseif fields.alternate then
local num local num
@ -414,14 +585,14 @@ mt.register_on_player_receive_fields(function(player, formname, fields)
end end
data.rnum = num and data.rnum + 1 or 1 data.rnum = num and data.rnum + 1 or 1
craftguide:get_formspec(player_name) show_fs(player, player_name)
elseif (fields.key_enter_field == "filter" or fields.search) and elseif (fields.key_enter_field == "filter" or fields.search) and
fields.filter ~= "" then fields.filter ~= "" then
data.filter = fields.filter:lower() data.filter = fields.filter:lower()
data.pagenum = 1 data.pagenum = 1
craftguide:get_filter_items(data, player) get_filter_items(data, player)
craftguide:get_formspec(player_name) show_fs(player, player_name)
elseif fields.prev or fields.next then elseif fields.prev or fields.next then
data.pagenum = data.pagenum - (fields.prev and 1 or -1) data.pagenum = data.pagenum - (fields.prev and 1 or -1)
@ -432,13 +603,13 @@ mt.register_on_player_receive_fields(function(player, formname, fields)
data.pagenum = data.pagemax data.pagenum = data.pagemax
end end
craftguide:get_formspec(player_name) show_fs(player, player_name)
elseif (fields.size_inc and data.iX < MAX_LIMIT) or elseif (fields.size_inc and data.iX < MAX_LIMIT) or
(fields.size_dec and data.iX > MIN_LIMIT) then (fields.size_dec and data.iX > MIN_LIMIT) then
data.pagenum = 1 data.pagenum = 1
data.iX = data.iX - (fields.size_dec and 1 or -1) data.iX = data.iX - (fields.size_dec and 1 or -1)
craftguide:get_formspec(player_name) show_fs(player, player_name)
else for item in pairs(fields) do else for item in pairs(fields) do
if item:find(":") then if item:find(":") then
@ -449,131 +620,200 @@ mt.register_on_player_receive_fields(function(player, formname, fields)
end end
local is_fuel = get_fueltime(item) > 0 local is_fuel = get_fueltime(item) > 0
local recipes = get_recipes(item) local recipes = get_recipes(item) or {}
if not recipes and not is_fuel then return end recipes = add_custom_recipes(item, recipes)
if not next(recipes) and not is_fuel then return end
if not data.show_usage and item == data.item and not progressive_mode then if not data.show_usage and item == data.item and not progressive_mode then
data.usages = craftguide:get_item_usages(item) data.usages = get_item_usages(item)
if next(data.usages) then if next(data.usages) then
data.show_usage = true data.show_usage = true
data.rnum = 1 data.rnum = 1
end end
craftguide:get_formspec(player_name) show_fs(player, player_name)
else else
if progressive_mode then if progressive_mode then
local inv = player:get_inventory() local inv = player:get_inventory()
local _, has_item = craftguide:recipe_in_inv(inv, item) local has_item
recipes, has_item = recipe_in_inv(inv, item, recipes)
if not has_item then return end if not has_item then return end
recipes = craftguide:recipe_in_inv(inv, item, recipes)
end end
data.item = item data.item = item
data.recipes_item = recipes data.recipes_item = recipes
data.rnum = 1 data.rnum = 1
data.show_usage = nil data.show_usage = nil
data.fuel = is_fuel
craftguide:get_formspec(player_name, is_fuel) show_fs(player, player_name)
end end
end end
end end
end end
end) end
function craftguide:on_use(itemstack, user) if sfinv_only then
if not datas.init_items then sfinv.register_page("craftguide:craftguide", {
self:get_init_items() title = "Craft Guide",
get = function(self, player, context)
local player_name = player:get_player_name()
return sfinv.make_formspec(
player,
context,
get_formspec(player_name)
)
end,
on_enter = function(self, player, context)
local player_name = player:get_player_name()
local data = datas[player_name]
if progressive_mode or not data then
init_datas(player, player_name)
end
end,
on_player_receive_fields = function(self, player, context, fields)
get_fields(player, fields)
end,
})
else
mt.register_on_player_receive_fields(get_fields)
local function on_use(itemstack, user)
local player_name = user:get_player_name()
local data = datas[player_name]
if progressive_mode or not data then
init_datas(user, player_name)
get_formspec(player_name)
else
show_formspec(player_name, "craftguide", data.formspec)
end
end end
local player_name = user:get_player_name() mt.register_craftitem("craftguide:book", {
local data = datas[player_name] description = S("Crafting Guide"),
inventory_image = "craftguide_book.png",
if progressive_mode or not data then wield_image = "craftguide_book.png",
datas[player_name] = {filter = "", pagenum = 1, iX = DEFAULT_SIZE} stack_max = 1,
if progressive_mode then groups = {book = 1},
self:get_filter_items(datas[player_name], user) on_use = function(itemstack, user)
on_use(itemstack, user)
end end
})
self:get_formspec(player_name) mt.register_node("craftguide:sign", {
else description = S("Crafting Guide Sign"),
show_formspec(player_name, "craftguide", data.formspec) 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,
groups = {wood = 1, oddly_breakable_by_hand = 1, flammable = 3},
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}
},
on_construct = function(pos)
local meta = mt.get_meta(pos)
meta:set_string("infotext", S("Crafting Guide Sign"))
end,
on_rightclick = function(pos, node, user, itemstack)
on_use(itemstack, user)
end
})
mt.register_craft({
output = "craftguide:book",
type = "shapeless",
recipe = {"default:book"}
})
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
})
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"),
action = function(player)
on_use(nil, player)
end,
image = "craftguide_book.png",
})
end end
end end
mt.register_craftitem("craftguide:book", { if not progressive_mode then
description = S("Crafting Guide"), mt.register_chatcommand("craft", {
inventory_image = "craftguide_book.png", description = S("Show recipe(s) of the pointed node"),
wield_image = "craftguide_book.png", func = function(name)
stack_max = 1, local player = mt.get_player_by_name(name)
groups = {book = 1}, local ppos = player:get_pos()
on_use = function(itemstack, user) local dir = player:get_look_dir()
craftguide:on_use(itemstack, user) local eye_h = {x = ppos.x, y = ppos.y + 1.625, z = ppos.z}
end local node_name
})
mt.register_node("craftguide:sign", { for i = 1, 10 do
description = S("Crafting Guide Sign"), local look_at = vector_add(eye_h, vector_mul(dir, i))
drawtype = "nodebox", local node = mt.get_node(look_at)
tiles = {"craftguide_sign.png"},
inventory_image = "craftguide_sign_inv.png",
wield_image = "craftguide_sign_inv.png",
paramtype = "light",
paramtype2 = "wallmounted",
sunlight_propagates = true,
groups = {wood = 1, oddly_breakable_by_hand = 1, flammable = 3},
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}
},
on_construct = function(pos)
local meta = minetest.get_meta(pos)
meta:set_string("infotext", S("Crafting Guide Sign"))
end,
on_rightclick = function(pos, node, user, itemstack)
craftguide:on_use(itemstack, user)
end
})
mt.register_craft({ if node.name ~= "air" then
output = "craftguide:book", node_name = node.name
type = "shapeless", break
recipe = {"default:book"} end
}) end
mt.register_craft({ if not node_name then
type = "fuel", return false, colorize("[craftguide] ") .. S("No node pointed")
recipe = "craftguide:book", elseif not datas[name] then
burntime = 3 init_datas(player, name)
}) end
mt.register_craft({ local data = datas[name]
output = "craftguide:sign", local is_fuel = get_fueltime(node_name) > 0
type = "shapeless", local recipes = get_recipes(node_name) or {}
recipe = {"default:sign_wall_wood"} recipes = add_custom_recipes(node_name, recipes)
})
mt.register_craft({ if not next(recipes) and not is_fuel then
type = "fuel", return false, colorize("[craftguide] ") ..
recipe = "craftguide:sign", S("No recipe for this node:") .. " " ..
burntime = 10 colorize(node_name)
}) end
if rawget(_G, "sfinv_buttons") then data.show_usage = nil
sfinv_buttons.register_button("craftguide", { data.filter = ""
title = S("Crafting Guide"), data.item = node_name
tooltip = S("Shows a list of available crafting recipes, cooking recipes and fuels"), data.pagenum = 1
action = function(player) data.rnum = 1
craftguide:on_use(nil, player) data.recipes_item = recipes
data.items = datas.init_items
data.fuel = is_fuel
return true, show_fs(player, name)
end, end,
image = "craftguide_book.png",
}) })
end end
mt.register_alias("xdecor:crafting_guide", "craftguide:book")
--[[ Custom recipes (>3x3) test code --[[ Custom recipes (>3x3) test code
mt.register_craftitem("craftguide:custom_recipe_test", { mt.register_craftitem("craftguide:custom_recipe_test", {

4
settingtypes.txt Normal file
View File

@ -0,0 +1,4 @@
#For enabling some options of craftguide.
craftguide_progressive_mode (Progressive Mode) bool false
craftguide_sfinv_only (Sfinv only) bool false

Binary file not shown.

Before

Width:  |  Height:  |  Size: 242 B

After

Width:  |  Height:  |  Size: 230 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 708 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 727 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 728 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 227 B

After

Width:  |  Height:  |  Size: 305 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB