You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
713 lines
20 KiB
713 lines
20 KiB
//========= Copyright Valve Corporation, All rights reserved. ============// |
|
// |
|
// Purpose: |
|
// |
|
// $NoKeywords: $ |
|
// |
|
//===========================================================================// |
|
#include "quakedef.h" |
|
#include "bspfile.h" |
|
#include "host.h" |
|
#include "sys.h" |
|
#include "filesystem_engine.h" |
|
#include "utldict.h" |
|
#include "demo.h" |
|
#ifndef SWDS |
|
#include "vgui_baseui_interface.h" |
|
#endif |
|
|
|
// memdbgon must be the last include file in a .cpp file!!! |
|
#include "tier0/memdbgon.h" |
|
|
|
// Imported from other .cpp files |
|
void Host_Map_f( const CCommand &args ); |
|
void Host_Map_Background_f( const CCommand &args ); |
|
void Host_Map_Commentary_f( const CCommand &args ); |
|
void Host_Changelevel_f( const CCommand &args ); |
|
void Host_Changelevel2_f( const CCommand &args ); |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: For each map, stores when the map last changed on disk and whether |
|
// it is a valid map |
|
//----------------------------------------------------------------------------- |
|
class CMapListItem |
|
{ |
|
public: |
|
enum |
|
{ |
|
INVALID = 0, |
|
PENDING, |
|
VALID, |
|
}; |
|
|
|
CMapListItem( void ); |
|
|
|
void SetValid( int valid ); |
|
int GetValid( void ) const; |
|
|
|
void SetFileTimestamp( long ts ); |
|
long GetFileTimestamp( void ) const; |
|
|
|
bool IsSameTime( long ts ) const; |
|
|
|
static long GetFSTimeStamp( char const *name ); |
|
static int CheckFSHeaderVersion( char const *name ); |
|
|
|
private: |
|
int m_nValid; |
|
long m_lFileTimestamp; |
|
}; |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
CMapListItem::CMapListItem( void ) |
|
{ |
|
m_nValid = PENDING; |
|
m_lFileTimestamp = 0L; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
// Input : valid - |
|
//----------------------------------------------------------------------------- |
|
void CMapListItem::SetValid( int valid ) |
|
{ |
|
m_nValid = valid; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
// Output : Returns true on success, false on failure. |
|
//----------------------------------------------------------------------------- |
|
int CMapListItem::GetValid( void ) const |
|
{ |
|
return m_nValid; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
// Input : ts - |
|
//----------------------------------------------------------------------------- |
|
void CMapListItem::SetFileTimestamp( long ts ) |
|
{ |
|
m_lFileTimestamp = ts; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
// Output : long |
|
//----------------------------------------------------------------------------- |
|
long CMapListItem::GetFileTimestamp( void ) const |
|
{ |
|
return m_lFileTimestamp; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Check whether this map file has changed related to the passed in timestamp |
|
// Input : ts - |
|
// Output : Returns true on success, false on failure. |
|
//----------------------------------------------------------------------------- |
|
bool CMapListItem::IsSameTime( long ts ) const |
|
{ |
|
return ( m_lFileTimestamp == ts ) ? true : false; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Get the timestamp for the file from the file system |
|
// Input : *name - |
|
// Output : long |
|
//----------------------------------------------------------------------------- |
|
long CMapListItem::GetFSTimeStamp( char const *name ) |
|
{ |
|
long ts = g_pFileSystem->GetFileTime( name ); |
|
return ts; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Check whether the specified map header version is up-to-date |
|
// Input : *name - |
|
// Output : Returns true on success, false on failure. |
|
//----------------------------------------------------------------------------- |
|
int CMapListItem::CheckFSHeaderVersion( char const *name ) |
|
{ |
|
dheader_t header; |
|
memset( &header, 0, sizeof( header ) ); |
|
|
|
FileHandle_t fp = g_pFileSystem->Open ( name, "rb" ); |
|
if ( fp ) |
|
{ |
|
g_pFileSystem->Read( &header, sizeof( header ), fp ); |
|
g_pFileSystem->Close( fp ); |
|
} |
|
|
|
return ( header.version >= MINBSPVERSION && header.version <= BSPVERSION ) ? VALID : INVALID; |
|
} |
|
|
|
// How often to check the filesystem for updated map info |
|
#define MIN_REFRESH_INTERVAL 60.0f |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Stores the current list of maps for the engine |
|
//----------------------------------------------------------------------------- |
|
class CMapListManager |
|
{ |
|
public: |
|
CMapListManager( void ); |
|
~CMapListManager( void ); |
|
|
|
// See if it's time to revisit the items in the list |
|
void RefreshList( void ); |
|
|
|
// Get item count, etc |
|
int GetMapCount( void ) const; |
|
int IsMapValid( int index ) const; |
|
char const *GetMapName( int index ) const; |
|
|
|
void Think( void ); |
|
|
|
private: |
|
// Clear list |
|
void ClearList( void ); |
|
// Rebuild list from scratch |
|
void BuildList( void ); |
|
|
|
private: |
|
// Dictionary of items |
|
CUtlDict< CMapListItem, int > m_Items; |
|
|
|
// Time of last update |
|
float m_flLastRefreshTime; |
|
|
|
bool m_bDirty; |
|
}; |
|
|
|
// Singleton manager object |
|
static CMapListManager g_MapListMgr; |
|
|
|
void Host_UpdateMapList( void ) |
|
{ |
|
g_MapListMgr.Think(); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
CMapListManager::CMapListManager( void ) |
|
{ |
|
m_flLastRefreshTime = -1.0f; |
|
m_bDirty = false; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
CMapListManager::~CMapListManager( void ) |
|
{ |
|
ClearList(); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CMapListManager::Think( void ) |
|
{ |
|
return; |
|
|
|
if ( !m_bDirty ) |
|
return; |
|
|
|
#ifndef SWDS |
|
// Only update pending files if console is visible to avoid slamming FS while in a map |
|
if ( !EngineVGui()->IsConsoleVisible() ) |
|
return; |
|
#endif |
|
|
|
int i; |
|
|
|
m_bDirty = false; |
|
|
|
for ( i = m_Items.Count() - 1; i >= 0 ; i-- ) |
|
{ |
|
CMapListItem *item = &m_Items[ i ]; |
|
if ( item->GetValid() != CMapListItem::PENDING ) |
|
{ |
|
continue; |
|
} |
|
|
|
char const *filename = m_Items.GetElementName( i ); |
|
|
|
item->SetValid( CMapListItem::CheckFSHeaderVersion( filename ) ); |
|
|
|
// Keep fixing things up next frame |
|
m_bDirty = true; |
|
break; |
|
} |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: FIXME: Refresh doesn't notice maps that have been deleted... oh well |
|
//----------------------------------------------------------------------------- |
|
void CMapListManager::RefreshList( void ) |
|
{ |
|
if ( m_flLastRefreshTime == -1.0f ) |
|
{ |
|
BuildList(); |
|
return; |
|
} |
|
|
|
if ( realtime < m_flLastRefreshTime + MIN_REFRESH_INTERVAL ) |
|
return; |
|
|
|
ConDMsg( "Refreshing map list...\n" ); |
|
|
|
// Search the directory structure. |
|
char mapwild[MAX_QPATH]; |
|
Q_strncpy(mapwild,"maps/*.bsp", sizeof( mapwild ) ); |
|
char const *findfn = Sys_FindFirst( mapwild, NULL, 0 ); |
|
while ( findfn ) |
|
{ |
|
if ( IsPC() && V_stristr( findfn, ".360.bsp" ) ) |
|
{ |
|
// ignore 360 bsp |
|
findfn = Sys_FindNext( NULL, 0 ); |
|
continue; |
|
} |
|
else if ( IsX360() && !V_stristr( findfn, ".360.bsp" ) ) |
|
{ |
|
// ignore pc bsp |
|
findfn = Sys_FindNext( NULL, 0 ); |
|
continue; |
|
} |
|
|
|
// Make full fileame (maps/foo.bsp) and map name (foo) |
|
char szFileName[ MAX_QPATH ] = { 0 }; |
|
V_snprintf( szFileName, sizeof( szFileName ), "maps/%s", findfn ); |
|
|
|
char szMapName[256] = { 0 }; |
|
V_strncpy( szMapName, findfn, sizeof( szMapName ) ); |
|
char *pExt = V_stristr( szMapName, ".bsp" ); |
|
if ( pExt ) |
|
{ |
|
*pExt = '\0'; |
|
} |
|
|
|
int idx = m_Items.Find( szMapName ); |
|
if ( idx == m_Items.InvalidIndex() ) |
|
{ |
|
CMapListItem item; |
|
item.SetFileTimestamp( item.GetFSTimeStamp( szFileName ) ); |
|
item.SetValid( CMapListItem::PENDING ); |
|
// Insert into dictionary |
|
m_Items.Insert( szMapName, item ); |
|
|
|
m_bDirty = true; |
|
} |
|
else |
|
{ |
|
CMapListItem *item = &m_Items[ idx ]; |
|
Assert( item ); |
|
|
|
// Make sure data is up to date |
|
long timestamp = g_pFileSystem->GetFileTime( szFileName ); |
|
if ( !item->IsSameTime( timestamp ) ) |
|
{ |
|
item->SetFileTimestamp( timestamp ); |
|
item->SetValid( CMapListItem::PENDING ); |
|
|
|
m_bDirty = true; |
|
} |
|
} |
|
|
|
findfn = Sys_FindNext( NULL, 0 ); |
|
} |
|
|
|
Sys_FindClose(); |
|
|
|
m_flLastRefreshTime = realtime; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
// Output : int |
|
//----------------------------------------------------------------------------- |
|
int CMapListManager::GetMapCount( void ) const |
|
{ |
|
return m_Items.Count(); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
// Input : index - |
|
// Output : Returns true on success, false on failure. |
|
//----------------------------------------------------------------------------- |
|
int CMapListManager::IsMapValid( int index ) const |
|
{ |
|
if ( !m_Items.IsValidIndex( index ) ) |
|
return false; |
|
|
|
CMapListItem const *item = &m_Items[ index ]; |
|
Assert( item ); |
|
return item->GetValid(); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
// Input : index - |
|
// Output : char const |
|
//----------------------------------------------------------------------------- |
|
char const *CMapListManager::GetMapName( int index ) const |
|
{ |
|
if ( !m_Items.IsValidIndex( index ) ) |
|
return "Invalid!!!"; |
|
|
|
return m_Items.GetElementName( index ); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Wipe the list |
|
//----------------------------------------------------------------------------- |
|
void CMapListManager::ClearList( void ) |
|
{ |
|
m_Items.Purge(); |
|
m_bDirty = false; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Rebuild the entire list |
|
//----------------------------------------------------------------------------- |
|
void CMapListManager::BuildList( void ) |
|
{ |
|
ClearList(); |
|
|
|
// Search the directory structure. |
|
char mapwild[MAX_QPATH]; |
|
Q_strncpy(mapwild,"maps/*.bsp", sizeof( mapwild ) ); |
|
char const *findfn = Sys_FindFirst( mapwild, NULL, 0 ); |
|
while ( findfn ) |
|
{ |
|
if ( IsPC() && V_stristr( findfn, ".360.bsp" ) ) |
|
{ |
|
// ignore 360 bsp |
|
findfn = Sys_FindNext( NULL, 0 ); |
|
continue; |
|
} |
|
else if ( IsX360() && !V_stristr( findfn, ".360.bsp" ) ) |
|
{ |
|
// ignore pc bsp |
|
findfn = Sys_FindNext( NULL, 0 ); |
|
continue; |
|
} |
|
|
|
// Make full fileame (maps/foo.bsp) and map name (foo) |
|
char szFileName[ MAX_QPATH ] = { 0 }; |
|
V_snprintf( szFileName, sizeof( szFileName ), "maps/%s", findfn ); |
|
|
|
char szMapName[256] = { 0 }; |
|
V_strncpy( szMapName, findfn, sizeof( szMapName ) ); |
|
char *pExt = V_stristr( szMapName, ".bsp" ); |
|
if ( pExt ) |
|
{ |
|
*pExt = '\0'; |
|
} |
|
|
|
CMapListItem item; |
|
item.SetFileTimestamp( item.GetFSTimeStamp( szFileName ) ); |
|
item.SetValid( CMapListItem::PENDING ); |
|
|
|
// Insert into dictionary |
|
int idx = m_Items.Find( szMapName ); |
|
if ( idx == m_Items.InvalidIndex() ) |
|
{ |
|
m_Items.Insert( szMapName, item ); |
|
} |
|
|
|
findfn = Sys_FindNext( NULL, 0 ); |
|
} |
|
|
|
Sys_FindClose(); |
|
|
|
// Remember time we build the list |
|
m_flLastRefreshTime = realtime; |
|
|
|
m_bDirty = true; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
// Input : *pakorfilesys - |
|
// *mapname - |
|
// Output : static void |
|
//----------------------------------------------------------------------------- |
|
static bool MapList_CheckPrintMap( const char *pakorfilesys, const char *mapname, int valid, |
|
bool showoutdated, bool verbose ) |
|
{ |
|
bool validorpending = ( valid != CMapListItem::INVALID ) ? true : false; |
|
|
|
if ( !verbose ) |
|
{ |
|
return validorpending; |
|
} |
|
|
|
char prefix[ 32 ]; |
|
prefix[ 0 ] = 0; |
|
|
|
switch ( valid ) |
|
{ |
|
default: |
|
case CMapListItem::VALID: |
|
break; |
|
case CMapListItem::PENDING: |
|
Q_strncpy( prefix, "PENDING: ", sizeof( prefix ) ); |
|
break; |
|
case CMapListItem::INVALID: |
|
Q_strncpy( prefix, "OUTDATED: ", sizeof( prefix ) ); |
|
break; |
|
} |
|
|
|
if ( validorpending ^ showoutdated ) |
|
{ |
|
ConMsg( "%s %s %s\n", prefix, pakorfilesys, mapname ); |
|
} |
|
|
|
return validorpending; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
// Input : *pszSubString - |
|
// listobsolete - |
|
// maxitemlength - |
|
// Output : static int |
|
//----------------------------------------------------------------------------- |
|
static int MapList_CountMaps( const char *pszSubString, bool listobsolete, int& maxitemlength ) |
|
{ |
|
g_MapListMgr.RefreshList(); |
|
|
|
maxitemlength = 0; |
|
|
|
int substringlength = 0; |
|
if ( pszSubString && pszSubString[0] ) |
|
{ |
|
substringlength = strlen(pszSubString); |
|
} |
|
|
|
// |
|
// search through the path, one element at a time |
|
// |
|
int count = 0; |
|
int showOutdated; |
|
for( showOutdated = listobsolete ? 1 : 0; showOutdated >= 0; showOutdated-- ) |
|
{ |
|
for ( int i = 0; i < g_MapListMgr.GetMapCount(); i++ ) |
|
{ |
|
char const *mapname = g_MapListMgr.GetMapName( i ); |
|
int valid = g_MapListMgr.IsMapValid( i ); |
|
|
|
if ( !substringlength || V_stristr( mapname, pszSubString ) ) |
|
{ |
|
if ( MapList_CheckPrintMap( "(fs)", mapname, valid, showOutdated ? true : false, false ) ) |
|
{ |
|
maxitemlength = max( maxitemlength, (int)( strlen( mapname ) + 1 ) ); |
|
count++; |
|
} |
|
} |
|
} |
|
} |
|
|
|
return count; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
// Lists all maps matching the substring |
|
// If the substring is empty, or "*", then lists all maps |
|
// Input : *pszSubString - |
|
//----------------------------------------------------------------------------- |
|
int MapList_ListMaps( const char *pszSubString, bool listobsolete, bool verbose, int maxcount, int maxitemlength, char maplist[][ 64 ] ) |
|
{ |
|
g_MapListMgr.RefreshList(); |
|
int substringlength = 0; |
|
if (pszSubString && pszSubString[0]) |
|
{ |
|
substringlength = strlen(pszSubString); |
|
} |
|
|
|
// |
|
// search through the path, one element at a time |
|
// |
|
|
|
if ( verbose ) |
|
{ |
|
ConMsg( "-------------\n"); |
|
} |
|
|
|
int count = 0; |
|
int showOutdated; |
|
for( showOutdated = listobsolete ? 1 : 0; showOutdated >= 0; showOutdated-- ) |
|
{ |
|
if ( count >= maxcount ) |
|
break; |
|
|
|
//search the directory structure. |
|
for ( int i = 0; i < g_MapListMgr.GetMapCount(); i++ ) |
|
{ |
|
if ( count >= maxcount ) |
|
break; |
|
|
|
char const *mapname = g_MapListMgr.GetMapName( i ); |
|
int valid = g_MapListMgr.IsMapValid( i ); |
|
|
|
if ( !substringlength || V_stristr( mapname, pszSubString ) ) |
|
{ |
|
if ( MapList_CheckPrintMap( "(fs)", mapname, valid, showOutdated ? true : false, verbose ) ) |
|
{ |
|
if ( maxitemlength != 0 ) |
|
{ |
|
Q_strncpy( maplist[ count ], mapname, maxitemlength ); |
|
} |
|
count++; |
|
} |
|
} |
|
} |
|
} |
|
|
|
return count; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
// Input : *partial - |
|
// context - |
|
// longest - |
|
// maxcommands - |
|
// **commands - |
|
// Output : int |
|
//----------------------------------------------------------------------------- |
|
int _Host_Map_f_CompletionFunc( char const *cmdname, char const *partial, char commands[ COMMAND_COMPLETION_MAXITEMS ][ COMMAND_COMPLETION_ITEM_LENGTH ] ) |
|
{ |
|
char *substring = (char *)partial; |
|
if ( Q_strstr( partial, cmdname ) ) |
|
{ |
|
substring = (char *)partial + strlen( cmdname ); |
|
} |
|
|
|
int longest = 0; |
|
int count = min( MapList_CountMaps( substring, false, longest ), COMMAND_COMPLETION_MAXITEMS ); |
|
if ( count > 0 ) |
|
{ |
|
MapList_ListMaps( substring, false, false, COMMAND_COMPLETION_MAXITEMS, longest, commands ); |
|
|
|
// Now prepend maps * in front of all of the options |
|
int i; |
|
for ( i = 0; i < count ; i++ ) |
|
{ |
|
char old[ COMMAND_COMPLETION_ITEM_LENGTH ]; |
|
Q_strncpy( old, commands[ i ], sizeof( old ) ); |
|
Q_snprintf( commands[ i ], sizeof( commands[ i ] ), "%s%s", cmdname, old ); |
|
} |
|
} |
|
|
|
return count; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
// Input : *partial - |
|
// context - |
|
// longest - |
|
// maxcommands - |
|
// **commands - |
|
// Output : int |
|
//----------------------------------------------------------------------------- |
|
static int Host_Map_f_CompletionFunc( char const *partial, char commands[ COMMAND_COMPLETION_MAXITEMS ][ COMMAND_COMPLETION_ITEM_LENGTH ] ) |
|
{ |
|
char const *cmdname = "map "; |
|
return _Host_Map_f_CompletionFunc( cmdname, partial, commands ); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
// Input : *partial - |
|
// context - |
|
// longest - |
|
// maxcommands - |
|
// **commands - |
|
// Output : int |
|
//----------------------------------------------------------------------------- |
|
static int Host_Map_Commentary_f_CompletionFunc( char const *partial, char commands[ COMMAND_COMPLETION_MAXITEMS ][ COMMAND_COMPLETION_ITEM_LENGTH ] ) |
|
{ |
|
char const *cmdname = "map_commentary "; |
|
return _Host_Map_f_CompletionFunc( cmdname, partial, commands ); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
// Input : *partial - |
|
// context - |
|
// longest - |
|
// maxcommands - |
|
// **commands - |
|
// Output : int |
|
//----------------------------------------------------------------------------- |
|
static int Host_Changelevel_f_CompletionFunc( char const *partial, char commands[ COMMAND_COMPLETION_MAXITEMS ][ COMMAND_COMPLETION_ITEM_LENGTH ] ) |
|
{ |
|
char const *cmdname = "changelevel "; |
|
return _Host_Map_f_CompletionFunc( cmdname, partial, commands ); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
// Input : *partial - |
|
// context - |
|
// longest - |
|
// maxcommands - |
|
// **commands - |
|
// Output : int |
|
//----------------------------------------------------------------------------- |
|
static int Host_Changelevel2_f_CompletionFunc( char const *partial, char commands[ COMMAND_COMPLETION_MAXITEMS ][ COMMAND_COMPLETION_ITEM_LENGTH ] ) |
|
{ |
|
char const *cmdname = "changelevel2 "; |
|
return _Host_Map_f_CompletionFunc( cmdname, partial, commands ); |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: do a dir of the maps dir |
|
//----------------------------------------------------------------------------- |
|
static void Host_Maps_f( const CCommand &args ) |
|
{ |
|
const char *pszSubString = NULL; |
|
|
|
if ( args.ArgC() != 2 && args.ArgC() != 3 ) |
|
{ |
|
ConMsg( "Usage: maps <substring>\nmaps * for full listing\n" ); |
|
return; |
|
} |
|
|
|
if ( args.ArgC() == 2 ) |
|
{ |
|
pszSubString = args[1]; |
|
if (!pszSubString || !pszSubString[0]) |
|
return; |
|
} |
|
|
|
if ( pszSubString && ( pszSubString[0] == '*' )) |
|
pszSubString = NULL; |
|
|
|
int longest = 0; |
|
int count = MapList_CountMaps( pszSubString, true, longest ); |
|
if ( count > 0 ) |
|
{ |
|
MapList_ListMaps( pszSubString, true, true, count, 0, NULL ); |
|
} |
|
} |
|
|
|
#ifndef BENCHMARK |
|
static ConCommand maps("maps", Host_Maps_f, "Displays list of maps." ); |
|
static ConCommand map("map", Host_Map_f, "Start playing on specified map.", FCVAR_DONTRECORD, Host_Map_f_CompletionFunc ); |
|
static ConCommand map_background("map_background", Host_Map_Background_f, "Runs a map as the background to the main menu.", FCVAR_DONTRECORD, Host_Map_f_CompletionFunc ); |
|
static ConCommand map_commentary("map_commentary", Host_Map_Commentary_f, "Start playing, with commentary, on a specified map.", FCVAR_DONTRECORD, Host_Map_Commentary_f_CompletionFunc ); |
|
static ConCommand changelevel("changelevel", Host_Changelevel_f, "Change server to the specified map", FCVAR_DONTRECORD, Host_Changelevel_f_CompletionFunc ); |
|
static ConCommand changelevel2("changelevel2", Host_Changelevel2_f, "Transition to the specified map in single player", FCVAR_DONTRECORD, Host_Changelevel2_f_CompletionFunc ); |
|
#endif
|
|
|