]> icculus.org git repositories - icculus/iodoom3.git/blob - neo/framework/Common.cpp
Various Mac OS X tweaks to get this to build. Probably breaking things.
[icculus/iodoom3.git] / neo / framework / Common.cpp
1 /*
2 ===========================================================================
3
4 Doom 3 GPL Source Code
5 Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company. 
6
7 This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?).  
8
9 Doom 3 Source Code is free software: you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation, either version 3 of the License, or
12 (at your option) any later version.
13
14 Doom 3 Source Code is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 GNU General Public License for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with Doom 3 Source Code.  If not, see <http://www.gnu.org/licenses/>.
21
22 In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code.  If not, please request a copy in writing from id Software at the address below.
23
24 If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
25
26 ===========================================================================
27 */
28
29 #include "../idlib/precompiled.h"
30 #pragma hdrstop
31
32 #include "../renderer/Image.h"
33
34 #define MAX_PRINT_MSG_SIZE      4096
35 #define MAX_WARNING_LIST        256
36
37 typedef enum {
38         ERP_NONE,
39         ERP_FATAL,                                              // exit the entire game with a popup window
40         ERP_DROP,                                               // print to console and disconnect from game
41         ERP_DISCONNECT                                  // don't kill server
42 } errorParm_t;
43
44 #if defined( _DEBUG )
45         #define BUILD_DEBUG "-debug"
46 #else
47         #define BUILD_DEBUG ""
48 #endif
49
50 struct version_s {
51                         version_s( void ) { sprintf( string, "%s.%d%s %s %s %s", ENGINE_VERSION, BUILD_NUMBER, BUILD_DEBUG, BUILD_STRING, __DATE__, __TIME__ ); }
52         char    string[256];
53 } version;
54
55 idCVar com_version( "si_version", version.string, CVAR_SYSTEM|CVAR_ROM|CVAR_SERVERINFO, "engine version" );
56 idCVar com_skipRenderer( "com_skipRenderer", "0", CVAR_BOOL|CVAR_SYSTEM, "skip the renderer completely" );
57 idCVar com_machineSpec( "com_machineSpec", "-1", CVAR_INTEGER | CVAR_ARCHIVE | CVAR_SYSTEM, "hardware classification, -1 = not detected, 0 = low quality, 1 = medium quality, 2 = high quality, 3 = ultra quality" );
58 idCVar com_purgeAll( "com_purgeAll", "0", CVAR_BOOL | CVAR_ARCHIVE | CVAR_SYSTEM, "purge everything between level loads" );
59 idCVar com_memoryMarker( "com_memoryMarker", "-1", CVAR_INTEGER | CVAR_SYSTEM | CVAR_INIT, "used as a marker for memory stats" );
60 idCVar com_preciseTic( "com_preciseTic", "1", CVAR_BOOL|CVAR_SYSTEM, "run one game tick every async thread update" );
61 idCVar com_asyncInput( "com_asyncInput", "0", CVAR_BOOL|CVAR_SYSTEM, "sample input from the async thread" );
62 #define ASYNCSOUND_INFO "0: mix sound inline, 1: memory mapped async mix, 2: callback mixing, 3: write async mix"
63 #if defined( MACOS_X )
64 idCVar com_asyncSound( "com_asyncSound", "2", CVAR_INTEGER|CVAR_SYSTEM|CVAR_ROM, ASYNCSOUND_INFO );
65 #elif defined( __linux__ )
66 idCVar com_asyncSound( "com_asyncSound", "3", CVAR_INTEGER|CVAR_SYSTEM|CVAR_ROM, ASYNCSOUND_INFO );
67 #else
68 idCVar com_asyncSound( "com_asyncSound", "1", CVAR_INTEGER|CVAR_SYSTEM, ASYNCSOUND_INFO, 0, 1 );
69 #endif
70 idCVar com_forceGenericSIMD( "com_forceGenericSIMD", "0", CVAR_BOOL | CVAR_SYSTEM | CVAR_NOCHEAT, "force generic platform independent SIMD" );
71 idCVar com_developer( "developer", "0", CVAR_BOOL|CVAR_SYSTEM|CVAR_NOCHEAT, "developer mode" );
72 idCVar com_allowConsole( "com_allowConsole", "0", CVAR_BOOL | CVAR_SYSTEM | CVAR_NOCHEAT, "allow toggling console with the tilde key" );
73 idCVar com_speeds( "com_speeds", "0", CVAR_BOOL|CVAR_SYSTEM|CVAR_NOCHEAT, "show engine timings" );
74 idCVar com_showFPS( "com_showFPS", "0", CVAR_BOOL|CVAR_SYSTEM|CVAR_ARCHIVE|CVAR_NOCHEAT, "show frames rendered per second" );
75 idCVar com_showMemoryUsage( "com_showMemoryUsage", "0", CVAR_BOOL|CVAR_SYSTEM|CVAR_NOCHEAT, "show total and per frame memory usage" );
76 idCVar com_showAsyncStats( "com_showAsyncStats", "0", CVAR_BOOL|CVAR_SYSTEM|CVAR_NOCHEAT, "show async network stats" );
77 idCVar com_showSoundDecoders( "com_showSoundDecoders", "0", CVAR_BOOL|CVAR_SYSTEM|CVAR_NOCHEAT, "show sound decoders" );
78 idCVar com_timestampPrints( "com_timestampPrints", "0", CVAR_SYSTEM, "print time with each console print, 1 = msec, 2 = sec", 0, 2, idCmdSystem::ArgCompletion_Integer<0,2> );
79 idCVar com_timescale( "timescale", "1", CVAR_SYSTEM | CVAR_FLOAT, "scales the time", 0.1f, 10.0f );
80 idCVar com_logFile( "logFile", "0", CVAR_SYSTEM | CVAR_NOCHEAT, "1 = buffer log, 2 = flush after each print", 0, 2, idCmdSystem::ArgCompletion_Integer<0,2> );
81 idCVar com_logFileName( "logFileName", "qconsole.log", CVAR_SYSTEM | CVAR_NOCHEAT, "name of log file, if empty, qconsole.log will be used" );
82 idCVar com_makingBuild( "com_makingBuild", "0", CVAR_BOOL | CVAR_SYSTEM, "1 when making a build" );
83 idCVar com_updateLoadSize( "com_updateLoadSize", "0", CVAR_BOOL | CVAR_SYSTEM | CVAR_NOCHEAT, "update the load size after loading a map" );
84 idCVar com_videoRam( "com_videoRam", "64", CVAR_INTEGER | CVAR_SYSTEM | CVAR_NOCHEAT | CVAR_ARCHIVE, "holds the last amount of detected video ram" );
85
86 idCVar com_product_lang_ext( "com_product_lang_ext", "1", CVAR_INTEGER | CVAR_SYSTEM | CVAR_ARCHIVE, "Extension to use when creating language files." );
87
88 // com_speeds times
89 int                             time_gameFrame;
90 int                             time_gameDraw;
91 int                             time_frontend;                  // renderSystem frontend time
92 int                             time_backend;                   // renderSystem backend time
93
94 int                             com_frameTime;                  // time for the current frame in milliseconds
95 int                             com_frameNumber;                // variable frame number
96 volatile int    com_ticNumber;                  // 60 hz tics
97 int                             com_editors;                    // currently opened editor(s)
98 bool                    com_editorActive;               //  true if an editor has focus
99
100 #ifdef _WIN32
101 HWND                    com_hwndMsg = NULL;
102 bool                    com_outputMsg = false;
103 unsigned int    com_msgID = -1;
104 #endif
105
106 #ifdef __DOOM_DLL__
107 idGame *                game = NULL;
108 idGameEdit *    gameEdit = NULL;
109 #endif
110
111 // writes si_version to the config file - in a kinda obfuscated way
112 //#define ID_WRITE_VERSION
113
114 class idCommonLocal : public idCommon {
115 public:
116                                                                 idCommonLocal( void );
117
118         virtual void                            Init( int argc, const char **argv, const char *cmdline );
119         virtual void                            Shutdown( void );
120         virtual void                            Quit( void );
121         virtual bool                            IsInitialized( void ) const;
122         virtual void                            Frame( void );
123         virtual void                            GUIFrame( bool execCmd, bool network );
124         virtual void                            Async( void );
125         virtual void                            StartupVariable( const char *match, bool once );
126         virtual void                            InitTool( const toolFlag_t tool, const idDict *dict );
127         virtual void                            ActivateTool( bool active );
128         virtual void                            WriteConfigToFile( const char *filename );
129         virtual void                            WriteFlaggedCVarsToFile( const char *filename, int flags, const char *setCmd );
130         virtual void                            BeginRedirect( char *buffer, int buffersize, void (*flush)( const char * ) );
131         virtual void                            EndRedirect( void );
132         virtual void                            SetRefreshOnPrint( bool set );
133         virtual void                            Printf( const char *fmt, ... ) id_attribute((format(printf,2,3)));
134         virtual void                            VPrintf( const char *fmt, va_list arg );
135         virtual void                            DPrintf( const char *fmt, ... ) id_attribute((format(printf,2,3)));
136         virtual void                            Warning( const char *fmt, ... ) id_attribute((format(printf,2,3)));
137         virtual void                            DWarning( const char *fmt, ...) id_attribute((format(printf,2,3)));
138         virtual void                            PrintWarnings( void );
139         virtual void                            ClearWarnings( const char *reason );
140         virtual void                            Error( const char *fmt, ... ) id_attribute((format(printf,2,3)));
141         virtual void                            FatalError( const char *fmt, ... ) id_attribute((format(printf,2,3)));
142         virtual const idLangDict *      GetLanguageDict( void );
143
144         virtual const char *            KeysFromBinding( const char *bind );
145         virtual const char *            BindingFromKey( const char *key );
146
147         virtual int                                     ButtonState( int key );
148         virtual int                                     KeyState( int key );
149
150         void                                            InitGame( void );
151         void                                            ShutdownGame( bool reloading );
152
153         // localization
154         void                                            InitLanguageDict( void );
155         void                                            LocalizeGui( const char *fileName, idLangDict &langDict );
156         void                                            LocalizeMapData( const char *fileName, idLangDict &langDict );
157         void                                            LocalizeSpecificMapData( const char *fileName, idLangDict &langDict, const idLangDict &replaceArgs );
158
159         void                                            SetMachineSpec( void );
160
161 private:
162         void                                            InitCommands( void );
163         void                                            InitRenderSystem( void );
164         void                                            InitSIMD( void );
165         bool                                            AddStartupCommands( void );
166         void                                            ParseCommandLine( int argc, const char **argv );
167         void                                            ClearCommandLine( void );
168         bool                                            SafeMode( void );
169         void                                            CheckToolMode( void );
170         void                                            CloseLogFile( void );
171         void                                            WriteConfiguration( void );
172         void                                            DumpWarnings( void );
173         void                                            SingleAsyncTic( void );
174         void                                            LoadGameDLL( void );
175         void                                            UnloadGameDLL( void );
176         void                                            PrintLoadingMessage( const char *msg );
177         void                                            FilterLangList( idStrList* list, idStr lang );
178
179         bool                                            com_fullyInitialized;
180         bool                                            com_refreshOnPrint;             // update the screen every print for dmap
181         int                                                     com_errorEntered;               // 0, ERP_DROP, etc
182         bool                                            com_shuttingDown;
183
184         idFile *                                        logFile;
185
186         char                                            errorMessage[MAX_PRINT_MSG_SIZE];
187
188         char *                                          rd_buffer;
189         int                                                     rd_buffersize;
190         void                                            (*rd_flush)( const char *buffer );
191
192         idStr                                           warningCaption;
193         idStrList                                       warningList;
194         idStrList                                       errorList;
195
196         int                                                     gameDLL;
197
198         idLangDict                                      languageDict;
199
200 #ifdef ID_WRITE_VERSION
201         idCompressor *                          config_compressor;
202 #endif
203 };
204
205 idCommonLocal   commonLocal;
206 idCommon *              common = &commonLocal;
207
208
209 /*
210 ==================
211 idCommonLocal::idCommonLocal
212 ==================
213 */
214 idCommonLocal::idCommonLocal( void ) {
215         com_fullyInitialized = false;
216         com_refreshOnPrint = false;
217         com_errorEntered = 0;
218         com_shuttingDown = false;
219
220         logFile = NULL;
221
222         strcpy( errorMessage, "" );
223
224         rd_buffer = NULL;
225         rd_buffersize = 0;
226         rd_flush = NULL;
227
228         gameDLL = 0;
229
230 #ifdef ID_WRITE_VERSION
231         config_compressor = NULL;
232 #endif
233 }
234
235 /*
236 ==================
237 idCommonLocal::BeginRedirect
238 ==================
239 */
240 void idCommonLocal::BeginRedirect( char *buffer, int buffersize, void (*flush)( const char *) ) {
241         if ( !buffer || !buffersize || !flush ) {
242                 return;
243         }
244         rd_buffer = buffer;
245         rd_buffersize = buffersize;
246         rd_flush = flush;
247
248         *rd_buffer = 0;
249 }
250
251 /*
252 ==================
253 idCommonLocal::EndRedirect
254 ==================
255 */
256 void idCommonLocal::EndRedirect( void ) {
257         if ( rd_flush && rd_buffer[ 0 ] ) {
258                 rd_flush( rd_buffer );
259         }
260
261         rd_buffer = NULL;
262         rd_buffersize = 0;
263         rd_flush = NULL;
264 }
265
266 #ifdef _WIN32
267
268 /*
269 ==================
270 EnumWindowsProc
271 ==================
272 */
273 BOOL CALLBACK EnumWindowsProc( HWND hwnd, LPARAM lParam ) {
274         char buff[1024];
275
276         ::GetWindowText( hwnd, buff, sizeof( buff ) );
277         if ( idStr::Icmpn( buff, EDITOR_WINDOWTEXT, strlen( EDITOR_WINDOWTEXT ) ) == 0 ) {
278                 com_hwndMsg = hwnd;
279                 return FALSE;
280         }
281         return TRUE;
282 }
283
284 /*
285 ==================
286 FindEditor
287 ==================
288 */
289 bool FindEditor( void ) {
290         com_hwndMsg = NULL;
291         EnumWindows( EnumWindowsProc, 0 );
292         return !( com_hwndMsg == NULL );
293 }
294
295 #endif
296
297 /*
298 ==================
299 idCommonLocal::CloseLogFile
300 ==================
301 */
302 void idCommonLocal::CloseLogFile( void ) {
303         if ( logFile ) {
304                 com_logFile.SetBool( false ); // make sure no further VPrintf attempts to open the log file again
305                 fileSystem->CloseFile( logFile );
306                 logFile = NULL;
307         }
308 }
309
310 /*
311 ==================
312 idCommonLocal::SetRefreshOnPrint
313 ==================
314 */
315 void idCommonLocal::SetRefreshOnPrint( bool set ) {
316         com_refreshOnPrint = set;
317 }
318
319 /*
320 ==================
321 idCommonLocal::VPrintf
322
323 A raw string should NEVER be passed as fmt, because of "%f" type crashes.
324 ==================
325 */
326 void idCommonLocal::VPrintf( const char *fmt, va_list args ) {
327         char            msg[MAX_PRINT_MSG_SIZE];
328         int                     timeLength;
329         static bool     logFileFailed = false;
330
331         // if the cvar system is not initialized
332         if ( !cvarSystem->IsInitialized() ) {
333                 return;
334         }
335
336         // optionally put a timestamp at the beginning of each print,
337         // so we can see how long different init sections are taking
338         if ( com_timestampPrints.GetInteger() ) {
339                 int     t = Sys_Milliseconds();
340                 if ( com_timestampPrints.GetInteger() == 1 ) {
341                         t /= 1000;
342                 }
343                 sprintf( msg, "[%i]", t );
344                 timeLength = strlen( msg );
345         } else {
346                 timeLength = 0;
347         }
348
349         // don't overflow
350         if ( idStr::vsnPrintf( msg+timeLength, MAX_PRINT_MSG_SIZE-timeLength-1, fmt, args ) < 0 ) {
351                 msg[sizeof(msg)-2] = '\n'; msg[sizeof(msg)-1] = '\0'; // avoid output garbling
352                 Sys_Printf( "idCommon::VPrintf: truncated to %d characters\n", strlen(msg)-1 );
353         }
354
355         if ( rd_buffer ) {
356                 if ( (int)( strlen( msg ) + strlen( rd_buffer ) ) > ( rd_buffersize - 1 ) ) {
357                         rd_flush( rd_buffer );
358                         *rd_buffer = 0;
359                 }
360                 strcat( rd_buffer, msg );
361                 return;
362         }
363
364         // echo to console buffer
365         console->Print( msg );
366
367         // remove any color codes
368         idStr::RemoveColors( msg );
369
370         // echo to dedicated console and early console
371         Sys_Printf( "%s", msg );
372
373         // print to script debugger server
374         // DebuggerServerPrint( msg );
375
376 #if 0   // !@#
377 #if defined(_DEBUG) && defined(WIN32)
378         if ( strlen( msg ) < 512 ) {
379                 TRACE( msg );
380         }
381 #endif
382 #endif
383
384         // logFile
385         if ( com_logFile.GetInteger() && !logFileFailed && fileSystem->IsInitialized() ) {
386                 static bool recursing;
387
388                 if ( !logFile && !recursing ) {
389                         struct tm *newtime;
390                         ID_TIME_T aclock;
391                         const char *fileName = com_logFileName.GetString()[0] ? com_logFileName.GetString() : "qconsole.log";
392
393                         // fileSystem->OpenFileWrite can cause recursive prints into here
394                         recursing = true;
395
396                         logFile = fileSystem->OpenFileWrite( fileName );
397                         if ( !logFile ) {
398                                 logFileFailed = true;
399                                 FatalError( "failed to open log file '%s'\n", fileName );
400                         }
401
402                         recursing = false;
403
404                         if ( com_logFile.GetInteger() > 1 ) {
405                                 // force it to not buffer so we get valid
406                                 // data even if we are crashing
407                                 logFile->ForceFlush();
408                         }
409
410                         time( &aclock );
411                         newtime = localtime( &aclock );
412                         Printf( "log file '%s' opened on %s\n", fileName, asctime( newtime ) );
413                 }
414                 if ( logFile ) {
415                         logFile->Write( msg, strlen( msg ) );
416                         logFile->Flush();       // ForceFlush doesn't help a whole lot
417                 }
418         }
419
420         // don't trigger any updates if we are in the process of doing a fatal error
421         if ( com_errorEntered != ERP_FATAL ) {
422                 // update the console if we are in a long-running command, like dmap
423                 if ( com_refreshOnPrint ) {
424                         session->UpdateScreen();
425                 }
426
427                 // let session redraw the animated loading screen if necessary
428                 session->PacifierUpdate();
429         }
430
431 #ifdef _WIN32
432
433         if ( com_outputMsg ) {
434                 if ( com_msgID == -1 ) {
435                         com_msgID = ::RegisterWindowMessage( DMAP_MSGID );
436                         if ( !FindEditor() ) {
437                                 com_outputMsg = false;
438                         } else {
439                                 Sys_ShowWindow( false );
440                         }
441                 }
442                 if ( com_hwndMsg ) {
443                         ATOM atom = ::GlobalAddAtom( msg );
444                         ::PostMessage( com_hwndMsg, com_msgID, 0, static_cast<LPARAM>(atom) );
445                 }
446         }
447
448 #endif
449 }
450
451 /*
452 ==================
453 idCommonLocal::Printf
454
455 Both client and server can use this, and it will output to the appropriate place.
456
457 A raw string should NEVER be passed as fmt, because of "%f" type crashers.
458 ==================
459 */
460 void idCommonLocal::Printf( const char *fmt, ... ) {
461         va_list argptr;
462         va_start( argptr, fmt );
463         VPrintf( fmt, argptr );
464         va_end( argptr );
465 }
466
467 /*
468 ==================
469 idCommonLocal::DPrintf
470
471 prints message that only shows up if the "developer" cvar is set
472 ==================
473 */
474 void idCommonLocal::DPrintf( const char *fmt, ... ) {
475         va_list         argptr;
476         char            msg[MAX_PRINT_MSG_SIZE];
477                 
478         if ( !cvarSystem->IsInitialized() || !com_developer.GetBool() ) {
479                 return;                 // don't confuse non-developers with techie stuff...
480         }
481
482         va_start( argptr, fmt );
483         idStr::vsnPrintf( msg, sizeof(msg), fmt, argptr );
484         va_end( argptr );
485         msg[sizeof(msg)-1] = '\0';
486         
487         // never refresh the screen, which could cause reentrency problems
488         bool temp = com_refreshOnPrint;
489         com_refreshOnPrint = false;
490
491         Printf( S_COLOR_RED"%s", msg );
492
493         com_refreshOnPrint = temp;
494 }
495
496 /*
497 ==================
498 idCommonLocal::DWarning
499
500 prints warning message in yellow that only shows up if the "developer" cvar is set
501 ==================
502 */
503 void idCommonLocal::DWarning( const char *fmt, ... ) {
504         va_list         argptr;
505         char            msg[MAX_PRINT_MSG_SIZE];
506                 
507         if ( !com_developer.GetBool() ) {
508                 return;                 // don't confuse non-developers with techie stuff...
509         }
510
511         va_start( argptr, fmt );
512         idStr::vsnPrintf( msg, sizeof(msg), fmt, argptr );
513         va_end( argptr );
514         msg[sizeof(msg)-1] = '\0';
515
516         Printf( S_COLOR_YELLOW"WARNING: %s\n", msg );
517 }
518
519 /*
520 ==================
521 idCommonLocal::Warning
522
523 prints WARNING %s and adds the warning message to a queue to be printed later on
524 ==================
525 */
526 void idCommonLocal::Warning( const char *fmt, ... ) {
527         va_list         argptr;
528         char            msg[MAX_PRINT_MSG_SIZE];
529                 
530         va_start( argptr, fmt );
531         idStr::vsnPrintf( msg, sizeof(msg), fmt, argptr );
532         va_end( argptr );
533         msg[sizeof(msg)-1] = 0;
534
535         Printf( S_COLOR_YELLOW "WARNING: " S_COLOR_RED "%s\n", msg );
536
537         if ( warningList.Num() < MAX_WARNING_LIST ) {
538                 warningList.AddUnique( msg );
539         }
540 }
541
542 /*
543 ==================
544 idCommonLocal::PrintWarnings
545 ==================
546 */
547 void idCommonLocal::PrintWarnings( void ) {
548         int i;
549
550         if ( !warningList.Num() ) {
551                 return;
552         }
553
554         warningList.Sort();
555
556         Printf( "------------- Warnings ---------------\n" );
557         Printf( "during %s...\n", warningCaption.c_str() );
558
559         for ( i = 0; i < warningList.Num(); i++ ) {
560                 Printf( S_COLOR_YELLOW "WARNING: " S_COLOR_RED "%s\n", warningList[i].c_str() );
561         }
562         if ( warningList.Num() ) {
563                 if ( warningList.Num() >= MAX_WARNING_LIST ) {
564                         Printf( "more than %d warnings\n", MAX_WARNING_LIST );
565                 } else {
566                         Printf( "%d warnings\n", warningList.Num() );
567                 }
568         }
569 }
570
571 /*
572 ==================
573 idCommonLocal::ClearWarnings
574 ==================
575 */
576 void idCommonLocal::ClearWarnings( const char *reason ) {
577         warningCaption = reason;
578         warningList.Clear();
579 }
580
581 /*
582 ==================
583 idCommonLocal::DumpWarnings
584 ==================
585 */
586 void idCommonLocal::DumpWarnings( void ) {
587         int                     i;
588         idFile          *warningFile;
589
590         if ( !warningList.Num() ) {
591                 return;
592         }
593
594         warningFile = fileSystem->OpenFileWrite( "warnings.txt", "fs_savepath" );
595         if ( warningFile ) {
596
597                 warningFile->Printf( "------------- Warnings ---------------\n\n" );
598                 warningFile->Printf( "during %s...\n", warningCaption.c_str() );
599                 warningList.Sort();
600                 for ( i = 0; i < warningList.Num(); i++ ) {
601                         warningList[i].RemoveColors();
602                         warningFile->Printf( "WARNING: %s\n", warningList[i].c_str() );
603                 }
604                 if ( warningList.Num() >= MAX_WARNING_LIST ) {
605                         warningFile->Printf( "\nmore than %d warnings!\n", MAX_WARNING_LIST );
606                 } else {
607                         warningFile->Printf( "\n%d warnings.\n", warningList.Num() );
608                 }
609
610                 warningFile->Printf( "\n\n-------------- Errors ---------------\n\n" );
611                 errorList.Sort();
612                 for ( i = 0; i < errorList.Num(); i++ ) {
613                         errorList[i].RemoveColors();
614                         warningFile->Printf( "ERROR: %s", errorList[i].c_str() );
615                 }
616
617                 warningFile->ForceFlush();
618
619                 fileSystem->CloseFile( warningFile );
620
621 #if defined(_WIN32) && !defined(_DEBUG)
622                 idStr   osPath;
623                 osPath = fileSystem->RelativePathToOSPath( "warnings.txt", "fs_savepath" );
624                 WinExec( va( "Notepad.exe %s", osPath.c_str() ), SW_SHOW );
625 #endif
626         }
627 }
628
629 /*
630 ==================
631 idCommonLocal::Error
632 ==================
633 */
634 void idCommonLocal::Error( const char *fmt, ... ) {
635         va_list         argptr;
636         static int      lastErrorTime;
637         static int      errorCount;
638         int                     currentTime;
639
640         int code = ERP_DROP;
641
642         // always turn this off after an error
643         com_refreshOnPrint = false;
644
645         // when we are running automated scripts, make sure we
646         // know if anything failed
647         if ( cvarSystem->GetCVarInteger( "fs_copyfiles" ) ) {
648                 code = ERP_FATAL;
649         }
650
651         // if we don't have GL running, make it a fatal error
652         if ( !renderSystem->IsOpenGLRunning() ) {
653                 code = ERP_FATAL;
654         }
655
656         // if we got a recursive error, make it fatal
657         if ( com_errorEntered ) {
658                 // if we are recursively erroring while exiting
659                 // from a fatal error, just kill the entire
660                 // process immediately, which will prevent a
661                 // full screen rendering window covering the
662                 // error dialog
663                 if ( com_errorEntered == ERP_FATAL ) {
664                         Sys_Quit();
665                 }
666                 code = ERP_FATAL;
667         }
668
669         // if we are getting a solid stream of ERP_DROP, do an ERP_FATAL
670         currentTime = Sys_Milliseconds();
671         if ( currentTime - lastErrorTime < 100 ) {
672                 if ( ++errorCount > 3 ) {
673                         code = ERP_FATAL;
674                 }
675         } else {
676                 errorCount = 0;
677         }
678         lastErrorTime = currentTime;
679
680         com_errorEntered = code;
681
682         va_start (argptr,fmt);
683         idStr::vsnPrintf( errorMessage, sizeof(errorMessage), fmt, argptr );
684         va_end (argptr);
685         errorMessage[sizeof(errorMessage)-1] = '\0';
686
687         // copy the error message to the clip board
688         Sys_SetClipboardData( errorMessage );
689
690         // add the message to the error list
691         errorList.AddUnique( errorMessage );
692
693         // Dont shut down the session for gui editor or debugger
694         if ( !( com_editors & ( EDITOR_GUI | EDITOR_DEBUGGER ) ) ) {
695                 session->Stop();
696         }
697
698         if ( code == ERP_DISCONNECT ) {
699                 com_errorEntered = 0;
700                 throw idException( errorMessage );
701         // The gui editor doesnt want thing to com_error so it handles exceptions instead
702         } else if( com_editors & ( EDITOR_GUI | EDITOR_DEBUGGER ) ) {
703                 com_errorEntered = 0;
704                 throw idException( errorMessage );
705         } else if ( code == ERP_DROP ) {
706                 Printf( "********************\nERROR: %s\n********************\n", errorMessage );
707                 com_errorEntered = 0;
708                 throw idException( errorMessage );
709         } else {
710                 Printf( "********************\nERROR: %s\n********************\n", errorMessage );
711         }
712
713         if ( cvarSystem->GetCVarBool( "r_fullscreen" ) ) {
714                 cmdSystem->BufferCommandText( CMD_EXEC_NOW, "vid_restart partial windowed\n" );
715         }
716
717         Shutdown();
718
719         Sys_Error( "%s", errorMessage );
720 }
721
722 /*
723 ==================
724 idCommonLocal::FatalError
725
726 Dump out of the game to a system dialog
727 ==================
728 */
729 void idCommonLocal::FatalError( const char *fmt, ... ) {
730         va_list         argptr;
731
732         // if we got a recursive error, make it fatal
733         if ( com_errorEntered ) {
734                 // if we are recursively erroring while exiting
735                 // from a fatal error, just kill the entire
736                 // process immediately, which will prevent a
737                 // full screen rendering window covering the
738                 // error dialog
739
740                 Sys_Printf( "FATAL: recursed fatal error:\n%s\n", errorMessage );
741
742                 va_start( argptr, fmt );
743                 idStr::vsnPrintf( errorMessage, sizeof(errorMessage), fmt, argptr );
744                 va_end( argptr );
745                 errorMessage[sizeof(errorMessage)-1] = '\0';
746
747                 Sys_Printf( "%s\n", errorMessage );
748
749                 // write the console to a log file?
750                 Sys_Quit();
751         }
752         com_errorEntered = ERP_FATAL;
753
754         va_start( argptr, fmt );
755         idStr::vsnPrintf( errorMessage, sizeof(errorMessage), fmt, argptr );
756         va_end( argptr );
757         errorMessage[sizeof(errorMessage)-1] = '\0';
758
759         if ( cvarSystem->GetCVarBool( "r_fullscreen" ) ) {
760                 cmdSystem->BufferCommandText( CMD_EXEC_NOW, "vid_restart partial windowed\n" );
761         }
762
763         Sys_SetFatalError( errorMessage );
764
765         Shutdown();
766
767         Sys_Error( "%s", errorMessage );
768 }
769
770 /*
771 ==================
772 idCommonLocal::Quit
773 ==================
774 */
775 void idCommonLocal::Quit( void ) {
776
777 #ifdef ID_ALLOW_TOOLS
778         if ( com_editors & EDITOR_RADIANT ) {
779                 RadiantInit();
780                 return;
781         }
782 #endif
783
784         // don't try to shutdown if we are in a recursive error
785         if ( !com_errorEntered ) {
786                 Shutdown();
787         }
788
789         Sys_Quit();
790 }
791
792
793 /*
794 ============================================================================
795
796 COMMAND LINE FUNCTIONS
797
798 + characters separate the commandLine string into multiple console
799 command lines.
800
801 All of these are valid:
802
803 doom +set test blah +map test
804 doom set test blah+map test
805 doom set test blah + map test
806
807 ============================================================================
808 */
809
810 #define         MAX_CONSOLE_LINES       32
811 int                     com_numConsoleLines;
812 idCmdArgs       com_consoleLines[MAX_CONSOLE_LINES];
813
814 /*
815 ==================
816 idCommonLocal::ParseCommandLine
817 ==================
818 */
819 void idCommonLocal::ParseCommandLine( int argc, const char **argv ) {
820         int i, current_count;
821
822         com_numConsoleLines = 0;
823         current_count = 0;
824         // API says no program path
825         for ( i = 0; i < argc; i++ ) {
826                 if ( argv[ i ][ 0 ] == '+' ) {
827                         com_numConsoleLines++;
828                         com_consoleLines[ com_numConsoleLines-1 ].AppendArg( argv[ i ] + 1 );
829                 } else {
830                         if ( !com_numConsoleLines ) {
831                                 com_numConsoleLines++;
832                         }
833                         com_consoleLines[ com_numConsoleLines-1 ].AppendArg( argv[ i ] );
834                 }
835         }
836 }
837
838 /*
839 ==================
840 idCommonLocal::ClearCommandLine
841 ==================
842 */
843 void idCommonLocal::ClearCommandLine( void ) {
844         com_numConsoleLines = 0;
845 }
846
847 /*
848 ==================
849 idCommonLocal::SafeMode
850
851 Check for "safe" on the command line, which will
852 skip loading of config file (DoomConfig.cfg)
853 ==================
854 */
855 bool idCommonLocal::SafeMode( void ) {
856         int                     i;
857
858         for ( i = 0 ; i < com_numConsoleLines ; i++ ) {
859                 if ( !idStr::Icmp( com_consoleLines[ i ].Argv(0), "safe" )
860                         || !idStr::Icmp( com_consoleLines[ i ].Argv(0), "cvar_restart" ) ) {
861                         com_consoleLines[ i ].Clear();
862                         return true;
863                 }
864         }
865         return false;
866 }
867
868 /*
869 ==================
870 idCommonLocal::CheckToolMode
871
872 Check for "renderbump", "dmap", or "editor" on the command line,
873 and force fullscreen off in those cases
874 ==================
875 */
876 void idCommonLocal::CheckToolMode( void ) {
877         int                     i;
878
879         for ( i = 0 ; i < com_numConsoleLines ; i++ ) {
880                 if ( !idStr::Icmp( com_consoleLines[ i ].Argv(0), "guieditor" ) ) {
881                         com_editors |= EDITOR_GUI;
882                 }
883                 else if ( !idStr::Icmp( com_consoleLines[ i ].Argv(0), "debugger" ) ) {
884                         com_editors |= EDITOR_DEBUGGER;
885                 }
886                 else if ( !idStr::Icmp( com_consoleLines[ i ].Argv(0), "editor" ) ) {
887                         com_editors |= EDITOR_RADIANT;
888                 }
889                 // Nerve: Add support for the material editor
890                 else if ( !idStr::Icmp( com_consoleLines[ i ].Argv(0), "materialEditor" ) ) {
891                         com_editors |= EDITOR_MATERIAL;
892                 }
893                 
894                 if ( !idStr::Icmp( com_consoleLines[ i ].Argv(0), "renderbump" )
895                         || !idStr::Icmp( com_consoleLines[ i ].Argv(0), "editor" )
896                         || !idStr::Icmp( com_consoleLines[ i ].Argv(0), "guieditor" )
897                         || !idStr::Icmp( com_consoleLines[ i ].Argv(0), "debugger" )
898                         || !idStr::Icmp( com_consoleLines[ i ].Argv(0), "dmap" )
899                         || !idStr::Icmp( com_consoleLines[ i ].Argv(0), "materialEditor" )
900                         ) {
901                         cvarSystem->SetCVarBool( "r_fullscreen", false );
902                         return;
903                 }
904         }
905 }
906
907 /*
908 ==================
909 idCommonLocal::StartupVariable
910
911 Searches for command line parameters that are set commands.
912 If match is not NULL, only that cvar will be looked for.
913 That is necessary because cddir and basedir need to be set
914 before the filesystem is started, but all other sets should
915 be after execing the config and default.
916 ==================
917 */
918 void idCommonLocal::StartupVariable( const char *match, bool once ) {
919         int                     i;
920         const char *s;
921
922         i = 0;
923         while ( i < com_numConsoleLines ) {
924                 if ( strcmp( com_consoleLines[ i ].Argv( 0 ), "set" ) ) {
925                         i++;
926                         continue;
927                 }
928
929                 s = com_consoleLines[ i ].Argv(1);
930
931                 if ( !match || !idStr::Icmp( s, match ) ) {
932                         cvarSystem->SetCVarString( s, com_consoleLines[ i ].Argv( 2 ) );
933                         if ( once ) {
934                                 // kill the line
935                                 int j = i + 1;
936                                 while ( j < com_numConsoleLines ) {
937                                         com_consoleLines[ j - 1 ] = com_consoleLines[ j ];
938                                         j++;
939                                 }
940                                 com_numConsoleLines--;
941                                 continue;
942                         }
943                 }
944                 i++;
945         }
946 }
947
948 /*
949 ==================
950 idCommonLocal::AddStartupCommands
951
952 Adds command line parameters as script statements
953 Commands are separated by + signs
954
955 Returns true if any late commands were added, which
956 will keep the demoloop from immediately starting
957 ==================
958 */
959 bool idCommonLocal::AddStartupCommands( void ) {
960         int             i;
961         bool    added;
962
963         added = false;
964         // quote every token, so args with semicolons can work
965         for ( i = 0; i < com_numConsoleLines; i++ ) {
966                 if ( !com_consoleLines[i].Argc() ) {
967                         continue;
968                 }
969
970                 // set commands won't override menu startup
971                 if ( idStr::Icmpn( com_consoleLines[i].Argv(0), "set", 3 ) ) {
972                         added = true;
973                 }
974                 // directly as tokenized so nothing gets screwed
975                 cmdSystem->BufferCommandArgs( CMD_EXEC_APPEND, com_consoleLines[i] );
976         }
977
978         return added;
979 }
980
981 /*
982 =================
983 idCommonLocal::InitTool
984 =================
985 */
986 void idCommonLocal::InitTool( const toolFlag_t tool, const idDict *dict ) {
987 #ifdef ID_ALLOW_TOOLS
988         if ( tool & EDITOR_SOUND ) {
989                 SoundEditorInit( dict );
990         } else if ( tool & EDITOR_LIGHT ) {
991                 LightEditorInit( dict );
992         } else if ( tool & EDITOR_PARTICLE ) {
993                 ParticleEditorInit( dict );
994         } else if ( tool & EDITOR_AF ) {
995                 AFEditorInit( dict );
996         }
997 #endif
998 }
999
1000 /*
1001 ==================
1002 idCommonLocal::ActivateTool
1003
1004 Activates or Deactivates a tool
1005 ==================
1006 */
1007 void idCommonLocal::ActivateTool( bool active ) {
1008         com_editorActive = active;
1009         Sys_GrabMouseCursor( !active );
1010 }
1011
1012 /*
1013 ==================
1014 idCommonLocal::WriteFlaggedCVarsToFile
1015 ==================
1016 */
1017 void idCommonLocal::WriteFlaggedCVarsToFile( const char *filename, int flags, const char *setCmd ) {
1018         idFile *f;
1019
1020         f = fileSystem->OpenFileWrite( filename );
1021         if ( !f ) {
1022                 Printf( "Couldn't write %s.\n", filename );
1023                 return;
1024         }
1025         cvarSystem->WriteFlaggedVariables( flags, setCmd, f );
1026         fileSystem->CloseFile( f );
1027 }
1028
1029 /*
1030 ==================
1031 idCommonLocal::WriteConfigToFile
1032 ==================
1033 */
1034 void idCommonLocal::WriteConfigToFile( const char *filename ) {
1035         idFile *f;
1036 #ifdef ID_WRITE_VERSION
1037         ID_TIME_T t;
1038         char *curtime;
1039         idStr runtag;
1040         idFile_Memory compressed( "compressed" );
1041         idBase64 out;
1042 #endif
1043
1044         f = fileSystem->OpenFileWrite( filename );
1045         if ( !f ) {
1046                 Printf ("Couldn't write %s.\n", filename );
1047                 return;
1048         }
1049
1050 #ifdef ID_WRITE_VERSION
1051         assert( config_compressor );
1052         t = time( NULL );
1053         curtime = ctime( &t );
1054         sprintf( runtag, "%s - %s", cvarSystem->GetCVarString( "si_version" ), curtime );
1055         config_compressor->Init( &compressed, true, 8 );
1056         config_compressor->Write( runtag.c_str(), runtag.Length() );
1057         config_compressor->FinishCompress( );
1058         out.Encode( (const byte *)compressed.GetDataPtr(), compressed.Length() );
1059         f->Printf( "// %s\n", out.c_str() );
1060 #endif
1061
1062         idKeyInput::WriteBindings( f );
1063         cvarSystem->WriteFlaggedVariables( CVAR_ARCHIVE, "seta", f );
1064         fileSystem->CloseFile( f );
1065 }
1066
1067 /*
1068 ===============
1069 idCommonLocal::WriteConfiguration
1070
1071 Writes key bindings and archived cvars to config file if modified
1072 ===============
1073 */
1074 void idCommonLocal::WriteConfiguration( void ) {
1075         // if we are quiting without fully initializing, make sure
1076         // we don't write out anything
1077         if ( !com_fullyInitialized ) {
1078                 return;
1079         }
1080
1081         if ( !( cvarSystem->GetModifiedFlags() & CVAR_ARCHIVE ) ) {
1082                 return;
1083         }
1084         cvarSystem->ClearModifiedFlags( CVAR_ARCHIVE );
1085
1086         // disable printing out the "Writing to:" message
1087         bool developer = com_developer.GetBool();
1088         com_developer.SetBool( false );
1089
1090         WriteConfigToFile( CONFIG_FILE );
1091         session->WriteCDKey( );
1092
1093         // restore the developer cvar
1094         com_developer.SetBool( developer );
1095 }
1096
1097 /*
1098 ===============
1099 KeysFromBinding()
1100 Returns the key bound to the command
1101 ===============
1102 */
1103 const char* idCommonLocal::KeysFromBinding( const char *bind ) {
1104         return idKeyInput::KeysFromBinding( bind );
1105 }
1106
1107 /*
1108 ===============
1109 BindingFromKey()
1110 Returns the binding bound to key
1111 ===============
1112 */
1113 const char* idCommonLocal::BindingFromKey( const char *key ) {
1114         return idKeyInput::BindingFromKey( key );
1115 }
1116
1117 /*
1118 ===============
1119 ButtonState()
1120 Returns the state of the button
1121 ===============
1122 */
1123 int     idCommonLocal::ButtonState( int key ) {
1124         return usercmdGen->ButtonState(key);
1125 }
1126
1127 /*
1128 ===============
1129 ButtonState()
1130 Returns the state of the key
1131 ===============
1132 */
1133 int     idCommonLocal::KeyState( int key ) {
1134         return usercmdGen->KeyState(key);
1135 }
1136
1137 //============================================================================
1138
1139 #ifdef ID_ALLOW_TOOLS
1140 /*
1141 ==================
1142 Com_Editor_f
1143
1144   we can start the editor dynamically, but we won't ever get back
1145 ==================
1146 */
1147 static void Com_Editor_f( const idCmdArgs &args ) {
1148         RadiantInit();
1149 }
1150
1151 /*
1152 =============
1153 Com_ScriptDebugger_f
1154 =============
1155 */
1156 static void Com_ScriptDebugger_f( const idCmdArgs &args ) {
1157         // Make sure it wasnt on the command line
1158         if ( !( com_editors & EDITOR_DEBUGGER ) ) {
1159                 common->Printf( "Script debugger is currently disabled\n" );
1160                 // DebuggerClientLaunch();
1161         }
1162 }
1163
1164 /*
1165 =============
1166 Com_EditGUIs_f
1167 =============
1168 */
1169 static void Com_EditGUIs_f( const idCmdArgs &args ) {
1170         GUIEditorInit();
1171 }
1172
1173 /*
1174 =============
1175 Com_MaterialEditor_f
1176 =============
1177 */
1178 static void Com_MaterialEditor_f( const idCmdArgs &args ) {
1179         // Turn off sounds
1180         soundSystem->SetMute( true );
1181         MaterialEditorInit();
1182 }
1183 #endif // ID_ALLOW_TOOLS
1184
1185 /*
1186 ============
1187 idCmdSystemLocal::PrintMemInfo_f
1188
1189 This prints out memory debugging data
1190 ============
1191 */
1192 static void PrintMemInfo_f( const idCmdArgs &args ) {
1193         MemInfo_t mi;
1194
1195         memset( &mi, 0, sizeof( mi ) );
1196         mi.filebase = session->GetCurrentMapName();
1197
1198         renderSystem->PrintMemInfo( &mi );                      // textures and models
1199         soundSystem->PrintMemInfo( &mi );                       // sounds
1200
1201         common->Printf( " Used image memory: %s bytes\n", idStr::FormatNumber( mi.imageAssetsTotal ).c_str() );
1202         mi.assetTotals += mi.imageAssetsTotal;
1203
1204         common->Printf( " Used model memory: %s bytes\n", idStr::FormatNumber( mi.modelAssetsTotal ).c_str() );
1205         mi.assetTotals += mi.modelAssetsTotal;
1206
1207         common->Printf( " Used sound memory: %s bytes\n", idStr::FormatNumber( mi.soundAssetsTotal ).c_str() );
1208         mi.assetTotals += mi.soundAssetsTotal;
1209
1210         common->Printf( " Used asset memory: %s bytes\n", idStr::FormatNumber( mi.assetTotals ).c_str() );
1211
1212         // write overview file
1213         idFile *f;
1214
1215         f = fileSystem->OpenFileAppend( "maps/printmeminfo.txt" );
1216         if ( !f ) {
1217                 return;
1218         }
1219
1220         f->Printf( "total(%s ) image(%s ) model(%s ) sound(%s ): %s\n", idStr::FormatNumber( mi.assetTotals ).c_str(), idStr::FormatNumber( mi.imageAssetsTotal ).c_str(), 
1221                 idStr::FormatNumber( mi.modelAssetsTotal ).c_str(), idStr::FormatNumber( mi.soundAssetsTotal ).c_str(), mi.filebase.c_str() );
1222
1223         fileSystem->CloseFile( f );
1224 }
1225
1226 #ifdef ID_ALLOW_TOOLS
1227 /*
1228 ==================
1229 Com_EditLights_f
1230 ==================
1231 */
1232 static void Com_EditLights_f( const idCmdArgs &args ) {
1233         LightEditorInit( NULL );
1234         cvarSystem->SetCVarInteger( "g_editEntityMode", 1 );
1235 }
1236
1237 /*
1238 ==================
1239 Com_EditSounds_f
1240 ==================
1241 */
1242 static void Com_EditSounds_f( const idCmdArgs &args ) {
1243         SoundEditorInit( NULL );
1244         cvarSystem->SetCVarInteger( "g_editEntityMode", 2 );
1245 }
1246
1247 /*
1248 ==================
1249 Com_EditDecls_f
1250 ==================
1251 */
1252 static void Com_EditDecls_f( const idCmdArgs &args ) {
1253         DeclBrowserInit( NULL );
1254 }
1255
1256 /*
1257 ==================
1258 Com_EditAFs_f
1259 ==================
1260 */
1261 static void Com_EditAFs_f( const idCmdArgs &args ) {
1262         AFEditorInit( NULL );
1263 }
1264
1265 /*
1266 ==================
1267 Com_EditParticles_f
1268 ==================
1269 */
1270 static void Com_EditParticles_f( const idCmdArgs &args ) {
1271         ParticleEditorInit( NULL );
1272 }
1273
1274 /*
1275 ==================
1276 Com_EditScripts_f
1277 ==================
1278 */
1279 static void Com_EditScripts_f( const idCmdArgs &args ) {
1280         ScriptEditorInit( NULL );
1281 }
1282
1283 /*
1284 ==================
1285 Com_EditPDAs_f
1286 ==================
1287 */
1288 static void Com_EditPDAs_f( const idCmdArgs &args ) {
1289         PDAEditorInit( NULL );
1290 }
1291 #endif // ID_ALLOW_TOOLS
1292
1293 /*
1294 ==================
1295 Com_Error_f
1296
1297 Just throw a fatal error to test error shutdown procedures.
1298 ==================
1299 */
1300 static void Com_Error_f( const idCmdArgs &args ) {
1301         if ( !com_developer.GetBool() ) {
1302                 commonLocal.Printf( "error may only be used in developer mode\n" );
1303                 return;
1304         }
1305
1306         if ( args.Argc() > 1 ) {
1307                 commonLocal.FatalError( "Testing fatal error" );
1308         } else {
1309                 commonLocal.Error( "Testing drop error" );
1310         }
1311 }
1312
1313 /*
1314 ==================
1315 Com_Freeze_f
1316
1317 Just freeze in place for a given number of seconds to test error recovery.
1318 ==================
1319 */
1320 static void Com_Freeze_f( const idCmdArgs &args ) {
1321         float   s;
1322         int             start, now;
1323
1324         if ( args.Argc() != 2 ) {
1325                 commonLocal.Printf( "freeze <seconds>\n" );
1326                 return;
1327         }
1328
1329         if ( !com_developer.GetBool() ) {
1330                 commonLocal.Printf( "freeze may only be used in developer mode\n" );
1331                 return;
1332         }
1333
1334         s = atof( args.Argv(1) );
1335
1336         start = eventLoop->Milliseconds();
1337
1338         while ( 1 ) {
1339                 now = eventLoop->Milliseconds();
1340                 if ( ( now - start ) * 0.001f > s ) {
1341                         break;
1342                 }
1343         }
1344 }
1345
1346 /*
1347 =================
1348 Com_Crash_f
1349
1350 A way to force a bus error for development reasons
1351 =================
1352 */
1353 static void Com_Crash_f( const idCmdArgs &args ) {
1354         if ( !com_developer.GetBool() ) {
1355                 commonLocal.Printf( "crash may only be used in developer mode\n" );
1356                 return;
1357         }
1358
1359         * ( int * ) 0 = 0x12345678;
1360 }
1361
1362 /*
1363 =================
1364 Com_Quit_f
1365 =================
1366 */
1367 static void Com_Quit_f( const idCmdArgs &args ) {
1368         commonLocal.Quit();
1369 }
1370
1371 /*
1372 ===============
1373 Com_WriteConfig_f
1374
1375 Write the config file to a specific name
1376 ===============
1377 */
1378 void Com_WriteConfig_f( const idCmdArgs &args ) {
1379         idStr   filename;
1380
1381         if ( args.Argc() != 2 ) {
1382                 commonLocal.Printf( "Usage: writeconfig <filename>\n" );
1383                 return;
1384         }
1385
1386         filename = args.Argv(1);
1387         filename.DefaultFileExtension( ".cfg" );
1388         commonLocal.Printf( "Writing %s.\n", filename.c_str() );
1389         commonLocal.WriteConfigToFile( filename );
1390 }
1391
1392 /*
1393 =================
1394 Com_SetMachineSpecs_f
1395 =================
1396 */
1397 void Com_SetMachineSpec_f( const idCmdArgs &args ) {
1398         commonLocal.SetMachineSpec();
1399 }
1400
1401 /*
1402 =================
1403 Com_ExecMachineSpecs_f
1404 =================
1405 */
1406 #ifdef MACOS_X
1407 void OSX_GetVideoCard( int& outVendorId, int& outDeviceId );
1408 bool OSX_GetCPUIdentification( int& cpuId, bool& oldArchitecture );
1409 #endif
1410 void Com_ExecMachineSpec_f( const idCmdArgs &args ) {
1411         if ( com_machineSpec.GetInteger() == 3 ) {
1412                 cvarSystem->SetCVarInteger( "image_anisotropy", 1, CVAR_ARCHIVE );
1413                 cvarSystem->SetCVarInteger( "image_lodbias", 0, CVAR_ARCHIVE );
1414                 cvarSystem->SetCVarInteger( "image_forceDownSize", 0, CVAR_ARCHIVE );
1415                 cvarSystem->SetCVarInteger( "image_roundDown", 1, CVAR_ARCHIVE );
1416                 cvarSystem->SetCVarInteger( "image_preload", 1, CVAR_ARCHIVE );
1417                 cvarSystem->SetCVarInteger( "image_useAllFormats", 1, CVAR_ARCHIVE );
1418                 cvarSystem->SetCVarInteger( "image_downSizeSpecular", 0, CVAR_ARCHIVE );
1419                 cvarSystem->SetCVarInteger( "image_downSizeBump", 0, CVAR_ARCHIVE );
1420                 cvarSystem->SetCVarInteger( "image_downSizeSpecularLimit", 64, CVAR_ARCHIVE );
1421                 cvarSystem->SetCVarInteger( "image_downSizeBumpLimit", 256, CVAR_ARCHIVE );
1422                 cvarSystem->SetCVarInteger( "image_usePrecompressedTextures", 0, CVAR_ARCHIVE );
1423                 cvarSystem->SetCVarInteger( "image_downsize", 0                 , CVAR_ARCHIVE );
1424                 cvarSystem->SetCVarString( "image_filter", "GL_LINEAR_MIPMAP_LINEAR", CVAR_ARCHIVE );
1425                 cvarSystem->SetCVarInteger( "image_anisotropy", 8, CVAR_ARCHIVE );
1426                 cvarSystem->SetCVarInteger( "image_useCompression", 0, CVAR_ARCHIVE );
1427                 cvarSystem->SetCVarInteger( "image_ignoreHighQuality", 0, CVAR_ARCHIVE );
1428                 cvarSystem->SetCVarInteger( "s_maxSoundsPerShader", 0, CVAR_ARCHIVE );
1429                 cvarSystem->SetCVarInteger( "r_mode", 5, CVAR_ARCHIVE );
1430                 cvarSystem->SetCVarInteger( "image_useNormalCompression", 0, CVAR_ARCHIVE );
1431                 cvarSystem->SetCVarInteger( "r_multiSamples", 0, CVAR_ARCHIVE );
1432         } else if ( com_machineSpec.GetInteger() == 2 ) {
1433                 cvarSystem->SetCVarString( "image_filter", "GL_LINEAR_MIPMAP_LINEAR", CVAR_ARCHIVE );
1434                 cvarSystem->SetCVarInteger( "image_anisotropy", 1, CVAR_ARCHIVE );
1435                 cvarSystem->SetCVarInteger( "image_lodbias", 0, CVAR_ARCHIVE );
1436                 cvarSystem->SetCVarInteger( "image_forceDownSize", 0, CVAR_ARCHIVE );
1437                 cvarSystem->SetCVarInteger( "image_roundDown", 1, CVAR_ARCHIVE );
1438                 cvarSystem->SetCVarInteger( "image_preload", 1, CVAR_ARCHIVE );
1439                 cvarSystem->SetCVarInteger( "image_useAllFormats", 1, CVAR_ARCHIVE );
1440                 cvarSystem->SetCVarInteger( "image_downSizeSpecular", 0, CVAR_ARCHIVE );
1441                 cvarSystem->SetCVarInteger( "image_downSizeBump", 0, CVAR_ARCHIVE );
1442                 cvarSystem->SetCVarInteger( "image_downSizeSpecularLimit", 64, CVAR_ARCHIVE );
1443                 cvarSystem->SetCVarInteger( "image_downSizeBumpLimit", 256, CVAR_ARCHIVE );
1444                 cvarSystem->SetCVarInteger( "image_usePrecompressedTextures", 1, CVAR_ARCHIVE );
1445                 cvarSystem->SetCVarInteger( "image_downsize", 0, CVAR_ARCHIVE );
1446                 cvarSystem->SetCVarInteger( "image_anisotropy", 8, CVAR_ARCHIVE );
1447                 cvarSystem->SetCVarInteger( "image_useCompression", 1, CVAR_ARCHIVE );
1448                 cvarSystem->SetCVarInteger( "image_ignoreHighQuality", 0, CVAR_ARCHIVE );
1449                 cvarSystem->SetCVarInteger( "s_maxSoundsPerShader", 0, CVAR_ARCHIVE );
1450                 cvarSystem->SetCVarInteger( "image_useNormalCompression", 0, CVAR_ARCHIVE );
1451                 cvarSystem->SetCVarInteger( "r_mode", 4, CVAR_ARCHIVE );
1452                 cvarSystem->SetCVarInteger( "r_multiSamples", 0, CVAR_ARCHIVE );
1453         } else if ( com_machineSpec.GetInteger() == 1 ) {
1454                 cvarSystem->SetCVarString( "image_filter", "GL_LINEAR_MIPMAP_LINEAR", CVAR_ARCHIVE );
1455                 cvarSystem->SetCVarInteger( "image_anisotropy", 1, CVAR_ARCHIVE );
1456                 cvarSystem->SetCVarInteger( "image_lodbias", 0, CVAR_ARCHIVE );
1457                 cvarSystem->SetCVarInteger( "image_downSize", 0, CVAR_ARCHIVE );
1458                 cvarSystem->SetCVarInteger( "image_forceDownSize", 0, CVAR_ARCHIVE );
1459                 cvarSystem->SetCVarInteger( "image_roundDown", 1, CVAR_ARCHIVE );
1460                 cvarSystem->SetCVarInteger( "image_preload", 1, CVAR_ARCHIVE );
1461                 cvarSystem->SetCVarInteger( "image_useCompression", 1, CVAR_ARCHIVE );
1462                 cvarSystem->SetCVarInteger( "image_useAllFormats", 1, CVAR_ARCHIVE );
1463                 cvarSystem->SetCVarInteger( "image_usePrecompressedTextures", 1, CVAR_ARCHIVE );
1464                 cvarSystem->SetCVarInteger( "image_downSizeSpecular", 0, CVAR_ARCHIVE );
1465                 cvarSystem->SetCVarInteger( "image_downSizeBump", 0, CVAR_ARCHIVE );
1466                 cvarSystem->SetCVarInteger( "image_downSizeSpecularLimit", 64, CVAR_ARCHIVE );
1467                 cvarSystem->SetCVarInteger( "image_downSizeBumpLimit", 256, CVAR_ARCHIVE );
1468                 cvarSystem->SetCVarInteger( "image_useNormalCompression", 2, CVAR_ARCHIVE );
1469                 cvarSystem->SetCVarInteger( "r_mode", 3, CVAR_ARCHIVE );
1470                 cvarSystem->SetCVarInteger( "r_multiSamples", 0, CVAR_ARCHIVE );
1471         } else {
1472                 cvarSystem->SetCVarString( "image_filter", "GL_LINEAR_MIPMAP_LINEAR", CVAR_ARCHIVE );
1473                 cvarSystem->SetCVarInteger( "image_anisotropy", 1, CVAR_ARCHIVE );
1474                 cvarSystem->SetCVarInteger( "image_lodbias", 0, CVAR_ARCHIVE );
1475                 cvarSystem->SetCVarInteger( "image_roundDown", 1, CVAR_ARCHIVE );
1476                 cvarSystem->SetCVarInteger( "image_preload", 1, CVAR_ARCHIVE );
1477                 cvarSystem->SetCVarInteger( "image_useAllFormats", 1, CVAR_ARCHIVE );
1478                 cvarSystem->SetCVarInteger( "image_usePrecompressedTextures", 1, CVAR_ARCHIVE );
1479                 cvarSystem->SetCVarInteger( "image_downSize", 1, CVAR_ARCHIVE );
1480                 cvarSystem->SetCVarInteger( "image_anisotropy", 0, CVAR_ARCHIVE );
1481                 cvarSystem->SetCVarInteger( "image_useCompression", 1, CVAR_ARCHIVE );
1482                 cvarSystem->SetCVarInteger( "image_ignoreHighQuality", 1, CVAR_ARCHIVE );
1483                 cvarSystem->SetCVarInteger( "s_maxSoundsPerShader", 1, CVAR_ARCHIVE );
1484                 cvarSystem->SetCVarInteger( "image_downSizeSpecular", 1, CVAR_ARCHIVE );
1485                 cvarSystem->SetCVarInteger( "image_downSizeBump", 1, CVAR_ARCHIVE );
1486                 cvarSystem->SetCVarInteger( "image_downSizeSpecularLimit", 64, CVAR_ARCHIVE );
1487                 cvarSystem->SetCVarInteger( "image_downSizeBumpLimit", 256, CVAR_ARCHIVE );
1488                 cvarSystem->SetCVarInteger( "r_mode", 3 , CVAR_ARCHIVE );
1489                 cvarSystem->SetCVarInteger( "image_useNormalCompression", 2, CVAR_ARCHIVE );
1490                 cvarSystem->SetCVarInteger( "r_multiSamples", 0, CVAR_ARCHIVE );
1491         }
1492
1493         if ( Sys_GetVideoRam() < 128 ) {
1494                 cvarSystem->SetCVarBool( "image_ignoreHighQuality", true, CVAR_ARCHIVE );
1495                 cvarSystem->SetCVarInteger( "image_downSize", 1, CVAR_ARCHIVE );
1496                 cvarSystem->SetCVarInteger( "image_downSizeLimit", 256, CVAR_ARCHIVE );
1497                 cvarSystem->SetCVarInteger( "image_downSizeSpecular", 1, CVAR_ARCHIVE );
1498                 cvarSystem->SetCVarInteger( "image_downSizeSpecularLimit", 64, CVAR_ARCHIVE );
1499                 cvarSystem->SetCVarInteger( "image_downSizeBump", 1, CVAR_ARCHIVE );
1500                 cvarSystem->SetCVarInteger( "image_downSizeBumpLimit", 256, CVAR_ARCHIVE );
1501         }
1502
1503         if ( Sys_GetSystemRam() < 512 ) {
1504                 cvarSystem->SetCVarBool( "image_ignoreHighQuality", true, CVAR_ARCHIVE );
1505                 cvarSystem->SetCVarInteger( "s_maxSoundsPerShader", 1, CVAR_ARCHIVE );
1506                 cvarSystem->SetCVarInteger( "image_downSize", 1, CVAR_ARCHIVE );
1507                 cvarSystem->SetCVarInteger( "image_downSizeLimit", 256, CVAR_ARCHIVE );
1508                 cvarSystem->SetCVarInteger( "image_downSizeSpecular", 1, CVAR_ARCHIVE );
1509                 cvarSystem->SetCVarInteger( "image_downSizeSpecularLimit", 64, CVAR_ARCHIVE );
1510                 cvarSystem->SetCVarBool( "com_purgeAll", true, CVAR_ARCHIVE );
1511                 cvarSystem->SetCVarBool( "r_forceLoadImages", true, CVAR_ARCHIVE );
1512         } else {
1513                 cvarSystem->SetCVarBool( "com_purgeAll", false, CVAR_ARCHIVE );
1514                 cvarSystem->SetCVarBool( "r_forceLoadImages", false, CVAR_ARCHIVE );
1515         }
1516
1517         bool oldCard = false;
1518         bool nv10or20 = false;
1519         renderSystem->GetCardCaps( oldCard, nv10or20 );
1520         if ( oldCard ) {
1521                 cvarSystem->SetCVarBool( "g_decals", false, CVAR_ARCHIVE );
1522                 cvarSystem->SetCVarBool( "g_projectileLights", false, CVAR_ARCHIVE );
1523                 cvarSystem->SetCVarBool( "g_doubleVision", false, CVAR_ARCHIVE );
1524                 cvarSystem->SetCVarBool( "g_muzzleFlash", false, CVAR_ARCHIVE );
1525         } else {
1526                 cvarSystem->SetCVarBool( "g_decals", true, CVAR_ARCHIVE );
1527                 cvarSystem->SetCVarBool( "g_projectileLights", true, CVAR_ARCHIVE );
1528                 cvarSystem->SetCVarBool( "g_doubleVision", true, CVAR_ARCHIVE );
1529                 cvarSystem->SetCVarBool( "g_muzzleFlash", true, CVAR_ARCHIVE );
1530         }
1531         if ( nv10or20 ) {
1532                 cvarSystem->SetCVarInteger( "image_useNormalCompression", 1, CVAR_ARCHIVE );
1533         }
1534
1535 #if MACOS_X
1536         // On low settings, G4 systems & 64MB FX5200/NV34 Systems should default shadows off
1537         bool oldArch;
1538         int vendorId, deviceId, cpuId;
1539         OSX_GetVideoCard( vendorId, deviceId );
1540         OSX_GetCPUIdentification( cpuId, oldArch );
1541         bool isFX5200 = vendorId == 0x10DE && ( deviceId & 0x0FF0 ) == 0x0320;
1542         if ( ( oldArch || ( isFX5200 && Sys_GetVideoRam() < 128 ) ) && com_machineSpec.GetInteger() == 0 ) {
1543                 cvarSystem->SetCVarBool( "r_shadows", false, CVAR_ARCHIVE );
1544         } else {
1545                 cvarSystem->SetCVarBool( "r_shadows", true, CVAR_ARCHIVE );
1546         }
1547 #endif
1548 }
1549
1550 /*
1551 =================
1552 Com_ReloadEngine_f
1553 =================
1554 */
1555 void Com_ReloadEngine_f( const idCmdArgs &args ) {
1556         bool menu = false;
1557
1558         if ( !commonLocal.IsInitialized() ) {
1559                 return;
1560         }
1561
1562         if ( args.Argc() > 1 && idStr::Icmp( args.Argv( 1 ), "menu" ) == 0 ) {
1563                 menu = true;
1564         }
1565
1566         common->Printf( "============= ReloadEngine start =============\n" );
1567         if ( !menu ) {
1568                 Sys_ShowConsole( 1, false );
1569         }
1570         commonLocal.ShutdownGame( true );
1571         commonLocal.InitGame();
1572         if ( !menu && !idAsyncNetwork::serverDedicated.GetBool() ) {
1573                 Sys_ShowConsole( 0, false );
1574         }
1575         common->Printf( "============= ReloadEngine end ===============\n" );
1576
1577         if ( !cmdSystem->PostReloadEngine() ) {
1578                 if ( menu ) {
1579                         session->StartMenu( );
1580                 }
1581         }
1582 }
1583
1584 /*
1585 ===============
1586 idCommonLocal::GetLanguageDict
1587 ===============
1588 */
1589 const idLangDict *idCommonLocal::GetLanguageDict( void ) {
1590         return &languageDict;
1591 }
1592
1593 /*
1594 ===============
1595 idCommonLocal::FilterLangList
1596 ===============
1597 */
1598 void idCommonLocal::FilterLangList( idStrList* list, idStr lang ) {
1599         
1600         idStr temp;
1601         for( int i = 0; i < list->Num(); i++ ) {
1602                 temp = (*list)[i];
1603                 temp = temp.Right(temp.Length()-strlen("strings/"));
1604                 temp = temp.Left(lang.Length());
1605                 if(idStr::Icmp(temp, lang) != 0) {
1606                         list->RemoveIndex(i);
1607                         i--;
1608                 }
1609         }
1610 }
1611
1612 /*
1613 ===============
1614 idCommonLocal::InitLanguageDict
1615 ===============
1616 */
1617 void idCommonLocal::InitLanguageDict( void ) {
1618         idStr fileName;
1619         languageDict.Clear();
1620
1621         //D3XP: Instead of just loading a single lang file for each language
1622         //we are going to load all files that begin with the language name
1623         //similar to the way pak files work. So you can place english001.lang
1624         //to add new strings to the english language dictionary
1625         idFileList*     langFiles;
1626         langFiles =  fileSystem->ListFilesTree( "strings", ".lang", true );
1627         
1628         idStrList langList = langFiles->GetList();
1629
1630         StartupVariable( "sys_lang", false );   // let it be set on the command line - this is needed because this init happens very early
1631         idStr langName = cvarSystem->GetCVarString( "sys_lang" );
1632
1633         //Loop through the list and filter
1634         idStrList currentLangList = langList;
1635         FilterLangList(&currentLangList, langName);
1636         
1637         if ( currentLangList.Num() == 0 ) {
1638                 // reset cvar to default and try to load again
1639                 cmdSystem->BufferCommandText( CMD_EXEC_NOW, "reset sys_lang" );
1640                 langName = cvarSystem->GetCVarString( "sys_lang" );
1641                 currentLangList = langList;
1642                 FilterLangList(&currentLangList, langName);
1643         }
1644
1645         for( int i = 0; i < currentLangList.Num(); i++ ) {
1646                 //common->Printf("%s\n", currentLangList[i].c_str());
1647                 languageDict.Load( currentLangList[i], false );
1648         }
1649
1650         fileSystem->FreeFileList(langFiles);
1651
1652         Sys_InitScanTable();
1653 }
1654
1655 /*
1656 ===============
1657 idCommonLocal::LocalizeSpecificMapData
1658 ===============
1659 */
1660 void idCommonLocal::LocalizeSpecificMapData( const char *fileName, idLangDict &langDict, const idLangDict &replaceArgs ) {
1661         idStr out, ws, work;
1662
1663         idMapFile map;
1664         if ( map.Parse( fileName, false, false ) ) {
1665                 int count = map.GetNumEntities();
1666                 for ( int i = 0; i < count; i++ ) {
1667                         idMapEntity *ent = map.GetEntity( i );
1668                         if ( ent ) {
1669                                 for ( int j = 0; j < replaceArgs.GetNumKeyVals(); j++ ) {
1670                                         const idLangKeyValue *kv = replaceArgs.GetKeyVal( j );
1671                                         const char *temp = ent->epairs.GetString( kv->key );
1672                                         if ( temp && *temp ) {
1673                                                 idStr val = kv->value;
1674                                                 if ( val == temp ) {
1675                                                         ent->epairs.Set( kv->key, langDict.AddString( temp ) );
1676                                                 }
1677                                         }
1678                                 }
1679                         }
1680                 }
1681         map.Write( fileName, ".map" );
1682         }
1683 }
1684
1685 /*
1686 ===============
1687 idCommonLocal::LocalizeMapData
1688 ===============
1689 */
1690 void idCommonLocal::LocalizeMapData( const char *fileName, idLangDict &langDict ) {
1691         const char *buffer = NULL;
1692         idLexer src( LEXFL_NOFATALERRORS | LEXFL_NOSTRINGCONCAT | LEXFL_ALLOWMULTICHARLITERALS | LEXFL_ALLOWBACKSLASHSTRINGCONCAT );
1693
1694         common->SetRefreshOnPrint( true );
1695
1696         if ( fileSystem->ReadFile( fileName, (void**)&buffer ) > 0 ) {
1697                 src.LoadMemory( buffer, strlen(buffer), fileName );
1698                 if ( src.IsLoaded() ) {
1699                         common->Printf( "Processing %s\n", fileName );
1700                         idStr mapFileName;
1701                         idToken token, token2;
1702                         idLangDict replaceArgs;
1703                         while ( src.ReadToken( &token ) ) {
1704                                 mapFileName = token;
1705                                 replaceArgs.Clear();
1706                                 src.ExpectTokenString( "{" );
1707                                 while ( src.ReadToken( &token) ) {
1708                                         if ( token == "}" ) {
1709                                                 break;
1710                                         }
1711                                         if ( src.ReadToken( &token2 ) ) {
1712                                                 if ( token2 == "}" ) {
1713                                                         break;
1714                                                 }
1715                                                 replaceArgs.AddKeyVal( token, token2 );
1716                                         }
1717                                 }
1718                                 common->Printf( "  localizing map %s...\n", mapFileName.c_str() );
1719                                 LocalizeSpecificMapData( mapFileName, langDict, replaceArgs );
1720                         }
1721                 }
1722                 fileSystem->FreeFile( (void*)buffer );
1723         }
1724
1725         common->SetRefreshOnPrint( false );
1726 }
1727
1728 /*
1729 ===============
1730 idCommonLocal::LocalizeGui
1731 ===============
1732 */
1733 void idCommonLocal::LocalizeGui( const char *fileName, idLangDict &langDict ) {
1734         idStr out, ws, work;
1735         const char *buffer = NULL;
1736         out.Empty();
1737         int k;
1738         char ch;
1739         char slash = '\\';
1740         char tab = 't';
1741         char nl = 'n';
1742         idLexer src( LEXFL_NOFATALERRORS | LEXFL_NOSTRINGCONCAT | LEXFL_ALLOWMULTICHARLITERALS | LEXFL_ALLOWBACKSLASHSTRINGCONCAT );
1743         if ( fileSystem->ReadFile( fileName, (void**)&buffer ) > 0 ) {
1744                 src.LoadMemory( buffer, strlen(buffer), fileName );
1745                 if ( src.IsLoaded() ) {
1746                         idFile *outFile = fileSystem->OpenFileWrite( fileName ); 
1747                         common->Printf( "Processing %s\n", fileName );
1748                         session->UpdateScreen();
1749                         idToken token;
1750                         while( src.ReadToken( &token ) ) {
1751                                 src.GetLastWhiteSpace( ws );
1752                                 out += ws;
1753                                 if ( token.type == TT_STRING ) {
1754                                         out += va( "\"%s\"", token.c_str() );
1755                                 } else {
1756                                         out += token;
1757                                 }
1758                                 if ( out.Length() > 200000 ) {
1759                                         outFile->Write( out.c_str(), out.Length() );
1760                                         out = "";
1761                                 }
1762                                 work = token.Right( 6 );
1763                                 if ( token.Icmp( "text" ) == 0 || work.Icmp( "::text" ) == 0 || token.Icmp( "choices" ) == 0 ) {
1764                                         if ( src.ReadToken( &token ) ) {
1765                                                 // see if already exists, if so save that id to this position in this file
1766                                                 // otherwise add this to the list and save the id to this position in this file
1767                                                 src.GetLastWhiteSpace( ws );
1768                                                 out += ws;
1769                                                 token = langDict.AddString( token );
1770                                                 out += "\"";
1771                                                 for ( k = 0; k < token.Length(); k++ ) {
1772                                                         ch = token[k];
1773                                                         if ( ch == '\t' ) {
1774                                                                 out += slash;
1775                                                                 out += tab;
1776                                                         } else if ( ch == '\n' || ch == '\r' ) {
1777                                                                 out += slash;
1778                                                                 out += nl;
1779                                                         } else {
1780                                                                 out += ch;
1781                                                         }
1782                                                 }
1783                                                 out += "\"";
1784                                         }
1785                                 } else if ( token.Icmp( "comment" ) == 0 ) {
1786                                         if ( src.ReadToken( &token ) ) {
1787                                                 // need to write these out by hand to preserve any \n's
1788                                                 // see if already exists, if so save that id to this position in this file
1789                                                 // otherwise add this to the list and save the id to this position in this file
1790                                                 src.GetLastWhiteSpace( ws );
1791                                                 out += ws;
1792                                                 out += "\"";
1793                                                 for ( k = 0; k < token.Length(); k++ ) {
1794                                                         ch = token[k];
1795                                                         if ( ch == '\t' ) {
1796                                                                 out += slash;
1797                                                                 out += tab;
1798                                                         } else if ( ch == '\n' || ch == '\r' ) {
1799                                                                 out += slash;
1800                                                                 out += nl;
1801                                                         } else {
1802                                                                 out += ch;
1803                                                         }
1804                                                 }
1805                                                 out += "\"";
1806                                         }
1807                                 }
1808                         }
1809                         outFile->Write( out.c_str(), out.Length() );
1810                         fileSystem->CloseFile( outFile );
1811                 }
1812                 fileSystem->FreeFile( (void*)buffer );
1813         }
1814 }
1815
1816 /*
1817 =================
1818 ReloadLanguage_f
1819 =================
1820 */
1821 void Com_ReloadLanguage_f( const idCmdArgs &args ) {
1822         commonLocal.InitLanguageDict();
1823 }
1824
1825 typedef idHashTable<idStrList> ListHash;
1826 void LoadMapLocalizeData(ListHash& listHash) {
1827
1828         idStr fileName = "map_localize.cfg";
1829         const char *buffer = NULL;
1830         idLexer src( LEXFL_NOFATALERRORS | LEXFL_NOSTRINGCONCAT | LEXFL_ALLOWMULTICHARLITERALS | LEXFL_ALLOWBACKSLASHSTRINGCONCAT );
1831
1832         if ( fileSystem->ReadFile( fileName, (void**)&buffer ) > 0 ) {
1833                 src.LoadMemory( buffer, strlen(buffer), fileName );
1834                 if ( src.IsLoaded() ) {
1835                         idStr classname;
1836                         idToken token;
1837
1838
1839
1840                         while ( src.ReadToken( &token ) ) {
1841                                 classname = token;
1842                                 src.ExpectTokenString( "{" );
1843
1844                                 idStrList list;
1845                                 while ( src.ReadToken( &token) ) {
1846                                         if ( token == "}" ) {
1847                                                 break;
1848                                         }
1849                                         list.Append(token);
1850                                 }
1851
1852                                 listHash.Set(classname, list);
1853                         }
1854                 }
1855                 fileSystem->FreeFile( (void*)buffer );
1856         }
1857
1858 }
1859
1860 void LoadGuiParmExcludeList(idStrList& list) {
1861
1862         idStr fileName = "guiparm_exclude.cfg";
1863         const char *buffer = NULL;
1864         idLexer src( LEXFL_NOFATALERRORS | LEXFL_NOSTRINGCONCAT | LEXFL_ALLOWMULTICHARLITERALS | LEXFL_ALLOWBACKSLASHSTRINGCONCAT );
1865
1866         if ( fileSystem->ReadFile( fileName, (void**)&buffer ) > 0 ) {
1867                 src.LoadMemory( buffer, strlen(buffer), fileName );
1868                 if ( src.IsLoaded() ) {
1869                         idStr classname;
1870                         idToken token;
1871
1872
1873
1874                         while ( src.ReadToken( &token ) ) {
1875                                 list.Append(token);
1876                         }
1877                 }
1878                 fileSystem->FreeFile( (void*)buffer );
1879         }
1880 }
1881
1882 bool TestMapVal(idStr& str) {
1883         //Already Localized?
1884         if(str.Find("#str_") != -1) {
1885                 return false;
1886         }
1887
1888         return true;
1889 }
1890
1891 bool TestGuiParm(const char* parm, const char* value, idStrList& excludeList) {
1892
1893         idStr testVal = value;
1894
1895         //Already Localized?
1896         if(testVal.Find("#str_") != -1) {
1897                 return false;
1898         }
1899
1900         //Numeric
1901         if(testVal.IsNumeric()) {
1902                 return false;
1903         }
1904
1905         //Contains ::
1906         if(testVal.Find("::") != -1) {
1907                 return false;
1908         }
1909
1910         //Contains /
1911         if(testVal.Find("/") != -1) {
1912                 return false;
1913         }
1914
1915         if(excludeList.Find(testVal)) {
1916                 return false;
1917         }
1918
1919         return true;
1920 }
1921
1922 void GetFileList(const char* dir, const char* ext, idStrList& list) {
1923
1924         //Recurse Subdirectories
1925         idStrList dirList;
1926         Sys_ListFiles(dir, "/", dirList);
1927         for(int i = 0; i < dirList.Num(); i++) {
1928                 if(dirList[i] == "." || dirList[i] == "..") {
1929                         continue;
1930                 }
1931                 idStr fullName = va("%s/%s", dir, dirList[i].c_str());
1932                 GetFileList(fullName, ext, list);
1933         }
1934
1935         idStrList fileList;
1936         Sys_ListFiles(dir, ext, fileList);
1937         for(int i = 0; i < fileList.Num(); i++) {
1938                 idStr fullName = va("%s/%s", dir, fileList[i].c_str());
1939                 list.Append(fullName);
1940         }
1941 }
1942
1943 int LocalizeMap(const char* mapName, idLangDict &langDict, ListHash& listHash, idStrList& excludeList, bool writeFile) {
1944
1945         common->Printf("Localizing Map '%s'\n", mapName);
1946
1947         int strCount = 0;
1948         
1949         idMapFile map;
1950         if ( map.Parse(mapName, false, false ) ) {
1951                 int count = map.GetNumEntities();
1952                 for ( int j = 0; j < count; j++ ) {
1953                         idMapEntity *ent = map.GetEntity( j );
1954                         if ( ent ) {
1955
1956                                 idStr classname = ent->epairs.GetString("classname");
1957
1958                                 //Hack: for info_location
1959                                 bool hasLocation = false;
1960
1961                                 idStrList* list;
1962                                 listHash.Get(classname, &list);
1963                                 if(list) {
1964
1965                                         for(int k = 0; k < list->Num(); k++) {
1966
1967                                                 idStr val = ent->epairs.GetString((*list)[k], "");
1968                                                 
1969                                                 if(val.Length() && classname == "info_location" && (*list)[k] == "location") {
1970                                                         hasLocation = true;
1971                                                 }
1972
1973                                                 if(val.Length() && TestMapVal(val)) {
1974                                                         
1975                                                         if(!hasLocation || (*list)[k] == "location") {
1976                                                                 //Localize it!!!
1977                                                                 strCount++;
1978                                                                 ent->epairs.Set( (*list)[k], langDict.AddString( val ) );
1979                                                         }
1980                                                 }
1981                                         }
1982                                 }
1983
1984                                 listHash.Get("all", &list);
1985                                 if(list) {
1986                                         for(int k = 0; k < list->Num(); k++) {
1987                                                 idStr val = ent->epairs.GetString((*list)[k], "");
1988                                                 if(val.Length() && TestMapVal(val)) {
1989                                                         //Localize it!!!
1990                                                         strCount++;
1991                                                         ent->epairs.Set( (*list)[k], langDict.AddString( val ) );
1992                                                 }
1993                                         }
1994                                 }
1995
1996                                 //Localize the gui_parms
1997                                 const idKeyValue* kv = ent->epairs.MatchPrefix("gui_parm");
1998                                 while( kv ) {
1999                                         if(TestGuiParm(kv->GetKey(), kv->GetValue(), excludeList)) {
2000                                                 //Localize It!
2001                                                 strCount++;
2002                                                 ent->epairs.Set( kv->GetKey(), langDict.AddString( kv->GetValue() ) );
2003                                         }
2004                                         kv = ent->epairs.MatchPrefix( "gui_parm", kv );
2005                                 }
2006                         }
2007                 }
2008                 if(writeFile && strCount > 0)  {
2009                         //Before we write the map file lets make a backup of the original
2010                         idStr file =  fileSystem->RelativePathToOSPath(mapName);
2011                         idStr bak = file.Left(file.Length() - 4);
2012                         bak.Append(".bak_loc");
2013                         fileSystem->CopyFile( file, bak );
2014                         
2015                         map.Write( mapName, ".map" );
2016                 }
2017         }
2018
2019         common->Printf("Count: %d\n", strCount);
2020         return strCount;
2021 }
2022
2023 /*
2024 =================
2025 LocalizeMaps_f
2026 =================
2027 */
2028 void Com_LocalizeMaps_f( const idCmdArgs &args ) {
2029         if ( args.Argc() < 2 ) {
2030                 common->Printf( "Usage: localizeMaps <count | dictupdate | all> <map>\n" );
2031                 return;
2032         }
2033
2034         int strCount = 0;
2035         
2036         bool count = false;
2037         bool dictUpdate = false;
2038         bool write = false;
2039
2040         if ( idStr::Icmp( args.Argv(1), "count" ) == 0 ) {
2041                 count = true;
2042         } else if ( idStr::Icmp( args.Argv(1), "dictupdate" ) == 0 ) {
2043                 count = true;
2044                 dictUpdate = true;
2045         } else if ( idStr::Icmp( args.Argv(1), "all" ) == 0 ) {
2046                 count = true;
2047                 dictUpdate = true;
2048                 write = true;
2049         } else {
2050                 common->Printf( "Invalid Command\n" );
2051                 common->Printf( "Usage: localizeMaps <count | dictupdate | all>\n" );
2052                 return;
2053
2054         }
2055
2056         idLangDict strTable;
2057         idStr filename = va("strings/english%.3i.lang", com_product_lang_ext.GetInteger());
2058         if(strTable.Load( filename ) == false) {
2059                 //This is a new file so set the base index
2060                 strTable.SetBaseID(com_product_lang_ext.GetInteger()*100000);
2061         }
2062
2063         common->SetRefreshOnPrint( true );
2064         
2065         ListHash listHash;
2066         LoadMapLocalizeData(listHash);
2067
2068         idStrList excludeList;
2069         LoadGuiParmExcludeList(excludeList);
2070
2071         if(args.Argc() == 3) {
2072                 strCount += LocalizeMap(args.Argv(2), strTable, listHash, excludeList, write);
2073         } else {
2074                 idStrList files;
2075                 GetFileList("z:/d3xp/d3xp/maps/game", "*.map", files);
2076                 for ( int i = 0; i < files.Num(); i++ ) {
2077                         idStr file =  fileSystem->OSPathToRelativePath(files[i]);
2078                         strCount += LocalizeMap(file, strTable, listHash, excludeList, write);          
2079                 }
2080         }
2081
2082         if(count) {
2083                 common->Printf("Localize String Count: %d\n", strCount);
2084         }
2085
2086         common->SetRefreshOnPrint( false );
2087
2088         if(dictUpdate) {
2089                 strTable.Save( filename );
2090         }
2091 }
2092
2093 /*
2094 =================
2095 LocalizeGuis_f
2096 =================
2097 */
2098 void Com_LocalizeGuis_f( const idCmdArgs &args ) {
2099
2100         if ( args.Argc() != 2 ) {
2101                 common->Printf( "Usage: localizeGuis <all | gui>\n" );
2102                 return;
2103         }
2104
2105         idLangDict strTable;
2106
2107         idStr filename = va("strings/english%.3i.lang", com_product_lang_ext.GetInteger());
2108         if(strTable.Load( filename ) == false) {
2109                 //This is a new file so set the base index
2110                 strTable.SetBaseID(com_product_lang_ext.GetInteger()*100000);
2111         }
2112
2113         idFileList *files;
2114         if ( idStr::Icmp( args.Argv(1), "all" ) == 0 ) {
2115                 idStr game = cvarSystem->GetCVarString( "fs_game" );
2116                 if(game.Length()) {
2117                         files = fileSystem->ListFilesTree( "guis", "*.gui", true, game );
2118                 } else {
2119                         files = fileSystem->ListFilesTree( "guis", "*.gui", true );
2120                 }
2121                 for ( int i = 0; i < files->GetNumFiles(); i++ ) {
2122                         commonLocal.LocalizeGui( files->GetFile( i ), strTable );
2123                 }
2124                 fileSystem->FreeFileList( files );
2125
2126                 if(game.Length()) {
2127                         files = fileSystem->ListFilesTree( "guis", "*.pd", true, game );
2128                 } else {
2129                         files = fileSystem->ListFilesTree( "guis", "*.pd", true, "d3xp" );
2130                 }
2131                 
2132                 for ( int i = 0; i < files->GetNumFiles(); i++ ) {
2133                         commonLocal.LocalizeGui( files->GetFile( i ), strTable );
2134                 }
2135                 fileSystem->FreeFileList( files );
2136
2137         } else {
2138                 commonLocal.LocalizeGui( args.Argv(1), strTable );
2139         }
2140         strTable.Save( filename );
2141 }
2142
2143 void Com_LocalizeGuiParmsTest_f( const idCmdArgs &args ) {
2144
2145         common->SetRefreshOnPrint( true );
2146
2147         idFile *localizeFile = fileSystem->OpenFileWrite( "gui_parm_localize.csv" ); 
2148         idFile *noLocalizeFile = fileSystem->OpenFileWrite( "gui_parm_nolocalize.csv" ); 
2149
2150         idStrList excludeList;
2151         LoadGuiParmExcludeList(excludeList);
2152
2153         idStrList files;
2154         GetFileList("z:/d3xp/d3xp/maps/game", "*.map", files);
2155
2156         for ( int i = 0; i < files.Num(); i++ ) {
2157                 
2158                 common->Printf("Testing Map '%s'\n", files[i].c_str());
2159                 idMapFile map;
2160
2161                 idStr file =  fileSystem->OSPathToRelativePath(files[i]);
2162                 if ( map.Parse(file, false, false ) ) {
2163                         int count = map.GetNumEntities();
2164                         for ( int j = 0; j < count; j++ ) {
2165                                 idMapEntity *ent = map.GetEntity( j );
2166                                 if ( ent ) {
2167                                         const idKeyValue* kv = ent->epairs.MatchPrefix("gui_parm");
2168                                         while( kv ) {
2169                                                 if(TestGuiParm(kv->GetKey(), kv->GetValue(), excludeList)) {
2170                                                         idStr out = va("%s,%s,%s\r\n", kv->GetValue().c_str(), kv->GetKey().c_str(), file.c_str());
2171                                                         localizeFile->Write( out.c_str(), out.Length() );
2172                                                 } else {
2173                                                         idStr out = va("%s,%s,%s\r\n", kv->GetValue().c_str(), kv->GetKey().c_str(), file.c_str());
2174                                                         noLocalizeFile->Write( out.c_str(), out.Length() );
2175                                                 }
2176                                                 kv = ent->epairs.MatchPrefix( "gui_parm", kv );
2177                                         }
2178                                 }
2179                         }
2180                 }
2181         }
2182         
2183         fileSystem->CloseFile( localizeFile );
2184         fileSystem->CloseFile( noLocalizeFile );
2185
2186         common->SetRefreshOnPrint( false );
2187 }
2188
2189
2190 void Com_LocalizeMapsTest_f( const idCmdArgs &args ) {
2191
2192         ListHash listHash;
2193         LoadMapLocalizeData(listHash);
2194
2195
2196         common->SetRefreshOnPrint( true );
2197
2198         idFile *localizeFile = fileSystem->OpenFileWrite( "map_localize.csv" ); 
2199         
2200         idStrList files;
2201         GetFileList("z:/d3xp/d3xp/maps/game", "*.map", files);
2202
2203         for ( int i = 0; i < files.Num(); i++ ) {
2204
2205                 common->Printf("Testing Map '%s'\n", files[i].c_str());
2206                 idMapFile map;
2207
2208                 idStr file =  fileSystem->OSPathToRelativePath(files[i]);
2209                 if ( map.Parse(file, false, false ) ) {
2210                         int count = map.GetNumEntities();
2211                         for ( int j = 0; j < count; j++ ) {
2212                                 idMapEntity *ent = map.GetEntity( j );
2213                                 if ( ent ) {
2214                                         
2215                                         //Temp code to get a list of all entity key value pairs
2216                                         /*idStr classname = ent->epairs.GetString("classname");
2217                                         if(classname == "worldspawn" || classname == "func_static" || classname == "light" || classname == "speaker" || classname.Left(8) == "trigger_") {
2218                                                 continue;
2219                                         }
2220                                         for( int i = 0; i < ent->epairs.GetNumKeyVals(); i++) {
2221                                                 const idKeyValue* kv = ent->epairs.GetKeyVal(i);
2222                                                 idStr out = va("%s,%s,%s,%s\r\n", classname.c_str(), kv->GetKey().c_str(), kv->GetValue().c_str(), file.c_str());
2223                                                 localizeFile->Write( out.c_str(), out.Length() );
2224                                         }*/
2225
2226                                         idStr classname = ent->epairs.GetString("classname");
2227                                         
2228                                         //Hack: for info_location
2229                                         bool hasLocation = false;
2230
2231                                         idStrList* list;
2232                                         listHash.Get(classname, &list);
2233                                         if(list) {
2234
2235                                                 for(int k = 0; k < list->Num(); k++) {
2236
2237                                                         idStr val = ent->epairs.GetString((*list)[k], "");
2238                                                         
2239                                                         if(classname == "info_location" && (*list)[k] == "location") {
2240                                                                 hasLocation = true;
2241                                                         }
2242
2243                                                         if(val.Length() && TestMapVal(val)) {
2244                                                                 
2245                                                                 if(!hasLocation || (*list)[k] == "location") {
2246                                                                         idStr out = va("%s,%s,%s\r\n", val.c_str(), (*list)[k].c_str(), file.c_str());
2247                                                                         localizeFile->Write( out.c_str(), out.Length() );
2248                                                                 }
2249                                                         }
2250                                                 }
2251                                         }
2252
2253                                         listHash.Get("all", &list);
2254                                         if(list) {
2255                                                 for(int k = 0; k < list->Num(); k++) {
2256                                                         idStr val = ent->epairs.GetString((*list)[k], "");
2257                                                         if(val.Length() && TestMapVal(val)) {
2258                                                                 idStr out = va("%s,%s,%s\r\n", val.c_str(), (*list)[k].c_str(), file.c_str());
2259                                                                 localizeFile->Write( out.c_str(), out.Length() );
2260                                                         }
2261                                                 }
2262                                         }
2263                                 }
2264                         }
2265                 }
2266         }
2267
2268         fileSystem->CloseFile( localizeFile );
2269
2270         common->SetRefreshOnPrint( false );
2271 }
2272
2273 /*
2274 =================
2275 Com_StartBuild_f
2276 =================
2277 */
2278 void Com_StartBuild_f( const idCmdArgs &args ) {
2279         globalImages->StartBuild();
2280 }
2281
2282 /*
2283 =================
2284 Com_FinishBuild_f
2285 =================
2286 */
2287 void Com_FinishBuild_f( const idCmdArgs &args ) {
2288         if ( game ) {
2289                 game->CacheDictionaryMedia( NULL );
2290         }
2291         globalImages->FinishBuild( ( args.Argc() > 1 ) );
2292 }
2293
2294 /*
2295 ==============
2296 Com_Help_f
2297 ==============
2298 */
2299 void Com_Help_f( const idCmdArgs &args ) {
2300         common->Printf( "\nCommonly used commands:\n" );
2301         common->Printf( "  spawnServer      - start the server.\n" );
2302         common->Printf( "  disconnect       - shut down the server.\n" );
2303         common->Printf( "  listCmds         - list all console commands.\n" );
2304         common->Printf( "  listCVars        - list all console variables.\n" );
2305         common->Printf( "  kick             - kick a client by number.\n" );
2306         common->Printf( "  gameKick         - kick a client by name.\n" );
2307         common->Printf( "  serverNextMap    - immediately load next map.\n" );
2308         common->Printf( "  serverMapRestart - restart the current map.\n" );
2309         common->Printf( "  serverForceReady - force all players to ready status.\n" );
2310         common->Printf( "\nCommonly used variables:\n" );
2311         common->Printf( "  si_name          - server name (change requires a restart to see)\n" );
2312         common->Printf( "  si_gametype      - type of game.\n" );
2313         common->Printf( "  si_fragLimit     - max kills to win (or lives in Last Man Standing).\n" );
2314         common->Printf( "  si_timeLimit     - maximum time a game will last.\n" );
2315         common->Printf( "  si_warmup        - do pre-game warmup.\n" );
2316         common->Printf( "  si_pure          - pure server.\n" );
2317         common->Printf( "  g_mapCycle       - name of .scriptcfg file for cycling maps.\n" );
2318         common->Printf( "See mapcycle.scriptcfg for an example of a mapcyle script.\n\n" );
2319 }
2320
2321 /*
2322 =================
2323 idCommonLocal::InitCommands
2324 =================
2325 */
2326 void idCommonLocal::InitCommands( void ) {
2327         cmdSystem->AddCommand( "error", Com_Error_f, CMD_FL_SYSTEM|CMD_FL_CHEAT, "causes an error" );
2328         cmdSystem->AddCommand( "crash", Com_Crash_f, CMD_FL_SYSTEM|CMD_FL_CHEAT, "causes a crash" );
2329         cmdSystem->AddCommand( "freeze", Com_Freeze_f, CMD_FL_SYSTEM|CMD_FL_CHEAT, "freezes the game for a number of seconds" );
2330         cmdSystem->AddCommand( "quit", Com_Quit_f, CMD_FL_SYSTEM, "quits the game" );
2331         cmdSystem->AddCommand( "exit", Com_Quit_f, CMD_FL_SYSTEM, "exits the game" );
2332         cmdSystem->AddCommand( "writeConfig", Com_WriteConfig_f, CMD_FL_SYSTEM, "writes a config file" );
2333         cmdSystem->AddCommand( "reloadEngine", Com_ReloadEngine_f, CMD_FL_SYSTEM, "reloads the engine down to including the file system" );
2334         cmdSystem->AddCommand( "setMachineSpec", Com_SetMachineSpec_f, CMD_FL_SYSTEM, "detects system capabilities and sets com_machineSpec to appropriate value" );
2335         cmdSystem->AddCommand( "execMachineSpec", Com_ExecMachineSpec_f, CMD_FL_SYSTEM, "execs the appropriate config files and sets cvars based on com_machineSpec" );
2336
2337 #if     !defined( ID_DEMO_BUILD ) && !defined( ID_DEDICATED )
2338         // compilers
2339         cmdSystem->AddCommand( "dmap", Dmap_f, CMD_FL_TOOL, "compiles a map", idCmdSystem::ArgCompletion_MapName );
2340         cmdSystem->AddCommand( "renderbump", RenderBump_f, CMD_FL_TOOL, "renders a bump map", idCmdSystem::ArgCompletion_ModelName );
2341         cmdSystem->AddCommand( "renderbumpFlat", RenderBumpFlat_f, CMD_FL_TOOL, "renders a flat bump map", idCmdSystem::ArgCompletion_ModelName );
2342         cmdSystem->AddCommand( "runAAS", RunAAS_f, CMD_FL_TOOL, "compiles an AAS file for a map", idCmdSystem::ArgCompletion_MapName );
2343         cmdSystem->AddCommand( "runAASDir", RunAASDir_f, CMD_FL_TOOL, "compiles AAS files for all maps in a folder", idCmdSystem::ArgCompletion_MapName );
2344         cmdSystem->AddCommand( "runReach", RunReach_f, CMD_FL_TOOL, "calculates reachability for an AAS file", idCmdSystem::ArgCompletion_MapName );
2345         cmdSystem->AddCommand( "roq", RoQFileEncode_f, CMD_FL_TOOL, "encodes a roq file" );
2346 #endif
2347
2348 #ifdef ID_ALLOW_TOOLS
2349         // editors
2350         cmdSystem->AddCommand( "editor", Com_Editor_f, CMD_FL_TOOL, "launches the level editor Radiant" );
2351         cmdSystem->AddCommand( "editLights", Com_EditLights_f, CMD_FL_TOOL, "launches the in-game Light Editor" );
2352         cmdSystem->AddCommand( "editSounds", Com_EditSounds_f, CMD_FL_TOOL, "launches the in-game Sound Editor" );
2353         cmdSystem->AddCommand( "editDecls", Com_EditDecls_f, CMD_FL_TOOL, "launches the in-game Declaration Editor" );
2354         cmdSystem->AddCommand( "editAFs", Com_EditAFs_f, CMD_FL_TOOL, "launches the in-game Articulated Figure Editor" );
2355         cmdSystem->AddCommand( "editParticles", Com_EditParticles_f, CMD_FL_TOOL, "launches the in-game Particle Editor" );
2356         cmdSystem->AddCommand( "editScripts", Com_EditScripts_f, CMD_FL_TOOL, "launches the in-game Script Editor" );
2357         cmdSystem->AddCommand( "editGUIs", Com_EditGUIs_f, CMD_FL_TOOL, "launches the GUI Editor" );
2358         cmdSystem->AddCommand( "editPDAs", Com_EditPDAs_f, CMD_FL_TOOL, "launches the in-game PDA Editor" );
2359         cmdSystem->AddCommand( "debugger", Com_ScriptDebugger_f, CMD_FL_TOOL, "launches the Script Debugger" );
2360
2361         //BSM Nerve: Add support for the material editor
2362         cmdSystem->AddCommand( "materialEditor", Com_MaterialEditor_f, CMD_FL_TOOL, "launches the Material Editor" );
2363 #endif
2364
2365         cmdSystem->AddCommand( "printMemInfo", PrintMemInfo_f, CMD_FL_SYSTEM, "prints memory debugging data" );
2366
2367         // idLib commands
2368         cmdSystem->AddCommand( "memoryDump", Mem_Dump_f, CMD_FL_SYSTEM|CMD_FL_CHEAT, "creates a memory dump" );
2369         cmdSystem->AddCommand( "memoryDumpCompressed", Mem_DumpCompressed_f, CMD_FL_SYSTEM|CMD_FL_CHEAT, "creates a compressed memory dump" );
2370         cmdSystem->AddCommand( "showStringMemory", idStr::ShowMemoryUsage_f, CMD_FL_SYSTEM, "shows memory used by strings" );
2371         cmdSystem->AddCommand( "showDictMemory", idDict::ShowMemoryUsage_f, CMD_FL_SYSTEM, "shows memory used by dictionaries" );
2372         cmdSystem->AddCommand( "listDictKeys", idDict::ListKeys_f, CMD_FL_SYSTEM|CMD_FL_CHEAT, "lists all keys used by dictionaries" );
2373         cmdSystem->AddCommand( "listDictValues", idDict::ListValues_f, CMD_FL_SYSTEM|CMD_FL_CHEAT, "lists all values used by dictionaries" );
2374         cmdSystem->AddCommand( "testSIMD", idSIMD::Test_f, CMD_FL_SYSTEM|CMD_FL_CHEAT, "test SIMD code" );
2375
2376         // localization
2377         cmdSystem->AddCommand( "localizeGuis", Com_LocalizeGuis_f, CMD_FL_SYSTEM|CMD_FL_CHEAT, "localize guis" );
2378         cmdSystem->AddCommand( "localizeMaps", Com_LocalizeMaps_f, CMD_FL_SYSTEM|CMD_FL_CHEAT, "localize maps" );
2379         cmdSystem->AddCommand( "reloadLanguage", Com_ReloadLanguage_f, CMD_FL_SYSTEM, "reload language dict" );
2380
2381         //D3XP Localization
2382         cmdSystem->AddCommand( "localizeGuiParmsTest", Com_LocalizeGuiParmsTest_f, CMD_FL_SYSTEM, "Create test files that show gui parms localized and ignored." );
2383         cmdSystem->AddCommand( "localizeMapsTest", Com_LocalizeMapsTest_f, CMD_FL_SYSTEM, "Create test files that shows which strings will be localized." );
2384
2385         // build helpers
2386         cmdSystem->AddCommand( "startBuild", Com_StartBuild_f, CMD_FL_SYSTEM|CMD_FL_CHEAT, "prepares to make a build" );
2387         cmdSystem->AddCommand( "finishBuild", Com_FinishBuild_f, CMD_FL_SYSTEM|CMD_FL_CHEAT, "finishes the build process" );
2388
2389 #ifdef ID_DEDICATED
2390         cmdSystem->AddCommand( "help", Com_Help_f, CMD_FL_SYSTEM, "shows help" );
2391 #endif
2392 }
2393
2394 /*
2395 =================
2396 idCommonLocal::InitRenderSystem
2397 =================
2398 */
2399 void idCommonLocal::InitRenderSystem( void ) {
2400         if ( com_skipRenderer.GetBool() ) {
2401                 return;
2402         }
2403
2404         renderSystem->InitOpenGL();
2405         PrintLoadingMessage( common->GetLanguageDict()->GetString( "#str_04343" ) );
2406 }
2407
2408 /*
2409 =================
2410 idCommonLocal::PrintLoadingMessage
2411 =================
2412 */
2413 void idCommonLocal::PrintLoadingMessage( const char *msg ) {
2414         if ( !( msg && *msg ) ) {
2415                 return;
2416         }
2417         renderSystem->BeginFrame( renderSystem->GetScreenWidth(), renderSystem->GetScreenHeight() );
2418         renderSystem->DrawStretchPic( 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, 0, 0, 1, 1, declManager->FindMaterial( "splashScreen" ) );
2419         int len = strlen( msg );
2420         renderSystem->DrawSmallStringExt( ( 640 - len * SMALLCHAR_WIDTH ) / 2, 410, msg, idVec4( 0.0f, 0.81f, 0.94f, 1.0f ), true, declManager->FindMaterial( "textures/bigchars" ) );
2421         renderSystem->EndFrame( NULL, NULL );
2422 }
2423
2424 /*
2425 =================
2426 idCommonLocal::InitSIMD
2427 =================
2428 */
2429 void idCommonLocal::InitSIMD( void ) {
2430         idSIMD::InitProcessor( "doom", com_forceGenericSIMD.GetBool() );
2431         com_forceGenericSIMD.ClearModified();
2432 }
2433
2434 /*
2435 =================
2436 idCommonLocal::Frame
2437 =================
2438 */
2439 void idCommonLocal::Frame( void ) {
2440         try {
2441
2442                 // pump all the events
2443                 Sys_GenerateEvents();
2444
2445                 // write config file if anything changed
2446                 WriteConfiguration(); 
2447
2448                 // change SIMD implementation if required
2449                 if ( com_forceGenericSIMD.IsModified() ) {
2450                         InitSIMD();
2451                 }
2452
2453                 eventLoop->RunEventLoop();
2454
2455                 com_frameTime = com_ticNumber * USERCMD_MSEC;
2456
2457                 idAsyncNetwork::RunFrame();
2458
2459                 if ( idAsyncNetwork::IsActive() ) {
2460                         if ( idAsyncNetwork::serverDedicated.GetInteger() != 1 ) {
2461                                 session->GuiFrameEvents();
2462                                 session->UpdateScreen( false );
2463                         }
2464                 } else {
2465                         session->Frame();
2466
2467                         // normal, in-sequence screen update
2468                         session->UpdateScreen( false );
2469                 }
2470
2471                 // report timing information
2472                 if ( com_speeds.GetBool() ) {
2473                         static int      lastTime;
2474                         int             nowTime = Sys_Milliseconds();
2475                         int             com_frameMsec = nowTime - lastTime;
2476                         lastTime = nowTime;
2477                         Printf( "frame:%i all:%3i gfr:%3i rf:%3i bk:%3i\n", com_frameNumber, com_frameMsec, time_gameFrame, time_frontend, time_backend );
2478                         time_gameFrame = 0;
2479                         time_gameDraw = 0;
2480                 }       
2481
2482                 com_frameNumber++;
2483
2484                 // set idLib frame number for frame based memory dumps
2485                 idLib::frameNumber = com_frameNumber;
2486
2487                 // the FPU stack better be empty at this point or some bad code or compiler bug left values on the stack
2488                 if ( !Sys_FPU_StackIsEmpty() ) {
2489                         Printf( Sys_FPU_GetState() );
2490                         FatalError( "idCommon::Frame: the FPU stack is not empty at the end of the frame\n" );
2491                 }
2492         }
2493
2494         catch( idException & ) {
2495                 return;                 // an ERP_DROP was thrown
2496         }
2497 }
2498
2499 /*
2500 =================
2501 idCommonLocal::GUIFrame
2502 =================
2503 */
2504 void idCommonLocal::GUIFrame( bool execCmd, bool network ) {
2505         Sys_GenerateEvents();
2506         eventLoop->RunEventLoop( execCmd );     // and execute any commands
2507         com_frameTime = com_ticNumber * USERCMD_MSEC;
2508         if ( network ) {
2509                 idAsyncNetwork::RunFrame();
2510         }
2511         session->Frame();
2512         session->UpdateScreen( false ); 
2513 }
2514
2515 /*
2516 =================
2517 idCommonLocal::SingleAsyncTic
2518
2519 The system will asyncronously call this function 60 times a second to
2520 handle the time-critical functions that we don't want limited to
2521 the frame rate:
2522
2523 sound mixing
2524 user input generation (conditioned by com_asyncInput)
2525 packet server operation
2526 packet client operation
2527
2528 We are not using thread safe libraries, so any functionality put here must
2529 be VERY VERY careful about what it calls.
2530 =================
2531 */
2532
2533 typedef struct {
2534         int                             milliseconds;                   // should always be incremeting by 60hz
2535         int                             deltaMsec;                              // should always be 16
2536         int                             timeConsumed;                   // msec spent in Com_AsyncThread()
2537         int                             clientPacketsReceived;
2538         int                             serverPacketsReceived;
2539         int                             mostRecentServerPacketSequence;
2540 } asyncStats_t;
2541
2542 static const int MAX_ASYNC_STATS = 1024;
2543 asyncStats_t    com_asyncStats[MAX_ASYNC_STATS];                // indexed by com_ticNumber
2544 int prevAsyncMsec;
2545 int     lastTicMsec;
2546
2547 void idCommonLocal::SingleAsyncTic( void ) {
2548         // main thread code can prevent this from happening while modifying
2549         // critical data structures
2550         Sys_EnterCriticalSection();
2551
2552         asyncStats_t *stat = &com_asyncStats[com_ticNumber & (MAX_ASYNC_STATS-1)];
2553         memset( stat, 0, sizeof( *stat ) );
2554         stat->milliseconds = Sys_Milliseconds();
2555         stat->deltaMsec = stat->milliseconds - com_asyncStats[(com_ticNumber - 1) & (MAX_ASYNC_STATS-1)].milliseconds;
2556
2557         if ( usercmdGen && com_asyncInput.GetBool() ) {
2558                 usercmdGen->UsercmdInterrupt();
2559         }
2560
2561         switch ( com_asyncSound.GetInteger() ) {
2562                 case 1:
2563                         soundSystem->AsyncUpdate( stat->milliseconds );
2564                         break;
2565                 case 3:
2566                         soundSystem->AsyncUpdateWrite( stat->milliseconds );
2567                         break;
2568         }
2569
2570         // we update com_ticNumber after all the background tasks
2571         // have completed their work for this tic
2572         com_ticNumber++;
2573
2574         stat->timeConsumed = Sys_Milliseconds() - stat->milliseconds;
2575
2576         Sys_LeaveCriticalSection();
2577 }
2578
2579 /*
2580 =================
2581 idCommonLocal::Async
2582 =================
2583 */
2584 void idCommonLocal::Async( void ) {
2585         if ( com_shuttingDown ) {
2586                 return;
2587         }
2588
2589         int     msec = Sys_Milliseconds();
2590         if ( !lastTicMsec ) {
2591                 lastTicMsec = msec - USERCMD_MSEC;
2592         }
2593
2594         if ( !com_preciseTic.GetBool() ) {
2595                 // just run a single tic, even if the exact msec isn't precise
2596                 SingleAsyncTic();
2597                 return;
2598         }
2599
2600         int ticMsec = USERCMD_MSEC;
2601
2602         // the number of msec per tic can be varies with the timescale cvar
2603         float timescale = com_timescale.GetFloat();
2604         if ( timescale != 1.0f ) {
2605                 ticMsec /= timescale;
2606                 if ( ticMsec < 1 ) {
2607                         ticMsec = 1;
2608                 }
2609         }
2610
2611         // don't skip too many
2612         if ( timescale == 1.0f ) {
2613                 if ( lastTicMsec + 10 * USERCMD_MSEC < msec ) {
2614                         lastTicMsec = msec - 10*USERCMD_MSEC;
2615                 }
2616         }
2617
2618         while ( lastTicMsec + ticMsec <= msec ) {
2619                 SingleAsyncTic();
2620                 lastTicMsec += ticMsec;
2621         }
2622 }
2623
2624 /*
2625 =================
2626 idCommonLocal::LoadGameDLL
2627 =================
2628 */
2629 void idCommonLocal::LoadGameDLL( void ) {
2630 #ifdef __DOOM_DLL__
2631         char                    dllPath[ MAX_OSPATH ];
2632
2633         gameImport_t    gameImport;
2634         gameExport_t    gameExport;
2635         GetGameAPI_t    GetGameAPI;
2636
2637         fileSystem->FindDLL( "game", dllPath, true );
2638
2639         if ( !dllPath[ 0 ] ) {
2640                 common->FatalError( "couldn't find game dynamic library" );
2641                 return;
2642         }
2643         common->DPrintf( "Loading game DLL: '%s'\n", dllPath );
2644         gameDLL = sys->DLL_Load( dllPath );
2645         if ( !gameDLL ) {
2646                 common->FatalError( "couldn't load game dynamic library" );
2647                 return;
2648         }
2649
2650         GetGameAPI = (GetGameAPI_t) Sys_DLL_GetProcAddress( gameDLL, "GetGameAPI" );
2651         if ( !GetGameAPI ) {
2652                 Sys_DLL_Unload( gameDLL );
2653                 gameDLL = NULL;
2654                 common->FatalError( "couldn't find game DLL API" );
2655                 return;
2656         }
2657
2658         gameImport.version                                      = GAME_API_VERSION;
2659         gameImport.sys                                          = ::sys;
2660         gameImport.common                                       = ::common;
2661         gameImport.cmdSystem                            = ::cmdSystem;
2662         gameImport.cvarSystem                           = ::cvarSystem;
2663         gameImport.fileSystem                           = ::fileSystem;
2664         gameImport.networkSystem                        = ::networkSystem;
2665         gameImport.renderSystem                         = ::renderSystem;
2666         gameImport.soundSystem                          = ::soundSystem;
2667         gameImport.renderModelManager           = ::renderModelManager;
2668         gameImport.uiManager                            = ::uiManager;
2669         gameImport.declManager                          = ::declManager;
2670         gameImport.AASFileManager                       = ::AASFileManager;
2671         gameImport.collisionModelManager        = ::collisionModelManager;
2672
2673         gameExport                                                      = *GetGameAPI( &gameImport );
2674
2675         if ( gameExport.version != GAME_API_VERSION ) {
2676                 Sys_DLL_Unload( gameDLL );
2677                 gameDLL = NULL;
2678                 common->FatalError( "wrong game DLL API version" );
2679                 return;
2680         }
2681
2682         game                                                            = gameExport.game;
2683         gameEdit                                                        = gameExport.gameEdit;
2684
2685 #endif
2686
2687         // initialize the game object
2688         if ( game != NULL ) {
2689                 game->Init();
2690         }
2691 }
2692
2693 /*
2694 =================
2695 idCommonLocal::UnloadGameDLL
2696 =================
2697 */
2698 void idCommonLocal::UnloadGameDLL( void ) {
2699
2700         // shut down the game object
2701         if ( game != NULL ) {
2702                 game->Shutdown();
2703         }
2704
2705 #ifdef __DOOM_DLL__
2706
2707         if ( gameDLL ) {
2708                 Sys_DLL_Unload( gameDLL );
2709                 gameDLL = NULL;
2710         }
2711         game = NULL;
2712         gameEdit = NULL;
2713
2714 #endif
2715 }
2716
2717 /*
2718 =================
2719 idCommonLocal::IsInitialized
2720 =================
2721 */
2722 bool idCommonLocal::IsInitialized( void ) const {
2723         return com_fullyInitialized;
2724 }
2725
2726 /*
2727 =================
2728 idCommonLocal::SetMachineSpec
2729 =================
2730 */
2731 void idCommonLocal::SetMachineSpec( void ) {
2732         cpuid_t cpu = Sys_GetProcessorId();
2733         double ghz = Sys_ClockTicksPerSecond() * 0.000000001f;
2734         int vidRam = Sys_GetVideoRam();
2735         int sysRam = Sys_GetSystemRam();
2736         bool oldCard = false;
2737         bool nv10or20 = false;
2738
2739         renderSystem->GetCardCaps( oldCard, nv10or20 );
2740
2741         Printf( "Detected\n \t%.2f GHz CPU\n\t%i MB of System memory\n\t%i MB of Video memory on %s\n\n", ghz, sysRam, vidRam, ( oldCard ) ? "a less than optimal video architecture" : "an optimal video architecture" );
2742
2743         if ( ghz >= 2.75f && vidRam >= 512 && sysRam >= 1024 && !oldCard ) {
2744                 Printf( "This system qualifies for Ultra quality!\n" );
2745                 com_machineSpec.SetInteger( 3 );
2746         } else if ( ghz >= ( ( cpu & CPUID_AMD ) ? 1.9f : 2.19f ) && vidRam >= 256 && sysRam >= 512 && !oldCard ) {
2747                 Printf( "This system qualifies for High quality!\n" );
2748                 com_machineSpec.SetInteger( 2 );
2749         } else if ( ghz >= ( ( cpu & CPUID_AMD ) ? 1.1f : 1.25f ) && vidRam >= 128 && sysRam >= 384 ) {
2750                 Printf( "This system qualifies for Medium quality.\n" );
2751                 com_machineSpec.SetInteger( 1 );
2752         } else {
2753                 Printf( "This system qualifies for Low quality.\n" );
2754                 com_machineSpec.SetInteger( 0 );
2755         }
2756         com_videoRam.SetInteger( vidRam );
2757 }
2758
2759 /*
2760 =================
2761 idCommonLocal::Init
2762 =================
2763 */
2764 void idCommonLocal::Init( int argc, const char **argv, const char *cmdline ) {
2765         try {
2766
2767                 // set interface pointers used by idLib
2768                 idLib::sys                      = sys;
2769                 idLib::common           = common;
2770                 idLib::cvarSystem       = cvarSystem;
2771                 idLib::fileSystem       = fileSystem;
2772
2773                 // initialize idLib
2774                 idLib::Init();
2775
2776                 // clear warning buffer
2777                 ClearWarnings( GAME_NAME " initialization" );
2778                 
2779                 // parse command line options
2780                 idCmdArgs args;
2781                 if ( cmdline ) {
2782                         // tokenize if the OS doesn't do it for us
2783                         args.TokenizeString( cmdline, true );
2784                         argv = args.GetArgs( &argc );
2785                 }
2786                 ParseCommandLine( argc, argv );
2787
2788                 // init console command system
2789                 cmdSystem->Init();
2790
2791                 // init CVar system
2792                 cvarSystem->Init();
2793
2794                 // start file logging right away, before early console or whatever
2795                 StartupVariable( "win_outputDebugString", false );
2796
2797                 // register all static CVars
2798                 idCVar::RegisterStaticVars();
2799
2800                 // print engine version
2801                 Printf( "%s\n", version.string );
2802
2803                 // initialize key input/binding, done early so bind command exists
2804                 idKeyInput::Init();
2805
2806                 // init the console so we can take prints
2807                 console->Init();
2808
2809                 // get architecture info
2810                 Sys_Init();
2811
2812                 // initialize networking
2813                 Sys_InitNetworking();
2814
2815                 // override cvars from command line
2816                 StartupVariable( NULL, false );
2817
2818                 if ( !idAsyncNetwork::serverDedicated.GetInteger() && Sys_AlreadyRunning() ) {
2819                         Sys_Quit();
2820                 }
2821
2822                 // initialize processor specific SIMD implementation
2823                 InitSIMD();
2824
2825                 // init commands
2826                 InitCommands();
2827
2828 #ifdef ID_WRITE_VERSION
2829                 config_compressor = idCompressor::AllocArithmetic();
2830 #endif
2831
2832                 // game specific initialization
2833                 InitGame();
2834
2835                 // don't add startup commands if no CD key is present
2836 #if ID_ENFORCE_KEY
2837                 if ( !session->CDKeysAreValid( false ) || !AddStartupCommands() ) {
2838 #else
2839                 if ( !AddStartupCommands() ) {
2840 #endif
2841                         // if the user didn't give any commands, run default action
2842                         session->StartMenu( true );
2843                 }
2844
2845                 Printf( "--- Common Initialization Complete ---\n" );
2846
2847                 // print all warnings queued during initialization
2848                 PrintWarnings();
2849
2850 #ifdef  ID_DEDICATED
2851                 Printf( "\nType 'help' for dedicated server info.\n\n" );
2852 #endif
2853
2854                 // remove any prints from the notify lines
2855                 console->ClearNotifyLines();
2856                 
2857                 ClearCommandLine();
2858
2859                 com_fullyInitialized = true;
2860         }
2861
2862         catch( idException & ) {
2863                 Sys_Error( "Error during initialization" );
2864         }
2865 }
2866
2867
2868 /*
2869 =================
2870 idCommonLocal::Shutdown
2871 =================
2872 */
2873 void idCommonLocal::Shutdown( void ) {
2874
2875         com_shuttingDown = true;
2876
2877         idAsyncNetwork::server.Kill();
2878         idAsyncNetwork::client.Shutdown();
2879
2880         // game specific shut down
2881         ShutdownGame( false );
2882
2883         // shut down non-portable system services
2884         Sys_Shutdown();
2885
2886         // shut down the console
2887         console->Shutdown();
2888
2889         // shut down the key system
2890         idKeyInput::Shutdown();
2891
2892         // shut down the cvar system
2893         cvarSystem->Shutdown();
2894
2895         // shut down the console command system
2896         cmdSystem->Shutdown();
2897
2898 #ifdef ID_WRITE_VERSION
2899         delete config_compressor;
2900         config_compressor = NULL;
2901 #endif
2902
2903         // free any buffered warning messages
2904         ClearWarnings( GAME_NAME " shutdown" );
2905         warningCaption.Clear();
2906         errorList.Clear();
2907
2908         // free language dictionary
2909         languageDict.Clear();
2910
2911         // enable leak test
2912         Mem_EnableLeakTest( "doom" );
2913
2914         // shutdown idLib
2915         idLib::ShutDown();
2916 }
2917
2918 /*
2919 =================
2920 idCommonLocal::InitGame
2921 =================
2922 */
2923 void idCommonLocal::InitGame( void ) {
2924         // initialize the file system
2925         fileSystem->Init();
2926
2927         // initialize the declaration manager
2928         declManager->Init();
2929
2930         // force r_fullscreen 0 if running a tool
2931         CheckToolMode();
2932
2933         idFile *file = fileSystem->OpenExplicitFileRead( fileSystem->RelativePathToOSPath( CONFIG_SPEC, "fs_savepath" ) );
2934         bool sysDetect = ( file == NULL );
2935         if ( file ) {
2936                 fileSystem->CloseFile( file );
2937         } else {
2938                 file = fileSystem->OpenFileWrite( CONFIG_SPEC );
2939                 fileSystem->CloseFile( file );
2940         }
2941         
2942         idCmdArgs args;
2943         if ( sysDetect ) {
2944                 SetMachineSpec();
2945                 Com_ExecMachineSpec_f( args );
2946         }
2947
2948         // initialize the renderSystem data structures, but don't start OpenGL yet
2949         renderSystem->Init();
2950
2951         // initialize string database right off so we can use it for loading messages
2952         InitLanguageDict();
2953
2954         PrintLoadingMessage( common->GetLanguageDict()->GetString( "#str_04344" ) );
2955
2956         // load the font, etc
2957         console->LoadGraphics();
2958
2959         // init journalling, etc
2960         eventLoop->Init();
2961
2962         PrintLoadingMessage( common->GetLanguageDict()->GetString( "#str_04345" ) );
2963
2964         // exec the startup scripts
2965         cmdSystem->BufferCommandText( CMD_EXEC_APPEND, "exec editor.cfg\n" );
2966         cmdSystem->BufferCommandText( CMD_EXEC_APPEND, "exec default.cfg\n" );
2967
2968         // skip the config file if "safe" is on the command line
2969         if ( !SafeMode() ) {
2970                 cmdSystem->BufferCommandText( CMD_EXEC_APPEND, "exec " CONFIG_FILE "\n" );
2971         }
2972         cmdSystem->BufferCommandText( CMD_EXEC_APPEND, "exec autoexec.cfg\n" );
2973
2974         // reload the language dictionary now that we've loaded config files
2975         cmdSystem->BufferCommandText( CMD_EXEC_APPEND, "reloadLanguage\n" );
2976
2977         // run cfg execution
2978         cmdSystem->ExecuteCommandBuffer();
2979
2980         // re-override anything from the config files with command line args
2981         StartupVariable( NULL, false );
2982
2983         // if any archived cvars are modified after this, we will trigger a writing of the config file
2984         cvarSystem->ClearModifiedFlags( CVAR_ARCHIVE );
2985
2986         // cvars are initialized, but not the rendering system. Allow preference startup dialog
2987         Sys_DoPreferences();
2988
2989         // init the user command input code
2990         usercmdGen->Init();
2991
2992         PrintLoadingMessage( common->GetLanguageDict()->GetString( "#str_04346" ) );
2993
2994         // start the sound system, but don't do any hardware operations yet
2995         soundSystem->Init();
2996
2997         PrintLoadingMessage( common->GetLanguageDict()->GetString( "#str_04347" ) );
2998
2999         // init async network
3000         idAsyncNetwork::Init();
3001
3002 #ifdef  ID_DEDICATED
3003         idAsyncNetwork::server.InitPort();
3004         cvarSystem->SetCVarBool( "s_noSound", true );
3005 #else
3006         if ( idAsyncNetwork::serverDedicated.GetInteger() == 1 ) {
3007                 idAsyncNetwork::server.InitPort();
3008                 cvarSystem->SetCVarBool( "s_noSound", true );
3009         } else {
3010                 // init OpenGL, which will open a window and connect sound and input hardware
3011                 PrintLoadingMessage( common->GetLanguageDict()->GetString( "#str_04348" ) );
3012                 InitRenderSystem();
3013         }
3014 #endif
3015
3016         PrintLoadingMessage( common->GetLanguageDict()->GetString( "#str_04349" ) );
3017
3018         // initialize the user interfaces
3019         uiManager->Init();
3020
3021         // startup the script debugger
3022         // DebuggerServerInit();
3023
3024         PrintLoadingMessage( common->GetLanguageDict()->GetString( "#str_04350" ) );
3025
3026         // load the game dll
3027         LoadGameDLL();
3028         
3029         PrintLoadingMessage( common->GetLanguageDict()->GetString( "#str_04351" ) );
3030
3031         // init the session
3032         session->Init();
3033
3034         // have to do this twice.. first one sets the correct r_mode for the renderer init
3035         // this time around the backend is all setup correct.. a bit fugly but do not want
3036         // to mess with all the gl init at this point.. an old vid card will never qualify for 
3037         if ( sysDetect ) {
3038                 SetMachineSpec();
3039                 Com_ExecMachineSpec_f( args );
3040                 cvarSystem->SetCVarInteger( "s_numberOfSpeakers", 6 );
3041                 cmdSystem->BufferCommandText( CMD_EXEC_NOW, "s_restart\n" );
3042                 cmdSystem->ExecuteCommandBuffer();
3043         }
3044 }
3045
3046 /*
3047 =================
3048 idCommonLocal::ShutdownGame
3049 =================
3050 */
3051 void idCommonLocal::ShutdownGame( bool reloading ) {
3052
3053         // kill sound first
3054         idSoundWorld *sw = soundSystem->GetPlayingSoundWorld();
3055         if ( sw ) {
3056                 sw->StopAllSounds();
3057         }
3058         soundSystem->ClearBuffer();
3059
3060         // shutdown the script debugger
3061         // DebuggerServerShutdown();
3062
3063         idAsyncNetwork::client.Shutdown();
3064
3065         // shut down the session
3066         session->Shutdown();
3067
3068         // shut down the user interfaces
3069         uiManager->Shutdown();
3070
3071         // shut down the sound system
3072         soundSystem->Shutdown();
3073
3074         // shut down async networking
3075         idAsyncNetwork::Shutdown();
3076
3077         // shut down the user command input code
3078         usercmdGen->Shutdown();
3079
3080         // shut down the event loop
3081         eventLoop->Shutdown();
3082
3083         // shut down the renderSystem
3084         renderSystem->Shutdown();
3085
3086         // shutdown the decl manager
3087         declManager->Shutdown();
3088
3089         // unload the game dll
3090         UnloadGameDLL();
3091
3092         // dump warnings to "warnings.txt"
3093 #ifdef DEBUG
3094         DumpWarnings();
3095 #endif
3096         // only shut down the log file after all output is done
3097         CloseLogFile();
3098
3099         // shut down the file system
3100         fileSystem->Shutdown( reloading );
3101 }