magic_sys/tool_analyzer.lua
2018-03-06 15:38:57 +01:00

251 lines
5.9 KiB
Lua

-- takes a 2 dimensional table with strings, returns a string
-- padding is used to make rows distinguishable
local function column(t, padding)
padding = padding or " "
-- collect lengths
local h = #t
local w = #t[1]
local maxlen = {}
for j = 1,w do
local col_width = 0
for i = 1,h do
-- length instead of # for UTF-8 support
local l = t[i][j]:len()
if l > col_width then
col_width = l
end
end
maxlen[j] = col_width
end
-- generate the string
local lines = {}
for i = 1,h do
local line = {}
for j = 1,w do
local text = t[i][j]
local l = text:len()
local col_width = maxlen[j]
-- align right
line[j] = string.rep(" ", col_width - l) .. text
end
lines[i] = table.concat(line, padding)
end
return table.concat(lines, "\n")
end
local function analyze(item)
local name = item:get_name()
local def = minetest.registered_tools[name]
assert(def, "not a tool")
local caps = item:get_tool_capabilities()
local groupcaps = caps.groupcaps
local groups = {}
for group, data in pairs(groupcaps) do
local lvstats = {}
for level = 0,data.maxlevel do
local result = {}
for v in pairs(data.times) do
local p = minetest.get_dig_params(
{[group] = v, level = level},
caps
)
if p.diggable then
if p.time ~= 0 then
p.time = string.format("%-5.3g", p.time)
else
p.time = "0.15 (immediate)"
end
else
p.time = "not diggable"
end
result[v] = p
end
lvstats[level] = result
end
groups[#groups+1] = {group, lvstats}
end
-- TODO format date
local msg =
'# Stats for the tool "' .. name .. '" (' .. os.date() .. ")\n\n" ..
"## Digging speed and maximum uses\n\n" ..
"The following tables show digging time and maximum number of\n" ..
"nodes that can be dug for each supported group and level.\n\n"
-- TODO show whether tool capabilities are overridden in item metadata
-- add digging speed and wear for each group and level
local sort_func = function(a, b)
return a[1] < b[1]
end
table.sort(groups, sort_func)
for i = 1,#groups do
local v = groups[i]
local groupname = v[1]
msg = msg .. "### Group " .. groupname ..
", values show the digging time\n\n"
local w = 0
local w_l = 3
local lines = {}
local lvstats = v[2]
for i = 0, #lvstats do
local line = {string.format("level=%d", i)}
local stats = lvstats[i]
local wear
for i,v in pairs(stats) do
wear = v.wear
line[i + 2] = v.time
if i > w then
w = i
elseif i < w_l then
w_l = i
end
end
line[2] = string.format("%.3g", 65535 / wear)
lines[i + 2] = line
end
-- add description
lines[1] = {"", "max uses"}
for i = 3, 3 + w - w_l do
lines[1][i] = string.format("%s=%d", groupname, i + w_l - 3)
end
-- fill in missings with empty string
for i = 2,#lines do
local line = lines[i]
for i = 3, w + 2 do
line[i] = line[i + w_l - 1] or ""
end
end
msg = msg .. column(lines) .. "\n\n\n"
end
-- add damage
if caps.damage_groups then
msg = msg .. "## Damage\n\n"
for name,v in pairs(caps.damage_groups) do
msg = msg .. name .. ":\t" .. v .. "\n"
end
msg = msg .. "\n\n"
end
msg = msg .. "## Other stats\n\n"
-- full punch interval TODO what is this
if caps.full_punch_interval then
msg = msg .. string.format("full_punch_interval: %.3g\n",
caps.full_punch_interval)
end
-- TODO what is max_drop_level
-- add range
if def.range then
msg = msg .. "range: " .. def.range .. "\n"
end
if def.liquids_pointable then
msg = msg .. "This tool points liquids.\n"
end
return msg
end
minetest.register_node("magic_sys:tool_analyzer", {
description = "Tool Analyzer",
tiles = {"default_wood.png"},
groups = {cracky=3},
on_construct = function(pos)
local meta = minetest.get_meta(pos)
meta:set_string("formspec",
"size[8,8]" ..
"label[1,0.5;Tool:]" ..
"list[context;tool;2,0.5;1,1;]" ..
"button[3,0.5;2,2;analyze;Analyze tool]" ..
"label[1,1.5;Book:]" ..
"list[context;book;2,1.5;1,1;]" ..
"list[current_player;main;0,3;8,4;]" ..
"listring[context;book]" ..
"listring[current_player;main]" ..
"listring[context;tool]" ..
"listring[current_player;main]"
)
meta:set_string("infotext", "Tool Analyzer")
local inv = meta:get_inventory()
inv:set_size("tool", 1)
inv:set_size("book", 1)
end,
can_dig = function(pos)
local inv = minetest.get_meta(pos):get_inventory()
return inv:is_empty"tool" and inv:is_empty"book"
end,
allow_metadata_inventory_put = function(pos, listname, _, stack, player)
if minetest.is_protected(pos, player:get_player_name()) then
return 0
end
local itemname = stack:get_name()
if listname == "book" then
if itemname == "default:book" then
-- TODO: multiple books
return 1
end
return 0
end
if listname == "tool" then
if minetest.registered_tools[itemname] then
return 1
end
return 0
end
return 0
end,
-- TODO: fix items can be put by swapping
allow_metadata_inventory_take = function(pos, _, _, stack, player)
if minetest.is_protected(pos, player:get_player_name()) then
return 0
end
return stack:get_count()
end,
on_receive_fields = function(pos, _, fields, player)
if not fields.analyze then
return
end
local pname = player:get_player_name()
if minetest.is_protected(pos, pname) then
return
end
local inv = minetest.get_meta(pos):get_inventory()
local book = inv:get_stack("book", 1)
if book:to_string() ~= "default:book" then
return
end
local tool = inv:get_stack("tool", 1)
local toolname = tool:get_name()
if not minetest.registered_tools[toolname] then
return
end
if not magic_sys.before_tool_analyze(player) then
return
end
local text = analyze(tool)
book:set_name"default:book_written"
book:get_meta():from_table{fields = {
title = "Analyzed " .. toolname,
owner = pname,
description = "Analyzed " .. toolname,
text = text,
page = 1,
page_max = 1,
}}
inv:set_stack("book", 1, book)
end,
})