lazarr/mods/lzr_levels/init.lua

237 lines
7.2 KiB
Lua
Raw Normal View History

2021-12-21 15:35:16 -08:00
local S = minetest.get_translator("lzr_levels")
2021-12-21 10:56:56 -08:00
lzr_levels = {}
local ROOM_NODE = "lzr_core:wood"
2022-01-08 18:04:13 -08:00
local WINDOW_NODE = "lzr_decor:woodframed_glass"
2021-12-21 10:56:56 -08:00
local WINDOW_HEIGHT = 3
local WINDOW_DIST = 3
2021-12-23 13:43:26 -08:00
local LAST_LEVEL = 10
2021-12-21 10:56:56 -08:00
2021-12-28 14:43:01 -08:00
local current_level = nil
local level_data = {}
-- Read the level schematics to find out some metadata about them
local analyze_levels = function()
-- Mark levels that contain at least 1 rotatable block
for l=1, LAST_LEVEL do
2022-01-10 12:11:59 -08:00
local schem = minetest.read_schematic(minetest.get_modpath("lzr_levels").."/schematics/lzr_levels_level_"..l..".mts", {write_yslice_prob="none"})
level_data[l] = {
2022-01-10 12:11:59 -08:00
contains_rotatable_block = false,
size = schem.size,
}
for d=1, #schem.data do
local nodename = schem.data[d].name
local is_rotatable = minetest.get_item_group(nodename, "rotatable") == 1
if is_rotatable then
level_data[l].contains_rotatable_block = true
break
end
end
end
end
2021-12-21 10:56:56 -08:00
local build_room = function(param)
local pos = param.pos
local psize = param.size
local posses_border = {}
local posses_window = {}
local posses_air = {}
local size = vector.add(psize, {x=1,y=1,z=1})
for x=0,size.x do
for z=0,size.z do
for y=0,size.y do
local offset = {x=x-1, y=y-1, z=z-1}
if (x >= 1 and x < size.x) and
(y >= 1 and y < size.y) and
(z >= 1 and z < size.z) then
table.insert(posses_air, vector.add(pos, offset))
elseif y == WINDOW_HEIGHT and ((x >= 1 and x < size.x and x % WINDOW_DIST == 0) or (z >= 1 and z < size.z and z % WINDOW_DIST == 0)) then
table.insert(posses_window, vector.add(pos, offset))
else
table.insert(posses_border, vector.add(pos, offset))
end
end
end
end
minetest.bulk_set_node(posses_border, {name=ROOM_NODE})
minetest.bulk_set_node(posses_window, {name=WINDOW_NODE})
minetest.bulk_set_node(posses_air, {name="air"})
end
local emerge_callback = function(blockpos, action, calls_remaining, param)
minetest.log("verbose", "[lzr_levels] emerge_callback() ...")
if action == minetest.EMERGE_ERRORED then
minetest.log("error", "[lzr_levels] Room emerging error.")
elseif action == minetest.EMERGE_CANCELLED then
minetest.log("error", "[lzr_levels] Room emerging cancelled.")
elseif calls_remaining == 0 and (action == minetest.EMERGE_GENERATED or action == minetest.EMERGE_FROM_DISK or action == minetest.EMERGE_FROM_MEMORY) then
build_room(param)
2022-01-11 09:05:24 -08:00
local level_ok = lzr_levels.build_level(param.level)
if not level_ok then
minetest.log("error", "[lzr_levels] Room emerge callback done with error")
else
minetest.log("action", "[lzr_levels] Room emerge callback done")
end
2021-12-21 10:56:56 -08:00
end
end
2021-12-21 15:17:36 -08:00
local prepare_room = function(pos, size, level)
minetest.emerge_area(pos, vector.add(pos, size), emerge_callback, {pos=pos, size=size, level=level})
2021-12-21 10:56:56 -08:00
end
2021-12-21 15:17:36 -08:00
function lzr_levels.build_room(pos, size, level)
prepare_room(pos, size, level)
end
function lzr_levels.prepare_and_build_level(level)
lzr_levels.build_room(lzr_globals.LEVEL_POS, {x=10, y=6, z=10}, level)
end
function lzr_levels.build_level(level)
2022-01-11 09:05:24 -08:00
local schem = minetest.place_schematic(lzr_globals.LEVEL_POS, minetest.get_modpath("lzr_levels").."/schematics/lzr_levels_level_"..level..".mts", "0", {}, true, "")
if schem then
-- Propagate lasers and check for insta-win
2022-01-11 09:05:24 -08:00
lzr_laser.full_laser_update(lzr_globals.PLAYFIELD_START, lzr_globals.PLAYFIELD_END)
local done = lzr_laser.check_level_won()
if done then
lzr_levels.level_complete()
end
2022-01-11 09:05:24 -08:00
else
minetest.log("error", "[lzr_levels] lzr_levels.build_level failed to build level")
end
return schem
2021-12-21 10:56:56 -08:00
end
2021-12-21 15:35:16 -08:00
2021-12-25 18:37:04 -08:00
local function clear_inventory(player)
local inv = player:get_inventory()
for i=1,inv:get_size("main") do
inv:set_stack("main", i, "")
end
2021-12-25 18:37:04 -08:00
end
local function reset_inventory(player, needs_rotate)
2021-12-25 18:37:04 -08:00
clear_inventory(player)
if needs_rotate then
local inv = player:get_inventory()
inv:add_item("main", "screwdriver2:screwdriver")
end
2021-12-23 13:43:26 -08:00
end
local get_singleplayer = function()
return minetest.get_player_by_name("singleplayer")
end
function lzr_levels.start_level(level)
current_level = level
local player = get_singleplayer()
2022-01-09 08:05:34 -08:00
local start_pos = vector.add(lzr_globals.LEVEL_POS, {x=4,y=-0.5,z=4})
player:set_pos(start_pos)
player:set_look_horizontal(0)
2021-12-23 13:43:26 -08:00
lzr_levels.prepare_and_build_level(level)
local needs_rotate = level_data[current_level].contains_rotatable_block
reset_inventory(player, needs_rotate)
2021-12-23 14:06:10 -08:00
lzr_messages.show_message(player, S("Level @1", level), 3)
2022-01-12 18:24:29 -08:00
if lzr_gamestate.get_state() ~= lzr_gamestate.EDITOR then
lzr_gamestate.set_state(lzr_gamestate.LEVEL)
end
minetest.sound_play({name = "lzr_levels_level_enter", gain = 1}, {to_player=player:get_player_name()}, true)
end
function lzr_levels.level_complete()
if lzr_gamestate.get_state() == lzr_gamestate.LEVEL_COMPLETE then
return false
end
local player = get_singleplayer()
lzr_messages.show_message(player, S("Level @1 complete!", current_level), 3)
minetest.sound_play({name = "lzr_levels_level_complete", gain = 1}, {to_player=player:get_player_name()}, true)
lzr_gamestate.set_state(lzr_gamestate.LEVEL_COMPLETE)
minetest.after(3, function(completed_level)
if lzr_gamestate.get_state() == lzr_gamestate.LEVEL_COMPLETE and current_level == completed_level then
lzr_levels.next_level()
end
end, current_level)
2021-12-23 13:43:26 -08:00
end
2021-12-21 15:35:16 -08:00
function lzr_levels.next_level()
2021-12-23 13:43:26 -08:00
local player = get_singleplayer()
2021-12-21 15:35:16 -08:00
current_level = current_level + 1
if current_level > LAST_LEVEL then
2021-12-23 14:06:10 -08:00
lzr_messages.show_message(player, S("Final level completed!"), 5)
2021-12-21 15:35:16 -08:00
else
2021-12-23 13:43:26 -08:00
lzr_levels.start_level(current_level)
2021-12-21 15:35:16 -08:00
end
end
2021-12-23 13:43:26 -08:00
2021-12-25 18:37:04 -08:00
function lzr_levels.leave_level()
local player = get_singleplayer()
current_level = nil
clear_inventory(player)
player:set_pos(vector.add(lzr_globals.MENU_SHIP_POS, lzr_globals.MENU_SHIP_PLAYER_SPAWN_OFFSET))
player:set_look_horizontal(0)
2022-01-08 18:53:55 -08:00
lzr_gamestate.set_state(lzr_gamestate.MENU)
2021-12-25 18:37:04 -08:00
end
2021-12-23 13:43:26 -08:00
minetest.register_chatcommand("level", {
privs = { server = true },
description = S("Go to level"),
params = S("<level>"),
func = function(name, param)
local level = tonumber(param)
if not level then
return false
end
if level < 1 or level > LAST_LEVEL then
return false, S("Invalid level!")
end
lzr_levels.start_level(level)
return true
end,
})
minetest.register_chatcommand("restart", {
privs = {},
params = "",
description = S("Restart current level"),
func = function(name, param)
2022-01-08 18:53:55 -08:00
if lzr_gamestate.get_state() == lzr_gamestate.LEVEL then
2021-12-25 18:37:04 -08:00
lzr_levels.start_level(current_level)
return true
else
return false, S("Not playing in a level!")
end
end,
})
minetest.register_chatcommand("leave", {
privs = {},
params = "",
description = S("Leave current level"),
func = function(name, param)
if lzr_gamestate.get_state() == lzr_gamestate.LEVEL or lzr_gamestate.get_state() == lzr_gamestate.LEVEL_COMPLETE then
2021-12-25 18:37:04 -08:00
lzr_levels.leave_level(current_level)
return true
else
return false, S("Not playing in a level!")
end
2021-12-23 13:43:26 -08:00
end,
})
lzr_gamestate.register_on_enter_state(function(state)
if state == lzr_gamestate.LEVEL then
local player = minetest.get_player_by_name("singleplayer")
lzr_player.set_play_inventory(player)
lzr_gui.set_play_gui(player)
lzr_laser.full_laser_update(lzr_globals.PLAYFIELD_START, lzr_globals.PLAYFIELD_END)
local done = lzr_laser.check_level_won()
if done then
lzr_levels.level_complete()
end
end
end)
analyze_levels()