]> git.lizzy.rs Git - minetest.git/blob - builtin/mainmenu.lua
91084c2c63d066bca47fab69b2c789a58c10c017
[minetest.git] / builtin / mainmenu.lua
1 os.setlocale("C", "numeric")
2
3 local scriptpath = engine.get_scriptdir()
4
5 dofile(scriptpath .. DIR_DELIM .. "mainmenu_worldlist.lua")
6 dofile(scriptpath .. DIR_DELIM .. "modmgr.lua")
7 dofile(scriptpath .. DIR_DELIM .. "modstore.lua")
8 dofile(scriptpath .. DIR_DELIM .. "gamemgr.lua")
9
10 local menu = {}
11 local tabbuilder = {}
12 local menubar = {}
13 local worldlist = nil
14
15 --------------------------------------------------------------------------------
16 function render_favourite(spec,render_details)
17         local text = ""
18         
19         if spec.name ~= nil then
20                 text = text .. fs_escape_string(spec.name:trim())
21                 
22 --              if spec.description ~= nil and
23 --                      fs_escape_string(spec.description):trim() ~= "" then
24 --                      text = text .. " (" .. fs_escape_string(spec.description) .. ")"
25 --              end
26         else
27                 if spec.address ~= nil then
28                         text = text .. spec.address:trim()
29                 end
30         end
31         
32         if not render_details then
33                 return text
34         end
35         
36         local details = ""
37         if spec.password == true then
38                 details = details .. "*"
39         else
40                 details = details .. "_"
41         end
42         
43         if spec.creative then
44                 details = details .. "C"
45         else
46                 details = details .. "_"
47         end
48         
49         if spec.damage then
50                 details = details .. "D"
51         else
52                 details = details .. "_"
53         end
54         
55         if spec.pvp then
56                 details = details .. "P"
57         else
58                 details = details .. "_"
59         end
60         details = details .. "  "
61         
62         return fs_escape_string(details) .. text
63 end
64
65 --------------------------------------------------------------------------------
66 os.tempfolder = function()
67         local filetocheck = os.tmpname()
68         os.remove(filetocheck)
69         
70         local randname = "MTTempModFolder_" .. math.random(0,10000)
71         if DIR_DELIM == "\\" then
72                 local tempfolder = os.getenv("TEMP")
73                 return tempfolder .. filetocheck
74         else
75                 local backstring = filetocheck:reverse()
76                 return filetocheck:sub(0,filetocheck:len()-backstring:find(DIR_DELIM)+1) ..randname
77         end
78
79 end
80
81 --------------------------------------------------------------------------------
82 function cleanup_path(temppath)
83         
84         local parts = temppath:split("-")
85         temppath = ""   
86         for i=1,#parts,1 do
87                 if temppath ~= "" then
88                         temppath = temppath .. "_"
89                 end
90                 temppath = temppath .. parts[i]
91         end
92         
93         parts = temppath:split(".")
94         temppath = ""   
95         for i=1,#parts,1 do
96                 if temppath ~= "" then
97                         temppath = temppath .. "_"
98                 end
99                 temppath = temppath .. parts[i]
100         end
101         
102         parts = temppath:split("'")
103         temppath = ""   
104         for i=1,#parts,1 do
105                 if temppath ~= "" then
106                         temppath = temppath .. ""
107                 end
108                 temppath = temppath .. parts[i]
109         end
110         
111         parts = temppath:split(" ")
112         temppath = ""   
113         for i=1,#parts,1 do
114                 if temppath ~= "" then
115                         temppath = temppath
116                 end
117                 temppath = temppath .. parts[i]
118         end
119         
120         return temppath
121 end
122
123 --------------------------------------------------------------------------------
124
125 function menu.set_texture(identifier,gamedetails)
126         local texture_set = false
127         if menu.texturepack ~= nil and gamedetails ~= nil then
128                 local path = menu.basetexturedir .. 
129                                                 gamedetails.id .. "_menu_" .. identifier .. ".png"
130                 
131                 if engine.set_background(identifier,path) then
132                         texture_set = true
133                 end
134         end
135         
136         if not texture_set and gamedetails ~= nil then
137                 local path = gamedetails.path .. DIR_DELIM .."menu" .. 
138                                                                          DIR_DELIM .. identifier .. ".png"
139                 if engine.set_background(identifier,path) then
140                         texture_set = true
141                 end
142         end
143         
144         if not texture_set then
145                 local path = menu.basetexturedir .. DIR_DELIM .."menu_" .. 
146                                                                                 identifier .. ".png"
147                 if engine.set_background(identifier,path) then
148                         texture_set = true
149                 end
150         end
151         
152         if not texture_set then
153                 local path = menu.defaulttexturedir .. DIR_DELIM .."menu_" .. 
154                                                                                 identifier .. ".png"
155                 engine.set_background(identifier,path)
156         end
157 end
158
159 --------------------------------------------------------------------------------
160 function menu.update_gametype()
161         
162         
163         
164         if (menu.game_last_check == nil or
165                 menu.game_last_check ~= menu.last_game) and
166                 tabbuilder.current_tab == "singleplayer" then
167                 
168                 local gamedetails = menu.lastgame()
169                 engine.set_topleft_text(gamedetails.name)
170                 filterlist.set_filtercriteria(worldlist,gamedetails.id)
171                 
172                 --background
173                 local background_set = false
174                 if menu.texturepack ~= nil then
175                         local path_background_texture = menu.basetexturedir .. 
176                                                                                 gamedetails.id .. "_menu_background.png"
177                         
178                         if engine.set_background("background",path_background_texture) then
179                                 background_set = true
180                                 engine.set_clouds(false)
181                         end
182                 end
183                 
184                 if not background_set then
185                         local path_background_texture = gamedetails.path .. DIR_DELIM .."menu" .. 
186                                                                                  DIR_DELIM .. "background.png"
187                         if engine.set_background("background",path_background_texture) then
188                                 background_set = true
189                                 engine.set_clouds(false)
190                         end
191                 end
192                 
193                 if not background_set then
194                         engine.set_clouds(true)
195                 end
196                 
197                 menu.set_texture("overlay",gamedetails)
198                 menu.set_texture("header",gamedetails)
199                 menu.set_texture("footer",gamedetails)
200                 
201                 menu.game_last_check = menu.last_game
202         else
203                 if menu.game_last_check ~= menu.last_game then
204                         menu.game_last_check = menu.last_game
205                         menu.reset_gametype()
206                 end
207         end
208 end
209
210 --------------------------------------------------------------------------------
211 function menu.reset_gametype()
212         filterlist.set_filtercriteria(worldlist,nil)
213         menu.game_last_check = nil
214         
215         local path_background_texture = menu.basetexturedir .. "menu_background.png"
216                         
217         if engine.set_background("background",path_background_texture) then
218                 background_set = true
219                 engine.set_clouds(false)
220         else
221                 engine.set_clouds(true)
222         end 
223
224         menu.set_texture("overlay",nil)
225         menu.set_texture("header",nil)
226         menu.set_texture("footer",nil)
227         engine.set_topleft_text("")
228 end
229
230 --------------------------------------------------------------------------------
231 function get_last_folder(text,count)
232         local parts = text:split(DIR_DELIM)
233         
234         if count == nil then
235                 return parts[#parts]
236         end
237         
238         local retval = ""
239         for i=1,count,1 do
240                 retval = retval .. parts[#parts - (count-i)] .. DIR_DELIM
241         end
242         
243         return retval
244 end
245
246 --------------------------------------------------------------------------------
247 function init_globals()
248         --init gamedata
249         gamedata.worldindex = 0
250         
251         worldlist = filterlist.create(
252                                         engine.get_worlds,
253                                         compare_worlds,
254                                         function(element,uid)
255                                                 if element.name == uid then
256                                                         return true
257                                                 end
258                                                 return false
259                                         end, --unique id compare fct
260                                         function(element,gameid)
261                                                 if element.gameid == gameid then
262                                                         return true
263                                                 end
264                                                 return false
265                                         end --filter fct
266                                         )
267                                         
268         filterlist.add_sort_mechanism(worldlist,"alphabetic",sort_worlds_alphabetic)
269         filterlist.set_sortmode(worldlist,"alphabetic")
270                                         
271 end
272
273 --------------------------------------------------------------------------------
274 function identify_filetype(name)
275
276         if name:sub(-3):lower() == "zip" then
277                 return {
278                                 name = name,
279                                 type = "zip"
280                                 }
281         end
282         
283         if name:sub(-6):lower() == "tar.gz" or
284                 name:sub(-3):lower() == "tgz"then
285                 return {
286                                 name = name,
287                                 type = "tgz"
288                                 }
289         end
290         
291         if name:sub(-6):lower() == "tar.bz2" then
292                 return {
293                                 name = name,
294                                 type = "tbz"
295                                 }
296         end
297         
298         if name:sub(-2):lower() == "7z" then
299                 return {
300                                 name = name,
301                                 type = "7z"
302                                 }
303         end
304
305         return {
306                 name = name,
307                 type = "ukn"
308         }
309 end
310
311 --------------------------------------------------------------------------------
312 function update_menu()
313
314         local formspec = "size[12,5.2]"
315         
316         -- handle errors
317         if gamedata.errormessage ~= nil then
318                 formspec = formspec ..
319                         "field[1,2;10,2;;ERROR: " ..
320                         gamedata.errormessage .. 
321                         ";]"..
322                         "button[4.5,4.2;3,0.5;btn_error_confirm;Ok]"
323         else
324                 formspec = formspec .. tabbuilder.gettab()
325         end
326
327         engine.update_formspec(formspec)
328 end
329
330 --------------------------------------------------------------------------------
331 function menu.render_world_list()
332         local retval = ""
333         
334         local current_worldlist = filterlist.get_list(worldlist)
335         
336         for i,v in ipairs(current_worldlist) do
337                 if retval ~= "" then
338                         retval = retval ..","
339                 end
340                 
341                 retval = retval .. v.name .. 
342                                         " \\[" .. v.gameid .. "\\]"
343         end
344
345         return retval
346 end
347
348 --------------------------------------------------------------------------------
349 function menu.init()
350         --init menu data
351         gamemgr.update_gamelist()
352         
353         menu.last_game  = tonumber(engine.setting_get("main_menu_last_game_idx"))
354         
355         if type(menu.last_game) ~= "number" then
356                 menu.last_game = 1
357         end
358
359         if engine.setting_getbool("public_serverlist") then
360                 menu.favorites = engine.get_favorites("online")
361         else
362                 menu.favorites = engine.get_favorites("local")
363         end
364         
365         
366         menu.defaulttexturedir = engine.get_gamepath() .. DIR_DELIM .. ".." ..
367                                                 DIR_DELIM .. "textures" .. DIR_DELIM .. "base" .. 
368                                                 DIR_DELIM .. "pack" .. DIR_DELIM
369         menu.basetexturedir = menu.defaulttexturedir
370         
371         menu.texturepack = engine.setting_get("texture_path")
372         
373         if menu.texturepack ~= nil then
374                 menu.basetexturedir = menu.texturepack .. DIR_DELIM
375         end
376 end
377
378 --------------------------------------------------------------------------------
379 function menu.lastgame()
380         if menu.last_game > 0 and menu.last_game <= #gamemgr.games then
381                 return gamemgr.games[menu.last_game]
382         end
383         
384         if #gamemgr.games >= 1 then
385                 menu.last_game = 1
386                 return gamemgr.games[menu.last_game]
387         end
388         
389         --error case!!
390         return nil
391 end
392
393 --------------------------------------------------------------------------------
394 function menu.update_last_game()
395
396         local current_world = filterlist.get_raw_element(worldlist,
397                                                         engine.setting_get("mainmenu_last_selected_world")
398                                                         )
399                                                         
400         if current_world == nil then
401                 return
402         end
403                 
404         for i=1,#gamemgr.games,1 do             
405                 if gamemgr.games[i].id == current_world.gameid then
406                         menu.last_game = i
407                         engine.setting_set("main_menu_last_game_idx",menu.last_game)
408                         break
409                 end
410         end
411 end
412
413 --------------------------------------------------------------------------------
414 function menu.handle_key_up_down(fields,textlist,settingname)
415
416         if fields["key_up"] then
417                 local oldidx = engine.get_textlist_index(textlist)
418                 
419                 if oldidx > 1 then
420                         local newidx = oldidx -1
421                         engine.setting_set(settingname,
422                                 filterlist.get_engine_index(worldlist,newidx))
423                 end
424         end
425         
426         if fields["key_down"] then
427                 local oldidx = engine.get_textlist_index(textlist)
428                 
429                 if oldidx < filterlist.size(worldlist) then
430                         local newidx = oldidx + 1
431                         engine.setting_set(settingname,
432                                 filterlist.get_engine_index(worldlist,newidx))
433                 end
434         end
435 end
436
437
438 --------------------------------------------------------------------------------
439 function menubar.handle_buttons(fields)
440         for i=1,#menubar.buttons,1 do
441                 if fields[menubar.buttons[i].btn_name] ~= nil then
442                         menu.last_game = menubar.buttons[i].index
443                         engine.setting_set("main_menu_last_game_idx",menu.last_game)
444                         menu.update_gametype()
445                 end
446         end
447 end
448
449 --------------------------------------------------------------------------------
450 function menubar.refresh()
451         menubar.formspec = "box[-0.3,5.625;12.4,1.3;000000]" ..
452                                            "box[-0.3,5.6;12.4,0.05;FFFFFF]"
453         menubar.buttons = {}
454
455         local button_base = -0.25
456         
457         local maxbuttons = #gamemgr.games
458         
459         if maxbuttons > 10 then
460                 maxbuttons = 10
461         end
462         
463         for i=1,maxbuttons,1 do
464
465                 local btn_name = "menubar_btn_" .. gamemgr.games[i].id
466                 local buttonpos = button_base + (i-1) * 1.245
467                 if gamemgr.games[i].menuicon_path ~= nil and
468                         gamemgr.games[i].menuicon_path ~= "" then
469
470                         menubar.formspec = menubar.formspec ..
471                                 "image_button[" .. buttonpos ..  ",5.7;1.3,1.3;"  ..
472                                 gamemgr.games[i].menuicon_path .. ";" .. btn_name .. ";;true;false]"
473                 else
474                 
475                         local part1 = gamemgr.games[i].id:sub(1,5)
476                         local part2 = gamemgr.games[i].id:sub(6,10)
477                         local part3 = gamemgr.games[i].id:sub(11)
478                         
479                         local text = part1 .. "\n" .. part2
480                         if part3 ~= nil and
481                                 part3 ~= "" then
482                                 text = text .. "\n" .. part3
483                         end
484                         menubar.formspec = menubar.formspec ..
485                                 "image_button[" .. buttonpos ..  ",5.7;1.3,1.3;;" ..btn_name ..
486                                 ";" .. text .. ";true;true]"
487                 end
488                 
489                 local toadd = {
490                         btn_name = btn_name,
491                         index = i,
492                 }
493                 
494                 table.insert(menubar.buttons,toadd)
495         end
496 end
497
498 --------------------------------------------------------------------------------
499 function tabbuilder.dialog_create_world()
500         local mapgens = {"v6", "v7", "indev", "singlenode", "math"}
501
502         local current_mg = engine.setting_get("mg_name")
503
504         local mglist = ""
505         local selindex = 1
506         local i = 1
507         for k,v in pairs(mapgens) do
508                 if current_mg == v then
509                         selindex = i
510                 end
511                 i = i + 1
512                 mglist = mglist .. v .. ","
513         end
514         mglist = mglist:sub(1, -2)
515
516         local retval = 
517                 "label[2,0;World name]"..
518                 "label[2,1;Mapgen]"..
519                 "field[4.5,0.4;6,0.5;te_world_name;;]" ..
520                 "label[2,2;Game]"..
521                 "button[5,4.5;2.6,0.5;world_create_confirm;Create]" ..
522                 "button[7.5,4.5;2.8,0.5;world_create_cancel;Cancel]" ..
523                 "dropdown[4.2,1;6.3;dd_mapgen;" .. mglist .. ";" .. selindex .. "]" ..
524                 "textlist[4.2,1.9;5.8,2.3;games;" ..
525                 gamemgr.gamelist() ..
526                 ";" .. menu.last_game .. ";true]"
527
528         return retval
529 end
530
531 --------------------------------------------------------------------------------
532 function tabbuilder.dialog_delete_world()
533         return  "label[2,2;Delete World \"" .. filterlist.get_raw_list(worldlist)[menu.world_to_del].name .. "\"?]"..
534                         "button[3.5,4.2;2.6,0.5;world_delete_confirm;Yes]" ..
535                         "button[6,4.2;2.8,0.5;world_delete_cancel;No]"
536 end
537
538 --------------------------------------------------------------------------------
539 function tabbuilder.gettab()
540         local retval = ""
541         
542         if tabbuilder.show_buttons then
543                 retval = retval .. tabbuilder.tab_header()
544         end
545
546         if tabbuilder.current_tab == "singleplayer" then
547                 retval = retval .. tabbuilder.tab_singleplayer()
548         end
549         
550         if tabbuilder.current_tab == "multiplayer" then
551                 retval = retval .. tabbuilder.tab_multiplayer()
552         end
553
554         if tabbuilder.current_tab == "server" then
555                 retval = retval .. tabbuilder.tab_server()
556         end
557         
558         if tabbuilder.current_tab == "settings" then
559                 retval = retval .. tabbuilder.tab_settings()
560         end
561         
562         if tabbuilder.current_tab == "credits" then
563                 retval = retval .. tabbuilder.tab_credits()
564         end
565         
566         if tabbuilder.current_tab == "dialog_create_world" then
567                 retval = retval .. tabbuilder.dialog_create_world()
568         end
569         
570         if tabbuilder.current_tab == "dialog_delete_world" then
571                 retval = retval .. tabbuilder.dialog_delete_world()
572         end
573         
574         retval = retval .. modmgr.gettab(tabbuilder.current_tab)
575         retval = retval .. gamemgr.gettab(tabbuilder.current_tab)
576         retval = retval .. modstore.gettab(tabbuilder.current_tab)
577
578         return retval
579 end
580
581 --------------------------------------------------------------------------------
582 function tabbuilder.handle_create_world_buttons(fields)
583         
584         if fields["world_create_confirm"] or
585                 fields["key_enter"] then
586                 
587                 local worldname = fields["te_world_name"]
588                 local gameindex = engine.get_textlist_index("games")
589                 
590                 if gameindex > 0 and
591                         worldname ~= "" then
592                         
593                         local message = nil
594                         
595                         if not filterlist.uid_exists(worldlist,worldname) then
596                                 engine.setting_set("mg_name",fields["dd_mapgen"])
597                                 message = engine.create_world(worldname,gameindex)
598                         else
599                                 message = "A world named \"" .. worldname .. "\" already exists"
600                         end
601                         
602                         if message ~= nil then
603                                 gamedata.errormessage = message
604                         else
605                                 menu.last_game = gameindex
606                                 engine.setting_set("main_menu_last_game_idx",gameindex)
607                                 
608                                 filterlist.refresh(worldlist)
609                                 engine.setting_set("mainmenu_last_selected_world",
610                                                                         filterlist.engine_index_by_uid(worldlist,worldname))
611                         end
612                 else
613                         gamedata.errormessage = "No worldname given or no game selected"
614                 end
615         end
616         
617         if fields["games"] then
618                 tabbuilder.skipformupdate = true
619                 return
620         end
621         
622         --close dialog
623         tabbuilder.is_dialog = false
624         tabbuilder.show_buttons = true
625         tabbuilder.current_tab = engine.setting_get("main_menu_tab")
626 end
627
628 --------------------------------------------------------------------------------
629 function tabbuilder.handle_delete_world_buttons(fields)
630         
631         if fields["world_delete_confirm"] then
632                 if menu.world_to_del > 0 and 
633                         menu.world_to_del <= #filterlist.get_raw_list(worldlist) then
634                         engine.delete_world(menu.world_to_del)
635                         menu.world_to_del = 0
636                         filterlist.refresh(worldlist)
637                 end
638         end
639         
640         tabbuilder.is_dialog = false
641         tabbuilder.show_buttons = true
642         tabbuilder.current_tab = engine.setting_get("main_menu_tab")
643 end
644
645 --------------------------------------------------------------------------------
646 function tabbuilder.handle_multiplayer_buttons(fields)
647         
648         if fields["te_name"] ~= nil then
649                 gamedata.playername = fields["te_name"]
650                 engine.setting_set("name", fields["te_name"])
651         end
652         
653         if fields["favourites"] ~= nil then
654                 local event = explode_textlist_event(fields["favourites"])
655                 if event.typ == "DCL" then
656                         gamedata.address = menu.favorites[event.index].address
657                         gamedata.port = menu.favorites[event.index].port
658                         gamedata.playername             = fields["te_name"]
659                         if fields["te_pwd"] ~= nil then
660                                 gamedata.password               = fields["te_pwd"]
661                         end
662                         gamedata.selected_world = 0
663                         
664                         if menu.favorites ~= nil then
665                                 gamedata.servername = menu.favorites[event.index].name
666                                 gamedata.serverdescription = menu.favorites[event.index].description
667                         end
668                         
669                         if gamedata.address ~= nil and
670                                 gamedata.port ~= nil then
671                                 
672                                 engine.start()
673                         end
674                 end
675                 
676                 if event.typ == "CHG" then
677                         local address = menu.favorites[event.index].address
678                         local port = menu.favorites[event.index].port
679                         
680                         if address ~= nil and
681                                 port ~= nil then
682                                 engine.setting_set("address",address)
683                                 engine.setting_set("port",port)
684                         end
685                         
686                         menu.fav_selected = event.index
687                 end
688                 return
689         end
690         
691         if fields["key_up"] ~= nil or
692                 fields["key_down"] ~= nil then
693                 
694                 local fav_idx = engine.get_textlist_index("favourites")
695                 
696                 if fields["key_up"] ~= nil and fav_idx > 1 then
697                         fav_idx = fav_idx -1
698                 else if fields["key_down"] and fav_idx < #menu.favorites then
699                         fav_idx = fav_idx +1
700                 end end
701                 
702                 local address = menu.favorites[fav_idx].address
703                 local port = menu.favorites[fav_idx].port
704                 
705                 if address ~= nil and
706                         port ~= nil then
707                         engine.setting_set("address",address)
708                         engine.setting_set("port",port)
709                 end
710                 
711                 menu.fav_selected = fav_idx
712                 return
713         end
714         
715         if fields["cb_public_serverlist"] ~= nil then
716                 engine.setting_setbool("public_serverlist",
717                         tabbuilder.tobool(fields["cb_public_serverlist"]))
718                         
719                 if engine.setting_getbool("public_serverlist") then
720                         menu.favorites = engine.get_favorites("online")
721                 else
722                         menu.favorites = engine.get_favorites("local")
723                 end
724                 menu.fav_selected = nil
725                 return
726         end
727
728         if fields["btn_delete_favorite"] ~= nil then
729                 local current_favourite = engine.get_textlist_index("favourites")
730                 engine.delete_favorite(current_favourite)
731                 menu.favorites = engine.get_favorites()
732                 menu.fav_selected = nil
733                 
734                 engine.setting_set("address","")
735                 engine.setting_get("port","")
736                 
737                 return
738         end
739
740         if fields["btn_mp_connect"] ~= nil or
741                 fields["key_enter"] then
742                 
743                 gamedata.playername             = fields["te_name"]
744                 gamedata.password               = fields["te_pwd"]
745                 gamedata.address                = fields["te_address"]
746                 gamedata.port                   = fields["te_port"]
747                 
748                 local fav_idx = engine.get_textlist_index("favourites")
749                 
750                 if fav_idx > 0 and fav_idx <= #menu.favorites and
751                         menu.favorites[fav_idx].address == fields["te_address"] and
752                         menu.favorites[fav_idx].port == fields["te_port"] then
753                         
754                         gamedata.servername                     = menu.favorites[fav_idx].name
755                         gamedata.serverdescription      = menu.favorites[fav_idx].description
756                 else
757                         gamedata.servername = ""
758                         gamedata.serverdescription = ""
759                 end
760
761                 gamedata.selected_world = 0
762                 
763                 engine.start()
764                 return
765         end
766 end
767
768 --------------------------------------------------------------------------------
769 function tabbuilder.handle_server_buttons(fields)
770
771         local world_doubleclick = false
772
773         if fields["srv_worlds"] ~= nil then
774                 local event = explode_textlist_event(fields["srv_worlds"])
775                 
776                 if event.typ == "DCL" then
777                         world_doubleclick = true
778                 end
779                 if event.typ == "CHG" then
780                         engine.setting_set("mainmenu_last_selected_world",
781                                 filterlist.get_engine_index(worldlist,engine.get_textlist_index("srv_worlds")))
782                 end
783         end
784         
785         menu.handle_key_up_down(fields,"srv_worlds","mainmenu_last_selected_world")
786         
787         if fields["cb_creative_mode"] then
788                 engine.setting_setbool("creative_mode",tabbuilder.tobool(fields["cb_creative_mode"]))
789         end
790         
791         if fields["cb_enable_damage"] then
792                 engine.setting_setbool("enable_damage",tabbuilder.tobool(fields["cb_enable_damage"]))
793         end
794
795         if fields["cb_server_announce"] then
796                 engine.setting_setbool("server_announce",tabbuilder.tobool(fields["cb_server_announce"]))
797         end
798         
799         if fields["start_server"] ~= nil or
800                 world_doubleclick or
801                 fields["key_enter"] then
802                 local selected = engine.get_textlist_index("srv_worlds")
803                 if selected > 0 then
804                         gamedata.playername             = fields["te_playername"]
805                         gamedata.password               = fields["te_passwd"]
806                         gamedata.port                   = fields["te_serverport"]
807                         gamedata.address                = ""
808                         gamedata.selected_world = filterlist.get_engine_index(worldlist,selected)
809                         
810                         menu.update_last_game(gamedata.selected_world)
811                         engine.start()
812                 end
813         end
814         
815         if fields["world_create"] ~= nil then
816                 tabbuilder.current_tab = "dialog_create_world"
817                 tabbuilder.is_dialog = true
818                 tabbuilder.show_buttons = false
819         end
820         
821         if fields["world_delete"] ~= nil then
822                 local selected = engine.get_textlist_index("srv_worlds")
823                 if selected > 0 and
824                         selected <= filterlist.size(worldlist) then
825                         local world = filterlist.get_list(worldlist)[selected]
826                         if world ~= nil and
827                                 world.name ~= nil and
828                                 world.name ~= "" then
829                                 menu.world_to_del = filterlist.get_engine_index(worldlist,selected)
830                                 tabbuilder.current_tab = "dialog_delete_world"
831                                 tabbuilder.is_dialog = true
832                                 tabbuilder.show_buttons = false
833                         else
834                                 menu.world_to_del = 0
835                         end
836                 end
837         end
838         
839         if fields["world_configure"] ~= nil then
840                 selected = engine.get_textlist_index("srv_worlds")
841                 if selected > 0 then
842                         modmgr.world_config_selected_world = filterlist.get_engine_index(worldlist,selected)
843                         if modmgr.init_worldconfig() then
844                                 tabbuilder.current_tab = "dialog_configure_world"
845                                 tabbuilder.is_dialog = true
846                                 tabbuilder.show_buttons = false
847                         end
848                 end
849         end
850 end
851
852 --------------------------------------------------------------------------------
853 function tabbuilder.tobool(text)
854         if text == "true" then
855                 return true
856         else
857                 return false
858         end
859 end
860
861 --------------------------------------------------------------------------------
862 function tabbuilder.handle_settings_buttons(fields)
863         if fields["cb_fancy_trees"] then
864                 engine.setting_setbool("new_style_leaves",tabbuilder.tobool(fields["cb_fancy_trees"]))
865         end
866                 
867         if fields["cb_smooth_lighting"] then
868                 engine.setting_setbool("smooth_lighting",tabbuilder.tobool(fields["cb_smooth_lighting"]))
869         end
870         if fields["cb_3d_clouds"] then
871                 engine.setting_setbool("enable_3d_clouds",tabbuilder.tobool(fields["cb_3d_clouds"]))
872         end
873         if fields["cb_opaque_water"] then
874                 engine.setting_setbool("opaque_water",tabbuilder.tobool(fields["cb_opaque_water"]))
875         end
876                         
877         if fields["cb_mipmapping"] then
878                 engine.setting_setbool("mip_map",tabbuilder.tobool(fields["cb_mipmapping"]))
879         end
880         if fields["cb_anisotrophic"] then
881                 engine.setting_setbool("anisotropic_filter",tabbuilder.tobool(fields["cb_anisotrophic"]))
882         end
883         if fields["cb_bilinear"] then
884                 engine.setting_setbool("bilinear_filter",tabbuilder.tobool(fields["cb_bilinear"]))
885         end
886         if fields["cb_trilinear"] then
887                 engine.setting_setbool("trilinear_filter",tabbuilder.tobool(fields["cb_trilinear"]))
888         end
889                         
890         if fields["cb_shaders"] then
891                 engine.setting_setbool("enable_shaders",tabbuilder.tobool(fields["cb_shaders"]))
892         end
893         if fields["cb_pre_ivis"] then
894                 engine.setting_setbool("preload_item_visuals",tabbuilder.tobool(fields["cb_pre_ivis"]))
895         end
896         if fields["cb_particles"] then
897                 engine.setting_setbool("enable_particles",tabbuilder.tobool(fields["cb_particles"]))
898         end
899         if fields["cb_finite_liquid"] then
900                 engine.setting_setbool("liquid_finite",tabbuilder.tobool(fields["cb_finite_liquid"]))
901         end
902
903         if fields["btn_change_keys"] ~= nil then
904                 engine.show_keys_menu()
905         end
906 end
907
908 --------------------------------------------------------------------------------
909 function tabbuilder.handle_singleplayer_buttons(fields)
910
911         local world_doubleclick = false
912
913         if fields["sp_worlds"] ~= nil then
914                 local event = explode_textlist_event(fields["sp_worlds"])
915                 
916                 if event.typ == "DCL" then
917                         world_doubleclick = true
918                 end
919                 
920                 if event.typ == "CHG" then
921                         engine.setting_set("mainmenu_last_selected_world",
922                                 filterlist.get_engine_index(worldlist,engine.get_textlist_index("sp_worlds")))
923                 end
924         end
925         
926         menu.handle_key_up_down(fields,"sp_worlds","mainmenu_last_selected_world")
927         
928         if fields["cb_creative_mode"] then
929                 engine.setting_setbool("creative_mode",tabbuilder.tobool(fields["cb_creative_mode"]))
930         end
931         
932         if fields["cb_enable_damage"] then
933                 engine.setting_setbool("enable_damage",tabbuilder.tobool(fields["cb_enable_damage"]))
934         end
935
936         if fields["play"] ~= nil or
937                 world_doubleclick or
938                 fields["key_enter"] then
939                 local selected = engine.get_textlist_index("sp_worlds")
940                 if selected > 0 then
941                         gamedata.selected_world = filterlist.get_engine_index(worldlist,selected)
942                         gamedata.singleplayer   = true
943                         
944                         menu.update_last_game(gamedata.selected_world)
945                         
946                         engine.start()
947                 end
948         end
949         
950         if fields["world_create"] ~= nil then
951                 tabbuilder.current_tab = "dialog_create_world"
952                 tabbuilder.is_dialog = true
953                 tabbuilder.show_buttons = false
954         end
955         
956         if fields["world_delete"] ~= nil then
957                 local selected = engine.get_textlist_index("sp_worlds")
958                 if selected > 0 and
959                         selected <= filterlist.size(worldlist) then
960                         local world = filterlist.get_list(worldlist)[selected]
961                         if world ~= nil and
962                                 world.name ~= nil and
963                                 world.name ~= "" then
964                                 menu.world_to_del = filterlist.get_engine_index(worldlist,selected)
965                                 tabbuilder.current_tab = "dialog_delete_world"
966                                 tabbuilder.is_dialog = true
967                                 tabbuilder.show_buttons = false
968                         else
969                                 menu.world_to_del = 0
970                         end
971                 end
972         end
973         
974         if fields["world_configure"] ~= nil then
975                 selected = engine.get_textlist_index("sp_worlds")
976                 if selected > 0 then
977                         modmgr.world_config_selected_world = filterlist.get_engine_index(worldlist,selected)
978                         if modmgr.init_worldconfig() then
979                                 tabbuilder.current_tab = "dialog_configure_world"
980                                 tabbuilder.is_dialog = true
981                                 tabbuilder.show_buttons = false
982                         end
983                 end
984         end
985 end
986
987 --------------------------------------------------------------------------------
988 function tabbuilder.tab_header()
989
990         if tabbuilder.last_tab_index == nil then
991                 tabbuilder.last_tab_index = 1
992         end
993         
994         local toadd = ""
995         
996         for i=1,#tabbuilder.current_buttons,1 do
997                 
998                 if toadd ~= "" then
999                         toadd = toadd .. ","
1000                 end
1001                 
1002                 toadd = toadd .. tabbuilder.current_buttons[i].caption
1003         end
1004         return "tabheader[-0.3,-0.99;main_tab;" .. toadd ..";" .. tabbuilder.last_tab_index .. ";true;false]"
1005 end
1006
1007 --------------------------------------------------------------------------------
1008 function tabbuilder.handle_tab_buttons(fields)
1009
1010         if fields["main_tab"] then
1011                 local index = tonumber(fields["main_tab"])
1012                 tabbuilder.last_tab_index = index
1013                 tabbuilder.current_tab = tabbuilder.current_buttons[index].name
1014                 
1015                 engine.setting_set("main_menu_tab",tabbuilder.current_tab)
1016         end
1017         
1018         --handle tab changes
1019         if tabbuilder.current_tab ~= tabbuilder.old_tab then
1020                 if tabbuilder.current_tab ~= "singleplayer" then
1021                         menu.reset_gametype()
1022                 end
1023         end
1024         
1025         if tabbuilder.current_tab == "singleplayer" then
1026                 menu.update_gametype()
1027         end
1028         
1029         tabbuilder.old_tab = tabbuilder.current_tab
1030 end
1031
1032 --------------------------------------------------------------------------------
1033 function tabbuilder.init()
1034         tabbuilder.current_tab = engine.setting_get("main_menu_tab")
1035         
1036         if tabbuilder.current_tab == nil or
1037                 tabbuilder.current_tab == "" then
1038                 tabbuilder.current_tab = "singleplayer"
1039                 engine.setting_set("main_menu_tab",tabbuilder.current_tab)
1040         end
1041         
1042         
1043         --initialize tab buttons
1044         tabbuilder.last_tab = nil
1045         tabbuilder.show_buttons = true
1046         
1047         tabbuilder.current_buttons = {}
1048         table.insert(tabbuilder.current_buttons,{name="singleplayer", caption="Singleplayer"})
1049         table.insert(tabbuilder.current_buttons,{name="multiplayer", caption="Client"})
1050         table.insert(tabbuilder.current_buttons,{name="server", caption="Server"})
1051         table.insert(tabbuilder.current_buttons,{name="settings", caption="Settings"})
1052         
1053         if engine.setting_getbool("main_menu_game_mgr") then
1054                 table.insert(tabbuilder.current_buttons,{name="game_mgr", caption="Games"})
1055         end
1056         
1057         if engine.setting_getbool("main_menu_mod_mgr") then
1058                 table.insert(tabbuilder.current_buttons,{name="mod_mgr", caption="Mods"})
1059         end
1060         table.insert(tabbuilder.current_buttons,{name="credits", caption="Credits"})
1061         
1062         
1063         for i=1,#tabbuilder.current_buttons,1 do
1064                 if tabbuilder.current_buttons[i].name == tabbuilder.current_tab then
1065                         tabbuilder.last_tab_index = i
1066                 end
1067         end
1068         
1069         menu.update_gametype()
1070 end
1071
1072 --------------------------------------------------------------------------------
1073 function tabbuilder.tab_multiplayer()
1074
1075         local retval =
1076                 "vertlabel[0,-0.25;CLIENT]" ..
1077                 "label[1,-0.25;Favorites:]"..
1078                 "label[1,4.25;Address/Port]"..
1079                 "label[9,2.75;Name/Password]" ..
1080                 "field[1.25,5.25;5.5,0.5;te_address;;" ..engine.setting_get("address") .."]" ..
1081                 "field[6.75,5.25;2.25,0.5;te_port;;" ..engine.setting_get("port") .."]" ..
1082                 "checkbox[1,3.6;cb_public_serverlist;Public Serverlist;" ..
1083                 dump(engine.setting_getbool("public_serverlist")) .. "]"
1084                 
1085         if not engine.setting_getbool("public_serverlist") then
1086                 retval = retval .. 
1087                 "button[6.45,3.95;2.25,0.5;btn_delete_favorite;Delete]"
1088         end
1089         
1090         retval = retval ..
1091                 "button[9,4.95;2.5,0.5;btn_mp_connect;Connect]" ..
1092                 "field[9.3,3.75;2.5,0.5;te_name;;" ..engine.setting_get("name") .."]" ..
1093                 "pwdfield[9.3,4.5;2.5,0.5;te_pwd;]" ..
1094                 "textarea[9.3,0.25;2.5,2.75;;"
1095         if menu.fav_selected ~= nil and 
1096                 menu.favorites[menu.fav_selected].description ~= nil then
1097                 retval = retval .. 
1098                         fs_escape_string(menu.favorites[menu.fav_selected].description,true)
1099         end
1100         
1101         retval = retval .. 
1102                 ";]" ..
1103                 "textlist[1,0.35;7.5,3.35;favourites;"
1104
1105         local render_details = engine.setting_getbool("public_serverlist")
1106
1107         if #menu.favorites > 0 then
1108                 retval = retval .. render_favourite(menu.favorites[1],render_details)
1109                 
1110                 for i=2,#menu.favorites,1 do
1111                         retval = retval .. "," .. render_favourite(menu.favorites[i],render_details)
1112                 end
1113         end
1114
1115         if menu.fav_selected ~= nil then
1116                 retval = retval .. ";" .. menu.fav_selected .. "]"
1117         else
1118                 retval = retval .. ";0]"
1119         end
1120
1121         return retval
1122 end
1123
1124 --------------------------------------------------------------------------------
1125 function tabbuilder.tab_server()
1126
1127         local index = filterlist.get_current_index(worldlist,
1128                                 tonumber(engine.setting_get("mainmenu_last_selected_world"))
1129                                 )
1130         
1131         local retval = 
1132                 "button[4,4.15;2.6,0.5;world_delete;Delete]" ..
1133                 "button[6.5,4.15;2.8,0.5;world_create;New]" ..
1134                 "button[9.2,4.15;2.55,0.5;world_configure;Configure]" ..
1135                 "button[8.5,4.9;3.25,0.5;start_server;Start Game]" ..
1136                 "label[4,-0.25;Select World:]"..
1137                 "vertlabel[0,-0.25;START SERVER]" ..
1138                 "checkbox[0.5,0.25;cb_creative_mode;Creative Mode;" ..
1139                 dump(engine.setting_getbool("creative_mode")) .. "]"..
1140                 "checkbox[0.5,0.7;cb_enable_damage;Enable Damage;" ..
1141                 dump(engine.setting_getbool("enable_damage")) .. "]"..
1142                 "checkbox[0.5,1.15;cb_server_announce;Public;" ..
1143                 dump(engine.setting_getbool("server_announce")) .. "]"..
1144                 "field[0.8,3.2;3,0.5;te_playername;Name;" ..
1145                 engine.setting_get("name") .. "]" ..
1146                 "pwdfield[0.8,4.2;3,0.5;te_passwd;Password]" ..
1147                 "field[0.8,5.2;3,0.5;te_serverport;Server Port;30000]" ..
1148                 "textlist[4,0.25;7.5,3.7;srv_worlds;" ..
1149                 menu.render_world_list() ..
1150                 ";" .. index .. "]"
1151                 
1152         return retval
1153 end
1154
1155 --------------------------------------------------------------------------------
1156 function tabbuilder.tab_settings()
1157         return  "vertlabel[0,0;SETTINGS]" ..
1158                         "checkbox[1,0.75;cb_fancy_trees;Fancy trees;"           .. dump(engine.setting_getbool("new_style_leaves"))     .. "]"..
1159                         "checkbox[1,1.25;cb_smooth_lighting;Smooth Lighting;".. dump(engine.setting_getbool("smooth_lighting")) .. "]"..
1160                         "checkbox[1,1.75;cb_3d_clouds;3D Clouds;"                       .. dump(engine.setting_getbool("enable_3d_clouds"))     .. "]"..
1161                         "checkbox[1,2.25;cb_opaque_water;Opaque Water;"                 .. dump(engine.setting_getbool("opaque_water"))         .. "]"..
1162                         
1163                         "checkbox[4,0.75;cb_mipmapping;Mip-Mapping;"            .. dump(engine.setting_getbool("mip_map"))                      .. "]"..
1164                         "checkbox[4,1.25;cb_anisotrophic;Anisotropic Filtering;".. dump(engine.setting_getbool("anisotropic_filter"))   .. "]"..
1165                         "checkbox[4,1.75;cb_bilinear;Bi-Linear Filtering;"      .. dump(engine.setting_getbool("bilinear_filter"))      .. "]"..
1166                         "checkbox[4,2.25;cb_trilinear;Tri-Linear Filtering;"    .. dump(engine.setting_getbool("trilinear_filter"))     .. "]"..
1167                         
1168                         "checkbox[7.5,0.75;cb_shaders;Shaders;"                         .. dump(engine.setting_getbool("enable_shaders"))               .. "]"..
1169                         "checkbox[7.5,1.25;cb_pre_ivis;Preload item visuals;".. dump(engine.setting_getbool("preload_item_visuals"))    .. "]"..
1170                         "checkbox[7.5,1.75;cb_particles;Enable Particles;"      .. dump(engine.setting_getbool("enable_particles"))     .. "]"..
1171                         "checkbox[7.5,2.25;cb_finite_liquid;Finite Liquid;"     .. dump(engine.setting_getbool("liquid_finite"))                .. "]"..
1172                         
1173                         "button[1,3.75;2.25,0.5;btn_change_keys;Change keys]"
1174 end
1175
1176 --------------------------------------------------------------------------------
1177 function tabbuilder.tab_singleplayer()
1178         
1179         local index = filterlist.get_current_index(worldlist,
1180                                 tonumber(engine.setting_get("mainmenu_last_selected_world"))
1181                                 )
1182
1183         return  "button[4,4.15;2.6,0.5;world_delete;Delete]" ..
1184                         "button[6.5,4.15;2.8,0.5;world_create;New]" ..
1185                         "button[9.2,4.15;2.55,0.5;world_configure;Configure]" ..
1186                         "button[8.5,4.95;3.25,0.5;play;Play]" ..
1187                         "label[4,-0.25;Select World:]"..
1188                         "vertlabel[0,-0.25;SINGLE PLAYER]" ..
1189                         "checkbox[0.5,0.25;cb_creative_mode;Creative Mode;" ..
1190                         dump(engine.setting_getbool("creative_mode")) .. "]"..
1191                         "checkbox[0.5,0.7;cb_enable_damage;Enable Damage;" ..
1192                         dump(engine.setting_getbool("enable_damage")) .. "]"..
1193                         "textlist[4,0.25;7.5,3.7;sp_worlds;" ..
1194                         menu.render_world_list() ..
1195                         ";" .. index .. "]" ..
1196                         menubar.formspec
1197 end
1198
1199 --------------------------------------------------------------------------------
1200 function tabbuilder.tab_credits()
1201         return  "vertlabel[0,-0.5;CREDITS]" ..
1202                         "label[0.5,3;Minetest " .. engine.get_version() .. "]" ..
1203                         "label[0.5,3.3;http://minetest.net]" .. 
1204                         "image[0.5,1;" .. menu.defaulttexturedir .. "logo.png]" ..
1205                         "textlist[3.5,-0.25;8.5,5.8;list_credits;" ..
1206                         "#FFFF00Core Developers," ..
1207                         "Perttu Ahola (celeron55) <celeron55@gmail.com>,"..
1208                         "Ryan Kwolek (kwolekr) <kwolekr@minetest.net>,"..
1209                         "PilzAdam <pilzadam@minetest.net>," ..
1210                         "IIya Zhuravlev (thexyz) <xyz@minetest.net>,"..
1211                         "Lisa Milne (darkrose) <lisa@ltmnet.com>,"..
1212                         "Maciej Kasatkin (RealBadAngel) <mk@realbadangel.pl>,"..
1213                         "proller <proler@gmail.com>,"..
1214                         "sfan5 <sfan5@live.de>,"..
1215                         "kahrl <kahrl@gmx.net>,"..
1216                         ","..
1217                         "#FFFF00Active Contributors," ..
1218                         "sapier,"..
1219                         "Vanessa Ezekowitz (VanessaE) <vanessaezekowitz@gmail.com>,"..
1220                         "Jurgen Doser (doserj) <jurgen.doser@gmail.com>,"..
1221                         "Jeija <jeija@mesecons.net>,"..
1222                         "MirceaKitsune <mirceakitsune@gmail.com>,"..
1223                         "ShadowNinja,"..
1224                         "dannydark <the_skeleton_of_a_child@yahoo.co.uk>,"..
1225                         "0gb.us <0gb.us@0gb.us>,"..
1226                         "," ..
1227                         "#FFFF00Previous Contributors," ..
1228                         "Guiseppe Bilotta (Oblomov) <guiseppe.bilotta@gmail.com>,"..
1229                         "Jonathan Neuschafer <j.neuschaefer@gmx.net>,"..
1230                         "Nils Dagsson Moskopp (erlehmann) <nils@dieweltistgarnichtso.net>,"..
1231                         "Constantin Wenger (SpeedProg) <constantin.wenger@googlemail.com>,"..
1232                         "matttpt <matttpt@gmail.com>,"..
1233                         "JacobF <queatz@gmail.com>,"..
1234                         ";0;true]"
1235 end
1236
1237 --------------------------------------------------------------------------------
1238 function tabbuilder.checkretval(retval)
1239
1240         if retval ~= nil then
1241                 if retval.current_tab ~= nil then
1242                         tabbuilder.current_tab = retval.current_tab
1243                 end
1244                 
1245                 if retval.is_dialog ~= nil then
1246                         tabbuilder.is_dialog = retval.is_dialog
1247                 end
1248                 
1249                 if retval.show_buttons ~= nil then
1250                         tabbuilder.show_buttons = retval.show_buttons
1251                 end
1252                 
1253                 if retval.skipformupdate ~= nil then
1254                         tabbuilder.skipformupdate = retval.skipformupdate
1255                 end
1256         end
1257 end
1258
1259 --------------------------------------------------------------------------------
1260 --------------------------------------------------------------------------------
1261 -- initialize callbacks
1262 --------------------------------------------------------------------------------
1263 --------------------------------------------------------------------------------
1264 engine.button_handler = function(fields)
1265         --print("Buttonhandler: tab: " .. tabbuilder.current_tab .. " fields: " .. dump(fields))
1266         
1267         if fields["btn_error_confirm"] then
1268                 gamedata.errormessage = nil
1269         end
1270         
1271         local retval = modmgr.handle_buttons(tabbuilder.current_tab,fields)
1272         tabbuilder.checkretval(retval)
1273         
1274         retval = gamemgr.handle_buttons(tabbuilder.current_tab,fields)
1275         tabbuilder.checkretval(retval)
1276         
1277         retval = modstore.handle_buttons(tabbuilder.current_tab,fields)
1278         tabbuilder.checkretval(retval)
1279         
1280         if tabbuilder.current_tab == "dialog_create_world" then
1281                 tabbuilder.handle_create_world_buttons(fields)
1282         end
1283         
1284         if tabbuilder.current_tab == "dialog_delete_world" then
1285                 tabbuilder.handle_delete_world_buttons(fields)
1286         end
1287         
1288         if tabbuilder.current_tab == "singleplayer" then
1289                 tabbuilder.handle_singleplayer_buttons(fields)
1290         end
1291         
1292         if tabbuilder.current_tab == "multiplayer" then
1293                 tabbuilder.handle_multiplayer_buttons(fields)
1294         end
1295         
1296         if tabbuilder.current_tab == "settings" then
1297                 tabbuilder.handle_settings_buttons(fields)
1298         end
1299         
1300         if tabbuilder.current_tab == "server" then
1301                 tabbuilder.handle_server_buttons(fields)
1302         end
1303         
1304         --tab buttons
1305         tabbuilder.handle_tab_buttons(fields)
1306         
1307         --menubar buttons
1308         menubar.handle_buttons(fields)
1309         
1310         if not tabbuilder.skipformupdate then
1311                 --update menu
1312                 update_menu()
1313         else
1314                 tabbuilder.skipformupdate = false
1315         end
1316 end
1317
1318 --------------------------------------------------------------------------------
1319 engine.event_handler = function(event)
1320         if event == "MenuQuit" then
1321                 if tabbuilder.is_dialog then
1322                         tabbuilder.is_dialog = false
1323                         tabbuilder.show_buttons = true
1324                         tabbuilder.current_tab = engine.setting_get("main_menu_tab")
1325                         menu.update_gametype()
1326                         update_menu()
1327                 else
1328                         engine.close()
1329                 end
1330         end
1331 end
1332
1333 --------------------------------------------------------------------------------
1334 --------------------------------------------------------------------------------
1335 -- menu startup
1336 --------------------------------------------------------------------------------
1337 --------------------------------------------------------------------------------
1338 init_globals()
1339 menu.init()
1340 tabbuilder.init()
1341 menubar.refresh()
1342 modstore.init()
1343
1344 update_menu()