dlg_create_world.lua 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477
  1. --Minetest
  2. --Copyright (C) 2014 sapier
  3. --
  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.
  8. --
  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.
  13. --
  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.
  17. local worldname = ""
  18. local function table_to_flags(ftable)
  19. -- Convert e.g. { jungles = true, caves = false } to "jungles,nocaves"
  20. local str = {}
  21. for flag, is_set in pairs(ftable) do
  22. str[#str + 1] = is_set and flag or ("no" .. flag)
  23. end
  24. return table.concat(str, ",")
  25. end
  26. -- Same as check_flag but returns a string
  27. local function strflag(flags, flag)
  28. return (flags[flag] == true) and "true" or "false"
  29. end
  30. local cb_caverns = { "caverns", fgettext("Caverns"), "caverns",
  31. fgettext("Very large caverns deep in the underground") }
  32. local tt_sea_rivers = fgettext("Sea level rivers")
  33. local flag_checkboxes = {
  34. v5 = {
  35. cb_caverns,
  36. },
  37. v7 = {
  38. cb_caverns,
  39. { "ridges", fgettext("Rivers"), "ridges", tt_sea_rivers },
  40. { "mountains", fgettext("Mountains"), "mountains" },
  41. { "floatlands", fgettext("Floatlands (experimental)"), "floatlands",
  42. fgettext("Floating landmasses in the sky") },
  43. },
  44. carpathian = {
  45. cb_caverns,
  46. { "rivers", fgettext("Rivers"), "rivers", tt_sea_rivers },
  47. },
  48. valleys = {
  49. { "altitude-chill", fgettext("Altitude chill"), "altitude_chill",
  50. fgettext("Reduces heat with altitude") },
  51. { "altitude-dry", fgettext("Altitude dry"), "altitude_dry",
  52. fgettext("Reduces humidity with altitude") },
  53. { "humid-rivers", fgettext("Humid rivers"), "humid_rivers",
  54. fgettext("Increases humidity around rivers") },
  55. { "vary-river-depth", fgettext("Vary river depth"), "vary_river_depth",
  56. fgettext("Low humidity and high heat causes shallow or dry rivers") },
  57. },
  58. flat = {
  59. cb_caverns,
  60. { "hills", fgettext("Hills"), "hills" },
  61. { "lakes", fgettext("Lakes"), "lakes" },
  62. },
  63. fractal = {
  64. { "terrain", fgettext("Additional terrain"), "terrain",
  65. fgettext("Generate non-fractal terrain: Oceans and underground") },
  66. },
  67. v6 = {
  68. { "trees", fgettext("Trees and jungle grass"), "trees" },
  69. { "flat", fgettext("Flat terrain"), "flat" },
  70. { "mudflow", fgettext("Mud flow"), "mudflow",
  71. fgettext("Terrain surface erosion") },
  72. -- Biome settings are in mgv6_biomes below
  73. },
  74. }
  75. local mgv6_biomes = {
  76. {
  77. fgettext("Temperate, Desert, Jungle, Tundra, Taiga"),
  78. {jungles = true, snowbiomes = true}
  79. },
  80. {
  81. fgettext("Temperate, Desert, Jungle"),
  82. {jungles = true, snowbiomes = false}
  83. },
  84. {
  85. fgettext("Temperate, Desert"),
  86. {jungles = false, snowbiomes = false}
  87. },
  88. }
  89. local function create_world_formspec(dialogdata)
  90. -- Error out when no games found
  91. if #pkgmgr.games == 0 then
  92. return "size[12.25,3,true]" ..
  93. "box[0,0;12,2;" .. mt_color_orange .. "]" ..
  94. "textarea[0.3,0;11.7,2;;;"..
  95. fgettext("You have no games installed.") .. "\n" ..
  96. fgettext("Download one from minetest.net") .. "]" ..
  97. "button[4.75,2.5;3,0.5;world_create_cancel;" .. fgettext("Cancel") .. "]"
  98. end
  99. local mapgens = core.get_mapgen_names()
  100. local current_seed = core.settings:get("fixed_map_seed") or ""
  101. local current_mg = core.settings:get("mg_name")
  102. local gameid = core.settings:get("menu_last_game")
  103. local flags = {
  104. main = core.settings:get_flags("mg_flags"),
  105. v5 = core.settings:get_flags("mgv5_spflags"),
  106. v6 = core.settings:get_flags("mgv6_spflags"),
  107. v7 = core.settings:get_flags("mgv7_spflags"),
  108. fractal = core.settings:get_flags("mgfractal_spflags"),
  109. carpathian = core.settings:get_flags("mgcarpathian_spflags"),
  110. valleys = core.settings:get_flags("mgvalleys_spflags"),
  111. flat = core.settings:get_flags("mgflat_spflags"),
  112. }
  113. local gameidx = 0
  114. if gameid ~= nil then
  115. local _
  116. _, gameidx = pkgmgr.find_by_gameid(gameid)
  117. if gameidx == nil then
  118. gameidx = 0
  119. end
  120. end
  121. local game_by_gameidx = core.get_game(gameidx)
  122. local disallowed_mapgen_settings = {}
  123. if game_by_gameidx ~= nil then
  124. local gamepath = game_by_gameidx.path
  125. local gameconfig = Settings(gamepath.."/game.conf")
  126. local allowed_mapgens = (gameconfig:get("allowed_mapgens") or ""):split()
  127. for key, value in pairs(allowed_mapgens) do
  128. allowed_mapgens[key] = value:trim()
  129. end
  130. local disallowed_mapgens = (gameconfig:get("disallowed_mapgens") or ""):split()
  131. for key, value in pairs(disallowed_mapgens) do
  132. disallowed_mapgens[key] = value:trim()
  133. end
  134. if #allowed_mapgens > 0 then
  135. for i = #mapgens, 1, -1 do
  136. if table.indexof(allowed_mapgens, mapgens[i]) == -1 then
  137. table.remove(mapgens, i)
  138. end
  139. end
  140. end
  141. if disallowed_mapgens then
  142. for i = #mapgens, 1, -1 do
  143. if table.indexof(disallowed_mapgens, mapgens[i]) > 0 then
  144. table.remove(mapgens, i)
  145. end
  146. end
  147. end
  148. local ds = (gameconfig:get("disallowed_mapgen_settings") or ""):split()
  149. for _, value in pairs(ds) do
  150. disallowed_mapgen_settings[value:trim()] = true
  151. end
  152. end
  153. local mglist = ""
  154. local selindex
  155. local i = 1
  156. local first_mg
  157. for k,v in pairs(mapgens) do
  158. if not first_mg then
  159. first_mg = v
  160. end
  161. if current_mg == v then
  162. selindex = i
  163. end
  164. i = i + 1
  165. mglist = mglist .. v .. ","
  166. end
  167. if not selindex then
  168. selindex = 1
  169. current_mg = first_mg
  170. end
  171. mglist = mglist:sub(1, -2)
  172. local mg_main_flags = function(mapgen, y)
  173. if mapgen == "singlenode" then
  174. return "", y
  175. end
  176. if disallowed_mapgen_settings["mg_flags"] then
  177. return "", y
  178. end
  179. local form = "checkbox[0," .. y .. ";flag_mg_caves;" ..
  180. fgettext("Caves") .. ";"..strflag(flags.main, "caves").."]"
  181. y = y + 0.5
  182. form = form .. "checkbox[0,"..y..";flag_mg_dungeons;" ..
  183. fgettext("Dungeons") .. ";"..strflag(flags.main, "dungeons").."]"
  184. y = y + 0.5
  185. local d_name = fgettext("Decorations")
  186. local d_tt
  187. if mapgen == "v6" then
  188. d_tt = fgettext("Structures appearing on the terrain (no effect on trees and jungle grass created by v6)")
  189. else
  190. d_tt = fgettext("Structures appearing on the terrain, typically trees and plants")
  191. end
  192. form = form .. "checkbox[0,"..y..";flag_mg_decorations;" ..
  193. d_name .. ";" ..
  194. strflag(flags.main, "decorations").."]" ..
  195. "tooltip[flag_mg_decorations;" ..
  196. d_tt ..
  197. "]"
  198. y = y + 0.5
  199. form = form .. "tooltip[flag_mg_caves;" ..
  200. fgettext("Network of tunnels and caves")
  201. .. "]"
  202. return form, y
  203. end
  204. local mg_specific_flags = function(mapgen, y)
  205. if not flag_checkboxes[mapgen] then
  206. return "", y
  207. end
  208. if disallowed_mapgen_settings["mg"..mapgen.."_spflags"] then
  209. return "", y
  210. end
  211. local form = ""
  212. for _,tab in pairs(flag_checkboxes[mapgen]) do
  213. local id = "flag_mg"..mapgen.."_"..tab[1]
  214. form = form .. ("checkbox[0,%f;%s;%s;%s]"):
  215. format(y, id, tab[2], strflag(flags[mapgen], tab[3]))
  216. if tab[4] then
  217. form = form .. "tooltip["..id..";"..tab[4].."]"
  218. end
  219. y = y + 0.5
  220. end
  221. if mapgen ~= "v6" then
  222. -- No special treatment
  223. return form, y
  224. end
  225. -- Special treatment for v6 (add biome widgets)
  226. -- Biome type (jungles, snowbiomes)
  227. local biometype
  228. if flags.v6.snowbiomes == true then
  229. biometype = 1
  230. elseif flags.v6.jungles == true then
  231. biometype = 2
  232. else
  233. biometype = 3
  234. end
  235. y = y + 0.3
  236. form = form .. "label[0,"..(y+0.1)..";" .. fgettext("Biomes") .. "]"
  237. y = y + 0.6
  238. form = form .. "dropdown[0,"..y..";6.3;mgv6_biomes;"
  239. for b=1, #mgv6_biomes do
  240. form = form .. mgv6_biomes[b][1]
  241. if b < #mgv6_biomes then
  242. form = form .. ","
  243. end
  244. end
  245. form = form .. ";" .. biometype.. "]"
  246. -- biomeblend
  247. y = y + 0.55
  248. form = form .. "checkbox[0,"..y..";flag_mgv6_biomeblend;" ..
  249. fgettext("Biome blending") .. ";"..strflag(flags.v6, "biomeblend").."]" ..
  250. "tooltip[flag_mgv6_biomeblend;" ..
  251. fgettext("Smooth transition between biomes") .. "]"
  252. return form, y
  253. end
  254. current_seed = core.formspec_escape(current_seed)
  255. local y_start = 0.0
  256. local y = y_start
  257. local str_flags, str_spflags
  258. local label_flags, label_spflags = "", ""
  259. y = y + 0.3
  260. str_flags, y = mg_main_flags(current_mg, y)
  261. if str_flags ~= "" then
  262. label_flags = "label[0,"..y_start..";" .. fgettext("Mapgen flags") .. "]"
  263. y_start = y + 0.4
  264. else
  265. y_start = 0.0
  266. end
  267. y = y_start + 0.3
  268. str_spflags = mg_specific_flags(current_mg, y)
  269. if str_spflags ~= "" then
  270. label_spflags = "label[0,"..y_start..";" .. fgettext("Mapgen-specific flags") .. "]"
  271. end
  272. -- Warning if only devtest is installed
  273. local devtest_only = ""
  274. local gamelist_height = 2.3
  275. if #pkgmgr.games == 1 and pkgmgr.games[1].id == "devtest" then
  276. devtest_only = "box[0,0;5.8,1.7;#ff8800]" ..
  277. "textarea[0.3,0;6,1.8;;;"..
  278. fgettext("Warning: The Development Test is meant for developers.") .. "\n" ..
  279. fgettext("Download a game, such as Minetest Game, from minetest.net") .. "]"
  280. gamelist_height = 0.5
  281. end
  282. local retval =
  283. "size[12.25,7,true]" ..
  284. -- Left side
  285. "container[0,0]"..
  286. "field[0.3,0.6;6,0.5;te_world_name;" ..
  287. fgettext("World name") ..
  288. ";" .. core.formspec_escape(worldname) .. "]" ..
  289. "field[0.3,1.7;6,0.5;te_seed;" ..
  290. fgettext("Seed") ..
  291. ";".. current_seed .. "]" ..
  292. "label[0,2;" .. fgettext("Mapgen") .. "]"..
  293. "dropdown[0,2.5;6.3;dd_mapgen;" .. mglist .. ";" .. selindex .. "]" ..
  294. "label[0,3.35;" .. fgettext("Game") .. "]"..
  295. "textlist[0,3.85;5.8,"..gamelist_height..";games;" ..
  296. pkgmgr.gamelist() .. ";" .. gameidx .. ";false]" ..
  297. "container[0,4.5]" ..
  298. devtest_only ..
  299. "container_end[]" ..
  300. "container_end[]" ..
  301. -- Right side
  302. "container[6.2,0]"..
  303. label_flags .. str_flags ..
  304. label_spflags .. str_spflags ..
  305. "container_end[]"..
  306. -- Menu buttons
  307. "button[3.25,6.5;3,0.5;world_create_confirm;" .. fgettext("Create") .. "]" ..
  308. "button[6.25,6.5;3,0.5;world_create_cancel;" .. fgettext("Cancel") .. "]"
  309. return retval
  310. end
  311. local function create_world_buttonhandler(this, fields)
  312. if fields["world_create_confirm"] or
  313. fields["key_enter"] then
  314. local worldname = fields["te_world_name"]
  315. local gameindex = core.get_textlist_index("games")
  316. if gameindex ~= nil then
  317. -- For unnamed worlds use the generated name 'world<number>',
  318. -- where the number increments: it is set to 1 larger than the largest
  319. -- generated name number found.
  320. if worldname == "" then
  321. local worldnum_max = 0
  322. for _, world in ipairs(menudata.worldlist:get_list()) do
  323. if world.name:match("^world%d+$") then
  324. local worldnum = tonumber(world.name:sub(6))
  325. worldnum_max = math.max(worldnum_max, worldnum)
  326. end
  327. end
  328. worldname = "world" .. worldnum_max + 1
  329. end
  330. core.settings:set("fixed_map_seed", fields["te_seed"])
  331. local message
  332. if not menudata.worldlist:uid_exists_raw(worldname) then
  333. core.settings:set("mg_name",fields["dd_mapgen"])
  334. message = core.create_world(worldname,gameindex)
  335. else
  336. message = fgettext("A world named \"$1\" already exists", worldname)
  337. end
  338. if message ~= nil then
  339. gamedata.errormessage = message
  340. else
  341. core.settings:set("menu_last_game",pkgmgr.games[gameindex].id)
  342. if this.data.update_worldlist_filter then
  343. menudata.worldlist:set_filtercriteria(pkgmgr.games[gameindex].id)
  344. mm_texture.update("singleplayer", pkgmgr.games[gameindex].id)
  345. end
  346. menudata.worldlist:refresh()
  347. core.settings:set("mainmenu_last_selected_world",
  348. menudata.worldlist:raw_index_by_uid(worldname))
  349. end
  350. else
  351. gamedata.errormessage = fgettext("No game selected")
  352. end
  353. this:delete()
  354. return true
  355. end
  356. worldname = fields.te_world_name
  357. if fields["games"] then
  358. local gameindex = core.get_textlist_index("games")
  359. core.settings:set("menu_last_game", pkgmgr.games[gameindex].id)
  360. return true
  361. end
  362. for k,v in pairs(fields) do
  363. local split = string.split(k, "_", nil, 3)
  364. if split and split[1] == "flag" then
  365. local setting
  366. if split[2] == "mg" then
  367. setting = "mg_flags"
  368. else
  369. setting = split[2].."_spflags"
  370. end
  371. -- We replaced the underscore of flag names with a dash.
  372. local flag = string.gsub(split[3], "-", "_")
  373. local ftable = core.settings:get_flags(setting)
  374. if v == "true" then
  375. ftable[flag] = true
  376. else
  377. ftable[flag] = false
  378. end
  379. local flags = table_to_flags(ftable)
  380. core.settings:set(setting, flags)
  381. return true
  382. end
  383. end
  384. if fields["world_create_cancel"] then
  385. this:delete()
  386. return true
  387. end
  388. if fields["mgv6_biomes"] then
  389. local entry = core.formspec_escape(fields["mgv6_biomes"])
  390. for b=1, #mgv6_biomes do
  391. if entry == mgv6_biomes[b][1] then
  392. local ftable = core.settings:get_flags("mgv6_spflags")
  393. ftable.jungles = mgv6_biomes[b][2].jungles
  394. ftable.snowbiomes = mgv6_biomes[b][2].snowbiomes
  395. local flags = table_to_flags(ftable)
  396. core.settings:set("mgv6_spflags", flags)
  397. return true
  398. end
  399. end
  400. end
  401. if fields["dd_mapgen"] then
  402. core.settings:set("mg_name", fields["dd_mapgen"])
  403. return true
  404. end
  405. return false
  406. end
  407. function create_create_world_dlg(update_worldlistfilter)
  408. worldname = ""
  409. local retval = dialog_create("sp_create_world",
  410. create_world_formspec,
  411. create_world_buttonhandler,
  412. nil)
  413. retval.update_worldlist_filter = update_worldlistfilter
  414. return retval
  415. end