]> icculus.org git repositories - icculus/iodoom3.git/blob - neo/framework/Session_menu.cpp
hello world
[icculus/iodoom3.git] / neo / framework / Session_menu.cpp
1 /*
2 ===========================================================================
3
4 Doom 3 GPL Source Code
5 Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company. 
6
7 This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?).  
8
9 Doom 3 Source Code is free software: you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation, either version 3 of the License, or
12 (at your option) any later version.
13
14 Doom 3 Source Code is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 GNU General Public License for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with Doom 3 Source Code.  If not, see <http://www.gnu.org/licenses/>.
21
22 In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code.  If not, please request a copy in writing from id Software at the address below.
23
24 If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
25
26 ===========================================================================
27 */
28
29 #include "../idlib/precompiled.h"
30 #pragma hdrstop
31
32 #include "Session_local.h"
33
34 idCVar  idSessionLocal::gui_configServerRate( "gui_configServerRate", "0", CVAR_GUI | CVAR_ARCHIVE | CVAR_ROM | CVAR_INTEGER, "" );
35
36 // implements the setup for, and commands from, the main menu
37
38 /*
39 ==============
40 idSessionLocal::GetActiveMenu
41 ==============
42 */
43 idUserInterface *idSessionLocal::GetActiveMenu( void ) {
44         return guiActive;
45 }
46
47 /*
48 ==============
49 idSessionLocal::StartMainMenu
50 ==============
51 */
52 void idSessionLocal::StartMenu( bool playIntro ) {
53         if ( guiActive == guiMainMenu ) {
54                 return;
55         }
56
57         if ( readDemo ) {
58                 // if we're playing a demo, esc kills it
59                 UnloadMap();
60         }
61
62         // pause the game sound world
63         if ( sw != NULL && !sw->IsPaused() ) {
64                 sw->Pause();
65         }
66
67         // start playing the menu sounds
68         soundSystem->SetPlayingSoundWorld( menuSoundWorld );
69
70         SetGUI( guiMainMenu, NULL );
71         guiMainMenu->HandleNamedEvent( playIntro ? "playIntro" : "noIntro" );
72
73
74         if(fileSystem->HasD3XP()) {
75                 guiMainMenu->SetStateString("game_list", common->GetLanguageDict()->GetString( "#str_07202" ));
76         } else {
77                 guiMainMenu->SetStateString("game_list", common->GetLanguageDict()->GetString( "#str_07212" ));
78         }
79
80         console->Close();
81
82 }
83
84 /*
85 =================
86 idSessionLocal::SetGUI
87 =================
88 */
89 void idSessionLocal::SetGUI( idUserInterface *gui, HandleGuiCommand_t handle ) {
90         const char      *cmd;
91
92         guiActive = gui;
93         guiHandle = handle;
94         if ( guiMsgRestore ) {
95                 common->DPrintf( "idSessionLocal::SetGUI: cleared an active message box\n" );
96                 guiMsgRestore = NULL;
97         }
98         if ( !guiActive ) {
99                 return;
100         }
101
102         if ( guiActive == guiMainMenu ) {
103                 SetSaveGameGuiVars();
104                 SetMainMenuGuiVars();
105         } else if ( guiActive == guiRestartMenu ) {
106                 SetSaveGameGuiVars();
107         }
108
109         sysEvent_t  ev;
110         memset( &ev, 0, sizeof( ev ) );
111         ev.evType = SE_NONE;
112
113         cmd = guiActive->HandleEvent( &ev, com_frameTime );
114         guiActive->Activate( true, com_frameTime );
115 }
116
117 /*
118 ===============
119 idSessionLocal::ExitMenu
120 ===============
121 */
122 void idSessionLocal::ExitMenu( void ) {
123         guiActive = NULL;
124
125         // go back to the game sounds
126         soundSystem->SetPlayingSoundWorld( sw );
127
128         // unpause the game sound world
129         if ( sw != NULL && sw->IsPaused() ) {
130                 sw->UnPause();
131         }
132 }
133
134 /*
135 ===============
136 idListSaveGameCompare
137 ===============
138 */
139 ID_INLINE int idListSaveGameCompare( const fileTIME_T *a, const fileTIME_T *b ) {
140         return b->timeStamp - a->timeStamp;
141 }
142
143 /*
144 ===============
145 idSessionLocal::GetSaveGameList
146 ===============
147 */
148 void idSessionLocal::GetSaveGameList( idStrList &fileList, idList<fileTIME_T> &fileTimes ) {
149         int i;
150         idFileList *files;
151
152         // NOTE: no fs_game_base for savegames
153         idStr game = cvarSystem->GetCVarString( "fs_game" );
154         if( game.Length() ) {
155                 files = fileSystem->ListFiles( "savegames", ".save", false, false, game );
156         } else {
157                 files = fileSystem->ListFiles( "savegames", ".save" );
158         }
159         
160         fileList = files->GetList();
161         fileSystem->FreeFileList( files );
162
163         for ( i = 0; i < fileList.Num(); i++ ) {
164                 ID_TIME_T timeStamp;
165
166                 fileSystem->ReadFile( "savegames/" + fileList[i], NULL, &timeStamp );
167                 fileList[i].StripLeading( '/' );
168                 fileList[i].StripFileExtension();
169
170                 fileTIME_T ft;
171                 ft.index = i;
172                 ft.timeStamp = timeStamp;
173                 fileTimes.Append( ft );
174         }
175
176         fileTimes.Sort( idListSaveGameCompare );
177 }
178
179 /*
180 ===============
181 idSessionLocal::SetSaveGameGuiVars
182 ===============
183 */
184 void idSessionLocal::SetSaveGameGuiVars( void ) {
185         int i;
186         idStr name;
187         idStrList fileList;
188         idList<fileTIME_T> fileTimes;
189
190         loadGameList.Clear();
191         fileList.Clear();
192         fileTimes.Clear();
193
194         GetSaveGameList( fileList, fileTimes );
195
196         loadGameList.SetNum( fileList.Num() );
197         for ( i = 0; i < fileList.Num(); i++ ) {
198                 loadGameList[i] = fileList[fileTimes[i].index];
199
200                 idLexer src(LEXFL_NOERRORS|LEXFL_NOSTRINGCONCAT);
201                 if ( src.LoadFile( va("savegames/%s.txt", loadGameList[i].c_str()) ) ) {
202                         idToken tok;
203                         src.ReadToken( &tok );
204                         name = tok;
205                 } else {
206                         name = loadGameList[i];
207                 }
208
209                 name += "\t";
210
211                 idStr date = Sys_TimeStampToStr( fileTimes[i].timeStamp );
212                 name += date;
213
214                 guiActive->SetStateString( va("loadgame_item_%i", i), name);
215         }
216         guiActive->DeleteStateVar( va("loadgame_item_%i", fileList.Num()) );
217
218         guiActive->SetStateString( "loadgame_sel_0", "-1" );
219         guiActive->SetStateString( "loadgame_shot", "guis/assets/blankLevelShot" );
220
221 }
222
223 /*
224 ===============
225 idSessionLocal::SetModsMenuGuiVars
226 ===============
227 */
228 void idSessionLocal::SetModsMenuGuiVars( void ) {
229         int i;
230         idModList *list = fileSystem->ListMods();
231
232         modsList.SetNum( list->GetNumMods() );
233
234         // Build the gui list
235         for ( i = 0; i < list->GetNumMods(); i++ ) {
236                 guiActive->SetStateString( va("modsList_item_%i", i), list->GetDescription( i ) );
237                 modsList[i] = list->GetMod( i );
238         }
239         guiActive->DeleteStateVar( va("modsList_item_%i", list->GetNumMods()) );
240         guiActive->SetStateString( "modsList_sel_0", "-1" );
241
242         fileSystem->FreeModList( list );
243 }
244
245
246 /*
247 ===============
248 idSessionLocal::SetMainMenuSkin
249 ===============
250 */
251 void idSessionLocal::SetMainMenuSkin( void ) {
252         // skins
253         idStr str = cvarSystem->GetCVarString( "mod_validSkins" );
254         idStr uiSkin = cvarSystem->GetCVarString( "ui_skin" );
255         idStr skin;
256         int skinId = 1;
257         int count = 1;
258         while ( str.Length() ) {
259                 int n = str.Find( ";" );
260                 if ( n >= 0 ) {
261                         skin = str.Left( n );
262                         str = str.Right( str.Length() - n - 1 );
263                 } else {
264                         skin = str;
265                         str = "";
266                 }
267                 if ( skin.Icmp( uiSkin ) == 0 ) {
268                         skinId = count;
269                 }
270                 count++;
271         }
272
273         for ( int i = 0; i < count; i++ ) {
274                 guiMainMenu->SetStateInt( va( "skin%i", i+1 ), 0 );
275         }
276         guiMainMenu->SetStateInt( va( "skin%i", skinId ), 1 );
277 }
278
279 /*
280 ===============
281 idSessionLocal::SetPbMenuGuiVars
282 ===============
283 */
284 void idSessionLocal::SetPbMenuGuiVars( void ) {
285 }
286
287 /*
288 ===============
289 idSessionLocal::SetMainMenuGuiVars
290 ===============
291 */
292 void idSessionLocal::SetMainMenuGuiVars( void ) {
293
294         guiMainMenu->SetStateString( "serverlist_sel_0", "-1" );
295         guiMainMenu->SetStateString( "serverlist_selid_0", "-1" ); 
296
297         guiMainMenu->SetStateInt( "com_machineSpec", com_machineSpec.GetInteger() );
298
299         // "inetGame" will hold a hand-typed inet address, which is not archived to a cvar
300         guiMainMenu->SetStateString( "inetGame", "" );
301
302         // key bind names
303         guiMainMenu->SetKeyBindingNames();
304
305         // flag for in-game menu
306         if ( mapSpawned ) {
307                 guiMainMenu->SetStateString( "inGame", IsMultiplayer() ? "2" : "1" );
308         } else {
309                 guiMainMenu->SetStateString( "inGame", "0" );
310         }
311
312         SetCDKeyGuiVars( );
313 #ifdef ID_DEMO_BUILD
314         guiMainMenu->SetStateString( "nightmare", "0" );
315 #else
316         guiMainMenu->SetStateString( "nightmare", cvarSystem->GetCVarBool( "g_nightmare" ) ? "1" : "0" );
317 #endif
318         guiMainMenu->SetStateString( "browser_levelshot", "guis/assets/splash/pdtempa" );
319
320         SetMainMenuSkin();
321         // Mods Menu
322         SetModsMenuGuiVars();
323
324         guiMsg->SetStateString( "visible_hasxp", fileSystem->HasD3XP() ? "1" : "0" );
325
326 #if defined( __linux__ )
327         guiMainMenu->SetStateString( "driver_prompt", "1" );
328 #else
329         guiMainMenu->SetStateString( "driver_prompt", "0" );
330 #endif
331
332         SetPbMenuGuiVars();
333 }
334
335 /*
336 ==============
337 idSessionLocal::HandleSaveGameMenuCommands
338 ==============
339 */
340 bool idSessionLocal::HandleSaveGameMenuCommand( idCmdArgs &args, int &icmd ) {
341
342         const char *cmd = args.Argv(icmd-1);
343
344         if ( !idStr::Icmp( cmd, "loadGame" ) ) {
345                 int choice = guiActive->State().GetInt("loadgame_sel_0");
346                 if ( choice >= 0 && choice < loadGameList.Num() ) {
347                         sessLocal.LoadGame( loadGameList[choice] );
348                 }
349                 return true;
350         }
351
352         if ( !idStr::Icmp( cmd, "saveGame" ) ) {
353                 const char *saveGameName = guiActive->State().GetString("saveGameName");
354                 if ( saveGameName && saveGameName[0] ) {
355
356                         // First see if the file already exists unless they pass '1' to authorize the overwrite
357                         if ( icmd == args.Argc() || atoi(args.Argv( icmd++ )) == 0 ) {
358                                 idStr saveFileName = saveGameName;
359                                 sessLocal.ScrubSaveGameFileName( saveFileName );
360                                 saveFileName = "savegames/" + saveFileName;
361                                 saveFileName.SetFileExtension(".save");
362
363                                 idStr game = cvarSystem->GetCVarString( "fs_game" );
364                                 idFile *file;
365                                 if(game.Length()) {
366                                         file = fileSystem->OpenFileRead( saveFileName, true, game );
367                                 } else {
368                                         file = fileSystem->OpenFileRead( saveFileName );
369                                 }
370                                 
371                                 if ( file != NULL ) {
372                                         fileSystem->CloseFile( file );
373
374                                         // The file exists, see if it's an autosave
375                                         saveFileName.SetFileExtension(".txt");
376                                         idLexer src(LEXFL_NOERRORS|LEXFL_NOSTRINGCONCAT);
377                                         if ( src.LoadFile( saveFileName ) ) {
378                                                 idToken tok;
379                                                 src.ReadToken( &tok ); // Name
380                                                 src.ReadToken( &tok ); // Map
381                                                 src.ReadToken( &tok ); // Screenshot
382                                                 if ( !tok.IsEmpty() ) {
383                                                         // NOTE: base/ gui doesn't handle that one
384                                                         guiActive->HandleNamedEvent( "autosaveOverwriteError" );
385                                                         return true;
386                                                 }
387                                         }
388                                         guiActive->HandleNamedEvent( "saveGameOverwrite" );
389                                         return true;
390                                 }
391                         }
392
393                         sessLocal.SaveGame( saveGameName );
394                         SetSaveGameGuiVars( );
395                         guiActive->StateChanged( com_frameTime );
396                 }
397                 return true;
398         }
399
400         if ( !idStr::Icmp( cmd, "deleteGame" ) ) {
401                 int choice = guiActive->State().GetInt( "loadgame_sel_0" );
402                 if ( choice >= 0 && choice < loadGameList.Num() ) {
403                         fileSystem->RemoveFile( va("savegames/%s.save", loadGameList[choice].c_str()) );
404                         fileSystem->RemoveFile( va("savegames/%s.tga", loadGameList[choice].c_str()) );
405                         fileSystem->RemoveFile( va("savegames/%s.txt", loadGameList[choice].c_str()) );
406                         SetSaveGameGuiVars( );
407                         guiActive->StateChanged( com_frameTime );
408                 }
409                 return true;
410         }
411
412         if ( !idStr::Icmp( cmd, "updateSaveGameInfo" ) ) {
413                 int choice = guiActive->State().GetInt( "loadgame_sel_0" );
414                 if ( choice >= 0 && choice < loadGameList.Num() ) {
415                         const idMaterial *material;
416
417                         idStr saveName, description, screenshot;
418                         idLexer src(LEXFL_NOERRORS|LEXFL_NOSTRINGCONCAT);
419                         if ( src.LoadFile( va("savegames/%s.txt", loadGameList[choice].c_str()) ) ) {
420                                 idToken tok;
421
422                                 src.ReadToken( &tok );
423                                 saveName = tok;
424
425                                 src.ReadToken( &tok );
426                                 description = tok;
427
428                                 src.ReadToken( &tok );
429                                 screenshot = tok;
430
431                         } else {
432                                 saveName = loadGameList[choice];
433                                 description = loadGameList[choice];
434                                 screenshot = "";
435                         }
436                         if ( screenshot.Length() == 0 ) {
437                                 screenshot = va("savegames/%s.tga", loadGameList[choice].c_str());
438                         }
439                         material = declManager->FindMaterial( screenshot );
440                         if ( material ) {
441                                 material->ReloadImages( false );
442                         }
443                         guiActive->SetStateString( "loadgame_shot",  screenshot );
444
445                         saveName.RemoveColors();
446                         guiActive->SetStateString( "saveGameName", saveName );
447                         guiActive->SetStateString( "saveGameDescription", description );
448
449                         ID_TIME_T timeStamp;
450                         fileSystem->ReadFile( va("savegames/%s.save", loadGameList[choice].c_str()), NULL, &timeStamp );
451                         idStr date = Sys_TimeStampToStr(timeStamp);
452                         int tab = date.Find( '\t' );
453                         idStr time = date.Right( date.Length() - tab - 1);
454                         guiActive->SetStateString( "saveGameDate", date.Left( tab ) );
455                         guiActive->SetStateString( "saveGameTime", time );
456                 }
457                 return true;
458         }
459
460         return false;
461 }
462
463 /*
464 ==============
465 idSessionLocal::HandleRestartMenuCommands
466
467 Executes any commands returned by the gui
468 ==============
469 */
470 void idSessionLocal::HandleRestartMenuCommands( const char *menuCommand ) {
471         // execute the command from the menu
472         int icmd;
473         idCmdArgs args;
474
475         args.TokenizeString( menuCommand, false );
476
477         for( icmd = 0; icmd < args.Argc(); ) {
478                 const char *cmd = args.Argv( icmd++ );
479
480                 if ( HandleSaveGameMenuCommand( args, icmd ) ) {
481                         continue;
482                 }
483
484                 if ( !idStr::Icmp( cmd, "restart" ) ) {
485                         if ( !LoadGame( GetAutoSaveName( mapSpawnData.serverInfo.GetString("si_map") ) ) ) {
486                                 // If we can't load the autosave then just restart the map
487                                 MoveToNewMap( mapSpawnData.serverInfo.GetString("si_map") );
488                         }
489                         continue;
490                 }
491
492                 if ( !idStr::Icmp( cmd, "quit" ) ) {
493                         ExitMenu();
494                         common->Quit();
495                         return;
496                 }
497
498                 if ( !idStr::Icmp ( cmd, "exec" ) ) {
499                         cmdSystem->BufferCommandText( CMD_EXEC_APPEND, args.Argv( icmd++ ) );
500                         continue;
501                 }
502
503                 if ( !idStr::Icmp( cmd, "play" ) ) {
504                         if ( args.Argc() - icmd >= 1 ) {
505                                 idStr snd = args.Argv(icmd++);
506                                 sw->PlayShaderDirectly(snd);
507                         }
508                         continue;
509                 }
510         }
511 }
512
513 /*
514 ==============
515 idSessionLocal::HandleIntroMenuCommands
516
517 Executes any commands returned by the gui
518 ==============
519 */
520 void idSessionLocal::HandleIntroMenuCommands( const char *menuCommand ) {
521         // execute the command from the menu
522         int i;
523         idCmdArgs args;
524
525         args.TokenizeString( menuCommand, false );
526
527         for( i = 0; i < args.Argc(); ) {
528                 const char *cmd = args.Argv( i++ );
529
530                 if ( !idStr::Icmp( cmd, "startGame" ) ) {
531                         menuSoundWorld->ClearAllSoundEmitters();
532                         ExitMenu();
533                         continue;
534                 }
535
536                 if ( !idStr::Icmp( cmd, "play" ) ) {
537                         if ( args.Argc() - i >= 1 ) {
538                                 idStr snd = args.Argv(i++);
539                                 menuSoundWorld->PlayShaderDirectly(snd);
540                         }
541                         continue;
542                 }
543         }
544 }
545
546 /*
547 ==============
548 idSessionLocal::UpdateMPLevelShot
549 ==============
550 */
551 void idSessionLocal::UpdateMPLevelShot( void ) {
552         char screenshot[ MAX_STRING_CHARS ];
553         fileSystem->FindMapScreenshot( cvarSystem->GetCVarString( "si_map" ), screenshot, MAX_STRING_CHARS );
554         guiMainMenu->SetStateString( "current_levelshot", screenshot );
555 }
556
557 /*
558 ==============
559 idSessionLocal::HandleMainMenuCommands
560
561 Executes any commands returned by the gui
562 ==============
563 */
564 void idSessionLocal::HandleMainMenuCommands( const char *menuCommand ) {
565         // execute the command from the menu
566         int icmd;
567         idCmdArgs args;
568
569         args.TokenizeString( menuCommand, false );
570
571         for( icmd = 0; icmd < args.Argc(); ) {
572                 const char *cmd = args.Argv( icmd++ );
573
574                 if ( HandleSaveGameMenuCommand( args, icmd ) ) {
575                         continue;
576                 }
577
578                 // always let the game know the command is being run
579                 if ( game ) {
580                         game->HandleMainMenuCommands( cmd, guiActive );
581                 }
582                 
583                 if ( !idStr::Icmp( cmd, "startGame" ) ) {
584                         cvarSystem->SetCVarInteger( "g_skill", guiMainMenu->State().GetInt( "skill" ) );
585                         if ( icmd < args.Argc() ) {
586                                 StartNewGame( args.Argv( icmd++ ) );
587                         } else {
588 #ifndef ID_DEMO_BUILD
589                                 StartNewGame( "game/mars_city1" );
590 #else
591                                 StartNewGame( "game/demo_mars_city1" );
592 #endif
593                         }
594                         // need to do this here to make sure com_frameTime is correct or the gui activates with a time that 
595                         // is "however long map load took" time in the past
596                         common->GUIFrame( false, false );
597                         SetGUI( guiIntro, NULL );
598                         guiIntro->StateChanged( com_frameTime, true );
599                         // stop playing the game sounds
600                         soundSystem->SetPlayingSoundWorld( menuSoundWorld );
601
602                         continue;
603                 }
604
605                 if ( !idStr::Icmp( cmd, "quit" ) ) {
606                         ExitMenu();
607                         common->Quit();
608                         return;
609                 }
610
611                 if ( !idStr::Icmp( cmd, "loadMod" ) ) {
612                         int choice = guiActive->State().GetInt( "modsList_sel_0" );
613                         if ( choice >= 0 && choice < modsList.Num() ) {
614                                 cvarSystem->SetCVarString( "fs_game", modsList[ choice ] );
615                                 cmdSystem->BufferCommandText( CMD_EXEC_APPEND, "reloadEngine menu\n" );
616                         }
617                 }
618
619                 if ( !idStr::Icmp( cmd, "UpdateServers" ) ) {
620                         if ( guiActive->State().GetBool( "lanSet" ) ) {
621                                 cmdSystem->BufferCommandText( CMD_EXEC_NOW, "LANScan" );
622                         } else {
623                                 idAsyncNetwork::GetNETServers();
624                         }
625                         continue;
626                 }
627
628                 if ( !idStr::Icmp( cmd, "RefreshServers" ) ) {
629                         if ( guiActive->State().GetBool( "lanSet" ) ) {
630                                 cmdSystem->BufferCommandText( CMD_EXEC_NOW, "LANScan" );
631                         } else {
632                                 idAsyncNetwork::client.serverList.NetScan( );
633                         }
634                         continue;
635                 }
636
637                 if ( !idStr::Icmp( cmd, "FilterServers" ) ) {
638                         idAsyncNetwork::client.serverList.ApplyFilter( );
639                         continue;
640                 }
641
642                 if ( !idStr::Icmp( cmd, "sortServerName" ) ) {
643                         idAsyncNetwork::client.serverList.SetSorting( SORT_SERVERNAME );
644                         continue;
645                 }
646
647                 if ( !idStr::Icmp( cmd, "sortGame" ) ) {
648                         idAsyncNetwork::client.serverList.SetSorting( SORT_GAME );
649                         continue;
650                 }
651
652                 if ( !idStr::Icmp( cmd, "sortPlayers" ) ) {
653                         idAsyncNetwork::client.serverList.SetSorting( SORT_PLAYERS );
654                         continue;
655                 }
656
657                 if ( !idStr::Icmp( cmd, "sortPing" ) ) {
658                         idAsyncNetwork::client.serverList.SetSorting( SORT_PING );
659                         continue;
660                 }
661
662                 if ( !idStr::Icmp( cmd, "sortGameType" ) ) {
663                         idAsyncNetwork::client.serverList.SetSorting( SORT_GAMETYPE );
664                         continue;
665                 }
666
667                 if ( !idStr::Icmp( cmd, "sortMap" ) ) {
668                         idAsyncNetwork::client.serverList.SetSorting( SORT_MAP );
669                         continue;
670                 }
671
672                 if ( !idStr::Icmp( cmd, "serverList" ) ) {
673                         idAsyncNetwork::client.serverList.GUIUpdateSelected();
674                         continue;
675                 }
676
677                 if ( !idStr::Icmp( cmd, "LANConnect" ) ) {
678                         int sel = guiActive->State().GetInt( "serverList_selid_0" ); 
679                         cmdSystem->BufferCommandText( CMD_EXEC_NOW, va( "Connect %d\n", sel ) );
680                         return;
681                 }
682
683                 if ( !idStr::Icmp( cmd, "MAPScan" ) ) {
684                         const char *gametype = cvarSystem->GetCVarString( "si_gameType" );
685                         if ( gametype == NULL || *gametype == 0 || idStr::Icmp( gametype, "singleplayer" ) == 0 ) {
686                                 gametype = "Deathmatch";
687                         }
688
689                         int i, num;
690                         idStr si_map = cvarSystem->GetCVarString("si_map");
691                         const idDict *dict;
692
693                         guiMainMenu_MapList->Clear();
694                         guiMainMenu_MapList->SetSelection( 0 );
695                         num = fileSystem->GetNumMaps();
696                         for ( i = 0; i < num; i++ ) {
697                                 dict = fileSystem->GetMapDecl( i );
698                                 if ( dict && dict->GetBool( gametype ) ) {
699                                         const char *mapName = dict->GetString( "name" );
700                                         if ( mapName[ 0 ] == '\0' ) {
701                                                 mapName = dict->GetString( "path" );
702                                         }
703                                         mapName = common->GetLanguageDict()->GetString( mapName );
704                                         guiMainMenu_MapList->Add( i, mapName );
705                                         if ( !si_map.Icmp( dict->GetString( "path" ) ) ) {
706                                                 guiMainMenu_MapList->SetSelection( guiMainMenu_MapList->Num() - 1 );
707                                         }
708                                 }
709                         }
710                         i = guiMainMenu_MapList->GetSelection( NULL, 0 );
711                         if ( i >= 0 ) {
712                                 dict = fileSystem->GetMapDecl( i);
713                         } else {
714                                 dict = NULL;
715                         }
716                         cvarSystem->SetCVarString( "si_map", ( dict ? dict->GetString( "path" ) : "" ) );
717
718                         // set the current level shot
719                         UpdateMPLevelShot();
720                         continue;
721                 }
722
723                 if ( !idStr::Icmp( cmd, "click_mapList" ) ) {
724                         int mapNum = guiMainMenu_MapList->GetSelection( NULL, 0 );
725                         const idDict *dict = fileSystem->GetMapDecl( mapNum );
726                         if ( dict ) {
727                                 cvarSystem->SetCVarString( "si_map", dict->GetString( "path" ) );
728                         }
729                         UpdateMPLevelShot();
730                         continue;
731                 }
732
733                 if ( !idStr::Icmp( cmd, "inetConnect" ) ) {
734                         const char      *s = guiMainMenu->State().GetString( "inetGame" );
735
736                         if ( !s || s[0] == 0 ) {
737                                 // don't put the menu away if there isn't a valid selection
738                                 continue;
739                         }
740
741                         cmdSystem->BufferCommandText( CMD_EXEC_NOW, va( "connect %s", s ) );
742                         return;
743                 }
744
745                 if ( !idStr::Icmp( cmd, "startMultiplayer" ) ) {
746                         int dedicated = guiActive->State().GetInt( "dedicated" );
747                         cvarSystem->SetCVarBool( "net_LANServer", guiActive->State().GetBool( "server_type" ) );
748                         if ( gui_configServerRate.GetInteger() > 0 ) {
749                                 // guess the best rate for upstream, number of internet clients
750                                 if ( gui_configServerRate.GetInteger() == 5 || cvarSystem->GetCVarBool( "net_LANServer" ) ) {
751                                         cvarSystem->SetCVarInteger( "net_serverMaxClientRate", 25600 );
752                                 } else {
753                                         // internet players
754                                         int n_clients = cvarSystem->GetCVarInteger( "si_maxPlayers" );
755                                         if ( !dedicated ) {
756                                                 n_clients--;
757                                         }
758                                         int maxclients = 0;
759                                         switch ( gui_configServerRate.GetInteger() ) {
760                                                 case 1:
761                                                         // 128 kbits
762                                                         cvarSystem->SetCVarInteger( "net_serverMaxClientRate", 8000 );
763                                                         maxclients = 2;
764                                                         break;
765                                                 case 2:
766                                                         // 256 kbits
767                                                         cvarSystem->SetCVarInteger( "net_serverMaxClientRate", 9500 );
768                                                         maxclients = 3;
769                                                         break;
770                                                 case 3:
771                                                         // 384 kbits
772                                                         cvarSystem->SetCVarInteger( "net_serverMaxClientRate", 10500 );
773                                                         maxclients = 4;
774                                                         break;
775                                                 case 4:
776                                                         // 512 and above..
777                                                         cvarSystem->SetCVarInteger( "net_serverMaxClientRate", 14000 );
778                                                         maxclients = 4;
779                                                         break;
780                                         }
781                                         if ( n_clients > maxclients ) {
782                                                 if ( MessageBox( MSG_OKCANCEL, va( common->GetLanguageDict()->GetString( "#str_04315" ), dedicated ? maxclients : Min( 8, maxclients + 1 ) ), common->GetLanguageDict()->GetString( "#str_04316" ), true, "OK" )[ 0 ] == '\0' ) {
783                                                         continue;
784                                                 }
785                                                 cvarSystem->SetCVarInteger( "si_maxPlayers", dedicated ? maxclients : Min( 8, maxclients + 1 ) );
786                                         }
787                                 }
788                         }
789
790                         if ( !dedicated && !cvarSystem->GetCVarBool( "net_LANServer" ) && cvarSystem->GetCVarInteger("si_maxPlayers") > 4 ) {
791                                 // "Dedicated server mode is recommended for internet servers with more than 4 players. Continue in listen mode?"
792                                 if ( !MessageBox( MSG_YESNO, common->GetLanguageDict()->GetString ( "#str_00100625" ), common->GetLanguageDict()->GetString ( "#str_00100626" ), true, "yes" )[ 0 ] ) {
793                                         continue;
794                                 }
795                         }
796
797                         if ( dedicated ) {
798                                 cvarSystem->SetCVarInteger( "net_serverDedicated", 1 );
799                         } else {
800                                 cvarSystem->SetCVarInteger( "net_serverDedicated", 0 );
801                         }
802
803
804
805                         ExitMenu();
806                         // may trigger a reloadEngine - APPEND
807                         cmdSystem->BufferCommandText( CMD_EXEC_APPEND, "SpawnServer\n" );
808                         return;
809                 }
810
811                 if ( !idStr::Icmp( cmd, "mpSkin")) {
812                         idStr skin;
813                         if ( args.Argc() - icmd >= 1 ) {
814                                 skin = args.Argv( icmd++ );
815                                 cvarSystem->SetCVarString( "ui_skin", skin );
816                                 SetMainMenuSkin();
817                         }
818                         continue;
819                 }
820
821                 if ( !idStr::Icmp( cmd, "close" ) ) {
822                         // if we aren't in a game, the menu can't be closed
823                         if ( mapSpawned ) {
824                                 ExitMenu();
825                         }
826                         continue;
827                 }
828
829                 if ( !idStr::Icmp( cmd, "resetdefaults" ) ) {
830                         cmdSystem->BufferCommandText( CMD_EXEC_NOW, "exec default.cfg" );
831                         guiMainMenu->SetKeyBindingNames();
832                         continue;
833                 }
834
835
836                 if ( !idStr::Icmp( cmd, "bind" ) ) {
837                         if ( args.Argc() - icmd >= 2 ) {
838                                 int key = atoi( args.Argv( icmd++ ) );
839                                 idStr bind = args.Argv( icmd++ );
840                                 if ( idKeyInput::NumBinds( bind ) >= 2 && !idKeyInput::KeyIsBoundTo( key, bind ) ) {
841                                         idKeyInput::UnbindBinding( bind );
842                                 }
843                                 idKeyInput::SetBinding( key, bind );
844                                 guiMainMenu->SetKeyBindingNames();
845                         }
846                         continue;
847                 }
848
849                 if ( !idStr::Icmp( cmd, "play" ) ) {
850                         if ( args.Argc() - icmd >= 1 ) {
851                                 idStr snd = args.Argv( icmd++ );
852                                 int channel = 1;
853                                 if ( snd.Length() == 1 ) {
854                                         channel = atoi( snd );
855                                         snd = args.Argv( icmd++ );
856                                 }
857                                 menuSoundWorld->PlayShaderDirectly( snd, channel );
858
859                         }
860                         continue;
861                 }
862
863                 if ( !idStr::Icmp( cmd, "music" ) ) {
864                         if ( args.Argc() - icmd >= 1 ) {
865                                 idStr snd = args.Argv( icmd++ );
866                                 menuSoundWorld->PlayShaderDirectly( snd, 2 );
867                         }
868                         continue;
869                 }
870
871                 // triggered from mainmenu or mpmain
872                 if ( !idStr::Icmp( cmd, "sound" ) ) {
873                         idStr vcmd;
874                         if ( args.Argc() - icmd >= 1 ) {
875                                 vcmd = args.Argv( icmd++ );
876                         }
877                         if ( !vcmd.Length() || !vcmd.Icmp( "speakers" ) ) {
878                                 int old = cvarSystem->GetCVarInteger( "s_numberOfSpeakers" );
879                                 cmdSystem->BufferCommandText( CMD_EXEC_NOW, "s_restart\n" );
880                                 if ( old != cvarSystem->GetCVarInteger( "s_numberOfSpeakers" ) ) {
881 #ifdef _WIN32
882                                         MessageBox( MSG_OK, common->GetLanguageDict()->GetString( "#str_04142" ), common->GetLanguageDict()->GetString( "#str_04141" ), true );
883 #else
884                                         // a message that doesn't mention the windows control panel
885                                         MessageBox( MSG_OK, common->GetLanguageDict()->GetString( "#str_07230" ), common->GetLanguageDict()->GetString( "#str_04141" ), true );
886 #endif
887                                 }
888                         }
889                         if ( !vcmd.Icmp( "eax" ) ) {
890                                 if ( cvarSystem->GetCVarBool( "s_useEAXReverb" ) ) {
891                                         int eax = soundSystem->IsEAXAvailable();
892                                         switch ( eax ) {
893                                         case 2:
894                                                 // OpenAL subsystem load failed
895                                                 MessageBox( MSG_OK, common->GetLanguageDict()->GetString( "#str_07238" ), common->GetLanguageDict()->GetString( "#str_07231" ), true );
896                                                 break;
897                                         case 1:
898                                                 // when you restart
899                                                 MessageBox( MSG_OK, common->GetLanguageDict()->GetString( "#str_04137" ), common->GetLanguageDict()->GetString( "#str_07231" ), true );
900                                                 break;
901                                         case -1:
902                                                 cvarSystem->SetCVarBool( "s_useEAXReverb", false );
903                                                 // disabled
904                                                 MessageBox( MSG_OK, common->GetLanguageDict()->GetString( "#str_07233" ), common->GetLanguageDict()->GetString( "#str_07231" ), true );
905                                                 break;
906                                         case 0:
907                                                 cvarSystem->SetCVarBool( "s_useEAXReverb", false );
908                                                 // not available
909                                                 MessageBox( MSG_OK, common->GetLanguageDict()->GetString( "#str_07232" ), common->GetLanguageDict()->GetString( "#str_07231" ), true );
910                                                 break;
911                                         }
912                                 } else {
913                                         // also turn off OpenAL so we fully go back to legacy mixer
914                                         cvarSystem->SetCVarBool( "s_useOpenAL", false );
915                                         // when you restart
916                                         MessageBox( MSG_OK, common->GetLanguageDict()->GetString( "#str_04137" ), common->GetLanguageDict()->GetString( "#str_07231" ), true );
917                                 }
918                         }
919                         if ( !vcmd.Icmp( "drivar" ) ) {
920                                 cmdSystem->BufferCommandText( CMD_EXEC_NOW, "s_restart\n" );                            
921                         }
922                         continue;
923                 }
924
925                 if ( !idStr::Icmp( cmd, "video" ) ) {
926                         idStr vcmd;
927                         if ( args.Argc() - icmd >= 1 ) {
928                                 vcmd = args.Argv( icmd++ );
929                         }
930
931                         int oldSpec = com_machineSpec.GetInteger();
932
933                         if ( idStr::Icmp( vcmd, "low" ) == 0 ) {
934                                 com_machineSpec.SetInteger( 0 );
935                         } else if ( idStr::Icmp( vcmd, "medium" ) == 0 ) {
936                                 com_machineSpec.SetInteger( 1 );
937                         } else  if ( idStr::Icmp( vcmd, "high" ) == 0 ) {
938                                 com_machineSpec.SetInteger( 2 );
939                         } else  if ( idStr::Icmp( vcmd, "ultra" ) == 0 ) {
940                                 com_machineSpec.SetInteger( 3 );
941                         } else if ( idStr::Icmp( vcmd, "recommended" ) == 0 ) {
942                                 cmdSystem->BufferCommandText( CMD_EXEC_NOW, "setMachineSpec\n" );
943                         }
944
945                         if ( oldSpec != com_machineSpec.GetInteger() ) {
946                                 guiActive->SetStateInt( "com_machineSpec", com_machineSpec.GetInteger() );
947                                 guiActive->StateChanged( com_frameTime );
948                                 cmdSystem->BufferCommandText( CMD_EXEC_NOW, "execMachineSpec\n" );
949                         }
950
951                         if ( idStr::Icmp( vcmd, "restart" )  == 0) {
952                                 guiActive->HandleNamedEvent( "cvar write render" );
953                                 cmdSystem->BufferCommandText( CMD_EXEC_NOW, "vid_restart\n" );
954                         }
955
956                         continue;
957                 }
958
959                 if ( !idStr::Icmp( cmd, "clearBind" ) ) {
960                         if ( args.Argc() - icmd >= 1 ) {
961                                 idKeyInput::UnbindBinding( args.Argv( icmd++ ) );
962                                 guiMainMenu->SetKeyBindingNames();
963                         }
964                         continue;
965                 }
966
967                 // FIXME: obsolete
968                 if ( !idStr::Icmp( cmd, "chatdone" ) ) {
969                         idStr temp = guiActive->State().GetString( "chattext" );
970                         temp += "\r";
971                         guiActive->SetStateString( "chattext", "" );
972                         continue;
973                 }
974
975                 if ( !idStr::Icmp ( cmd, "exec" ) ) {
976
977                         //Backup the language so we can restore it after defaults.
978                         idStr lang = cvarSystem->GetCVarString("sys_lang");
979
980                         cmdSystem->BufferCommandText( CMD_EXEC_NOW, args.Argv( icmd++ ) );
981                         if ( idStr::Icmp( "cvar_restart", args.Argv( icmd - 1 ) ) == 0 ) {
982                                 cmdSystem->BufferCommandText( CMD_EXEC_NOW, "exec default.cfg" );
983                                 cmdSystem->BufferCommandText( CMD_EXEC_NOW, "setMachineSpec\n" );
984
985                                 //Make sure that any r_brightness changes take effect
986                                 float bright = cvarSystem->GetCVarFloat("r_brightness");
987                                 cvarSystem->SetCVarFloat("r_brightness", 0.0f);
988                                 cvarSystem->SetCVarFloat("r_brightness", bright);
989
990                                 //Force user info modified after a reset to defaults
991                                 cvarSystem->SetModifiedFlags(CVAR_USERINFO);
992
993                                 guiActive->SetStateInt( "com_machineSpec", com_machineSpec.GetInteger() );
994
995                                 //Restore the language
996                                 cvarSystem->SetCVarString("sys_lang", lang);
997
998                         }
999                         continue;
1000                 }
1001
1002                 if ( !idStr::Icmp ( cmd, "loadBinds" ) ) {
1003                         guiMainMenu->SetKeyBindingNames();
1004                         continue;
1005                 }
1006                 
1007                 if ( !idStr::Icmp( cmd, "systemCvars" ) ) {
1008                         guiActive->HandleNamedEvent( "cvar read render" );
1009                         guiActive->HandleNamedEvent( "cvar read sound" );
1010                         continue;
1011                 }
1012
1013                 if ( !idStr::Icmp( cmd, "SetCDKey" ) ) {
1014                         // we can't do this from inside the HandleMainMenuCommands code, otherwise the message box stuff gets confused
1015                         cmdSystem->BufferCommandText( CMD_EXEC_APPEND, "promptKey\n" );
1016                         continue;
1017                 }
1018
1019                 if ( !idStr::Icmp( cmd, "CheckUpdate" ) ) {
1020                         idAsyncNetwork::client.SendVersionCheck();
1021                         continue;
1022                 }
1023
1024                 if ( !idStr::Icmp( cmd, "CheckUpdate2" ) ) {
1025                         idAsyncNetwork::client.SendVersionCheck( true );
1026                         continue;
1027                 }
1028
1029                 if ( !idStr::Icmp( cmd, "checkKeys" ) ) {
1030 #if ID_ENFORCE_KEY
1031                         // not a strict check so you silently auth in the background without bugging the user
1032                         if ( !session->CDKeysAreValid( false ) ) {
1033                                 cmdSystem->BufferCommandText( CMD_EXEC_NOW, "promptKey force" );
1034                                 cmdSystem->ExecuteCommandBuffer();
1035                         }                       
1036 #endif
1037                         continue;
1038                 }
1039
1040                 // triggered from mainmenu or mpmain
1041                 if ( !idStr::Icmp( cmd, "punkbuster" ) ) {
1042                         idStr vcmd;
1043                         if ( args.Argc() - icmd >= 1 ) {
1044                                 vcmd = args.Argv( icmd++ );
1045                         }
1046                         // filtering PB based on enabled/disabled
1047                         idAsyncNetwork::client.serverList.ApplyFilter( );
1048                         SetPbMenuGuiVars();
1049                         continue;
1050                 }
1051         }
1052 }
1053
1054 /*
1055 ==============
1056 idSessionLocal::HandleChatMenuCommands
1057
1058 Executes any commands returned by the gui
1059 ==============
1060 */
1061 void idSessionLocal::HandleChatMenuCommands( const char *menuCommand ) {
1062         // execute the command from the menu
1063         int i;
1064         idCmdArgs args;
1065
1066         args.TokenizeString( menuCommand, false );
1067
1068         for ( i = 0; i < args.Argc(); ) {
1069                 const char *cmd = args.Argv( i++ );
1070
1071                 if ( idStr::Icmp( cmd, "chatactive" ) == 0 ) {
1072                         //chat.chatMode = CHAT_GLOBAL;
1073                         continue;
1074                 }
1075                 if ( idStr::Icmp( cmd, "chatabort" ) == 0 ) {
1076                         //chat.chatMode = CHAT_NONE;
1077                         continue;
1078                 }
1079                 if ( idStr::Icmp( cmd, "netready" ) == 0 ) {
1080                         bool b = cvarSystem->GetCVarBool( "ui_ready" );
1081                         cvarSystem->SetCVarBool( "ui_ready", !b );
1082                         continue;
1083                 }
1084                 if ( idStr::Icmp( cmd, "netstart" ) == 0 ) {
1085                         cmdSystem->BufferCommandText( CMD_EXEC_NOW, "netcommand start\n" );
1086                         continue;
1087                 }
1088         }
1089 }
1090
1091 /*
1092 ==============
1093 idSessionLocal::HandleInGameCommands
1094
1095 Executes any commands returned by the gui
1096 ==============
1097 */
1098 void idSessionLocal::HandleInGameCommands( const char *menuCommand ) {
1099         // execute the command from the menu
1100         idCmdArgs args;
1101
1102         args.TokenizeString( menuCommand, false );
1103
1104         const char *cmd = args.Argv( 0 );
1105         if ( !idStr::Icmp( cmd, "close" ) ) {
1106                 if ( guiActive ) {
1107                         sysEvent_t  ev;
1108                         ev.evType = SE_NONE;
1109                         const char      *cmd;
1110                         cmd = guiActive->HandleEvent( &ev, com_frameTime );
1111                         guiActive->Activate( false, com_frameTime );
1112                         guiActive = NULL;
1113                 }
1114         }
1115 }
1116
1117 /*
1118 ==============
1119 idSessionLocal::DispatchCommand
1120 ==============
1121 */
1122 void idSessionLocal::DispatchCommand( idUserInterface *gui, const char *menuCommand, bool doIngame ) {
1123
1124         if ( !gui ) {
1125                 gui = guiActive;
1126         }
1127
1128         if ( gui == guiMainMenu ) {
1129                 HandleMainMenuCommands( menuCommand );
1130                 return;
1131         } else if ( gui == guiIntro) {
1132                 HandleIntroMenuCommands( menuCommand );
1133         } else if ( gui == guiMsg ) {
1134                 HandleMsgCommands( menuCommand );
1135         } else if ( gui == guiTakeNotes ) {
1136                 HandleNoteCommands( menuCommand );
1137         } else if ( gui == guiRestartMenu ) {
1138                 HandleRestartMenuCommands( menuCommand );
1139         } else if ( game && guiActive && guiActive->State().GetBool( "gameDraw" ) ) {
1140                 const char *cmd = game->HandleGuiCommands( menuCommand );
1141                 if ( !cmd ) {
1142                         guiActive = NULL;
1143                 } else if ( idStr::Icmp( cmd, "main" ) == 0 ) {
1144                         StartMenu();
1145                 } else if ( strstr( cmd, "sound " ) == cmd ) {
1146                         // pipe the GUI sound commands not handled by the game to the main menu code
1147                         HandleMainMenuCommands( cmd );
1148                 }
1149         } else if ( guiHandle ) {
1150                 if ( (*guiHandle)( menuCommand ) ) {
1151                         return;
1152                 }
1153         } else if ( !doIngame ) {
1154                 common->DPrintf( "idSessionLocal::DispatchCommand: no dispatch found for command '%s'\n", menuCommand );
1155         }
1156
1157         if ( doIngame ) {
1158                 HandleInGameCommands( menuCommand );
1159         }
1160 }
1161
1162
1163 /*
1164 ==============
1165 idSessionLocal::MenuEvent
1166
1167 Executes any commands returned by the gui
1168 ==============
1169 */
1170 void idSessionLocal::MenuEvent( const sysEvent_t *event ) {
1171         const char      *menuCommand;
1172
1173         if ( guiActive == NULL ) {
1174                 return;
1175         }
1176
1177         menuCommand = guiActive->HandleEvent( event, com_frameTime );
1178
1179         if ( !menuCommand || !menuCommand[0] ) {
1180                 // If the menu didn't handle the event, and it's a key down event for an F key, run the bind
1181                 if ( event->evType == SE_KEY && event->evValue2 == 1 && event->evValue >= K_F1 && event->evValue <= K_F12 ) {
1182                         idKeyInput::ExecKeyBinding( event->evValue );
1183                 }
1184                 return;
1185         }
1186
1187         DispatchCommand( guiActive, menuCommand );
1188 }
1189
1190 /*
1191 =================
1192 idSessionLocal::GuiFrameEvents
1193 =================
1194 */
1195 void idSessionLocal::GuiFrameEvents() {
1196         const char      *cmd;
1197         sysEvent_t  ev;
1198         idUserInterface *gui;
1199
1200         // stop generating move and button commands when a local console or menu is active
1201         // running here so SP, async networking and no game all go through it
1202         if ( console->Active() || guiActive ) {
1203                 usercmdGen->InhibitUsercmd( INHIBIT_SESSION, true );
1204         } else {
1205                 usercmdGen->InhibitUsercmd( INHIBIT_SESSION, false );
1206         }
1207
1208         if ( guiTest ) {
1209                 gui = guiTest;
1210         } else if ( guiActive ) {
1211                 gui = guiActive;
1212         } else {
1213                 return;
1214         }
1215
1216         memset( &ev, 0, sizeof( ev ) );
1217
1218         ev.evType = SE_NONE;
1219         cmd = gui->HandleEvent( &ev, com_frameTime );
1220         if ( cmd && cmd[0] ) {
1221                 DispatchCommand( guiActive, cmd );
1222         }
1223 }
1224
1225 /*
1226 =================
1227 idSessionLocal::BoxDialogSanityCheck
1228 =================
1229 */
1230 bool idSessionLocal::BoxDialogSanityCheck( void ) {
1231         if ( !common->IsInitialized() ) {
1232                 common->DPrintf( "message box sanity check: !common->IsInitialized()\n" );
1233                 return false;
1234         }
1235         if ( !guiMsg ) {
1236                 return false;
1237         }
1238         if ( guiMsgRestore ) {
1239                 common->DPrintf( "message box sanity check: recursed\n" );
1240                 return false;
1241         }
1242         if ( cvarSystem->GetCVarInteger( "net_serverDedicated" ) ) {
1243                 common->DPrintf( "message box sanity check: not compatible with dedicated server\n" );
1244                 return false;
1245         }
1246         return true;
1247 }
1248
1249 /*
1250 =================
1251 idSessionLocal::MessageBox
1252 =================
1253 */
1254 const char* idSessionLocal::MessageBox( msgBoxType_t type, const char *message, const char *title, bool wait, const char *fire_yes, const char *fire_no, bool network ) {
1255         
1256         common->DPrintf( "MessageBox: %s - %s\n", title ? title : "", message ? message : "" );
1257         
1258         if ( !BoxDialogSanityCheck() ) {
1259                 return NULL;
1260         }
1261
1262         guiMsg->SetStateString( "title", title ? title : "" );
1263         guiMsg->SetStateString( "message", message ? message : "" );
1264         if ( type == MSG_WAIT ) {
1265                 guiMsg->SetStateString( "visible_msgbox", "0" );
1266                 guiMsg->SetStateString( "visible_waitbox", "1" );
1267         } else {
1268                 guiMsg->SetStateString( "visible_msgbox", "1" );
1269                 guiMsg->SetStateString( "visible_waitbox", "0" );
1270         }
1271
1272         guiMsg->SetStateString( "visible_entry", "0" );
1273         guiMsg->SetStateString( "visible_cdkey", "0" );
1274         switch ( type ) {
1275                 case MSG_INFO:
1276                         guiMsg->SetStateString( "mid", "" );
1277                         guiMsg->SetStateString( "visible_mid", "0" );
1278                         guiMsg->SetStateString( "visible_left", "0" );
1279                         guiMsg->SetStateString( "visible_right", "0" );
1280                         break;
1281                 case MSG_OK:
1282                         guiMsg->SetStateString( "mid", common->GetLanguageDict()->GetString( "#str_04339" ) );
1283                         guiMsg->SetStateString( "visible_mid", "1" );
1284                         guiMsg->SetStateString( "visible_left", "0" );
1285                         guiMsg->SetStateString( "visible_right", "0" );
1286                         break;
1287                 case MSG_ABORT:
1288                         guiMsg->SetStateString( "mid", common->GetLanguageDict()->GetString( "#str_04340" ) );
1289                         guiMsg->SetStateString( "visible_mid", "1" );
1290                         guiMsg->SetStateString( "visible_left", "0" );
1291                         guiMsg->SetStateString( "visible_right", "0" );
1292                         break;
1293                 case MSG_OKCANCEL:
1294                         guiMsg->SetStateString( "left", common->GetLanguageDict()->GetString( "#str_04339" ) );
1295                         guiMsg->SetStateString( "right", common->GetLanguageDict()->GetString( "#str_04340" ) );
1296                         guiMsg->SetStateString( "visible_mid", "0" );
1297                         guiMsg->SetStateString( "visible_left", "1" );
1298                         guiMsg->SetStateString( "visible_right", "1" );
1299                         break;
1300                 case MSG_YESNO:
1301                         guiMsg->SetStateString( "left", common->GetLanguageDict()->GetString( "#str_04341" ) );
1302                         guiMsg->SetStateString( "right", common->GetLanguageDict()->GetString( "#str_04342" ) );
1303                         guiMsg->SetStateString( "visible_mid", "0" );
1304                         guiMsg->SetStateString( "visible_left", "1" );
1305                         guiMsg->SetStateString( "visible_right", "1" );
1306                         break;
1307                 case MSG_PROMPT:
1308                         guiMsg->SetStateString( "left", common->GetLanguageDict()->GetString( "#str_04339" ) );
1309                         guiMsg->SetStateString( "right", common->GetLanguageDict()->GetString( "#str_04340" ) );
1310                         guiMsg->SetStateString( "visible_mid", "0" );
1311                         guiMsg->SetStateString( "visible_left", "1" );
1312                         guiMsg->SetStateString( "visible_right", "1" );
1313                         guiMsg->SetStateString( "visible_entry", "1" );                 
1314                         guiMsg->HandleNamedEvent( "Prompt" );
1315                         break;
1316                 case MSG_CDKEY:
1317                         guiMsg->SetStateString( "left", common->GetLanguageDict()->GetString( "#str_04339" ) );
1318                         guiMsg->SetStateString( "right", common->GetLanguageDict()->GetString( "#str_04340" ) );
1319                         guiMsg->SetStateString( "visible_msgbox", "0" );
1320                         guiMsg->SetStateString( "visible_cdkey", "1" );
1321                         guiMsg->SetStateString( "visible_hasxp", fileSystem->HasD3XP() ? "1" : "0" );
1322                         // the current cdkey / xpkey values may have bad/random data in them
1323                         // it's best to avoid printing them completely, unless the key is good
1324                         if ( cdkey_state == CDKEY_OK ) {
1325                                 guiMsg->SetStateString( "str_cdkey", cdkey );
1326                                 guiMsg->SetStateString( "visible_cdchk", "0" );
1327                         } else {
1328                                 guiMsg->SetStateString( "str_cdkey", "" );
1329                                 guiMsg->SetStateString( "visible_cdchk", "1" );
1330                         }
1331                         guiMsg->SetStateString( "str_cdchk", "" );
1332                         if ( xpkey_state == CDKEY_OK ) {
1333                                 guiMsg->SetStateString( "str_xpkey", xpkey );
1334                                 guiMsg->SetStateString( "visible_xpchk", "0" );
1335                         } else {
1336                                 guiMsg->SetStateString( "str_xpkey", "" );
1337                                 guiMsg->SetStateString( "visible_xpchk", "1" );
1338                         }
1339                         guiMsg->SetStateString( "str_xpchk", "" );
1340                         guiMsg->HandleNamedEvent( "CDKey" );
1341                         break;
1342                 case MSG_WAIT:
1343                         break;
1344                 default:
1345                         common->Printf( "idSessionLocal::MessageBox: unknown msg box type\n" );
1346         }
1347         msgFireBack[ 0 ] = fire_yes ? fire_yes : "";
1348         msgFireBack[ 1 ] = fire_no ? fire_no : "";
1349         guiMsgRestore = guiActive;
1350         guiActive = guiMsg;
1351         guiMsg->SetCursor( 325, 290 );
1352         guiActive->Activate( true, com_frameTime );
1353         msgRunning = true;
1354         msgRetIndex = -1;
1355         
1356         if ( wait ) {
1357                 // play one frame ignoring events so we don't get confused by parasite button releases
1358                 msgIgnoreButtons = true;
1359                 common->GUIFrame( true, network );
1360                 msgIgnoreButtons = false;
1361                 while ( msgRunning ) {
1362                         common->GUIFrame( true, network );
1363                 }
1364                 if ( msgRetIndex < 0 ) {
1365                         // MSG_WAIT and other StopBox calls
1366                         return NULL;
1367                 }
1368                 if ( type == MSG_PROMPT ) {
1369                         if ( msgRetIndex == 0 ) {
1370                                 guiMsg->State().GetString( "str_entry", "", msgFireBack[ 0 ] );
1371                                 return msgFireBack[ 0 ].c_str();
1372                         } else {
1373                                 return NULL;
1374                         }
1375                 } else if ( type == MSG_CDKEY ) {
1376                         if ( msgRetIndex == 0 ) {
1377                                 // the visible_ values distinguish looking at a valid key, or editing it
1378                                 sprintf( msgFireBack[ 0 ], "%1s;%16s;%2s;%1s;%16s;%2s",
1379                                                  guiMsg->State().GetString( "visible_cdchk" ),
1380                                                  guiMsg->State().GetString( "str_cdkey" ),
1381                                                  guiMsg->State().GetString( "str_cdchk" ),
1382                                                  guiMsg->State().GetString( "visible_xpchk" ),                                           
1383                                                  guiMsg->State().GetString( "str_xpkey" ),
1384                                                  guiMsg->State().GetString( "str_xpchk" ) );
1385                                 return msgFireBack[ 0 ].c_str();
1386                         } else {
1387                                 return NULL;
1388                         }
1389                 } else {
1390                         return msgFireBack[ msgRetIndex ].c_str();
1391                 }
1392         }
1393         return NULL;
1394 }
1395
1396 /*
1397 =================
1398 idSessionLocal::DownloadProgressBox
1399 =================
1400 */
1401 void idSessionLocal::DownloadProgressBox( backgroundDownload_t *bgl, const char *title, int progress_start, int progress_end ) {
1402         int dlnow = 0, dltotal = 0;
1403         int startTime = Sys_Milliseconds();
1404         int lapsed;
1405         idStr sNow, sTotal, sBW, sETA, sMsg;
1406
1407         if ( !BoxDialogSanityCheck() ) {
1408                 return;
1409         }
1410
1411         guiMsg->SetStateString( "visible_msgbox", "1" );
1412         guiMsg->SetStateString( "visible_waitbox", "0" );
1413
1414         guiMsg->SetStateString( "visible_entry", "0" );
1415         guiMsg->SetStateString( "visible_cdkey", "0" );
1416
1417         guiMsg->SetStateString( "mid", "Cancel" );
1418         guiMsg->SetStateString( "visible_mid", "1" );
1419         guiMsg->SetStateString( "visible_left", "0" );
1420         guiMsg->SetStateString( "visible_right", "0" );
1421
1422         guiMsg->SetStateString( "title", title );
1423         guiMsg->SetStateString( "message", "Connecting.." );
1424
1425         guiMsgRestore = guiActive;
1426         guiActive = guiMsg;
1427         msgRunning = true;
1428
1429         while ( 1 ) {
1430                 while ( msgRunning ) {
1431                         common->GUIFrame( true, false );
1432                         if ( bgl->completed ) {
1433                                 guiActive = guiMsgRestore;
1434                                 guiMsgRestore = NULL;
1435                                 return;
1436                         } else if ( bgl->url.dltotal != dltotal || bgl->url.dlnow != dlnow ) {
1437                                 dltotal = bgl->url.dltotal;
1438                                 dlnow = bgl->url.dlnow;
1439                                 lapsed = Sys_Milliseconds() - startTime;
1440                                 sNow.BestUnit( "%.2f", dlnow, MEASURE_SIZE );
1441                                 if ( lapsed > 2000 ) {
1442                                         sBW.BestUnit( "%.1f", ( 1000.0f * dlnow ) / lapsed, MEASURE_BANDWIDTH );
1443                                 } else {
1444                                         sBW = "-- KB/s";
1445                                 }
1446                                 if ( dltotal ) {
1447                                         sTotal.BestUnit( "%.2f", dltotal, MEASURE_SIZE );
1448                                         if ( lapsed < 2000 ) {
1449                                                 sprintf( sMsg, "%s / %s", sNow.c_str(), sTotal.c_str() );
1450                                         } else {
1451                                                 sprintf( sETA, "%.0f sec", ( (float)dltotal / (float)dlnow - 1.0f ) * lapsed / 1000 );
1452                                                 sprintf( sMsg, "%s / %s ( %s - %s )", sNow.c_str(), sTotal.c_str(), sBW.c_str(), sETA.c_str() );
1453                                         }
1454                                 } else {
1455                                         if ( lapsed < 2000 ) {
1456                                                 sMsg = sNow;
1457                                         } else {
1458                                                 sprintf( sMsg, "%s - %s", sNow.c_str(), sBW.c_str() );
1459                                         }
1460                                 }
1461                                 if ( dltotal ) {
1462                                         guiMsg->SetStateString( "progress", va( "%d", progress_start + dlnow * ( progress_end - progress_start ) / dltotal ) );
1463                                 } else {
1464                                         guiMsg->SetStateString( "progress", "0" );
1465                                 }
1466                                 guiMsg->SetStateString( "message", sMsg.c_str() );
1467                         }
1468                 }
1469                 // abort was used - tell the downloader and wait till final stop
1470                 bgl->url.status = DL_ABORTING;
1471                 guiMsg->SetStateString( "title", "Aborting.." );
1472                 guiMsg->SetStateString( "visible_mid", "0" );
1473                 // continue looping
1474                 guiMsgRestore = guiActive;
1475                 guiActive = guiMsg;
1476                 msgRunning = true;
1477         }
1478 }
1479
1480 /*
1481 =================
1482 idSessionLocal::StopBox
1483 =================
1484 */
1485 void idSessionLocal::StopBox() {
1486         if ( guiActive == guiMsg ) {
1487                 HandleMsgCommands( "stop" );
1488         }
1489 }
1490
1491 /*
1492 =================
1493 idSessionLocal::HandleMsgCommands
1494 =================
1495 */
1496 void idSessionLocal::HandleMsgCommands( const char *menuCommand ) {
1497         assert( guiActive == guiMsg );
1498         // "stop" works even on first frame
1499         if ( idStr::Icmp( menuCommand, "stop" ) == 0 ) {
1500                 // force hiding the current dialog
1501                 guiActive = guiMsgRestore;
1502                 guiMsgRestore = NULL;
1503                 msgRunning = false;
1504                 msgRetIndex = -1;
1505         }
1506         if ( msgIgnoreButtons ) {
1507                 common->DPrintf( "MessageBox HandleMsgCommands 1st frame ignore\n" );
1508                 return;
1509         }
1510         if ( idStr::Icmp( menuCommand, "mid" ) == 0 || idStr::Icmp( menuCommand, "left" ) == 0 ) {
1511                 guiActive = guiMsgRestore;
1512                 guiMsgRestore = NULL;
1513                 msgRunning = false;
1514                 msgRetIndex = 0;
1515                 DispatchCommand( guiActive, msgFireBack[ 0 ].c_str() );
1516         } else if ( idStr::Icmp( menuCommand, "right" ) == 0 ) {
1517                 guiActive = guiMsgRestore;
1518                 guiMsgRestore = NULL;
1519                 msgRunning = false;
1520                 msgRetIndex = 1;
1521                 DispatchCommand( guiActive, msgFireBack[ 1 ].c_str() );
1522         }
1523 }
1524
1525 /*
1526 =================
1527 idSessionLocal::HandleNoteCommands
1528 =================
1529 */
1530 #define NOTEDATFILE "C:/notenumber.dat"
1531
1532 void idSessionLocal::HandleNoteCommands( const char *menuCommand ) {
1533         guiActive = NULL;
1534
1535         if ( idStr::Icmp( menuCommand,  "note" ) == 0 && mapSpawned ) {
1536
1537                 idFile *file = NULL;
1538                 for ( int tries = 0; tries < 10; tries++ ) {
1539                         file = fileSystem->OpenExplicitFileRead( NOTEDATFILE );
1540                         if ( file != NULL ) {
1541                                 break;
1542                         }
1543                         Sys_Sleep( 500 );
1544                 }
1545                 int noteNumber = 1000;
1546                 if ( file ) {
1547                         file->Read( &noteNumber, 4 );
1548                         fileSystem->CloseFile( file );
1549                 }
1550
1551                 int i;
1552                 idStr str, noteNum, shotName, workName, fileName = "viewnotes/";
1553                 idStrList fileList;
1554
1555                 const char *severity = NULL;
1556                 const char *p = guiTakeNotes->State().GetString( "notefile" );
1557                 if ( p == NULL || *p == '\0' ) {
1558                         p = cvarSystem->GetCVarString( "ui_name" );
1559                 }
1560
1561                 bool extended = guiTakeNotes->State().GetBool( "extended" );
1562                 if ( extended ) {
1563                         if ( guiTakeNotes->State().GetInt( "severity" ) == 1 ) {
1564                                 severity = "WishList_Viewnotes/";
1565                         } else {
1566                                 severity = "MustFix_Viewnotes/";
1567                         }
1568                         fileName += severity;
1569
1570                         const idDecl *mapDecl = declManager->FindType(DECL_ENTITYDEF, mapSpawnData.serverInfo.GetString( "si_map" ), false );
1571                         const idDeclEntityDef *mapInfo = static_cast<const idDeclEntityDef *>(mapDecl);
1572
1573                         if ( mapInfo ) {
1574                                 fileName += mapInfo->dict.GetString( "devname" );
1575                         } else {
1576                                 fileName += mapSpawnData.serverInfo.GetString( "si_map" );
1577                                 fileName.StripFileExtension();
1578                         }
1579
1580                         int count = guiTakeNotes->State().GetInt( "person_numsel" );
1581                         if ( count == 0 ) {
1582                                 fileList.Append( fileName + "/Nobody" );
1583                         } else {
1584                                 for ( i = 0; i < count; i++ ) {
1585                                         int person = guiTakeNotes->State().GetInt( va( "person_sel_%i", i ) );
1586                                         workName = fileName + "/";
1587                                         workName += guiTakeNotes->State().GetString( va( "person_item_%i", person ), "Nobody" );
1588                                         fileList.Append( workName );
1589                                 }
1590                         }
1591                 } else {
1592                         fileName += "maps/";
1593                         fileName += mapSpawnData.serverInfo.GetString( "si_map" );
1594                         fileName.StripFileExtension();
1595                         fileList.Append( fileName );
1596                 }
1597
1598                 bool bCon = cvarSystem->GetCVarBool( "con_noPrint" );
1599                 cvarSystem->SetCVarBool( "con_noPrint", true );
1600                 for ( i = 0; i < fileList.Num(); i++ ) {
1601                         workName = fileList[i];
1602                         workName += "/";
1603                         workName += p;
1604                         int workNote = noteNumber;
1605                         R_ScreenshotFilename( workNote, workName, shotName );
1606
1607                         noteNum = shotName;
1608                         noteNum.StripPath();
1609                         noteNum.StripFileExtension();
1610
1611                         if ( severity && *severity ) {
1612                                 workName = severity;
1613                                 workName += "viewNotes";
1614                         }
1615
1616                         sprintf( str, "recordViewNotes \"%s\" \"%s\" \"%s\"\n", workName.c_str(), noteNum.c_str(), guiTakeNotes->State().GetString( "note" ) );
1617                         
1618                         cmdSystem->BufferCommandText( CMD_EXEC_NOW, str );
1619                         cmdSystem->ExecuteCommandBuffer();
1620
1621                         UpdateScreen();
1622                         renderSystem->TakeScreenshot( renderSystem->GetScreenWidth(), renderSystem->GetScreenHeight(), shotName, 1, NULL );
1623                 }
1624                 noteNumber++;
1625
1626                 for ( int tries = 0; tries < 10; tries++ ) {
1627                         file = fileSystem->OpenExplicitFileWrite( "p:/viewnotes/notenumber.dat" );
1628                         if ( file != NULL ) {
1629                                 break;
1630                         }
1631                         Sys_Sleep( 500 );
1632                 }
1633                 if ( file ) {
1634                         file->Write( &noteNumber, 4 );
1635                         fileSystem->CloseFile( file );
1636                 }
1637
1638                 cmdSystem->BufferCommandText( CMD_EXEC_NOW, "closeViewNotes\n" );
1639                 cvarSystem->SetCVarBool( "con_noPrint", bCon );
1640         }
1641 }
1642
1643 /*
1644 ===============
1645 idSessionLocal::SetCDKeyGuiVars
1646 ===============
1647 */
1648 void idSessionLocal::SetCDKeyGuiVars( void ) {
1649         if ( !guiMainMenu ) {
1650                 return;
1651         }
1652         guiMainMenu->SetStateString( "str_d3key_state", common->GetLanguageDict()->GetString( va( "#str_071%d", 86 + cdkey_state ) ) );
1653         guiMainMenu->SetStateString( "str_xpkey_state", common->GetLanguageDict()->GetString( va( "#str_071%d", 86 + xpkey_state ) ) );
1654 }