2020-02-23 09:55:15 -05:00
|
|
|
-- LUALOCALS < ---------------------------------------------------------
|
2020-06-22 06:31:44 -04:00
|
|
|
local minetest, nodecore, pairs, string, table, tonumber, vector
|
|
|
|
= minetest, nodecore, pairs, string, table, tonumber, vector
|
2020-06-22 07:21:33 -04:00
|
|
|
local string_format, table_remove, table_sort
|
|
|
|
= string.format, table.remove, table.sort
|
2020-02-23 09:55:15 -05:00
|
|
|
-- LUALOCALS > ---------------------------------------------------------
|
|
|
|
|
|
|
|
local modname = minetest.get_current_modname()
|
|
|
|
|
|
|
|
local glyph = "nc_writing:glyph1"
|
|
|
|
local maxdist = tonumber(minetest.settings:get(modname .. "_maxdist")) or 32
|
|
|
|
local minpower = tonumber(minetest.settings:get(modname .. "_minpower")) or 3
|
|
|
|
|
2020-06-22 07:21:33 -04:00
|
|
|
local function sparkly(posa, posb)
|
|
|
|
local minpos = {
|
|
|
|
x = (posa.x < posb.x and posa.x or posb.x) - 0.5,
|
|
|
|
y = (posa.y < posb.y and posa.y or posb.y) - 0.5,
|
|
|
|
z = (posa.z < posb.z and posa.z or posb.z) - 0.5
|
|
|
|
}
|
|
|
|
local maxpos = {
|
|
|
|
x = (posa.x > posb.x and posa.x or posb.x) + 0.5,
|
|
|
|
y = (posa.y > posb.y and posa.y or posb.y) + 1.5,
|
|
|
|
z = (posa.z > posb.z and posa.z or posb.z) + 0.5
|
|
|
|
}
|
|
|
|
local volume = (maxpos.x - minpos.x + 1) * (maxpos.y - minpos.y + 1)
|
|
|
|
* (maxpos.z - minpos.z + 1)
|
2020-02-23 09:55:15 -05:00
|
|
|
minetest.add_particlespawner({
|
2020-06-22 07:21:33 -04:00
|
|
|
amount = 5 * volume,
|
2020-02-23 09:55:15 -05:00
|
|
|
time = 0.25,
|
2020-06-22 07:21:33 -04:00
|
|
|
minpos = minpos,
|
|
|
|
maxpos = maxpos,
|
2020-02-23 09:55:15 -05:00
|
|
|
minvel = {x = -0.5, y = -0.5, z = -0.5},
|
|
|
|
maxvel = {x = 0.5, y = 0.5, z = 0.5},
|
|
|
|
texture = "nc_lux_base.png^[mask:nc_lux_dot_mask.png^[opacity:128",
|
|
|
|
minexptime = 0.20,
|
|
|
|
maxexptime = 0.25,
|
|
|
|
glow = 4
|
|
|
|
})
|
|
|
|
end
|
|
|
|
|
|
|
|
local function zipscan(pos, dir)
|
|
|
|
for i = 1, maxdist - 1 do
|
|
|
|
local p = {
|
|
|
|
x = pos.x + dir.x * i,
|
|
|
|
y = pos.y + dir.y * i,
|
|
|
|
z = pos.z + dir.z * i
|
|
|
|
}
|
|
|
|
if nodecore.walkable(p) then return end
|
|
|
|
if dir.y == 0 and nodecore.walkable({x = p.x, y = p.y + 1, z = p.z}) then return end
|
|
|
|
local node = minetest.get_node(p)
|
|
|
|
local face = nodecore.facedirs[node.param2]
|
|
|
|
if node.name == glyph and vector.equals(face.k, dir) then
|
|
|
|
if dir.y == 1 then dir = vector.add(dir, face.b) end
|
|
|
|
return vector.add(p, dir)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2020-06-22 06:31:44 -04:00
|
|
|
local function zipcheck(pos)
|
2020-02-23 09:55:15 -05:00
|
|
|
local node = minetest.get_node(pos)
|
|
|
|
|
|
|
|
local face = nodecore.facedirs[node.param2]
|
|
|
|
local dir = face.k
|
|
|
|
local hit = zipscan(pos, dir)
|
|
|
|
if not hit then return end
|
|
|
|
|
|
|
|
if nodecore.walkable(hit) or
|
|
|
|
nodecore.walkable({x = hit.x, y = hit.y + 1, z = hit.z})
|
|
|
|
then return end
|
|
|
|
|
2020-06-22 06:31:44 -04:00
|
|
|
return hit
|
2020-02-23 09:55:15 -05:00
|
|
|
end
|
|
|
|
|
|
|
|
local cache = {}
|
2020-06-22 06:31:44 -04:00
|
|
|
local function zipdata_get(player)
|
|
|
|
local pname = player:get_player_name()
|
|
|
|
local found = cache[pname]
|
|
|
|
if found then return found end
|
|
|
|
local s = player:get_meta():get_string(modname) or ""
|
|
|
|
found = s and s ~= "" and minetest.deserialize(s) or {}
|
|
|
|
cache[pname] = found
|
|
|
|
return found
|
|
|
|
end
|
|
|
|
local function zipdata_set(player, data)
|
|
|
|
local pname = player:get_player_name()
|
|
|
|
cache[pname] = data
|
|
|
|
player:get_meta():set_string(modname, data and minetest.serialize(data) or "")
|
|
|
|
end
|
|
|
|
|
|
|
|
local function appendpos(oldpos, pos)
|
2020-06-22 07:21:33 -04:00
|
|
|
for _, p in pairs(oldpos) do
|
|
|
|
if vector.equals(pos, p) then return oldpos end
|
|
|
|
end
|
2020-06-22 06:31:44 -04:00
|
|
|
oldpos[#oldpos + 1] = pos
|
|
|
|
if #oldpos > 100 then table_remove(oldpos, 1) end
|
|
|
|
return oldpos
|
|
|
|
end
|
2020-02-23 09:55:15 -05:00
|
|
|
|
2020-06-22 07:21:33 -04:00
|
|
|
local enercache = {}
|
|
|
|
local function energized(pos)
|
|
|
|
local hash = minetest.hash_node_position(pos)
|
|
|
|
local found = enercache[hash]
|
|
|
|
if found and found > nodecore.gametime then return end
|
|
|
|
enercache[hash] = nodecore.gametime + 1
|
|
|
|
minetest.add_particlespawner({
|
|
|
|
amount = 10,
|
|
|
|
time = 1,
|
|
|
|
minpos = {x = pos.x - 0.5, y = pos.y - 0.5, z = pos.z - 0.5},
|
|
|
|
maxpos = {x = pos.x + 0.5, y = pos.y + 1.5, z = pos.z + 0.5},
|
|
|
|
minvel = {x = -0.5, y = -0.5, z = -0.5},
|
|
|
|
maxvel = {x = 0.5, y = 0.5, z = 0.5},
|
|
|
|
texture = "nc_lux_base.png^[mask:nc_lux_dot_mask.png^[opacity:128",
|
|
|
|
minexptime = 0.20,
|
|
|
|
maxexptime = 0.25,
|
|
|
|
glow = 4
|
|
|
|
})
|
|
|
|
end
|
|
|
|
|
2020-02-23 09:55:15 -05:00
|
|
|
local function playercheck(player)
|
|
|
|
local vel = player:get_player_velocity()
|
|
|
|
if vector.dot(vel, vel) > 0.1 then return end
|
|
|
|
|
2020-06-22 07:21:33 -04:00
|
|
|
local ctl = player:get_player_control()
|
|
|
|
if ctl.sneak or ctl.jump or ctl.up or ctl.down or ctl.left or ctl.right then return end
|
|
|
|
|
2020-06-22 06:31:44 -04:00
|
|
|
local data = zipdata_get(player)
|
|
|
|
if not data.pos then return end
|
2020-02-23 09:55:15 -05:00
|
|
|
|
|
|
|
local pos = vector.round(player:get_pos())
|
2020-06-22 06:31:44 -04:00
|
|
|
if vector.distance(pos, data.pos) > 2 then
|
|
|
|
for _, p in pairs(data.oldpos or {}) do
|
2020-06-22 07:21:33 -04:00
|
|
|
if vector.distance(pos, p) <= 2 then
|
|
|
|
nodecore.log("action", string_format(
|
|
|
|
"%s: %s pos correction from %s to %s",
|
|
|
|
modname, player:get_player_name(),
|
|
|
|
minetest.pos_to_string(pos),
|
|
|
|
minetest.pos_to_string(p)))
|
|
|
|
player:set_pos(data.pos)
|
|
|
|
return energized(pos)
|
|
|
|
end
|
2020-06-22 06:31:44 -04:00
|
|
|
end
|
2020-06-22 07:21:33 -04:00
|
|
|
nodecore.log("action", string_format("%s: %s exits ziprune at %s",
|
|
|
|
modname, player:get_player_name(), minetest.pos_to_string(pos)))
|
2020-06-22 06:31:44 -04:00
|
|
|
return zipdata_set(player)
|
2020-02-23 09:55:15 -05:00
|
|
|
end
|
|
|
|
|
2020-06-22 07:21:33 -04:00
|
|
|
local runes = nodecore.find_nodes_around(pos, glyph, 1)
|
|
|
|
table_sort(runes, function(a, b)
|
|
|
|
local da = vector.distance(pos, a)
|
|
|
|
local db = vector.distance(pos, b)
|
|
|
|
if da ~= db then return da < db end
|
|
|
|
if a.y ~= b.y then return a.y < b.y end
|
|
|
|
if a.x ~= b.x then return a.x < b.x end
|
|
|
|
return a.z < b.z
|
|
|
|
end)
|
|
|
|
for _, p in pairs(runes) do
|
2020-06-22 06:31:44 -04:00
|
|
|
local hit = zipcheck(p)
|
|
|
|
if hit then
|
2020-06-22 07:21:33 -04:00
|
|
|
nodecore.log("action", string_format("%s: %s zips from %s to %s",
|
|
|
|
modname, player:get_player_name(), minetest.pos_to_string(pos),
|
2020-06-22 06:31:44 -04:00
|
|
|
minetest.pos_to_string(hit)))
|
|
|
|
data.oldpos = appendpos(data.oldpos or {}, data.pos)
|
|
|
|
data.pos = hit
|
|
|
|
zipdata_set(player, data)
|
|
|
|
player:set_pos({x = hit.x, y = hit.y - 0.49, z = hit.z})
|
2020-06-22 07:21:33 -04:00
|
|
|
nodecore.sound_play(modname .. "_zip", {pos = hit})
|
|
|
|
return sparkly(p, hit)
|
2020-06-22 06:31:44 -04:00
|
|
|
end
|
2020-02-23 09:55:15 -05:00
|
|
|
end
|
2020-06-22 07:21:33 -04:00
|
|
|
|
|
|
|
energized(pos)
|
2020-02-23 09:55:15 -05:00
|
|
|
end
|
|
|
|
|
|
|
|
minetest.register_globalstep(function()
|
|
|
|
for _, player in pairs(minetest.get_connected_players()) do
|
|
|
|
playercheck(player)
|
|
|
|
end
|
|
|
|
end)
|
|
|
|
|
|
|
|
local powernodes = {}
|
|
|
|
for i = minpower, 8 do powernodes["nc_lux:cobble" .. i] = true end
|
2020-06-21 00:12:20 -04:00
|
|
|
nodecore.register_dnt({
|
|
|
|
name = modname,
|
|
|
|
time = 1,
|
2020-02-23 09:55:15 -05:00
|
|
|
action = function(pos, node)
|
2020-06-21 00:12:20 -04:00
|
|
|
if node.name ~= glyph then return end
|
|
|
|
|
2020-02-23 09:55:15 -05:00
|
|
|
local face = nodecore.facedirs[node.param2]
|
|
|
|
|
|
|
|
local unode = minetest.get_node(vector.add(pos, face.b))
|
|
|
|
if not powernodes[unode.name] then return end
|
|
|
|
|
|
|
|
if not zipscan(pos, face.k) then return end
|
|
|
|
|
2020-06-21 00:12:20 -04:00
|
|
|
nodecore.dnt_set(pos, modname)
|
2020-02-23 09:55:15 -05:00
|
|
|
minetest.add_particlespawner({
|
|
|
|
amount = 20,
|
|
|
|
time = 1,
|
|
|
|
minpos = {x = pos.x - 0.5, y = pos.y - 7/16, z = pos.z - 0.5},
|
|
|
|
maxpos = {x = pos.x + 0.5, y = pos.y - 7/16, z = pos.z + 0.5},
|
|
|
|
minvel = {x = 0, y = 0, z = 0},
|
|
|
|
maxvel = {x = 0, y = 0, z = 0},
|
|
|
|
minacc = {x = 0, y = 1, z = 0},
|
|
|
|
maxacc = {x = 0, y = 1, z = 0},
|
|
|
|
texture = "nc_lux_base.png^[mask:nc_lux_dot_mask.png^[opacity:128",
|
|
|
|
minexptime = 1,
|
|
|
|
maxexptime = 2,
|
|
|
|
glow = 4
|
|
|
|
})
|
|
|
|
|
|
|
|
for _, player in pairs(minetest.get_connected_players()) do
|
|
|
|
if vector.equals(vector.round(player:get_pos()), pos) then
|
2020-06-22 06:31:44 -04:00
|
|
|
zipdata_set(player, {pos = pos})
|
2020-06-22 07:21:33 -04:00
|
|
|
nodecore.sound_play(modname .. "_zip", {pos = pos})
|
2020-02-23 09:55:15 -05:00
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
})
|
2020-06-21 00:12:20 -04:00
|
|
|
|
|
|
|
nodecore.register_limited_abm({
|
|
|
|
label = "ZipRune Detection",
|
|
|
|
interval = 1,
|
|
|
|
chance = 1,
|
|
|
|
limited_max = 100,
|
|
|
|
limited_alert = 1000,
|
|
|
|
nodenames = {glyph},
|
|
|
|
neighbors = {"group:lux_cobble"},
|
|
|
|
action = function(pos) nodecore.dnt_set(pos, modname) end
|
|
|
|
})
|