2 --Copyright (C) 2014 sapier
4 --This program is free software; you can redistribute it and/or modify
5 --it under the terms of the GNU Lesser General Public License as published by
6 --the Free Software Foundation; either version 2.1 of the License, or
7 --(at your option) any later version.
9 --This program is distributed in the hope that it will be useful,
10 --but WITHOUT ANY WARRANTY; without even the implied warranty of
11 --MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 --GNU Lesser General Public License for more details.
14 --You should have received a copy of the GNU Lesser General Public License along
15 --with this program; if not, write to the Free Software Foundation, Inc.,
16 --51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 -- cf. tab_local, the gamebar already provides game selection so we hide the list from here
19 local hide_gamelist = PLATFORM ~= "Android"
21 local function table_to_flags(ftable)
22 -- Convert e.g. { jungles = true, caves = false } to "jungles,nocaves"
24 for flag, is_set in pairs(ftable) do
25 str[#str + 1] = is_set and flag or ("no" .. flag)
27 return table.concat(str, ",")
30 -- Same as check_flag but returns a string
31 local function strflag(flags, flag)
32 return (flags[flag] == true) and "true" or "false"
35 local cb_caverns = { "caverns", fgettext("Caverns"),
36 fgettext("Very large caverns deep in the underground") }
38 local flag_checkboxes = {
44 { "ridges", fgettext("Rivers"), fgettext("Sea level rivers") },
45 { "mountains", fgettext("Mountains") },
46 { "floatlands", fgettext("Floatlands (experimental)"),
47 fgettext("Floating landmasses in the sky") },
51 { "rivers", fgettext("Rivers"), fgettext("Sea level rivers") },
54 { "altitude_chill", fgettext("Altitude chill"),
55 fgettext("Reduces heat with altitude") },
56 { "altitude_dry", fgettext("Altitude dry"),
57 fgettext("Reduces humidity with altitude") },
58 { "humid_rivers", fgettext("Humid rivers"),
59 fgettext("Increases humidity around rivers") },
60 { "vary_river_depth", fgettext("Vary river depth"),
61 fgettext("Low humidity and high heat causes shallow or dry rivers") },
65 { "hills", fgettext("Hills") },
66 { "lakes", fgettext("Lakes") },
69 { "terrain", fgettext("Additional terrain"),
70 fgettext("Generate non-fractal terrain: Oceans and underground") },
73 { "trees", fgettext("Trees and jungle grass") },
74 { "flat", fgettext("Flat terrain") },
75 { "mudflow", fgettext("Mud flow"), fgettext("Terrain surface erosion") },
76 -- Biome settings are in mgv6_biomes below
82 fgettext("Temperate, Desert, Jungle, Tundra, Taiga"),
83 {jungles = true, snowbiomes = true}
86 fgettext("Temperate, Desert, Jungle"),
87 {jungles = true, snowbiomes = false}
90 fgettext("Temperate, Desert"),
91 {jungles = false, snowbiomes = false}
95 local function create_world_formspec(dialogdata)
97 -- Error out when no games found
98 if #pkgmgr.games == 0 then
99 return "size[12.25,3,true]" ..
100 "box[0,0;12,2;" .. mt_color_orange .. "]" ..
101 "textarea[0.3,0;11.7,2;;;"..
102 fgettext("You have no games installed.") .. "\n" ..
103 fgettext("Download one from minetest.net") .. "]" ..
104 "button[4.75,2.5;3,0.5;world_create_cancel;" .. fgettext("Cancel") .. "]"
107 local current_mg = dialogdata.mg
108 local mapgens = core.get_mapgen_names()
110 local gameid = core.settings:get("menu_last_game")
112 local flags = dialogdata.flags
114 local game, gameidx = pkgmgr.find_by_gameid(gameid)
115 if game == nil and hide_gamelist then
116 -- should never happen but just pick the first game
117 game = pkgmgr.get_game(1)
119 core.settings:set("menu_last_game", game.id)
120 elseif game == nil then
124 local disallowed_mapgen_settings = {}
126 local gameconfig = Settings(game.path.."/game.conf")
128 local allowed_mapgens = (gameconfig:get("allowed_mapgens") or ""):split()
129 for key, value in pairs(allowed_mapgens) do
130 allowed_mapgens[key] = value:trim()
133 local disallowed_mapgens = (gameconfig:get("disallowed_mapgens") or ""):split()
134 for key, value in pairs(disallowed_mapgens) do
135 disallowed_mapgens[key] = value:trim()
138 if #allowed_mapgens > 0 then
139 for i = #mapgens, 1, -1 do
140 if table.indexof(allowed_mapgens, mapgens[i]) == -1 then
141 table.remove(mapgens, i)
146 if #disallowed_mapgens > 0 then
147 for i = #mapgens, 1, -1 do
148 if table.indexof(disallowed_mapgens, mapgens[i]) > 0 then
149 table.remove(mapgens, i)
154 local ds = (gameconfig:get("disallowed_mapgen_settings") or ""):split()
155 for _, value in pairs(ds) do
156 disallowed_mapgen_settings[value:trim()] = true
162 do -- build the list of mapgens
165 for k, v in pairs(mapgens) do
169 if current_mg == v then
173 mglist = mglist .. core.formspec_escape(v) .. ","
177 current_mg = first_mg
179 mglist = mglist:sub(1, -2)
182 -- The logic of the flag element IDs is as follows:
183 -- "flag_main_foo-bar-baz" controls dialogdata.flags["main"]["foo_bar_baz"]
184 -- see the buttonhandler for the implementation of this
186 local mg_main_flags = function(mapgen, y)
187 if mapgen == "singlenode" then
190 if disallowed_mapgen_settings["mg_flags"] then
194 local form = "checkbox[0," .. y .. ";flag_main_caves;" ..
195 fgettext("Caves") .. ";"..strflag(flags.main, "caves").."]"
198 form = form .. "checkbox[0,"..y..";flag_main_dungeons;" ..
199 fgettext("Dungeons") .. ";"..strflag(flags.main, "dungeons").."]"
202 local d_name = fgettext("Decorations")
204 if mapgen == "v6" then
205 d_tt = fgettext("Structures appearing on the terrain (no effect on trees and jungle grass created by v6)")
207 d_tt = fgettext("Structures appearing on the terrain, typically trees and plants")
209 form = form .. "checkbox[0,"..y..";flag_main_decorations;" ..
211 strflag(flags.main, "decorations").."]" ..
212 "tooltip[flag_mg_decorations;" ..
217 form = form .. "tooltip[flag_main_caves;" ..
218 fgettext("Network of tunnels and caves")
223 local mg_specific_flags = function(mapgen, y)
224 if not flag_checkboxes[mapgen] then
227 if disallowed_mapgen_settings["mg"..mapgen.."_spflags"] then
231 for _, tab in pairs(flag_checkboxes[mapgen]) do
232 local id = "flag_"..mapgen.."_"..tab[1]:gsub("_", "-")
233 form = form .. ("checkbox[0,%f;%s;%s;%s]"):
234 format(y, id, tab[2], strflag(flags[mapgen], tab[1]))
237 form = form .. "tooltip["..id..";"..tab[3].."]"
242 if mapgen ~= "v6" then
243 -- No special treatment
246 -- Special treatment for v6 (add biome widgets)
248 -- Biome type (jungles, snowbiomes)
250 if flags.v6.snowbiomes == true then
252 elseif flags.v6.jungles == true then
259 form = form .. "label[0,"..(y+0.1)..";" .. fgettext("Biomes") .. "]"
262 form = form .. "dropdown[0,"..y..";6.3;mgv6_biomes;"
263 for b=1, #mgv6_biomes do
264 form = form .. mgv6_biomes[b][1]
265 if b < #mgv6_biomes then
269 form = form .. ";" .. biometype.. "]"
273 form = form .. "checkbox[0,"..y..";flag_v6_biomeblend;" ..
274 fgettext("Biome blending") .. ";"..strflag(flags.v6, "biomeblend").."]" ..
275 "tooltip[flag_v6_biomeblend;" ..
276 fgettext("Smooth transition between biomes") .. "]"
283 local str_flags, str_spflags
284 local label_flags, label_spflags = "", ""
286 str_flags, y = mg_main_flags(current_mg, y)
287 if str_flags ~= "" then
288 label_flags = "label[0,"..y_start..";" .. fgettext("Mapgen flags") .. "]"
294 str_spflags = mg_specific_flags(current_mg, y)
295 if str_spflags ~= "" then
296 label_spflags = "label[0,"..y_start..";" .. fgettext("Mapgen-specific flags") .. "]"
299 -- Warning if only devtest is installed
300 local devtest_only = ""
301 local gamelist_height = 2.3
302 if #pkgmgr.games == 1 and pkgmgr.games[1].id == "devtest" then
303 devtest_only = "box[0,0;5.8,1.7;#ff8800]" ..
304 "textarea[0.3,0;6,1.8;;;"..
305 fgettext("Warning: The Development Test is meant for developers.") .. "\n" ..
306 fgettext("Download a game, such as Minetest Game, from minetest.net") .. "]"
307 gamelist_height = 0.5
311 "size[12.25,7,true]" ..
315 "field[0.3,0.6;6,0.5;te_world_name;" ..
316 fgettext("World name") ..
317 ";" .. core.formspec_escape(dialogdata.worldname) .. "]" ..
318 "set_focus[te_world_name;false]"
320 if not disallowed_mapgen_settings["seed"] then
322 retval = retval .. "field[0.3,1.7;6,0.5;te_seed;" ..
324 ";".. core.formspec_escape(dialogdata.seed) .. "]"
329 "label[0,2;" .. fgettext("Mapgen") .. "]"..
330 "dropdown[0,2.5;6.3;dd_mapgen;" .. mglist .. ";" .. selindex .. "]"
332 if not hide_gamelist or devtest_only ~= "" then
334 "label[0,3.35;" .. fgettext("Game") .. "]"..
335 "textlist[0,3.85;5.8,"..gamelist_height..";games;" ..
336 pkgmgr.gamelist() .. ";" .. gameidx .. ";false]" ..
337 "container[0,4.5]" ..
347 label_flags .. str_flags ..
348 label_spflags .. str_spflags ..
352 "button[3.25,6.5;3,0.5;world_create_confirm;" .. fgettext("Create") .. "]" ..
353 "button[6.25,6.5;3,0.5;world_create_cancel;" .. fgettext("Cancel") .. "]"
359 local function create_world_buttonhandler(this, fields)
361 if fields["world_create_confirm"] or
362 fields["key_enter"] then
364 local worldname = fields["te_world_name"]
365 local game, gameindex
366 if hide_gamelist then
367 game, gameindex = pkgmgr.find_by_gameid(core.settings:get("menu_last_game"))
369 gameindex = core.get_textlist_index("games")
370 game = pkgmgr.get_game(gameindex)
375 message = fgettext("No game selected")
378 if message == nil then
379 -- For unnamed worlds use the generated name 'world<number>',
380 -- where the number increments: it is set to 1 larger than the largest
381 -- generated name number found.
382 if worldname == "" then
383 local worldnum_max = 0
384 for _, world in ipairs(menudata.worldlist:get_list()) do
385 if world.name:match("^world%d+$") then
386 local worldnum = tonumber(world.name:sub(6))
387 worldnum_max = math.max(worldnum_max, worldnum)
390 worldname = "world" .. worldnum_max + 1
393 if menudata.worldlist:uid_exists_raw(worldname) then
394 message = fgettext("A world named \"$1\" already exists", worldname)
398 if message == nil then
399 this.data.seed = fields["te_seed"] or ""
400 this.data.mg = fields["dd_mapgen"]
402 -- actual names as used by engine
404 fixed_map_seed = this.data.seed,
405 mg_name = this.data.mg,
406 mg_flags = table_to_flags(this.data.flags.main),
407 mgv5_spflags = table_to_flags(this.data.flags.v5),
408 mgv6_spflags = table_to_flags(this.data.flags.v6),
409 mgv7_spflags = table_to_flags(this.data.flags.v7),
410 mgfractal_spflags = table_to_flags(this.data.flags.fractal),
411 mgcarpathian_spflags = table_to_flags(this.data.flags.carpathian),
412 mgvalleys_spflags = table_to_flags(this.data.flags.valleys),
413 mgflat_spflags = table_to_flags(this.data.flags.flat),
415 message = core.create_world(worldname, gameindex, settings)
418 if message == nil then
419 core.settings:set("menu_last_game", game.id)
420 if this.data.update_worldlist_filter then
421 menudata.worldlist:set_filtercriteria(game.id)
423 menudata.worldlist:refresh()
424 core.settings:set("mainmenu_last_selected_world",
425 menudata.worldlist:raw_index_by_uid(worldname))
428 gamedata.errormessage = message
433 this.data.worldname = fields["te_world_name"]
434 this.data.seed = fields["te_seed"] or ""
436 if fields["games"] then
437 local gameindex = core.get_textlist_index("games")
438 core.settings:set("menu_last_game", pkgmgr.games[gameindex].id)
442 for k,v in pairs(fields) do
443 local split = string.split(k, "_", nil, 3)
444 if split and split[1] == "flag" then
445 -- We replaced the underscore of flag names with a dash.
446 local flag = string.gsub(split[3], "-", "_")
447 local ftable = this.data.flags[split[2]]
449 ftable[flag] = v == "true"
454 if fields["world_create_cancel"] then
459 if fields["mgv6_biomes"] then
460 local entry = core.formspec_escape(fields["mgv6_biomes"])
461 for b=1, #mgv6_biomes do
462 if entry == mgv6_biomes[b][1] then
463 local ftable = this.data.flags.v6
464 ftable.jungles = mgv6_biomes[b][2].jungles
465 ftable.snowbiomes = mgv6_biomes[b][2].snowbiomes
471 if fields["dd_mapgen"] then
472 this.data.mg = fields["dd_mapgen"]
480 function create_create_world_dlg(update_worldlistfilter)
481 local retval = dialog_create("sp_create_world",
482 create_world_formspec,
483 create_world_buttonhandler,
486 update_worldlist_filter = update_worldlistfilter,
488 -- settings the world is created with:
489 seed = core.settings:get("fixed_map_seed") or "",
490 mg = core.settings:get("mg_name"),
492 main = core.settings:get_flags("mg_flags"),
493 v5 = core.settings:get_flags("mgv5_spflags"),
494 v6 = core.settings:get_flags("mgv6_spflags"),
495 v7 = core.settings:get_flags("mgv7_spflags"),
496 fractal = core.settings:get_flags("mgfractal_spflags"),
497 carpathian = core.settings:get_flags("mgcarpathian_spflags"),
498 valleys = core.settings:get_flags("mgvalleys_spflags"),
499 flat = core.settings:get_flags("mgflat_spflags"),