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