Counter Strike : Global Offensive Source Code
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.

812 lines
22 KiB

  1. //===== Copyright � 1996-2005, Valve Corporation, All rights reserved. ======//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //
  7. //===========================================================================//
  8. #include "quakedef.h"
  9. #include "bspfile.h"
  10. #include "host.h"
  11. #include "sys.h"
  12. #include "filesystem_engine.h"
  13. #include "utldict.h"
  14. #include "demo.h"
  15. #include "tier2/fileutils.h"
  16. #ifndef DEDICATED
  17. #include "vgui_baseui_interface.h"
  18. #endif
  19. // memdbgon must be the last include file in a .cpp file!!!
  20. #include "tier0/memdbgon.h"
  21. // Imported from other .cpp files
  22. void Host_Map_f( const CCommand &args );
  23. void Host_MapGroup_f( const CCommand &args );
  24. void Host_SplitScreen_Map_f( const CCommand &args );
  25. void Host_Map_Background_f( const CCommand &args );
  26. void Host_Map_Commentary_f( const CCommand &args );
  27. void Host_Changelevel_f( const CCommand &args );
  28. void Host_Changelevel2_f( const CCommand &args );
  29. ConVar host_maplist_recurse_subdirs( "host_maplist_recurse_subdirs", "1" );
  30. //-----------------------------------------------------------------------------
  31. // Purpose: For each map, stores when the map last changed on disk and whether
  32. // it is a valid map
  33. //-----------------------------------------------------------------------------
  34. class CMapListItem
  35. {
  36. public:
  37. enum
  38. {
  39. INVALID = 0,
  40. PENDING,
  41. VALID,
  42. };
  43. CMapListItem( void );
  44. void SetValid( int valid );
  45. int GetValid( void ) const;
  46. void SetFileTimestamp( long ts );
  47. long GetFileTimestamp( void ) const;
  48. bool IsSameTime( long ts ) const;
  49. static long GetFSTimeStamp( char const *name );
  50. static int CheckFSHeaderVersion( char const *name );
  51. private:
  52. int m_nValid;
  53. long m_lFileTimestamp;
  54. };
  55. //-----------------------------------------------------------------------------
  56. // Purpose:
  57. //-----------------------------------------------------------------------------
  58. CMapListItem::CMapListItem( void )
  59. {
  60. m_nValid = PENDING;
  61. m_lFileTimestamp = 0L;
  62. }
  63. //-----------------------------------------------------------------------------
  64. // Purpose:
  65. // Input : valid -
  66. //-----------------------------------------------------------------------------
  67. void CMapListItem::SetValid( int valid )
  68. {
  69. m_nValid = valid;
  70. }
  71. //-----------------------------------------------------------------------------
  72. // Purpose:
  73. // Output : Returns true on success, false on failure.
  74. //-----------------------------------------------------------------------------
  75. int CMapListItem::GetValid( void ) const
  76. {
  77. return m_nValid;
  78. }
  79. //-----------------------------------------------------------------------------
  80. // Purpose:
  81. // Input : ts -
  82. //-----------------------------------------------------------------------------
  83. void CMapListItem::SetFileTimestamp( long ts )
  84. {
  85. m_lFileTimestamp = ts;
  86. }
  87. //-----------------------------------------------------------------------------
  88. // Purpose:
  89. // Output : long
  90. //-----------------------------------------------------------------------------
  91. long CMapListItem::GetFileTimestamp( void ) const
  92. {
  93. return m_lFileTimestamp;
  94. }
  95. //-----------------------------------------------------------------------------
  96. // Purpose: Check whether this map file has changed related to the passed in timestamp
  97. // Input : ts -
  98. // Output : Returns true on success, false on failure.
  99. //-----------------------------------------------------------------------------
  100. bool CMapListItem::IsSameTime( long ts ) const
  101. {
  102. return ( m_lFileTimestamp == ts ) ? true : false;
  103. }
  104. //-----------------------------------------------------------------------------
  105. // Purpose: Get the timestamp for the file from the file system
  106. // Input : *name -
  107. // Output : long
  108. //-----------------------------------------------------------------------------
  109. long CMapListItem::GetFSTimeStamp( char const *name )
  110. {
  111. long ts = g_pFileSystem->GetFileTime( name );
  112. return ts;
  113. }
  114. //-----------------------------------------------------------------------------
  115. // Purpose: Check whether the specified map header version is up-to-date
  116. // Input : *name -
  117. // Output : Returns true on success, false on failure.
  118. //-----------------------------------------------------------------------------
  119. int CMapListItem::CheckFSHeaderVersion( char const *name )
  120. {
  121. BSPHeader_t header;
  122. memset( &header, 0, sizeof( header ) );
  123. FileHandle_t fp = g_pFileSystem->Open ( name, "rb" );
  124. if ( fp )
  125. {
  126. g_pFileSystem->Read( &header, sizeof( header ), fp );
  127. g_pFileSystem->Close( fp );
  128. }
  129. return ( header.m_nVersion >= MINBSPVERSION && header.m_nVersion <= BSPVERSION ) ? VALID : INVALID;
  130. }
  131. // How often to check the filesystem for updated map info
  132. #define MIN_REFRESH_INTERVAL 60.0f
  133. //-----------------------------------------------------------------------------
  134. // Purpose: Stores the current list of maps for the engine
  135. //-----------------------------------------------------------------------------
  136. class CMapListManager
  137. {
  138. public:
  139. CMapListManager( void );
  140. ~CMapListManager( void );
  141. // See if it's time to revisit the items in the list
  142. void RefreshList( void );
  143. // Get item count, etc
  144. int GetMapCount( void ) const;
  145. int IsMapValid( int index ) const;
  146. char const *GetMapName( int index ) const;
  147. void Think( void );
  148. private:
  149. // Clear list
  150. void ClearList( void );
  151. // Rebuild list from scratch
  152. void BuildList( void );
  153. private:
  154. // Dictionary of items
  155. CUtlDict< CMapListItem, int > m_Items;
  156. // Time of last update
  157. float m_flLastRefreshTime;
  158. bool m_bDirty;
  159. };
  160. // Singleton manager object
  161. static CMapListManager g_MapListMgr;
  162. void Host_UpdateMapList( void )
  163. {
  164. g_MapListMgr.Think();
  165. }
  166. //-----------------------------------------------------------------------------
  167. // Purpose:
  168. //-----------------------------------------------------------------------------
  169. CMapListManager::CMapListManager( void )
  170. {
  171. m_flLastRefreshTime = -1.0f;
  172. m_bDirty = false;
  173. }
  174. //-----------------------------------------------------------------------------
  175. // Purpose:
  176. //-----------------------------------------------------------------------------
  177. CMapListManager::~CMapListManager( void )
  178. {
  179. ClearList();
  180. }
  181. //-----------------------------------------------------------------------------
  182. // Purpose:
  183. //-----------------------------------------------------------------------------
  184. void CMapListManager::Think( void )
  185. {
  186. return;
  187. if ( !m_bDirty )
  188. return;
  189. #ifndef DEDICATED
  190. // Only update pending files if console is visible to avoid slamming FS while in a map
  191. if ( !EngineVGui()->IsConsoleVisible() )
  192. return;
  193. #endif
  194. int i;
  195. m_bDirty = false;
  196. for ( i = m_Items.Count() - 1; i >= 0 ; i-- )
  197. {
  198. CMapListItem *item = &m_Items[ i ];
  199. if ( item->GetValid() != CMapListItem::PENDING )
  200. {
  201. continue;
  202. }
  203. char const *filename = m_Items.GetElementName( i );
  204. item->SetValid( CMapListItem::CheckFSHeaderVersion( filename ) );
  205. // Keep fixing things up next frame
  206. m_bDirty = true;
  207. break;
  208. }
  209. }
  210. //-----------------------------------------------------------------------------
  211. // Purpose: FIXME: Refresh doesn't notice maps that have been deleted... oh well
  212. //-----------------------------------------------------------------------------
  213. void CMapListManager::RefreshList( void )
  214. {
  215. if ( m_flLastRefreshTime == -1.0f )
  216. {
  217. BuildList();
  218. return;
  219. }
  220. if ( realtime < m_flLastRefreshTime + MIN_REFRESH_INTERVAL )
  221. return;
  222. ConDMsg( "Refreshing map list...\n" );
  223. if ( host_maplist_recurse_subdirs.GetBool() )
  224. {
  225. char mapwild[MAX_QPATH];
  226. Q_snprintf( mapwild, sizeof( mapwild ), "*.%sbsp", IsX360() ? "360." : "" );
  227. CUtlVector<CUtlString> outList;
  228. RecursiveFindFilesMatchingName( &outList, "maps", mapwild, "GAME" );
  229. FOR_EACH_VEC( outList, i )
  230. {
  231. const char* curMap = outList[i].Access();
  232. int idx = m_Items.Find( curMap );
  233. if ( idx == m_Items.InvalidIndex() )
  234. {
  235. CMapListItem item;
  236. item.SetFileTimestamp( item.GetFSTimeStamp( curMap ) );
  237. item.SetValid( CMapListItem::PENDING );
  238. // Insert into dictionary
  239. m_Items.Insert( curMap, item );
  240. m_bDirty = true;
  241. }
  242. else
  243. {
  244. CMapListItem *item = &m_Items[ idx ];
  245. Assert( item );
  246. // Make sure data is up to date
  247. long timestamp = g_pFileSystem->GetFileTime( curMap );
  248. if ( !item->IsSameTime( timestamp ) )
  249. {
  250. item->SetFileTimestamp( timestamp );
  251. item->SetValid( CMapListItem::PENDING );
  252. m_bDirty = true;
  253. }
  254. }
  255. }
  256. }
  257. else
  258. {
  259. // Search the directory structure.
  260. char mapwild[MAX_QPATH];
  261. Q_strncpy(mapwild,"maps/*.bsp", sizeof( mapwild ) );
  262. char const *findfn = Sys_FindFirst( mapwild, NULL, 0 );
  263. while ( findfn )
  264. {
  265. if ( IsPC() && V_stristr( findfn, ".360.bsp" ) )
  266. {
  267. // ignore 360 bsp
  268. findfn = Sys_FindNext( NULL, 0 );
  269. continue;
  270. }
  271. else if ( IsX360() && !V_stristr( findfn, ".360.bsp" ) )
  272. {
  273. // ignore pc bsp
  274. findfn = Sys_FindNext( NULL, 0 );
  275. continue;
  276. }
  277. char sz[ MAX_QPATH ];
  278. Q_snprintf( sz, sizeof( sz ), "maps/%s", findfn );
  279. int idx = m_Items.Find( sz );
  280. if ( idx == m_Items.InvalidIndex() )
  281. {
  282. CMapListItem item;
  283. item.SetFileTimestamp( item.GetFSTimeStamp( sz ) );
  284. item.SetValid( CMapListItem::PENDING );
  285. // Insert into dictionary
  286. m_Items.Insert( sz, item );
  287. m_bDirty = true;
  288. }
  289. else
  290. {
  291. CMapListItem *item = &m_Items[ idx ];
  292. Assert( item );
  293. // Make sure data is up to date
  294. long timestamp = g_pFileSystem->GetFileTime( sz );
  295. if ( !item->IsSameTime( timestamp ) )
  296. {
  297. item->SetFileTimestamp( timestamp );
  298. item->SetValid( CMapListItem::PENDING );
  299. m_bDirty = true;
  300. }
  301. }
  302. findfn = Sys_FindNext( NULL, 0 );
  303. }
  304. Sys_FindClose();
  305. }
  306. m_flLastRefreshTime = realtime;
  307. }
  308. //-----------------------------------------------------------------------------
  309. // Purpose:
  310. // Output : int
  311. //-----------------------------------------------------------------------------
  312. int CMapListManager::GetMapCount( void ) const
  313. {
  314. return m_Items.Count();
  315. }
  316. //-----------------------------------------------------------------------------
  317. // Purpose:
  318. // Input : index -
  319. // Output : Returns true on success, false on failure.
  320. //-----------------------------------------------------------------------------
  321. int CMapListManager::IsMapValid( int index ) const
  322. {
  323. if ( !m_Items.IsValidIndex( index ) )
  324. return false;
  325. CMapListItem const *item = &m_Items[ index ];
  326. Assert( item );
  327. return item->GetValid();
  328. }
  329. //-----------------------------------------------------------------------------
  330. // Purpose:
  331. // Input : index -
  332. // Output : char const
  333. //-----------------------------------------------------------------------------
  334. char const *CMapListManager::GetMapName( int index ) const
  335. {
  336. if ( !m_Items.IsValidIndex( index ) )
  337. return "Invalid!!!";
  338. return m_Items.GetElementName( index );
  339. }
  340. //-----------------------------------------------------------------------------
  341. // Purpose: Wipe the list
  342. //-----------------------------------------------------------------------------
  343. void CMapListManager::ClearList( void )
  344. {
  345. m_Items.Purge();
  346. m_bDirty = false;
  347. }
  348. //-----------------------------------------------------------------------------
  349. // Purpose: Rebuild the entire list
  350. //-----------------------------------------------------------------------------
  351. void CMapListManager::BuildList( void )
  352. {
  353. ClearList();
  354. if ( host_maplist_recurse_subdirs.GetBool() )
  355. {
  356. char mapwild[MAX_QPATH];
  357. Q_snprintf( mapwild, sizeof( mapwild ), "*.%sbsp", IsX360() ? "360." : "" );
  358. CUtlVector<CUtlString> outList;
  359. RecursiveFindFilesMatchingName( &outList, "maps", mapwild, "GAME" );
  360. FOR_EACH_VEC( outList, i )
  361. {
  362. const char* curMap = outList[i].Access();
  363. if ( IsPC() && V_stristr( curMap, ".360.bsp" ) )
  364. {
  365. // ignore 360 bsp
  366. continue;
  367. }
  368. else if ( IsX360() && !V_stristr( curMap, ".360.bsp" ) )
  369. {
  370. // ignore pc bsp
  371. continue;
  372. }
  373. CMapListItem item;
  374. item.SetFileTimestamp( item.GetFSTimeStamp( curMap ) );
  375. item.SetValid( CMapListItem::PENDING );
  376. // Insert into dictionary
  377. int idx = m_Items.Find( curMap );
  378. if ( idx == m_Items.InvalidIndex() )
  379. {
  380. m_Items.Insert( curMap, item );
  381. }
  382. }
  383. }
  384. else
  385. {
  386. // Search the directory structure.
  387. char mapwild[MAX_QPATH];
  388. Q_snprintf( mapwild, sizeof( mapwild ), "maps/*.%sbsp", IsX360() ? "360." : "" );
  389. char const *findfn = Sys_FindFirst( mapwild, NULL, 0 );
  390. while ( findfn )
  391. {
  392. if ( IsPC() && V_stristr( findfn, ".360.bsp" ) )
  393. {
  394. // ignore 360 bsp
  395. findfn = Sys_FindNext( NULL, 0 );
  396. continue;
  397. }
  398. else if ( IsX360() && !V_stristr( findfn, ".360.bsp" ) )
  399. {
  400. // ignore pc bsp
  401. findfn = Sys_FindNext( NULL, 0 );
  402. continue;
  403. }
  404. char sz[ MAX_QPATH ];
  405. Q_snprintf( sz, sizeof( sz ), "maps/%s", findfn );
  406. CMapListItem item;
  407. item.SetFileTimestamp( item.GetFSTimeStamp( sz ) );
  408. item.SetValid( CMapListItem::PENDING );
  409. // Insert into dictionary
  410. int idx = m_Items.Find( sz );
  411. if ( idx == m_Items.InvalidIndex() )
  412. {
  413. m_Items.Insert( sz, item );
  414. }
  415. findfn = Sys_FindNext( NULL, 0 );
  416. }
  417. Sys_FindClose();
  418. }
  419. // Remember time we build the list
  420. m_flLastRefreshTime = realtime;
  421. m_bDirty = true;
  422. }
  423. //-----------------------------------------------------------------------------
  424. // Purpose:
  425. // Input : *pakorfilesys -
  426. // *mapname -
  427. // Output : static void
  428. //-----------------------------------------------------------------------------
  429. static bool MapList_CheckPrintMap( const char *pakorfilesys, const char *mapname, int valid,
  430. bool showoutdated, bool verbose )
  431. {
  432. bool validorpending = ( valid != CMapListItem::INVALID ) ? true : false;
  433. if ( !verbose )
  434. {
  435. return validorpending;
  436. }
  437. char prefix[ 32 ];
  438. prefix[ 0 ] = 0;
  439. switch ( valid )
  440. {
  441. default:
  442. case CMapListItem::VALID:
  443. break;
  444. case CMapListItem::PENDING:
  445. Q_strncpy( prefix, "PENDING: ", sizeof( prefix ) );
  446. break;
  447. case CMapListItem::INVALID:
  448. Q_strncpy( prefix, "OUTDATED: ", sizeof( prefix ) );
  449. break;
  450. }
  451. if ( validorpending ^ showoutdated )
  452. {
  453. ConMsg( "%s %s %s\n", prefix, pakorfilesys, mapname );
  454. }
  455. return validorpending;
  456. }
  457. //-----------------------------------------------------------------------------
  458. // Purpose:
  459. // Input : *pszSubString -
  460. // listobsolete -
  461. // maxitemlength -
  462. // Output : static int
  463. //-----------------------------------------------------------------------------
  464. static int MapList_CountMaps( const char *pszSubString, bool listobsolete, int& maxitemlength )
  465. {
  466. g_MapListMgr.RefreshList();
  467. maxitemlength = 0;
  468. int substringlength = 0;
  469. if ( pszSubString && pszSubString[0] )
  470. {
  471. substringlength = strlen(pszSubString);
  472. }
  473. //
  474. // search through the path, one element at a time
  475. //
  476. int count = 0;
  477. int showOutdated;
  478. for( showOutdated = listobsolete ? 1 : 0; showOutdated >= 0; showOutdated-- )
  479. {
  480. for ( int i = 0; i < g_MapListMgr.GetMapCount(); i++ )
  481. {
  482. char const *mapname = g_MapListMgr.GetMapName( i );
  483. int valid = g_MapListMgr.IsMapValid( i );
  484. if ( !substringlength || ( V_stristr( &mapname[ 5 ], pszSubString ) != NULL ) )
  485. {
  486. if ( MapList_CheckPrintMap( "(fs)", &mapname[ 5 ], valid, showOutdated ? true : false, false ) )
  487. {
  488. maxitemlength = MAX( maxitemlength, (int)( strlen( &mapname[ 5 ] ) + 1 ) );
  489. count++;
  490. }
  491. }
  492. }
  493. }
  494. return count;
  495. }
  496. //-----------------------------------------------------------------------------
  497. // Purpose:
  498. // Lists all maps matching the substring
  499. // If the substring is empty, or "*", then lists all maps
  500. // Input : *pszSubString -
  501. //-----------------------------------------------------------------------------
  502. static int MapList_ListMaps( const char *pszSubString, bool listobsolete, bool verbose, int maxcount, int maxitemlength, char maplist[][ 64 ] )
  503. {
  504. int substringlength = 0;
  505. if (pszSubString && pszSubString[0])
  506. {
  507. substringlength = strlen(pszSubString);
  508. }
  509. //
  510. // search through the path, one element at a time
  511. //
  512. if ( verbose )
  513. {
  514. ConMsg( "-------------\n");
  515. }
  516. int count = 0;
  517. int showOutdated;
  518. for( showOutdated = listobsolete ? 1 : 0; showOutdated >= 0; showOutdated-- )
  519. {
  520. if ( count >= maxcount )
  521. break;
  522. //search the directory structure.
  523. for ( int i = 0; i < g_MapListMgr.GetMapCount(); i++ )
  524. {
  525. if ( count >= maxcount )
  526. break;
  527. char const *mapname = g_MapListMgr.GetMapName( i );
  528. int valid = g_MapListMgr.IsMapValid( i );
  529. if ( !substringlength || ( V_stristr( &mapname[ 5 ], pszSubString ) != NULL ) )
  530. {
  531. if ( MapList_CheckPrintMap( "(fs)", &mapname[ 5 ], valid, showOutdated ? true : false, verbose ) )
  532. {
  533. if ( maxitemlength != 0 )
  534. {
  535. Q_strncpy( maplist[ count ], &mapname[ 5 ], maxitemlength );
  536. }
  537. count++;
  538. }
  539. }
  540. }
  541. }
  542. return count;
  543. }
  544. //-----------------------------------------------------------------------------
  545. // Purpose:
  546. // Input : *partial -
  547. // context -
  548. // longest -
  549. // maxcommands -
  550. // **commands -
  551. // Output : int
  552. //-----------------------------------------------------------------------------
  553. int _Host_Map_f_CompletionFunc( char const *cmdname, char const *partial, char commands[ COMMAND_COMPLETION_MAXITEMS ][ COMMAND_COMPLETION_ITEM_LENGTH ] )
  554. {
  555. char *substring = (char *)partial;
  556. if ( Q_strstr( partial, cmdname ) )
  557. {
  558. substring = (char *)partial + strlen( cmdname );
  559. }
  560. int longest = 0;
  561. int count = MIN( MapList_CountMaps( substring, false, longest ), COMMAND_COMPLETION_MAXITEMS );
  562. if ( count > 0 )
  563. {
  564. MapList_ListMaps( substring, false, false, COMMAND_COMPLETION_MAXITEMS, longest, commands );
  565. // Now prepend maps * in front of all of the options
  566. int i;
  567. for ( i = 0; i < count ; i++ )
  568. {
  569. char old[ COMMAND_COMPLETION_ITEM_LENGTH ];
  570. Q_strncpy( old, commands[ i ], sizeof( old ) );
  571. Q_snprintf( commands[ i ], sizeof( commands[ i ] ), "%s%s", cmdname, old );
  572. commands[ i ][ strlen( commands[ i ] ) - 4 ] = 0;
  573. }
  574. }
  575. return count;
  576. }
  577. //-----------------------------------------------------------------------------
  578. // Purpose:
  579. // Input : *partial -
  580. // context -
  581. // longest -
  582. // maxcommands -
  583. // **commands -
  584. // Output : int
  585. //-----------------------------------------------------------------------------
  586. static int Host_SSMap_f_CompletionFunc( char const *partial, char commands[ COMMAND_COMPLETION_MAXITEMS ][ COMMAND_COMPLETION_ITEM_LENGTH ] )
  587. {
  588. char const *cmdname = "ss_map ";
  589. return _Host_Map_f_CompletionFunc( cmdname, partial, commands );
  590. }
  591. //-----------------------------------------------------------------------------
  592. // Purpose:
  593. // Input : *partial -
  594. // context -
  595. // longest -
  596. // maxcommands -
  597. // **commands -
  598. // Output : int
  599. //-----------------------------------------------------------------------------
  600. static int Host_Map_f_CompletionFunc( char const *partial, char commands[ COMMAND_COMPLETION_MAXITEMS ][ COMMAND_COMPLETION_ITEM_LENGTH ] )
  601. {
  602. char const *cmdname = "map ";
  603. return _Host_Map_f_CompletionFunc( cmdname, partial, commands );
  604. }
  605. //-----------------------------------------------------------------------------
  606. // Purpose:
  607. // Input : *partial -
  608. // context -
  609. // longest -
  610. // maxcommands -
  611. // **commands -
  612. // Output : int
  613. //-----------------------------------------------------------------------------
  614. static int Host_Background_f_CompletionFunc( char const *partial, char commands[ COMMAND_COMPLETION_MAXITEMS ][ COMMAND_COMPLETION_ITEM_LENGTH ] )
  615. {
  616. char const *cmdname = "map_background ";
  617. return _Host_Map_f_CompletionFunc( cmdname, partial, commands );
  618. }
  619. //-----------------------------------------------------------------------------
  620. // Purpose:
  621. // Input : *partial -
  622. // context -
  623. // longest -
  624. // maxcommands -
  625. // **commands -
  626. // Output : int
  627. //-----------------------------------------------------------------------------
  628. static int Host_Map_Commentary_f_CompletionFunc( char const *partial, char commands[ COMMAND_COMPLETION_MAXITEMS ][ COMMAND_COMPLETION_ITEM_LENGTH ] )
  629. {
  630. char const *cmdname = "map_commentary ";
  631. return _Host_Map_f_CompletionFunc( cmdname, partial, commands );
  632. }
  633. //-----------------------------------------------------------------------------
  634. // Purpose:
  635. // Input : *partial -
  636. // context -
  637. // longest -
  638. // maxcommands -
  639. // **commands -
  640. // Output : int
  641. //-----------------------------------------------------------------------------
  642. static int Host_Changelevel_f_CompletionFunc( char const *partial, char commands[ COMMAND_COMPLETION_MAXITEMS ][ COMMAND_COMPLETION_ITEM_LENGTH ] )
  643. {
  644. char const *cmdname = "changelevel ";
  645. return _Host_Map_f_CompletionFunc( cmdname, partial, commands );
  646. }
  647. //-----------------------------------------------------------------------------
  648. // Purpose:
  649. // Input : *partial -
  650. // context -
  651. // longest -
  652. // maxcommands -
  653. // **commands -
  654. // Output : int
  655. //-----------------------------------------------------------------------------
  656. static int Host_Changelevel2_f_CompletionFunc( char const *partial, char commands[ COMMAND_COMPLETION_MAXITEMS ][ COMMAND_COMPLETION_ITEM_LENGTH ] )
  657. {
  658. char const *cmdname = "changelevel2 ";
  659. return _Host_Map_f_CompletionFunc( cmdname, partial, commands );
  660. }
  661. //-----------------------------------------------------------------------------
  662. // Purpose: do a dir of the maps dir
  663. //-----------------------------------------------------------------------------
  664. static void Host_Maps_f( const CCommand &args )
  665. {
  666. const char *pszSubString = NULL;
  667. if ( args.ArgC() != 2 && args.ArgC() != 3 )
  668. {
  669. ConMsg( "Usage: maps <substring>\nmaps * for full listing\n" );
  670. return;
  671. }
  672. if ( args.ArgC() == 2 )
  673. {
  674. pszSubString = args[1];
  675. if (!pszSubString || !pszSubString[0])
  676. return;
  677. }
  678. if ( pszSubString && ( pszSubString[0] == '*' ))
  679. pszSubString = NULL;
  680. int longest = 0;
  681. int count = MapList_CountMaps( pszSubString, true, longest );
  682. if ( count > 0 )
  683. {
  684. MapList_ListMaps( pszSubString, true, true, count, 0, NULL );
  685. }
  686. }
  687. #ifndef BENCHMARK
  688. static ConCommand maps("maps", Host_Maps_f, "Displays list of maps." );
  689. static ConCommand map("map", Host_Map_f, "Start playing on specified map.", FCVAR_DONTRECORD, Host_Map_f_CompletionFunc );
  690. static ConCommand mapgroup( "mapgroup", Host_MapGroup_f, "Specify a map group", FCVAR_DONTRECORD );
  691. static ConCommand ss_map("ss_map", Host_SplitScreen_Map_f, "Start playing on specified map with max allowed splitscreen players.", FCVAR_DONTRECORD, Host_SSMap_f_CompletionFunc );
  692. static ConCommand map_background("map_background", Host_Map_Background_f, "Runs a map as the background to the main menu.", FCVAR_DONTRECORD, Host_Background_f_CompletionFunc );
  693. 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 );
  694. static ConCommand changelevel("changelevel", Host_Changelevel_f, "Change server to the specified map", FCVAR_DONTRECORD, Host_Changelevel_f_CompletionFunc );
  695. static ConCommand changelevel2("changelevel2", Host_Changelevel2_f, "Transition to the specified map in single player", FCVAR_DONTRECORD, Host_Changelevel2_f_CompletionFunc );
  696. #endif