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