/* =========================================================================== IceTech GPL Source Code Copyright (C) 2026 Justin Marshall This file is part of the IceTech GPL Source Code (?IceTech Source Code?). IceTech Source Code is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. IceTech Source Code is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with IceTech Source Code. If not, see . In addition, the IceTech 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 IceTech Source Code. If not, please request a copy in writing from id Software at the address below. If you have questions concerning this license or the applicable additional terms, you may contact in writing Justin Marshall, justinmarshall20@gmail.com =========================================================================== */ #include "precompiled.h" #pragma hdrstop #include "../renderer/Image.h" #include "Session_local.h" #define MAX_PRINT_MSG_SIZE 4096 #define MAX_WARNING_LIST 256 typedef enum { ERP_NONE, ERP_FATAL, // exit the entire game with a popup window ERP_DROP, // print to console and disconnect from game ERP_DISCONNECT // don't kill server } errorParm_t; #if defined( _DEBUG ) #define BUILD_DEBUG "-debug" #else #define BUILD_DEBUG "" #endif struct version_s { version_s( void ) { sprintf( string, "%s.%d%s %s %s %s", ENGINE_VERSION, BUILD_NUMBER, BUILD_DEBUG, BUILD_STRING, __DATE__, __TIME__ ); } char string[256]; } version; idCVar com_version( "si_version", version.string, CVAR_SYSTEM|CVAR_ROM|CVAR_SERVERINFO, "engine version" ); idCVar com_skipRenderer( "com_skipRenderer", "0", CVAR_BOOL|CVAR_SYSTEM, "skip the renderer completely" ); 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" ); idCVar com_purgeAll( "com_purgeAll", "0", CVAR_BOOL | CVAR_ARCHIVE | CVAR_SYSTEM, "purge everything between level loads" ); idCVar com_memoryMarker( "com_memoryMarker", "-1", CVAR_INTEGER | CVAR_SYSTEM | CVAR_INIT, "used as a marker for memory stats" ); idCVar com_preciseTic( "com_preciseTic", "1", CVAR_BOOL|CVAR_SYSTEM, "run one game tick every async thread update" ); idCVar com_asyncInput( "com_asyncInput", "0", CVAR_BOOL|CVAR_SYSTEM, "sample input from the async thread" ); #define ASYNCSOUND_INFO "0: mix sound inline, 1: memory mapped async mix, 2: callback mixing, 3: write async mix" #if defined( MACOS_X ) idCVar com_asyncSound( "com_asyncSound", "2", CVAR_INTEGER|CVAR_SYSTEM|CVAR_ROM, ASYNCSOUND_INFO ); #elif defined( __linux__ ) idCVar com_asyncSound( "com_asyncSound", "3", CVAR_INTEGER|CVAR_SYSTEM|CVAR_ROM, ASYNCSOUND_INFO ); #else idCVar com_asyncSound( "com_asyncSound", "1", CVAR_INTEGER|CVAR_SYSTEM, ASYNCSOUND_INFO, 0, 1 ); #endif idCVar com_forceGenericSIMD( "com_forceGenericSIMD", "0", CVAR_BOOL | CVAR_SYSTEM | CVAR_NOCHEAT, "force generic platform independent SIMD" ); idCVar com_developer( "developer", "0", CVAR_BOOL|CVAR_SYSTEM|CVAR_NOCHEAT, "developer mode" ); idCVar com_allowConsole( "com_allowConsole", "0", CVAR_BOOL | CVAR_SYSTEM | CVAR_NOCHEAT, "allow toggling console with the tilde key" ); idCVar com_speeds( "com_speeds", "0", CVAR_BOOL|CVAR_SYSTEM|CVAR_NOCHEAT, "show engine timings" ); idCVar com_showFPS( "com_showFPS", "0", CVAR_BOOL|CVAR_SYSTEM|CVAR_ARCHIVE|CVAR_NOCHEAT, "show frames rendered per second" ); idCVar com_showMemoryUsage( "com_showMemoryUsage", "0", CVAR_BOOL|CVAR_SYSTEM|CVAR_NOCHEAT, "show total and per frame memory usage" ); idCVar com_showAsyncStats( "com_showAsyncStats", "0", CVAR_BOOL|CVAR_SYSTEM|CVAR_NOCHEAT, "show async network stats" ); idCVar com_showSoundDecoders( "com_showSoundDecoders", "0", CVAR_BOOL|CVAR_SYSTEM|CVAR_NOCHEAT, "show sound decoders" ); 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> ); idCVar com_timescale( "timescale", "1", CVAR_SYSTEM | CVAR_FLOAT, "scales the time", 0.1f, 10.0f ); idCVar com_logFile( "logFile", "0", CVAR_SYSTEM | CVAR_NOCHEAT, "1 = buffer log, 2 = flush after each print", 0, 2, idCmdSystem::ArgCompletion_Integer<0,2> ); idCVar com_logFileName( "logFileName", "qconsole.log", CVAR_SYSTEM | CVAR_NOCHEAT, "name of log file, if empty, qconsole.log will be used" ); idCVar com_makingBuild( "com_makingBuild", "0", CVAR_BOOL | CVAR_SYSTEM, "1 when making a build" ); idCVar com_updateLoadSize( "com_updateLoadSize", "0", CVAR_BOOL | CVAR_SYSTEM | CVAR_NOCHEAT, "update the load size after loading a map" ); idCVar com_videoRam( "com_videoRam", "64", CVAR_INTEGER | CVAR_SYSTEM | CVAR_NOCHEAT | CVAR_ARCHIVE, "holds the last amount of detected video ram" ); #ifdef QUAKE4 idCVar com_skipUltraQuality( "com_skipUltraQuality", "0", CVAR_BOOL | CVAR_SYSTEM | CVAR_ARCHIVE, "skip ultra quality as an auto-detect target" ); idCVar com_Bundler( "com_Bundler", "0", CVAR_BOOL | CVAR_SYSTEM | CVAR_INIT, "run in bundle creation mode" ); #ifndef _XENON idCVar com_MakeLoadScreens( "com_MakeLoadScreens", "0", CVAR_BOOL | CVAR_SYSTEM | CVAR_INIT, "generate load screen data" ); #endif idCVar com_QuickLoad( "com_QuickLoad", "0", CVAR_BOOL | CVAR_SYSTEM, "allow quick load/save behavior" ); idCVar com_Limits( "com_Limits", "0", CVAR_BOOL | CVAR_SYSTEM | CVAR_NOCHEAT, "show engine limit information" ); idCVar com_BinaryWrite( "com_BinaryWrite", "0", CVAR_BOOL | CVAR_SYSTEM, "write binary lexer data" ); idCVar com_BinaryRead( "com_BinaryRead", "0", CVAR_BOOL | CVAR_SYSTEM, "read binary lexer data" ); #ifdef RV_BINARYDECLS idCVar com_BinaryDeclRead( "com_BinaryDeclRead", "0", CVAR_BOOL | CVAR_SYSTEM, "read binary decl data" ); #endif #ifdef RV_SINGLE_DECL_FILE idCVar com_SingleDeclFile( "com_SingleDeclFile", "0", CVAR_BOOL | CVAR_SYSTEM, "load decls from a single file" ); idCVar com_WriteSingleDeclFIle( "com_WriteSingleDeclFile", "0", CVAR_BOOL | CVAR_SYSTEM, "write decls to a single file" ); #endif idCVar com_uniqueWarnings( "com_uniqueWarnings", "1", CVAR_BOOL | CVAR_SYSTEM | CVAR_ARCHIVE, "only print a unique warning once" ); idCVar com_showMemAllocTags( "com_showMemAllocTags", "0", CVAR_BOOL | CVAR_SYSTEM | CVAR_NOCHEAT, "show Mem_Alloc tag statistics" ); #if defined(_XENON) idCVar com_showXenTexCacheStats( "com_showXenTexCacheStats", "0", CVAR_BOOL | CVAR_SYSTEM | CVAR_NOCHEAT, "show Xenon texture cache stats" ); idCVar com_showXenHardwareTimers( "com_showXenHardwareTimers", "0", CVAR_BOOL | CVAR_SYSTEM | CVAR_NOCHEAT, "show Xenon hardware timers" ); idCVar com_showXenThreadUsage( "com_showXenThreadUsage", "0", CVAR_BOOL | CVAR_SYSTEM | CVAR_NOCHEAT, "show Xenon thread usage" ); #endif #endif idCVar com_product_lang_ext( "com_product_lang_ext", "1", CVAR_INTEGER | CVAR_SYSTEM | CVAR_ARCHIVE, "Extension to use when creating language files." ); idCVar com_engineHz("com_engineHz", "90", CVAR_FLOAT | CVAR_ARCHIVE, "Frames per second the engine runs at", 10.0f, 1024.0f); idCVar com_deltaTimeClamp("com_deltaTimeClamp", "50", CVAR_INTEGER, "don't process more than this time in a single frame"); float com_engineHz_latched = 90.0f; // Latched version of cvar, updated between map loads int64_t com_engineHz_numerator = 100LL * 1000LL; int64_t com_engineHz_denominator = 100LL * 60LL; // com_speeds times int time_gameFrame; int time_gameDraw; int time_frontend; // renderSystem frontend time int time_backend; // renderSystem backend time #ifdef QUAKE4 int time_waiting; // wait time, surfaced by Quake 4's timing/debug HUD path bool com_debugHudActive; // true when the game debug HUD is active #endif int com_frameTime; // time for the current frame in milliseconds int com_frameNumber; // variable frame number volatile int com_ticNumber; // 60 hz tics int com_editors; // currently opened editor(s) bool com_editorActive; // true if an editor has focus #ifdef _WIN32 HWND com_hwndMsg = NULL; bool com_outputMsg = false; unsigned int com_msgID = -1; #endif #ifdef __DOOM_DLL__ idGame * game = NULL; idGameEdit * gameEdit = NULL; #endif // writes si_version to the config file - in a kinda obfuscated way //#define ID_WRITE_VERSION #ifdef QUAKE4 /* ================== Com_GetVersion ================== */ const char *Com_GetVersion( void ) { return cvarSystem->GetCVarString( "si_version" ); } /* ================== Com_GetErrorMessage ================== */ const char *Com_GetErrorMessage( void ) { return common ? common->GetErrorMessage() : ""; } void GSSStartData( void ) { } void GSSEndData( void ) { } const char *Com_GetStringValue( void *var ) { return var ? *( reinterpret_cast( var ) + 1 ) : ""; } class rvLanguage { public: rvLanguage( void ) { hasVO = false; } void SetLanguage( const idStr &lang ) { language = lang; } const char * GetLanguage( void ) const { return language.c_str(); } void SetHasVO( bool in ) { hasVO = in; } bool HasVO( void ) const { return hasVO; } bool Load( const char *fileName, bool clear = false ) { return strings.Load( fileName, clear ); } const idLangKeyValue *GetString( int i ) const { return strings.GetKeyVal( i ); } const char * GetString( const char *token ) const { return strings.GetString( token ); } int GetNumStrings( void ) const { return strings.GetNumKeyVals(); } const idLangDict *GetDict( void ) const { return &strings; } idStr language; idLangDict strings; bool hasVO; }; /* ================== MemInfo::MemInfo ================== */ MemInfo::MemInfo( void ) { total = 0; assetTotals = 0; imageAssetsTotal = 0; modelAssetsTotal = 0; soundAssetsTotal = 0; collAssetsTotal = 0; animsAssetsTotal = 0; aasAssetsTotal = 0; imageAssetsCount = 0; modelAssetsCount = 0; soundAssetsCount = 0; collAssetsCount = 0; animsAssetsCount = 0; aasAssetsCount = 0; } #endif class idCommonLocal : public idCommon { public: idCommonLocal( void ); virtual void Init( int argc, const char **argv, const char *cmdline ); virtual void Shutdown( void ); virtual void Quit( void ); virtual bool IsInitialized( void ) const; virtual void Frame( void ); virtual void GUIFrame( bool execCmd, bool network ); virtual void StartupVariable( const char *match, bool once ); #ifdef QUAKE4 virtual int GetUserCmdHz( void ) const; virtual int GetUserCmdMSec( void ) const; virtual int GetFrameTime( void ) const; virtual bool IsRenderableGameFrame( void ) const; virtual void SetRenderableGameFrame( bool in ); virtual const char * GetErrorMessage( void ) const; virtual bool IsToolActive( void ) const; #ifdef _RV_MEM_SYS_SUPPORT virtual void InitHeaps( void ); virtual void ShutdownHeaps( void ); #endif virtual void RunAlwaysThinkGUIs( int time ); virtual bool DoingDeclValidation( void ); virtual void SetCrashReportAutoSendString( const char *psString ); #endif virtual void InitTool( const toolFlag_t tool, const idDict *dict ); virtual void ActivateTool( bool active ); virtual void WriteConfigToFile( const char *filename ); virtual void WriteFlaggedCVarsToFile( const char *filename, int flags, const char *setCmd ); #ifdef QUAKE4 virtual void BeginRedirect( char *buffer, int buffersize, void (*flush)( const char * ), bool rcon = false ); #else virtual void BeginRedirect( char *buffer, int buffersize, void (*flush)( const char * ) ); #endif virtual void EndRedirect( void ); virtual void SetRefreshOnPrint( bool set ); virtual void Printf( const char *fmt, ... ) id_attribute((format(printf,2,3))); virtual void VPrintf( const char *fmt, va_list arg ); virtual void DPrintf( const char *fmt, ... ) id_attribute((format(printf,2,3))); virtual void Warning( const char *fmt, ... ) id_attribute((format(printf,2,3))); virtual void DWarning( const char *fmt, ...) id_attribute((format(printf,2,3))); virtual void PrintWarnings( void ); virtual void ClearWarnings( const char *reason ); virtual void Error( const char *fmt, ... ) id_attribute((format(printf,2,3))); virtual void FatalError( const char *fmt, ... ) id_attribute((format(printf,2,3))); virtual const idLangDict * GetLanguageDict( void ); #ifdef QUAKE4 virtual void DumpWarnings( void ); virtual const char * GetLocalizedString( const char *token, int langIndex = -1 ); virtual const idLangKeyValue *GetLocalizedString( int index, int langIndex = -1 ); virtual int GetNumLanguages( void ) const; virtual int GetNumLocalizedStrings( void ) const; virtual const char * GetLanguage( int index ) const; virtual bool LanguageHasVO( int index ) const; #endif #ifdef PREY virtual void MaterialKeyForBinding(const char* binding, char* materialName, char* keyText, bool* wideKey); #endif virtual const char * KeysFromBinding( const char *bind ); virtual const char * BindingFromKey( const char *key ); virtual int ButtonState( int key ); virtual int KeyState( int key ); #ifdef QUAKE4 virtual int GetRModeForMachineSpec( int machineSpec ) const; virtual void SetDesiredMachineSpec( int machineSpec ); virtual bool IsRCon( void ) const; #endif void InitGame( void ); void ShutdownGame( bool reloading ); // localization void InitLanguageDict( void ); void LocalizeGui( const char *fileName, idLangDict &langDict ); void LocalizeMapData( const char *fileName, idLangDict &langDict ); void LocalizeSpecificMapData( const char *fileName, idLangDict &langDict, const idLangDict &replaceArgs ); void SetMachineSpec( void ); private: void InitCommands( void ); void InitRenderSystem( void ); void InitSIMD( void ); bool AddStartupCommands( void ); void ParseCommandLine( int argc, const char **argv ); void ClearCommandLine( void ); bool SafeMode( void ); void CheckToolMode( void ); void CloseLogFile( void ); void WriteConfiguration( void ); #ifndef QUAKE4 void DumpWarnings( void ); #endif void LoadGameDLL( void ); void UnloadGameDLL( void ); void PrintLoadingMessage( const char *msg ); void FilterLangList( idStrList* list, idStr lang ); #ifdef QUAKE4 bool AddLanguage( const idStr &language ); void SetActiveLanguage( void ); void ApplyVideoSettings( void ); void SingleAsyncTic( void ); #endif bool com_fullyInitialized; bool com_refreshOnPrint; // update the screen every print for dmap int com_errorEntered; // 0, ERP_DROP, etc bool com_shuttingDown; idFile * logFile; char errorMessage[MAX_PRINT_MSG_SIZE]; char * rd_buffer; int rd_buffersize; void (*rd_flush)( const char *buffer ); #ifdef QUAKE4 bool rd_rcon; #endif idStr warningCaption; idStrList warningList; idStrList errorList; #ifdef QUAKE4 int warningCount[MAX_WARNING_LIST]; #endif INT_PTR gameDLL; idLangDict languageDict; #ifdef QUAKE4 idList languages; int languageDictIndex; int desiredMachineSpec; bool com_renderableGameFrame; #endif #ifdef ID_WRITE_VERSION idCompressor * config_compressor; #endif int gameFrame; // Frame number of the local game double gameTimeResidual; // left over msec from the last game frame virtual float Get_com_engineHz_latched(void); virtual int64_t Get_com_engineHz_numerator(void); virtual int64_t Get_com_engineHz_denominator(void); }; idCommonLocal commonLocal; idCommon * common = &commonLocal; /* ================== idCommonLocal::idCommonLocal ================== */ idCommonLocal::idCommonLocal( void ) { com_fullyInitialized = false; com_refreshOnPrint = false; com_errorEntered = 0; com_shuttingDown = false; gameFrame = 0; gameTimeResidual = 0; logFile = NULL; strcpy( errorMessage, "" ); rd_buffer = NULL; rd_buffersize = 0; rd_flush = NULL; #ifdef QUAKE4 rd_rcon = false; languageDictIndex = 0; desiredMachineSpec = -1; com_renderableGameFrame = true; memset( warningCount, 0, sizeof( warningCount ) ); #endif gameDLL = 0; #ifdef ID_WRITE_VERSION config_compressor = NULL; #endif } /* ================== idCommonLocal::BeginRedirect ================== */ #ifdef QUAKE4 void idCommonLocal::BeginRedirect( char *buffer, int buffersize, void (*flush)( const char *), bool rcon ) { #else void idCommonLocal::BeginRedirect( char *buffer, int buffersize, void (*flush)( const char *) ) { #endif if ( !buffer || !buffersize || !flush ) { return; } rd_buffer = buffer; rd_buffersize = buffersize; rd_flush = flush; #ifdef QUAKE4 rd_rcon = rcon; #endif *rd_buffer = 0; } /* ================== idCommonLocal::EndRedirect ================== */ void idCommonLocal::EndRedirect( void ) { if ( rd_flush && rd_buffer[ 0 ] ) { rd_flush( rd_buffer ); } rd_buffer = NULL; rd_buffersize = 0; rd_flush = NULL; #ifdef QUAKE4 rd_rcon = false; #endif } #ifdef _WIN32 /* ================== EnumWindowsProc ================== */ BOOL CALLBACK EnumWindowsProc( HWND hwnd, LPARAM lParam ) { char buff[1024]; ::GetWindowText( hwnd, buff, sizeof( buff ) ); if ( idStr::Icmpn( buff, EDITOR_WINDOWTEXT, strlen( EDITOR_WINDOWTEXT ) ) == 0 ) { com_hwndMsg = hwnd; return FALSE; } return TRUE; } /* ================== FindEditor ================== */ bool FindEditor( void ) { com_hwndMsg = NULL; EnumWindows( EnumWindowsProc, 0 ); return !( com_hwndMsg == NULL ); } #endif /* ================== idCommonLocal::CloseLogFile ================== */ void idCommonLocal::CloseLogFile( void ) { if ( logFile ) { com_logFile.SetBool( false ); // make sure no further VPrintf attempts to open the log file again fileSystem->CloseFile( logFile ); logFile = NULL; } } /* ================== idCommonLocal::SetRefreshOnPrint ================== */ void idCommonLocal::SetRefreshOnPrint( bool set ) { com_refreshOnPrint = set; } /* ================== idCommonLocal::VPrintf A raw string should NEVER be passed as fmt, because of "%f" type crashes. ================== */ void idCommonLocal::VPrintf( const char *fmt, va_list args ) { char msg[MAX_PRINT_MSG_SIZE]; int timeLength; static bool logFileFailed = false; // if the cvar system is not initialized if ( !cvarSystem->IsInitialized() ) { return; } // optionally put a timestamp at the beginning of each print, // so we can see how long different init sections are taking if ( com_timestampPrints.GetInteger() ) { int t = Sys_Milliseconds(); if ( com_timestampPrints.GetInteger() == 1 ) { t /= 1000; } sprintf( msg, "[%i]", t ); timeLength = strlen( msg ); } else { timeLength = 0; } // don't overflow if ( idStr::vsnPrintf( msg+timeLength, MAX_PRINT_MSG_SIZE-timeLength-1, fmt, args ) < 0 ) { msg[sizeof(msg)-2] = '\n'; msg[sizeof(msg)-1] = '\0'; // avoid output garbling Sys_Printf( "idCommon::VPrintf: truncated to %d characters\n", strlen(msg)-1 ); } if ( rd_buffer ) { if ( (int)( strlen( msg ) + strlen( rd_buffer ) ) > ( rd_buffersize - 1 ) ) { rd_flush( rd_buffer ); *rd_buffer = 0; } strcat( rd_buffer, msg ); return; } // echo to console buffer console->Print( msg ); // remove any color codes idStr::RemoveColors( msg ); // echo to dedicated console and early console Sys_Printf( "%s", msg ); // print to script debugger server // DebuggerServerPrint( msg ); #if 0 // !@# #if defined(_DEBUG) && defined(WIN32) if ( strlen( msg ) < 512 ) { TRACE( msg ); } #endif #endif // logFile if ( com_logFile.GetInteger() && !logFileFailed && fileSystem->IsInitialized() ) { static bool recursing; if ( !logFile && !recursing ) { struct tm *newtime; ID_TIME_T aclock; const char *fileName = com_logFileName.GetString()[0] ? com_logFileName.GetString() : "qconsole.log"; // fileSystem->OpenFileWrite can cause recursive prints into here recursing = true; logFile = fileSystem->OpenFileWrite( fileName ); if ( !logFile ) { logFileFailed = true; FatalError( "failed to open log file '%s'\n", fileName ); } recursing = false; if ( com_logFile.GetInteger() > 1 ) { // force it to not buffer so we get valid // data even if we are crashing logFile->ForceFlush(); } time( &aclock ); newtime = localtime( &aclock ); Printf( "log file '%s' opened on %s\n", fileName, asctime( newtime ) ); } if ( logFile ) { logFile->Write( msg, strlen( msg ) ); logFile->Flush(); // ForceFlush doesn't help a whole lot } } // don't trigger any updates if we are in the process of doing a fatal error if ( com_errorEntered != ERP_FATAL ) { // update the console if we are in a long-running command, like dmap if ( com_refreshOnPrint ) { session->UpdateScreen(); } // let session redraw the animated loading screen if necessary session->PacifierUpdate(); } #ifdef _WIN32 if ( com_outputMsg ) { if ( com_msgID == -1 ) { com_msgID = ::RegisterWindowMessage( DMAP_MSGID ); if ( !FindEditor() ) { com_outputMsg = false; } else { Sys_ShowWindow( false ); } } if ( com_hwndMsg ) { ATOM atom = ::GlobalAddAtom( msg ); ::PostMessage( com_hwndMsg, com_msgID, 0, static_cast(atom) ); } } #endif } /* ================== idCommonLocal::Printf Both client and server can use this, and it will output to the appropriate place. A raw string should NEVER be passed as fmt, because of "%f" type crashers. ================== */ void idCommonLocal::Printf( const char *fmt, ... ) { va_list argptr; va_start( argptr, fmt ); VPrintf( fmt, argptr ); va_end( argptr ); } /* ================== idCommonLocal::DPrintf prints message that only shows up if the "developer" cvar is set ================== */ void idCommonLocal::DPrintf( const char *fmt, ... ) { va_list argptr; char msg[MAX_PRINT_MSG_SIZE]; if ( !cvarSystem->IsInitialized() || !com_developer.GetBool() ) { return; // don't confuse non-developers with techie stuff... } va_start( argptr, fmt ); idStr::vsnPrintf( msg, sizeof(msg), fmt, argptr ); va_end( argptr ); msg[sizeof(msg)-1] = '\0'; // never refresh the screen, which could cause reentrency problems bool temp = com_refreshOnPrint; com_refreshOnPrint = false; Printf( S_COLOR_RED"%s", msg ); com_refreshOnPrint = temp; } /* ================== idCommonLocal::DWarning prints warning message in yellow that only shows up if the "developer" cvar is set ================== */ void idCommonLocal::DWarning( const char *fmt, ... ) { va_list argptr; char msg[MAX_PRINT_MSG_SIZE]; if ( !com_developer.GetBool() ) { return; // don't confuse non-developers with techie stuff... } va_start( argptr, fmt ); idStr::vsnPrintf( msg, sizeof(msg), fmt, argptr ); va_end( argptr ); msg[sizeof(msg)-1] = '\0'; Printf( S_COLOR_YELLOW"WARNING: %s\n", msg ); } /* ================== idCommonLocal::Warning prints WARNING %s and adds the warning message to a queue to be printed later on ================== */ void idCommonLocal::Warning( const char *fmt, ... ) { va_list argptr; char msg[MAX_PRINT_MSG_SIZE]; va_start( argptr, fmt ); idStr::vsnPrintf( msg, sizeof(msg), fmt, argptr ); va_end( argptr ); msg[sizeof(msg)-1] = 0; #ifdef QUAKE4 int warningIndex = -1; for ( int i = 0; i < warningList.Num(); i++ ) { if ( idStr::Cmp( warningList[i].c_str(), msg ) == 0 ) { warningIndex = i; break; } } if ( warningIndex < 0 && warningList.Num() < MAX_WARNING_LIST ) { warningIndex = warningList.Append( msg ); warningCount[warningIndex] = 0; } bool printWarning = true; if ( warningIndex >= 0 ) { if ( com_uniqueWarnings.GetBool() && warningCount[warningIndex] > 0 ) { printWarning = false; } if ( warningCount[warningIndex] < 1000 ) { warningCount[warningIndex]++; } } if ( printWarning ) { Printf( S_COLOR_YELLOW "WARNING: " S_COLOR_RED "%s\n", msg ); } #else Printf( S_COLOR_YELLOW "WARNING: " S_COLOR_RED "%s\n", msg ); if ( warningList.Num() < MAX_WARNING_LIST ) { warningList.AddUnique( msg ); } #endif } /* ================== idCommonLocal::PrintWarnings ================== */ void idCommonLocal::PrintWarnings( void ) { int i; if ( !warningList.Num() ) { return; } #ifndef QUAKE4 warningList.Sort(); #endif Printf( "------------- Warnings ---------------\n" ); Printf( "during %s...\n", warningCaption.c_str() ); for ( i = 0; i < warningList.Num(); i++ ) { Printf( S_COLOR_YELLOW "WARNING: " S_COLOR_RED "%s\n", warningList[i].c_str() ); } if ( warningList.Num() ) { if ( warningList.Num() >= MAX_WARNING_LIST ) { Printf( "more than %d warnings\n", MAX_WARNING_LIST ); } else { Printf( "%d warnings\n", warningList.Num() ); } } } /* ================== idCommonLocal::ClearWarnings ================== */ void idCommonLocal::ClearWarnings( const char *reason ) { warningCaption = reason; warningList.Clear(); #ifdef QUAKE4 memset( warningCount, 0, sizeof( warningCount ) ); #endif } /* ================== idCommonLocal::DumpWarnings ================== */ void idCommonLocal::DumpWarnings( void ) { int i; idFile *warningFile; if ( !warningList.Num() ) { return; } warningFile = fileSystem->OpenFileWrite( "warnings.txt", "fs_savepath" ); if ( warningFile ) { warningFile->Printf( "------------- Warnings ---------------\n\n" ); warningFile->Printf( "during %s...\n", warningCaption.c_str() ); #ifndef QUAKE4 warningList.Sort(); #endif for ( i = 0; i < warningList.Num(); i++ ) { warningList[i].RemoveColors(); #ifdef QUAKE4 warningFile->Printf( "WARNING: %s (%d times)\n", warningList[i].c_str(), warningCount[i] ); #else warningFile->Printf( "WARNING: %s\n", warningList[i].c_str() ); #endif } if ( warningList.Num() >= MAX_WARNING_LIST ) { warningFile->Printf( "\nmore than %d warnings!\n", MAX_WARNING_LIST ); } else { warningFile->Printf( "\n%d warnings.\n", warningList.Num() ); } warningFile->Printf( "\n\n-------------- Errors ---------------\n\n" ); errorList.Sort(); for ( i = 0; i < errorList.Num(); i++ ) { errorList[i].RemoveColors(); warningFile->Printf( "ERROR: %s", errorList[i].c_str() ); } warningFile->ForceFlush(); fileSystem->CloseFile( warningFile ); #if defined(_WIN32) && !defined(_DEBUG) #ifdef QUAKE4 if ( !com_makingBuild.GetBool() && !com_updateLoadSize.GetBool() ) { #endif idStr osPath; osPath = fileSystem->RelativePathToOSPath( "warnings.txt", "fs_savepath" ); WinExec( va( "Notepad.exe %s", osPath.c_str() ), SW_SHOW ); #ifdef QUAKE4 } #endif #endif } } /* ================== idCommonLocal::Error ================== */ void idCommonLocal::Error( const char *fmt, ... ) { va_list argptr; static int lastErrorTime; static int errorCount; int currentTime; int code = ERP_DROP; // always turn this off after an error com_refreshOnPrint = false; // when we are running automated scripts, make sure we // know if anything failed if ( cvarSystem->GetCVarInteger( "fs_copyfiles" ) ) { code = ERP_FATAL; } // if we don't have GL running, make it a fatal error if ( !renderSystem->IsOpenGLRunning() ) { code = ERP_FATAL; } // if we got a recursive error, make it fatal if ( com_errorEntered ) { // if we are recursively erroring while exiting // from a fatal error, just kill the entire // process immediately, which will prevent a // full screen rendering window covering the // error dialog if ( com_errorEntered == ERP_FATAL ) { Sys_Quit(); } code = ERP_FATAL; } // if we are getting a solid stream of ERP_DROP, do an ERP_FATAL currentTime = Sys_Milliseconds(); if ( currentTime - lastErrorTime < 100 ) { if ( ++errorCount > 3 ) { code = ERP_FATAL; } } else { errorCount = 0; } lastErrorTime = currentTime; com_errorEntered = code; va_start (argptr,fmt); idStr::vsnPrintf( errorMessage, sizeof(errorMessage), fmt, argptr ); va_end (argptr); errorMessage[sizeof(errorMessage)-1] = '\0'; // copy the error message to the clip board Sys_SetClipboardData( errorMessage ); // add the message to the error list errorList.AddUnique( errorMessage ); // Dont shut down the session for gui editor or debugger if ( !( com_editors & ( EDITOR_GUI | EDITOR_DEBUGGER ) ) ) { session->Stop(); } if ( code == ERP_DISCONNECT ) { com_errorEntered = 0; throw idException( errorMessage ); // The gui editor doesnt want thing to com_error so it handles exceptions instead } else if( com_editors & ( EDITOR_GUI | EDITOR_DEBUGGER ) ) { com_errorEntered = 0; throw idException( errorMessage ); } else if ( code == ERP_DROP ) { Printf( "********************\nERROR: %s\n********************\n", errorMessage ); com_errorEntered = 0; throw idException( errorMessage ); } else { Printf( "********************\nERROR: %s\n********************\n", errorMessage ); } if ( cvarSystem->GetCVarBool( "r_fullscreen" ) ) { cmdSystem->BufferCommandText( CMD_EXEC_NOW, "vid_restart partial windowed\n" ); } Shutdown(); Sys_Error( "%s", errorMessage ); } /* ================== idCommonLocal::FatalError Dump out of the game to a system dialog ================== */ void idCommonLocal::FatalError( const char *fmt, ... ) { va_list argptr; // if we got a recursive error, make it fatal if ( com_errorEntered ) { // if we are recursively erroring while exiting // from a fatal error, just kill the entire // process immediately, which will prevent a // full screen rendering window covering the // error dialog Sys_Printf( "FATAL: recursed fatal error:\n%s\n", errorMessage ); va_start( argptr, fmt ); idStr::vsnPrintf( errorMessage, sizeof(errorMessage), fmt, argptr ); va_end( argptr ); errorMessage[sizeof(errorMessage)-1] = '\0'; Sys_Printf( "%s\n", errorMessage ); // write the console to a log file? Sys_Quit(); } com_errorEntered = ERP_FATAL; va_start( argptr, fmt ); idStr::vsnPrintf( errorMessage, sizeof(errorMessage), fmt, argptr ); va_end( argptr ); errorMessage[sizeof(errorMessage)-1] = '\0'; if ( cvarSystem->GetCVarBool( "r_fullscreen" ) ) { cmdSystem->BufferCommandText( CMD_EXEC_NOW, "vid_restart partial windowed\n" ); } Sys_SetFatalError( errorMessage ); Shutdown(); Sys_Error( "%s", errorMessage ); } /* ================== idCommonLocal::Quit ================== */ void idCommonLocal::Quit( void ) { #ifdef ID_ALLOW_TOOLS if ( com_editors & EDITOR_RADIANT ) { RadiantInit(); return; } #endif // don't try to shutdown if we are in a recursive error if ( !com_errorEntered ) { Shutdown(); } Sys_Quit(); } /* ============================================================================ COMMAND LINE FUNCTIONS + characters separate the commandLine string into multiple console command lines. All of these are valid: doom +set test blah +map test doom set test blah+map test doom set test blah + map test ============================================================================ */ #define MAX_CONSOLE_LINES 32 int com_numConsoleLines; idCmdArgs com_consoleLines[MAX_CONSOLE_LINES]; /* ================== idCommonLocal::ParseCommandLine ================== */ void idCommonLocal::ParseCommandLine( int argc, const char **argv ) { int i, current_count; com_numConsoleLines = 0; current_count = 0; // API says no program path for ( i = 0; i < argc; i++ ) { if ( argv[ i ][ 0 ] == '+' ) { com_numConsoleLines++; com_consoleLines[ com_numConsoleLines-1 ].AppendArg( argv[ i ] + 1 ); } else { if ( !com_numConsoleLines ) { com_numConsoleLines++; } com_consoleLines[ com_numConsoleLines-1 ].AppendArg( argv[ i ] ); } } } /* ================== idCommonLocal::ClearCommandLine ================== */ void idCommonLocal::ClearCommandLine( void ) { com_numConsoleLines = 0; } /* ================== idCommonLocal::SafeMode Check for "safe" on the command line, which will skip loading of config file (DoomConfig.cfg) ================== */ bool idCommonLocal::SafeMode( void ) { int i; for ( i = 0 ; i < com_numConsoleLines ; i++ ) { if ( !idStr::Icmp( com_consoleLines[ i ].Argv(0), "safe" ) || !idStr::Icmp( com_consoleLines[ i ].Argv(0), "cvar_restart" ) ) { com_consoleLines[ i ].Clear(); return true; } } return false; } /* ================== idCommonLocal::CheckToolMode Check for "renderbump", "dmap", or "editor" on the command line, and force fullscreen off in those cases ================== */ void idCommonLocal::CheckToolMode( void ) { int i; for ( i = 0 ; i < com_numConsoleLines ; i++ ) { if ( !idStr::Icmp( com_consoleLines[ i ].Argv(0), "guieditor" ) ) { com_editors |= EDITOR_GUI; } else if ( !idStr::Icmp( com_consoleLines[ i ].Argv(0), "debugger" ) ) { com_editors |= EDITOR_DEBUGGER; } else if ( !idStr::Icmp( com_consoleLines[ i ].Argv(0), "editor" ) ) { com_editors |= EDITOR_RADIANT; } // Nerve: Add support for the material editor else if ( !idStr::Icmp( com_consoleLines[ i ].Argv(0), "materialEditor" ) ) { com_editors |= EDITOR_MATERIAL; } if ( !idStr::Icmp( com_consoleLines[ i ].Argv(0), "renderbump" ) || !idStr::Icmp( com_consoleLines[ i ].Argv(0), "editor" ) || !idStr::Icmp( com_consoleLines[ i ].Argv(0), "guieditor" ) || !idStr::Icmp( com_consoleLines[ i ].Argv(0), "debugger" ) || !idStr::Icmp( com_consoleLines[ i ].Argv(0), "dmap" ) || !idStr::Icmp( com_consoleLines[ i ].Argv(0), "materialEditor" ) ) { cvarSystem->SetCVarBool( "r_fullscreen", false ); return; } } } /* ================== idCommonLocal::StartupVariable Searches for command line parameters that are set commands. If match is not NULL, only that cvar will be looked for. That is necessary because cddir and basedir need to be set before the filesystem is started, but all other sets should be after execing the config and default. ================== */ void idCommonLocal::StartupVariable( const char *match, bool once ) { int i; const char *s; i = 0; while ( i < com_numConsoleLines ) { if ( strcmp( com_consoleLines[ i ].Argv( 0 ), "set" ) ) { i++; continue; } s = com_consoleLines[ i ].Argv(1); if ( !match || !idStr::Icmp( s, match ) ) { cvarSystem->SetCVarString( s, com_consoleLines[ i ].Argv( 2 ) ); if ( once ) { // kill the line int j = i + 1; while ( j < com_numConsoleLines ) { com_consoleLines[ j - 1 ] = com_consoleLines[ j ]; j++; } com_numConsoleLines--; continue; } } i++; } } /* ================== idCommonLocal::AddStartupCommands Adds command line parameters as script statements Commands are separated by + signs Returns true if any late commands were added, which will keep the demoloop from immediately starting ================== */ bool idCommonLocal::AddStartupCommands( void ) { int i; bool added; added = false; // quote every token, so args with semicolons can work for ( i = 0; i < com_numConsoleLines; i++ ) { if ( !com_consoleLines[i].Argc() ) { continue; } // set commands won't override menu startup if ( idStr::Icmpn( com_consoleLines[i].Argv(0), "set", 3 ) ) { added = true; } // directly as tokenized so nothing gets screwed cmdSystem->BufferCommandArgs( CMD_EXEC_APPEND, com_consoleLines[i] ); } return added; } /* ================= idCommonLocal::InitTool ================= */ void idCommonLocal::InitTool( const toolFlag_t tool, const idDict *dict ) { #ifdef ID_ALLOW_TOOLS if ( tool & EDITOR_SOUND ) { SoundEditorInit( dict ); } else if ( tool & EDITOR_LIGHT ) { LightEditorInit( dict ); } else if ( tool & EDITOR_PARTICLE ) { ParticleEditorInit( dict ); } else if ( tool & EDITOR_AF ) { AFEditorInit( dict ); } #endif } /* ================== idCommonLocal::ActivateTool Activates or Deactivates a tool ================== */ void idCommonLocal::ActivateTool( bool active ) { com_editorActive = active; Sys_GrabMouseCursor( !active ); } /* ================== idCommonLocal::WriteFlaggedCVarsToFile ================== */ void idCommonLocal::WriteFlaggedCVarsToFile( const char *filename, int flags, const char *setCmd ) { idFile *f; f = fileSystem->OpenFileWrite( filename ); if ( !f ) { Printf( "Couldn't write %s.\n", filename ); return; } cvarSystem->WriteFlaggedVariables( flags, setCmd, f ); fileSystem->CloseFile( f ); } /* ================== idCommonLocal::WriteConfigToFile ================== */ void idCommonLocal::WriteConfigToFile( const char *filename ) { idFile *f; #ifdef ID_WRITE_VERSION ID_TIME_T t; char *curtime; idStr runtag; idFile_Memory compressed( "compressed" ); idBase64 out; #endif f = fileSystem->OpenFileWrite( filename ); if ( !f ) { Printf ("Couldn't write %s.\n", filename ); return; } #ifdef ID_WRITE_VERSION assert( config_compressor ); t = time( NULL ); curtime = ctime( &t ); sprintf( runtag, "%s - %s", cvarSystem->GetCVarString( "si_version" ), curtime ); config_compressor->Init( &compressed, true, 8 ); config_compressor->Write( runtag.c_str(), runtag.Length() ); config_compressor->FinishCompress( ); out.Encode( (const byte *)compressed.GetDataPtr(), compressed.Length() ); f->Printf( "// %s\n", out.c_str() ); #endif idKeyInput::WriteBindings( f ); cvarSystem->WriteFlaggedVariables( CVAR_ARCHIVE, "seta", f ); fileSystem->CloseFile( f ); } /* =============== idCommonLocal::WriteConfiguration Writes key bindings and archived cvars to config file if modified =============== */ void idCommonLocal::WriteConfiguration( void ) { // if we are quiting without fully initializing, make sure // we don't write out anything if ( !com_fullyInitialized ) { return; } if ( !( cvarSystem->GetModifiedFlags() & CVAR_ARCHIVE ) ) { return; } cvarSystem->ClearModifiedFlags( CVAR_ARCHIVE ); // disable printing out the "Writing to:" message bool developer = com_developer.GetBool(); com_developer.SetBool( false ); #ifdef QUAKE4 WriteConfigToFile( "Quake4Config.cfg" ); #else WriteConfigToFile( CONFIG_FILE ); #endif session->WriteCDKey( ); // restore the developer cvar com_developer.SetBool( developer ); } /* =============== KeysFromBinding() Returns the key bound to the command =============== */ const char* idCommonLocal::KeysFromBinding( const char *bind ) { return idKeyInput::KeysFromBinding( bind ); } /* =============== BindingFromKey() Returns the binding bound to key =============== */ const char* idCommonLocal::BindingFromKey( const char *key ) { return idKeyInput::BindingFromKey( key ); } /* =============== ButtonState() Returns the state of the button =============== */ int idCommonLocal::ButtonState( int key ) { return usercmdGen->ButtonState(key); } /* =============== ButtonState() Returns the state of the key =============== */ int idCommonLocal::KeyState( int key ) { return usercmdGen->KeyState(key); } #ifdef QUAKE4 /* =============== idCommonLocal::GetUserCmdHz =============== */ int idCommonLocal::GetUserCmdHz( void ) const { return 60; } /* =============== idCommonLocal::GetUserCmdMSec =============== */ int idCommonLocal::GetUserCmdMSec( void ) const { return 1000 / GetUserCmdHz(); } /* =============== idCommonLocal::GetFrameTime =============== */ int idCommonLocal::GetFrameTime( void ) const { return com_frameTime; } /* =============== idCommonLocal::IsRenderableGameFrame =============== */ bool idCommonLocal::IsRenderableGameFrame( void ) const { return com_renderableGameFrame; } /* =============== idCommonLocal::SetRenderableGameFrame =============== */ void idCommonLocal::SetRenderableGameFrame( bool in ) { com_renderableGameFrame = in; } /* =============== idCommonLocal::GetErrorMessage =============== */ const char *idCommonLocal::GetErrorMessage( void ) const { return errorMessage; } /* =============== idCommonLocal::IsToolActive =============== */ bool idCommonLocal::IsToolActive( void ) const { return com_editorActive; } #ifdef _RV_MEM_SYS_SUPPORT void idCommonLocal::InitHeaps( void ) { } void idCommonLocal::ShutdownHeaps( void ) { } #endif /* =============== idCommonLocal::RunAlwaysThinkGUIs =============== */ void idCommonLocal::RunAlwaysThinkGUIs( int time ) { //uiManager->RunAlwaysThinkGUIs( time ); } /* =============== idCommonLocal::DoingDeclValidation =============== */ bool idCommonLocal::DoingDeclValidation( void ) { return ( com_editors & EDITOR_DECL_VALIDATING ) == EDITOR_DECL_VALIDATING; } /* =============== idCommonLocal::SetCrashReportAutoSendString =============== */ void idCommonLocal::SetCrashReportAutoSendString( const char *psString ) { #ifdef _WIN32 // Quake 4 forwarded this to the crash-info layer. Keep this harmless when the // crash-info API is not linked into the Doom 3 codebase. // CI_SetCrashReportAutoSendString( psString ); #else (void)psString; #endif } /* =============== idCommonLocal::GetRModeForMachineSpec =============== */ int idCommonLocal::GetRModeForMachineSpec( int machineSpec ) const { if ( machineSpec == 3 ) { return 5; } if ( machineSpec == 2 ) { return 4; } return 3; } /* =============== idCommonLocal::SetDesiredMachineSpec =============== */ void idCommonLocal::SetDesiredMachineSpec( int machineSpec ) { desiredMachineSpec = machineSpec; } /* =============== idCommonLocal::IsRCon =============== */ bool idCommonLocal::IsRCon( void ) const { return rd_rcon; } #endif //============================================================================ #ifdef ID_ALLOW_TOOLS /* ================== Com_Editor_f we can start the editor dynamically, but we won't ever get back ================== */ static void Com_Editor_f( const idCmdArgs &args ) { RadiantInit(); } /* ============= Com_ScriptDebugger_f ============= */ static void Com_ScriptDebugger_f( const idCmdArgs &args ) { // Make sure it wasnt on the command line if ( !( com_editors & EDITOR_DEBUGGER ) ) { common->Printf( "Script debugger is currently disabled\n" ); // DebuggerClientLaunch(); } } /* ============= Com_EditGUIs_f ============= */ static void Com_EditGUIs_f( const idCmdArgs &args ) { GUIEditorInit(); } /* ============= Com_MaterialEditor_f ============= */ static void Com_MaterialEditor_f( const idCmdArgs &args ) { // Turn off sounds soundSystem->SetMute( true ); MaterialEditorInit(); } #endif // ID_ALLOW_TOOLS /* ============ idCmdSystemLocal::PrintMemInfo_f This prints out memory debugging data ============ */ static void PrintMemInfo_f( const idCmdArgs &args ) { } #ifdef ID_ALLOW_TOOLS /* ================== Com_EditLights_f ================== */ static void Com_EditLights_f( const idCmdArgs &args ) { LightEditorInit( NULL ); cvarSystem->SetCVarInteger( "g_editEntityMode", 1 ); } /* ================== Com_EditSounds_f ================== */ static void Com_EditSounds_f( const idCmdArgs &args ) { SoundEditorInit( NULL ); cvarSystem->SetCVarInteger( "g_editEntityMode", 2 ); } /* ================== Com_EditDecls_f ================== */ static void Com_EditDecls_f( const idCmdArgs &args ) { DeclBrowserInit( NULL ); } /* ================== Com_EditAFs_f ================== */ static void Com_EditAFs_f( const idCmdArgs &args ) { AFEditorInit( NULL ); } /* ================== Com_EditParticles_f ================== */ static void Com_EditParticles_f( const idCmdArgs &args ) { ParticleEditorInit( NULL ); } /* ================== Com_EditScripts_f ================== */ static void Com_EditScripts_f( const idCmdArgs &args ) { ScriptEditorInit( NULL ); } /* ================== Com_EditPDAs_f ================== */ static void Com_EditPDAs_f( const idCmdArgs &args ) { PDAEditorInit( NULL ); } #endif // ID_ALLOW_TOOLS /* ================== Com_Error_f Just throw a fatal error to test error shutdown procedures. ================== */ static void Com_Error_f( const idCmdArgs &args ) { if ( !com_developer.GetBool() ) { commonLocal.Printf( "error may only be used in developer mode\n" ); return; } if ( args.Argc() > 1 ) { commonLocal.FatalError( "Testing fatal error" ); } else { commonLocal.Error( "Testing drop error" ); } } /* ================== Com_Freeze_f Just freeze in place for a given number of seconds to test error recovery. ================== */ static void Com_Freeze_f( const idCmdArgs &args ) { float s; int start, now; if ( args.Argc() != 2 ) { commonLocal.Printf( "freeze \n" ); return; } if ( !com_developer.GetBool() ) { commonLocal.Printf( "freeze may only be used in developer mode\n" ); return; } s = atof( args.Argv(1) ); start = eventLoop->Milliseconds(); while ( 1 ) { now = eventLoop->Milliseconds(); if ( ( now - start ) * 0.001f > s ) { break; } } } /* ================= Com_Crash_f A way to force a bus error for development reasons ================= */ static void Com_Crash_f( const idCmdArgs &args ) { if ( !com_developer.GetBool() ) { commonLocal.Printf( "crash may only be used in developer mode\n" ); return; } * ( int * ) 0 = 0x12345678; } /* ================= Com_Quit_f ================= */ static void Com_Quit_f( const idCmdArgs &args ) { commonLocal.Quit(); } /* =============== Com_WriteConfig_f Write the config file to a specific name =============== */ void Com_WriteConfig_f( const idCmdArgs &args ) { idStr filename; if ( args.Argc() != 2 ) { commonLocal.Printf( "Usage: writeconfig \n" ); return; } filename = args.Argv(1); filename.DefaultFileExtension( ".cfg" ); commonLocal.Printf( "Writing %s.\n", filename.c_str() ); commonLocal.WriteConfigToFile( filename ); } /* ================= Com_SetMachineSpecs_f ================= */ void Com_SetMachineSpec_f( const idCmdArgs &args ) { commonLocal.SetMachineSpec(); } #ifdef QUAKE4 /* ================= Com_ExecMPMachineSpec_f ================= */ void Com_ExecMPMachineSpec_f( const idCmdArgs &args ) { cvarSystem->SetCVarInteger( "image_anisotropy", 1, CVAR_ARCHIVE ); cvarSystem->SetCVarFloat( "r_lod_animations_distance", 500.0f ); cvarSystem->SetCVarBool( "r_lod_shadows", true ); cvarSystem->SetCVarBool( "r_lod_entities", true ); } /* ================= Com_WriteAssetLog_f ================= */ void Com_WriteAssetLog_f( const idCmdArgs &args ) { //fileSystem->WriteAssetLog(); } /* ================= Com_ClearAssetLog_f ================= */ void Com_ClearAssetLog_f( const idCmdArgs &args ) { //fileSystem->ClearAssetLog(); } /* ================= Com_ShowMemory_f ================= */ void Com_ShowMemory_f( const idCmdArgs &args ) { common->Printf( "Memory usage:\n" ); unsigned int total = 0; if ( gameEdit ) { total += gameEdit->ScriptSummary( args ); total += gameEdit->ClassSummary( args ); total += gameEdit->EntitySummary( args ); } //total += declManager->ListDeclSummary( args ); if ( session->rw ) { total += session->rw->MemorySummary( args ); } common->Printf( "Total - %.1fMeg\n", (float)total / 1024.0f ); } /* ================= IncrementCVar_f ================= */ void IncrementCVar_f( const idCmdArgs &args ) { if ( args.Argc() < 4 ) { return; } const char *cvarName = args.Argv( 1 ); float incAmt = atof( args.Argv( 2 ) ); float maxAmt = atof( args.Argv( 3 ) ); float val = cvarSystem->GetCVarFloat( cvarName ) + incAmt; if ( val > maxAmt ) { val = maxAmt; } cvarSystem->SetCVarFloat( cvarName, val ); } /* ================= DecrementCVar_f ================= */ void DecrementCVar_f( const idCmdArgs &args ) { if ( args.Argc() < 4 ) { return; } const char *cvarName = args.Argv( 1 ); float decAmt = atof( args.Argv( 2 ) ); float minAmt = atof( args.Argv( 3 ) ); float val = cvarSystem->GetCVarFloat( cvarName ) - decAmt; if ( val < minAmt ) { val = minAmt; } cvarSystem->SetCVarFloat( cvarName, val ); } /* ================= idCommonLocal::WriteConfiguration_f ================= */ static void Com_WriteConfiguration_f( const idCmdArgs &args ) { commonLocal.WriteConfigToFile( "Quake4Config.cfg" ); } #endif /* ================= Com_ExecMachineSpecs_f ================= */ #ifdef MACOS_X void OSX_GetVideoCard( int& outVendorId, int& outDeviceId ); bool OSX_GetCPUIdentification( int& cpuId, bool& oldArchitecture ); #endif void Com_ExecMachineSpec_f( const idCmdArgs &args ) { #ifdef QUAKE4 int downSize; int downSizeLimit; int downSizeSpecular; int downSizeSpecularLimit; int downSizeBump; int downSizeBumpLimit; if ( com_machineSpec.GetInteger() == 3 ) { cvarSystem->SetCVarInteger( "image_useCompression", 0, CVAR_ARCHIVE ); cvarSystem->SetCVarInteger( "image_useNormalCompression", 0, CVAR_ARCHIVE ); cvarSystem->SetCVarInteger( "image_usePrecompressedTextures", 0, CVAR_ARCHIVE ); cvarSystem->SetCVarInteger( "image_lodbias", 0, CVAR_ARCHIVE ); cvarSystem->SetCVarInteger( "image_anisotropy", 8, CVAR_ARCHIVE ); cvarSystem->SetCVarInteger( "image_ignoreHighQuality", 0, CVAR_ARCHIVE ); downSize = 0; downSizeLimit = 256; downSizeSpecular = 0; downSizeSpecularLimit = 256; downSizeBump = 0; downSizeBumpLimit = 256; cvarSystem->SetCVarInteger( "r_mode", 5, CVAR_ARCHIVE ); cvarSystem->SetCVarInteger( "r_multiSamples", 0, CVAR_ARCHIVE ); cvarSystem->SetCVarFloat( "g_brassTime", 2.0f, CVAR_ARCHIVE ); cvarSystem->SetCVarFloat( "bse_scale", 1.2f, CVAR_ARCHIVE ); cvarSystem->SetCVarBool( "r_skipNewAmbient", false, CVAR_ARCHIVE ); } else if ( com_machineSpec.GetInteger() == 2 ) { cvarSystem->SetCVarInteger( "image_useCompression", 1, CVAR_ARCHIVE ); if ( !cvarSystem->GetCVarInteger( "image_useNormalCompression" ) ) { cvarSystem->SetCVarInteger( "image_useNormalCompression", 2, CVAR_ARCHIVE ); } cvarSystem->SetCVarInteger( "image_usePrecompressedTextures", 1, CVAR_ARCHIVE ); cvarSystem->SetCVarInteger( "image_lodbias", 0, CVAR_ARCHIVE ); cvarSystem->SetCVarInteger( "image_anisotropy", 4, CVAR_ARCHIVE ); cvarSystem->SetCVarInteger( "image_ignoreHighQuality", 0, CVAR_ARCHIVE ); downSize = 0; downSizeLimit = 256; downSizeSpecular = 0; downSizeSpecularLimit = 64; downSizeBump = 0; downSizeBumpLimit = 256; cvarSystem->SetCVarInteger( "r_mode", 4, CVAR_ARCHIVE ); cvarSystem->SetCVarInteger( "r_multiSamples", 0, CVAR_ARCHIVE ); cvarSystem->SetCVarFloat( "g_brassTime", 1.0f, CVAR_ARCHIVE ); cvarSystem->SetCVarFloat( "bse_scale", 1.0f, CVAR_ARCHIVE ); cvarSystem->SetCVarBool( "r_skipNewAmbient", false, CVAR_ARCHIVE ); } else if ( com_machineSpec.GetInteger() == 1 ) { cvarSystem->SetCVarInteger( "image_useCompression", 1, CVAR_ARCHIVE ); if ( !cvarSystem->GetCVarInteger( "image_useNormalCompression" ) ) { cvarSystem->SetCVarInteger( "image_useNormalCompression", 2, CVAR_ARCHIVE ); } cvarSystem->SetCVarInteger( "image_usePrecompressedTextures", 1, CVAR_ARCHIVE ); cvarSystem->SetCVarInteger( "image_lodbias", 0, CVAR_ARCHIVE ); cvarSystem->SetCVarInteger( "image_anisotropy", 1, CVAR_ARCHIVE ); cvarSystem->SetCVarInteger( "image_ignoreHighQuality", 1, CVAR_ARCHIVE ); downSize = 0; downSizeLimit = 256; downSizeSpecular = 0; downSizeSpecularLimit = 64; downSizeBump = 0; downSizeBumpLimit = 256; cvarSystem->SetCVarInteger( "r_mode", 3, CVAR_ARCHIVE ); cvarSystem->SetCVarInteger( "r_multiSamples", 0, CVAR_ARCHIVE ); cvarSystem->SetCVarFloat( "g_brassTime", 0.0f, CVAR_ARCHIVE ); cvarSystem->SetCVarFloat( "bse_scale", 0.6f, CVAR_ARCHIVE ); cvarSystem->SetCVarBool( "r_skipNewAmbient", true, CVAR_ARCHIVE ); } else { cvarSystem->SetCVarInteger( "image_useCompression", 1, CVAR_ARCHIVE ); if ( !cvarSystem->GetCVarInteger( "image_useNormalCompression" ) ) { cvarSystem->SetCVarInteger( "image_useNormalCompression", 2, CVAR_ARCHIVE ); } cvarSystem->SetCVarInteger( "image_usePrecompressedTextures", 1, CVAR_ARCHIVE ); cvarSystem->SetCVarInteger( "image_lodbias", 0, CVAR_ARCHIVE ); cvarSystem->SetCVarInteger( "image_anisotropy", 1, CVAR_ARCHIVE ); cvarSystem->SetCVarInteger( "image_ignoreHighQuality", 1, CVAR_ARCHIVE ); downSize = 1; downSizeLimit = 256; downSizeSpecular = 1; downSizeSpecularLimit = 64; downSizeBump = 1; downSizeBumpLimit = 256; cvarSystem->SetCVarInteger( "r_mode", 3, CVAR_ARCHIVE ); cvarSystem->SetCVarInteger( "r_multiSamples", 0, CVAR_ARCHIVE ); cvarSystem->SetCVarFloat( "g_brassTime", 0.0f, CVAR_ARCHIVE ); cvarSystem->SetCVarFloat( "bse_scale", 0.3f, CVAR_ARCHIVE ); cvarSystem->SetCVarBool( "r_skipNewAmbient", true, CVAR_ARCHIVE ); } if ( Sys_GetVideoRam() < 80 ) { cvarSystem->SetCVarBool( "image_ignoreHighQuality", true, CVAR_ARCHIVE ); downSize = 1; downSizeLimit = 128; downSizeSpecular = 1; downSizeSpecularLimit = 64; downSizeBump = 1; downSizeBumpLimit = 128; } if ( Sys_GetSystemRam() >= 750 ) { cvarSystem->SetCVarInteger( "s_maxSoundsPerShader", Sys_GetSystemRam() >= 1000 ? 0 : 2, CVAR_ARCHIVE ); cvarSystem->SetCVarBool( "com_purgeAll", false, CVAR_ARCHIVE ); cvarSystem->SetCVarBool( "r_forceLoadImages", false, CVAR_ARCHIVE ); } else { cvarSystem->SetCVarBool( "image_ignoreHighQuality", true, CVAR_ARCHIVE ); cvarSystem->SetCVarInteger( "s_maxSoundsPerShader", 1, CVAR_ARCHIVE ); cvarSystem->SetCVarBool( "com_purgeAll", true, CVAR_ARCHIVE ); cvarSystem->SetCVarBool( "r_forceLoadImages", true, CVAR_ARCHIVE ); } cvarSystem->SetCVarInteger( "image_downSize", downSize, CVAR_ARCHIVE ); cvarSystem->SetCVarInteger( "image_downSizeLimit", downSizeLimit, CVAR_ARCHIVE ); cvarSystem->SetCVarInteger( "image_downSizeSpecular", downSizeSpecular, CVAR_ARCHIVE ); cvarSystem->SetCVarInteger( "image_downSizeSpecularLimit", downSizeSpecularLimit, CVAR_ARCHIVE ); cvarSystem->SetCVarInteger( "image_downSizeBump", downSizeBump, CVAR_ARCHIVE ); cvarSystem->SetCVarInteger( "image_downSizeBumpLimit", downSizeBumpLimit, CVAR_ARCHIVE ); bool oldCard = false; bool nv10or20 = false; renderSystem->GetCardCaps( oldCard, nv10or20 ); if ( oldCard ) { cvarSystem->SetCVarBool( "g_decals", false, CVAR_ARCHIVE ); cvarSystem->SetCVarBool( "g_projectileLights", false, CVAR_ARCHIVE ); cvarSystem->SetCVarBool( "r_skipNewAmbient", true, CVAR_ARCHIVE ); } else { cvarSystem->SetCVarBool( "g_decals", true, CVAR_ARCHIVE ); cvarSystem->SetCVarBool( "g_projectileLights", true, CVAR_ARCHIVE ); } return; #else if ( com_machineSpec.GetInteger() == 3 ) { cvarSystem->SetCVarInteger( "image_anisotropy", 1, CVAR_ARCHIVE ); cvarSystem->SetCVarInteger( "image_lodbias", 0, CVAR_ARCHIVE ); cvarSystem->SetCVarInteger( "image_forceDownSize", 0, CVAR_ARCHIVE ); cvarSystem->SetCVarInteger( "image_roundDown", 1, CVAR_ARCHIVE ); cvarSystem->SetCVarInteger( "image_preload", 1, CVAR_ARCHIVE ); cvarSystem->SetCVarInteger( "image_useAllFormats", 1, CVAR_ARCHIVE ); cvarSystem->SetCVarInteger( "image_downSizeSpecular", 0, CVAR_ARCHIVE ); cvarSystem->SetCVarInteger( "image_downSizeBump", 0, CVAR_ARCHIVE ); cvarSystem->SetCVarInteger( "image_downSizeSpecularLimit", 64, CVAR_ARCHIVE ); cvarSystem->SetCVarInteger( "image_downSizeBumpLimit", 256, CVAR_ARCHIVE ); cvarSystem->SetCVarInteger( "image_usePrecompressedTextures", 0, CVAR_ARCHIVE ); cvarSystem->SetCVarInteger( "image_downsize", 0 , CVAR_ARCHIVE ); cvarSystem->SetCVarString( "image_filter", "GL_LINEAR_MIPMAP_LINEAR", CVAR_ARCHIVE ); cvarSystem->SetCVarInteger( "image_anisotropy", 8, CVAR_ARCHIVE ); cvarSystem->SetCVarInteger( "image_useCompression", 0, CVAR_ARCHIVE ); cvarSystem->SetCVarInteger( "image_ignoreHighQuality", 0, CVAR_ARCHIVE ); cvarSystem->SetCVarInteger( "s_maxSoundsPerShader", 0, CVAR_ARCHIVE ); cvarSystem->SetCVarInteger( "r_mode", 5, CVAR_ARCHIVE ); cvarSystem->SetCVarInteger( "image_useNormalCompression", 0, CVAR_ARCHIVE ); cvarSystem->SetCVarInteger( "r_multiSamples", 0, CVAR_ARCHIVE ); } else if ( com_machineSpec.GetInteger() == 2 ) { cvarSystem->SetCVarString( "image_filter", "GL_LINEAR_MIPMAP_LINEAR", CVAR_ARCHIVE ); cvarSystem->SetCVarInteger( "image_anisotropy", 1, CVAR_ARCHIVE ); cvarSystem->SetCVarInteger( "image_lodbias", 0, CVAR_ARCHIVE ); cvarSystem->SetCVarInteger( "image_forceDownSize", 0, CVAR_ARCHIVE ); cvarSystem->SetCVarInteger( "image_roundDown", 1, CVAR_ARCHIVE ); cvarSystem->SetCVarInteger( "image_preload", 1, CVAR_ARCHIVE ); cvarSystem->SetCVarInteger( "image_useAllFormats", 1, CVAR_ARCHIVE ); cvarSystem->SetCVarInteger( "image_downSizeSpecular", 0, CVAR_ARCHIVE ); cvarSystem->SetCVarInteger( "image_downSizeBump", 0, CVAR_ARCHIVE ); cvarSystem->SetCVarInteger( "image_downSizeSpecularLimit", 64, CVAR_ARCHIVE ); cvarSystem->SetCVarInteger( "image_downSizeBumpLimit", 256, CVAR_ARCHIVE ); cvarSystem->SetCVarInteger( "image_usePrecompressedTextures", 1, CVAR_ARCHIVE ); cvarSystem->SetCVarInteger( "image_downsize", 0, CVAR_ARCHIVE ); cvarSystem->SetCVarInteger( "image_anisotropy", 8, CVAR_ARCHIVE ); cvarSystem->SetCVarInteger( "image_useCompression", 1, CVAR_ARCHIVE ); cvarSystem->SetCVarInteger( "image_ignoreHighQuality", 0, CVAR_ARCHIVE ); cvarSystem->SetCVarInteger( "s_maxSoundsPerShader", 0, CVAR_ARCHIVE ); cvarSystem->SetCVarInteger( "image_useNormalCompression", 0, CVAR_ARCHIVE ); cvarSystem->SetCVarInteger( "r_mode", 4, CVAR_ARCHIVE ); cvarSystem->SetCVarInteger( "r_multiSamples", 0, CVAR_ARCHIVE ); } else if ( com_machineSpec.GetInteger() == 1 ) { cvarSystem->SetCVarString( "image_filter", "GL_LINEAR_MIPMAP_LINEAR", CVAR_ARCHIVE ); cvarSystem->SetCVarInteger( "image_anisotropy", 1, CVAR_ARCHIVE ); cvarSystem->SetCVarInteger( "image_lodbias", 0, CVAR_ARCHIVE ); cvarSystem->SetCVarInteger( "image_downSize", 0, CVAR_ARCHIVE ); cvarSystem->SetCVarInteger( "image_forceDownSize", 0, CVAR_ARCHIVE ); cvarSystem->SetCVarInteger( "image_roundDown", 1, CVAR_ARCHIVE ); cvarSystem->SetCVarInteger( "image_preload", 1, CVAR_ARCHIVE ); cvarSystem->SetCVarInteger( "image_useCompression", 1, CVAR_ARCHIVE ); cvarSystem->SetCVarInteger( "image_useAllFormats", 1, CVAR_ARCHIVE ); cvarSystem->SetCVarInteger( "image_usePrecompressedTextures", 1, CVAR_ARCHIVE ); cvarSystem->SetCVarInteger( "image_downSizeSpecular", 0, CVAR_ARCHIVE ); cvarSystem->SetCVarInteger( "image_downSizeBump", 0, CVAR_ARCHIVE ); cvarSystem->SetCVarInteger( "image_downSizeSpecularLimit", 64, CVAR_ARCHIVE ); cvarSystem->SetCVarInteger( "image_downSizeBumpLimit", 256, CVAR_ARCHIVE ); cvarSystem->SetCVarInteger( "image_useNormalCompression", 2, CVAR_ARCHIVE ); cvarSystem->SetCVarInteger( "r_mode", 3, CVAR_ARCHIVE ); cvarSystem->SetCVarInteger( "r_multiSamples", 0, CVAR_ARCHIVE ); } else { cvarSystem->SetCVarString( "image_filter", "GL_LINEAR_MIPMAP_LINEAR", CVAR_ARCHIVE ); cvarSystem->SetCVarInteger( "image_anisotropy", 1, CVAR_ARCHIVE ); cvarSystem->SetCVarInteger( "image_lodbias", 0, CVAR_ARCHIVE ); cvarSystem->SetCVarInteger( "image_roundDown", 1, CVAR_ARCHIVE ); cvarSystem->SetCVarInteger( "image_preload", 1, CVAR_ARCHIVE ); cvarSystem->SetCVarInteger( "image_useAllFormats", 1, CVAR_ARCHIVE ); cvarSystem->SetCVarInteger( "image_usePrecompressedTextures", 1, CVAR_ARCHIVE ); cvarSystem->SetCVarInteger( "image_downSize", 1, CVAR_ARCHIVE ); cvarSystem->SetCVarInteger( "image_anisotropy", 0, CVAR_ARCHIVE ); cvarSystem->SetCVarInteger( "image_useCompression", 1, CVAR_ARCHIVE ); cvarSystem->SetCVarInteger( "image_ignoreHighQuality", 1, CVAR_ARCHIVE ); cvarSystem->SetCVarInteger( "s_maxSoundsPerShader", 1, CVAR_ARCHIVE ); cvarSystem->SetCVarInteger( "image_downSizeSpecular", 1, CVAR_ARCHIVE ); cvarSystem->SetCVarInteger( "image_downSizeBump", 1, CVAR_ARCHIVE ); cvarSystem->SetCVarInteger( "image_downSizeSpecularLimit", 64, CVAR_ARCHIVE ); cvarSystem->SetCVarInteger( "image_downSizeBumpLimit", 256, CVAR_ARCHIVE ); cvarSystem->SetCVarInteger( "r_mode", 3 , CVAR_ARCHIVE ); cvarSystem->SetCVarInteger( "image_useNormalCompression", 2, CVAR_ARCHIVE ); cvarSystem->SetCVarInteger( "r_multiSamples", 0, CVAR_ARCHIVE ); } if ( Sys_GetVideoRam() < 128 ) { cvarSystem->SetCVarBool( "image_ignoreHighQuality", true, CVAR_ARCHIVE ); cvarSystem->SetCVarInteger( "image_downSize", 1, CVAR_ARCHIVE ); cvarSystem->SetCVarInteger( "image_downSizeLimit", 256, CVAR_ARCHIVE ); cvarSystem->SetCVarInteger( "image_downSizeSpecular", 1, CVAR_ARCHIVE ); cvarSystem->SetCVarInteger( "image_downSizeSpecularLimit", 64, CVAR_ARCHIVE ); cvarSystem->SetCVarInteger( "image_downSizeBump", 1, CVAR_ARCHIVE ); cvarSystem->SetCVarInteger( "image_downSizeBumpLimit", 256, CVAR_ARCHIVE ); } if ( Sys_GetSystemRam() < 512 ) { cvarSystem->SetCVarBool( "image_ignoreHighQuality", true, CVAR_ARCHIVE ); cvarSystem->SetCVarInteger( "s_maxSoundsPerShader", 1, CVAR_ARCHIVE ); cvarSystem->SetCVarInteger( "image_downSize", 1, CVAR_ARCHIVE ); cvarSystem->SetCVarInteger( "image_downSizeLimit", 256, CVAR_ARCHIVE ); cvarSystem->SetCVarInteger( "image_downSizeSpecular", 1, CVAR_ARCHIVE ); cvarSystem->SetCVarInteger( "image_downSizeSpecularLimit", 64, CVAR_ARCHIVE ); cvarSystem->SetCVarBool( "com_purgeAll", true, CVAR_ARCHIVE ); cvarSystem->SetCVarBool( "r_forceLoadImages", true, CVAR_ARCHIVE ); } else { cvarSystem->SetCVarBool( "com_purgeAll", false, CVAR_ARCHIVE ); cvarSystem->SetCVarBool( "r_forceLoadImages", false, CVAR_ARCHIVE ); } bool oldCard = false; bool nv10or20 = false; renderSystem->GetCardCaps( oldCard, nv10or20 ); if ( oldCard ) { cvarSystem->SetCVarBool( "g_decals", false, CVAR_ARCHIVE ); cvarSystem->SetCVarBool( "g_projectileLights", false, CVAR_ARCHIVE ); cvarSystem->SetCVarBool( "g_doubleVision", false, CVAR_ARCHIVE ); cvarSystem->SetCVarBool( "g_muzzleFlash", false, CVAR_ARCHIVE ); } else { cvarSystem->SetCVarBool( "g_decals", true, CVAR_ARCHIVE ); cvarSystem->SetCVarBool( "g_projectileLights", true, CVAR_ARCHIVE ); cvarSystem->SetCVarBool( "g_doubleVision", true, CVAR_ARCHIVE ); cvarSystem->SetCVarBool( "g_muzzleFlash", true, CVAR_ARCHIVE ); } if ( nv10or20 ) { cvarSystem->SetCVarInteger( "image_useNormalCompression", 1, CVAR_ARCHIVE ); } #if MACOS_X // On low settings, G4 systems & 64MB FX5200/NV34 Systems should default shadows off bool oldArch; int vendorId, deviceId, cpuId; OSX_GetVideoCard( vendorId, deviceId ); OSX_GetCPUIdentification( cpuId, oldArch ); bool isFX5200 = vendorId == 0x10DE && ( deviceId & 0x0FF0 ) == 0x0320; if ( ( oldArch || ( isFX5200 && Sys_GetVideoRam() < 128 ) ) && com_machineSpec.GetInteger() == 0 ) { cvarSystem->SetCVarBool( "r_shadows", false, CVAR_ARCHIVE ); } else { cvarSystem->SetCVarBool( "r_shadows", true, CVAR_ARCHIVE ); } #endif #endif // QUAKE4 } /* ================= Com_ReloadEngine_f ================= */ void Com_ReloadEngine_f( const idCmdArgs &args ) { bool menu = false; if ( !commonLocal.IsInitialized() ) { return; } #ifdef QUAKE4 fileSystem->SetIsFileLoadingAllowed( true ); #endif if ( args.Argc() > 1 && idStr::Icmp( args.Argv( 1 ), "menu" ) == 0 ) { menu = true; } common->Printf( "============= ReloadEngine start =============\n" ); if ( !menu ) { Sys_ShowConsole( 1, false ); } commonLocal.ShutdownGame( true ); commonLocal.InitGame(); if ( !menu && !idAsyncNetwork::serverDedicated.GetBool() ) { Sys_ShowConsole( 0, false ); } common->Printf( "============= ReloadEngine end ===============\n" ); if ( !cmdSystem->PostReloadEngine() ) { if ( menu ) { session->StartMenu( ); } } #ifdef QUAKE4 fileSystem->SetIsFileLoadingAllowed( false ); #endif } /* =============== idCommonLocal::GetLanguageDict =============== */ const idLangDict *idCommonLocal::GetLanguageDict( void ) { #ifdef QUAKE4 if ( languages.Num() > 0 ) { return languages[languageDictIndex].GetDict(); } #endif return &languageDict; } #ifdef QUAKE4 /* =============== idCommonLocal::GetLocalizedString =============== */ const char *idCommonLocal::GetLocalizedString( const char *token, int langIndex ) { if ( !token || !token[0] ) { return ""; } if ( idStr::Cmpn( token, STRTABLE_ID, STRTABLE_ID_LENGTH ) != 0 ) { return token; } if ( languages.Num() <= 0 ) { return token; } if ( langIndex < 0 || langIndex >= languages.Num() ) { langIndex = languageDictIndex; } return languages[langIndex].GetString( token ); } /* =============== idCommonLocal::GetLocalizedString =============== */ const idLangKeyValue *idCommonLocal::GetLocalizedString( int index, int langIndex ) { if ( languages.Num() <= 0 ) { return NULL; } if ( langIndex < 0 || langIndex >= languages.Num() ) { langIndex = languageDictIndex; } return languages[langIndex].GetString( index ); } int idCommonLocal::GetNumLanguages( void ) const { return languages.Num(); } int idCommonLocal::GetNumLocalizedStrings( void ) const { if ( languages.Num() <= 0 ) { return 0; } return languages[0].GetNumStrings(); } const char *idCommonLocal::GetLanguage( int index ) const { if ( languages.Num() <= 0 ) { return ""; } if ( index < 0 || index >= languages.Num() ) { index = languageDictIndex; } return languages[index].GetLanguage(); } bool idCommonLocal::LanguageHasVO( int index ) const { if ( languages.Num() <= 0 ) { return false; } if ( index < 0 || index >= languages.Num() ) { index = languageDictIndex; } return languages[index].HasVO(); } bool idCommonLocal::AddLanguage( const idStr &language ) { for ( int i = 0; i < languages.Num(); i++ ) { if ( idStr::Icmp( languages[i].GetLanguage(), language.c_str() ) == 0 ) { return false; } } rvLanguage lang; lang.SetLanguage( language ); languages.Append( lang ); return true; } void idCommonLocal::SetActiveLanguage( void ) { idStr lang = cvarSystem->GetCVarString( "sys_lang" ); for ( int i = 0; i < languages.Num(); i++ ) { if ( idStr::Icmp( lang.c_str(), languages[i].GetLanguage() ) == 0 ) { languageDictIndex = i; return; } } cmdSystem->BufferCommandText( CMD_EXEC_NOW, "reset sys_lang" ); languageDictIndex = 0; } #endif /* =============== idCommonLocal::FilterLangList =============== */ void idCommonLocal::FilterLangList( idStrList* list, idStr lang ) { idStr temp; for( int i = 0; i < list->Num(); i++ ) { temp = (*list)[i]; temp = temp.Right(temp.Length()-strlen("strings/")); temp = temp.Left(lang.Length()); if(idStr::Icmp(temp, lang) != 0) { list->RemoveIndex(i); i--; } } } /* =============== idCommonLocal::InitLanguageDict =============== */ void idCommonLocal::InitLanguageDict( void ) { #ifdef QUAKE4 languageDict.Clear(); languages.Clear(); idFileList *langFiles = fileSystem->ListFilesTree( "strings", ".lang", true ); idStrList langList = langFiles->GetList(); StartupVariable( "sys_lang", false ); idStr english = "english"; AddLanguage( english ); for ( int i = 0; i < langList.Num(); i++ ) { idStr temp = langList[i]; temp.StripLeading( "strings/" ); int underscore = temp.Find( '_' ); if ( underscore > 0 ) { temp = temp.Left( underscore ); AddLanguage( temp ); } } if ( languages.Num() > 0 ) { Printf( "Found default language English with VO\n" ); languages[0].SetHasVO( true ); } for ( int i = 1; i < languages.Num(); i++ ) { idStr folder = va( "sound/vo_%s", languages[i].GetLanguage() ); idFileList *langFolders = fileSystem->ListFiles( folder, "/" ); bool hasVO = ( langFolders && langFolders->GetNumFiles() > 0 ); languages[i].SetHasVO( hasVO ); if ( hasVO ) { Printf( ".... found additional language '%s' with VO\n", languages[i].GetLanguage() ); } else { Printf( ".... found additional language '%s' without VO\n", languages[i].GetLanguage() ); } fileSystem->FreeFileList( langFolders ); } for ( int i = 0; i < languages.Num(); i++ ) { idStrList currentLangList = langList; FilterLangList( ¤tLangList, languages[i].GetLanguage() ); for ( int j = 0; j < currentLangList.Num(); j++ ) { languages[i].Load( currentLangList[j], false ); if ( i == 0 ) { languageDict.Load( currentLangList[j], false ); } } } fileSystem->FreeFileList( langFiles ); SetActiveLanguage(); Sys_InitScanTable(); #else idStr fileName; languageDict.Clear(); //D3XP: Instead of just loading a single lang file for each language //we are going to load all files that begin with the language name //similar to the way pak files work. So you can place english001.lang //to add new strings to the english language dictionary idFileList* langFiles; langFiles = fileSystem->ListFilesTree( "strings", ".lang", true ); idStrList langList = langFiles->GetList(); StartupVariable( "sys_lang", false ); // let it be set on the command line - this is needed because this init happens very early idStr langName = cvarSystem->GetCVarString( "sys_lang" ); //Loop through the list and filter idStrList currentLangList = langList; FilterLangList(¤tLangList, langName); if ( currentLangList.Num() == 0 ) { // reset cvar to default and try to load again cmdSystem->BufferCommandText( CMD_EXEC_NOW, "reset sys_lang" ); langName = cvarSystem->GetCVarString( "sys_lang" ); currentLangList = langList; FilterLangList(¤tLangList, langName); } for( int i = 0; i < currentLangList.Num(); i++ ) { //common->Printf("%s\n", currentLangList[i].c_str()); languageDict.Load( currentLangList[i], false ); } fileSystem->FreeFileList(langFiles); Sys_InitScanTable(); #endif } /* =============== idCommonLocal::LocalizeSpecificMapData =============== */ void idCommonLocal::LocalizeSpecificMapData( const char *fileName, idLangDict &langDict, const idLangDict &replaceArgs ) { idStr out, ws, work; idMapFile map; if ( map.Parse( fileName, false, false ) ) { int count = map.GetNumEntities(); for ( int i = 0; i < count; i++ ) { idMapEntity *ent = map.GetEntity( i ); if ( ent ) { for ( int j = 0; j < replaceArgs.GetNumKeyVals(); j++ ) { const idLangKeyValue *kv = replaceArgs.GetKeyVal( j ); const char *temp = ent->epairs.GetString( kv->key ); if ( temp && *temp ) { idStr val = kv->value; if ( val == temp ) { ent->epairs.Set( kv->key, langDict.AddString( temp ) ); } } } } } map.Write( fileName, ".map" ); } } /* =============== idCommonLocal::LocalizeMapData =============== */ void idCommonLocal::LocalizeMapData( const char *fileName, idLangDict &langDict ) { const char *buffer = NULL; idLexer src( LEXFL_NOFATALERRORS | LEXFL_NOSTRINGCONCAT | LEXFL_ALLOWMULTICHARLITERALS | LEXFL_ALLOWBACKSLASHSTRINGCONCAT ); common->SetRefreshOnPrint( true ); if ( fileSystem->ReadFile( fileName, (void**)&buffer ) > 0 ) { src.LoadMemory( buffer, strlen(buffer), fileName ); if ( src.IsLoaded() ) { common->Printf( "Processing %s\n", fileName ); idStr mapFileName; idToken token, token2; idLangDict replaceArgs; while ( src.ReadToken( &token ) ) { mapFileName = token; replaceArgs.Clear(); src.ExpectTokenString( "{" ); while ( src.ReadToken( &token) ) { if ( token == "}" ) { break; } if ( src.ReadToken( &token2 ) ) { if ( token2 == "}" ) { break; } replaceArgs.AddKeyVal( token, token2 ); } } common->Printf( " localizing map %s...\n", mapFileName.c_str() ); LocalizeSpecificMapData( mapFileName, langDict, replaceArgs ); } } fileSystem->FreeFile( (void*)buffer ); } common->SetRefreshOnPrint( false ); } /* =============== idCommonLocal::LocalizeGui =============== */ void idCommonLocal::LocalizeGui( const char *fileName, idLangDict &langDict ) { idStr out, ws, work; const char *buffer = NULL; out.Empty(); int k; char ch; char slash = '\\'; char tab = 't'; char nl = 'n'; idLexer src( LEXFL_NOFATALERRORS | LEXFL_NOSTRINGCONCAT | LEXFL_ALLOWMULTICHARLITERALS | LEXFL_ALLOWBACKSLASHSTRINGCONCAT ); if ( fileSystem->ReadFile( fileName, (void**)&buffer ) > 0 ) { src.LoadMemory( buffer, strlen(buffer), fileName ); if ( src.IsLoaded() ) { idFile *outFile = fileSystem->OpenFileWrite( fileName ); common->Printf( "Processing %s\n", fileName ); session->UpdateScreen(); idToken token; while( src.ReadToken( &token ) ) { src.GetLastWhiteSpace( ws ); out += ws; if ( token.type == TT_STRING ) { out += va( "\"%s\"", token.c_str() ); } else { out += token; } if ( out.Length() > 200000 ) { outFile->Write( out.c_str(), out.Length() ); out = ""; } work = token.Right( 6 ); if ( token.Icmp( "text" ) == 0 || work.Icmp( "::text" ) == 0 || token.Icmp( "choices" ) == 0 ) { if ( src.ReadToken( &token ) ) { // see if already exists, if so save that id to this position in this file // otherwise add this to the list and save the id to this position in this file src.GetLastWhiteSpace( ws ); out += ws; token = langDict.AddString( token ); out += "\""; for ( k = 0; k < token.Length(); k++ ) { ch = token[k]; if ( ch == '\t' ) { out += slash; out += tab; } else if ( ch == '\n' || ch == '\r' ) { out += slash; out += nl; } else { out += ch; } } out += "\""; } } else if ( token.Icmp( "comment" ) == 0 ) { if ( src.ReadToken( &token ) ) { // need to write these out by hand to preserve any \n's // see if already exists, if so save that id to this position in this file // otherwise add this to the list and save the id to this position in this file src.GetLastWhiteSpace( ws ); out += ws; out += "\""; for ( k = 0; k < token.Length(); k++ ) { ch = token[k]; if ( ch == '\t' ) { out += slash; out += tab; } else if ( ch == '\n' || ch == '\r' ) { out += slash; out += nl; } else { out += ch; } } out += "\""; } } } outFile->Write( out.c_str(), out.Length() ); fileSystem->CloseFile( outFile ); } fileSystem->FreeFile( (void*)buffer ); } } /* ================= ReloadLanguage_f ================= */ void Com_ReloadLanguage_f( const idCmdArgs &args ) { #ifdef QUAKE4 fileSystem->SetIsFileLoadingAllowed( true ); #endif commonLocal.InitLanguageDict(); #ifdef QUAKE4 fileSystem->SetIsFileLoadingAllowed( false ); #endif } typedef idHashTable ListHash; void LoadMapLocalizeData(ListHash& listHash) { idStr fileName = "map_localize.cfg"; const char *buffer = NULL; idLexer src( LEXFL_NOFATALERRORS | LEXFL_NOSTRINGCONCAT | LEXFL_ALLOWMULTICHARLITERALS | LEXFL_ALLOWBACKSLASHSTRINGCONCAT ); if ( fileSystem->ReadFile( fileName, (void**)&buffer ) > 0 ) { src.LoadMemory( buffer, strlen(buffer), fileName ); if ( src.IsLoaded() ) { idStr classname; idToken token; while ( src.ReadToken( &token ) ) { classname = token; src.ExpectTokenString( "{" ); idStrList list; while ( src.ReadToken( &token) ) { if ( token == "}" ) { break; } list.Append(token); } listHash.Set(classname, list); } } fileSystem->FreeFile( (void*)buffer ); } } void LoadGuiParmExcludeList(idStrList& list) { idStr fileName = "guiparm_exclude.cfg"; const char *buffer = NULL; idLexer src( LEXFL_NOFATALERRORS | LEXFL_NOSTRINGCONCAT | LEXFL_ALLOWMULTICHARLITERALS | LEXFL_ALLOWBACKSLASHSTRINGCONCAT ); if ( fileSystem->ReadFile( fileName, (void**)&buffer ) > 0 ) { src.LoadMemory( buffer, strlen(buffer), fileName ); if ( src.IsLoaded() ) { idStr classname; idToken token; while ( src.ReadToken( &token ) ) { list.Append(token); } } fileSystem->FreeFile( (void*)buffer ); } } bool TestMapVal(idStr& str) { //Already Localized? if(str.Find("#str_") != -1) { return false; } return true; } bool TestGuiParm(const char* parm, const char* value, idStrList& excludeList) { idStr testVal = value; //Already Localized? if(testVal.Find("#str_") != -1) { return false; } //Numeric if(testVal.IsNumeric()) { return false; } //Contains :: if(testVal.Find("::") != -1) { return false; } //Contains / if(testVal.Find("/") != -1) { return false; } if(excludeList.Find(testVal)) { return false; } return true; } void GetFileList(const char* dir, const char* ext, idStrList& list) { //Recurse Subdirectories idStrList dirList; Sys_ListFiles(dir, "/", dirList); for(int i = 0; i < dirList.Num(); i++) { if(dirList[i] == "." || dirList[i] == "..") { continue; } idStr fullName = va("%s/%s", dir, dirList[i].c_str()); GetFileList(fullName, ext, list); } idStrList fileList; Sys_ListFiles(dir, ext, fileList); for(int i = 0; i < fileList.Num(); i++) { idStr fullName = va("%s/%s", dir, fileList[i].c_str()); list.Append(fullName); } } int LocalizeMap(const char* mapName, idLangDict &langDict, ListHash& listHash, idStrList& excludeList, bool writeFile) { common->Printf("Localizing Map '%s'\n", mapName); int strCount = 0; idMapFile map; if ( map.Parse(mapName, false, false ) ) { int count = map.GetNumEntities(); for ( int j = 0; j < count; j++ ) { idMapEntity *ent = map.GetEntity( j ); if ( ent ) { idStr classname = ent->epairs.GetString("classname"); //Hack: for info_location bool hasLocation = false; idStrList* list; listHash.Get(classname, &list); if(list) { for(int k = 0; k < list->Num(); k++) { idStr val = ent->epairs.GetString((*list)[k], ""); if(val.Length() && classname == "info_location" && (*list)[k] == "location") { hasLocation = true; } if(val.Length() && TestMapVal(val)) { if(!hasLocation || (*list)[k] == "location") { //Localize it!!! strCount++; ent->epairs.Set( (*list)[k], langDict.AddString( val ) ); } } } } listHash.Get("all", &list); if(list) { for(int k = 0; k < list->Num(); k++) { idStr val = ent->epairs.GetString((*list)[k], ""); if(val.Length() && TestMapVal(val)) { //Localize it!!! strCount++; ent->epairs.Set( (*list)[k], langDict.AddString( val ) ); } } } //Localize the gui_parms const idKeyValue* kv = ent->epairs.MatchPrefix("gui_parm"); while( kv ) { if(TestGuiParm(kv->GetKey(), kv->GetValue(), excludeList)) { //Localize It! strCount++; ent->epairs.Set( kv->GetKey(), langDict.AddString( kv->GetValue() ) ); } kv = ent->epairs.MatchPrefix( "gui_parm", kv ); } } } if(writeFile && strCount > 0) { //Before we write the map file lets make a backup of the original idStr file = fileSystem->RelativePathToOSPath(mapName); idStr bak = file.Left(file.Length() - 4); bak.Append(".bak_loc"); fileSystem->CopyFile( file, bak ); map.Write( mapName, ".map" ); } } common->Printf("Count: %d\n", strCount); return strCount; } /* ================= LocalizeMaps_f ================= */ void Com_LocalizeMaps_f( const idCmdArgs &args ) { if ( args.Argc() < 2 ) { common->Printf( "Usage: localizeMaps \n" ); return; } int strCount = 0; bool count = false; bool dictUpdate = false; bool write = false; if ( idStr::Icmp( args.Argv(1), "count" ) == 0 ) { count = true; } else if ( idStr::Icmp( args.Argv(1), "dictupdate" ) == 0 ) { count = true; dictUpdate = true; } else if ( idStr::Icmp( args.Argv(1), "all" ) == 0 ) { count = true; dictUpdate = true; write = true; } else { common->Printf( "Invalid Command\n" ); common->Printf( "Usage: localizeMaps \n" ); return; } idLangDict strTable; idStr filename = va("strings/english%.3i.lang", com_product_lang_ext.GetInteger()); if(strTable.Load( filename ) == false) { //This is a new file so set the base index strTable.SetBaseID(com_product_lang_ext.GetInteger()*100000); } common->SetRefreshOnPrint( true ); ListHash listHash; LoadMapLocalizeData(listHash); idStrList excludeList; LoadGuiParmExcludeList(excludeList); if(args.Argc() == 3) { strCount += LocalizeMap(args.Argv(2), strTable, listHash, excludeList, write); } else { idStrList files; GetFileList("z:/d3xp/d3xp/maps/game", "*.map", files); for ( int i = 0; i < files.Num(); i++ ) { idStr file = fileSystem->OSPathToRelativePath(files[i]); strCount += LocalizeMap(file, strTable, listHash, excludeList, write); } } if(count) { common->Printf("Localize String Count: %d\n", strCount); } common->SetRefreshOnPrint( false ); if(dictUpdate) { strTable.Save( filename ); } } /* ================= LocalizeGuis_f ================= */ void Com_LocalizeGuis_f( const idCmdArgs &args ) { if ( args.Argc() != 2 ) { common->Printf( "Usage: localizeGuis \n" ); return; } idLangDict strTable; idStr filename = va("strings/english%.3i.lang", com_product_lang_ext.GetInteger()); if(strTable.Load( filename ) == false) { //This is a new file so set the base index strTable.SetBaseID(com_product_lang_ext.GetInteger()*100000); } idFileList *files; if ( idStr::Icmp( args.Argv(1), "all" ) == 0 ) { idStr game = cvarSystem->GetCVarString( "fs_game" ); if(game.Length()) { files = fileSystem->ListFilesTree( "guis", "*.gui", true, game ); } else { files = fileSystem->ListFilesTree( "guis", "*.gui", true ); } for ( int i = 0; i < files->GetNumFiles(); i++ ) { commonLocal.LocalizeGui( files->GetFile( i ), strTable ); } fileSystem->FreeFileList( files ); if(game.Length()) { files = fileSystem->ListFilesTree( "guis", "*.pd", true, game ); } else { files = fileSystem->ListFilesTree( "guis", "*.pd", true, "d3xp" ); } for ( int i = 0; i < files->GetNumFiles(); i++ ) { commonLocal.LocalizeGui( files->GetFile( i ), strTable ); } fileSystem->FreeFileList( files ); } else { commonLocal.LocalizeGui( args.Argv(1), strTable ); } strTable.Save( filename ); } void Com_LocalizeGuiParmsTest_f( const idCmdArgs &args ) { common->SetRefreshOnPrint( true ); idFile *localizeFile = fileSystem->OpenFileWrite( "gui_parm_localize.csv" ); idFile *noLocalizeFile = fileSystem->OpenFileWrite( "gui_parm_nolocalize.csv" ); idStrList excludeList; LoadGuiParmExcludeList(excludeList); idStrList files; GetFileList("z:/d3xp/d3xp/maps/game", "*.map", files); for ( int i = 0; i < files.Num(); i++ ) { common->Printf("Testing Map '%s'\n", files[i].c_str()); idMapFile map; idStr file = fileSystem->OSPathToRelativePath(files[i]); if ( map.Parse(file, false, false ) ) { int count = map.GetNumEntities(); for ( int j = 0; j < count; j++ ) { idMapEntity *ent = map.GetEntity( j ); if ( ent ) { const idKeyValue* kv = ent->epairs.MatchPrefix("gui_parm"); while( kv ) { if(TestGuiParm(kv->GetKey(), kv->GetValue(), excludeList)) { idStr out = va("%s,%s,%s\r\n", kv->GetValue().c_str(), kv->GetKey().c_str(), file.c_str()); localizeFile->Write( out.c_str(), out.Length() ); } else { idStr out = va("%s,%s,%s\r\n", kv->GetValue().c_str(), kv->GetKey().c_str(), file.c_str()); noLocalizeFile->Write( out.c_str(), out.Length() ); } kv = ent->epairs.MatchPrefix( "gui_parm", kv ); } } } } } fileSystem->CloseFile( localizeFile ); fileSystem->CloseFile( noLocalizeFile ); common->SetRefreshOnPrint( false ); } void Com_LocalizeMapsTest_f( const idCmdArgs &args ) { ListHash listHash; LoadMapLocalizeData(listHash); common->SetRefreshOnPrint( true ); idFile *localizeFile = fileSystem->OpenFileWrite( "map_localize.csv" ); idStrList files; GetFileList("z:/d3xp/d3xp/maps/game", "*.map", files); for ( int i = 0; i < files.Num(); i++ ) { common->Printf("Testing Map '%s'\n", files[i].c_str()); idMapFile map; idStr file = fileSystem->OSPathToRelativePath(files[i]); if ( map.Parse(file, false, false ) ) { int count = map.GetNumEntities(); for ( int j = 0; j < count; j++ ) { idMapEntity *ent = map.GetEntity( j ); if ( ent ) { //Temp code to get a list of all entity key value pairs /*idStr classname = ent->epairs.GetString("classname"); if(classname == "worldspawn" || classname == "func_static" || classname == "light" || classname == "speaker" || classname.Left(8) == "trigger_") { continue; } for( int i = 0; i < ent->epairs.GetNumKeyVals(); i++) { const idKeyValue* kv = ent->epairs.GetKeyVal(i); idStr out = va("%s,%s,%s,%s\r\n", classname.c_str(), kv->GetKey().c_str(), kv->GetValue().c_str(), file.c_str()); localizeFile->Write( out.c_str(), out.Length() ); }*/ idStr classname = ent->epairs.GetString("classname"); //Hack: for info_location bool hasLocation = false; idStrList* list; listHash.Get(classname, &list); if(list) { for(int k = 0; k < list->Num(); k++) { idStr val = ent->epairs.GetString((*list)[k], ""); if(classname == "info_location" && (*list)[k] == "location") { hasLocation = true; } if(val.Length() && TestMapVal(val)) { if(!hasLocation || (*list)[k] == "location") { idStr out = va("%s,%s,%s\r\n", val.c_str(), (*list)[k].c_str(), file.c_str()); localizeFile->Write( out.c_str(), out.Length() ); } } } } listHash.Get("all", &list); if(list) { for(int k = 0; k < list->Num(); k++) { idStr val = ent->epairs.GetString((*list)[k], ""); if(val.Length() && TestMapVal(val)) { idStr out = va("%s,%s,%s\r\n", val.c_str(), (*list)[k].c_str(), file.c_str()); localizeFile->Write( out.c_str(), out.Length() ); } } } } } } } fileSystem->CloseFile( localizeFile ); common->SetRefreshOnPrint( false ); } /* ================= Com_StartBuild_f ================= */ void Com_StartBuild_f( const idCmdArgs &args ) { globalImages->StartBuild(); } /* ================= Com_FinishBuild_f ================= */ void Com_FinishBuild_f( const idCmdArgs &args ) { if ( game ) { game->CacheDictionaryMedia( NULL ); } globalImages->FinishBuild( ( args.Argc() > 1 ) ); } /* ============== Com_Help_f ============== */ void Com_Help_f( const idCmdArgs &args ) { common->Printf( "\nCommonly used commands:\n" ); common->Printf( " spawnServer - start the server.\n" ); common->Printf( " disconnect - shut down the server.\n" ); common->Printf( " listCmds - list all console commands.\n" ); common->Printf( " listCVars - list all console variables.\n" ); common->Printf( " kick - kick a client by number.\n" ); common->Printf( " gameKick - kick a client by name.\n" ); common->Printf( " serverNextMap - immediately load next map.\n" ); common->Printf( " serverMapRestart - restart the current map.\n" ); common->Printf( " serverForceReady - force all players to ready status.\n" ); common->Printf( "\nCommonly used variables:\n" ); common->Printf( " si_name - server name (change requires a restart to see)\n" ); common->Printf( " si_gametype - type of game.\n" ); common->Printf( " si_fragLimit - max kills to win (or lives in Last Man Standing).\n" ); common->Printf( " si_timeLimit - maximum time a game will last.\n" ); common->Printf( " si_warmup - do pre-game warmup.\n" ); common->Printf( " si_pure - pure server.\n" ); common->Printf( " g_mapCycle - name of .scriptcfg file for cycling maps.\n" ); common->Printf( "See mapcycle.scriptcfg for an example of a mapcyle script.\n\n" ); } /* ================= idCommonLocal::InitCommands ================= */ void idCommonLocal::InitCommands( void ) { cmdSystem->AddCommand( "error", Com_Error_f, CMD_FL_SYSTEM|CMD_FL_CHEAT, "causes an error" ); cmdSystem->AddCommand( "crash", Com_Crash_f, CMD_FL_SYSTEM|CMD_FL_CHEAT, "causes a crash" ); cmdSystem->AddCommand( "freeze", Com_Freeze_f, CMD_FL_SYSTEM|CMD_FL_CHEAT, "freezes the game for a number of seconds" ); cmdSystem->AddCommand( "quit", Com_Quit_f, CMD_FL_SYSTEM, "quits the game" ); cmdSystem->AddCommand( "exit", Com_Quit_f, CMD_FL_SYSTEM, "exits the game" ); cmdSystem->AddCommand( "writeConfig", Com_WriteConfig_f, CMD_FL_SYSTEM, "writes a config file" ); cmdSystem->AddCommand( "reloadEngine", Com_ReloadEngine_f, CMD_FL_SYSTEM, "reloads the engine down to including the file system" ); cmdSystem->AddCommand( "setMachineSpec", Com_SetMachineSpec_f, CMD_FL_SYSTEM, "detects system capabilities and sets com_machineSpec to appropriate value" ); cmdSystem->AddCommand( "execMachineSpec", Com_ExecMachineSpec_f, CMD_FL_SYSTEM, "execs the appropriate config files and sets cvars based on com_machineSpec" ); #ifdef QUAKE4 cmdSystem->AddCommand( "execMPMachineSpec", Com_ExecMPMachineSpec_f, CMD_FL_SYSTEM, "sets cvars for multiplayer" ); cmdSystem->AddCommand( "showMemory", Com_ShowMemory_f, CMD_FL_TOOL, "gives a reasonably detailed account of memory usage" ); #endif #if !defined( ID_DEMO_BUILD ) && !defined( ID_DEDICATED ) // compilers cmdSystem->AddCommand( "dmap", Dmap_f, CMD_FL_TOOL, "compiles a map", idCmdSystem::ArgCompletion_MapName ); cmdSystem->AddCommand( "renderbump", RenderBump_f, CMD_FL_TOOL, "renders a bump map", idCmdSystem::ArgCompletion_ModelName ); cmdSystem->AddCommand( "renderbumpFlat", RenderBumpFlat_f, CMD_FL_TOOL, "renders a flat bump map", idCmdSystem::ArgCompletion_ModelName ); cmdSystem->AddCommand( "runAAS", RunAAS_f, CMD_FL_TOOL, "compiles an AAS file for a map", idCmdSystem::ArgCompletion_MapName ); cmdSystem->AddCommand( "runAASDir", RunAASDir_f, CMD_FL_TOOL, "compiles AAS files for all maps in a folder", idCmdSystem::ArgCompletion_MapName ); cmdSystem->AddCommand( "runReach", RunReach_f, CMD_FL_TOOL, "calculates reachability for an AAS file", idCmdSystem::ArgCompletion_MapName ); cmdSystem->AddCommand( "roq", RoQFileEncode_f, CMD_FL_TOOL, "encodes a roq file" ); #endif #ifdef ID_ALLOW_TOOLS cmdSystem->AddCommand("nnbuildmat", nnbuildmat_f, CMD_FL_TOOL, "confidential"); // editors cmdSystem->AddCommand( "editor", Com_Editor_f, CMD_FL_TOOL, "launches the level editor Radiant" ); cmdSystem->AddCommand( "editLights", Com_EditLights_f, CMD_FL_TOOL, "launches the in-game Light Editor" ); cmdSystem->AddCommand( "editSounds", Com_EditSounds_f, CMD_FL_TOOL, "launches the in-game Sound Editor" ); cmdSystem->AddCommand( "editDecls", Com_EditDecls_f, CMD_FL_TOOL, "launches the in-game Declaration Editor" ); cmdSystem->AddCommand( "editAFs", Com_EditAFs_f, CMD_FL_TOOL, "launches the in-game Articulated Figure Editor" ); cmdSystem->AddCommand( "editParticles", Com_EditParticles_f, CMD_FL_TOOL, "launches the in-game Particle Editor" ); cmdSystem->AddCommand( "editScripts", Com_EditScripts_f, CMD_FL_TOOL, "launches the in-game Script Editor" ); cmdSystem->AddCommand( "editGUIs", Com_EditGUIs_f, CMD_FL_TOOL, "launches the GUI Editor" ); cmdSystem->AddCommand( "editPDAs", Com_EditPDAs_f, CMD_FL_TOOL, "launches the in-game PDA Editor" ); cmdSystem->AddCommand( "debugger", Com_ScriptDebugger_f, CMD_FL_TOOL, "launches the Script Debugger" ); //BSM Nerve: Add support for the material editor cmdSystem->AddCommand( "materialEditor", Com_MaterialEditor_f, CMD_FL_TOOL, "launches the Material Editor" ); #endif cmdSystem->AddCommand( "printMemInfo", PrintMemInfo_f, CMD_FL_SYSTEM, "prints memory debugging data" ); #ifdef QUAKE4 cmdSystem->AddCommand( "writeAssetLog", Com_WriteAssetLog_f, CMD_FL_SYSTEM, "generates log file of all the assets loaded" ); cmdSystem->AddCommand( "clearAssetLog", Com_ClearAssetLog_f, CMD_FL_SYSTEM, "clears log of all the assets loaded" ); #endif // idLib commands cmdSystem->AddCommand( "memoryDump", Mem_Dump_f, CMD_FL_SYSTEM|CMD_FL_CHEAT, "creates a memory dump" ); cmdSystem->AddCommand( "memoryDumpCompressed", Mem_DumpCompressed_f, CMD_FL_SYSTEM|CMD_FL_CHEAT, "creates a compressed memory dump" ); cmdSystem->AddCommand( "showStringMemory", idStr::ShowMemoryUsage_f, CMD_FL_SYSTEM, "shows memory used by strings" ); cmdSystem->AddCommand( "showDictMemory", idDict::ShowMemoryUsage_f, CMD_FL_SYSTEM, "shows memory used by dictionaries" ); cmdSystem->AddCommand( "listDictKeys", idDict::ListKeys_f, CMD_FL_SYSTEM|CMD_FL_CHEAT, "lists all keys used by dictionaries" ); cmdSystem->AddCommand( "listDictValues", idDict::ListValues_f, CMD_FL_SYSTEM|CMD_FL_CHEAT, "lists all values used by dictionaries" ); cmdSystem->AddCommand( "testSIMD", idSIMD::Test_f, CMD_FL_SYSTEM|CMD_FL_CHEAT, "test SIMD code" ); // localization cmdSystem->AddCommand( "localizeGuis", Com_LocalizeGuis_f, CMD_FL_SYSTEM|CMD_FL_CHEAT, "localize guis" ); cmdSystem->AddCommand( "localizeMaps", Com_LocalizeMaps_f, CMD_FL_SYSTEM|CMD_FL_CHEAT, "localize maps" ); cmdSystem->AddCommand( "reloadLanguage", Com_ReloadLanguage_f, CMD_FL_SYSTEM, "reload language dict" ); //D3XP Localization cmdSystem->AddCommand( "localizeGuiParmsTest", Com_LocalizeGuiParmsTest_f, CMD_FL_SYSTEM, "Create test files that show gui parms localized and ignored." ); cmdSystem->AddCommand( "localizeMapsTest", Com_LocalizeMapsTest_f, CMD_FL_SYSTEM, "Create test files that shows which strings will be localized." ); // build helpers cmdSystem->AddCommand( "startBuild", Com_StartBuild_f, CMD_FL_SYSTEM|CMD_FL_CHEAT, "prepares to make a build" ); cmdSystem->AddCommand( "finishBuild", Com_FinishBuild_f, CMD_FL_SYSTEM|CMD_FL_CHEAT, "finishes the build process" ); #ifdef QUAKE4 cmdSystem->AddCommand( "IncrementCVar", IncrementCVar_f, CMD_FL_SYSTEM, "IncrementCVar " ); cmdSystem->AddCommand( "DecrementCVar", DecrementCVar_f, CMD_FL_SYSTEM, "DecrementCVar " ); cmdSystem->AddCommand( "WriteConfiguration", Com_WriteConfiguration_f, CMD_FL_SYSTEM, "WriteConfiguration" ); #endif #ifdef ID_DEDICATED cmdSystem->AddCommand( "help", Com_Help_f, CMD_FL_SYSTEM, "shows help" ); #endif } /* ================= idCommonLocal::InitRenderSystem ================= */ void idCommonLocal::InitRenderSystem( void ) { if ( com_skipRenderer.GetBool() ) { return; } renderSystem->InitOpenGL(); #ifdef QUAKE4 PrintLoadingMessage( GetLocalizedString( "#str_104343" ) ); #else PrintLoadingMessage( common->GetLanguageDict()->GetString( "#str_04343" ) ); #endif } /* ================= idCommonLocal::PrintLoadingMessage ================= */ void idCommonLocal::PrintLoadingMessage( const char *msg ) { if ( !( msg && *msg ) ) { return; } renderSystem->BeginFrame( renderSystem->GetScreenWidth(), renderSystem->GetScreenHeight() ); #ifdef QUAKE4 renderSystem->DrawStretchPic( 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, 0, 0, 1, 1, declManager->FindMaterial( "gfx/splashScreen" ) ); int len = strlen( msg ); renderSystem->DrawSmallStringExt( ( SCREEN_WIDTH - len * SMALLCHAR_WIDTH ) / 2, SCREEN_HEIGHT - 70, msg, idVec4( 0.0f, 0.81f, 0.94f, 1.0f ), true, declManager->FindMaterial( "gfx/2d/bigchars" ) ); #else renderSystem->DrawStretchPic( 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, 0, 0, 1, 1, declManager->FindMaterial( "splashScreen" ) ); int len = strlen( msg ); // renderSystem->DrawSmallStringExt( ( SCREEN_WIDTH - len * SMALLCHAR_WIDTH ) / 2, SCREEN_HEIGHT - 70, msg, idVec4( 0.0f, 0.81f, 0.94f, 1.0f ), true, declManager->FindMaterial( "textures/bigchars" ) ); #endif renderSystem->EndFrame( NULL, NULL ); } /* ================= idCommonLocal::InitSIMD ================= */ void idCommonLocal::InitSIMD( void ) { #ifdef QUAKE4 idSIMD::InitProcessor( "engine", com_forceGenericSIMD.GetBool() ); #else idSIMD::InitProcessor( "doom", com_forceGenericSIMD.GetBool() ); #endif com_forceGenericSIMD.ClearModified(); } /* ================= idCommonLocal::Frame ================= */ void idCommonLocal::Frame(void) { if (com_editorActive) { gameFrame++; return; } try { // pump all the events Sys_GenerateEvents(); // write config file if anything changed WriteConfiguration(); // change SIMD implementation if required if (com_forceGenericSIMD.IsModified()) { InitSIMD(); } eventLoop->RunEventLoop(); if (Sys_IsWindowVisible()) { //-------------------------------------------- // Determine how many game tics we are going to run, // now that the previous frame is completely finished. // // It is important that any waiting on the GPU be done // before this, or there will be a bad stuttering when // dropping frames for performance management. //-------------------------------------------- // input: // thisFrameTime // com_noSleep // com_engineHz // com_fixedTic // com_deltaTimeClamp // IsMultiplayer // // in/out state: // gameFrame // gameTimeResidual // lastFrameTime // syncNextFrame // // Output: // numGameFrames // How many game frames to run int numGameFrames = 0; for (;;) { const int thisFrameTime = Sys_Milliseconds(); static int lastFrameTime = thisFrameTime; // initialized only the first time const int deltaMilliseconds = thisFrameTime - lastFrameTime; lastFrameTime = thisFrameTime; // if there was a large gap in time since the last frame, or the frame // rate is very very low, limit the number of frames we will run const int clampedDeltaMilliseconds = min(deltaMilliseconds, com_deltaTimeClamp.GetInteger()); gameTimeResidual += clampedDeltaMilliseconds * com_timescale.GetFloat(); // don't run any frames when paused //if (pauseGame) { // gameFrame++; // gameTimeResidual = 0; // break; //} // debug cvar to force multiple game tics //if (com_fixedTic.GetInteger() > 0) { // numGameFrames = com_fixedTic.GetInteger(); // gameFrame += numGameFrames; // gameTimeResidual = 0; // break; //} //if (syncNextGameFrame) { // // don't sleep at all // syncNextGameFrame = false; // gameFrame++; // numGameFrames++; // gameTimeResidual = 0; // break; //} for (;; ) { // How much time to wait before running the next frame, // based on com_engineHz const int frameDelay = FRAME_TO_MSEC(gameFrame + 1) - FRAME_TO_MSEC(gameFrame); if (gameTimeResidual < frameDelay) { break; } gameTimeResidual -= frameDelay; gameFrame++; numGameFrames++; com_ticNumber++; } sessLocal.latchedTicNumber = com_ticNumber; if (numGameFrames > 0) { // ready to actually run them break; } // if we are vsyncing, we always want to run at least one game // frame and never sleep, which might happen due to scheduling issues // if we were just looking at real time. //if (com_noSleep.GetBool()) { // numGameFrames = 1; // gameFrame += numGameFrames; // gameTimeResidual = 0; // break; //} // not enough time has passed to run a frame, as might happen if // we don't have vsync on, or the monitor is running at 120hz while // com_engineHz is 60, so sleep a bit and check again Sys_Sleep(0); } } else { gameFrame++; } com_frameTime = Sys_Milliseconds(); idAsyncNetwork::RunFrame(); if (idAsyncNetwork::IsActive()) { if (idAsyncNetwork::serverDedicated.GetInteger() != 1) { session->GuiFrameEvents(); session->UpdateScreen(false); } } else { session->Frame(); // normal, in-sequence screen update session->UpdateScreen(false); } // report timing information if (com_speeds.GetBool()) { static int lastTime; int nowTime = Sys_Milliseconds(); int com_frameMsec = nowTime - lastTime; lastTime = nowTime; Printf("frame:%i all:%3i gfr:%3i rf:%3i bk:%3i\n", com_frameNumber, com_frameMsec, time_gameFrame, time_frontend, time_backend); time_gameFrame = 0; time_gameDraw = 0; } com_frameNumber++; // set idLib frame number for frame based memory dumps idLib::frameNumber = com_frameNumber; // the FPU stack better be empty at this point or some bad code or compiler bug left values on the stack if (!Sys_FPU_StackIsEmpty()) { Printf(Sys_FPU_GetState()); FatalError("idCommon::Frame: the FPU stack is not empty at the end of the frame\n"); } } catch (idException&) { return; // an ERP_DROP was thrown } } /* ================= idCommonLocal::GUIFrame ================= */ void idCommonLocal::GUIFrame( bool execCmd, bool network ) { Sys_GenerateEvents(); eventLoop->RunEventLoop( execCmd ); // and execute any commands com_frameTime = com_ticNumber * USERCMD_MSEC; if ( network ) { idAsyncNetwork::RunFrame(); } session->Frame(); session->UpdateScreen( false ); } /* ================= idCommonLocal::LoadGameDLL ================= */ void idCommonLocal::LoadGameDLL( void ) { #ifdef __DOOM_DLL__ char dllPath[ MAX_OSPATH ]; gameImport_t gameImport; gameExport_t gameExport; GetGameAPI_t GetGameAPI; #ifdef PREY fileSystem->FindDLL( "preygame", dllPath, true); #else fileSystem->FindDLL( "game", dllPath, true ); #endif if ( !dllPath[ 0 ] ) { common->FatalError( "couldn't find game dynamic library" ); return; } common->DPrintf( "Loading game DLL: '%s'\n", dllPath ); gameDLL = sys->DLL_Load( dllPath ); if ( !gameDLL ) { common->FatalError( "couldn't load game dynamic library" ); return; } GetGameAPI = (GetGameAPI_t) Sys_DLL_GetProcAddress( gameDLL, "GetGameAPI" ); if ( !GetGameAPI ) { Sys_DLL_Unload( gameDLL ); gameDLL = NULL; common->FatalError( "couldn't find game DLL API" ); return; } gameImport.version = GAME_API_VERSION; gameImport.sys = ::sys; gameImport.common = ::common; gameImport.cmdSystem = ::cmdSystem; gameImport.cvarSystem = ::cvarSystem; gameImport.fileSystem = ::fileSystem; gameImport.networkSystem = ::networkSystem; gameImport.renderSystem = ::renderSystem; gameImport.soundSystem = ::soundSystem; gameImport.renderModelManager = ::renderModelManager; gameImport.uiManager = ::uiManager; gameImport.declManager = ::declManager; gameImport.AASFileManager = ::AASFileManager; gameImport.collisionModelManager = ::collisionModelManager; #ifdef QUAKE4 gameImport.session = ::session; #endif gameExport = *GetGameAPI( &gameImport ); if ( gameExport.version != GAME_API_VERSION ) { Sys_DLL_Unload( gameDLL ); gameDLL = NULL; common->FatalError( "wrong game DLL API version" ); return; } game = gameExport.game; gameEdit = gameExport.gameEdit; #endif // initialize the game object #ifdef QUAKE4 if ( game != NULL ) { game->Init(); } #else if ( game != NULL ) { game->Init(); } #endif } /* ================= idCommonLocal::UnloadGameDLL ================= */ void idCommonLocal::UnloadGameDLL( void ) { // shut down the game object if ( game != NULL ) { game->Shutdown(); } #ifdef __DOOM_DLL__ if ( gameDLL ) { Sys_DLL_Unload( gameDLL ); gameDLL = NULL; } game = NULL; gameEdit = NULL; #endif } /* ================= idCommonLocal::IsInitialized ================= */ bool idCommonLocal::IsInitialized( void ) const { return com_fullyInitialized; } /* ================= idCommonLocal::SetMachineSpec ================= */ void idCommonLocal::SetMachineSpec( void ) { #ifdef QUAKE4 cpuid_t cpu = Sys_GetProcessorId(); double ghz = Sys_ClockTicksPerSecond() * 0.000000001f; int vidRam = Sys_GetVideoRam(); int sysRam = Sys_GetSystemRam(); bool oldCard = false; bool nv10or20 = false; renderSystem->GetCardCaps( oldCard, nv10or20 ); Printf( "Detected\n \t%.2f GHz CPU\n\t%i MB of System memory\n\t%i MB of Video memory on %s\n\n", ghz, sysRam, vidRam, ( oldCard ) ? "a less than optimal video architecture" : "an optimal video architecture" ); if ( cpu & CPUID_AMD ) { ghz *= 1.6f; } else if ( cpu & CPUID_HTT ) { ghz *= 1.15f; } if ( !com_skipUltraQuality.GetBool() && ghz >= 2.89f && vidRam >= 300 && sysRam >= 1000 && !oldCard ) { Printf( "This system qualifies for Ultra quality!\n" ); com_machineSpec.SetInteger( 3 ); } else if ( ghz >= 2.89f && vidRam >= 160 && sysRam >= 1000 && !oldCard ) { Printf( "This system qualifies for High quality!\n" ); com_machineSpec.SetInteger( 2 ); } else if ( ghz >= 2.29f && vidRam >= 160 && sysRam >= 750 && !oldCard ) { Printf( "This system qualifies for Medium quality.\n" ); com_machineSpec.SetInteger( 1 ); } else { Printf( "This system qualifies for Low quality.\n" ); com_machineSpec.SetInteger( 0 ); } com_videoRam.SetInteger( vidRam ); return; #else cpuid_t cpu = Sys_GetProcessorId(); double ghz = Sys_ClockTicksPerSecond() * 0.000000001f; int vidRam = Sys_GetVideoRam(); int sysRam = Sys_GetSystemRam(); bool oldCard = false; bool nv10or20 = false; renderSystem->GetCardCaps( oldCard, nv10or20 ); Printf( "Detected\n \t%.2f GHz CPU\n\t%i MB of System memory\n\t%i MB of Video memory on %s\n\n", ghz, sysRam, vidRam, ( oldCard ) ? "a less than optimal video architecture" : "an optimal video architecture" ); if ( ghz >= 2.75f && vidRam >= 512 && sysRam >= 1024 && !oldCard ) { Printf( "This system qualifies for Ultra quality!\n" ); com_machineSpec.SetInteger( 3 ); } else if ( ghz >= ( ( cpu & CPUID_AMD ) ? 1.9f : 2.19f ) && vidRam >= 256 && sysRam >= 512 && !oldCard ) { Printf( "This system qualifies for High quality!\n" ); com_machineSpec.SetInteger( 2 ); } else if ( ghz >= ( ( cpu & CPUID_AMD ) ? 1.1f : 1.25f ) && vidRam >= 128 && sysRam >= 384 ) { Printf( "This system qualifies for Medium quality.\n" ); com_machineSpec.SetInteger( 1 ); } else { Printf( "This system qualifies for Low quality.\n" ); com_machineSpec.SetInteger( 0 ); } com_videoRam.SetInteger( vidRam ); #endif } /* ================= idCommonLocal::Init ================= */ void idCommonLocal::Init( int argc, const char **argv, const char *cmdline ) { try { // set interface pointers used by idLib idLib::sys = sys; idLib::common = common; idLib::cvarSystem = cvarSystem; idLib::fileSystem = fileSystem; #ifdef QUAKE4 com_debugHudActive = false; #endif // initialize idLib idLib::Init(); // clear warning buffer #ifdef QUAKE4 ClearWarnings( "Quake4 initialization" ); #else ClearWarnings( GAME_NAME " initialization" ); #endif // parse command line options idCmdArgs args; if ( cmdline ) { // tokenize if the OS doesn't do it for us args.TokenizeString( cmdline, true ); argv = args.GetArgs( &argc ); } ParseCommandLine( argc, argv ); // init console command system cmdSystem->Init(); // init CVar system cvarSystem->Init(); // start file logging right away, before early console or whatever StartupVariable( "win_outputDebugString", false ); // register all static CVars idCVar::RegisterStaticVars(); // print engine version Printf( "%s\n", version.string ); // initialize key input/binding, done early so bind command exists idKeyInput::Init(); // init the console so we can take prints console->Init(); // get architecture info Sys_Init(); // initialize networking Sys_InitNetworking(); // override cvars from command line StartupVariable( NULL, false ); #ifdef QUAKE4 if ( cvarSystem->GetCVarInteger( "net_serverDedicated" ) ) { cvarSystem->SetCVarInteger( "win_viewlog", 1 ); } Sys_ShowConsole( cvarSystem->GetCVarInteger( "win_viewlog" ), true ); if ( argc > 0 && argv && argv[0] && !idStr::Icmp( argv[0], "bundler" ) ) { cvarSystem->SetCVarBool( "com_makingBuild", true ); cvarSystem->SetCVarBool( "com_Bundler", true ); } #endif if ( !idAsyncNetwork::serverDedicated.GetInteger() && Sys_AlreadyRunning() ) { Sys_Quit(); } // initialize processor specific SIMD implementation InitSIMD(); // init commands InitCommands(); #ifdef ID_WRITE_VERSION config_compressor = idCompressor::AllocArithmetic(); #endif // game specific initialization InitGame(); // don't add startup commands if no CD key is present #if ID_ENFORCE_KEY if ( !session->CDKeysAreValid( false ) || !AddStartupCommands() ) { #else if ( !AddStartupCommands() ) { #endif // if the user didn't give any commands, run default action #ifdef QUAKE4 session->StartMenu( "playIntro" ); #else session->StartMenu( true ); #endif } #ifdef QUAKE4 Printf( "------ Common Initialization Complete -------\n" ); #else Printf( "--- Common Initialization Complete ---\n" ); #endif // print all warnings queued during initialization PrintWarnings(); #ifdef ID_DEDICATED Printf( "\nType 'help' for dedicated server info.\n\n" ); #endif // remove any prints from the notify lines console->ClearNotifyLines(); ClearCommandLine(); com_fullyInitialized = true; } catch( idException & ) { Sys_Error( "Error during initialization" ); } } /* ================= idCommonLocal::Shutdown ================= */ void idCommonLocal::Shutdown( void ) { if ( com_shuttingDown ) { return; } com_shuttingDown = true; #ifdef QUAKE4 ApplyVideoSettings(); #endif idAsyncNetwork::server.Kill(); idAsyncNetwork::client.Shutdown(); // game specific shut down ShutdownGame( false ); // shut down non-portable system services Sys_Shutdown(); // shut down the console console->Shutdown(); // shut down the key system idKeyInput::Shutdown(); // shut down the cvar system cvarSystem->Shutdown(); // shut down the console command system cmdSystem->Shutdown(); #ifdef ID_WRITE_VERSION delete config_compressor; config_compressor = NULL; #endif // free any buffered warning messages #ifdef QUAKE4 ClearWarnings( "Quake4 shutdown" ); #else ClearWarnings( GAME_NAME " shutdown" ); #endif warningCaption.Clear(); errorList.Clear(); // free language dictionary languageDict.Clear(); #ifdef QUAKE4 languages.Clear(); #endif // enable leak test #ifdef QUAKE4 Mem_EnableLeakTest( "engine" ); #else Mem_EnableLeakTest( "doom" ); #endif // shutdown idLib idLib::ShutDown(); } #ifdef QUAKE4 /* ================= idCommonLocal::ApplyVideoSettings ================= */ void idCommonLocal::ApplyVideoSettings( void ) { if ( desiredMachineSpec != -1 ) { idCmdArgs args; int desiredRMode = cvarSystem->GetCVarInteger( "r_mode" ); Com_ExecMachineSpec_f( args ); cvarSystem->SetCVarInteger( "r_mode", desiredRMode ); WriteConfigToFile( "Quake4Config.cfg" ); } } #endif /* ================= idCommonLocal::InitGame ================= */ void idCommonLocal::InitGame( void ) { // initialize the file system fileSystem->Init(); // initialize the declaration manager declManager->Init(); // force r_fullscreen 0 if running a tool CheckToolMode(); idFile *file = fileSystem->OpenExplicitFileRead( fileSystem->RelativePathToOSPath( CONFIG_SPEC, "fs_savepath" ) ); bool sysDetect = ( file == NULL ); if ( file ) { fileSystem->CloseFile( file ); } else { file = fileSystem->OpenFileWrite( CONFIG_SPEC ); fileSystem->CloseFile( file ); } idCmdArgs args; if ( sysDetect ) { SetMachineSpec(); Com_ExecMachineSpec_f( args ); #ifdef QUAKE4 cvarSystem->SetCVarInteger( "s_numberOfSpeakers", 6 ); #endif } // initialize the renderSystem data structures, but don't start OpenGL yet renderSystem->Init(); // initialize string database right off so we can use it for loading messages InitLanguageDict(); #ifdef QUAKE4 PrintLoadingMessage( GetLocalizedString( "#str_104344" ) ); #else PrintLoadingMessage( common->GetLanguageDict()->GetString( "#str_04344" ) ); #endif // load the font, etc console->LoadGraphics(); // init journalling, etc eventLoop->Init(); #ifdef QUAKE4 PrintLoadingMessage( GetLocalizedString( "#str_104345" ) ); #else PrintLoadingMessage( common->GetLanguageDict()->GetString( "#str_04345" ) ); #endif // exec the startup scripts #ifdef QUAKE4 cmdSystem->BufferCommandText( CMD_EXEC_APPEND, "exec default.cfg\n" ); cmdSystem->BufferCommandText( CMD_EXEC_APPEND, "exec editor.cfg\n" ); #else cmdSystem->BufferCommandText( CMD_EXEC_APPEND, "exec editor.cfg\n" ); cmdSystem->BufferCommandText( CMD_EXEC_APPEND, "exec default.cfg\n" ); #endif // skip the config file if "safe" is on the command line if ( !SafeMode() ) { #ifdef QUAKE4 cmdSystem->BufferCommandText( CMD_EXEC_APPEND, "exec Quake4Config.cfg\n" ); #else cmdSystem->BufferCommandText( CMD_EXEC_APPEND, "exec " CONFIG_FILE "\n" ); #endif } cmdSystem->BufferCommandText( CMD_EXEC_APPEND, "exec autoexec.cfg\n" ); #ifdef QUAKE4 if ( com_Bundler.GetBool() ) { cmdSystem->BufferCommandText( CMD_EXEC_APPEND, "exec bundlesettings.cfg\n" ); } #endif #ifdef QUAKE4 // Quake 4 swaps active dictionaries after config execution rather than reloading all files here. #else // reload the language dictionary now that we've loaded config files cmdSystem->BufferCommandText( CMD_EXEC_APPEND, "reloadLanguage\n" ); #endif // run cfg execution cmdSystem->ExecuteCommandBuffer(); #ifdef QUAKE4 SetActiveLanguage(); #endif // re-override anything from the config files with command line args StartupVariable( NULL, false ); // if any archived cvars are modified after this, we will trigger a writing of the config file cvarSystem->ClearModifiedFlags( CVAR_ARCHIVE ); // cvars are initialized, but not the rendering system. Allow preference startup dialog Sys_DoPreferences(); // init the user command input code usercmdGen->Init(); #ifdef QUAKE4 PrintLoadingMessage( GetLocalizedString( "#str_104346" ) ); #else PrintLoadingMessage( common->GetLanguageDict()->GetString( "#str_04346" ) ); #endif // start the sound system, but don't do any hardware operations yet soundSystem->Init(); #ifdef QUAKE4 PrintLoadingMessage( GetLocalizedString( "#str_104347" ) ); #else PrintLoadingMessage( common->GetLanguageDict()->GetString( "#str_04347" ) ); #endif // init async network idAsyncNetwork::Init(); #ifdef ID_DEDICATED idAsyncNetwork::server.InitPort(); cvarSystem->SetCVarBool( "s_noSound", true ); #else if ( idAsyncNetwork::serverDedicated.GetInteger() == 1 ) { idAsyncNetwork::server.InitPort(); cvarSystem->SetCVarBool( "s_noSound", true ); } else { // init OpenGL, which will open a window and connect sound and input hardware #ifdef QUAKE4 PrintLoadingMessage( GetLocalizedString( "#str_104348" ) ); #else PrintLoadingMessage( common->GetLanguageDict()->GetString( "#str_04348" ) ); #endif InitRenderSystem(); } #endif #ifdef QUAKE4 PrintLoadingMessage( GetLocalizedString( "#str_104349" ) ); #else PrintLoadingMessage( common->GetLanguageDict()->GetString( "#str_04349" ) ); #endif // initialize the user interfaces uiManager->Init(); // startup the script debugger // DebuggerServerInit(); #ifdef QUAKE4 PrintLoadingMessage( GetLocalizedString( "#str_104350" ) ); #else PrintLoadingMessage( common->GetLanguageDict()->GetString( "#str_04350" ) ); #endif // load the game dll LoadGameDLL(); #ifdef QUAKE4 PrintLoadingMessage( GetLocalizedString( "#str_104351" ) ); #else PrintLoadingMessage( common->GetLanguageDict()->GetString( "#str_04351" ) ); #endif // init the session session->Init(); // have to do this twice.. first one sets the correct r_mode for the renderer init // this time around the backend is all setup correct.. a bit fugly but do not want // to mess with all the gl init at this point.. an old vid card will never qualify for if ( sysDetect ) { SetMachineSpec(); Com_ExecMachineSpec_f( args ); cvarSystem->SetCVarInteger( "s_numberOfSpeakers", 6 ); cmdSystem->BufferCommandText( CMD_EXEC_NOW, "s_restart\n" ); cmdSystem->ExecuteCommandBuffer(); } } /* ================= idCommonLocal::ShutdownGame ================= */ void idCommonLocal::ShutdownGame( bool reloading ) { // kill sound first idSoundWorld *sw = soundSystem->GetPlayingSoundWorld(); if ( sw ) { sw->StopAllSounds(); } soundSystem->ClearBuffer(); // shutdown the script debugger // DebuggerServerShutdown(); idAsyncNetwork::client.Shutdown(); // shut down the session session->Shutdown(); // shut down the user interfaces uiManager->Shutdown(); // shut down the sound system soundSystem->Shutdown(); // shut down async networking idAsyncNetwork::Shutdown(); // shut down the user command input code usercmdGen->Shutdown(); // shut down the event loop eventLoop->Shutdown(); // shut down the renderSystem renderSystem->Shutdown(); // shutdown the decl manager declManager->Shutdown(); // unload the game dll UnloadGameDLL(); // dump warnings to "warnings.txt" #if defined(DEBUG) || defined(QUAKE4) DumpWarnings(); #endif // only shut down the log file after all output is done CloseLogFile(); // shut down the file system fileSystem->Shutdown( reloading ); } float idCommonLocal::Get_com_engineHz_latched(void) { return com_engineHz_latched; } int64_t idCommonLocal::Get_com_engineHz_numerator(void) { return com_engineHz_numerator; } int64_t idCommonLocal::Get_com_engineHz_denominator(void) { return com_engineHz_denominator; } #ifdef PREY void idCommonLocal::MaterialKeyForBinding(const char* binding, char* materialName, char* keyText, bool* wideKey) { bool unused1 = false; bool unused2 = false; idStr keyName; idStr displayName; const char* rawKey = idKeyInput::SingleKeyFromBinding(binding, unused1); if (rawKey != NULL) { keyName = rawKey; } const char* localizedKey = idKeyInput::SingleKeyFromBinding(binding, unused2); if (localizedKey != NULL) { displayName = localizedKey; } keyText[0] = '\0'; *wideKey = false; if (keyName.Length() <= 0) { strcpy(materialName, "textures/interface/tips/keywide"); const idLangDict* lang = GetLanguageDict(); strcpy(keyText, lang->GetString("#str_07133")); *wideKey = true; return; } if (!keyName.Icmp("mouse1")) { strcpy(materialName, "textures/interface/tips/mouse1"); return; } if (!keyName.Icmp("mouse2")) { strcpy(materialName, "textures/interface/tips/mouse2"); return; } if (!keyName.Icmp("mouse3")) { strcpy(materialName, "textures/interface/tips/mouse3"); return; } if (!keyName.Icmp("mwheelup")) { strcpy(materialName, "textures/interface/tips/mouseup"); return; } if (!keyName.Icmp("mwheeldown")) { strcpy(materialName, "textures/interface/tips/mousedn"); return; } if (!keyName.Icmp("uparrow")) { strcpy(materialName, "textures/interface/tips/uparrow"); return; } if (!keyName.Icmp("downarrow")) { strcpy(materialName, "textures/interface/tips/downarrow"); return; } if (!keyName.Icmp("leftarrow")) { strcpy(materialName, "textures/interface/tips/leftarrow"); return; } if (!keyName.Icmp("rightarrow")) { strcpy(materialName, "textures/interface/tips/rightarrow"); return; } if (!keyName.Icmp("enter")) { strcpy(materialName, "textures/interface/tips/enter"); *wideKey = true; return; } if (!keyName.Icmp("backspace")) { strcpy(materialName, "textures/interface/tips/backspace"); *wideKey = true; return; } if (!keyName.Icmp("tab")) { strcpy(materialName, "textures/interface/tips/tab"); *wideKey = true; return; } if (!keyName.Icmp("menu")) { strcpy(materialName, "textures/interface/tips/menu"); return; } if (!keyName.Icmp("shift")) { strcpy(materialName, "textures/interface/tips/shift"); *wideKey = true; return; } /* Generic short printable keys use the normal key material and put the localized/display key text on top of it. The original excludes large/special keys from this path: printscreen, keypad keys, pause, capslock, windows keys, modifiers, and space. */ if (keyName.Icmp("printscreen") && keyName.Icmpn("kp_", 3) && keyName.Icmp("pause") && keyName.Icmp("capslock") && keyName.Icmp("lwin") && keyName.Icmp("rwin") && keyName.Icmp("shift") && keyName.Icmp("ctrl") && keyName.Icmp("alt") && keyName.Icmp("space") && displayName.Length() <= 3) { strcpy(materialName, "textures/interface/tips/key"); strcpy(keyText, displayName.c_str()); return; } /* Everything else falls back to the wide key material with text. This handles longer key names or special keys that do not have dedicated art. */ strcpy(materialName, "textures/interface/tips/keywide"); strcpy(keyText, displayName.c_str()); *wideKey = true; } #endif