460 lines
14 KiB
Lua
460 lines
14 KiB
Lua
local S = minetest.get_translator("lzr_laser")
|
|
|
|
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_detector_dir = function(param2)
|
|
local dir_input = minetest.facedir_to_dir(param2)
|
|
if not dir_input then
|
|
return
|
|
end
|
|
dir_input = vector.multiply(dir_input, -1)
|
|
return dir_input
|
|
end
|
|
|
|
lzr_laser.check_detector = function(detector_pos, laser_dir)
|
|
local detector = minetest.get_node(detector_pos)
|
|
local detector_group = minetest.get_item_group(detector.name, "detector")
|
|
if detector_group == 0 then
|
|
return false
|
|
end
|
|
local reverse_laser_dir = vector.multiply(laser_dir, -1)
|
|
local detector_dir_in = lzr_laser.get_detector_dir(detector.param2)
|
|
if not detector_dir_in then
|
|
return false
|
|
end
|
|
if vector.equals(reverse_laser_dir, detector_dir_in) then
|
|
return true
|
|
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 at mirror_pos with a laser coming towards
|
|
-- the mirror with the laser_dir direction (direction vector).
|
|
-- Returns the "output direction" of the laser or false if can't get mirrored.
|
|
lzr_laser.get_mirrored_laser_dir = function(mirror_pos, laser_dir)
|
|
local mirror = minetest.get_node(mirror_pos)
|
|
local mirror_group = minetest.get_item_group(mirror.name, "mirror")
|
|
local mirror_transmissive_group = minetest.get_item_group(mirror.name, "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(mirror.param2)
|
|
if not mirror_dir_in then
|
|
return false
|
|
end
|
|
if vector.equals(reverse_laser_dir, mirror_dir_in) then
|
|
return mirror_dir_out
|
|
elseif vector.equals(reverse_laser_dir, mirror_dir_out) then
|
|
return mirror_dir_in
|
|
end
|
|
return false
|
|
end
|
|
|
|
-- Update the whole playfield after placing or digging a laser node
|
|
local full_update = function()
|
|
local state = lzr_gamestate.get_state()
|
|
if state ~= lzr_gamestate.LEVEL 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()
|
|
end
|
|
end
|
|
|
|
-- Same as above, but special case after a detector was placed.
|
|
-- This is hack to tell check_level_won that there 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.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(true)
|
|
if done then
|
|
lzr_levels.level_complete()
|
|
end
|
|
end
|
|
|
|
local after_rotate = function()
|
|
full_update()
|
|
end
|
|
|
|
local register_element = function(subname, def, options)
|
|
local def_core = table.copy(def)
|
|
if not options then options = {} end
|
|
if options.is_detector then
|
|
def_core.after_place_node = full_update_detector_placed
|
|
else
|
|
def_core.after_place_node = full_update
|
|
end
|
|
def_core.after_dig_node = full_update
|
|
def_core._after_rotate = after_rotate
|
|
if options.activate ~= false then
|
|
def_core._lzr_active = "lzr_laser:"..subname.."_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
|
|
def_core.groups[subname] = 1
|
|
def_core.can_dig = function()
|
|
return lzr_gamestate.get_state() ~= lzr_gamestate.LEVEL_COMPLETE
|
|
end
|
|
def_core.on_place = function(itemstack, placer, pointed_thing)
|
|
if lzr_gamestate.get_state() == lzr_gamestate.LEVEL_COMPLETE then
|
|
-- Prevent node placement when in 'level complete' state
|
|
return itemstack
|
|
else
|
|
-- 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
|
|
end
|
|
|
|
minetest.register_node("lzr_laser:"..subname, def_core)
|
|
|
|
local def_core_on
|
|
if options.activate ~= false then
|
|
def_core_on = table.copy(def_core)
|
|
def_core_on.description = S("@1 (active)", def.description)
|
|
def_core_on._lzr_active = nil
|
|
def_core_on._lzr_inactive = "lzr_laser:"..subname
|
|
def_core_on.tiles = def.tiles_on
|
|
def_core_on.mesh = def.mesh_on
|
|
def_core_on.drop = "lzr_laser:"..subname
|
|
def_core_on.groups[subname] = 2
|
|
def_core_on.light_source = def.light_source_on
|
|
minetest.register_node("lzr_laser:"..subname.."_on", def_core_on)
|
|
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.description = S("@1 (takable)", def.description)
|
|
minetest.register_node("lzr_laser:"..subname.."_takable", def_takable)
|
|
|
|
if options.activate ~= false then
|
|
def_takable._lzr_active = "lzr_laser:"..subname.."_takable_on"
|
|
local def_takable_on = table.copy(def_core_on)
|
|
def_takable_on.tiles = def.tiles_takable_on
|
|
def_takable_on.light_source = def.light_source_on
|
|
def_takable_on.groups.takable = 1
|
|
def_takable_on.description = S("@1 (takable, active)", def.description)
|
|
def_takable_on.drop = "lzr_laser:"..subname.."_takable"
|
|
def_takable_on._lzr_inactive = "lzr_laser:"..subname.."_takable"
|
|
minetest.register_node("lzr_laser:"..subname.."_takable_on", def_takable_on)
|
|
end
|
|
end
|
|
end
|
|
|
|
-- Mirror nodebox
|
|
local wedge_box = {}
|
|
for i=-8, 7 do
|
|
table.insert(wedge_box, { i/16, -0.5, i/16, (i+1)/16, 0.5, 0.5 })
|
|
end
|
|
|
|
register_element("crate", {
|
|
description = S("Crate"),
|
|
tiles_off = {
|
|
"lzr_laser_crate_fixed.png",
|
|
},
|
|
tiles_takable_off = {
|
|
"lzr_laser_crate.png",
|
|
},
|
|
sounds = lzr_sounds.node_sound_wood_defaults(),
|
|
}, { allow_take = true, activate = false })
|
|
|
|
register_element("mirror", {
|
|
description = S("Mirror"),
|
|
paramtype = "light",
|
|
paramtype2 = "facedir",
|
|
tiles_off = {
|
|
"lzr_laser_mirror_top.png^lzr_laser_fixed.png",
|
|
"lzr_laser_mirror_top.png^[transformFY^lzr_laser_fixed.png",
|
|
"lzr_laser_mirror_hole.png^lzr_laser_fixed.png",
|
|
"lzr_laser_mirror_block.png^lzr_laser_fixed.png",
|
|
"lzr_laser_mirror_block.png^lzr_laser_fixed.png",
|
|
"lzr_laser_mirror_hole.png^lzr_laser_fixed.png",
|
|
},
|
|
tiles_on = {
|
|
"lzr_laser_mirror_on_top.png^lzr_laser_fixed.png",
|
|
"lzr_laser_mirror_on_top.png^[transformFY^lzr_laser_fixed.png",
|
|
"lzr_laser_mirror_on_hole.png^lzr_laser_fixed.png",
|
|
"lzr_laser_mirror_on_block.png^lzr_laser_fixed.png",
|
|
"lzr_laser_mirror_on_block.png^lzr_laser_fixed.png",
|
|
"lzr_laser_mirror_on_hole.png^lzr_laser_fixed.png",
|
|
},
|
|
tiles_takable_off = {
|
|
"lzr_laser_mirror_top.png",
|
|
"lzr_laser_mirror_top.png^[transformFY",
|
|
"lzr_laser_mirror_hole.png",
|
|
"lzr_laser_mirror_block.png",
|
|
"lzr_laser_mirror_block.png",
|
|
"lzr_laser_mirror_hole.png",
|
|
},
|
|
tiles_takable_on = {
|
|
"lzr_laser_mirror_on_top.png",
|
|
"lzr_laser_mirror_on_top.png^[transformFY",
|
|
"lzr_laser_mirror_on_hole.png",
|
|
"lzr_laser_mirror_on_block.png",
|
|
"lzr_laser_mirror_on_block.png",
|
|
"lzr_laser_mirror_on_hole.png",
|
|
},
|
|
|
|
light_source_on = 3,
|
|
|
|
collision_box = {
|
|
type = "fixed",
|
|
fixed = wedge_box,
|
|
},
|
|
groups = { rotatable = 1, laser_block = 1 },
|
|
sounds = lzr_sounds.node_sound_glass_defaults({
|
|
_rotate = {name = "lzr_laser_mirror_rotate", gain = 1.0},
|
|
})
|
|
}, { allow_take = true })
|
|
|
|
register_element("transmissive_mirror", {
|
|
description = S("Transmissive Mirror"),
|
|
paramtype = "light",
|
|
paramtype2 = "facedir",
|
|
tiles_takable_off = {
|
|
"lzr_laser_transmissive_mirror_top.png",
|
|
"lzr_laser_transmissive_mirror_top.png^[transformFY",
|
|
"lzr_laser_transmissive_mirror_hole.png",
|
|
"lzr_laser_transmissive_mirror_block.png",
|
|
"lzr_laser_transmissive_mirror_block.png",
|
|
"lzr_laser_transmissive_mirror_hole.png",
|
|
},
|
|
tiles_takable_on = {
|
|
"lzr_laser_transmissive_mirror_on_top.png",
|
|
"lzr_laser_transmissive_mirror_on_top.png^[transformFY",
|
|
"lzr_laser_transmissive_mirror_on_hole.png",
|
|
"lzr_laser_transmissive_mirror_on_block.png",
|
|
"lzr_laser_transmissive_mirror_on_block.png",
|
|
"lzr_laser_transmissive_mirror_on_hole.png",
|
|
},
|
|
tiles_off = {
|
|
"lzr_laser_transmissive_mirror_top.png^lzr_laser_fixed.png",
|
|
"lzr_laser_transmissive_mirror_top.png^[transformFY^lzr_laser_fixed.png",
|
|
"lzr_laser_transmissive_mirror_hole.png^lzr_laser_fixed.png",
|
|
"lzr_laser_transmissive_mirror_block.png^lzr_laser_fixed.png",
|
|
"lzr_laser_transmissive_mirror_block.png^lzr_laser_fixed.png",
|
|
"lzr_laser_transmissive_mirror_hole.png^lzr_laser_fixed.png",
|
|
},
|
|
tiles_on = {
|
|
"lzr_laser_transmissive_mirror_on_top.png^lzr_laser_fixed.png",
|
|
"lzr_laser_transmissive_mirror_on_top.png^[transformFY^lzr_laser_fixed.png",
|
|
"lzr_laser_transmissive_mirror_on_hole.png^lzr_laser_fixed.png",
|
|
"lzr_laser_transmissive_mirror_on_block.png^lzr_laser_fixed.png",
|
|
"lzr_laser_transmissive_mirror_on_block.png^lzr_laser_fixed.png",
|
|
"lzr_laser_transmissive_mirror_on_hole.png^lzr_laser_fixed.png",
|
|
},
|
|
light_source_on = 3,
|
|
collision_box = {
|
|
type = "fixed",
|
|
fixed = wedge_box,
|
|
},
|
|
groups = { rotatable = 1, laser_block = 1 },
|
|
sounds = lzr_sounds.node_sound_glass_defaults({
|
|
_rotate = {name = "lzr_laser_mirror_rotate", gain = 1.0},
|
|
})
|
|
}, { allow_take = true })
|
|
|
|
register_element("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 = 3,
|
|
groups = { laser_block = 1 },
|
|
sounds = lzr_sounds.node_sound_glass_defaults({
|
|
_rotate = {name = "lzr_laser_mirror_rotate", gain = 1.0},
|
|
})
|
|
}, { allow_take = true })
|
|
|
|
|
|
|
|
|
|
register_element("emitter", {
|
|
description = S("Emitter"),
|
|
paramtype2 = "facedir",
|
|
tiles_takable_off = {
|
|
"lzr_laser_emitter.png",
|
|
"lzr_laser_emitter.png",
|
|
"lzr_laser_emitter.png",
|
|
"lzr_laser_emitter.png",
|
|
"lzr_laser_emitter.png",
|
|
"lzr_laser_emitter_front.png",
|
|
},
|
|
tiles_takable_on = {
|
|
"lzr_laser_emitter_on.png",
|
|
"lzr_laser_emitter_on.png",
|
|
"lzr_laser_emitter_on.png",
|
|
"lzr_laser_emitter_on.png",
|
|
"lzr_laser_emitter_on.png",
|
|
"lzr_laser_emitter_on_front.png",
|
|
|
|
},
|
|
tiles_off = {
|
|
"lzr_laser_emitter.png^lzr_laser_fixed.png",
|
|
"lzr_laser_emitter.png^lzr_laser_fixed.png",
|
|
"lzr_laser_emitter.png^lzr_laser_fixed.png",
|
|
"lzr_laser_emitter.png^lzr_laser_fixed.png",
|
|
"lzr_laser_emitter.png^lzr_laser_fixed.png",
|
|
"lzr_laser_emitter_front.png^lzr_laser_fixed.png",
|
|
},
|
|
tiles_on = {
|
|
"lzr_laser_emitter_on.png^lzr_laser_fixed.png",
|
|
"lzr_laser_emitter_on.png^lzr_laser_fixed.png",
|
|
"lzr_laser_emitter_on.png^lzr_laser_fixed.png",
|
|
"lzr_laser_emitter_on.png^lzr_laser_fixed.png",
|
|
"lzr_laser_emitter_on.png^lzr_laser_fixed.png",
|
|
"lzr_laser_emitter_on_front.png^lzr_laser_fixed.png",
|
|
|
|
},
|
|
light_source_on = 7,
|
|
on_rightclick = 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" then
|
|
nname = "lzr_laser:emitter_on"
|
|
on = true
|
|
elseif node.name == "lzr_laser:emitter_on" then
|
|
nname = "lzr_laser:emitter"
|
|
elseif node.name == "lzr_laser:emitter_takable" then
|
|
nname = "lzr_laser:emitter_takable_on"
|
|
on = true
|
|
elseif node.name == "lzr_laser:emitter_takable_on" then
|
|
nname = "lzr_laser:emitter_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 = { laser_block = 1 },
|
|
sounds = lzr_sounds.node_sound_wood_defaults(),
|
|
}, { allow_take = true })
|
|
|
|
register_element("detector", {
|
|
description = S("Detector"),
|
|
paramtype2 = "facedir",
|
|
tiles_off = {
|
|
"lzr_laser_detector.png^lzr_laser_fixed.png",
|
|
"lzr_laser_detector.png^lzr_laser_fixed.png",
|
|
"lzr_laser_detector.png^lzr_laser_fixed.png",
|
|
"lzr_laser_detector.png^lzr_laser_fixed.png",
|
|
"lzr_laser_detector.png^lzr_laser_fixed.png",
|
|
"lzr_laser_detector_front.png^lzr_laser_fixed.png",
|
|
},
|
|
tiles_on = {
|
|
"lzr_laser_detector_on.png^lzr_laser_fixed.png",
|
|
"lzr_laser_detector_on.png^lzr_laser_fixed.png",
|
|
"lzr_laser_detector_on.png^lzr_laser_fixed.png",
|
|
"lzr_laser_detector_on.png^lzr_laser_fixed.png",
|
|
"lzr_laser_detector_on.png^lzr_laser_fixed.png",
|
|
"lzr_laser_detector_on_front.png^lzr_laser_fixed.png",
|
|
},
|
|
tiles_takable_off = {
|
|
"lzr_laser_detector.png",
|
|
"lzr_laser_detector.png",
|
|
"lzr_laser_detector.png",
|
|
"lzr_laser_detector.png",
|
|
"lzr_laser_detector.png",
|
|
"lzr_laser_detector_front.png",
|
|
},
|
|
tiles_takable_on = {
|
|
"lzr_laser_detector_on.png",
|
|
"lzr_laser_detector_on.png",
|
|
"lzr_laser_detector_on.png",
|
|
"lzr_laser_detector_on.png",
|
|
"lzr_laser_detector_on.png",
|
|
"lzr_laser_detector_on_front.png",
|
|
},
|
|
light_source_on = 5,
|
|
groups = { laser_block = 1 },
|
|
sounds = lzr_sounds.node_sound_wood_defaults(),
|
|
}, { allow_take = true, is_detector = true })
|
|
|