2024-08-12 00:10:19 +02:00

1255 lines
45 KiB
Lua

local S = minetest.get_translator("lzr_laser")
-- Opacity (0-255) of skull when it is "gone",
-- i.e. is non-walkable
local OPACITY_SKULL_GONE = 128
-- Special string to mark a tile in a laser element as the 'laser tile'
-- for lzr_laser.register_element. The laser tile is the
-- the tile (texture) that represents the laser itself. This string
-- will be replaced automatically by the appropriate laser texture
-- on registration
lzr_laser.LASER_TILE = "<<<LASER>>>"
local colortiles = {
lzr_laser.TILE_LASER_R,
lzr_laser.TILE_LASER_G,
lzr_laser.TILE_LASER_Y,
lzr_laser.TILE_LASER_B,
lzr_laser.TILE_LASER_M,
lzr_laser.TILE_LASER_C,
lzr_laser.TILE_LASER_W,
}
local mirror_out = {
[0] = {1,0,0},
[1] = {0,0,-1},
[2] = {-1,0,0},
[3] = {0,0,1},
[4] = {1,0,0},
[5] = {0,1,0},
[6] = {-1,0,0},
[7] = {0,-1,0},
[8] = {1,0,0},
[9] = {0,-1,0},
[10] = {-1,0,0},
[11] = {0,1,0},
[12] = {0,-1,0},
[13] = {0,0,-1},
[14] = {0,1,0},
[15] = {0,0,1},
[16] = {0,1,0},
[17] = {0,0,-1},
[18] = {0,-1,0},
[19] = {0,0,1},
[20] = {-1,0,0},
[21] = {0,0,-1},
[22] = {1,0,0},
[23] = {0,0,1},
}
lzr_laser.get_front_dir = function(param2)
if not param2 then
return
end
local dir_input = minetest.facedir_to_dir(param2)
if not dir_input then
return
end
local v = vector.new(dir_input[1], dir_input[2], dir_input[3])
dir_input = vector.multiply(v, -1)
return dir_input
end
lzr_laser.get_front_dir = function(param2)
if not param2 then
return
end
local dir_input = minetest.facedir_to_dir(param2)
if not dir_input then
return
end
local v = vector.new(dir_input[1], dir_input[2], dir_input[3])
dir_input = vector.multiply(v, -1)
return dir_input
end
lzr_laser.get_barrel_axis = function(param2)
if not param2 then
return
end
if (param2 >= 0 and param2 <= 3) or (param2 >= 20 and param2 <= 23) then
return "y"
elseif (param2 >= 4 and param2 <= 11) then
return "z"
elseif (param2 >= 12 and param2 <= 19) then
return "x"
else
return "y"
end
end
lzr_laser.get_pane_axis = function(param2)
if not param2 then
return
end
local dir = minetest.facedir_to_dir(param2)
if dir.x ~= 0 then
return "x"
elseif dir.y ~= 0 then
return "y"
elseif dir.z ~= 0 then
return "z"
end
end
lzr_laser.check_front = function(node_pos, laser_dir)
local node = minetest.get_node(node_pos)
local node_dir_in = lzr_laser.get_front_dir(node.param2)
if not node_dir_in then
return false
end
local reverse_laser_dir = vector.multiply(laser_dir, -1)
if vector.equals(reverse_laser_dir, node_dir_in) then
return true
end
return false
end
lzr_laser.check_detector = function(detector_pos, nodename, laser_dir, laser_color)
local detector_group = minetest.get_item_group(nodename, "detector")
if detector_group == 0 then
return false
end
-- Check if laser goes into hole
if lzr_laser.check_front(detector_pos, laser_dir) then
local detector_color = minetest.get_item_group(nodename, "detector_color")
-- Detector does not care about color: Instant success
if detector_color == 0 then
return true
-- If detector *does* care about color, it must be an exact match
elseif laser_color == detector_color then
return true
end
end
return false
end
lzr_laser.get_mirror_dirs = function(param2)
local dir_input = minetest.facedir_to_dir(param2)
if not dir_input then
return
end
dir_input = vector.multiply(dir_input, -1)
local dir_output = vector.new(unpack(mirror_out[param2]))
return dir_input, dir_output
end
-- Mirror a laser that touches a mirror with a laser coming towards
-- the mirror with the laser_dir direction (direction vector).
-- * nodename: Name of mirror node
-- * param2: param2 of mirror node
-- * laser_dir: Direction of incoming laser
-- Returns <output direction>, <mirror output side>
-- 1) If the laser can be mirrored, then <output direction> is the direction of
-- the mirrored laser and <mirror output> denotes on of the 2 possible
-- sides the laser came from: true if it came in the front side, false if
-- it came from the angled side. <mirror output> is useful for the
-- transmissive mirror.
-- 2) If the laser cannot be mirrored <mirror output> is false and
-- <mirror output side> is nil
lzr_laser.get_mirrored_laser_dir = function(nodename, param2, laser_dir)
local mirror_group = minetest.get_item_group(nodename, "mirror")
local mirror_transmissive_group = minetest.get_item_group(nodename, "transmissive_mirror")
if mirror_group == 0 and mirror_transmissive_group == 0 then
return false
end
local reverse_laser_dir = vector.multiply(laser_dir, -1)
local mirror_dir_in, mirror_dir_out = lzr_laser.get_mirror_dirs(param2)
if not mirror_dir_in then
return false
end
if vector.equals(reverse_laser_dir, mirror_dir_in) then
return mirror_dir_out, true
elseif vector.equals(reverse_laser_dir, mirror_dir_out) then
return mirror_dir_in, false
end
return false
end
function lzr_laser.unlock_chests(min, max)
local closed_chests = minetest.find_nodes_in_area(min, max, {"group:chest_closed"})
local detectors = minetest.find_nodes_in_area(min, max, {"group:detector"})
for c=1, #closed_chests do
local cpos = closed_chests[c]
local node = minetest.get_node(cpos)
local def = minetest.registered_nodes[node.name]
if def._lzr_unlock then
def._lzr_unlock(cpos, node)
for d=1, #detectors do
local dpos = detectors[d]
lzr_laser.particle_line(dpos, cpos, "lzr_laser_particle_trigger.png")
end
end
end
end
-- Update the whole playfield and check for victory
local full_update = function()
local state = lzr_gamestate.get_state()
if state ~= lzr_gamestate.LEVEL and state ~= lzr_gamestate.LEVEL_COMPLETE and state ~= lzr_gamestate.EDITOR then
return
end
lzr_laser.full_laser_update(lzr_globals.PLAYFIELD_START, lzr_globals.PLAYFIELD_END)
if state == lzr_gamestate.EDITOR then
return
end
local done = lzr_laser.check_level_won()
if done then
lzr_levels.level_complete()
else
local detectors = lzr_laser.check_all_detectors()
if detectors then
lzr_laser.unlock_chests(lzr_globals.PLAYFIELD_START, lzr_globals.PLAYFIELD_END)
end
end
end
-- Same as above, but special case after a detector was placed.
-- This is hack to tell the detector check that the one detector in the player
-- inventory has to be ignored because after_dig_node is called BEFORE
-- the inventory change after placing the node.
local full_update_detector_placed = function()
local state = lzr_gamestate.get_state()
if state ~= lzr_gamestate.LEVEL and state ~= lzr_gamestate.LEVEL_COMPLETE and state ~= lzr_gamestate.EDITOR then
return
end
lzr_laser.full_laser_update(lzr_globals.PLAYFIELD_START, lzr_globals.PLAYFIELD_END)
if state == lzr_gamestate.EDITOR then
return
end
local done = lzr_laser.check_level_won()
if done then
lzr_levels.level_complete()
else
local detectors = lzr_laser.check_all_detectors(true)
if detectors then
lzr_laser.unlock_chests(lzr_globals.PLAYFIELD_START, lzr_globals.PLAYFIELD_END)
end
end
end
minetest.register_on_placenode(function(pos, newnode, placer)
local state = lzr_gamestate.get_state()
if state ~= lzr_gamestate.LEVEL and state ~= lzr_gamestate.LEVEL_COMPLETE and state ~= lzr_gamestate.EDITOR then
return
end
if minetest.get_item_group(newnode.name, "detector") ~= 0 then
full_update_detector_placed()
else
full_update()
end
end)
minetest.register_on_dignode(function(pos, newnode, placer)
local state = lzr_gamestate.get_state()
if state ~= lzr_gamestate.LEVEL and state ~= lzr_gamestate.LEVEL_COMPLETE and state ~= lzr_gamestate.EDITOR then
return
end
full_update()
end)
local after_rotate = function()
full_update()
end
local element_on_place = function(itemstack, placer, pointed_thing)
-- node's on_rightclick action takes precedence
if pointed_thing.type == "node" and placer then
local node = minetest.get_node(pointed_thing.under)
local def = minetest.registered_nodes[node.name]
local sneak = placer:get_player_control().sneak
if def and def.on_rightclick and not sneak then
def.on_rightclick(pointed_thing.under, node, placer, itemstack, pointed_thing)
return itemstack
end
end
-- Default node placement behavior
return minetest.item_place_node(itemstack, placer, pointed_thing)
end
--[[ Register a 'laser element', i.e. a collection of nodes that
are supposed to interact with lasers. Each of these nodes is called a 'laser block'.
A single laser element may register many many nodes, depending on its
complexity.
Laser elements may have the following properties:
* They may be in an active or inactive state
* They may be takable by the player, or not (must be enabled with `options.allow_take`)
* For the active state, by default a node for every laser color will be added
* All its nodes share a new group that identify it as part of a laser element (in `options.group`)
The registered nodes follow these naming conventions:
* `<basename>`: This is the base node. Inactive, cannot be taken
* `<basename>_on_<color>`: Active, cannot be taken. <color> is a colorcode from 1 to lzr_globals.MAX_COLORCODE
* `<basename>_takable`: Inactive, can be taken
* `<basename>_takable_on_<color>`: Active, can be taken. <color> is a colorcode from 1 to lzr_globals.MAX_COLORCODE
If `options.register_color` is false, the active nodes won't have a `<color>`
suffix. Instead, they will be:
* `<basename>_on`: Active, non-takable
* `<basename>_takable_on`: Active, takable
Groups:
The following groups will be added automatically to the nodes:
* `[options.group]=1` to the inactive nodes
* `[options.group]=2` to the active nodes
* `breakable=1` to every node
* `takable=1` to nodes that can be taken by the player
* `not_in_creative_inventory=1` to active nodes by default
* `laser_block_color=<colorcode>` to active nodes with a laser color (not if `options.register_color` is false)
Parameters:
* basename: Itemstring identifier of the base node
May be preceded by a color to force a node name, as handled by minetest.register_node
* def: Definition table to define the node. All fields of the Minetest node definition can be applied here.
In addition, the following fields are special:
* description: Description of the base node. The other node variants
will have automatic variations added
* after_rotate: Called after the node was rotated by the rotating hook
* tiles_off: `tiles` table for the inactive and non-takable state
* tiles_on: `tiles` table for the active and non-takable state
* tiles_takable_off: `tiles` table for the inactive and non-takable state
* tiles_takable_on: `tiles` table for the active and non-takable state
* mesh_off: `mesh` value in inactive state
* mesh_on: `mesh` value in active state
* light_source_on: `light_source` value for the nodes in active state (default: 0)
* light_source_off: `light_source` value for the nodes in inactive state (default: 0)
Note about tiles: If your laser element has a laser in it, use the special tile `lzr_laser.LASER_TILE`
in the `tiles_*` tables to represent the tiles texture. This function will replace
it with the appropriate laser color.
* options: Additional options to further specify the laser element.
All fields are optional except 'group'. List of fields:
* group: Mandatory name of group that identifies the nodes as
part of the laser elementto add. Will add [group]=1 for inactive nodes
and [group]=2 for active nodes
* not_walkable_if_off: If true, the element turns non-walkable
if active (default: false)
* allow_take: If true, add 'takable' nodes (default: false)
* keep_state_on_take: If true, element will keep its on/off state
when taken by player (default: false)
* activate: If true, add 'activated' nodes (default: true)
* inactive: If set, override define the node name of the element in inactive
state (default: nil)
* active_in_creative: If true, allow the 'active' nodes to
be shown in the “Creative inventory” (read: level editor)
(default: false)
* register_colors: If true, all laser color variants will
be added for the active node state, registering a node
for every colorcode (default: true)
]]
lzr_laser.register_element = function(basename, def, options)
local real_basename = basename
if string.sub(basename, 1, 1) == ":" then
real_basename = string.sub(basename, 2, -1)
end
local def_core = table.copy(def)
if not options then options = {} end
if options.not_walkable_if_off then
def_core.walkable = false
end
if options.allow_take then
def_core._lzr_takable = real_basename.."_takable"
end
if options.allow_take then
def_core.description = S("@1 (fixed)", def.description)
else
def_core.description = def.description
end
def_core._after_rotate = after_rotate
if options.activate ~= false then
def_core._lzr_active = real_basename.."_on"
end
def_core.tiles = def.tiles_off
def_core.mesh = def.mesh_off
if not def_core.groups then
def_core.groups = {}
end
def_core.groups.breakable = 1
local groupname
if options.group then
groupname = options.group
else
error("[lzr_laser] lzr_laser.register_element: No group name specified in options for laser element with basename: "..tostring(basename))
end
def_core.groups[groupname] = 1
def_core.on_place = element_on_place
if options.inactive ~= nil then
def_core._lzr_inactive = options.inactive
if not options.keep_state_on_take then
def_core.drop = options.inactive
end
end
minetest.register_node(basename, def_core)
local def_core_on
if options.activate ~= false then
def_core_on = table.copy(def_core)
if options.not_walkable_if_off then
def_core_on.walkable = true
elseif options.not_walkable_if_on then
def_core_on.walkable = false
end
if options.allow_take then
def_core_on.description = S("@1 (fixed, active)", def.description)
else
def_core_on.description = S("@1 (active)", def.description)
end
def_core_on._lzr_inactive = real_basename
def_core_on.tiles = def.tiles_on
def_core_on.mesh = def.mesh_on
if not options.keep_state_on_take then
def_core_on.drop = real_basename
end
if options.allow_take then
def_core_on._lzr_takable = real_basename.."_takable_on"
end
def_core_on.groups[groupname] = 2
if not options.active_in_creative then
def_core_on.groups.not_in_creative_inventory = 1
def_core_on.inventory_image = nil
def_core_on.wield_image = nil
end
def_core_on.light_source = def.light_source_on
if options.register_color == false then
minetest.register_node(basename.."_on", def_core_on)
else
for c=1, lzr_globals.MAX_COLORCODE do
local def_core_on_c = table.copy(def_core_on)
for t=1, #def_core_on_c.tiles do
if def_core_on_c.tiles[t] == lzr_laser.LASER_TILE then
def_core_on_c.tiles[t] = colortiles[c]
end
end
def_core_on_c.groups.laser_block_color = c
minetest.register_node(basename.."_on_"..c, def_core_on_c)
end
end
end
if options.allow_take then
local def_takable = table.copy(def_core)
def_takable.tiles = def.tiles_takable_off
def_takable.groups.takable = 1
def_takable._lzr_untakable = real_basename
def_takable.description = def.description
if options.inactive ~= nil then
def_takable._lzr_inactive = options.inactive.."_takable"
if not options.keep_state_on_take then
def_takable.drop = options.inactive.."_takable"
end
end
minetest.register_node(basename.."_takable", def_takable)
if options.activate ~= false then
def_takable._lzr_active = real_basename.."_takable_on"
local def_takable_on = table.copy(def_core_on)
def_takable_on._lzr_untakable = real_basename.."_on"
def_takable_on.tiles = def.tiles_takable_on
def_takable_on.light_source = def.light_source_on
def_takable_on.groups.takable = 1
if not options.active_in_creative then
def_takable_on.groups.not_in_creative_inventory = 1
def_takable_on.inventory_image = nil
def_takable_on.wield_image = nil
end
def_takable_on.description = S("@1 (active)", def.description)
if not options.keep_state_on_take then
def_takable_on.drop = real_basename.."_takable"
end
def_takable_on._lzr_inactive = real_basename.."_takable"
def_takable_on._lzr_active = real_basename.."_takable_on"
if options.register_color == false then
minetest.register_node(basename.."_takable_on", def_takable_on)
else
for c=1, lzr_globals.MAX_COLORCODE do
local def_takable_on_c = table.copy(def_takable_on)
for t=1, #def_takable_on_c.tiles do
if def_takable_on_c.tiles[t] == lzr_laser.LASER_TILE then
def_takable_on_c.tiles[t] = colortiles[c]
end
end
def_takable_on_c.groups.laser_block_color = c
minetest.register_node(basename.."_takable_on_"..c, def_takable_on_c)
end
end
end
end
end
minetest.register_node("lzr_laser:crate", {
description = S("Heavy Crate"),
tiles = {
"lzr_laser_crate_fixed.png",
},
sounds = lzr_sounds.node_sound_wood_defaults(),
groups = { crate = 1, breakable = 1 },
})
minetest.register_node("lzr_laser:crate_mossy", {
description = S("Mossy Heavy Crate"),
tiles = {
"lzr_laser_crate_fixed_mossy.png",
},
sounds = lzr_sounds.node_sound_wood_defaults(),
groups = { crate = 1, breakable = 1 },
})
minetest.register_node("lzr_laser:crate_takable", {
description = S("Light Crate"),
tiles = {
"lzr_laser_crate.png",
},
sounds = lzr_sounds.node_sound_wood_defaults(),
groups = { crate = 1, breakable = 1, takable = 1 },
})
lzr_laser.register_element("lzr_laser:mirror", {
description = S("Mirror"),
paramtype = "light",
paramtype2 = "facedir",
tiles_off = {
{name="lzr_laser_mirror_block.png^lzr_laser_fixed.png", backface_culling=true},
{name="lzr_laser_mirror_mirror.png", backface_culling=true},
{name="lzr_laser_mirror_backside.png^lzr_laser_fixed.png", backface_culling=true},
},
tiles_on = {
lzr_laser.LASER_TILE,
{name="lzr_laser_mirror_block.png^lzr_laser_fixed.png", backface_culling=true},
{name="lzr_laser_mirror_mirror.png", backface_culling=true},
{name="lzr_laser_mirror_backside.png^lzr_laser_fixed.png", backface_culling=true},
},
tiles_takable_off = {
{name="lzr_laser_mirror_block.png", backface_culling=true},
{name="lzr_laser_mirror_mirror.png", backface_culling=true},
{name="lzr_laser_mirror_backside.png", backface_culling=true},
},
tiles_takable_on = {
lzr_laser.LASER_TILE,
{name="lzr_laser_mirror_block.png", backface_culling=true},
{name="lzr_laser_mirror_mirror.png", backface_culling=true},
{name="lzr_laser_mirror_backside.png", backface_culling=true},
},
use_texture_alpha = lzr_laser.ALPHA_LASER,
drawtype = "mesh",
mesh_off = "lzr_laser_mirror.obj",
mesh_on = "lzr_laser_mirror_on.obj",
light_source_on = lzr_globals.LASER_GLOW,
groups = { rotatable = 1, laser_block = 1 },
sounds = lzr_sounds.node_sound_glass_defaults({
_rotate = {name = "lzr_laser_mirror_rotate", gain = 1.0},
})
}, { group = "mirror", allow_take = true })
local tm_def = {
description = S("Transmissive Mirror"),
paramtype = "light",
paramtype2 = "facedir",
use_texture_alpha = lzr_laser.ALPHA_LASER,
drawtype = "mesh",
groups = { rotatable = 1, laser_block = 1 },
sounds = lzr_sounds.node_sound_glass_defaults({
_rotate = {name = "lzr_laser_mirror_rotate", gain = 1.0},
}),
}
-- Transmissive mirror, inactive (also known as "State 00")
local tm_def_off = table.copy(tm_def)
tm_def_off._lzr_transmissive_mirror_state = "00"
tm_def_off.tiles_off = {
{name="lzr_laser_transmissive_mirror_block.png^lzr_laser_fixed.png", backface_culling=true},
{name="lzr_laser_transmissive_mirror_mirror.png", backface_culling=true},
{name="lzr_laser_transmissive_mirror_mirror_out.png", backface_culling=true},
}
tm_def_off.tiles_takable_off = {
{name="lzr_laser_transmissive_mirror_block.png", backface_culling=true},
{name="lzr_laser_transmissive_mirror_mirror.png", backface_culling=true},
{name="lzr_laser_transmissive_mirror_mirror_out.png", backface_culling=true},
}
tm_def_off.mesh_off = "lzr_laser_tmirror.obj"
local tm_options_off = { allow_take = true, activate = false, group = "transmissive_mirror", register_color = false }
lzr_laser.register_element("lzr_laser:transmissive_mirror_00", tm_def_off, tm_options_off)
-- Transmissive Mirror, active
-- Register active transmissive mirrors
--[[
This registers a LOT of nodes, for each laser color AND
laser color combination. The transmissive mirror needs to deal with
multiple cases in which the laser impacts the mirror from
one of two possible sides of the angled mirror.
There are 4 basic possibilities:
* No laser: State 00 (inactive state, already handled above)
* Laser from side A: State X0
* Laser from side B: State 0X
* Laser from both sides: State XX
Where X = a colorcode of laser
The incoming direction of the laser is important because it determines
on which side the laser will "go through" the mirror.
In the following pictures, we will label each side:
* A: Front of the mirror
* B: Right of the mirror (relatively spoken)
* C: Opposite side of A
* D: Opposite side of B
C
D B
A
The lasers may come from side A or side B.
If they come from side C or D, they are blocked.
A laser from side A will be deflected to B
but also be "let through" to C. This is State X0.
C
^
|
+---+
| |/
D | /---> B
|/|
+ |
|
^
A
A laser from side B will be deflected to A
but also be "let through" to D. This is State 0X.
C
+---+
| /
D <--|-/---< B
|/|
+ |
|
v
A
If lasers come from both sides, this is
essentially a combination of State 0X and X0.
This is State XX. It looks like this:
C
^
|
|
+---+
| |/
D <--|-/----<> B
|/|
+ |
|
^
v
A
Laser from A is deflected to B, AND
the laser from B is deflected to A. This causes
both lasers to overlap while travelling between A and B,
causing the colors to be mixed. E.g. red + green = yellow.
This is just the normal laser behavior, overlapping
happens with the regular laser as well.
But also, laser from A goes through to C, AND
laser from B goes through to D. The "let through"
portion of the node must assume the color of the
incoming laser and NOT the mixed color between A and B.
This means in State XX, it is possible for the node
having to deal with not one, but three laser colors:
One for the portion A-B, one for center to D, and
one for center to C. This unfortunately means that
a LOT of nodes must be registered, one for each
possible combination.
For example, with a red laser from A, and a green laser
from B, the laser colors of the node must be:
* A to B: yellow (mix from red and green)
* center to C: red
* center to D: green
However, even if there can be up to 3 laser colors in the same
node, the node only needs to "know" 2 colors, not 3: one for
each incoming laser. The 3rd laser laser color results from
color mixing and can be derived from the incoming lasers.
If the laser only comes from one side,
the lasers inside the node will always be of the same color,
so fewer registrations are needed here.
This is because both the deflected laser and the laser that
goes through are the same laser.
<<< WHAT DOES THIS ALL MEAN??? >>>
In short:
* If no lasers are incoming (state 00), nothing special to do.
* If one laser is incoming (state X0 or 0X), register nodes for every colorcode.
* If two lasers are incoming (state XX), register nodes for each possible combination of *two* colorcodes
]]
-- Definition templates for active transmissive mirrors
-- State 0X (1 laser from one side)
local tm_def_on_0X = table.copy(tm_def)
tm_def_on_0X.light_source = lzr_globals.LASER_GLOW
if not tm_def_on_0X.groups then
tm_def_on_0X.groups = {}
end
tm_def_on_0X.groups.not_in_creative_inventory = 1
tm_def_on_0X.tiles_off = {
lzr_laser.LASER_TILE, -- << will be replaced
{name="lzr_laser_transmissive_mirror_block.png^lzr_laser_fixed.png", backface_culling=true},
{name="lzr_laser_transmissive_mirror_mirror.png", backface_culling=true},
{name="lzr_laser_transmissive_mirror_mirror_out.png", backface_culling=true},
}
tm_def_on_0X.tiles_takable_off = {
lzr_laser.LASER_TILE, -- << will be replaced
{name="lzr_laser_transmissive_mirror_block.png", backface_culling=true},
{name="lzr_laser_transmissive_mirror_mirror.png", backface_culling=true},
{name="lzr_laser_transmissive_mirror_mirror_out.png", backface_culling=true},
}
tm_def_on_0X.mesh_off = "lzr_laser_tmirror_on_thru1.obj"
-- State X0 (1 laser from other side)
local tm_def_on_X0 = table.copy(tm_def_on_0X)
tm_def_on_X0.mesh_off = "lzr_laser_tmirror_on_thru2.obj"
-- State XX (laser from both sides)
local tm_def_on_XX = table.copy(tm_def_on_0X)
tm_def_on_XX.tiles_off = {
lzr_laser.LASER_TILE, -- << incoming lasers
lzr_laser.LASER_TILE, -- << outgoing laser behind mirror
lzr_laser.LASER_TILE, -- << outgoing laser behind mirror (other side)
{name="lzr_laser_transmissive_mirror_block.png^lzr_laser_fixed.png", backface_culling=true},
{name="lzr_laser_transmissive_mirror_mirror.png", backface_culling=true},
{name="lzr_laser_transmissive_mirror_mirror_out.png", backface_culling=true},
}
tm_def_on_XX.tiles_takable_off = {
lzr_laser.LASER_TILE, -- << incoming lasers
lzr_laser.LASER_TILE, -- << outgoing laser behind mirror
lzr_laser.LASER_TILE, -- << outgoing laser behind mirror (other side)
{name="lzr_laser_transmissive_mirror_block.png", backface_culling=true},
{name="lzr_laser_transmissive_mirror_mirror.png", backface_culling=true},
{name="lzr_laser_transmissive_mirror_mirror_out.png", backface_culling=true},
}
tm_def_on_XX.mesh_off = "lzr_laser_tmirror_on_thru3.obj"
local tm_options_on = table.copy(tm_options_off)
tm_options_on.inactive = "lzr_laser:transmissive_mirror_00"
-- Iterate through all possible combinations of 2 colorcodes
-- and register the neccessary active transmissive mirrors accordingly
for laser1=0, #colortiles do
for laser2=0, #colortiles do
local laserid = tostring(laser1) .. tostring(laser2)
-- State 0X (X = 1 to max. colorcode)
if laser1 == 0 and laser2 > 0 then
local def = table.copy(tm_def_on_0X)
def._lzr_transmissive_mirror_state = laserid
def.description = S("Transmissive Mirror (active, @1)", laserid)
-- Apply the laser color
def.tiles_off[1] = colortiles[laser2]
def.tiles_takable_off[1] = colortiles[laser2]
lzr_laser.register_element("lzr_laser:transmissive_mirror_"..laserid, def, tm_options_on)
-- State X0
elseif laser1 > 0 and laser2 == 0 then
local def = table.copy(tm_def_on_X0)
def._lzr_transmissive_mirror_state = laserid
def.description = S("Transmissive Mirror (active, @1)", laserid)
-- Apply the laser color
def.tiles_off[1] = colortiles[laser1]
def.tiles_takable_off[1] = colortiles[laser1]
lzr_laser.register_element("lzr_laser:transmissive_mirror_"..laserid, def, tm_options_on)
-- State XX
elseif laser1 > 0 and laser2 > 0 then
local def = table.copy(tm_def_on_XX)
def._lzr_transmissive_mirror_state = laserid
def.description = S("Transmissive Mirror (active, @1)", laserid)
-- Apply the laser color (need 3 textures, explained above)
local laser_mixed = bit.bor(laser1, laser2)
def.tiles_off[1] = colortiles[laser_mixed]
def.tiles_takable_off[1] = colortiles[laser_mixed]
def.tiles_off[2] = colortiles[laser1]
def.tiles_takable_off[2] = colortiles[laser1]
def.tiles_off[3] = colortiles[laser2]
def.tiles_takable_off[3] = colortiles[laser2]
lzr_laser.register_element("lzr_laser:transmissive_mirror_"..laserid, def, tm_options_on)
end
end
end
lzr_laser.register_element("lzr_laser:crystal", {
description = S("Crystal"),
paramtype = "light",
paramtype2 = "facedir",
tiles_takable_off = {
"lzr_laser_crystal.png",
},
tiles_takable_on = {
"lzr_laser_crystal_on.png",
},
tiles_off = {
"lzr_laser_crystal.png^lzr_laser_fixed.png",
},
tiles_on = {
"lzr_laser_crystal_on.png^lzr_laser_fixed.png",
},
light_source_on = lzr_globals.LASER_GLOW,
groups = { laser_block = 1 },
sounds = lzr_sounds.node_sound_glass_defaults(),
}, { allow_take = true, group = "crystal" })
-- List of emitters
local emitters = {
-- list order: color name, suffix for item ID, suffix for texture, description, colorcode
{ "red", "_red", "", S("Red Emitter"), lzr_globals.COLOR_RED },
{ "green", "_green", "_green", S("Green Emitter"), lzr_globals.COLOR_GREEN },
{ "blue", "_blue", "_blue", S("Blue Emitter"), lzr_globals.COLOR_BLUE },
{ "yellow", "_yellow", "_yellow", S("Yellow Emitter"), lzr_globals.COLOR_YELLOW },
{ "magenta", "_magenta", "_magenta", S("Magenta Emitter"), lzr_globals.COLOR_MAGENTA },
{ "cyan", "_cyan", "_cyan", S("Cyan Emitter"), lzr_globals.COLOR_CYAN },
{ "white", "_white", "_white", S("White Emitter"), lzr_globals.COLOR_WHITE },
}
for e=1, #emitters do
local suffix = emitters[e][2]
local suffix_tex = emitters[e][3]
lzr_laser.register_element("lzr_laser:emitter"..suffix, {
description = emitters[e][4],
paramtype2 = "facedir",
tiles_takable_off = {
"lzr_laser_emitter"..suffix_tex..".png",
"lzr_laser_emitter"..suffix_tex..".png",
"lzr_laser_emitter"..suffix_tex..".png",
"lzr_laser_emitter"..suffix_tex..".png",
"lzr_laser_emitter"..suffix_tex..".png",
"lzr_laser_emitter"..suffix_tex.."_front.png",
},
tiles_takable_on = {
"lzr_laser_emitter"..suffix_tex.."_on.png",
"lzr_laser_emitter"..suffix_tex.."_on.png",
"lzr_laser_emitter"..suffix_tex.."_on.png",
"lzr_laser_emitter"..suffix_tex.."_on.png",
"lzr_laser_emitter"..suffix_tex.."_on.png",
"lzr_laser_emitter"..suffix_tex.."_on_front.png",
},
tiles_off = {
"lzr_laser_emitter"..suffix_tex..".png^lzr_laser_fixed.png",
"lzr_laser_emitter"..suffix_tex..".png^lzr_laser_fixed.png",
"lzr_laser_emitter"..suffix_tex..".png^lzr_laser_fixed.png",
"lzr_laser_emitter"..suffix_tex..".png^lzr_laser_fixed.png",
"lzr_laser_emitter"..suffix_tex..".png^lzr_laser_fixed.png",
"lzr_laser_emitter"..suffix_tex.."_front.png^lzr_laser_fixed.png",
},
tiles_on = {
"lzr_laser_emitter"..suffix_tex.."_on.png^lzr_laser_fixed.png",
"lzr_laser_emitter"..suffix_tex.."_on.png^lzr_laser_fixed.png",
"lzr_laser_emitter"..suffix_tex.."_on.png^lzr_laser_fixed.png",
"lzr_laser_emitter"..suffix_tex.."_on.png^lzr_laser_fixed.png",
"lzr_laser_emitter"..suffix_tex.."_on.png^lzr_laser_fixed.png",
"lzr_laser_emitter"..suffix_tex.."_on_front.png^lzr_laser_fixed.png",
},
light_source_on = 7,
_lzr_on_toggle = function(pos, node)
if lzr_gamestate.get_state() == lzr_gamestate.LEVEL_COMPLETE then
return
end
local nname
local on = false
if node.name == "lzr_laser:emitter"..suffix then
nname = "lzr_laser:emitter"..suffix.."_on"
on = true
elseif node.name == "lzr_laser:emitter"..suffix.."_on" then
nname = "lzr_laser:emitter"..suffix
elseif node.name == "lzr_laser:emitter"..suffix.."_takable" then
nname = "lzr_laser:emitter"..suffix.."_takable_on"
on = true
elseif node.name == "lzr_laser:emitter"..suffix.."_takable_on" then
nname = "lzr_laser:emitter"..suffix.."_takable"
end
if on then
minetest.sound_play({name="lzr_laser_emitter_activate", gain=1.0}, {pos=pos}, true)
else
minetest.sound_play({name="lzr_laser_emitter_activate", gain=0.8}, {pos=pos, pitch=0.7}, true)
end
minetest.swap_node(pos, {name=nname, param2=node.param2})
full_update()
end,
groups = { rotatable = 2, laser_block = 1, emitter_color = emitters[e][5] },
sounds = lzr_sounds.node_sound_wood_defaults(),
}, { allow_take = true, keep_state_on_take = true, active_in_creative = true, register_color = false, group = "emitter" })
end
minetest.register_alias("lzr_laser:emitter", "lzr_laser:emitter_red")
minetest.register_alias("lzr_laser:emitter_takable", "lzr_laser:emitter_red_takable")
minetest.register_alias("lzr_laser:emitter_on", "lzr_laser:emitter_red_on")
minetest.register_alias("lzr_laser:emitter_takable_on", "lzr_laser:emitter_red_takable_on")
-- List of detectors
local detectors = {
-- list order: color name, suffix for item ID, suffix for texture, description, colorcode
-- Colorless detector that accepts any color
{ "", "", "", S("Detector "), nil },
-- Colored detectors that accept only one color
{ "red", "_red", "_red", S("Red Detector"), lzr_globals.COLOR_RED },
{ "green", "_green", "_green", S("Green Detector"), lzr_globals.COLOR_GREEN },
{ "blue", "_blue", "_blue", S("Blue Detector"), lzr_globals.COLOR_BLUE },
{ "yellow", "_yellow", "_yellow", S("Yellow Detector"), lzr_globals.COLOR_YELLOW },
{ "magenta", "_magenta", "_magenta", S("Magenta Detector"), lzr_globals.COLOR_MAGENTA },
{ "cyan", "_cyan", "_cyan", S("Cyan Detector"), lzr_globals.COLOR_CYAN },
{ "white", "_white", "_white", S("White Detector"), lzr_globals.COLOR_WHITE },
}
for d=1, #detectors do
local suffix = detectors[d][2]
local suffix_tex = detectors[d][3]
local desc = detectors[d][4]
local colorcode = detectors[d][5]
lzr_laser.register_element("lzr_laser:detector"..suffix, {
description = desc,
paramtype2 = "facedir",
tiles_off = {
"lzr_laser_detector"..suffix_tex..".png^lzr_laser_fixed.png",
"lzr_laser_detector"..suffix_tex..".png^lzr_laser_fixed.png",
"lzr_laser_detector"..suffix_tex..".png^lzr_laser_fixed.png",
"lzr_laser_detector"..suffix_tex..".png^lzr_laser_fixed.png",
"lzr_laser_detector"..suffix_tex..".png^lzr_laser_fixed.png",
"lzr_laser_detector"..suffix_tex.."_front.png^lzr_laser_fixed.png",
},
tiles_on = {
"lzr_laser_detector"..suffix_tex.."_on.png^lzr_laser_fixed.png",
"lzr_laser_detector"..suffix_tex.."_on.png^lzr_laser_fixed.png",
"lzr_laser_detector"..suffix_tex.."_on.png^lzr_laser_fixed.png",
"lzr_laser_detector"..suffix_tex.."_on.png^lzr_laser_fixed.png",
"lzr_laser_detector"..suffix_tex.."_on.png^lzr_laser_fixed.png",
"lzr_laser_detector"..suffix_tex.."_on_front.png^lzr_laser_fixed.png",
},
tiles_takable_off = {
"lzr_laser_detector"..suffix_tex..".png",
"lzr_laser_detector"..suffix_tex..".png",
"lzr_laser_detector"..suffix_tex..".png",
"lzr_laser_detector"..suffix_tex..".png",
"lzr_laser_detector"..suffix_tex..".png",
"lzr_laser_detector"..suffix_tex.."_front.png",
},
tiles_takable_on = {
"lzr_laser_detector"..suffix_tex.."_on.png",
"lzr_laser_detector"..suffix_tex.."_on.png",
"lzr_laser_detector"..suffix_tex.."_on.png",
"lzr_laser_detector"..suffix_tex.."_on.png",
"lzr_laser_detector"..suffix_tex.."_on.png",
"lzr_laser_detector"..suffix_tex.."_on_front.png",
},
light_source_on = 5,
groups = { rotatable = 2, laser_block = 1, detector_color = colorcode },
sounds = lzr_sounds.node_sound_wood_defaults(),
}, { allow_take = true, is_detector = true, register_color = false, group = "detector" })
end
-- Hollow barrel
lzr_laser.register_element("lzr_laser:hollow_barrel", {
description = S("Hollow Barrel"),
paramtype = "light",
paramtype2 = "facedir",
drawtype = "mesh",
mesh_off = "lzr_laser_hollow_barrel.obj",
mesh_on = "lzr_laser_hollow_barrel_on.obj",
tiles_off = {
"lzr_laser_hollow_barrel_top.png^lzr_laser_fixed.png",
"lzr_laser_hollow_barrel_top.png^lzr_laser_fixed.png",
"lzr_laser_hollow_barrel_sides.png^lzr_laser_fixed.png",
"lzr_laser_hollow_barrel_insides.png",
},
tiles_on = {
"lzr_laser_hollow_barrel_top.png^lzr_laser_fixed.png",
"lzr_laser_hollow_barrel_top.png^lzr_laser_fixed.png",
"lzr_laser_hollow_barrel_sides.png^lzr_laser_fixed.png",
"lzr_laser_hollow_barrel_insides.png",
lzr_laser.LASER_TILE,
},
tiles_takable_off = {
"lzr_laser_hollow_barrel_top.png",
"lzr_laser_hollow_barrel_top.png",
"lzr_laser_hollow_barrel_sides.png",
"lzr_laser_hollow_barrel_insides.png",
},
tiles_takable_on = {
"lzr_laser_hollow_barrel_top.png",
"lzr_laser_hollow_barrel_top.png",
"lzr_laser_hollow_barrel_sides.png",
"lzr_laser_hollow_barrel_insides.png",
lzr_laser.LASER_TILE,
},
use_texture_alpha = lzr_laser.ALPHA_LASER,
light_source_on = lzr_globals.LASER_GLOW,
groups = { rotatable = 1, laser_block = 1 },
sounds = lzr_sounds.node_sound_wood_defaults(),
}, { allow_take = true, group = "hollow_barrel" })
-- Is non-walkable if off,
-- and walkable if on.
lzr_laser.register_element("lzr_laser:skull_cursed", {
description = S("Cursed Skull"),
drawtype = "mesh",
-- Mesh based on skull nodebox by rudzik8
mesh_off = "lzr_laser_skull.obj",
mesh_on = "lzr_laser_skull.obj",
collision_box = {type="regular"},
selection_box = {type="regular"},
paramtype = "light",
paramtype2 = "facedir",
tiles_off = {
{ name = "(lzr_laser_cskull_top.png^lzr_laser_fixed.png)^[opacity:"..OPACITY_SKULL_GONE, backface_culling = true },
{ name = "(lzr_laser_cskull_bottom.png^lzr_laser_fixed.png)^[opacity:"..OPACITY_SKULL_GONE, backface_culling = true },
{ name = "(lzr_laser_cskull_side.png^lzr_laser_fixed.png)^[opacity:"..OPACITY_SKULL_GONE, backface_culling = true },
{ name = "(lzr_laser_cskull_side.png^lzr_laser_fixed.png^[transformFX)^[opacity:"..OPACITY_SKULL_GONE, backface_culling = true },
{ name = "(lzr_laser_cskull_back.png^lzr_laser_fixed.png)^[opacity:"..OPACITY_SKULL_GONE, backface_culling = true },
{ name = "(lzr_laser_cskull_front.png^lzr_laser_fixed.png)^[opacity:"..OPACITY_SKULL_GONE, backface_culling = true },
},
tiles_on = {
{ name = "lzr_laser_cskull_top.png^lzr_laser_fixed.png", backface_culling = true },
{ name = "lzr_laser_cskull_bottom.png^lzr_laser_fixed.png", backface_culling = true },
{ name = "lzr_laser_cskull_side.png^lzr_laser_fixed.png", backface_culling = true },
{ name = "lzr_laser_cskull_side.png^lzr_laser_fixed.png^[transformFX", backface_culling = true },
{ name = "lzr_laser_cskull_back.png^lzr_laser_fixed.png", backface_culling = true },
{ name = "lzr_laser_cskull_front.png^lzr_laser_fixed.png^lzr_laser_cskull_on.png", backface_culling = true },
},
tiles_takable_off = {
{ name = "lzr_laser_cskull_top.png^[opacity:"..OPACITY_SKULL_GONE, backface_culling = true },
{ name = "lzr_laser_cskull_bottom.png^[opacity:"..OPACITY_SKULL_GONE, backface_culling = true },
{ name = "lzr_laser_cskull_side.png^[opacity:"..OPACITY_SKULL_GONE, backface_culling = true },
{ name = "(lzr_laser_cskull_side.png^[transformFX)^[opacity:"..OPACITY_SKULL_GONE, backface_culling = true },
{ name = "lzr_laser_cskull_back.png^[opacity:"..OPACITY_SKULL_GONE, backface_culling = true },
{ name = "lzr_laser_cskull_front.png^[opacity:"..OPACITY_SKULL_GONE, backface_culling = true },
},
tiles_takable_on = {
{ name = "lzr_laser_cskull_top.png", backface_culling = true },
{ name = "lzr_laser_cskull_bottom.png", backface_culling = true },
{ name = "lzr_laser_cskull_side.png", backface_culling = true },
{ name = "lzr_laser_cskull_side.png^[transformFX", backface_culling = true },
{ name = "lzr_laser_cskull_back.png", backface_culling = true },
{ name = "lzr_laser_cskull_front.png^lzr_laser_cskull_on.png", backface_culling = true },
},
use_texture_alpha = "blend",
light_source_on = 5,
groups = { rotatable = 2, skull = 1, laser_block = 1 },
on_rotate = screwdriver.rotate_simple,
sounds = lzr_sounds.node_sound_stone_defaults(),
}, { allow_take = true, not_walkable_if_off = true, register_color = false, group = "skull_cursed" })
-- Is walkable if off,
-- and non-walkable if on.
lzr_laser.register_element("lzr_laser:skull_shy", {
description = S("Shy Skull"),
drawtype = "mesh",
-- Mesh based on skull nodebox by rudzik8
mesh_off = "lzr_laser_skull.obj",
mesh_on = "lzr_laser_skull.obj",
collision_box = {type="regular"},
selection_box = {type="regular"},
paramtype = "light",
paramtype2 = "facedir",
tiles_off = {
{ name = "lzr_laser_sskull_top.png^lzr_laser_fixed.png", backface_culling = true },
{ name = "lzr_laser_sskull_bottom.png^lzr_laser_fixed.png", backface_culling = true },
{ name = "lzr_laser_sskull_side.png^lzr_laser_fixed.png", backface_culling = true },
{ name = "lzr_laser_sskull_side.png^lzr_laser_fixed.png^[transformFX", backface_culling = true },
{ name = "lzr_laser_sskull_back.png^lzr_laser_fixed.png", backface_culling = true },
{ name = "lzr_laser_sskull_front.png^lzr_laser_fixed.png", backface_culling = true },
},
tiles_on = {
{ name = "(lzr_laser_sskull_top.png^lzr_laser_fixed.png)^[opacity:"..OPACITY_SKULL_GONE, backface_culling = true },
{ name = "(lzr_laser_sskull_bottom.png^lzr_laser_fixed.png)^[opacity:"..OPACITY_SKULL_GONE, backface_culling = true },
{ name = "(lzr_laser_sskull_side.png^lzr_laser_fixed.png)^[opacity:"..OPACITY_SKULL_GONE, backface_culling = true },
{ name = "(lzr_laser_sskull_side.png^lzr_laser_fixed.png^[transformFX)^[opacity:"..OPACITY_SKULL_GONE, backface_culling = true },
{ name = "(lzr_laser_sskull_back.png^lzr_laser_fixed.png)^[opacity:"..OPACITY_SKULL_GONE, backface_culling = true },
{ name = "(lzr_laser_sskull_front.png^lzr_laser_fixed.png^lzr_laser_sskull_on.png)^[opacity:"..OPACITY_SKULL_GONE, backface_culling = true },
},
tiles_takable_off = {
{ name = "lzr_laser_sskull_top.png", backface_culling = true },
{ name = "lzr_laser_sskull_bottom.png", backface_culling = true },
{ name = "lzr_laser_sskull_side.png", backface_culling = true },
{ name = "lzr_laser_sskull_side.png^[transformFX", backface_culling = true },
{ name = "lzr_laser_sskull_back.png", backface_culling = true },
{ name = "lzr_laser_sskull_front.png", backface_culling = true },
},
tiles_takable_on = {
{ name = "lzr_laser_sskull_top.png^[opacity:"..OPACITY_SKULL_GONE, backface_culling = true },
{ name = "lzr_laser_sskull_bottom.png^[opacity:"..OPACITY_SKULL_GONE, backface_culling = true },
{ name = "lzr_laser_sskull_side.png^[opacity:"..OPACITY_SKULL_GONE, backface_culling = true },
{ name = "(lzr_laser_sskull_side.png^[transformFX)^[opacity:"..OPACITY_SKULL_GONE, backface_culling = true },
{ name = "lzr_laser_sskull_back.png^[opacity:"..OPACITY_SKULL_GONE, backface_culling = true },
{ name = "lzr_laser_sskull_front.png^lzr_laser_sskull_on.png^[opacity:"..OPACITY_SKULL_GONE, backface_culling = true },
},
use_texture_alpha = "blend",
light_source_on = 5,
groups = { rotatable = 2, skull = 2, laser_block = 1 },
on_rotate = screwdriver.rotate_simple,
sounds = lzr_sounds.node_sound_stone_defaults(),
}, { allow_take = true, not_walkable_if_on = true, register_color = false, group = "skull_shy" })
minetest.register_node("lzr_laser:barricade", {
description = S("Barricade"),
drawtype = "mesh",
mesh = "lzr_laser_burning.obj",
paramtype = "light",
inventory_image = "xdecor_baricade.png",
wield_image = "xdecor_baricade.png",
tiles = {"blank.png","xdecor_baricade.png"},
use_texture_alpha = "clip",
groups = { breakable = 1, flammable = 1, laser_destroys = 2 },
sounds = lzr_sounds.node_sound_wood_defaults({
dug = {name="lzr_laser_barricade_break", gain=1.0},
}),
on_place = element_on_place,
_lzr_active = "lzr_laser:barricade_on",
})
minetest.register_node("lzr_laser:barricade_on", {
description = S("Burning Barricade"),
drawtype = "mesh",
paramtype = "light",
light_source = 12,
mesh = "lzr_laser_burning.obj",
inventory_image = "lzr_laser_baricade_burning.png",
wield_image = "lzr_laser_baricade_burning.png",
use_texture_alpha = "clip",
tiles = {
{ name="fire_basic_flame_animated.png", animation={
type = "vertical_frames",
aspect_w = 16,
aspect_h = 16,
length = 1.0,
},},
{ name="lzr_laser_baricade_burning_animated.png", animation={
type = "vertical_frames",
aspect_w = 16,
aspect_h = 16,
length = 1.0,
},},
},
groups = { breakable = 1, not_in_creative_inventory = 1 },
sounds = lzr_sounds.node_sound_wood_defaults({
dug = {name="lzr_laser_barricade_break", gain=1.0},
}),
on_construct = function(pos)
minetest.sound_play({name="lzr_laser_quickburn", gain=1.0}, {pos=pos}, true)
local timer = minetest.get_node_timer(pos)
timer:start(1)
end,
on_timer = function(pos)
-- spawn a few particles for the removed node
minetest.add_particlespawner({
amount = 16,
time = 0.001,
minpos = vector.subtract(pos, vector.new(0.5, 0.5, 0.5)),
maxpos = vector.add(pos, vector.new(0.5, 0.5, 0.5)),
minvel = vector.new(-0.5, -0.2, -0.5),
maxvel = vector.new(0.5, 0.2, 0.5),
minacc = vector.new(0, -lzr_globals.GRAVITY, 0),
maxacc = vector.new(0, -lzr_globals.GRAVITY, 0),
minsize = 1.5,
maxsize = 1.5,
node = {name="lzr_laser:barricade"},
})
-- Play randomly-pitched break sound
local pitch = 1.0+math.random(-100, 100)*0.001 -- 0.9..1.1
minetest.sound_play({name="lzr_laser_barricade_break", gain=1.0}, {gain=1.0, pitch=pitch, pos=pos}, true)
-- remove node
minetest.remove_node(pos)
full_update()
-- propagate to neighbors
local posses = {
vector.new(-1,0,0),
vector.new(1,0,0),
vector.new(0,-1,0),
vector.new(0,1,0),
vector.new(0,0,-1),
vector.new(0,0,1),
}
for p=1, #posses do
local ppos = vector.add(pos, posses[p])
local node = minetest.get_node(ppos)
local def = minetest.registered_nodes[node.name]
if def and def._lzr_active then
if minetest.get_item_group(node.name, "flammable") > 0 then
minetest.set_node(ppos, {name=def._lzr_active})
end
end
end
end,
drop = "",
on_place = element_on_place,
_lzr_inactive = "lzr_laser:barricade",
})
-- Aliases for the pre-laser color era
minetest.register_alias("lzr_laser:mirror_takable_on", "lzr_laser:mirror_takable_on_1")
minetest.register_alias("lzr_laser:mirror_on", "lzr_laser:mirror_on_1")
minetest.register_alias("lzr_laser:hollow_barrel_on", "lzr_laser:hollow_barrel_on_1")
minetest.register_alias("lzr_laser:hollow_barrel_takable_on", "lzr_laser:hollow_barrel_takable_on_1")