tab_local.lua 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466
  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 current_game, singleplayer_refresh_gamebar
  18. local valid_disabled_settings = {
  19. ["enable_damage"]=true,
  20. ["creative_mode"]=true,
  21. ["enable_server"]=true,
  22. }
  23. -- Name and port stored to persist when updating the formspec
  24. local current_name = core.settings:get("name")
  25. local current_port = core.settings:get("port")
  26. -- Currently chosen game in gamebar for theming and filtering
  27. function current_game()
  28. local gameid = core.settings:get("menu_last_game")
  29. local game = gameid and pkgmgr.find_by_gameid(gameid)
  30. -- Fall back to first game installed if one exists.
  31. if not game and #pkgmgr.games > 0 then
  32. -- If devtest is the first game in the list and there is another
  33. -- game available, pick the other game instead.
  34. local picked_game
  35. if pkgmgr.games[1].id == "devtest" and #pkgmgr.games > 1 then
  36. picked_game = 2
  37. else
  38. picked_game = 1
  39. end
  40. game = pkgmgr.games[picked_game]
  41. gameid = game.id
  42. core.settings:set("menu_last_game", gameid)
  43. end
  44. return game
  45. end
  46. -- Apply menu changes from given game
  47. function apply_game(game)
  48. core.settings:set("menu_last_game", game.id)
  49. menudata.worldlist:set_filtercriteria(game.id)
  50. mm_game_theme.set_game(game)
  51. local index = filterlist.get_current_index(menudata.worldlist,
  52. tonumber(core.settings:get("mainmenu_last_selected_world")))
  53. if not index or index < 1 then
  54. local selected = core.get_textlist_index("sp_worlds")
  55. if selected ~= nil and selected < #menudata.worldlist:get_list() then
  56. index = selected
  57. else
  58. index = #menudata.worldlist:get_list()
  59. end
  60. end
  61. menu_worldmt_legacy(index)
  62. end
  63. function singleplayer_refresh_gamebar()
  64. local old_bar = ui.find_by_name("game_button_bar")
  65. if old_bar ~= nil then
  66. old_bar:delete()
  67. end
  68. -- Hide gamebar if no games are installed
  69. if #pkgmgr.games == 0 then
  70. return false
  71. end
  72. local function game_buttonbar_button_handler(fields)
  73. for _, game in ipairs(pkgmgr.games) do
  74. if fields["game_btnbar_" .. game.id] then
  75. apply_game(game)
  76. return true
  77. end
  78. end
  79. end
  80. local btnbar = buttonbar_create(
  81. "game_button_bar",
  82. core.settings:get_bool("enable_touch") and {x = 0, y = 7.25} or {x = 0, y = 7.475},
  83. {x = 15.5, y = 1.25},
  84. "#000000",
  85. game_buttonbar_button_handler)
  86. for _, game in ipairs(pkgmgr.games) do
  87. local btn_name = "game_btnbar_" .. game.id
  88. local image = nil
  89. local text = nil
  90. local tooltip = core.formspec_escape(game.title)
  91. if (game.menuicon_path or "") ~= "" then
  92. image = core.formspec_escape(game.menuicon_path)
  93. else
  94. local part1 = game.id:sub(1,5)
  95. local part2 = game.id:sub(6,10)
  96. local part3 = game.id:sub(11)
  97. text = part1 .. "\n" .. part2
  98. if part3 ~= "" then
  99. text = text .. "\n" .. part3
  100. end
  101. end
  102. btnbar:add_button(btn_name, text, image, tooltip)
  103. end
  104. local plus_image = core.formspec_escape(defaulttexturedir .. "plus.png")
  105. btnbar:add_button("game_open_cdb", "", plus_image, fgettext("Install games from ContentDB"))
  106. return true
  107. end
  108. local function get_disabled_settings(game)
  109. if not game then
  110. return {}
  111. end
  112. local gameconfig = Settings(game.path .. "/game.conf")
  113. local disabled_settings = {}
  114. if gameconfig then
  115. local disabled_settings_str = (gameconfig:get("disabled_settings") or ""):split()
  116. for _, value in pairs(disabled_settings_str) do
  117. local state = false
  118. value = value:trim()
  119. if string.sub(value, 1, 1) == "!" then
  120. state = true
  121. value = string.sub(value, 2)
  122. end
  123. if valid_disabled_settings[value] then
  124. disabled_settings[value] = state
  125. else
  126. core.log("error", "Invalid disabled setting in game.conf: "..tostring(value))
  127. end
  128. end
  129. end
  130. return disabled_settings
  131. end
  132. local function get_formspec(tabview, name, tabdata)
  133. -- Point the player to ContentDB when no games are found
  134. if #pkgmgr.games == 0 then
  135. return table.concat({
  136. "style[label_button;border=false]",
  137. "button[2.75,1.5;10,1;label_button;", fgettext("You have no games installed."), "]",
  138. "button[5.25,3.5;5,1.2;game_open_cdb;", fgettext("Install a game"), "]"})
  139. end
  140. local retval = ""
  141. local index = filterlist.get_current_index(menudata.worldlist,
  142. tonumber(core.settings:get("mainmenu_last_selected_world")))
  143. local list = menudata.worldlist:get_list()
  144. local world = list and index and list[index]
  145. local game
  146. if world then
  147. game = pkgmgr.find_by_gameid(world.gameid)
  148. else
  149. game = current_game()
  150. end
  151. local disabled_settings = get_disabled_settings(game)
  152. local creative, damage, host = "", "", ""
  153. -- Y offsets for game settings checkboxes
  154. local y = 0.2
  155. local yo = 0.5625
  156. if disabled_settings["creative_mode"] == nil then
  157. creative = "checkbox[0,"..y..";cb_creative_mode;".. fgettext("Creative Mode") .. ";" ..
  158. dump(core.settings:get_bool("creative_mode")) .. "]"
  159. y = y + yo
  160. end
  161. if disabled_settings["enable_damage"] == nil then
  162. damage = "checkbox[0,"..y..";cb_enable_damage;".. fgettext("Enable Damage") .. ";" ..
  163. dump(core.settings:get_bool("enable_damage")) .. "]"
  164. y = y + yo
  165. end
  166. if disabled_settings["enable_server"] == nil then
  167. host = "checkbox[0,"..y..";cb_server;".. fgettext("Host Server") ..";" ..
  168. dump(core.settings:get_bool("enable_server")) .. "]"
  169. y = y + yo
  170. end
  171. retval = retval ..
  172. "container[5.25,4.875]" ..
  173. "button[0,0;3.225,0.8;world_delete;".. fgettext("Delete") .. "]" ..
  174. "button[3.325,0;3.225,0.8;world_configure;".. fgettext("Select Mods") .. "]" ..
  175. "button[6.65,0;3.225,0.8;world_create;".. fgettext("New") .. "]" ..
  176. "container_end[]" ..
  177. "container[0.375,0.375]" ..
  178. creative ..
  179. damage ..
  180. host ..
  181. "container_end[]" ..
  182. "container[5.25,0.375]" ..
  183. "label[0,0.2;".. fgettext("Select World:") .. "]"..
  184. "textlist[0,0.5;9.875,3.9;sp_worlds;" ..
  185. menu_render_worldlist() ..
  186. ";" .. index .. "]" ..
  187. "container_end[]"
  188. if core.settings:get_bool("enable_server") and disabled_settings["enable_server"] == nil then
  189. retval = retval ..
  190. "button[10.1875,5.925;4.9375,0.8;play;".. fgettext("Host Game") .. "]" ..
  191. "container[0.375,0.375]" ..
  192. "checkbox[0,"..y..";cb_server_announce;" .. fgettext("Announce Server") .. ";" ..
  193. dump(core.settings:get_bool("server_announce")) .. "]"
  194. -- Reset y so that the text fields always start at the same position,
  195. -- regardless of whether some of the checkboxes are hidden.
  196. y = 0.2 + 4 * yo + 0.35
  197. retval = retval .. "field[0," .. y .. ";4.5,0.75;te_playername;" .. fgettext("Name") .. ";" ..
  198. core.formspec_escape(current_name) .. "]"
  199. y = y + 1.15 + 0.25
  200. retval = retval .. "pwdfield[0," .. y .. ";4.5,0.75;te_passwd;" .. fgettext("Password") .. "]"
  201. y = y + 1.15 + 0.25
  202. local bind_addr = core.settings:get("bind_address")
  203. if bind_addr ~= nil and bind_addr ~= "" then
  204. retval = retval ..
  205. "field[0," .. y .. ";3,0.75;te_serveraddr;" .. fgettext("Bind Address") .. ";" ..
  206. core.formspec_escape(core.settings:get("bind_address")) .. "]" ..
  207. "field[3.25," .. y .. ";1.25,0.75;te_serverport;" .. fgettext("Port") .. ";" ..
  208. core.formspec_escape(current_port) .. "]"
  209. else
  210. retval = retval ..
  211. "field[0," .. y .. ";4.5,0.75;te_serverport;" .. fgettext("Server Port") .. ";" ..
  212. core.formspec_escape(current_port) .. "]"
  213. end
  214. retval = retval .. "container_end[]"
  215. else
  216. retval = retval ..
  217. "button[10.1875,5.925;4.9375,0.8;play;" .. fgettext("Play Game") .. "]"
  218. end
  219. return retval
  220. end
  221. local function main_button_handler(this, fields, name, tabdata)
  222. assert(name == "local")
  223. if fields.game_open_cdb then
  224. local maintab = ui.find_by_name("maintab")
  225. local dlg = create_contentdb_dlg("game")
  226. dlg:set_parent(maintab)
  227. maintab:hide()
  228. dlg:show()
  229. return true
  230. end
  231. if this.dlg_create_world_closed_at == nil then
  232. this.dlg_create_world_closed_at = 0
  233. end
  234. local world_doubleclick = false
  235. if fields["te_playername"] then
  236. current_name = fields["te_playername"]
  237. end
  238. if fields["te_serverport"] then
  239. current_port = fields["te_serverport"]
  240. end
  241. if fields["sp_worlds"] ~= nil then
  242. local event = core.explode_textlist_event(fields["sp_worlds"])
  243. local selected = core.get_textlist_index("sp_worlds")
  244. menu_worldmt_legacy(selected)
  245. if event.type == "DCL" then
  246. world_doubleclick = true
  247. end
  248. if event.type == "CHG" and selected ~= nil then
  249. core.settings:set("mainmenu_last_selected_world",
  250. menudata.worldlist:get_raw_index(selected))
  251. return true
  252. end
  253. end
  254. if menu_handle_key_up_down(fields,"sp_worlds","mainmenu_last_selected_world") then
  255. return true
  256. end
  257. if fields["cb_creative_mode"] then
  258. core.settings:set("creative_mode", fields["cb_creative_mode"])
  259. local selected = core.get_textlist_index("sp_worlds")
  260. menu_worldmt(selected, "creative_mode", fields["cb_creative_mode"])
  261. return true
  262. end
  263. if fields["cb_enable_damage"] then
  264. core.settings:set("enable_damage", fields["cb_enable_damage"])
  265. local selected = core.get_textlist_index("sp_worlds")
  266. menu_worldmt(selected, "enable_damage", fields["cb_enable_damage"])
  267. return true
  268. end
  269. if fields["cb_server"] then
  270. core.settings:set("enable_server", fields["cb_server"])
  271. return true
  272. end
  273. if fields["cb_server_announce"] then
  274. core.settings:set("server_announce", fields["cb_server_announce"])
  275. local selected = core.get_textlist_index("srv_worlds")
  276. menu_worldmt(selected, "server_announce", fields["cb_server_announce"])
  277. return true
  278. end
  279. if fields["play"] ~= nil or world_doubleclick or fields["key_enter"] then
  280. local enter_key_duration = core.get_us_time() - this.dlg_create_world_closed_at
  281. if world_doubleclick and enter_key_duration <= 200000 then -- 200 ms
  282. this.dlg_create_world_closed_at = 0
  283. return true
  284. end
  285. local selected = core.get_textlist_index("sp_worlds")
  286. gamedata.selected_world = menudata.worldlist:get_raw_index(selected)
  287. if selected == nil or gamedata.selected_world == 0 then
  288. gamedata.errormessage =
  289. fgettext_ne("No world created or selected!")
  290. return true
  291. end
  292. -- Update last game
  293. local world = menudata.worldlist:get_raw_element(gamedata.selected_world)
  294. local game_obj
  295. if world then
  296. game_obj = pkgmgr.find_by_gameid(world.gameid)
  297. core.settings:set("menu_last_game", game_obj.id)
  298. end
  299. local disabled_settings = get_disabled_settings(game_obj)
  300. for k, _ in pairs(valid_disabled_settings) do
  301. local v = disabled_settings[k]
  302. if v ~= nil then
  303. if k == "enable_server" and v == true then
  304. error("Setting 'enable_server' cannot be force-enabled! The game.conf needs to be fixed.")
  305. end
  306. core.settings:set_bool(k, disabled_settings[k])
  307. end
  308. end
  309. if core.settings:get_bool("enable_server") then
  310. gamedata.playername = fields["te_playername"]
  311. gamedata.password = fields["te_passwd"]
  312. gamedata.port = fields["te_serverport"]
  313. gamedata.address = ""
  314. core.settings:set("port",gamedata.port)
  315. if fields["te_serveraddr"] ~= nil then
  316. core.settings:set("bind_address",fields["te_serveraddr"])
  317. end
  318. else
  319. gamedata.singleplayer = true
  320. end
  321. core.start()
  322. return true
  323. end
  324. if fields["world_create"] ~= nil then
  325. this.dlg_create_world_closed_at = 0
  326. local create_world_dlg = create_create_world_dlg()
  327. create_world_dlg:set_parent(this)
  328. this:hide()
  329. create_world_dlg:show()
  330. return true
  331. end
  332. if fields["world_delete"] ~= nil then
  333. local selected = core.get_textlist_index("sp_worlds")
  334. if selected ~= nil and
  335. selected <= menudata.worldlist:size() then
  336. local world = menudata.worldlist:get_list()[selected]
  337. if world ~= nil and
  338. world.name ~= nil and
  339. world.name ~= "" then
  340. local index = menudata.worldlist:get_raw_index(selected)
  341. local delete_world_dlg = create_delete_world_dlg(world.name,index)
  342. delete_world_dlg:set_parent(this)
  343. this:hide()
  344. delete_world_dlg:show()
  345. end
  346. end
  347. return true
  348. end
  349. if fields["world_configure"] ~= nil then
  350. local selected = core.get_textlist_index("sp_worlds")
  351. if selected ~= nil then
  352. local configdialog =
  353. create_configure_world_dlg(
  354. menudata.worldlist:get_raw_index(selected))
  355. if (configdialog ~= nil) then
  356. configdialog:set_parent(this)
  357. this:hide()
  358. configdialog:show()
  359. end
  360. end
  361. return true
  362. end
  363. end
  364. local function on_change(type)
  365. if type == "ENTER" then
  366. local game = current_game()
  367. if game then
  368. apply_game(game)
  369. else
  370. mm_game_theme.set_engine()
  371. end
  372. if singleplayer_refresh_gamebar() then
  373. ui.find_by_name("game_button_bar"):show()
  374. end
  375. elseif type == "LEAVE" then
  376. menudata.worldlist:set_filtercriteria(nil)
  377. local gamebar = ui.find_by_name("game_button_bar")
  378. if gamebar then
  379. gamebar:hide()
  380. end
  381. end
  382. end
  383. --------------------------------------------------------------------------------
  384. return {
  385. name = "local",
  386. caption = fgettext("Start Game"),
  387. cbf_formspec = get_formspec,
  388. cbf_button_handler = main_button_handler,
  389. on_change = on_change
  390. }