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

  1. // RAVEN BEGIN
  2. // bdube: note that this file is no longer merged with Doom3 updates
  3. //
  4. // MERGE_DATE 09/30/2004
  5.  
  6. #include "../idlib/precompiled.h"
  7. #pragma hdrstop
  8.  
  9. #include "Game_local.h"
  10.  
  11. #if !defined(__GAME_PROJECTILE_H__)
  12.     #include "Projectile.h"
  13. #endif
  14.  
  15. /*
  16. ===============================================================================
  17.  
  18.   idMoveable
  19.     
  20. ===============================================================================
  21. */
  22.  
  23. const idEventDef EV_BecomeNonSolid( "becomeNonSolid" );
  24. const idEventDef EV_SetOwnerFromSpawnArgs( "<setOwnerFromSpawnArgs>" );
  25. const idEventDef EV_IsAtRest( "isAtRest", NULL, 'd' );
  26. const idEventDef EV_CanDamage( "canDamage", "f" );
  27. const idEventDef EV_SetHealth( "setHealth", "f" );
  28. const idEventDef EV_RadiusDamage( "<radiusDamage>", "es" );
  29.  
  30. CLASS_DECLARATION( idDamagable, idMoveable )
  31.     EVENT( EV_Activate,                    idMoveable::Event_Activate )
  32.     EVENT( EV_BecomeNonSolid,            idMoveable::Event_BecomeNonSolid )
  33.     EVENT( EV_SetOwnerFromSpawnArgs,    idMoveable::Event_SetOwnerFromSpawnArgs )
  34.     EVENT( EV_IsAtRest,                    idMoveable::Event_IsAtRest )
  35.     EVENT( EV_CanDamage,                idMoveable::Event_CanDamage )
  36.     EVENT( EV_SetHealth,                idMoveable::Event_SetHealth )
  37.     EVENT( EV_RadiusDamage,                idMoveable::Event_RadiusDamage )
  38. END_CLASS
  39.  
  40. static const float BOUNCE_SOUND_MIN_VELOCITY    = 80.0f;
  41. static const float BOUNCE_SOUND_MAX_VELOCITY    = 400.0f;
  42. static const int   BOUNCE_SOUND_DELAY_MIN        = 500.0f;
  43. static const int   BOUNCE_SOUND_DELAY_MAX        = 1200.0f;
  44.  
  45. /*
  46. ================
  47. idMoveable::idMoveable
  48. ================
  49. */
  50. idMoveable::idMoveable( void ) {
  51.      minDamageVelocity    = 100.0f;
  52.      maxDamageVelocity    = 200.0f;
  53.     nextCollideFxTime    = 0;
  54.      initialSpline        = NULL;
  55.      initialSplineDir    = vec3_zero;
  56.     unbindOnDeath        = false;
  57.     allowStep            = false;
  58.      canDamage            = false;
  59.     
  60.     lastAttacker        = NULL;
  61. }
  62.  
  63. /*
  64. ================
  65. idMoveable::~idMoveable
  66. ================
  67. */
  68. idMoveable::~idMoveable( void ) {
  69.      delete initialSpline;
  70.      initialSpline = NULL;
  71.      SetPhysics( NULL );
  72. }
  73.  
  74. /*
  75. ================
  76. idMoveable::Spawn
  77. ================
  78. */
  79. void idMoveable::Spawn( void ) {
  80.     idTraceModel trm;
  81.     float density, friction, bouncyness;
  82.     int clipShrink;
  83.     idStr clipModelName;
  84.     bool setClipModel = false;
  85.     idBounds bounds;
  86.     
  87.     // check if a clip model is set
  88.     spawnArgs.GetString( "clipmodel", "", clipModelName );
  89.     if ( !clipModelName[0] ) {
  90.         idVec3 size;
  91.         if ( spawnArgs.GetVector( "mins", NULL, bounds[0] ) &&
  92.             spawnArgs.GetVector( "maxs", NULL, bounds[1] ) ) {
  93.             setClipModel = true;
  94.             if ( bounds[0][0] > bounds[1][0] || bounds[0][1] > bounds[1][1] || bounds[0][2] > bounds[1][2] ) {
  95.                 gameLocal.Error( "Invalid bounds '%s'-'%s' on moveable '%s'", bounds[0].ToString(), bounds[1].ToString(), name.c_str() );
  96.             }
  97.         } else if ( spawnArgs.GetVector( "size", NULL, size ) ) {
  98.             if ( ( size.x < 0.0f ) || ( size.y < 0.0f ) || ( size.z < 0.0f ) ) {
  99.                 gameLocal.Error( "Invalid size '%s' on moveable '%s'", size.ToString(), name.c_str() );
  100.             }
  101.             bounds[0].Set( size.x * -0.5f, size.y * -0.5f, 0.0f );
  102.             bounds[1].Set( size.x * 0.5f, size.y * 0.5f, size.z );
  103.             setClipModel = true;
  104.         }
  105.     }
  106.  
  107.     if ( setClipModel ) {
  108.         trm.SetupBox( bounds );
  109.     } else {
  110.         if ( !clipModelName[0] ) {
  111.             clipModelName = spawnArgs.GetString ( "model" );        // use the visual model
  112.         }
  113.         clipModelName.BackSlashesToSlashes();
  114.  
  115.         if ( !collisionModelManager->TrmFromModel( gameLocal.GetMapName(), clipModelName, trm ) ) {
  116.             gameLocal.Error( "idMoveable '%s': cannot load collision model %s", name.c_str(), clipModelName.c_str() );
  117.             return;
  118.         }
  119.     }
  120.  
  121.     // if the model should be shrinked
  122.     clipShrink = spawnArgs.GetInt( "clipshrink" );
  123.     if ( clipShrink != 0 ) {
  124.         trm.Shrink( clipShrink * CM_CLIP_EPSILON );
  125.     }
  126.  
  127.     // get rigid body properties
  128.     spawnArgs.GetFloat( "density", "0.5", density );
  129.     density = idMath::ClampFloat( 0.001f, 1000.0f, density );
  130.     spawnArgs.GetFloat( "friction", "0.05", friction );
  131.     friction = idMath::ClampFloat( 0.0f, 1.0f, friction );
  132.     spawnArgs.GetFloat( "bouncyness", "0.6", bouncyness );
  133.     bouncyness = idMath::ClampFloat( 0.0f, 1.0f, bouncyness );
  134.     unbindOnDeath = spawnArgs.GetBool( "unbindondeath" );
  135.  
  136.     nextCollideFxTime = 0;
  137.  
  138.     damage = spawnArgs.GetString( "def_damage", "" );
  139.     canDamage = spawnArgs.GetBool( "damageWhenActive" ) ? false : true;
  140.     health = spawnArgs.GetInt( "health", "0" );
  141.     spawnArgs.GetString( "broken", "", brokenModel );
  142.  
  143.     if ( health ) {
  144.         if ( brokenModel != "" && !renderModelManager->CheckModel( brokenModel ) ) {
  145.             gameLocal.Error( "idMoveable '%s' at (%s): cannot load broken model '%s'", name.c_str(), GetPhysics()->GetOrigin().ToString(0), brokenModel.c_str() );
  146.         }
  147.     }
  148.  
  149.     fl.takedamage = (health > 0 );
  150.  
  151.     // setup the physics
  152.     physicsObj.SetSelf( this );
  153. // RAVEN BEGIN
  154. // mwhitlock: Dynamic memory consolidation
  155.     RV_PUSH_HEAP_MEM( this );
  156. // RAVEN END
  157.     physicsObj.SetClipModel( new idClipModel( trm, GetRenderModelMaterial() ), density );
  158. // RAVEN BEGIN
  159. // mwhitlock: Dynamic memory consolidation
  160.     RV_POP_HEAP();
  161. // RAVEN END
  162.     physicsObj.SetOrigin( GetPhysics()->GetOrigin() );
  163.     physicsObj.SetAxis( GetPhysics()->GetAxis() );
  164.     physicsObj.SetBouncyness( bouncyness );
  165.     physicsObj.SetFriction( 0.6f, 0.6f, friction );
  166.     physicsObj.SetGravity( gameLocal.GetGravity() );
  167.     physicsObj.SetContents( CONTENTS_SOLID );
  168.     physicsObj.SetClipMask( MASK_SOLID | CONTENTS_BODY | CONTENTS_CORPSE | CONTENTS_MOVEABLECLIP | CONTENTS_WATER );
  169.     SetPhysics( &physicsObj );
  170.  
  171.     if ( spawnArgs.GetBool( "nodrop" ) ) {
  172.         physicsObj.PutToRest();
  173.     } else {
  174.         physicsObj.DropToFloor();
  175.     }
  176.  
  177.     if ( spawnArgs.GetBool( "noimpact" ) || spawnArgs.GetBool( "notPushable" ) ) {
  178.         physicsObj.DisableImpact();
  179.     }
  180.  
  181.     if ( spawnArgs.GetBool( "nonsolid" ) ) {
  182.         BecomeNonSolid();
  183.     }
  184.  
  185.     allowStep = spawnArgs.GetBool( "allowStep", "1" );
  186.  
  187. // RAVEN BEGIN
  188. // cdr: Obstacle Avoidance
  189.     fl.isAIObstacle = !physicsObj.IsPushable();
  190. // RAVEN END
  191.  
  192.     PostEventMS( &EV_SetOwnerFromSpawnArgs, 0 );
  193. }
  194.  
  195. /*
  196. ================
  197. idMoveable::Save
  198. ================
  199. */
  200. void idMoveable::Save( idSaveGame *savefile ) const {
  201.  
  202.     savefile->WriteStaticObject( physicsObj );
  203.     
  204.     savefile->WriteString( brokenModel );
  205.     savefile->WriteString( damage );
  206.     savefile->WriteInt( nextCollideFxTime );
  207.      savefile->WriteFloat( minDamageVelocity );
  208.      savefile->WriteFloat( maxDamageVelocity );
  209.  
  210.     savefile->WriteInt( initialSpline != NULL ? initialSpline->GetTime( 0 ) : -1 );
  211.     savefile->WriteVec3( initialSplineDir );
  212.  
  213.     savefile->WriteBool( unbindOnDeath );
  214.     savefile->WriteBool( allowStep );
  215.     savefile->WriteBool( canDamage );
  216.     
  217.     lastAttacker.Save(savefile);        // cnicholson: Added unsaved var
  218. }
  219.  
  220. /*
  221. ================
  222. idMoveable::Restore
  223. ================
  224. */
  225. void idMoveable::Restore( idRestoreGame *savefile ) {
  226.        int initialSplineTime;
  227.  
  228.     savefile->ReadStaticObject( physicsObj );
  229.  
  230.     savefile->ReadString( brokenModel );
  231.     savefile->ReadString( damage );
  232.     savefile->ReadInt( nextCollideFxTime );
  233.      savefile->ReadFloat( minDamageVelocity );
  234.      savefile->ReadFloat( maxDamageVelocity );
  235.  
  236.     savefile->ReadInt( initialSplineTime );
  237.     if ( initialSplineTime != -1 ) {
  238.            InitInitialSpline( initialSplineTime );
  239.      } else {
  240.          initialSpline = NULL;
  241.        }
  242.  
  243.     savefile->ReadVec3( initialSplineDir );
  244.     savefile->ReadBool( unbindOnDeath );
  245.     savefile->ReadBool( allowStep );
  246.     savefile->ReadBool( canDamage );    // cnicholson: Added unrestored var
  247.  
  248.     lastAttacker.Restore(savefile);        // cnicholson: Added unrestored var
  249.  
  250.        RestorePhysics( &physicsObj );
  251. }
  252.  
  253. /*
  254. ================
  255. idMoveable::Hide
  256. ================
  257. */
  258. void idMoveable::Hide( void ) {
  259. // RAVEN BEGIN
  260. // abahr: changed parent scope
  261.     idDamagable::Hide();
  262.     physicsObj.SetContents( 0 );
  263. }
  264.  
  265. /*
  266. ================
  267. idMoveable::Show
  268. ================
  269. */
  270. void idMoveable::Show( void ) {
  271. // RAVEN BEGIN
  272. // abahr: changed parent scope
  273.     idDamagable::Show();
  274.     if ( !spawnArgs.GetBool( "nonsolid" ) ) {
  275.         physicsObj.SetContents( CONTENTS_SOLID );
  276.     }
  277. }
  278.  
  279. /*
  280. =================
  281. idMoveable::Collide
  282. =================
  283. */
  284. bool idMoveable::Collide( const trace_t &collision, const idVec3 &velocity ) {
  285.     float len, f;
  286.     idVec3 dir;
  287.     idEntity *ent;
  288.  
  289.     dir = velocity;
  290.     len = dir.NormalizeFast();
  291.  
  292.     if ( len > BOUNCE_SOUND_MIN_VELOCITY ) {
  293.         if ( gameLocal.time > nextCollideFxTime ) {
  294.             PlayEffect ( gameLocal.GetEffect(spawnArgs,"fx_collide",collision.c.materialType), collision.c.point, collision.c.normal.ToMat3() );
  295. // RAVEN BEGIN
  296. // jscott: fixed negative sqrt call
  297.             if( len > BOUNCE_SOUND_MAX_VELOCITY ) {
  298.                 f = 1.0f;
  299.             } else if( len <= BOUNCE_SOUND_MIN_VELOCITY ) {
  300.                 f = 0.0f;
  301.             } else {
  302.                 f = ( len - BOUNCE_SOUND_MIN_VELOCITY ) * ( 1.0f / ( BOUNCE_SOUND_MAX_VELOCITY - BOUNCE_SOUND_MIN_VELOCITY ) );
  303.             }
  304. // RAVEN END
  305.             SetSoundVolume( f );
  306.             StartSound( "snd_bounce", SND_CHANNEL_BODY, 0, false, NULL );
  307.  
  308.             nextCollideFxTime = gameLocal.time + BOUNCE_SOUND_DELAY_MIN + gameLocal.random.RandomInt(BOUNCE_SOUND_DELAY_MAX - BOUNCE_SOUND_DELAY_MIN);
  309.         }
  310.     }
  311.  
  312.     if ( canDamage && damage.Length() ) {
  313.         ent = gameLocal.entities[ collision.c.entityNum ];
  314.         if ( ent && len > minDamageVelocity ) {
  315. // RAVEN BEGIN
  316. // jscott: fixed negative sqrt call
  317.             if( len > maxDamageVelocity ) {
  318.                 f = 1.0f;
  319.             } else if( len <= minDamageVelocity ) {
  320.                 f = 0.0f;
  321.             } else {
  322.                 f = idMath::Sqrt( len - minDamageVelocity ) * ( 1.0f / idMath::Sqrt( maxDamageVelocity - minDamageVelocity ) );
  323.             }
  324. // RAVEN END
  325.             ent->Damage( this, GetPhysics()->GetClipModel()->GetOwner(), dir, damage, f, INVALID_JOINT );
  326.         }
  327.     }
  328.  
  329.     return false;
  330. }
  331.  
  332. /*
  333. ============
  334. idMoveable::Damage
  335. ============
  336. */
  337. void idMoveable::Damage( idEntity *inflictor, idEntity *attacker, const idVec3 &dir, const char *damageDefName, const float damageScale, const int location ) {
  338.     idDamagable::Damage ( inflictor, attacker, dir, damageDefName, damageScale, location );
  339.     
  340.     // Cache the attacker to ensure credit for a kill is given to the entity that caused the damage
  341.     lastAttacker = inflictor;
  342. // jshepard:
  343. //    gameLocal.Warning("idMoveable Damaged! Health is %d", health);
  344.  
  345. }
  346.  
  347. /*
  348. ============
  349. idMoveable::Killed
  350. ============
  351. */
  352. void idMoveable::Killed( idEntity *inflictor, idEntity *attacker, int damage, const idVec3 &dir, int location ) {
  353.  
  354. // jshepard: I am dead!
  355. //    gameLocal.Warning("idMoveable Killed! Health is %d", health);
  356.  
  357. /*
  358.     // No more taking damage
  359.     fl.takedamage = false;
  360.     
  361.     // Should the moveable launch around when killed?
  362.     int launchTime;
  363.     launchTime = SEC2MS ( spawnArgs.GetFloat ( "launch_time", "0" );    
  364.     if ( launchTime > 0 ) {
  365.         launchOffset = spawnArgs.GetVector ( "launch_offset" );
  366.         launchDir    = spawnArgs.GetVector ( "        
  367.     }
  368.     
  369.     spawnArgs.GetFloat ( "explode_lapse", 
  370.     PostEventSec ( &EV_Remove, explodeLapse );
  371.     
  372.     // Two part explosion?
  373.     explode_impulse
  374.     explode_lapse
  375.  
  376.     if ( unbindOnDeath ) {
  377.         Unbind();
  378.     }
  379.  
  380.     if ( brokenModel != "" ) {
  381.         SetModel( brokenModel );
  382.     }
  383.  
  384.     if ( explode ) {    
  385.         if ( brokenModel == "" ) {
  386.             Hide();
  387.             physicsObj.PutToRest();
  388.             GetPhysics()->SetContents( 0 );
  389.             PostEventMS( &EV_Remove, 0 );
  390.         }
  391.  
  392.         const char *splash = spawnArgs.GetString( "def_splash_damage", "" );
  393.         if ( splash && *splash ) {
  394.             gameLocal.RadiusDamage( GetPhysics()->GetOrigin(), inflictor, inflictor, this, this, splash );
  395.         }
  396.  
  397.         StartSound( "snd_explode", SND_CHANNEL_ANY );
  398.  
  399.         StopAllEffects ( );
  400.         gameLocal.PlayEffect ( gameLocal.GetEffect(spawnArgs, "fx_explode"), GetPhysics()->GetOrigin(), (-GetPhysics()->GetGravityNormal()).ToMat3(), false, vec3_origin, true );                
  401.     }
  402.  
  403.     if ( renderEntity.gui[ 0 ] ) {
  404.         renderEntity.gui[ 0 ] = NULL;
  405.     }
  406.  
  407.     ActivateTargets( this );
  408.  
  409.     fl.takedamage = false;
  410. */
  411. }
  412.  
  413.  
  414. /*
  415. ================
  416. idMoveable::ExecuteStage
  417. ================
  418. */
  419. void idMoveable::ExecuteStage ( void ) {
  420.     // Splash damage?
  421.     const char *splash;
  422.     if ( stageDict->GetString( "def_splash_damage", "", &splash ) && *splash ) {
  423. //        gameLocal.RadiusDamage( GetPhysics()->GetOrigin(), this, lastAttacker.GetEntity()?lastAttacker.GetEntity():this, this, this, splash );
  424.         PostEventMS( &EV_RadiusDamage, 0, lastAttacker.GetEntity()?lastAttacker.GetEntity():this, splash );
  425.     }
  426.  
  427.     idDamagable::ExecuteStage();
  428. }
  429.  
  430. /*
  431. ================
  432. idMoveable::AddDamageEffect
  433. ================
  434. */
  435. void idMoveable::AddDamageEffect ( const trace_t &collision, const idVec3 &velocity, const char *damageDefName, idEntity* inflictor ) {
  436.  
  437.     // Play an impact effect during this stage?
  438.     if ( stageDict ) {
  439.         PlayEffect ( gameLocal.GetEffect ( *stageDict, "fx_impact" ),
  440.                      collision.c.point, collision.c.normal.ToMat3(), 
  441.                      true, vec3_origin, true );
  442.     }                     
  443. }
  444.  
  445. /*
  446. ================
  447. idMoveable::AllowStep
  448. ================
  449. */
  450. bool idMoveable::AllowStep( void ) const {
  451.     return allowStep;
  452. }
  453.  
  454. /*
  455. ================
  456. idMoveable::BecomeNonSolid
  457. ================
  458. */
  459. void idMoveable::BecomeNonSolid( void ) {
  460.     // set CONTENTS_RENDERMODEL so bullets still collide with the moveable
  461.     physicsObj.SetContents( CONTENTS_CORPSE | CONTENTS_RENDERMODEL );
  462.     physicsObj.SetClipMask( MASK_SOLID | CONTENTS_CORPSE | CONTENTS_MOVEABLECLIP );
  463. }
  464.  
  465. /*
  466. ================
  467. idMoveable::EnableDamage
  468. ================
  469. */
  470. void idMoveable::EnableDamage( bool enable, float duration ) {
  471.     canDamage = enable;
  472.     if ( duration ) {
  473.         PostEventSec( &EV_CanDamage, duration, ( !enable ) ? 0.0f : 1.0f );
  474.     }
  475. }
  476.  
  477. /*
  478. ================
  479. idMoveable::InitInitialSpline
  480. ================
  481. */
  482. void idMoveable::InitInitialSpline( int startTime ) {
  483.     int initialSplineTime;
  484.  
  485.     initialSpline = GetSpline();
  486.     initialSplineTime = spawnArgs.GetInt( "initialSplineTime", "300" );
  487.  
  488.     if ( initialSpline != NULL ) {
  489.         initialSpline->MakeUniform( initialSplineTime );
  490.         initialSpline->ShiftTime( startTime - initialSpline->GetTime( 0 ) );
  491.         initialSplineDir = initialSpline->GetCurrentFirstDerivative( startTime );
  492.         initialSplineDir *= physicsObj.GetAxis().Transpose();
  493.         initialSplineDir.Normalize();
  494.         BecomeActive( TH_THINK );
  495.     }
  496. }
  497.  
  498. /*
  499. ================
  500. idMoveable::FollowInitialSplinePath
  501. ================
  502. */
  503. bool idMoveable::FollowInitialSplinePath( void ) {
  504.     if ( initialSpline != NULL ) {
  505.         if ( gameLocal.time < initialSpline->GetTime( initialSpline->GetNumValues() - 1 ) ) {
  506.             idVec3 splinePos = initialSpline->GetCurrentValue( gameLocal.time );
  507.             idVec3 linearVelocity = ( splinePos - physicsObj.GetOrigin() ) * gameLocal.GetMHz();
  508.             physicsObj.SetLinearVelocity( linearVelocity );
  509.  
  510.             idVec3 splineDir = initialSpline->GetCurrentFirstDerivative( gameLocal.time );
  511.             idVec3 dir = initialSplineDir * physicsObj.GetAxis();
  512.             idVec3 angularVelocity = dir.Cross( splineDir );
  513.             angularVelocity.Normalize();
  514.             angularVelocity *= idMath::ACos16( dir * splineDir / splineDir.Length() ) * gameLocal.GetMHz();
  515.             physicsObj.SetAngularVelocity( angularVelocity );
  516.             return true;
  517.         } else {
  518.             delete initialSpline;
  519.             initialSpline = NULL;
  520.         }
  521.     }
  522.     return false;
  523. }
  524.  
  525. /*
  526. ================
  527. idMoveable::Think
  528. ================
  529. */
  530. void idMoveable::Think( void ) {
  531.     if ( thinkFlags & TH_THINK ) {
  532.         // Move to the next stage?
  533.         UpdateStage ( );
  534.  
  535.         if ( !FollowInitialSplinePath() && stage == -1 ) {
  536.             BecomeInactive( TH_THINK );
  537.         }
  538.     }
  539. // RAVEN BEGIN
  540. // abahr: changed parent scope
  541.     idDamagable::Think();
  542. }
  543.  
  544. /*
  545. ================
  546. idMoveable::GetRenderModelMaterial
  547. ================
  548. */
  549. const idMaterial *idMoveable::GetRenderModelMaterial( void ) const {
  550.     if ( renderEntity.customShader ) {
  551.         return renderEntity.customShader;
  552.     }
  553.     if ( renderEntity.hModel && renderEntity.hModel->NumSurfaces() ) {
  554.          return renderEntity.hModel->Surface( 0 )->shader;
  555.     }
  556.     return NULL;
  557. }
  558.  
  559. /*
  560. ================
  561. idMoveable::WriteToSnapshot
  562. ================
  563. */
  564. void idMoveable::WriteToSnapshot( idBitMsgDelta &msg ) const {
  565.     physicsObj.WriteToSnapshot( msg );
  566. }
  567.  
  568. /*
  569. ================
  570. idMoveable::ReadFromSnapshot
  571. ================
  572. */
  573. void idMoveable::ReadFromSnapshot( const idBitMsgDelta &msg ) {
  574.     physicsObj.ReadFromSnapshot( msg );
  575.     if ( msg.HasChanged() ) {
  576.         UpdateVisuals();
  577.     }
  578. }
  579.  
  580. /*
  581. ================
  582. idMoveable::Event_BecomeNonSolid
  583. ================
  584. */
  585. void idMoveable::Event_BecomeNonSolid( void ) {
  586.     BecomeNonSolid();
  587. }
  588.  
  589. /*
  590. ================
  591. idMoveable::Event_Activate
  592. ================
  593. */
  594. void idMoveable::Event_Activate( idEntity *activator ) {
  595.     float delay;
  596.     idVec3 init_velocity, init_avelocity;
  597.  
  598.     Show();
  599.  
  600.     if ( !spawnArgs.GetInt( "notPushable" ) ) {
  601.         physicsObj.EnableImpact();
  602.     }
  603.  
  604.     physicsObj.Activate();
  605.  
  606.     spawnArgs.GetVector( "init_velocity", "0 0 0", init_velocity );
  607.     spawnArgs.GetVector( "init_avelocity", "0 0 0", init_avelocity );
  608.  
  609.     delay = spawnArgs.GetFloat( "init_velocityDelay", "0" );
  610.     if ( delay == 0.0f ) {
  611.         physicsObj.SetLinearVelocity( init_velocity );
  612.     } else {
  613.         PostEventSec( &EV_SetLinearVelocity, delay, init_velocity );
  614.     }
  615.  
  616.     delay = spawnArgs.GetFloat( "init_avelocityDelay", "0" );
  617.     if ( delay == 0.0f ) {
  618.         physicsObj.SetAngularVelocity( init_avelocity );
  619.     } else {
  620.         PostEventSec( &EV_SetAngularVelocity, delay, init_avelocity );
  621.     }
  622.  
  623.     InitInitialSpline( gameLocal.time );
  624.  
  625. // RAVEN BEGIN
  626. // jshepard: we should update it's stage on activation, specifically for falling blocks.
  627.     UpdateStage();
  628. // RAVEN END
  629.  
  630. }
  631.  
  632. /*
  633. ================
  634. idMoveable::Event_SetOwnerFromSpawnArgs
  635. ================
  636. */
  637. void idMoveable::Event_SetOwnerFromSpawnArgs( void ) {
  638.     idStr owner;
  639.  
  640.     if ( spawnArgs.GetString( "owner", "", owner ) ) {
  641.         ProcessEvent( &EV_SetOwner, gameLocal.FindEntity( owner ) );
  642.     }
  643. }
  644.  
  645. /*
  646. ================
  647. idMoveable::Event_IsAtRest
  648. ================
  649. */
  650. void idMoveable::Event_IsAtRest( void ) {
  651.     idThread::ReturnInt( physicsObj.IsAtRest() );
  652. }
  653.  
  654. /*
  655. ================
  656. idMoveable::Event_CanDamage
  657. ================
  658. */
  659. void idMoveable::Event_CanDamage( float enable ) {
  660.     canDamage = ( enable != 0.0f );
  661. }
  662.  
  663. /*
  664. ================
  665. idMoveable::Event_SetHealth
  666. ================
  667. */
  668. void idMoveable::Event_SetHealth( float newHealth ) {
  669.     health = newHealth;
  670. }
  671.  
  672. /*
  673. ================
  674. idMoveable::Event_RadiusDamage
  675. ================
  676. */
  677. void idMoveable::Event_RadiusDamage( idEntity *attacker, const char* splash ) {
  678.     gameLocal.RadiusDamage( GetPhysics()->GetOrigin(), this, attacker, this, this, splash );
  679. }
  680.  
  681. /*
  682. ===============================================================================
  683.  
  684.   idBarrel
  685.     
  686. ===============================================================================
  687. */
  688.  
  689. CLASS_DECLARATION( idMoveable, idBarrel )
  690. END_CLASS
  691.  
  692. /*
  693. ================
  694. idBarrel::idBarrel
  695. ================
  696. */
  697. idBarrel::idBarrel() {
  698.     radius = 1.0f;
  699.     barrelAxis = 0;
  700.     lastOrigin.Zero();
  701.     lastAxis.Identity();
  702.     additionalRotation = 0.0f;
  703.     additionalAxis.Identity();
  704.     fl.networkSync = true;
  705. }
  706.  
  707. /*
  708. ================
  709. idBarrel::Save
  710. ================
  711. */
  712. void idBarrel::Save( idSaveGame *savefile ) const {
  713.     savefile->WriteFloat( radius );
  714.     savefile->WriteInt( barrelAxis );
  715.     savefile->WriteVec3( lastOrigin );
  716.     savefile->WriteMat3( lastAxis );
  717.     savefile->WriteFloat( additionalRotation );
  718.     savefile->WriteMat3( additionalAxis );
  719. }
  720.  
  721. /*
  722. ================
  723. idBarrel::Restore
  724. ================
  725. */
  726. void idBarrel::Restore( idRestoreGame *savefile ) {
  727.     savefile->ReadFloat( radius );
  728.     savefile->ReadInt( barrelAxis );
  729.     savefile->ReadVec3( lastOrigin );
  730.     savefile->ReadMat3( lastAxis );
  731.     savefile->ReadFloat( additionalRotation );
  732.     savefile->ReadMat3( additionalAxis );
  733. }
  734.  
  735. /*
  736. ================
  737. idBarrel::BarrelThink
  738. ================
  739. */
  740. void idBarrel::BarrelThink( void ) {
  741.     bool wasAtRest, onGround;
  742.     float movedDistance, rotatedDistance, angle;
  743.     idVec3 curOrigin, gravityNormal, dir;
  744.     idMat3 curAxis, axis;
  745.  
  746.     wasAtRest = IsAtRest();
  747.  
  748.     // Progress to the next stage?
  749.     UpdateStage ( );
  750.     
  751.     // run physics
  752.     RunPhysics();
  753.  
  754.     // only need to give the visual model an additional rotation if the physics were run
  755.     if ( !wasAtRest ) {
  756.  
  757.         // current physics state
  758.         onGround = GetPhysics()->HasGroundContacts();
  759.         curOrigin = GetPhysics()->GetOrigin();
  760.         curAxis = GetPhysics()->GetAxis();
  761.  
  762.         // if the barrel is on the ground
  763.         if ( onGround ) {
  764.             gravityNormal = GetPhysics()->GetGravityNormal();
  765.  
  766.             dir = curOrigin - lastOrigin;
  767.             dir -= gravityNormal * dir * gravityNormal;
  768.             movedDistance = dir.LengthSqr();
  769.  
  770.             // if the barrel moved and the barrel is not aligned with the gravity direction
  771.             if ( movedDistance > 0.0f && idMath::Fabs( gravityNormal * curAxis[barrelAxis] ) < 0.7f ) {
  772.  
  773.                 // barrel movement since last think frame orthogonal to the barrel axis
  774.                 movedDistance = idMath::Sqrt( movedDistance );
  775.                 dir *= 1.0f / movedDistance;
  776.                 movedDistance = ( 1.0f - idMath::Fabs( dir * curAxis[barrelAxis] ) ) * movedDistance;
  777.  
  778.                 // get rotation about barrel axis since last think frame
  779.                 angle = lastAxis[(barrelAxis+1)%3] * curAxis[(barrelAxis+1)%3];
  780.                 angle = idMath::ACos( angle );
  781.                 // distance along cylinder hull
  782.                 rotatedDistance = angle * radius;
  783.  
  784.                 // if the barrel moved further than it rotated about it's axis
  785.                 if ( movedDistance > rotatedDistance ) {
  786.  
  787.                     // additional rotation of the visual model to make it look
  788.                     // like the barrel rolls instead of slides
  789.                     angle = 180.0f * (movedDistance - rotatedDistance) / (radius * idMath::PI);
  790.                     if ( gravityNormal.Cross( curAxis[barrelAxis] ) * dir < 0.0f ) {
  791.                         additionalRotation += angle;
  792.                     } else {
  793.                         additionalRotation -= angle;
  794.                     }
  795.                     dir = vec3_origin;
  796.                     dir[barrelAxis] = 1.0f;
  797.                     additionalAxis = idRotation( vec3_origin, dir, additionalRotation ).ToMat3();
  798.                 }
  799.             }
  800.         }
  801.  
  802.         // save state for next think
  803.         lastOrigin = curOrigin;
  804.         lastAxis = curAxis;
  805.     }
  806.  
  807.     Present();
  808. }
  809.  
  810. /*
  811. ================
  812. idBarrel::Think
  813. ================
  814. */
  815. void idBarrel::Think( void ) {
  816.     if ( thinkFlags & TH_THINK ) {
  817.         if ( !FollowInitialSplinePath() && stage == -1 ) {
  818.             BecomeInactive( TH_THINK );
  819.         }
  820.     }
  821.  
  822.     BarrelThink();
  823. }
  824.  
  825. /*
  826. ================
  827. idBarrel::GetPhysicsToVisualTransform
  828. ================
  829. */
  830. bool idBarrel::GetPhysicsToVisualTransform( idVec3 &origin, idMat3 &axis ) {
  831.     origin = vec3_origin;
  832.     axis = additionalAxis;
  833.     return true;
  834. }
  835.  
  836. /*
  837. ================
  838. idBarrel::Spawn
  839. ================
  840. */
  841. void idBarrel::Spawn( void ) {
  842.     const idBounds &bounds = GetPhysics()->GetBounds();
  843.  
  844.     // radius of the barrel cylinder
  845.     radius = ( bounds[1][0] - bounds[0][0] ) * 0.5f;
  846.  
  847.     // always a vertical barrel with cylinder axis parallel to the z-axis
  848.     barrelAxis = 2;
  849.  
  850.     lastOrigin = GetPhysics()->GetOrigin();
  851.     lastAxis = GetPhysics()->GetAxis();
  852.  
  853.     additionalRotation = 0.0f;
  854.     additionalAxis.Identity();
  855. }
  856.  
  857. /*
  858. ================
  859. idBarrel::ClientPredictionThink
  860. ================
  861. */
  862. void idBarrel::ClientPredictionThink( void ) {
  863.     Think();
  864. }
  865.  
  866.  
  867. /*
  868. ===============================================================================
  869.  
  870. idExplodingBarrel
  871.  
  872. ===============================================================================
  873. */
  874. const idEventDef EV_Respawn( "<respawn>" );
  875. const idEventDef EV_TriggerTargets( "<triggertargets>" );
  876.  
  877. CLASS_DECLARATION( idBarrel, idExplodingBarrel )
  878.     EVENT( EV_Activate,                    idExplodingBarrel::Event_Activate )
  879.     EVENT( EV_Respawn,                    idExplodingBarrel::Event_Respawn )
  880.     EVENT( EV_Explode,                    idExplodingBarrel::Event_Explode )
  881.     EVENT( EV_TriggerTargets,            idExplodingBarrel::Event_TriggerTargets )
  882. END_CLASS
  883.  
  884. /*
  885. ================
  886. idExplodingBarrel::idExplodingBarrel
  887. ================
  888. */
  889. idExplodingBarrel::idExplodingBarrel() {
  890.     spawnOrigin.Zero();
  891.     spawnAxis.Zero();
  892.     state = NORMAL;
  893.     ipsHandle = -1;
  894.     lightHandle = -1;
  895.     memset( &ipsEntity, 0, sizeof( ipsEntity ) );
  896.     memset( &light, 0, sizeof( light ) );
  897.     ipsTime = 0;
  898.     lightTime = 0;
  899.     time = 0.0f;
  900.      explodeFinishTime = 0;
  901. }
  902.  
  903. /*
  904. ================
  905. idExplodingBarrel::~idExplodingBarrel
  906. ================
  907. */
  908. idExplodingBarrel::~idExplodingBarrel() {
  909.     if ( ipsHandle >= 0 ){
  910.         gameRenderWorld->FreeEntityDef( ipsHandle );
  911.     }
  912.     if ( lightHandle >= 0 ) {
  913.         gameRenderWorld->FreeLightDef( lightHandle );
  914.     }
  915. }
  916.  
  917. /*
  918. ================
  919. idExplodingBarrel::Save
  920. ================
  921. */
  922. void idExplodingBarrel::Save( idSaveGame *savefile ) const {
  923.  
  924.     savefile->WriteInt( state );
  925.     savefile->WriteVec3( spawnOrigin );
  926.     savefile->WriteMat3( spawnAxis );
  927.     savefile->WriteInt( ipsHandle );
  928.     savefile->WriteInt( lightHandle );
  929.     savefile->WriteRenderEntity( ipsEntity );
  930.     savefile->WriteRenderLight( light );
  931.     savefile->WriteInt( ipsTime );
  932.     savefile->WriteInt( lightTime );
  933.     savefile->WriteFloat( time );
  934.     savefile->WriteInt( explodeFinishTime );
  935. }
  936.  
  937. /*
  938. ================
  939. idExplodingBarrel::Restore
  940. ================
  941. */
  942. void idExplodingBarrel::Restore( idRestoreGame *savefile ) {
  943.     
  944.     savefile->ReadInt( (int &)state );
  945.     savefile->ReadVec3( spawnOrigin );
  946.     savefile->ReadMat3( spawnAxis );
  947.     savefile->ReadInt( (int &)ipsHandle );
  948.     savefile->ReadInt( (int &)lightHandle );
  949. // RAVEN BEGIN
  950.     savefile->ReadRenderEntity( ipsEntity, &spawnArgs );
  951. // RAVEN END        
  952.     savefile->ReadRenderLight( light );
  953.     if ( lightHandle != -1 ) {
  954.         //get the handle again as it's out of date after a restore!
  955.         lightHandle = gameRenderWorld->AddLightDef( &light );
  956.     }
  957.     savefile->ReadInt( ipsTime );
  958.     savefile->ReadInt( lightTime );
  959.     savefile->ReadFloat( time );
  960.     savefile->ReadInt( explodeFinishTime );
  961.  
  962.     // precache decls
  963.     const char *splash = spawnArgs.GetString( "def_splash_damage", "damage_explosion" );
  964.     if ( splash && *splash ) {
  965.         declManager->FindType( DECL_ENTITYDEF, splash, false, false );
  966.     }
  967.     
  968.      if ( ipsHandle != -1 ) {
  969.          ipsHandle = gameRenderWorld->AddEntityDef( &ipsEntity );
  970.      }
  971. }
  972.  
  973. /*
  974. ================
  975. idExplodingBarrel::Spawn
  976. ================
  977. */
  978. void idExplodingBarrel::Spawn( void ) {
  979.     health = spawnArgs.GetInt( "health", "5" );
  980.     fl.takedamage = true;
  981.     spawnOrigin = GetPhysics()->GetOrigin();
  982.     spawnAxis = GetPhysics()->GetAxis();
  983.     state = NORMAL;
  984.     ipsHandle = -1;
  985.     lightHandle = -1;
  986.     lightTime = 0;
  987.     ipsTime = 0;
  988.     time = spawnArgs.GetFloat( "time" );
  989.     memset( &ipsEntity, 0, sizeof( ipsEntity ) );
  990.     memset( &light, 0, sizeof( light ) );
  991.     explodeFinishTime = 0;
  992.  
  993.     // precache decls
  994.     const char *splash = spawnArgs.GetString( "def_splash_damage", "damage_explosion" );
  995.     if ( splash && *splash ) {
  996.         declManager->FindType( DECL_ENTITYDEF, splash, false, false );
  997.     }
  998. }
  999.  
  1000. /*
  1001. ================
  1002. idExplodingBarrel::Think
  1003. ================
  1004. */
  1005. void idExplodingBarrel::Think( void ) {
  1006.     idBarrel::BarrelThink();
  1007.  
  1008.     // MP: EXPLODED means no effect on client when updating the state
  1009.     if ( !gameLocal.isClient && state == EXPLODING ) {
  1010.         if ( gameLocal.time > explodeFinishTime ) {
  1011.             state = EXPLODED;
  1012.         }
  1013.     }
  1014.  
  1015.     if ( lightHandle >= 0 ){
  1016.         if ( state == BURNING ) {
  1017.             // ramp the color up over 250 ms
  1018.             float pct = (gameLocal.time - lightTime) / 250.f;
  1019.             if ( pct > 1.0f ) {
  1020.                 pct = 1.0f;
  1021.             }
  1022.             light.origin = physicsObj.GetAbsBounds().GetCenter();
  1023.             light.axis = mat3_identity;
  1024.             light.shaderParms[ SHADERPARM_RED ] = pct;
  1025.             light.shaderParms[ SHADERPARM_GREEN ] = pct;
  1026.             light.shaderParms[ SHADERPARM_BLUE ] = pct;
  1027.             light.shaderParms[ SHADERPARM_ALPHA ] = pct;
  1028.             gameRenderWorld->UpdateLightDef( lightHandle, &light );
  1029.         } else {
  1030.             if ( gameLocal.time - lightTime > 250 ) {
  1031.                 gameRenderWorld->FreeLightDef( lightHandle );
  1032.                 lightHandle = -1;
  1033.             }
  1034.             return;
  1035.         }
  1036.     }
  1037.  
  1038.     if ( !gameLocal.isClient && state != BURNING && state != EXPLODING ) {
  1039.         BecomeInactive( TH_THINK );
  1040.         return;
  1041.     }
  1042.  
  1043.     if ( ipsHandle >= 0 ){
  1044.         ipsEntity.origin = physicsObj.GetAbsBounds().GetCenter();
  1045.         ipsEntity.axis = mat3_identity;
  1046.         gameRenderWorld->UpdateEntityDef( ipsHandle, &ipsEntity );
  1047.     }
  1048. }
  1049.    
  1050. /*
  1051. ================
  1052. idExplodingBarrel::AddIPS
  1053. ================
  1054. */
  1055. void idExplodingBarrel::AddIPS( const char *name, bool burn ) {
  1056.     if ( name && *name ) {
  1057.         if ( ipsHandle >= 0 ){
  1058.             gameRenderWorld->FreeEntityDef( ipsHandle );
  1059.         }
  1060.         memset( &ipsEntity, 0, sizeof ( ipsEntity ) );
  1061.         const idDeclModelDef *modelDef = static_cast<const idDeclModelDef *>( declManager->FindType( DECL_MODELDEF, name ) );
  1062.         if ( modelDef ) {
  1063.             ipsEntity.origin = physicsObj.GetAbsBounds().GetCenter();
  1064.             ipsEntity.axis = mat3_identity;
  1065.             ipsEntity.hModel = modelDef->ModelHandle();
  1066.             float rgb = ( burn ) ? 0.0f : 1.0f;
  1067.             ipsEntity.shaderParms[ SHADERPARM_RED ] = rgb;
  1068.             ipsEntity.shaderParms[ SHADERPARM_GREEN ] = rgb;
  1069.             ipsEntity.shaderParms[ SHADERPARM_BLUE ] = rgb;
  1070.             ipsEntity.shaderParms[ SHADERPARM_ALPHA ] = rgb;
  1071.             ipsEntity.shaderParms[ SHADERPARM_TIMEOFFSET ] = -MS2SEC( gameLocal.time );
  1072.             ipsEntity.shaderParms[ SHADERPARM_DIVERSITY ] = ( burn ) ? 1.0f : gameLocal.random.RandomInt( 90 );
  1073.             if ( !ipsEntity.hModel ) {
  1074.                 ipsEntity.hModel = renderModelManager->FindModel( name );
  1075.             }
  1076.             ipsHandle = gameRenderWorld->AddEntityDef( &ipsEntity );
  1077.             if ( burn ) {
  1078.                 BecomeActive( TH_THINK );
  1079.             }
  1080.             ipsTime = gameLocal.time;
  1081.         }
  1082.     }
  1083. }
  1084.  
  1085. /*
  1086. ================
  1087. idExplodingBarrel::AddLight
  1088. ================
  1089. */
  1090. void idExplodingBarrel::AddLight( const char *name, bool burn ) {
  1091.     if ( lightHandle >= 0 ){
  1092.         gameRenderWorld->FreeLightDef( lightHandle );
  1093.     }
  1094.     memset( &light, 0, sizeof ( light ) );
  1095.     light.axis = mat3_identity;
  1096.     light.lightRadius.x = spawnArgs.GetFloat( "light_radius" );
  1097.     light.lightRadius.y = light.lightRadius.z = light.lightRadius.x;
  1098.     light.origin = physicsObj.GetOrigin();
  1099.     light.origin.z += 128;
  1100.     light.pointLight = true;
  1101. // RAVEN BEGIN
  1102. // dluetscher: added detail levels to render lights
  1103.     light.detailLevel = DEFAULT_LIGHT_DETAIL_LEVEL;
  1104. // dluetscher: made sure that barrels are set to no shadows
  1105.     light.noShadows = true;
  1106. // RAVEN END
  1107.     light.shader = declManager->FindMaterial( name );
  1108.     light.shaderParms[ SHADERPARM_RED ] = 2.0f;
  1109.     light.shaderParms[ SHADERPARM_GREEN ] = 2.0f;
  1110.     light.shaderParms[ SHADERPARM_BLUE ] = 2.0f;
  1111.     light.shaderParms[ SHADERPARM_ALPHA ] = 2.0f;
  1112.     lightHandle = gameRenderWorld->AddLightDef( &light );
  1113.     lightTime = gameLocal.time;
  1114.     BecomeActive( TH_THINK );
  1115. }
  1116.  
  1117. /*
  1118. ================
  1119. idExplodingBarrel::ExplodingEffects
  1120. ================
  1121. */
  1122. void idExplodingBarrel::ExplodingEffects( void ) {
  1123.     const char *temp;
  1124.  
  1125.     StartSound( "snd_explode", SND_CHANNEL_ANY, 0, false, NULL );
  1126.  
  1127.     temp = spawnArgs.GetString( "model_damage", "" );
  1128.     if ( temp && *temp ) {
  1129.         SetModel( temp );
  1130.         Show();
  1131.     }
  1132.  
  1133. // RAVEN BEGIN
  1134. // bdube: replaced with playing an effect
  1135. /*
  1136.     temp = spawnArgs.GetString( "mtr_lightexplode", "" );
  1137.     if ( temp && *temp ) {
  1138.         AddLight( temp, false );
  1139.     }
  1140. */
  1141.     StopEffect ( "fx_burn" );
  1142.     gameLocal.PlayEffect ( gameLocal.GetEffect(spawnArgs, "fx_explode"), GetPhysics()->GetOrigin(), (-GetPhysics()->GetGravityNormal()).ToMat3(), false, vec3_origin, true );
  1143.  
  1144.     gameLocal.ProjectDecal( GetPhysics()->GetOrigin(), GetPhysics()->GetGravity(), 128.0f, true, 96.0f, "textures/decals/genericdamage" );
  1145. }
  1146.  
  1147. /*
  1148. ================
  1149. idExplodingBarrel::Killed
  1150. ================
  1151. */
  1152. void idExplodingBarrel::Killed( idEntity *inflictor, idEntity *attacker, int damage, const idVec3 &dir, int location ) {
  1153.  
  1154.      if ( IsHidden() || state == EXPLODED || state == EXPLODING || state == BURNING ) {
  1155.         return;
  1156.     }
  1157.  
  1158.     float f = spawnArgs.GetFloat( "burn" );
  1159.     if ( f > 0.0f && state == NORMAL ) {
  1160.         state = BURNING;
  1161.         PostEventSec( &EV_Explode, f );
  1162.         StartSound( "snd_burn", SND_CHANNEL_ANY, 0, false, NULL );
  1163.         PlayEffect ( gameLocal.GetEffect(spawnArgs,"fx_burn"), 
  1164.                      vec3_origin, (-GetPhysics()->GetGravityNormal()).ToMat3(), true, vec3_origin, true );                     
  1165.         return;
  1166.     } else {
  1167.         state = EXPLODING;
  1168.          spawnArgs.GetInt( "explode_lapse", "1000", explodeFinishTime );
  1169.          explodeFinishTime += gameLocal.time;
  1170.     }
  1171.  
  1172.     // do this before applying radius damage so the ent can trace to any damagable ents nearby
  1173.     Hide();
  1174.     physicsObj.SetContents( 0 );
  1175.  
  1176.     const char *splash = spawnArgs.GetString( "def_splash_damage", "damage_explosion" );
  1177.     if ( splash && *splash ) {
  1178. //        gameLocal.RadiusDamage( GetPhysics()->GetOrigin(), this, inflictor, this, this, splash );
  1179.         PostEventMS( &EV_RadiusDamage, 0, this, splash);
  1180.     }
  1181.  
  1182.     ExplodingEffects( );
  1183.  
  1184. // RAVEN BEGIN
  1185. // bdube: replaced with playing an effect
  1186. /*    
  1187.     //FIXME: need to precache all the debris stuff here and in the projectiles
  1188.     const idKeyValue *kv = spawnArgs.MatchPrefix( "def_debris" );
  1189.     // bool first = true;
  1190.     while ( kv ) {
  1191.         const idDict *debris_args = gameLocal.FindEntityDefDict( kv->GetValue(), false );
  1192.         if ( debris_args ) {
  1193.             idEntity *ent;
  1194.             idVec3 dir;
  1195.             idDebris *debris;
  1196.             //if ( first ) {
  1197.                 dir = physicsObj.GetAxis()[1];
  1198.             //    first = false;
  1199.             //} else {
  1200.                 dir.x += gameLocal.random.CRandomFloat() * 4.0f;
  1201.                 dir.y += gameLocal.random.CRandomFloat() * 4.0f;
  1202.                 //dir.z = gameLocal.random.RandomFloat() * 8.0f;
  1203.             //}
  1204.             dir.Normalize();
  1205.  
  1206.             gameLocal.SpawnEntityDef( *debris_args, &ent, false );
  1207.             if ( !ent || !ent->IsType( idDebris::Type ) ) {
  1208.                 gameLocal.Error( "'projectile_debris' is not an idDebris" );
  1209.             }
  1210.  
  1211.             debris = static_cast<idDebris *>(ent);
  1212.             debris->Create( this, physicsObj.GetOrigin(), dir.ToMat3() );
  1213.             debris->Launch();
  1214.             debris->GetRenderEntity()->shaderParms[ SHADERPARM_TIME_OF_DEATH ] = ( gameLocal.time + 1500 ) * 0.001f;
  1215.             debris->UpdateVisuals();
  1216.             
  1217.         }
  1218.         kv = spawnArgs.MatchPrefix( "def_debris", kv );
  1219.     }
  1220. */
  1221. // RAVEN END
  1222.  
  1223.     physicsObj.PutToRest();
  1224.     CancelEvents( &EV_Explode );
  1225.     CancelEvents( &EV_Activate );
  1226.  
  1227.     f = spawnArgs.GetFloat( "respawn" );
  1228.     if ( f > 0.0f ) {
  1229.         PostEventSec( &EV_Respawn, f );
  1230.     } else {
  1231.         PostEventMS( &EV_Remove, 5000 );
  1232.     }
  1233.  
  1234.     if ( spawnArgs.GetBool( "triggerTargets" ) ) {
  1235.         ActivateTargets( this );
  1236.     }
  1237. }
  1238.  
  1239. /*
  1240. ================
  1241. idExplodingBarrel::Think
  1242. ================
  1243. */
  1244. void idExplodingBarrel::Damage( idEntity *inflictor, idEntity *attacker, const idVec3 &dir, 
  1245.                       const char *damageDefName, const float damageScale, const int location ) {
  1246.  
  1247.  
  1248.     const idDict *damageDef = gameLocal.FindEntityDefDict( damageDefName, false );
  1249.     if ( !damageDef ) {
  1250.         gameLocal.Error( "Unknown damageDef '%s'\n", damageDefName );
  1251.     }
  1252.     if ( damageDef->FindKey( "radius" ) && GetPhysics()->GetContents() != 0 && GetBindMaster() == NULL ) {
  1253.         PostEventMS( &EV_Explode, 400 );
  1254.     } else {
  1255.         idEntity::Damage( inflictor, attacker, dir, damageDefName, damageScale, location );
  1256.     }
  1257. }
  1258.  
  1259.  
  1260. /*
  1261. ================
  1262. idExplodingBarrel::Event_TriggerTargets
  1263. ================
  1264. */
  1265. void idExplodingBarrel::Event_TriggerTargets() {
  1266.     ActivateTargets( this );
  1267. }
  1268.  
  1269. /*
  1270. ================
  1271. idExplodingBarrel::Event_Explode
  1272. ================
  1273. */
  1274. void idExplodingBarrel::Event_Explode() {
  1275.     if ( state == NORMAL || state == BURNING ) {
  1276.         state = BURNEXPIRED;
  1277.         Killed( NULL, NULL, 0, vec3_zero, 0 );
  1278.     }
  1279. }
  1280.  
  1281. /*
  1282. ================
  1283. idExplodingBarrel::Event_Respawn
  1284. ================
  1285. */
  1286. void idExplodingBarrel::Event_Respawn() {
  1287.      const char *temp = spawnArgs.GetString( "model" );
  1288.     if ( temp && *temp ) {
  1289.         SetModel( temp );
  1290.     }
  1291.     health = spawnArgs.GetInt( "health", "5" );
  1292.     fl.takedamage = (health > 0);
  1293.     physicsObj.SetOrigin( spawnOrigin );
  1294.     physicsObj.SetAxis( spawnAxis );
  1295.     physicsObj.SetContents( CONTENTS_SOLID );
  1296.     physicsObj.DropToFloor();
  1297.     state = NORMAL;
  1298.     Show();
  1299.     UpdateVisuals();
  1300. }
  1301.  
  1302. /*
  1303. ================
  1304. idMoveable::Event_Activate
  1305. ================
  1306. */
  1307. void idExplodingBarrel::Event_Activate( idEntity *activator ) {
  1308.     Killed( activator, activator, 0, vec3_origin, 0 );
  1309. }
  1310.  
  1311.  
  1312.  
  1313. /*
  1314. ================
  1315. idMoveable::WriteToSnapshot
  1316. ================
  1317. */
  1318. void idExplodingBarrel::WriteToSnapshot( idBitMsgDelta &msg ) const {
  1319.     idMoveable::WriteToSnapshot( msg );
  1320.     msg.WriteBits( IsHidden(), 1 );
  1321.     msg.WriteBits( state, 3 );
  1322. }
  1323.  
  1324. /*
  1325. ================
  1326. idMoveable::ReadFromSnapshot
  1327. ================
  1328. */
  1329. void idExplodingBarrel::ReadFromSnapshot( const idBitMsgDelta &msg ) {
  1330.     explode_state_t newState;
  1331.  
  1332.     idMoveable::ReadFromSnapshot( msg );
  1333.     if ( msg.ReadBits( 1 ) ) {
  1334.         Hide();
  1335.     } else {
  1336.         Show();
  1337.     }
  1338.     newState = (explode_state_t)msg.ReadBits( 3 );
  1339.     if ( newState != state ) {
  1340.         state = newState;
  1341.         if ( state == EXPLODING ) {
  1342.             ExplodingEffects( );
  1343.         }
  1344.     }
  1345. }
  1346.  
  1347. // RAVEN END
  1348.