local S = minetest.get_translator("lzr_level_select") local F = minetest.formspec_escape lzr_level_select = {} local current_level_selection = nil local current_custom_level_selection = nil local custom_levels local no_levels_form = function(player, message) return "formspec_version[4]size[8,3.5]".. "textarea[0.5,0.5;7,1.8;;;"..F(message).."]".. "button_exit[3,2.5;2,0.6;okay;"..F(S("OK")).."]" end lzr_level_select.open_dialog = function(player, level_set) local caption if level_set == "core" then caption = S("Select level:") elseif level_set == "custom" then caption = S("Select custom level:") else minetest.log("error", "[lzr_level_select] open_dialog called with unknown level_set!") return false end local form = "formspec_version[4]size[6,10]".. "label[0.5,0.4;"..F(caption).."]".. "button_exit[1.5,8.5;3,1;okay;"..F(S("Start")).."]".. "tablecolumns[color;text]".. "table[0.5,0.8;5,7.5;levellist;" local list = {} local entry_header = "" local first_uncompleted_level = nil if level_set == "core" then -- Built-in level set local completed_levels = lzr_levels.get_completed_levels() for l=1, lzr_levels.LAST_LEVEL do if completed_levels[l] then entry_header = "#00FF00" else if not first_uncompleted_level then first_uncompleted_level = l end entry_header = "" end table.insert(list, entry_header..","..F(lzr_levels.get_level_name(l, nil, true))) end if not first_uncompleted_level then first_uncompleted_level = 1 end current_level_selection = first_uncompleted_level else -- Custom level set (editor levels) local list_levels = lzr_editor.get_custom_levels() custom_levels = {} for l=1, #list_levels do local levelname = list_levels[l] -- Hide the autosave level because it's not meant -- for playing if levelname ~= lzr_globals.AUTOSAVE_NAME then table.insert(custom_levels, levelname) local proper_name = lzr_editor.get_custom_level_name(levelname, true) table.insert(list, entry_header..","..F(proper_name)) end end first_uncompleted_level = 1 current_custom_level_selection = 1 end if not first_uncompleted_level then first_uncompleted_level = 1 end local list_str = table.concat(list, ",") form = form .. list_str .. ";"..first_uncompleted_level.."]" local formname if level_set == "core" then if #list == 0 then form = no_levels_form(player, S("There are no levels.")) end formname = "lzr_level_select:levellist" else if #list == 0 then form = no_levels_form(player, S("There are no custom levels.").."\n".. S("Install levels from your friends or use the level editor to build your own.")) end formname = "lzr_level_select:levellist_custom" end minetest.show_formspec(player:get_player_name(), formname, form) end local load_custom_level = function(level, player) minetest.log("action", "[lzr_level_select] Player selects custom level: "..level) local csv = minetest.get_worldpath().."/levels/"..level..".csv" local levels_path = minetest.get_worldpath().."/levels" local custom_level_data = lzr_levels.analyze_levels(csv, levels_path) if custom_level_data then -- Load level with metadata (preferred) lzr_levels.start_level(1, custom_level_data) else -- Fallback when CSV file could not be read custom_level_data = lzr_levels.create_fallback_level_data(level, levels_path) lzr_levels.start_level(1, custom_level_data) minetest.log("action", "[lzr_level_select] No CSV file found for custom level: "..tostring(level)..". Using fallback") end end minetest.register_on_player_receive_fields(function(player, formname, fields) if formname == "lzr_level_select:levellist" then if fields.okay then if current_level_selection then lzr_levels.start_level(current_level_selection) end elseif fields.levellist then local expl = minetest.explode_table_event(fields.levellist) if expl.type == "CHG" then current_level_selection = expl.row elseif expl.type == "DCL" then current_level_selection = expl.row lzr_levels.start_level(current_level_selection) minetest.close_formspec(player:get_player_name(), "lzr_level_select:levellist") elseif expl.type == "INV" then current_level_selection = nil end end elseif formname == "lzr_level_select:levellist_custom" then if fields.okay then if custom_levels and current_custom_level_selection then local level = custom_levels[current_custom_level_selection] if level then load_custom_level(level, player) end end elseif fields.levellist then local expl = minetest.explode_table_event(fields.levellist) if expl.type == "CHG" then current_custom_level_selection = expl.row elseif expl.type == "DCL" then current_custom_level_selection = expl.row if custom_levels then local level = custom_levels[current_custom_level_selection] if level then load_custom_level(level, player) end end minetest.close_formspec(player:get_player_name(), "lzr_level_select:levellist_custom") elseif expl.type == "INV" then current_custom_level_selection = nil end end end end) minetest.register_chatcommand("level", { privs = { server = true }, description = S("Go to level"), params = S(""), func = function(name, param) local level = tonumber(param) if not level then return false end if level < 1 or level > lzr_levels.LAST_LEVEL then return false, S("Invalid level!") end lzr_levels.start_level(level) return true end, })