Session_menu.cpp 47 KB

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