2019-01-06 12:02:37 -05:00
|
|
|
-- LUALOCALS < ---------------------------------------------------------
|
2019-12-06 07:01:12 -05:00
|
|
|
local ItemStack, ipairs, math, minetest, nodecore, pairs, string,
|
|
|
|
tonumber, tostring, type, unpack, vector
|
|
|
|
= ItemStack, ipairs, math, minetest, nodecore, pairs, string,
|
|
|
|
tonumber, tostring, type, unpack, vector
|
|
|
|
local math_cos, math_log, math_pi, math_random, math_sin, math_sqrt,
|
|
|
|
string_gsub, string_lower
|
|
|
|
= math.cos, math.log, math.pi, math.random, math.sin, math.sqrt,
|
|
|
|
string.gsub, string.lower
|
2019-01-06 12:02:37 -05:00
|
|
|
-- LUALOCALS > ---------------------------------------------------------
|
|
|
|
|
|
|
|
for k, v in pairs(minetest) do
|
|
|
|
if type(v) == "function" then
|
|
|
|
-- Late-bind in case minetest methods overridden.
|
|
|
|
nodecore[k] = function(...) return minetest[k](...) end
|
|
|
|
else
|
|
|
|
nodecore[k] = v
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2019-08-31 09:26:53 -04:00
|
|
|
local function underride(t, u, u2, ...)
|
|
|
|
if u2 then underride(u, u2, ...) end
|
2019-01-08 02:03:18 -05:00
|
|
|
for k, v in pairs(u) do
|
|
|
|
if t[k] == nil then
|
|
|
|
t[k] = v
|
|
|
|
elseif type(t[k]) == "table" and type(v) == "table" then
|
|
|
|
underride(t[k], v)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
return t
|
|
|
|
end
|
|
|
|
nodecore.underride = underride
|
|
|
|
|
2019-01-06 12:02:37 -05:00
|
|
|
function nodecore.mkreg()
|
|
|
|
local t = {}
|
|
|
|
local f = function(x) t[#t + 1] = x end
|
|
|
|
return f, t
|
|
|
|
end
|
|
|
|
|
2019-02-24 10:19:22 -05:00
|
|
|
function nodecore.memoize(func)
|
|
|
|
local cache
|
|
|
|
return function()
|
|
|
|
if cache then return cache[1] end
|
|
|
|
cache = {func()}
|
|
|
|
return cache[1]
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2019-01-06 12:02:37 -05:00
|
|
|
function nodecore.dirs()
|
|
|
|
return {
|
2019-03-07 00:35:27 -05:00
|
|
|
{n = "e", x = 1, y = 0, z = 0},
|
|
|
|
{n = "w", x = -1, y = 0, z = 0},
|
|
|
|
{n = "u", x = 0, y = 1, z = 0},
|
|
|
|
{n = "d", x = 0, y = -1, z = 0},
|
|
|
|
{n = "n", x = 0, y = 0, z = 1},
|
|
|
|
{n = "s", x = 0, y = 0, z = -1}
|
2019-01-06 12:02:37 -05:00
|
|
|
}
|
|
|
|
end
|
|
|
|
|
|
|
|
function nodecore.pickrand(tbl, weight)
|
|
|
|
weight = weight or function() end
|
|
|
|
local t = {}
|
|
|
|
local max = 0
|
|
|
|
for k, v in pairs(tbl) do
|
|
|
|
local w = weight(v) or 1
|
|
|
|
if w > 0 then
|
|
|
|
max = max + w
|
2019-01-06 13:04:07 -05:00
|
|
|
t[#t + 1] = {w = w, k = k, v = v}
|
2019-01-06 12:02:37 -05:00
|
|
|
end
|
|
|
|
end
|
|
|
|
if max <= 0 then return end
|
|
|
|
max = math_random() * max
|
2019-08-31 09:26:53 -04:00
|
|
|
for _, v in ipairs(t) do
|
2019-01-06 12:02:37 -05:00
|
|
|
max = max - v.w
|
2019-01-06 13:04:07 -05:00
|
|
|
if max <= 0 then return v.v, v.k end
|
2019-01-06 12:02:37 -05:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2019-09-05 22:48:30 -04:00
|
|
|
do
|
|
|
|
local saved
|
|
|
|
function nodecore.boxmuller()
|
|
|
|
local old = saved
|
|
|
|
if old then
|
|
|
|
saved = nil
|
|
|
|
return old
|
|
|
|
end
|
|
|
|
local r = math_sqrt(-2 * math_log(math_random()))
|
|
|
|
local t = 2 * math_pi * math_random()
|
|
|
|
saved = r * math_sin(t)
|
|
|
|
return r * math_cos(t)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2019-01-06 12:02:37 -05:00
|
|
|
function nodecore.extend_item(name, func)
|
2019-03-13 23:51:59 -04:00
|
|
|
local orig = minetest.registered_items[name] or {}
|
2019-01-06 12:02:37 -05:00
|
|
|
local copy = {}
|
|
|
|
for k, v in pairs(orig) do copy[k] = v end
|
|
|
|
copy = func(copy, orig) or copy
|
|
|
|
minetest.register_item(":" .. name, copy)
|
|
|
|
end
|
|
|
|
|
2019-03-30 21:23:02 -04:00
|
|
|
function nodecore.fixedbox(x, ...)
|
|
|
|
return {type = "fixed", fixed = {
|
|
|
|
x or {-0.5, -0.5, -0.5, 0.5, 0.5, 0.5},
|
|
|
|
...
|
2019-08-27 19:14:51 -04:00
|
|
|
}}
|
2019-03-30 21:23:02 -04:00
|
|
|
end
|
2019-01-06 12:02:37 -05:00
|
|
|
|
2019-02-24 21:54:33 -05:00
|
|
|
function nodecore.interact(player)
|
2019-11-28 08:55:09 -05:00
|
|
|
if not player then return end
|
2019-02-24 21:54:33 -05:00
|
|
|
if type(player) ~= "string" then
|
2019-11-28 08:55:09 -05:00
|
|
|
if not (player.is_player and player:is_player()) then
|
|
|
|
return true
|
|
|
|
end
|
2019-02-24 21:54:33 -05:00
|
|
|
player = player:get_player_name()
|
|
|
|
end
|
|
|
|
return minetest.get_player_privs(player).interact
|
|
|
|
end
|
|
|
|
|
2019-01-06 12:02:37 -05:00
|
|
|
function nodecore.wieldgroup(who, group)
|
|
|
|
local wielded = who and who:get_wielded_item()
|
2019-01-06 13:04:07 -05:00
|
|
|
local nodedef = minetest.registered_nodes[wielded:get_name()]
|
|
|
|
if nodedef then return nodedef.groups and nodedef.groups[group] end
|
2019-01-06 12:02:37 -05:00
|
|
|
local caps = wielded and wielded:get_tool_capabilities()
|
|
|
|
return caps and caps.groupcaps and caps.groupcaps[group]
|
|
|
|
end
|
|
|
|
|
2019-01-24 23:16:12 -05:00
|
|
|
function nodecore.toolspeed(what, groups)
|
|
|
|
if not what then return end
|
|
|
|
local dg = what:get_tool_capabilities().groupcaps
|
|
|
|
local t
|
|
|
|
for gn, lv in pairs(groups) do
|
|
|
|
local gt = dg[gn]
|
|
|
|
gt = gt and gt.times
|
|
|
|
gt = gt and gt[lv]
|
|
|
|
if gt and (not t or t > gt) then t = gt end
|
|
|
|
end
|
2019-04-06 23:42:23 -04:00
|
|
|
if (not t) and (not what:is_empty()) then
|
|
|
|
return nodecore.toolspeed(ItemStack(""), groups)
|
|
|
|
end
|
2019-01-24 23:16:12 -05:00
|
|
|
return t
|
|
|
|
end
|
|
|
|
|
2019-01-06 12:02:37 -05:00
|
|
|
function nodecore.interval(after, func)
|
|
|
|
local function go()
|
|
|
|
minetest.after(after, go)
|
|
|
|
return func()
|
|
|
|
end
|
|
|
|
minetest.after(after, go)
|
|
|
|
end
|
|
|
|
|
2019-02-09 22:44:56 -05:00
|
|
|
function nodecore.wear_wield(player, groups, qty)
|
|
|
|
local wielded = player:get_wielded_item()
|
|
|
|
if wielded then
|
|
|
|
local wdef = wielded:get_definition()
|
|
|
|
local tp = wielded:get_tool_capabilities()
|
|
|
|
local dp = minetest.get_dig_params(groups, tp)
|
|
|
|
if wdef and wdef.after_use then
|
|
|
|
wielded = wdef.after_use(wielded, player, nil, dp) or wielded
|
|
|
|
else
|
|
|
|
if not minetest.settings:get_bool("creative_mode") then
|
|
|
|
wielded:add_wear(dp.wear * (qty or 1))
|
|
|
|
if wielded:get_count() <= 0 and wdef.sound
|
|
|
|
and wdef.sound.breaks then
|
|
|
|
minetest.sound_play(wdef.sound.breaks,
|
2019-09-12 20:20:59 -04:00
|
|
|
{object = player, gain = 0.5})
|
2019-02-09 22:44:56 -05:00
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
return player:set_wielded_item(wielded)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
function nodecore.consume_wield(player, qty)
|
2019-01-06 12:02:37 -05:00
|
|
|
local wielded = player:get_wielded_item()
|
|
|
|
if wielded then
|
|
|
|
local wdef = wielded:get_definition()
|
2019-01-25 00:54:11 -05:00
|
|
|
if wdef.stack_max > 1 and qty then
|
2019-01-06 13:04:07 -05:00
|
|
|
local have = wielded:get_count() - qty
|
|
|
|
if have <= 0 then
|
|
|
|
wielded = ItemStack("")
|
|
|
|
else
|
|
|
|
wielded:set_count(have)
|
|
|
|
end
|
2019-01-06 12:02:37 -05:00
|
|
|
end
|
2019-01-06 13:04:07 -05:00
|
|
|
return player:set_wielded_item(wielded)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
function nodecore.loaded_mods()
|
|
|
|
local t = {}
|
|
|
|
for _, v in pairs(minetest.get_modnames()) do
|
|
|
|
t[v] = true
|
2019-01-06 12:02:37 -05:00
|
|
|
end
|
2019-01-06 13:04:07 -05:00
|
|
|
return t
|
2019-01-06 12:02:37 -05:00
|
|
|
end
|
2019-01-17 00:01:00 -05:00
|
|
|
|
|
|
|
function nodecore.node_group(name, pos, node)
|
|
|
|
node = node or minetest.get_node(pos)
|
2019-03-13 23:51:59 -04:00
|
|
|
local def = minetest.registered_nodes[node.name] or {}
|
|
|
|
return def.groups and def.groups[name]
|
2019-01-17 00:01:00 -05:00
|
|
|
end
|
2019-01-25 00:12:29 -05:00
|
|
|
|
|
|
|
function nodecore.item_eject(pos, stack, speed, qty, vel)
|
2019-01-25 09:26:15 -05:00
|
|
|
stack = ItemStack(stack)
|
|
|
|
speed = speed or 0
|
2019-01-25 00:12:29 -05:00
|
|
|
vel = vel or {x = 0, y = 0, z = 0}
|
2019-02-21 09:46:26 -05:00
|
|
|
if speed == 0 and vel.x == 0 and vel.y == 0 and vel.z == 0
|
|
|
|
and nodecore.place_stack and minetest.get_node(pos).name == "air" then
|
|
|
|
stack:set_count(stack:get_count() * (qty or 1))
|
|
|
|
return nodecore.place_stack(pos, stack)
|
|
|
|
end
|
2019-08-31 09:26:53 -04:00
|
|
|
for _ = 1, (qty or 1) do
|
2019-01-25 01:15:14 -05:00
|
|
|
local v = {
|
|
|
|
x = vel.x + (math_random() - 0.5) * speed,
|
2019-01-25 01:23:44 -05:00
|
|
|
y = vel.y + math_random() * speed,
|
2019-01-25 01:15:14 -05:00
|
|
|
z = vel.z + (math_random() - 0.5) * speed,
|
|
|
|
}
|
|
|
|
local p = {
|
2019-01-25 09:26:15 -05:00
|
|
|
x = v.x > 0 and pos.x + 0.4 or v.x < 0 and pos.x - 0.4 or pos.x,
|
|
|
|
y = pos.y + 0.25,
|
|
|
|
z = v.z > 0 and pos.z + 0.4 or v.z < 0 and pos.z - 0.4 or pos.z,
|
2019-01-25 01:15:14 -05:00
|
|
|
}
|
|
|
|
local obj = minetest.add_item(p, stack)
|
2019-09-05 07:36:28 -04:00
|
|
|
if obj then obj:set_velocity(v) end
|
2019-01-25 00:12:29 -05:00
|
|
|
end
|
|
|
|
end
|
2019-01-27 22:34:53 -05:00
|
|
|
|
2019-11-28 11:40:28 -05:00
|
|
|
do
|
|
|
|
local stddirs = {}
|
|
|
|
for _, v in pairs(nodecore.dirs()) do
|
|
|
|
if v.y <= 0 then stddirs[#stddirs + 1] = v end
|
2019-11-28 11:29:21 -05:00
|
|
|
end
|
2019-11-28 11:40:28 -05:00
|
|
|
function nodecore.item_disperse(pos, name, qty, outdirs)
|
2019-11-28 13:04:35 -05:00
|
|
|
if qty < 1 then return end
|
2019-11-28 11:40:28 -05:00
|
|
|
local dirs = {}
|
|
|
|
for _, d in pairs(outdirs or stddirs) do
|
|
|
|
local p = vector.add(pos, d)
|
|
|
|
if nodecore.buildable_to(p) then
|
|
|
|
dirs[#dirs + 1] = {pos = p, qty = 0}
|
|
|
|
end
|
|
|
|
end
|
|
|
|
if #dirs < 1 then
|
|
|
|
return nodecore.item_eject(pos, name .. " " .. qty)
|
|
|
|
end
|
|
|
|
for _ = 1, qty do
|
|
|
|
local p = dirs[math_random(1, #dirs)]
|
|
|
|
p.qty = p.qty + 1
|
|
|
|
end
|
|
|
|
for _, v in pairs(dirs) do
|
|
|
|
if v.qty > 0 then
|
|
|
|
nodecore.item_eject(v.pos, name .. " " .. v.qty)
|
|
|
|
end
|
2019-11-28 11:29:21 -05:00
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2019-11-30 10:28:35 -05:00
|
|
|
function nodecore.find_nodes_around(pos, spec, r, s)
|
2019-11-18 22:17:17 -05:00
|
|
|
r = r or 1
|
2019-11-30 10:28:35 -05:00
|
|
|
if type(r) == "number" then
|
|
|
|
return minetest.find_nodes_in_area(
|
|
|
|
{x = pos.x - r, y = pos.y - r, z = pos.z - r},
|
|
|
|
{x = pos.x + r, y = pos.y + r, z = pos.z + r},
|
|
|
|
spec)
|
|
|
|
end
|
|
|
|
s = s or r
|
|
|
|
return minetest.find_nodes_in_area(
|
|
|
|
{x = pos.x - (r.x or r[1]), y = pos.y - (r.y or r[2]), z = pos.z - (r.z or r[3])},
|
|
|
|
{x = pos.x + (s.x or s[1]), y = pos.y + (s.y or s[2]), z = pos.z + (s.z or s[3])},
|
|
|
|
spec)
|
|
|
|
end
|
|
|
|
function nodecore.quenched(pos, r)
|
|
|
|
local qty = #nodecore.find_nodes_around(pos, "group:coolant", r)
|
|
|
|
return (qty > 0) and qty or nil
|
2019-01-28 23:13:21 -05:00
|
|
|
end
|
2019-03-05 23:05:56 -05:00
|
|
|
|
2019-03-07 10:04:32 -05:00
|
|
|
function nodecore.node_spin_custom(...)
|
|
|
|
local arr = {...}
|
|
|
|
arr[0] = false
|
|
|
|
local lut = {}
|
|
|
|
for i = 1, #arr do
|
|
|
|
lut[arr[i - 1]] = arr[i]
|
|
|
|
end
|
|
|
|
lut[arr[#arr]] = arr[1]
|
|
|
|
local qty = #arr
|
|
|
|
|
2019-08-31 09:26:53 -04:00
|
|
|
return function(pos, node, clicker, itemstack)
|
2019-03-07 10:04:32 -05:00
|
|
|
node = node or minetest.get_node(pos)
|
|
|
|
node.param2 = lut[node.param2] or lut[false]
|
|
|
|
if clicker:is_player() then
|
|
|
|
minetest.log(clicker:get_player_name() .. " spins "
|
|
|
|
.. node.name .. " at " .. minetest.pos_to_string(pos)
|
|
|
|
.. " to param2 " .. node.param2 .. " ("
|
|
|
|
.. qty .. " total)")
|
|
|
|
end
|
|
|
|
minetest.swap_node(pos, node)
|
2019-08-14 21:46:55 -04:00
|
|
|
nodecore.node_sound(pos, "place")
|
2019-03-07 10:04:32 -05:00
|
|
|
local def = minetest.registered_items[node.name] or {}
|
|
|
|
if def.on_spin then def.on_spin(pos, node) end
|
|
|
|
return itemstack
|
|
|
|
end
|
|
|
|
end
|
|
|
|
function nodecore.node_spin_filtered(func)
|
|
|
|
local rots = {}
|
|
|
|
for i = 0, 23 do
|
|
|
|
local f = nodecore.facedirs[i]
|
|
|
|
local hit
|
|
|
|
for j = 1, #rots do
|
|
|
|
if not hit then
|
|
|
|
local o = nodecore.facedirs[rots[j]]
|
|
|
|
hit = hit or func(f, o)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
if not hit then rots[#rots + 1] = f.id end
|
|
|
|
end
|
|
|
|
return nodecore.node_spin_custom(unpack(rots))
|
2019-03-05 23:05:56 -05:00
|
|
|
end
|
2019-03-07 00:58:37 -05:00
|
|
|
|
|
|
|
function nodecore.node_change(pos, node, newname)
|
|
|
|
if node.name == newname then return end
|
|
|
|
return minetest.set_node(pos, underride({name = newname}, node))
|
|
|
|
end
|
2019-12-06 07:01:12 -05:00
|
|
|
|
|
|
|
local function scrubkey(s)
|
|
|
|
return string_lower(string_gsub(tostring(s), "%W+", "_"))
|
|
|
|
end
|
|
|
|
|
|
|
|
function nodecore.rate_adjustment(...)
|
|
|
|
local rate = 1
|
|
|
|
local key = scrubkey(nodecore.product)
|
|
|
|
for _, k in ipairs({...}) do
|
|
|
|
if not k then break end
|
|
|
|
key = key .. "_" .. scrubkey(k)
|
|
|
|
local adj = tonumber(minetest.settings:get(key))
|
|
|
|
if adj then rate = rate * adj end
|
|
|
|
end
|
|
|
|
return rate
|
|
|
|
end
|