Compare commits

...

24 Commits

Author SHA1 Message Date
d1ee125a1a Remove erroneous quotation marks 2019-01-04 02:19:29 +01:00
b980dccaee Use of string.format instead of concat 2019-01-02 18:57:35 +01:00
4c02a5e5f5 Merge pull request #41 from pauloue/fixes2
Fix two bugs
2019-01-02 12:27:12 +01:00
f8b7a72635 Fix alternate button not working in some cases 2019-01-02 01:11:08 -05:00
1034fd7c0e Fix repeated clicks of same item not toggling usages mode 2019-01-02 00:35:21 -05:00
4bca02f0db Add assertions 2018-12-30 21:52:13 +01:00
4b97b08aa7 Variable naming 2018-12-30 21:22:01 +01:00
7745ccd863 Not really important 2018-12-30 21:10:39 +01:00
65b51ad3e5 Do not alternate if X > 1 2018-12-30 21:00:04 +01:00
897fc3a21d Show usages for fuel-able items with no recipes 2018-12-30 20:43:26 +01:00
e1eedb69bb Minor optimization 2018-12-19 18:36:09 +01:00
f188580b8c Correct checking 2018-12-17 22:48:53 +01:00
783a84d3c6 Define custom recipe's width inside craft declaration 2018-12-17 19:17:43 +01:00
74a2750a4d Fix tooltip 2018-12-17 01:14:55 +01:00
9da500ce2c ... and make the other functions local 2018-12-17 01:02:51 +01:00
610117de08 Make craftguide a global var 2018-12-17 00:38:58 +01:00
53833af635 Add an API for custom recipes 2018-12-17 00:37:49 +01:00
b2a7f5430a Add a /craft command to show recipe of pointed node 2018-12-13 20:31:45 +01:00
0b4f202ffb New icons 2018-11-25 16:08:20 +01:00
eff2fa82f3 Fix custom recipes since latest commit 2018-11-18 20:52:00 +01:00
8630fccaea More alignment 2018-11-18 20:06:45 +01:00
4d4e8f7d50 Rotate arrow images 2018-11-18 18:40:58 +01:00
6d3f8ce32a Fix cooktime tooltip 2018-11-18 18:26:09 +01:00
ed861ea1b9 Formspec improvements (fixes #39) 2018-11-17 18:24:12 +01:00
12 changed files with 585 additions and 253 deletions

View File

@ -6,4 +6,5 @@ read_globals = {
"default",
"sfinv",
"sfinv_buttons",
"vector",
}

36
LICENSE
View File

@ -1,3 +1,6 @@
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:
@ -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.
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

@ -3,13 +3,36 @@
#### `craftguide` is the most comprehensive crafting guide on Minetest. ####
#### Consult the [Minetest Wiki](http://wiki.minetest.net/Crafting_guide) for more details. ####
#### This crafting guide is usable with a blue book named *"Crafting Guide"* ####
This crafting guide is a blue book named *"Crafting Guide"* or a wooden sign.
#### 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.
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.
The progressive mode can be enabled with `craftguide_progressive_mode = true` in `minetest.conf`.
`craftguide` is also integrated in `sfinv` (Minetest Game inventory) when you enable it with
`craftguide_sfinv_only = true` in `minetest.conf`.
![Preview2](http://i.imgur.com/3q7rVSo.png)
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 = "Digging",
icon = "default_tool_steelpick.png",
})
```
#### Registering a custom crafting recipe ####
```Lua
craftguide.register_craft({
type = "digging",
width = 1,
output = "default:cobble 2",
items = {"default:stone"},
})
```
![Preview2](https://i.imgur.com/bToFH38.png)

748
init.lua
View File

@ -1,4 +1,10 @@
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 sfinv_only = mt.settings:get_bool("craftguide_sfinv_only")
@ -7,7 +13,7 @@ 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 reg_items = mt.registered_items
craftguide.path = minetest.get_modpath("craftguide")
craftguide.path = mt.get_modpath("craftguide")
-- Intllib
local S = dofile(craftguide.path .. "/intllib.lua")
@ -15,14 +21,17 @@ craftguide.intllib = S
-- Lua 5.3 removed `table.maxn`, use this alternative in case of breakage:
-- https://github.com/kilbith/xdecor/blob/master/handlers/helpers.lua#L1
local remove, maxn, sort = table.remove, table.maxn, table.sort
local remove, maxn, sort, concat = table.remove, table.maxn, table.sort, table.concat
local vector_add, vector_mul = vector.add, vector.multiply
local min, max, floor, ceil = math.min, math.max, math.floor, math.ceil
local fmt = string.format
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))
local GRID_LIMIT = 5
local BUTTON_SIZE = 1.1
local group_stereotypes = {
wool = "wool:white",
@ -34,7 +43,99 @@ local group_stereotypes = {
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
local function __func()
return debug.getinfo(2, "n").name
end
function craftguide.register_craft_type(name, def)
local func = "craftguide." .. __func() .. "(): "
assert(name, func .. "'name' field missing")
assert(def.description, func .. "'description' field missing")
assert(def.icon, func .. "'icon' field missing")
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",
})
function craftguide.register_craft(def)
local func = "craftguide." .. __func() .. "(): "
assert(def.type, func .. "'type' field missing")
assert(def.width, func .. "'width' field missing")
assert(def.output, func .. "'output' field missing")
assert(def.items, func .. "'items' field missing")
craftguide.custom_crafts[#craftguide.custom_crafts + 1] = def
end
craftguide.register_craft({
type = "digging",
width = 1,
output = "default:cobble",
items = {"default:stone"},
})
local color_codes = {
red = "#FF0000",
yellow = "#FFFF00",
}
local function colorize(str, color)
color = color or "yellow"
return mt.colorize(color_codes[color], 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.input = nil
data.pagenum = 1
data.rnum = 1
data.items = progressive_mode and data.init_filter_items or datas.init_items
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
local itemsub = item:sub(7)
if group_stereotypes[itemsub] then
@ -53,20 +154,7 @@ function craftguide:group_to_item(item)
return item:sub(1,6) == "group:" and "" or item
end
local function extract_groups(str)
if str:sub(1,6) ~= "group:" then return end
return str:sub(7):split(",")
end
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
function craftguide:get_tooltip(item, recipe_type, cooktime, groups)
local function get_tooltip(item, recipe_type, cooktime, groups)
local tooltip, item_desc = "tooltip[" .. item .. ";", ""
local fueltime = get_fueltime(item)
local has_extras = groups or recipe_type == "cooking" or fueltime > 0
@ -103,73 +191,158 @@ function craftguide:get_tooltip(item, recipe_type, cooktime, groups)
return has_extras and tooltip .. "]" or ""
end
function craftguide:get_recipe(iY, xoffset, recipe_num, recipes, show_usage)
local formspec, recipes_total = "", #recipes
if recipes_total > 1 then
formspec = formspec ..
"button[0," .. (iY + (sfinv_only and 3.8 or 3.3)) ..
";2,1;alternate;" .. S("Alternate") .. "]" ..
"label[0," .. (iY + (sfinv_only and 3.3 or 2.8)) .. ";" ..
(show_usage and S("Usage") or S("Recipe")) .. " " ..
S("@1 of @2", recipe_num, recipes_total) .. "]"
local function get_recipe_fs(iX, iY, xoffset, recipe_num, recipes, show_usage)
if not recipes[1] then
return ""
end
local fs = {}
fs[#fs + 1] = fmt("button[%f,%f;%f,%f;%s;%s %u %s %u]",
iX - (sfinv_only and 2.2 or 2.6),
iY + (sfinv_only and 3.9 or 3.3),
2.2,
1,
"alternate",
show_usage and S("Usage") or S("Recipe"),
recipe_num,
S("of"),
#recipes)
local recipe_type = recipes[recipe_num].type
local items = recipes[recipe_num].items
local width = recipes[recipe_num].width
if recipe_type == "cooking" or (recipe_type == "normal" and width == 0) then
local icon = recipe_type == "cooking" and "furnace" or "shapeless"
formspec = formspec ..
"image[" .. (xoffset - 0.8) .. "," .. (iY + (sfinv_only and 2.2 or 1.7)) ..
";0.5,0.5;craftguide_" .. icon .. ".png]"
end
if width == 0 then
local cooktime = width
if recipe_type == "cooking" then
width = 1
elseif width == 0 then
width = min(3, #items)
end
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
formspec = formspec ..
"label[" .. xoffset .. "," .. (iY + 2) .. ";" ..
S("Recipe is too big to\nbe displayed (@1x@2)", width, rows) .. "]"
if recipe_type ~= "cooking" and (width > GRID_LIMIT or rows > GRID_LIMIT) then
fs[#fs + 1] = fmt("label[%f,%f;%s]",
(iX / 2) - 2,
iY + 2.2,
S("Recipe is too big to be displayed (@1x@2)", width, rows))
return concat(fs)
else
local btn_size = 1
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))
if recipe_type == "normal" and (width > 3 or rows > 3) then
btn_size = width > 3 and 3 / width or 3 / rows
X = btn_size * (i % width) + xoffset
Y = btn_size * floor((i - 1) / width) + (iY + 3) - min(2, rows)
if recipe_type ~= "cooking" and (width > 3 or rows > 3) then
BUTTON_SIZE = width > 3 and 3 / width or 3 / rows
s_btn_size = BUTTON_SIZE
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
local groups = extract_groups(v)
local label = groups and "\nG" or ""
local item_r = self:group_to_item(v)
local tltip = self:get_tooltip(item_r, recipe_type, width, groups)
local item_r = group_to_item(v)
local tltp = get_tooltip(item_r, recipe_type, cooktime, groups)
formspec = formspec ..
"item_image_button[" .. X .. "," ..
(Y + (sfinv_only and 0.7 or 0.2)) .. ";" ..
btn_size .. "," .. btn_size .. ";" .. item_r ..
";" .. item_r .. ";" .. label .. "]" .. tltip
end
fs[#fs + 1] = fmt("item_image_button[%f,%f;%f,%f;%s;%s;%s]",
X,
Y + (sfinv_only and 0.7 or 0.2),
BUTTON_SIZE,
BUTTON_SIZE,
item_r,
item_r:match("%S*"),
label)
fs[#fs + 1] = tltp
end
local output = recipes[recipe_num].output:match("%S+")
return formspec ..
"image[" .. (xoffset - 1) .. "," .. (iY + (sfinv_only and 2.85 or 2.35)) ..
";0.9,0.7;craftguide_arrow.png]" ..
"item_image_button[" .. (xoffset - 2) .. "," ..
(iY + (sfinv_only and 2.7 or 2.2)) .. ";1,1;" ..
output .. ";" .. output .. ";]" .. self:get_tooltip(output)
BUTTON_SIZE = 1.1
end
function craftguide:get_formspec(player_name, is_fuel)
local custom_recipe = craftguide.craft_types[recipe_type]
if recipe_type == "cooking" or custom_recipe or
(recipe_type == "normal" and width == 0) then
local icon = recipe_type == "cooking" and "furnace" or "shapeless"
fs[#fs + 1] = fmt("image[%f,%f;%f,%f;%s]",
rightest + 1.2,
iY + (sfinv_only and 2.2 or 1.7),
0.5,
0.5,
custom_recipe and custom_recipe.icon or
"craftguide_" .. icon .. ".png^[resize:16x16")
fs[#fs + 1] = fmt("tooltip[%f,%f;%f,%f;%s]",
rightest + 1.2,
iY + (sfinv_only and 2.2 or 1.7),
0.5,
0.5,
custom_recipe and custom_recipe.description or
recipe_type:gsub("^%l", string.upper))
end
local output = recipes[recipe_num].output
local output_s = output:match("%S+")
local arrow_X = rightest + (s_btn_size or BUTTON_SIZE)
local output_X = arrow_X + 0.9
fs[#fs + 1] = fmt("image[%f,%f;%f,%f;%s]",
arrow_X,
iY + (sfinv_only and 2.85 or 2.35),
0.9,
0.7,
"craftguide_arrow.png")
if output == "BURN" then
fs[#fs + 1] = fmt("image[%f,%f;%f,%f;%s]",
output_X,
iY + (sfinv_only and 2.68 or 2.18),
1.1,
1.1,
"craftguide_fire.png")
else
fs[#fs + 1] = fmt("item_image_button[%f,%f;%f,%f;%s;%s;]",
output_X,
iY + (sfinv_only and 2.7 or 2.2),
BUTTON_SIZE,
BUTTON_SIZE,
output,
output_s)
end
fs[#fs + 1] = get_tooltip(output_s)
local output_is_fuel = get_fueltime(output) > 0
if output_is_fuel then
fs[#fs + 1] = fmt("image[%f,%f;%f,%f;%s]",
output_X + 1,
iY + (sfinv_only and 2.83 or 2.33),
0.6,
0.4,
"craftguide_arrow.png")
fs[#fs + 1] = fmt("image[%f,%f;%f,%f;%s]",
output_X + 1.6,
iY + (sfinv_only and 2.68 or 2.18),
0.6,
0.6,
"craftguide_fire.png")
end
return concat(fs)
end
local function get_formspec(player_name)
local data = datas[player_name]
local iY = sfinv_only and 4 or data.iX - 5
local ipp = data.iX * iY
@ -180,110 +353,95 @@ function craftguide:get_formspec(player_name, is_fuel)
data.pagemax = max(1, ceil(#data.items / ipp))
local formspec = ""
local fs = {}
if not sfinv_only then
formspec = formspec ..
"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") .. "]" ..
"button[" .. (data.iX * 0.48) .. ",-0.02;0.7,1;size_inc;+]" ..
"button[" .. ((data.iX * 0.48) + 0.5) .. ",-0.02;0.7,1;size_dec;-]"
fs[#fs + 1] = "size[" .. (data.iX - 0.35) .. "," .. (iY + 4) .. ";]"
fs[#fs + 1] = "tooltip[size_inc;" .. S("Increase window size") .. "]"
fs[#fs + 1] = "tooltip[size_dec;" .. S("Decrease window size") .. "]"
fs[#fs + 1] = "image_button[" .. (data.iX * 0.47) ..
",0.12;0.8,0.8;craftguide_zoomin_icon.png;size_inc;]"
fs[#fs + 1] = "image_button[" .. ((data.iX * 0.47) + 0.6) ..
",0.12;0.8,0.8;craftguide_zoomout_icon.png;size_dec;]"
end
formspec = formspec .. [[
button[2.4,0.23;0.8,0.5;search;?]
button[3.05,0.23;0.8,0.5;clear;X]
fs[#fs + 1] = [[
background[1,1;1,1;craftguide_bg.png;true]
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]
]] ..
"tooltip[search;" .. S("Search") .. "]" ..
"tooltip[clear;" .. S("Reset") .. "]" ..
"tooltip[prev;" .. S("Previous page") .. "]" ..
"tooltip[next;" .. S("Next page") .. "]" ..
"button[" .. (data.iX - 3.1) .. ",0;0.8,0.95;prev;<]" ..
"label[" .. (data.iX - 2.2) .. ",0.18;" ..
colorize(data.pagenum) .. " / " .. data.pagemax .. "]" ..
"button[" .. (data.iX - 1.2) .. ",0;0.8,0.95;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 + (even_num and 0.5 or 0)
fs[#fs + 1] = "tooltip[search;" .. S("Search") .. "]"
fs[#fs + 1] = "tooltip[clear;" .. S("Reset") .. "]"
fs[#fs + 1] = "tooltip[prev;" .. S("Previous page") .. "]"
fs[#fs + 1] = "tooltip[next;" .. S("Next page") .. "]"
fs[#fs + 1] = "image_button[" .. (data.iX - (sfinv_only and 2.6 or 3.1)) ..
",0.12;0.8,0.8;craftguide_prev_icon.png;prev;]"
fs[#fs + 1] = "label[" .. (data.iX - (sfinv_only and 1.7 or 2.2)) ..
",0.22;" .. colorize(data.pagenum) .. " / " .. data.pagemax .. "]"
fs[#fs + 1] = "image_button[" .. (data.iX - (sfinv_only and 0.7 or 1.2) -
(data.iX >= 11 and 0.08 or 0)) ..
",0.12;0.8,0.8;craftguide_next_icon.png;next;]"
fs[#fs + 1] = "field[0.3,0.32;2.5,1;filter;;" .. mt.formspec_escape(data.filter) .. "]"
local xoffset = data.iX / 2.15
if not next(data.items) then
formspec = formspec ..
"label[" .. (xoffset - (even_num and 1.5 or 1)) .. ",2;" ..
S("No item to show") .. "]"
fs[#fs + 1] = fmt("label[%f,%f;%s]",
(data.iX / 2) - 1,
2,
S("No item to show"))
end
local first_item = (data.pagenum - 1) * ipp
for i = first_item, first_item + ipp - 1 do
local name = data.items[i + 1]
if not name then break end
if not name then
break
end
local X = i % data.iX
local Y = (i % ipp - X) / data.iX + 1
formspec = formspec ..
"item_image_button[" .. (X - (X * 0.05)) .. "," .. Y .. ";1.1,1.1;" ..
name .. ";" .. name .. "_inv;]"
fs[#fs + 1] = fmt("item_image_button[%f,%f;%f,%f;%s;%s;]",
X - (sfinv_only and 0 or (X * 0.05)),
Y,
BUTTON_SIZE,
BUTTON_SIZE,
name,
name)
end
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
formspec = formspec ..
"image[" .. (xoffset - 1) .. "," ..
(iY + (sfinv_only and 2.85 or 2.35)) ..
";0.9,0.7;craftguide_arrow.png]" ..
"item_image_button[" .. xoffset .. "," ..
(iY + (sfinv_only and 2.7 or 2.2)) ..
";1,1;" .. data.item .. ";" .. data.item .. ";]" ..
self:get_tooltip(data.item) ..
"image[" .. (xoffset - 2) .. "," ..
(iY + (sfinv_only and 2.68 or 2.18)) ..
";1,1;craftguide_fire.png]"
else
local show_usage = data.show_usage
formspec = formspec ..
self:get_recipe(iY, xoffset,
if data.input and reg_items[data.input] then
local usage = data.show_usage
fs[#fs + 1] = get_recipe_fs(data.iX,
iY,
xoffset,
data.rnum,
(show_usage and data.usages or data.recipes_item),
show_usage)
end
(usage and data.usages or data.recipes_item),
usage)
end
data.formspec = formspec
fs = concat(fs)
data.formspec = fs
if sfinv_only then
return formspec
return fs
else
show_formspec(player_name, "craftguide", formspec)
show_formspec(player_name, "craftguide", fs)
end
end
local function player_has_item(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
local show_fs = function(player, player_name)
if sfinv_only then
local context = sfinv.get_or_create_context(player)
sfinv.set_player_inventory_formspec(player, context)
else
get_formspec(player_name)
end
end
return items_with_group
end
local function item_in_inv(inv, item)
return inv:contains_item("main", item)
end
function craftguide:recipe_in_inv(inv, item_name, recipes_f)
local function recipe_in_inv(inv, item_name, recipes_f)
local recipes = recipes_f or get_recipes(item_name) or {}
local show_item_recipes = {}
@ -299,6 +457,7 @@ function craftguide:recipe_in_inv(inv, item_name, recipes_f)
end
end
end
if not group_in_inv and not item_in_inv(inv, item) then
show_item_recipes[i] = false
end
@ -311,28 +470,10 @@ function craftguide:recipe_in_inv(inv, item_name, recipes_f)
end
end
return recipes, player_has_item(show_item_recipes)
return recipes, in_table(show_item_recipes)
end
function craftguide:get_init_items()
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 function get_filter_items(data, player)
local filter = data.filter
if datas.searches[filter] then
data.items = datas.searches[filter]
@ -353,7 +494,7 @@ function craftguide:get_filter_items(data, player)
filtered_list[counter] = item
end
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
counter = counter + 1
filtered_list[counter] = item
@ -377,7 +518,73 @@ function craftguide:get_filter_items(data, player)
data.items = filtered_list
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] = {
type = craft.type,
width = craft.width,
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 = {}
for name, def in pairs(reg_items) do
if not (def.groups.not_in_craft_guide == 1 or
@ -414,101 +621,111 @@ local function get_fields(player, ...)
formname, fields = args[1], args[2]
end
if not sfinv_only and formname ~= "craftguide" then return end
if not sfinv_only and formname ~= "craftguide" then
return
end
local player_name = player:get_player_name()
local data = datas[player_name]
local show_fs = function(is_fuel)
if sfinv_only then
local context = sfinv.get_or_create_context(player)
context.fuel = is_fuel
sfinv.set_player_inventory_formspec(player, context)
else
craftguide:get_formspec(player_name, is_fuel)
end
end
if fields.clear then
data.show_usage = nil
data.filter = ""
data.item = nil
data.pagenum = 1
data.rnum = 1
data.items = progressive_mode and data.init_filter_items or datas.init_items
show_fs()
reset_datas(data)
show_fs(player, player_name)
elseif fields.alternate then
local num
if data.show_usage then
num = data.usages[data.rnum + 1]
else
num = data.recipes_item[data.rnum + 1]
if #(data.show_usage and data.usages or data.recipes_item) == 1 then
return
end
data.rnum = num and data.rnum + 1 or 1
show_fs()
local next_i
if data.show_usage then
next_i = data.usages[data.rnum + 1]
else
next_i = data.recipes_item[data.rnum + 1]
end
data.rnum = next_i and data.rnum + 1 or 1
show_fs(player, player_name)
elseif (fields.key_enter_field == "filter" or fields.search) and
fields.filter ~= "" then
data.filter = fields.filter:lower()
data.pagenum = 1
craftguide:get_filter_items(data, player)
show_fs()
get_filter_items(data, player)
show_fs(player, player_name)
elseif fields.prev or fields.next then
data.pagenum = data.pagenum - (fields.prev and 1 or -1)
if data.pagenum > data.pagemax then
data.pagenum = 1
elseif data.pagenum == 0 then
data.pagenum = data.pagemax
end
show_fs()
show_fs(player, player_name)
elseif (fields.size_inc and data.iX < MAX_LIMIT) or
(fields.size_dec and data.iX > MIN_LIMIT) then
data.pagenum = 1
data.iX = data.iX - (fields.size_dec and 1 or -1)
show_fs()
show_fs(player, player_name)
else for item in pairs(fields) do
if item:find(":") then
if item:sub(-4) == "_inv" then
item = item:sub(1,-5)
elseif item:find("%s") then
if item:find("%s") then
item = item:match("%S*")
end
local is_fuel = get_fueltime(item) > 0
local recipes = get_recipes(item)
if not recipes and not is_fuel then return end
local recipes = get_recipes(item) or {}
recipes = add_custom_recipes(item, recipes)
if not data.show_usage and item == data.item and not progressive_mode then
data.usages = craftguide:get_item_usages(item)
if next(data.usages) then
data.show_usage = true
data.rnum = 1
local no_recipes = not next(recipes)
if no_recipes and not is_fuel then
return
end
show_fs()
if item ~= data.input then
data.show_usage = nil
else
if progressive_mode then
local inv = player:get_inventory()
local _, has_item = craftguide:recipe_in_inv(inv, item)
if not has_item then return end
recipes = craftguide:recipe_in_inv(inv, item, recipes)
data.show_usage = not data.show_usage
end
data.item = item
if not progressive_mode and is_fuel and no_recipes then
data.show_usage = true
end
if data.show_usage then
data.usages = get_item_usages(item)
if is_fuel then
data.usages[#data.usages + 1] = {
width = 1,
type = "normal",
items = {item},
output = "BURN",
}
end
if not next(data.usages) then
data.show_usage = nil
end
elseif progressive_mode then
local inv = player:get_inventory()
local has_item
recipes, has_item = recipe_in_inv(inv, item, recipes)
if not has_item then
return
end
end
data.input = item
data.recipes_item = recipes
data.rnum = 1
data.show_usage = nil
show_fs(is_fuel)
end
show_fs(player, player_name)
end
end
end
@ -517,29 +734,25 @@ end
if sfinv_only then
sfinv.register_page("craftguide:craftguide", {
title = "Craft Guide",
get = function(self, player, context)
local player_name = player:get_player_name()
return sfinv.make_formspec(
player,
context,
craftguide:get_formspec(player_name, context.fuel)
get_formspec(player_name)
)
end,
on_enter = function(self, player, context)
if not datas.init_items then
craftguide:get_init_items()
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
datas[player_name] = {filter = "", pagenum = 1, iX = 8}
if progressive_mode then
craftguide:get_filter_items(datas[player_name], player)
end
init_datas(player, player_name)
end
end,
on_player_receive_fields = function(self, player, context, fields)
get_fields(player, fields)
end,
@ -547,21 +760,13 @@ if sfinv_only then
else
mt.register_on_player_receive_fields(get_fields)
function craftguide:on_use(itemstack, user)
if not datas.init_items then
self:get_init_items()
end
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
datas[player_name] = {filter = "", pagenum = 1, iX = DEFAULT_SIZE}
if progressive_mode then
self:get_filter_items(datas[player_name], user)
end
self:get_formspec(player_name)
init_datas(user, player_name)
get_formspec(player_name)
else
show_formspec(player_name, "craftguide", data.formspec)
end
@ -574,7 +779,7 @@ else
stack_max = 1,
groups = {book = 1},
on_use = function(itemstack, user)
craftguide:on_use(itemstack, user)
on_use(itemstack, user)
end
})
@ -594,12 +799,14 @@ else
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)
local meta = mt.get_meta(pos)
meta:set_string("infotext", S("Crafting Guide Sign"))
end,
on_rightclick = function(pos, node, user, itemstack)
craftguide:on_use(itemstack, user)
on_use(itemstack, user)
end
})
@ -626,16 +833,81 @@ else
recipe = "craftguide:sign",
burntime = 10
})
end
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)
craftguide:on_use(nil, player)
end,
image = "craftguide_book.png",
action = function(player)
on_use(nil, player)
end,
})
end
end
if not progressive_mode then
mt.register_chatcommand("craft", {
description = S("Show recipe(s) of the pointed node"),
func = function(name)
local player = mt.get_player_by_name(name)
local ppos = player:get_pos()
local dir = player:get_look_dir()
local eye_h = {x = ppos.x, y = ppos.y + 1.625, z = ppos.z}
local node_name
for i = 1, 10 do
local look_at = vector_add(eye_h, vector_mul(dir, i))
local node = mt.get_node(look_at)
if node.name ~= "air" then
node_name = node.name
break
end
end
if not node_name then
return false, colorize("[craftguide] ", "red") ..
S("No node pointed")
elseif not datas[name] then
init_datas(player, name)
end
local data = datas[name]
reset_datas(data)
local is_fuel = get_fueltime(node_name) > 0
local recipes = get_recipes(node_name) or {}
recipes = add_custom_recipes(node_name, recipes)
local no_recipes = not next(recipes)
if no_recipes and not is_fuel then
return false, colorize("[craftguide] ", "red") ..
S("No recipe for this node:") .. " " ..
colorize(node_name)
end
if is_fuel and no_recipes then
data.usages = get_item_usages(node_name)
if is_fuel then
data.usages[#data.usages + 1] = {
width = 1,
type = "normal",
items = {node_name},
output = "BURN",
}
end
if next(data.usages) then
data.show_usage = true
end
end
data.input = node_name
data.recipes_item = recipes
return true, show_fs(player, name)
end,
})
end

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