2024-12-10 02:34:33 +01:00

301 lines
11 KiB
Lua

local S = minetest.get_translator("lzr_laser")
-- List of laser color hex codes.
-- These are the builtin default colors that cannot be changed.
lzr_laser.DEFAULT_LASER_COLORS = {
[lzr_globals.COLOR_RED] = "FF0000",
[lzr_globals.COLOR_GREEN] = "00FF00",
[lzr_globals.COLOR_BLUE] = "1212FF",
[lzr_globals.COLOR_YELLOW] = "FFFF00",
[lzr_globals.COLOR_CYAN] = "00FFFF",
[lzr_globals.COLOR_MAGENTA] = "FF00FF",
[lzr_globals.COLOR_WHITE] = "FFFFFF",
}
-- These are the user-changable laser colors that will actually
-- be used by the lasers in the game.
-- This table may contain user overrides; otherwise it is
-- equal to the default colors.
lzr_laser.LASER_COLORS = table.copy(lzr_laser.DEFAULT_LASER_COLORS)
local function read_laser_color_settings()
for c=1, #lzr_globals.COLOR_NAMES do
local setting = minetest.settings:get("lzr_laser_color_"..lzr_globals.COLOR_NAMES[c])
if setting then
local hexcode = string.match(setting, "[0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F]")
if hexcode then
lzr_laser.LASER_COLORS[c] = hexcode
minetest.log("action", "[lzr_laser] Custom laser color read from setting 'lzr_laser_color_"..lzr_globals.COLOR_NAMES[c]..": "..hexcode)
elseif setting ~= "" then
minetest.log("warning", "[lzr_laser] Setting 'lzr_laser_color_"..lzr_globals.COLOR_NAMES[c].."' has wrong syntax. Must be a 6-digit hexadecimal number (0-9, A-F).")
end
end
end
end
read_laser_color_settings()
-- List of patterns to apply on lasers to distinguish them by some other
-- way than just color. Implemented to deal with colorblindness.
local LASER_PATTERNS = {
[lzr_globals.COLOR_RED] = nil, -- no pattern, use a solid line
[lzr_globals.COLOR_GREEN] = { name = "lzr_laser_pattern_lines.png", size = 16 },
[lzr_globals.COLOR_BLUE] = { name = "lzr_laser_pattern_dots.png", size = 16 },
[lzr_globals.COLOR_YELLOW] = { name = "lzr_laser_pattern_checkers.png", size = 16 },
[lzr_globals.COLOR_CYAN] = { name = "lzr_laser_pattern_long_checkers.png", size = 16 },
[lzr_globals.COLOR_MAGENTA] = { name = "lzr_laser_pattern_alternating.png", size = 16 },
[lzr_globals.COLOR_WHITE] = { name = "lzr_laser_pattern_holes.png", size = 32 },
}
-- Shorthand to generate a laser tile. We don't use texture files,
-- we generate them on the fly!
local maketile = function(colorcode, alpha)
local use_patterns = minetest.settings:get_bool("lzr_patterned_lasers", false)
local alpha_append = ""
local pattern_append = ""
if alpha then
alpha_append = lzr_globals.LASER_ALPHA_STRING
end
local texsize = 16
if use_patterns then
local pattern = LASER_PATTERNS[colorcode]
if pattern ~= nil then
pattern_append = "^[mask:"..pattern.name
texsize = pattern.size
end
end
local texture =
-- Generate the texture base color
"([fill:"..texsize.."x"..texsize..":"..
"#"..lzr_laser.LASER_COLORS[colorcode]..alpha_append..")"
-- Apply a pattern on the laser, if enabled (allows to distinguish
-- lasers other than by color to circumvent colorblindness)
.. pattern_append
return { name = texture, backface_culling = true }
end
-- List of all possible laser tiles
if lzr_globals.OPAQUE_LASERS then
lzr_laser.TILE_LASER_R = maketile(lzr_globals.COLOR_RED)
lzr_laser.TILE_LASER_G = maketile(lzr_globals.COLOR_GREEN)
lzr_laser.TILE_LASER_B = maketile(lzr_globals.COLOR_BLUE)
lzr_laser.TILE_LASER_Y = maketile(lzr_globals.COLOR_YELLOW)
lzr_laser.TILE_LASER_C = maketile(lzr_globals.COLOR_CYAN)
lzr_laser.TILE_LASER_M = maketile(lzr_globals.COLOR_MAGENTA)
lzr_laser.TILE_LASER_W = maketile(lzr_globals.COLOR_WHITE)
lzr_laser.ALPHA_LASER = "clip"
else
lzr_laser.TILE_LASER_R = maketile(lzr_globals.COLOR_RED, true)
lzr_laser.TILE_LASER_G = maketile(lzr_globals.COLOR_GREEN, true)
lzr_laser.TILE_LASER_B = maketile(lzr_globals.COLOR_BLUE, true)
lzr_laser.TILE_LASER_Y = maketile(lzr_globals.COLOR_YELLOW, true)
lzr_laser.TILE_LASER_C = maketile(lzr_globals.COLOR_CYAN, true)
lzr_laser.TILE_LASER_M = maketile(lzr_globals.COLOR_MAGENTA, true)
lzr_laser.TILE_LASER_W = maketile(lzr_globals.COLOR_WHITE, true)
lzr_laser.ALPHA_LASER = "blend"
end
-- Distance from center to side of the laser beam square. Not really the radius, but it sounds cooler. :P
local LASER_RADIUS = -1/16
-- Register laser nodes, i.e. the actual
-- laser beams in the map.
--[[ This registers a node for every possible laser combination.
A laser node contains 1 to 3 laser beams, each along the
X, Y and Z axis. Also, each laser beam can have one of
each possible laser color (defined by colorcodes from 0
to lzr_globals.MAX_COLORCODE).
When there is no laser on any axis, there is no need
for a laser node.
The number of registered nodes is
(<number of laser colors + 1> ^ 3) - 1
]]
for color_x=0, lzr_globals.MAX_COLORCODE do
for color_y=0, lzr_globals.MAX_COLORCODE do
for color_z=0, lzr_globals.MAX_COLORCODE do
local dirstring = color_x .. color_y .. color_z
local dirs = lzr_laser.dirstring_to_dirs(dirstring)
-- Count the active axes
local axes = 0
local axes_active = {x=false,y=false,z=false}
for a=1,3 do
if dirs[a] ~= 0 then
axes = axes + 1
if a == 1 then
axes_active.x = true
elseif a == 2 then
axes_active.y = true
elseif a == 3 then
axes_active.z = true
end
end
end
local color2tile = function(colorcode)
if colorcode == 0 then
return "blank.png"
end
if colorcode == lzr_globals.COLOR_RED then
return lzr_laser.TILE_LASER_R
elseif colorcode == lzr_globals.COLOR_GREEN then
return lzr_laser.TILE_LASER_G
elseif colorcode == lzr_globals.COLOR_YELLOW then
return lzr_laser.TILE_LASER_Y
elseif colorcode == lzr_globals.COLOR_BLUE then
return lzr_laser.TILE_LASER_B
elseif colorcode == lzr_globals.COLOR_CYAN then
return lzr_laser.TILE_LASER_C
elseif colorcode == lzr_globals.COLOR_MAGENTA then
return lzr_laser.TILE_LASER_M
elseif colorcode == lzr_globals.COLOR_WHITE then
return lzr_laser.TILE_LASER_W
else
-- error
return "no_texture.png"
end
end
-- Pick a mesh depending on the axes on where to put
-- a laser beam.
-- The meshes are made so that the "ends" of the lasers
-- are "open", i.e. don't have an additional face.
-- This ensures the laser beam looks like a real
-- continuous beam reather than a sequence of nodes.
local tex, mesh
-- Single laser
if axes == 1 then
-- Simple: Just pick a mesh for the laser direction, and then the color
if axes_active.x then
mesh = "lzr_laser_laser_100.obj"
tex = { color2tile(color_x) }
elseif axes_active.y then
mesh = "lzr_laser_laser_010.obj"
tex = { color2tile(color_y)}
else
mesh = "lzr_laser_laser_001.obj"
tex = { color2tile(color_z) }
end
-- 2 lasers crossing
elseif axes == 2 then
-- A bit trickier: We have two primary colors from 2 lasers,
-- but at the crossing, we mix both colors with the 'combined' var.
if axes_active.x == false then
mesh = "lzr_laser_laser_011.obj"
-- Color mixing is just a bitwise OR of 2 colorcodes. Because the colorcodes
-- are aligned in the correct way for this to work.
local combined = bit.bor(color_y, color_z)
tex = { color2tile(combined), color2tile(color_y), color2tile(color_z) }
elseif axes_active.y == false then
mesh = "lzr_laser_laser_101.obj"
local combined = bit.bor(color_x, color_z)
tex = { color2tile(color_x), color2tile(combined), color2tile(color_z) }
else
mesh = "lzr_laser_laser_110.obj"
local combined = bit.bor(color_x, color_y)
tex = { color2tile(color_x), color2tile(color_y), color2tile(combined) }
end
-- Note
-- 3 lasers crossing
elseif axes == 3 then
-- Easy again: Pick a mesh and 3 colors for the 3 axes
mesh = "lzr_laser_laser_111.obj"
tex = { color2tile(color_x), color2tile(color_y), color2tile(color_z) }
end
-- This generates an unique number for each possible laser combination
local lasergroup = lzr_laser.colors_to_laser_group(color_x, color_y, color_z)
if tex then
-- Finally register the laser
minetest.register_node("lzr_laser:laser_"..dirstring, {
--~ Laser block description. @1 = color code uniquely identifying the color(s) of the laser beam(s) in that node
description = S("Laser (@1)", lzr_laser.dirstring_to_colstring(dirstring)),
paramtype = "light",
light_source = lzr_globals.LASER_GLOW,
drawtype = "mesh",
mesh = mesh,
sunlight_propagates = true,
walkable = false,
use_texture_alpha = lzr_laser.ALPHA_LASER,
tiles = tex,
pointable = false,
buildable_to = true,
groups = { laser = lasergroup, not_in_creative_inventory = 1, dig_immediate = 3 },
drop = "",
})
if axes == 1 then
-- Combination node: Barrier + laser
minetest.register_node("lzr_laser:barrier_laser_"..dirstring, {
--~ Description of a block that is both laser and invisible barrier. @1 = color code uniquely identifying the color(s) of the laser beam(s) in that node
description = S("Barrier Laser (@1)", lzr_laser.dirstring_to_colstring(dirstring)),
paramtype = "light",
light_source = lzr_globals.LASER_GLOW,
drawtype = "mesh",
mesh = mesh,
sunlight_propagates = true,
walkable = true,
use_texture_alpha = lzr_laser.ALPHA_LASER,
tiles = tex,
buildable_to = false,
-- Can't point through or select; player should not be able to
-- build at the level borders or point anything through it.
pointable = "blocking",
pointabilities = {
nodes = {
["group:barrier"] = true,
}
},
collision_box = { type = "regular" },
groups = { breakable = 1, barrier = 2, laser = lasergroup, not_in_creative_inventory = 1 },
drop = "",
})
-- Combination node: Rain Membrane + laser
minetest.register_node("lzr_laser:rain_membrane_laser_"..dirstring, {
--~ Description of a block that is both laser and invisible barrier that lets rain through but not the player. @1 = color code uniquely identifying the color(s) of the laser beam(s) in that node
description = S("Rain Membrane Laser (@1)", lzr_laser.dirstring_to_colstring(dirstring)),
paramtype = "light",
light_source = lzr_globals.LASER_GLOW,
drawtype = "mesh",
mesh = mesh,
sunlight_propagates = true,
walkable = true,
use_texture_alpha = lzr_laser.ALPHA_LASER,
tiles = tex,
buildable_to = false,
-- Can't point through or select; player should not be able to
-- build at the level borders or point anything through it.
pointable = "blocking",
pointabilities = {
nodes = {
["group:barrier"] = true,
}
},
collision_box = lzr_globals.RAIN_MEMBRANE_COLLISION_BOX,
selection_box = {
type = "regular",
},
is_ground_content = false,
groups = { breakable = 1, rain_membrane = 1, barrier = 2, laser = lasergroup, not_in_creative_inventory = 1 },
drop = "",
})
end
end
end
end
end