Compare commits
12 Commits
Author | SHA1 | Date | |
---|---|---|---|
e3861bcc6a | |||
6b76c8c10f | |||
5f68d2de11 | |||
ea12d5ca14 | |||
3d77ec58b4 | |||
83151cb394 | |||
337ac898cd | |||
cb0200a222 | |||
ae4b15a748 | |||
2fa14ae146 | |||
8b86dfc857 | |||
c468ab22fd |
13
API.md
@ -73,10 +73,6 @@ end)
|
||||
|
||||
Removes the recipe filter with the given name.
|
||||
|
||||
#### `craftguide.set_recipe_filter(name, function(recipe, player))`
|
||||
|
||||
Removes all recipe filters and adds a new one.
|
||||
|
||||
#### `craftguide.get_recipe_filters()`
|
||||
|
||||
Returns a map of recipe filters, indexed by name.
|
||||
@ -155,3 +151,12 @@ You can add a stereotype like so:
|
||||
```Lua
|
||||
craftguide.group_stereotypes.radioactive = "mod:item"
|
||||
```
|
||||
|
||||
#### `craftguide.background`
|
||||
|
||||
You can set a custom background theme by overriding this variable:
|
||||
|
||||
```Lua
|
||||
craftguide.background = "my_custom_bg.png"
|
||||
|
||||
```
|
||||
|
@ -17,5 +17,4 @@ Use the command `/craft` to show the recipe(s) of the pointed node.
|
||||
For developers, `craftguide` also has a [modding API](https://github.com/minetest-mods/craftguide/blob/master/API.md).
|
||||
|
||||
|
||||

|
||||
|
||||

|
||||
|
@ -1,2 +0,0 @@
|
||||
sfinv?
|
||||
sfinv_buttons?
|
503
init.lua
@ -1,6 +1,9 @@
|
||||
craftguide = {}
|
||||
|
||||
craftguide.background = "craftguide_bg_full.png"
|
||||
|
||||
local pdata = {}
|
||||
local core = core
|
||||
|
||||
-- Caches
|
||||
local init_items = {}
|
||||
@ -12,21 +15,29 @@ local fuel_cache = {}
|
||||
local progressive_mode = core.settings:get_bool("craftguide_progressive_mode")
|
||||
local sfinv_only = core.settings:get_bool("craftguide_sfinv_only") and rawget(_G, "sfinv")
|
||||
|
||||
local log = core.log
|
||||
local after = core.after
|
||||
local colorize = core.colorize
|
||||
local reg_items = core.registered_items
|
||||
local get_result = core.get_craft_result
|
||||
local get_players = core.get_connected_players
|
||||
local show_formspec = core.show_formspec
|
||||
local globalstep = core.register_globalstep
|
||||
local on_shutdown = core.register_on_shutdown
|
||||
local get_craft_result = core.get_craft_result
|
||||
local get_players = core.get_connected_players
|
||||
local on_joinplayer = core.register_on_joinplayer
|
||||
local register_command = core.register_chatcommand
|
||||
local get_all_recipes = core.get_all_craft_recipes
|
||||
local get_player_by_name = core.get_player_by_name
|
||||
local on_mods_loaded = core.register_on_mods_loaded
|
||||
local on_leaveplayer = core.register_on_leaveplayer
|
||||
local serialize, deserialize = core.serialize, core.deserialize
|
||||
local on_receive_fields = core.register_on_player_receive_fields
|
||||
|
||||
local ESC = core.formspec_escape
|
||||
local S = core.get_translator("craftguide")
|
||||
|
||||
local maxn, sort, concat, copy =
|
||||
table.maxn, table.sort, table.concat, table.copy
|
||||
local maxn, sort, concat, copy, insert =
|
||||
table.maxn, table.sort, table.concat, table.copy, table.insert
|
||||
|
||||
local fmt, find, gmatch, match, sub, split, upper, lower =
|
||||
string.format, string.find, string.gmatch, string.match,
|
||||
@ -36,11 +47,10 @@ local min, max, floor, ceil = math.min, math.max, math.floor, math.ceil
|
||||
local pairs, next = pairs, next
|
||||
local vec_add, vec_mul = vector.add, vector.multiply
|
||||
|
||||
local DEFAULT_SIZE = 10
|
||||
local MIN_LIMIT, MAX_LIMIT = 10, 12
|
||||
DEFAULT_SIZE = min(MAX_LIMIT, max(MIN_LIMIT, DEFAULT_SIZE))
|
||||
|
||||
local GRID_LIMIT = 5
|
||||
local ROWS = sfinv_only and 9 or 11
|
||||
local LINES = 5
|
||||
local IPP = ROWS * LINES
|
||||
local GRID_LIMIT = 8
|
||||
|
||||
local FMT = {
|
||||
box = "box[%f,%f;%f,%f;%s]",
|
||||
@ -63,24 +73,6 @@ craftguide.group_stereotypes = {
|
||||
mesecon_conductor_craftable = "mesecons:wire_00000000_off",
|
||||
}
|
||||
|
||||
local item_lists = {
|
||||
"main",
|
||||
"craft",
|
||||
"craftpreview",
|
||||
}
|
||||
|
||||
local function table_merge(t, t2)
|
||||
t, t2 = t or {}, t2 or {}
|
||||
local c = #t
|
||||
|
||||
for i = 1, #t2 do
|
||||
c = c + 1
|
||||
t[c] = t2[i]
|
||||
end
|
||||
|
||||
return t
|
||||
end
|
||||
|
||||
local function table_replace(t, val, new)
|
||||
for k, v in pairs(t) do
|
||||
if v == val then
|
||||
@ -89,36 +81,6 @@ local function table_replace(t, val, new)
|
||||
end
|
||||
end
|
||||
|
||||
local function table_diff(t, t2)
|
||||
local hash = {}
|
||||
|
||||
for i = 1, #t do
|
||||
local v = t[i]
|
||||
hash[v] = true
|
||||
end
|
||||
|
||||
for i = 1, #t2 do
|
||||
local v = t2[i]
|
||||
hash[v] = nil
|
||||
end
|
||||
|
||||
local diff, c = {}, 0
|
||||
|
||||
for i = 1, #t do
|
||||
local v = t[i]
|
||||
if hash[v] then
|
||||
c = c + 1
|
||||
diff[c] = v
|
||||
end
|
||||
end
|
||||
|
||||
return diff
|
||||
end
|
||||
|
||||
local function __func()
|
||||
return debug.getinfo(2, "n").name
|
||||
end
|
||||
|
||||
local function is_str(x)
|
||||
return type(x) == "string"
|
||||
end
|
||||
@ -135,24 +97,35 @@ local function is_func(x)
|
||||
return type(x) == "function"
|
||||
end
|
||||
|
||||
local custom_crafts, craft_types = {}, {}
|
||||
local craft_types = {}
|
||||
|
||||
function craftguide.register_craft_type(name, def)
|
||||
local func = "craftguide." .. __func() .. "(): "
|
||||
assert(is_str(name), func .. "'name' field missing")
|
||||
assert(is_str(def.description), func .. "'description' field missing")
|
||||
assert(is_str(def.icon), func .. "'icon' field missing")
|
||||
if not is_str(name) or name == "" then
|
||||
return log("error", "craftguide.register_craft_type(): name missing")
|
||||
end
|
||||
|
||||
if not is_str(def.description) then
|
||||
def.description = ""
|
||||
end
|
||||
|
||||
if not is_str(def.icon) then
|
||||
def.icon = ""
|
||||
end
|
||||
|
||||
craft_types[name] = def
|
||||
end
|
||||
|
||||
function craftguide.register_craft(def)
|
||||
if not is_table(def) or not next(def) then
|
||||
return log("error", "craftguide.register_craft(): craft definition missing")
|
||||
end
|
||||
|
||||
if def.result then
|
||||
def.output = def.result -- Backward compatibility
|
||||
end
|
||||
|
||||
if not is_str(def.output) then
|
||||
def.output = ""
|
||||
if not is_str(def.output) or def.output == "" then
|
||||
return log("error", "craftguide.register_craft(): output missing")
|
||||
end
|
||||
|
||||
if not is_table(def.items) then
|
||||
@ -188,15 +161,19 @@ function craftguide.register_craft(def)
|
||||
end
|
||||
end
|
||||
|
||||
custom_crafts[#custom_crafts + 1] = def
|
||||
local output = match(def.output, "%S*")
|
||||
recipes_cache[output] = recipes_cache[output] or {}
|
||||
insert(recipes_cache[output], def)
|
||||
end
|
||||
|
||||
local recipe_filters = {}
|
||||
|
||||
function craftguide.add_recipe_filter(name, f)
|
||||
local func = "craftguide." .. __func() .. "(): "
|
||||
assert(is_str(name), func .. "filter name missing")
|
||||
assert(is_func(f), func .. "filter function missing")
|
||||
if not is_str(name) or name == "" then
|
||||
return log("error", "craftguide.add_recipe_filter(): name missing")
|
||||
elseif not is_func(f) then
|
||||
return log("error", "craftguide.add_recipe_filter(): function missing")
|
||||
end
|
||||
|
||||
recipe_filters[name] = f
|
||||
end
|
||||
@ -205,14 +182,6 @@ function craftguide.remove_recipe_filter(name)
|
||||
recipe_filters[name] = nil
|
||||
end
|
||||
|
||||
function craftguide.set_recipe_filter(name, f)
|
||||
local func = "craftguide." .. __func() .. "(): "
|
||||
assert(is_str(name), func .. "filter name missing")
|
||||
assert(is_func(f), func .. "filter function missing")
|
||||
|
||||
recipe_filters = {[name] = f}
|
||||
end
|
||||
|
||||
function craftguide.get_recipe_filters()
|
||||
return recipe_filters
|
||||
end
|
||||
@ -228,9 +197,11 @@ end
|
||||
local search_filters = {}
|
||||
|
||||
function craftguide.add_search_filter(name, f)
|
||||
local func = "craftguide." .. __func() .. "(): "
|
||||
assert(is_str(name), func .. "filter name missing")
|
||||
assert(is_func(f), func .. "filter function missing")
|
||||
if not is_str(name) or name == "" then
|
||||
return log("error", "craftguide.add_search_filter(): name missing")
|
||||
elseif not is_func(f) then
|
||||
return log("error", "craftguide.add_search_filter(): function missing")
|
||||
end
|
||||
|
||||
search_filters[name] = f
|
||||
end
|
||||
@ -246,9 +217,7 @@ end
|
||||
local function item_has_groups(item_groups, groups)
|
||||
for i = 1, #groups do
|
||||
local group = groups[i]
|
||||
if (item_groups[group] or 0) == 0 then
|
||||
return
|
||||
end
|
||||
if (item_groups[group] or 0) == 0 then return end
|
||||
end
|
||||
|
||||
return true
|
||||
@ -270,7 +239,7 @@ local function groups_item_in_recipe(item, recipe)
|
||||
local item_groups = reg_items[item].groups
|
||||
|
||||
for _, recipe_item in pairs(recipe.items) do
|
||||
if sub(recipe_item, 1, 6) == "group:" then
|
||||
if sub(recipe_item, 1,6) == "group:" then
|
||||
local groups = extract_groups(recipe_item)
|
||||
if item_has_groups(item_groups, groups) then
|
||||
local usage = copy(recipe)
|
||||
@ -338,17 +307,17 @@ end
|
||||
|
||||
local function cache_recipes(output)
|
||||
local recipes = get_all_recipes(output) or {}
|
||||
local num = #recipes
|
||||
|
||||
for i = 1, #custom_crafts do
|
||||
local custom_craft = custom_crafts[i]
|
||||
if match(custom_craft.output, "%S*") == output then
|
||||
recipes[#recipes + 1] = custom_craft
|
||||
if num > 0 then
|
||||
if recipes_cache[output] then
|
||||
for i = 1, num do
|
||||
insert(recipes_cache[output], 1, recipes[i])
|
||||
end
|
||||
else
|
||||
recipes_cache[output] = recipes
|
||||
end
|
||||
end
|
||||
|
||||
if #recipes > 0 then
|
||||
recipes_cache[output] = recipes
|
||||
end
|
||||
end
|
||||
|
||||
local function cache_usages(item)
|
||||
@ -375,16 +344,14 @@ local function get_recipes(item, data, player)
|
||||
|
||||
if data.show_usages then
|
||||
recipes = apply_recipe_filters(usages_cache[item], player)
|
||||
if recipes and #recipes == 0 then
|
||||
return
|
||||
end
|
||||
if recipes and #recipes == 0 then return end
|
||||
end
|
||||
|
||||
return recipes
|
||||
end
|
||||
|
||||
local function get_burntime(item)
|
||||
return get_result({method = "fuel", width = 1, items = {item}}).time
|
||||
return get_craft_result({method = "fuel", width = 1, items = {item}}).time
|
||||
end
|
||||
|
||||
local function cache_fuel(item)
|
||||
@ -452,11 +419,12 @@ local function get_tooltip(item, groups, cooktime, burntime)
|
||||
return fmt("tooltip[%s;%s]", item, ESC(tooltip))
|
||||
end
|
||||
|
||||
local function get_recipe_fs(data, iY)
|
||||
local function get_recipe_fs(data)
|
||||
local fs = {}
|
||||
local recipe = data.recipes[data.rnum]
|
||||
local width = recipe.width
|
||||
local xoffset = data.iX / 2.15
|
||||
local xoffset = sfinv_only and 3.83 or 4.66
|
||||
local yoffset = sfinv_only and 6 or 6.6
|
||||
local cooktime, shapeless
|
||||
|
||||
if recipe.type == "cooking" then
|
||||
@ -475,32 +443,36 @@ local function get_recipe_fs(data, iY)
|
||||
ESC(S("Recipe @1 of @2", data.rnum, #data.recipes))
|
||||
|
||||
fs[#fs + 1] = fmt(FMT.button,
|
||||
sfinv_only and 5.8 or data.iX - 2.6,
|
||||
sfinv_only and 7.9 or iY + 3.3,
|
||||
2.2,
|
||||
1,
|
||||
"alternate",
|
||||
btn_lab)
|
||||
xoffset + (sfinv_only and 1.98 or 2.7),
|
||||
yoffset + (sfinv_only and 1.9 or 1.2),
|
||||
2.2, 1, "alternate", btn_lab)
|
||||
|
||||
if width > GRID_LIMIT or rows > GRID_LIMIT then
|
||||
fs[#fs + 1] = fmt(FMT.label,
|
||||
(data.iX / 2) - 2,
|
||||
iY + 2.2,
|
||||
sfinv_only and 2 or 3, 7,
|
||||
ESC(S("Recipe is too big to be displayed (@1x@2)", width, rows)))
|
||||
|
||||
return concat(fs)
|
||||
end
|
||||
|
||||
for i, item in pairs(recipe.items) do
|
||||
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))
|
||||
for i = 1, width * rows do
|
||||
local item = recipe.items[i] or ""
|
||||
local X = ceil((i - 1) % width - width) + xoffset
|
||||
local Y = ceil(i / width) + yoffset - min(2, rows)
|
||||
|
||||
if width > 3 or rows > 3 then
|
||||
btn_size = width > 3 and 3 / width or 3 / rows
|
||||
local xof = 1 - 4 / width
|
||||
local yof = 1 - 4 / rows
|
||||
local x_y = width > rows and xof or yof
|
||||
|
||||
btn_size = width > rows and
|
||||
(3.5 + (xof * 2)) / width or (3.5 + (yof * 2)) / rows
|
||||
s_btn_size = btn_size
|
||||
X = btn_size * ((i - 1) % width) + xoffset - 2.65
|
||||
Y = btn_size * floor((i - 1) / width) + (iY + 3) - min(2, rows)
|
||||
|
||||
X = (btn_size * ((i - 1) % width) + xoffset -
|
||||
(sfinv_only and 2.83 or (xoffset - 2))) * (0.83 - (x_y / 5))
|
||||
Y = (btn_size * floor((i - 1) / width) +
|
||||
(5 + ((sfinv_only and 0.81 or 1.5) + x_y))) * (0.86 - (x_y / 5))
|
||||
end
|
||||
|
||||
if X > rightest then
|
||||
@ -517,13 +489,8 @@ local function get_recipe_fs(data, iY)
|
||||
local label = groups and "\nG" or ""
|
||||
|
||||
fs[#fs + 1] = fmt(FMT.item_image_button,
|
||||
X,
|
||||
Y + (sfinv_only and 0.7 or 0.2),
|
||||
btn_size,
|
||||
btn_size,
|
||||
item,
|
||||
match(item, "%S*"),
|
||||
ESC(label))
|
||||
X, Y + (sfinv_only and 0.7 or 0),
|
||||
btn_size, btn_size, item, match(item, "%S*"), ESC(label))
|
||||
|
||||
local burntime = fuel_cache[item]
|
||||
|
||||
@ -542,70 +509,47 @@ local function get_recipe_fs(data, iY)
|
||||
icon = fmt("craftguide_%s.png^[resize:16x16", icon)
|
||||
end
|
||||
|
||||
local pos_y = yoffset + (sfinv_only and 0.25 or -0.45)
|
||||
|
||||
fs[#fs + 1] = fmt(FMT.image,
|
||||
min(3.9, rightest) + 1.2,
|
||||
sfinv_only and 6.2 or iY + 1.7,
|
||||
0.5,
|
||||
0.5,
|
||||
icon)
|
||||
min(3.9, rightest) + 1.2, pos_y, 0.5, 0.5, icon)
|
||||
|
||||
local tooltip = custom_recipe and custom_recipe.description or
|
||||
shapeless and S("Shapeless") or S("Cooking")
|
||||
|
||||
fs[#fs + 1] = fmt("tooltip[%f,%f;%f,%f;%s]",
|
||||
rightest + 1.2,
|
||||
sfinv_only and 6.2 or iY + 1.7,
|
||||
0.5,
|
||||
0.5,
|
||||
ESC(tooltip))
|
||||
rightest + 1.2, pos_y, 0.5, 0.5, ESC(tooltip))
|
||||
end
|
||||
|
||||
local arrow_X = rightest + (s_btn_size or 1.1)
|
||||
local output_X = arrow_X + 0.9
|
||||
|
||||
fs[#fs + 1] = fmt(FMT.image,
|
||||
arrow_X,
|
||||
sfinv_only and 6.85 or iY + 2.35,
|
||||
0.9,
|
||||
0.7,
|
||||
"craftguide_arrow.png")
|
||||
arrow_X, yoffset + (sfinv_only and 0.9 or 0.2),
|
||||
0.9, 0.7, "craftguide_arrow.png")
|
||||
|
||||
if recipe.type == "fuel" then
|
||||
fs[#fs + 1] = fmt(FMT.image,
|
||||
output_X,
|
||||
sfinv_only and 6.68 or iY + 2.18,
|
||||
1.1,
|
||||
1.1,
|
||||
"craftguide_fire.png")
|
||||
output_X, yoffset + (sfinv_only and 0.7 or 0),
|
||||
1.1, 1.1, "craftguide_fire.png")
|
||||
else
|
||||
local output_name = match(recipe.output, "%S+")
|
||||
local burntime = fuel_cache[output_name]
|
||||
|
||||
fs[#fs + 1] = fmt(FMT.item_image_button,
|
||||
output_X,
|
||||
sfinv_only and 6.7 or iY + 2.2,
|
||||
1.1,
|
||||
1.1,
|
||||
recipe.output,
|
||||
ESC(output_name),
|
||||
"")
|
||||
output_X, yoffset + (sfinv_only and 0.7 or 0),
|
||||
1.1, 1.1, recipe.output, ESC(output_name), "")
|
||||
|
||||
if burntime then
|
||||
fs[#fs + 1] = get_tooltip(output_name, nil, nil, burntime)
|
||||
|
||||
fs[#fs + 1] = fmt(FMT.image,
|
||||
output_X + 1,
|
||||
sfinv_only and 6.83 or iY + 2.33,
|
||||
0.6,
|
||||
0.4,
|
||||
"craftguide_arrow.png")
|
||||
output_X + 1, yoffset + (sfinv_only and 0.7 or 0.1),
|
||||
0.6, 0.4, "craftguide_arrow.png")
|
||||
|
||||
fs[#fs + 1] = fmt(FMT.image,
|
||||
output_X + 1.6,
|
||||
sfinv_only and 6.68 or iY + 2.18,
|
||||
0.6,
|
||||
0.6,
|
||||
"craftguide_fire.png")
|
||||
output_X + 1.6, yoffset + (sfinv_only and 0.55 or 0),
|
||||
0.6, 0.6, "craftguide_fire.png")
|
||||
end
|
||||
end
|
||||
|
||||
@ -614,53 +558,53 @@ end
|
||||
|
||||
local function make_formspec(name)
|
||||
local data = pdata[name]
|
||||
local iY = sfinv_only and 4 or data.iX - 5
|
||||
local ipp = data.iX * iY
|
||||
|
||||
data.pagemax = max(1, ceil(#data.items / ipp))
|
||||
data.pagemax = max(1, ceil(#data.items / IPP))
|
||||
|
||||
local fs = {}
|
||||
|
||||
if not sfinv_only then
|
||||
fs[#fs + 1] = fmt("size[%f,%f;]", data.iX - 0.35, iY + 4)
|
||||
|
||||
fs[#fs + 1] = [[
|
||||
no_prepend[]
|
||||
background[1,1;1,1;craftguide_bg.png;true]
|
||||
]]
|
||||
|
||||
fs[#fs + 1] = fmt([[
|
||||
image_button[%f,0.12;0.8,0.8;craftguide_zoomin_icon.png;size_inc;]
|
||||
image_button[%f,0.12;0.8,0.8;craftguide_zoomout_icon.png;size_dec;]
|
||||
]],
|
||||
data.iX * 0.47,
|
||||
data.iX * 0.47 + 0.6)
|
||||
size[%f,%f;]
|
||||
no_prepend[]
|
||||
bgcolor[#00000000;false]
|
||||
background[1,1;1,1;%s;true;10]
|
||||
]],
|
||||
9.5, 8.4, craftguide.background)
|
||||
end
|
||||
|
||||
fs[#fs + 1] = fmt("field[0.3,0.33;2.5,1;filter;;%s]", ESC(data.filter))
|
||||
|
||||
fs[#fs + 1] = [[
|
||||
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;]
|
||||
fs[#fs + 1] = fmt([[
|
||||
field[0.25,0.2;%f,1;filter;;%s]
|
||||
field_close_on_enter[filter;false]
|
||||
]]
|
||||
]],
|
||||
sfinv_only and 2.76 or 2.72, ESC(data.filter))
|
||||
|
||||
fs[#fs + 1] = fmt("label[%f,%f;%s / %u]",
|
||||
sfinv_only and 6.3 or data.iX - 2.2,
|
||||
0.22,
|
||||
colorize("yellow", data.pagenum),
|
||||
data.pagemax)
|
||||
local search_icon = "craftguide_search_icon.png"
|
||||
local clear_icon = "craftguide_clear_icon.png"
|
||||
|
||||
fs[#fs + 1] = fmt([[
|
||||
image_button[%f,0.12;0.8,0.8;craftguide_prev_icon.png;prev;]
|
||||
image_button[%f,0.12;0.8,0.8;craftguide_next_icon.png;next;]
|
||||
image_button[%f,-0.05;0.85,0.85;%s;search;;;false;%s^\[colorize:yellow:255]
|
||||
image_button[%f,-0.05;0.85,0.85;%s;clear;;;false;%s^\[colorize:red:255]
|
||||
]],
|
||||
sfinv_only and 5.5 or data.iX - 3.1,
|
||||
sfinv_only and 7.3 or (data.iX - 1.2) - (data.iX >= 11 and 0.08 or 0))
|
||||
sfinv_only and 2.6 or 2.54, search_icon, search_icon,
|
||||
sfinv_only and 3.3 or 3.25, clear_icon, clear_icon)
|
||||
|
||||
fs[#fs + 1] = fmt("label[%f,%f;%s / %u]",
|
||||
sfinv_only and 6.35 or 7.85, 0.06,
|
||||
colorize("yellow", data.pagenum), data.pagemax)
|
||||
|
||||
local prev_icon = "craftguide_next_icon.png^\\[transformFX"
|
||||
local next_icon = "craftguide_next_icon.png"
|
||||
|
||||
fs[#fs + 1] = fmt([[
|
||||
image_button[%f,-0.05;0.8,0.8;%s;prev;;;false;%s^\[colorize:yellow:255]
|
||||
image_button[%f,-0.05;0.8,0.8;%s;next;;;false;%s^\[colorize:yellow:255]
|
||||
]],
|
||||
sfinv_only and 5.45 or 6.83, prev_icon, prev_icon,
|
||||
sfinv_only and 7.2 or 8.75, next_icon, next_icon)
|
||||
|
||||
if #data.items == 0 then
|
||||
local no_item = S("No item to show")
|
||||
local pos = (data.iX / 2) - 1
|
||||
local pos = sfinv_only and 3 or 3.8
|
||||
|
||||
if next(recipe_filters) and #init_items > 0 and data.filter == "" then
|
||||
no_item = S("Collect items to reveal more recipes")
|
||||
@ -670,27 +614,22 @@ local function make_formspec(name)
|
||||
fs[#fs + 1] = fmt(FMT.label, pos, 2, ESC(no_item))
|
||||
end
|
||||
|
||||
local first_item = (data.pagenum - 1) * ipp
|
||||
for i = first_item, first_item + ipp - 1 do
|
||||
local first_item = (data.pagenum - 1) * IPP
|
||||
for i = first_item, first_item + IPP - 1 do
|
||||
local item = data.items[i + 1]
|
||||
if not item then
|
||||
break
|
||||
end
|
||||
if not item then break end
|
||||
|
||||
local X = i % data.iX
|
||||
local Y = (i % ipp - X) / data.iX + 1
|
||||
local X = i % ROWS
|
||||
local Y = (i % IPP - X) / ROWS + 1
|
||||
|
||||
fs[#fs + 1] = fmt("item_image_button[%f,%f;%f,%f;%s;%s_inv;]",
|
||||
X - (sfinv_only and 0 or (X * 0.05)),
|
||||
Y,
|
||||
1.1,
|
||||
1.1,
|
||||
item,
|
||||
item)
|
||||
X - (X * (sfinv_only and 0.12 or 0.14)) - 0.05,
|
||||
Y - (Y * 0.1) - 0.1,
|
||||
1, 1, item, item)
|
||||
end
|
||||
|
||||
if data.recipes and #data.recipes > 0 then
|
||||
fs[#fs + 1] = get_recipe_fs(data, iY)
|
||||
fs[#fs + 1] = get_recipe_fs(data)
|
||||
end
|
||||
|
||||
return concat(fs)
|
||||
@ -781,7 +720,6 @@ local function init_data(name)
|
||||
pdata[name] = {
|
||||
filter = "",
|
||||
pagenum = 1,
|
||||
iX = sfinv_only and 8 or DEFAULT_SIZE,
|
||||
items = init_items,
|
||||
items_raw = init_items,
|
||||
}
|
||||
@ -831,41 +769,38 @@ local function get_init_items()
|
||||
sort(init_items)
|
||||
end
|
||||
|
||||
local function on_receive_fields(player, fields)
|
||||
local function _fields(player, fields)
|
||||
local name = player:get_player_name()
|
||||
local data = pdata[name]
|
||||
local _f = fields
|
||||
|
||||
if fields.clear then
|
||||
if _f.clear then
|
||||
reset_data(data)
|
||||
show_fs(player, name)
|
||||
return true
|
||||
|
||||
elseif fields.alternate then
|
||||
if #data.recipes == 1 then
|
||||
return
|
||||
end
|
||||
|
||||
elseif _f.alternate then
|
||||
if #data.recipes == 1 then return end
|
||||
local num_next = data.rnum + 1
|
||||
data.rnum = data.recipes[num_next] and num_next or 1
|
||||
show_fs(player, name)
|
||||
|
||||
elseif (fields.key_enter_field == "filter" or fields.search) and
|
||||
fields.filter ~= "" then
|
||||
local fltr = lower(fields.filter)
|
||||
if data.filter == fltr then
|
||||
return
|
||||
end
|
||||
show_fs(player, name)
|
||||
return true
|
||||
|
||||
elseif (_f.key_enter_field == "filter" or _f.search) and _f.filter ~= "" then
|
||||
local fltr = lower(_f.filter)
|
||||
if data.filter == fltr then return end
|
||||
|
||||
data.filter = fltr
|
||||
data.pagenum = 1
|
||||
search(data)
|
||||
|
||||
show_fs(player, name)
|
||||
return true
|
||||
|
||||
elseif fields.prev or fields.next then
|
||||
if data.pagemax == 1 then
|
||||
return
|
||||
end
|
||||
|
||||
data.pagenum = data.pagenum - (fields.prev and 1 or -1)
|
||||
elseif _f.prev or _f.next then
|
||||
if data.pagemax == 1 then return end
|
||||
data.pagenum = data.pagenum - (_f.prev and 1 or -1)
|
||||
|
||||
if data.pagenum > data.pagemax then
|
||||
data.pagenum = 1
|
||||
@ -874,15 +809,10 @@ local function on_receive_fields(player, fields)
|
||||
end
|
||||
|
||||
show_fs(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_inc and 1 or -1)
|
||||
show_fs(player, name)
|
||||
return true
|
||||
else
|
||||
local item
|
||||
for field in pairs(fields) do
|
||||
for field in pairs(_f) do
|
||||
if find(field, ":") then
|
||||
item = field
|
||||
break
|
||||
@ -892,7 +822,7 @@ local function on_receive_fields(player, fields)
|
||||
if not item then
|
||||
return
|
||||
elseif sub(item, -4) == "_inv" then
|
||||
item = sub(item, 1, -5)
|
||||
item = sub(item, 1,-5)
|
||||
end
|
||||
|
||||
if item ~= data.query_item then
|
||||
@ -902,21 +832,20 @@ local function on_receive_fields(player, fields)
|
||||
end
|
||||
|
||||
local recipes = get_recipes(item, data, player)
|
||||
if not recipes then
|
||||
return
|
||||
end
|
||||
if not recipes then return end
|
||||
|
||||
data.query_item = item
|
||||
data.recipes = recipes
|
||||
data.rnum = 1
|
||||
|
||||
show_fs(player, name)
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
core.register_on_mods_loaded(get_init_items)
|
||||
on_mods_loaded(get_init_items)
|
||||
|
||||
core.register_on_joinplayer(function(player)
|
||||
on_joinplayer(function(player)
|
||||
local name = player:get_player_name()
|
||||
init_data(name)
|
||||
end)
|
||||
@ -943,13 +872,13 @@ if sfinv_only then
|
||||
end,
|
||||
|
||||
on_player_receive_fields = function(self, player, context, fields)
|
||||
on_receive_fields(player, fields)
|
||||
_fields(player, fields)
|
||||
end,
|
||||
})
|
||||
else
|
||||
core.register_on_player_receive_fields(function(player, formname, fields)
|
||||
on_receive_fields(function(player, formname, fields)
|
||||
if formname == "craftguide" then
|
||||
on_receive_fields(player, fields)
|
||||
_fields(player, fields)
|
||||
end
|
||||
end)
|
||||
|
||||
@ -980,17 +909,17 @@ else
|
||||
description = S("Crafting Guide Sign"),
|
||||
drawtype = "nodebox",
|
||||
tiles = {"craftguide_sign.png"},
|
||||
inventory_image = "craftguide_sign_inv.png",
|
||||
wield_image = "craftguide_sign_inv.png",
|
||||
inventory_image = "craftguide_sign.png",
|
||||
wield_image = "craftguide_sign.png",
|
||||
paramtype = "light",
|
||||
paramtype2 = "wallmounted",
|
||||
sunlight_propagates = true,
|
||||
groups = {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}
|
||||
wall_top = {-0.5, 0.4375, -0.5, 0.5, 0.5, 0.5},
|
||||
wall_bottom = {-0.5, -0.5, -0.5, 0.5, -0.4375, 0.5},
|
||||
wall_side = {-0.5, -0.5, -0.5, -0.4375, 0.5, 0.5}
|
||||
},
|
||||
|
||||
on_construct = function(pos)
|
||||
@ -1048,7 +977,7 @@ if progressive_mode then
|
||||
local function item_in_inv(item, inv_items)
|
||||
local inv_items_size = #inv_items
|
||||
|
||||
if sub(item, 1, 6) == "group:" then
|
||||
if sub(item, 1,6) == "group:" then
|
||||
local groups = extract_groups(item)
|
||||
for i = 1, inv_items_size do
|
||||
local inv_item = reg_items[inv_items[i]]
|
||||
@ -1070,9 +999,7 @@ if progressive_mode then
|
||||
|
||||
local function recipe_in_inv(recipe, inv_items)
|
||||
for _, item in pairs(recipe.items) do
|
||||
if not item_in_inv(item, inv_items) then
|
||||
return
|
||||
end
|
||||
if not item_in_inv(item, inv_items) then return end
|
||||
end
|
||||
|
||||
return true
|
||||
@ -1102,6 +1029,50 @@ if progressive_mode then
|
||||
return filtered
|
||||
end
|
||||
|
||||
local item_lists = {
|
||||
"main",
|
||||
"craft",
|
||||
"craftpreview",
|
||||
}
|
||||
|
||||
local function table_merge(t, t2)
|
||||
t, t2 = t or {}, t2 or {}
|
||||
local c = #t
|
||||
|
||||
for i = 1, #t2 do
|
||||
c = c + 1
|
||||
t[c] = t2[i]
|
||||
end
|
||||
|
||||
return t
|
||||
end
|
||||
|
||||
local function table_diff(t, t2)
|
||||
local hash = {}
|
||||
|
||||
for i = 1, #t do
|
||||
local v = t[i]
|
||||
hash[v] = true
|
||||
end
|
||||
|
||||
for i = 1, #t2 do
|
||||
local v = t2[i]
|
||||
hash[v] = nil
|
||||
end
|
||||
|
||||
local diff, c = {}, 0
|
||||
|
||||
for i = 1, #t do
|
||||
local v = t[i]
|
||||
if hash[v] then
|
||||
c = c + 1
|
||||
diff[c] = v
|
||||
end
|
||||
end
|
||||
|
||||
return diff
|
||||
end
|
||||
|
||||
local function get_inv_items(player)
|
||||
local inv = player:get_inventory()
|
||||
local stacks = {}
|
||||
@ -1196,7 +1167,7 @@ if progressive_mode then
|
||||
|
||||
poll_new_items()
|
||||
|
||||
minetest.register_globalstep(function(dtime)
|
||||
globalstep(function(dtime)
|
||||
for i = 1, #PLAYERS do
|
||||
local player = PLAYERS[i]
|
||||
local name = player:get_player_name()
|
||||
@ -1210,7 +1181,7 @@ if progressive_mode then
|
||||
|
||||
craftguide.add_recipe_filter("Default progressive filter", progressive_filter)
|
||||
|
||||
core.register_on_joinplayer(function(player)
|
||||
on_joinplayer(function(player)
|
||||
PLAYERS = get_players()
|
||||
|
||||
local meta = player:get_meta()
|
||||
@ -1223,15 +1194,15 @@ if progressive_mode then
|
||||
data.hud = {
|
||||
bg = player:hud_add({
|
||||
hud_elem_type = "image",
|
||||
position = {x = 0.8, y = 1},
|
||||
position = {x = 0.78, y = 1},
|
||||
alignment = {x = 1, y = 1},
|
||||
scale = {x = 320, y = 112},
|
||||
scale = {x = 370, y = 112},
|
||||
text = "craftguide_bg.png",
|
||||
}),
|
||||
|
||||
book = player:hud_add({
|
||||
hud_elem_type = "image",
|
||||
position = {x = 0.81, y = 1.02},
|
||||
position = {x = 0.79, y = 1.02},
|
||||
alignment = {x = 1, y = 1},
|
||||
scale = {x = 4, y = 4},
|
||||
text = "craftguide_book.png",
|
||||
@ -1239,7 +1210,7 @@ if progressive_mode then
|
||||
|
||||
text = player:hud_add({
|
||||
hud_elem_type = "text",
|
||||
position = {x = 0.85, y = 1.04},
|
||||
position = {x = 0.84, y = 1.04},
|
||||
alignment = {x = 1, y = 1},
|
||||
number = 0xFFFFFF,
|
||||
text = "",
|
||||
@ -1247,21 +1218,28 @@ if progressive_mode then
|
||||
}
|
||||
end)
|
||||
|
||||
local to_save = {
|
||||
"inv_items",
|
||||
"known_recipes",
|
||||
}
|
||||
|
||||
local function save_meta(player)
|
||||
local meta = player:get_meta()
|
||||
local name = player:get_player_name()
|
||||
local data = pdata[name]
|
||||
|
||||
meta:set_string("inv_items", serialize(data.inv_items))
|
||||
meta:set_string("known_recipes", serialize(data.known_recipes))
|
||||
for i = 1, #to_save do
|
||||
local meta_name = to_save[i]
|
||||
meta:set_string(meta_name, serialize(data[meta_name]))
|
||||
end
|
||||
end
|
||||
|
||||
core.register_on_leaveplayer(function(player)
|
||||
on_leaveplayer(function(player)
|
||||
PLAYERS = get_players()
|
||||
save_meta(player)
|
||||
end)
|
||||
|
||||
core.register_on_shutdown(function()
|
||||
on_shutdown(function()
|
||||
for i = 1, #PLAYERS do
|
||||
local player = PLAYERS[i]
|
||||
save_meta(player)
|
||||
@ -1269,12 +1247,12 @@ if progressive_mode then
|
||||
end)
|
||||
end
|
||||
|
||||
core.register_on_leaveplayer(function(player)
|
||||
on_leaveplayer(function(player)
|
||||
local name = player:get_player_name()
|
||||
pdata[name] = nil
|
||||
end)
|
||||
|
||||
core.register_chatcommand("craft", {
|
||||
register_command("craft", {
|
||||
description = S("Show recipe(s) of the pointed node"),
|
||||
func = function(name)
|
||||
local player = get_player_by_name(name)
|
||||
@ -1334,8 +1312,9 @@ core.register_chatcommand("craft", {
|
||||
})
|
||||
|
||||
function craftguide.show(name, item, show_usages)
|
||||
local func = "craftguide." .. __func() .. "(): "
|
||||
assert(is_str(name), func .. "player name missing")
|
||||
if not is_str(name) or name == "" then
|
||||
return log("error", "craftguide.show(): player name missing")
|
||||
end
|
||||
|
||||
local data = pdata[name]
|
||||
local player = get_player_by_name(name)
|
||||
|
2
mod.conf
@ -1 +1,3 @@
|
||||
name = craftguide
|
||||
optional_depends = sfinv, sfinv_buttons
|
||||
description = The most comprehensive Crafting Guide on Minetest
|
||||
|
Before Width: | Height: | Size: 169 B After Width: | Height: | Size: 68 B |
BIN
textures/craftguide_bg_full.png
Normal file
After Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 728 B |
Before Width: | Height: | Size: 685 B After Width: | Height: | Size: 894 B |
Before Width: | Height: | Size: 685 B |
Before Width: | Height: | Size: 3.5 KiB |
Before Width: | Height: | Size: 2.9 KiB |