Compare commits

..

1 Commits

Author SHA1 Message Date
d6542a2697 Ajoute message de chargement du mod dans le journal "action" 2018-12-24 01:25:12 +01:00
3 changed files with 259 additions and 505 deletions

View File

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

View File

@ -3,36 +3,13 @@
#### `craftguide` is the most comprehensive crafting guide on Minetest. #### #### `craftguide` is the most comprehensive crafting guide on Minetest. ####
#### Consult the [Minetest Wiki](http://wiki.minetest.net/Crafting_guide) for more details. #### #### Consult the [Minetest Wiki](http://wiki.minetest.net/Crafting_guide) for more details. ####
This crafting guide is a blue book named *"Crafting Guide"* or a wooden sign. #### This crafting guide is usable with a blue book named *"Crafting Guide"* ####
This crafting guide features a **progressive mode**. #### 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 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`.
`craftguide` is also integrated in `sfinv` (Minetest Game inventory) when you enable it with `craftguide` is also integrated in `sfinv` (Minetest Game inventory) when you enable it with
`craftguide_sfinv_only = true` in `minetest.conf`. `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 = "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) ![Preview2](https://i.imgur.com/bToFH38.png)

708
init.lua
View File

@ -1,10 +1,4 @@
craftguide = { local craftguide, datas, mt = {}, {searches = {}}, minetest
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 sfinv_only = mt.settings:get_bool("craftguide_sfinv_only")
@ -13,7 +7,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 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 = mt.get_modpath("craftguide") craftguide.path = minetest.get_modpath("craftguide")
-- Intllib -- Intllib
local S = dofile(craftguide.path .. "/intllib.lua") local S = dofile(craftguide.path .. "/intllib.lua")
@ -21,10 +15,8 @@ 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, concat = table.remove, table.maxn, table.sort, table.concat 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 fmt = string.format
local DEFAULT_SIZE = 10 local DEFAULT_SIZE = 10
local MIN_LIMIT, MAX_LIMIT = 10, 12 local MIN_LIMIT, MAX_LIMIT = 10, 12
@ -43,99 +35,7 @@ local group_stereotypes = {
mesecon_conductor_craftable = "mesecons:wire_00000000_off", mesecon_conductor_craftable = "mesecons:wire_00000000_off",
} }
local function extract_groups(str) function craftguide:group_to_item(item)
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 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
@ -154,7 +54,20 @@ local function 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 get_tooltip(item, recipe_type, cooktime, groups) 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 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
@ -191,24 +104,16 @@ local function get_tooltip(item, recipe_type, cooktime, groups)
return has_extras and tooltip .. "]" or "" return has_extras and tooltip .. "]" or ""
end end
local function get_recipe_fs(iX, iY, xoffset, recipe_num, recipes, show_usage) function craftguide:get_recipe(iX, iY, xoffset, recipe_num, recipes, show_usage)
if not recipes[1] then local formspec, recipes_total = "", #recipes
return "" if recipes_total > 1 then
formspec = formspec ..
"button[" .. (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")) .. " " ..
S("@1 of @2", recipe_num, recipes_total) .. "]"
end 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 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
@ -223,20 +128,18 @@ local function get_recipe_fs(iX, iY, xoffset, recipe_num, recipes, show_usage)
local rows = ceil(maxn(items) / width) local rows = ceil(maxn(items) / width)
local rightest, s_btn_size = 0 local rightest, s_btn_size = 0
if recipe_type ~= "cooking" and (width > GRID_LIMIT or rows > GRID_LIMIT) then if recipe_type == "normal" and (width > GRID_LIMIT or rows > GRID_LIMIT) then
fs[#fs + 1] = fmt("label[%f,%f;%s]", formspec = formspec ..
(iX / 2) - 2, "label[" .. ((iX / 2) - 2) .. "," .. (iY + 2.2) .. ";" ..
iY + 2.2, S("Recipe is too big to be displayed (@1x@2)", width, rows) .. "]"
S("Recipe is too big to be displayed (@1x@2)", width, rows)) return formspec
return concat(fs)
else else
for i, v in pairs(items) do for i, v in pairs(items) do
local X = ceil((i - 1) % width + xoffset - width) - local X = ceil((i - 1) % width + xoffset - width) -
(sfinv_only and 0 or 0.2) (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 ~= "cooking" and (width > 3 or rows > 3) then if recipe_type == "normal" and (width > 3 or rows > 3) then
BUTTON_SIZE = width > 3 and 3 / width or 3 / rows BUTTON_SIZE = width > 3 and 3 / width or 3 / rows
s_btn_size = BUTTON_SIZE s_btn_size = BUTTON_SIZE
X = BUTTON_SIZE * (i % width) + xoffset - 2.65 X = BUTTON_SIZE * (i % width) + xoffset - 2.65
@ -249,100 +152,60 @@ local function get_recipe_fs(iX, iY, xoffset, recipe_num, recipes, show_usage)
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 = group_to_item(v) local item_r = self:group_to_item(v)
local tltp = get_tooltip(item_r, recipe_type, cooktime, groups) local tltip = self:get_tooltip(item_r, recipe_type, cooktime, groups)
fs[#fs + 1] = fmt("item_image_button[%f,%f;%f,%f;%s;%s;%s]", formspec = formspec ..
X, "item_image_button[" .. X .. "," ..
Y + (sfinv_only and 0.7 or 0.2), (Y + (sfinv_only and 0.7 or 0.2)) .. ";" ..
BUTTON_SIZE, BUTTON_SIZE .. "," .. BUTTON_SIZE .. ";" .. item_r ..
BUTTON_SIZE, ";" .. item_r .. ";" .. label .. "]" .. tltip
item_r,
item_r:match("%S*"),
label)
fs[#fs + 1] = tltp
end end
BUTTON_SIZE = 1.1 BUTTON_SIZE = 1.1
end end
local custom_recipe = craftguide.craft_types[recipe_type] if recipe_type == "cooking" or (recipe_type == "normal" and width == 0) then
if recipe_type == "cooking" or custom_recipe or
(recipe_type == "normal" and width == 0) then
local icon = recipe_type == "cooking" and "furnace" or "shapeless" local icon = recipe_type == "cooking" and "furnace" or "shapeless"
formspec = formspec ..
fs[#fs + 1] = fmt("image[%f,%f;%f,%f;%s]", "image[" .. (rightest + 1.2) .. "," ..
rightest + 1.2, (iY + (sfinv_only and 2.2 or 1.7)) ..
iY + (sfinv_only and 2.2 or 1.7), ";0.5,0.5;craftguide_" .. icon .. ".png]"
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 end
local output = recipes[recipe_num].output local output = recipes[recipe_num].output:match("%S+")
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 arrow_X = rightest + (s_btn_size or BUTTON_SIZE)
local output_X = arrow_X + 0.9 local output_X = arrow_X + 0.9
fs[#fs + 1] = fmt("image[%f,%f;%f,%f;%s]", formspec = formspec ..
arrow_X, "image[" .. arrow_X .. "," ..
iY + (sfinv_only and 2.85 or 2.35), (iY + (sfinv_only and 2.85 or 2.35)) ..
0.9, ";0.9,0.7;craftguide_arrow.png]" ..
0.7,
"craftguide_arrow.png")
if output == "BURN" then "item_image_button[" .. output_X .. "," ..
fs[#fs + 1] = fmt("image[%f,%f;%f,%f;%s]", (iY + (sfinv_only and 2.7 or 2.2)) .. ";" ..
output_X, BUTTON_SIZE .. "," .. BUTTON_SIZE .. ";" ..
iY + (sfinv_only and 2.68 or 2.18), output .. ";" .. output .. ";]" ..
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) self:get_tooltip(output)
local output_is_fuel = get_fueltime(output) > 0
if output_is_fuel then if output_is_fuel then
fs[#fs + 1] = fmt("image[%f,%f;%f,%f;%s]", formspec = formspec ..
output_X + 1, "image[" .. (output_X + 1) .. "," ..
iY + (sfinv_only and 2.83 or 2.33), (iY + (sfinv_only and 2.83 or 2.33)) ..
0.6, ";0.6,0.4;craftguide_arrow.png]" ..
0.4,
"craftguide_arrow.png")
fs[#fs + 1] = fmt("image[%f,%f;%f,%f;%s]", "image[" .. (output_X + 1.6) .. "," ..
output_X + 1.6, (iY + (sfinv_only and 2.68 or 2.18)) ..
iY + (sfinv_only and 2.68 or 2.18), ";0.6,0.6;craftguide_fire.png]"
0.6,
0.6,
"craftguide_fire.png")
end end
return concat(fs) return formspec
end end
local function get_formspec(player_name) function craftguide:get_formspec(player_name, is_fuel)
local data = datas[player_name] local data = datas[player_name]
local iY = sfinv_only and 4 or data.iX - 5 local iY = sfinv_only and 4 or data.iX - 5
local ipp = data.iX * iY local ipp = data.iX * iY
@ -353,95 +216,122 @@ local function get_formspec(player_name)
data.pagemax = max(1, ceil(#data.items / ipp)) data.pagemax = max(1, ceil(#data.items / ipp))
local fs = {} local formspec = ""
if not sfinv_only then if not sfinv_only then
fs[#fs + 1] = "size[" .. (data.iX - 0.35) .. "," .. (iY + 4) .. ";]" formspec = formspec ..
fs[#fs + 1] = "tooltip[size_inc;" .. S("Increase window size") .. "]" "size[" .. (data.iX - 0.35) .. "," .. (iY + 4) .. ";]" ..
fs[#fs + 1] = "tooltip[size_dec;" .. S("Decrease window size") .. "]" "background[1,1;1,1;craftguide_bg.png;true]" ..
fs[#fs + 1] = "image_button[" .. (data.iX * 0.47) .. "tooltip[size_inc;" .. S("Increase window size") .. "]" ..
",0.12;0.8,0.8;craftguide_zoomin_icon.png;size_inc;]" "tooltip[size_dec;" .. S("Decrease window size") .. "]" ..
fs[#fs + 1] = "image_button[" .. ((data.iX * 0.47) + 0.6) .. "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;]" ",0.12;0.8,0.8;craftguide_zoomout_icon.png;size_dec;]"
end end
fs[#fs + 1] = [[ formspec = formspec .. [[
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[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;] 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") .. "]" ..
fs[#fs + 1] = "tooltip[search;" .. S("Search") .. "]" "tooltip[clear;" .. S("Reset") .. "]" ..
fs[#fs + 1] = "tooltip[clear;" .. S("Reset") .. "]" "tooltip[prev;" .. S("Previous page") .. "]" ..
fs[#fs + 1] = "tooltip[prev;" .. S("Previous page") .. "]" "tooltip[next;" .. S("Next page") .. "]" ..
fs[#fs + 1] = "tooltip[next;" .. S("Next page") .. "]" "image_button[" .. (data.iX - (sfinv_only and 2.6 or 3.1)) ..
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;]" ..
",0.12;0.8,0.8;craftguide_prev_icon.png;prev;]" "label[" .. (data.iX - (sfinv_only and 1.7 or 2.2)) .. ",0.22;" ..
fs[#fs + 1] = "label[" .. (data.iX - (sfinv_only and 1.7 or 2.2)) .. colorize(data.pagenum) .. " / " .. data.pagemax .. "]" ..
",0.22;" .. colorize(data.pagenum) .. " / " .. data.pagemax .. "]" "image_button[" .. (data.iX - (sfinv_only and 0.7 or 1.2) -
fs[#fs + 1] = "image_button[" .. (data.iX - (sfinv_only and 0.7 or 1.2) -
(data.iX >= 11 and 0.08 or 0)) .. (data.iX >= 11 and 0.08 or 0)) ..
",0.12;0.8,0.8;craftguide_next_icon.png;next;]" ",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) .. "]" "field[0.3,0.32;2.5,1;filter;;" .. mt.formspec_escape(data.filter) .. "]"
local xoffset = data.iX / 2.15 local xoffset = data.iX / 2.15
if not next(data.items) then if not next(data.items) then
fs[#fs + 1] = fmt("label[%f,%f;%s]", formspec = formspec ..
(data.iX / 2) - 1, "label[" .. ((data.iX / 2) - 1) .. ",2;" .. S("No item to show") .. "]"
2,
S("No item to show"))
end end
local first_item = (data.pagenum - 1) * ipp local first_item = (data.pagenum - 1) * ipp
for i = first_item, first_item + ipp - 1 do for i = first_item, first_item + ipp - 1 do
local name = data.items[i + 1] local name = data.items[i + 1]
if not name then if not name then break end
break
end
local X = i % data.iX local X = i % data.iX
local Y = (i % ipp - X) / data.iX + 1 local Y = (i % ipp - X) / data.iX + 1
fs[#fs + 1] = fmt("item_image_button[%f,%f;%f,%f;%s;%s;]", formspec = formspec ..
X - (sfinv_only and 0 or (X * 0.05)), "item_image_button[" ..
Y, (X - (sfinv_only and 0 or (X * 0.05))) .. "," ..
BUTTON_SIZE, Y .. ";" .. BUTTON_SIZE .. "," .. BUTTON_SIZE .. ";" ..
BUTTON_SIZE, name .. ";" .. name .. "_inv;]"
name,
name)
end end
if data.input and reg_items[data.input] then if data.item and reg_items[data.item] then
local usage = data.show_usage if not data.recipes_item or (is_fuel and not get_recipe(data.item).items) then
fs[#fs + 1] = get_recipe_fs(data.iX, local X = floor(xoffset) - (sfinv_only and 0 or 0.2)
formspec = formspec ..
"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]" ..
self:get_tooltip(data.item) ..
"image[" .. (X + 2.1) .. "," ..
(iY + (sfinv_only and 2.68 or 2.18)) ..
";1.1,1.1;craftguide_fire.png]"
else
local show_usage = data.show_usage
formspec = formspec ..
self:get_recipe(data.iX,
iY, iY,
xoffset, xoffset,
data.rnum, data.rnum,
(usage and data.usages or data.recipes_item), (show_usage and data.usages or data.recipes_item),
usage) show_usage)
end
end end
fs = concat(fs) data.formspec = formspec
data.formspec = fs
if sfinv_only then if sfinv_only then
return fs return formspec
else else
show_formspec(player_name, "craftguide", fs) show_formspec(player_name, "craftguide", formspec)
end end
end end
local show_fs = function(player, player_name) local function player_has_item(T)
if sfinv_only then for i = 1, #T do
local context = sfinv.get_or_create_context(player) if T[i] then
sfinv.set_player_inventory_formspec(player, context) return true
else end
get_formspec(player_name)
end end
end end
local function recipe_in_inv(inv, item_name, recipes_f) 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
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 = {}
@ -457,7 +347,6 @@ local function recipe_in_inv(inv, item_name, recipes_f)
end end
end end
end end
if not group_in_inv and not item_in_inv(inv, item) then if not group_in_inv and not item_in_inv(inv, item) then
show_item_recipes[i] = false show_item_recipes[i] = false
end end
@ -470,10 +359,28 @@ local function recipe_in_inv(inv, item_name, recipes_f)
end end
end end
return recipes, in_table(show_item_recipes) return recipes, player_has_item(show_item_recipes)
end end
local function get_filter_items(data, player) 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 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]
@ -494,7 +401,7 @@ local function 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 = recipe_in_inv(inv, item) local _, has_item = self: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
@ -518,73 +425,7 @@ local function get_filter_items(data, player)
data.items = filtered_list data.items = filtered_list
end end
local function init_datas(user, name) function craftguide:get_item_usages(item)
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 = {} 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
@ -621,111 +462,101 @@ local function get_fields(player, ...)
formname, fields = args[1], args[2] formname, fields = args[1], args[2]
end end
if not sfinv_only and formname ~= "craftguide" then if not sfinv_only and formname ~= "craftguide" then return end
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]
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 if fields.clear then
reset_datas(data) data.show_usage = nil
show_fs(player, player_name) 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()
elseif fields.alternate then elseif fields.alternate then
if #(data.show_usage and data.usages or data.recipes_item) == 1 then local num
return
end
local next_i
if data.show_usage then if data.show_usage then
next_i = data.usages[data.rnum + 1] num = data.usages[data.rnum + 1]
else else
next_i = data.recipes_item[data.rnum + 1] num = data.recipes_item[data.rnum + 1]
end end
data.rnum = next_i and data.rnum + 1 or 1 data.rnum = num and data.rnum + 1 or 1
show_fs(player, player_name) show_fs()
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
get_filter_items(data, player) craftguide:get_filter_items(data, player)
show_fs(player, player_name) show_fs()
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)
if data.pagenum > data.pagemax then if data.pagenum > data.pagemax then
data.pagenum = 1 data.pagenum = 1
elseif data.pagenum == 0 then elseif data.pagenum == 0 then
data.pagenum = data.pagemax data.pagenum = data.pagemax
end end
show_fs(player, player_name) show_fs()
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)
show_fs(player, player_name) show_fs()
else for item in pairs(fields) do else for item in pairs(fields) do
if item:find(":") then if item:find(":") then
if item:find("%s") then if item:sub(-4) == "_inv" then
item = item:sub(1,-5)
elseif item:find("%s") then
item = item:match("%S*") item = item:match("%S*")
end end
local is_fuel = get_fueltime(item) > 0 local is_fuel = get_fueltime(item) > 0
local recipes = get_recipes(item) or {} local recipes = get_recipes(item)
recipes = add_custom_recipes(item, recipes) if not recipes and not is_fuel then return end
local no_recipes = not next(recipes) if not data.show_usage and item == data.item and not progressive_mode then
if no_recipes and not is_fuel then data.usages = craftguide:get_item_usages(item)
return if next(data.usages) then
end
if item ~= data.input then
data.show_usage = nil
else
data.show_usage = not data.show_usage
end
if not progressive_mode and is_fuel and no_recipes then
data.show_usage = true data.show_usage = true
data.rnum = 1
end end
if data.show_usage then show_fs()
data.usages = get_item_usages(item) else
if progressive_mode then
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 inv = player:get_inventory()
local has_item local _, has_item = craftguide:recipe_in_inv(inv, item)
recipes, has_item = recipe_in_inv(inv, item, recipes)
if not has_item then if not has_item then return end
return recipes = craftguide:recipe_in_inv(inv, item, recipes)
end
end end
data.input = item data.item = item
data.recipes_item = recipes data.recipes_item = recipes
data.rnum = 1 data.rnum = 1
data.show_usage = nil
show_fs(player, player_name) show_fs(is_fuel)
end
end end
end end
end end
@ -734,25 +565,29 @@ end
if sfinv_only then if sfinv_only then
sfinv.register_page("craftguide:craftguide", { sfinv.register_page("craftguide:craftguide", {
title = "Craft Guide", title = "Craft Guide",
get = function(self, player, context) get = function(self, player, context)
local player_name = player:get_player_name() local player_name = player:get_player_name()
return sfinv.make_formspec( return sfinv.make_formspec(
player, player,
context, context,
get_formspec(player_name) craftguide:get_formspec(player_name, context.fuel)
) )
end, end,
on_enter = function(self, player, context) on_enter = function(self, player, context)
if not datas.init_items then
craftguide:get_init_items()
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 progressive_mode or not data then if progressive_mode or not data then
init_datas(player, player_name) datas[player_name] = {filter = "", pagenum = 1, iX = 8}
if progressive_mode then
craftguide:get_filter_items(datas[player_name], player)
end
end end
end, end,
on_player_receive_fields = function(self, player, context, fields) on_player_receive_fields = function(self, player, context, fields)
get_fields(player, fields) get_fields(player, fields)
end, end,
@ -760,13 +595,21 @@ if sfinv_only then
else else
mt.register_on_player_receive_fields(get_fields) mt.register_on_player_receive_fields(get_fields)
local function on_use(itemstack, user) function craftguide:on_use(itemstack, user)
if not datas.init_items then
self:get_init_items()
end
local player_name = user:get_player_name() local player_name = user:get_player_name()
local data = datas[player_name] local data = datas[player_name]
if progressive_mode or not data then if progressive_mode or not data then
init_datas(user, player_name) datas[player_name] = {filter = "", pagenum = 1, iX = DEFAULT_SIZE}
get_formspec(player_name) if progressive_mode then
self:get_filter_items(datas[player_name], user)
end
self:get_formspec(player_name)
else else
show_formspec(player_name, "craftguide", data.formspec) show_formspec(player_name, "craftguide", data.formspec)
end end
@ -779,7 +622,7 @@ else
stack_max = 1, stack_max = 1,
groups = {book = 1}, groups = {book = 1},
on_use = function(itemstack, user) on_use = function(itemstack, user)
on_use(itemstack, user) craftguide:on_use(itemstack, user)
end end
}) })
@ -799,14 +642,12 @@ else
wall_bottom = {-0.4375, -0.5, -0.3125, 0.4375, -0.4375, 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} wall_side = {-0.5, -0.3125, -0.4375, -0.4375, 0.3125, 0.4375}
}, },
on_construct = function(pos) on_construct = function(pos)
local meta = mt.get_meta(pos) local meta = minetest.get_meta(pos)
meta:set_string("infotext", S("Crafting Guide Sign")) meta:set_string("infotext", S("Crafting Guide Sign"))
end, end,
on_rightclick = function(pos, node, user, itemstack) on_rightclick = function(pos, node, user, itemstack)
on_use(itemstack, user) craftguide:on_use(itemstack, user)
end end
}) })
@ -833,81 +674,16 @@ else
recipe = "craftguide:sign", recipe = "craftguide:sign",
burntime = 10 burntime = 10
}) })
end
if rawget(_G, "sfinv_buttons") then if rawget(_G, "sfinv_buttons") then
sfinv_buttons.register_button("craftguide", { sfinv_buttons.register_button("craftguide", {
title = S("Crafting Guide"), title = S("Crafting Guide"),
tooltip = S("Shows a list of available crafting recipes, cooking recipes and fuels"), tooltip = S("Shows a list of available crafting recipes, cooking recipes and fuels"),
image = "craftguide_book.png",
action = function(player) action = function(player)
on_use(nil, player) craftguide: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,
image = "craftguide_book.png",
}) })
end end
@ -933,3 +709,5 @@ for x = 1, 6 do
}) })
end end
]] ]]
minetest.log("action", "[craftguide] loaded.")