]> git.lizzy.rs Git - minetest.git/blobdiff - builtin/mainmenu/dlg_create_world.lua
Add unit tests for pkgmgr.install_dir
[minetest.git] / builtin / mainmenu / dlg_create_world.lua
index 0d977a17ca24896739a1699bf38c33fa07da21d9..806e019a96e2f7929017ebdbbfa47ffcc0438491 100644 (file)
@@ -15,8 +15,6 @@
 --with this program; if not, write to the Free Software Foundation, Inc.,
 --51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 
-local worldname = ""
-
 local function table_to_flags(ftable)
        -- Convert e.g. { jungles = true, caves = false } to "jungles,nocaves"
        local str = {}
@@ -31,9 +29,8 @@ local function strflag(flags, flag)
        return (flags[flag] == true) and "true" or "false"
 end
 
-local cb_caverns = { "caverns", fgettext("Caverns"), "caverns",
+local cb_caverns = { "caverns", fgettext("Caverns"),
        fgettext("Very large caverns deep in the underground") }
-local tt_sea_rivers = fgettext("Sea level rivers")
 
 local flag_checkboxes = {
        v5 = {
@@ -41,38 +38,38 @@ local flag_checkboxes = {
        },
        v7 = {
                cb_caverns,
-               { "ridges", fgettext("Rivers"), "ridges", tt_sea_rivers },
-               { "mountains", fgettext("Mountains"), "mountains" },
-               { "floatlands", fgettext("Floatlands (experimental)"), "floatlands",
+               { "ridges", fgettext("Rivers"), fgettext("Sea level rivers") },
+               { "mountains", fgettext("Mountains") },
+               { "floatlands", fgettext("Floatlands (experimental)"),
                fgettext("Floating landmasses in the sky") },
        },
        carpathian = {
                cb_caverns,
-               { "rivers", fgettext("Rivers"), "rivers", tt_sea_rivers },
+               { "rivers", fgettext("Rivers"), fgettext("Sea level rivers") },
        },
        valleys = {
-               { "altitude-chill", fgettext("Altitude chill"), "altitude_chill",
+               { "altitude_chill", fgettext("Altitude chill"),
                fgettext("Reduces heat with altitude") },
-               { "altitude-dry", fgettext("Altitude dry"), "altitude_dry",
+               { "altitude_dry", fgettext("Altitude dry"),
                fgettext("Reduces humidity with altitude") },
-               { "humid-rivers", fgettext("Humid rivers"), "humid_rivers",
+               { "humid_rivers", fgettext("Humid rivers"),
                fgettext("Increases humidity around rivers") },
-               { "vary-river-depth", fgettext("Vary river depth"), "vary_river_depth",
+               { "vary_river_depth", fgettext("Vary river depth"),
                fgettext("Low humidity and high heat causes shallow or dry rivers") },
        },
        flat = {
-               { "hills", fgettext("Hills"), "hills" },
-               { "lakes", fgettext("Lakes"), "lakes" },
+               cb_caverns,
+               { "hills", fgettext("Hills") },
+               { "lakes", fgettext("Lakes") },
        },
        fractal = {
-               { "terrain", fgettext("Additional terrain"), "terrain",
+               { "terrain", fgettext("Additional terrain"),
                fgettext("Generate non-fractal terrain: Oceans and underground") },
        },
        v6 = {
-               { "trees", fgettext("Trees and jungle grass"), "trees" },
-               { "flat", fgettext("Flat terrain"), "flat" },
-               { "mudflow", fgettext("Mud flow"), "mudflow",
-               fgettext("Terrain surface erosion") },
+               { "trees", fgettext("Trees and jungle grass") },
+               { "flat", fgettext("Flat terrain") },
+               { "mudflow", fgettext("Mud flow"), fgettext("Terrain surface erosion") },
                -- Biome settings are in mgv6_biomes below
        },
 }
@@ -94,48 +91,33 @@ local mgv6_biomes = {
 
 local function create_world_formspec(dialogdata)
 
-       -- Error out when no games found
+       -- Point the player to ContentDB when no games are found
        if #pkgmgr.games == 0 then
-               return "size[12.25,3,true]" ..
-                       "box[0,0;12,2;#ff8800]" ..
-                       "textarea[0.3,0;11.7,2;;;"..
-                       fgettext("You have no games installed.") .. "\n" ..
-                       fgettext("Download one from minetest.net") .. "]" ..
-                       "button[4.75,2.5;3,0.5;world_create_cancel;" .. fgettext("Cancel") .. "]"
+               return "size[8,2.5,true]" ..
+                       "style[label_button;border=false]" ..
+                       "button[0.5,0.5;7,0.5;label_button;" ..
+                       fgettext("You have no games installed.") .. "]" ..
+                       "button[0.5,1.5;2.5,0.5;world_create_open_cdb;" .. fgettext("Install a game") .. "]" ..
+                       "button[5.0,1.5;2.5,0.5;world_create_cancel;" .. fgettext("Cancel") .. "]"
        end
 
+       local current_mg = dialogdata.mg
        local mapgens = core.get_mapgen_names()
 
-       local current_seed = core.settings:get("fixed_map_seed") or ""
-       local current_mg   = core.settings:get("mg_name")
        local gameid = core.settings:get("menu_last_game")
 
-       local flags = {
-               main = core.settings:get_flags("mg_flags"),
-               v5 = core.settings:get_flags("mgv5_spflags"),
-               v6 = core.settings:get_flags("mgv6_spflags"),
-               v7 = core.settings:get_flags("mgv7_spflags"),
-               fractal = core.settings:get_flags("mgfractal_spflags"),
-               carpathian = core.settings:get_flags("mgcarpathian_spflags"),
-               valleys = core.settings:get_flags("mgvalleys_spflags"),
-               flat = core.settings:get_flags("mgflat_spflags"),
-       }
+       local flags = dialogdata.flags
 
-       local gameidx = 0
-       if gameid ~= nil then
-               local _
-               _, gameidx = pkgmgr.find_by_gameid(gameid)
-
-               if gameidx == nil then
-                       gameidx = 0
-               end
+       local game = pkgmgr.find_by_gameid(gameid)
+       if game == nil then
+               -- should never happen but just pick the first game
+               game = pkgmgr.get_game(1)
+               core.settings:set("menu_last_game", game.id)
        end
 
-       local game_by_gameidx = core.get_game(gameidx)
        local disallowed_mapgen_settings = {}
-       if game_by_gameidx ~= nil then
-               local gamepath = game_by_gameidx.path
-               local gameconfig = Settings(gamepath.."/game.conf")
+       if game ~= nil then
+               local gameconfig = Settings(game.path.."/game.conf")
 
                local allowed_mapgens = (gameconfig:get("allowed_mapgens") or ""):split()
                for key, value in pairs(allowed_mapgens) do
@@ -155,7 +137,7 @@ local function create_world_formspec(dialogdata)
                        end
                end
 
-               if disallowed_mapgens then
+               if #disallowed_mapgens > 0 then
                        for i = #mapgens, 1, -1 do
                                if table.indexof(disallowed_mapgens, mapgens[i]) > 0 then
                                        table.remove(mapgens, i)
@@ -171,23 +153,29 @@ local function create_world_formspec(dialogdata)
 
        local mglist = ""
        local selindex
-       local i = 1
-       local first_mg
-       for k,v in pairs(mapgens) do
-               if not first_mg then
-                       first_mg = v
+       do -- build the list of mapgens
+               local i = 1
+               local first_mg
+               for k, v in pairs(mapgens) do
+                       if not first_mg then
+                               first_mg = v
+                       end
+                       if current_mg == v then
+                               selindex = i
+                       end
+                       i = i + 1
+                       mglist = mglist .. core.formspec_escape(v) .. ","
                end
-               if current_mg == v then
-                       selindex = i
+               if not selindex then
+                       selindex = 1
+                       current_mg = first_mg
                end
-               i = i + 1
-               mglist = mglist .. v .. ","
+               mglist = mglist:sub(1, -2)
        end
-       if not selindex then
-               selindex = 1
-               current_mg = first_mg
-       end
-       mglist = mglist:sub(1, -2)
+
+       -- The logic of the flag element IDs is as follows:
+       -- "flag_main_foo-bar-baz" controls dialogdata.flags["main"]["foo_bar_baz"]
+       -- see the buttonhandler for the implementation of this
 
        local mg_main_flags = function(mapgen, y)
                if mapgen == "singlenode" then
@@ -197,11 +185,11 @@ local function create_world_formspec(dialogdata)
                        return "", y
                end
 
-               local form = "checkbox[0," .. y .. ";flag_mg_caves;" ..
+               local form = "checkbox[0," .. y .. ";flag_main_caves;" ..
                        fgettext("Caves") .. ";"..strflag(flags.main, "caves").."]"
                y = y + 0.5
 
-               form = form .. "checkbox[0,"..y..";flag_mg_dungeons;" ..
+               form = form .. "checkbox[0,"..y..";flag_main_dungeons;" ..
                        fgettext("Dungeons") .. ";"..strflag(flags.main, "dungeons").."]"
                y = y + 0.5
 
@@ -212,7 +200,7 @@ local function create_world_formspec(dialogdata)
                else
                        d_tt = fgettext("Structures appearing on the terrain, typically trees and plants")
                end
-               form = form .. "checkbox[0,"..y..";flag_mg_decorations;" ..
+               form = form .. "checkbox[0,"..y..";flag_main_decorations;" ..
                        d_name .. ";" ..
                        strflag(flags.main, "decorations").."]" ..
                        "tooltip[flag_mg_decorations;" ..
@@ -220,7 +208,7 @@ local function create_world_formspec(dialogdata)
                        "]"
                y = y + 0.5
 
-               form = form .. "tooltip[flag_mg_caves;" ..
+               form = form .. "tooltip[flag_main_caves;" ..
                fgettext("Network of tunnels and caves")
                .. "]"
                return form, y
@@ -234,13 +222,13 @@ local function create_world_formspec(dialogdata)
                        return "", y
                end
                local form = ""
-               for _,tab in pairs(flag_checkboxes[mapgen]) do
-                       local id = "flag_mg"..mapgen.."_"..tab[1]
+               for _, tab in pairs(flag_checkboxes[mapgen]) do
+                       local id = "flag_"..mapgen.."_"..tab[1]:gsub("_", "-")
                        form = form .. ("checkbox[0,%f;%s;%s;%s]"):
-                               format(y, id, tab[2], strflag(flags[mapgen], tab[3]))
+                               format(y, id, tab[2], strflag(flags[mapgen], tab[1]))
 
-                       if tab[4] then
-                               form = form .. "tooltip["..id..";"..tab[4].."]"
+                       if tab[3] then
+                               form = form .. "tooltip["..id..";"..tab[3].."]"
                        end
                        y = y + 0.5
                end
@@ -276,16 +264,14 @@ local function create_world_formspec(dialogdata)
 
                -- biomeblend
                y = y + 0.55
-               form = form .. "checkbox[0,"..y..";flag_mgv6_biomeblend;" ..
+               form = form .. "checkbox[0,"..y..";flag_v6_biomeblend;" ..
                        fgettext("Biome blending") .. ";"..strflag(flags.v6, "biomeblend").."]" ..
-                       "tooltip[flag_mgv6_biomeblend;" ..
+                       "tooltip[flag_v6_biomeblend;" ..
                        fgettext("Smooth transition between biomes") .. "]"
 
                return form, y
        end
 
-       current_seed = core.formspec_escape(current_seed)
-
        local y_start = 0.0
        local y = y_start
        local str_flags, str_spflags
@@ -304,17 +290,6 @@ local function create_world_formspec(dialogdata)
                label_spflags = "label[0,"..y_start..";" .. fgettext("Mapgen-specific flags") .. "]"
        end
 
-       -- Warning if only minimal is installed
-       local minimal_only = ""
-       local gamelist_height = 2.3
-       if #pkgmgr.games == 1 and pkgmgr.games[1].id == "minimal" then
-               minimal_only = "box[0,0;5.8,1.7;#ff8800]" ..
-                               "textarea[0.3,0;6,1.8;;;"..
-                               fgettext("Warning: The minimal development test is meant for developers.") .. "\n" ..
-                               fgettext("Download a game, such as Minetest Game, from minetest.net") .. "]"
-               gamelist_height = 0.5
-       end
-
        local retval =
                "size[12.25,7,true]" ..
 
@@ -322,21 +297,33 @@ local function create_world_formspec(dialogdata)
                "container[0,0]"..
                "field[0.3,0.6;6,0.5;te_world_name;" ..
                fgettext("World name") ..
-               ";" .. core.formspec_escape(worldname) .. "]" ..
+               ";" .. core.formspec_escape(dialogdata.worldname) .. "]" ..
+               "set_focus[te_world_name;false]"
 
-               "field[0.3,1.7;6,0.5;te_seed;" ..
-               fgettext("Seed") ..
-               ";".. current_seed .. "]" ..
+       if not disallowed_mapgen_settings["seed"] then
 
+               retval = retval .. "field[0.3,1.7;6,0.5;te_seed;" ..
+                               fgettext("Seed") ..
+                               ";".. core.formspec_escape(dialogdata.seed) .. "]"
+
+       end
+
+       retval = retval ..
                "label[0,2;" .. fgettext("Mapgen") .. "]"..
-               "dropdown[0,2.5;6.3;dd_mapgen;" .. mglist .. ";" .. selindex .. "]" ..
+               "dropdown[0,2.5;6.3;dd_mapgen;" .. mglist .. ";" .. selindex .. "]"
+
+       -- Warning if only devtest is installed
+       if #pkgmgr.games == 1 and pkgmgr.games[1].id == "devtest" then
+               retval = retval ..
+                       "container[0,3.5]" ..
+                       "box[0,0;5.8,1.7;#ff8800]" ..
+                       "textarea[0.4,0.1;6,1.8;;;"..
+                       fgettext("Development Test is meant for developers.") .. "]" ..
+                       "button[1,1;4,0.5;world_create_open_cdb;" .. fgettext("Install another game") .. "]" ..
+                       "container_end[]"
+       end
 
-               "label[0,3.35;" .. fgettext("Game") .. "]"..
-               "textlist[0,3.85;5.8,"..gamelist_height..";games;" ..
-               pkgmgr.gamelist() .. ";" .. gameidx .. ";false]" ..
-               "container[0,4.5]" ..
-               minimal_only ..
-               "container_end[]" ..
+       retval = retval ..
                "container_end[]" ..
 
                -- Right side
@@ -355,49 +342,81 @@ end
 
 local function create_world_buttonhandler(this, fields)
 
+       if fields["world_create_open_cdb"] then
+               local dlg = create_store_dlg("game")
+               dlg:set_parent(this.parent)
+               this:delete()
+               this.parent:hide()
+               dlg:show()
+               return true
+       end
+
        if fields["world_create_confirm"] or
                fields["key_enter"] then
 
                local worldname = fields["te_world_name"]
-               local gameindex = core.get_textlist_index("games")
+               local game, gameindex = pkgmgr.find_by_gameid(core.settings:get("menu_last_game"))
 
-               if gameindex ~= nil then
+               local message
+               if game == nil then
+                       message = fgettext("No game selected")
+               end
+
+               if message == nil then
+                       -- For unnamed worlds use the generated name 'world<number>',
+                       -- where the number increments: it is set to 1 larger than the largest
+                       -- generated name number found.
                        if worldname == "" then
-                               local random_number = math.random(10000, 99999)
-                               local random_world_name = "Unnamed" .. random_number
-                               worldname = random_world_name
+                               local worldnum_max = 0
+                               for _, world in ipairs(menudata.worldlist:get_list()) do
+                                       if world.name:match("^world%d+$") then
+                                               local worldnum = tonumber(world.name:sub(6))
+                                               worldnum_max = math.max(worldnum_max, worldnum)
+                                       end
+                               end
+                               worldname = "world" .. worldnum_max + 1
                        end
 
-                       core.settings:set("fixed_map_seed", fields["te_seed"])
-
-                       local message
-                       if not menudata.worldlist:uid_exists_raw(worldname) then
-                               core.settings:set("mg_name",fields["dd_mapgen"])
-                               message = core.create_world(worldname,gameindex)
-                       else
+                       if menudata.worldlist:uid_exists_raw(worldname) then
                                message = fgettext("A world named \"$1\" already exists", worldname)
                        end
+               end
 
-                       if message ~= nil then
-                               gamedata.errormessage = message
-                       else
-                               core.settings:set("menu_last_game",pkgmgr.games[gameindex].id)
-                               if this.data.update_worldlist_filter then
-                                       menudata.worldlist:set_filtercriteria(pkgmgr.games[gameindex].id)
-                                       mm_texture.update("singleplayer", pkgmgr.games[gameindex].id)
-                               end
-                               menudata.worldlist:refresh()
-                               core.settings:set("mainmenu_last_selected_world",
-                                                                       menudata.worldlist:raw_index_by_uid(worldname))
-                       end
-               else
-                       gamedata.errormessage = fgettext("No game selected")
+               if message == nil then
+                       this.data.seed = fields["te_seed"] or ""
+                       this.data.mg = fields["dd_mapgen"]
+
+                       -- actual names as used by engine
+                       local settings = {
+                               fixed_map_seed = this.data.seed,
+                               mg_name = this.data.mg,
+                               mg_flags = table_to_flags(this.data.flags.main),
+                               mgv5_spflags = table_to_flags(this.data.flags.v5),
+                               mgv6_spflags = table_to_flags(this.data.flags.v6),
+                               mgv7_spflags = table_to_flags(this.data.flags.v7),
+                               mgfractal_spflags = table_to_flags(this.data.flags.fractal),
+                               mgcarpathian_spflags = table_to_flags(this.data.flags.carpathian),
+                               mgvalleys_spflags = table_to_flags(this.data.flags.valleys),
+                               mgflat_spflags = table_to_flags(this.data.flags.flat),
+                       }
+                       message = core.create_world(worldname, gameindex, settings)
+               end
+
+               if message == nil then
+                       core.settings:set("menu_last_game", game.id)
+                       menudata.worldlist:set_filtercriteria(game.id)
+                       menudata.worldlist:refresh()
+                       core.settings:set("mainmenu_last_selected_world",
+                                       menudata.worldlist:raw_index_by_uid(worldname))
                end
+
+               gamedata.errormessage = message
                this:delete()
                return true
        end
 
-       worldname = fields.te_world_name
+       this.data.worldname = fields["te_world_name"]
+       this.data.seed = fields["te_seed"] or ""
 
        if fields["games"] then
                local gameindex = core.get_textlist_index("games")
@@ -408,22 +427,11 @@ local function create_world_buttonhandler(this, fields)
        for k,v in pairs(fields) do
                local split = string.split(k, "_", nil, 3)
                if split and split[1] == "flag" then
-                       local setting
-                       if split[2] == "mg" then
-                               setting = "mg_flags"
-                       else
-                               setting = split[2].."_spflags"
-                       end
                        -- We replaced the underscore of flag names with a dash.
                        local flag = string.gsub(split[3], "-", "_")
-                       local ftable = core.settings:get_flags(setting)
-                       if v == "true" then
-                               ftable[flag] = true
-                       else
-                               ftable[flag] = false
-                       end
-                       local flags = table_to_flags(ftable)
-                       core.settings:set(setting, flags)
+                       local ftable = this.data.flags[split[2]]
+                       assert(ftable)
+                       ftable[flag] = v == "true"
                        return true
                end
        end
@@ -434,21 +442,19 @@ local function create_world_buttonhandler(this, fields)
        end
 
        if fields["mgv6_biomes"] then
-               local entry = minetest.formspec_escape(fields["mgv6_biomes"])
+               local entry = core.formspec_escape(fields["mgv6_biomes"])
                for b=1, #mgv6_biomes do
                        if entry == mgv6_biomes[b][1] then
-                               local ftable = core.settings:get_flags("mgv6_spflags")
+                               local ftable = this.data.flags.v6
                                ftable.jungles = mgv6_biomes[b][2].jungles
                                ftable.snowbiomes = mgv6_biomes[b][2].snowbiomes
-                               local flags = table_to_flags(ftable)
-                               core.settings:set("mgv6_spflags", flags)
                                return true
                        end
                end
        end
 
        if fields["dd_mapgen"] then
-               core.settings:set("mg_name", fields["dd_mapgen"])
+               this.data.mg = fields["dd_mapgen"]
                return true
        end
 
@@ -456,13 +462,27 @@ local function create_world_buttonhandler(this, fields)
 end
 
 
-function create_create_world_dlg(update_worldlistfilter)
-       worldname = ""
+function create_create_world_dlg()
        local retval = dialog_create("sp_create_world",
                                        create_world_formspec,
                                        create_world_buttonhandler,
                                        nil)
-       retval.update_worldlist_filter = update_worldlistfilter
+       retval.data = {
+               worldname = "",
+               -- settings the world is created with:
+               seed = core.settings:get("fixed_map_seed") or "",
+               mg = core.settings:get("mg_name"),
+               flags = {
+                       main = core.settings:get_flags("mg_flags"),
+                       v5 = core.settings:get_flags("mgv5_spflags"),
+                       v6 = core.settings:get_flags("mgv6_spflags"),
+                       v7 = core.settings:get_flags("mgv7_spflags"),
+                       fractal = core.settings:get_flags("mgfractal_spflags"),
+                       carpathian = core.settings:get_flags("mgcarpathian_spflags"),
+                       valleys = core.settings:get_flags("mgvalleys_spflags"),
+                       flat = core.settings:get_flags("mgflat_spflags"),
+               }
+       }
 
        return retval
 end