1255 lines
45 KiB
Lua
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")
|