diff --git a/CREDITS.md b/CREDITS.md
index f84259ea..ceb74105 100644
--- a/CREDITS.md
+++ b/CREDITS.md
@@ -153,6 +153,10 @@ All levels by Wuzzy.
- by MAJ061785
- A shortened version of the original sound is used for this game
- License: CC BY 3.0
+- `lzr_treasure_chest_lock_regen.ogg`:
+ - Heavily distorted derivative work of `lzr_treasure_chest_lock_break.ogg`
+ - By Wuzzy and MAJ061785
+ - License: CC BY 3.0
- `lzr_laser_detector_activate.ogg`
- derivative work from sound by Artninja
- License: CC BY 4.0
diff --git a/mods/lzr_treasure/init.lua b/mods/lzr_treasure/init.lua
index 3343abc7..051ae96f 100644
--- a/mods/lzr_treasure/init.lua
+++ b/mods/lzr_treasure/init.lua
@@ -18,15 +18,102 @@ local register_chest = function(id, def)
local sound_open = def.sound_open or "lzr_treasure_chest_open"
local sound_open_fail = def.sound_open_fail or "lzr_treasure_chest_open_fail"
local sound_lock_break = def.sound_lock_break or "lzr_treasure_chest_lock_break"
+ local sound_lock_regen = def.sound_lock_regen or "lzr_treasure_chest_lock_regen"
+
+ local lock_chest = function(pos, node, check_gamestate)
+ local add_lock = true
+ if check_gamestate and lzr_gamestate.get_state() ~= lzr_gamestate.LEVEL and not def.regen_lock then
+ add_lock = false
+ end
+ if add_lock then
+ minetest.swap_node(pos, {name="lzr_treasure:chest_"..id.."_locked", param2=node.param2})
+
+ minetest.after(0.1, function()
+
+ minetest.sound_play({name=sound_lock_regen, gain=0.8}, {pos=pos}, true)
+
+ local dir = minetest.facedir_to_dir(node.param2)
+ local w = 3/16
+ local k = 9/16
+ local l = 8/16
+ local minoff, maxoff
+ if dir.x > 0 then
+ minoff = vector.new(-k, -w, -w)
+ maxoff = vector.new(-l, w, w)
+ elseif dir.x < 0 then
+ minoff = vector.new(l, -w, -w)
+ maxoff = vector.new(k, w, w)
+ elseif dir.z > 0 then
+ minoff = vector.new(-w, -w, -k)
+ maxoff = vector.new(w, w, -l)
+ elseif dir.z < 0 then
+ minoff = vector.new(-w, -w, l)
+ maxoff = vector.new(w, w, k)
+ end
+ local avgoff = vector.new()
+ avgoff.x = (minoff.x + maxoff.x) / 2
+ avgoff.y = (minoff.y + maxoff.y) / 2
+ avgoff.z = (minoff.z + maxoff.z) / 2
+ if minoff then
+ minetest.add_particlespawner({
+ amount = 42,
+ time = 0.001,
+ minpos = vector.add(pos, minoff),
+ maxpos = vector.add(pos, maxoff),
+ minsize = 0.5,
+ maxsize = 0.5,
+ minexptime = 1.60,
+ maxexptime = 1.65,
+ radius = {
+ min = 0.4,
+ max = 0.5,
+ bias = 0.5,
+ },
+ attract = {
+ kind = "point",
+ strength = 4,
+ origin = vector.add(pos, avgoff),
+ },
+ texture = "lzr_treasure_particle_lock.png",
+ })
+ else
+ minetest.log("error", "[lzr_treasure] Could not find correct position to spawn treasure chest lock particles")
+ end
+ end)
+ end
+ end
+
+ local on_toggle_unlocked
+ local g_unlocked_receiver
+ local g_unlocked_element
+ local g_locked_element
+ local g_unlocked_nici
+ local tt_help_unlocked = S("Contains a gold block")
+ local tt_help_locked = S("Contains a gold block")
+ local element_group = "chest_element"
+ if def.regen_lock then
+ on_toggle_unlocked = function(pos, node)
+ lock_chest(pos, node, true)
+ end
+ g_unlocked_receiver = 1
+ g_unlocked_element = 2
+ g_locked_element = 1
+ -- Hide unlocked chest from creative inventory when the lock
+ -- is able to regenerate to enforce some consistency in the editor.
+ g_unlocked_nici = 1
+ tt_help_unlocked = tt_help_unlocked .. "\n"..S("Gets locked when triggered off")
+ tt_help_locked = tt_help_locked .. "\n"..S("Lock breaks when triggered on, but it re-appears when triggered off")
+ else
+ tt_help_locked = tt_help_locked .. "\n"..S("Lock breaks when triggered on")
+ end
minetest.register_node("lzr_treasure:chest_"..id.."_unlocked", {
description = def.description_unlocked,
- _tt_help = S("Contains a gold block"),
+ _tt_help = tt_help_unlocked,
paramtype2 = "facedir",
tiles = { def.tile_top, def.tile_bottom, def.tile_side, def.tile_side, def.tile_side, def.tile_front },
- groups = { breakable = 1, chest = 1, chest_closed = 1, rotatable = 3 },
+ groups = { breakable = 1, chest = 1, chest_closed = 1, rotatable = 3, receiver = g_unlocked_receiver, chest_element = g_unlocked_element, not_in_creative_inventory = g_unlocked_nici },
sounds = def.node_sounds,
- on_rotate = screwdriver.rotate_simple,
on_punch = function(pos, node, puncher)
if lzr_gamestate.get_state() ~= lzr_gamestate.LEVEL then
return
@@ -49,15 +136,20 @@ local register_chest = function(id, def)
victory_job = nil
end)
end,
+ after_place_node = lzr_laser.trigger_after_place_node,
+ after_dig_node = lzr_laser.trigger_after_dig_node,
+ on_rotate = screwdriver.rotate_simple,
+ _lzr_on_toggle = on_toggle_unlocked,
+ _lzr_element_group = element_group,
})
local unlock_chest = function(pos, node, check_gamestate)
local break_lock = true
- if check_gamestate and lzr_gamestate.get_state() ~= lzr_gamestate.LEVEL then
+ if check_gamestate and lzr_gamestate.get_state() ~= lzr_gamestate.LEVEL and not def.regen_lock then
break_lock = false
end
if break_lock then
- minetest.set_node(pos, {name="lzr_treasure:chest_"..id.."_unlocked", param2=node.param2})
+ minetest.swap_node(pos, {name="lzr_treasure:chest_"..id.."_unlocked", param2=node.param2})
end
minetest.after(0.1, function()
@@ -106,13 +198,11 @@ local register_chest = function(id, def)
minetest.register_node("lzr_treasure:chest_"..id.."_locked", {
description = def.description_locked,
- _tt_help = S("Contains a gold block").."\n"..
- S("Lock breaks when all detectors in the level are active"),
+ _tt_help = tt_help_locked,
paramtype2 = "facedir",
tiles = { def.tile_top, def.tile_bottom, def.tile_side, def.tile_side, def.tile_side, def.tile_front_lock },
- groups = { breakable = 1, chest = 2, chest_closed = 1, rotatable = 3, receiver = 1 },
+ groups = { breakable = 1, chest = 2, chest_closed = 1, rotatable = 3, receiver = 1, chest_element = g_locked_element },
sounds = def.node_sounds,
- on_rotate = screwdriver.rotate_simple,
on_punch = function(pos, node, puncher)
if lzr_gamestate.get_state() ~= lzr_gamestate.LEVEL then
return
@@ -121,6 +211,7 @@ local register_chest = function(id, def)
end,
after_place_node = lzr_laser.trigger_after_place_node,
after_dig_node = lzr_laser.trigger_after_dig_node,
+ on_rotate = screwdriver.rotate_simple,
-- Unlock chest, always
_lzr_unlock = function(pos, node)
unlock_chest(pos, node)
@@ -129,6 +220,7 @@ local register_chest = function(id, def)
_lzr_on_toggle = function(pos, node)
unlock_chest(pos, node, true)
end,
+ _lzr_element_group = element_group,
})
-- Open empty chest (is laser-compatible)
@@ -259,6 +351,8 @@ register_chest("dark", {
tile_front = "lzr_treasure_dark_chest_front.png",
tile_front_lock = "lzr_treasure_dark_chest_lock.png",
node_sounds = lzr_sounds.node_sound_stone_defaults(),
+ -- The dark chest can regenerate its lock when toggled off
+ regen_lock = true,
})
minetest.register_alias("lzr_treasure:chest_wood_open", "lzr_treasure:chest_wood_open_fixed")
diff --git a/mods/lzr_treasure/sounds/lzr_treasure_chest_lock_regen.ogg b/mods/lzr_treasure/sounds/lzr_treasure_chest_lock_regen.ogg
new file mode 100644
index 00000000..d66f05c7
Binary files /dev/null and b/mods/lzr_treasure/sounds/lzr_treasure_chest_lock_regen.ogg differ