Refactor lzr_laser mod

master
Wuzzy 2021-12-21 15:32:34 +01:00
parent 202131968a
commit 25cba4a685
5 changed files with 145 additions and 137 deletions

View File

@ -1,138 +1,4 @@
local S = minetest.get_translator("lzr_laser")
lzr_laser = {}
-- Distance from center to side of the laser beam square. Not really the radius, but it sounds cooler. :P
local LASER_RADIUS = -1/16
-- DATA FORMATS:
--[[ dirstring: A representation of 6 cardinal directions which are either
'active' (1) or 'inactive' (0)
Each direction has the character "1" or "0".
The characters stand for these directions, in order: -X, +X, -Y, +Y, -Z, +Z
Example: "101010"
]]
--[[ dirs table: Like dirstring, but in table format. It's a table
with 6 numbers, each of them being either 1 or 0. The same order of
directions is used like for dirstring.
Example: { 1, 0, 1, 0, 1, 0 }
]]
-- Converts a dirstring to a dirs table
function dirstring_to_dirs(dirstring)
local dirs = {}
for d=1, 6 do
if string.sub(dirstring, d, d) == "1" then
dirs[d] = 1
elseif string.sub(dirstring, d, d) == "0" then
dirs[d] = 0
else
error("[lzr_laser] dirstring_to_dirs: Invalid dirstring!")
end
end
return dirs
end
-- Converts a dirs table to a dirstring
function dirs_to_dirstring(dirs)
local dirstring = ""
for d=1, 6 do
if dirs[d] == 0 then
dirstring = dirstring .. "0"
elseif dirs[d] == 1 then
dirstring = dirstring .. "1"
else
error("[lzr_laser] dirs_to_dirstring: Invalid dirs!")
end
end
return dirstring
end
-- Returns a nodebox for the given dirs table
function dirs_to_nodebox(dirs)
local boxes = {}
local x = dirs[1] == 1 or dirs[4] == 1
local y = dirs[2] == 1 or dirs[5] == 1
local z = dirs[3] == 1 or dirs[6] == 1
-- True if 2 or more axes are used
local multidir = (x and y) or (x and z) or (y and z)
-- Center block
if multidir and (x or y or z) then
table.insert(boxes, { -LASER_RADIUS, -LASER_RADIUS, -LASER_RADIUS, LASER_RADIUS, LASER_RADIUS, LASER_RADIUS })
end
-- Axes (X, Y, Z)
if x then
if not multidir then
table.insert(boxes, { -0.5, -LASER_RADIUS, -LASER_RADIUS, 0.5, LASER_RADIUS, LASER_RADIUS })
else
table.insert(boxes, { -0.5, -LASER_RADIUS, -LASER_RADIUS, LASER_RADIUS, LASER_RADIUS, LASER_RADIUS })
table.insert(boxes, { -LASER_RADIUS, -LASER_RADIUS, -LASER_RADIUS, 0.5, LASER_RADIUS, LASER_RADIUS })
end
end
if y then
if not multidir then
table.insert(boxes, { -LASER_RADIUS, -0.5, -LASER_RADIUS, LASER_RADIUS, 0.5, LASER_RADIUS })
else
table.insert(boxes, { -LASER_RADIUS, -0.5, -LASER_RADIUS, LASER_RADIUS, LASER_RADIUS, LASER_RADIUS })
table.insert(boxes, { -LASER_RADIUS, -LASER_RADIUS, -LASER_RADIUS, LASER_RADIUS, 0.5, LASER_RADIUS })
end
end
if z then
if not multidir then
table.insert(boxes, { -LASER_RADIUS, -LASER_RADIUS, -0.5, LASER_RADIUS, LASER_RADIUS, 0.5 })
else
table.insert(boxes, { -LASER_RADIUS, -LASER_RADIUS, -0.5, LASER_RADIUS, LASER_RADIUS, LASER_RADIUS })
table.insert(boxes, { -LASER_RADIUS, -LASER_RADIUS, -LASER_RADIUS, LASER_RADIUS, LASER_RADIUS, 0.5 })
end
end
return boxes
end
-- Convert number to string in binary form
-- * num: Number
-- * minLength: Minimum number of characters the string must have, will
-- fill string with leading zeroes if needed (default: 1)
-- Returns: string
function dec2bin(num, minLength)
if not minLength then
minLength = 1
end
local t = {}
local rem
while num > 0 do
rem = math.fmod(num,2)
t[#t+1] = rem
num = (num-rem)/2
end
local bin = table.concat(t)
bin = string.reverse(bin)
local length = string.len(bin)
if length < minLength then
bin = string.rep("0", minLength - length) .. bin
end
return bin
end
-- Register laser nodes
-- 64 nodes because 2^6 (6 directions with on/off state)
for i=1, 64 do
local dirstring = dec2bin(i, 6)
local dirs = dirstring_to_dirs(dirstring)
minetest.register_node("lzr_laser:laser_"..dirstring, {
description = S("Laser (@1)", dirstring),
paramtype = "light",
drawtype = "nodebox",
sunlight_propagates = true,
walkable = false,
use_texture_alpha = "blend",
tiles = { "lzr_laser_laser.png", },
--TODO: Remove pointability
-- pointable = false,
node_box = {
type = "fixed",
fixed = dirs_to_nodebox(dirs),
},
groups = { laser = 1, not_in_creative_inventory = 1 },
})
end
dofile(minetest.get_modpath("lzr_laser").."/util.lua")
dofile(minetest.get_modpath("lzr_laser").."/laser.lua")

70
mods/lzr_laser/laser.lua Normal file
View File

@ -0,0 +1,70 @@
local S = minetest.get_translator("lzr_laser")
-- Distance from center to side of the laser beam square. Not really the radius, but it sounds cooler. :P
local LASER_RADIUS = -1/16
-- Returns a nodebox for the given dirs table
local function dirs_to_nodebox(dirs)
local boxes = {}
local x = dirs[1] == 1 or dirs[4] == 1
local y = dirs[2] == 1 or dirs[5] == 1
local z = dirs[3] == 1 or dirs[6] == 1
-- True if 2 or more axes are used
local multidir = (x and y) or (x and z) or (y and z)
-- Center block
if multidir and (x or y or z) then
table.insert(boxes, { -LASER_RADIUS, -LASER_RADIUS, -LASER_RADIUS, LASER_RADIUS, LASER_RADIUS, LASER_RADIUS })
end
-- Axes (X, Y, Z)
if x then
if not multidir then
table.insert(boxes, { -0.5, -LASER_RADIUS, -LASER_RADIUS, 0.5, LASER_RADIUS, LASER_RADIUS })
else
table.insert(boxes, { -0.5, -LASER_RADIUS, -LASER_RADIUS, LASER_RADIUS, LASER_RADIUS, LASER_RADIUS })
table.insert(boxes, { -LASER_RADIUS, -LASER_RADIUS, -LASER_RADIUS, 0.5, LASER_RADIUS, LASER_RADIUS })
end
end
if y then
if not multidir then
table.insert(boxes, { -LASER_RADIUS, -0.5, -LASER_RADIUS, LASER_RADIUS, 0.5, LASER_RADIUS })
else
table.insert(boxes, { -LASER_RADIUS, -0.5, -LASER_RADIUS, LASER_RADIUS, LASER_RADIUS, LASER_RADIUS })
table.insert(boxes, { -LASER_RADIUS, -LASER_RADIUS, -LASER_RADIUS, LASER_RADIUS, 0.5, LASER_RADIUS })
end
end
if z then
if not multidir then
table.insert(boxes, { -LASER_RADIUS, -LASER_RADIUS, -0.5, LASER_RADIUS, LASER_RADIUS, 0.5 })
else
table.insert(boxes, { -LASER_RADIUS, -LASER_RADIUS, -0.5, LASER_RADIUS, LASER_RADIUS, LASER_RADIUS })
table.insert(boxes, { -LASER_RADIUS, -LASER_RADIUS, -LASER_RADIUS, LASER_RADIUS, LASER_RADIUS, 0.5 })
end
end
return boxes
end
-- Register laser nodes
-- 64 nodes because 2^6 (6 directions with on/off state)
for i=1, 64 do
local dirstring = lzr_laser.dec2bin(i, 6)
local dirs = lzr_laser.dirstring_to_dirs(dirstring)
minetest.register_node("lzr_laser:laser_"..dirstring, {
description = S("Laser (@1)", dirstring),
paramtype = "light",
drawtype = "nodebox",
sunlight_propagates = true,
walkable = false,
use_texture_alpha = "blend",
tiles = { "lzr_laser_laser.png", },
--TODO: Remove pointability
-- pointable = false,
node_box = {
type = "fixed",
fixed = dirs_to_nodebox(dirs),
},
groups = { laser = 1, not_in_creative_inventory = 1 },
})
end

1
mods/lzr_laser/mod.conf Normal file
View File

@ -0,0 +1 @@
name = lzr_laser

Binary file not shown.

After

Width:  |  Height:  |  Size: 144 B

71
mods/lzr_laser/util.lua Normal file
View File

@ -0,0 +1,71 @@
-- Distance from center to side of the laser beam square. Not really the radius, but it sounds cooler. :P
local LASER_RADIUS = -1/16
-- DATA FORMATS:
--[[ dirstring: A representation of 6 cardinal directions which are either
'active' (1) or 'inactive' (0)
Each direction has the character "1" or "0".
The characters stand for these directions, in order: -X, +X, -Y, +Y, -Z, +Z
Example: "101010"
]]
--[[ dirs table: Like dirstring, but in table format. It's a table
with 6 numbers, each of them being either 1 or 0. The same order of
directions is used like for dirstring.
Example: { 1, 0, 1, 0, 1, 0 }
]]
-- Converts a dirstring to a dirs table
function lzr_laser.dirstring_to_dirs(dirstring)
local dirs = {}
for d=1, 6 do
if string.sub(dirstring, d, d) == "1" then
dirs[d] = 1
elseif string.sub(dirstring, d, d) == "0" then
dirs[d] = 0
else
error("[lzr_laser] dirstring_to_dirs: Invalid dirstring!")
end
end
return dirs
end
-- Converts a dirs table to a dirstring
function lzr_laser.dirs_to_dirstring(dirs)
local dirstring = ""
for d=1, 6 do
if dirs[d] == 0 then
dirstring = dirstring .. "0"
elseif dirs[d] == 1 then
dirstring = dirstring .. "1"
else
error("[lzr_laser] dirs_to_dirstring: Invalid dirs!")
end
end
return dirstring
end
-- Convert number to string in binary form
-- * num: Number
-- * minLength: Minimum number of characters the string must have, will
-- fill string with leading zeroes if needed (default: 1)
-- Returns: string
function lzr_laser.dec2bin(num, minLength)
if not minLength then
minLength = 1
end
local t = {}
local rem
while num > 0 do
rem = math.fmod(num,2)
t[#t+1] = rem
num = (num-rem)/2
end
local bin = table.concat(t)
bin = string.reverse(bin)
local length = string.len(bin)
if length < minLength then
bin = string.rep("0", minLength - length) .. bin
end
return bin
end