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

  1. /*
  2.  
  3. Various utility objects and functions.
  4.  
  5. */
  6.  
  7. #include "../idlib/precompiled.h"
  8. #pragma hdrstop
  9.  
  10. #include "Game_local.h"
  11.  
  12. // RAVEN BEGIN
  13. // nmckenzie: added ai
  14. #if !defined(__GAME_PROJECTILE_H__)
  15.     #include "Projectile.h"
  16. #endif
  17. #include "ai/AI.h"
  18. // RAVEN END
  19.  
  20. /*
  21. ===============================================================================
  22.  
  23. idSpawnableEntity
  24.  
  25. A simple, spawnable entity with a model and no functionable ability of it's own.
  26. For example, it can be used as a placeholder during development, for marking
  27. locations on maps for script, or for simple placed models without any behavior
  28. that can be bound to other entities.  Should not be subclassed.
  29. ===============================================================================
  30. */
  31.  
  32. CLASS_DECLARATION( idEntity, idSpawnableEntity )
  33. END_CLASS
  34.  
  35. /*
  36. ======================
  37. idSpawnableEntity::Spawn
  38. ======================
  39. */
  40. void idSpawnableEntity::Spawn() {
  41.     // this just holds dict information
  42. }
  43.  
  44.  
  45. /*
  46. ===============================================================================
  47.  
  48.     idPlayerStart
  49.  
  50. ===============================================================================
  51. */
  52.  
  53. const idEventDef EV_TeleportStage( "<TeleportStage>", "e" );
  54.  
  55. CLASS_DECLARATION( idEntity, idPlayerStart )
  56.     EVENT( EV_Activate,            idPlayerStart::Event_TeleportPlayer )
  57.     EVENT( EV_TeleportStage,    idPlayerStart::Event_TeleportStage )
  58. END_CLASS
  59.  
  60. /*
  61. ===============
  62. idPlayerStart::idPlayerStart
  63. ================
  64. */
  65. idPlayerStart::idPlayerStart( void ) {
  66.     teleportStage = 0;
  67. }
  68.  
  69. /*
  70. ===============
  71. idPlayerStart::Spawn
  72. ================
  73. */
  74. void idPlayerStart::Spawn( void ) {
  75.     teleportStage = 0;
  76.  
  77.     //HACK: begin "show spawn point" hack for RJ
  78.     /*if( !spawnArgs.GetInt("text") )    {
  79.         gameLocal.Warning("texting up spawn point '%s'", GetName());
  80.         idDict        args;
  81.         idEntity*    textEntity;
  82.         idVec3        newOrigin;
  83.  
  84.         newOrigin = GetPhysics()->GetOrigin();
  85.         newOrigin.z += 64;
  86.  
  87.         args.SetVector ( "origin", newOrigin );
  88.         args.Set ( "text", GetName() );
  89.         args.SetBool ( "playerOriented", 1 );
  90.         args.SetBool ( "force", 1 );
  91.         args.Set ( "target", GetName() );
  92.         args.Set ( "classname", "text" );
  93.  
  94.         gameLocal.SpawnEntityDef ( args, &textEntity );
  95.  
  96.         //mark the spawn point so it doesn't do this again
  97.         spawnArgs.SetInt("text", 1);
  98.  
  99.     }*/
  100. }
  101.  
  102. /*
  103. ================
  104. idPlayerStart::Save
  105. ================
  106. */
  107. void idPlayerStart::Save( idSaveGame *savefile ) const {
  108.     savefile->WriteInt( teleportStage );
  109. }
  110.  
  111. /*
  112. ================
  113. idPlayerStart::Restore
  114. ================
  115. */
  116. void idPlayerStart::Restore( idRestoreGame *savefile ) {
  117.     savefile->ReadInt( teleportStage );
  118. }
  119.  
  120. /*
  121. ================
  122. idPlayerStart::ClientReceiveEvent
  123. ================
  124. */
  125. bool idPlayerStart::ClientReceiveEvent( int event, int time, const idBitMsg &msg ) {
  126.     int entityNumber;
  127.  
  128.     switch( event ) {
  129.         case EVENT_TELEPORTPLAYER: {
  130.             entityNumber = msg.ReadBits( GENTITYNUM_BITS );
  131.             idPlayer *player = static_cast<idPlayer *>( gameLocal.entities[entityNumber] );
  132. // RAVEN BEGIN
  133. // jnewquist: Use accessor for static class type 
  134.             if ( player != NULL && player->IsType( idPlayer::GetClassType() ) ) {
  135. // RAVEN END
  136.                 Event_TeleportPlayer( player );
  137.             }
  138.             return true;
  139.         }
  140.         default: {
  141.             return idEntity::ClientReceiveEvent( event, time, msg );
  142.         }
  143.     }
  144. //unreachable
  145. //    return false;
  146. }
  147.  
  148. /*
  149. ===============
  150. idPlayerStart::Event_TeleportStage
  151.  
  152. FIXME: add functionality to fx system ( could be done with player scripting too )
  153. ================
  154. */
  155. void idPlayerStart::Event_TeleportStage( idPlayer *player ) {
  156.     float teleportDelay = spawnArgs.GetFloat( "teleportDelay" );
  157.     switch ( teleportStage ) {
  158.         case 0:
  159.             player->playerView.Flash( colorWhite, 125 );
  160.             player->SetInfluenceLevel( INFLUENCE_LEVEL3 );
  161.             player->SetInfluenceView( spawnArgs.GetString( "mtr_teleportFx" ), NULL, 0.0f, NULL );
  162.             soundSystem->FadeSoundClasses( SOUNDWORLD_GAME, 0, -20.0f, teleportDelay );
  163.             player->StartSound( "snd_teleport_start", SND_CHANNEL_BODY2, 0, false, NULL );
  164.             teleportStage++;
  165.             PostEventSec( &EV_TeleportStage, teleportDelay, player );
  166.             break;
  167.         case 1:
  168.             soundSystem->FadeSoundClasses( SOUNDWORLD_GAME, 0, 0.0f, 0.25f );
  169.             teleportStage++;
  170.             PostEventSec( &EV_TeleportStage, 0.25f, player );
  171.             break;
  172.         case 2:
  173.             player->SetInfluenceView( NULL, NULL, 0.0f, NULL );
  174.             TeleportPlayer( player );
  175.             player->StopSound( SND_CHANNEL_BODY2, false );
  176.             player->SetInfluenceLevel( INFLUENCE_NONE );
  177.             teleportStage = 0;
  178.             break;
  179.         default:
  180.             break;
  181.     }
  182. }
  183.  
  184. /*
  185. ===============
  186. idPlayerStart::TeleportPlayer
  187. ================
  188. */
  189. void idPlayerStart::TeleportPlayer( idPlayer *player ) {
  190.     float pushVel = spawnArgs.GetFloat( "push", "50000" );
  191.     float f = spawnArgs.GetFloat( "visualEffect", "0" );
  192.     const char *viewName = spawnArgs.GetString( "visualView", "" );
  193.     idEntity *ent = viewName ? gameLocal.FindEntity( viewName ) : NULL;
  194.  
  195.     if ( f && ent ) {
  196.         // place in private camera view for some time
  197.         // the entity needs to teleport to where the camera view is to have the PVS right
  198.         player->Teleport( ent->GetPhysics()->GetOrigin(), ang_zero, this );
  199.         player->StartSound( "snd_teleport_enter", SND_CHANNEL_ANY, 0, false, NULL );
  200.         player->SetPrivateCameraView( static_cast<idCamera*>(ent) );
  201.         // the player entity knows where to spawn from the previous Teleport call
  202.         if ( !gameLocal.isClient ) {
  203.             player->PostEventSec( &EV_Player_ExitTeleporter, f );
  204.         }
  205.     } else {
  206.         // direct to exit, Teleport will take care of the killbox
  207.         player->Teleport( GetPhysics()->GetOrigin(), GetPhysics()->GetAxis().ToAngles(), NULL );
  208.  
  209.         // multiplayer hijacked this entity, so only push the player in multiplayer
  210.         if ( gameLocal.isMultiplayer ) {
  211.             //direct teleport, play effect & sound
  212.             player->StartSound( "snd_teleport_enter", SND_CHANNEL_ANY, 0, false, NULL );
  213.             gameLocal.PlayEffect( player->spawnArgs, "fx_teleport", player->GetPhysics()->GetOrigin(), idVec3(0,0,1).ToMat3(), false, vec3_origin );
  214.             //push
  215.             idVec3 impulse( pushVel, 0, 0 );
  216.             impulse *= GetPhysics( )->GetAxis ( );
  217.             player->ApplyImpulse( gameLocal.world, 0, player->GetPhysics( )->GetOrigin( ), impulse );
  218.         }
  219.     }
  220. }
  221.  
  222. /*
  223. ===============
  224. idPlayerStart::Teleport
  225. For non-players
  226. ================
  227. */
  228. void idPlayerStart::Teleport( idEntity* other ) {
  229.     other->SetOrigin( GetPhysics()->GetOrigin() );
  230.     idVec3 vel = other->GetPhysics()->GetLinearVelocity();
  231.     vel *= GetPhysics()->GetAxis();
  232.     other->GetPhysics()->SetLinearVelocity( vel );
  233. }
  234.  
  235. /*
  236. ===============
  237. idPlayerStart::Event_TeleportPlayer
  238. ================
  239. */
  240. void idPlayerStart::Event_TeleportPlayer( idEntity *activator ) {
  241.     idPlayer *player;
  242.  
  243. // RAVEN BEGIN
  244. // jnewquist: Use accessor for static class type 
  245.     if ( activator->IsType( idPlayer::GetClassType() ) ) {
  246. // RAVEN END
  247.         player = static_cast<idPlayer*>( activator );
  248.     } else {
  249.         player = NULL;
  250.         Teleport( activator );
  251.     }
  252.     if ( player ) {
  253.         if ( spawnArgs.GetBool( "visualFx" ) ) {
  254.  
  255.             teleportStage = 0;
  256.             Event_TeleportStage( player );
  257.  
  258.         } else {
  259.  
  260.             if ( gameLocal.isServer ) {
  261.                 idBitMsg    msg;
  262.                 byte        msgBuf[MAX_EVENT_PARAM_SIZE];
  263.  
  264.                 msg.Init( msgBuf, sizeof( msgBuf ) );
  265.                 msg.BeginWriting();
  266.                 msg.WriteBits( player->entityNumber, GENTITYNUM_BITS );
  267.                 ServerSendInstanceEvent( EVENT_TELEPORTPLAYER, &msg, false, -1 );
  268.             }
  269.  
  270.             TeleportPlayer( player );
  271.         }
  272.     }
  273. }
  274.  
  275. /*
  276. ===============================================================================
  277.  
  278.     idActivator
  279.  
  280. ===============================================================================
  281. */
  282.  
  283. CLASS_DECLARATION( idEntity, idActivator )
  284.     EVENT( EV_Activate,        idActivator::Event_Activate )
  285. END_CLASS
  286.  
  287. /*
  288. ===============
  289. idActivator::Save
  290. ================
  291. */
  292. void idActivator::Save( idSaveGame *savefile ) const {
  293.     savefile->WriteBool( stay_on );
  294. }
  295.  
  296. /*
  297. ===============
  298. idActivator::Restore
  299. ================
  300. */
  301. void idActivator::Restore( idRestoreGame *savefile ) {
  302.     savefile->ReadBool( stay_on );
  303.  
  304.     if ( stay_on ) {
  305.         BecomeActive( TH_THINK );
  306.     }
  307. }
  308.  
  309. /*
  310. ===============
  311. idActivator::Spawn
  312. ================
  313. */
  314. void idActivator::Spawn( void ) {
  315.     bool start_off;
  316.  
  317.     spawnArgs.GetBool( "stay_on", "0", stay_on );
  318.     spawnArgs.GetBool( "start_off", "0", start_off );
  319.  
  320. // RAVEN BEGIN
  321. // bdube: optional clip model on activators
  322.     const char    *temp;
  323.     if ( spawnArgs.GetString( "clipmodel", "", &temp ) ) {
  324. // RAVEN BEGIN
  325. // mwhitlock: Dynamic memory consolidation
  326.         RV_PUSH_HEAP_MEM(this);
  327. // RAVEN END
  328.         GetPhysics()->SetClipModel( new idClipModel(temp), 1.0f );
  329. // RAVEN BEGIN
  330. // mwhitlock: Dynamic memory consolidation
  331.         RV_POP_HEAP();
  332. // RAVEN END
  333.     } else {
  334.         GetPhysics()->SetClipBox( idBounds( vec3_origin ).Expand( 4 ), 1.0f );
  335.     }
  336.  
  337.     GetPhysics()->SetContents( 0 );
  338. // RAVEN END
  339.  
  340.     if ( !start_off ) {
  341.         BecomeActive( TH_THINK );
  342.     }
  343. }
  344.  
  345. /*
  346. ===============
  347. idActivator::Think
  348. ================
  349. */
  350. void idActivator::Think( void ) {
  351.     RunPhysics();
  352.     if ( thinkFlags & TH_THINK ) {
  353.         if ( TouchTriggers() ) {
  354.             if ( !stay_on ) {
  355.                 BecomeInactive( TH_THINK );
  356.             }
  357.         }
  358.     }
  359.     Present();
  360. }
  361.  
  362. /*
  363. ===============
  364. idActivator::Activate
  365. ================
  366. */
  367. void idActivator::Event_Activate( idEntity *activator ) {
  368.     if ( thinkFlags & TH_THINK ) {
  369.         BecomeInactive( TH_THINK );
  370.     } else {
  371.         BecomeActive( TH_THINK );
  372.     }
  373. }
  374.  
  375.  
  376. /*
  377. ===============================================================================
  378.  
  379. idPathCorner
  380.  
  381. ===============================================================================
  382. */
  383.  
  384. CLASS_DECLARATION( idEntity, idPathCorner )
  385. //    EVENT( AI_RandomPath,        idPathCorner::Event_RandomPath )
  386. END_CLASS
  387.  
  388. /*
  389. =====================
  390. idPathCorner::Spawn
  391. =====================
  392. */
  393. void idPathCorner::Spawn( void ) {
  394. }
  395.  
  396. /*
  397. =====================
  398. idPathCorner::DrawDebugInfo
  399. =====================
  400. */
  401. void idPathCorner::DrawDebugInfo( void ) {
  402.     idEntity *ent;
  403.     idBounds bnds( idVec3( -4.0, -4.0f, -8.0f ), idVec3( 4.0, 4.0f, 64.0f ) );
  404.  
  405.     for( ent = gameLocal.spawnedEntities.Next(); ent != NULL; ent = ent->spawnNode.Next() ) {
  406.         if ( !ent->IsType( idPathCorner::Type ) ) {
  407.             continue;
  408.         }
  409.  
  410.         idVec3 org = ent->GetPhysics()->GetOrigin();
  411.         gameRenderWorld->DebugBounds( colorRed, bnds, org, 0 );
  412.     }
  413. }
  414.  
  415. /*
  416. ============
  417. idPathCorner::RandomPath
  418. ============
  419. */
  420. idPathCorner *idPathCorner::RandomPath( const idEntity *source, const idEntity *ignore ) {
  421.     int    i;
  422.     int    num;
  423.     int which;
  424.     idEntity *ent;
  425.     idPathCorner *path[ MAX_GENTITIES ];
  426.  
  427.     num = 0;
  428.     for( i = 0; i < source->targets.Num(); i++ ) {
  429.         ent = source->targets[ i ].GetEntity();
  430.         if ( ent && ( ent != ignore ) && ent->IsType( idPathCorner::Type ) ) {
  431.             path[ num++ ] = static_cast<idPathCorner *>( ent );
  432.             if ( num >= MAX_GENTITIES ) {
  433.                 break;
  434.             }
  435.         }
  436.     }
  437.  
  438.     if ( !num ) {
  439.         return NULL;
  440.     }
  441.  
  442.     which = gameLocal.random.RandomInt( num );
  443.     return path[ which ];
  444. }
  445.  
  446. /*
  447. =====================
  448. idPathCorner::Event_RandomPath
  449. =====================
  450. */
  451. void idPathCorner::Event_RandomPath( void ) {
  452.     idPathCorner *path;
  453.  
  454.     path = RandomPath( this, NULL );
  455.     idThread::ReturnEntity( path );
  456. }
  457.  
  458. /*
  459. ===============================================================================
  460.  
  461.   idDamagable
  462.     
  463. ===============================================================================
  464. */
  465.  
  466. const idEventDef EV_RestoreDamagable( "<RestoreDamagable>" );
  467. // RAVEN BEGIN
  468. // kfuller: spawn other things
  469. const idEventDef EV_SpawnForcefield( "<SpawnForcefield>" );
  470. const idEventDef EV_SpawnTriggerHurt( "<SpawnTriggerHurt>" );
  471. // RAVEN END
  472.  
  473. CLASS_DECLARATION( idEntity, idDamagable )
  474.     EVENT( EV_Activate,            idDamagable::Event_BecomeBroken )
  475.     EVENT( EV_RestoreDamagable,    idDamagable::Event_RestoreDamagable )
  476. END_CLASS
  477.  
  478. /*
  479. ================
  480. idDamagable::idDamagable
  481. ================
  482. */
  483. idDamagable::idDamagable( void ) {
  484.     count = 0;
  485.     nextTriggerTime = 0;
  486.     invincibleTime = 0;
  487. }
  488.  
  489. /*
  490. ================
  491. idDamagable::Save
  492. ================
  493. */
  494. void idDamagable::Save( idSaveGame *savefile ) const {
  495.  
  496.     savefile->WriteInt( invincibleTime );
  497.  
  498.     savefile->WriteInt( stage );
  499.     savefile->WriteInt( stageNext );
  500.     
  501.     // cnicholson: Don't save the stageDict, its setup in the restore
  502.     
  503.     savefile->WriteInt( stageEndTime );
  504.     savefile->WriteInt( stageEndHealth );
  505.     savefile->WriteInt( stageEndSpeed );
  506.     savefile->WriteBool( stageEndOnGround );
  507.     savefile->WriteBool( activateStageOnTrigger );
  508.  
  509.     savefile->WriteInt( count );
  510.     savefile->WriteInt( nextTriggerTime );
  511. }
  512.  
  513. /*
  514. ================
  515. idDamagable::Restore
  516. ================
  517. */
  518. void idDamagable::Restore( idRestoreGame *savefile ) {
  519.  
  520.     const char* stageName;
  521.     
  522.     savefile->ReadInt( invincibleTime );
  523.  
  524.     savefile->ReadInt( stage );
  525.     savefile->ReadInt( stageNext );
  526.     savefile->ReadInt( stageEndTime );
  527.     savefile->ReadInt( stageEndHealth );
  528.     savefile->ReadInt( stageEndSpeed );
  529.     savefile->ReadBool( stageEndOnGround );
  530.     savefile->ReadBool( activateStageOnTrigger );
  531.  
  532.     savefile->ReadInt( count );
  533.     savefile->ReadInt( nextTriggerTime );
  534.     
  535.  
  536.     // Get the stage name, if there is none then there are no more stages
  537.     stageDict = NULL;
  538.     if ( spawnArgs.GetString ( va( "def_stage%d", stage ), "", &stageName ) && stageName ) {
  539.  
  540.         stageDict = gameLocal.FindEntityDefDict ( stageName, false );
  541.     }
  542. }
  543.  
  544. /*
  545. ================
  546. idDamagable::Spawn
  547. ================
  548. */
  549. void idDamagable::Spawn( void ) {
  550.     idStr    broken;
  551.     bool    keepContents;
  552.  
  553. // RAVEN BEGIN
  554. // abahr: stage stuff
  555.     stage                = 0;
  556.     stageNext            = 1;
  557.     stageDict            = NULL;
  558.     stageEndTime        = 0;
  559.     stageEndHealth        = 9999;
  560.     stageEndSpeed        = 0;
  561. //jshepard:
  562.     stageEndOnGround    = false;
  563. // RAVEN END
  564.  
  565.     health = spawnArgs.GetInt( "health", "5" );
  566.  
  567. // RAVEN BEGIN
  568. // abahr: stage stuff
  569.    stageEndHealth = health - 1;
  570.     activateStageOnTrigger = spawnArgs.GetBool("activateOnTrigger");
  571. // RAVEN END
  572.  
  573.     spawnArgs.GetInt( "count", "1", count );
  574.     invincibleTime = gameLocal.GetTime() + SEC2MS( spawnArgs.GetFloat( "invincibleTime", "0" ) );
  575.     nextTriggerTime = 0;
  576.     
  577.     // make sure the model gets cached
  578.     spawnArgs.GetString( "broken", "", broken );
  579.     if ( broken.Length() && !renderModelManager->CheckModel( broken ) ) {
  580.         gameLocal.Error( "idDamagable '%s' at (%s): cannot load broken model '%s'", name.c_str(), GetPhysics()->GetOrigin().ToString(0), broken.c_str() );
  581.     }
  582.  
  583. // RAVEN BEGIN
  584. // bdube: turn take damage off if it has no health
  585.     fl.takedamage = health > 0 ? true : false;
  586. // RAVEN END
  587.  
  588.     keepContents = spawnArgs.GetBool( "KeepContents" );
  589.  
  590.     if ( keepContents ) {
  591.         // do nothing, keep the contents from the model
  592.     } else {
  593.         GetPhysics()->SetContents( CONTENTS_SOLID );
  594.     }
  595. }
  596.  
  597. /*
  598. ================
  599. idDamagable::BecomeBroken
  600. ================
  601. */
  602. void idDamagable::BecomeBroken( idEntity *activator ) {
  603.     float    forceState;
  604.     int        numStates;
  605.     int        cycle;
  606.     float    wait;
  607.     
  608.     if ( gameLocal.time < nextTriggerTime ) {
  609.         return;
  610.     }
  611.  
  612.     spawnArgs.GetFloat( "wait", "0.1", wait );
  613.     nextTriggerTime = gameLocal.time + SEC2MS( wait );
  614.     if ( count > 0 ) {
  615.         count--;
  616.         if ( !count ) {
  617.             fl.takedamage = false;
  618.         } else {
  619.             health = spawnArgs.GetInt( "health", "5" );
  620.         }
  621.     }
  622.  
  623.     idStr    broken;
  624.  
  625.     spawnArgs.GetString( "broken", "", broken );
  626.     if ( broken.Length() ) {
  627.         SetModel( broken );
  628.     }
  629.  
  630.     // offset the start time of the shader to sync it to the gameLocal time
  631.     renderEntity.shaderParms[ SHADERPARM_TIMEOFFSET ] = -MS2SEC( gameLocal.time );
  632.  
  633.     spawnArgs.GetInt( "numstates", "1", numStates );
  634.     spawnArgs.GetInt( "cycle", "0", cycle );
  635.     spawnArgs.GetFloat( "forcestate", "0", forceState );
  636.  
  637.     // set the state parm
  638.     if ( cycle ) {
  639.         renderEntity.shaderParms[ SHADERPARM_MODE ]++;
  640.         if ( renderEntity.shaderParms[ SHADERPARM_MODE ] > numStates ) {
  641.             renderEntity.shaderParms[ SHADERPARM_MODE ] = 0;
  642.         }
  643.     } else if ( forceState ) {
  644.         renderEntity.shaderParms[ SHADERPARM_MODE ] = forceState;
  645.     } else {
  646.         renderEntity.shaderParms[ SHADERPARM_MODE ] = gameLocal.random.RandomInt( numStates ) + 1;
  647.     }
  648.  
  649.     renderEntity.shaderParms[ SHADERPARM_TIMEOFFSET ] = -MS2SEC( gameLocal.time );
  650.  
  651.     ActivateTargets( activator );
  652.  
  653.     if ( spawnArgs.GetBool( "hideWhenBroken" ) ) {
  654.         Hide();
  655.         PostEventMS( &EV_RestoreDamagable, nextTriggerTime - gameLocal.time );
  656.         BecomeActive( TH_THINK );
  657.     }
  658. }
  659.  
  660. /*
  661. ============
  662. idMoveable::Damage
  663. ============
  664. */
  665. // RAVEN BEGIN
  666. // abahr
  667. void idDamagable::Damage( idEntity *inflictor, idEntity *attacker, const idVec3 &dir, const char *damageDefName, const float damageScale, const int location ) {
  668.  
  669.     if ( invincibleTime > gameLocal.GetTime() )    {
  670.         return;
  671.     }
  672.  
  673.     // If there is a damage filter we need to check to see if the damage def meets the requirement
  674.     const char* damageFilter;
  675.     if ( spawnArgs.GetString ( "damage_filter", "", &damageFilter ) && *damageFilter ) {
  676.         const idDict *damageDef = gameLocal.FindEntityDefDict( damageDefName, false );
  677.         if ( !damageDef ) {
  678.             gameLocal.Error( "Unknown damageDef '%s'\n", damageDefName );
  679.         }
  680.         // If the filter isnt matched then ignore it
  681.         if ( !damageDef->GetBool ( va("filter_%s", damageFilter ) ) ) {
  682.             return;
  683.         }
  684.     }
  685.     if ( spawnArgs.GetBool( "nosplash", "0" ) ) {
  686.         //ignore splash damage
  687.         const idDict *damageDef = gameLocal.FindEntityDefDict( damageDefName, false );
  688.         if ( !damageDef ) {
  689.             gameLocal.Error( "Unknown damageDef '%s'\n", damageDefName );
  690.         }
  691.         //if it has radius, then it's splash damage and ignore it
  692.         if ( damageDef->GetFloat ( "radius", "0" ) ) {
  693.             return;
  694.         }
  695.     }
  696.     
  697.     idEntity::Damage ( inflictor, attacker, dir, damageDefName, damageScale, location );
  698.     
  699.     // Force a stage update so impact effects will be correct
  700.     UpdateStage();
  701. }
  702.  
  703. /*
  704. ================
  705. idDamagable::Killed
  706. ================
  707. */
  708. void idDamagable::Killed( idEntity *inflictor, idEntity *attacker, int damage, const idVec3 &dir, int location ) {
  709.     if ( gameLocal.time < nextTriggerTime ) {
  710.         health += damage;
  711.         return;
  712.     }
  713.  
  714.     BecomeBroken( attacker );
  715. }
  716.  
  717. /*
  718. ================
  719. idDamagable::UpdateStage
  720. ================
  721. */
  722. void idDamagable::UpdateStage ( void ) {
  723.     
  724.     // If there is a stage to go to then see if its time to do that
  725.      if ( stage != stageNext ) {
  726.         int     oldstage;
  727.  
  728.         // Check to see if the stage is complete
  729.         oldstage = stage;
  730.         while ( health < stageEndHealth || (stageEndTime != 0 && gameLocal.time > stageEndTime ) || (stageEndOnGround && GetPhysics()->HasGroundContacts()) || activateStageOnTrigger ) {
  731.             stage = stageNext;
  732.             
  733.             //this only needs to happen once
  734.             activateStageOnTrigger = false;
  735.  
  736.             // Get the stage name, if there is none then there are no more stages
  737.             const char* stageName;
  738.             if ( !spawnArgs.GetString ( va("def_stage%d", stage ), "", &stageName ) || !stageName ) {
  739.                 stage = 0;
  740.                 break;
  741.             }
  742.  
  743.             // Get the stage dictionary
  744.             stageDict = gameLocal.FindEntityDefDict ( stageName, false );
  745.             if ( !stageDict ) {
  746.                 gameLocal.Warning ( "could not find stage '%s' for moveable '%s'", stageName, name.c_str() );
  747.                 stage = 0;
  748.                 break;
  749.             }
  750.  
  751.             // Get the end conditions of the stage
  752.             stageEndHealth = stageDict->GetInt ( "end_health", "-9999" );
  753.  
  754.             stageEndOnGround = stageDict->GetBool( "end_onGround" );
  755.  
  756.             // Timed?            
  757.             stageEndTime = SEC2MS ( GetStageFloat ( "end_time" ) );
  758.             if ( stageEndTime > 0 ) {
  759.                 stageEndTime += gameLocal.time;            
  760.             }        
  761.             
  762.             // Set the next stage to move to when end conditions met
  763.             stageNext = stage + 1;
  764.  
  765.             // Execute the new stage
  766.             ExecuteStage ( );
  767.         }
  768.     }    
  769. }
  770.  
  771. /*
  772. ================
  773. idDamagable::ExecuteStage
  774. ================
  775. */
  776. void idDamagable::ExecuteStage ( void ) {
  777.     const idKeyValue* kv;
  778.     bool              remove;
  779.     
  780.     // Remove the entity this frame?
  781.     remove = stageDict->GetBool ( "remove" );
  782.     
  783.     // Targets?
  784.     if ( stageDict->GetBool( "triggerTargets" ) ) {
  785.         ActivateTargets( this );
  786.     }
  787.  
  788.     // Unbind targets
  789.     if ( stageDict->GetBool( "unbindTargets" ) ) {
  790.         UnbindTargets( this );
  791.     }
  792.  
  793.     // Stop current looping effects
  794.     StopAllEffects ( );
  795.  
  796.     // Play all effects (if they start with "fx_loop" then also loop them
  797.     for ( kv = stageDict->MatchPrefix ( "fx_" ); kv; kv = stageDict->MatchPrefix("fx_",kv) ) {
  798.         if ( !kv->GetKey().Icmpn ( "fx_loop", 7 ) ) {
  799.             if ( !remove ) {
  800.                 PlayEffect ( gameLocal.GetEffect ( *stageDict, kv->GetKey() ), 
  801.                              renderEntity.origin + GetStageVector ( va("offset_%s", kv->GetKey().c_str() ) ), 
  802.                              GetStageVector ( va("dir_%s", kv->GetKey().c_str() ), "1 0 0" ).ToMat3() * renderEntity.axis, 
  803.                              true );
  804.             }
  805.         } else {
  806.             gameLocal.PlayEffect ( gameLocal.GetEffect ( *stageDict, "fx_explode" ), 
  807.                                    GetPhysics()->GetOrigin() + GetStageVector ( va("offset_%s", kv->GetKey().c_str() ) ) * GetPhysics()->GetAxis(), 
  808.                                    GetStageVector ( va("dir_%s", kv->GetKey().c_str() ), "1 0 0" ).ToMat3() );
  809.         }
  810.     }
  811.  
  812.     // Kick off debris
  813.     for ( kv = stageDict->MatchPrefix ( "def_debris" ); kv; kv = stageDict->MatchPrefix("def_debris",kv) ) {        
  814.         const idDict* args = gameLocal.FindEntityDefDict ( kv->GetValue(), false );
  815.         if ( !args ) {
  816.             continue;
  817.         }
  818. // RAVEN BEGIN
  819. // mwhitlock: Dynamic memory consolidation
  820.         RV_PUSH_HEAP_MEM(this);
  821. // RAVEN END
  822.         rvClientMoveable* cent = new rvClientMoveable;
  823. // RAVEN BEGIN
  824. // mwhitlock: Dynamic memory consolidation
  825.         RV_POP_HEAP();
  826. // RAVEN END
  827.         cent->SetOrigin ( GetPhysics()->GetOrigin() + GetStageVector ( va("offset_%s", kv->GetKey().c_str()) ) * GetPhysics()->GetAxis() );
  828.         cent->SetAxis ( GetPhysics()->GetAxis ( ) );
  829.         cent->Spawn ( args );
  830.         
  831.         idVec3 vel;
  832.         vel = GetStageVector ( va("vel_%s", kv->GetKey().c_str()) ) * GetPhysics()->GetAxis();
  833.         vel += GetPhysics()->GetLinearVelocity ( );
  834.         cent->GetPhysics()->SetLinearVelocity ( vel );
  835.         cent->PostEventMS ( &CL_FadeOut, 2500, 2500 );
  836.     }
  837.  
  838.     // Apply force to all objects nearby
  839.     float fPush;
  840.     stageDict->GetFloat("radiusPush","0",fPush);
  841.     if (fPush > 0)    {
  842.         gameLocal.RadiusPush( GetPhysics()->GetOrigin(), 128, fPush, this, this, 1.0f, true );
  843.     }
  844.     
  845.     // Remove the entity now?
  846.     if ( remove ) {
  847.         Hide ( );
  848.         PostEventMS ( &EV_Remove, 0 );
  849.         return;
  850.     } 
  851.     
  852.     // Switch model?
  853.     const char* model;
  854.     if ( stageDict->GetString ( "model", "", &model ) && *model ) {            
  855.         SetModel( model );
  856.     }
  857.  
  858.     // Skin?
  859.     const char* skin;
  860.     if ( stageDict->GetString ( "skin", "", &skin ) && *skin ) {
  861.         renderEntity.customSkin = declManager->FindSkin ( skin, false );
  862.     }
  863.     
  864.     // Velocities
  865.     idVec3 vel;
  866.     vel  = GetStageVector ( "vel_world" );
  867.     vel += (GetStageVector ( "vel_local" ) * GetPhysics()->GetAxis() );
  868.     vel += GetPhysics()->GetLinearVelocity ( );    
  869.     GetPhysics()->SetLinearVelocity ( vel );
  870.         
  871.     // Enable thinking to ensure stages are run
  872.     BecomeActive ( TH_THINK );
  873. }
  874.  
  875. /*
  876. ================
  877. idDamagable::GetStageVector
  878. ================
  879. */
  880. idVec3 idDamagable::GetStageVector ( const char* key, const char* defaultString ) const {
  881.     idVec3 mins;
  882.     if ( stageDict->GetVector ( va("%s_min", key ), "", mins ) ) {
  883.         idVec3 maxs;
  884.         stageDict->GetVector ( va("%s_max", key), mins.ToString(), maxs );
  885.         return mins + (maxs - mins) * gameLocal.random.RandomFloat ( );
  886.     }
  887.     
  888.     return stageDict->GetVector ( key, defaultString );
  889. }
  890.  
  891. /*
  892. ================
  893. idDamagable::GetStageFloat
  894. ================
  895. */
  896. float idDamagable::GetStageFloat    ( const char* key, const char* defaultString ) const {
  897.     float minValue;
  898.     if ( stageDict->GetFloat ( va("%s_min", key ), "", minValue ) ) {
  899.         float maxValue;
  900.         stageDict->GetFloat ( va("%s_max", key), va("%g",minValue), maxValue );
  901.         return minValue + (maxValue - minValue) * gameLocal.random.CRandomFloat ( );
  902.     }
  903.     
  904.     return stageDict->GetFloat ( key, defaultString );
  905. }
  906.  
  907. /*
  908. ================
  909. idDamagable::GetStageInt
  910. ================
  911. */
  912. int idDamagable::GetStageInt    ( const char* key, const char* defaultString ) const {
  913.     int minValue;
  914.     if ( stageDict->GetInt ( va("%s_min", key ), "", minValue ) ) {
  915.         int maxValue;
  916.         stageDict->GetInt ( va("%s_max", key), va("%d",minValue), maxValue );
  917.         return minValue + (maxValue - minValue) * gameLocal.random.CRandomFloat ( );
  918.     }
  919.     
  920.     return stageDict->GetInt ( key, defaultString );
  921. }
  922.  
  923. /*
  924. ================
  925. idDamagable::Event_BecomeBroken
  926. ================
  927. */
  928. void idDamagable::Event_BecomeBroken( idEntity *activator ) {
  929.     BecomeBroken( activator );
  930.  
  931. // RAVEN BEGIN
  932. // bdube: start stages
  933.     UpdateStage ( );
  934. // RAVEN END
  935. }
  936.  
  937. /*
  938. ================
  939. idDamagable::Event_RestoreDamagable
  940. ================
  941. */
  942. void idDamagable::Event_RestoreDamagable( void ) {
  943.     health = spawnArgs.GetInt( "health", "5" );
  944.     Show();
  945. }
  946.  
  947.  
  948. /*
  949. ===============================================================================
  950.  
  951.   idExplodable
  952.     
  953. ===============================================================================
  954. */
  955.  
  956. CLASS_DECLARATION( idEntity, idExplodable )
  957.     EVENT( EV_Activate,    idExplodable::Event_Explode )
  958. END_CLASS
  959.  
  960. /*
  961. ================
  962. idExplodable::Spawn
  963. ================
  964. */
  965. void idExplodable::Spawn( void ) {
  966.     Hide();
  967. }
  968.  
  969. /*
  970. ================
  971. idExplodable::Event_Explode
  972. ================
  973. */
  974. void idExplodable::Event_Explode( idEntity *activator ) {
  975.     const char *temp;
  976.  
  977.     if ( spawnArgs.GetString( "def_damage", "damage_explosion", &temp ) ) {
  978.         gameLocal.RadiusDamage( GetPhysics()->GetOrigin(), activator, activator, this, this, temp );
  979.     }
  980.  
  981.     StartSound( "snd_explode", SND_CHANNEL_ANY, 0, false, NULL );
  982.  
  983.     // Show() calls UpdateVisuals, so we don't need to call it ourselves after setting the shaderParms
  984.     renderEntity.shaderParms[SHADERPARM_RED]        = 1.0f;
  985.     renderEntity.shaderParms[SHADERPARM_GREEN]        = 1.0f;
  986.     renderEntity.shaderParms[SHADERPARM_BLUE]        = 1.0f;
  987.     renderEntity.shaderParms[SHADERPARM_ALPHA]        = 1.0f;
  988.     renderEntity.shaderParms[SHADERPARM_TIMEOFFSET] = -MS2SEC( gameLocal.time );
  989.     renderEntity.shaderParms[SHADERPARM_DIVERSITY]    = 0.0f;
  990.     Show();
  991.  
  992.     PostEventMS( &EV_Remove, 2000 );
  993.  
  994.     ActivateTargets( activator );
  995. }
  996.  
  997.  
  998. /*
  999. ===============================================================================
  1000.  
  1001.   idSpring
  1002.     
  1003. ===============================================================================
  1004. */
  1005.  
  1006. CLASS_DECLARATION( idEntity, idSpring )
  1007.     EVENT( EV_PostSpawn,    idSpring::Event_LinkSpring )
  1008. END_CLASS
  1009.  
  1010. /*
  1011. ================
  1012. idSpring::Think
  1013. ================
  1014. */
  1015. void idSpring::Think( void ) {
  1016.     idVec3 start, end, origin;
  1017.     idMat3 axis;
  1018.  
  1019.     // run physics
  1020.     RunPhysics();
  1021.  
  1022.     if ( thinkFlags & TH_THINK ) {
  1023.         // evaluate force
  1024.         spring.Evaluate( gameLocal.time );
  1025.  
  1026.         start = p1;
  1027.         if ( ent1 && ent1->GetPhysics() ) {
  1028.             axis = ent1->GetPhysics()->GetAxis();
  1029.             origin = ent1->GetPhysics()->GetOrigin();
  1030.             start = origin + start * axis;
  1031.         }
  1032.  
  1033.         end = p2;
  1034.         if ( ent2 && ent2->GetPhysics() ) {
  1035.             axis = ent2->GetPhysics()->GetAxis();
  1036.             origin = ent2->GetPhysics()->GetOrigin();
  1037.             end = origin + p2 * axis;
  1038.         }
  1039.         
  1040.         gameRenderWorld->DebugLine( idVec4(1, 1, 0, 1), start, end, 0, true );
  1041.     }
  1042.  
  1043.     Present();
  1044. }
  1045.  
  1046. /*
  1047. ================
  1048. idSpring::Event_LinkSpring
  1049. ================
  1050. */
  1051. void idSpring::Event_LinkSpring( void ) {
  1052.     idStr name1, name2;
  1053.  
  1054.     spawnArgs.GetString( "ent1", "", name1 );
  1055.     spawnArgs.GetString( "ent2", "", name2 );
  1056.  
  1057.     if ( name1.Length() ) {
  1058.         ent1 = gameLocal.FindEntity( name1 );
  1059.         if ( !ent1 ) {
  1060.             gameLocal.Error( "idSpring '%s' at (%s): cannot find first entity '%s'", name.c_str(), GetPhysics()->GetOrigin().ToString(0), name1.c_str() );
  1061.         }
  1062.     }
  1063.     else {
  1064.         ent1 = gameLocal.entities[ENTITYNUM_WORLD];
  1065.     }
  1066.  
  1067.     if ( name2.Length() ) {
  1068.         ent2 = gameLocal.FindEntity( name2 );
  1069.         if ( !ent2 ) {
  1070.             gameLocal.Error( "idSpring '%s' at (%s): cannot find second entity '%s'", name.c_str(), GetPhysics()->GetOrigin().ToString(0), name2.c_str() );
  1071.         }
  1072.     }
  1073.     else {
  1074.         ent2 = gameLocal.entities[ENTITYNUM_WORLD];
  1075.     }
  1076.     spring.SetPosition( ent1->GetPhysics(), id1, p1, ent2->GetPhysics(), id2, p2 );
  1077.     BecomeActive( TH_THINK );
  1078. }
  1079.  
  1080. /*
  1081. ================
  1082. idSpring::Spawn
  1083. ================
  1084. */
  1085. void idSpring::Spawn( void ) {
  1086.     float Kstretch, damping, restLength;
  1087.  
  1088.     spawnArgs.GetInt( "id1", "0", id1 );
  1089.     spawnArgs.GetInt( "id2", "0", id2 );
  1090.     spawnArgs.GetVector( "point1", "0 0 0", p1 );
  1091.     spawnArgs.GetVector( "point2", "0 0 0", p2 );
  1092.     spawnArgs.GetFloat( "constant", "100.0f", Kstretch );
  1093.     spawnArgs.GetFloat( "damping", "10.0f", damping );
  1094.     spawnArgs.GetFloat( "restlength", "0.0f", restLength );
  1095.  
  1096.     spring.InitSpring( Kstretch, 0.0f, damping, restLength );
  1097.  
  1098.     ent1 = ent2 = NULL;
  1099.  
  1100.     PostEventMS( &EV_PostSpawn, 0 );
  1101. }
  1102.  
  1103. /*
  1104. ================
  1105. idSpring::Save
  1106. ================
  1107. */
  1108. void idSpring::Save( idSaveGame *savefile ) const {
  1109.     savefile->WriteInt ( id1 );
  1110.     savefile->WriteInt ( id2 );
  1111.     savefile->WriteVec3 ( p1 );
  1112.     savefile->WriteVec3 ( p2 );
  1113.     spring.Save ( savefile );
  1114. }
  1115.  
  1116. /*
  1117. ================
  1118. idSpring::Restore
  1119. ================
  1120. */
  1121. void idSpring::Restore( idRestoreGame *savefile ) {
  1122.     savefile->ReadInt ( id1 );
  1123.     savefile->ReadInt ( id2 );
  1124.     savefile->ReadVec3 ( p1 );
  1125.     savefile->ReadVec3 ( p2 );
  1126.     spring.Restore ( savefile );
  1127.     Event_LinkSpring ( );    
  1128. }
  1129.  
  1130. /*
  1131. ===============================================================================
  1132.  
  1133.   idForceField
  1134.     
  1135. ===============================================================================
  1136. */
  1137.  
  1138. const idEventDef EV_Toggle( "Toggle", NULL );
  1139.  
  1140. CLASS_DECLARATION( idEntity, idForceField )
  1141.     EVENT( EV_Activate,        idForceField::Event_Activate )
  1142.     EVENT( EV_Toggle,        idForceField::Event_Toggle )
  1143.     EVENT( EV_FindTargets,    idForceField::Event_FindTargets )
  1144. END_CLASS
  1145.  
  1146. /*
  1147. ===============
  1148. idForceField::Toggle
  1149. ================
  1150. */
  1151. void idForceField::Toggle( void ) {
  1152.     if ( thinkFlags & TH_THINK ) {
  1153.         BecomeInactive( TH_THINK );
  1154.     } else {
  1155.         BecomeActive( TH_THINK );
  1156.     }
  1157. }
  1158.  
  1159. /*
  1160. ================
  1161. idForceField::Think
  1162. ================
  1163. */
  1164. void idForceField::Think( void ) {
  1165.     if ( thinkFlags & TH_THINK ) {
  1166.         // evaluate force
  1167.         forceField.Evaluate( gameLocal.time );
  1168.     }
  1169.     Present();
  1170. }
  1171.  
  1172. /*
  1173. ================
  1174. idForceField::Save
  1175. ================
  1176. */
  1177. void idForceField::Save( idSaveGame *savefile ) const {
  1178.     savefile->WriteStaticObject( forceField );
  1179. }
  1180.  
  1181. /*
  1182. ================
  1183. idForceField::Restore
  1184. ================
  1185. */
  1186. void idForceField::Restore( idRestoreGame *savefile ) {
  1187.     savefile->ReadStaticObject( forceField );
  1188. }
  1189.  
  1190. /*
  1191. ================
  1192. idForceField::Spawn
  1193. ================
  1194. */
  1195. void idForceField::Spawn( void ) {
  1196.     idVec3 uniform;
  1197.     float explosion, implosion, randomTorque;
  1198.  
  1199.     if ( spawnArgs.GetVector( "uniform", "0 0 0", uniform ) ) {
  1200.         forceField.Uniform( uniform );
  1201.     } else if ( spawnArgs.GetFloat( "explosion", "0", explosion ) ) {
  1202.         forceField.Explosion( explosion );
  1203.     } else if ( spawnArgs.GetFloat( "implosion", "0", implosion ) ) {
  1204.         forceField.Implosion( implosion );
  1205.     }
  1206.  
  1207.     if ( spawnArgs.GetFloat( "randomTorque", "0", randomTorque ) ) {
  1208.         forceField.RandomTorque( randomTorque );
  1209.     }
  1210.  
  1211.     if ( spawnArgs.GetBool( "applyForce", "0" ) ) {
  1212.         forceField.SetApplyType( FORCEFIELD_APPLY_FORCE );
  1213.     } else if ( spawnArgs.GetBool( "applyImpulse", "0" ) ) {
  1214.         forceField.SetApplyType( FORCEFIELD_APPLY_IMPULSE );
  1215.     } else {
  1216.         forceField.SetApplyType( FORCEFIELD_APPLY_VELOCITY );
  1217.     }
  1218.  
  1219.     forceField.SetPlayerOnly( spawnArgs.GetBool( "playerOnly", "0" ) );
  1220.     forceField.SetMonsterOnly( spawnArgs.GetBool( "monsterOnly", "0" ) );
  1221.  
  1222.     // set the collision model on the force field
  1223. // RAVEN BEGIN
  1224. // mwhitlock: Dynamic memory consolidation
  1225.     RV_PUSH_HEAP_MEM(this);
  1226. // RAVEN END
  1227.     forceField.SetClipModel( new idClipModel( GetPhysics()->GetClipModel() ) );
  1228. // RAVEN BEGIN
  1229. // mwhitlock: Dynamic memory consolidation
  1230.     RV_POP_HEAP();
  1231. // RAVEN END
  1232.     forceField.SetOwner( this );
  1233.     // remove the collision model from the physics object
  1234.     GetPhysics()->SetClipModel( NULL, 1.0f );
  1235.  
  1236.     if ( spawnArgs.GetBool( "start_on" ) ) {
  1237.         BecomeActive( TH_THINK );
  1238.     }
  1239. }
  1240.  
  1241. /*
  1242. ===============
  1243. idForceField::Event_Toggle
  1244. ================
  1245. */
  1246. void idForceField::Event_Toggle( void ) {
  1247.     Toggle();
  1248. }
  1249.  
  1250. /*
  1251. ================
  1252. idForceField::Event_Activate
  1253. ================
  1254. */
  1255. void idForceField::Event_Activate( idEntity *activator ) {
  1256.     float wait;
  1257.  
  1258.     Toggle();
  1259.     if ( spawnArgs.GetFloat( "wait", "0.01", wait ) ) {
  1260.         PostEventSec( &EV_Toggle, wait );
  1261.     }
  1262. }
  1263.  
  1264. /*
  1265. ================
  1266. idForceField::Event_FindTargets
  1267. ================
  1268. */
  1269. void idForceField::Event_FindTargets( void ) {
  1270.     FindTargets();
  1271.     RemoveNullTargets();
  1272.     if ( targets.Num() ) {
  1273.         forceField.Uniform( targets[0].GetEntity()->GetPhysics()->GetOrigin() - GetPhysics()->GetOrigin() );
  1274.     }
  1275. }
  1276.  
  1277. // RAVEN BEGIN
  1278. // bdube: jump pads
  1279.  
  1280. /*
  1281. ===============================================================================
  1282.  
  1283.   idForceField
  1284.     
  1285. ===============================================================================
  1286. */
  1287.  
  1288. const int JUMPPAD_EFFECT_DELAY    = 100;
  1289.  
  1290. CLASS_DECLARATION( idForceField, rvJumpPad )
  1291.     EVENT( EV_FindTargets,    rvJumpPad::Event_FindTargets )
  1292. END_CLASS
  1293.  
  1294. /*
  1295. ================
  1296. rvJumpPad::rvJumpPad
  1297. ================
  1298. */
  1299. rvJumpPad::rvJumpPad ( void ) {
  1300.     lastEffectTime = -1;
  1301. }
  1302.  
  1303. /*
  1304. ================
  1305. rvJumpPad::Think
  1306. ================
  1307. */
  1308. void rvJumpPad::Think( void ) {
  1309.     if ( thinkFlags & TH_THINK ) {
  1310.         // evaluate force
  1311.         forceField.Evaluate( gameLocal.time );
  1312.         
  1313.         // If force has been applied to an entity and jump pad effect hasnt been played for a bit
  1314.         // then play it now.
  1315.         if ( forceField.GetLastApplyTime ( ) - lastEffectTime > JUMPPAD_EFFECT_DELAY ) {
  1316.             // start locally
  1317.             StartSound( "snd_jump", SND_CHANNEL_ITEM, 0, false, NULL );
  1318.             if ( spawnArgs.GetString( "fx_jump" )[ 0 ] ) {
  1319.                 PlayEffect( "fx_jump", renderEntity.origin, effectAxis, false, vec3_origin, false );
  1320.             }
  1321.  
  1322.             // send through unreliable
  1323.             if ( gameLocal.isServer ) {
  1324.                 idBitMsg    msg;
  1325.                 byte        msgBuf[ MAX_GAME_MESSAGE_SIZE ];
  1326.  
  1327.                 msg.Init( msgBuf, sizeof( msgBuf ) );
  1328.                 msg.WriteByte( GAME_UNRELIABLE_MESSAGE_EVENT );
  1329.                 msg.WriteBits( gameLocal.GetSpawnId( this ), 32 );
  1330.                 msg.WriteByte( EVENT_JUMPFX );
  1331.                 gameLocal.SendUnreliableMessagePVS( msg, this, gameLocal.pvs.GetPVSArea( renderEntity.origin ) );
  1332.             }
  1333.             
  1334.             lastEffectTime = forceField.GetLastApplyTime( );
  1335.         }
  1336.     }
  1337.     Present();
  1338. }
  1339.  
  1340. /*
  1341. ================
  1342. rvJumpPad::Spawn
  1343. ================
  1344. */
  1345. void rvJumpPad::Spawn( void ) {
  1346.     forceField.SetApplyType( FORCEFIELD_APPLY_VELOCITY );
  1347.     forceField.SetOwner( this );
  1348. }
  1349.  
  1350. /*
  1351. ================
  1352. rvJumpPad::Event_FindTargets
  1353. ================
  1354. */
  1355. void rvJumpPad::Event_FindTargets( void ) {
  1356.     FindTargets();
  1357.     RemoveNullTargets();
  1358.     if ( targets.Num() ) {
  1359.         idEntity* ent;
  1360.         ent = targets[0].GetEntity();
  1361.         assert( ent );
  1362.         
  1363.         idVec3 vert;
  1364.         idVec3 diff;
  1365.         idVec3 vel;
  1366.         idVec3 localGravity( gameLocal.GetCurrentGravity(this) );
  1367.         idVec3 localGravityNormal( localGravity.ToNormal() );
  1368.         float  time;
  1369.         float  dist;
  1370.         
  1371.         // Find the distance along the gravity vector between the jump pad and its target
  1372.         diff = (ent->GetPhysics()->GetOrigin() - GetPhysics()->GetOrigin());
  1373.         vert = (diff * localGravityNormal) * localGravityNormal;
  1374.         
  1375.         // Determine how long it would take to cover the distance along the gravity vector
  1376.         time = idMath::Sqrt( vert.Length() / (0.5f * localGravity.Length()) );
  1377.         if ( !time ) {
  1378.             PostEventMS( &EV_Remove, 0 );
  1379.             return;
  1380.         }
  1381.  
  1382.         // The final velocity is the direction between the jump pad and its target using
  1383.         // the travel time to determine the forward vector and adding in an inverse gravity vector.
  1384.         vel  = diff - vert;
  1385.         dist = vel.Normalize();
  1386.         
  1387.         vel = vel * (dist / time);
  1388.         vel += (localGravity * -time);
  1389.  
  1390.         forceField.Uniform( vel );
  1391.  
  1392.         // calculate a coordinate axis where the vector to the jumppad target is forward
  1393.         // use this to play the fx_jump fx
  1394.         diff.Normalize();
  1395.         effectAxis = diff.ToMat3();
  1396.     }
  1397. }
  1398.  
  1399. /*
  1400. ===============
  1401. rvJumpPad::ClientReceiveEvent
  1402. ===============
  1403. */
  1404. bool rvJumpPad::ClientReceiveEvent( int event, int time, const idBitMsg &msg ) {
  1405.     switch ( event ) {
  1406.     case EVENT_JUMPFX: {
  1407.         if ( spawnArgs.GetString( "fx_jump" )[ 0 ] ) {
  1408.             PlayEffect( "fx_jump", renderEntity.origin, effectAxis, false, vec3_origin, false );
  1409.         }
  1410.         StartSound( "snd_jump", SND_CHANNEL_ITEM, 0, false, NULL );
  1411.         return true;
  1412.     }
  1413.     default:
  1414.         return idEntity::ClientReceiveEvent( event, time, msg );
  1415.     }
  1416. }
  1417.  
  1418. // RAVEN END
  1419.  
  1420. /*
  1421. ===============================================================================
  1422.  
  1423.     idAnimated
  1424.  
  1425. ===============================================================================
  1426. */
  1427.  
  1428. const idEventDef EV_Animated_Start( "<start>" );
  1429. const idEventDef EV_LaunchMissiles( "launchMissiles", "ssssdf" );
  1430. const idEventDef EV_LaunchMissilesUpdate( "<launchMissiles>", "dddd" );
  1431. const idEventDef EV_AnimDone( "<AnimDone>", "d" );
  1432. const idEventDef EV_StartRagdoll( "startRagdoll" );
  1433.  
  1434. // RAVEN BEGIN
  1435. // bdube: script object
  1436. const idEventDef EV_SetAnimState ( "setAnimState", "sd" );
  1437. // RAVEN END
  1438.  
  1439. CLASS_DECLARATION( idAFEntity_Gibbable, idAnimated )
  1440.     EVENT( EV_Activate,                idAnimated::Event_Activate )
  1441.     EVENT( EV_Animated_Start,        idAnimated::Event_Start )
  1442.     EVENT( EV_StartRagdoll,            idAnimated::Event_StartRagdoll )
  1443.     EVENT( EV_AnimDone,                idAnimated::Event_AnimDone )
  1444.     EVENT( EV_Footstep,                idAnimated::Event_Footstep )
  1445.     EVENT( EV_FootstepLeft,            idAnimated::Event_Footstep )
  1446.     EVENT( EV_FootstepRight,        idAnimated::Event_Footstep )
  1447.     EVENT( EV_LaunchMissiles,        idAnimated::Event_LaunchMissiles )
  1448.     EVENT( EV_LaunchMissilesUpdate,    idAnimated::Event_LaunchMissilesUpdate )
  1449.  
  1450. // RAVEN BEGIN
  1451. // bdube: script object
  1452.     EVENT( EV_SetAnimState,            idAnimated::Event_SetAnimState )
  1453.     EVENT( AI_PlayAnim,                idAnimated::Event_PlayAnim )
  1454.     EVENT( AI_PlayCycle,            idAnimated::Event_PlayCycle )
  1455.     EVENT( AI_AnimDone,                idAnimated::Event_AnimDone2 )
  1456. // RAVEN END
  1457.  
  1458. END_CLASS
  1459.  
  1460. /*
  1461. ===============
  1462. idAnimated::idAnimated
  1463. ================
  1464. */
  1465. idAnimated::idAnimated() {
  1466.     int        i;
  1467.  
  1468.     anim = 0;
  1469.     blendFrames = 0;
  1470.     soundJoint = INVALID_JOINT;
  1471.     activated = false;
  1472.     combatModel = NULL;
  1473.     activator = NULL;
  1474.     current_anim_index = 0;
  1475.     num_anims = 0;
  1476. // RAVEN BEGIN
  1477. // bdube: script control
  1478.     scriptThread = NULL;
  1479.     for( i = 0; i < ANIM_NumAnimChannels; i++ ) {
  1480.         animDoneTime[i] = 0;
  1481.     }
  1482. // RAVEN END
  1483. }
  1484.  
  1485. /*
  1486. ===============
  1487. idAnimated::idAnimated
  1488. ================
  1489. */
  1490. idAnimated::~idAnimated() {
  1491.     delete combatModel;
  1492.     combatModel = NULL;
  1493.     
  1494. // RAVEN BEGIN
  1495. // bdube: kill script object
  1496.     delete scriptThread;
  1497. // RAVEN END        
  1498. }
  1499.  
  1500. /*
  1501. ===============
  1502. idAnimated::Save
  1503. ================
  1504. */
  1505. void idAnimated::Save( idSaveGame *savefile ) const {
  1506.     int        i;
  1507.  
  1508.     savefile->WriteInt( num_anims );
  1509.     savefile->WriteInt( current_anim_index );
  1510.     savefile->WriteInt( anim );
  1511.     savefile->WriteInt( blendFrames );
  1512.     savefile->WriteJoint( soundJoint );
  1513.     activator.Save( savefile );
  1514.     savefile->WriteBool( activated );
  1515.  
  1516. // RAVEN BEGIN
  1517.     savefile->WriteObject( scriptThread );
  1518.     savefile->WriteString( state );
  1519.     savefile->WriteString( idealState );
  1520.     for( i = 0; i < ANIM_NumAnimChannels; i++ ) {
  1521.         savefile->WriteInt( animDoneTime[i] );
  1522.     }
  1523. // RAVEN END
  1524. }
  1525.  
  1526. /*
  1527. ===============
  1528. idAnimated::Restore
  1529. ================
  1530. */
  1531. void idAnimated::Restore( idRestoreGame *savefile ) {
  1532.     int        i;
  1533.  
  1534.     savefile->ReadInt( num_anims );
  1535.     savefile->ReadInt( current_anim_index );
  1536.     savefile->ReadInt( anim );
  1537.     savefile->ReadInt( blendFrames );
  1538.     savefile->ReadJoint( soundJoint );
  1539.     activator.Restore( savefile );
  1540.     savefile->ReadBool( activated );
  1541.  
  1542. // RAVEN BEGIN
  1543.     savefile->ReadObject( reinterpret_cast<idClass *&>( scriptThread ) );
  1544.     savefile->ReadString( state );
  1545.     savefile->ReadString( idealState );
  1546.     for( i = 0; i < ANIM_NumAnimChannels; i++ ) {
  1547.         savefile->ReadInt( animDoneTime[i] );
  1548.     }
  1549. // RAVEN END
  1550. }
  1551.  
  1552. /*
  1553. ===============
  1554. idAnimated::Spawn
  1555. ================
  1556. */
  1557. void idAnimated::Spawn( void ) {
  1558.     idStr        animname;
  1559.     int            anim2;
  1560.     float        wait;
  1561.     const char    *joint;
  1562.  
  1563.     joint = spawnArgs.GetString( "sound_bone", "origin" ); 
  1564.     soundJoint = animator.GetJointHandle( joint );
  1565.     if ( soundJoint == INVALID_JOINT ) {
  1566.         gameLocal.Warning( "idAnimated '%s' at (%s): cannot find joint '%s' for sound playback", name.c_str(), GetPhysics()->GetOrigin().ToString(0), joint );
  1567.     }
  1568.  
  1569.     LoadAF( NULL );
  1570.  
  1571.     // allow bullets to collide with a combat model
  1572.     if ( spawnArgs.GetBool( "combatModel", "0" ) ) {
  1573. // RAVEN BEGIN
  1574. // mwhitlock: Dynamic memory consolidation
  1575.         RV_PUSH_HEAP_MEM(this);
  1576. // RAVEN END
  1577.         combatModel = new idClipModel( modelDefHandle );
  1578. // RAVEN BEGIN
  1579. // mwhitlock: Dynamic memory consolidation
  1580.         RV_POP_HEAP();
  1581. // RAVEN END
  1582.     }
  1583.  
  1584.     // allow the entity to take damage
  1585.     if ( spawnArgs.GetBool( "takeDamage", "0" ) ) {
  1586.         fl.takedamage = true;
  1587.     }
  1588.  
  1589.     blendFrames = 0;
  1590.  
  1591. // RAVEN BEGIN
  1592. // bdube: script control
  1593.     // setup script object
  1594.     const char* scriptObjectName;
  1595.     if ( spawnArgs.GetString( "scriptobject", NULL, &scriptObjectName ) ) {
  1596.         if ( !scriptObject.SetType( scriptObjectName ) ) {
  1597.             gameLocal.Error( "Script object '%s' not found on entity '%s'.", scriptObjectName, name.c_str() );
  1598.         }
  1599.  
  1600.         // init the script object's data
  1601.         scriptObject.ClearObject();
  1602.  
  1603.         // call script object's constructor
  1604.         const function_t *constructor;
  1605.         constructor = scriptObject.GetConstructor();
  1606.         if ( constructor ) {
  1607.             // start a thread that will initialize after Spawn is done being called
  1608. // RAVEN BEGIN
  1609. // mwhitlock: Dynamic memory consolidation
  1610.             RV_PUSH_HEAP_MEM(this);
  1611. // RAVEN END
  1612.             scriptThread = new idThread();
  1613. // RAVEN BEGIN
  1614. // mwhitlock: Dynamic memory consolidation
  1615.             RV_POP_HEAP();
  1616. // RAVEN END
  1617.             scriptThread->ManualDelete();
  1618.             scriptThread->ManualControl();
  1619.             scriptThread->SetThreadName( name.c_str() );
  1620.             scriptThread->CallFunction( this, constructor, true );
  1621.             scriptThread->Execute ( );
  1622.         }
  1623.     
  1624.         fl.takedamage = true;
  1625.  
  1626.         return;
  1627.     }    
  1628. // RAVEN END
  1629.  
  1630.     current_anim_index = 0;
  1631.     spawnArgs.GetInt( "num_anims", "0", num_anims );
  1632.  
  1633.     blendFrames = spawnArgs.GetInt( "blend_in" );
  1634.  
  1635.     animname = spawnArgs.GetString( num_anims ? "anim1" : "anim" );
  1636.     if ( !animname.Length() ) {
  1637.         anim = 0;
  1638.     } else {
  1639.         anim = animator.GetAnim( animname );
  1640.         if ( !anim ) {
  1641.             gameLocal.Error( "idAnimated '%s' at (%s): cannot find anim '%s'", name.c_str(), GetPhysics()->GetOrigin().ToString(0), animname.c_str() );
  1642.         }
  1643.     }
  1644.  
  1645.     if ( spawnArgs.GetBool( "hide" ) ) {
  1646.         Hide();
  1647.  
  1648.         if ( !num_anims ) {
  1649.             blendFrames = 0;
  1650.         }
  1651.     } else if ( spawnArgs.GetString( "start_anim", "", animname ) ) {
  1652.         anim2 = animator.GetAnim( animname );
  1653.         if ( !anim2 ) {
  1654.             gameLocal.Error( "idAnimated '%s' at (%s): cannot find anim '%s'", name.c_str(), GetPhysics()->GetOrigin().ToString(0), animname.c_str() );
  1655.         }
  1656.         animator.CycleAnim( ANIMCHANNEL_ALL, anim2, gameLocal.time, 0 );
  1657.     } else if ( anim ) {
  1658.         // init joints to the first frame of the animation
  1659. // RAVEN BEGIN
  1660.         frameBlend_t frameBlend = { 0, 0, 0, 1.0f, 0 };
  1661.         animator.SetFrame( ANIMCHANNEL_ALL, anim, frameBlend );        
  1662. // RAVEN END
  1663.  
  1664.         if ( !num_anims ) {
  1665.             blendFrames = 0;
  1666.         }
  1667.     }
  1668.  
  1669.     spawnArgs.GetFloat( "wait", "-1", wait );
  1670.  
  1671.     if ( wait >= 0 ) {
  1672.         PostEventSec( &EV_Activate, wait, this );
  1673.     }
  1674. }
  1675.  
  1676. /*
  1677. ===============
  1678. idAnimated::LoadAF
  1679. ===============
  1680. */
  1681. bool idAnimated::LoadAF( const char* keyname ) {
  1682.     idStr fileName;
  1683.  
  1684.     if ( !keyname || !*keyname ) {
  1685.         keyname = "ragdoll";
  1686.     }
  1687.  
  1688.     if ( !spawnArgs.GetString( keyname, "*unknown*", fileName ) ) {
  1689.         return false;
  1690.     }
  1691.     af.SetAnimator( GetAnimator() );
  1692.     return af.Load( this, fileName );
  1693. }
  1694.  
  1695. /*
  1696. ===============
  1697. idAnimated::GetPhysicsToSoundTransform
  1698. ===============
  1699. */
  1700. bool idAnimated::GetPhysicsToSoundTransform( idVec3 &origin, idMat3 &axis ) {
  1701.     animator.GetJointTransform( soundJoint, gameLocal.time, origin, axis );
  1702.     axis = renderEntity.axis;
  1703.     return true;
  1704. }
  1705.  
  1706. /*
  1707. ================
  1708. idAnimated::StartRagdoll
  1709. ================
  1710. */
  1711. bool idAnimated::StartRagdoll( void ) {
  1712.     // if no AF loaded
  1713.     if ( !af.IsLoaded() ) {
  1714.         return false;
  1715.     }
  1716.  
  1717.     // if the AF is already active
  1718.     if ( af.IsActive() ) {
  1719.         return true;
  1720.     }
  1721.  
  1722.     // disable any collision model used
  1723.     GetPhysics()->DisableClip();
  1724.  
  1725.     // start using the AF
  1726.     af.StartFromCurrentPose( spawnArgs.GetInt( "velocityTime", "0" ) );
  1727.     
  1728.     return true;
  1729. }
  1730.  
  1731. /*
  1732. =====================
  1733. idAnimated::PlayNextAnim
  1734. =====================
  1735. */
  1736. void idAnimated::PlayNextAnim( void ) {
  1737.     const char *animname;
  1738.     int len;
  1739.     int cycle;
  1740.  
  1741.     if ( current_anim_index >= num_anims ) {
  1742.         Hide();
  1743.         if ( spawnArgs.GetBool( "remove" ) ) {
  1744.             PostEventMS( &EV_Remove, 0 );
  1745.         } else {
  1746.             current_anim_index = 0;
  1747.         }
  1748.         return;
  1749.     }
  1750.  
  1751.     Show();
  1752.     current_anim_index++;
  1753.  
  1754.     spawnArgs.GetString( va( "anim%d", current_anim_index ), NULL, &animname );
  1755.     if ( !animname ) {
  1756.         anim = 0;
  1757.         animator.Clear( ANIMCHANNEL_ALL, gameLocal.time, FRAME2MS( blendFrames ) );
  1758.         return;
  1759.     }
  1760.  
  1761.     anim = animator.GetAnim( animname );
  1762.     if ( !anim ) {
  1763.         gameLocal.Warning( "missing anim '%s' on %s", animname, name.c_str() );
  1764.         return;
  1765.     }
  1766.  
  1767.     if ( g_debugCinematic.GetBool() ) {
  1768.         gameLocal.Printf( "%d: '%s' start anim '%s'\n", gameLocal.framenum, GetName(), animname );
  1769.     }
  1770.         
  1771.     spawnArgs.GetInt( "cycle", "1", cycle );
  1772.     if ( ( current_anim_index == num_anims ) && spawnArgs.GetBool( "loop_last_anim" ) ) {
  1773.         cycle = -1;
  1774.     }
  1775.  
  1776.     animator.CycleAnim( ANIMCHANNEL_ALL, anim, gameLocal.time, FRAME2MS( blendFrames ) );
  1777.     animator.CurrentAnim( ANIMCHANNEL_ALL )->SetCycleCount( cycle );
  1778.  
  1779.     len = animator.CurrentAnim( ANIMCHANNEL_ALL )->PlayLength();
  1780.     if ( len >= 0 ) {
  1781.         PostEventMS( &EV_AnimDone, len, current_anim_index );
  1782.     }
  1783.  
  1784.     // offset the start time of the shader to sync it to the game time
  1785.     renderEntity.shaderParms[ SHADERPARM_TIMEOFFSET ] = -MS2SEC( gameLocal.time );
  1786.  
  1787.     animator.ForceUpdate();
  1788.     UpdateAnimation();
  1789.     UpdateVisuals();
  1790.     Present();
  1791. }
  1792.  
  1793. /*
  1794. ===============
  1795. idAnimated::Event_StartRagdoll
  1796. ================
  1797. */
  1798. void idAnimated::Event_StartRagdoll( void ) {
  1799.     StartRagdoll();
  1800. }
  1801.  
  1802. /*
  1803. ===============
  1804. idAnimated::Event_AnimDone
  1805. ================
  1806. */
  1807. void idAnimated::Event_AnimDone( int animindex ) {
  1808.     if ( g_debugCinematic.GetBool() ) {
  1809.         const idAnim *animPtr = animator.GetAnim( anim );
  1810.         gameLocal.Printf( "%d: '%s' end anim '%s'\n", gameLocal.framenum, GetName(), animPtr ? animPtr->Name() : "" );
  1811.     }
  1812.  
  1813.     if ( ( animindex >= num_anims ) && spawnArgs.GetBool( "remove" ) ) {
  1814.         Hide();
  1815.         PostEventMS( &EV_Remove, 0 );
  1816.     } else if ( spawnArgs.GetBool( "auto_advance" ) ) {
  1817.         PlayNextAnim();
  1818.     } else {
  1819.         activated = false;
  1820.     }
  1821.  
  1822.     ActivateTargets( activator.GetEntity() );
  1823. }
  1824.  
  1825. /*
  1826. ===============
  1827. idAnimated::Event_Activate
  1828. ================
  1829. */
  1830. void idAnimated::Event_Activate( idEntity *_activator ) {
  1831. // RAVEN BEGIN
  1832. // bdube: script object support
  1833.     if ( scriptThread ) {
  1834.         CallHandler ( "onActivate" );
  1835.         return;
  1836.     }
  1837. // RAVEN END
  1838.  
  1839.     if ( num_anims ) {
  1840.         PlayNextAnim();
  1841.         activator = _activator;
  1842.         return;
  1843.     }
  1844.  
  1845.     if ( activated ) {
  1846.         // already activated
  1847.         return;
  1848.     }
  1849.  
  1850.     activated = true;
  1851.     activator = _activator;
  1852.     ProcessEvent( &EV_Animated_Start );
  1853. }
  1854.  
  1855. /*
  1856. ===============
  1857. idAnimated::Event_Start
  1858. ================
  1859. */
  1860. void idAnimated::Event_Start( void ) {
  1861.     int cycle;
  1862.     int len;
  1863.  
  1864.     Show();
  1865.  
  1866.     if ( num_anims ) {
  1867.         PlayNextAnim();
  1868.         return;
  1869.     }
  1870.  
  1871.     if ( anim ) {
  1872.         if ( g_debugCinematic.GetBool() ) {
  1873.             const idAnim *animPtr = animator.GetAnim( anim );
  1874.             gameLocal.Printf( "%d: '%s' start anim '%s'\n", gameLocal.framenum, GetName(), animPtr ? animPtr->Name() : "" );
  1875.         }
  1876.         spawnArgs.GetInt( "cycle", "1", cycle );
  1877.         animator.CycleAnim( ANIMCHANNEL_ALL, anim, gameLocal.time, FRAME2MS( blendFrames ) );
  1878.         animator.CurrentAnim( ANIMCHANNEL_ALL )->SetCycleCount( cycle );
  1879.  
  1880.         len = animator.CurrentAnim( ANIMCHANNEL_ALL )->PlayLength();
  1881.         if ( len >= 0 ) {
  1882.             PostEventMS( &EV_AnimDone, len, 1 );
  1883.         }
  1884.     }
  1885.  
  1886.     // offset the start time of the shader to sync it to the game time
  1887.     renderEntity.shaderParms[ SHADERPARM_TIMEOFFSET ] = -MS2SEC( gameLocal.time );
  1888.  
  1889.     animator.ForceUpdate();
  1890.     UpdateAnimation();
  1891.     UpdateVisuals();
  1892.     Present();
  1893. }
  1894.  
  1895. /*
  1896. ===============
  1897. idAnimated::Event_Footstep
  1898. ===============
  1899. */
  1900. void idAnimated::Event_Footstep( void ) {
  1901.     StartSound( "snd_footstep", SND_CHANNEL_BODY, 0, false, NULL );
  1902. }
  1903.  
  1904. /*
  1905. =====================
  1906. idAnimated::Event_LaunchMissilesUpdate
  1907. =====================
  1908. */
  1909. void idAnimated::Event_LaunchMissilesUpdate( int launchjoint, int targetjoint, int numshots, int framedelay ) {
  1910.     idVec3            launchPos;
  1911.     idVec3            targetPos;
  1912.     idMat3            axis;
  1913.     idVec3            dir;
  1914.     idEntity *        ent;
  1915.     idProjectile *    projectile;
  1916.     const idDict *    projectileDef;
  1917.     const char *    projectilename;
  1918.  
  1919.     projectilename = spawnArgs.GetString( "projectilename" );
  1920.     projectileDef = gameLocal.FindEntityDefDict( projectilename, false );
  1921.     if ( !projectileDef ) {
  1922.         gameLocal.Warning( "idAnimated '%s' at (%s): 'launchMissiles' called with unknown projectile '%s'", name.c_str(), GetPhysics()->GetOrigin().ToString(0), projectilename );
  1923.         return;
  1924.     }
  1925.  
  1926.     StartSound( "snd_missile", SND_CHANNEL_WEAPON, 0, false, NULL );
  1927.  
  1928.     animator.GetJointTransform( ( jointHandle_t )launchjoint, gameLocal.time, launchPos, axis );
  1929.     launchPos = renderEntity.origin + launchPos * renderEntity.axis;
  1930.     
  1931. // RAVEN BEGIN
  1932. // bdube: with no target bone it will just shoot out the direction of the bones orientation
  1933.     if ( targetjoint != INVALID_JOINT ) {
  1934.         animator.GetJointTransform( ( jointHandle_t )targetjoint, gameLocal.time, targetPos, axis );
  1935.         targetPos = renderEntity.origin + targetPos * renderEntity.axis;
  1936.         dir = targetPos - launchPos;
  1937.     } else {
  1938.         axis *= renderEntity.axis;
  1939.         dir = axis[0];
  1940.     }
  1941. // RAVEN END
  1942.  
  1943.     dir.Normalize();
  1944.  
  1945.     gameLocal.SpawnEntityDef( *projectileDef, &ent, false );
  1946. // RAVEN BEGIN
  1947. // jnewquist: Use accessor for static class type 
  1948.     if ( !ent || !ent->IsType( idProjectile::GetClassType() ) ) {
  1949. // RAVEN END
  1950.         gameLocal.Error( "idAnimated '%s' at (%s): in 'launchMissiles' call '%s' is not an idProjectile", name.c_str(), GetPhysics()->GetOrigin().ToString(0), projectilename );
  1951.     }
  1952.     projectile = ( idProjectile * )ent;
  1953.     projectile->Create( this, launchPos, dir );
  1954.     projectile->Launch( launchPos, dir, vec3_origin );
  1955.  
  1956.     if ( numshots > 0 ) {
  1957.         PostEventMS( &EV_LaunchMissilesUpdate, FRAME2MS( framedelay ), launchjoint, targetjoint, numshots - 1, framedelay );
  1958.     }
  1959. }
  1960.  
  1961. /*
  1962. =====================
  1963. idAnimated::Event_LaunchMissiles
  1964. =====================
  1965. */
  1966. void idAnimated::Event_LaunchMissiles( const char *projectilename, const char *sound, const char *launchjoint, const char *targetjoint, int numshots, int framedelay ) {
  1967.     const idDict *    projectileDef;
  1968.     jointHandle_t    launch;
  1969.     jointHandle_t    target;
  1970.  
  1971.     projectileDef = gameLocal.FindEntityDefDict( projectilename, false );
  1972.     if ( !projectileDef ) {
  1973.         gameLocal.Warning( "idAnimated '%s' at (%s): unknown projectile '%s'", name.c_str(), GetPhysics()->GetOrigin().ToString(0), projectilename );
  1974.         return;
  1975.     }
  1976.  
  1977.     launch = animator.GetJointHandle( launchjoint );
  1978.     if ( launch == INVALID_JOINT ) {
  1979.         gameLocal.Warning( "idAnimated '%s' at (%s): unknown launch joint '%s'", name.c_str(), GetPhysics()->GetOrigin().ToString(0), launchjoint );
  1980.         gameLocal.Error( "Unknown joint '%s'", launchjoint );
  1981.     }
  1982.  
  1983.     target = animator.GetJointHandle( targetjoint );
  1984. // RAVEN BEGIN
  1985. // bdube: invalid is ok now, it means shoot out the direction of the bone
  1986. //    if ( target == INVALID_JOINT ) {
  1987. //        gameLocal.Warning( "idAnimated '%s' at (%s): unknown target joint '%s'", name.c_str(), GetPhysics()->GetOrigin().ToString(0), targetjoint );
  1988. //    }
  1989. // RAVEN END
  1990.  
  1991.     spawnArgs.Set( "projectilename", projectilename );
  1992.     spawnArgs.Set( "missilesound", sound );
  1993.  
  1994.     CancelEvents( &EV_LaunchMissilesUpdate );
  1995. // RAVEN BEGIN
  1996. // nmckenzie: Do this now.  No delays.  No event loops or updates.  Just a straightforward DO THIS.  Tacky.
  1997.     if ( numshots == 1 && framedelay == 0 ){
  1998.         Event_LaunchMissilesUpdate ( launch, target, 1, 0 );
  1999.     }
  2000.     else{
  2001.         ProcessEvent( &EV_LaunchMissilesUpdate, launch, target, numshots - 1, framedelay );
  2002.     }
  2003. // RAVEN END
  2004. }
  2005.  
  2006. // RAVEN BEGIN
  2007. // bdube: added
  2008. /*
  2009. =====================
  2010. idAnimated::ShouldConstructScriptObjectAtSpawn
  2011. =====================
  2012. */
  2013. bool idAnimated::ShouldConstructScriptObjectAtSpawn( void ) const {
  2014.     return false;
  2015. }
  2016.  
  2017. /*
  2018. =====================
  2019. idAnimated::Think
  2020. =====================
  2021. */
  2022. void idAnimated::Think ( void ) {
  2023.     UpdateScript ( );
  2024.     idAFEntity_Gibbable::Think ( );
  2025. }
  2026.  
  2027. /*
  2028. =====================
  2029. idAnimated::Think
  2030. =====================
  2031. */
  2032. void idAnimated::Damage ( idEntity* inflictor, idEntity* attacker, const idVec3& dir, const char* damageDefName, const float damageScale, const int location ) {
  2033.     if ( !scriptThread ) {
  2034.         return;
  2035.     }
  2036.  
  2037.     CallHandler ( "onDamage" );    
  2038. }
  2039.  
  2040. /*
  2041. =====================
  2042. idAnimated::Event_PlayAnim
  2043. =====================
  2044. */
  2045. void idAnimated::Event_PlayAnim( int channel, const char *animname ) {
  2046.     int anim;
  2047.     
  2048.     anim = animator.GetAnim( animname );
  2049.     if ( !anim ) {
  2050.         gameLocal.Warning( "missing '%s' animation on '%s' (%s)", animname, name.c_str(), GetEntityDefName() );
  2051.         animator.Clear( channel, gameLocal.time, FRAME2MS( blendFrames ) );
  2052.         animDoneTime[channel] = 0;
  2053.         idThread::ReturnFloat( false );
  2054.     } else {
  2055.         animator.PlayAnim( channel, anim, gameLocal.time, FRAME2MS( blendFrames ) );
  2056.         animDoneTime[channel] = animator.CurrentAnim( channel )->GetEndTime();
  2057.         idThread::ReturnFloat( MS2SEC( animDoneTime[channel] - gameLocal.time ) );
  2058.     }
  2059.     blendFrames = 0;
  2060. }
  2061.  
  2062. /*
  2063. ===============
  2064. idAnimated::Event_PlayCycle
  2065. ===============
  2066. */
  2067. void idAnimated::Event_PlayCycle( int channel, const char *animname ) {
  2068.     int anim;
  2069.  
  2070.     anim = animator.GetAnim( animname );
  2071.     if ( !anim ) {
  2072.         gameLocal.Warning( "missing '%s' animation on '%s' (%s)", animname, name.c_str(), GetEntityDefName() );
  2073.         animator.Clear( channel, gameLocal.time, FRAME2MS( blendFrames ) );
  2074.         animDoneTime[channel] = 0;
  2075.     } else {
  2076.         animator.CycleAnim( channel, anim, gameLocal.time, FRAME2MS( blendFrames ) );
  2077.         animDoneTime[channel] = animator.CurrentAnim( channel )->GetEndTime();
  2078.     }
  2079.     blendFrames = 0;
  2080. }
  2081.  
  2082. /*
  2083. ===============
  2084. idAnimated::Event_AnimDone2
  2085. ===============
  2086. */
  2087. void idAnimated::Event_AnimDone2( int channel, int blend ) {
  2088.     if ( animDoneTime[channel] - FRAME2MS( blend ) <= gameLocal.time ) {
  2089.         idThread::ReturnInt( true );
  2090.     } else {
  2091.         idThread::ReturnInt( false );
  2092.     }
  2093. }
  2094.  
  2095. /*
  2096. ===============
  2097. idAnimated::Event_SetAnimState 
  2098. ===============
  2099. */
  2100. void idAnimated::Event_SetAnimState  ( const char* statename, int blend ) {
  2101.     const function_t *func;
  2102.  
  2103.     func = scriptObject.GetFunction( statename );
  2104.     if ( !func ) {
  2105.         gameLocal.Error( "Can't find function '%s' in object '%s'", statename, scriptObject.GetTypeName() );
  2106.     }
  2107.  
  2108.     idealState = statename;
  2109.     blendFrames = blend;
  2110.     scriptThread->DoneProcessing();
  2111. }
  2112.  
  2113. /*
  2114. ================
  2115. idAnimated::UpdateScript
  2116. ================
  2117. */
  2118. void idAnimated::UpdateScript( void ) {
  2119.     int    count;
  2120.  
  2121.     if ( !scriptThread || !gameLocal.isNewFrame  ) {
  2122.         return;
  2123.     }
  2124.  
  2125.     if ( idealState.Length() ) {
  2126.         SetState( idealState, blendFrames );
  2127.     }
  2128.     
  2129.     // If no state has been set then dont execute nothing
  2130.     if ( !state.Length ( ) || scriptThread->IsWaiting() ) {
  2131.         return;
  2132.     }
  2133.  
  2134.     // update script state
  2135.     count = 10;
  2136.     while( ( scriptThread->Execute() || idealState.Length() ) && count-- ) {
  2137.         if ( idealState.Length() ) {
  2138.             SetState( idealState, blendFrames );
  2139.         }
  2140.     }
  2141. }
  2142.  
  2143. /*
  2144. =====================
  2145. idAnimated::CallHandler
  2146. =====================
  2147. */
  2148. void idAnimated::CallHandler ( const char* handler ) {
  2149.     const function_t *func;
  2150.     func = scriptObject.GetFunction( handler );
  2151.     if ( !func ) {
  2152.         return;
  2153.     }
  2154.  
  2155.     scriptThread->CallFunction( this, func, false );
  2156.     scriptThread->Execute ( );
  2157. }
  2158.  
  2159. /*
  2160. =====================
  2161. idAnimated::SetState
  2162. =====================
  2163. */
  2164. void idAnimated::SetState( const char *statename, int frames ) {
  2165.     const function_t *func;
  2166.  
  2167.     func = scriptObject.GetFunction( statename );
  2168.     if ( !func ) {
  2169.         gameLocal.Error( "Can't find function '%s' in object '%s'", statename, scriptObject.GetTypeName() );
  2170.     }
  2171.  
  2172.     scriptThread->CallFunction( this, func, true );
  2173.     state = statename;
  2174.     blendFrames = frames;
  2175.     idealState = "";
  2176. }
  2177.  
  2178. // RAVEN END
  2179.  
  2180. /*
  2181. ===============================================================================
  2182.  
  2183.     idStaticEntity
  2184.  
  2185.     Some static entities may be optimized into inline geometry by dmap
  2186.  
  2187. ===============================================================================
  2188. */
  2189.  
  2190. CLASS_DECLARATION( idEntity, idStaticEntity )
  2191.     EVENT( EV_Activate,                idStaticEntity::Event_Activate )
  2192. END_CLASS
  2193.  
  2194. /*
  2195. ===============
  2196. idStaticEntity::idStaticEntity
  2197. ===============
  2198. */
  2199. idStaticEntity::idStaticEntity( void ) {
  2200.     spawnTime = 0;
  2201.     active = false;
  2202.     fadeFrom.Set( 1, 1, 1, 1 );
  2203.     fadeTo.Set( 1, 1, 1, 1 );
  2204.     fadeStart = 0;
  2205.     fadeEnd    = 0;
  2206.     runGui = false;
  2207. }
  2208.  
  2209. /*
  2210. ===============
  2211. idStaticEntity::Save
  2212. ===============
  2213. */
  2214. void idStaticEntity::Save( idSaveGame *savefile ) const {
  2215.     savefile->WriteInt( spawnTime );
  2216.     savefile->WriteBool( active );
  2217.     savefile->WriteVec4( fadeFrom );
  2218.     savefile->WriteVec4( fadeTo );
  2219.     savefile->WriteInt( fadeStart );
  2220.     savefile->WriteInt( fadeEnd );
  2221.     savefile->WriteBool( runGui );
  2222. }
  2223.  
  2224. /*
  2225. ===============
  2226. idStaticEntity::Restore
  2227. ===============
  2228. */
  2229. void idStaticEntity::Restore( idRestoreGame *savefile ) {
  2230.     savefile->ReadInt( spawnTime );
  2231.     savefile->ReadBool( active );
  2232.     savefile->ReadVec4( fadeFrom );
  2233.     savefile->ReadVec4( fadeTo );
  2234.     savefile->ReadInt( fadeStart );
  2235.     savefile->ReadInt( fadeEnd );
  2236.     savefile->ReadBool( runGui );
  2237. }
  2238.  
  2239. /*
  2240. ===============
  2241. idStaticEntity::Spawn
  2242. ===============
  2243. */
  2244. void idStaticEntity::Spawn( void ) {
  2245.     bool solid;
  2246.     bool hidden;
  2247.     bool keepContents;
  2248.  
  2249. // RAVEN BEGIN
  2250. // rjohnson: inline models can be solid, since the entities hang around anyway (don't know why it was done that way)
  2251.     solid = spawnArgs.GetBool( "solid" );
  2252.  
  2253.     // an inline static model will not do anything at all
  2254.     if ( spawnArgs.GetBool( "inline" ) || gameLocal.world->spawnArgs.GetBool( "inlineAllStatics" ) ) {
  2255.         Hide();
  2256.         if ( solid ) {
  2257.             GetPhysics()->SetContents( CONTENTS_SOLID );
  2258.         }
  2259.         return;
  2260.     }
  2261. // RAVEN END
  2262.  
  2263.     hidden = spawnArgs.GetBool( "hide" );
  2264.     keepContents = spawnArgs.GetBool( "KeepContents" );
  2265.  
  2266.     if ( keepContents ) {
  2267.         // do nothing, keep the contents from the model
  2268.     } else if ( solid && !hidden ) {
  2269.         GetPhysics()->SetContents( CONTENTS_SOLID );
  2270.     } else {
  2271.         GetPhysics()->SetContents( 0 );
  2272.     }
  2273.  
  2274.     spawnTime = gameLocal.time;
  2275.     active = false;
  2276.  
  2277.     idStr model = spawnArgs.GetString( "model" );
  2278.     // FIXME: temp also catch obsolete .ips extension
  2279.     if ( model.Find( ".ips" ) >= 0 || model.Find( ".prt" ) >= 0 ) {
  2280.         // we want the parametric particles out of sync with each other
  2281.         renderEntity.shaderParms[ SHADERPARM_TIMEOFFSET ] = gameLocal.random.RandomInt( 32767 );
  2282.     }
  2283.  
  2284.     fadeFrom.Set( 1, 1, 1, 1 );
  2285.     fadeTo.Set( 1, 1, 1, 1 );
  2286.     fadeStart = 0;
  2287.     fadeEnd    = 0;
  2288.  
  2289.     // NOTE: this should be used very rarely because it is expensive
  2290.     runGui = spawnArgs.GetBool( "runGui" );
  2291.     if ( runGui ) {
  2292.         BecomeActive( TH_THINK );
  2293.     }
  2294. }
  2295.  
  2296. /*
  2297. ================
  2298. idStaticEntity::ShowEditingDialog
  2299. ================
  2300. */
  2301. void idStaticEntity::ShowEditingDialog( void ) {
  2302. // RAVEN BEGIN
  2303. // bdube: not using
  2304. //    common->InitTool( EDITOR_PARTICLE, &spawnArgs );
  2305. // RAVEN END
  2306. }
  2307. /*
  2308. ================
  2309. idStaticEntity::Think
  2310. ================
  2311. */
  2312. void idStaticEntity::Think( void ) {
  2313.     idEntity::Think();
  2314.     if ( thinkFlags & TH_THINK ) {
  2315.         if ( runGui && renderEntity.gui[0] ) {
  2316.             idPlayer *player = gameLocal.GetLocalPlayer();
  2317.             if ( player ) {
  2318.                 if ( !player->objectiveSystemOpen ) {
  2319.                     for( int i = 0; i < MAX_RENDERENTITY_GUI; i++ ) {
  2320.                         if ( renderEntity.gui[ i ] ) {
  2321.                             renderEntity.gui[ i ]->StateChanged( gameLocal.time, true );
  2322.                         }
  2323.                     }
  2324.                 }
  2325.             }
  2326.         }
  2327.         if ( fadeEnd > 0 ) {
  2328.             idVec4 color;
  2329.             if ( gameLocal.time < fadeEnd ) {
  2330.                 color.Lerp( fadeFrom, fadeTo, ( float )( gameLocal.time - fadeStart ) / ( float )( fadeEnd - fadeStart ) );
  2331.             } else {
  2332.                 color = fadeTo;
  2333.                 fadeEnd = 0;
  2334.                 BecomeInactive( TH_THINK );
  2335.             }
  2336.             SetColor( color );
  2337.         }
  2338.     }
  2339. }
  2340.  
  2341. /*
  2342. ================
  2343. idStaticEntity::Fade
  2344. ================
  2345. */
  2346. void idStaticEntity::Fade( const idVec4 &to, float fadeTime ) {
  2347.     GetColor( fadeFrom );
  2348.     fadeTo = to;
  2349.     fadeStart = gameLocal.time;
  2350.     fadeEnd = gameLocal.time + SEC2MS( fadeTime );
  2351.     BecomeActive( TH_THINK );
  2352. }
  2353.  
  2354. /*
  2355. ================
  2356. idStaticEntity::Hide
  2357. ================
  2358. */
  2359. void idStaticEntity::Hide( void ) {
  2360.     idEntity::Hide();
  2361.     GetPhysics()->SetContents( 0 );
  2362. }
  2363.  
  2364. /*
  2365. ================
  2366. idStaticEntity::Show
  2367. ================
  2368. */
  2369. void idStaticEntity::Show( void ) {
  2370.     idEntity::Show();
  2371.     if ( spawnArgs.GetBool( "solid" ) ) {
  2372.         GetPhysics()->SetContents( CONTENTS_SOLID );
  2373.     }
  2374. }
  2375.  
  2376. /*
  2377. ================
  2378. idStaticEntity::Event_Activate
  2379. ================
  2380. */
  2381. void idStaticEntity::Event_Activate( idEntity *activator ) {
  2382.     idStr activateGui;
  2383.  
  2384.     spawnTime = gameLocal.time;
  2385.     active = !active;
  2386.  
  2387.     const idKeyValue *kv = spawnArgs.FindKey( "hide" );
  2388.     if ( kv ) {
  2389.         if ( IsHidden() ) {
  2390.             Show();
  2391.         } else {
  2392.             Hide();
  2393.         }
  2394.     }
  2395.  
  2396.     renderEntity.shaderParms[ SHADERPARM_TIMEOFFSET ] = -MS2SEC( spawnTime );
  2397.     renderEntity.shaderParms[5] = active;
  2398.     // this change should be a good thing, it will automatically turn on 
  2399.     // lights etc.. when triggered so that does not have to be specifically done
  2400.     // with trigger parms.. it MIGHT break things so need to keep an eye on it
  2401.     renderEntity.shaderParms[ SHADERPARM_MODE ] = ( renderEntity.shaderParms[ SHADERPARM_MODE ] ) ?  0.0f : 1.0f;
  2402.     BecomeActive( TH_UPDATEVISUALS );
  2403. }
  2404.  
  2405. /*
  2406. ================
  2407. idStaticEntity::WriteToSnapshot
  2408. ================
  2409. */
  2410. void idStaticEntity::WriteToSnapshot( idBitMsgDelta &msg ) const {
  2411.     GetPhysics()->WriteToSnapshot( msg );
  2412.     WriteBindToSnapshot( msg );
  2413.     WriteColorToSnapshot( msg );
  2414.     WriteGUIToSnapshot( msg );
  2415.     msg.WriteBits( IsHidden()?1:0, 1 );
  2416. }
  2417.  
  2418. /*
  2419. ================
  2420. idStaticEntity::ReadFromSnapshot
  2421. ================
  2422. */
  2423. void idStaticEntity::ReadFromSnapshot( const idBitMsgDelta &msg ) {
  2424.     bool hidden;
  2425.  
  2426.     GetPhysics()->ReadFromSnapshot( msg );
  2427.     ReadBindFromSnapshot( msg );
  2428.     ReadColorFromSnapshot( msg );
  2429.     ReadGUIFromSnapshot( msg );
  2430.     hidden = msg.ReadBits( 1 ) == 1;
  2431.     if ( hidden != IsHidden() ) {
  2432.         if ( hidden ) {
  2433.             Hide();
  2434.         } else {
  2435.             Show();
  2436.         }
  2437.     }
  2438.     if ( msg.HasChanged() ) {
  2439.         UpdateVisuals();
  2440.     }
  2441. }
  2442.  
  2443.  
  2444. /*
  2445. ===============================================================================
  2446.  
  2447. idFuncEmitter
  2448.  
  2449. ===============================================================================
  2450. */
  2451.  
  2452.  
  2453. CLASS_DECLARATION( idStaticEntity, idFuncEmitter )
  2454. EVENT( EV_Activate,                idFuncEmitter::Event_Activate )
  2455. END_CLASS
  2456.  
  2457. /*
  2458. ===============
  2459. idFuncEmitter::idFuncEmitter
  2460. ===============
  2461. */
  2462. idFuncEmitter::idFuncEmitter( void ) {
  2463.     hidden = false;
  2464. }
  2465.  
  2466. /*
  2467. ===============
  2468. idFuncEmitter::Spawn
  2469. ===============
  2470. */
  2471. void idFuncEmitter::Spawn( void ) {
  2472.     if ( spawnArgs.GetBool( "start_off" ) ) {
  2473.         hidden = true;
  2474.         renderEntity.shaderParms[SHADERPARM_PARTICLE_STOPTIME] = MS2SEC( 1 );
  2475.         UpdateVisuals();
  2476.     } else {
  2477.         hidden = false;
  2478.     }
  2479. }
  2480.  
  2481. /*
  2482. ===============
  2483. idFuncEmitter::Save
  2484. ===============
  2485. */
  2486. void idFuncEmitter::Save( idSaveGame *savefile ) const {
  2487.     savefile->WriteBool( hidden );
  2488. }
  2489.  
  2490. /*
  2491. ===============
  2492. idFuncEmitter::Restore
  2493. ===============
  2494. */
  2495. void idFuncEmitter::Restore( idRestoreGame *savefile ) {
  2496.     savefile->ReadBool( hidden );
  2497. }
  2498.  
  2499. /*
  2500. ================
  2501. idFuncEmitter::Event_Activate
  2502. ================
  2503. */
  2504. void idFuncEmitter::Event_Activate( idEntity *activator ) {
  2505.     if ( hidden || spawnArgs.GetBool( "cycleTrigger" ) ) {
  2506.         renderEntity.shaderParms[SHADERPARM_PARTICLE_STOPTIME] = 0;
  2507.         renderEntity.shaderParms[SHADERPARM_TIMEOFFSET] = -MS2SEC( gameLocal.time );
  2508.         hidden = false;
  2509.     } else {
  2510.         renderEntity.shaderParms[SHADERPARM_PARTICLE_STOPTIME] = MS2SEC( gameLocal.time );
  2511.         hidden = true;
  2512.     }
  2513.     UpdateVisuals();
  2514. }
  2515.  
  2516. /*
  2517. ================
  2518. idFuncEmitter::WriteToSnapshot
  2519. ================
  2520. */
  2521. void idFuncEmitter::WriteToSnapshot( idBitMsgDelta &msg ) const {
  2522.     msg.WriteBits( hidden ? 1 : 0, 1 );
  2523.     msg.WriteFloat( renderEntity.shaderParms[ SHADERPARM_PARTICLE_STOPTIME ] );
  2524.     msg.WriteFloat( renderEntity.shaderParms[ SHADERPARM_TIMEOFFSET ] );
  2525. }
  2526.  
  2527. /*
  2528. ================
  2529. idFuncEmitter::ReadFromSnapshot
  2530. ================
  2531. */
  2532. void idFuncEmitter::ReadFromSnapshot( const idBitMsgDelta &msg ) {
  2533.     hidden = msg.ReadBits( 1 ) != 0;
  2534.     renderEntity.shaderParms[ SHADERPARM_PARTICLE_STOPTIME ] = msg.ReadFloat();
  2535.     renderEntity.shaderParms[ SHADERPARM_TIMEOFFSET ] = msg.ReadFloat();
  2536.     if ( msg.HasChanged() ) {
  2537.         UpdateVisuals();
  2538.     }
  2539. }
  2540.  
  2541.  
  2542. /*
  2543. ===============================================================================
  2544.  
  2545. idFuncSplat
  2546.  
  2547. ===============================================================================
  2548. */
  2549.  
  2550.  
  2551. const idEventDef EV_Splat( "<Splat>" );
  2552. CLASS_DECLARATION( idFuncEmitter, idFuncSplat )
  2553. EVENT( EV_Activate,        idFuncSplat::Event_Activate )
  2554. EVENT( EV_Splat,        idFuncSplat::Event_Splat )
  2555. END_CLASS
  2556.  
  2557. /*
  2558. ===============
  2559. idFuncSplat::idFuncSplat
  2560. ===============
  2561. */
  2562. idFuncSplat::idFuncSplat( void ) {
  2563. }
  2564.  
  2565. /*
  2566. ===============
  2567. idFuncSplat::Spawn
  2568. ===============
  2569. */
  2570. void idFuncSplat::Spawn( void ) {
  2571. }
  2572.  
  2573. /*
  2574. ================
  2575. idFuncSplat::Event_Splat
  2576. ================
  2577. */
  2578. void idFuncSplat::Event_Splat( void ) {
  2579.     const char *splat = NULL;
  2580.     int count = spawnArgs.GetInt( "splatCount", "1" );
  2581.     for ( int i = 0; i < count; i++ ) {
  2582.         splat = spawnArgs.RandomPrefix( "mtr_splat", gameLocal.random );
  2583.         if ( splat && *splat ) {
  2584.             float size = spawnArgs.GetFloat( "splatSize", "128" );
  2585.             float dist = spawnArgs.GetFloat( "splatDistance", "128" );
  2586.             float angle = spawnArgs.GetFloat( "splatAngle", "0" );
  2587.             gameLocal.ProjectDecal( GetPhysics()->GetOrigin(), GetPhysics()->GetAxis()[2], dist, true, size, splat, angle );
  2588.         }
  2589.     }
  2590.     StartSound( "snd_splat", SND_CHANNEL_ANY, 0, false, NULL );
  2591. }
  2592.  
  2593. /*
  2594. ================
  2595. idFuncSplat::Event_Activate
  2596. ================
  2597. */
  2598. void idFuncSplat::Event_Activate( idEntity *activator ) {
  2599.     idFuncEmitter::Event_Activate( activator );
  2600.     PostEventSec( &EV_Splat, spawnArgs.GetFloat( "splatDelay", "0.25" ) );
  2601.     StartSound( "snd_spurt", SND_CHANNEL_ANY, 0, false, NULL );
  2602. }
  2603.  
  2604. /*
  2605. ===============================================================================
  2606.  
  2607.     idTextEntity
  2608.  
  2609. ===============================================================================
  2610. */
  2611.  
  2612. CLASS_DECLARATION( idEntity, idTextEntity )
  2613. END_CLASS
  2614.  
  2615. /*
  2616. ================
  2617. idTextEntity::Spawn
  2618. ================
  2619. */
  2620. void idTextEntity::Spawn( void ) {
  2621.     // these are cached as the are used each frame
  2622.     text = spawnArgs.GetString( "text" );
  2623.     playerOriented = spawnArgs.GetBool( "playerOriented" );
  2624.     bool force = spawnArgs.GetBool( "force" );
  2625.     if ( developer.GetBool() || force ) {
  2626.         BecomeActive(TH_THINK);
  2627.     }
  2628. }
  2629.  
  2630. /*
  2631. ================
  2632. idTextEntity::Save
  2633. ================
  2634. */
  2635. void idTextEntity::Save( idSaveGame *savefile ) const {
  2636.     savefile->WriteString( text );
  2637.     savefile->WriteBool( playerOriented );
  2638. }
  2639.  
  2640. /*
  2641. ================
  2642. idTextEntity::Restore
  2643. ================
  2644. */
  2645. void idTextEntity::Restore( idRestoreGame *savefile ) {
  2646.     savefile->ReadString( text );
  2647.     savefile->ReadBool( playerOriented );
  2648. }
  2649.  
  2650. /*
  2651. ================
  2652. idTextEntity::Think
  2653. ================
  2654. */
  2655. void idTextEntity::Think( void ) {
  2656.     if ( thinkFlags & TH_THINK ) {
  2657.         gameRenderWorld->DrawText( text, GetPhysics()->GetOrigin(), 0.25, colorWhite, playerOriented ? gameLocal.GetLocalPlayer()->viewAngles.ToMat3() : GetPhysics()->GetAxis().Transpose(), 1 );
  2658.         for ( int i = 0; i < targets.Num(); i++ ) {
  2659.             if ( targets[i].GetEntity() ) {
  2660.                 gameRenderWorld->DebugArrow( colorBlue, GetPhysics()->GetOrigin(), targets[i].GetEntity()->GetPhysics()->GetOrigin(), 1 );
  2661.             }
  2662.         }
  2663.     } else {
  2664.         BecomeInactive( TH_ALL );
  2665.     }
  2666. }
  2667.  
  2668. /*
  2669. ================
  2670. idTextEntity::Think
  2671. ================
  2672. */
  2673. void idTextEntity::ClientPredictionThink( void ) {
  2674.     if ( thinkFlags & TH_THINK ) {
  2675.         gameRenderWorld->DrawText( text, GetPhysics()->GetOrigin(), 0.25, colorWhite, playerOriented ? gameLocal.GetLocalPlayer()->viewAngles.ToMat3() : GetPhysics()->GetAxis().Transpose(), 1 );
  2676.         for ( int i = 0; i < targets.Num(); i++ ) {
  2677.             if ( targets[i].GetEntity() ) {
  2678.                 gameRenderWorld->DebugArrow( colorBlue, GetPhysics()->GetOrigin(), targets[i].GetEntity()->GetPhysics()->GetOrigin(), 1 );
  2679.             }
  2680.         }
  2681.     } else {
  2682.         BecomeInactive( TH_ALL );
  2683.     }
  2684. }
  2685.  
  2686.  
  2687.  
  2688. /*
  2689. ===============================================================================
  2690.  
  2691.     idVacuumSeperatorEntity
  2692.  
  2693.     Can be triggered to let vacuum through a portal (blown out window)
  2694.  
  2695. ===============================================================================
  2696. */
  2697.  
  2698. CLASS_DECLARATION( idEntity, idVacuumSeparatorEntity )
  2699.     EVENT( EV_Activate,        idVacuumSeparatorEntity::Event_Activate )
  2700. END_CLASS
  2701.  
  2702.  
  2703. /*
  2704. ================
  2705. idVacuumSeparatorEntity::idVacuumSeparatorEntity
  2706. ================
  2707. */
  2708. idVacuumSeparatorEntity::idVacuumSeparatorEntity( void ) {
  2709.     portal = 0;
  2710. }
  2711.  
  2712. /*
  2713. ================
  2714. idVacuumSeparatorEntity::Save
  2715. ================
  2716. */
  2717. void idVacuumSeparatorEntity::Save( idSaveGame *savefile ) const {
  2718.     savefile->WriteInt( (int)portal );
  2719.     savefile->WriteInt( gameRenderWorld->GetPortalState( portal ) );
  2720. }
  2721.  
  2722. /*
  2723. ================
  2724. idVacuumSeparatorEntity::Restore
  2725. ================
  2726. */
  2727. void idVacuumSeparatorEntity::Restore( idRestoreGame *savefile ) {
  2728.     int state;
  2729.  
  2730.     savefile->ReadInt( (int &)portal );
  2731.     savefile->ReadInt( state );
  2732.  
  2733.     gameLocal.SetPortalState( portal, state );
  2734. }
  2735.  
  2736. /*
  2737. ================
  2738. idVacuumSeparatorEntity::Spawn
  2739. ================
  2740. */
  2741. void idVacuumSeparatorEntity::Spawn() {
  2742.     idBounds b;
  2743.  
  2744.     b = idBounds( spawnArgs.GetVector( "origin" ) ).Expand( 16 );
  2745.     portal = gameRenderWorld->FindPortal( b );
  2746.     if ( !portal ) {
  2747.         gameLocal.Warning( "VacuumSeparator '%s' didn't contact a portal", spawnArgs.GetString( "name" ) );
  2748.         return;
  2749.     }
  2750.     gameLocal.SetPortalState( portal, PS_BLOCK_AIR | PS_BLOCK_LOCATION );
  2751. }
  2752.  
  2753. /*
  2754. ================
  2755. idVacuumSeparatorEntity::Event_Activate
  2756. ================
  2757. */
  2758. void idVacuumSeparatorEntity::Event_Activate( idEntity *activator ) {
  2759.     if ( !portal ) {
  2760.         return;
  2761.     }
  2762.     gameLocal.SetPortalState( portal, PS_BLOCK_NONE );
  2763. }
  2764.  
  2765.  
  2766. /*
  2767. ===============================================================================
  2768.  
  2769. idLocationSeparatorEntity
  2770.  
  2771. ===============================================================================
  2772. */
  2773.  
  2774. CLASS_DECLARATION( idEntity, idLocationSeparatorEntity )
  2775. END_CLASS
  2776.  
  2777. /*
  2778. ================
  2779. idLocationSeparatorEntity::Spawn
  2780. ================
  2781. */
  2782. void idLocationSeparatorEntity::Spawn() {
  2783.     idBounds b;
  2784.  
  2785.     b = idBounds( spawnArgs.GetVector( "origin" ) ).Expand( 16 );
  2786.     qhandle_t portal = gameRenderWorld->FindPortal( b );
  2787.     if ( !portal ) {
  2788.         gameLocal.Warning( "LocationSeparator '%s' didn't contact a portal", spawnArgs.GetString( "name" ) );
  2789.     }
  2790.     gameLocal.SetPortalState( portal, PS_BLOCK_LOCATION );
  2791. }
  2792.  
  2793.  
  2794. /*
  2795. ===============================================================================
  2796.  
  2797.     idVacuumEntity
  2798.  
  2799.     Levels should only have a single vacuum entity.
  2800.  
  2801. ===============================================================================
  2802. */
  2803.  
  2804. CLASS_DECLARATION( idEntity, idVacuumEntity )
  2805. END_CLASS
  2806.  
  2807. /*
  2808. ================
  2809. idVacuumEntity::Spawn
  2810. ================
  2811. */
  2812. void idVacuumEntity::Spawn() {
  2813.     if ( gameLocal.vacuumAreaNum != -1 ) {
  2814.         gameLocal.Warning( "idVacuumEntity::Spawn: multiple idVacuumEntity in level" );
  2815.         return;
  2816.     }
  2817.  
  2818.     idVec3 org = spawnArgs.GetVector( "origin" );
  2819.  
  2820.     gameLocal.vacuumAreaNum = gameRenderWorld->PointInArea( org );
  2821. }
  2822.  
  2823. // RAVEN BEGIN
  2824. // abahr:
  2825. /*
  2826. ===============================================================================
  2827.  
  2828.     rvGravitySeparatorEntity
  2829.  
  2830. ===============================================================================
  2831. */
  2832.  
  2833. CLASS_DECLARATION( idEntity, rvGravitySeparatorEntity )
  2834.     EVENT( EV_Activate,        rvGravitySeparatorEntity::Event_Activate )
  2835. END_CLASS
  2836.  
  2837.  
  2838. /*
  2839. ================
  2840. rvGravitySeparatorEntity::idVacuumSeparatorEntity
  2841. ================
  2842. */
  2843. rvGravitySeparatorEntity::rvGravitySeparatorEntity( void ) {
  2844.     portal = 0;
  2845. }
  2846.  
  2847. /*
  2848. ================
  2849. rvGravitySeparatorEntity::Save
  2850. ================
  2851. */
  2852. void rvGravitySeparatorEntity::Save( idSaveGame *savefile ) const {
  2853.     savefile->WriteInt( (int)portal );
  2854.     savefile->WriteInt( gameRenderWorld->GetPortalState( portal ) );
  2855. }
  2856.  
  2857. /*
  2858. ================
  2859. rvGravitySeparatorEntity::Restore
  2860. ================
  2861. */
  2862. void rvGravitySeparatorEntity::Restore( idRestoreGame *savefile ) {
  2863.     int state;
  2864.  
  2865.     savefile->ReadInt( (int &)portal );
  2866.     savefile->ReadInt( state );
  2867.  
  2868.     gameLocal.SetPortalState( portal, state );
  2869. }
  2870.  
  2871. /*
  2872. ================
  2873. rvGravitySeparatorEntity::Spawn
  2874. ================
  2875. */
  2876. void rvGravitySeparatorEntity::Spawn() {
  2877.     idBounds b;
  2878.  
  2879.     b = idBounds( spawnArgs.GetVector( "origin" ) ).Expand( 16 );
  2880.     portal = gameRenderWorld->FindPortal( b );
  2881.     if ( !portal ) {
  2882.         gameLocal.Warning( "GravitySeparator '%s' didn't contact a portal", spawnArgs.GetString( "name" ) );
  2883.         return;
  2884.     }
  2885.     gameLocal.SetPortalState( portal, gameRenderWorld->GetPortalState(portal) | PS_BLOCK_GRAVITY );
  2886. }
  2887.  
  2888. /*
  2889. ================
  2890. rvGravitySeparatorEntity::Event_Activate
  2891. ================
  2892. */
  2893. void rvGravitySeparatorEntity::Event_Activate( idEntity *activator ) {
  2894.     if ( !portal ) {
  2895.         return;
  2896.     }
  2897.  
  2898.     int portalState = gameRenderWorld->GetPortalState( portal );
  2899.     gameLocal.SetPortalState( portal, (portalState & PS_BLOCK_GRAVITY) > 0 ? (portalState & ~PS_BLOCK_GRAVITY) : portalState | PS_BLOCK_GRAVITY );
  2900. }
  2901.  
  2902. /*
  2903. ===============================================================================
  2904.  
  2905.     rvGravityEntity
  2906.  
  2907. ===============================================================================
  2908. */
  2909. ABSTRACT_DECLARATION( idEntity, rvGravityArea )
  2910. END_CLASS
  2911.  
  2912. /*
  2913. ================
  2914. rvGravityArea::Spawn
  2915. ================
  2916. */
  2917. void rvGravityArea::Spawn() {
  2918.     area = gameRenderWorld->PointInArea( spawnArgs.GetVector("origin") );
  2919.     gameLocal.AddUniqueGravityInfo( this );
  2920. }
  2921.  
  2922. /*
  2923. ================
  2924. rvGravityArea::Save
  2925. ================
  2926. */
  2927. void rvGravityArea::Save( idSaveGame *savefile ) const {
  2928.     savefile->WriteInt( area );
  2929. }
  2930.  
  2931. /*
  2932. ================
  2933. rvGravityArea::Restore
  2934. ================
  2935. */
  2936. void rvGravityArea::Restore( idRestoreGame *savefile ) {
  2937.     savefile->ReadInt( area );
  2938. }
  2939.  
  2940. /*
  2941. ================
  2942. rvGravityArea::IsEqualTo
  2943. ================
  2944. */
  2945. bool rvGravityArea::IsEqualTo( const rvGravityArea* area ) const {
  2946.     assert( area );
  2947.     return !idStr::Icmp( GetName(), area->GetName() );
  2948. }
  2949.  
  2950. /*
  2951. ================
  2952. rvGravityArea::operator==
  2953. ================
  2954. */
  2955. bool rvGravityArea::operator==( const rvGravityArea* area ) const {
  2956.     return IsEqualTo( area );
  2957. }
  2958.  
  2959. /*
  2960. ================
  2961. rvGravityArea::operator==
  2962. ================
  2963. */
  2964. bool rvGravityArea::operator==( const rvGravityArea& area ) const {
  2965.     return IsEqualTo( &area );
  2966. }
  2967.  
  2968. /*
  2969. ================
  2970. rvGravityArea::operator!=
  2971. ================
  2972. */
  2973. bool rvGravityArea::operator!=( const rvGravityArea* area ) const {
  2974.     return !IsEqualTo( area );
  2975. }
  2976.  
  2977. /*
  2978. ================
  2979. rvGravityArea::operator!=
  2980. ================
  2981. */
  2982. bool rvGravityArea::operator!=( const rvGravityArea& area ) const {
  2983.     return !IsEqualTo( &area );
  2984. }
  2985.  
  2986. /*
  2987. ===============================================================================
  2988.  
  2989.     rvGravityEntity_Static
  2990.  
  2991. ===============================================================================
  2992. */
  2993. CLASS_DECLARATION( rvGravityArea, rvGravityArea_Static )
  2994. END_CLASS
  2995.  
  2996. /*
  2997. ================
  2998. rvGravityArea_Static::Spawn
  2999. ================
  3000. */
  3001. void rvGravityArea_Static::Spawn() {
  3002.     gravity = spawnArgs.GetVector( "gravity" );// * gameLocal.GetGravity().Length();
  3003. }
  3004.  
  3005. /*
  3006. ================
  3007. rvGravityArea_Static::Save
  3008. ================
  3009. */
  3010. void rvGravityArea_Static::Save( idSaveGame *savefile ) const {
  3011.     savefile->WriteVec3( gravity );
  3012. }
  3013.  
  3014. /*
  3015. ================
  3016. rvGravityArea_Static::Restore
  3017. ================
  3018. */
  3019. void rvGravityArea_Static::Restore( idRestoreGame *savefile ) {
  3020.     savefile->ReadVec3( gravity );
  3021. }
  3022.  
  3023. /*
  3024. ===============================================================================
  3025.  
  3026.     rvGravityArea_SurfaceNormal
  3027.  
  3028. ===============================================================================
  3029. */
  3030. CLASS_DECLARATION( rvGravityArea, rvGravityArea_SurfaceNormal )
  3031. END_CLASS
  3032.  
  3033. /*
  3034. ================
  3035. rvGravityArea_SurfaceNormal::GetGravity
  3036. ================
  3037. */
  3038. const idVec3 rvGravityArea_SurfaceNormal::GetGravity( const idVec3& origin, const idMat3& axis, int clipMask, idEntity* passEntity ) const {
  3039.     trace_t results;
  3040.  
  3041. // RAVEN BEGIN
  3042. // ddynerman: multiple clip worlds
  3043.     if( !gameLocal.TracePoint( this, results, origin, origin + -axis[2] * 50.0f, clipMask, passEntity ) ) {
  3044. // RAVEN END
  3045.         return gameLocal.GetGravity();
  3046.     }
  3047.  
  3048.     return -results.c.normal * gameLocal.GetGravity().Length();
  3049. }
  3050.  
  3051. /*
  3052. ================
  3053. rvGravityArea_SurfaceNormal::GetGravity
  3054. ================
  3055. */
  3056. const idVec3 rvGravityArea_SurfaceNormal::GetGravity( const idEntity* ent ) const {
  3057.     return GetGravity( ent->GetPhysics() );
  3058. }
  3059.  
  3060. /*
  3061. ================
  3062. rvGravityArea_SurfaceNormal::GetGravity
  3063. ================
  3064. */
  3065. const idVec3 rvGravityArea_SurfaceNormal::GetGravity( const rvClientEntity* ent ) const {
  3066.     return GetGravity( ent->GetPhysics() );
  3067. }
  3068.  
  3069. /*
  3070. ================
  3071. rvGravityArea_SurfaceNormal::GetGravity
  3072. ================
  3073. */
  3074. const idVec3 rvGravityArea_SurfaceNormal::GetGravity( const idPhysics* physics ) const {
  3075.     return GetGravity( physics->GetOrigin(), physics->GetAxis(), physics->GetClipMask(), physics->GetSelf() );
  3076. }
  3077. // RAVEN END
  3078.  
  3079.  
  3080. /*
  3081. ===============================================================================
  3082.  
  3083. idLocationEntity
  3084.  
  3085. ===============================================================================
  3086. */
  3087.  
  3088. CLASS_DECLARATION( idEntity, idLocationEntity )
  3089. END_CLASS
  3090.  
  3091. /*
  3092. ======================
  3093. idLocationEntity::Spawn
  3094. ======================
  3095. */
  3096. void idLocationEntity::Spawn() {
  3097.     idStr realName;
  3098.  
  3099.     // this just holds dict information
  3100.  
  3101.     // if "location" not already set, use the entity name.
  3102.     if ( !spawnArgs.GetString( "location", "", realName ) ) {
  3103.         spawnArgs.Set( "location", name );
  3104.     }
  3105. }
  3106.  
  3107. /*
  3108. ======================
  3109. idLocationEntity::GetLocation
  3110. ======================
  3111. */
  3112. const char *idLocationEntity::GetLocation( void ) const {
  3113.     return spawnArgs.GetString( "location" );
  3114. }
  3115.  
  3116. /*
  3117. ===============================================================================
  3118.  
  3119.     idBeam
  3120.  
  3121. ===============================================================================
  3122. */
  3123.  
  3124. CLASS_DECLARATION( idEntity, idBeam )
  3125.     EVENT( EV_PostSpawn,            idBeam::Event_MatchTarget )
  3126.     EVENT( EV_Activate,                idBeam::Event_Activate )
  3127. END_CLASS
  3128.  
  3129. /*
  3130. ===============
  3131. idBeam::idBeam
  3132. ===============
  3133. */
  3134. idBeam::idBeam() {
  3135.     target = NULL;
  3136.     master = NULL;
  3137. }
  3138.  
  3139. /*
  3140. ===============
  3141. idBeam::Save
  3142. ===============
  3143. */
  3144. void idBeam::Save( idSaveGame *savefile ) const {
  3145.     target.Save( savefile );
  3146.     master.Save( savefile );
  3147. }
  3148.  
  3149. /*
  3150. ===============
  3151. idBeam::Restore
  3152. ===============
  3153. */
  3154. void idBeam::Restore( idRestoreGame *savefile ) {
  3155.     target.Restore( savefile );
  3156.     master.Restore( savefile );
  3157. }
  3158.  
  3159. /*
  3160. ===============
  3161. idBeam::Spawn
  3162. ===============
  3163. */
  3164. void idBeam::Spawn( void ) {
  3165.     float width;
  3166.  
  3167.     if ( spawnArgs.GetFloat( "width", "0", width ) ) {
  3168.         renderEntity.shaderParms[ SHADERPARM_BEAM_WIDTH ] = width;
  3169.     }
  3170.  
  3171.     SetModel( "_BEAM" );
  3172.     Hide();
  3173.     PostEventMS( &EV_PostSpawn, 0 );
  3174. }
  3175.  
  3176. /*
  3177. ================
  3178. idBeam::Think
  3179. ================
  3180. */
  3181. void idBeam::Think( void ) {
  3182.     idBeam *masterEnt;
  3183.  
  3184.     if ( !IsHidden() && !target.GetEntity() ) {
  3185.         // hide if our target is removed
  3186.         Hide();
  3187.     }
  3188.  
  3189.     RunPhysics();
  3190.  
  3191.     masterEnt = master.GetEntity();
  3192.     if ( masterEnt ) {
  3193.         const idVec3 &origin = GetPhysics()->GetOrigin();
  3194.         masterEnt->SetBeamTarget( origin );
  3195.     }
  3196.     Present();
  3197. }
  3198.  
  3199. /*
  3200. ================
  3201. idBeam::SetMaster
  3202. ================
  3203. */
  3204. void idBeam::SetMaster( idBeam *masterbeam ) {
  3205.     master = masterbeam;
  3206. }
  3207. /*
  3208. ================
  3209. idBeam::SetBeamTarget
  3210. ================
  3211. */
  3212. void idBeam::SetBeamTarget( const idVec3 &origin ) {
  3213.     if ( ( renderEntity.shaderParms[ SHADERPARM_BEAM_END_X ] != origin.x ) || ( renderEntity.shaderParms[ SHADERPARM_BEAM_END_Y ] != origin.y ) || ( renderEntity.shaderParms[ SHADERPARM_BEAM_END_Z ] != origin.z ) ) {
  3214.         renderEntity.shaderParms[ SHADERPARM_BEAM_END_X ] = origin.x;
  3215.         renderEntity.shaderParms[ SHADERPARM_BEAM_END_Y ] = origin.y;
  3216.         renderEntity.shaderParms[ SHADERPARM_BEAM_END_Z ] = origin.z;
  3217.         UpdateVisuals();
  3218.     }
  3219. }
  3220.  
  3221. /*
  3222. ================
  3223. idBeam::Show
  3224. ================
  3225. */
  3226. void idBeam::Show( void ) {
  3227.     idBeam *targetEnt;
  3228.  
  3229.     idEntity::Show();
  3230.  
  3231.     targetEnt = target.GetEntity();
  3232.     if ( targetEnt ) {
  3233.         const idVec3 &origin = targetEnt->GetPhysics()->GetOrigin();
  3234.         SetBeamTarget( origin );
  3235.     }
  3236. }
  3237.  
  3238. /*
  3239. ================
  3240. idBeam::Event_MatchTarget
  3241. ================
  3242. */
  3243. void idBeam::Event_MatchTarget( void ) {
  3244.     int i;
  3245.     idEntity *targetEnt;
  3246.     idBeam *targetBeam;
  3247.  
  3248.     if ( !targets.Num() ) {
  3249.         return;
  3250.     }
  3251.  
  3252.     targetBeam = NULL;
  3253.     for( i = 0; i < targets.Num(); i++ ) {
  3254.         targetEnt = targets[ i ].GetEntity();
  3255.         if ( targetEnt && targetEnt->IsType( idBeam::Type ) ) {
  3256.             targetBeam = static_cast<idBeam *>( targetEnt );
  3257.             break;
  3258.         }
  3259.     }
  3260.  
  3261.     if ( !targetBeam ) {
  3262.         gameLocal.Error( "Could not find valid beam target for '%s'", name.c_str() );
  3263.     }
  3264.  
  3265.     target = targetBeam;
  3266.     targetBeam->SetMaster( this );
  3267.     if ( !spawnArgs.GetBool( "start_off" ) ) {
  3268.         Show();
  3269.     }
  3270. }
  3271.  
  3272. /*
  3273. ================
  3274. idBeam::Event_Activate
  3275. ================
  3276. */
  3277. void idBeam::Event_Activate( idEntity *activator ) {
  3278.     if ( IsHidden() ) {
  3279.         Show();
  3280.     } else {
  3281.         Hide();        
  3282.     }
  3283. }
  3284.  
  3285. /*
  3286. ================
  3287. idBeam::WriteToSnapshot
  3288. ================
  3289. */
  3290. void idBeam::WriteToSnapshot( idBitMsgDelta &msg ) const {
  3291.     GetPhysics()->WriteToSnapshot( msg );
  3292.     WriteBindToSnapshot( msg );
  3293.     WriteColorToSnapshot( msg );
  3294.     msg.WriteFloat( renderEntity.shaderParms[SHADERPARM_BEAM_END_X] );
  3295.     msg.WriteFloat( renderEntity.shaderParms[SHADERPARM_BEAM_END_Y] );
  3296.     msg.WriteFloat( renderEntity.shaderParms[SHADERPARM_BEAM_END_Z] );
  3297. }
  3298.  
  3299. /*
  3300. ================
  3301. idBeam::ReadFromSnapshot
  3302. ================
  3303. */
  3304. void idBeam::ReadFromSnapshot( const idBitMsgDelta &msg ) {
  3305.     GetPhysics()->ReadFromSnapshot( msg );
  3306.     ReadBindFromSnapshot( msg );
  3307.     ReadColorFromSnapshot( msg );
  3308.     renderEntity.shaderParms[SHADERPARM_BEAM_END_X] = msg.ReadFloat();
  3309.     renderEntity.shaderParms[SHADERPARM_BEAM_END_Y] = msg.ReadFloat();
  3310.     renderEntity.shaderParms[SHADERPARM_BEAM_END_Z] = msg.ReadFloat();
  3311.     if ( msg.HasChanged() ) {
  3312.         UpdateVisuals();
  3313.     }
  3314. }
  3315.  
  3316.  
  3317. /*
  3318. ===============================================================================
  3319.  
  3320.     idLiquid
  3321.  
  3322. ===============================================================================
  3323. */
  3324.  
  3325. CLASS_DECLARATION( idEntity, idLiquid )
  3326.     EVENT( EV_Touch,            idLiquid::Event_Touch )
  3327. END_CLASS
  3328.  
  3329. /*
  3330. ================
  3331. idLiquid::Save
  3332. ================
  3333. */
  3334. void idLiquid::Save( idSaveGame *savefile ) const {
  3335.     // Nothing to save
  3336.     // cnicholson: It says nothing to save here, no mention of *model
  3337. }
  3338.  
  3339. /*
  3340. ================
  3341. idLiquid::Restore
  3342. ================
  3343. */
  3344. void idLiquid::Restore( idRestoreGame *savefile ) {
  3345.     //FIXME: NO!
  3346.     Spawn();
  3347. }
  3348.  
  3349. /*
  3350. ================
  3351. idLiquid::Spawn
  3352. ================
  3353. */
  3354. void idLiquid::Spawn() {
  3355. /*
  3356.     model = dynamic_cast<idRenderModelLiquid *>( renderEntity.hModel );
  3357.     if ( !model ) {
  3358.         gameLocal.Error( "Entity '%s' must have liquid model", name.c_str() );
  3359.     }
  3360.     model->Reset();
  3361.     GetPhysics()->SetContents( CONTENTS_TRIGGER );
  3362. */
  3363. }
  3364.  
  3365. /*
  3366. ================
  3367. idLiquid::Event_Touch
  3368. ================
  3369. */
  3370. void idLiquid::Event_Touch( idEntity *other, trace_t *trace ) {
  3371.     // FIXME: for QuakeCon
  3372. /*
  3373.     idVec3 pos;
  3374.  
  3375.     pos = other->GetPhysics()->GetOrigin() - GetPhysics()->GetOrigin();
  3376.     model->IntersectBounds( other->GetPhysics()->GetBounds().Translate( pos ), -10.0f );
  3377. */
  3378. }
  3379.  
  3380.  
  3381. /*
  3382. ===============================================================================
  3383.  
  3384.     idShaking
  3385.  
  3386. ===============================================================================
  3387. */
  3388.  
  3389. CLASS_DECLARATION( idEntity, idShaking )
  3390.     EVENT( EV_Activate,                idShaking::Event_Activate )
  3391. END_CLASS
  3392.  
  3393. /*
  3394. ===============
  3395. idShaking::idShaking
  3396. ===============
  3397. */
  3398. idShaking::idShaking() {
  3399.     active = false;
  3400. }
  3401.  
  3402.  
  3403. idShaking::~idShaking() { 
  3404.     SetPhysics( NULL );
  3405. }
  3406.  
  3407. /*
  3408. ===============
  3409. idShaking::Save
  3410. ===============
  3411. */
  3412. void idShaking::Save( idSaveGame *savefile ) const {
  3413.     savefile->WriteBool( active );
  3414.     savefile->WriteStaticObject( physicsObj );
  3415. }
  3416.  
  3417. /*
  3418. ===============
  3419. idShaking::Restore
  3420. ===============
  3421. */
  3422. void idShaking::Restore( idRestoreGame *savefile ) {
  3423.     savefile->ReadBool( active );
  3424.     savefile->ReadStaticObject( physicsObj );
  3425.     RestorePhysics( &physicsObj );
  3426. }
  3427.  
  3428. /*
  3429. ===============
  3430. idShaking::Spawn
  3431. ===============
  3432. */
  3433. void idShaking::Spawn( void ) {
  3434.     physicsObj.SetSelf( this );
  3435. // RAVEN BEGIN
  3436. // mwhitlock: Dynamic memory consolidation
  3437.     RV_PUSH_HEAP_MEM(this);
  3438. // RAVEN END
  3439.     physicsObj.SetClipModel( new idClipModel( GetPhysics()->GetClipModel() ), 1.0f );
  3440. // RAVEN BEGIN
  3441. // mwhitlock: Dynamic memory consolidation
  3442.     RV_POP_HEAP();
  3443. // RAVEN END
  3444.     physicsObj.SetOrigin( GetPhysics()->GetOrigin() );
  3445.     physicsObj.SetAxis( GetPhysics()->GetAxis() );
  3446.     physicsObj.SetClipMask( MASK_SOLID );
  3447.     SetPhysics( &physicsObj );
  3448.     
  3449.     active = false;
  3450.     if ( !spawnArgs.GetBool( "start_off" ) ) {
  3451.         BeginShaking();
  3452.     }
  3453. }
  3454.  
  3455. /*
  3456. ================
  3457. idShaking::BeginShaking
  3458. ================
  3459. */
  3460. void idShaking::BeginShaking( void ) {
  3461.     int            phase;
  3462.     idAngles    shake;
  3463.     int            period;
  3464.  
  3465.     active = true;
  3466.     phase = gameLocal.random.RandomInt( 1000 );
  3467.     shake = spawnArgs.GetAngles( "shake", "0.5 0.5 0.5" );
  3468.     period = spawnArgs.GetFloat( "period", "0.05" ) * 1000;
  3469.     physicsObj.SetAngularExtrapolation( extrapolation_t(EXTRAPOLATION_DECELSINE|EXTRAPOLATION_NOSTOP), phase, period * 0.25f, GetPhysics()->GetAxis().ToAngles(), shake, ang_zero );
  3470. }
  3471.  
  3472. /*
  3473. ================
  3474. idShaking::Event_Activate
  3475. ================
  3476. */
  3477. void idShaking::Event_Activate( idEntity *activator ) {
  3478.     if ( !active ) {
  3479.         BeginShaking();
  3480.     } else {
  3481.         active = false;
  3482.         physicsObj.SetAngularExtrapolation( EXTRAPOLATION_NONE, 0, 0, physicsObj.GetAxis().ToAngles(), ang_zero, ang_zero );
  3483.     }
  3484. }
  3485.  
  3486. /*
  3487. ===============================================================================
  3488.  
  3489.     idEarthQuake
  3490.  
  3491. ===============================================================================
  3492. */
  3493. idCVar g_earthquake( "g_earthquake", "1", 0, "controls earthquake effect" );
  3494.  
  3495. CLASS_DECLARATION( idEntity, idEarthQuake )
  3496.     EVENT( EV_Activate,                idEarthQuake::Event_Activate )
  3497. END_CLASS
  3498.  
  3499. /*
  3500. ===============
  3501. idEarthQuake::idEarthQuake
  3502. ===============
  3503. */
  3504. idEarthQuake::idEarthQuake() {
  3505.     wait = 0.0f;
  3506.     random = 0.0f;
  3507.     nextTriggerTime = 0;
  3508.     shakeStopTime = 0;
  3509.     triggered = false;
  3510.     playerOriented = false;
  3511.     disabled = false;
  3512.     shakeTime = 0.0f;
  3513. }
  3514.  
  3515. /*
  3516. ===============
  3517. idEarthQuake::Save
  3518. ===============
  3519. */
  3520. void idEarthQuake::Save( idSaveGame *savefile ) const {
  3521.     savefile->WriteInt( nextTriggerTime );
  3522.     savefile->WriteInt( shakeStopTime );
  3523.     savefile->WriteFloat( wait );
  3524.     savefile->WriteFloat( random );
  3525.     savefile->WriteBool( triggered );
  3526.     savefile->WriteBool( playerOriented );
  3527.     savefile->WriteBool( disabled );
  3528.     savefile->WriteFloat( shakeTime );
  3529. }
  3530.  
  3531. /*
  3532. ===============
  3533. idEarthQuake::Restore
  3534. ===============
  3535. */
  3536. void idEarthQuake::Restore( idRestoreGame *savefile ) {
  3537.     savefile->ReadInt( nextTriggerTime );
  3538.     savefile->ReadInt( shakeStopTime );
  3539.     savefile->ReadFloat( wait );
  3540.     savefile->ReadFloat( random );
  3541.     savefile->ReadBool( triggered );
  3542.     savefile->ReadBool( playerOriented );
  3543.     savefile->ReadBool( disabled );
  3544.     savefile->ReadFloat( shakeTime );
  3545.  
  3546.     if ( shakeStopTime > gameLocal.time ) {
  3547.         BecomeActive( TH_THINK );
  3548.     }
  3549. }
  3550.  
  3551. /*
  3552. ===============
  3553. idEarthQuake::Spawn
  3554. ===============
  3555. */
  3556. void idEarthQuake::Spawn( void ) {
  3557.     nextTriggerTime = 0;
  3558.     shakeStopTime = 0;
  3559.     wait = spawnArgs.GetFloat( "wait", "15" );
  3560.     random = spawnArgs.GetFloat( "random", "5" );
  3561.     triggered = spawnArgs.GetBool( "triggered" );
  3562.     playerOriented = spawnArgs.GetBool( "playerOriented" );
  3563.     disabled = false;
  3564.     shakeTime = spawnArgs.GetFloat( "shakeTime", "0" );
  3565.  
  3566.     if ( !triggered ){
  3567.         PostEventSec( &EV_Activate, spawnArgs.GetFloat( "wait" ), this );
  3568.     }
  3569.     BecomeInactive( TH_THINK );
  3570. }
  3571.  
  3572. /*
  3573. ================
  3574. idEarthQuake::Event_Activate
  3575. ================
  3576. */
  3577. void idEarthQuake::Event_Activate( idEntity *activator ) {
  3578.     
  3579.     if ( nextTriggerTime > gameLocal.time ) {
  3580.         return;
  3581.     }
  3582.  
  3583.     if ( disabled && activator == this ) {
  3584.         return;
  3585.     }
  3586.  
  3587.     idPlayer *player = gameLocal.GetLocalPlayer();
  3588.     if ( player == NULL ) {
  3589.         return;
  3590.     }
  3591.  
  3592.     nextTriggerTime = 0;
  3593.  
  3594.     if ( !triggered && activator != this ){
  3595.         // if we are not triggered ( i.e. random ), disable or enable
  3596.         disabled ^= 1;
  3597.         if (disabled) {
  3598.             return;
  3599.         } else {
  3600.             PostEventSec( &EV_Activate, wait + random * gameLocal.random.CRandomFloat(), this );
  3601.         }
  3602.     }
  3603.  
  3604.     ActivateTargets( activator );
  3605.  
  3606.     const idSoundShader *shader = declManager->FindSound( spawnArgs.GetString( "snd_quake" ) );
  3607.     if ( playerOriented ) {
  3608.         player->StartSoundShader( shader, SND_CHANNEL_ANY, SSF_GLOBAL, false, NULL );
  3609.     } else {
  3610.         StartSoundShader( shader, SND_CHANNEL_ANY, SSF_GLOBAL, false, NULL );
  3611.     }
  3612.  
  3613. // RAVEN BEGIN
  3614. // kfuller: look for fx entities and the like that may want to be triggered when a mortar round (aka earthquake) goes off
  3615.     AffectNearbyEntities(spawnArgs.GetFloat("affectEntities", "0"));
  3616. // RAVEN END
  3617.  
  3618.     if ( shakeTime > 0.0f ) {
  3619.         shakeStopTime = gameLocal.time + SEC2MS( shakeTime );
  3620.         BecomeActive( TH_THINK );
  3621.     }
  3622.  
  3623.     if ( wait > 0.0f ) {
  3624.         if ( !triggered ) {
  3625.             PostEventSec( &EV_Activate, wait + random * gameLocal.random.CRandomFloat(), this );
  3626.         } else {
  3627.             nextTriggerTime = gameLocal.time + SEC2MS( wait + random * gameLocal.random.CRandomFloat() );
  3628.         }
  3629.     } else if ( shakeTime == 0.0f ) {
  3630.         PostEventMS( &EV_Remove, 0 );
  3631.     }
  3632. }
  3633.  
  3634. // RAVEN BEGIN
  3635. // kfuller: look for fx entities and the like that may want to be triggered when a mortar round, earthquake, etc goes off
  3636. void idEarthQuake::AffectNearbyEntities(float affectRadius)
  3637. {
  3638.     if( !g_earthquake.GetBool() ) 
  3639.     {
  3640.         return;
  3641.     }
  3642.  
  3643.     if (affectRadius == 0)
  3644.     {
  3645.         return;
  3646.     }
  3647.     idVec3        affectOrigin(GetPhysics()->GetOrigin());
  3648.     
  3649.     if (playerOriented)
  3650.     {
  3651.         idPlayer *player = gameLocal.GetLocalPlayer();
  3652.         if ( player == NULL )
  3653.         {
  3654.             return;
  3655.         }
  3656.         affectOrigin = player->GetPhysics()->GetOrigin();
  3657.     }
  3658.  
  3659.     idEntity *    entityList[ MAX_GENTITIES ];
  3660.     int            numListedEntities = 0;
  3661.     idEntity    *curEnt = NULL;
  3662.     bool        requiresLOS = spawnArgs.GetBool("requiresLOS", "false");
  3663.  
  3664.     // get all entities touching the bounds
  3665.     numListedEntities = gameLocal.EntitiesWithinRadius(affectOrigin, affectRadius, entityList, MAX_GENTITIES );
  3666.     for (int i = 0; i < numListedEntities; i++)
  3667.     {
  3668.         // only affect certain entities. first check if they have the "quakeChance" key/value, then send them an earthquake event
  3669.         curEnt = entityList[i];
  3670.         if (curEnt && curEnt->spawnArgs.GetFloat("quakeChance"))
  3671.         {
  3672.             curEnt->PostEventMS(&EV_Earthquake, 0, (float)requiresLOS);
  3673.         }
  3674.     }
  3675. }
  3676. // RAVEN END
  3677.  
  3678. /*
  3679. ===============
  3680. idEarthQuake::Think
  3681. ================
  3682. */
  3683. void idEarthQuake::Think( void ) {
  3684.     if ( thinkFlags & TH_THINK ) {
  3685.         if ( gameLocal.time > shakeStopTime ) {
  3686.             BecomeInactive( TH_THINK );
  3687.             if ( wait <= 0.0f ) {
  3688.                 PostEventMS( &EV_Remove, 0 );
  3689.             }
  3690.             return;
  3691.         }
  3692.         float shakeVolume = soundSystem->CurrentShakeAmplitudeForPosition( SOUNDWORLD_GAME, gameLocal.time, gameLocal.GetLocalPlayer()->firstPersonViewOrigin );
  3693.         gameLocal.RadiusPush( GetPhysics()->GetOrigin(), 256, 1500 * shakeVolume, this, this, 1.0f, true );
  3694.     }
  3695.     BecomeInactive( TH_UPDATEVISUALS );
  3696. }
  3697.  
  3698. /*
  3699. ===============================================================================
  3700.  
  3701.     idFuncPortal
  3702.  
  3703. ===============================================================================
  3704. */
  3705.  
  3706. CLASS_DECLARATION( idEntity, idFuncPortal )
  3707.     EVENT( EV_Activate,                idFuncPortal::Event_Activate )
  3708. END_CLASS
  3709.  
  3710. /*
  3711. ===============
  3712. idFuncPortal::idFuncPortal
  3713. ===============
  3714. */
  3715. idFuncPortal::idFuncPortal() {
  3716.     portal = 0;
  3717.     state = false;
  3718. }
  3719.  
  3720. /*
  3721. ===============
  3722. idFuncPortal::Save
  3723. ===============
  3724. */
  3725. void idFuncPortal::Save( idSaveGame *savefile ) const {
  3726.     savefile->WriteInt( (int)portal );
  3727.     savefile->WriteBool( state );
  3728. }
  3729.  
  3730. /*
  3731. ===============
  3732. idFuncPortal::Restore
  3733. ===============
  3734. */
  3735. void idFuncPortal::Restore( idRestoreGame *savefile ) {
  3736.     savefile->ReadInt( (int &)portal );
  3737.     savefile->ReadBool( state );
  3738.     gameLocal.SetPortalState( portal, state ? PS_BLOCK_ALL : PS_BLOCK_NONE );
  3739. }
  3740.  
  3741. /*
  3742. ===============
  3743. idFuncPortal::Spawn
  3744. ===============
  3745. */
  3746. void idFuncPortal::Spawn( void ) {
  3747.     portal = gameRenderWorld->FindPortal( GetPhysics()->GetAbsBounds().Expand( 32.0f ) );
  3748.     if ( portal > 0 ) {
  3749.         state = spawnArgs.GetBool( "start_on" );
  3750.         gameLocal.SetPortalState( portal, state ? PS_BLOCK_ALL : PS_BLOCK_NONE );
  3751.     }
  3752. }
  3753.  
  3754. /*
  3755. ================
  3756. idFuncPortal::Event_Activate
  3757. ================
  3758. */
  3759. void idFuncPortal::Event_Activate( idEntity *activator ) {
  3760.     if ( portal > 0 ) {
  3761.         state = !state;
  3762.         gameLocal.SetPortalState( portal, state ? PS_BLOCK_ALL : PS_BLOCK_NONE );
  3763.     }
  3764. }
  3765.  
  3766. /*
  3767. ===============================================================================
  3768.  
  3769.     idFuncAASPortal
  3770.  
  3771. ===============================================================================
  3772. */
  3773.  
  3774. CLASS_DECLARATION( idEntity, idFuncAASPortal )
  3775.     EVENT( EV_Activate,                idFuncAASPortal::Event_Activate )
  3776. END_CLASS
  3777.  
  3778. /*
  3779. ===============
  3780. idFuncAASPortal::idFuncAASPortal
  3781. ===============
  3782. */
  3783. idFuncAASPortal::idFuncAASPortal() {
  3784.     state = false;
  3785. }
  3786.  
  3787. /*
  3788. ===============
  3789. idFuncAASPortal::Save
  3790. ===============
  3791. */
  3792. void idFuncAASPortal::Save( idSaveGame *savefile ) const {
  3793.     savefile->WriteBool( state );
  3794. }
  3795.  
  3796. /*
  3797. ===============
  3798. idFuncAASPortal::Restore
  3799. ===============
  3800. */
  3801. void idFuncAASPortal::Restore( idRestoreGame *savefile ) {
  3802.     savefile->ReadBool( state );
  3803.     gameLocal.SetAASAreaState( GetPhysics()->GetAbsBounds(), AREACONTENTS_CLUSTERPORTAL, state );
  3804. }
  3805.  
  3806. /*
  3807. ===============
  3808. idFuncAASPortal::Spawn
  3809. ===============
  3810. */
  3811. void idFuncAASPortal::Spawn( void ) {
  3812.     state = spawnArgs.GetBool( "start_on" );
  3813.     gameLocal.SetAASAreaState( GetPhysics()->GetAbsBounds(), AREACONTENTS_CLUSTERPORTAL, state );
  3814. }
  3815.  
  3816. /*
  3817. ================
  3818. idFuncAASPortal::Event_Activate
  3819. ================
  3820. */
  3821. void idFuncAASPortal::Event_Activate( idEntity *activator ) {
  3822.     state ^= 1;
  3823.     gameLocal.SetAASAreaState( GetPhysics()->GetAbsBounds(), AREACONTENTS_CLUSTERPORTAL, state );
  3824. }
  3825.  
  3826. /*
  3827. ===============================================================================
  3828.  
  3829.     idFuncAASObstacle
  3830.  
  3831. ===============================================================================
  3832. */
  3833.  
  3834. CLASS_DECLARATION( idEntity, idFuncAASObstacle )
  3835.     EVENT( EV_Activate,                idFuncAASObstacle::Event_Activate )
  3836. END_CLASS
  3837.  
  3838. /*
  3839. ===============
  3840. idFuncAASObstacle::idFuncAASObstacle
  3841. ===============
  3842. */
  3843. idFuncAASObstacle::idFuncAASObstacle() {
  3844.     state = false;
  3845. }
  3846.  
  3847. /*
  3848. ===============
  3849. idFuncAASObstacle::Save
  3850. ===============
  3851. */
  3852. void idFuncAASObstacle::Save( idSaveGame *savefile ) const {
  3853.     savefile->WriteBool( state );
  3854. }
  3855.  
  3856. /*
  3857. ===============
  3858. idFuncAASObstacle::Restore
  3859. ===============
  3860. */
  3861. void idFuncAASObstacle::Restore( idRestoreGame *savefile ) {
  3862.     savefile->ReadBool( state );
  3863.     gameLocal.SetAASAreaState( GetPhysics()->GetAbsBounds(), AREACONTENTS_OBSTACLE, state );
  3864. }
  3865.  
  3866. /*
  3867. ===============
  3868. idFuncAASObstacle::Spawn
  3869. ===============
  3870. */
  3871. void idFuncAASObstacle::Spawn( void ) {
  3872.     state = spawnArgs.GetBool( "start_on" );
  3873.     gameLocal.SetAASAreaState( GetPhysics()->GetAbsBounds(), AREACONTENTS_OBSTACLE, state );
  3874. }
  3875.  
  3876. /*
  3877. ================
  3878. idFuncAASObstacle::Event_Activate
  3879. ================
  3880. */
  3881. void idFuncAASObstacle::Event_Activate( idEntity *activator ) {
  3882.     state ^= 1;
  3883.     gameLocal.SetAASAreaState( GetPhysics()->GetAbsBounds(), AREACONTENTS_OBSTACLE, state );
  3884. }
  3885.  
  3886. /*
  3887. ================
  3888. idFuncAASObstacle::SetState
  3889. ================
  3890. */
  3891. void idFuncAASObstacle::SetState ( bool _state ) {
  3892.     state = _state;
  3893.     gameLocal.SetAASAreaState( GetPhysics()->GetAbsBounds(), AREACONTENTS_OBSTACLE, state );
  3894. }
  3895.  
  3896. /*
  3897. ===============================================================================
  3898.  
  3899. idFuncRadioChatter
  3900.  
  3901. ===============================================================================
  3902. */
  3903.  
  3904. const idEventDef EV_ResetRadioHud( "<resetradiohud>", "e" );
  3905. idEntityPtr<idFuncRadioChatter> idFuncRadioChatter::lastRadioChatter = 0;
  3906.  
  3907. CLASS_DECLARATION( idEntity, idFuncRadioChatter )
  3908. EVENT( EV_Activate,                idFuncRadioChatter::Event_Activate )
  3909. EVENT( EV_ResetRadioHud,        idFuncRadioChatter::Event_ResetRadioHud )
  3910. EVENT( EV_IsActive,                idFuncRadioChatter::Event_IsActive )
  3911. END_CLASS
  3912.  
  3913. /*
  3914. ===============
  3915. idFuncRadioChatter::idFuncRadioChatter
  3916. ===============
  3917. */
  3918. idFuncRadioChatter::idFuncRadioChatter() {
  3919.     time = 0.0f;
  3920.     isActive = false;
  3921. }
  3922.  
  3923. /*
  3924. ===============
  3925. idFuncRadioChatter::Save
  3926. ===============
  3927. */
  3928. void idFuncRadioChatter::Save( idSaveGame *savefile ) const {
  3929.     savefile->WriteFloat( time );
  3930.     savefile->WriteBool( isActive ); // cnicholson: Added unsaved var
  3931.     lastRadioChatter.Save ( savefile );
  3932. }
  3933.  
  3934. /*
  3935. ===============
  3936. idFuncRadioChatter::Restore
  3937. ===============
  3938. */
  3939. void idFuncRadioChatter::Restore( idRestoreGame *savefile ) {
  3940.     savefile->ReadFloat( time );
  3941.     savefile->ReadBool( isActive ); // cnicholson: Added unrestored var
  3942.     lastRadioChatter.Restore ( savefile );
  3943. }
  3944.  
  3945. /*
  3946. ===============
  3947. idFuncRadioChatter::Spawn
  3948. ===============
  3949. */
  3950. void idFuncRadioChatter::Spawn( void ) {
  3951.     time = spawnArgs.GetFloat( "time", "5.0" );
  3952. }
  3953.  
  3954. /*
  3955. ================
  3956. idFuncRadioChatter::Event_Activate
  3957. ================
  3958. */
  3959. void idFuncRadioChatter::Event_Activate( idEntity *activator ) {
  3960.     idPlayer *player;
  3961.     const char    *sound;
  3962.     const idSoundShader *shader;
  3963.     int length;
  3964.     bool isDirectedAtPlayer = false;    
  3965.  
  3966.     lastRadioChatter = this;
  3967.  
  3968. // RAVEN BEGIN
  3969. // jnewquist: Use accessor for static class type 
  3970.     if ( activator && activator->IsType( idPlayer::GetClassType() ) ) {
  3971. // RAVEN END
  3972.         player = static_cast<idPlayer *>( activator );
  3973.     } else {
  3974.         player = gameLocal.GetLocalPlayer();
  3975.     }
  3976.  
  3977. // RAVEN BEGIN
  3978. // bdube: replaced named event with method
  3979.     player->StartRadioChatter();
  3980. // twhitaker: for isActive() script event
  3981.     isActive = true;
  3982. // RAVEN END
  3983.  
  3984.     sound = spawnArgs.GetString( "snd_radiochatter", "" );
  3985.     if ( sound && *sound ) {
  3986.         shader = declManager->FindSound( sound );
  3987.         if ( shader && shader->IsVO_ForPlayer()){
  3988.             isDirectedAtPlayer = true;
  3989.         }
  3990.         player->StartSoundShader( shader, SND_CHANNEL_RADIO, SSF_GLOBAL, false, &length );
  3991.         time = MS2SEC( length + 150 );
  3992.     }
  3993.  
  3994.     if ( player && player->GetHud() ) {
  3995.         player->GetHud()->SetStateBool( "rhinochatter", isDirectedAtPlayer );
  3996.     }
  3997.  
  3998.     // we still put the hud up because this is used with no sound on 
  3999.     // certain frame commands when the chatter is triggered
  4000.     PostEventSec( &EV_ResetRadioHud, time, player );
  4001. }
  4002.  
  4003. /*
  4004. ================
  4005. idFuncRadioChatter::Event_ResetRadioHud
  4006. ================
  4007. */
  4008. void idFuncRadioChatter::Event_ResetRadioHud( idEntity *activator ) {
  4009. // RAVEN BEGIN
  4010. // jnewquist: Use accessor for static class type 
  4011.     idPlayer *player = ( activator->IsType( idPlayer::GetClassType() ) ) ? static_cast<idPlayer *>( activator ) : gameLocal.GetLocalPlayer();
  4012. // RAVEN END
  4013. // RAVEN BEGIN
  4014. // bdube: replaced named event with method
  4015.     player->StopRadioChatter();
  4016. // twhitaker: for isActive() script event
  4017.     isActive = false;
  4018. // RAVEN END
  4019.     ActivateTargets( activator );
  4020. }
  4021.  
  4022. /*
  4023. ================
  4024. idFuncRadioChatter::Event_ResetRadioHud
  4025. ================
  4026. */
  4027. void idFuncRadioChatter::Event_IsActive( void ) {
  4028.     idThread::ReturnFloat( static_cast< float >( isActive ) );
  4029. }
  4030.  
  4031. /*
  4032. ================
  4033. idFuncRadioChatter::RepeatLast
  4034. ================
  4035. */
  4036. void idFuncRadioChatter::RepeatLast( void ) {
  4037.     if ( lastRadioChatter ) {
  4038.         lastRadioChatter->Event_Activate( gameLocal.GetLocalPlayer() );
  4039.     }
  4040. }
  4041.  
  4042. /*
  4043. ===============================================================================
  4044.  
  4045.     idPhantomObjects
  4046.  
  4047. ===============================================================================
  4048. */
  4049.  
  4050. CLASS_DECLARATION( idEntity, idPhantomObjects )
  4051.     EVENT( EV_Activate,                idPhantomObjects::Event_Activate )
  4052. END_CLASS
  4053.  
  4054. /*
  4055. ===============
  4056. idPhantomObjects::idPhantomObjects
  4057. ===============
  4058. */
  4059. idPhantomObjects::idPhantomObjects() {
  4060.     target            = NULL;
  4061.     end_time        = 0;
  4062.     throw_time         = 0.0f;
  4063.     shake_time         = 0.0f;
  4064.     shake_ang.Zero();
  4065.     speed            = 0.0f;
  4066.     min_wait        = 0;
  4067.     max_wait        = 0;
  4068.     fl.neverDormant    = false;
  4069. }
  4070.  
  4071. /*
  4072. ===============
  4073. idPhantomObjects::Save
  4074. ===============
  4075. */
  4076. void idPhantomObjects::Save( idSaveGame *savefile ) const {
  4077.     int i;
  4078.  
  4079.     savefile->WriteInt( end_time );
  4080.     savefile->WriteFloat( throw_time );
  4081.     savefile->WriteFloat( shake_time );
  4082.     savefile->WriteVec3( shake_ang );
  4083.     savefile->WriteFloat( speed );
  4084.     savefile->WriteInt( min_wait );
  4085.     savefile->WriteInt( max_wait );
  4086.     target.Save( savefile );
  4087.     savefile->WriteInt( targetTime.Num() );
  4088.     for( i = 0; i < targetTime.Num(); i++ ) {
  4089.         savefile->WriteInt( targetTime[ i ] );
  4090.     }
  4091.  
  4092.     for( i = 0; i < lastTargetPos.Num(); i++ ) {
  4093.         savefile->WriteVec3( lastTargetPos[ i ] );
  4094.     }
  4095. }
  4096.  
  4097. /*
  4098. ===============
  4099. idPhantomObjects::Restore
  4100. ===============
  4101. */
  4102. void idPhantomObjects::Restore( idRestoreGame *savefile ) {
  4103.     int num;
  4104.     int i;
  4105.  
  4106.     savefile->ReadInt( end_time );
  4107.     savefile->ReadFloat( throw_time );
  4108.     savefile->ReadFloat( shake_time );
  4109.     savefile->ReadVec3( shake_ang );
  4110.     savefile->ReadFloat( speed );
  4111.     savefile->ReadInt( min_wait );
  4112.     savefile->ReadInt( max_wait );
  4113.     target.Restore( savefile );
  4114.     
  4115.     savefile->ReadInt( num );    
  4116.     targetTime.SetGranularity( 1 );
  4117.     targetTime.SetNum( num );
  4118.     lastTargetPos.SetGranularity( 1 );
  4119.     lastTargetPos.SetNum( num );
  4120.  
  4121.     for( i = 0; i < num; i++ ) {
  4122.         savefile->ReadInt( targetTime[ i ] );
  4123.     }
  4124.  
  4125.     if ( savefile->GetBuildNumber() == INITIAL_RELEASE_BUILD_NUMBER ) {
  4126.         // these weren't saved out in the first release
  4127.         for( i = 0; i < num; i++ ) {
  4128.             lastTargetPos[ i ].Zero();
  4129.         }
  4130.     } else {
  4131.         for( i = 0; i < num; i++ ) {
  4132.             savefile->ReadVec3( lastTargetPos[ i ] );
  4133.         }
  4134.     }
  4135. }
  4136.  
  4137. /*
  4138. ===============
  4139. idPhantomObjects::Spawn
  4140. ===============
  4141. */
  4142. void idPhantomObjects::Spawn( void ) {
  4143.     throw_time = spawnArgs.GetFloat( "time", "5" );
  4144.     speed = spawnArgs.GetFloat( "speed", "1200" );
  4145.     shake_time = spawnArgs.GetFloat( "shake_time", "1" );
  4146.     throw_time -= shake_time;
  4147.     if ( throw_time < 0.0f ) {
  4148.         throw_time = 0.0f;
  4149.     }
  4150.     min_wait = SEC2MS( spawnArgs.GetFloat( "min_wait", "1" ) );
  4151.     max_wait = SEC2MS( spawnArgs.GetFloat( "max_wait", "3" ) );
  4152.  
  4153.     shake_ang = spawnArgs.GetVector( "shake_ang", "65 65 65" );
  4154.     Hide();
  4155.     GetPhysics()->SetContents( 0 );
  4156. }
  4157.  
  4158. /*
  4159. ================
  4160. idPhantomObjects::Event_Activate
  4161. ================
  4162. */
  4163. void idPhantomObjects::Event_Activate( idEntity *activator ) {
  4164.     int i;
  4165.     float time;
  4166.     float frac;
  4167.     float scale;
  4168.  
  4169.     if ( thinkFlags & TH_THINK ) {
  4170.         BecomeInactive( TH_THINK );
  4171.         return;
  4172.     }
  4173.  
  4174.     RemoveNullTargets();
  4175.     if ( !targets.Num() ) {
  4176.         return;
  4177.     }
  4178.  
  4179. // RAVEN BEGIN
  4180. // jnewquist: Use accessor for static class type 
  4181.     if ( !activator || !activator->IsType( idActor::GetClassType() ) ) {
  4182. // RAVEN END
  4183.         target = gameLocal.GetLocalPlayer();
  4184.     } else {
  4185.         target = static_cast<idActor *>( activator );
  4186.     }
  4187.     
  4188.     end_time = gameLocal.time + SEC2MS( spawnArgs.GetFloat( "end_time", "0" ) );
  4189.  
  4190.     targetTime.SetNum( targets.Num() );
  4191.     lastTargetPos.SetNum( targets.Num() );
  4192.  
  4193.     const idVec3 &toPos = target.GetEntity()->GetEyePosition();
  4194.  
  4195.     // calculate the relative times of all the objects
  4196.     time = 0.0f;
  4197.     for( i = 0; i < targetTime.Num(); i++ ) {
  4198.         targetTime[ i ] = SEC2MS( time );
  4199.         lastTargetPos[ i ] = toPos;
  4200.  
  4201.         frac = 1.0f - ( float )i / ( float )targetTime.Num();
  4202.         time += ( gameLocal.random.RandomFloat() + 1.0f ) * 0.5f * frac + 0.1f;
  4203.     }
  4204.  
  4205.     // scale up the times to fit within throw_time
  4206.     scale = throw_time / time;
  4207.     for( i = 0; i < targetTime.Num(); i++ ) {
  4208.         targetTime[ i ] = gameLocal.time + SEC2MS( shake_time )+ targetTime[ i ] * scale;
  4209.     }
  4210.  
  4211.     BecomeActive( TH_THINK );
  4212. }
  4213.  
  4214. /*
  4215. ===============
  4216. idPhantomObjects::Think
  4217. ================
  4218. */
  4219. void idPhantomObjects::Think( void ) {
  4220.     int            i;
  4221.     int            num;
  4222.     float        time;
  4223.     idVec3        vel;
  4224.     idVec3        ang;
  4225.     idEntity    *ent;
  4226.     idActor        *targetEnt;
  4227.     idPhysics    *entPhys;
  4228.     trace_t        tr;
  4229.  
  4230.     // if we are completely closed off from the player, don't do anything at all
  4231.     if ( CheckDormant() ) {
  4232.         return;
  4233.     }
  4234.  
  4235.     if ( !( thinkFlags & TH_THINK ) ) {
  4236.         BecomeInactive( thinkFlags & ~TH_THINK );
  4237.         return;
  4238.     }
  4239.  
  4240.     targetEnt = target.GetEntity();
  4241.     if ( !targetEnt || ( targetEnt->health <= 0 ) || ( end_time && ( gameLocal.time > end_time ) ) || gameLocal.inCinematic ) {
  4242.         BecomeInactive( TH_THINK );
  4243.     }
  4244.  
  4245.     const idVec3 &toPos = targetEnt->GetEyePosition();
  4246.  
  4247.     num = 0;
  4248.     for ( i = 0; i < targets.Num(); i++ ) {
  4249.         ent = targets[ i ].GetEntity();
  4250.         if ( !ent ) {
  4251.             continue;
  4252.         }
  4253.         
  4254.         if ( ent->fl.hidden ) {
  4255.             // don't throw hidden objects
  4256.             continue;
  4257.         }
  4258.  
  4259.         if ( !targetTime[ i ] ) {
  4260.             // already threw this object
  4261.             continue;
  4262.         }
  4263.  
  4264.         num++;
  4265.  
  4266.         time = MS2SEC( targetTime[ i ] - gameLocal.time );
  4267.         if ( time > shake_time ) {
  4268.             continue;
  4269.         }
  4270.  
  4271.         entPhys = ent->GetPhysics();
  4272.         const idVec3 &entOrg = entPhys->GetOrigin();
  4273.  
  4274. // RAVEN BEGIN
  4275. // ddynerman: multiple clip worlds
  4276.         gameLocal.TracePoint( this, tr, entOrg, toPos, MASK_OPAQUE, ent );
  4277. // RAVEN END
  4278.         if ( tr.fraction >= 1.0f || ( gameLocal.GetTraceEntity( tr ) == targetEnt ) ) {
  4279.             lastTargetPos[ i ] = toPos;
  4280.         }
  4281.  
  4282.         if ( time < 0.0f ) {
  4283.             idAI::PredictTrajectory( entPhys->GetOrigin(), lastTargetPos[ i ], speed, entPhys->GetGravity(), 
  4284.                 entPhys->GetClipModel(), entPhys->GetClipMask(), 256.0f, ent, targetEnt, ai_debugTrajectory.GetBool() ? 1 : 0, vel );
  4285.             vel *= speed;
  4286.             entPhys->SetLinearVelocity( vel );
  4287.             if ( !end_time ) {
  4288.                 targetTime[ i ] = 0;
  4289.             } else {
  4290.                 targetTime[ i ] = gameLocal.time + gameLocal.random.RandomInt( max_wait - min_wait ) + min_wait;
  4291.             }
  4292. // RAVEN BEGIN
  4293. // jnewquist: Use accessor for static class type 
  4294.             if ( ent->IsType( idMoveable::GetClassType() ) ) {
  4295. // RAVEN END
  4296.                 idMoveable *ment = static_cast<idMoveable*>( ent );
  4297.                 ment->EnableDamage( true, 2.5f );
  4298.             }
  4299.         } else {
  4300.             // this is not the right way to set the angular velocity, but the effect is nice, so I'm keeping it. :)
  4301.             ang.Set( gameLocal.random.CRandomFloat() * shake_ang.x, gameLocal.random.CRandomFloat() * shake_ang.y, gameLocal.random.CRandomFloat() * shake_ang.z );
  4302.             ang *= ( 1.0f - time / shake_time );
  4303.             entPhys->SetAngularVelocity( ang );
  4304.         }
  4305.     }
  4306.  
  4307.     if ( !num ) {
  4308.         BecomeInactive( TH_THINK );
  4309.     }
  4310. }
  4311.  
  4312. // RAVEN BEGIN
  4313. // bdube: jump points
  4314.  
  4315. /*
  4316. ===============================================================================
  4317.  
  4318. rvDebugJumpPoint
  4319.  
  4320. ===============================================================================
  4321. */
  4322.  
  4323. CLASS_DECLARATION( idEntity, rvDebugJumpPoint )
  4324. END_CLASS
  4325.  
  4326. /*
  4327. =====================
  4328. rvDebugJumpPoint::Spawn
  4329. =====================
  4330. */
  4331. void rvDebugJumpPoint::Spawn() {
  4332.     // Add the jump point
  4333.     gameDebug.JumpAdd ( name, GetPhysics()->GetOrigin(), GetPhysics()->GetAxis().ToAngles ( ) );
  4334.     
  4335.     // Dont need the entity any more
  4336.     PostEventMS( &EV_Remove, 0 );
  4337. }
  4338.  
  4339.  
  4340. /*
  4341. ===============================================================================
  4342.  
  4343. rvFuncSaveGame
  4344.  
  4345. ===============================================================================
  4346. */
  4347.  
  4348. CLASS_DECLARATION( idEntity, rvFuncSaveGame )
  4349.     EVENT( EV_Activate,        rvFuncSaveGame::Event_Activate )
  4350. END_CLASS
  4351.  
  4352. void rvFuncSaveGame::Spawn( void ) {
  4353.  
  4354. }
  4355.  
  4356. void rvFuncSaveGame::Event_Activate( idEntity *activator ) {
  4357.     // TODO: Xenon - request the player to save the game.
  4358.     cmdSystem->BufferCommandText( CMD_EXEC_APPEND, "saveGame checkPoint" );
  4359. }
  4360.