techage/basis/laser_lib.lua
2022-07-11 20:20:00 +02:00

147 lines
3.9 KiB
Lua

--[[
TechAge
=======
Copyright (C) 2019-2021 Joachim Stolberg
GPL v3
See LICENSE.txt for more information
Laser basis functions
]]--
local Entities = {}
local SIZES = {1, 2, 3, 6, 12, 24, 48} -- for laser entities
local GAP_MIN = 1 -- between 2 blocks
local GAP_MAX = 2 * 48 -- between 2 blocks
-- Return the area (pos1,pos2) for a destination node
local function get_pos_range(pos, dir)
local pos1 = vector.add(pos, vector.multiply(dir, GAP_MIN + 1)) -- min
local pos2 = vector.add(pos, vector.multiply(dir, GAP_MAX + 1)) -- max
return pos1, pos2
end
-- Return first pos after start pos and the destination pos
local function get_positions(pos, mem, dir)
local pos1 = vector.add(pos, dir) -- start pos
local _, pos2 = get_pos_range(pos, dir) -- last pos
local _, pos3 = minetest.line_of_sight(pos1, pos2)
pos3 = pos3 or pos2 -- destination node pos
if not mem.peer_node_pos or not vector.equals(pos3, mem.peer_node_pos) then
mem.peer_node_pos = pos3
local dist = vector.distance(pos1, pos3)
if dist > GAP_MIN and dist <= GAP_MAX then
return true, pos1, pos3 -- new values
else
return false -- invalid values
end
end
return true -- no new values
end
-- return for both laser entities the pos and length
local function get_laser_length_and_pos(pos1, pos2, dir)
local dist = vector.distance(pos1, pos2)
for _, size in ipairs(SIZES) do
if dist <= (size * 2) then
pos1 = vector.add (pos1, vector.multiply(dir, (size / 2) - 0.5))
pos2 = vector.subtract(pos2, vector.multiply(dir, (size / 2) + 0.5))
return size, pos1, pos2
end
end
end
local function del_laser(pos)
local key = minetest.hash_node_position(pos)
local items = Entities[key]
if items then
local laser1, laser2 = items[1], items[2]
laser1:remove()
laser2:remove()
Entities[key] = nil
end
return key
end
local function add_laser(pos, pos1, pos2, size, param2)
local key = del_laser(pos)
local laser1 = minetest.add_entity(pos1, "techage:laser" .. size)
if laser1 then
local yaw = math.pi / 2 * (param2 + 1)
laser1:set_rotation({x = 0, y = yaw, z = 0})
end
local laser2 = minetest.add_entity(pos2, "techage:laser" .. size)
if laser2 then
param2 = (param2 + 2) % 4 -- flip dir
local yaw = math.pi / 2 * (param2 + 1)
laser2:set_rotation({x = 0, y = yaw, z = 0})
end
Entities[key] = {laser1, laser2}
end
for _, size in ipairs(SIZES) do
minetest.register_entity("techage:laser" .. size, {
initial_properties = {
visual = "cube",
textures = {
"techage_laser.png",
"techage_laser.png",
"techage_laser.png",
"techage_laser.png",
"techage_laser.png",
"techage_laser.png",
},
use_texture_alpha = true,
physical = false,
collide_with_objects = false,
pointable = false,
static_save = false,
visual_size = {x = size, y = 0.05, z = 0.05},
glow = 14,
shaded = true,
},
})
end
-------------------------------------------------------------------------------
-- API functions
-------------------------------------------------------------------------------
-- if force is not true, do not redraw the laser if nothing has changed
function techage.renew_laser(pos, force)
local mem = techage.get_mem(pos)
if force then
mem.peer_node_pos = nil
mem.param2 = nil
end
mem.param2 = mem.param2 or minetest.get_node(pos).param2
local dir = minetest.facedir_to_dir(mem.param2)
local res, pos1, pos2 = get_positions(pos, mem, dir)
if pos1 then
local size, pos3, pos4 = get_laser_length_and_pos(pos1, pos2, dir)
if size then
add_laser(pos, pos3, pos4, size, mem.param2)
return res, pos1, pos2
end
end
return res
end
function techage.add_laser(pos, pos1, pos2)
local dir = vector.direction(pos1, pos2)
local param2 = minetest.dir_to_facedir(dir)
local size, pos3, pos4 = get_laser_length_and_pos(pos1, pos2, dir)
if size then
add_laser(pos, pos3, pos4, size, param2)
end
end
-- techage.del_laser(pos)
techage.del_laser = del_laser