mirror of
https://github.com/id-Software/DOOM-3-BFG.git
synced 2024-12-11 13:11:47 +00:00
a405b37f13
If the window loses focus com_pause is set to 1, when it regains focus it's set to 0. The behaviour on Win32 stayed the same (the implementation is less hacky though) and Linux now matchces that.
1929 lines
46 KiB
C++
1929 lines
46 KiB
C++
/*
|
|
===========================================================================
|
|
|
|
Doom 3 BFG Edition GPL Source Code
|
|
Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
|
|
Copyright (C) 2012 Robert Beckebans
|
|
|
|
This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
|
|
|
|
Doom 3 BFG Edition 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.
|
|
|
|
Doom 3 BFG Edition 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 Doom 3 BFG Edition Source Code. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
In addition, the Doom 3 BFG Edition Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition 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 id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
|
|
|
|
===========================================================================
|
|
*/
|
|
|
|
#include "precompiled.h"
|
|
#pragma hdrstop
|
|
|
|
#include "Common_local.h"
|
|
|
|
#include "ConsoleHistory.h"
|
|
#include "../renderer/AutoRenderBink.h"
|
|
|
|
#include "../sound/sound.h"
|
|
|
|
// RB begin
|
|
#if defined(USE_DOOMCLASSIC)
|
|
#include "../../doomclassic/doom/doomlib.h"
|
|
#include "../../doomclassic/doom/d_event.h"
|
|
#include "../../doomclassic/doom/d_main.h"
|
|
#endif
|
|
// RB end
|
|
|
|
|
|
#include "../sys/sys_savegame.h"
|
|
|
|
#if defined( _DEBUG )
|
|
#define BUILD_DEBUG "-debug"
|
|
#else
|
|
#define BUILD_DEBUG ""
|
|
#endif
|
|
|
|
struct version_s
|
|
{
|
|
version_s()
|
|
{
|
|
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_forceGenericSIMD( "com_forceGenericSIMD", "0", CVAR_BOOL | CVAR_SYSTEM | CVAR_NOCHEAT, "force generic platform independent SIMD" );
|
|
|
|
#ifdef ID_RETAIL
|
|
idCVar com_allowConsole( "com_allowConsole", "0", CVAR_BOOL | CVAR_SYSTEM | CVAR_INIT, "allow toggling console with the tilde key" );
|
|
#else
|
|
idCVar com_allowConsole( "com_allowConsole", "1", CVAR_BOOL | CVAR_SYSTEM | CVAR_INIT, "allow toggling console with the tilde key" );
|
|
#endif
|
|
|
|
idCVar com_developer( "developer", "0", CVAR_BOOL | CVAR_SYSTEM | CVAR_NOCHEAT, "developer mode" );
|
|
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_updateLoadSize( "com_updateLoadSize", "0", CVAR_BOOL | CVAR_SYSTEM | CVAR_NOCHEAT, "update the load size after loading a map" );
|
|
|
|
idCVar com_productionMode( "com_productionMode", "0", CVAR_SYSTEM | CVAR_BOOL, "0 - no special behavior, 1 - building a production build, 2 - running a production build" );
|
|
|
|
idCVar com_japaneseCensorship( "com_japaneseCensorship", "0", CVAR_NOCHEAT, "Enable Japanese censorship" );
|
|
|
|
idCVar preload_CommonAssets( "preload_CommonAssets", "1", CVAR_SYSTEM | CVAR_BOOL, "preload common assets" );
|
|
|
|
idCVar net_inviteOnly( "net_inviteOnly", "1", CVAR_BOOL | CVAR_ARCHIVE, "whether or not the private server you create allows friends to join or invite only" );
|
|
|
|
// DG: add cvar for pause
|
|
idCVar com_pause( "com_pause", "0", CVAR_BOOL | CVAR_SYSTEM , "set to 1 to pause game, to 0 to unpause again" );
|
|
// DG end
|
|
|
|
extern idCVar g_demoMode;
|
|
|
|
idCVar com_engineHz( "com_engineHz", "60", CVAR_FLOAT | CVAR_ARCHIVE, "Frames per second the engine runs at", 10.0f, 1024.0f );
|
|
float com_engineHz_latched = 60.0f; // Latched version of cvar, updated between map loads
|
|
int64 com_engineHz_numerator = 100LL * 1000LL;
|
|
int64 com_engineHz_denominator = 100LL * 60LL;
|
|
|
|
// RB begin
|
|
#if defined(_WIN32)
|
|
HWND com_hwndMsg = NULL;
|
|
#endif
|
|
// RB end
|
|
|
|
#ifdef __DOOM_DLL__
|
|
idGame* game = NULL;
|
|
idGameEdit* gameEdit = NULL;
|
|
#endif
|
|
|
|
idCommonLocal commonLocal;
|
|
idCommon* common = &commonLocal;
|
|
|
|
|
|
idCVar com_skipIntroVideos( "com_skipIntroVideos", "0", CVAR_BOOL , "skips intro videos" );
|
|
|
|
// For doom classic
|
|
struct Globals;
|
|
|
|
/*
|
|
==================
|
|
idCommonLocal::idCommonLocal
|
|
==================
|
|
*/
|
|
idCommonLocal::idCommonLocal() :
|
|
readSnapshotIndex( 0 ),
|
|
writeSnapshotIndex( 0 ),
|
|
optimalPCTBuffer( 0.5f ),
|
|
optimalTimeBuffered( 0.0f ),
|
|
optimalTimeBufferedWindow( 0.0f ),
|
|
lastPacifierSessionTime( 0 ),
|
|
lastPacifierGuiTime( 0 ),
|
|
lastPacifierDialogState( false ),
|
|
showShellRequested( false )
|
|
// RB begin
|
|
#if defined(USE_DOOMCLASSIC)
|
|
,
|
|
currentGame( DOOM3_BFG ),
|
|
idealCurrentGame( DOOM3_BFG ),
|
|
doomClassicMaterial( NULL )
|
|
#endif
|
|
// RB end
|
|
{
|
|
|
|
snapCurrent.localTime = -1;
|
|
snapPrevious.localTime = -1;
|
|
snapCurrent.serverTime = -1;
|
|
snapPrevious.serverTime = -1;
|
|
snapTimeBuffered = 0.0f;
|
|
effectiveSnapRate = 0.0f;
|
|
totalBufferedTime = 0;
|
|
totalRecvTime = 0;
|
|
|
|
com_fullyInitialized = false;
|
|
com_refreshOnPrint = false;
|
|
com_errorEntered = ERP_NONE;
|
|
com_shuttingDown = false;
|
|
com_isJapaneseSKU = false;
|
|
|
|
logFile = NULL;
|
|
|
|
strcpy( errorMessage, "" );
|
|
|
|
rd_buffer = NULL;
|
|
rd_buffersize = 0;
|
|
rd_flush = NULL;
|
|
|
|
gameDLL = 0;
|
|
|
|
loadGUI = NULL;
|
|
nextLoadTip = 0;
|
|
isHellMap = false;
|
|
wipeForced = false;
|
|
defaultLoadscreen = false;
|
|
|
|
menuSoundWorld = NULL;
|
|
|
|
insideUpdateScreen = false;
|
|
insideExecuteMapChange = false;
|
|
|
|
mapSpawnData.savegameFile = NULL;
|
|
|
|
currentMapName.Clear();
|
|
aviDemoShortName.Clear();
|
|
|
|
renderWorld = NULL;
|
|
soundWorld = NULL;
|
|
menuSoundWorld = NULL;
|
|
readDemo = NULL;
|
|
writeDemo = NULL;
|
|
|
|
gameFrame = 0;
|
|
gameTimeResidual = 0;
|
|
syncNextGameFrame = true;
|
|
mapSpawned = false;
|
|
aviCaptureMode = false;
|
|
timeDemo = TD_NO;
|
|
|
|
nextSnapshotSendTime = 0;
|
|
nextUsercmdSendTime = 0;
|
|
|
|
clientPrediction = 0;
|
|
|
|
saveFile = NULL;
|
|
stringsFile = NULL;
|
|
|
|
ClearWipe();
|
|
}
|
|
|
|
/*
|
|
==================
|
|
idCommonLocal::Quit
|
|
==================
|
|
*/
|
|
void idCommonLocal::Quit()
|
|
{
|
|
|
|
// 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* const* argv )
|
|
{
|
|
int i, current_count;
|
|
|
|
com_numConsoleLines = 0;
|
|
current_count = 0;
|
|
// API says no program path
|
|
for( i = 0; i < argc; i++ )
|
|
{
|
|
if( idStr::Icmp( argv[ i ], "+connect_lobby" ) == 0 )
|
|
{
|
|
// Handle Steam bootable invites.
|
|
|
|
// RB begin
|
|
#if defined(_WIN32)
|
|
session->HandleBootableInvite( _atoi64( argv[ i + 1 ] ) );
|
|
#else
|
|
session->HandleBootableInvite( atol( argv[ i + 1 ] ) );
|
|
#endif
|
|
// RB end
|
|
}
|
|
else 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::SafeMode
|
|
|
|
Check for "safe" on the command line, which will
|
|
skip loading of config file (DoomConfig.cfg)
|
|
==================
|
|
*/
|
|
bool idCommonLocal::SafeMode()
|
|
{
|
|
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::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 )
|
|
{
|
|
int i = 0;
|
|
while( i < com_numConsoleLines )
|
|
{
|
|
if( strcmp( com_consoleLines[ i ].Argv( 0 ), "set" ) != 0 )
|
|
{
|
|
i++;
|
|
continue;
|
|
}
|
|
const char* s = com_consoleLines[ i ].Argv( 1 );
|
|
|
|
if( !match || !idStr::Icmp( s, match ) )
|
|
{
|
|
cvarSystem->SetCVarString( s, com_consoleLines[ i ].Argv( 2 ) );
|
|
}
|
|
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
|
|
==================
|
|
*/
|
|
void idCommonLocal::AddStartupCommands()
|
|
{
|
|
// quote every token, so args with semicolons can work
|
|
for( int i = 0; i < com_numConsoleLines; i++ )
|
|
{
|
|
if( !com_consoleLines[i].Argc() )
|
|
{
|
|
continue;
|
|
}
|
|
// directly as tokenized so nothing gets screwed
|
|
cmdSystem->BufferCommandArgs( CMD_EXEC_APPEND, com_consoleLines[i] );
|
|
}
|
|
}
|
|
|
|
/*
|
|
==================
|
|
idCommonLocal::WriteConfigToFile
|
|
==================
|
|
*/
|
|
void idCommonLocal::WriteConfigToFile( const char* filename )
|
|
{
|
|
idFile* f = fileSystem->OpenFileWrite( filename );
|
|
if( !f )
|
|
{
|
|
Printf( "Couldn't write %s.\n", filename );
|
|
return;
|
|
}
|
|
|
|
idKeyInput::WriteBindings( f );
|
|
cvarSystem->WriteFlaggedVariables( CVAR_ARCHIVE, "set", f );
|
|
fileSystem->CloseFile( f );
|
|
}
|
|
|
|
/*
|
|
===============
|
|
idCommonLocal::WriteConfiguration
|
|
|
|
Writes key bindings and archived cvars to config file if modified
|
|
===============
|
|
*/
|
|
void idCommonLocal::WriteConfiguration()
|
|
{
|
|
// 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 );
|
|
|
|
// save to the profile
|
|
idLocalUser* user = session->GetSignInManager().GetMasterLocalUser();
|
|
if( user != NULL )
|
|
{
|
|
user->SaveProfileSettings();
|
|
}
|
|
|
|
#ifdef CONFIG_FILE
|
|
// disable printing out the "Writing to:" message
|
|
bool developer = com_developer.GetBool();
|
|
com_developer.SetBool( false );
|
|
|
|
WriteConfigToFile( CONFIG_FILE );
|
|
|
|
// restore the developer cvar
|
|
com_developer.SetBool( developer );
|
|
#endif
|
|
}
|
|
|
|
/*
|
|
===============
|
|
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 );
|
|
}
|
|
|
|
/*
|
|
============
|
|
idCmdSystemLocal::PrintMemInfo_f
|
|
|
|
This prints out memory debugging data
|
|
============
|
|
*/
|
|
CONSOLE_COMMAND( printMemInfo, "prints memory debugging data", NULL )
|
|
{
|
|
MemInfo_t mi;
|
|
memset( &mi, 0, sizeof( mi ) );
|
|
mi.filebase = commonLocal.GetCurrentMapName();
|
|
|
|
renderSystem->PrintMemInfo( &mi ); // textures and models
|
|
soundSystem->PrintMemInfo( &mi ); // sounds
|
|
|
|
common->Printf( " Used image memory: %s bytes\n", idStr::FormatNumber( mi.imageAssetsTotal ).c_str() );
|
|
mi.assetTotals += mi.imageAssetsTotal;
|
|
|
|
common->Printf( " Used model memory: %s bytes\n", idStr::FormatNumber( mi.modelAssetsTotal ).c_str() );
|
|
mi.assetTotals += mi.modelAssetsTotal;
|
|
|
|
common->Printf( " Used sound memory: %s bytes\n", idStr::FormatNumber( mi.soundAssetsTotal ).c_str() );
|
|
mi.assetTotals += mi.soundAssetsTotal;
|
|
|
|
common->Printf( " Used asset memory: %s bytes\n", idStr::FormatNumber( mi.assetTotals ).c_str() );
|
|
|
|
// write overview file
|
|
idFile* f;
|
|
|
|
f = fileSystem->OpenFileAppend( "maps/printmeminfo.txt" );
|
|
if( !f )
|
|
{
|
|
return;
|
|
}
|
|
|
|
f->Printf( "total(%s ) image(%s ) model(%s ) sound(%s ): %s\n", idStr::FormatNumber( mi.assetTotals ).c_str(), idStr::FormatNumber( mi.imageAssetsTotal ).c_str(),
|
|
idStr::FormatNumber( mi.modelAssetsTotal ).c_str(), idStr::FormatNumber( mi.soundAssetsTotal ).c_str(), mi.filebase.c_str() );
|
|
|
|
fileSystem->CloseFile( f );
|
|
}
|
|
|
|
/*
|
|
==================
|
|
Com_Error_f
|
|
|
|
Just throw a fatal error to test error shutdown procedures.
|
|
==================
|
|
*/
|
|
CONSOLE_COMMAND( error, "causes an error", NULL )
|
|
{
|
|
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.
|
|
==================
|
|
*/
|
|
CONSOLE_COMMAND( freeze, "freezes the game for a number of seconds", NULL )
|
|
{
|
|
float s;
|
|
int start, now;
|
|
|
|
if( args.Argc() != 2 )
|
|
{
|
|
commonLocal.Printf( "freeze <seconds>\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
|
|
=================
|
|
*/
|
|
CONSOLE_COMMAND( crash, "causes a crash", NULL )
|
|
{
|
|
if( !com_developer.GetBool() )
|
|
{
|
|
commonLocal.Printf( "crash may only be used in developer mode\n" );
|
|
return;
|
|
}
|
|
#ifdef __GNUC__
|
|
__builtin_trap();
|
|
#else
|
|
* ( int* ) 0 = 0x12345678;
|
|
#endif
|
|
}
|
|
|
|
/*
|
|
=================
|
|
Com_Quit_f
|
|
=================
|
|
*/
|
|
CONSOLE_COMMAND_SHIP( quit, "quits the game", NULL )
|
|
{
|
|
commonLocal.Quit();
|
|
}
|
|
CONSOLE_COMMAND_SHIP( exit, "exits the game", NULL )
|
|
{
|
|
commonLocal.Quit();
|
|
}
|
|
|
|
/*
|
|
===============
|
|
Com_WriteConfig_f
|
|
|
|
Write the config file to a specific name
|
|
===============
|
|
*/
|
|
CONSOLE_COMMAND( writeConfig, "writes a config file", NULL )
|
|
{
|
|
idStr filename;
|
|
|
|
if( args.Argc() != 2 )
|
|
{
|
|
commonLocal.Printf( "Usage: writeconfig <filename>\n" );
|
|
return;
|
|
}
|
|
|
|
filename = args.Argv( 1 );
|
|
filename.DefaultFileExtension( ".cfg" );
|
|
commonLocal.Printf( "Writing %s.\n", filename.c_str() );
|
|
commonLocal.WriteConfigToFile( filename );
|
|
}
|
|
|
|
/*
|
|
========================
|
|
idCommonLocal::CheckStartupStorageRequirements
|
|
========================
|
|
*/
|
|
void idCommonLocal::CheckStartupStorageRequirements()
|
|
{
|
|
// RB: disabled savegame and profile storage checks, because it fails sometimes without any clear reason
|
|
#if 0
|
|
int64 availableSpace = 0;
|
|
|
|
// ------------------------------------------------------------------------
|
|
// Savegame and Profile required storage
|
|
// ------------------------------------------------------------------------
|
|
{
|
|
// Make sure the save path exists in case it was deleted.
|
|
// If the path cannot be created we can safely assume there is no
|
|
// free space because in that case nothing can be saved anyway.
|
|
const char* savepath = cvarSystem->GetCVarString( "fs_savepath" );
|
|
idStr directory = savepath;
|
|
//idStr directory = fs_savepath.GetString();
|
|
directory += "\\"; // so it doesn't think the last part is a file and ignores in the directory creation
|
|
fileSystem->CreateOSPath( directory );
|
|
|
|
// Get the free space on the save path.
|
|
availableSpace = Sys_GetDriveFreeSpaceInBytes( savepath );
|
|
|
|
// If free space fails then get space on drive as a fall back
|
|
// (the directory will be created later anyway)
|
|
if( availableSpace <= 1 )
|
|
{
|
|
idStr savePath( savepath );
|
|
if( savePath.Length() >= 3 )
|
|
{
|
|
if( savePath[ 1 ] == ':' && savePath[ 2 ] == '\\' &&
|
|
( ( savePath[ 0 ] >= 'A' && savePath[ 0 ] <= 'Z' ) ||
|
|
( savePath[ 0 ] >= 'a' && savePath[ 0 ] <= 'z' ) ) )
|
|
{
|
|
savePath = savePath.Left( 3 );
|
|
availableSpace = Sys_GetDriveFreeSpaceInBytes( savePath );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
const int MIN_SAVE_STORAGE_PROFILE = 1024 * 1024;
|
|
const int MIN_SAVE_STORAGE_SAVEGAME = MIN_SAVEGAME_SIZE_BYTES;
|
|
|
|
uint64 requiredSizeBytes = MIN_SAVE_STORAGE_SAVEGAME + MIN_SAVE_STORAGE_PROFILE;
|
|
|
|
idLib::Printf( "requiredSizeBytes: %lld\n", requiredSizeBytes );
|
|
|
|
if( ( int64 )( requiredSizeBytes - availableSpace ) > 0 )
|
|
{
|
|
class idSWFScriptFunction_Continue : public idSWFScriptFunction_RefCounted
|
|
{
|
|
public:
|
|
virtual ~idSWFScriptFunction_Continue() {}
|
|
idSWFScriptVar Call( idSWFScriptObject* thisObject, const idSWFParmList& parms )
|
|
{
|
|
common->Dialog().ClearDialog( GDM_INSUFFICENT_STORAGE_SPACE );
|
|
common->Quit();
|
|
return idSWFScriptVar();
|
|
}
|
|
};
|
|
|
|
idStaticList< idSWFScriptFunction*, 4 > callbacks;
|
|
idStaticList< idStrId, 4 > optionText;
|
|
callbacks.Append( new( TAG_SWF ) idSWFScriptFunction_Continue() );
|
|
optionText.Append( idStrId( "#STR_SWF_ACCEPT" ) );
|
|
|
|
// build custom space required string
|
|
// #str_dlg_space_required ~= "There is insufficient storage available. Please free %s and try again."
|
|
idStr format = idStrId( "#str_dlg_startup_insufficient_storage" ).GetLocalizedString();
|
|
idStr size;
|
|
if( requiredSizeBytes > ( 1024 * 1024 ) )
|
|
{
|
|
size = va( "%.1f MB", ( float )requiredSizeBytes / ( 1024.0f * 1024.0f ) + 0.1f ); // +0.1 to avoid truncation
|
|
}
|
|
else
|
|
{
|
|
size = va( "%.1f KB", ( float )requiredSizeBytes / 1024.0f + 0.1f );
|
|
}
|
|
idStr msg = va( format.c_str(), size.c_str() );
|
|
|
|
common->Dialog().AddDynamicDialog( GDM_INSUFFICENT_STORAGE_SPACE, callbacks, optionText, true, msg );
|
|
}
|
|
#endif
|
|
// RB end
|
|
|
|
session->GetAchievementSystem().Start();
|
|
}
|
|
|
|
/*
|
|
===============
|
|
idCommonLocal::JapaneseCensorship
|
|
===============
|
|
*/
|
|
bool idCommonLocal::JapaneseCensorship() const
|
|
{
|
|
return com_japaneseCensorship.GetBool() || com_isJapaneseSKU;
|
|
}
|
|
|
|
/*
|
|
===============
|
|
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
|
|
===============
|
|
*/
|
|
extern idCVar sys_lang;
|
|
void idCommonLocal::InitLanguageDict()
|
|
{
|
|
idStr fileName;
|
|
|
|
//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();
|
|
|
|
// Loop through the list and filter
|
|
idStrList currentLangList = langList;
|
|
FilterLangList( ¤tLangList, sys_lang.GetString() );
|
|
|
|
if( currentLangList.Num() == 0 )
|
|
{
|
|
// reset to english and try to load again
|
|
sys_lang.SetString( ID_LANG_ENGLISH );
|
|
currentLangList = langList;
|
|
FilterLangList( ¤tLangList, sys_lang.GetString() );
|
|
}
|
|
|
|
idLocalization::ClearDictionary();
|
|
for( int i = 0; i < currentLangList.Num(); i++ )
|
|
{
|
|
//common->Printf("%s\n", currentLangList[i].c_str());
|
|
const byte* buffer = NULL;
|
|
int len = fileSystem->ReadFile( currentLangList[i], ( void** )&buffer );
|
|
if( len <= 0 )
|
|
{
|
|
assert( false && "couldn't read the language dict file" );
|
|
break;
|
|
}
|
|
idLocalization::LoadDictionary( buffer, len, currentLangList[i] );
|
|
fileSystem->FreeFile( ( void* )buffer );
|
|
}
|
|
|
|
fileSystem->FreeFileList( langFiles );
|
|
}
|
|
|
|
/*
|
|
=================
|
|
ReloadLanguage_f
|
|
=================
|
|
*/
|
|
CONSOLE_COMMAND( reloadLanguage, "reload language dict", NULL )
|
|
{
|
|
commonLocal.InitLanguageDict();
|
|
}
|
|
|
|
#include "../renderer/Image.h"
|
|
|
|
/*
|
|
=================
|
|
Com_StartBuild_f
|
|
=================
|
|
*/
|
|
CONSOLE_COMMAND( startBuild, "prepares to make a build", NULL )
|
|
{
|
|
globalImages->StartBuild();
|
|
}
|
|
|
|
/*
|
|
=================
|
|
Com_FinishBuild_f
|
|
=================
|
|
*/
|
|
CONSOLE_COMMAND( finishBuild, "finishes the build process", NULL )
|
|
{
|
|
if( game )
|
|
{
|
|
game->CacheDictionaryMedia( NULL );
|
|
}
|
|
globalImages->FinishBuild( ( args.Argc() > 1 ) );
|
|
}
|
|
|
|
/*
|
|
=================
|
|
idCommonLocal::RenderSplash
|
|
=================
|
|
*/
|
|
void idCommonLocal::RenderSplash()
|
|
{
|
|
const float sysWidth = renderSystem->GetWidth() * renderSystem->GetPixelAspect();
|
|
const float sysHeight = renderSystem->GetHeight();
|
|
const float sysAspect = sysWidth / sysHeight;
|
|
const float splashAspect = 16.0f / 9.0f;
|
|
const float adjustment = sysAspect / splashAspect;
|
|
const float barHeight = ( adjustment >= 1.0f ) ? 0.0f : ( 1.0f - adjustment ) * ( float )SCREEN_HEIGHT * 0.25f;
|
|
const float barWidth = ( adjustment <= 1.0f ) ? 0.0f : ( adjustment - 1.0f ) * ( float )SCREEN_WIDTH * 0.25f;
|
|
if( barHeight > 0.0f )
|
|
{
|
|
renderSystem->SetColor( colorBlack );
|
|
renderSystem->DrawStretchPic( 0, 0, SCREEN_WIDTH, barHeight, 0, 0, 1, 1, whiteMaterial );
|
|
renderSystem->DrawStretchPic( 0, SCREEN_HEIGHT - barHeight, SCREEN_WIDTH, barHeight, 0, 0, 1, 1, whiteMaterial );
|
|
}
|
|
if( barWidth > 0.0f )
|
|
{
|
|
renderSystem->SetColor( colorBlack );
|
|
renderSystem->DrawStretchPic( 0, 0, barWidth, SCREEN_HEIGHT, 0, 0, 1, 1, whiteMaterial );
|
|
renderSystem->DrawStretchPic( SCREEN_WIDTH - barWidth, 0, barWidth, SCREEN_HEIGHT, 0, 0, 1, 1, whiteMaterial );
|
|
}
|
|
renderSystem->SetColor4( 1, 1, 1, 1 );
|
|
renderSystem->DrawStretchPic( barWidth, barHeight, SCREEN_WIDTH - barWidth * 2.0f, SCREEN_HEIGHT - barHeight * 2.0f, 0, 0, 1, 1, splashScreen );
|
|
|
|
const emptyCommand_t* cmd = renderSystem->SwapCommandBuffers( &time_frontend, &time_backend, &time_shadows, &time_gpu );
|
|
renderSystem->RenderCommandBuffers( cmd );
|
|
}
|
|
|
|
/*
|
|
=================
|
|
idCommonLocal::RenderBink
|
|
=================
|
|
*/
|
|
void idCommonLocal::RenderBink( const char* path )
|
|
{
|
|
const float sysWidth = renderSystem->GetWidth() * renderSystem->GetPixelAspect();
|
|
const float sysHeight = renderSystem->GetHeight();
|
|
const float sysAspect = sysWidth / sysHeight;
|
|
const float movieAspect = ( 16.0f / 9.0f );
|
|
const float imageWidth = SCREEN_WIDTH * movieAspect / sysAspect;
|
|
const float chop = 0.5f * ( SCREEN_WIDTH - imageWidth );
|
|
|
|
idStr materialText;
|
|
materialText.Format( "{ translucent { videoMap %s } }", path );
|
|
|
|
idMaterial* material = const_cast<idMaterial*>( declManager->FindMaterial( "splashbink" ) );
|
|
material->Parse( materialText.c_str(), materialText.Length(), false );
|
|
material->ResetCinematicTime( Sys_Milliseconds() );
|
|
|
|
while( Sys_Milliseconds() <= material->GetCinematicStartTime() + material->CinematicLength() )
|
|
{
|
|
renderSystem->DrawStretchPic( chop, 0, imageWidth, SCREEN_HEIGHT, 0, 0, 1, 1, material );
|
|
const emptyCommand_t* cmd = renderSystem->SwapCommandBuffers( &time_frontend, &time_backend, &time_shadows, &time_gpu );
|
|
renderSystem->RenderCommandBuffers( cmd );
|
|
Sys_GenerateEvents();
|
|
Sys_Sleep( 10 );
|
|
}
|
|
|
|
material->MakeDefault();
|
|
}
|
|
|
|
/*
|
|
=================
|
|
idCommonLocal::InitSIMD
|
|
=================
|
|
*/
|
|
void idCommonLocal::InitSIMD()
|
|
{
|
|
idSIMD::InitProcessor( "doom", com_forceGenericSIMD.GetBool() );
|
|
com_forceGenericSIMD.ClearModified();
|
|
}
|
|
|
|
|
|
/*
|
|
=================
|
|
idCommonLocal::LoadGameDLL
|
|
=================
|
|
*/
|
|
void idCommonLocal::LoadGameDLL()
|
|
{
|
|
#ifdef __DOOM_DLL__
|
|
char dllPath[ MAX_OSPATH ];
|
|
|
|
gameImport_t gameImport;
|
|
gameExport_t gameExport;
|
|
GetGameAPI_t GetGameAPI;
|
|
|
|
fileSystem->FindDLL( "game", dllPath, true );
|
|
|
|
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;
|
|
}
|
|
|
|
const char* functionName = "GetGameAPI";
|
|
GetGameAPI = ( GetGameAPI_t ) Sys_DLL_GetProcAddress( gameDLL, functionName );
|
|
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.renderSystem = ::renderSystem;
|
|
gameImport.soundSystem = ::soundSystem;
|
|
gameImport.renderModelManager = ::renderModelManager;
|
|
gameImport.uiManager = ::uiManager;
|
|
gameImport.declManager = ::declManager;
|
|
gameImport.AASFileManager = ::AASFileManager;
|
|
gameImport.collisionModelManager = ::collisionModelManager;
|
|
|
|
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
|
|
if( game != NULL )
|
|
{
|
|
game->Init();
|
|
}
|
|
}
|
|
|
|
/*
|
|
=================
|
|
idCommonLocal::UnloadGameDLL
|
|
=================
|
|
*/
|
|
void idCommonLocal::CleanupShell()
|
|
{
|
|
if( game != NULL )
|
|
{
|
|
game->Shell_Cleanup();
|
|
}
|
|
}
|
|
|
|
/*
|
|
=================
|
|
idCommonLocal::UnloadGameDLL
|
|
=================
|
|
*/
|
|
void idCommonLocal::UnloadGameDLL()
|
|
{
|
|
|
|
// 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() const
|
|
{
|
|
return com_fullyInitialized;
|
|
}
|
|
|
|
|
|
//======================================================================================
|
|
|
|
|
|
/*
|
|
=================
|
|
idCommonLocal::Init
|
|
=================
|
|
*/
|
|
void idCommonLocal::Init( int argc, const char* const* argv, const char* cmdline )
|
|
{
|
|
try
|
|
{
|
|
// set interface pointers used by idLib
|
|
idLib::sys = sys;
|
|
idLib::common = common;
|
|
idLib::cvarSystem = cvarSystem;
|
|
idLib::fileSystem = fileSystem;
|
|
|
|
// initialize idLib
|
|
idLib::Init();
|
|
|
|
// clear warning buffer
|
|
ClearWarnings( GAME_NAME " initialization" );
|
|
|
|
idLib::Printf( va( "Command line: %s\n", cmdline ) );
|
|
//::MessageBox( NULL, cmdline, "blah", MB_OK );
|
|
// 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();
|
|
|
|
// register all static CVars
|
|
idCVar::RegisterStaticVars();
|
|
|
|
idLib::Printf( "QA Timing INIT: %06dms\n", Sys_Milliseconds() );
|
|
|
|
// 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 );
|
|
|
|
consoleUsed = com_allowConsole.GetBool();
|
|
|
|
if( Sys_AlreadyRunning() )
|
|
{
|
|
Sys_Quit();
|
|
}
|
|
|
|
// initialize processor specific SIMD implementation
|
|
InitSIMD();
|
|
|
|
// initialize the file system
|
|
fileSystem->Init();
|
|
|
|
const char* defaultLang = Sys_DefaultLanguage();
|
|
com_isJapaneseSKU = ( idStr::Icmp( defaultLang, ID_LANG_JAPANESE ) == 0 );
|
|
|
|
// Allow the system to set a default lanugage
|
|
Sys_SetLanguageFromSystem();
|
|
|
|
// Pre-allocate our 20 MB save buffer here on time, instead of on-demand for each save....
|
|
|
|
saveFile.SetNameAndType( SAVEGAME_CHECKPOINT_FILENAME, SAVEGAMEFILE_BINARY );
|
|
saveFile.PreAllocate( MIN_SAVEGAME_SIZE_BYTES );
|
|
|
|
stringsFile.SetNameAndType( SAVEGAME_STRINGS_FILENAME, SAVEGAMEFILE_BINARY );
|
|
stringsFile.PreAllocate( MAX_SAVEGAME_STRING_TABLE_SIZE );
|
|
|
|
fileSystem->BeginLevelLoad( "_startup", saveFile.GetDataPtr(), saveFile.GetAllocated() );
|
|
|
|
// initialize the declaration manager
|
|
declManager->Init();
|
|
|
|
// init journalling, etc
|
|
eventLoop->Init();
|
|
|
|
// init the parallel job manager
|
|
parallelJobManager->Init();
|
|
|
|
// exec the startup scripts
|
|
cmdSystem->BufferCommandText( CMD_EXEC_APPEND, "exec default.cfg\n" );
|
|
|
|
#ifdef CONFIG_FILE
|
|
// skip the config file if "safe" is on the command line
|
|
if( !SafeMode() && !g_demoMode.GetBool() )
|
|
{
|
|
cmdSystem->BufferCommandText( CMD_EXEC_APPEND, "exec " CONFIG_FILE "\n" );
|
|
}
|
|
#endif
|
|
|
|
cmdSystem->BufferCommandText( CMD_EXEC_APPEND, "exec autoexec.cfg\n" );
|
|
|
|
// run cfg execution
|
|
cmdSystem->ExecuteCommandBuffer();
|
|
|
|
// re-override anything from the config files with command line args
|
|
StartupVariable( NULL );
|
|
|
|
// if any archived cvars are modified after this, we will trigger a writing of the config file
|
|
cvarSystem->ClearModifiedFlags( CVAR_ARCHIVE );
|
|
|
|
// init OpenGL, which will open a window and connect sound and input hardware
|
|
renderSystem->InitOpenGL();
|
|
|
|
// Support up to 2 digits after the decimal point
|
|
com_engineHz_denominator = 100LL * com_engineHz.GetFloat();
|
|
com_engineHz_latched = com_engineHz.GetFloat();
|
|
|
|
// start the sound system, but don't do any hardware operations yet
|
|
soundSystem->Init();
|
|
|
|
// initialize the renderSystem data structures
|
|
renderSystem->Init();
|
|
|
|
whiteMaterial = declManager->FindMaterial( "_white" );
|
|
|
|
if( idStr::Icmp( sys_lang.GetString(), ID_LANG_FRENCH ) == 0 )
|
|
{
|
|
// If the user specified french, we show french no matter what SKU
|
|
splashScreen = declManager->FindMaterial( "guis/assets/splash/legal_french" );
|
|
}
|
|
else if( idStr::Icmp( defaultLang, ID_LANG_FRENCH ) == 0 )
|
|
{
|
|
// If the lead sku is french (ie: europe), display figs
|
|
splashScreen = declManager->FindMaterial( "guis/assets/splash/legal_figs" );
|
|
}
|
|
else
|
|
{
|
|
// Otherwise show it in english
|
|
splashScreen = declManager->FindMaterial( "guis/assets/splash/legal_english" );
|
|
}
|
|
|
|
const int legalMinTime = 4000;
|
|
const bool showVideo = ( !com_skipIntroVideos.GetBool() && fileSystem->UsingResourceFiles() );
|
|
if( showVideo )
|
|
{
|
|
RenderBink( "video\\loadvideo.bik" );
|
|
RenderSplash();
|
|
RenderSplash();
|
|
}
|
|
else
|
|
{
|
|
idLib::Printf( "Skipping Intro Videos!\n" );
|
|
// display the legal splash screen
|
|
// No clue why we have to render this twice to show up...
|
|
RenderSplash();
|
|
RenderSplash();
|
|
}
|
|
|
|
|
|
int legalStartTime = Sys_Milliseconds();
|
|
declManager->Init2();
|
|
|
|
// initialize string database so we can use it for loading messages
|
|
InitLanguageDict();
|
|
|
|
// spawn the game thread, even if we are going to run without SMP
|
|
// one meg stack, because it can parse decls from gui surfaces (unfortunately)
|
|
// use a lower priority so job threads can run on the same core
|
|
gameThread.StartWorkerThread( "Game/Draw", CORE_1B, THREAD_BELOW_NORMAL, 0x100000 );
|
|
// boost this thread's priority, so it will prevent job threads from running while
|
|
// the render back end still has work to do
|
|
|
|
// init the user command input code
|
|
usercmdGen->Init();
|
|
|
|
Sys_SetRumble( 0, 0, 0 );
|
|
|
|
// initialize the user interfaces
|
|
uiManager->Init();
|
|
|
|
// startup the script debugger
|
|
// DebuggerServerInit();
|
|
|
|
// load the game dll
|
|
LoadGameDLL();
|
|
|
|
// On the PC touch them all so they get included in the resource build
|
|
if( !fileSystem->UsingResourceFiles() )
|
|
{
|
|
declManager->FindMaterial( "guis/assets/splash/legal_english" );
|
|
declManager->FindMaterial( "guis/assets/splash/legal_french" );
|
|
declManager->FindMaterial( "guis/assets/splash/legal_figs" );
|
|
// register the japanese font so it gets included
|
|
renderSystem->RegisterFont( "DFPHeiseiGothicW7" );
|
|
// Make sure all videos get touched because you can bring videos from one map to another, they need to be included in all maps
|
|
for( int i = 0; i < declManager->GetNumDecls( DECL_VIDEO ); i++ )
|
|
{
|
|
declManager->DeclByIndex( DECL_VIDEO, i );
|
|
}
|
|
}
|
|
|
|
fileSystem->UnloadResourceContainer( "_ordered" );
|
|
|
|
// the same idRenderWorld will be used for all games
|
|
// and demos, insuring that level specific models
|
|
// will be freed
|
|
renderWorld = renderSystem->AllocRenderWorld();
|
|
soundWorld = soundSystem->AllocSoundWorld( renderWorld );
|
|
|
|
menuSoundWorld = soundSystem->AllocSoundWorld( NULL );
|
|
menuSoundWorld->PlaceListener( vec3_origin, mat3_identity, 0 );
|
|
|
|
// init the session
|
|
session->Initialize();
|
|
session->InitializeSoundRelatedSystems();
|
|
|
|
InitializeMPMapsModes();
|
|
|
|
// leaderboards need to be initialized after InitializeMPMapsModes, which populates the MP Map list.
|
|
if( game != NULL )
|
|
{
|
|
game->Leaderboards_Init();
|
|
}
|
|
|
|
CreateMainMenu();
|
|
|
|
commonDialog.Init();
|
|
|
|
// load the console history file
|
|
consoleHistory.LoadHistoryFile();
|
|
|
|
AddStartupCommands();
|
|
|
|
StartMenu( true );
|
|
|
|
while( Sys_Milliseconds() - legalStartTime < legalMinTime )
|
|
{
|
|
RenderSplash();
|
|
Sys_GenerateEvents();
|
|
Sys_Sleep( 10 );
|
|
};
|
|
|
|
// print all warnings queued during initialization
|
|
PrintWarnings();
|
|
|
|
// remove any prints from the notify lines
|
|
console->ClearNotifyLines();
|
|
|
|
CheckStartupStorageRequirements();
|
|
|
|
|
|
if( preload_CommonAssets.GetBool() && fileSystem->UsingResourceFiles() )
|
|
{
|
|
idPreloadManifest manifest;
|
|
manifest.LoadManifest( "_common.preload" );
|
|
globalImages->Preload( manifest, false );
|
|
soundSystem->Preload( manifest );
|
|
}
|
|
|
|
fileSystem->EndLevelLoad();
|
|
|
|
// RB begin
|
|
#if defined(USE_DOOMCLASSIC)
|
|
// Initialize support for Doom classic.
|
|
doomClassicMaterial = declManager->FindMaterial( "_doomClassic" );
|
|
idImage* image = globalImages->GetImage( "_doomClassic" );
|
|
if( image != NULL )
|
|
{
|
|
idImageOpts opts;
|
|
opts.format = FMT_RGBA8;
|
|
opts.colorFormat = CFM_DEFAULT;
|
|
opts.width = DOOMCLASSIC_RENDERWIDTH;
|
|
opts.height = DOOMCLASSIC_RENDERHEIGHT;
|
|
opts.numLevels = 1;
|
|
image->AllocImage( opts, TF_LINEAR, TR_REPEAT );
|
|
}
|
|
#endif
|
|
// RB end
|
|
|
|
com_fullyInitialized = true;
|
|
|
|
|
|
// No longer need the splash screen
|
|
if( splashScreen != NULL )
|
|
{
|
|
for( int i = 0; i < splashScreen->GetNumStages(); i++ )
|
|
{
|
|
idImage* image = splashScreen->GetStage( i )->texture.image;
|
|
if( image != NULL )
|
|
{
|
|
image->PurgeImage();
|
|
}
|
|
}
|
|
}
|
|
|
|
Printf( "--- Common Initialization Complete ---\n" );
|
|
|
|
idLib::Printf( "QA Timing IIS: %06dms\n", Sys_Milliseconds() );
|
|
}
|
|
catch( idException& )
|
|
{
|
|
Sys_Error( "Error during initialization" );
|
|
}
|
|
}
|
|
|
|
/*
|
|
=================
|
|
idCommonLocal::Shutdown
|
|
=================
|
|
*/
|
|
void idCommonLocal::Shutdown()
|
|
{
|
|
|
|
if( com_shuttingDown )
|
|
{
|
|
return;
|
|
}
|
|
com_shuttingDown = true;
|
|
|
|
|
|
// Kill any pending saves...
|
|
printf( "session->GetSaveGameManager().CancelToTerminate();\n" );
|
|
session->GetSaveGameManager().CancelToTerminate();
|
|
|
|
// kill sound first
|
|
printf( "soundSystem->StopAllSounds();\n" );
|
|
soundSystem->StopAllSounds();
|
|
|
|
// shutdown the script debugger
|
|
// DebuggerServerShutdown();
|
|
|
|
if( aviCaptureMode )
|
|
{
|
|
printf( "EndAVICapture();\n" );
|
|
EndAVICapture();
|
|
}
|
|
|
|
printf( "Stop();\n" );
|
|
Stop();
|
|
|
|
printf( "CleanupShell();\n" );
|
|
CleanupShell();
|
|
|
|
printf( "delete loadGUI;\n" );
|
|
delete loadGUI;
|
|
loadGUI = NULL;
|
|
|
|
printf( "delete renderWorld;\n" );
|
|
delete renderWorld;
|
|
renderWorld = NULL;
|
|
|
|
printf( "delete soundWorld;\n" );
|
|
delete soundWorld;
|
|
soundWorld = NULL;
|
|
|
|
printf( "delete menuSoundWorld;\n" );
|
|
delete menuSoundWorld;
|
|
menuSoundWorld = NULL;
|
|
|
|
// shut down the session
|
|
printf( "session->ShutdownSoundRelatedSystems();\n" );
|
|
session->ShutdownSoundRelatedSystems();
|
|
printf( "session->Shutdown();\n" );
|
|
session->Shutdown();
|
|
|
|
// shutdown, deallocate leaderboard definitions.
|
|
if( game != NULL )
|
|
{
|
|
printf( "game->Leaderboards_Shutdown();\n" );
|
|
game->Leaderboards_Shutdown();
|
|
}
|
|
|
|
// shut down the user interfaces
|
|
printf( "uiManager->Shutdown();\n" );
|
|
uiManager->Shutdown();
|
|
|
|
// shut down the sound system
|
|
printf( "soundSystem->Shutdown();\n" );
|
|
soundSystem->Shutdown();
|
|
|
|
// shut down the user command input code
|
|
printf( "usercmdGen->Shutdown();\n" );
|
|
usercmdGen->Shutdown();
|
|
|
|
// shut down the event loop
|
|
printf( "eventLoop->Shutdown();\n" );
|
|
eventLoop->Shutdown();
|
|
|
|
// shutdown the decl manager
|
|
printf( "declManager->Shutdown();\n" );
|
|
declManager->Shutdown();
|
|
|
|
// shut down the renderSystem
|
|
printf( "renderSystem->Shutdown();\n" );
|
|
renderSystem->Shutdown();
|
|
|
|
printf( "commonDialog.Shutdown();\n" );
|
|
commonDialog.Shutdown();
|
|
|
|
// unload the game dll
|
|
printf( "UnloadGameDLL();\n" );
|
|
UnloadGameDLL();
|
|
|
|
printf( "saveFile.Clear( true );\n" );
|
|
saveFile.Clear( true );
|
|
printf( "stringsFile.Clear( true );\n" );
|
|
stringsFile.Clear( true );
|
|
|
|
// only shut down the log file after all output is done
|
|
printf( "CloseLogFile();\n" );
|
|
CloseLogFile();
|
|
|
|
// shut down the file system
|
|
printf( "fileSystem->Shutdown( false );\n" );
|
|
fileSystem->Shutdown( false );
|
|
|
|
// shut down non-portable system services
|
|
printf( "Sys_Shutdown();\n" );
|
|
Sys_Shutdown();
|
|
|
|
// shut down the console
|
|
printf( "console->Shutdown();\n" );
|
|
console->Shutdown();
|
|
|
|
// shut down the key system
|
|
printf( "idKeyInput::Shutdown();\n" );
|
|
idKeyInput::Shutdown();
|
|
|
|
// shut down the cvar system
|
|
printf( "cvarSystem->Shutdown();\n" );
|
|
cvarSystem->Shutdown();
|
|
|
|
// shut down the console command system
|
|
printf( "cmdSystem->Shutdown();\n" );
|
|
cmdSystem->Shutdown();
|
|
|
|
// free any buffered warning messages
|
|
printf( "ClearWarnings( GAME_NAME \" shutdown\" );\n" );
|
|
ClearWarnings( GAME_NAME " shutdown" );
|
|
printf( "warningCaption.Clear();\n" );
|
|
warningCaption.Clear();
|
|
printf( "errorList.Clear();\n" );
|
|
errorList.Clear();
|
|
|
|
// shutdown idLib
|
|
printf( "idLib::ShutDown();\n" );
|
|
idLib::ShutDown();
|
|
}
|
|
|
|
/*
|
|
========================
|
|
idCommonLocal::CreateMainMenu
|
|
========================
|
|
*/
|
|
void idCommonLocal::CreateMainMenu()
|
|
{
|
|
if( game != NULL )
|
|
{
|
|
// note which media we are going to need to load
|
|
declManager->BeginLevelLoad();
|
|
renderSystem->BeginLevelLoad();
|
|
soundSystem->BeginLevelLoad();
|
|
uiManager->BeginLevelLoad();
|
|
|
|
// create main inside an "empty" game level load - so assets get
|
|
// purged automagically when we transition to a "real" map
|
|
game->Shell_CreateMenu( false );
|
|
game->Shell_Show( true );
|
|
game->Shell_SyncWithSession();
|
|
|
|
// load
|
|
renderSystem->EndLevelLoad();
|
|
soundSystem->EndLevelLoad();
|
|
declManager->EndLevelLoad();
|
|
uiManager->EndLevelLoad( "" );
|
|
}
|
|
}
|
|
|
|
/*
|
|
===============
|
|
idCommonLocal::Stop
|
|
|
|
called on errors and game exits
|
|
===============
|
|
*/
|
|
void idCommonLocal::Stop( bool resetSession )
|
|
{
|
|
ClearWipe();
|
|
|
|
// clear mapSpawned and demo playing flags
|
|
UnloadMap();
|
|
|
|
soundSystem->StopAllSounds();
|
|
|
|
insideUpdateScreen = false;
|
|
insideExecuteMapChange = false;
|
|
|
|
// drop all guis
|
|
ExitMenu();
|
|
|
|
if( resetSession )
|
|
{
|
|
session->QuitMatchToTitle();
|
|
}
|
|
}
|
|
|
|
/*
|
|
===============
|
|
idCommonLocal::BusyWait
|
|
===============
|
|
*/
|
|
void idCommonLocal::BusyWait()
|
|
{
|
|
Sys_GenerateEvents();
|
|
|
|
const bool captureToImage = false;
|
|
UpdateScreen( captureToImage );
|
|
|
|
session->UpdateSignInManager();
|
|
session->Pump();
|
|
}
|
|
|
|
/*
|
|
===============
|
|
idCommonLocal::WaitForSessionState
|
|
===============
|
|
*/
|
|
bool idCommonLocal::WaitForSessionState( idSession::sessionState_t desiredState )
|
|
{
|
|
if( session->GetState() == desiredState )
|
|
{
|
|
return true;
|
|
}
|
|
|
|
while( true )
|
|
{
|
|
BusyWait();
|
|
|
|
idSession::sessionState_t sessionState = session->GetState();
|
|
if( sessionState == desiredState )
|
|
{
|
|
return true;
|
|
}
|
|
if( sessionState != idSession::LOADING &&
|
|
sessionState != idSession::SEARCHING &&
|
|
sessionState != idSession::CONNECTING &&
|
|
sessionState != idSession::BUSY &&
|
|
sessionState != desiredState )
|
|
{
|
|
return false;
|
|
}
|
|
|
|
Sys_Sleep( 10 );
|
|
}
|
|
}
|
|
|
|
/*
|
|
========================
|
|
idCommonLocal::LeaveGame
|
|
========================
|
|
*/
|
|
void idCommonLocal::LeaveGame()
|
|
{
|
|
|
|
const bool captureToImage = false;
|
|
UpdateScreen( captureToImage );
|
|
|
|
ResetNetworkingState();
|
|
|
|
|
|
Stop( false );
|
|
|
|
CreateMainMenu();
|
|
|
|
StartMenu();
|
|
|
|
|
|
}
|
|
|
|
/*
|
|
===============
|
|
idCommonLocal::ProcessEvent
|
|
===============
|
|
*/
|
|
bool idCommonLocal::ProcessEvent( const sysEvent_t* event )
|
|
{
|
|
// hitting escape anywhere brings up the menu
|
|
if( game && game->IsInGame() )
|
|
{
|
|
if( event->evType == SE_KEY && event->evValue2 == 1 && ( event->evValue == K_ESCAPE || event->evValue == K_JOY9 ) )
|
|
{
|
|
if( !game->Shell_IsActive() )
|
|
{
|
|
|
|
// menus / etc
|
|
if( MenuEvent( event ) )
|
|
{
|
|
return true;
|
|
}
|
|
|
|
console->Close();
|
|
|
|
StartMenu();
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
console->Close();
|
|
|
|
// menus / etc
|
|
if( MenuEvent( event ) )
|
|
{
|
|
return true;
|
|
}
|
|
|
|
game->Shell_ClosePause();
|
|
}
|
|
}
|
|
}
|
|
|
|
// let the pull-down console take it if desired
|
|
if( console->ProcessEvent( event, false ) )
|
|
{
|
|
return true;
|
|
}
|
|
if( session->ProcessInputEvent( event ) )
|
|
{
|
|
return true;
|
|
}
|
|
|
|
if( Dialog().IsDialogActive() )
|
|
{
|
|
Dialog().HandleDialogEvent( event );
|
|
return true;
|
|
}
|
|
|
|
// RB begin
|
|
#if defined(USE_DOOMCLASSIC)
|
|
|
|
// Let Doom classic run events.
|
|
if( IsPlayingDoomClassic() )
|
|
{
|
|
// Translate the event to Doom classic format.
|
|
event_t classicEvent;
|
|
if( event->evType == SE_KEY )
|
|
{
|
|
|
|
if( event->evValue2 == 1 )
|
|
{
|
|
classicEvent.type = ev_keydown;
|
|
}
|
|
else if( event->evValue2 == 0 )
|
|
{
|
|
classicEvent.type = ev_keyup;
|
|
}
|
|
|
|
DoomLib::SetPlayer( 0 );
|
|
|
|
extern Globals* g;
|
|
if( g != NULL )
|
|
{
|
|
classicEvent.data1 = DoomLib::RemapControl( event->GetKey() );
|
|
|
|
D_PostEvent( &classicEvent );
|
|
}
|
|
DoomLib::SetPlayer( -1 );
|
|
}
|
|
|
|
// Let the classics eat all events.
|
|
return true;
|
|
}
|
|
#endif
|
|
// RB end
|
|
|
|
// menus / etc
|
|
if( MenuEvent( event ) )
|
|
{
|
|
return true;
|
|
}
|
|
|
|
// if we aren't in a game, force the console to take it
|
|
if( !mapSpawned )
|
|
{
|
|
console->ProcessEvent( event, true );
|
|
return true;
|
|
}
|
|
|
|
// in game, exec bindings for all key downs
|
|
if( event->evType == SE_KEY && event->evValue2 == 1 )
|
|
{
|
|
idKeyInput::ExecKeyBinding( event->evValue );
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/*
|
|
========================
|
|
idCommonLocal::ResetPlayerInput
|
|
========================
|
|
*/
|
|
void idCommonLocal::ResetPlayerInput( int playerIndex )
|
|
{
|
|
userCmdMgr.ResetPlayer( playerIndex );
|
|
}
|
|
|
|
// RB begin
|
|
#if defined(USE_DOOMCLASSIC)
|
|
|
|
/*
|
|
========================
|
|
idCommonLocal::SwitchToGame
|
|
========================
|
|
*/
|
|
void idCommonLocal::SwitchToGame( currentGame_t newGame )
|
|
{
|
|
idealCurrentGame = newGame;
|
|
}
|
|
|
|
/*
|
|
========================
|
|
idCommonLocal::PerformGameSwitch
|
|
========================
|
|
*/
|
|
void idCommonLocal::PerformGameSwitch()
|
|
{
|
|
// If the session state is past the menu, we should be in Doom 3.
|
|
// This will happen if, for example, we accept an invite while playing
|
|
// Doom or Doom 2.
|
|
if( session->GetState() > idSession::IDLE )
|
|
{
|
|
idealCurrentGame = DOOM3_BFG;
|
|
}
|
|
|
|
if( currentGame == idealCurrentGame )
|
|
{
|
|
return;
|
|
}
|
|
|
|
const int DOOM_CLASSIC_HZ = 35;
|
|
|
|
if( idealCurrentGame == DOOM_CLASSIC || idealCurrentGame == DOOM2_CLASSIC )
|
|
{
|
|
// Pause Doom 3 sound.
|
|
if( menuSoundWorld != NULL )
|
|
{
|
|
menuSoundWorld->Pause();
|
|
}
|
|
|
|
DoomLib::skipToNew = false;
|
|
DoomLib::skipToLoad = false;
|
|
|
|
// Reset match parameters for the classics.
|
|
DoomLib::matchParms = idMatchParameters();
|
|
|
|
// The classics use the usercmd manager too, clear it.
|
|
userCmdMgr.SetDefaults();
|
|
|
|
// Classics need a local user too.
|
|
session->UpdateSignInManager();
|
|
session->GetSignInManager().RegisterLocalUser( 0 );
|
|
|
|
com_engineHz_denominator = 100LL * DOOM_CLASSIC_HZ;
|
|
com_engineHz_latched = DOOM_CLASSIC_HZ;
|
|
|
|
DoomLib::SetCurrentExpansion( idealCurrentGame );
|
|
|
|
}
|
|
else if( idealCurrentGame == DOOM3_BFG )
|
|
{
|
|
DoomLib::Interface.Shutdown();
|
|
com_engineHz_denominator = 100LL * com_engineHz.GetFloat();
|
|
com_engineHz_latched = com_engineHz.GetFloat();
|
|
|
|
// Don't MoveToPressStart if we have an invite, we need to go
|
|
// directly to the lobby.
|
|
if( session->GetState() <= idSession::IDLE )
|
|
{
|
|
session->MoveToPressStart();
|
|
}
|
|
|
|
// Unpause Doom 3 sound.
|
|
if( menuSoundWorld != NULL )
|
|
{
|
|
menuSoundWorld->UnPause();
|
|
}
|
|
}
|
|
|
|
currentGame = idealCurrentGame;
|
|
}
|
|
|
|
#endif // #if defined(USE_DOOMCLASSIC)
|
|
// RB end
|
|
|
|
/*
|
|
==================
|
|
Common_WritePrecache_f
|
|
==================
|
|
*/
|
|
CONSOLE_COMMAND( writePrecache, "writes precache commands", NULL )
|
|
{
|
|
if( args.Argc() != 2 )
|
|
{
|
|
common->Printf( "USAGE: writePrecache <execFile>\n" );
|
|
return;
|
|
}
|
|
idStr str = args.Argv( 1 );
|
|
str.DefaultFileExtension( ".cfg" );
|
|
idFile* f = fileSystem->OpenFileWrite( str );
|
|
declManager->WritePrecacheCommands( f );
|
|
renderModelManager->WritePrecacheCommands( f );
|
|
uiManager->WritePrecacheCommands( f );
|
|
|
|
fileSystem->CloseFile( f );
|
|
}
|
|
|
|
/*
|
|
================
|
|
Common_Disconnect_f
|
|
================
|
|
*/
|
|
CONSOLE_COMMAND_SHIP( disconnect, "disconnects from a game", NULL )
|
|
{
|
|
session->QuitMatch();
|
|
}
|
|
|
|
/*
|
|
===============
|
|
Common_Hitch_f
|
|
===============
|
|
*/
|
|
CONSOLE_COMMAND( hitch, "hitches the game", NULL )
|
|
{
|
|
if( args.Argc() == 2 )
|
|
{
|
|
Sys_Sleep( atoi( args.Argv( 1 ) ) );
|
|
}
|
|
else
|
|
{
|
|
Sys_Sleep( 100 );
|
|
}
|
|
}
|
|
|
|
CONSOLE_COMMAND( showStringMemory, "shows memory used by strings", NULL )
|
|
{
|
|
idStr::ShowMemoryUsage_f( args );
|
|
}
|
|
CONSOLE_COMMAND( showDictMemory, "shows memory used by dictionaries", NULL )
|
|
{
|
|
idDict::ShowMemoryUsage_f( args );
|
|
}
|
|
CONSOLE_COMMAND( listDictKeys, "lists all keys used by dictionaries", NULL )
|
|
{
|
|
idDict::ListKeys_f( args );
|
|
}
|
|
CONSOLE_COMMAND( listDictValues, "lists all values used by dictionaries", NULL )
|
|
{
|
|
idDict::ListValues_f( args );
|
|
}
|
|
CONSOLE_COMMAND( testSIMD, "test SIMD code", NULL )
|
|
{
|
|
idSIMD::Test_f( args );
|
|
}
|