home *** CD-ROM | disk | FTP | other *** search
/ GameStar 2006 March / Gamestar_82_2006-03_dvd.iso / DVDStar / Editace / quake4_sdkv10.exe / source / game / Game_local.cpp < prev    next >
C/C++ Source or Header  |  2005-11-14  |  213KB  |  8,187 lines

  1. #include "../idlib/precompiled.h"
  2. #pragma hdrstop
  3.  
  4. #include "Game_local.h"
  5.  
  6. // RAVEN BEGIN
  7. #include "../bse/BSEInterface.h"
  8. #include "Projectile.h"
  9. #include "client/ClientEffect.h"
  10. #include "ai/AI.h"
  11. #include "ai/AI_Manager.h"
  12. #include "ai/AAS_tactical.h"
  13. #include "Game_Log.h"
  14. // RAVEN END
  15.  
  16. //#define UI_DEBUG    1
  17.  
  18. #ifdef GAME_DLL
  19.  
  20. idSys *                        sys = NULL;
  21. idCommon *                    common = NULL;
  22. idCmdSystem *                cmdSystem = NULL;
  23. idCVarSystem *                cvarSystem = NULL;
  24. idFileSystem *                fileSystem = NULL;
  25. idNetworkSystem *            networkSystem = NULL;
  26. idRenderSystem *            renderSystem = NULL;
  27. idSoundSystem *                soundSystem = NULL;
  28. idRenderModelManager *        renderModelManager = NULL;
  29. idUserInterfaceManager *    uiManager = NULL;
  30. idDeclManager *                declManager = NULL;
  31. idAASFileManager *            AASFileManager = NULL;
  32. idCollisionModelManager *    collisionModelManager = NULL;
  33.  
  34. // RAVEN BEGIN
  35. // jscott: game interface to the fx system
  36. rvBSEManager *                bse = NULL;
  37. // RAVEN END
  38.  
  39. idCVar *                    idCVar::staticVars = NULL;
  40.  
  41. // RAVEN BEGIN
  42. // rjohnson: new help system for cvar ui
  43. idCVarHelp *                idCVarHelp::staticCVarHelps = NULL;
  44. idCVarHelp *                idCVarHelp::staticCVarHelpsTail = NULL;
  45. // RAVEN END
  46.  
  47. #if defined( MACOS_X )
  48. idCVar com_forceGenericSIMD( "com_forceGenericSIMD", "1", CVAR_BOOL|CVAR_SYSTEM, "force generic platform independent SIMD" );
  49. #else
  50. idCVar com_forceGenericSIMD( "com_forceGenericSIMD", "0", CVAR_BOOL|CVAR_SYSTEM, "force generic platform independent SIMD" );
  51. #endif
  52.  
  53. #endif
  54.  
  55. idRenderWorld *                gameRenderWorld = NULL;        // all drawing is done to this world
  56.  
  57. static gameExport_t            gameExport;
  58.  
  59. // global animation lib
  60. // RAVEN BEGIN
  61. // jsinger: changed to a pointer to prevent its constructor from allocating
  62. //          memory before the unified allocator could be initialized
  63. idAnimManager                *animationLib = NULL;
  64. // RAVEN END
  65.  
  66. // the rest of the engine will only reference the "game" variable, while all local aspects stay hidden
  67. idGameLocal                    gameLocal;
  68. idGame *                    game = &gameLocal;    // statically pointed at an idGameLocal
  69.  
  70. const char *idGameLocal::sufaceTypeNames[ MAX_SURFACE_TYPES ] = {
  71.     "none",    "metal", "stone", "flesh", "wood", "cardboard", "liquid", "glass", "plastic",
  72.     "ricochet", "surftype10", "surftype11", "surftype12", "surftype13", "surftype14", "surftype15"
  73. };
  74.  
  75. /*
  76. ===========
  77. GetGameAPI
  78. ============
  79. */
  80. extern "C" gameExport_t *GetGameAPI( gameImport_t *import ) {
  81.  
  82.     if ( import->version == GAME_API_VERSION ) {
  83.  
  84.         // set interface pointers used by the game
  85.         sys                            = import->sys;
  86.         common                        = import->common;
  87.         cmdSystem                    = import->cmdSystem;
  88.         cvarSystem                    = import->cvarSystem;
  89.         fileSystem                    = import->fileSystem;
  90.         networkSystem                = import->networkSystem;
  91.         renderSystem                = import->renderSystem;
  92.         soundSystem                    = import->soundSystem;
  93.         renderModelManager            = import->renderModelManager;
  94.         uiManager                    = import->uiManager;
  95.         declManager                    = import->declManager;
  96.         AASFileManager                = import->AASFileManager;
  97.         collisionModelManager        = import->collisionModelManager;
  98. // RAVEN BEGIN
  99. // jscott: import the fx system
  100.         bse                            = import->bse;
  101. // RAVEN END
  102.  
  103. // RAVEN BEGIN
  104. // dluetscher: import the memory system variables
  105. #ifdef _RV_MEM_SYS_SUPPORT
  106.         ::currentHeapArena            = import->heapArena;
  107.         rvSetAllSysHeaps( import->systemHeapArray );
  108. #endif
  109. // RAVEN END
  110.     }
  111.  
  112.     // set interface pointers used by idLib
  113.     idLib::sys                    = sys;
  114.     idLib::common                = common;
  115.     idLib::cvarSystem            = cvarSystem;
  116.     idLib::fileSystem            = fileSystem;
  117.  
  118.     // setup export interface
  119.     gameExport.version = GAME_API_VERSION;
  120.     gameExport.game = game;
  121.     gameExport.gameEdit = gameEdit;
  122. // RAVEN BEGIN
  123. // bdube: game log
  124.     gameExport.gameLog = gameLog;
  125. // RAVEN END    
  126.  
  127.     return &gameExport;
  128. }
  129.  
  130. /*
  131. ===========
  132. TestGameAPI
  133. ============
  134. */
  135. void TestGameAPI( void ) {
  136.     gameImport_t testImport;
  137.     gameExport_t testExport;
  138.  
  139.     testImport.sys                        = ::sys;
  140.     testImport.common                    = ::common;
  141.     testImport.cmdSystem                = ::cmdSystem;
  142.     testImport.cvarSystem                = ::cvarSystem;
  143.     testImport.fileSystem                = ::fileSystem;
  144.     testImport.networkSystem            = ::networkSystem;
  145.     testImport.renderSystem                = ::renderSystem;
  146.     testImport.soundSystem                = ::soundSystem;
  147.     testImport.renderModelManager        = ::renderModelManager;
  148.     testImport.uiManager                = ::uiManager;
  149.     testImport.declManager                = ::declManager;
  150.     testImport.AASFileManager            = ::AASFileManager;
  151.     testImport.collisionModelManager    = ::collisionModelManager;
  152.  
  153. // RAVEN BEGIN
  154. // jscott: import the fx system
  155.     testImport.bse                        = ::bse;
  156. // RAVEN END
  157.  
  158.     testExport = *GetGameAPI( &testImport );
  159. }
  160.  
  161. /*
  162. ===========
  163. idGameLocal::idGameLocal
  164. ============
  165. */
  166. idGameLocal::idGameLocal() {
  167.     Clear();
  168. }
  169.  
  170. /*
  171. ===========
  172. idGameLocal::Clear
  173. ============
  174. */
  175. void idGameLocal::Clear( void ) {
  176.     int i;
  177.  
  178.     pendingDisconnect = false;
  179.     
  180.     serverInfo.Clear();
  181.     numClients = 0;
  182.     for ( i = 0; i < MAX_CLIENTS; i++ ) {
  183.         userInfo[i].Clear();
  184.         persistentPlayerInfo[i].Clear();
  185.     }
  186.     usercmds = NULL;
  187.     memset( entities, 0, sizeof( entities ) );
  188.     memset( spawnIds, -1, sizeof( spawnIds ) );
  189.     firstFreeIndex = 0;
  190.     num_entities = 0;
  191.     spawnedEntities.Clear();
  192.     activeEntities.Clear();
  193.     numEntitiesToDeactivate = 0;
  194.     sortPushers = false;
  195.     sortTeamMasters = false;
  196.     persistentLevelInfo.Clear();
  197.     memset( globalShaderParms, 0, sizeof( globalShaderParms ) );
  198.     random.SetSeed( 0 );
  199.     world = NULL;
  200.     frameCommandThread = NULL;
  201.     testmodel = NULL;
  202. // RAVEN BEGIN
  203. // bdube: not using id effects
  204. //    testFx = NULL;
  205. // ddynerman: multiple clip worlds
  206.     ShutdownInstances();
  207. // mwhitlock: Dynamic memory consolidation
  208.     clip.Clear();
  209. // RAVEN END
  210.     
  211.     for ( i = 0; i < MAX_CLIENTS; i++ ) {
  212.         clientsPVS[ i ].i = -1;
  213.         clientsPVS[ i ].h = -1;
  214.     }
  215.     freePlayerPVS = false;
  216.     pvs.Shutdown();
  217.     sessionCommand.Clear();
  218.     locationEntities = NULL;
  219. // RAVEN BEGIN
  220. // bdube: not using smoke particles
  221. //    smokeParticles = NULL;
  222. // RAVEN END
  223.     editEntities = NULL;
  224.     entityHash.Clear( 1024, MAX_GENTITIES );
  225.     inCinematic = false;
  226.     cinematicSkipTime = 0;
  227.     cinematicStopTime = 0;
  228.     cinematicMaxSkipTime = 0;
  229.     framenum = 0;
  230.     previousTime = 0;
  231.     time = 0;
  232.     vacuumAreaNum = 0;
  233.  
  234. // RAVEN BEGIN
  235. // abahr
  236.     gravityInfo.Clear();
  237.     scriptObjectProxies.Clear();
  238. // RAVEN END
  239.  
  240.     mapFileName.Clear();
  241. // RAVEN BEGIN
  242. // rjohnson: entity usage stats
  243.     mapFileNameStripped.Clear();
  244. // RAVEN END
  245.     mapFile = NULL;
  246.     spawnCount = INITIAL_SPAWN_COUNT;
  247.     memset( isMapEntity, 0, sizeof( bool ) * MAX_GENTITIES );
  248.  
  249.     camera = NULL;
  250.  
  251. // RAVEN BEGIN
  252. // jscott: for portal skies
  253.     portalSky = NULL;
  254. // RAVEN END
  255.  
  256.     aasList.Clear();
  257.     aasNames.Clear();
  258. // RAVEN BEGIN
  259. // bdube: added
  260.     lastAIAlertEntity = NULL;
  261.     lastAIAlertEntityTime = 0;
  262.     lastAIAlertActor = NULL;
  263.     lastAIAlertActorTime = 0;
  264. // RAVEN END
  265.     spawnArgs.Clear();
  266.     gravity.Set( 0, 0, -1 );
  267.     playerPVS.h = -1;
  268.     playerConnectedAreas.h = -1;
  269.     gamestate = GAMESTATE_UNINITIALIZED;
  270.     skipCinematic = false;
  271.     influenceActive = false;
  272.  
  273.     localClientNum = 0;
  274.     isMultiplayer = false;
  275.     isServer = false;
  276.     isClient = false;
  277.     realClientTime = 0;
  278.     isNewFrame = true;
  279.     entityDefBits = 0;
  280.  
  281.     nextGibTime = 0;
  282.     globalMaterial = NULL;
  283.     newInfo.Clear();
  284.     lastGUIEnt = NULL;
  285.     lastGUI = 0;
  286.     
  287.     memset( clientEntityStates, 0, sizeof( clientEntityStates ) );
  288.     memset( clientPVS, 0, sizeof( clientPVS ) );
  289.     memset( clientSnapshots, 0, sizeof( clientSnapshots ) );
  290.  
  291.     eventQueue.Init();
  292. //    savedEventQueue.Init();
  293.  
  294. // RAVEN BEGIN
  295. // bdube: client entities
  296.     clientSpawnCount = INITIAL_SPAWN_COUNT;
  297.     clientSpawnedEntities.Clear();
  298.     memset( clientEntities, 0, sizeof( clientEntities ) );
  299.     memset( clientSpawnIds, -1, sizeof( clientSpawnIds ) );
  300.  
  301.     gameDebug.Shutdown ( );
  302.     gameLogLocal.Shutdown ( );
  303.     currentThinkingEntity = NULL;
  304. // RAVEN END
  305.  
  306.     memset( lagometer, 0, sizeof( lagometer ) );
  307.  
  308.     demoState = DEMO_NONE;
  309. }
  310.  
  311. /*
  312. ===========
  313. idGameLocal::Init
  314.  
  315.   initialize the game object, only happens once at startup, not each level load
  316. ============
  317. */
  318. // RAVEN BEGIN
  319. // jsinger: attempt to eliminate cross-DLL allocation issues
  320. extern idHashTable<rvViseme> *visemeTable100;
  321. extern idHashTable<rvViseme> *visemeTable66;
  322. extern idHashTable<rvViseme> *visemeTable33;
  323. #ifdef RV_UNIFIED_ALLOCATOR
  324. void idGameLocal::Init( void *(*allocator)(size_t size), void (*deallocator)( void *ptr ), size_t (*msize)(void *ptr) ) {
  325. #else
  326. void idGameLocal::Init( void ) {
  327. #endif
  328. // RAVEN END
  329.     const idDict *dict;
  330.     idAAS *aas;
  331.  
  332. #ifndef GAME_DLL
  333.  
  334.     TestGameAPI();
  335.  
  336. #else
  337.  
  338.     mHz = common->GetUserCmdHz();
  339.     msec = common->GetUserCmdMSec();
  340.  
  341. // RAVEN BEGIN
  342. // jsinger: attempt to eliminate cross-DLL allocation issues
  343. #ifdef RV_UNIFIED_ALLOCATOR
  344.     Memory::InitAllocator(allocator, deallocator, msize);
  345. #endif
  346. // RAVEN END
  347.     // initialize idLib
  348.     idLib::Init();
  349.  
  350.     // register static cvars declared in the game
  351.     idCVar::RegisterStaticVars();
  352.  
  353.     // initialize processor specific SIMD
  354.     idSIMD::InitProcessor( "game", com_forceGenericSIMD.GetBool() );
  355.  
  356. #endif
  357. // RAVEN BEGIN
  358. // jsinger: these need to be initialized after the InitAllocator call above in order
  359. //          to avoid crashes when the allocator is used.
  360.     animationLib = new idAnimManager();
  361.     visemeTable100 = new idHashTable<rvViseme>;
  362.     visemeTable66 = new idHashTable<rvViseme>;
  363.     visemeTable33 = new idHashTable<rvViseme>;
  364. // RAVEN END
  365.  
  366.     Printf( "------------- Initializing Game -------------\n" );
  367.     Printf( "gamename: %s\n", GAME_VERSION );
  368.     Printf( "gamedate: %s\n", __DATE__ );
  369.  
  370. // RAVEN BEGIN
  371. // rjohnson: new help system for cvar ui
  372.     idCVarHelp::RegisterStatics();
  373.  
  374. // jsinger: added to support serialization/deserialization of binary decls
  375. #ifdef RV_BINARYDECLS
  376.     idStr prefix="";
  377.     if(cvarSystem->GetCVarBool("com_binaryDeclRead"))
  378.     {
  379.         prefix = "binary/";
  380.     }
  381.     declManager->RegisterDeclType( "model",                DECL_MODELDEF,        idDeclAllocator<idDeclModelDef>, idDeclStreamAllocator<idDeclModelDef> );
  382.     //declManager->RegisterDeclType( "export",            DECL_MODELEXPORT,    idDeclAllocator<idDecl>, idDeclStreamAllocator<idDecl> );
  383.     declManager->RegisterDeclType( "camera",            DECL_CAMERADEF,        idDeclAllocator<idDeclCameraDef>, idDeclStreamAllocator<idDeclCameraDef> );
  384.     declManager->RegisterDeclFolderWrapper( prefix + "def",            ".def",            DECL_ENTITYDEF );
  385.     declManager->RegisterDeclFolderWrapper( prefix + "af",            ".af",            DECL_AF );
  386. #else
  387. // RAVEN END
  388.     // register game specific decl types
  389.     declManager->RegisterDeclType( "model",                DECL_MODELDEF,        idDeclAllocator<idDeclModelDef> );
  390.     declManager->RegisterDeclType( "export",            DECL_MODELEXPORT,    idDeclAllocator<idDecl> );
  391.  
  392. // RAVEN BEGIN
  393. // rjohnson: camera is now contained in a def for frame commands
  394.     declManager->RegisterDeclType( "camera",            DECL_CAMERADEF,        idDeclAllocator<idDeclCameraDef> );
  395. // RAVEN END
  396.  
  397.     // register game specific decl folders
  398. // RAVEN BEGIN
  399. #ifndef RV_SINGLE_DECL_FILE
  400.     declManager->RegisterDeclFolderWrapper( "def",            ".def",            DECL_ENTITYDEF );
  401. // bdube: not used in quake 4
  402. //    declManager->RegisterDeclFolder( "fx",                    ".fx",            DECL_FX );
  403. //    declManager->RegisterDeclFolder( "particles",            ".prt",            DECL_PARTICLE );
  404.     declManager->RegisterDeclFolderWrapper( "af",            ".af",            DECL_AF );
  405. //    declManager->RegisterDeclFolderWrapper( "newpdas",        ".pda",            DECL_PDA );
  406. #else
  407.     if(!cvarSystem->GetCVarBool("com_SingleDeclFile"))
  408.     {
  409.         declManager->RegisterDeclFolderWrapper( "def",            ".def",            DECL_ENTITYDEF );
  410.         declManager->RegisterDeclFolderWrapper( "af",            ".af",            DECL_AF );
  411.     }
  412.     else
  413.     {
  414.         // loads the second set of decls from the file which will contain
  415.         // modles, cameras
  416.         declManager->LoadDeclsFromFile();
  417.         declManager->FinishLoadingDecls();
  418.     }
  419. #endif
  420. #endif  // RV_BINARYDECLS
  421. // RAVEN END
  422.  
  423.     cmdSystem->AddCommand( "listModelDefs", idListDecls_f<DECL_MODELDEF>, CMD_FL_SYSTEM|CMD_FL_GAME, "lists model defs" );
  424.     cmdSystem->AddCommand( "printModelDefs", idPrintDecls_f<DECL_MODELDEF>, CMD_FL_SYSTEM|CMD_FL_GAME, "prints a model def", idCmdSystem::ArgCompletion_Decl<DECL_MODELDEF> );
  425.  
  426.     Clear();
  427.  
  428.     idEvent::Init();
  429. // RAVEN BEGIN
  430. // jnewquist: Register subclasses explicitly so they aren't dead-stripped
  431.     idClass::RegisterClasses();
  432. // RAVEN END
  433.     idClass::Init();
  434.  
  435.     InitConsoleCommands();
  436.     // load default scripts
  437.     program.Startup( SCRIPT_DEFAULT );
  438.     
  439. // RAVEN BEGIN
  440. // bdube: disable id particles
  441. /*
  442.     smokeParticles = new idSmokeParticles;
  443. */
  444. // RAVEN END
  445.  
  446.     // set up the aas
  447. // RAVEN BEGIN
  448. // ddynerman: added false as 2nd parameter, otherwise def will be created
  449.     dict = FindEntityDefDict( "aas_types", false );
  450. // RAVEN END
  451.     if ( !dict ) {
  452.         Error( "Unable to find entityDef for 'aas_types'" );
  453.     }
  454.  
  455.     // allocate space for the aas
  456.     const idKeyValue *kv = dict->MatchPrefix( "type" );
  457.     while( kv != NULL ) {
  458. // RAVEN BEGIN
  459. // jnewquist: Tag scope and callees to track allocations using "new".
  460.         MEM_SCOPED_TAG(tag,MA_AAS);
  461. // RAVEN END
  462.         aas = idAAS::Alloc();
  463.         aasList.Append( aas );
  464.         aasNames.Append( kv->GetValue() );
  465.         kv = dict->MatchPrefix( "type", kv );
  466.     }
  467.  
  468.     gamestate = GAMESTATE_NOMAP;
  469.  
  470.     Printf( "...%d aas types\n", aasList.Num() );
  471.     Printf( "game initialized.\n" );
  472.     Printf( "---------------------------------------------\n" );
  473.     
  474. // RAVEN BEGIN
  475. // bdube: debug stuff
  476.     gameDebug.Init ( );
  477.     gameLogLocal.Init ( );
  478.  
  479. // jscott: facial animation init
  480.     if( !FAS_Init( "annosoft" ) ) {
  481.         common->Warning( "Failed to load viseme file" );
  482.     }
  483.  
  484. // jnewquist: Tag scope and callees to track allocations using "new".
  485.     MEM_SCOPED_TAG(tag,MA_RENDER);
  486. // shouchard:  make sure ban list starts out in a known state
  487.     banListLoaded = false;
  488.     banListChanged = false;
  489.     memset( clientGuids, 0, sizeof( clientGuids ) );
  490. // RAVEN END
  491.  
  492. // RAVEN BEGIN
  493. // mwhitlock: Dynamic memory consolidation
  494. #if defined(_RV_MEM_SYS_SUPPORT)
  495.     for(int i=0;i<MAX_CLIENTS;i++)
  496.     {
  497.         persistentPlayerInfo[i].SetAllocatorHeap(rvGetSysHeap(RV_HEAP_ID_PERMANENT));
  498.     }
  499.     entityHash.SetAllocatorHeap(rvGetSysHeap(RV_HEAP_ID_LEVEL));
  500.     gravityInfo.SetAllocatorHeap(rvGetSysHeap(RV_HEAP_ID_LEVEL));
  501.     scriptObjectProxies.SetAllocatorHeap(rvGetSysHeap(RV_HEAP_ID_LEVEL));
  502.     entityUsageList.SetAllocatorHeap(rvGetSysHeap(RV_HEAP_ID_LEVEL));
  503.     ambientLights.SetAllocatorHeap(rvGetSysHeap(RV_HEAP_ID_LEVEL));
  504.     instances.SetAllocatorHeap(rvGetSysHeap(RV_HEAP_ID_LEVEL));
  505.     clip.SetAllocatorHeap(rvGetSysHeap(RV_HEAP_ID_LEVEL));
  506. #endif
  507. // RAVEN END
  508. }
  509.  
  510. /*
  511. ===========
  512. idGameLocal::Shutdown
  513.  
  514.   shut down the entire game
  515. ============
  516. */
  517. void idGameLocal::Shutdown( void ) {
  518.  
  519.     int        i;
  520.  
  521.     if ( !common ) {
  522.         return;
  523.     }
  524.  
  525. // RAVEN BEGIN
  526. // jscott: FAS
  527.     FAS_Shutdown();
  528. // shouchard:  clean up ban list stuff
  529.     SaveBanList();
  530.     FlushBanList();
  531. // RAVEN END
  532.  
  533.     Printf( "--------------- Game Shutdown ---------------\n" );
  534.  
  535.     mpGame.Shutdown();
  536.  
  537.     MapShutdown();
  538.  
  539.     aasList.DeleteContents( true );
  540.     aasNames.Clear();
  541.  
  542.     idAI::FreeObstacleAvoidanceNodes();
  543.  
  544.     // shutdown the model exporter
  545.     idModelExport::Shutdown();
  546.  
  547.     idEvent::Shutdown();
  548.  
  549.     program.Shutdown();
  550.  
  551.     idClass::Shutdown();
  552.  
  553.     // clear list with forces
  554.     idForce::ClearForceList();
  555.  
  556.     // free the program data
  557.     program.FreeData();
  558.  
  559.     // delete the .map file
  560.     delete mapFile;
  561.     mapFile = NULL;
  562.  
  563.     // free the collision map
  564.     collisionModelManager->FreeMap( GetMapName() );
  565.  
  566. // RAVEN BEGIN
  567. // jscott: free up static objects
  568.     for( i = 0; i < MAX_CLIENTS; i++ ) {
  569.         userInfo[i].Clear();
  570.         persistentPlayerInfo[i].Clear();
  571.     }
  572.  
  573.     for( i = 0; i < entityUsageList.Num(); i++ ) {
  574.         entityUsageList[i].Clear();
  575.     }
  576.  
  577.     serverInfo.Clear();
  578.     persistentLevelInfo.Clear();
  579.     sessionCommand.Clear();
  580.     mapFileName.Clear();
  581.     mapFileNameStripped.Clear();
  582.     entityUsageList.Clear();
  583.  
  584.     newInfo.Clear();
  585.     spawnArgs.Clear();
  586.     shakeSounds.Clear();
  587. // RAVEN END
  588.  
  589.     ShutdownConsoleCommands();
  590.  
  591.     // free memory allocated by class objects
  592.     Clear();
  593.  
  594.     // shut down the animation manager
  595. // RAVEN BEGIN
  596. // jsinger: animationLib changed to a pointer
  597.     animationLib->Shutdown();
  598. // RAVEN END
  599.  
  600. // RAVEN BEGIN
  601. // rjohnson: entity usage stats
  602.     entityUsageList.Clear();
  603. // RAVEN END
  604.  
  605.     Printf( "---------------------------------------------\n" );
  606.  
  607. #ifdef GAME_DLL
  608.  
  609.     // remove auto-completion function pointers pointing into this DLL
  610.     cvarSystem->RemoveFlaggedAutoCompletion( CVAR_GAME );
  611.  
  612.     // enable leak test
  613.     Mem_EnableLeakTest( "game" );
  614.  
  615.     // shutdown idLib
  616.     idLib::ShutDown();
  617.  
  618. #endif
  619. }
  620.  
  621. /*
  622. ===========
  623. idGameLocal::SaveGame
  624.  
  625. save the current player state, level name, and level state
  626. the session may have written some data to the file already
  627. ============
  628. */
  629. // RAVEN BEGIN
  630. // mekberg: added saveTypes
  631. void idGameLocal::SaveGame( idFile *f, saveType_t saveType ) {
  632. // RAVEN END
  633.     int i;
  634.     idEntity *ent;
  635.     idEntity *link;
  636.  
  637.     //remove weapon effect entites from the world
  638.     if(    GetLocalPlayer() && 
  639.         !GetLocalPlayer()->IsInVehicle() &&    
  640.         GetLocalPlayer()->weapon )    {
  641.         
  642.         GetLocalPlayer()->weapon->PreSave();
  643.     }
  644.  
  645.     idSaveGame savegame( f );
  646.  
  647.     if (g_flushSave.GetBool( ) == true ) { 
  648.         // force flushing with each write... for tracking down
  649.         // save game bugs.
  650.         f->ForceFlush();
  651.     }
  652.  
  653.     savegame.WriteBuildNumber( BUILD_NUMBER );
  654.  
  655.     // go through all entities and threads and add them to the object list
  656.     for( i = 0; i < MAX_GENTITIES; i++ ) {
  657.         ent = entities[i];
  658.  
  659.         if ( ent ) {
  660.             if ( ent->GetTeamMaster() && ent->GetTeamMaster() != ent ) {
  661.                 continue;
  662.             }
  663.             for ( link = ent; link != NULL; link = link->GetNextTeamEntity() ) {
  664.                 savegame.AddObject( link );
  665.             }
  666.         }
  667.     }
  668.  
  669.     idList<idThread *> threads;
  670.     threads = idThread::GetThreads();
  671.  
  672.     for( i = 0; i < threads.Num(); i++ ) {
  673.         savegame.AddObject( threads[i] );
  674.     }
  675.  
  676. // RAVEN BEGIN
  677. // abahr: saving clientEntities
  678.     rvClientEntity* clientEnt = NULL;
  679.     for( i = 0; i < MAX_CENTITIES; ++i ) {
  680.         clientEnt = clientEntities[ i ];
  681.         if( !clientEnt ) {
  682.             continue;
  683.         }
  684. //        if( clientEnt->IsType( rvClientEffect::GetClassType() )){
  685. //            continue;
  686. //        }
  687.         savegame.AddObject( clientEnt );
  688.     }
  689. // RAVEN END
  690.  
  691.     // write out complete object list
  692.     savegame.WriteObjectList();
  693.  
  694.     program.Save( &savegame );
  695.  
  696.     savegame.WriteInt( g_skill.GetInteger() );
  697.  
  698.     savegame.WriteDict( &serverInfo );
  699.  
  700.     savegame.WriteInt( numClients );
  701.     for( i = 0; i < numClients; i++ ) {
  702. // RAVEN BEGIN
  703. // mekberg: don't write out userinfo. Grab from cvars
  704. //        savegame.WriteDict( &userInfo[ i ] );
  705. // RAVEN END
  706. //        savegame.WriteUsercmd( usercmds[ i ] );
  707.         savegame.WriteDict( &persistentPlayerInfo[ i ] );
  708.     }
  709.  
  710.     for( i = 0; i < MAX_GENTITIES; i++ ) {
  711.         savegame.WriteObject( entities[ i ] );
  712.         savegame.WriteInt( spawnIds[ i ] );
  713.     }
  714.  
  715. // RAVEN BEGIN
  716. // abahr: more clientEntities saving
  717.     for( i = 0; i < MAX_CENTITIES; i++ ) {
  718. //        if( clientEntities[ i ] && clientEntities[ i ]->IsType( rvClientEffect::GetClassType() )){
  719. //            continue;
  720. //        }
  721.         savegame.WriteObject( clientEntities[ i ] );
  722.         savegame.WriteInt( clientSpawnIds[ i ] );
  723.     }
  724. // RAVEN END
  725.  
  726.     savegame.WriteInt( firstFreeIndex );
  727.     savegame.WriteInt( num_entities );
  728.  
  729.     // enityHash is restored by idEntity::Restore setting the entity name.
  730.  
  731.     savegame.WriteObject( world );
  732.  
  733.     savegame.WriteInt( spawnedEntities.Num() );
  734.     for( ent = spawnedEntities.Next(); ent != NULL; ent = ent->spawnNode.Next() ) {
  735.         savegame.WriteObject( ent );
  736.     }
  737.  
  738. // RAVEN BEGIN
  739. // abahr: saving scriptObject proxies
  740.     savegame.WriteInt( scriptObjectProxies.Num() );
  741.     for( i = 0; i < scriptObjectProxies.Num(); ++i ) {
  742.         scriptObjectProxies[i].Save( &savegame );
  743.     }
  744. // abahr: save out client stuff
  745.     savegame.WriteInt( clientSpawnedEntities.Num() );
  746.     for( clientEnt = clientSpawnedEntities.Next(); clientEnt != NULL; clientEnt = clientEnt->spawnNode.Next() ) {
  747.         savegame.WriteObject( clientEnt );
  748.     }
  749. // RAVEN END
  750.  
  751.     savegame.WriteInt( activeEntities.Num() );
  752.     for( ent = activeEntities.Next(); ent != NULL; ent = ent->activeNode.Next() ) {
  753.         savegame.WriteObject( ent );
  754.     }
  755.  
  756.     savegame.WriteInt( numEntitiesToDeactivate );
  757.     savegame.WriteBool( sortPushers );
  758.     savegame.WriteBool( sortTeamMasters );
  759.     savegame.WriteDict( &persistentLevelInfo );
  760.  
  761.     for( i = 0; i < MAX_GLOBAL_SHADER_PARMS; i++ ) {
  762.         savegame.WriteFloat( globalShaderParms[ i ] );
  763.     }
  764.  
  765.     savegame.WriteInt( random.GetSeed() );
  766.     savegame.WriteObject( frameCommandThread );
  767.  
  768.     // clip
  769.     // push
  770.     // pvs
  771.  
  772.     testmodel = NULL;
  773. // RAVEN BEGIN
  774. // bdube: no test fx
  775. //    testFx = NULL;
  776. // RAVEN END
  777.  
  778.     savegame.WriteString( sessionCommand );
  779. // RAVEN BEGIN
  780. // nmckenzie: Let the AI system save itself too.
  781.     aiManager.Save( &savegame );
  782. // RAVEN END
  783.  
  784.     // FIXME: save smoke particles
  785.  
  786.     savegame.WriteInt( cinematicSkipTime );
  787.     savegame.WriteInt( cinematicStopTime );
  788.     savegame.WriteInt( cinematicMaxSkipTime );
  789.     savegame.WriteBool( inCinematic );
  790.     savegame.WriteBool( skipCinematic );
  791.  
  792.     savegame.WriteBool( isMultiplayer );
  793.     savegame.WriteInt( gameType );
  794.  
  795.     savegame.WriteInt( framenum );
  796.     savegame.WriteInt( previousTime );
  797.     savegame.WriteInt( time );
  798.  
  799.     savegame.WriteInt( vacuumAreaNum );
  800.  
  801.     savegame.WriteInt( entityDefBits );
  802.     savegame.WriteBool( isServer );
  803.     savegame.WriteBool( isClient );
  804. // RAVEN BEGIN
  805.     savegame.WriteBool( isListenServer );
  806. // RAVEN END
  807.  
  808.     savegame.WriteInt( localClientNum );
  809.  
  810.     // snapshotEntities is used for multiplayer only
  811.  
  812.     savegame.WriteInt( realClientTime );
  813.     savegame.WriteBool( isNewFrame );
  814.  
  815.     savegame.WriteBool( mapCycleLoaded );
  816.     savegame.WriteInt( spawnCount );
  817.  
  818.     if ( !locationEntities ) {
  819.         savegame.WriteInt( 0 );
  820.     } else {
  821.         savegame.WriteInt( gameRenderWorld->NumAreas() );
  822.         for( i = 0; i < gameRenderWorld->NumAreas(); i++ ) {
  823.             savegame.WriteObject( locationEntities[ i ] );
  824.         }
  825.     }
  826.  
  827.     savegame.WriteObject( camera );
  828.  
  829.     savegame.WriteMaterial( globalMaterial );
  830.  
  831. // RAVEN BEGIN
  832. // bdube: added
  833.     lastAIAlertActor.Save( &savegame );
  834.     lastAIAlertEntity.Save( &savegame );
  835.     savegame.WriteInt( lastAIAlertEntityTime );
  836.     savegame.WriteInt( lastAIAlertActorTime );
  837. // RAVEN END
  838.  
  839.     savegame.WriteDict( &spawnArgs );
  840.  
  841.     savegame.WriteInt( playerPVS.i );
  842.     savegame.WriteInt( playerPVS.h );
  843.     savegame.WriteInt( playerConnectedAreas.i );
  844.     savegame.WriteInt( playerConnectedAreas.h );
  845.  
  846.     savegame.WriteVec3( gravity );
  847.  
  848.     // gamestate
  849.  
  850.     savegame.WriteBool( influenceActive );
  851.     savegame.WriteInt( nextGibTime );
  852.  
  853.     // spawnSpots
  854.     // initialSpots
  855.     // currentInitialSpot
  856.     // newInfo
  857.     // makingBuild
  858.     // shakeSounds
  859.  
  860.     // write out pending events
  861.     idEvent::Save( &savegame );
  862.  
  863.     savegame.Close();
  864.  
  865. // RAVEN BEGIN
  866. // mekberg: added saveTypes and wrapped saveMessage
  867.     if ( saveType != ST_AUTO && GetLocalPlayer() && GetLocalPlayer()->GetHud() ) {
  868.         GetLocalPlayer()->SaveMessage();
  869.     }
  870.  
  871. // jshepard: resume weapon operation
  872.     if(    GetLocalPlayer() && 
  873.         !GetLocalPlayer()->IsInVehicle() &&    
  874.         GetLocalPlayer()->weapon )    {
  875.         GetLocalPlayer()->weapon->PostSave();
  876.     }
  877. // RAVEN END
  878. }
  879.  
  880. /*
  881. ===========
  882. idGameLocal::GetPersistentPlayerInfo
  883. ============
  884. */
  885. const idDict &idGameLocal::GetPersistentPlayerInfo( int clientNum ) {
  886.     idEntity    *ent;
  887.  
  888.     persistentPlayerInfo[ clientNum ].Clear();
  889.     ent = entities[ clientNum ];
  890. // RAVEN BEGIN
  891. // jnewquist: Use accessor for static class type 
  892.     if ( ent && ent->IsType( idPlayer::GetClassType() ) ) {
  893. // RAVEN END
  894.         static_cast<idPlayer *>(ent)->SavePersistantInfo();
  895.     }
  896.  
  897.     return persistentPlayerInfo[ clientNum ];
  898. }
  899.  
  900. /*
  901. ===========
  902. idGameLocal::SetPersistentPlayerInfo
  903. ============
  904. */
  905. void idGameLocal::SetPersistentPlayerInfo( int clientNum, const idDict &playerInfo ) {
  906.     TIME_THIS_SCOPE( __FUNCLINE__);
  907.     persistentPlayerInfo[ clientNum ] = playerInfo;
  908. }
  909.  
  910. /*
  911. ============
  912. idGameLocal::Printf
  913. ============
  914. */
  915. void idGameLocal::Printf( const char *fmt, ... ) const {
  916.     va_list        argptr;
  917.     char        text[MAX_STRING_CHARS];
  918.  
  919.     va_start( argptr, fmt );
  920.     idStr::vsnPrintf( text, sizeof( text ), fmt, argptr );
  921.     va_end( argptr );
  922.  
  923.     common->Printf( "%s", text );
  924. }
  925.  
  926. /*
  927. ============
  928. idGameLocal::DPrintf
  929. ============
  930. */
  931. void idGameLocal::DPrintf( const char *fmt, ... ) const {
  932.     va_list        argptr;
  933.     char        text[MAX_STRING_CHARS];
  934.  
  935.     if ( !developer.GetBool() ) {
  936.         return;
  937.     }
  938.  
  939.     va_start( argptr, fmt );
  940.     idStr::vsnPrintf( text, sizeof( text ), fmt, argptr );
  941.     va_end( argptr );
  942.  
  943.     common->Printf( "%s", text );
  944. }
  945.  
  946. /*
  947. ============
  948. idGameLocal::Warning
  949. ============
  950. */
  951. void idGameLocal::Warning( const char *fmt, ... ) const {
  952.     va_list        argptr;
  953.     char        text[MAX_STRING_CHARS];
  954.     idThread *    thread;
  955.  
  956.     va_start( argptr, fmt );
  957.     idStr::vsnPrintf( text, sizeof( text ), fmt, argptr );
  958.     va_end( argptr );
  959.  
  960.     thread = idThread::CurrentThread();
  961. // MERGE:FIXME - the following now gets into a recursive stack overflow when enemies are killed.  Not sure why.
  962. // nmckenzie:
  963. /*    if ( thread ) {
  964.         thread->Warning( "%s", text );
  965.     } else {*/
  966.         common->Warning( "%s", text );
  967. //    }
  968. }
  969.  
  970. /*
  971. ============
  972. idGameLocal::DWarning
  973. ============
  974. */
  975. void idGameLocal::DWarning( const char *fmt, ... ) const {
  976.     va_list        argptr;
  977.     char        text[MAX_STRING_CHARS];
  978.     idThread *    thread;
  979.  
  980.     if ( !developer.GetBool() ) {
  981.         return;
  982.     }
  983.  
  984.     va_start( argptr, fmt );
  985.     idStr::vsnPrintf( text, sizeof( text ), fmt, argptr );
  986.     va_end( argptr );
  987.  
  988.     thread = idThread::CurrentThread();
  989.     if ( thread ) {
  990.         thread->Warning( "%s", text );
  991.     } else {
  992.         common->DWarning( "%s", text );
  993.     }
  994. }
  995.  
  996. /*
  997. ============
  998. idGameLocal::Error
  999. ============
  1000. */
  1001. void idGameLocal::Error( const char *fmt, ... ) const {
  1002.     va_list        argptr;
  1003.     char        text[MAX_STRING_CHARS];
  1004.     idThread *    thread;
  1005.  
  1006.     va_start( argptr, fmt );
  1007.     idStr::vsnPrintf( text, sizeof( text ), fmt, argptr );
  1008.     va_end( argptr );
  1009.  
  1010. // RAVEN BEGIN
  1011. // scork: some model errors arrive here during validation which kills the whole process, so let's just warn about them instead...
  1012.     if ( common->DoingDeclValidation() ) {
  1013.         this->Warning( "%s", text );
  1014.         return;
  1015.     }
  1016. // RAVEN END
  1017.  
  1018.     thread = idThread::CurrentThread();
  1019.     if ( thread ) {
  1020.         thread->Error( "%s", text );
  1021.     } else {
  1022.         common->Error( "%s", text );
  1023.     }
  1024. }
  1025.  
  1026. /*
  1027. ===========
  1028. idGameLocal::SetLocalClient
  1029. ============
  1030. */
  1031. void idGameLocal::SetLocalClient( int clientNum ) {
  1032.     localClientNum = clientNum;
  1033. }
  1034.  
  1035. /*
  1036. ===========
  1037. idGameLocal::SetUserInfo
  1038. ============
  1039. */
  1040. const idDict* idGameLocal::SetUserInfo( int clientNum, const idDict &userInfo, bool isClient ) {
  1041.     
  1042.     TIME_THIS_SCOPE( __FUNCLINE__);
  1043.     
  1044.     int i;
  1045.     bool modifiedInfo = false;
  1046.  
  1047.     this->isClient = isClient;
  1048.  
  1049.     if ( clientNum >= 0 && clientNum < MAX_CLIENTS ) {
  1050.         idGameLocal::userInfo[ clientNum ] = userInfo;
  1051.  
  1052.         // server sanity
  1053.         if ( !isClient ) {
  1054.  
  1055.             // don't let numeric nicknames, it can be exploited to go around kick and ban commands from the server
  1056.             if ( idStr::IsNumeric( this->userInfo[ clientNum ].GetString( "ui_name" ) ) ) {
  1057. #if UI_DEBUG
  1058.                 common->Printf( "SetUserInfo: client %d changed name from %s to %s_\n", 
  1059.                     clientNum, idGameLocal::userInfo[ clientNum ].GetString( "ui_name" ), idGameLocal::userInfo[ clientNum ].GetString( "ui_name" ) );
  1060. #endif
  1061.                 idGameLocal::userInfo[ clientNum ].Set( "ui_name", va( "%s_", idGameLocal::userInfo[ clientNum ].GetString( "ui_name" ) ) );
  1062.                 modifiedInfo = true;
  1063.             }
  1064.         
  1065.             // don't allow dupe nicknames
  1066.             for ( i = 0; i < numClients; i++ ) {
  1067.                 if ( i == clientNum ) {
  1068.                     continue;
  1069.                 }
  1070. // RAVEN BEGIN
  1071. // jnewquist: Use accessor for static class type 
  1072.                 if ( entities[ i ] && entities[ i ]->IsType( idPlayer::GetClassType() ) ) {
  1073. // RAVEN END
  1074.                     if ( !idStr::Icmp( idGameLocal::userInfo[ clientNum ].GetString( "ui_name" ), idGameLocal::userInfo[ i ].GetString( "ui_name" ) ) ) {
  1075. #if UI_DEBUG
  1076.                         common->Printf( "SetUserInfo: client %d changed name from %s to %s_ because of client %d\n", 
  1077.                             clientNum, idGameLocal::userInfo[ clientNum ].GetString( "ui_name" ), idGameLocal::userInfo[ clientNum ].GetString( "ui_name" ), i );
  1078. #endif
  1079.                         idGameLocal::userInfo[ clientNum ].Set( "ui_name", va( "%s_", idGameLocal::userInfo[ clientNum ].GetString( "ui_name" ) ) );
  1080.                         modifiedInfo = true;
  1081.                         i = -1;    // rescan
  1082.                         continue;
  1083.                     }
  1084.                 }
  1085.             }
  1086.         }
  1087.  
  1088. // RAVEN BEGIN
  1089. // jnewquist: Use accessor for static class type 
  1090.         if ( entities[ clientNum ] && entities[ clientNum ]->IsType( idPlayer::GetClassType() ) ) {
  1091. // RAVEN END
  1092.             modifiedInfo |= static_cast<idPlayer *>( entities[ clientNum ] )->UserInfoChanged();
  1093.         }
  1094.  
  1095.         if ( !isClient ) {
  1096.             // now mark this client in game
  1097.             mpGame.EnterGame( clientNum );
  1098.         }
  1099.     }
  1100.  
  1101.     if ( modifiedInfo ) {
  1102.         newInfo = idGameLocal::userInfo[ clientNum ];
  1103.         return &newInfo;
  1104.     }
  1105.     return NULL;
  1106. }
  1107.  
  1108. /*
  1109. ===========
  1110. idGameLocal::GetUserInfo
  1111. ============
  1112. */
  1113. const idDict* idGameLocal::GetUserInfo( int clientNum ) {
  1114. // RAVEN BEGIN
  1115. // jnewquist: Use accessor for static class type 
  1116.     if ( entities[ clientNum ] && entities[ clientNum ]->IsType( idPlayer::GetClassType() ) ) {
  1117. // RAVEN END
  1118.         return &userInfo[ clientNum ];
  1119.     }
  1120.     return NULL;
  1121. }
  1122.  
  1123. /*
  1124. ===========
  1125. idGameLocal::SetServerInfo
  1126. ============
  1127. */
  1128. void idGameLocal::SetServerInfo( const idDict &_serverInfo ) {
  1129.     TIME_THIS_SCOPE( __FUNCLINE__);
  1130.     
  1131.     idBitMsg    outMsg;
  1132.     byte        msgBuf[MAX_GAME_MESSAGE_SIZE];
  1133.     bool timeLimitChanged = false;
  1134.  
  1135. // RAVEN BEGIN
  1136. // mekberg: clear announcer and reschedule time announcements
  1137.     if ( ( isClient || isListenServer ) && mpGame.GetGameState( ) && mpGame.GetGameState( )->GetMPGameState( ) == GAMEON &&
  1138.         serverInfo.GetInt( "si_timelimit" ) != _serverInfo.GetInt( "si_timelimit" ) ) {
  1139.             timeLimitChanged = true;
  1140.     }
  1141.  
  1142.     serverInfo = _serverInfo;
  1143.  
  1144.     if ( timeLimitChanged ) {
  1145.         mpGame.ClearAnnouncerSounds( );
  1146.         mpGame.ScheduleTimeAnnouncements( );
  1147.     }
  1148. // RAVEN END
  1149.  
  1150.     if ( isServer ) {
  1151.         // Let our clients know the server info changed
  1152.         outMsg.Init( msgBuf, sizeof( msgBuf ) );
  1153.         outMsg.WriteByte( GAME_RELIABLE_MESSAGE_SERVERINFO );
  1154.         outMsg.WriteDeltaDict( gameLocal.serverInfo, NULL );
  1155.         networkSystem->ServerSendReliableMessage( -1, outMsg );
  1156.     }
  1157. }
  1158.  
  1159. /*
  1160. ===================
  1161. idGameLocal::LoadMap
  1162.  
  1163. Initializes all map variables common to both save games and spawned games.
  1164. ===================
  1165. */
  1166. void idGameLocal::LoadMap( const char *mapName, int randseed ) {
  1167.     int i;
  1168. // RAVEN BEGIN
  1169. // jnewquist: Tag scope and callees to track allocations using "new".
  1170.     MEM_SCOPED_TAG(tag,MA_PARSER);
  1171. // RAVEN END
  1172.     bool sameMap = (mapFile && idStr::Icmp(mapFile->GetName(), mapName) == 0);
  1173.  
  1174.     networkSystem->SetLoadingText( mapName );
  1175.  
  1176.     InitAsyncNetwork();
  1177.  
  1178.     // these can changed based upon sp / mp
  1179.     mHz = common->GetUserCmdHz();
  1180.     msec = common->GetUserCmdMSec();
  1181.  
  1182.     if ( !sameMap || ( mapFile && mapFile->NeedsReload() ) ) {
  1183.         // load the .map file
  1184.         if ( mapFile ) {
  1185.             delete mapFile;
  1186.         }
  1187.         mapFile = new idMapFile;
  1188.         if ( !mapFile->Parse( idStr( mapName ) + ".map" ) ) {
  1189.             delete mapFile;
  1190.             mapFile = NULL;
  1191.             Error( "Couldn't load %s", mapName );
  1192.         }
  1193. // RAVEN BEGIN
  1194. // rjohnson: added resolve for handling func_groups and other aspects.  Before, radiant would do this processing on a map destroying the original data
  1195.         mapFile->Resolve();
  1196. // RAVEN END
  1197.     }
  1198.     mapFileName = mapFile->GetName();
  1199.     
  1200.     assert(!idStr::Cmp(mapFileName, mapFile->GetName()));
  1201.     
  1202. // RAVEN BEGIN
  1203. // rjohnson: entity usage stats
  1204.     mapFileNameStripped = mapFileName;
  1205.     mapFileNameStripped.StripFileExtension();
  1206.     mapFileNameStripped.StripPath();
  1207.  
  1208.     const char*    entityFilter;
  1209.  
  1210.     gameLocal.serverInfo.GetString( "si_entityFilter", "", &entityFilter );
  1211.     if ( entityFilter && *entityFilter ) {
  1212.         mapFileNameStripped += " ";
  1213.         mapFileNameStripped += entityFilter;
  1214.     }
  1215. // RAVEN END
  1216.  
  1217.     // load the collision map
  1218.     networkSystem->SetLoadingText( common->GetLocalizedString( "#str_107668" ) );
  1219.     collisionModelManager->LoadMap( mapFile, false );
  1220.  
  1221.     numClients = 0;
  1222.  
  1223.     // initialize all entities for this game
  1224.     memset( entities, 0, sizeof( entities ) );
  1225.     usercmds = NULL;
  1226.     memset( spawnIds, -1, sizeof( spawnIds ) );
  1227.     spawnCount = INITIAL_SPAWN_COUNT;
  1228.     
  1229.     spawnedEntities.Clear();
  1230.     activeEntities.Clear();
  1231.     numEntitiesToDeactivate = 0;
  1232.     sortTeamMasters = false;
  1233.     sortPushers = false;
  1234.     lastGUIEnt = NULL;
  1235.     lastGUI = 0;
  1236.  
  1237. // RAVEN BEGIN
  1238. // bdube: client entities
  1239.     clientSpawnCount = INITIAL_SPAWN_COUNT;
  1240.     clientSpawnedEntities.Clear ( );
  1241.     memset ( clientSpawnIds, -1, sizeof(clientSpawnIds ) );
  1242.     memset ( clientEntities, 0, sizeof(clientEntities) );
  1243.     firstFreeClientIndex = 0;
  1244. // RAVEN END
  1245.  
  1246.     globalMaterial = NULL;
  1247.  
  1248.     memset( globalShaderParms, 0, sizeof( globalShaderParms ) );
  1249.  
  1250.     // always leave room for the max number of clients,
  1251.     // even if they aren't all used, so numbers inside that
  1252.     // range are NEVER anything but clients
  1253.     num_entities    = MAX_CLIENTS;
  1254.     firstFreeIndex    = MAX_CLIENTS;
  1255.  
  1256.     // reset the random number generator.
  1257.     random.SetSeed( isMultiplayer ? randseed : 0 );
  1258.  
  1259.     camera            = NULL;
  1260.     world            = NULL;
  1261.     testmodel        = NULL;
  1262. // RAVEN BEGIN
  1263. // bdube: not using id effects
  1264. //    testFx            = NULL;
  1265. // RAVEN END
  1266.  
  1267. // RAVEN BEGIN
  1268. // bdube: merged
  1269.     lastAIAlertEntity = NULL;
  1270.     lastAIAlertEntityTime = 0;
  1271.     lastAIAlertActor = NULL;
  1272.     lastAIAlertActorTime = 0;
  1273. // RAVEN END
  1274.     
  1275.     previousTime    = 0;
  1276.     time            = 0;
  1277.     framenum        = 0;
  1278.     sessionCommand = "";
  1279.     nextGibTime        = 0;
  1280.  
  1281.     vacuumAreaNum = -1;        // if an info_vacuum is spawned, it will set this
  1282.  
  1283. // RAVEN BEGIN
  1284. // abahr
  1285.     gravityInfo.Clear();
  1286.     scriptObjectProxies.Clear();
  1287. // RAVEN END
  1288.  
  1289.     if ( !editEntities ) {
  1290.         editEntities = new idEditEntities;
  1291.     }
  1292.  
  1293.     if( gameLocal.isMultiplayer ) {
  1294.         gravity.Set( 0, 0, -g_mp_gravity.GetFloat() );
  1295.     } else {
  1296.         gravity.Set( 0, 0, -g_gravity.GetFloat() );
  1297.     }
  1298.  
  1299.     spawnArgs.Clear();
  1300.  
  1301. // RAVEN BEGIN
  1302. // nmckenzie:
  1303.     //make sure we clear all reachabilities we marked as blocked!
  1304.     aiManager.UnMarkAllReachBlocked();
  1305.     aiManager.Clear();
  1306. // RAVEN END
  1307.  
  1308.     skipCinematic = false;
  1309.     inCinematic = false;
  1310.     cinematicSkipTime = 0;
  1311.     cinematicStopTime = 0;
  1312.     cinematicMaxSkipTime = 0;
  1313.  
  1314. // RAVEN BEGIN
  1315. // ddynerman: main world instance
  1316.     PACIFIER_UPDATE;
  1317.     AddInstance( 0, true );
  1318.     assert( instances.Num() == 1 && instances[ 0 ]->GetInstanceID() == 0 );
  1319. // RAVEN END
  1320.     pvs.Init();
  1321. // RAVEN BEGIN
  1322. // mwhitlock: Xenon texture streaming
  1323. #if defined(_XENON)
  1324.     // Experimental use of game's PVS for reducing amount of stuff streamed. Will
  1325.     // do this a bit more cleanly if I decide to keep this.
  1326.     extern idPVS* pvsForStreaming;
  1327.     pvsForStreaming=&pvs;
  1328. #endif
  1329. // RAVEN END
  1330.  
  1331.     playerPVS.i = -1;
  1332.     playerConnectedAreas.i = -1;
  1333.  
  1334.     // load navigation system for all the different monster sizes
  1335.     for( i = 0; i < aasNames.Num(); i++ ) {
  1336.         aasList[ i ]->Init( idStr( mapFileName ).SetFileExtension( aasNames[ i ] ).c_str(), mapFile->GetGeometryCRC() );
  1337.     }
  1338.  
  1339. // RAVEN BEGIN
  1340. // cdr: Obstacle Avoidance
  1341.     AI_MoveInitialize();
  1342. // RAVEN END
  1343.  
  1344.  
  1345.  
  1346. // RAVEN BEGIN
  1347. // bdube: not using smoke particles
  1348.     // clear the smoke particle free list
  1349. //    smokeParticles->Init();
  1350. // RAVEN END
  1351.     FindEntityDef( "preCacheExtras", false );
  1352.  
  1353.     if ( !sameMap ) {
  1354.         mapFile->RemovePrimitiveData();
  1355.     }
  1356.  
  1357. // RAVEN BEGIN
  1358. // ddynerman: ambient light list
  1359.     ambientLights.Clear();
  1360. // RAVEN END
  1361. }
  1362.  
  1363. /*
  1364. ===================
  1365. idGameLocal::LocalMapRestart
  1366. ===================
  1367. */
  1368. void idGameLocal::LocalMapRestart( int instance ) {
  1369.     int i, latchSpawnCount;
  1370.  
  1371.     Printf( "----------- Game Map Restart (%s) ------------\n", instance == -1 ? "all instances" : va( "instance %d", instance ) );
  1372.  
  1373.     // client always respawns everything, so make sure it picks up the right map entities
  1374.     if( instance == -1 || isClient ) {
  1375.         memset( isMapEntity, 0, sizeof(bool) * MAX_GENTITIES );
  1376.     } else {
  1377.         assert( instance >= 0 && instance < instances.Num() );
  1378.  
  1379.         for( int i = 0; i < instances[ instance ]->GetNumMapEntities(); i++ ) {
  1380.             if( instances[ instance ]->GetMapEntityNumber( i ) >= 0 && instances[ instance ]->GetMapEntityNumber( i ) < MAX_GENTITIES ) {
  1381.                 isMapEntity[ instances[ instance ]->GetMapEntityNumber( i ) ] = false;
  1382.             }
  1383.         }
  1384.     }
  1385.  
  1386. // RAVEN BEGIN
  1387. // jnewquist: Controller rumble
  1388. #ifdef _XBOX
  1389.     extern void IN_KillRumble(void);
  1390.     IN_KillRumble();
  1391. #endif
  1392. // RAVEN END
  1393.  
  1394.     gamestate = GAMESTATE_SHUTDOWN;
  1395.  
  1396.     for ( i = 0; i < MAX_CLIENTS; i++ ) {
  1397. // RAVEN BEGIN
  1398. // jnewquist: Use accessor for static class type 
  1399.         if ( entities[ i ] && entities[ i ]->IsType( idPlayer::GetClassType() ) && (isClient || instance == -1 || entities[ i ]->GetInstance() == instance ) ) {
  1400. // RAVEN END
  1401.             static_cast< idPlayer * >( entities[ i ] )->PrepareForRestart();
  1402.         }
  1403.     }
  1404.  
  1405.     eventQueue.Shutdown();
  1406.  
  1407.     MapClear( false, instance );
  1408.  
  1409.     // clear the sound system
  1410.     soundSystem->StopAllSounds( SOUNDWORLD_GAME );
  1411.  
  1412.     // clear icons
  1413.     iconManager->Shutdown();
  1414.  
  1415.     // the spawnCount is reset to zero temporarily to spawn the map entities with the same spawnId
  1416.     // if we don't do that, network clients are confused and don't show any map entities
  1417.     latchSpawnCount = spawnCount;
  1418.     spawnCount = INITIAL_SPAWN_COUNT;
  1419.  
  1420.     gamestate = GAMESTATE_STARTUP;
  1421.  
  1422.     program.Restart();
  1423.  
  1424.     InitScriptForMap();
  1425.  
  1426.     MapPopulate( instance );
  1427.  
  1428.     // once the map is populated, set the spawnCount back to where it was so we don't risk any collision
  1429.     // (note that if there are no players in the game, we could just leave it at it's current value)
  1430.     spawnCount = latchSpawnCount;
  1431.  
  1432.     // setup the client entities again
  1433.     for ( i = 0; i < MAX_CLIENTS; i++ ) {
  1434. // RAVEN BEGIN
  1435. // jnewquist: Use accessor for static class type 
  1436.         if ( entities[ i ] && entities[ i ]->IsType( idPlayer::GetClassType() ) && (isClient || instance == -1 || entities[ i ]->GetInstance() == instance ) ) {
  1437. // RAVEN END
  1438.             static_cast< idPlayer * >( entities[ i ] )->Restart();
  1439.         }
  1440.     }
  1441.  
  1442.     gamestate = GAMESTATE_ACTIVE;
  1443.  
  1444. // RAVEN BEGIN
  1445. // shouchard:  profiling
  1446.     if ( cvarSystem->GetCVarBool( "net_debugFrameTime" ) ) {
  1447.         cvarSystem->SetCVarBool( "net_debugStartLevel", true );
  1448.     }
  1449. // RAVEN END
  1450.  
  1451.     Printf( "--------------------------------------\n" );
  1452. }
  1453.  
  1454. /*
  1455. ===================
  1456. idGameLocal::MapRestart
  1457. ===================
  1458. */
  1459. void idGameLocal::MapRestart( int instance ) {
  1460.     idBitMsg    outMsg;
  1461.     byte        msgBuf[MAX_GAME_MESSAGE_SIZE];
  1462.     idDict        newInfo;
  1463.     int            i;
  1464.     const idKeyValue *keyval, *keyval2;
  1465.  
  1466.     if ( isClient ) {
  1467. // RAVEN BEGIN
  1468. // ddynerman: check if gametype changed
  1469.         SetGameType();
  1470. // RAVEN END
  1471.         LocalMapRestart( instance );
  1472.     } else {
  1473.         newInfo = *cvarSystem->MoveCVarsToDict( CVAR_SERVERINFO );
  1474.         // this has to be after the cvars are moved to the dict
  1475.         for ( i = 0; i < newInfo.GetNumKeyVals(); i++ ) {
  1476.  
  1477.             keyval = newInfo.GetKeyVal( i );
  1478.             keyval2 = serverInfo.FindKey( keyval->GetKey() );
  1479.             if ( !keyval2 ) {
  1480.                 break;
  1481.             }
  1482.             // a select set of si_ changes will cause a full restart of the server
  1483.             if ( keyval->GetValue().Icmp( keyval2->GetValue() ) &&
  1484.                 ( !keyval->GetKey().Icmp( "si_pure" ) || !keyval->GetKey().Icmp( "si_map" ) ) ) {
  1485.                 break;
  1486.             }
  1487. //RAVEN BEGIN
  1488.             //asalmon: need to restart if the game type has changed but the map has not cause someone could be connecting
  1489.             if(  keyval->GetValue().Icmp( keyval2->GetValue() ) && (!keyval->GetKey().Icmp("si_gametype")))
  1490.             {
  1491.                 break;
  1492.             }
  1493. //RAVEN END
  1494.         }
  1495.         cmdSystem->BufferCommandText( CMD_EXEC_NOW, "rescanSI" );
  1496.  
  1497. // RAVEN BEGIN
  1498. // ddynerman: check if gametype changed
  1499.         SetGameType();
  1500. // RAVEN END
  1501.  
  1502.         if ( i != newInfo.GetNumKeyVals() ) {
  1503.             cmdSystem->BufferCommandText( CMD_EXEC_APPEND, "nextMap" );
  1504.         } else {
  1505.             outMsg.Init( msgBuf, sizeof( msgBuf ) );
  1506.             outMsg.WriteByte( GAME_RELIABLE_MESSAGE_RESTART );
  1507.             outMsg.WriteBits( 1, 1 );
  1508.             outMsg.WriteDeltaDict( serverInfo, NULL );
  1509.             networkSystem->ServerSendReliableMessage( -1, outMsg );
  1510.  
  1511.             LocalMapRestart( instance );
  1512.             mpGame.MapRestart();
  1513.         }
  1514.     }
  1515. }
  1516.  
  1517. /*
  1518. ===================
  1519. idGameLocal::VerifyServerSettings_f
  1520. ===================
  1521. */
  1522. void idGameLocal::VerifyServerSettings_f( const idCmdArgs &args ) {
  1523.     gameLocal.mpGame.PickMap( si_gameType.GetString() );
  1524. }
  1525.  
  1526. /*
  1527. ===================
  1528. idGameLocal::MapRestart_f
  1529. ===================
  1530. */
  1531. void idGameLocal::MapRestart_f( const idCmdArgs &args ) {
  1532.     if ( !gameLocal.isMultiplayer || gameLocal.isClient ) {
  1533.         common->Printf( "server is not running - use spawnServer\n" );
  1534.         cmdSystem->BufferCommandText( CMD_EXEC_APPEND, "spawnServer\n" );
  1535.         return;
  1536.     }
  1537.     
  1538.     int instance = -1;
  1539.     if( args.Argc() > 1 ) {
  1540.         instance = atoi( args.Args( 1 ) );
  1541.         if( instance < 0 || instance >= gameLocal.GetNumInstances() ) {
  1542.             common->Warning( "idGameLocal::MapRestart_f() - Invalid instance '%d' specified\n", instance );
  1543.             return;
  1544.         }
  1545.         gameLocal.LocalMapRestart( instance );
  1546.         return;
  1547.     }
  1548.  
  1549.     gameLocal.MapRestart( instance );
  1550. }
  1551.  
  1552. /*
  1553. ===================
  1554. idGameLocal::NextMap
  1555. ===================
  1556. */
  1557. bool idGameLocal::NextMap( void ) {
  1558.     const function_t    *func;
  1559.     idThread            *thread;
  1560.     idDict                newInfo;
  1561.     const idKeyValue    *keyval, *keyval2;
  1562.     int                    i;
  1563.     const char            *mapCycleList, *currentMap;
  1564.  
  1565. //RAVEN BEGIN
  1566. //asalmon: pick another map on Xenon
  1567. #ifdef _XENON
  1568.     //Live()->PickMap();
  1569.     return true;
  1570. #endif
  1571. //RAVEN END
  1572.  
  1573. // RAVEN BEGIN
  1574. // rjohnson: traditional map cycle
  1575. //        si_mapCycle "mp/q4dm4;mp/q4dm5;mp/q4dm6"
  1576.     mapCycleList = si_mapCycle.GetString();
  1577.     if ( mapCycleList && strlen( mapCycleList ) ) {
  1578.         idLexer src;
  1579.         idToken token, firstFound;
  1580.         int        numMaps = 0;
  1581.         bool    foundMap = false;
  1582.  
  1583.         src.FreeSource();
  1584.         src.SetFlags( LEXFL_NOFATALERRORS | LEXFL_ALLOWPATHNAMES | LEXFL_ALLOWMULTICHARLITERALS | LEXFL_ALLOWBACKSLASHSTRINGCONCAT );
  1585.         src.LoadMemory( mapCycleList, strlen( mapCycleList ), "idGameLocal::NextMap" );
  1586.         if ( src.IsLoaded() ) {
  1587.  
  1588.             currentMap = si_map.GetString();
  1589.             while( src.ReadToken( &token ) ) {
  1590.                 if ( token == ";" ) {
  1591.                     continue;
  1592.                 }
  1593.                 numMaps++;
  1594.  
  1595.                 if ( numMaps == 1 ) {
  1596.                     // guarantee that we use a map no matter what ( or when we wrap )
  1597.                     firstFound = token;
  1598.                 }
  1599.                 if ( foundMap ) {
  1600.                     firstFound = token;
  1601.                     break;
  1602.                 }
  1603.                 
  1604.                 if ( idStr::Icmp( token, currentMap ) == 0 ) {
  1605.                     foundMap = true;
  1606.                 }
  1607.             }
  1608.  
  1609.             if ( firstFound != "" ) {
  1610.                 si_map.SetString( firstFound );
  1611.                 return true;
  1612.             }
  1613.         }
  1614.  
  1615.         return false;
  1616.     }
  1617. // RAVEN END
  1618.  
  1619.     if ( !g_mapCycle.GetString()[0] ) {
  1620.         Printf( common->GetLocalizedString( "#str_104294" ) );
  1621.         return false;
  1622.     }
  1623.     if ( fileSystem->ReadFile( g_mapCycle.GetString(), NULL, NULL ) < 0 ) {
  1624.         if ( fileSystem->ReadFile( va( "%s.scriptcfg", g_mapCycle.GetString() ), NULL, NULL ) < 0 ) {
  1625.             Printf( "map cycle script '%s': not found\n", g_mapCycle.GetString() );
  1626.             return false;
  1627.         } else {
  1628.             g_mapCycle.SetString( va( "%s.scriptcfg", g_mapCycle.GetString() ) );
  1629.         }
  1630.     }
  1631.  
  1632.     Printf( "map cycle script: '%s'\n", g_mapCycle.GetString() );
  1633.     func = program.FindFunction( "mapcycle::cycle" );
  1634.     if ( !func ) {
  1635.         program.CompileFile( g_mapCycle.GetString() );
  1636.         func = program.FindFunction( "mapcycle::cycle" );
  1637.     }
  1638.     if ( !func ) {
  1639.         Printf( "Couldn't find mapcycle::cycle\n" );
  1640.         return false;
  1641.     }
  1642.     thread = new idThread( func );
  1643.     thread->Start();
  1644.     delete thread;
  1645.  
  1646.     newInfo = *cvarSystem->MoveCVarsToDict( CVAR_SERVERINFO );
  1647.     for ( i = 0; i < newInfo.GetNumKeyVals(); i++ ) {
  1648.         keyval = newInfo.GetKeyVal( i );
  1649.         keyval2 = serverInfo.FindKey( keyval->GetKey() );
  1650.         if ( !keyval2 || keyval->GetValue().Icmp( keyval2->GetValue() ) ) {
  1651.             break;
  1652.         }
  1653.     }
  1654.     return ( i != newInfo.GetNumKeyVals() );
  1655. }
  1656.  
  1657. /*
  1658. ===================
  1659. idGameLocal::NextMap_f
  1660. ===================
  1661. */
  1662. void idGameLocal::NextMap_f( const idCmdArgs &args ) {
  1663.     if ( !gameLocal.isMultiplayer || gameLocal.isClient ) {
  1664.         common->Printf( "server is not running\n" );
  1665.         return;
  1666.     }
  1667.  
  1668.     gameLocal.NextMap( );
  1669.     // next map was either voted for or triggered by a server command - always restart
  1670.     gameLocal.MapRestart( );
  1671. }
  1672.  
  1673. /*
  1674. ===================
  1675. idGameLocal::MapPopulate
  1676. ===================
  1677. */
  1678. void idGameLocal::MapPopulate( int instance ) {
  1679.  
  1680. // RAVEN BEGIN
  1681. // jnewquist: Tag scope and callees to track allocations using "new".
  1682.     MEM_SCOPED_TAG(tag,MA_ENTITY);
  1683. // RAVEN END
  1684.  
  1685.     if ( isMultiplayer ) {
  1686.         cvarSystem->SetCVarBool( "r_skipSpecular", false );
  1687.     }
  1688.     // parse the key/value pairs and spawn entities
  1689. // RAVEN BEGIN
  1690. // ddynerman: instance code
  1691.     // reload the instances
  1692.     if( instance == -1 ) {
  1693.         for( int i = 0; i < instances.Num(); i++ ) {
  1694.             if( instances[ i ] ) {
  1695.                 instances[ i ]->Restart();
  1696.             }
  1697.         }
  1698.     } else {
  1699.         assert( instance >= 0 && instance < instances.Num() );
  1700.         instances[ instance ]->Restart();
  1701.     }
  1702. // RAVEN END
  1703.     // mark location entities in all connected areas
  1704.     SpreadLocations();
  1705.  
  1706.     // RAVEN BEGIN
  1707.     // ddynerman: prepare the list of spawn spots
  1708.     InitializeSpawns();
  1709.     // RAVEN END
  1710.  
  1711.     // execute pending events before the very first game frame
  1712.     // this makes sure the map script main() function is called
  1713.     // before the physics are run so entities can bind correctly
  1714.     Printf( "------------ Processing events --------------\n" );
  1715.     idEvent::ServiceEvents();
  1716. }
  1717.  
  1718. /*
  1719. ===================
  1720. idGameLocal::InitFromNewMap
  1721. ===================
  1722. */
  1723. void idGameLocal::InitFromNewMap( const char *mapName, idRenderWorld *renderWorld, bool isServer, bool isClient, int randseed ) {
  1724.  
  1725.     TIME_THIS_SCOPE( __FUNCLINE__);
  1726.     
  1727.     this->isServer = isServer;
  1728.     this->isClient = isClient;
  1729. // RAVEN BEGIN
  1730. // ddynerman: listen server
  1731.     this->isListenServer = isServer && !cvarSystem->GetCVarBool( "net_serverDedicated" );
  1732. // RAVEN END
  1733.     this->isMultiplayer = isServer || isClient;
  1734.  
  1735.     PACIFIER_UPDATE;
  1736.  
  1737. //RAVEN BEGIN
  1738. //asalmon: stats for single player
  1739.     if(!this->isMultiplayer) {
  1740. #ifdef _MPBETA
  1741.         return;
  1742. #else
  1743.         statManager->EndGame();
  1744. #ifdef _XENON
  1745.         Live()->DeleteSPSession(true);
  1746. #endif
  1747.         statManager->Shutdown();
  1748.         statManager->Init();
  1749.         statManager->BeginGame();
  1750.         statManager->ClientConnect(0);
  1751. #ifdef _XENON
  1752.         Live()->CreateSPSession();
  1753. #endif
  1754. #endif // _MPBETA
  1755.     }
  1756. //RAVEN END
  1757.  
  1758.     if ( mapFileName.Length() ) {
  1759.         MapShutdown();
  1760.     }
  1761.  
  1762.     Printf( "-------------- Game Map Init ----------------\n" );
  1763.  
  1764.     gamestate = GAMESTATE_STARTUP;
  1765.  
  1766.     gameRenderWorld = renderWorld;
  1767.  
  1768. // RAVEN BEGIN
  1769. // mwhitlock: Dynamic memory consolidation
  1770. #if defined(_RV_MEM_SYS_SUPPORT)
  1771.     animationLib->BeginLevelLoad();
  1772. #endif
  1773.     
  1774. // ddynerman: set gametype
  1775.     SetGameType();
  1776. // RAVEN END
  1777.  
  1778.     LoadMap( mapName, randseed );
  1779.  
  1780.     InitScriptForMap();
  1781.  
  1782.     MapPopulate();
  1783.  
  1784.     mpGame.Reset();
  1785.  
  1786.     mpGame.Precache();
  1787.  
  1788. // RAVEN BEGIN
  1789. // mwhitlock: Dynamic memory consolidation
  1790. #if defined(_RV_MEM_SYS_SUPPORT)
  1791.     animationLib->EndLevelLoad();
  1792. #endif
  1793. // RAVEN END
  1794.  
  1795.     // free up any unused animations
  1796. // RAVEN BEGIN
  1797. // jsinger: animationLib changed to a pointer
  1798.     animationLib->FlushUnusedAnims();
  1799. // RAVEN END
  1800.  
  1801.     gamestate = GAMESTATE_ACTIVE;
  1802.  
  1803.     Printf( "---------------------------------------------\n" );
  1804. }
  1805.  
  1806. /*
  1807. =================
  1808. idGameLocal::InitFromSaveGame
  1809. =================
  1810. */
  1811. bool idGameLocal::InitFromSaveGame( const char *mapName, idRenderWorld *renderWorld, idFile *saveGameFile ) {
  1812.     TIME_THIS_SCOPE( __FUNCLINE__);
  1813.     
  1814.     int i;
  1815.     int num;
  1816.     idEntity *ent;
  1817.     idDict si;
  1818.  
  1819.     if ( mapFileName.Length() ) {
  1820.         MapShutdown();
  1821.     }
  1822.  
  1823.     Printf( "---------- Game Map Init SaveGame -----------\n" );
  1824.  
  1825.     gamestate = GAMESTATE_STARTUP;
  1826.  
  1827.     gameRenderWorld = renderWorld;
  1828.  
  1829.     idRestoreGame savegame( saveGameFile );
  1830.  
  1831.     savegame.ReadBuildNumber();
  1832.  
  1833.     // Create the list of all objects in the game
  1834.     savegame.CreateObjects();
  1835.  
  1836.     // Load the idProgram, also checking to make sure scripting hasn't changed since the savegame
  1837.     if ( program.Restore( &savegame ) == false ) {
  1838.  
  1839.         // Abort the load process, and let the session know so that it can restart the level
  1840.         // with the player persistent data.
  1841.         savegame.DeleteObjects();
  1842.         program.Restart();
  1843.  
  1844.         return false;
  1845.     }
  1846.  
  1847.     // load the map needed for this savegame
  1848.     LoadMap( mapName, 0 );
  1849.  
  1850.     savegame.ReadInt( i );
  1851.     g_skill.SetInteger( i );
  1852.  
  1853.     // precache any media specified in the map
  1854.     for ( i = 0; i < mapFile->GetNumEntities(); i++ ) {
  1855.         idMapEntity *mapEnt = mapFile->GetEntity( i );
  1856.  
  1857.         if ( !InhibitEntitySpawn( mapEnt->epairs ) ) {
  1858.             CacheDictionaryMedia( &mapEnt->epairs );
  1859.             const char *classname = mapEnt->epairs.GetString( "classname" );
  1860.             if ( classname != '\0' ) {
  1861.                 FindEntityDef( classname, false );
  1862.             }
  1863.         }
  1864.     }
  1865.  
  1866.     savegame.ReadDict( &si );
  1867.     SetServerInfo( si );
  1868.  
  1869.     savegame.ReadInt( numClients );
  1870.     for( i = 0; i < numClients; i++ ) {
  1871. // RAVEN BEGIN
  1872. // mekberg: don't read in userinfo. Grab from cvars
  1873. //        savegame.ReadDict( &userInfo[ i ] );
  1874. // RAVEN END
  1875. //        savegame.ReadUsercmd( usercmds[ i ] );
  1876.         savegame.ReadDict( &persistentPlayerInfo[ i ] );
  1877.     }
  1878.  
  1879.     for( i = 0; i < MAX_GENTITIES; i++ ) {
  1880.         savegame.ReadObject( reinterpret_cast<idClass *&>( entities[ i ] ) );
  1881.         savegame.ReadInt( spawnIds[ i ] );
  1882.  
  1883.         // restore the entityNumber
  1884.         if ( entities[ i ] != NULL ) {
  1885.             entities[ i ]->entityNumber = i;
  1886.         }
  1887.     }
  1888.  
  1889.     // Precache the player
  1890. // RAVEN BEGIN
  1891. // bdube: changed so we actually cache stuff
  1892.     FindEntityDef ( idPlayer::GetSpawnClassname ( ) );
  1893.  
  1894. // abahr: saving clientEntities
  1895.     for( i = 0; i < MAX_CENTITIES; i++ ) {
  1896.         savegame.ReadObject( reinterpret_cast<idClass *&>( clientEntities[ i ] ) );
  1897.         savegame.ReadInt( clientSpawnIds[ i ] );
  1898.  
  1899.         // restore the entityNumber
  1900.         if ( clientEntities[ i ] != NULL ) {
  1901.             clientEntities[ i ]->entityNumber = i;
  1902.         }
  1903.     }
  1904. // RAVEN END
  1905.  
  1906.     savegame.ReadInt( firstFreeIndex );
  1907.     savegame.ReadInt( num_entities );
  1908.  
  1909.     // enityHash is restored by idEntity::Restore setting the entity name.
  1910.  
  1911.     savegame.ReadObject( reinterpret_cast<idClass *&>( world ) );
  1912.  
  1913.     savegame.ReadInt( num );
  1914.     for( i = 0; i < num; i++ ) {
  1915.         savegame.ReadObject( reinterpret_cast<idClass *&>( ent ) );
  1916.         assert( ent );
  1917.         if ( ent ) {
  1918.             ent->spawnNode.AddToEnd( spawnedEntities );
  1919.         }
  1920.     }
  1921.  
  1922. // RAVEN BEGIN
  1923. // abahr: save scriptObject proxies
  1924.     savegame.ReadInt( num );
  1925.     scriptObjectProxies.SetNum( num );
  1926.     for( i = 0; i < num; ++i ) {
  1927.         scriptObjectProxies[i].Restore( &savegame );
  1928.     }
  1929. // abahr: save client entity stuff
  1930.     rvClientEntity* clientEnt = NULL;
  1931.     savegame.ReadInt( num );
  1932.     for( i = 0; i < num; ++i ) {
  1933.         savegame.ReadObject( reinterpret_cast<idClass *&>( clientEnt ) );
  1934.         assert( clientEnt );
  1935.         if ( clientEnt  ) {
  1936.             clientEnt->spawnNode.AddToEnd( clientSpawnedEntities );
  1937.         }
  1938.     }
  1939. // RAVEN END
  1940.  
  1941.     savegame.ReadInt( num );
  1942.     for( i = 0; i < num; i++ ) {
  1943.         savegame.ReadObject( reinterpret_cast<idClass *&>( ent ) );
  1944.         assert( ent );
  1945.         if ( ent ) {
  1946.             ent->activeNode.AddToEnd( activeEntities );
  1947.         }
  1948.     }
  1949.  
  1950.     savegame.ReadInt( numEntitiesToDeactivate );
  1951.     savegame.ReadBool( sortPushers );
  1952.     savegame.ReadBool( sortTeamMasters );
  1953.     savegame.ReadDict( &persistentLevelInfo );
  1954.  
  1955.     for( i = 0; i < MAX_GLOBAL_SHADER_PARMS; i++ ) {
  1956.         savegame.ReadFloat( globalShaderParms[ i ] );
  1957.     }
  1958.  
  1959.     savegame.ReadInt( i );
  1960.     random.SetSeed( i );
  1961.  
  1962.     savegame.ReadObject( reinterpret_cast<idClass *&>( frameCommandThread ) );
  1963.  
  1964.     // clip
  1965.     // push
  1966.     // pvs
  1967.  
  1968.     // testmodel = "<NULL>"
  1969.     // testFx = "<NULL>"
  1970.  
  1971.     savegame.ReadString( sessionCommand );
  1972. // RAVEN BEGIN
  1973. // nmckenzie: Let the AI system load itself too.
  1974.     aiManager.Restore( &savegame );
  1975. // RAVEN END
  1976.  
  1977.     // FIXME: save smoke particles
  1978.  
  1979.     savegame.ReadInt( cinematicSkipTime );
  1980.     savegame.ReadInt( cinematicStopTime );
  1981.     savegame.ReadInt( cinematicMaxSkipTime );
  1982.     savegame.ReadBool( inCinematic );
  1983.     savegame.ReadBool( skipCinematic );
  1984.  
  1985.     savegame.ReadBool( isMultiplayer );
  1986.     savegame.ReadInt( (int &)gameType );
  1987.  
  1988.     savegame.ReadInt( framenum );
  1989.     savegame.ReadInt( previousTime );
  1990.     savegame.ReadInt( time );
  1991.  
  1992.     savegame.ReadInt( vacuumAreaNum );
  1993.  
  1994.     savegame.ReadInt( entityDefBits );
  1995.     savegame.ReadBool( isServer );
  1996.     savegame.ReadBool( isClient );
  1997. // RAVEN BEGIN
  1998.     savegame.ReadBool( isListenServer );
  1999. // RAVEN END
  2000.  
  2001.     savegame.ReadInt( localClientNum );
  2002.  
  2003.     // snapshotEntities is used for multiplayer only
  2004.  
  2005.     savegame.ReadInt( realClientTime );
  2006.     savegame.ReadBool( isNewFrame );
  2007.  
  2008.     savegame.ReadBool( mapCycleLoaded );
  2009.     savegame.ReadInt( spawnCount );
  2010.  
  2011.     savegame.ReadInt( num );
  2012.     if ( num ) {
  2013.         if ( num != gameRenderWorld->NumAreas() ) {
  2014.             savegame.Error( "idGameLocal::InitFromSaveGame: number of areas in map differs from save game." );
  2015.         }
  2016.  
  2017.         locationEntities = new idLocationEntity *[ num ];
  2018.         for( i = 0; i < num; i++ ) {
  2019.             savegame.ReadObject( reinterpret_cast<idClass *&>( locationEntities[ i ] ) );
  2020.         }
  2021.     }
  2022.  
  2023.     savegame.ReadObject( reinterpret_cast<idClass *&>( camera ) );
  2024.  
  2025.     savegame.ReadMaterial( globalMaterial );
  2026.  
  2027. // RAVEN BEGIN
  2028. // bdube: added
  2029.     lastAIAlertEntity.Restore( &savegame );
  2030.     savegame.ReadInt( lastAIAlertEntityTime );
  2031.     lastAIAlertActor.Restore( &savegame );
  2032.     savegame.ReadInt( lastAIAlertActorTime );
  2033. // RAVEN END
  2034.  
  2035.     savegame.ReadDict( &spawnArgs );
  2036.  
  2037.     savegame.ReadInt( playerPVS.i );
  2038.     savegame.ReadInt( (int &)playerPVS.h );
  2039.     savegame.ReadInt( playerConnectedAreas.i );
  2040.     savegame.ReadInt( (int &)playerConnectedAreas.h );
  2041.  
  2042.     savegame.ReadVec3( gravity );
  2043.  
  2044.     // gamestate is restored after restoring everything else
  2045.  
  2046.     savegame.ReadBool( influenceActive );
  2047.     savegame.ReadInt( nextGibTime );
  2048.  
  2049.     // spawnSpots
  2050.     // initialSpots
  2051.     // currentInitialSpot
  2052.     // newInfo
  2053.     // makingBuild
  2054.     // shakeSounds
  2055.  
  2056.     // Read out pending events
  2057.     idEvent::Restore( &savegame );
  2058.  
  2059.     savegame.RestoreObjects();
  2060.  
  2061.     mpGame.Reset();
  2062.  
  2063.     mpGame.Precache();
  2064.  
  2065.     // free up any unused animations
  2066. // RAVEN BEGIN
  2067. // jsinger: animationLib changed to a pointer
  2068.     animationLib->FlushUnusedAnims();
  2069. // RAVEN END
  2070.  
  2071.     gamestate = GAMESTATE_ACTIVE;
  2072.  
  2073.     Printf( "--------------------------------------\n" );
  2074.  
  2075.     return true;
  2076. }
  2077.  
  2078. /*
  2079. ===========
  2080. idGameLocal::MapClear
  2081. ===========
  2082. */
  2083. // RAVEN BEGIN
  2084. // ddynerman: multiple instances 
  2085. void idGameLocal::MapClear( bool clearClients, int instance ) {
  2086. // RAVEN END
  2087.     int i;
  2088.  
  2089. // RAVEN BEGIN
  2090. // bdube: delete client entities first since they reference real entities
  2091.     for( i = 0; i < MAX_CENTITIES; i++ ) {
  2092.         // on the server we need to keep around client entities bound to entities in our instance2
  2093.         if( gameLocal.isServer && gameLocal.GetLocalPlayer() && instance != -1 &&
  2094.             instance != gameLocal.GetLocalPlayer()->GetInstance() && 
  2095.             clientEntities[ i ] && clientEntities[ i ]->GetBindMaster() && 
  2096.             clientEntities[ i ]->GetBindMaster()->GetInstance() == gameLocal.GetLocalPlayer()->GetInstance() ) {
  2097.             continue;
  2098.         }
  2099.         delete clientEntities[ i ];
  2100.         clientEntities[ i ] = NULL;
  2101.         clientSpawnIds[ i ] = -1;
  2102.     }
  2103. // RAVEN END
  2104.  
  2105.     for( i = ( clearClients ? 0 : MAX_CLIENTS ); i < MAX_GENTITIES; i++ ) {
  2106.         if( instance >= 0 && entities[ i ] && entities[ i ]->GetInstance() != instance ) {
  2107.             continue;
  2108.         }
  2109.  
  2110.         delete entities[ i ];
  2111.         // ~idEntity is in charge of setting the pointer to NULL
  2112.         // it will also clear pending events for this entity
  2113.         assert( !entities[ i ] );
  2114. // RAVEN BEGIN
  2115. // see FIXME in idRestoreGame::Error
  2116.         entities[ i ] = NULL;
  2117. // RAVEN END
  2118.         spawnIds[ i ] = -1;
  2119.     }
  2120.  
  2121.     entityHash.Clear( 1024, MAX_GENTITIES );
  2122.  
  2123.     if ( !clearClients ) {
  2124.         // add back the hashes of the clients/stuff in other instances
  2125.         for ( i = 0; i < MAX_GENTITIES; i++ ) {
  2126.             if ( !entities[ i ] ) {
  2127.                 continue;
  2128.             }
  2129.             entityHash.Add( entityHash.GenerateKey( entities[ i ]->name.c_str(), true ), i );
  2130.         }
  2131.     }
  2132.  
  2133. // RAVEN BEGIN
  2134. // jscott: clear out portal skies
  2135.     portalSky = NULL;
  2136. // abahr:
  2137.     gravityInfo.Clear();
  2138.     scriptObjectProxies.Clear();
  2139. // RAVEN END
  2140.  
  2141.     delete frameCommandThread;
  2142.     frameCommandThread = NULL;
  2143.  
  2144.     if ( editEntities ) {
  2145.         delete editEntities;
  2146.         editEntities = NULL;
  2147.     }
  2148.  
  2149.     delete[] locationEntities;
  2150.     locationEntities = NULL;
  2151.     
  2152. // RAVEN BEGIN
  2153. // ddynerman: mp clear
  2154.     if( gameLocal.isMultiplayer ) {
  2155.         ClearForwardSpawns();
  2156.         for( i = 0; i < TEAM_MAX; i++ ) {
  2157.             teamSpawnSpots[ i ].Clear();
  2158.         }
  2159.         mpGame.ClearMap();
  2160.     }
  2161.     ambientLights.Clear();
  2162. // RAVEN END    
  2163. }
  2164.  
  2165. // RAVEN BEGIN
  2166. // ddynerman: instance-specific clear
  2167. void idGameLocal::InstanceClear( int instance ) {
  2168.     // note: clears all ents EXCEPT those in the instance
  2169.     int i;
  2170.  
  2171.     for( i = 0; i < MAX_CENTITIES; i++ ) {
  2172.         delete clientEntities[ i ];
  2173.         assert( !clientEntities[ i ] );
  2174.         clientSpawnIds[ i ] = -1;
  2175.     }
  2176.  
  2177.     for( i = MAX_CLIENTS; i < MAX_GENTITIES; i++ ) {
  2178.         if( i == ENTITYNUM_CLIENT || i == ENTITYNUM_WORLD ) {
  2179.             continue;
  2180.         }
  2181.  
  2182.         if( entities[ i ] && entities[ i ]->fl.persistAcrossInstances ) {
  2183.             //common->DPrintf( "Instance %d: persistant: excluding ent from clear: %s (%s)\n", instance, entities[ i ]->name.c_str(), entities[ i ]->GetClassname() );
  2184.             continue;
  2185.         }
  2186.  
  2187.         //if( entities[ i ] ) {
  2188.             //Printf( "Instance %d: CLEARING ent from clear: %s (%s)\n", instance, entities[ i ]->name.c_str(), entities[ i ]->GetClassname() );
  2189.         //}
  2190.         
  2191.         delete entities[ i ];
  2192.         // ~idEntity is in charge of setting the pointer to NULL
  2193.         // it will also clear pending events for this entity
  2194.         assert( !entities[ i ] );
  2195.         // RAVEN BEGIN
  2196.         // see FIXME in idRestoreGame::Error
  2197.         entities[ i ] = NULL;
  2198.         // RAVEN END
  2199.         spawnIds[ i ] = -1;
  2200.     }
  2201.  
  2202.     entityHash.Clear( 1024, MAX_GENTITIES );
  2203.  
  2204.     for ( i = 0; i < MAX_CLIENTS; i++ ) {
  2205.         if ( !entities[ i ] ) {
  2206.             continue;
  2207.         }
  2208.         entityHash.Add( entityHash.GenerateKey( entities[ i ]->name.c_str(), true ), i );
  2209.     }
  2210.  
  2211. // RAVEN BEGIN
  2212. // jscott: clear out portal skies
  2213.     portalSky = NULL;
  2214.     // abahr:
  2215.     gravityInfo.Clear();
  2216.     scriptObjectProxies.Clear();
  2217. // RAVEN END
  2218.  
  2219.     delete frameCommandThread;
  2220.     frameCommandThread = NULL;
  2221.  
  2222.     if ( editEntities ) {
  2223.         delete editEntities;
  2224.         editEntities = NULL;
  2225.     }
  2226.  
  2227.     delete[] locationEntities;
  2228.     locationEntities = NULL;
  2229.  
  2230.     // RAVEN BEGIN
  2231.     // ddynerman: mp clear
  2232.     if( gameLocal.isMultiplayer ) {
  2233.         ClearForwardSpawns();
  2234.         for( i = 0; i < TEAM_MAX; i++ ) {
  2235.             teamSpawnSpots[ i ].Clear();
  2236.         }
  2237.         mpGame.ClearMap();
  2238.     }
  2239.     ambientLights.Clear();
  2240. }
  2241. // RAVEN END
  2242.  
  2243. /*
  2244. ===========
  2245. idGameLocal::MapShutdown
  2246. ============
  2247. */
  2248. void idGameLocal::MapShutdown( void ) {
  2249.     Printf( "------------ Game Map Shutdown --------------\n" );
  2250.     
  2251.     gamestate = GAMESTATE_SHUTDOWN;
  2252.  
  2253.     soundSystem->ResetListener();
  2254.  
  2255. // RAVEN BEGIN
  2256. // rjohnson: new blur special effect
  2257.     renderSystem->ShutdownSpecialEffects();
  2258. // RAVEN END
  2259.  
  2260.     // clear out camera if we're in a cinematic
  2261.     if ( inCinematic ) {
  2262.         camera = NULL;
  2263.         inCinematic = false;
  2264.     }
  2265.  
  2266. // RAVEN BEGIN
  2267. // jscott: cleanup playbacks
  2268.     gameEdit->ShutdownPlaybacks();
  2269. // RAVEN END
  2270.  
  2271.     MapClear( true );
  2272.  
  2273. // RAVEN BEGIN
  2274. // jscott: make sure any spurious events are killed
  2275.     idEvent::ClearEventList();
  2276.  
  2277.     // reset the script to the state it was before the map was started
  2278.     program.Restart();
  2279.  
  2280. // bdube: game debug
  2281.     gameDebug.Shutdown( );
  2282.     gameLogLocal.Shutdown( );
  2283. // RAVEN END
  2284.  
  2285.     iconManager->Shutdown();
  2286.  
  2287.     pvs.Shutdown();
  2288.  
  2289. // RAVEN BEGIN
  2290. // ddynerman: MP multiple instances
  2291.     ShutdownInstances();
  2292. // mwhitlock: Dynamic memory consolidation
  2293.     clip.Clear();
  2294. // RAVEN END
  2295.     idClipModel::ClearTraceModelCache();
  2296.  
  2297. // RAVEN BEGIN
  2298. // mwhitlock: Dynamic memory consolidation
  2299. #if defined(_RV_MEM_SYS_SUPPORT)
  2300.     idForce::ClearForceList();
  2301. #endif
  2302. // RAVEN END
  2303.  
  2304.     ShutdownAsyncNetwork();
  2305.  
  2306.     mapFileName.Clear();
  2307.  
  2308.     gameRenderWorld = NULL;
  2309.  
  2310.     gamestate = GAMESTATE_NOMAP;
  2311.  
  2312.     Printf( "---------------------------------------------\n" );
  2313. }
  2314.  
  2315. /*
  2316. ===================
  2317. idGameLocal::DumpOggSounds
  2318. ===================
  2319. */
  2320. void idGameLocal::DumpOggSounds( void ) {
  2321.     int i, j, k, size, totalSize;
  2322.     idFile *file;
  2323.     idStrList oggSounds, weaponSounds;
  2324.     const idSoundShader *soundShader;
  2325.     const soundShaderParms_t *parms;
  2326.     idStr soundName;
  2327.  
  2328.     for ( i = 0; i < declManager->GetNumDecls( DECL_SOUND ); i++ ) {
  2329.         soundShader = static_cast<const idSoundShader *>(declManager->DeclByIndex( DECL_SOUND, i, false ));
  2330.         parms = soundShader->GetParms();
  2331.  
  2332.         if ( soundShader->EverReferenced() && soundShader->GetState() != DS_DEFAULTED ) {
  2333.  
  2334.             const_cast<idSoundShader *>(soundShader)->EnsureNotPurged();
  2335.  
  2336.             for ( j = 0; j < soundShader->GetNumSounds(); j++ ) {
  2337.                 soundName = soundShader->GetSound( j );
  2338.                 soundName.BackSlashesToSlashes();
  2339.  
  2340.                 // don't OGG sounds that cause a shake because that would
  2341.                 // cause continuous seeking on the OGG file which is expensive
  2342.                 if ( parms->shakes != 0.0f ) {
  2343.                     shakeSounds.AddUnique( soundName );
  2344.                     continue;
  2345.                 }
  2346.  
  2347.                 // if not voice over or combat chatter
  2348.                 if (    soundName.Find( "/vo/", false ) == -1 &&
  2349.                         soundName.Find( "/combat_chatter/", false ) == -1 &&
  2350.                         soundName.Find( "/bfgcarnage/", false ) == -1 &&
  2351.                         soundName.Find( "/enpro/", false ) == - 1 &&
  2352.                         soundName.Find( "/soulcube/energize_01.wav", false ) == -1 ) {
  2353.                     // don't OGG weapon sounds
  2354.                     if (    soundName.Find( "weapon", false ) != -1 ||
  2355.                             soundName.Find( "gun", false ) != -1 ||
  2356.                             soundName.Find( "bullet", false ) != -1 ||
  2357.                             soundName.Find( "bfg", false ) != -1 ||
  2358.                             soundName.Find( "plasma", false ) != -1 ) {
  2359.                         weaponSounds.AddUnique( soundName );
  2360.                         continue;
  2361.                     }
  2362.                 }
  2363.  
  2364.                 for ( k = 0; k < shakeSounds.Num(); k++ ) {
  2365.                     if ( shakeSounds[k].IcmpPath( soundName ) == 0 ) {
  2366.                         break;
  2367.                     }
  2368.                 }
  2369.                 if ( k < shakeSounds.Num() ) {
  2370.                     continue;
  2371.                 }
  2372.  
  2373.                 oggSounds.AddUnique( soundName );
  2374.             }
  2375.         }
  2376.     }
  2377.  
  2378.     file = fileSystem->OpenFileWrite( "makeogg.bat", "fs_savepath" );
  2379.     if ( file == NULL ) {
  2380.         common->Warning( "Couldn't open makeogg.bat" );
  2381.         return;
  2382.     }
  2383.  
  2384.     // list all the shake sounds
  2385.     totalSize = 0;
  2386.     for ( i = 0; i < shakeSounds.Num(); i++ ) {
  2387.         size = fileSystem->ReadFile( shakeSounds[i], NULL, NULL );
  2388.         totalSize += size;
  2389.         shakeSounds[i].Replace( "/", "\\" );
  2390.         file->Printf( "echo \"%s\" (%d kB)\n", shakeSounds[i].c_str(), size >> 10 );
  2391.     }
  2392.     file->Printf( "echo %d kB in shake sounds\n\n\n", totalSize >> 10 );
  2393.  
  2394.     // list all the weapon sounds
  2395.     totalSize = 0;
  2396.     for ( i = 0; i < weaponSounds.Num(); i++ ) {
  2397.         size = fileSystem->ReadFile( weaponSounds[i], NULL, NULL );
  2398.         totalSize += size;
  2399.         weaponSounds[i].Replace( "/", "\\" );
  2400.         file->Printf( "echo \"%s\" (%d kB)\n", weaponSounds[i].c_str(), size >> 10 );
  2401.     }
  2402.     file->Printf( "echo %d kB in weapon sounds\n\n\n", totalSize >> 10 );
  2403.  
  2404.     // list commands to convert all other sounds to ogg
  2405.     totalSize = 0;
  2406.     for ( i = 0; i < oggSounds.Num(); i++ ) {
  2407. // RAVEN BEGIN
  2408. // rjohnson: changed path to raven's directories
  2409. // jnewquist: Use filesystem search path to get absolute file path
  2410.         idStr    tempFile;
  2411.         idFile *f = fileSystem->OpenFileRead( oggSounds[i] );
  2412.         if ( !f ) {
  2413.             continue;
  2414.         }
  2415.         size = f->Length();
  2416.         totalSize += size;
  2417.         tempFile = f->GetFullPath();
  2418.         fileSystem->CloseFile(f);
  2419.         f = NULL;
  2420.         tempFile.Replace( "/", "\\" );
  2421.  
  2422. // jnewquist: prevent alterations to files relative to cdpath
  2423.         const char *cdPath = cvarSystem->GetCVarString("fs_cdpath");
  2424.         const int cdPathLen = idStr::Length(cdPath);
  2425.         if ( cdPathLen > 0 && idStr::Icmpn(cdPath, tempFile, cdPathLen) == 0 ) {
  2426.             file->Printf( "rem Ignored file from CD path: %s\n", tempFile.c_str() );
  2427.             continue;
  2428.         }
  2429.  
  2430.         file->Printf( "echo %d / %d\n", i, oggSounds.Num() );
  2431.         file->Printf( "k:\\utility\\oggenc -q 0 \"%s\"\n", tempFile.c_str() );
  2432.         file->Printf( "del \"%s\"\n", tempFile.c_str() );
  2433. // RAVEN END
  2434.     }
  2435.     file->Printf( "\n\necho %d kB in OGG sounds\n\n\n", totalSize >> 10 );
  2436.  
  2437.     fileSystem->CloseFile( file );
  2438.  
  2439.     shakeSounds.Clear();
  2440. }
  2441.  
  2442. /*
  2443. ===================
  2444. idGameLocal::GetShakeSounds
  2445. ===================
  2446. */
  2447. void idGameLocal::GetShakeSounds( const idDict *dict ) {
  2448.     const idSoundShader *soundShader;
  2449.     const char *soundShaderName;
  2450.     idStr soundName;
  2451.  
  2452.     soundShaderName = dict->GetString( "s_shader" );
  2453.     if ( soundShaderName != '\0' && dict->GetFloat( "s_shakes" ) != 0.0f ) {
  2454.         soundShader = declManager->FindSound( soundShaderName );
  2455.  
  2456.         for ( int i = 0; i < soundShader->GetNumSounds(); i++ ) {
  2457.             soundName = soundShader->GetSound( i );
  2458.             soundName.BackSlashesToSlashes();
  2459.  
  2460.             shakeSounds.AddUnique( soundName );
  2461.         }
  2462.     }
  2463. }
  2464.  
  2465. /*
  2466. ===================
  2467. idGameLocal::CacheDictionaryMedia
  2468.  
  2469. This is called after parsing an EntityDef and for each entity spawnArgs before
  2470. merging the entitydef.  It could be done post-merge, but that would
  2471. avoid the fast pre-cache check associated with each entityDef
  2472. ===================
  2473. */
  2474. void idGameLocal::CacheDictionaryMedia( const idDict *dict ) {
  2475.     idDict spawnerArgs;
  2476.     
  2477.     TIME_THIS_SCOPE( __FUNCLINE__);
  2478.  
  2479.     if ( dict == NULL ) {
  2480. #ifndef _XENON
  2481.         if ( cvarSystem->GetCVarBool( "com_makingBuild") ) {
  2482.             DumpOggSounds();
  2483.         }
  2484. #endif
  2485.         return;
  2486.     }
  2487.  
  2488. #ifndef _XENON
  2489.     if ( cvarSystem->GetCVarBool( "com_makingBuild" ) ) {
  2490.         GetShakeSounds( dict );
  2491.     }
  2492. #endif
  2493.  
  2494.     int numVals = dict->GetNumKeyVals();
  2495.     
  2496.     for ( int i = 0; i < numVals; ++i ) {
  2497.         const idKeyValue *kv = dict->GetKeyVal( i );
  2498.         
  2499.         #define MATCH(s) \
  2500.             (!kv->GetKey().Icmpn( s, strlen(s) ))
  2501.         /**/
  2502.         
  2503.         if ( !kv || !kv->GetValue().Length() ) {
  2504.             continue;
  2505.         }
  2506.         
  2507.         if ( MATCH( "model" ) ) {
  2508.             
  2509.             TIME_THIS_SCOPE( __FUNCLINE__);
  2510.             
  2511.             MEM_SCOPED_TAG(tag,MA_MODEL);
  2512.             declManager->MediaPrint( "Precaching model %s\n", kv->GetValue().c_str() );
  2513.             // precache model/animations
  2514.             if ( declManager->FindType( DECL_MODELDEF, kv->GetValue(), false ) == NULL ) {
  2515.                 // precache the render model
  2516.                 renderModelManager->FindModel( kv->GetValue() );
  2517.                 // precache .cm files only
  2518.                 collisionModelManager->PreCacheModel( GetMapName(), kv->GetValue() );
  2519.             }
  2520.         } else if ( MATCH( "s_shader" ) ) {
  2521.             
  2522.             TIME_THIS_SCOPE( __FUNCLINE__);
  2523.             
  2524.             MEM_SCOPED_TAG(tag,MA_SOUND);
  2525.             declManager->FindType( DECL_SOUND, kv->GetValue() );
  2526.         } else if ( MATCH( "snd_" ) ) {
  2527.             
  2528.             TIME_THIS_SCOPE( __FUNCLINE__);
  2529.             
  2530.             MEM_SCOPED_TAG(tag,MA_SOUND);
  2531.             declManager->FindType( DECL_SOUND, kv->GetValue() );
  2532.         } else if ( MATCH( "gui_" ) ) {
  2533.             
  2534.             TIME_THIS_SCOPE( __FUNCLINE__);
  2535.             
  2536.             MEM_SCOPED_TAG(tag,MA_GUI);
  2537.             if ( !idStr::Icmp( kv->GetKey(), "gui_noninteractive" )
  2538.                 || !idStr::Icmpn( kv->GetKey(), "gui_parm", 8 )    
  2539.                 || !idStr::Icmp( kv->GetKey(), "gui_inventory" ) ) {
  2540.                 // unfortunate flag names, they aren't actually a gui
  2541.             } else {
  2542.                 declManager->MediaPrint( "Precaching gui %s\n", kv->GetValue().c_str() );
  2543.                 uiManager->FindGui( kv->GetValue().c_str(), true );
  2544.             }
  2545.         } else if ( MATCH( "texture" ) ) {
  2546.             
  2547.             TIME_THIS_SCOPE( __FUNCLINE__);
  2548.             
  2549.             MEM_SCOPED_TAG(tag,MA_MATERIAL);
  2550.             declManager->FindType( DECL_MATERIAL, kv->GetValue() );
  2551.         } else if ( MATCH( "mtr_" ) ) {
  2552.             
  2553.             TIME_THIS_SCOPE( __FUNCLINE__);
  2554.             
  2555.             MEM_SCOPED_TAG(tag,MA_MATERIAL);
  2556.             declManager->FindType( DECL_MATERIAL, kv->GetValue() );
  2557.         } else if ( MATCH( "screenShot" ) ) {
  2558.         
  2559.             TIME_THIS_SCOPE( __FUNCLINE__);
  2560.             
  2561.             MEM_SCOPED_TAG(tag,MA_MATERIAL);
  2562.             declManager->FindType( DECL_MATERIAL, kv->GetValue() );
  2563.         } else if ( MATCH( "inv_icon" ) ) {
  2564.             
  2565.             TIME_THIS_SCOPE( __FUNCLINE__);
  2566.             
  2567.             MEM_SCOPED_TAG(tag,MA_MATERIAL);
  2568.             declManager->FindType( DECL_MATERIAL, kv->GetValue() );
  2569.         } else if ( MATCH( "teleport" ) ) {
  2570.             
  2571.             TIME_THIS_SCOPE( __FUNCLINE__);
  2572.             
  2573.             MEM_SCOPED_TAG(tag,MA_EFFECT);
  2574.             int teleportType = atoi( kv->GetValue() );
  2575.             const char *p = ( teleportType ) ? va( "effects/teleporter%i.fx", teleportType ) : "effects/teleporter.fx";
  2576.             declManager->FindType( DECL_EFFECT, p );
  2577.         } else if ( MATCH( "fx_" ) ) {
  2578.             
  2579.             TIME_THIS_SCOPE( __FUNCLINE__);
  2580.             
  2581.             MEM_SCOPED_TAG(tag,MA_EFFECT);
  2582.             declManager->MediaPrint( "Precaching fx %s\n", kv->GetValue().c_str() );
  2583.             declManager->FindEffect( kv->GetValue() );
  2584.         } else if ( MATCH( "skin" ) ) {
  2585.             
  2586.             TIME_THIS_SCOPE( __FUNCLINE__);
  2587.             
  2588.             MEM_SCOPED_TAG(tag,MA_MATERIAL);
  2589.             declManager->MediaPrint( "Precaching skin %s\n", kv->GetValue().c_str() );
  2590.             declManager->FindType( DECL_SKIN, kv->GetValue() );
  2591.         } else if ( MATCH( "def_" ) ) {
  2592.             
  2593.             TIME_THIS_SCOPE( __FUNCLINE__);
  2594.             
  2595.             MEM_SCOPED_TAG(tag,MA_DECL);
  2596.             FindEntityDef( kv->GetValue().c_str(), false );
  2597.         } else if ( MATCH( "playback_" ) ) {
  2598.             
  2599.             TIME_THIS_SCOPE( __FUNCLINE__);
  2600.             
  2601.             MEM_SCOPED_TAG(tag,MA_ANIM);
  2602.             declManager->MediaPrint( "Precaching playback %s\n", kv->GetValue().c_str() );
  2603.             declManager->FindPlayback( kv->GetValue() );
  2604.         } else if ( MATCH( "lipsync_" ) ) {
  2605.             
  2606.             TIME_THIS_SCOPE( __FUNCLINE__);
  2607.             
  2608.             MEM_SCOPED_TAG(tag,MA_ANIM);
  2609.             declManager->MediaPrint( "Precaching lipsync %s\n", kv->GetValue().c_str() );
  2610.             declManager->FindLipSync( kv->GetValue() );
  2611.             declManager->FindSound ( kv->GetValue() );
  2612.         } else if ( MATCH( "icon " ) ) {
  2613.             
  2614.             TIME_THIS_SCOPE( __FUNCLINE__);
  2615.             
  2616.             MEM_SCOPED_TAG(tag,MA_MATERIAL);
  2617.             idLexer  src ( LEXFL_ALLOWPATHNAMES );
  2618.             idToken  token;
  2619.             idToken     token2;
  2620.             src.LoadMemory( kv->GetValue(), kv->GetValue().Length(), "icon" );
  2621.             
  2622.             src.ReadToken ( &token );
  2623.             if ( src.CheckTokenString ( "," ) ) {
  2624.                 int x, y, w, h;
  2625.                 src.ReadToken ( &token2 ) ;
  2626.                 x = token2.GetIntValue ( );
  2627.                 src.ExpectTokenString ( "," );
  2628.                 
  2629.                 src.ReadToken ( &token2 ) ;
  2630.                 y = token2.GetIntValue ( );
  2631.                 src.ExpectTokenString ( "," );
  2632.  
  2633.                 src.ReadToken ( &token2 ) ;
  2634.                 w = token2.GetIntValue ( );
  2635.                 src.ExpectTokenString ( "," );
  2636.  
  2637.                 src.ReadToken ( &token2 ) ;
  2638.                 h = token2.GetIntValue ( );
  2639.                 
  2640.                 uiManager->RegisterIcon ( kv->GetKey ( ).c_str() + 5, token, x, y, w, h );
  2641.             } else { 
  2642.                 uiManager->RegisterIcon ( kv->GetKey ( ).c_str() + 5, token );
  2643.             }
  2644.         } else if ( MATCH( "spawn_" ) ) {
  2645.             
  2646.             TIME_THIS_SCOPE( __FUNCLINE__);
  2647.             
  2648.             MEM_SCOPED_TAG(tag,MA_DECL);
  2649.             spawnerArgs.Set ( kv->GetKey ( ).c_str() + 6, kv->GetValue ( ) );
  2650.         }
  2651.         
  2652.         #undef MATCH
  2653.     }
  2654.  
  2655.     if ( spawnerArgs.GetNumKeyVals() ) {
  2656.         CacheDictionaryMedia ( &spawnerArgs );
  2657.     }
  2658. // RAVEN END
  2659. }
  2660.  
  2661. /*
  2662. ===========
  2663. idGameLocal::InitScriptForMap
  2664. ============
  2665. */
  2666. void idGameLocal::InitScriptForMap( void ) {
  2667.  
  2668. // RAVEN BEGIN
  2669. // jnewquist: Tag scope and callees to track allocations using "new".
  2670.     MEM_SCOPED_TAG(tag,MA_DEFAULT);
  2671. // RAVEN END
  2672.     // create a thread to run frame commands on
  2673.     frameCommandThread = new idThread();
  2674.     frameCommandThread->ManualDelete();
  2675.     frameCommandThread->SetThreadName( "frameCommands" );
  2676.  
  2677.  
  2678. // jnewquist: Tag scope and callees to track allocations using "new".
  2679.     MEM_SCOPED_TAG_SET(tag,MA_SCRIPT);
  2680.  
  2681.     // run the main game script function (not the level specific main)
  2682.     const function_t *func = program.FindFunction( SCRIPT_DEFAULTFUNC );
  2683.  
  2684.  
  2685. // jnewquist: Tag scope and callees to track allocations using "new".
  2686.     MEM_SCOPED_TAG_SET(tag,MA_DEFAULT);
  2687.  
  2688.     if ( func != NULL ) {
  2689.         idThread *thread = new idThread( func );
  2690.         if ( thread->Start() ) {
  2691.             // thread has finished executing, so delete it
  2692.             delete thread;
  2693.         }
  2694.     }
  2695.  
  2696. // RAVEN END
  2697.  
  2698. }
  2699.  
  2700. /*
  2701. ===========
  2702. idGameLocal::SpawnPlayer
  2703. ============
  2704. */
  2705. void idGameLocal::SpawnPlayer( int clientNum ) {
  2706.  
  2707.     TIME_THIS_SCOPE( __FUNCLINE__);
  2708.  
  2709.     idEntity    *ent;
  2710.     idDict        args;
  2711. // RAVEN BEGIN
  2712. // jnewquist: Tag scope and callees to track allocations using "new".
  2713.     MEM_SCOPED_TAG(tag,MA_ENTITY);
  2714. // RAVEN END
  2715.  
  2716.     // they can connect
  2717.     common->DPrintf( "SpawnPlayer: %i\n", clientNum );
  2718.  
  2719.     args.SetInt( "spawn_entnum", clientNum );
  2720.     args.Set( "name", va( "player%d", clientNum + 1 ) );
  2721. // RAVEN BEGIN
  2722. // bdube: changed marine class
  2723.     args.Set( "classname", idPlayer::GetSpawnClassname() );
  2724. // RAVEN END
  2725.     
  2726.     // This takes a really long time.
  2727.     PACIFIER_UPDATE;
  2728.     if ( !SpawnEntityDef( args, &ent ) || !entities[ clientNum ] ) {
  2729.         Error( "Failed to spawn player as '%s'", args.GetString( "classname" ) );
  2730.     }
  2731.  
  2732.     // make sure it's a compatible class
  2733. // RAVEN BEGIN
  2734. // jnewquist: Use accessor for static class type 
  2735.     if ( !ent->IsType( idPlayer::GetClassType() ) ) {
  2736. // RAVEN END
  2737.         Error( "'%s' spawned the player as a '%s'.  Player spawnclass must be a subclass of idPlayer.", args.GetString( "classname" ), ent->GetClassname() );
  2738.     }
  2739.  
  2740.     if ( clientNum >= numClients ) {
  2741.         numClients = clientNum + 1;
  2742.     }
  2743.  
  2744.     PACIFIER_UPDATE;
  2745.     mpGame.SpawnPlayer( clientNum );
  2746. }
  2747.  
  2748. /*
  2749. ================
  2750. idGameLocal::GetClientByNum
  2751. ================
  2752. */
  2753. idPlayer *idGameLocal::GetClientByNum( int current ) const {
  2754.     if ( current < 0 || current >= numClients ) {
  2755.         current = 0;
  2756.     }
  2757.     if ( entities[current] ) {
  2758.         return static_cast<idPlayer *>( entities[ current ] );
  2759.     }
  2760.     return NULL;
  2761. }
  2762.  
  2763. /*
  2764. ================
  2765. idGameLocal::GetClientByName
  2766. ================
  2767. */
  2768. idPlayer *idGameLocal::GetClientByName( const char *name ) const {
  2769.     int i;
  2770.     idEntity *ent;
  2771.     for ( i = 0 ; i < numClients ; i++ ) {
  2772.         ent = entities[ i ];
  2773. // RAVEN BEGIN
  2774. // jnewquist: Use accessor for static class type 
  2775.         if ( ent && ent->IsType( idPlayer::GetClassType() ) ) {
  2776. // RAVEN END
  2777. // RAVEN BEGIN
  2778. // bdube: escape codes
  2779.             if ( idStr::IcmpNoEscape( name, userInfo[ i ].GetString( "ui_name" ) ) == 0 ) {
  2780. // RAVEN END            
  2781.                 return static_cast<idPlayer *>( ent );
  2782.             }
  2783.         }
  2784.     }
  2785.     return NULL;
  2786. }
  2787.  
  2788. /*
  2789. ================
  2790. idGameLocal::GetClientByCmdArgs
  2791. ================
  2792. */
  2793. idPlayer *idGameLocal::GetClientByCmdArgs( const idCmdArgs &args ) const {
  2794.     idPlayer *player;
  2795.     idStr client = args.Argv( 1 );
  2796.     if ( !client.Length() ) {
  2797.         return NULL;
  2798.     }
  2799.     // we don't allow numeric ui_name so this can't go wrong
  2800.     if ( client.IsNumeric() ) {
  2801.         player = GetClientByNum( atoi( client.c_str() ) );
  2802.     } else {
  2803.         player = GetClientByName( client.c_str() );
  2804.     }
  2805.     if ( !player ) {
  2806.         common->Printf( "Player '%s' not found\n", client.c_str() );
  2807.     }
  2808.     return player;
  2809. }
  2810.  
  2811. /*
  2812. ================
  2813. idGameLocal::GetClientNumByName
  2814. ================
  2815. */
  2816. int idGameLocal::GetClientNumByName( const char *name ) const {
  2817.     int i;
  2818.     idEntity *ent;
  2819.     for ( i = 0 ; i < numClients ; i++ ) {
  2820.         ent = entities[ i ];
  2821.  
  2822.         if ( ent && ent->IsType( idPlayer::GetClassType() ) ) {
  2823.             if ( idStr::IcmpNoEscape( name, userInfo[ i ].GetString( "ui_name" ) ) == 0 ) {
  2824.                 return i;
  2825.             }
  2826.         }
  2827.     }
  2828.     return -1;
  2829. }
  2830.  
  2831. /*
  2832. ================
  2833. idGameLocal::GetNextClientNum
  2834. ================
  2835. */
  2836. int idGameLocal::GetNextClientNum( int _current ) const {
  2837.     int i, current;
  2838.  
  2839.     current = 0;
  2840.     for ( i = 0; i < numClients; i++) {
  2841.         current = ( _current + i + 1 ) % numClients;
  2842. // RAVEN BEGIN
  2843. // jnewquist: Use accessor for static class type 
  2844.         if ( entities[ current ] && entities[ current ]->IsType( idPlayer::GetClassType() ) ) {
  2845. // RAVEN END
  2846.             return current;
  2847.         }
  2848.     }
  2849.  
  2850.     return current;
  2851. }
  2852.  
  2853. /*
  2854. ================
  2855. idGameLocal::GetLocalPlayer
  2856.  
  2857. Nothing in the game tic should EVER make a decision based on what the
  2858. local client number is, it shouldn't even be aware that there is a
  2859. draw phase even happening.  This just returns client 0, which will
  2860. be correct for single player.
  2861. ================
  2862. */
  2863. idPlayer *idGameLocal::GetLocalPlayer() const {
  2864.     if ( localClientNum < 0 ) {
  2865.         return NULL;
  2866.     }
  2867.  
  2868. // RAVEN BEGIN
  2869. // jnewquist: Use accessor for static class type 
  2870.     if ( !entities[ localClientNum ] || !entities[ localClientNum ]->IsType( idPlayer::GetClassType() ) ) {
  2871. // RAVEN END
  2872.         // not fully in game yet
  2873.         return NULL;
  2874.     }
  2875.     return static_cast<idPlayer *>( entities[ localClientNum ] );
  2876. }
  2877.  
  2878. /*
  2879. ================
  2880. idGameLocal::SetupClientPVS
  2881. for client spectating others, get the pvs of spectated
  2882. ================
  2883. */
  2884. pvsHandle_t idGameLocal::GetClientPVS( idPlayer *player, pvsType_t type ) {
  2885.     if ( player->GetPrivateCameraView() ) {
  2886.         return pvs.SetupCurrentPVS( player->GetPrivateCameraView()->GetPVSAreas(), player->GetPrivateCameraView()->GetNumPVSAreas() );
  2887.     } else if ( camera ) {
  2888.         return pvs.SetupCurrentPVS( camera->GetPVSAreas(), camera->GetNumPVSAreas() );
  2889.     } else {
  2890.         if ( player->spectating && player->spectator != player->entityNumber && entities[ player->spectator ] ) {
  2891.             player = static_cast<idPlayer*>( entities[ player->spectator ] );
  2892.         }
  2893.         return pvs.SetupCurrentPVS( player->GetPVSAreas(), player->GetNumPVSAreas() );
  2894.     }
  2895. }
  2896.  
  2897. // RAVEN BEGIN
  2898. // jscott: for portal skies
  2899. /*
  2900. ================
  2901. idGameLocal::GetSpawnCount
  2902. ================
  2903. */
  2904. int idGameLocal::GetSpawnCount ( void ) const {
  2905.     return spawnCount;
  2906. }
  2907.  
  2908. /*
  2909. ================
  2910. idGameLocal::SetupPortalSkyPVS
  2911. ================
  2912. */
  2913. bool idGameLocal::SetupPortalSkyPVS( idPlayer *player ) {
  2914.  
  2915.     int            i, count, numAreas;
  2916.     const int    *areaNums;
  2917.     bool        *visibleAreas;
  2918.  
  2919.     if( !portalSky ) {
  2920.  
  2921.         return( false );
  2922.     }
  2923.  
  2924.     // Allocate room for the area flags
  2925.     numAreas = gameRenderWorld->NumAreas();
  2926.     visibleAreas = ( bool * )_alloca( numAreas );
  2927.     memset( visibleAreas, 0, numAreas );
  2928.  
  2929.     // Grab the areas the player can see....
  2930.     count = player->GetNumPVSAreas();
  2931.     areaNums = player->GetPVSAreas();
  2932.     for( i = 0; i < count; i++ ) {
  2933.  
  2934.         // Work out the referenced areas
  2935.         gameRenderWorld->FindVisibleAreas( player->GetPhysics()->GetOrigin(), areaNums[i], visibleAreas );
  2936.     }
  2937.  
  2938.     // Do any of the visible areas have a skybox?
  2939.     for( i = 0; i < numAreas; i++ ) {
  2940.  
  2941.         if( !visibleAreas[i] ) {
  2942.  
  2943.             continue;
  2944.         }
  2945.  
  2946.         if( gameRenderWorld->HasSkybox( i ) ) {
  2947.  
  2948.             break;
  2949.         }
  2950.     }
  2951.  
  2952.     // .. if any one has a skybox component, then merge in the portal sky
  2953.     return ( i != numAreas );
  2954. }
  2955. // RAVEN END
  2956.  
  2957. /*
  2958. ===============
  2959. idGameLocal::UpdateClientsPVS
  2960. ===============
  2961. */
  2962. void idGameLocal::UpdateClientsPVS( void ) {
  2963.     int i;
  2964.     for ( i = 0; i < numClients; i++ ) {
  2965.         if ( !entities[ i ] ) {
  2966.             continue;
  2967.         }
  2968.         assert( clientsPVS[ i ].i == -1 );
  2969.         clientsPVS[ i ] = GetClientPVS( static_cast< idPlayer * >( entities[ i ] ), PVS_NORMAL );
  2970.     }
  2971. }
  2972.  
  2973. /*
  2974. ================
  2975. idGameLocal::SetupPlayerPVS
  2976. ================
  2977. */
  2978. void idGameLocal::SetupPlayerPVS( void ) {
  2979.     int            i = 0;
  2980.     idPlayer *    player = NULL;
  2981.     pvsHandle_t    otherPVS, newPVS;
  2982.  
  2983.     UpdateClientsPVS( );
  2984.  
  2985.     playerPVS.i = -1;
  2986.     for ( i = 0; i < numClients; i++ ) {
  2987.         if ( !entities[i] ) {
  2988.             return;
  2989.         }
  2990.         assert( entities[i]->IsType( idPlayer::GetClassType() ) );
  2991.  
  2992.         player = static_cast<idPlayer *>( entities[ i ] );
  2993.  
  2994.         if ( playerPVS.i == -1 ) {
  2995.             playerPVS = clientsPVS[ i ];
  2996.             freePlayerPVS = false;    // don't try to free it as long as we stick to the client PVS
  2997.         } else {
  2998.             otherPVS = clientsPVS[ i ];
  2999.             newPVS = pvs.MergeCurrentPVS( playerPVS, otherPVS );
  3000.             if ( freePlayerPVS ) {
  3001.                 pvs.FreeCurrentPVS( playerPVS );
  3002.                 freePlayerPVS = false;
  3003.             }
  3004.             playerPVS = newPVS;
  3005.             freePlayerPVS = true;    // that merged one will need to be freed
  3006.         }
  3007.  
  3008. // RAVEN BEGIN
  3009. // jscott: for portal skies
  3010.         portalSkyVisible = SetupPortalSkyPVS( player );
  3011.         if ( portalSkyVisible ) {
  3012.  
  3013.             otherPVS = pvs.SetupCurrentPVS( portalSky->GetPVSAreas(), portalSky->GetNumPVSAreas() );
  3014.             newPVS = pvs.MergeCurrentPVS( playerPVS, otherPVS );
  3015.  
  3016.             if ( freePlayerPVS ) {
  3017.                 pvs.FreeCurrentPVS( playerPVS );
  3018.                 freePlayerPVS = false;
  3019.             }
  3020.             pvs.FreeCurrentPVS( otherPVS );
  3021.             playerPVS = newPVS;
  3022.             freePlayerPVS = true;
  3023.         }
  3024. // RAVEN END
  3025.  
  3026.         if ( playerConnectedAreas.i == -1 ) {
  3027.             playerConnectedAreas = GetClientPVS( player, PVS_CONNECTED_AREAS );
  3028.         } else {
  3029.             otherPVS = GetClientPVS( player, PVS_CONNECTED_AREAS );
  3030.             newPVS = pvs.MergeCurrentPVS( playerConnectedAreas, otherPVS );
  3031.             pvs.FreeCurrentPVS( playerConnectedAreas );
  3032.             pvs.FreeCurrentPVS( otherPVS );
  3033.             playerConnectedAreas = newPVS;
  3034.         }
  3035.     }
  3036. }
  3037.  
  3038. /*
  3039. ================
  3040. idGameLocal::FreePlayerPVS
  3041. ================
  3042. */
  3043. void idGameLocal::FreePlayerPVS( void ) {
  3044.     int i;
  3045.  
  3046.     // only clear playerPVS if it's a different handle than the one in clientsPVS
  3047.     if ( freePlayerPVS && playerPVS.i != -1 ) {
  3048.         pvs.FreeCurrentPVS( playerPVS );
  3049.         freePlayerPVS = false;
  3050.     }
  3051.     playerPVS.i = -1;
  3052.     for ( i = 0; i < MAX_CLIENTS; i++ ) {
  3053.         if ( clientsPVS[ i ].i >= 0 ) {
  3054.             pvs.FreeCurrentPVS( clientsPVS[ i ] );
  3055.             clientsPVS[i].i = -1;
  3056.         }
  3057.     }
  3058.     if ( playerConnectedAreas.i != -1 ) {
  3059.         pvs.FreeCurrentPVS( playerConnectedAreas );
  3060.         playerConnectedAreas.i = -1;
  3061.     }
  3062. }
  3063.  
  3064. /*
  3065. ================
  3066. idGameLocal::InPlayerPVS
  3067.  
  3068.   should only be called during entity thinking and event handling
  3069. ================
  3070. */
  3071. bool idGameLocal::InPlayerPVS( idEntity *ent ) const {
  3072.     if ( playerPVS.i == -1 ) {
  3073.         return false;
  3074.     }
  3075.     return pvs.InCurrentPVS( playerPVS, ent->GetPVSAreas(), ent->GetNumPVSAreas() );
  3076. }
  3077.  
  3078. /*
  3079. ================
  3080. idGameLocal::InPlayerConnectedArea
  3081.  
  3082.   should only be called during entity thinking and event handling
  3083. ================
  3084. */
  3085. bool idGameLocal::InPlayerConnectedArea( idEntity *ent ) const {
  3086.     if ( playerConnectedAreas.i == -1 ) {
  3087.         return false;
  3088.     }
  3089.     return pvs.InCurrentPVS( playerConnectedAreas, ent->GetPVSAreas(), ent->GetNumPVSAreas() );
  3090. }
  3091.  
  3092.  
  3093. /*
  3094. ================
  3095. idGameLocal::UpdateGravity
  3096. ================
  3097. */
  3098. void idGameLocal::UpdateGravity( void ) {
  3099.     idEntity *ent;
  3100.     
  3101.     idCVar* gravityCVar = NULL;
  3102.  
  3103.     if( gameLocal.isMultiplayer ) {
  3104.         gravityCVar = &g_mp_gravity;
  3105.     } else {
  3106.         gravityCVar = &g_gravity;
  3107.     }
  3108.  
  3109.     if ( gravityCVar->IsModified() ) {
  3110.         if ( gravityCVar->GetFloat() == 0.0f ) {
  3111.             gravityCVar->SetFloat( 1.0f );
  3112.         }
  3113.         gravity.Set( 0, 0, -gravityCVar->GetFloat() );
  3114.  
  3115.         // update all physics objects
  3116.         for( ent = spawnedEntities.Next(); ent != NULL; ent = ent->spawnNode.Next() ) {
  3117. // RAVEN BEGIN
  3118. // jnewquist: Use accessor for static class type 
  3119.             if ( ent->IsType( idAFEntity_Generic::GetClassType() ) ) {
  3120. // RAVEN END
  3121.                 idPhysics *phys = ent->GetPhysics();
  3122.                 if ( phys ) {
  3123.                     phys->SetGravity( gravity );
  3124.                 }
  3125. // RAVEN BEGIN
  3126. // ddynerman: jump pads
  3127.             } else if ( ent->IsType( rvJumpPad::GetClassType() ) ) {
  3128.                 ent->PostEventMS( &EV_FindTargets, 0 );
  3129.             }
  3130. // RAVEN END
  3131.         }
  3132.         gravityCVar->ClearModified();
  3133.     }
  3134. }
  3135.  
  3136. /*
  3137. ================
  3138. idGameLocal::GetGravity
  3139. ================
  3140. */
  3141. const idVec3 &idGameLocal::GetGravity( void ) const {
  3142.     return gravity;
  3143. }
  3144.  
  3145. /*
  3146. ================
  3147. idGameLocal::SortActiveEntityList
  3148.  
  3149.   Sorts the active entity list such that pushing entities come first,
  3150.   actors come next and physics team slaves appear after their master.
  3151. ================
  3152. */
  3153. void idGameLocal::SortActiveEntityList( void ) {
  3154.     idEntity *ent, *next_ent, *master, *part;
  3155.  
  3156.     // if the active entity list needs to be reordered to place physics team masters at the front
  3157.     if ( sortTeamMasters ) {
  3158.         // Sort bind masters first
  3159.         for ( ent = activeEntities.Next(); ent != NULL; ent = next_ent ) {
  3160.             next_ent = ent->activeNode.Next();
  3161.             for ( part = ent->GetBindMaster ( ); part; part = part->GetBindMaster ( ) ) {
  3162.                 // Ensure we dont rerun the whole active entity list if our cached next_ent is one 
  3163.                 // of the entities we are moving
  3164.                 if ( next_ent == part ) {
  3165.                     next_ent = next_ent->activeNode.Next();
  3166.                     part = ent->GetBindMaster ( );
  3167.                     continue;
  3168.                 }
  3169.                 part->activeNode.Remove();
  3170.                 part->activeNode.AddToFront( activeEntities );                                                
  3171.             }
  3172.         }                
  3173.     
  3174.         for ( ent = activeEntities.Next(); ent != NULL; ent = next_ent ) {
  3175.             next_ent = ent->activeNode.Next();
  3176.             master = ent->GetTeamMaster();
  3177.             if ( master && master == ent ) {
  3178.                 ent->activeNode.Remove();
  3179.                 ent->activeNode.AddToFront( activeEntities );                                                
  3180.             }
  3181.         }
  3182.     }
  3183.  
  3184.     // if the active entity list needs to be reordered to place pushers at the front
  3185.     if ( sortPushers ) {
  3186.  
  3187.         for ( ent = activeEntities.Next(); ent != NULL; ent = next_ent ) {
  3188.             next_ent = ent->activeNode.Next();
  3189.             master = ent->GetTeamMaster();
  3190.             if ( !master || master == ent ) {
  3191.                 // check if there is an actor on the team
  3192.                 for ( part = ent; part != NULL; part = part->GetNextTeamEntity() ) {
  3193. // RAVEN BEGIN
  3194. // jnewquist: Use accessor for static class type 
  3195.                     if ( part->GetPhysics()->IsType( idPhysics_Actor::GetClassType() ) ) {
  3196. // RAVEN END
  3197.                         break;
  3198.                     }
  3199.                 }
  3200.                 // if there is an actor on the team
  3201.                 if ( part ) {
  3202.                     ent->activeNode.Remove();
  3203.                     ent->activeNode.AddToFront( activeEntities );
  3204.                 }
  3205.             }
  3206.         }
  3207.  
  3208.         for ( ent = activeEntities.Next(); ent != NULL; ent = next_ent ) {
  3209.             next_ent = ent->activeNode.Next();
  3210.             master = ent->GetTeamMaster();
  3211.             if ( !master || master == ent ) {
  3212.                 // check if there is an entity on the team using parametric physics
  3213.                 for ( part = ent; part != NULL; part = part->GetNextTeamEntity() ) {
  3214.                     if ( part->GetPhysics()->IsType( idPhysics_Parametric::GetClassType() ) ) {
  3215.                         break;
  3216.                     }
  3217.                     if ( part->GetPhysics()->IsType( rvPhysics_Spline::GetClassType() ) ) {
  3218.                         break;
  3219.                     }
  3220.                 }
  3221.                 // if there is an entity on the team using parametric physics
  3222.                 if ( part ) {
  3223.                     ent->activeNode.Remove();
  3224.                     ent->activeNode.AddToFront( activeEntities );
  3225.                 }
  3226.             }
  3227.         }
  3228.     }
  3229.  
  3230.     sortTeamMasters = false;
  3231.     sortPushers = false;
  3232. }
  3233.  
  3234. /*
  3235. ================
  3236. idGameLocal::MenuFrame
  3237. Called each session frame when a map is not running (e.g. usually in the main menu)
  3238. ================
  3239. */
  3240. void idGameLocal::MenuFrame( void ) { }
  3241.  
  3242. /*
  3243. ================
  3244. idGameLocal::RunFrame
  3245. ================
  3246. */
  3247. // RAVEN BEGIN
  3248. gameReturn_t idGameLocal::RunFrame( const usercmd_t *clientCmds, int activeEditors, bool lastCatchupFrame ) {
  3249.     idEntity *    ent;
  3250.     int            num;
  3251.     float        ms;
  3252.     idTimer        timer_think, timer_events, timer_singlethink;
  3253.     idTimer        timer_misc, timer_misc2;
  3254.     gameReturn_t ret;
  3255.     idPlayer    *player;
  3256.     const renderView_t *view;
  3257.  
  3258.     editors = activeEditors;
  3259.     isLastPredictFrame = lastCatchupFrame;
  3260.  
  3261.     assert( !isClient );
  3262.  
  3263.     player = GetLocalPlayer();
  3264.  
  3265.     if ( !isMultiplayer && g_stopTime.GetBool() ) {
  3266.  
  3267.         // set the user commands for this frame
  3268.         usercmds = clientCmds;
  3269.  
  3270.         if ( player ) {
  3271.             // ddynerman: save the current thinking entity for instance-dependent
  3272.             currentThinkingEntity = player;
  3273.             player->Think();
  3274.             currentThinkingEntity = NULL;
  3275.         }
  3276.     } else do {
  3277.         // update the game time
  3278.         framenum++;
  3279.         previousTime = time;
  3280.         // bdube: use GetMSec access rather than USERCMD_TIME
  3281.         time += GetMSec();
  3282.         realClientTime = time;
  3283.  
  3284.         // bdube: added advanced debug support
  3285.         gameDebug.BeginFrame( );
  3286.         gameLogLocal.BeginFrame( time );
  3287.  
  3288. #ifdef GAME_DLL
  3289.         // allow changing SIMD usage on the fly
  3290.         if ( com_forceGenericSIMD.IsModified() ) {
  3291.             idSIMD::InitProcessor( "game", com_forceGenericSIMD.GetBool() );
  3292.         }
  3293. #endif
  3294.  
  3295.         // make sure the random number counter is used each frame so random events
  3296.         // are influenced by the player's actions
  3297.         random.RandomInt();
  3298.  
  3299.         if ( player ) {
  3300.             // update the renderview so that any gui videos play from the right frame
  3301.             view = player->GetRenderView();
  3302.             if ( view ) {
  3303.                 gameRenderWorld->SetRenderView( view );
  3304.             }
  3305.         }
  3306.  
  3307.         // If modview is running then let it think
  3308.         common->ModViewThink( );    
  3309.  
  3310.         // rjohnson: added option for guis to always think
  3311.         common->RunAlwaysThinkGUIs( time );
  3312.  
  3313.         // nmckenzie: Let AI System stuff update itself.
  3314.         if ( !isMultiplayer ) {
  3315. #ifndef _MPBETA
  3316.             aiManager.RunFrame();
  3317. #endif // !_MPBETA
  3318.         }
  3319.  
  3320.         timer_misc.Start();
  3321.         
  3322.         // set the user commands for this frame
  3323.         usercmds = clientCmds;
  3324.  
  3325.         // create a merged pvs for all players
  3326.         // do this before we process events, which may rely on PVS info
  3327.         SetupPlayerPVS();
  3328.  
  3329.         // process events on the server
  3330.         ServerProcessEntityNetworkEventQueue();
  3331.  
  3332.         // update our gravity vector if needed.
  3333.         UpdateGravity();
  3334.  
  3335.         if ( isLastPredictFrame ) {
  3336.             // jscott: effect system uses gravity and the player PVS
  3337.             bse->StartFrame();
  3338.         }
  3339.  
  3340.         // sort the active entity list
  3341.         SortActiveEntityList();
  3342.  
  3343.         timer_think.Clear();
  3344.         timer_think.Start();
  3345.  
  3346.         // jscott: for timing and effect handling
  3347.         timer_misc2.Start();
  3348.         timer_misc.Stop();
  3349.  
  3350.         // let entities think
  3351.         if ( g_timeentities.GetFloat() ) {
  3352.             // rjohnson: will now draw entity info for long thinkers
  3353.             idPlayer *player;
  3354.             idVec3 origin;
  3355.  
  3356.             player = GetLocalPlayer();
  3357.             if ( player ) {
  3358.                 origin = player->GetPhysics()->GetOrigin();
  3359.             }
  3360.  
  3361.             idBounds    viewTextBounds( origin );
  3362.             viewTextBounds.ExpandSelf( 128.0f );
  3363.  
  3364.             num = 0;
  3365.  
  3366.             for( ent = activeEntities.Next(); ent != NULL; ent = ent->activeNode.Next() ) {
  3367.                 if ( g_cinematic.GetBool() && inCinematic && !ent->cinematic ) {
  3368.                     ent->GetPhysics()->UpdateTime( time );
  3369.                     continue;
  3370.                 }
  3371.                 timer_singlethink.Clear();
  3372.                 timer_singlethink.Start();
  3373.                 // ddynerman: save the current thinking entity for instance-dependent
  3374.                 currentThinkingEntity = ent;
  3375.                 ent->Think();
  3376.                 currentThinkingEntity = NULL;
  3377.                 timer_singlethink.Stop();
  3378.                 ms = timer_singlethink.Milliseconds();
  3379.                 if ( ms >= g_timeentities.GetFloat() ) {
  3380.                     // rjohnson: will now draw entity info for long thinkers
  3381.                     Printf( "%d: entity '%s' [%s]: %.1f ms\n", time, ent->name.c_str(), ent->GetPhysics()->GetOrigin().ToString(), ms );
  3382.  
  3383.                     if ( ms >= g_timeentities.GetFloat() * 3.0f )
  3384.                     {
  3385.                         ent->mLastLongThinkColor = colorRed;
  3386.                     }
  3387.                     else
  3388.                     {
  3389.                         ent->mLastLongThinkColor[0] = 1.0f;
  3390.                         ent->mLastLongThinkColor[1] = 2.0f - (( ms - g_timeentities.GetFloat()) / g_timeentities.GetFloat() );
  3391.                         ent->mLastLongThinkColor[2] = 0.0f;
  3392.                         ent->mLastLongThinkColor[3] = 1.0f;
  3393.                     }
  3394.                     ent->DrawDebugEntityInfo( 0, &viewTextBounds, &ent->mLastLongThinkColor );
  3395.                     ent->mLastLongThinkTime = time + 2000;
  3396.                 }
  3397.                 else if ( ent->mLastLongThinkTime > time )
  3398.                 {
  3399.                     ent->DrawDebugEntityInfo( 0, &viewTextBounds, &ent->mLastLongThinkColor );
  3400.                 }
  3401.                 num++;
  3402.             }
  3403.         } else {
  3404.             if ( inCinematic ) {
  3405.                 num = 0;
  3406.                 for( ent = activeEntities.Next(); ent != NULL; ent = ent->activeNode.Next() ) {
  3407.                     if ( g_cinematic.GetBool() && !ent->cinematic ) {
  3408.                         ent->GetPhysics()->UpdateTime( time );
  3409.                         continue;
  3410.                     }
  3411.                     // ddynerman: save the current thinking entity for instance-dependent
  3412.                     currentThinkingEntity = ent;
  3413.                     ent->Think();
  3414.                     currentThinkingEntity = NULL;
  3415.                     num++;
  3416.                 }
  3417.             } else {
  3418.                 num = 0;
  3419.                 for( ent = activeEntities.Next(); ent != NULL; ent = ent->activeNode.Next() ) {
  3420.                     // ddynerman: save the current thinking entity for instance-dependent
  3421.                     currentThinkingEntity = ent;
  3422.                     ent->Think();
  3423.                     currentThinkingEntity = NULL;
  3424.                     num++;
  3425.                 }
  3426.             }
  3427.         }
  3428.  
  3429.         // remove any entities that have stopped thinking
  3430.         if ( numEntitiesToDeactivate ) {
  3431.             idEntity *next_ent;
  3432.             int c = 0;
  3433.             for( ent = activeEntities.Next(); ent != NULL; ent = next_ent ) {
  3434.                 next_ent = ent->activeNode.Next();
  3435.                 if ( !ent->thinkFlags ) {
  3436.                     ent->activeNode.Remove();
  3437.                     c++;
  3438.                 }
  3439.             }
  3440.             //assert( numEntitiesToDeactivate == c );
  3441.             numEntitiesToDeactivate = 0;
  3442.         }
  3443.  
  3444.         timer_think.Stop();
  3445.         timer_events.Clear();
  3446.         timer_events.Start();
  3447.  
  3448.         if ( isLastPredictFrame ) {
  3449.             // bdube: client entities
  3450.             rvClientEntity* cent;
  3451.             for( cent = clientSpawnedEntities.Next(); cent != NULL; cent = cent->spawnNode.Next() ) {
  3452.                 cent->Think();            
  3453.             }    
  3454.         }
  3455.  
  3456.         // service any pending events
  3457.         idEvent::ServiceEvents();
  3458.  
  3459.         // nrausch: player could have been deleted in an event
  3460.         player = GetLocalPlayer();
  3461.  
  3462.         timer_events.Stop();
  3463.  
  3464.         if ( isLastPredictFrame ) {
  3465.             // jscott: effect system uses gravity and the player PVS
  3466.             bse->EndFrame();
  3467.         }
  3468.  
  3469.         // do multiplayer related stuff
  3470.         if ( isMultiplayer ) {
  3471.             mpGame.Run();
  3472.         }
  3473.  
  3474.         // free the player pvs
  3475.         FreePlayerPVS();
  3476.  
  3477.         // display how long it took to calculate the current game frame
  3478.         if ( g_frametime.GetBool() ) {
  3479.             Printf( "game %d: all:%.1f th:%.1f ev:%.1f %d ents \n",
  3480.                 time, timer_think.Milliseconds() + timer_events.Milliseconds(),
  3481.                 timer_think.Milliseconds(), timer_events.Milliseconds(), num );
  3482.         }
  3483.  
  3484.         // build the return value
  3485.         ret.consistencyHash = 0;
  3486.         ret.sessionCommand[0] = 0;
  3487.  
  3488.         if ( !isMultiplayer && player ) {
  3489.             ret.health = player->health;
  3490.             ret.heartRate = 0.0f;
  3491.             ret.stamina = 0.0f;
  3492.             // combat is a 0-100 value based on lastHitTime and lastDmgTime
  3493.             // each make up 50% of the time spread over 10 seconds
  3494.             ret.combat = 0;
  3495.             if ( player->lastDmgTime > 0 && time < player->lastDmgTime + 10000 ) {
  3496.                 ret.combat += 50.0f * (float) ( time - player->lastDmgTime ) / 10000;
  3497.             }
  3498.             if ( player->lastHitTime > 0 && time < player->lastHitTime + 10000 ) {
  3499.                 ret.combat += 50.0f * (float) ( time - player->lastHitTime ) / 10000;
  3500.             }
  3501.         }
  3502.  
  3503.         // see if a target_sessionCommand has forced a changelevel
  3504.         if ( sessionCommand.Length() ) {
  3505.             strncpy( ret.sessionCommand, sessionCommand, sizeof( ret.sessionCommand ) );
  3506.             break;
  3507.         }
  3508.  
  3509.         // make sure we don't loop forever when skipping a cinematic
  3510.         if ( skipCinematic && ( time > cinematicMaxSkipTime ) ) {
  3511.             Warning( "Exceeded maximum cinematic skip length.  Cinematic may be looping infinitely." );
  3512.             skipCinematic = false;
  3513.             break;
  3514.         }
  3515.  
  3516.         // jscott: additional timings
  3517.         timer_misc2.Stop();
  3518.  
  3519.         if ( g_frametime.GetInteger() > 1 )  {
  3520.             gameLocal.Printf( "misc:%.1f misc2:%.1f\n", timer_misc.Milliseconds(), timer_misc2.Milliseconds() );
  3521.         }
  3522.         // bdube: let gameDebug know that its not in a game frame anymore
  3523.         gameDebug.EndFrame( );
  3524.         gameLogLocal.EndFrame( );
  3525.  
  3526.     } while( ( inCinematic || ( time < cinematicStopTime ) ) && skipCinematic );
  3527.  
  3528.     ret.syncNextGameFrame = skipCinematic;
  3529.     if ( skipCinematic ) {
  3530.         soundSystem->SetMute( false );
  3531.         skipCinematic = false;        
  3532.     }
  3533.  
  3534.     // show any debug info for this frame
  3535.     RunDebugInfo();
  3536.     D_DrawDebugLines();
  3537.  
  3538.     if ( pendingDisconnect ) {
  3539.         cmdSystem->BufferCommandText( CMD_EXEC_APPEND, "disconnect" );
  3540.         pendingDisconnect = false;
  3541.     }
  3542.  
  3543.     return ret;
  3544. }
  3545. // RAVEN END
  3546.  
  3547.  
  3548. /*
  3549. ======================================================================
  3550.  
  3551.   Game view drawing
  3552.  
  3553. ======================================================================
  3554. */
  3555.  
  3556. /*
  3557. ====================
  3558. idGameLocal::CalcFov
  3559.  
  3560. Calculates the horizontal and vertical field of view based on a horizontal field of view and custom aspect ratio
  3561. ====================
  3562. */
  3563. void idGameLocal::CalcFov( float base_fov, float &fov_x, float &fov_y ) const {
  3564.     float    x;
  3565.     float    y;
  3566.     float    ratio_x;
  3567.     float    ratio_y;
  3568.     
  3569.     if ( !sys->FPU_StackIsEmpty() ) {
  3570.         Printf( sys->FPU_GetState() );
  3571.         Error( "idGameLocal::CalcFov: FPU stack not empty" );
  3572.     }
  3573.  
  3574. // RAVEN BEGIN
  3575. // jnewquist: Option to adjust vertical fov instead of horizontal for non 4:3 modes
  3576.     if ( g_fixedHorizFOV.GetBool() ) {
  3577.         int aspectChoice = cvarSystem->GetCVarInteger( "r_aspectRatio" );
  3578.         switch( aspectChoice ) {
  3579.         default :
  3580.         case 0 :
  3581.             // 4:3
  3582.             ratio_x = 4.0f;
  3583.             ratio_y = 3.0f;
  3584.             break;
  3585.  
  3586.         case 1 :
  3587.             // 16:9
  3588.             ratio_x = 16.0f;
  3589.             ratio_y = 9.0f;
  3590.             break;
  3591.  
  3592.         case 2 :
  3593.             // 16:10
  3594.             ratio_x = 16.0f;
  3595.             ratio_y = 10.0f;
  3596.             break;
  3597.         }
  3598.         x = ratio_x / idMath::Tan( base_fov / 360.0f * idMath::PI );
  3599.         y = idMath::ATan( ratio_y, x );
  3600.         fov_y = y * 360.0f / idMath::PI;
  3601.         fov_x = base_fov;
  3602.         return;
  3603.     }
  3604. // RAVEN END
  3605.  
  3606.     // first, calculate the vertical fov based on a 640x480 view
  3607.     x = 640.0f / idMath::Tan( base_fov / 360.0f * idMath::PI );
  3608.     y = idMath::ATan( 480.0f, x );
  3609.     fov_y = y * 360.0f / idMath::PI;
  3610.  
  3611.     // FIXME: somehow, this is happening occasionally
  3612.     assert( fov_y > 0 );
  3613.     if ( fov_y <= 0 ) {
  3614.         Printf( sys->FPU_GetState() );
  3615.         Error( "idGameLocal::CalcFov: bad result" );
  3616.     }
  3617.  
  3618.     int aspectChoice = cvarSystem->GetCVarInteger( "r_aspectRatio" );
  3619.     switch( aspectChoice ) {
  3620.     default :
  3621.     case 0 :
  3622.         // 4:3
  3623.         fov_x = base_fov;
  3624.         return;
  3625.         break;
  3626.  
  3627.     case 1 :
  3628.         // 16:9
  3629.         ratio_x = 16.0f;
  3630.         ratio_y = 9.0f;
  3631.         break;
  3632.  
  3633.     case 2 :
  3634.         // 16:10
  3635.         ratio_x = 16.0f;
  3636.         ratio_y = 10.0f;
  3637.         break;
  3638.     }
  3639.  
  3640.     y = ratio_y / idMath::Tan( fov_y / 360.0f * idMath::PI );
  3641.     fov_x = idMath::ATan( ratio_x, y ) * 360.0f / idMath::PI;
  3642.  
  3643.     if ( fov_x < base_fov ) {
  3644.         fov_x = base_fov;
  3645.         x = ratio_x / idMath::Tan( fov_x / 360.0f * idMath::PI );
  3646.         fov_y = idMath::ATan( ratio_y, x ) * 360.0f / idMath::PI;
  3647.     }
  3648.  
  3649.     // FIXME: somehow, this is happening occasionally
  3650.     assert( ( fov_x > 0 ) && ( fov_y > 0 ) );
  3651.     if ( ( fov_y <= 0 ) || ( fov_x <= 0 ) ) {
  3652.         Printf( sys->FPU_GetState() );
  3653.         Error( "idGameLocal::CalcFov: bad result" );
  3654.     }
  3655. }
  3656.  
  3657. void ClearClipProfile( void );
  3658. void DisplayClipProfile( void );
  3659.  
  3660. /*
  3661. ================
  3662. idGameLocal::Draw
  3663.  
  3664. makes rendering and sound system calls
  3665. ================
  3666. */
  3667. bool idGameLocal::Draw( int clientNum ) {
  3668. //    DisplayClipProfile( );
  3669. //    ClearClipProfile( );
  3670.  
  3671.     if ( isMultiplayer ) {
  3672.         return mpGame.Draw( clientNum );
  3673.     }
  3674.  
  3675.     idPlayer *player = static_cast<idPlayer *>(entities[ clientNum ]);
  3676.  
  3677.     if ( !player ) {
  3678.         return false;
  3679.     }
  3680.  
  3681. // RAVEN BEGIN
  3682. // mwhitlock: Xenon texture streaming.
  3683. #if defined(_XENON)
  3684.     renderView_t *view = player->GetRenderView();
  3685.     // nrausch: view doesn't necessarily exist yet
  3686.     if ( !view ) {
  3687.         player->CalculateRenderView();
  3688.         view = player->GetRenderView();
  3689.     }
  3690.     if ( view )
  3691.     {
  3692.         view->streamingPrecache=player->streamingPrecache;
  3693.     }
  3694. #endif
  3695. // RAVEN END
  3696.     // render the scene
  3697.     player->playerView.RenderPlayerView( player->hud );
  3698.  
  3699. // RAVEN BEGIN
  3700. // mwhitlock: Xenon texture streaming
  3701. #if defined(_XENON)
  3702.     assert(gameRenderWorld!=0);
  3703.     if(gameRenderWorld!=0)
  3704.     {
  3705.         gameRenderWorld->StreamAreaTextures(!player->streamingPrecache);
  3706.         if(renderSystem->IsManuallyStreaming()) {
  3707.             renderSystem->ServiceManualStreaming();
  3708.         }
  3709.     }
  3710. #elif defined(TEST_MANUAL_STREAMING)
  3711.     if(renderSystem->IsManuallyStreaming()) {
  3712.         renderSystem->ServiceManualStreaming();
  3713.     }
  3714. #endif
  3715. // RAVEN END
  3716.  
  3717. // RAVEN BEGIN
  3718. // mwhitlock: Xenon texture streaming.
  3719. #if defined(_XENON)
  3720.     // We've pre-streamed all textures for first view, so clear the flag.
  3721.     player->streamingPrecache=false;
  3722. #endif
  3723. // RAVEN END
  3724.  
  3725. // RAVEN BEGIN
  3726. // bdube: debugging HUD
  3727.     gameDebug.DrawHud ( );
  3728. // RAVEN END
  3729.  
  3730.     return true;
  3731. }
  3732.  
  3733. /*
  3734. ================
  3735. idGameLocal::HandleESC
  3736. ================
  3737. */
  3738. escReply_t idGameLocal::HandleESC( idUserInterface **gui ) {
  3739.  
  3740. //RAVEN BEGIN
  3741. //asalmon: xbox dedicated server needs to bring up a special menu
  3742. #ifdef _XBOX
  3743.     if( cvarSystem->GetCVarBool( "net_serverDedicated" ))
  3744.     {
  3745.         return ESC_MAIN;
  3746.     }
  3747. #endif
  3748. //RAVEN END
  3749.  
  3750.     if ( isMultiplayer ) {
  3751.         *gui = StartMenu();
  3752.         // we may set the gui back to NULL to hide it
  3753.         return ESC_GUI;
  3754.     }
  3755.     idPlayer *player = GetLocalPlayer();
  3756.     if ( player ) {
  3757.         if ( player->HandleESC() ) {
  3758.             return ESC_IGNORE;
  3759.         } else {
  3760.             return ESC_MAIN;
  3761.         }
  3762.     }
  3763.     return ESC_MAIN;
  3764. }
  3765.  
  3766. /*
  3767. ================
  3768. idGameLocal::UpdatePlayerPostMainMenu
  3769. ================
  3770. */
  3771. void idGameLocal::UpdatePlayerPostMainMenu()    {
  3772.     idPlayer* player = GetLocalPlayer();
  3773.  
  3774.     //dedicated server?
  3775.     if( !player)    {
  3776.         return;
  3777.     }    
  3778.     
  3779.     //crosshair may have changed
  3780.     player->UpdateHudWeapon();
  3781. }
  3782.  
  3783. /*
  3784. ================
  3785. idGameLocal::StartMenu
  3786. ================
  3787. */
  3788. idUserInterface* idGameLocal::StartMenu( void ) {
  3789.     if ( !isMultiplayer ) {
  3790.         return NULL;
  3791.     }
  3792.     return mpGame.StartMenu();
  3793. }
  3794.  
  3795. /*
  3796. ================
  3797. idGameLocal::GetClientStats
  3798. ================
  3799. */
  3800. void idGameLocal::GetClientStats( int clientNum, char *data, const int len ) {
  3801.     mpGame.PlayerStats( clientNum, data, len );
  3802. }
  3803.  
  3804. /*
  3805. ================
  3806. idGameLocal::SwitchTeam
  3807. ================
  3808. */
  3809. void idGameLocal::SwitchTeam( int clientNum, int team ) {
  3810.  
  3811.     idPlayer *   player;
  3812.     player = clientNum >= 0 ? static_cast<idPlayer *>( gameLocal.entities[ clientNum ] ) : NULL;
  3813.  
  3814.     if ( !player ) {
  3815.         return;
  3816.     }
  3817.  
  3818.     int oldTeam = player->team;
  3819.  
  3820.     // Put in spectator mode
  3821.     if ( team == -1 ) {
  3822.         static_cast< idPlayer * >( entities[ clientNum ] )->Spectate( true );
  3823.     }
  3824.     // Switch to a team
  3825.     else {
  3826.         mpGame.SwitchToTeam ( clientNum, oldTeam, team );
  3827.     }
  3828. }
  3829.  
  3830. /*
  3831. ================
  3832. idGameLocal::HandleGuiCommands
  3833. ================
  3834. */
  3835. const char* idGameLocal::HandleGuiCommands( const char *menuCommand ) {
  3836.     if ( !isMultiplayer ) {
  3837.         return NULL;
  3838.     }
  3839.     return mpGame.HandleGuiCommands( menuCommand );
  3840. }
  3841.  
  3842. /*
  3843. ================
  3844. idGameLocal::HandleMainMenuCommands
  3845. ================
  3846. */
  3847. void idGameLocal::HandleMainMenuCommands( const char *menuCommand, idUserInterface *gui ) {
  3848.     if ( !idStr::Icmp( menuCommand, "initCreateServerSettings" ) ) {
  3849.         int    guiValue = 0;
  3850.  
  3851.         switch ( mpGame.GameTypeToVote( si_gameType.GetString() ) ) {
  3852.             case idMultiplayerGame::VOTE_GAMETYPE_DM:
  3853.                 guiValue = 0;
  3854.                 break;
  3855.             case idMultiplayerGame::VOTE_GAMETYPE_TOURNEY:
  3856.                 guiValue = 2;
  3857.                 break;
  3858.             case idMultiplayerGame::VOTE_GAMETYPE_TDM:
  3859.                 guiValue = 1;
  3860.                 break;
  3861.             case idMultiplayerGame::VOTE_GAMETYPE_CTF:
  3862.                 guiValue = 3;
  3863.                 break;
  3864.             case idMultiplayerGame::VOTE_GAMETYPE_ARENA_CTF:
  3865.                 guiValue = 4;
  3866.                 break;
  3867.         }
  3868.  
  3869.         gui->SetStateInt( "currentGametype", guiValue );
  3870.     }
  3871.     return;
  3872. }
  3873.  
  3874. /*
  3875. ================
  3876. idGameLocal::GetLevelMap
  3877.  
  3878.   should only be used for in-game level editing
  3879. ================
  3880. */
  3881. idMapFile *idGameLocal::GetLevelMap( void ) {
  3882. // RAVEN BEGIN
  3883. // rhummer: Added the HasBeenResolved check, if resolve has been run then it doesn't have func_groups.
  3884. //            Which we probably don't want, so force the map to be reloaded.
  3885.     if ( mapFile && mapFile->HasPrimitiveData() && !mapFile->HasBeenResloved() ) {
  3886. // RAVEN END
  3887.         return mapFile;
  3888.     }
  3889.     if ( !mapFileName.Length() ) {
  3890.         return NULL;
  3891.     }
  3892.  
  3893.     if ( mapFile ) {
  3894.         delete mapFile;
  3895.     }
  3896.  
  3897.     mapFile = new idMapFile;
  3898.     if ( !mapFile->Parse( mapFileName ) ) {
  3899.         delete mapFile;
  3900.         mapFile = NULL;
  3901.     }
  3902.  
  3903.     return mapFile;
  3904. }
  3905.  
  3906. /*
  3907. ================
  3908. idGameLocal::GetMapName
  3909. ================
  3910. */
  3911. const char *idGameLocal::GetMapName( void ) const {
  3912.     return mapFileName.c_str();
  3913. }
  3914.  
  3915. /*
  3916. ================
  3917. idGameLocal::CallFrameCommand
  3918. ================
  3919. */
  3920. void idGameLocal::CallFrameCommand( idEntity* ent, const char* frameCommand ) {
  3921.     const function_t *func = program.FindFunction( frameCommand );
  3922.     if ( !func ) {
  3923.         Warning( "Script function '%s' not found.", frameCommand );
  3924.         return;
  3925.     }
  3926.     CallFrameCommand ( ent, func );
  3927. }
  3928.  
  3929. void idGameLocal::CallFrameCommand( idEntity *ent, const function_t *frameCommand ) {
  3930.     frameCommandThread->CallFunction( ent, frameCommand, true );
  3931.     frameCommandThread->Execute();
  3932. }
  3933.  
  3934. /*
  3935. ================
  3936. idGameLocal::CallObjectFrameCommand
  3937. ================
  3938. */
  3939. void idGameLocal::CallObjectFrameCommand( idEntity *ent, const char *frameCommand ) {
  3940.     const function_t *func;
  3941.  
  3942.     func = ent->scriptObject.GetFunction( frameCommand );
  3943.     if ( !func ) {
  3944. // RAVEN BEGIN
  3945. // jnewquist: Use accessor for static class type 
  3946.         if ( !ent->IsType( idTestModel::GetClassType() ) ) {
  3947. // RAVEN END
  3948.             Error( "Unknown function '%s' called for frame command on entity '%s'", frameCommand, ent->name.c_str() );
  3949.         }
  3950.     } else {
  3951.         frameCommandThread->CallFunction( ent, func, true );
  3952.         frameCommandThread->Execute();
  3953.     }
  3954. }
  3955.  
  3956. /*
  3957. ================
  3958. idGameLocal::ShowTargets
  3959. ================
  3960. */
  3961. void idGameLocal::ShowTargets( void ) {
  3962.     idMat3        axis = GetLocalPlayer()->viewAngles.ToMat3();
  3963.     idVec3        up = axis[ 2 ] * 5.0f;
  3964.     const idVec3 &viewPos = GetLocalPlayer()->GetPhysics()->GetOrigin();
  3965.     idBounds    viewTextBounds( viewPos );
  3966.     idBounds    viewBounds( viewPos );
  3967.     idBounds    box( idVec3( -4.0f, -4.0f, -4.0f ), idVec3( 4.0f, 4.0f, 4.0f ) );
  3968.     idEntity    *ent;
  3969.     idEntity    *target;
  3970.     int            i;
  3971.     idBounds    totalBounds;
  3972.  
  3973.     viewTextBounds.ExpandSelf( 128.0f );
  3974.     viewBounds.ExpandSelf( 512.0f );
  3975.     for( ent = spawnedEntities.Next(); ent != NULL; ent = ent->spawnNode.Next() ) {
  3976.         totalBounds = ent->GetPhysics()->GetAbsBounds();
  3977.         for( i = 0; i < ent->targets.Num(); i++ ) {
  3978.             target = ent->targets[ i ].GetEntity();
  3979.             if ( target ) {
  3980.                 totalBounds.AddBounds( target->GetPhysics()->GetAbsBounds() );
  3981.             }
  3982.         }
  3983.  
  3984.         if ( !viewBounds.IntersectsBounds( totalBounds ) ) {
  3985.             continue;
  3986.         }
  3987.  
  3988.         float dist;
  3989.         idVec3 dir = totalBounds.GetCenter() - viewPos;
  3990.         dir.NormalizeFast();
  3991.         totalBounds.RayIntersection( viewPos, dir, dist );
  3992.         float frac = ( 512.0f - dist ) / 512.0f;
  3993.         if ( frac < 0.0f ) {
  3994.             continue;
  3995.         }
  3996.  
  3997.         gameRenderWorld->DebugBounds( ( ent->IsHidden() ? colorLtGrey : colorOrange ) * frac, ent->GetPhysics()->GetAbsBounds() );
  3998.         if ( viewTextBounds.IntersectsBounds( ent->GetPhysics()->GetAbsBounds() ) ) {
  3999.             idVec3 center = ent->GetPhysics()->GetAbsBounds().GetCenter();
  4000.             gameRenderWorld->DrawText( ent->name.c_str(), center - up, 0.1f, colorWhite * frac, axis, 1 );
  4001.             gameRenderWorld->DrawText( ent->GetEntityDefName(), center, 0.1f, colorWhite * frac, axis, 1 );
  4002.             gameRenderWorld->DrawText( va( "#%d", ent->entityNumber ), center + up, 0.1f, colorWhite * frac, axis, 1 );
  4003.         }
  4004.  
  4005.         for( i = 0; i < ent->targets.Num(); i++ ) {
  4006.             target = ent->targets[ i ].GetEntity();
  4007.             if ( target ) {
  4008.                 gameRenderWorld->DebugArrow( colorYellow * frac, ent->GetPhysics()->GetAbsBounds().GetCenter(), target->GetPhysics()->GetOrigin(), 10, 0 );
  4009.                 gameRenderWorld->DebugBounds( colorGreen * frac, box, target->GetPhysics()->GetOrigin() );
  4010.             }
  4011.         }
  4012.     }
  4013. }
  4014.  
  4015. /*
  4016. ================
  4017. idGameLocal::RunDebugInfo
  4018. ================
  4019. */
  4020. void idGameLocal::RunDebugInfo( void ) {
  4021.     idEntity *ent;
  4022.     idPlayer *player;
  4023.  
  4024.     player = GetLocalPlayer();
  4025.     if ( !player ) {
  4026.         return;
  4027.     }
  4028.  
  4029.     const idVec3 &origin = player->GetPhysics()->GetOrigin();
  4030.  
  4031.     if ( g_showEntityInfo.GetBool() ) {
  4032.         idBounds    viewTextBounds( origin );
  4033.         idBounds    viewBounds( origin );
  4034.  
  4035.         viewTextBounds.ExpandSelf( 128.0f );
  4036.         viewBounds.ExpandSelf( 512.0f );
  4037.         for( ent = spawnedEntities.Next(); ent != NULL; ent = ent->spawnNode.Next() ) {
  4038.             // don't draw the worldspawn
  4039.             if ( ent == world ) {
  4040.                 continue;
  4041.             }
  4042.  
  4043. // RAVEN BEGIN
  4044. // rjohnson: moved entity info out of idGameLocal into its own function
  4045.             ent->DrawDebugEntityInfo(&viewBounds, &viewTextBounds);
  4046. // RAVEN END
  4047.         }
  4048.     }
  4049.  
  4050.     // debug tool to draw bounding boxes around active entities
  4051.     if ( g_showActiveEntities.GetBool() ) {
  4052.         for( ent = activeEntities.Next(); ent != NULL; ent = ent->activeNode.Next() ) {
  4053.             idBounds    b = ent->GetPhysics()->GetBounds();
  4054.             if ( b.GetVolume() <= 0 ) {
  4055.                 b[0][0] = b[0][1] = b[0][2] = -8;
  4056.                 b[1][0] = b[1][1] = b[1][2] = 8;
  4057.             }
  4058.             if ( ent->fl.isDormant ) {
  4059.                 gameRenderWorld->DebugBounds( colorYellow, b, ent->GetPhysics()->GetOrigin() );
  4060.             } else {
  4061.                 gameRenderWorld->DebugBounds( colorGreen, b, ent->GetPhysics()->GetOrigin() );
  4062.             }
  4063.         }
  4064.     }
  4065.  
  4066. // RAVEN BEGIN
  4067. // bdube: client entities
  4068.     if ( cl_showEntityInfo.GetBool ( ) ) {
  4069.         rvClientEntity* cent;
  4070.         for( cent = clientSpawnedEntities.Next(); cent != NULL; cent = cent->spawnNode.Next() ) {
  4071.             cent->DrawDebugInfo ( );
  4072.         }                
  4073.     }
  4074. // RAVEN END
  4075.  
  4076.     if ( g_showTargets.GetBool() ) {
  4077.         ShowTargets();
  4078.     }
  4079.  
  4080.     if ( g_showTriggers.GetBool() ) {
  4081.         idTrigger::DrawDebugInfo();
  4082.     }
  4083.  
  4084.     if ( ai_showCombatNodes.GetBool() ) {
  4085. //        idCombatNode::DrawDebugInfo();
  4086.     }
  4087.  
  4088.     if ( ai_showPaths.GetBool() ) {
  4089.         idPathCorner::DrawDebugInfo();
  4090.     }
  4091.  
  4092.     if ( g_editEntityMode.GetBool() ) {
  4093.         if ( gameLocal.isMultiplayer )     {
  4094.             g_editEntityMode.SetInteger(0);
  4095.             Printf( "Not allowed in multiplayer.\n" );
  4096.         } else {
  4097.             editEntities->DisplayEntities();
  4098.         }
  4099.     }
  4100.  
  4101.     if ( g_showCollisionWorld.GetBool() ) {
  4102.         collisionModelManager->DrawModel( clip[0]->GetWorldCollisionModel(), vec3_origin, mat3_identity, origin, mat3_identity, 128.0f );
  4103.     }
  4104.  
  4105.     if ( g_showCollisionModels.GetBool() ) {
  4106.         if( g_showCollisionModels.GetInteger() == 2 ) {
  4107.             clip[ 0 ]->DrawClipModels( player->GetEyePosition(), g_maxShowDistance.GetFloat(), pm_thirdPerson.GetBool() ? NULL : player, &idPlayer::GetClassType() );
  4108.         } else {
  4109.             clip[ 0 ]->DrawClipModels( player->GetEyePosition(), g_maxShowDistance.GetFloat(), pm_thirdPerson.GetBool() ? NULL : player );
  4110.         }
  4111.         
  4112.     }
  4113.  
  4114.     if ( g_showCollisionTraces.GetBool() ) {
  4115.         clip[ 0 ]->PrintStatistics();
  4116.     }
  4117.  
  4118.     if ( g_showPVS.GetInteger() ) {
  4119.         pvs.DrawPVS( origin, ( g_showPVS.GetInteger() == 2 ) ? PVS_ALL_PORTALS_OPEN : PVS_NORMAL );
  4120.     }
  4121.  
  4122. // RAVEN BEGIN
  4123. // rjohnson: added debug hud
  4124.     if ( gameDebug.IsHudActive ( DBGHUD_PHYSICS ) )    {
  4125.         clip[ 0 ]->DebugHudStatistics();
  4126.     }
  4127.  
  4128.     clip[ 0 ]->ClearStatistics();
  4129. // RAVEN END
  4130.  
  4131.     if ( aas_test.GetInteger() >= 0 ) {
  4132.         idAAS *aas = GetAAS( aas_test.GetInteger() );
  4133.         if ( aas ) {
  4134.             aas->Test( origin );
  4135.             if ( ai_testPredictPath.GetBool() ) {
  4136.                 idVec3 velocity;
  4137.                 predictedPath_t path;
  4138.  
  4139.                 velocity.x = idMath::Cos( DEG2RAD( player->viewAngles.yaw ) ) * 100.0f;
  4140.                 velocity.y = idMath::Sin( DEG2RAD( player->viewAngles.yaw ) ) * 100.0f;
  4141.                 velocity.z = 0.0f;
  4142.                 idAI::PredictPath( player, aas, origin, velocity, 1000, 100, SE_ENTER_OBSTACLE | SE_BLOCKED | SE_ENTER_LEDGE_AREA, path );
  4143.             }
  4144.         }
  4145. // RAVEN BEGIN 
  4146. // rjohnson: added more debug drawing
  4147.         if ( aas_showAreas.GetInteger() == 3 ) {
  4148.             for( int i=0; i<aasNames.Num(); i++ ) {
  4149.                 aas = GetAAS( i );
  4150.                 if ( !aas || !aas->IsValid() ) {
  4151.                     continue;
  4152.                 }
  4153.  
  4154.                 if ( aas->GetSettings()->debugDraw ) {
  4155.                     aas->ShowAreas( origin );
  4156.                 }
  4157.             }
  4158.         }
  4159.         if ( aas_showProblemAreas.GetInteger() == 3 ) {
  4160.             for( int i=0; i<aasNames.Num(); i++ ) {
  4161.                 aas = GetAAS( i );
  4162.                 if ( !aas || !aas->IsValid() ) {
  4163.                     continue;
  4164.                 }
  4165.  
  4166.                 if ( aas->GetSettings()->debugDraw ) {
  4167.                     aas->ShowAreas( origin, true );
  4168.                 }
  4169.             }
  4170.         }
  4171. // RAVEN END
  4172.     }
  4173.  
  4174.     if ( ai_showObstacleAvoidance.GetInteger() == 2 ) {
  4175.         idAAS *aas = GetAAS( 0 );
  4176.         if ( aas ) {
  4177.             idVec3 seekPos;
  4178.             obstaclePath_t path;
  4179.  
  4180.             seekPos = player->GetPhysics()->GetOrigin() + player->viewAxis[0] * 200.0f;
  4181.             idAI::FindPathAroundObstacles( player->GetPhysics(), aas, NULL, player->GetPhysics()->GetOrigin(), seekPos, path );
  4182.         }
  4183.     }
  4184.  
  4185.     // collision map debug output
  4186.     collisionModelManager->DebugOutput( player->GetEyePosition(), mat3_identity );
  4187.  
  4188. // RAVEN BEGIN
  4189. // jscott: for debugging playbacks
  4190.     if( g_showPlayback.GetInteger() ) {
  4191.         gameEdit->DrawPlaybackDebugInfo();
  4192.     }
  4193. // RAVEN END
  4194.  
  4195. // RAVEN BEGIN
  4196. // ddynerman: SD's clip sector code
  4197.     if ( g_showClipSectors.GetBool() ) {
  4198.         clip[ 0 ]->DrawClipSectors();
  4199.     }
  4200.  
  4201.     if ( g_showAreaClipSectors.GetFloat() ) {
  4202.         clip[ 0 ]->DrawAreaClipSectors( g_showAreaClipSectors.GetFloat() );
  4203.     }
  4204. // RAVEN END
  4205. }
  4206.  
  4207. /*
  4208. ==================
  4209. idGameLocal::NumAAS
  4210. ==================
  4211. */
  4212. int    idGameLocal::NumAAS( void ) const {
  4213.     return aasList.Num();
  4214. }
  4215.  
  4216. /*
  4217. ==================
  4218. idGameLocal::GetAAS
  4219. ==================
  4220. */
  4221. idAAS *idGameLocal::GetAAS( int num ) const {
  4222.     if ( ( num >= 0 ) && ( num < aasList.Num() ) ) {
  4223.         if ( aasList[ num ] && aasList[ num ]->GetSettings() ) {
  4224.             return aasList[ num ];
  4225.         }
  4226.     }
  4227.     return NULL;
  4228. }
  4229.  
  4230. /*
  4231. ==================
  4232. idGameLocal::GetAAS
  4233. ==================
  4234. */
  4235. idAAS *idGameLocal::GetAAS( const char *name ) const {
  4236.     int i;
  4237.  
  4238.     for ( i = 0; i < aasNames.Num(); i++ ) {
  4239.         if ( aasNames[ i ] == name ) {
  4240.             if ( !aasList[ i ]->GetSettings() ) {
  4241.                 return NULL;
  4242.             } else {
  4243.                 return aasList[ i ];
  4244.             }
  4245.         }
  4246.     }
  4247.     return NULL;
  4248. }
  4249.  
  4250. /*
  4251. ==================
  4252. idGameLocal::SetAASAreaState
  4253. ==================
  4254. */
  4255. void idGameLocal::SetAASAreaState( const idBounds &bounds, const int areaContents, bool closed ) {
  4256.     int i;
  4257.  
  4258.     for( i = 0; i < aasList.Num(); i++ ) {
  4259.         aasList[ i ]->SetAreaState( bounds, areaContents, closed );
  4260.     }
  4261. }
  4262.  
  4263. /*
  4264. ==================
  4265. idGameLocal::AddAASObstacle
  4266. ==================
  4267. */
  4268. aasHandle_t idGameLocal::AddAASObstacle( const idBounds &bounds ) {
  4269.     int i;
  4270.     aasHandle_t obstacle;
  4271.     aasHandle_t check;
  4272.  
  4273.     if ( !aasList.Num() ) {
  4274.         return -1;
  4275.     }
  4276.  
  4277.     obstacle = aasList[ 0 ]->AddObstacle( bounds );
  4278.     for( i = 1; i < aasList.Num(); i++ ) {
  4279.         check = aasList[ i ]->AddObstacle( bounds );
  4280.         assert( check == obstacle );
  4281.     }
  4282.  
  4283.     return obstacle;
  4284. }
  4285.  
  4286. /*
  4287. ==================
  4288. idGameLocal::RemoveAASObstacle
  4289. ==================
  4290. */
  4291. void idGameLocal::RemoveAASObstacle( const aasHandle_t handle ) {
  4292.     int i;
  4293.  
  4294.     for( i = 0; i < aasList.Num(); i++ ) {
  4295.         aasList[ i ]->RemoveObstacle( handle );
  4296.     }
  4297. }
  4298.  
  4299. /*
  4300. ==================
  4301. idGameLocal::RemoveAllAASObstacles
  4302. ==================
  4303. */
  4304. void idGameLocal::RemoveAllAASObstacles( void ) {
  4305.     int i;
  4306.  
  4307.     for( i = 0; i < aasList.Num(); i++ ) {
  4308.         aasList[ i ]->RemoveAllObstacles();
  4309.     }
  4310. }
  4311.  
  4312. // RAVEN BEGIN
  4313. // mwhitlock: added entity memory usage stuff.
  4314. /*
  4315. ==================
  4316. idGameLocal::GetEntityMemoryUsage
  4317.  
  4318. Compute combined total memory footprint of server and client entity storage.
  4319. ==================
  4320. */
  4321.  
  4322. size_t idGameLocal::GetEntityMemoryUsage ( void ) const {
  4323.  
  4324.     // Server ents.
  4325.     size_t serverEntitiesSize = 0;
  4326.     for( idEntity *ent = gameLocal.spawnedEntities.Next(); ent != NULL; ent = ent->spawnNode.Next() ) {
  4327.          serverEntitiesSize += sizeof( idEntity );
  4328.     }
  4329.     
  4330.     // Client ents.
  4331.     size_t clientEntitiesSize = 0;
  4332.     for( rvClientEntity *ent = gameLocal.clientSpawnedEntities.Next() ; ent != NULL; ent = ent->spawnNode.Next() ) {
  4333.          clientEntitiesSize += ent->Size();
  4334.     }
  4335.     
  4336.     return serverEntitiesSize + clientEntitiesSize;
  4337. }
  4338. // RAVEN END
  4339.  
  4340. /*
  4341. ==================
  4342. idGameLocal::CheatsOk
  4343. ==================
  4344. */
  4345. bool idGameLocal::CheatsOk( bool requirePlayer ) {
  4346.     idPlayer *player;
  4347.  
  4348.     if ( isMultiplayer && !cvarSystem->GetCVarBool( "net_allowCheats" ) ) {
  4349.         Printf( "Not allowed in multiplayer.\n" );
  4350.         return false;
  4351.     }
  4352.  
  4353.     if ( developer.GetBool() ) {
  4354.         return true;
  4355.     }
  4356.  
  4357.     player = GetLocalPlayer();
  4358.     if ( !requirePlayer || ( player && ( player->health > 0 ) ) ) {
  4359.         return true;
  4360.     }
  4361.  
  4362.     Printf( "You must be alive to use this command.\n" );
  4363.  
  4364.     return false;
  4365. }
  4366.  
  4367. /*
  4368. ===================
  4369. idGameLocal::RegisterEntity
  4370. ===================
  4371. */
  4372. void idGameLocal::RegisterEntity( idEntity *ent ) {
  4373.     int spawn_entnum;
  4374.  
  4375.     if ( spawnCount >= ( 1 << ( 32 - GENTITYNUM_BITS ) ) ) {
  4376.         Error( "idGameLocal::RegisterEntity: spawn count overflow" );
  4377.     }
  4378.  
  4379.     if ( !spawnArgs.GetInt( "spawn_entnum", "0", spawn_entnum ) ) {
  4380.         while( entities[firstFreeIndex] && firstFreeIndex < ENTITYNUM_MAX_NORMAL ) {
  4381.             firstFreeIndex++;
  4382.         }
  4383.         if ( firstFreeIndex >= ENTITYNUM_MAX_NORMAL ) {
  4384.             Error( "no free entities" );
  4385.         }
  4386.         spawn_entnum = firstFreeIndex++;
  4387.     }
  4388.  
  4389.     entities[ spawn_entnum ] = ent;
  4390.     spawnIds[ spawn_entnum ] = spawnCount++;
  4391.     ent->entityNumber = spawn_entnum;
  4392.     ent->spawnNode.AddToEnd( spawnedEntities );
  4393.     ent->spawnArgs.TransferKeyValues( spawnArgs );
  4394.  
  4395.     if ( spawn_entnum >= num_entities ) {
  4396.         num_entities++;
  4397.     }
  4398.  
  4399. // RAVEN BEGIN
  4400. // bdube: keep track of last time an entity was registered    
  4401.     entityRegisterTime = time;
  4402. // RAVEN END
  4403. }
  4404.  
  4405. /*
  4406. ===================
  4407. idGameLocal::UnregisterEntity
  4408. ===================
  4409. */
  4410. void idGameLocal::UnregisterEntity( idEntity *ent ) {
  4411.     assert( ent );
  4412.  
  4413.     if ( editEntities ) {
  4414.         editEntities->RemoveSelectedEntity( ent );
  4415.     }
  4416.  
  4417.     if ( ( ent->entityNumber != ENTITYNUM_NONE ) && ( entities[ ent->entityNumber ] == ent ) ) {
  4418.         ent->spawnNode.Remove();
  4419.         entities[ ent->entityNumber ] = NULL;
  4420.         spawnIds[ ent->entityNumber ] = -1;
  4421.         if ( ent->entityNumber >= MAX_CLIENTS && ent->entityNumber < firstFreeIndex ) {
  4422.             firstFreeIndex = ent->entityNumber;
  4423.         }
  4424.         ent->entityNumber = ENTITYNUM_NONE;
  4425.     }
  4426.  
  4427. // RAVEN BEGIN
  4428. // bdube: keep track of last time an entity was registered    
  4429.     entityRegisterTime = time;
  4430. // RAVEN END
  4431. }
  4432.  
  4433. /*
  4434. ================
  4435. idGameLocal::SpawnEntityType
  4436. ================
  4437. */
  4438. idEntity *idGameLocal::SpawnEntityType( const idTypeInfo &classdef, const idDict *args, bool bIsClientReadSnapshot ) {
  4439.     idClass *obj;
  4440.  
  4441. #ifdef _DEBUG
  4442.     if ( isClient ) {
  4443.         assert( bIsClientReadSnapshot );
  4444.     }
  4445. #endif
  4446.  
  4447. // RAVEN BEGIN
  4448. // jnewquist: Use accessor for static class type 
  4449.     if ( !classdef.IsType( idEntity::GetClassType() ) ) {
  4450. // RAVEN END
  4451.         Error( "Attempted to spawn non-entity class '%s'", classdef.classname );
  4452.     }
  4453.  
  4454.     try {
  4455.         if ( args ) {
  4456.             spawnArgs = *args;
  4457.         } else {
  4458.             spawnArgs.Clear();
  4459.         }
  4460.         obj = classdef.CreateInstance();
  4461.         obj->CallSpawn();
  4462.     }
  4463.     
  4464.     catch( idAllocError & ) {
  4465.         obj = NULL;
  4466.     }
  4467.     spawnArgs.Clear();
  4468.  
  4469.     return static_cast<idEntity *>(obj);
  4470. }
  4471.  
  4472. /*
  4473. ===================
  4474. idGameLocal::SpawnEntityDef
  4475.  
  4476. Finds the spawn function for the entity and calls it,
  4477. returning false if not found
  4478. ===================
  4479. */
  4480. bool idGameLocal::SpawnEntityDef( const idDict &args, idEntity **ent, bool setDefaults ) {
  4481.     const char    *classname;
  4482.     const char    *spawn;
  4483.     idTypeInfo    *cls;
  4484.     idClass        *obj;
  4485.     idStr        error;
  4486.     const char  *name;
  4487.  
  4488.     TIME_THIS_SCOPE( __FUNCLINE__);
  4489.     
  4490.     if ( ent ) {
  4491.         *ent = NULL;
  4492.     }
  4493.  
  4494.     spawnArgs = args;
  4495.  
  4496.     if ( spawnArgs.GetBool( "nospawn" ) )
  4497.     {//not meant to actually spawn, just there for some compiling process
  4498.         return false;
  4499.     }
  4500.  
  4501.     if ( spawnArgs.GetString( "name", "", &name ) ) {
  4502. // RAVEN BEGIN
  4503. // jscott: fixed sprintf to idStr
  4504.         error = va( " on '%s'", name );
  4505. // RAVEN END
  4506.     }
  4507.     spawnArgs.GetString( "classname", NULL, &classname );
  4508.  
  4509.     const idDeclEntityDef *def = FindEntityDef( classname, false );
  4510.     if ( !def ) {
  4511. // RAVEN BEGIN
  4512. // jscott: a NULL classname would crash Warning()
  4513.         if( classname ) {
  4514.             Warning( "Unknown classname '%s'%s.", classname, error.c_str() );
  4515.         }
  4516. // RAVEN END
  4517.         return false;
  4518.     }
  4519.  
  4520.     spawnArgs.SetDefaults( &def->dict );
  4521.  
  4522. // RAVEN BEGIN
  4523. // rjohnson: entity usage stats
  4524.     if ( g_keepEntityStats.GetBool() ) {
  4525.         if ( idStr::Icmp( classname, "func_spawner" ) == 0 || 
  4526.              idStr::Icmp( classname, "func_spawner_enemy" ) == 0 ) {
  4527.             // special case for spawners
  4528.             for( int i = 1; ; i++ ) {
  4529.                 char        tempSpawn[128];
  4530.                 const char    *tempClassname;
  4531.  
  4532.                 sprintf( tempSpawn, "def_spawn_type%d", i );
  4533.                 tempClassname = spawnArgs.GetString( tempSpawn, NULL );
  4534.                 if ( tempClassname ) {
  4535.                     const idDeclEntityDef *tempDef = FindEntityDef( tempClassname, false );
  4536.  
  4537.                     if ( tempDef ) {
  4538.                         idDict    tempArgs = tempDef->dict;
  4539.  
  4540.                         tempArgs.Set( "mapFileName", mapFileNameStripped );
  4541.                         entityUsageList.Insert( tempArgs );
  4542.                     }
  4543.                 } else {
  4544.                     break;
  4545.                 }
  4546.             }
  4547.         }
  4548.         else if ( def->dict.GetBool( "report_stats" ) ) {
  4549.             idDict    tempArgs = spawnArgs;
  4550.             tempArgs.Set( "mapFileName", mapFileNameStripped );
  4551.             entityUsageList.Insert( tempArgs );
  4552.         }
  4553.     }
  4554. // RAVEN END
  4555.  
  4556.     // check if we should spawn a class object
  4557.     spawnArgs.GetString( "spawnclass", NULL, &spawn );
  4558.     if ( spawn ) {
  4559.  
  4560.         cls = idClass::GetClass( spawn );
  4561.         if ( !cls ) {
  4562.             Warning( "Could not spawn '%s'.  Class '%s' not found%s.", classname, spawn, error.c_str() );
  4563.             return false;
  4564.         }
  4565.  
  4566.         obj = cls->CreateInstance();
  4567.         if ( !obj ) {
  4568.             Warning( "Could not spawn '%s'. Instance could not be created%s.", classname, error.c_str() );
  4569.             return false;
  4570.         }
  4571.  
  4572.         obj->CallSpawn();
  4573.  
  4574. // RAVEN BEGIN
  4575. // jnewquist: Use accessor for static class type 
  4576.         if ( ent && obj->IsType( idEntity::GetClassType() ) ) {
  4577. // RAVEN END
  4578.             *ent = static_cast<idEntity *>(obj);
  4579.         }
  4580.  
  4581.         return true;
  4582.     }
  4583.  
  4584.     // check if we should call a script function to spawn
  4585.     spawnArgs.GetString( "spawnfunc", NULL, &spawn );
  4586.     if ( spawn ) {
  4587.         const function_t *func = program.FindFunction( spawn );
  4588.         if ( !func ) {
  4589.             Warning( "Could not spawn '%s'.  Script function '%s' not found%s.", classname, spawn, error.c_str() );
  4590.             return false;
  4591.         }
  4592.         idThread *thread = new idThread( func );
  4593.         thread->DelayedStart( 0 );
  4594.  
  4595.         return true;
  4596.     }
  4597.  
  4598.     Warning( "%s doesn't include a spawnfunc or spawnclass%s.", classname, error.c_str() );
  4599.     return false;
  4600. }
  4601.  
  4602. // abahr:
  4603. idEntity* idGameLocal::SpawnEntityDef( const char* entityDefName, const idDict* additionalArgs ) {
  4604.     idDict            finalArgs;
  4605.     const idDict*    entityDict = NULL;
  4606.     idEntity*        entity = NULL;
  4607.     
  4608.     TIME_THIS_SCOPE( __FUNCLINE__);
  4609.  
  4610.     if( !entityDefName ) {
  4611.         return NULL;
  4612.     }
  4613.  
  4614.     entityDict = FindEntityDefDict( entityDefName, false );
  4615.     if( !entityDict ) {
  4616.         return NULL;
  4617.     }
  4618.  
  4619.     if( !additionalArgs ) {
  4620.         SpawnEntityDef( *entityDict, &entity );
  4621.     } else {
  4622.         finalArgs.Copy( *entityDict );
  4623.         finalArgs.Copy( *additionalArgs );
  4624.         SpawnEntityDef( finalArgs, &entity );
  4625.     }
  4626.  
  4627.     return entity;
  4628. }
  4629. // RAVEN END
  4630.  
  4631. /*
  4632. ================
  4633. idGameLocal::FindEntityDef
  4634. ================
  4635. */
  4636. const idDeclEntityDef *idGameLocal::FindEntityDef( const char *name, bool makeDefault ) const {
  4637.     TIME_THIS_SCOPE( __FUNCLINE__);
  4638.     const idDecl *decl = NULL;
  4639.     if ( isMultiplayer ) {
  4640.         decl = declManager->FindType( DECL_ENTITYDEF, va( "%s_mp", name ), false );
  4641.     }
  4642.     if ( !decl ) {
  4643.         decl = declManager->FindType( DECL_ENTITYDEF, name, makeDefault );
  4644.     }
  4645.     return static_cast<const idDeclEntityDef *>( decl );
  4646. }
  4647.  
  4648. /*
  4649. ================
  4650. idGameLocal::FindEntityDefDict
  4651. ================
  4652. */
  4653. const idDict *idGameLocal::FindEntityDefDict( const char *name, bool makeDefault ) const {
  4654.     TIME_THIS_SCOPE( __FUNCLINE__);
  4655.     const idDeclEntityDef *decl = FindEntityDef( name, makeDefault );
  4656.     return decl ? &decl->dict : NULL;
  4657. }
  4658.  
  4659. /*
  4660. ================
  4661. idGameLocal::InhibitEntitySpawn
  4662. ================
  4663. */
  4664. bool idGameLocal::InhibitEntitySpawn( idDict &spawnArgs ) {
  4665.     
  4666.     bool result = false;
  4667.  
  4668.     if ( isMultiplayer ) {
  4669.         spawnArgs.GetBool( "not_multiplayer", "0", result );
  4670.     } else if ( g_skill.GetInteger() == 0 ) {
  4671.         spawnArgs.GetBool( "not_easy", "0", result );
  4672.     } else if ( g_skill.GetInteger() == 1 ) {
  4673.         spawnArgs.GetBool( "not_medium", "0", result );
  4674.     } else {
  4675.         spawnArgs.GetBool( "not_hard", "0", result );
  4676.     }
  4677.  
  4678.     const char *name;
  4679. #ifndef ID_DEMO_BUILD
  4680.     if ( g_skill.GetInteger() == 3 ) { 
  4681.         name = spawnArgs.GetString( "classname" );
  4682.         if ( idStr::Icmp( name, "item_medkit" ) == 0 || idStr::Icmp( name, "item_medkit_small" ) == 0 ) {
  4683.             result = true;
  4684.         }
  4685.     }
  4686. #endif
  4687.  
  4688. // RAVEN BEGIN
  4689. // bdube: suppress ents that don't match the entity filter
  4690.     const char* entityFilter;
  4691.     if ( serverInfo.GetString( "si_entityFilter", "", &entityFilter ) && *entityFilter ) {
  4692.         if ( spawnArgs.MatchPrefix ( "filter_" ) && !spawnArgs.GetBool ( va("filter_%s", entityFilter) ) ) {
  4693.             return true;
  4694.         }
  4695.     }
  4696. // RAVEN END
  4697.  
  4698.     return result;
  4699. }
  4700.  
  4701. /*
  4702. ================
  4703. idGameLocal::SetSkill
  4704. ================
  4705. */
  4706. void idGameLocal::SetSkill( int value ) {
  4707.     int skill_level;
  4708.  
  4709.     if ( value < 0 ) {
  4710.         skill_level = 0;
  4711.     } else if ( value > 3 ) {
  4712.         skill_level = 3;
  4713.     } else {
  4714.         skill_level = value;
  4715.     }
  4716.  
  4717.     g_skill.SetInteger( skill_level );
  4718. }
  4719.  
  4720. /*
  4721. ==============
  4722. idGameLocal::GameState
  4723.  
  4724. Used to allow entities to know if they're being spawned during the initial spawn.
  4725. ==============
  4726. */
  4727. gameState_t    idGameLocal::GameState( void ) const {
  4728.     return gamestate;
  4729. }
  4730.  
  4731. /*
  4732. ==============
  4733. idGameLocal::SpawnMapEntities
  4734.  
  4735. Parses textual entity definitions out of an entstring and spawns gentities.
  4736. ==============
  4737. */
  4738. // RAVEN BEGIN
  4739. // ddynerman: multiple game instances
  4740. void idGameLocal::SpawnMapEntities( int instance, unsigned short* entityNumIn, unsigned short* entityNumOut, int* startSpawnCount ) {
  4741. // RAVEN END
  4742.     int            i;
  4743.     int            num;
  4744.     int            inhibit;
  4745.     int            latchedSpawnCount = -1;
  4746.     idMapEntity    *mapEnt;
  4747.     int            numEntities;
  4748.     idDict        args;
  4749.     idDict        items;
  4750.  
  4751.     Printf( "Spawning entities\n" );
  4752.     
  4753.     TIME_THIS_SCOPE( __FUNCLINE__);
  4754.  
  4755.     if ( mapFile == NULL ) {
  4756.         Printf("No mapfile present\n");
  4757.         return;
  4758.     }
  4759.  
  4760.     SetSkill( g_skill.GetInteger() );
  4761.  
  4762.     numEntities = mapFile->GetNumEntities();
  4763.     if ( numEntities == 0 ) {
  4764.         Error( "...no entities" );
  4765.     }
  4766.  
  4767. // RAVEN BEGIN
  4768. // ddynerman:    on the server, perform world-initialization when spawning instance 0 only and while starting up
  4769. //                on the client, perform world-init when spawning while starting up, as client main instance may not be ID 0
  4770. //                always spawn world-init in single-player
  4771.     num = inhibit = 0;
  4772.  
  4773.     // the worldspawn is a special that performs any global setup
  4774.     // needed by a level
  4775.     if( ( gameLocal.isServer && instance == 0 && gamestate == GAMESTATE_STARTUP ) || (gameLocal.isClient && gamestate == GAMESTATE_STARTUP) || !gameLocal.isMultiplayer ) { 
  4776.         mapEnt = mapFile->GetEntity( 0 );
  4777.         args = mapEnt->epairs;
  4778.         args.SetInt( "spawn_entnum", ENTITYNUM_WORLD );
  4779.         
  4780.         // on the client, spawnCount won't always start at INITIAL_SPAWN_COUNT (see rvInstance::Populate())
  4781.         // make sure the world and physics ent get the right spawn id
  4782.         if( gameLocal.isClient && spawnCount != INITIAL_SPAWN_COUNT ) {
  4783.             latchedSpawnCount = spawnCount;
  4784.             spawnCount = INITIAL_SPAWN_COUNT;
  4785.         }
  4786.  
  4787. // abahr: precache stuff on worldSpawn like player def and other misc things
  4788.         CacheDictionaryMedia( &args );
  4789. // jnewquist: Use accessor for static class type
  4790.         if ( !SpawnEntityDef( args ) || !entities[ ENTITYNUM_WORLD ] || !entities[ ENTITYNUM_WORLD ]->IsType( idWorldspawn::GetClassType() ) ) {
  4791.             Error( "Problem spawning world entity" );
  4792.         }
  4793.         num++;
  4794.  
  4795. // bdube: dummy entity for client entities with physics
  4796.         args.Clear ( );
  4797.         args.SetInt( "spawn_entnum", ENTITYNUM_CLIENT );
  4798. // jnewquist: Use accessor for static class type 
  4799.         if ( !SpawnEntityType( rvClientPhysics::GetClassType(), &args, true ) || !entities[ ENTITYNUM_CLIENT ] ) {    
  4800.             Error( "Problem spawning client physics entity" );
  4801.         }
  4802.  
  4803.         if( gameLocal.isClient && latchedSpawnCount != -1 ) {
  4804.             spawnCount = latchedSpawnCount;
  4805.         }
  4806.  
  4807.         isMapEntity[ ENTITYNUM_CLIENT ] = true;
  4808.         isMapEntity[ ENTITYNUM_WORLD ] = true;
  4809. // RAVEN END
  4810.     } 
  4811.  
  4812.     // capture spawn count of start of map entities (after we've spawned in the physics ents)
  4813.     if( startSpawnCount ) {
  4814.         (*startSpawnCount) = spawnCount;
  4815.     }
  4816.  
  4817.     for ( i = 1 ; i < numEntities ; i++ ) {
  4818. //        if ( (i % 100) == 0 ) {
  4819. //            PACIFIER_UPDATE;
  4820. //        }
  4821.         mapEnt = mapFile->GetEntity( i );
  4822.         args = mapEnt->epairs;
  4823.  
  4824. // RAVEN BEGIN
  4825. // ddynerman: merge the dicts ahead of SpawnEntityDef() so we can inhibit using merged info
  4826.         const idDeclEntityDef* entityDef = FindEntityDef( args.GetString( "classname" ), false );
  4827.         
  4828.         if( entityDef == NULL ) {
  4829.             gameLocal.Error( "idGameLocal::SpawnMapEntities() - Unknown entity classname '%s'\n", args.GetString( "classname" ) );
  4830.             return;
  4831.         }
  4832.         args.SetDefaults( &(entityDef->dict) );
  4833. // RAVEN END
  4834.  
  4835.         if ( !InhibitEntitySpawn( args ) ) {
  4836.  
  4837. #ifndef _XENON            
  4838.             if( args.GetBool( "inv_item" ) ) {
  4839.                 if( !items.GetBool( args.GetString( "inv_icon" ) ) ) {
  4840.                     networkSystem->AddLoadingIcon( args.GetString( "inv_icon" ) );
  4841.                     networkSystem->SetLoadingText( common->GetLocalizedString( args.GetString( "inv_name" ) ) );
  4842.                     items.SetBool( args.GetString( "inv_icon" ), true );
  4843.                 }
  4844.             }
  4845. #endif
  4846.             // precache any media specified in the map entity
  4847.             CacheDictionaryMedia( &args );
  4848. // RAVEN BEGIN
  4849.             if( instance != 0 ) {
  4850. // ddynerman: allow this function to be called multiple-times to respawn map entities in other instances
  4851.                 args.SetInt( "instance", instance );
  4852.                 args.Set( "name", va( "%s_instance%d", args.GetString( "name" ), instance ) );
  4853.                 //gameLocal.Printf( "Instance %d: Spawning %s (class: %s)\n", instance, args.GetString( "name" ), args.GetString( "classname" ) ); 
  4854.                 
  4855.                 // need a better way to do this - map entities that target other map entities need
  4856.                 // to target the ones in the correct instance.  
  4857.                 idStr target;
  4858.                 if( args.GetString( "target", "", target ) ) {
  4859.                     args.Set( "target", va( "%s_instance%d", target.c_str(), instance ) );
  4860.                 }
  4861.  
  4862.                 // and also udpate binds on a per-instance bases
  4863.                 idStr bind;
  4864.                 if( args.GetString( "bind", "", bind ) ) {
  4865.                     args.Set( "bind", va( "%s_instance%d", bind.c_str(), instance ) );
  4866.                 }
  4867.  
  4868.                 // and also door triggers
  4869.                 idStr triggerOnOpen;
  4870.                 if( args.GetString( "triggerOnOpen", "", triggerOnOpen ) ) {
  4871.                     args.Set( "triggerOnOpen", va( "%s_instance%d", triggerOnOpen.c_str(), instance ) );
  4872.                 }
  4873.  
  4874.                 idStr triggerOpened;
  4875.                 if( args.GetString( "triggerOpened", "", triggerOpened ) ) {
  4876.                     args.Set( "triggerOpened", va( "%s_instance%d", triggerOpened.c_str(), instance ) );
  4877.                 }
  4878.             }
  4879.  
  4880.             if( entityNumIn ) {
  4881.                 if( entityNumIn[ i ] < 0 || entityNumIn[ i ] >= MAX_GENTITIES ) {
  4882.                     // this entity was not spawned in on the server, ignore it here
  4883.                     if( gameLocal.isClient ) {
  4884.                         inhibit++;
  4885.                         continue;
  4886.                     } else {
  4887.                         // on the server, this is an error
  4888.                         gameLocal.Error( "idGameLocal::SpawnMapEntities() - Trying to spawn a map entity with number -1 on the server\n" );
  4889.                         break;
  4890.                     }
  4891.  
  4892.                 }
  4893.                 args.SetInt( "spawn_entnum", entityNumIn[ i ] );
  4894.             }
  4895.  
  4896.             idEntity* ent = NULL;
  4897.             SpawnEntityDef( args, &ent );
  4898.     
  4899.             if( ent && entityNumOut ) {
  4900.                 entityNumOut[ i ] = ent->entityNumber;
  4901.             }
  4902.  
  4903.             if( gameLocal.GetLocalPlayer() && ent && gameLocal.isServer && instance != gameLocal.GetLocalPlayer()->GetInstance() ) {
  4904.                 // if we're spawning entities not in our instance, tell them not to draw
  4905.                 ent->BecomeInactive( TH_UPDATEVISUALS );
  4906.             }
  4907.  
  4908.             if ( ent ) {
  4909.                 isMapEntity[ ent->entityNumber ] = true;
  4910.             }
  4911. // RAVEN END
  4912.             num++;
  4913.         } else {
  4914.             inhibit++;
  4915.         }
  4916.     }
  4917.  
  4918.     Printf( "...%i entities spawned, %i inhibited\n\n", num, inhibit );
  4919. }
  4920.  
  4921.  
  4922. /*
  4923. ================
  4924. idGameLocal::AddEntityToHash
  4925. ================
  4926. */
  4927. void idGameLocal::AddEntityToHash( const char *name, idEntity *ent ) {
  4928.     if ( FindEntity( name ) ) {
  4929.         Error( "Multiple entities named '%s'", name );
  4930.     }
  4931.     entityHash.Add( entityHash.GenerateKey( name, true ), ent->entityNumber );
  4932. }
  4933.  
  4934. /*
  4935. ================
  4936. idGameLocal::RemoveEntityFromHash
  4937. ================
  4938. */
  4939. bool idGameLocal::RemoveEntityFromHash( const char *name, idEntity *ent ) {
  4940.     int hash, i;
  4941.  
  4942.     hash = entityHash.GenerateKey( name, true );
  4943.     for ( i = entityHash.First( hash ); i != -1; i = entityHash.Next( i ) ) {
  4944.         if ( entities[i] && entities[i] == ent && entities[i]->name.Icmp( name ) == 0 ) {
  4945.             entityHash.Remove( hash, i );
  4946.             return true;
  4947.         }
  4948.     }
  4949.     return false;
  4950. }
  4951.  
  4952. /*
  4953. ================
  4954. idGameLocal::GetTargets
  4955. ================
  4956. */
  4957. int idGameLocal::GetTargets( const idDict &args, idList< idEntityPtr<idEntity> > &list, const char *ref ) const {
  4958.     int i, num, refLength;
  4959.     const idKeyValue *arg;
  4960.     idEntity *ent;
  4961.  
  4962.     list.Clear();
  4963.  
  4964.     refLength = strlen( ref );
  4965.     num = args.GetNumKeyVals();
  4966.     for( i = 0; i < num; i++ ) {
  4967.  
  4968.         arg = args.GetKeyVal( i );
  4969.         if ( arg->GetKey().Icmpn( ref, refLength ) == 0 ) {
  4970.  
  4971.             ent = FindEntity( arg->GetValue() );
  4972.             if ( ent ) {
  4973.                 idEntityPtr<idEntity> &entityPtr = list.Alloc();
  4974.                 entityPtr = ent;
  4975.             }
  4976.         }
  4977.     }
  4978.  
  4979.     return list.Num();
  4980. }
  4981.  
  4982. /*
  4983. =============
  4984. idGameLocal::GetTraceEntity
  4985.  
  4986. returns the master entity of a trace.  for example, if the trace entity is the player's head, it will return the player.
  4987. =============
  4988. */
  4989. idEntity *idGameLocal::GetTraceEntity( const trace_t &trace ) const {
  4990.     idEntity *master;
  4991.  
  4992.     if ( !entities[ trace.c.entityNum ] ) {
  4993.         return NULL;
  4994.     }
  4995.     master = entities[ trace.c.entityNum ]->GetBindMaster();
  4996.     if ( master ) {
  4997.         return master;
  4998.     }
  4999.     return entities[ trace.c.entityNum ];
  5000. }
  5001.  
  5002. /*
  5003. =============
  5004. idGameLocal::ArgCompletion_EntityName
  5005.  
  5006. Argument completion for entity names
  5007. =============
  5008. */
  5009. void idGameLocal::ArgCompletion_EntityName( const idCmdArgs &args, void(*callback)( const char *s ) ) {
  5010.     int i;
  5011.  
  5012.     for( i = 0; i < gameLocal.num_entities; i++ ) {
  5013.         if ( gameLocal.entities[ i ] ) {
  5014.             callback( va( "%s %s", args.Argv( 0 ), gameLocal.entities[ i ]->name.c_str() ) );
  5015.         }
  5016.     }
  5017. }
  5018.  
  5019. /*
  5020. =============
  5021. idGameLocal::ArgCompletion_AIName
  5022.  
  5023. Argument completion for idAI entity names
  5024. =============
  5025. */
  5026. void idGameLocal::ArgCompletion_AIName( const idCmdArgs &args, void(*callback)( const char *s ) ) {
  5027.     int i;
  5028.  
  5029.     for( i = 0; i < gameLocal.num_entities; i++ ) {
  5030.         if ( gameLocal.entities[ i ] && gameLocal.entities[ i ]->IsType( idAI::GetClassType() ) ) {
  5031.             callback( va( "%s %s", args.Argv( 0 ), gameLocal.entities[ i ]->name.c_str() ) );
  5032.         }
  5033.     }
  5034. }
  5035.  
  5036. /*
  5037. =============
  5038. idGameLocal::FindEntity
  5039.  
  5040. Returns the entity whose name matches the specified string.
  5041. =============
  5042. */
  5043. idEntity *idGameLocal::FindEntity( const char *name ) const {
  5044.     int hash, i;
  5045.  
  5046.     hash = entityHash.GenerateKey( name, true );
  5047.     for ( i = entityHash.First( hash ); i != -1; i = entityHash.Next( i ) ) {
  5048.         if ( entities[i] && entities[i]->name.Icmp( name ) == 0 ) {
  5049.             return entities[i];
  5050.         }
  5051.     }
  5052.  
  5053.     return NULL;
  5054. }
  5055.  
  5056. /*
  5057. =============
  5058. idGameLocal::FindEntityUsingDef
  5059.  
  5060. Searches all active entities for the next one using the specified entityDef.
  5061.  
  5062. Searches beginning at the entity after from, or the beginning if NULL
  5063. NULL will be returned if the end of the list is reached.
  5064. =============
  5065. */
  5066. idEntity *idGameLocal::FindEntityUsingDef( idEntity *from, const char *match ) const {
  5067.     idEntity    *ent;
  5068.  
  5069.     if ( !from ) {
  5070.         ent = spawnedEntities.Next();
  5071.     } else {
  5072.         ent = from->spawnNode.Next();
  5073.     }
  5074.  
  5075.     for ( ; ent != NULL; ent = ent->spawnNode.Next() ) {
  5076.         assert( ent );
  5077.         if ( idStr::Icmp( ent->GetEntityDefName(), match ) == 0 ) {
  5078.             return ent;
  5079.         }
  5080.     }
  5081.  
  5082.     return NULL;
  5083. }
  5084.  
  5085. /*
  5086. =============
  5087. idGameLocal::FindTraceEntity
  5088.  
  5089. Searches all active entities for the closest ( to start ) match that intersects
  5090. the line start,end
  5091. =============
  5092. */
  5093. idEntity *idGameLocal::FindTraceEntity( idVec3 start, idVec3 end, const idTypeInfo &c, const idEntity *skip ) const {
  5094.     idEntity *ent;
  5095.     idEntity *bestEnt;
  5096.     float scale;
  5097.     float bestScale;
  5098.     idBounds b;
  5099.  
  5100.     bestEnt = NULL;
  5101.     bestScale = 1.0f;
  5102.     for( ent = spawnedEntities.Next(); ent != NULL; ent = ent->spawnNode.Next() ) {
  5103.         if ( ent->IsType( c ) && ent != skip ) {
  5104.             b = ent->GetPhysics()->GetAbsBounds().Expand( 16 );
  5105.             if ( b.RayIntersection( start, end-start, scale ) ) {
  5106.                 if ( scale >= 0.0f && scale < bestScale ) {
  5107.                     bestEnt = ent;
  5108.                     bestScale = scale;
  5109.                 }
  5110.             }
  5111.         }
  5112.     }
  5113.  
  5114.     return bestEnt;
  5115. }
  5116.  
  5117. /*
  5118. ================
  5119. idGameLocal::EntitiesWithinRadius
  5120. ================
  5121. */
  5122. int idGameLocal::EntitiesWithinRadius( const idVec3 org, float radius, idEntity **entityList, int maxCount ) const {
  5123.     idEntity *ent;
  5124.     idBounds bo( org );
  5125.     int entCount = 0;
  5126.  
  5127.     bo.ExpandSelf( radius );
  5128.     for( ent = spawnedEntities.Next(); ent != NULL; ent = ent->spawnNode.Next() ) {
  5129.         if ( ent->GetPhysics()->GetAbsBounds().IntersectsBounds( bo ) ) {
  5130.             entityList[entCount++] = ent;
  5131.         }
  5132.     }
  5133.  
  5134.     return entCount;
  5135. }
  5136.  
  5137. /*
  5138. =================
  5139. idGameLocal::KillBox
  5140.  
  5141. Kills all entities that would touch the proposed new positioning of ent. The ent itself will not being killed.
  5142. Checks if player entities are in the teleporter, and marks them to die at teleport exit instead of immediately.
  5143. If catch_teleport, this only marks teleport players for death on exit
  5144. =================
  5145. */
  5146. void idGameLocal::KillBox( idEntity *ent, bool catch_teleport ) {
  5147.     int            i;
  5148.     int            num;
  5149.     idEntity *    hit;
  5150.     idClipModel *cm;
  5151.     idClipModel *clipModels[ MAX_GENTITIES ];
  5152.     idPhysics    *phys;
  5153.  
  5154.     phys = ent->GetPhysics();
  5155.     if ( !phys->GetNumClipModels() ) {
  5156.         return;
  5157.     }
  5158.  
  5159. // RAVEN BEGIN
  5160. // ddynerman: multiple clip worlds
  5161.     num = ClipModelsTouchingBounds( ent, phys->GetAbsBounds(), phys->GetClipMask(), clipModels, MAX_GENTITIES );
  5162. // RAVEN END
  5163.     for ( i = 0; i < num; i++ ) {
  5164.         cm = clipModels[ i ];
  5165.  
  5166.         // don't check render entities
  5167.         if ( cm->IsRenderModel() ) {
  5168.             continue;
  5169.         }
  5170.  
  5171.         hit = cm->GetEntity();
  5172.         if ( ( hit == ent ) || !hit->fl.takedamage ) {
  5173.             continue;
  5174.         }
  5175.  
  5176.         if ( !phys->ClipContents( cm ) ) {
  5177.             continue;
  5178.         }
  5179.  
  5180.         // nail it
  5181. // RAVEN BEGIN
  5182. // jnewquist: Use accessor for static class type 
  5183.         if ( hit->IsType( idPlayer::GetClassType() ) && static_cast< idPlayer * >( hit )->IsInTeleport() ) {
  5184. // RAVEN END
  5185.             static_cast< idPlayer * >( hit )->TeleportDeath( ent->entityNumber );
  5186.         } else if ( !catch_teleport ) {
  5187.             hit->Damage( ent, ent, vec3_origin, "damage_telefrag", 1.0f, INVALID_JOINT );
  5188.         }
  5189.  
  5190.         if ( !gameLocal.isMultiplayer ) {
  5191.             // let the mapper know about it
  5192.             Warning( "'%s' telefragged '%s'", ent->name.c_str(), hit->name.c_str() );
  5193.         }
  5194.     }
  5195. }
  5196.  
  5197. /*
  5198. ================
  5199. idGameLocal::RequirementMet
  5200. ================
  5201. */
  5202. bool idGameLocal::RequirementMet( idEntity *activator, const idStr &requires, int removeItem ) {
  5203.     if ( requires.Length() ) {
  5204. // RAVEN BEGIN
  5205. // jnewquist: Use accessor for static class type 
  5206.         if ( activator->IsType( idPlayer::GetClassType() ) ) {
  5207. // RAVEN END
  5208.             idPlayer *player = static_cast<idPlayer *>(activator);
  5209.             idDict *item = player->FindInventoryItem( requires );
  5210.             if ( item ) {
  5211.                 if ( removeItem ) {
  5212.                     player->RemoveInventoryItem( item );
  5213.                 }
  5214.                 return true;
  5215.             } else {
  5216.                 return false;
  5217.             }
  5218.         }
  5219.     }
  5220.  
  5221.     return true;
  5222. }
  5223.  
  5224. /*
  5225. ============
  5226. idGameLocal::AlertAI
  5227. ============
  5228. */
  5229. void idGameLocal::AlertAI( idEntity *ent ) {
  5230. // RAVEN BEGIN
  5231. // bdube: merged
  5232.     if ( ent ) {
  5233. // RAVEN BEGIN
  5234. // jnewquist: Use accessor for static class type 
  5235.         if ( ent->IsType( idActor::GetClassType() ) ) {
  5236. // RAVEN END
  5237.             // alert them for the next frame
  5238.             lastAIAlertActorTime = time + GetMSec();
  5239.             lastAIAlertActor = static_cast<idActor *>( ent );
  5240.         } else {
  5241.             lastAIAlertEntityTime = time + GetMSec();
  5242.             lastAIAlertEntity = ent;
  5243.         }
  5244.     } else {
  5245.         lastAIAlertEntityTime = 0;
  5246.         lastAIAlertActorTime = 0;
  5247.         lastAIAlertEntity = NULL;
  5248.         lastAIAlertActor = NULL;
  5249.     }
  5250. // RAVEN END
  5251. }
  5252.  
  5253. // RAVEN BEGIN
  5254. // bdube: alert entity returns an entity, alert actor a an actor
  5255. /*
  5256. ============
  5257. idGameLocal::GetAlertEntity
  5258. ============
  5259. */
  5260. idEntity *idGameLocal::GetAlertEntity( void ) {
  5261.     if ( lastAIAlertEntityTime >= time ) {
  5262.         return lastAIAlertEntity.GetEntity();
  5263.     }
  5264.  
  5265.     return NULL;
  5266. }
  5267.  
  5268. /*
  5269. ============
  5270. idGameLocal::GetAlertActor
  5271. ============
  5272. */
  5273. idActor *idGameLocal::GetAlertActor( void ) {
  5274.     if ( lastAIAlertActorTime >= time ) {
  5275.         return lastAIAlertActor.GetEntity();
  5276.     }
  5277.  
  5278.     return NULL;
  5279. }
  5280. // RAVEN END
  5281.  
  5282. /*
  5283. ============
  5284. SortClipModelsByEntity
  5285. ============
  5286. */
  5287. static int SortClipModelsByEntity( const void* left, const void* right ) {
  5288.     idEntity* leftEntity  = left  ? (*((const idClipModel**)left))->GetEntity() : NULL;
  5289.     idEntity* rightEntity = right ? (*((const idClipModel**)right))->GetEntity() : NULL;
  5290.  
  5291.     int entityNumLeft = (leftEntity) ? leftEntity->entityNumber : 0;
  5292.     int entityNumRight = (rightEntity) ? rightEntity->entityNumber : 0;
  5293.  
  5294.     return entityNumLeft - entityNumRight;
  5295. }
  5296.  
  5297. // RAVEN BEGIN
  5298. /*
  5299. ============
  5300. idGameLocal::RadiusDamage
  5301. Returns the number of actors damaged
  5302. ============
  5303. */
  5304. // abahr: changed to work with deathPush
  5305. void idGameLocal::RadiusDamage( const idVec3 &origin, idEntity *inflictor, idEntity *attacker, idEntity *ignoreDamage, idEntity *ignorePush, const char *damageDefName, float dmgPower, int* hitCount ) {
  5306.     float        dist, damageScale, attackerDamageScale, attackerPushScale;
  5307.     idEntity*    ent = NULL;
  5308.     idEntity*    lastEnt = NULL;
  5309.     idClipModel* clipModel = NULL;
  5310.     idClipModel* clipModelList[ MAX_GENTITIES ];
  5311.     int            numListedClipModels;
  5312.     modelTrace_t    result;
  5313.     idVec3         v, damagePoint, dir;
  5314.     int            i, damage, radius, push;
  5315.  
  5316.     const idDict *damageDef = FindEntityDefDict( damageDefName, false );
  5317.     if ( !damageDef ) {
  5318.         Warning( "Unknown damageDef '%s'", damageDefName );
  5319.         return;
  5320.     }
  5321.  
  5322.     damageDef->GetInt( "damage", "20", damage );
  5323.     damageDef->GetInt( "radius", "50", radius );
  5324.     damageDef->GetInt( "push", va( "%d", damage * 100 ), push );
  5325.     damageDef->GetFloat( "attackerDamageScale", "0.5", attackerDamageScale );
  5326.     if( gameLocal.isMultiplayer ) {
  5327.         damageDef->GetFloat( "attackerPushScale", "2", attackerPushScale );
  5328.     } else {
  5329.         damageDef->GetFloat( "attackerPushScale", "0", attackerPushScale );
  5330.     }
  5331.  
  5332.     if ( radius < 1 ) {
  5333.         radius = 1;
  5334.     }
  5335.  
  5336.  
  5337. // ddynerman: multiple clip worlds
  5338.     numListedClipModels = ClipModelsTouchingBounds( inflictor, idBounds(origin).Expand(radius), MASK_ALL, clipModelList, MAX_GENTITIES );
  5339.     if( numListedClipModels > 0 ) {
  5340.         //Sort list by unique entities for easier searching
  5341.         qsort( clipModelList, numListedClipModels, sizeof(clipModelList[0]), SortClipModelsByEntity );
  5342.     }
  5343.  
  5344.     if ( inflictor ) {
  5345.         inflictor = inflictor->GetDamageEntity ( );
  5346.     }
  5347.     if ( attacker ) {
  5348.         attacker = attacker->GetDamageEntity ( );
  5349.     }
  5350.     if ( ignoreDamage ) {
  5351.         ignoreDamage = ignoreDamage->GetDamageEntity ( );
  5352.     }
  5353.  
  5354.     for( int c = 0; c < numListedClipModels; ++c ) {
  5355.         clipModel = clipModelList[ c ];
  5356.         assert( clipModel );
  5357.  
  5358.         ent = clipModel->GetEntity();
  5359.         
  5360.         // Skip all entitys that arent primary damage entities
  5361.         if ( !ent || ent != ent->GetDamageEntity ( ) ) {
  5362.             continue;
  5363.         }
  5364.  
  5365.         // Dont damage inflictor or the ignore entity
  5366.         if( ent == inflictor || ent == ignoreDamage ) {
  5367.             continue;
  5368.         }
  5369.  
  5370.         idBounds absBounds = clipModel->GetAbsBounds();
  5371.  
  5372.         // find the distance from the edge of the bounding box
  5373.         for ( i = 0; i < 3; i++ ) {
  5374.             if ( origin[ i ] < absBounds[0][ i ] ) {
  5375.                 v[ i ] = absBounds[0][ i ] - origin[ i ];
  5376.             } else if ( origin[ i ] > absBounds[1][ i ] ) {
  5377.                 v[ i ] = origin[ i ] - absBounds[1][ i ];
  5378.             } else {
  5379.                 v[ i ] = 0;
  5380.             }
  5381.         }
  5382.  
  5383.         dist = v.Length();
  5384.         if ( dist >= radius ) {
  5385.             continue;
  5386.         }
  5387.  
  5388.         if( gameRenderWorld->FastWorldTrace(result, origin, absBounds.GetCenter()) ) {
  5389.             continue;
  5390.         }
  5391.         
  5392.         RadiusPushClipModel ( inflictor, origin, push, clipModel );
  5393.  
  5394.         // Only damage unique entities.  This works because we have a sorted list
  5395.         if( lastEnt == ent ) {
  5396.             continue;
  5397.         }
  5398.  
  5399.         lastEnt = ent;
  5400.  
  5401.         if ( ent->CanDamage( origin, damagePoint, ignoreDamage ) ) {                        
  5402.             // push the center of mass higher than the origin so players
  5403.             // get knocked into the air more
  5404.             if( gameLocal.isMultiplayer ) {
  5405.                 // fudge the direction in MP to account for player height difference and origin shift
  5406.                 // 31.875 = origin is 23.875 units lower in Q4 than Q3 + player is 8 units taller in Q4
  5407.                 dir = ( ent->GetPhysics()->GetOrigin() + idVec3( 0.0f, 0.0f, 31.875f ) ) - origin;
  5408.             } else {
  5409.                 dir = ent->GetPhysics()->GetOrigin() - origin;
  5410.             }        
  5411.             
  5412.             dir[2] += 24;
  5413.  
  5414.              // get the damage scale
  5415.             damageScale = dmgPower * ( 1.0f - dist / radius );
  5416.             
  5417.             if ( ent == attacker ) {
  5418.                 damageScale *= attackerDamageScale;
  5419.             }
  5420.  
  5421.             dir.Normalize();
  5422.             ent->Damage( inflictor, attacker, dir, damageDefName, damageScale, CLIPMODEL_ID_TO_JOINT_HANDLE(ent->GetPhysics()->GetClipModel()->GetId()) );
  5423.  
  5424.             // for stats, count the first 
  5425.             if( attacker && attacker->IsType( idPlayer::GetClassType() ) && inflictor && inflictor->IsType( idProjectile::GetClassType() ) && ent->IsType( idPlayer::GetClassType() ) && hitCount ) {
  5426.                 // with splash damage projectiles, one projectile fire can damage multiple people.  If anyone is hit, 
  5427.                 // the shot counts as a hit but only report accuracy on the first one to avoid accuracies > 100%
  5428.                 statManager->WeaponHit( (const idActor*)attacker, ent, ((idProjectile*)inflictor)->methodOfDeath, (*hitCount) == 0 );
  5429.                 (*hitCount)++;
  5430.             }
  5431.         } 
  5432.     }
  5433. }
  5434. // RAVEN END
  5435.  
  5436. /*
  5437. ==============
  5438. idGameLocal::RadiusPush
  5439. ==============
  5440. */
  5441. void idGameLocal::RadiusPush( const idVec3 &origin, const float radius, const float push, const idEntity *inflictor, const idEntity *ignore, float inflictorScale, const bool quake ) {
  5442.     int i, numListedClipModels;
  5443.     idClipModel *clipModel;
  5444.     idClipModel *clipModelList[ MAX_GENTITIES ];
  5445.     idVec3 dir;
  5446.     idBounds bounds;
  5447.     modelTrace_t result;
  5448.     idEntity *ent;
  5449.     float scale;
  5450.  
  5451. // RAVEN BEGIN
  5452. // abahr: need to use gravity instead of assuming z is up
  5453.     dir = -GetCurrentGravity( const_cast<idEntity*>(inflictor) ).ToNormal();
  5454. // RAVEN END
  5455.  
  5456.     bounds = idBounds( origin ).Expand( radius );
  5457.  
  5458.     // get all clip models touching the bounds
  5459. // RAVEN BEGIN
  5460. // ddynerman: multiple clip worlds
  5461.     numListedClipModels = ClipModelsTouchingBounds( inflictor, bounds, -1, clipModelList, MAX_GENTITIES );
  5462.  
  5463. // bdube: getdamageentity
  5464.     if ( inflictor ) {
  5465.         inflictor = ((idEntity*)inflictor)->GetDamageEntity ( );
  5466.     }
  5467.     if ( ignore ) {
  5468.         ignore = ((idEntity*)ignore)->GetDamageEntity ( );
  5469.     }
  5470. // RAVEN END
  5471.  
  5472.     // apply impact to all the clip models through their associated physics objects
  5473.     for ( i = 0; i < numListedClipModels; i++ ) {
  5474.  
  5475.         clipModel = clipModelList[i];
  5476.  
  5477.         // never push render models
  5478.         if ( clipModel->IsRenderModel() ) {
  5479.             continue;
  5480.         }
  5481.  
  5482.         ent = clipModel->GetEntity();
  5483. // RAVEN BEGIN
  5484. // bdube: damage entity        
  5485.         if ( !ent || ent != ent->GetDamageEntity ( ) ) {
  5486.             continue;
  5487.         }
  5488. // RAVEN END
  5489.         
  5490.         // never push projectiles
  5491. // RAVEN BEGIN
  5492. // jnewquist: Use accessor for static class type 
  5493.         if ( ent->IsType( idProjectile::GetClassType() ) ) {
  5494. // RAVEN END
  5495.             continue;
  5496.         }
  5497.  
  5498.         // players use "knockback" in idPlayer::Damage
  5499. // RAVEN BEGIN
  5500. // jnewquist: Use accessor for static class type 
  5501.         if ( ent->IsType( idPlayer::GetClassType() ) && !quake ) {
  5502. // RAVEN END
  5503.             continue;
  5504.         }
  5505.  
  5506.         // don't push the ignore entity
  5507.         if ( ent == ignore ) {
  5508.             continue;
  5509.         }
  5510.  
  5511.         if ( gameRenderWorld->FastWorldTrace( result, origin, clipModel->GetOrigin() ) ) {
  5512.             continue;
  5513.         }
  5514.  
  5515.         // scale the push for the inflictor
  5516.         if ( ent == inflictor ) {
  5517.             scale = inflictorScale;
  5518.         } else {
  5519.             scale = 1.0f;
  5520.         }
  5521.  
  5522.         if ( quake ) {
  5523.             clipModel->GetEntity()->ApplyImpulse( world, clipModel->GetId(), clipModel->GetOrigin(), scale * push * dir );
  5524.         } else {
  5525. // RAVEN BEGIN
  5526. // bdube: inflictor
  5527.             RadiusPushClipModel( (idEntity*)inflictor, origin, scale * push, clipModel );
  5528. // RAVEN END
  5529.         }
  5530.     }
  5531. }
  5532.  
  5533. /*
  5534. ==============
  5535. idGameLocal::RadiusPushClipModel
  5536. ==============
  5537. */
  5538. // RAVEN BEGIN
  5539. // bdube: inflictor
  5540. void idGameLocal::RadiusPushClipModel( idEntity* inflictor, const idVec3 &origin, const float push, const idClipModel *clipModel ) {
  5541. // RAVEN END
  5542.     int i, j;
  5543.     float dot, dist, area;
  5544.     const idTraceModel *trm;
  5545.     const traceModelPoly_t *poly;
  5546.     idFixedWinding w;
  5547.     idVec3 v, localOrigin, center, impulse;
  5548.  
  5549.     trm = clipModel->GetTraceModel();
  5550.     if ( !trm || 1 ) {
  5551.         impulse = clipModel->GetAbsBounds().GetCenter() - origin;
  5552.         impulse.Normalize();
  5553. // RAVEN BEGIN
  5554. // abahr: removed because z isn't always up
  5555.         //impulse.z += 1.0f;
  5556.         //impulse = idVec3( 0.0, 0.0, 1.0 );
  5557.         clipModel->GetEntity()->ApplyImpulse( inflictor, clipModel->GetId(), clipModel->GetOrigin(), push * impulse, true );
  5558. // RAVEN END
  5559.         return;
  5560.     }
  5561.  
  5562.     localOrigin = ( origin - clipModel->GetOrigin() ) * clipModel->GetAxis().Transpose();
  5563.     for ( i = 0; i < trm->numPolys; i++ ) {
  5564.         poly = &trm->polys[i];
  5565.  
  5566.         center.Zero();
  5567.         for ( j = 0; j < poly->numEdges; j++ ) {
  5568.             v = trm->verts[ trm->edges[ abs(poly->edges[j]) ].v[ INTSIGNBITSET( poly->edges[j] ) ] ];
  5569.             center += v;
  5570.             v -= localOrigin;
  5571.             v.NormalizeFast();    // project point on a unit sphere
  5572.             w.AddPoint( v );
  5573.         }
  5574.         center /= poly->numEdges;
  5575.         v = center - localOrigin;
  5576.         dist = v.NormalizeFast();
  5577.         dot = v * poly->normal;
  5578.         if ( dot > 0.0f ) {
  5579.             continue;
  5580.         }
  5581.         area = w.GetArea();
  5582.         // impulse in polygon normal direction
  5583.         impulse = poly->normal * clipModel->GetAxis();
  5584.         // always push up for nicer effect
  5585.         impulse.z -= 1.0f;
  5586.         // scale impulse based on visible surface area and polygon angle
  5587.         impulse *= push * ( dot * area * ( 1.0f / ( 4.0f * idMath::PI ) ) );
  5588.         // scale away distance for nicer effect
  5589.         impulse *= ( dist * 2.0f );
  5590.         // impulse is applied to the center of the polygon
  5591.         center = clipModel->GetOrigin() + center * clipModel->GetAxis();
  5592.  
  5593. // RAVEN BEGIN
  5594. // bdube: inflictor
  5595.         clipModel->GetEntity()->ApplyImpulse( inflictor, clipModel->GetId(), center, impulse );
  5596. // RAVEN END
  5597.     }
  5598. }
  5599.  
  5600. /*
  5601. ===============
  5602. idGameLocal::ProjectDecal
  5603. ===============
  5604. */
  5605. void idGameLocal::ProjectDecal( const idVec3 &origin, const idVec3 &dir, float depth, bool parallel, float size, const char *material, float angle ) {
  5606.     float s, c;
  5607.     idMat3 axis, axistemp;
  5608.     idFixedWinding winding;
  5609.     idVec3 windingOrigin, projectionOrigin;
  5610.  
  5611.     static idVec3 decalWinding[4] = {
  5612.         idVec3(  1.0f,  1.0f, 0.0f ),
  5613.         idVec3( -1.0f,  1.0f, 0.0f ),
  5614.         idVec3( -1.0f, -1.0f, 0.0f ),
  5615.         idVec3(  1.0f, -1.0f, 0.0f )
  5616.     };
  5617.  
  5618.     if ( !g_decals.GetBool() ) {
  5619.         return;
  5620.     }
  5621.  
  5622. // RAVEN BEGIN
  5623. // rjohnson: no decals on dedicated server
  5624.     if ( isMultiplayer && !isClient && !isListenServer ) {
  5625.         // no decals on dedicated server
  5626.         return;
  5627.     }
  5628. // RAVEN END
  5629.  
  5630.     // randomly rotate the decal winding
  5631.     idMath::SinCos16( ( angle ) ? angle : random.RandomFloat() * idMath::TWO_PI, s, c );
  5632.  
  5633.     // winding orientation
  5634.     axis[2] = dir;
  5635.     axis[2].Normalize();
  5636.     axis[2].NormalVectors( axistemp[0], axistemp[1] );
  5637.     axis[0] = axistemp[ 0 ] * c + axistemp[ 1 ] * -s;
  5638.     axis[1] = axistemp[ 0 ] * -s + axistemp[ 1 ] * -c;
  5639.  
  5640.     windingOrigin = origin + depth * axis[2];
  5641.     if ( parallel ) {
  5642.         projectionOrigin = origin - depth * axis[2];
  5643.     } else {
  5644.         projectionOrigin = origin;
  5645.     }
  5646.  
  5647.     size *= 0.5f;
  5648.  
  5649.     winding.Clear();
  5650.     winding += idVec5( windingOrigin + ( axis * decalWinding[0] ) * size, idVec2( 1, 1 ) );
  5651.     winding += idVec5( windingOrigin + ( axis * decalWinding[1] ) * size, idVec2( 0, 1 ) );
  5652.     winding += idVec5( windingOrigin + ( axis * decalWinding[2] ) * size, idVec2( 0, 0 ) );
  5653.     winding += idVec5( windingOrigin + ( axis * decalWinding[3] ) * size, idVec2( 1, 0 ) );
  5654.     gameRenderWorld->ProjectDecalOntoWorld( winding, projectionOrigin, parallel, depth * 0.5f, declManager->FindMaterial( material ), time );
  5655. }
  5656.  
  5657. /*
  5658. ==============
  5659. idGameLocal::BloodSplat
  5660. ==============
  5661. */
  5662. // RAVEN BEGIN
  5663. // ddynerman: multiple collision models
  5664. void idGameLocal::BloodSplat( const idEntity* ent, const idVec3 &origin, const idVec3 &dirArg, float size, const char *material ) {
  5665.  
  5666.     float halfSize = size * 0.5f;
  5667.     idVec3 verts[] = {    idVec3( 0.0f, +halfSize, +halfSize ),
  5668.                         idVec3( 0.0f, +halfSize, -halfSize ),
  5669.                         idVec3( 0.0f, -halfSize, -halfSize ),
  5670.                         idVec3( 0.0f, -halfSize, +halfSize ) };
  5671.     idVec3 dir = dirArg;
  5672.     idTraceModel trm;
  5673.     idClipModel mdl;
  5674.     trace_t results;
  5675.  
  5676. // RAVEN BEGIN
  5677. // mekberg: changed from g_bloodEffects to g_decals
  5678.     if ( !g_decals.GetBool() ) {
  5679.         return;
  5680.     }
  5681. // RAVEN END
  5682.  
  5683.     size = halfSize + random.RandomFloat() * halfSize;
  5684.     trm.SetupPolygon( verts, 4 );
  5685.     mdl.LoadModel( trm, NULL );
  5686.  
  5687.     // I don't want dir to be axis aligned, as it is more likely to streak them (because most architecture is axis aligned
  5688.     dir.Set( dirArg.x*.1f, dirArg.y*.1f, -1 );
  5689.     dir.Normalize();
  5690.  
  5691. // RAVEN BEGIN
  5692. // ddynerman: multiple clip worlds
  5693.     Translation( ent, results, origin, origin + dir * 72.0f, &mdl, mat3_identity, CONTENTS_SOLID, NULL );
  5694. // RAVEN END
  5695.     ProjectDecal( results.endpos, dir, 2.0f * size, true, size, material );
  5696. }
  5697.  
  5698. /*
  5699. =============
  5700. idGameLocal::SetCamera
  5701. =============
  5702. */
  5703. void idGameLocal::SetCamera( idCamera *cam ) {
  5704.     int i;
  5705.     idEntity *ent;
  5706.     idAI *ai;
  5707.  
  5708.     // this should fix going into a cinematic when dead.. rare but happens
  5709.     idPlayer *client = GetLocalPlayer();
  5710.     if ( client->health <= 0 || client->pfl.dead ) {
  5711.         return;
  5712.     }
  5713.  
  5714.     camera = cam;
  5715.     if ( camera ) {
  5716. // RAVEN BEGIN
  5717. // bdube: tool support
  5718.         inCinematic = false;
  5719.         if( !( gameLocal.editors & ( EDITOR_MODVIEW | EDITOR_PLAYBACKS ) ) ) {
  5720.             inCinematic = true;
  5721.         }
  5722. // RAVEN END
  5723.  
  5724.         if ( skipCinematic && camera->spawnArgs.GetBool( "disconnect" ) ) {
  5725.             camera->spawnArgs.SetBool( "disconnect", false );
  5726.             cvarSystem->SetCVarFloat( "r_znear", 3.0f );
  5727.             cmdSystem->BufferCommandText( CMD_EXEC_APPEND, "disconnect\n" );
  5728.             skipCinematic = false;
  5729.             return;
  5730.         }
  5731.  
  5732.         if ( time > cinematicStopTime ) {
  5733.             cinematicSkipTime = time + CINEMATIC_SKIP_DELAY;
  5734.         }
  5735.  
  5736.         // set r_znear so that transitioning into/out of the player's head doesn't clip through the view
  5737.         cvarSystem->SetCVarFloat( "r_znear", 1.0f );
  5738.         
  5739.         // hide all the player models
  5740.         for( i = 0; i < numClients; i++ ) {
  5741.             if ( entities[ i ] ) {
  5742.                 client = static_cast< idPlayer* >( entities[ i ] );
  5743.                 client->EnterCinematic();
  5744.             }
  5745.         }
  5746.  
  5747.         if ( !cam->spawnArgs.GetBool( "ignore_enemies" ) ) {
  5748.             // kill any active monsters that are enemies of the player
  5749.             for ( ent = spawnedEntities.Next(); ent != NULL; ent = ent->spawnNode.Next() ) {
  5750.                 if ( ent->cinematic || ent->fl.isDormant ) {
  5751.                     // only kill entities that aren't needed for cinematics and aren't dormant
  5752.                     continue;
  5753.                 }
  5754.                 
  5755. // RAVEN BEGIN
  5756. // jnewquist: Use accessor for static class type 
  5757.                 if ( ent->IsType( idAI::GetClassType() ) ) {
  5758. // RAVEN END
  5759.                     ai = static_cast<idAI *>( ent );
  5760.                     if ( !ai->GetEnemy() || !ai->IsActive() ) {
  5761.                         // no enemy, or inactive, so probably safe to ignore
  5762.                         continue;
  5763.                     }
  5764. // RAVEN BEGIN
  5765. // jnewquist: Use accessor for static class type 
  5766.                 } else if ( ent->IsType( idProjectile::GetClassType() ) ) {
  5767. // RAVEN END
  5768.                     // remove all projectiles
  5769.                 } else if ( ent->spawnArgs.GetBool( "cinematic_remove" ) ) {
  5770.                     // remove anything marked to be removed during cinematics
  5771.                 } else {
  5772.                     // ignore everything else
  5773.                     continue;
  5774.                 }
  5775.  
  5776.                 // remove it
  5777.                 DPrintf( "removing '%s' for cinematic\n", ent->GetName() );
  5778.                 ent->PostEventMS( &EV_Remove, 0 );
  5779.             }
  5780.         }
  5781.  
  5782.     } else {
  5783.         inCinematic = false;
  5784.         cinematicStopTime = time + msec;
  5785.  
  5786.         // restore r_znear
  5787.         cvarSystem->SetCVarFloat( "r_znear", 3.0f );
  5788.  
  5789.         // show all the player models
  5790.         for( i = 0; i < numClients; i++ ) {
  5791.             if ( entities[ i ] ) {
  5792.                 idPlayer *client = static_cast< idPlayer* >( entities[ i ] );
  5793.                 client->ExitCinematic();
  5794.             }
  5795.         }
  5796.     }
  5797. }
  5798.  
  5799. // RAVEN BEGIN
  5800. // jscott: for portal skies
  5801. /*
  5802. =============
  5803. idGameLocal::GetPortalSky
  5804. =============
  5805. */
  5806. idCamera *idGameLocal::GetPortalSky( void ) const
  5807. {
  5808.     if( !portalSkyVisible ) {
  5809.  
  5810.         return( NULL );
  5811.     }
  5812.     return( portalSky );
  5813. }
  5814. /*
  5815. =============
  5816. idGameLocal::SetPortalSky
  5817. =============
  5818. */
  5819. void idGameLocal::SetPortalSky( idCamera *cam ) 
  5820. {
  5821.     portalSky = cam;
  5822. }
  5823. // RAVEN END
  5824.  
  5825. /*
  5826. =============
  5827. idGameLocal::GetCamera
  5828. =============
  5829. */
  5830. idCamera *idGameLocal::GetCamera( void ) const {
  5831.     return camera;
  5832. }
  5833.  
  5834. /*
  5835. =============
  5836. idGameLocal::SkipCinematic
  5837. =============
  5838. */
  5839. bool idGameLocal::SkipCinematic( void ) {
  5840.     if ( camera ) {
  5841.         if ( camera->spawnArgs.GetBool( "disconnect" ) ) {
  5842.             camera->spawnArgs.SetBool( "disconnect", false );
  5843.             cvarSystem->SetCVarFloat( "r_znear", 3.0f );
  5844.             cmdSystem->BufferCommandText( CMD_EXEC_APPEND, "disconnect\n" );
  5845.             skipCinematic = false;
  5846.             return false;
  5847.         }
  5848.  
  5849.         if ( camera->spawnArgs.GetBool( "instantSkip" ) ) {
  5850.             camera->Stop();
  5851.             return false;
  5852.         }
  5853.     }
  5854.  
  5855.     soundSystem->SetMute( true );
  5856.     if ( !skipCinematic ) {
  5857.         skipCinematic = true;
  5858.         cinematicMaxSkipTime = gameLocal.time + SEC2MS( g_cinematicMaxSkipTime.GetFloat() );
  5859.     }
  5860.  
  5861.     return true;
  5862. }
  5863.  
  5864. // RAVEN BEGIN
  5865. /*
  5866. ======================
  5867. idGameLocal::StartViewEffect
  5868.  
  5869. For passing in an effect triggered view effect
  5870. ======================
  5871. */
  5872. void idGameLocal::StartViewEffect( int type, float time, float scale )
  5873. {
  5874.     idPlayer        *player;
  5875.     idPlayerView    *view;
  5876.  
  5877.     player = GetLocalPlayer();
  5878.     if( player )
  5879.     {
  5880.         view = &player->playerView;
  5881.  
  5882.         switch( type )
  5883.         {
  5884.         case VIEWEFFECT_DOUBLEVISION:
  5885.             view->SetDoubleVisionParms( time, scale );
  5886.             break;
  5887.  
  5888.         case VIEWEFFECT_SHAKE:
  5889.             if( !gameLocal.isMultiplayer ) {
  5890.                 view->SetShakeParms( time, scale );
  5891.             }
  5892.             break;
  5893.  
  5894.         case VIEWEFFECT_TUNNEL:
  5895.             view->SetTunnelParms( time, scale );
  5896.             break;
  5897.  
  5898.         default:
  5899.             gameLocal.Warning( "Invalid view effect" );
  5900.             break;
  5901.         }
  5902.     }
  5903. }
  5904.  
  5905. /*
  5906. ======================
  5907. idGameLocal::GetPlayerView
  5908. ======================
  5909. */
  5910. void idGameLocal::GetPlayerView( idVec3 &origin, idMat3 &axis )
  5911. {
  5912.     idPlayer        *player;
  5913.     renderView_t    *view;
  5914.  
  5915.     player = GetLocalPlayer();
  5916.     if( player )
  5917.     {
  5918.         view = player->GetRenderView();
  5919.         origin = view->vieworg;
  5920.         axis = view->viewaxis;
  5921.     }
  5922.     else
  5923.     {
  5924.         origin = vec3_origin;
  5925.         axis = mat3_identity;
  5926.     }
  5927. }
  5928.  
  5929. /*
  5930. ======================
  5931. idGameLocal::Translation
  5932.  
  5933. small portion of physics required for the effects system
  5934. ======================
  5935. */
  5936. void idGameLocal::Translation( trace_t &trace, idVec3 &source, idVec3 &dest, idTraceModel *trm, int clipMask ) {    
  5937.  
  5938.     if( !trm ) {
  5939.         // HACK
  5940.         clip[0]->Translation( trace, source, dest, NULL, mat3_identity, clipMask, NULL, NULL );
  5941.     }
  5942.     else {
  5943.         idClipModel        cm;
  5944.     
  5945.         cm.LoadModel( *trm, NULL );
  5946.         // HACK
  5947.         clip[0]->Translation( trace, source, dest, &cm, mat3_identity, clipMask, NULL, NULL );
  5948.     }
  5949. }
  5950.  
  5951. /*
  5952. ======================
  5953. idGameLocal::SpawnClientMoveable
  5954. ======================
  5955. */
  5956. void idGameLocal::SpawnClientMoveable( const char* name, int lifetime, const idVec3& origin, const idMat3& axis, const idVec3& velocity, const idVec3& angular_velocity ) {
  5957.     // find the debris def
  5958.     const idDict* args = gameLocal.FindEntityDefDict( name, false );
  5959.     if ( !args ) {
  5960.         return;
  5961.     }
  5962.  
  5963.     // Ensure client moveables never last forever
  5964.     if ( lifetime <= 0 ) {
  5965.         lifetime = SEC2MS(args->GetFloat( "duration", "5" ));
  5966.     }
  5967.     int burn_time = idMath::ClampInt( 0, lifetime, SEC2MS(args->GetFloat( "burn_time", "2.5" )) );
  5968.     
  5969.     // Spawn the debris
  5970.     rvClientMoveable* cent = new rvClientMoveable;
  5971.     cent->SetOrigin( origin );
  5972.     cent->SetAxis( axis );
  5973.     cent->Spawn( args );
  5974.         
  5975.     cent->GetPhysics()->SetLinearVelocity( velocity );
  5976.     cent->GetPhysics()->SetAngularVelocity( angular_velocity );
  5977.  
  5978.     if ( !burn_time ) {
  5979.         //just disappear
  5980.         cent->PostEventMS( &EV_Remove, lifetime );    
  5981.     } else {
  5982.         cent->PostEventMS( &CL_FadeOut, lifetime-burn_time, burn_time );
  5983.     }
  5984. }
  5985.  
  5986. /*
  5987. ======================
  5988. idGameLocal::DebugSet
  5989. ======================
  5990. */
  5991. void idGameLocal::DebugSetString( const char* name, const char* value ) {
  5992.     gameDebug.SetString( name, value );
  5993. }
  5994. void idGameLocal::DebugSetFloat( const char* name, float value ) {
  5995.     gameDebug.SetFloat( name, value );
  5996. }
  5997. void idGameLocal::DebugSetInt( const char* name, int value ) {
  5998.     gameDebug.SetInt( name, value );
  5999. }
  6000.  
  6001. /*
  6002. ======================
  6003. idGameLocal::DebugGetStat
  6004. ======================
  6005. */
  6006. const char* idGameLocal::DebugGetStatString ( const char* name ) {
  6007.     return gameDebug.GetStatString( name );
  6008. }
  6009.  
  6010. int idGameLocal::DebugGetStatInt ( const char* name ) {
  6011.     return gameDebug.GetStatInt( name );
  6012. }
  6013.  
  6014. float idGameLocal::DebugGetStatFloat ( const char* name ) {
  6015.     return gameDebug.GetStatFloat( name );
  6016. }
  6017.  
  6018. /*
  6019. ======================
  6020. idGameLocal::IsDebugHudActive
  6021. ======================
  6022. */
  6023. bool idGameLocal::IsDebugHudActive ( void ) const {
  6024.     return gameDebug.IsHudActive( DBGHUD_ANY );
  6025. }
  6026.  
  6027.  
  6028. // rjohnson: added player info support for note taking system
  6029. /*
  6030. ======================
  6031. idGameLocal::GetPlayerInfo
  6032. ======================
  6033. */
  6034. bool idGameLocal::GetPlayerInfo( idVec3 &origin, idMat3 &axis, int PlayerNum, idAngles *deltaViewAngles, int reqClientNum ) {
  6035.     idPlayer    *player;
  6036.  
  6037.     if ( PlayerNum == -1 ) {
  6038.         player = GetLocalPlayer();
  6039.     } else {
  6040.         player = GetClientByNum( PlayerNum );
  6041.     }
  6042.  
  6043.     if( reqClientNum != -1 ) {
  6044.         idPlayer* reqClient = GetClientByNum( reqClientNum );
  6045.         if( reqClient && player ) {
  6046.             if( reqClient->GetInstance() != player->GetInstance() ) {
  6047.                 return false;
  6048.             }
  6049.         }
  6050.     }
  6051.  
  6052.     if ( !player ) {
  6053.         return false;
  6054.     }
  6055.  
  6056.     player->GetViewPos( origin, axis );
  6057.     origin = player->GetPhysics()->GetOrigin();
  6058.  
  6059.     if ( deltaViewAngles ) {
  6060.         *deltaViewAngles = player->GetDeltaViewAngles();
  6061.     }
  6062.  
  6063.     return true;
  6064. };
  6065.  
  6066. /*
  6067. ======================
  6068. idGameLocal::SetCurrentPlayerInfo
  6069. ======================
  6070. */
  6071. void idGameLocal::SetPlayerInfo( idVec3 &origin, idMat3 &axis, int PlayerNum ) {
  6072.     idPlayer    *player;
  6073.  
  6074.     if ( PlayerNum == -1 ) {
  6075.         player = GetLocalPlayer();
  6076.     } else {
  6077.         player = GetClientByNum( PlayerNum );
  6078.     }
  6079.  
  6080.     if ( !player ) {
  6081.         return;
  6082.     }
  6083.  
  6084.     player->Teleport( origin, axis.ToAngles(), NULL );
  6085. // RAVEN BEGIN
  6086. // ddynerman: save the current thinking entity for instance-dependent
  6087.     currentThinkingEntity = player;
  6088.     player->CalculateFirstPersonView();
  6089.     player->CalculateRenderView();
  6090.     currentThinkingEntity = NULL;
  6091. // RAVEN END
  6092.  
  6093.     return;
  6094. };
  6095.  
  6096. bool idGameLocal::PlayerChatDisabled( int clientNum ) {
  6097.     if( clientNum < 0 || clientNum >= MAX_CLIENTS || !entities[ clientNum ] ) {
  6098.         return false;
  6099.     }
  6100.  
  6101.     return !( ((idPlayer*)entities[ clientNum ])->isChatting || ((idPlayer*)entities[ clientNum ])->pfl.dead );
  6102. }
  6103.  
  6104. void idGameLocal::SetViewComments( const char *text ) {
  6105.     idPlayer    *player;
  6106.  
  6107.     player = GetLocalPlayer();
  6108.  
  6109.     if ( !player ) {
  6110.         return;
  6111.     }
  6112.  
  6113.     if ( text ) {
  6114.         player->hud->SetStateString( "viewcomments", text );
  6115.         player->hud->HandleNamedEvent( "showViewComments" );
  6116.     }
  6117.     else {
  6118.         player->hud->SetStateString( "viewcomments", "" );
  6119.         player->hud->HandleNamedEvent( "hideViewComments" );
  6120.     }
  6121. }
  6122.  
  6123. /*
  6124. ===================
  6125. idGameLocal::GetNumGravityAreas
  6126. ===================
  6127. */
  6128. int    idGameLocal::GetNumGravityAreas() const {
  6129.     return gravityInfo.Num();
  6130. }
  6131.  
  6132. /*
  6133. ===================
  6134. idGameLocal::GetGravityInfo
  6135. ===================
  6136. */
  6137. const rvGravityArea* idGameLocal::GetGravityInfo( int index ) const {
  6138.     return gravityInfo[ index ];
  6139. }
  6140.  
  6141. /*
  6142. ===================
  6143. idGameLocal::SetGravityArea
  6144. ===================
  6145. */
  6146. void idGameLocal::SetGravityInfo( int index, rvGravityArea* info ) {
  6147.     gravityInfo[ index ] = info;
  6148. }
  6149.  
  6150. /*
  6151. ===================
  6152. idGameLocal::AddUniqueGravityInfo
  6153. ===================
  6154. */
  6155. void idGameLocal::AddUniqueGravityInfo( rvGravityArea* info ) {
  6156.     gravityInfo.AddUnique( info );
  6157. }
  6158.  
  6159. /*
  6160. ===================
  6161. idGameLocal::GetCurrentGravityInfoIndex
  6162. ===================
  6163. */
  6164. int idGameLocal::GetCurrentGravityInfoIndex( const idVec3& origin ) const {
  6165.     int numGravityAreas = GetNumGravityAreas();
  6166.     if( !numGravityAreas ) {
  6167.         return -1;
  6168.     }
  6169.  
  6170.     int areaNum = gameRenderWorld->PointInArea( origin );
  6171.  
  6172.     for( int ix = 0; ix < numGravityAreas; ++ix ) {
  6173.         if( !gameRenderWorld->AreasAreConnected(GetGravityInfo(ix)->GetArea(), areaNum, PS_BLOCK_GRAVITY) ) {
  6174.             continue;
  6175.         }
  6176.          
  6177.         return ix;
  6178.     }
  6179.  
  6180.     return -1;
  6181. }
  6182.  
  6183. /*
  6184. ===================
  6185. idGameLocal::InGravityArea
  6186. ===================
  6187. */
  6188. bool idGameLocal::InGravityArea( idEntity* entity ) const {
  6189.     return GetCurrentGravityInfoIndex( entity ) >= 0;
  6190. }
  6191.  
  6192. /*
  6193. ===================
  6194. idGameLocal::GetCurrentGravityInfoIndex
  6195. ===================
  6196. */
  6197. int idGameLocal::GetCurrentGravityInfoIndex( idEntity* entity ) const {
  6198.     return GetCurrentGravityInfoIndex( entity->GetPhysics()->GetOrigin() );
  6199. }
  6200.  
  6201. /*
  6202. ===================
  6203. idGameLocal::GetCurrentGravity
  6204. ===================
  6205. */
  6206. const idVec3 idGameLocal::GetCurrentGravity( idEntity* entity ) const {
  6207.     int index = GetCurrentGravityInfoIndex( entity );
  6208.     return (index >= 0) ? gravityInfo[ index ]->GetGravity(entity) : GetGravity();
  6209. }
  6210.  
  6211. /*
  6212. ===================
  6213. idGameLocal::GetCurrentGravity
  6214. ===================
  6215. */
  6216. const idVec3 idGameLocal::GetCurrentGravity( const idVec3& origin, const idMat3& axis ) const {
  6217.     int index = GetCurrentGravityInfoIndex( origin );
  6218.     return (index >= 0) ? gravityInfo[ index ]->GetGravity(origin, axis, MASK_SOLID, NULL) : GetGravity();
  6219. }
  6220.  
  6221. /*
  6222. ===================
  6223. idGameLocal::InGravityArea
  6224. ===================
  6225. */
  6226. bool idGameLocal::InGravityArea( rvClientEntity* entity ) const {
  6227.     return GetCurrentGravityInfoIndex( entity ) >= 0;
  6228. }
  6229.  
  6230. /*
  6231. ===================
  6232. idGameLocal::GetCurrentGravityInfoIndex
  6233. ===================
  6234. */
  6235. int idGameLocal::GetCurrentGravityInfoIndex( rvClientEntity* entity ) const {
  6236.     return GetCurrentGravityInfoIndex( entity->GetPhysics()->GetOrigin() );
  6237. }
  6238.  
  6239. /*
  6240. ===================
  6241. idGameLocal::GetCurrentGravity
  6242. ===================
  6243. */
  6244. const idVec3 idGameLocal::GetCurrentGravity( rvClientEntity* entity ) const {
  6245.     int index = GetCurrentGravityInfoIndex( entity );
  6246.     return (index >= 0) ? gravityInfo[ index ]->GetGravity(entity) : GetGravity();
  6247. }
  6248.  
  6249. /*
  6250. ===================
  6251. idGameLocal::ReferenceScriptObjectProxy
  6252. ===================
  6253. */
  6254. idEntity* idGameLocal::ReferenceScriptObjectProxy( const char* scriptObjectName ) {
  6255.     idEntity*        proxy = NULL;
  6256.     idEntityPtr<idEntity> safeProxy;
  6257.     idDict            args;
  6258.     idScriptObject* object = NULL;
  6259.  
  6260.     for( int ix = 0; ix < scriptObjectProxies.Num(); ++ix ) {
  6261.         proxy = scriptObjectProxies[ ix ].GetEntity();
  6262.         assert( proxy );
  6263.         
  6264.         object = &proxy->scriptObject;
  6265.         if( !object->data ) {
  6266.             object->SetType( scriptObjectName );
  6267.             proxy->ConstructScriptObject();
  6268.             return proxy;
  6269.         }
  6270.     }
  6271.  
  6272.     args.Set( "classname", "func_static" );
  6273.     args.Set( "scriptobject", scriptObjectName );
  6274.     args.SetBool( "noclipmodel", true );
  6275.     bool spawned = SpawnEntityDef(args, &proxy);
  6276.     if ( !spawned ) {
  6277.         assert( 0 );
  6278.     }
  6279.     safeProxy = proxy;
  6280.     scriptObjectProxies.AddUnique( safeProxy );
  6281.     return proxy;
  6282. }
  6283.  
  6284. /*
  6285. ===================
  6286. idGameLocal::ReleaseScriptObjectProxy
  6287. ===================
  6288. */
  6289. void idGameLocal::ReleaseScriptObjectProxy( const char* proxyName ) {
  6290.     idScriptObject* object = NULL;
  6291.     idEntity*        entity = NULL;
  6292.  
  6293.     for( int ix = 0; ix < scriptObjectProxies.Num(); ++ix ) {
  6294.         entity = scriptObjectProxies[ ix ].GetEntity();
  6295.         if( entity && !idStr::Icmp(entity->GetName(), proxyName) ) {
  6296.             object = &entity->scriptObject;
  6297.             if( !object ) {
  6298.                 continue;
  6299.             }
  6300.             
  6301.             entity->DeconstructScriptObject();
  6302.             object->Free();
  6303.         }
  6304.     }
  6305. }
  6306.  
  6307. // RAVEN BEGIN
  6308. // rjohnson: entity usage stats
  6309. void idGameLocal::ListEntityStats( const idCmdArgs &args ) {
  6310.     int                i, j;
  6311.     idStr            currentMap;
  6312.     idList<idStr>    uniqueMapNames;
  6313.  
  6314.  
  6315.     for( i = 1; i < args.Argc(); i++ ) {
  6316.         if ( idStr::Icmp( args.Argv( i ), "clear" ) == 0 ) {
  6317.             entityUsageList.Clear();
  6318.             common->Printf("Entity stats cleared.\n");
  6319.             return;
  6320.         }
  6321.     }
  6322.  
  6323.     for( i = 0; i < entityUsageList.Num(); i++ ) {
  6324.         entityUsageList[ i ].SetInt( "reported_stat", false );
  6325.     }
  6326.  
  6327.     for( i = 0; i < entityUsageList.Num(); i++ ) {
  6328.         idStr    mapFileName, className;
  6329.         int        count;
  6330.  
  6331.         if ( entityUsageList[ i ].GetInt( "reported_stat" ) ) {
  6332.             continue;
  6333.         }
  6334.  
  6335.         entityUsageList[ i ].GetString( "mapFileName", "none", mapFileName );
  6336.         if ( currentMap != mapFileName )
  6337.         {
  6338.             if ( i ) {
  6339.                 common->Printf( "\n" );
  6340.             }
  6341.             common->Printf( "================ %s ================\n", mapFileName.c_str() );
  6342.             currentMap = mapFileName;
  6343.             uniqueMapNames.Insert( mapFileName );
  6344.         }
  6345.  
  6346.         entityUsageList[ i ].GetString( "classname", "none", className );
  6347.         count = 0;
  6348.  
  6349.         for( j = i; j < entityUsageList.Num(); j++ ) {
  6350.             idStr    checkMapFileName, checkClassName;
  6351.  
  6352.             entityUsageList[ j ].GetString( "mapFileName", "none", checkMapFileName );
  6353.             if ( checkMapFileName != mapFileName ) {
  6354.                 break;
  6355.             }
  6356.  
  6357.             entityUsageList[ j ].GetString( "classname", "none", checkClassName );
  6358.  
  6359.             if ( checkClassName == className ) {
  6360.                 entityUsageList[ j ].SetInt( "reported_stat", 1 );
  6361.                 count++;
  6362.             }
  6363.         }
  6364.  
  6365.         common->Printf("%d\t%s\n", count, className.c_str() );
  6366.     }
  6367.  
  6368.     common->Printf( "\n" );
  6369.     common->Printf( "\n" );
  6370.     common->Printf( "================ OVERALL ================\n" );
  6371.  
  6372.     for( i = 0; i < entityUsageList.Num(); i++ ) {
  6373.         idStr    mapFileName, className;
  6374.         int        count;
  6375.  
  6376.         if ( entityUsageList[ i ].GetInt( "reported_stat" ) == 2 ) {
  6377.             continue;
  6378.         }
  6379.  
  6380.         entityUsageList[ i ].GetString( "classname", "none", className );
  6381.         count = 0;
  6382.  
  6383.         for( j = i; j < entityUsageList.Num(); j++ ) {
  6384.             idStr    checkClassName;
  6385.  
  6386.             entityUsageList[ j ].GetString( "classname", "none", checkClassName );
  6387.  
  6388.             if ( checkClassName == className ) {
  6389.                 entityUsageList[ j ].SetInt( "reported_stat", 2 );
  6390.                 count++;
  6391.             }
  6392.         }
  6393.  
  6394.         common->Printf("%d\t%s\n", count, className.c_str() );
  6395.     }
  6396.  
  6397.     idFile *FH = fileSystem->OpenFileWrite( "EntityStats.csv" );
  6398.     if ( FH ) {
  6399.         int    size = sizeof( int ) * uniqueMapNames.Num();
  6400.         int    *count = ( int * )_alloca( size );
  6401.  
  6402.         FH->Printf("\"Definition\"");
  6403.         for( i = 0; i < uniqueMapNames.Num(); i++ ) {
  6404.             FH->Printf( ",\"%s\"", uniqueMapNames[ i ].c_str() );
  6405.         }
  6406.         FH->Printf(",Total\n");
  6407.  
  6408.         for( i = 0; i < entityUsageList.Num(); i++ ) {
  6409.             idStr    className;
  6410.             int        total;
  6411.  
  6412.             if ( entityUsageList[ i ].GetInt( "reported_stat" ) == 3 ) {
  6413.                 continue;
  6414.             }
  6415.  
  6416.             entityUsageList[ i ].GetString( "classname", "none", className );
  6417.  
  6418.             memset( count, 0, size );
  6419.             for( j = i; j < entityUsageList.Num(); j++ )
  6420.             {
  6421.                 idStr    checkMapFileName, checkClassName;
  6422.  
  6423.                 entityUsageList[ j ].GetString( "classname", "none", checkClassName );
  6424.  
  6425.                 if ( checkClassName == className ) {
  6426.                     entityUsageList[ j ].SetInt( "reported_stat", 3 );
  6427.                     entityUsageList[ j ].GetString( "mapFileName", "none", checkMapFileName );
  6428.  
  6429.                     int loc = uniqueMapNames.FindIndex( checkMapFileName );
  6430.                     if ( loc >= 0 ) {
  6431.                         count[ loc ]++;
  6432.                     }
  6433.                 }
  6434.             }
  6435.  
  6436.             total = 0;
  6437.             FH->Printf( "\"%s\"", className.c_str() );
  6438.             for( j = 0; j < uniqueMapNames.Num(); j++ ) {
  6439.                 FH->Printf( ",%d", count[ j ] );
  6440.                 total += count[ j ];
  6441.             }
  6442.             FH->Printf( ",%d\n", total );
  6443.         }
  6444.  
  6445.         fileSystem->CloseFile( FH );
  6446.     }
  6447. }
  6448. // RAVEN END
  6449.  
  6450. /*
  6451. ======================
  6452. idGameLocal::SpreadLocations
  6453.  
  6454. Now that everything has been spawned, associate areas with location entities
  6455. ======================
  6456. */
  6457. void idGameLocal::SpreadLocations() {
  6458.     idEntity *ent;
  6459.  
  6460. // RAVEN BEGIN
  6461.     if( !gameRenderWorld ) {
  6462.         common->Error( "GameRenderWorld is NULL!" );
  6463.     }
  6464. // RAVEN END
  6465.  
  6466.     // allocate the area table
  6467.     int    numAreas = gameRenderWorld->NumAreas();
  6468.     locationEntities = new idLocationEntity *[ numAreas ];
  6469.     memset( locationEntities, 0, numAreas * sizeof( *locationEntities ) );
  6470.  
  6471.     // for each location entity, make pointers from every area it touches
  6472.     for( ent = spawnedEntities.Next(); ent != NULL; ent = ent->spawnNode.Next() ) {
  6473. // RAVEN BEGIN
  6474. // jnewquist: Use accessor for static class type 
  6475.         if ( !ent->IsType( idLocationEntity::GetClassType() ) ) {
  6476. // RAVEN END
  6477.             continue;
  6478.         }
  6479.         idVec3    point = ent->spawnArgs.GetVector( "origin" );
  6480.         int areaNum = gameRenderWorld->PointInArea( point );
  6481.         if ( areaNum < 0 ) {
  6482.             Printf( "SpreadLocations: location '%s' is not in a valid area\n", ent->spawnArgs.GetString( "name" ) );
  6483.             continue;
  6484.         }
  6485.         if ( areaNum >= numAreas ) {
  6486.             Error( "idGameLocal::SpreadLocations: areaNum >= gameRenderWorld->NumAreas()" );
  6487.         }
  6488.         if ( locationEntities[areaNum] ) {
  6489.             Warning( "location entity '%s' overlaps '%s'", ent->spawnArgs.GetString( "name" ),
  6490.                 locationEntities[areaNum]->spawnArgs.GetString( "name" ) );
  6491.             continue;
  6492.         }
  6493.         locationEntities[areaNum] = static_cast<idLocationEntity *>(ent);
  6494.  
  6495.         // spread to all other connected areas
  6496.         for ( int i = 0 ; i < numAreas ; i++ ) {
  6497.             if ( i == areaNum ) {
  6498.                 continue;
  6499.             }
  6500.             if ( gameRenderWorld->AreasAreConnected( areaNum, i, PS_BLOCK_LOCATION ) ) {
  6501.                 locationEntities[i] = static_cast<idLocationEntity *>(ent);
  6502.             }
  6503.         }
  6504.     }
  6505. }
  6506.  
  6507. /*
  6508. ===================
  6509. idGameLocal::AddLocation
  6510. ===================
  6511. */
  6512. idLocationEntity* idGameLocal::AddLocation ( const idVec3& point, const char* name ) {
  6513.     int areaNum = gameRenderWorld->PointInArea( point );
  6514.     if ( areaNum < 0 ) {
  6515.         Warning ( "idGameLocal::AddLocation: cannot add location entity '%s' at '%g %g %g'\n", name, point.x, point.y, point.z );
  6516.         return NULL;
  6517.     }
  6518.     if ( areaNum >= gameRenderWorld->NumAreas() ) {
  6519.         Error( "idGameLocal::AddLocation: areaNum >= gameRenderWorld->NumAreas()" );
  6520.     }
  6521.     if ( locationEntities[areaNum] ) {
  6522.         Warning ( "idGameLocal::AddLocation: location '%s' already exists at '%g %g %g'\n", locationEntities[areaNum]->GetName(), point.x, point.y, point.z );
  6523.         return NULL;
  6524.     }
  6525.  
  6526.     // Spawn the new location entity
  6527.     idDict args;
  6528.     args.Set ( "location", name );
  6529.     locationEntities[areaNum] = static_cast<idLocationEntity*>(SpawnEntityType ( idLocationEntity::GetClassType(), &args ));
  6530.  
  6531.     // spread to all other connected areas
  6532.     for ( int i = gameRenderWorld->NumAreas() - 1 ; i >= 0 ; i-- ) {
  6533.         if ( i == areaNum ) {
  6534.             continue;
  6535.         }
  6536.         if ( gameRenderWorld->AreasAreConnected( areaNum, i, PS_BLOCK_LOCATION ) ) {
  6537.             locationEntities[i] = static_cast<idLocationEntity *>(locationEntities[areaNum]);
  6538.         }
  6539.     }
  6540.     
  6541.     return locationEntities[areaNum];
  6542. }
  6543.  
  6544. /*
  6545. ===================
  6546. idGameLocal::LocationForPoint
  6547.  
  6548. The player checks the location each frame to update the HUD text display
  6549. May return NULL
  6550. ===================
  6551. */
  6552. idLocationEntity *idGameLocal::LocationForPoint( const idVec3 &point ) {
  6553.     if ( !locationEntities ) {
  6554.         // before SpreadLocations() has been called
  6555.         return NULL;
  6556.     }
  6557.  
  6558.     int areaNum = gameRenderWorld->PointInArea( point );
  6559.     if ( areaNum < 0 ) {
  6560.         return NULL;
  6561.     }
  6562.     if ( areaNum >= gameRenderWorld->NumAreas() ) {
  6563.         Error( "idGameLocal::LocationForPoint: areaNum >= gameRenderWorld->NumAreas()" );
  6564.     }
  6565.  
  6566.     return locationEntities[ areaNum ];
  6567. }
  6568.  
  6569. /*
  6570. ============
  6571. idGameLocal::SetPortalState
  6572. ============
  6573. */
  6574. void idGameLocal::SetPortalState( qhandle_t portal, int blockingBits ) {
  6575.     idBitMsg outMsg;
  6576.     byte msgBuf[ MAX_GAME_MESSAGE_SIZE ];
  6577.  
  6578.     if ( !gameLocal.isClient ) {
  6579.         outMsg.Init( msgBuf, sizeof( msgBuf ) );
  6580.         outMsg.WriteByte( GAME_RELIABLE_MESSAGE_PORTAL );
  6581.         outMsg.WriteLong( portal );
  6582.         outMsg.WriteBits( blockingBits, NUM_RENDER_PORTAL_BITS );
  6583.         networkSystem->ServerSendReliableMessage( -1, outMsg );
  6584.     }
  6585.     gameRenderWorld->SetPortalState( portal, blockingBits );
  6586. }
  6587.  
  6588. /*
  6589. ============
  6590. idGameLocal::sortSpawnPoints
  6591. ============
  6592. */
  6593. int idGameLocal::sortSpawnPoints( const void *ptr1, const void *ptr2 ) {
  6594.     const spawnSpot_t *spot1 = static_cast<const spawnSpot_t *>( ptr1 );
  6595.     const spawnSpot_t *spot2 = static_cast<const spawnSpot_t *>( ptr2 );
  6596.     float diff;
  6597.  
  6598.     diff = spot1->dist - spot2->dist;
  6599.     if ( diff < 0.0f ) {
  6600.         return 1;
  6601.     } else if ( diff > 0.0f ) {
  6602.         return -1;
  6603.     } else {
  6604.         return 0;
  6605.     }
  6606. }
  6607.  
  6608. // RAVEN BEGIN
  6609. // ddynerman: new gametype specific spawn code
  6610. // TODO this should be moved to idMultiplayerGame
  6611. /*
  6612. ===========
  6613. idGameLocal::InitializeSpawns
  6614. randomize the order of the initial spawns
  6615. prepare for a sequence of initial player spawns
  6616. ============
  6617. */
  6618. void idGameLocal::InitializeSpawns( void ) {
  6619.     idEntity* spot = NULL;
  6620.  
  6621.     if ( !isMultiplayer || isClient ) {
  6622.         return;
  6623.     }
  6624.  
  6625.     spawnSpots.Clear();
  6626.  
  6627.     for( int i = 0; i < TEAM_MAX; i++ ) {
  6628.         teamSpawnSpots[i].Clear();
  6629.     }
  6630.     
  6631.     spot = FindEntityUsingDef( NULL, "info_player_team" );
  6632.     while( spot ) {
  6633. // RAVEN BEGIN
  6634. // jnewquist: Use accessor for static class type 
  6635.         if( spot->IsType ( idPlayerStart::GetClassType() ) ) {
  6636. // RAVEN END
  6637.             if( !idStr::Icmp(spot->spawnArgs.GetString("team"), "strogg") ) {
  6638.                 teamSpawnSpots[TEAM_STROGG].Append( static_cast<idPlayerStart*>(spot) );
  6639.             } else if( !idStr::Icmp(spot->spawnArgs.GetString("team"), "marine") ) {
  6640.                 teamSpawnSpots[TEAM_MARINE].Append( static_cast<idPlayerStart*>(spot) );
  6641.             }
  6642.  
  6643.             // spawnSpots contains info_player_team as well as info_player_deathmatch
  6644.             spawnSpots.Append ( static_cast<idPlayerStart*>(spot) );
  6645.             
  6646.         }
  6647.  
  6648.         spot = FindEntityUsingDef( spot, "info_player_team" );
  6649.     }
  6650.  
  6651.     spot = FindEntityUsingDef( NULL, "info_player_deathmatch" );
  6652.     while( spot ) {
  6653. // RAVEN BEGIN
  6654. // jnewquist: Use accessor for static class type 
  6655.         if( spot->IsType ( idPlayerStart::GetClassType() ) ) {
  6656. // RAVEN END
  6657.             spawnSpots.Append ( static_cast<idPlayerStart*>(spot) );
  6658.         }
  6659.         spot = FindEntityUsingDef( spot, "info_player_deathmatch" );
  6660.     }
  6661.  
  6662.     if( IsFlagGameType() ) {
  6663.         idEntity* flag = FindEntityUsingDef( NULL, "mp_ctf_marine_flag" );
  6664.         if( flag ) {
  6665.             mpGame.flagBaseLocation[ flag->spawnArgs.GetInt( "team", "0" ) ] = flag->GetPhysics()->GetOrigin();
  6666.         }
  6667.  
  6668.         flag = FindEntityUsingDef( NULL, "mp_ctf_strogg_flag" );
  6669.         if( flag ) {
  6670.             mpGame.flagBaseLocation[ flag->spawnArgs.GetInt( "team", "0" ) ] = flag->GetPhysics()->GetOrigin();
  6671.         }
  6672.     }
  6673.  
  6674.     while( spot ) {
  6675.         // RAVEN BEGIN
  6676.         // jnewquist: Use accessor for static class type 
  6677.         if( spot->IsType ( idPlayerStart::GetClassType() ) ) {
  6678.             // RAVEN END
  6679.             if( !idStr::Icmp(spot->spawnArgs.GetString("team"), "strogg") ) {
  6680.                 teamSpawnSpots[TEAM_STROGG].Append( static_cast<idPlayerStart*>(spot) );
  6681.             } else if( !idStr::Icmp(spot->spawnArgs.GetString("team"), "marine") ) {
  6682.                 teamSpawnSpots[TEAM_MARINE].Append( static_cast<idPlayerStart*>(spot) );
  6683.             }
  6684.  
  6685.             // spawnSpots contains info_player_team as well as info_player_deathmatch
  6686.             spawnSpots.Append ( static_cast<idPlayerStart*>(spot) );
  6687.  
  6688.         }
  6689.  
  6690.         spot = FindEntityUsingDef( spot, "info_player_team" );
  6691.     }
  6692.  
  6693.     if( IsFlagGameType() && ( teamSpawnSpots[ TEAM_STROGG ].Num() == 0 || teamSpawnSpots[ TEAM_MARINE ].Num() == 0 ) ) {
  6694.         Error( "InitializeSpawns() - Map must have at least one Marine and one Strogg spawn for CTF gametype.");
  6695.     }
  6696.  
  6697.     if( spawnSpots.Num() == 0 ) {
  6698.         Error( "InitializeSpawns() - Map must have a spawn spot." );
  6699.     }
  6700.  
  6701.     common->Printf( "%d general spawns\n", spawnSpots.Num() );
  6702.     common->Printf( "%d team spawns (%d strogg/%d marine)\n", teamSpawnSpots[TEAM_STROGG].Num() + teamSpawnSpots[TEAM_MARINE].Num(),
  6703.                                                          teamSpawnSpots[TEAM_STROGG].Num(), teamSpawnSpots[TEAM_MARINE].Num());
  6704. }
  6705.  
  6706. /*
  6707. ===========
  6708. idGameLocal::UpdateForwardSpawn
  6709. ddynerman: Updates forward spawn lists
  6710. ===========
  6711. */
  6712. void idGameLocal::UpdateForwardSpawns( rvCTFAssaultPlayerStart* point, int team ) {
  6713.     teamForwardSpawnSpots[ team ].Append( point );
  6714. }
  6715.  
  6716. /*
  6717. ===========
  6718. idGameLocal::ClearForwardSpawn
  6719. ddynerman: Clears forward spawn lists
  6720. ===========
  6721. */
  6722. void idGameLocal::ClearForwardSpawns( void ) {
  6723.     for( int i = 0; i < TEAM_MAX; i++ ) {
  6724.         teamForwardSpawnSpots[ i ].Clear();
  6725.     }
  6726. }
  6727.  
  6728. /*
  6729. ===========
  6730. idGameLocal::SelectSpawnSpot
  6731. ddynerman: Selects a spawn spot based on gametype and not-telefragging
  6732. ===========
  6733. */
  6734. idEntity* idGameLocal::SelectSpawnPoint( idPlayer* player ) {
  6735.     if( !isMultiplayer ) {
  6736.         idEntity* ent = FindEntityUsingDef( NULL, "info_player_start" );
  6737.         if ( !ent ) {
  6738.             Error( "No info_player_start on map.\n" );
  6739.         }
  6740.         return ent;
  6741.     }
  6742.  
  6743.     if( player == NULL ) {
  6744.         return NULL;
  6745.     }
  6746.  
  6747.     // Give spectators any old random spot
  6748.     if( player->team < 0 || player->team >= TEAM_MAX || player->spectating ) {
  6749.         common->DPrintf("Returning a random spot\n");
  6750.         return spawnSpots[ random.RandomInt( spawnSpots.Num() ) ];
  6751.     }
  6752.  
  6753.     idList<spawnSpot_t> weightedSpawns;
  6754.     idList<idPlayerStart*>* spawnArray = NULL;
  6755.  
  6756.     // Pick which spawns to use based on gametype
  6757.     if( gameLocal.gameType == GAME_DM || gameLocal.gameType == GAME_TDM || gameLocal.gameType == GAME_TOURNEY ) {
  6758.         spawnArray = &spawnSpots;
  6759.     } 
  6760.     else if( IsFlagGameType() ) {    
  6761.         if( teamForwardSpawnSpots[ player->team ].Num() ) {
  6762.             spawnArray = &teamForwardSpawnSpots[ player->team ];
  6763.         } else {
  6764.             spawnArray = &teamSpawnSpots[ player->team ];
  6765.         }
  6766.     }
  6767.  
  6768.     if ( spawnArray == NULL ) {
  6769.         Error( "SelectSpawnPoint() - invalid spawn list." );
  6770.         return NULL;
  6771.     }
  6772.  
  6773. #if 0
  6774.     // Run through each spawn point and mark it's distance to each player
  6775.     for( int i = 0; i < spawnArray->Num(); i++ ) {
  6776.         idVec3 pos = (*spawnArray)[ i ]->GetPhysics()->GetOrigin();
  6777.         spawnSpot_t newSpot;
  6778.         newSpot.dist = 0;
  6779.         newSpot.ent = (*spawnArray)[ i ];
  6780.         for( int j = 0; j < MAX_CLIENTS; j++ ) {    
  6781. // RAVEN BEGIN
  6782. // jnewquist: Use accessor for static class type 
  6783.             if ( !entities[ j ] || !entities[ j ]->IsType( idPlayer::GetClassType() )
  6784. // RAVEN END
  6785.                 || entities[ j ] == player
  6786.                 || static_cast< idPlayer * >( entities[ j ] )->spectating ) {
  6787.                 continue;
  6788.             }
  6789.  
  6790.             // ignore distance to people in other instances
  6791.             if( entities[ j ]->GetInstance() != player->GetInstance() ) {
  6792.                 continue;
  6793.             }
  6794.  
  6795.             // in team deathmatch, only figure distance to teammates
  6796.             if ( gameLocal.gameType == GAME_TDM ) {
  6797.                 if ( static_cast< idPlayer * >( entities[ j ] )->team != player->team ) {
  6798.                     continue;
  6799.                 }
  6800.             }
  6801.             
  6802.             newSpot.dist += ( pos - entities[ j ]->GetPhysics()->GetOrigin() ).LengthSqr();
  6803.         }
  6804.         weightedSpawns.Append( newSpot );
  6805.     }
  6806.  
  6807.     // before we sort the list, we randomize it's order.  In many cases player distance does not differentiate enough,
  6808.     // and we'd like some randomness in the other spawns.
  6809.     for( int i = 0; i < weightedSpawns.Num(); i++ ) {
  6810.         int j = random.RandomInt( weightedSpawns.Num() - i ) + i;
  6811.         if ( i == j ) {
  6812.             continue;
  6813.         }
  6814.         spawnSpot_t temp = weightedSpawns[ i ];
  6815.         weightedSpawns[ i ] = weightedSpawns[ j ];
  6816.         weightedSpawns[ j ] = temp;
  6817.     }
  6818.     
  6819.     // sort the list - spawn spots further from players will be at the beginning of the list, spawns closer will be at the end
  6820.     qsort( ( void * )weightedSpawns.Ptr(), spawnArray->Num(), sizeof( spawnSpot_t ), ( int (*)(const void *, const void *) )sortSpawnPoints );
  6821.  
  6822.     // how many spawns we should consider
  6823.     int factor = 3; // num spawns / 3 =~ 30%, so we use top/bottom ~30% of weightedSpawns
  6824.  
  6825.     if( gameType == GAME_DM || gameType == GAME_TOURNEY ) {
  6826.         // for deathmatch, pick a spot more remote areas
  6827.         return SpawnInRange( weightedSpawns, player, 0, (spawnArray->Num() - 1) / factor );
  6828.     } else if( gameType == GAME_TDM || IsFlagGameType() ) {
  6829.         // for team deathmatch and ctf pick a spot close to team mates
  6830.         return SpawnInRange( weightedSpawns, player, (spawnArray->Num() - 1) - ((spawnArray->Num() - 1) / factor), spawnArray->Num() - 1 );
  6831.     } else {
  6832.         Error( "SelectSpawnSpot() - Unknown gametype.");
  6833.         return NULL;
  6834.     }
  6835.  
  6836.     return SpawnInRange( weightedSpawns, player, 0, (weightedSpawns.Num() - 1) );
  6837.  
  6838. #else
  6839.  
  6840.     bool    completelyRandom = false;
  6841.     int        startIndex = 0;
  6842.     int        endIndex = 0;
  6843.  
  6844.     if ( gameType == GAME_CTF || 
  6845.          gameType == GAME_1F_CTF || 
  6846.          gameType == GAME_ARENA_CTF || 
  6847.          gameType == GAME_ARENA_1F_CTF ) {
  6848.         // remain random
  6849.  
  6850.         completelyRandom = true;
  6851.      } else if ( player->lastKiller.IsValid() && !player->lastKiller.GetEntity()->spectating ) {
  6852.         // pick from any spot except nearest to where your killer is currently at
  6853.  
  6854.         common->DPrintf( "killer is at %s\n", player->lastKiller.GetEntity()->GetPhysics()->GetOrigin().ToString( 0 ) );
  6855.  
  6856.         for( int i = 0; i < spawnArray->Num(); i++ ) {
  6857.             idVec3    pos = (*spawnArray)[ i ]->GetPhysics()->GetOrigin();
  6858.             float    dist = ( pos - player->lastKiller.GetEntity()->GetPhysics()->GetOrigin() ).LengthSqr();
  6859.  
  6860.             spawnSpot_t        newSpot;
  6861.  
  6862.             newSpot.dist = dist;
  6863.             newSpot.ent = (*spawnArray)[ i ];
  6864.  
  6865.             weightedSpawns.Append( newSpot );
  6866.         }
  6867.  
  6868.         // sort the list - spawn spots further from players will be at the beginning of the list, spawns closer will be at the end
  6869.         qsort( ( void * )weightedSpawns.Ptr(), weightedSpawns.Num(), sizeof( spawnSpot_t ), ( int (*)(const void *, const void *) )sortSpawnPoints );
  6870.  
  6871.         startIndex = 0;
  6872.         endIndex = weightedSpawns.Num() - 6 - 1;
  6873.  
  6874.         if ( endIndex < startIndex ) {
  6875.             // we don't have enough spawn points!
  6876.             completelyRandom = true;
  6877.         }
  6878.      } else {
  6879.         completelyRandom = true;
  6880.      }
  6881.  
  6882.      if ( completelyRandom ) {
  6883.         for( int i = 0; i < spawnArray->Num(); i++ ) {
  6884.             spawnSpot_t        newSpot;
  6885.  
  6886.             newSpot.dist = 0;
  6887.             newSpot.ent = (*spawnArray)[ i ];
  6888.  
  6889.             weightedSpawns.Append( newSpot );
  6890.         }
  6891.  
  6892.         startIndex = 0;
  6893.         endIndex = weightedSpawns.Num() - 1;
  6894.      }
  6895.  
  6896.     common->DPrintf( "spawning player from %d to %d out of %d\n", startIndex, endIndex, weightedSpawns.Num() - 1 );
  6897.     for( int i = startIndex; i <= endIndex; i++ ) {
  6898.         common->DPrintf( "   %d: %d\n", i, weightedSpawns[ i ].dist );
  6899.     }
  6900.  
  6901.     idEntity *spot = SpawnInRange( weightedSpawns, player, startIndex, endIndex, weightedSpawns.Num() - 1 );
  6902.  
  6903.     common->DPrintf( "Spawned at %s\n", spot->GetPhysics()->GetOrigin().ToString( 0 ) );
  6904.  
  6905.     return spot;
  6906. #endif
  6907. }
  6908.  
  6909. /*
  6910. ===========
  6911. idGameLocal::SpawnInRange
  6912. ddynerman:    Selects a spawn spot from spawns in the given range.  Not very 
  6913.             robust, will work best if either lowIndex is at the start of the
  6914.             array or highIndex is at the end.
  6915. ===========
  6916. */
  6917. idEntity* idGameLocal::SpawnInRange( idList<spawnSpot_t>& spawns, idEntity* player, int lowIndex, int highIndex, int maxIndex ) {
  6918.     idPlayer*        playerList[ MAX_CLIENTS ];
  6919.     idList< int >    rawIndex, randomIndex;
  6920.     int                i, index;
  6921.  
  6922.     for( i = lowIndex; i <= highIndex; i++ ) {
  6923.         rawIndex.Append( i );
  6924.     }
  6925.  
  6926.     for( i = lowIndex; i <= highIndex; i++ ) {
  6927.         index = random.RandomInt( rawIndex.Num() );
  6928.         randomIndex.Append( rawIndex[ index ] );
  6929.         rawIndex.RemoveIndex( index );
  6930.     }
  6931.  
  6932.     memset( playerList, 0, sizeof(idEntity*) * MAX_CLIENTS );
  6933.  
  6934.     for( i = 0; i < randomIndex.Num(); i++ ) {
  6935.         common->DPrintf( "checking spawn #%d at %s with dist of %d\n", 
  6936.             randomIndex[ i ], spawns[ randomIndex[ i ] ].ent->GetPhysics()->GetOrigin().ToString( 0 ), spawns[ randomIndex[ i ] ].dist );
  6937.  
  6938.         idBounds bound = player->GetPhysics()->GetBounds();
  6939.         bound.TranslateSelf( spawns[ randomIndex[ i ] ].ent->GetPhysics()->GetOrigin() );
  6940.  
  6941.         int numEntities = PlayersTouchingBounds( player, bound, CONTENTS_BODY, playerList, MAX_CLIENTS );
  6942.  
  6943.         if ( numEntities == 0 ) {
  6944.             return spawns[ randomIndex[ i ] ].ent;
  6945.         }
  6946.     }
  6947.  
  6948.     if ( lowIndex == 0 && highIndex == maxIndex ) {
  6949.         // bad news, no spawn point available!
  6950.         common->DPrintf( "no spawns left!\n");
  6951.         return spawns[ randomIndex[ 0 ] ].ent;
  6952.     }
  6953.  
  6954.     common->DPrintf( "no spawns within limited index, trying everything\n" );
  6955.  
  6956.     return SpawnInRange( spawns, player, 0, maxIndex, maxIndex );
  6957. }
  6958. // RAVEN END
  6959.  
  6960. /*
  6961. ================
  6962. idGameLocal::UpdateServerInfoFlags
  6963. ================
  6964. */
  6965. // RAVEN BEGIN
  6966. // ddynerman: new gametype strings
  6967. void idGameLocal::SetGameType( void ) {
  6968.     gameType = GAME_SP;
  6969.  
  6970.     if ( idStr::Icmp( serverInfo.GetString( "si_gameType" ), "singleplayer" ) ) {
  6971.         mpGame.SetGameType();
  6972.     }
  6973. }
  6974. // RAVEN END
  6975.  
  6976. /*
  6977. ================
  6978. idGameLocal::SetGlobalMaterial
  6979. ================
  6980. */
  6981. void idGameLocal::SetGlobalMaterial( const idMaterial *mat ) {
  6982.     globalMaterial = mat;
  6983. }
  6984.  
  6985. /*
  6986. ================
  6987. idGameLocal::GetGlobalMaterial
  6988. ================
  6989. */
  6990. const idMaterial *idGameLocal::GetGlobalMaterial() {
  6991.     return globalMaterial;
  6992. }
  6993.  
  6994. /*
  6995. ================
  6996. idGameLocal::GetSpawnId
  6997. ================
  6998. */
  6999. int idGameLocal::GetSpawnId( const idEntity* ent ) const {
  7000.     return ( gameLocal.spawnIds[ ent->entityNumber ] << GENTITYNUM_BITS ) | ent->entityNumber;
  7001. }
  7002.  
  7003. /*
  7004. ================
  7005. idGameLocal::ThrottleUserInfo
  7006. ================
  7007. */
  7008. void idGameLocal::ThrottleUserInfo( void ) {
  7009.     mpGame.ThrottleUserInfo();
  7010. }
  7011.  
  7012. /*
  7013. ===========
  7014. idGameLocal::GetBestGameType
  7015. ============
  7016. */
  7017. idStr idGameLocal::GetBestGameType( const char* map, const char* gametype ) {
  7018.     return gametype;
  7019. }
  7020.  
  7021. /*
  7022. ===========
  7023. idGameLocal::NeedRestart
  7024. ============
  7025. */
  7026. bool idGameLocal::NeedRestart() {
  7027.  
  7028.     idDict        newInfo;
  7029.     const idKeyValue *keyval, *keyval2;
  7030.  
  7031.     newInfo = *cvarSystem->MoveCVarsToDict( CVAR_SERVERINFO );
  7032.  
  7033.     for ( int i = 0; i < newInfo.GetNumKeyVals(); i++ ) {
  7034.         keyval = newInfo.GetKeyVal( i );
  7035.         keyval2 = serverInfo.FindKey( keyval->GetKey() );
  7036.         if ( !keyval2 ) {
  7037.             return true;
  7038.         }
  7039.         // a select set of si_ changes will cause a full restart of the server
  7040.         if ( keyval->GetValue().Icmp( keyval2->GetValue() ) && ( !keyval->GetKey().Icmp( "si_pure" ) || !keyval->GetKey().Icmp( "si_map" ) ) ) {
  7041.             return true;
  7042.         }
  7043.     }
  7044.     return false;
  7045. }
  7046.  
  7047. // RAVEN BEGIN
  7048. // jshepard: update player hud to alert to end of level
  7049. /*
  7050. ===================
  7051. idGameLocal::UpdateEndLevel
  7052. ===================
  7053. */
  7054. void idGameLocal::UpdateEndLevel()    {
  7055.     idPlayer * player = GetLocalPlayer();
  7056.  
  7057.     if( player && player->GetHud() ) {
  7058.         player->GetHud()->HandleNamedEvent( "showExit" );
  7059.     }
  7060. }
  7061.  
  7062.  
  7063. // bdube: added
  7064. /*
  7065. ================
  7066. idGameLocal::GetEffect
  7067.  
  7068. Get the handle of the effect with the given name
  7069. ================
  7070. */
  7071. const idDecl *idGameLocal::GetEffect ( const idDict& args, const char* effectName, const rvDeclMatType* materialType ) {
  7072.     const char *effectFile = NULL;
  7073.  
  7074.     float chance = args.GetFloat ( idStr("effectchance ") + effectName, "1" );    
  7075.     if ( random.RandomFloat ( ) > chance ) {
  7076.         return NULL;
  7077.     }
  7078.  
  7079.     // we should ALWAYS be playing sounds from the def.
  7080.     // hardcoded sounds MUST be avoided at all times because they won't get precached.
  7081.     assert( !idStr::Icmpn( effectName, "fx_", 3 ) );
  7082.  
  7083.     if ( materialType )    {
  7084.         idStr        temp;
  7085.         const char*    result = NULL;
  7086.         
  7087.         temp = effectName;
  7088.         temp += "_";
  7089.         temp += materialType->GetName();
  7090.     
  7091.         // See if the given material effect is specified
  7092.         if ( isMultiplayer ) {
  7093.             idStr    testMP = temp;
  7094.             testMP += "_mp";
  7095.  
  7096.             result = args.GetString( testMP );
  7097.         }
  7098.         if ( !result || !*result ) {
  7099.             result = args.GetString( temp );
  7100.         }
  7101.         if ( result && *result) {
  7102.             return( ( const idDecl * )declManager->FindEffect( result ) );
  7103.         }
  7104.     }    
  7105.  
  7106.     // grab the non material effect name
  7107.     if ( isMultiplayer ) {
  7108.         idStr    testMP = effectName;
  7109.         testMP += "_mp";
  7110.  
  7111.         effectFile = args.GetString( testMP );
  7112.     }
  7113.  
  7114.     if ( !effectFile || !*effectFile ) {
  7115.         effectFile = args.GetString( effectName );
  7116.     }
  7117.  
  7118.     if ( !effectFile || !*effectFile ) {
  7119.         return NULL;
  7120.     }
  7121.  
  7122.     return( ( const idDecl * )declManager->FindEffect( effectFile ) );
  7123. }
  7124.  
  7125. /*
  7126. ================
  7127. idGameLocal::PlayEffect
  7128.  
  7129. Plays an effect at the given origin using the given direction
  7130. ================
  7131. */
  7132. rvClientEffect* idGameLocal::PlayEffect( 
  7133.     const idDecl            *effect, 
  7134.     const idVec3&            origin, 
  7135.     const idMat3&            axis, 
  7136.     bool                    loop, 
  7137.     const idVec3&            endOrigin, 
  7138.     bool                    broadcast,
  7139.     effectCategory_t        category,
  7140.     const idVec4&            effectTint ) {
  7141.  
  7142.     if ( !effect ) {
  7143.         return NULL;
  7144.     }
  7145.  
  7146.     if ( !gameLocal.isNewFrame ) {
  7147.         return NULL;
  7148.     }
  7149.  
  7150.     if ( isServer && broadcast ) {
  7151.         idBitMsg    msg;
  7152.         byte        msgBuf[MAX_GAME_MESSAGE_SIZE];
  7153.         idCQuat        quat;
  7154.  
  7155.         quat = axis.ToCQuat();
  7156.         msg.Init( msgBuf, sizeof( msgBuf ) );
  7157.         msg.BeginWriting();
  7158.         msg.WriteByte( GAME_UNRELIABLE_MESSAGE_EFFECT );
  7159.         idGameLocal::WriteDecl( msg, effect );
  7160.         msg.WriteFloat( origin.x );
  7161.         msg.WriteFloat( origin.y );
  7162.         msg.WriteFloat( origin.z );
  7163.         msg.WriteFloat( quat.x );
  7164.         msg.WriteFloat( quat.y );
  7165.         msg.WriteFloat( quat.z );
  7166.         msg.WriteBits( loop, 1 );
  7167.         msg.WriteFloat( endOrigin.x );
  7168.         msg.WriteFloat( endOrigin.y );
  7169.         msg.WriteFloat( endOrigin.z );
  7170.         msg.WriteByte( category );
  7171.  
  7172.         // send to everyone who has start or end in it's PVS
  7173.         SendUnreliableMessagePVS( msg, currentThinkingEntity, pvs.GetPVSArea( origin ), pvs.GetPVSArea( endOrigin ) );
  7174.     }
  7175.  
  7176.     if ( isServer && localClientNum < 0 ) {
  7177.         // no effects on dedicated server
  7178.         return NULL;
  7179.     }
  7180.  
  7181.     if ( bse->Filtered( effect->GetName(), category ) ) {
  7182.         // Effect filtered out
  7183.         return NULL;
  7184.     }
  7185. // RAVEN END
  7186.  
  7187.     if ( gameLocal.isListenServer && currentThinkingEntity && gameLocal.GetLocalPlayer() ) {
  7188.         if ( currentThinkingEntity->GetInstance() != gameLocal.GetLocalPlayer()->GetInstance() ) {
  7189.             return NULL;
  7190.         }
  7191.     }
  7192.     
  7193.     // mwhitlock: Dynamic memory consolidation
  7194.     RV_PUSH_SYS_HEAP_ID(RV_HEAP_ID_MULTIPLE_FRAME);
  7195.     rvClientEffect* clientEffect = new rvClientEffect( effect );
  7196.     RV_POP_HEAP();
  7197.  
  7198.     clientEffect->SetOrigin( origin );
  7199.     clientEffect->SetAxis( axis );
  7200.     clientEffect->SetGravity( GetCurrentGravity( origin, axis ) );
  7201.     if ( !clientEffect->Play( gameLocal.time, loop, endOrigin ) ) {
  7202.         delete clientEffect;
  7203.         return NULL;
  7204.     }
  7205.  
  7206.     clientEffect->GetRenderEffect()->shaderParms[ SHADERPARM_RED ]        = effectTint[ 0 ];
  7207.     clientEffect->GetRenderEffect()->shaderParms[ SHADERPARM_GREEN ]    = effectTint[ 1 ];
  7208.     clientEffect->GetRenderEffect()->shaderParms[ SHADERPARM_BLUE ]        = effectTint[ 2 ];
  7209.     clientEffect->GetRenderEffect()->shaderParms[ SHADERPARM_ALPHA ]    = effectTint[ 3 ];
  7210.  
  7211.     return clientEffect;
  7212. }
  7213.  
  7214. void idGameLocal::CheckPlayerWhizzBy( idVec3 start, idVec3 end, idEntity* hitEnt, idEntity *attacker )
  7215. {
  7216.     //FIXME: make this client-side?  Work in MP?
  7217.     if ( gameLocal.isMultiplayer ) {
  7218.         return;
  7219.     }
  7220.     idPlayer* player = gameLocal.GetLocalPlayer();
  7221.     if ( !player ) {
  7222.         return;
  7223.     }
  7224.     if ( player->IsHidden() ) {
  7225.         return;
  7226.     }
  7227.     if ( player == attacker ) {
  7228.         return;
  7229.     }
  7230.     if ( player == hitEnt ) {
  7231.         return;
  7232.     }
  7233.     idVec3 center = player->firstPersonViewOrigin;
  7234.     idVec3 diff = end-center;
  7235.     if ( diff.Length() < 64.0f ) {
  7236.         //hit too close - didn't actually pass by, will hear impact sound instead
  7237.         return;
  7238.     }
  7239.     idVec3 closestPoint = player->firstPersonViewOrigin;
  7240.     if ( closestPoint.ProjectToLineSeg( start, end ) ) {
  7241.         //on line seg
  7242.         diff = closestPoint-center;
  7243.         if ( diff.Length() < 48.0f ) {
  7244.             //close enough to hear whizz-by
  7245.             idVec3 dir = end-start;
  7246.             dir.Normalize();
  7247.             idVec3 fxStart = closestPoint+dir*-32.0f;
  7248.             idVec3 fxEnd = closestPoint+dir*32.0f;
  7249.             player->PlayEffect( "fx_whizby", fxStart, player->firstPersonViewAxis, false, fxEnd );
  7250.         }
  7251.     }
  7252. }
  7253.  
  7254. /*
  7255. ================
  7256. idGameLocal::HitScan
  7257.  
  7258. Run a hitscan trace from the given origin and direction
  7259. ================
  7260. */
  7261. idEntity* idGameLocal::HitScan( 
  7262.     const idDict&    hitscanDict, 
  7263.     const idVec3&    origOrigin, 
  7264.     const idVec3&    origDir, 
  7265.     const idVec3&    origFxOrigin, 
  7266.     idEntity*        owner, 
  7267.     bool            noFX,
  7268.     float            damageScale,
  7269. // twhitaker: added additionalIgnore parameter
  7270.     idEntity*        additionalIgnore,
  7271.     int                areas[ 2 ]
  7272.     ) {
  7273.  
  7274.     idVec3        dir;
  7275.     idVec3        origin;
  7276.     idVec3        fxOrigin;
  7277.     idVec3        fxDir;
  7278.     idVec3        impulse;
  7279.     idVec4        hitscanTint( 1.0f, 1.0f, 1.0f, 1.0f );
  7280.     int            reflect;
  7281.     float        tracerChance;
  7282.     idEntity*    ignore;
  7283.     float        penetrate;
  7284.  
  7285.     if ( areas ) {
  7286.         areas[ 0 ] = pvs.GetPVSArea( origFxOrigin );
  7287.         areas[ 1 ] = -1;
  7288.     }
  7289.  
  7290.     ignore    = owner;
  7291.     penetrate = hitscanDict.GetFloat( "penetrate" );
  7292.  
  7293.     if( hitscanDict.GetBool( "hitscanTint" ) && owner->IsType( idPlayer::GetClassType() ) ) {
  7294.         hitscanTint = ((idPlayer*)owner)->GetHitscanTint();
  7295.     }
  7296.  
  7297.     // twhitaker: additionalIgnore parameter
  7298.     if ( !additionalIgnore ) {
  7299.         additionalIgnore = ignore;
  7300.     }    
  7301.  
  7302.     origin         = origOrigin;
  7303.     fxOrigin     = origFxOrigin;
  7304.     dir             = origDir;
  7305.     tracerChance = ((g_perfTest_weaponNoFX.GetBool())?0:hitscanDict.GetFloat( "tracerchance", "0" ));
  7306.  
  7307.     // Apply player powerups
  7308.     if ( owner && owner->IsType( idPlayer::GetClassType() ) ) {
  7309.         damageScale *= static_cast<idPlayer*>(owner)->PowerUpModifier(PMOD_PROJECTILE_DAMAGE);
  7310.     }
  7311.     
  7312.     // Run reflections
  7313.     for ( reflect = hitscanDict.GetFloat( "reflect", "0" ); reflect >= 0; reflect-- ) {    
  7314.         idVec3        start;
  7315.         idVec3        end;
  7316.         idEntity*    ent;
  7317.         idEntity*    actualHitEnt;
  7318.         trace_t        tr;
  7319.         int            contents;
  7320.         int            collisionArea;
  7321.         idVec3        collisionPoint;
  7322.         bool        tracer;
  7323.         
  7324.         // Calculate the end point of the trace
  7325.         start    = origin;
  7326.         if ( g_perfTest_hitscanShort.GetBool() ) {
  7327.             end         = start + (dir.ToMat3() * idVec3(idMath::ClampFloat(0,2048,hitscanDict.GetFloat ( "range", "2048" )),0,0));
  7328.         } else {
  7329.             end         = start + (dir.ToMat3() * idVec3(hitscanDict.GetFloat ( "range", "40000" ),0,0));
  7330.         }
  7331.         if ( g_perfTest_hitscanBBox.GetBool() ) {
  7332.             contents = MASK_SHOT_BOUNDINGBOX|CONTENTS_PROJECTILE;
  7333.         } else {
  7334.             contents = MASK_SHOT_RENDERMODEL|CONTENTS_WATER|CONTENTS_PROJECTILE;
  7335.         }
  7336.         
  7337.         // Loop the traces to handle cases where something can be shot through
  7338.         while ( 1 ) {                
  7339.             // Trace to see if we hit any entities
  7340. // RAVEN BEGIN
  7341. // ddynerman: multiple clip worlds
  7342.             if ( hitscanDict.GetFloat( "trace_size", "0" ) > 0.0f )
  7343.             {
  7344.                 float range = hitscanDict.GetFloat ( "range", "1024" );
  7345.                 if ( range > 4096.0f )
  7346.                 {
  7347.                     assert( !(range > 4096.0f) );
  7348.                     Warning( "idGameLocal::HitScan: hitscan def (%s) with trace_size must have max range of 4096!", hitscanDict.GetString( "classname" ) );
  7349.                     range = idMath::ClampFloat( 0.0f, 4096.0f, range );
  7350.                 }
  7351.                 end    = start + (dir * range);
  7352.  
  7353.                 idBounds traceBounds;
  7354.                 traceBounds.Zero();
  7355.                 traceBounds.ExpandSelf( hitscanDict.GetFloat( "trace_size", "0" ) );
  7356.                 // twhitaker: additionalIgnore parameter
  7357.                 TraceBounds( owner, tr, start, end, traceBounds, contents, additionalIgnore );
  7358.             }
  7359.             else
  7360.             {
  7361.                 // twhitaker: additionalIgnore parameter
  7362.                 TracePoint( owner, tr, start, end, contents, additionalIgnore );
  7363.             }
  7364.             //gameRenderWorld->DebugArrow( colorRed, start, end, 10, 5000 );
  7365. // RAVEN END
  7366.             
  7367.             // If the hitscan hit a no impact surface we can just return out
  7368.             //assert( tr.c.material );
  7369.             if ( tr.fraction >= 1.0f || (tr.c.material && tr.c.material->GetSurfaceFlags() & SURF_NOIMPACT) ) {                    
  7370.                 PlayEffect( hitscanDict, "fx_path", fxOrigin, dir.ToMat3(), false, tr.endpos, false, EC_IGNORE, hitscanTint );    
  7371.                 if ( random.RandomFloat( ) < tracerChance ) {
  7372.                     PlayEffect( hitscanDict, "fx_tracer", fxOrigin, dir.ToMat3(), false, tr.endpos );
  7373.                     tracer = true;
  7374.                 } else {
  7375.                     tracer = false;
  7376.                 }
  7377.  
  7378.                 if ( areas ) {
  7379.                     collisionArea = pvs.GetPVSArea( tr.endpos );
  7380.                     if ( collisionArea != areas[0] ) {
  7381.                         areas[1] = collisionArea;
  7382.                     }
  7383.                 }
  7384.  
  7385.                 return NULL;
  7386.             }
  7387.  
  7388.             // computing the collisionArea from the collisionPoint fails sometimes
  7389.             if ( areas ) {
  7390.                 collisionArea  = pvs.GetPVSArea( tr.c.point );
  7391.                 if ( collisionArea != areas[0] ) {
  7392.                     areas[1] = collisionArea;
  7393.                 }
  7394.             }
  7395.             collisionPoint = tr.c.point - ( tr.c.normal * tr.c.point - tr.c.dist ) * tr.c.normal;
  7396.             ent               = entities[ tr.c.entityNum ];
  7397.             actualHitEnt   = NULL;
  7398.             start           = collisionPoint;
  7399.  
  7400.             // Keep tracing if we hit water
  7401.             if ( (ent->GetPhysics()->GetContents() & CONTENTS_WATER) || (tr.c.material && (tr.c.material->GetContentFlags() & CONTENTS_WATER)) ) {
  7402.                 // Apply force to the water entity that was hit
  7403.                 ent->ApplyImpulse( owner, tr.c.id, tr.c.point, -(hitscanDict.GetFloat( "push", "5000" )) * tr.c.normal );
  7404.                 // Continue on excluding water
  7405.                 contents &= (~CONTENTS_WATER);
  7406.  
  7407.                 if ( !g_perfTest_weaponNoFX.GetBool() ) {
  7408.                     if ( ent->CanPlayImpactEffect( owner, ent ) ) {
  7409.                         if ( ent->IsType( idMover::GetClassType( ) ) ) {
  7410.                             ent->PlayEffect( GetEffect( hitscanDict, "fx_impact", tr.c.materialType ), collisionPoint, tr.c.normal.ToMat3(), false, vec3_origin, false, EC_IMPACT, hitscanTint );
  7411.                         } else {
  7412.                             gameLocal.PlayEffect( GetEffect( hitscanDict, "fx_impact", tr.c.materialType ), collisionPoint, tr.c.normal.ToMat3(), false, vec3_origin, false, EC_IMPACT, hitscanTint );
  7413.                         }
  7414.                     }
  7415.                 }
  7416.  
  7417.                 continue;
  7418.             // Reflect off a bounce target?
  7419.             } else if ( (tr.c.material->GetSurfaceFlags ( ) & SURF_BOUNCE) && !hitscanDict.GetBool ( "noBounce" ) ) {
  7420.                 reflect++;
  7421.             }
  7422.  
  7423.             // If the hit entity is bound to an actor use the actor instead
  7424.             if ( ent->fl.takedamage && ent->GetTeamMaster( ) && ent->GetTeamMaster( )->IsType ( idActor::GetClassType() ) ) {
  7425.                 actualHitEnt = ent;
  7426.                 ent = ent->GetTeamMaster( );
  7427.             }
  7428.  
  7429.             if ( !gameLocal.isClient ) {
  7430.  
  7431.                 // Apply force to the entity that was hit
  7432.                 ent->ApplyImpulse( owner, tr.c.id, tr.c.point, -tr.c.normal, &hitscanDict );
  7433.  
  7434.                 // Handle damage to the entity
  7435.                 if ( ent->fl.takedamage && !(( tr.c.material != NULL ) && ( tr.c.material->GetSurfaceFlags() & SURF_NODAMAGE )) ) {        
  7436.                     const char*    damage;
  7437.                 
  7438.                     damage    = NULL;
  7439.  
  7440.                     // RAVEN BEGIN
  7441.                     // jdischler: code from the other project..to ensure that if an attached head is hit, the body will use the head joint
  7442.                     //    otherwise damage zones for head attachments no-worky
  7443.                     int hitJoint = CLIPMODEL_ID_TO_JOINT_HANDLE(tr.c.id);
  7444.                     if ( ent->IsType(idActor::GetClassType()) )
  7445.                         {
  7446.                             idActor* entActor = static_cast<idActor*>(ent);
  7447.                             if ( entActor && entActor->GetHead() && entActor->GetHead()->IsType(idAFAttachment::GetClassType()) )
  7448.                                 {
  7449.                                     idAFAttachment* headEnt = static_cast<idAFAttachment*>(entActor->GetHead());
  7450.                                     if ( headEnt && headEnt->entityNumber == tr.c.entityNum )
  7451.                                         {//hit ent's head, get the proper joint for the head
  7452.                                             hitJoint = entActor->GetAnimator()->GetJointHandle("head");
  7453.                                         }
  7454.                                 }
  7455.                         }    
  7456.                     // RAVEN END
  7457.                     // Inflict damage
  7458.                     if ( tr.c.materialType ) {
  7459.                         damage = hitscanDict.GetString( va("def_damage_%s", tr.c.materialType->GetName()) );
  7460.                     }
  7461.                     if ( !damage || !*damage ) {
  7462.                         damage = hitscanDict.GetString ( "def_damage" );
  7463.                     }
  7464.  
  7465.                     if ( damage && damage[0] ) {
  7466.                         // RAVEN BEGIN
  7467.                         // ddynerman: stats
  7468.                         if( owner->IsType( idPlayer::GetClassType() ) && ent->IsType( idActor::GetClassType() ) && ent != owner && !((idPlayer*)owner)->pfl.dead ) {
  7469.                             statManager->WeaponHit( (idActor*)owner, ent, ((idPlayer*)owner)->GetCurrentWeapon() );
  7470.                         }
  7471.                         // RAVEN END
  7472.                         ent->Damage( owner, owner, dir, damage, damageScale, hitJoint );
  7473.                     }
  7474.  
  7475.                     // Let the entity add its own damage effect
  7476.                     if ( !g_perfTest_weaponNoFX.GetBool() ) {
  7477.                         ent->AddDamageEffect ( tr, dir, damage, owner );
  7478.                     }
  7479.                 } else { 
  7480.                     if ( actualHitEnt
  7481.                          && actualHitEnt != ent
  7482.                          && (tr.c.material->GetSurfaceFlags ( ) & SURF_BOUNCE)
  7483.                          && actualHitEnt->spawnArgs.GetBool( "takeBounceDamage" ) )
  7484.                         {//bleh...
  7485.                             const char*    damage = NULL;
  7486.                             // Inflict damage
  7487.                             if ( tr.c.materialType ) {
  7488.                                 damage = hitscanDict.GetString( va("def_damage_%s", tr.c.materialType->GetName()) );
  7489.                             }
  7490.                             if ( !damage || !*damage ) {
  7491.                                 damage = hitscanDict.GetString ( "def_damage" );
  7492.                             }
  7493.                             if ( damage && damage[0] ) {
  7494.                                 actualHitEnt->Damage( owner, owner, dir, damage, damageScale, CLIPMODEL_ID_TO_JOINT_HANDLE( tr.c.id ) );
  7495.                             }
  7496.                         }
  7497.                     if ( !g_perfTest_weaponNoFX.GetBool() ) {
  7498.                         ent->AddDamageEffect( tr, dir, hitscanDict.GetString ( "def_damage" ), owner );
  7499.                     }
  7500.                 }
  7501.             }
  7502.  
  7503.  
  7504.             // Pass through actors
  7505.             if ( ent->IsType ( idActor::GetClassType() ) && penetrate > 0.0f ) {            
  7506.                 start = collisionPoint;
  7507.                 additionalIgnore = ent;
  7508.                 damageScale *= penetrate;
  7509.                 continue;
  7510.             }
  7511.             break;
  7512.         }
  7513.             
  7514.         // Path effect 
  7515.         fxDir = collisionPoint - fxOrigin;
  7516.         fxDir.Normalize( );
  7517.         PlayEffect( hitscanDict, "fx_path", fxOrigin, fxDir.ToMat3(), false, collisionPoint, false, EC_IGNORE, hitscanTint );    
  7518.         if ( !ent->fl.takedamage && random.RandomFloat ( ) < tracerChance ) {
  7519.             PlayEffect( hitscanDict, "fx_tracer", fxOrigin, fxDir.ToMat3(), false, collisionPoint );
  7520.             tracer = true;
  7521.         } else {
  7522.             tracer = false;
  7523.         }
  7524.  
  7525.         if ( !reflect ) {
  7526.             //on initial trace only
  7527.             if ( hitscanDict.GetBool( "doWhizz" ) ) {
  7528.                 //play whizz-by sound if trace is close to player's head
  7529.                 CheckPlayerWhizzBy( origin, collisionPoint, ent, owner );
  7530.             }
  7531.         }
  7532.  
  7533.         // Play a different effect when reflecting
  7534.         if ( !reflect || ent->fl.takedamage ) {
  7535.             idMat3 axis;
  7536.             
  7537.             // Effect axis when hitting actors is along the direction of impact because actor models are 
  7538.             // very detailed.
  7539.             if ( ent->IsType ( idActor::GetClassType() ) ) {
  7540.                 axis = ((-dir + tr.c.normal) * 0.5f).ToMat3();
  7541.             } else {
  7542.                 axis = tr.c.normal.ToMat3();
  7543.             }
  7544.             
  7545.             if ( !g_perfTest_weaponNoFX.GetBool() ) {
  7546.                 if ( ent->CanPlayImpactEffect( owner, ent ) ) {
  7547.                     if ( ent->IsType( idMover::GetClassType( ) ) ) {
  7548.                         ent->PlayEffect( GetEffect( hitscanDict, "fx_impact", tr.c.materialType ), collisionPoint, axis, false, vec3_origin, false, EC_IMPACT, hitscanTint );                    
  7549.                     } else {
  7550.                         gameLocal.PlayEffect( GetEffect( hitscanDict, "fx_impact", tr.c.materialType ), collisionPoint, axis, false, vec3_origin, false, EC_IMPACT, hitscanTint );
  7551.                     }
  7552.                 }
  7553.             }
  7554.             
  7555.             // End of reflection
  7556.             return ent;
  7557.         } else {
  7558.             PlayEffect( GetEffect( hitscanDict, "fx_reflect", tr.c.materialType ), collisionPoint, tr.c.normal.ToMat3() );
  7559.         }
  7560.         
  7561.         // Calc new diretion based on bounce
  7562.         origin = start;
  7563.         fxOrigin = start;
  7564.         dir = ( dir - ( 2.0f * DotProduct( dir, tr.c.normal ) * tr.c.normal ) );
  7565.         dir.Normalize( );
  7566.  
  7567.         // Increase damage scale on reflect        
  7568.         damageScale += hitscanDict.GetFloat( "reflect_powerup", "0" );
  7569.     }    
  7570.     
  7571.     assert( false );
  7572.     
  7573.     return NULL;
  7574. }
  7575.  
  7576. /*
  7577. ===================
  7578. idGameLocal::RegisterClientEntity
  7579. ===================
  7580. */
  7581. void idGameLocal::RegisterClientEntity( rvClientEntity *cent ) {
  7582.     int entityNumber;
  7583.  
  7584.     assert ( cent );
  7585.  
  7586.     if ( clientSpawnCount >= ( 1 << ( 32 - CENTITYNUM_BITS ) ) ) {
  7587.         Error( "idGameLocal::RegisterClientEntity: spawn count overflow" );
  7588.     }
  7589.  
  7590.     // Find a free entity index to use
  7591.     while( clientEntities[firstFreeClientIndex] && firstFreeClientIndex < MAX_CENTITIES ) {
  7592.         firstFreeClientIndex++;
  7593.     }
  7594.     if ( firstFreeClientIndex >= MAX_CENTITIES ) {
  7595.         cent->PostEventMS ( &EV_Remove, 0 );
  7596.         Warning( "idGameLocal::RegisterClientEntity: no free client entities" );
  7597.         return;
  7598.     }
  7599.  
  7600.     entityNumber = firstFreeClientIndex++;
  7601.  
  7602.     // Add the client entity to the lists
  7603.     clientEntities[ entityNumber ] = cent;
  7604.     clientSpawnIds[ entityNumber ] = clientSpawnCount++;
  7605.     cent->entityNumber = entityNumber;
  7606.     cent->spawnNode.AddToEnd( clientSpawnedEntities );
  7607.  
  7608.     if ( entityNumber >= num_clientEntities ) {
  7609.         num_clientEntities++;
  7610.     }
  7611. }
  7612.  
  7613. /*
  7614. ===================
  7615. idGameLocal::UnregisterClientEntity
  7616. ===================
  7617. */
  7618. void idGameLocal::UnregisterClientEntity( rvClientEntity* cent ) {
  7619.     assert( cent );
  7620.     
  7621.     // No entity number then it failed to register
  7622.     if ( cent->entityNumber == -1 ) {
  7623.         return;
  7624.     }
  7625.     
  7626.     cent->spawnNode.Remove ( );
  7627.     cent->bindNode.Remove ( );
  7628.  
  7629.     if ( clientEntities [ cent->entityNumber ] == cent ) {
  7630.         clientEntities [ cent->entityNumber ] = NULL;
  7631.         clientSpawnIds[ cent->entityNumber ] = -1;
  7632.         if ( cent->entityNumber < firstFreeClientIndex ) {
  7633.             firstFreeClientIndex = cent->entityNumber;
  7634.         }
  7635.         cent->entityNumber = -1;
  7636.     }
  7637. }
  7638.  
  7639. // RAVEN BEGIN
  7640. // ddynerman: idClip wrapper functions
  7641.  
  7642. /*
  7643. ===================
  7644. idGameLocal::Translation
  7645. ===================
  7646. */
  7647. bool idGameLocal::Translation( const idEntity* ent, trace_t &results, const idVec3 &start, const idVec3 &end, const idClipModel *mdl, const idMat3 &trmAxis, int contentMask, const idEntity *passEntity, const idEntity *passEntity2 ) {
  7648.     idClip* clipWorld = GetEntityClipWorld( ent );
  7649.     
  7650.     if( clipWorld ) {
  7651.         return clipWorld->Translation( results, start, end, mdl, trmAxis, contentMask, passEntity, passEntity2 );
  7652.     } 
  7653.     
  7654.     return false;
  7655. }
  7656.  
  7657. /*
  7658. ===================
  7659. idGameLocal::Rotation
  7660. ===================
  7661. */
  7662. bool idGameLocal::Rotation( const idEntity* ent, trace_t &results, const idVec3 &start, const idRotation &rotation, const idClipModel *mdl, const idMat3 &trmAxis, int contentMask, const idEntity *passEntity ) {
  7663.     idClip* clipWorld = GetEntityClipWorld( ent );
  7664.     
  7665.     if( clipWorld ) {
  7666.         return clipWorld->Rotation( results, start, rotation, mdl, trmAxis, contentMask, passEntity );
  7667.     }
  7668.  
  7669.     return false;
  7670. }
  7671.  
  7672. /*
  7673. ===================
  7674. idGameLocal::Motion
  7675. ===================
  7676. */
  7677. bool idGameLocal::Motion( const idEntity* ent, trace_t &results, const idVec3 &start, const idVec3 &end, const idRotation &rotation, const idClipModel *mdl, const idMat3 &trmAxis, int contentMask, const idEntity *passEntity ) {
  7678.     idClip* clipWorld = GetEntityClipWorld( ent );
  7679.     
  7680.     if( clipWorld ) {
  7681.         return clipWorld->Motion( results, start, end, rotation, mdl, trmAxis, contentMask, passEntity );
  7682.     }
  7683.  
  7684.     return false;
  7685. }
  7686.  
  7687.  
  7688. /*
  7689. ===================
  7690. idGameLocal::Contacts
  7691. ===================
  7692. */
  7693. int idGameLocal::Contacts( const idEntity* ent, contactInfo_t *contacts, const int maxContacts, const idVec3 &start, const idVec6 &dir, const float depth, const idClipModel *mdl, const idMat3 &trmAxis, int contentMask, const idEntity *passEntity ) {
  7694.     idClip* clipWorld = GetEntityClipWorld( ent );
  7695.     
  7696.     if( clipWorld ) {
  7697.         return clipWorld->Contacts( contacts, maxContacts, start, dir, depth, mdl, trmAxis, contentMask, passEntity );
  7698.     }
  7699.  
  7700.     return 0;
  7701. }
  7702.  
  7703. /*
  7704. ===================
  7705. idGameLocal::Contents
  7706. ===================
  7707. */
  7708. int idGameLocal::Contents( const idEntity* ent, const idVec3 &start, const idClipModel *mdl, const idMat3 &trmAxis, int contentMask, const idEntity *passEntity, idEntity **touchedEntity ) {
  7709.     idClip* clipWorld = GetEntityClipWorld( ent );
  7710.     
  7711.     if( clipWorld ) {
  7712.         return clipWorld->Contents( start, mdl, trmAxis, contentMask, passEntity, touchedEntity );
  7713.     }
  7714.  
  7715.     return 0;
  7716. }
  7717.  
  7718. /*
  7719. ===================
  7720. idGameLocal::TracePoint
  7721. ===================
  7722. */
  7723. bool idGameLocal::TracePoint( const idEntity* ent, trace_t &results, const idVec3 &start, const idVec3 &end, int contentMask, const idEntity *passEntity ) {
  7724.     idClip* clipWorld = GetEntityClipWorld( ent );
  7725.     
  7726.     if( clipWorld ) {
  7727.         return clipWorld->TracePoint( results, start, end, contentMask, passEntity );
  7728.     }
  7729.  
  7730.     return false;
  7731. }
  7732.  
  7733. /*
  7734. ===================
  7735. idGameLocal::TraceBounds
  7736. ===================
  7737. */
  7738. bool idGameLocal::TraceBounds( const idEntity* ent, trace_t &results, const idVec3 &start, const idVec3 &end, const idBounds &bounds, int contentMask, const idEntity *passEntity ) {
  7739.     idClip* clipWorld = GetEntityClipWorld( ent );
  7740.     
  7741.     if( clipWorld ) {
  7742.         return clipWorld->TraceBounds( results, start, end, bounds, contentMask, passEntity );
  7743.     }
  7744.  
  7745.     return false;
  7746. }
  7747.  
  7748. /*
  7749. ===================
  7750. idGameLocal::TranslationModel
  7751. ===================
  7752. */
  7753. void idGameLocal::TranslationModel( const idEntity* ent, trace_t &results, const idVec3 &start, const idVec3 &end, const idClipModel *mdl, const idMat3 &trmAxis, int contentMask, idCollisionModel *model, const idVec3 &modelOrigin, const idMat3 &modelAxis ) {
  7754.     idClip* clipWorld = GetEntityClipWorld( ent );
  7755.     
  7756.     if( clipWorld ) {
  7757.         clipWorld->TranslationModel( results, start, end, mdl, trmAxis, contentMask, model, modelOrigin, modelAxis );
  7758.     }
  7759. }
  7760.  
  7761. /*
  7762. ===================
  7763. idGameLocal::RotationModel
  7764. ===================
  7765. */
  7766. void idGameLocal::RotationModel( const idEntity* ent, trace_t &results, const idVec3 &start, const idRotation &rotation, const idClipModel *mdl, const idMat3 &trmAxis, int contentMask, idCollisionModel *model, const idVec3 &modelOrigin, const idMat3 &modelAxis ) {
  7767.     idClip* clipWorld = GetEntityClipWorld( ent );
  7768.     
  7769.     if( clipWorld ) {
  7770.         clipWorld->RotationModel( results, start, rotation, mdl, trmAxis, contentMask, model, modelOrigin, modelAxis );
  7771.     }
  7772. }
  7773.  
  7774. /*
  7775. ===================
  7776. idGameLocal::ContactsModel
  7777. ===================
  7778. */
  7779. int idGameLocal::ContactsModel( const idEntity* ent, contactInfo_t *contacts, const int maxContacts, const idVec3 &start, const idVec6 &dir, const float depth, const idClipModel *mdl, const idMat3 &trmAxis, int contentMask, idCollisionModel *model, const idVec3 &modelOrigin, const idMat3 &modelAxis ) {
  7780.     idClip* clipWorld = GetEntityClipWorld( ent );
  7781.     
  7782.     if( clipWorld ) {
  7783.         return clipWorld->ContactsModel( contacts, maxContacts, start, dir, depth, mdl, trmAxis, contentMask, model, modelOrigin, modelAxis );
  7784.     }
  7785.  
  7786.     return 0;
  7787. }
  7788.  
  7789. /*
  7790. ===================
  7791. idGameLocal::ContentsModel
  7792. ===================
  7793. */
  7794. int idGameLocal::ContentsModel( const idEntity* ent, const idVec3 &start, const idClipModel *mdl, const idMat3 &trmAxis, int contentMask, idCollisionModel *model, const idVec3 &modelOrigin, const idMat3 &modelAxis ) {
  7795.     idClip* clipWorld = GetEntityClipWorld( ent );
  7796.     
  7797.     if( clipWorld ) {
  7798.         return clipWorld->ContentsModel( start, mdl, trmAxis, contentMask, model, modelOrigin, modelAxis );
  7799.     }
  7800.  
  7801.     return 0;
  7802. }
  7803.  
  7804. /*
  7805. ===================
  7806. idGameLocal::TranslationEntities
  7807. ===================
  7808. */    
  7809. void idGameLocal::TranslationEntities( const idEntity* ent, trace_t &results, const idVec3 &start, const idVec3 &end, const idClipModel *mdl, const idMat3 &trmAxis, int contentMask, const idEntity *passEntity, const idEntity *passEntity2 ) {
  7810.     idClip* clipWorld = GetEntityClipWorld( ent );
  7811.     
  7812.     if( clipWorld ) {
  7813.         clipWorld->TranslationEntities( results, start, end, mdl, trmAxis, contentMask, passEntity, passEntity2 );
  7814.     }
  7815. }
  7816.  
  7817. /*
  7818. ===================
  7819. idGameLocal::GetModelContactFeature
  7820. ===================
  7821. */
  7822. bool idGameLocal::GetModelContactFeature( const idEntity* ent, const contactInfo_t &contact, const idClipModel *clipModel, idFixedWinding &winding ) const {
  7823.     const idClip* clipWorld = GetEntityClipWorld( ent );
  7824.     
  7825.     if( clipWorld ) {
  7826.         return clipWorld->GetModelContactFeature( contact, clipModel, winding );
  7827.     }
  7828.  
  7829.     return false;
  7830. }
  7831.  
  7832. /*
  7833. ===================
  7834. idGameLocal::EntitiesTouchingBounds
  7835. ===================
  7836. */
  7837. int idGameLocal::EntitiesTouchingBounds    ( const idEntity* ent, const idBounds &bounds, int contentMask, idEntity **entityList, int maxCount ) const {
  7838.     const idClip* clipWorld = GetEntityClipWorld( ent );
  7839.     
  7840.     if( clipWorld ) {
  7841.         return clipWorld->EntitiesTouchingBounds( bounds, contentMask, entityList, maxCount );
  7842.     }
  7843.  
  7844.     return 0;
  7845. }
  7846.  
  7847. /*
  7848. ===================
  7849. idGameLocal::ClipModelsTouchingBounds
  7850. ===================
  7851. */
  7852. int idGameLocal::ClipModelsTouchingBounds( const idEntity* ent, const idBounds &bounds, int contentMask, idClipModel **clipModelList, int maxCount ) const {
  7853.     const idClip* clipWorld = GetEntityClipWorld( ent );
  7854.     
  7855.     if( clipWorld ) {
  7856.         return clipWorld->ClipModelsTouchingBounds( bounds, contentMask, clipModelList, maxCount );
  7857.     }
  7858.  
  7859.     return 0;
  7860. }
  7861.  
  7862. /*
  7863. ===================
  7864. idGameLocal::PlayersTouchingBounds
  7865. ===================
  7866. */
  7867. int idGameLocal::PlayersTouchingBounds    ( const idEntity* ent, const idBounds &bounds, int contentMask, idPlayer **entityList, int maxCount ) const {
  7868.     const idClip* clipWorld = GetEntityClipWorld( ent );
  7869.     
  7870.     if( clipWorld ) {
  7871.         return clipWorld->PlayersTouchingBounds( bounds, contentMask, entityList, maxCount );
  7872.     }
  7873.  
  7874.     return 0;
  7875. }
  7876.  
  7877. /*
  7878. ===================
  7879. idGameLocal::GetWorldBounds
  7880. ===================
  7881. */
  7882. const idBounds& idGameLocal::GetWorldBounds( const idEntity* ent ) const {
  7883.     const idClip* clipWorld = GetEntityClipWorld( ent );
  7884.     
  7885.     if( clipWorld ) {
  7886.         return clipWorld->GetWorldBounds();
  7887.     }
  7888.  
  7889.     return clip[ 0 ]->GetWorldBounds();
  7890. }
  7891.  
  7892. /*
  7893. ===================
  7894. idGameLocal::GetEntityClipWorld
  7895. ===================
  7896. */
  7897. idClip* idGameLocal::GetEntityClipWorld( const idEntity* ent ) {
  7898.     if( ent == NULL ) {
  7899.         return clip[ 0 ];
  7900.     }
  7901.  
  7902.     if( ent->GetClipWorld() < 0 || ent->GetClipWorld() >= clip.Num() ) {
  7903.         Warning( "idGameLocal::GetEntityClipWorld() - invalid clip world %d on entity %s (valid range: 0 - %d)\n", ent->GetClipWorld(), ent->GetClassname(), clip.Num() - 1 );
  7904.         return NULL;
  7905.     }
  7906.     return clip[ ent->GetClipWorld() ];
  7907. }
  7908.  
  7909. /*
  7910. ===================
  7911. idGameLocal::GetEntityClipWorld
  7912. ===================
  7913. */
  7914. const idClip* idGameLocal::GetEntityClipWorld( const idEntity* ent ) const {
  7915.     if( ent == NULL ) {
  7916.         return clip[ 0 ];
  7917.     }
  7918.  
  7919.     if( ent->GetClipWorld() < 0 || ent->GetClipWorld() >= clip.Num() ) {
  7920.         Warning( "idGameLocal::GetEntityClipWorld() - invalid clip world %d on entity %s (valid range: 0 - %d)\n", ent->GetClipWorld(), ent->GetClassname(), clip.Num() - 1  );
  7921.         return NULL;
  7922.     }
  7923.     return clip[ ent->GetClipWorld() ];
  7924. }
  7925.  
  7926. /*
  7927. ===================
  7928. idGameLocal::AddClipWorld
  7929. ===================
  7930. */
  7931. int idGameLocal::AddClipWorld( int id ) {
  7932.     if( id >= clip.Num() ) {
  7933.         // if we want an index higher in the list, fill the intermediate indices with empties
  7934.         for( int i = clip.Num(); i <= id; i++ ) {
  7935.             clip.Append( NULL );
  7936.         }
  7937.     }
  7938.  
  7939.     if( clip[ id ] == NULL ) {
  7940. // RAVEN BEGIN
  7941. // mwhitlock: Dynamic memory consolidation
  7942.         RV_PUSH_SYS_HEAP_ID(RV_HEAP_ID_LEVEL);
  7943. // RAVEN END
  7944.         clip[ id ] = new idClip();
  7945. // RAVEN BEGIN
  7946. // mwhitlock: Dynamic memory consolidation
  7947.         RV_POP_HEAP();
  7948. // RAVEN END
  7949.         clip[ id ]->Init();
  7950.     }
  7951.     return id;
  7952. }
  7953.  
  7954. /*
  7955. ===================
  7956. idGameLocal::RemoveClipWorld
  7957. ===================
  7958. */
  7959. void idGameLocal::RemoveClipWorld( int id ) {
  7960.     assert( id >= 0 && id < clip.Num() );
  7961.  
  7962.     clip[ id ]->Shutdown();
  7963.     delete clip[ id ];
  7964.     clip[ id ] = NULL;
  7965. }
  7966.  
  7967. /*
  7968. ===================
  7969. idGameLocal::ShutdownInstances
  7970. ===================
  7971. */
  7972. void idGameLocal::ShutdownInstances( void ) {
  7973.     if( gamestate == GAMESTATE_UNINITIALIZED ) {
  7974.         return;
  7975.     }
  7976.  
  7977.     instances.DeleteContents( true );
  7978.  
  7979.     // free the trace model used for the defaultClipModel
  7980.     idClip::FreeDefaultClipModel();
  7981. }
  7982.  
  7983. /*
  7984. ===================
  7985. idGameLocal::AddInstance
  7986. ===================
  7987. */
  7988. int idGameLocal::AddInstance( int id, bool deferPopulate ) {
  7989.     if( id == -1 ) {
  7990.         id = instances.Num();
  7991.     }
  7992.  
  7993.     if( id >= instances.Num() ) {
  7994.         // if we want an index higher in the list, fill the intermediate indices with empties
  7995.         for( int i = instances.Num(); i <= id; i++ ) {
  7996.             instances.Append( NULL );
  7997.         }
  7998.     }
  7999.  
  8000.     if( instances[ id ] == NULL ) {
  8001. // RAVEN BEGIN
  8002. // mwhitlock: Dynamic memory consolidation
  8003.         RV_PUSH_SYS_HEAP_ID(RV_HEAP_ID_LEVEL);
  8004.         instances[ id ] = new rvInstance( id, deferPopulate );
  8005.         RV_POP_HEAP();
  8006. // RAVEN END
  8007.         common->DPrintf( "idGameLocal::AddInstance(): Adding instance %d\n", instances[ id ]->GetInstanceID() );
  8008.     } else {
  8009.         common->DPrintf( "idGameLocal::AddInstance(): Instance %d already exists\n", instances[ id ]->GetInstanceID() );
  8010.     }
  8011.     
  8012.     
  8013.     return instances[ id ]->GetInstanceID();
  8014. }
  8015.  
  8016. /*
  8017. ===================
  8018. idGameLocal::RemoveInstance
  8019. ===================
  8020. */
  8021. void idGameLocal::RemoveInstance( int id ) {
  8022.     delete instances[ id ];
  8023.     instances[ id ] = NULL;
  8024. }
  8025.  
  8026. /*
  8027. ===================
  8028. idGameLocal::GetPlayerName
  8029. Returns the specified player name, max of 64 chars
  8030. ===================
  8031. */
  8032. void idGameLocal::GetPlayerName( int clientNum, char* name ) {
  8033.     if( !gameLocal.entities[ clientNum ] ) {
  8034.         return;
  8035.     }
  8036.  
  8037.     strncpy( name, gameLocal.GetUserInfo( clientNum )->GetString( "ui_name" ), 64 );
  8038.     name[ 63 ] = 0;
  8039. }
  8040.  
  8041. /*
  8042. ===================
  8043. idGameLocal::GetPlayerClan
  8044. Returns the specified player clan, max of 64 chars
  8045. ===================
  8046. */
  8047. void idGameLocal::GetPlayerClan( int clientNum, char* clan ) {
  8048.     if( !gameLocal.entities[ clientNum ] ) {
  8049.         return;
  8050.     }
  8051.  
  8052.     strncpy( clan, gameLocal.GetUserInfo( clientNum )->GetString( "ui_clan" ), 64 );
  8053.     clan[ 63 ] = 0;
  8054. }
  8055.  
  8056. /*
  8057. ===================
  8058. idGameLocal::SetFriend
  8059. ===================
  8060. */
  8061. void idGameLocal::SetFriend( int clientNum, bool isFriend ) {
  8062.     if( !gameLocal.GetLocalPlayer() ) {
  8063.         Warning( "idGameLocal::SetFriend() - SetFriend() called with NULL local player\n" );
  8064.         return;
  8065.     }
  8066.  
  8067.     gameLocal.GetLocalPlayer()->SetFriend( clientNum, isFriend );
  8068. }
  8069.  
  8070. /*
  8071. ===================
  8072. idGameLocal::GetLongGametypeName
  8073. ===================
  8074. */
  8075. const char*    idGameLocal::GetLongGametypeName( const char* gametype ) {
  8076.     return mpGame.GetLongGametypeName( gametype );
  8077. }
  8078.  
  8079. void idGameLocal::Cmd_PrintMapEntityNumbers_f( const idCmdArgs& args ) {
  8080.     int instance = 0;
  8081.  
  8082.     if ( args.Argc() > 1 ) {
  8083.         instance = atoi( args.Argv( 1 ) );
  8084.     } 
  8085.  
  8086.     if( gameLocal.instances[ instance ] ) {
  8087.         gameLocal.instances[ instance ]->PrintMapNumbers();
  8088.     }
  8089. }
  8090.  
  8091. void idGameLocal::Cmd_PrintSpawnIds_f( const idCmdArgs& args ) {
  8092.     for( int i = 0; i < MAX_GENTITIES; i++ ) {
  8093.         if( gameLocal.entities[ i ] ) {
  8094.             gameLocal.Printf( "Spawn id %d: %d\n", i, gameLocal.spawnIds[ i ] );
  8095.         }
  8096.     }
  8097. }
  8098.  
  8099.  
  8100. // RAVEN BEGIN
  8101. // mwhitlock: Dynamic memory consolidation
  8102. #if defined(_RV_MEM_SYS_SUPPORT)
  8103. /*
  8104. ===================
  8105. idGameLocal::FlushBeforelevelLoad
  8106. ===================
  8107. */
  8108. void idGameLocal::FlushBeforelevelLoad( void )
  8109. {
  8110.     TIME_THIS_SCOPE( __FUNCLINE__);
  8111.  
  8112. #ifndef _XENON
  8113.     MapShutdown();
  8114. #else
  8115.     mpGame.Clear();
  8116. #endif
  8117.     for(int i = 0; i < aasNames.Num(); i++)
  8118.     {
  8119.         aasList[i]->Shutdown();
  8120.     }
  8121. }
  8122. #endif
  8123. // RAVEN END
  8124.  
  8125. // dluetscher: moved the overloaded new/delete to sys_local.cpp and Game_local.cpp (from Heap.h)
  8126. //               so that the tools.dll will link.
  8127. #if !defined(_XBOX) && (defined(ID_REDIRECT_NEWDELETE) || defined(_RV_MEM_SYS_SUPPORT))
  8128.  
  8129. #undef new
  8130. #undef delete
  8131. #undef Mem_Alloc
  8132. #undef Mem_Free
  8133.  
  8134. #ifdef ID_DEBUG_MEMORY
  8135. void *operator new( size_t s, int t1, int t2, char *fileName, int lineNumber ) {
  8136.     return Mem_Alloc( s, fileName, lineNumber, MemScopedTag_GetTopTag() );
  8137. }
  8138.  
  8139. void operator delete( void *p, int t1, int t2, char *fileName, int lineNumber ) {
  8140.     Mem_Free( p, fileName, lineNumber );
  8141. }
  8142.  
  8143. void *operator new[]( size_t s, int t1, int t2, char *fileName, int lineNumber ) {
  8144.     return Mem_Alloc( s, fileName, lineNumber, MemScopedTag_GetTopTag() );
  8145. }
  8146.  
  8147. void operator delete[]( void *p, int t1, int t2, char *fileName, int lineNumber ) {
  8148.     Mem_Free( p, fileName, lineNumber );
  8149. }
  8150.  
  8151. void *operator new( size_t s ) {
  8152.     return Mem_Alloc( s, "", 0, MemScopedTag_GetTopTag() );
  8153. }
  8154.  
  8155. void operator delete( void *p ) {
  8156.     Mem_Free( p, "", 0 );
  8157. }
  8158.  
  8159. void *operator new[]( size_t s ) {
  8160.     return Mem_Alloc( s, "", 0, MemScopedTag_GetTopTag() );
  8161. }
  8162.  
  8163. void operator delete[]( void *p ) {
  8164.     Mem_Free( p, "", 0 );
  8165. }
  8166.  
  8167. #else    // #ifdef ID_DEBUG_MEMORY
  8168.  
  8169. void *operator new( size_t s ) {
  8170.     return Mem_Alloc( s, MemScopedTag_GetTopTag() );
  8171. }
  8172.  
  8173. void operator delete( void *p ) {
  8174.     Mem_Free( p );
  8175. }
  8176.  
  8177. void *operator new[]( size_t s ) {
  8178.     return Mem_Alloc( s, MemScopedTag_GetTopTag() );
  8179. }
  8180.  
  8181. void operator delete[]( void *p ) {
  8182.     Mem_Free( p );
  8183. }
  8184. #endif    // #else #ifdef ID_DEBUG_MEMORY
  8185. #endif    // #if defined(ID_REDIRECT_NEWDELETE) || defined(_RV_MEM_SYS_SUPPORT)
  8186. // RAVEN END
  8187.