home *** CD-ROM | disk | FTP | other *** search
/ GameStar 2006 March / Gamestar_82_2006-03_dvd.iso / DVDStar / Editace / quake4_sdkv10.exe / source / game / Actor.cpp next >
C/C++ Source or Header  |  2005-11-14  |  100KB  |  3,843 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.  
  12. #if !defined(__GAME_PROJECTILE_H__)
  13.     #include "Projectile.h"
  14. #endif
  15. #if !defined(__GAME_VEHICLE_H__)
  16.     #include "Vehicle/Vehicle.h"
  17. #endif
  18.  
  19. #include "ai/AI.h"
  20. #include "ai/AI_Manager.h"
  21.  
  22. /***********************************************************************
  23.  
  24.     idAnimState
  25.  
  26. ***********************************************************************/
  27.  
  28. /*
  29. =====================
  30. idAnimState::idAnimState
  31. =====================
  32. */
  33. idAnimState::idAnimState() {
  34.     self            = NULL;
  35.     animator        = NULL;
  36.     idleAnim        = true;
  37.     disabled        = true;
  38.     channel            = ANIMCHANNEL_ALL;
  39.     animBlendFrames = 0;
  40.     lastAnimBlendFrames = 0;    
  41. }
  42.  
  43. /*
  44. =====================
  45. idAnimState::~idAnimState
  46. =====================
  47. */
  48. idAnimState::~idAnimState() {
  49. }
  50.  
  51. /*
  52. =====================
  53. idAnimState::Save
  54. =====================
  55. */
  56. void idAnimState::Save( idSaveGame *savefile ) const {
  57.  
  58.     savefile->WriteBool( idleAnim );
  59.     savefile->WriteInt( animBlendFrames );
  60.     savefile->WriteInt( lastAnimBlendFrames );
  61.  
  62.     savefile->WriteObject( self );
  63.  
  64.     // Save the entity owner of the animator
  65.     savefile->WriteObject( animator->GetEntity() );
  66.  
  67.     savefile->WriteInt( channel );
  68.     savefile->WriteBool( disabled );
  69.  
  70. // RAVEN BEGIN
  71. // abahr:
  72.     stateThread.Save( savefile );
  73. // RAVEN END
  74. }
  75.  
  76. /*
  77. =====================
  78. idAnimState::Restore
  79. =====================
  80. */
  81. void idAnimState::Restore( idRestoreGame *savefile ) {
  82.  
  83.     savefile->ReadBool( idleAnim );
  84.     savefile->ReadInt( animBlendFrames );
  85.     savefile->ReadInt( lastAnimBlendFrames );
  86.  
  87.     savefile->ReadObject( reinterpret_cast<idClass *&>( self ) );
  88.  
  89.     idEntity *animowner;
  90.     savefile->ReadObject( reinterpret_cast<idClass *&>( animowner ) );
  91.     if ( animowner ) {
  92.         animator = animowner->GetAnimator();
  93.     }
  94.  
  95.     savefile->ReadInt( channel );
  96.     savefile->ReadBool( disabled );
  97.  
  98. // RAVEN BEGIN
  99. // abahr:
  100.     stateThread.Restore( savefile, self );
  101. // RAVEN END
  102. }
  103.  
  104. /*
  105. =====================
  106. idAnimState::Init
  107. =====================
  108. */
  109. // RAVEN BEGIN
  110. // bdube: converted self to entity ptr so any entity can use it
  111. void idAnimState::Init( idEntity *owner, idAnimator *_animator, int animchannel ) {
  112. // RAVEN BEGIN
  113.     assert( owner );
  114.     assert( _animator );
  115.     self = owner;
  116.     animator = _animator;
  117.     channel = animchannel;
  118.  
  119.     stateThread.SetName ( va("%s_anim_%d", owner->GetName(), animchannel ) );
  120.     stateThread.SetOwner ( owner );    
  121. }
  122.  
  123. /*
  124. =====================
  125. idAnimState::Shutdown
  126. =====================
  127. */
  128. void idAnimState::Shutdown( void ) {
  129.     stateThread.Clear ( true );
  130. }
  131.  
  132. /*
  133. =====================
  134. idAnimState::PostState
  135. =====================
  136. */
  137. void idAnimState::PostState ( const char* statename, int blendFrames, int delay, int flags ) {
  138.     if ( SRESULT_OK != stateThread.PostState ( statename, blendFrames, delay, flags ) ) {
  139.         gameLocal.Error ( "Could not find state function '%s' for entity '%s'", statename, self->GetName() );
  140.     }
  141.     disabled = false;
  142. }
  143.  
  144. /*
  145. =====================
  146. idAnimState::SetState
  147. =====================
  148. */
  149. void idAnimState::SetState( const char *statename, int blendFrames, int flags ) {
  150.     if ( SRESULT_OK != stateThread.SetState ( statename, blendFrames, 0, flags ) ) {
  151.         gameLocal.Error ( "Could not find state function '%s' for entity '%s'", statename, self->GetName() );
  152.     }
  153.  
  154.     animBlendFrames = blendFrames;
  155.     lastAnimBlendFrames = blendFrames;
  156.     disabled = false;
  157.     idleAnim = false;
  158. }
  159.  
  160. /*
  161. =====================
  162. idAnimState::StopAnim
  163. =====================
  164. */
  165. void idAnimState::StopAnim( int frames ) {
  166.     animBlendFrames = 0;
  167.     animator->Clear( channel, gameLocal.time, FRAME2MS( frames ) );
  168. }
  169.  
  170. /*
  171. =====================
  172. idAnimState::PlayAnim
  173. =====================
  174. */
  175. void idAnimState::PlayAnim( int anim ) {
  176.     if ( anim ) {
  177.         animator->PlayAnim( channel, anim, gameLocal.time, FRAME2MS( animBlendFrames ) );
  178.     }
  179.     animBlendFrames = 0;
  180. }
  181.  
  182. /*
  183. =====================
  184. idAnimState::CycleAnim
  185. =====================
  186. */
  187. void idAnimState::CycleAnim( int anim ) {
  188.     if ( anim ) {
  189.         animator->CycleAnim( channel, anim, gameLocal.time, FRAME2MS( animBlendFrames ) );
  190.     }
  191.     animBlendFrames = 0;
  192. }
  193.  
  194. /*
  195. =====================
  196. idAnimState::BecomeIdle
  197. =====================
  198. */
  199. void idAnimState::BecomeIdle( void ) {
  200.     idleAnim = true;
  201. }
  202.  
  203. /*
  204. =====================
  205. idAnimState::Disabled
  206. =====================
  207. */
  208. bool idAnimState::Disabled( void ) const {
  209.     return disabled;
  210. }
  211.  
  212. /*
  213. =====================
  214. idAnimState::AnimDone
  215. =====================
  216. */
  217. bool idAnimState::AnimDone( int blendFrames ) const {
  218.     int animDoneTime;
  219.     
  220.     animDoneTime = animator->CurrentAnim( channel )->GetEndTime();
  221.     if ( animDoneTime < 0 ) {
  222.         // playing a cycle
  223.         return false;
  224.     } else if ( animDoneTime - FRAME2MS( blendFrames ) <= gameLocal.time ) {
  225.         return true;
  226.     } else {
  227.         return false;
  228.     }
  229. }
  230.  
  231. /*
  232. =====================
  233. idAnimState::IsIdle
  234. =====================
  235. */
  236. bool idAnimState::IsIdle( void ) const {
  237.     return disabled || idleAnim;
  238. }
  239.  
  240. /*
  241. =====================
  242. idAnimState::GetAnimFlags
  243. =====================
  244. */
  245. animFlags_t idAnimState::GetAnimFlags( void ) const {
  246.     animFlags_t flags;
  247.  
  248.     memset( &flags, 0, sizeof( flags ) );
  249.     if ( !disabled && !AnimDone( 0 ) ) {
  250.         flags = animator->GetAnimFlags( animator->CurrentAnim( channel )->AnimNum() );
  251.     }
  252.  
  253.     return flags;
  254. }
  255.  
  256. /*
  257. =====================
  258. idAnimState::Enable
  259. =====================
  260. */
  261. void idAnimState::Enable( int blendFrames ) {
  262.     if ( disabled ) {
  263.         disabled = false;
  264.         animBlendFrames = blendFrames;
  265.         lastAnimBlendFrames = blendFrames;
  266.     }
  267. }
  268.  
  269. /*
  270. =====================
  271. idAnimState::Disable
  272. =====================
  273. */
  274. void idAnimState::Disable( void ) {
  275.     disabled = true;
  276.     idleAnim = false;
  277. }
  278.  
  279. /*
  280. =====================
  281. idAnimState::UpdateState
  282. =====================
  283. */
  284. bool idAnimState::UpdateState( void ) {
  285.     if ( disabled ) {
  286.         return false;
  287.     }
  288.  
  289.     stateThread.Execute ( );
  290.  
  291.     return true;
  292. }
  293.  
  294. /***********************************************************************
  295.  
  296.     idActor
  297.  
  298. ***********************************************************************/
  299.  
  300. const idEventDef AI_EnableEyeFocus( "enableEyeFocus" );
  301. const idEventDef AI_DisableEyeFocus( "disableEyeFocus" );
  302. const idEventDef AI_EnableBlink( "enableBlinking" );
  303. const idEventDef AI_DisableBlink( "disableBlinking" );
  304. const idEventDef EV_Footstep( "footstep" );
  305. const idEventDef EV_FootstepLeft( "leftFoot" );
  306. const idEventDef EV_FootstepRight( "rightFoot" );
  307. const idEventDef EV_EnableWalkIK( "EnableWalkIK" );
  308. const idEventDef EV_DisableWalkIK( "DisableWalkIK" );
  309. const idEventDef EV_EnableLegIK( "EnableLegIK", "d" );
  310. const idEventDef EV_DisableLegIK( "DisableLegIK", "d" );
  311. const idEventDef AI_StopAnim( "stopAnim", "dd" );
  312. const idEventDef AI_PlayAnim( "playAnim", "ds", 'd' );
  313. const idEventDef AI_PlayCycle( "playCycle", "ds", 'd' );
  314. const idEventDef AI_IdleAnim( "idleAnim", "ds", 'd' );
  315. const idEventDef AI_SetSyncedAnimWeight( "setSyncedAnimWeight", "ddf" );
  316. const idEventDef AI_SetBlendFrames( "setBlendFrames", "dd" );
  317. const idEventDef AI_GetBlendFrames( "getBlendFrames", "d", 'd' );
  318. const idEventDef AI_AnimDone( "animDone", "dd", 'd' );
  319. const idEventDef AI_OverrideAnim( "overrideAnim", "d" );
  320. const idEventDef AI_EnableAnim( "enableAnim", "dd" );
  321. const idEventDef AI_PreventPain( "preventPain", "f" );
  322. const idEventDef AI_DisablePain( "disablePain" );
  323. const idEventDef AI_EnablePain( "enablePain" );
  324. const idEventDef AI_SetAnimPrefix( "setAnimPrefix", "s" );
  325. const idEventDef AI_HasEnemies( "hasEnemies", NULL, 'd' );
  326. const idEventDef AI_NextEnemy( "nextEnemy", "E", 'e' );
  327. const idEventDef AI_ClosestEnemyToPoint( "closestEnemyToPoint", "v", 'e' );
  328. const idEventDef AI_GetHead( "getHead", NULL, 'e' );
  329.  
  330.  
  331. // RAVEN BEGIN
  332. // bdube: added
  333. const idEventDef AI_Flashlight("flashlight", "d" );
  334. const idEventDef AI_Teleport("teleport", "vv");
  335. const idEventDef AI_EnterVehicle ( "enterVehicle", "e" );
  336. const idEventDef AI_ExitVehicle ( "exitVehicle", "d" );
  337. const idEventDef AI_PostExitVehicle ( "<exitVehicle>", "d" );
  338.  
  339. //jshepard: change animation rate
  340. const idEventDef AI_SetAnimRate ( "setAnimRate","f");
  341. //MCG: damage over time
  342. const idEventDef EV_DamageOverTime ( "damageOverTime","ddEEvsfd" );
  343. const idEventDef EV_DamageOverTimeEffect ( "damageOverTimeEffect","dds" );
  344. // MCG: script-callable joint crawl effect
  345. const idEventDef EV_JointCrawlEffect ( "jointCrawlEffect","sf" );
  346.  
  347. // RAVEN END
  348.  
  349. CLASS_DECLARATION( idAFEntity_Gibbable, idActor )
  350.     EVENT( AI_EnableEyeFocus,            idActor::Event_EnableEyeFocus )
  351.     EVENT( AI_DisableEyeFocus,            idActor::Event_DisableEyeFocus )
  352.     EVENT( AI_EnableBlink,                idActor::Event_EnableBlink )
  353.     EVENT( AI_DisableBlink,                idActor::Event_DisableBlink )
  354.     EVENT( EV_Footstep,                    idActor::Event_Footstep )
  355.     EVENT( EV_FootstepLeft,                idActor::Event_Footstep )
  356.     EVENT( EV_FootstepRight,            idActor::Event_Footstep )
  357.     EVENT( EV_EnableWalkIK,                idActor::Event_EnableWalkIK )
  358.     EVENT( EV_DisableWalkIK,            idActor::Event_DisableWalkIK )
  359.     EVENT( EV_EnableLegIK,                idActor::Event_EnableLegIK )
  360.     EVENT( EV_DisableLegIK,                idActor::Event_DisableLegIK )
  361.     EVENT( AI_PreventPain,                idActor::Event_PreventPain )
  362.     EVENT( AI_DisablePain,                idActor::Event_DisablePain )
  363.     EVENT( AI_EnablePain,                idActor::Event_EnablePain )
  364.     EVENT( AI_SetAnimPrefix,            idActor::Event_SetAnimPrefix )
  365.     EVENT( AI_SetSyncedAnimWeight,        idActor::Event_SetSyncedAnimWeight )
  366.     EVENT( AI_SetBlendFrames,            idActor::Event_SetBlendFrames )
  367.     EVENT( AI_GetBlendFrames,            idActor::Event_GetBlendFrames )
  368.     EVENT( AI_OverrideAnim,                idActor::Event_OverrideAnim )
  369.     EVENT( AI_EnableAnim,                idActor::Event_EnableAnim )
  370.     EVENT( AI_HasEnemies,                idActor::Event_HasEnemies )
  371.     EVENT( AI_NextEnemy,                idActor::Event_NextEnemy )
  372.     EVENT( AI_ClosestEnemyToPoint,        idActor::Event_ClosestEnemyToPoint )
  373.     EVENT( EV_StopSound,                idActor::Event_StopSound )
  374.     EVENT( AI_GetHead,                    idActor::Event_GetHead )
  375.  
  376. // RAVEN BEGIN
  377. // bdube: added
  378.     EVENT( AI_Flashlight,                idActor::Event_Flashlight )
  379.     EVENT( AI_Teleport,                    idActor::Event_Teleport )
  380.     EVENT( AI_EnterVehicle,                idActor::Event_EnterVehicle )
  381.  
  382.     // twhitaker: Yeah... this just got confusing.
  383.     // basically, I need a delay in between the time the space bar is hit and the time the person actually get's ejected.
  384.     // this is mostly for things such as screen fades when exiting a vehicle.  This was the least obtrusive way I could think of.
  385.     EVENT( AI_ExitVehicle,                idActor::Event_PreExitVehicle )
  386.     EVENT( AI_PostExitVehicle,            idActor::Event_ExitVehicle )
  387.  
  388. // jshepard: added
  389.     EVENT( AI_SetAnimRate,                idActor::Event_SetAnimRate )
  390.  
  391. // twhitaker: added animation support (mostly for vehicle purposes)
  392.     EVENT( AI_PlayAnim,                    idActor::Event_PlayAnim )
  393.  
  394. // MCG: added recurring damage
  395.     EVENT( EV_DamageOverTime,            idActor::Event_DamageOverTime )
  396.     EVENT( EV_DamageOverTimeEffect,        idActor::Event_DamageOverTimeEffect )
  397. // MCG: script-callable joint crawl effect
  398.     EVENT( EV_JointCrawlEffect,            idActor::Event_JointCrawlEffect )
  399. // RAVEN END
  400.  
  401. END_CLASS
  402.  
  403. CLASS_STATES_DECLARATION ( idActor )
  404.     STATE ( "Wait_Frame",                idActor::State_Wait_Frame )
  405.     STATE ( "Wait_LegsAnim",            idActor::State_Wait_LegsAnim )
  406.     STATE ( "Wait_TorsoAnim",            idActor::State_Wait_TorsoAnim )
  407. END_CLASS_STATES
  408.  
  409. // RAVEN END
  410.  
  411. /*
  412. =====================
  413. idActor::idActor
  414. =====================
  415. */
  416. idActor::idActor( void )
  417. {
  418.     viewAxis.Identity();
  419.  
  420.     use_combat_bbox        = false;
  421.     head                = NULL;
  422.  
  423.     eyeOffset.Zero();
  424.     chestOffset.Zero();
  425.     modelOffset.Zero();
  426.  
  427.     team                = 0;
  428.     rank                = 0;
  429.     fovDot                = 0.0f;
  430.     pain_debounce_time    = 0;
  431.     pain_delay            = 0;
  432.  
  433.     leftEyeJoint        = INVALID_JOINT;
  434.     rightEyeJoint        = INVALID_JOINT;
  435.     soundJoint            = INVALID_JOINT;
  436.  
  437.     deltaViewAngles.Zero();
  438.  
  439.     painTime            = 0;
  440.     inDamageEvent        = false;
  441. // RAVEN BEGIN
  442. // bdube: reversed var
  443.     disablePain            = true;
  444. // RAVEN END
  445.     allowEyeFocus        = false;
  446.     
  447.     blink_anim            = NULL;
  448.     blink_time            = 0;
  449.     blink_min            = 0;
  450.     blink_max            = 0;
  451.  
  452.     finalBoss            = false;
  453.  
  454.     attachments.SetGranularity( 1 );
  455.  
  456.     enemyNode.SetOwner( this );
  457.     enemyList.SetOwner( this );
  458.  
  459.     teamNode.SetOwner ( this );
  460.  
  461.     memset( &flashlight, 0, sizeof( flashlight ) );
  462.     flashlightHandle = -1;
  463.  
  464.     deathPushTime    = 0;
  465.     
  466.     eyeOffsetJoint = INVALID_JOINT;
  467.     chestOffsetJoint = INVALID_JOINT;
  468.  
  469.     lightningEffects = 0;
  470.     lightningNextTime = 0;
  471. }
  472.  
  473. /*
  474. =====================
  475. idActor::~idActor
  476. =====================
  477. */
  478. idActor::~idActor( void ) {
  479. // RAVEN BEGIN
  480. // bdube: flashlights
  481.     if ( flashlightHandle != -1 )    {
  482.         gameRenderWorld->FreeLightDef( flashlightHandle );
  483.         flashlightHandle = -1;
  484.     }
  485. // RAVEN END
  486.  
  487.     int i;
  488.     idEntity *ent;
  489.  
  490.     StopSound( SND_CHANNEL_ANY, false );
  491.  
  492.     delete combatModel;
  493.     combatModel = NULL;
  494.  
  495.     if ( head.GetEntity() ) {
  496.         head.GetEntity()->ClearBody();
  497.         head.GetEntity()->PostEventMS( &EV_Remove, 0 );
  498.     }
  499.  
  500.     // remove any attached entities
  501.     for( i = 0; i < attachments.Num(); i++ ) {
  502.         ent = attachments[ i ].ent.GetEntity();
  503.         if ( ent ) {
  504.             ent->PostEventMS( &EV_Remove, 0 );
  505.         }
  506.     }
  507.  
  508.     ShutdownThreads();
  509. }
  510.  
  511. /*
  512. =====================
  513. idActor::Spawn
  514. =====================
  515. */
  516. void idActor::Spawn( void ) {
  517.     idEntity        *ent;
  518.     idStr            jointName;
  519.     float            fovDegrees;
  520.     float            fovDegreesClose;
  521.  
  522.     animPrefix    = "";
  523.  
  524.     spawnArgs.GetInt( "rank", "0", rank );
  525.     spawnArgs.GetInt( "team", "0", team );
  526.     spawnArgs.GetVector( "offsetModel", "0 0 0", modelOffset );
  527.  
  528.     spawnArgs.GetBool( "use_combat_bbox", "0", use_combat_bbox );    
  529.  
  530.     viewAxis = GetPhysics()->GetAxis();
  531.  
  532.     spawnArgs.GetFloat( "fov", "90", fovDegrees );
  533.     spawnArgs.GetFloat( "fovClose", "200", fovDegreesClose );
  534.     spawnArgs.GetFloat( "fovCloseRange", "180", fovCloseRange );
  535.     SetFOV( fovDegrees, fovDegreesClose );
  536.  
  537.     pain_debounce_time    = 0;
  538.  
  539.     pain_delay = SEC2MS( spawnArgs.GetFloat( "pain_delay" ) );
  540.  
  541.     LoadAF ( );
  542.  
  543.     walkIK.Init( this, IK_ANIM, modelOffset );
  544.  
  545.     // the animation used to be set to the IK_ANIM at this point, but that was fixed, resulting in
  546.     // attachments not binding correctly, so we're stuck setting the IK_ANIM before attaching things.
  547.     animator.ClearAllAnims( gameLocal.time, 0 );
  548. // RAVEN BEGIN
  549. // jscott: new setframe stuff
  550.     frameBlend_t frameBlend = { 0, 0, 0, 1.0f, 0 };
  551.     animator.SetFrame( ANIMCHANNEL_ALL, animator.GetAnim( IK_ANIM ), frameBlend );
  552. // RAVEN END
  553.  
  554.     // spawn any attachments we might have
  555.     const idKeyValue *kv = spawnArgs.MatchPrefix( "def_attach", NULL );
  556.     while ( kv ) {
  557.         idDict args;
  558.  
  559.         args.Set( "classname", kv->GetValue().c_str() );
  560.  
  561.         // make items non-touchable so the player can't take them out of the character's hands
  562.         args.Set( "no_touch", "1" );
  563.  
  564.         // don't let them drop to the floor
  565.         args.Set( "dropToFloor", "0" );
  566.         
  567.         gameLocal.SpawnEntityDef( args, &ent );
  568.         if ( !ent ) {
  569.             gameLocal.Error( "Couldn't spawn '%s' to attach to entity '%s'", kv->GetValue().c_str(), name.c_str() );
  570.         } else {
  571.             Attach( ent );
  572.         }
  573.         kv = spawnArgs.MatchPrefix( "def_attach", kv );
  574.     }
  575.  
  576.     SetupDamageGroups();
  577.  
  578.     // MP sets up heads on players from UpdateModelSetup()
  579.     if( !gameLocal.isMultiplayer || !IsType( idPlayer::GetClassType() ) ) {
  580.         SetupHead ( );
  581.     }
  582.  
  583.     // clear the bind anim
  584.     animator.ClearAllAnims( gameLocal.time, 0 );
  585.  
  586.     idEntity *headEnt = head.GetEntity();
  587.     idAnimator *headAnimator;
  588.     if ( headEnt ) {
  589.         headAnimator = headEnt->GetAnimator();
  590.     } else {
  591.         headAnimator = &animator;
  592.     }
  593.  
  594.     // set up blinking
  595.     blink_anim = headAnimator->GetAnim( "blink" );
  596.     blink_time = 0;    // it's ok to blink right away
  597.     blink_min = SEC2MS( spawnArgs.GetFloat( "blink_min", "0.5" ) );
  598.     blink_max = SEC2MS( spawnArgs.GetFloat( "blink_max", "8" ) );
  599.     fl.allowAutoBlink    = spawnArgs.GetBool( "allowAutoBlink", "1" );
  600.  
  601.     if ( spawnArgs.GetString( "sound_bone", "", jointName ) ) {
  602.         soundJoint = animator.GetJointHandle( jointName );
  603.         if ( soundJoint == INVALID_JOINT ) {
  604.             gameLocal.Warning( "idAnimated '%s' at (%s): cannot find joint '%s' for sound playback", name.c_str(), GetPhysics()->GetOrigin().ToString(0), jointName.c_str() );
  605.         }
  606.     }
  607.  
  608.     finalBoss = spawnArgs.GetBool( "finalBoss" );
  609.  
  610. // RAVEN BEGIN
  611. // bdube: flashlight
  612.     flashlightJoint = animator.GetJointHandle( spawnArgs.GetString ( "joint_flashlight", "flashlight" ) );
  613.  
  614.     memset( &flashlight, 0, sizeof( flashlight ) );
  615.     flashlight.suppressLightInViewID = entityNumber + 1;
  616.     flashlight.allowLightInViewID = 0;
  617.     flashlight.lightId = 1 + entityNumber;    
  618.  
  619.     flashlight.allowLightInViewID = 1;
  620.  
  621.     idVec3    color;
  622.     spawnArgs.GetVector ( "flashlightColor", "1 1 1", color );
  623.     
  624.     flashlight.pointLight                            = spawnArgs.GetBool( "flashlightPointLight", "1" );
  625. // mwhitlock: Xenon texture streaming
  626. #if defined(_XENON)
  627.     declManager->SetLightMaterialList(&flashlight.allMaterials);
  628. #endif
  629.     flashlight.shader                                = declManager->FindMaterial( spawnArgs.GetString( "mtr_flashlight", "muzzleflash" ), false );
  630. // mwhitlock: Xenon texture streaming
  631. #if defined(_XENON)
  632.     declManager->SetLightMaterialList(0);
  633. #endif
  634.     flashlight.shaderParms[ SHADERPARM_RED ]        = color[0];
  635.     flashlight.shaderParms[ SHADERPARM_GREEN ]        = color[1];
  636.     flashlight.shaderParms[ SHADERPARM_BLUE ]        = color[2];
  637.     flashlight.shaderParms[ SHADERPARM_TIMESCALE ]    = 1.0f;
  638.  
  639. // RAVEN BEGIN
  640. // dluetscher: added a default detail level to each render light
  641.     flashlight.detailLevel = DEFAULT_LIGHT_DETAIL_LEVEL;
  642. // RAVEN END
  643.  
  644.     flashlight.lightRadius[0] = flashlight.lightRadius[1] = 
  645.         flashlight.lightRadius[2] = spawnArgs.GetFloat ( "flashlightRadius" );
  646.  
  647.     if ( !flashlight.pointLight ) {
  648.         flashlight.target    = spawnArgs.GetVector( "flashlightTarget" );
  649.         flashlight.up        = spawnArgs.GetVector( "flashlightUp" );
  650.         flashlight.right    = spawnArgs.GetVector( "flashlightRight" );
  651.         flashlight.end        = spawnArgs.GetVector( "flashlightTarget" );
  652.     }
  653.     
  654.     spawnArgs.GetVector ( "flashlightOffset", "0 0 0", flashlightOffset );
  655.  
  656.     if ( spawnArgs.GetString( "flashlight_flaresurf", NULL ) ) {
  657.         HideSurface( spawnArgs.GetString( "flashlight_flaresurf", NULL ) );
  658.     }
  659.  
  660. // RAVEN END
  661.  
  662.     stateThread.SetName ( GetName() );
  663.     stateThread.SetOwner ( this );
  664.  
  665. // RAVEN BEGIN
  666. // cdr: Obstacle Avoidance
  667.     fl.isAIObstacle = true;
  668. // RAVEN END
  669.  
  670.     FinishSetup();
  671. }
  672.  
  673. /*
  674. ================
  675. idActor::FinishSetup
  676. ================
  677. */
  678. void idActor::FinishSetup( void ) {
  679.     if ( spawnArgs.GetBool ( "flashlight", "0" ) ) {
  680.         FlashlightUpdate ( true );
  681.     }
  682.  
  683.     SetupBody();
  684. }
  685.  
  686. /*
  687. ================
  688. idActor::SetupHead
  689. ================
  690. */
  691. void idActor::SetupHead( const char* headDefName, idVec3 headOffset ) {
  692.     idAFAttachment        *headEnt;
  693.     idStr                jointName;
  694.     jointHandle_t        joint;
  695.     const idKeyValue    *sndKV;
  696.  
  697.     if ( gameLocal.isClient && head.GetEntity() == NULL ) {
  698.         return;
  699.     }
  700.  
  701.     // If we don't pass in a specific head model, try looking it up
  702.     if( !headDefName[ 0 ] ) {
  703.         headDefName = spawnArgs.GetString( "def_head", "" );
  704. // jshepard: allow for heads to override persona defs
  705.         headDefName = spawnArgs.GetString( "override_head", headDefName );        
  706.     } 
  707.  
  708.     if ( headDefName[ 0 ] ) {
  709.         // free the old head if we want a new one
  710.         if( gameLocal.isServer ) {
  711.             if( head && idStr::Icmp( head->spawnArgs.GetString( "classname" ), headDefName ) ) {
  712.                 head->SetName( va( "%s_oldhead", name.c_str() ) );
  713.                 head->PostEventMS( &EV_Remove, 0 );
  714.                 head = NULL;
  715.             } else if( head ) {
  716.                 // the current head is OK
  717.                 return;
  718.             }
  719.         }
  720.  
  721.         jointName = spawnArgs.GetString( "joint_head" );
  722.         joint = animator.GetJointHandle( jointName );
  723.         if ( joint == INVALID_JOINT ) {
  724.             gameLocal.Error( "Joint '%s' not found for 'joint_head' on '%s'", jointName.c_str(), name.c_str() );
  725.         }
  726.  
  727.         // copy any sounds in case we have frame commands on the head
  728.         idDict    args;
  729.         sndKV = spawnArgs.MatchPrefix( "snd_", NULL );
  730.         while( sndKV ) {
  731.             args.Set( sndKV->GetKey(), sndKV->GetValue() );
  732.             sndKV = spawnArgs.MatchPrefix( "snd_", sndKV );
  733.         }
  734.  
  735.         if ( !gameLocal.isClient ) {
  736.             args.Set( "classname", headDefName );
  737.             if( !gameLocal.SpawnEntityDef( args, ( idEntity ** )&headEnt ) ) {
  738.                 gameLocal.Warning( "idActor::SetupHead() - Unknown head model '%s'\n", headDefName );
  739.                 return;
  740.             }
  741.             headEnt->spawnArgs.Set( "classname", headDefName );
  742.  
  743.             headEnt->SetName( va( "%s_head", name.c_str() ) );
  744.             headEnt->SetBody ( this, headEnt->spawnArgs.GetString ( "model" ), joint );
  745.             head = headEnt;
  746.         } else {
  747.             // we got our spawnid from the server
  748.             headEnt = head.GetEntity();
  749.             headEnt->SetBody ( this, headEnt->spawnArgs.GetString ( "model" ), joint );
  750.             headEnt->GetRenderEntity()->suppressSurfaceInViewID = entityNumber + 1;
  751.         }
  752.  
  753.         headEnt->BindToJoint( this, joint, true );
  754.         headEnt->GetPhysics()->SetOrigin( vec3_origin + headOffset);        
  755.         headEnt->GetPhysics()->SetAxis( mat3_identity );
  756.     } else if ( head ) {
  757.         head->PostEventMS( &EV_Remove, 0 );
  758.         head = NULL;
  759.     }
  760.  
  761.     if ( head ) {
  762.         int i;
  763.         // set the damage joint to be part of the head damage group
  764.         for( i = 0; i < damageGroups.Num(); i++ ) {
  765.             if ( damageGroups[ i ] == "head" ) {
  766.                 head->SetDamageJoint ( static_cast<jointHandle_t>( i ) );
  767.                 break;
  768.             }
  769.         }
  770.         
  771.         head->InitCopyJoints ( );
  772.         head->SetInstance( instance );
  773.     }
  774. }
  775.  
  776. /*
  777. ================
  778. idActor::Restart
  779. ================
  780. */
  781. void idActor::Restart( void ) {
  782.     assert( !head.GetEntity() );
  783.     // MP sets up heads from UpdateModelSetup()
  784.     if( !gameLocal.isMultiplayer ) {
  785.         SetupHead();
  786.     }
  787.     FinishSetup();
  788. }
  789.  
  790. /*
  791. ================
  792. idActor::Save
  793.  
  794. archive object for savegame file
  795. ================
  796. */
  797. void idActor::Save( idSaveGame *savefile ) const {
  798.     idActor *ent;
  799.     int i;
  800.  
  801.     savefile->WriteInt( team );
  802.  
  803.     // cnicholson:     This line was already commented out, so we aint changing it.
  804.     // No need to write/read teamNode
  805.     // idLinkList<idActor>        teamNode;
  806.  
  807.     savefile->WriteInt( rank );
  808.     savefile->WriteMat3( viewAxis );
  809.  
  810. // twhitaker: this confuses me... should we be writing out enemyList.Num() or enemyList.Next()->enemyNode->Num().  I'm not sure what these variables represent.
  811. // cnicholson: bdube said to do it how id does it, so here goes:
  812.     savefile->WriteInt( enemyList.Num() );
  813.     for ( ent = enemyList.Next(); ent != NULL; ent = ent->enemyNode.Next() ) {
  814.         savefile->WriteObject( ent );
  815.     }
  816.  
  817.     savefile->WriteInt( lightningNextTime );// cnicholson: Added unwritten var
  818.     savefile->WriteInt( lightningEffects );    // cnicholson: Added unwritten var
  819.  
  820.     savefile->WriteFloat( fovDot );
  821.     savefile->WriteFloat( fovCloseDot );
  822.     savefile->WriteFloat( fovCloseRange );
  823.     savefile->WriteVec3( eyeOffset );
  824.     savefile->WriteVec3( chestOffset );
  825.     savefile->WriteVec3( modelOffset );
  826.     savefile->WriteAngles( deltaViewAngles );
  827.  
  828.     savefile->WriteInt( pain_debounce_time );
  829.     savefile->WriteInt( pain_delay );
  830.  
  831.     savefile->WriteInt( damageGroups.Num() );
  832.     for( i = 0; i < damageGroups.Num(); i++ ) {
  833.         savefile->WriteString( damageGroups[ i ] );
  834.     }
  835.  
  836.     savefile->WriteInt( damageScale.Num() );
  837.     for( i = 0; i < damageScale.Num(); i++ ) {
  838.         savefile->WriteFloat( damageScale[ i ] );
  839.     }
  840. //MCG
  841.     savefile->WriteBool( inDamageEvent );
  842.  
  843.     savefile->WriteBool( use_combat_bbox );
  844.  
  845.     savefile->WriteJoint( leftEyeJoint );
  846.     savefile->WriteJoint( rightEyeJoint );
  847.     savefile->WriteJoint( soundJoint );
  848.     savefile->WriteJoint( eyeOffsetJoint );    
  849.     savefile->WriteJoint( chestOffsetJoint );
  850.     savefile->WriteJoint( neckJoint );
  851.     savefile->WriteJoint( headJoint );
  852.  
  853.     walkIK.Save( savefile );
  854.  
  855.     savefile->WriteString( animPrefix );
  856.     savefile->WriteString( painType );
  857.     savefile->WriteString( painAnim );
  858.     
  859.     savefile->WriteInt( blink_anim );
  860.     savefile->WriteInt( blink_time );
  861.     savefile->WriteInt( blink_min );
  862.     savefile->WriteInt( blink_max );
  863.  
  864.     headAnim.Save( savefile );
  865.     torsoAnim.Save( savefile );
  866.     legsAnim.Save( savefile );
  867.  
  868.     stateThread.Save( savefile );
  869.  
  870.     // idEntityPtr<idAFAttachment>    head;
  871.     head.Save( savefile );    // cnicholson: Added unwritten var
  872.  
  873.     savefile->WriteBool( disablePain );
  874.     savefile->WriteBool( allowEyeFocus );
  875.     savefile->WriteBool( finalBoss );
  876.  
  877.     savefile->WriteInt( painTime );
  878.  
  879.     savefile->WriteInt( attachments.Num() );
  880.     for ( i = 0; i < attachments.Num(); i++ ) {
  881.         attachments[i].ent.Save( savefile );
  882.         savefile->WriteInt( attachments[i].channel );
  883.     }
  884.  
  885.     vehicleController.Save ( savefile );
  886.  
  887.     // These aren't saved in the same order as they're declared, due to the dependency (I didn't see the need to change the order of declaration)
  888.     savefile->WriteInt ( flashlightHandle );
  889.     savefile->WriteJoint ( flashlightJoint );
  890.     savefile->WriteVec3 ( flashlightOffset );
  891.     savefile->WriteRenderLight ( flashlight );
  892.  
  893.     savefile->WriteInt( deathPushTime );
  894.     savefile->WriteVec3( deathPushForce );
  895.     savefile->WriteJoint( deathPushJoint );
  896. }
  897.  
  898. /*
  899. ================
  900. idActor::Restore
  901.  
  902. unarchives object from save game file
  903. ================
  904. */
  905. void idActor::Restore( idRestoreGame *savefile ) {
  906.     int i, num;
  907.     idActor *ent;
  908.  
  909.     savefile->ReadInt( team );
  910.  
  911. // cnicholson:     This line was already commented out, so we aint changing it.
  912. // No need to write/read teamNode
  913.     // idLinkList<idActor>        teamNode;
  914.  
  915.     savefile->ReadInt( rank );
  916.     savefile->ReadMat3( viewAxis );
  917.  
  918.     savefile->ReadInt( num );
  919.     for ( i = 0; i < num; i++ ) {
  920.         savefile->ReadObject( reinterpret_cast<idClass *&>( ent ) );
  921.         assert( ent );
  922.         if ( ent ) {
  923.             ent->enemyNode.AddToEnd( enemyList );
  924.         }
  925.     }
  926.  
  927.     savefile->ReadInt( lightningEffects );
  928.     savefile->ReadInt( lightningNextTime );
  929.  
  930.     savefile->ReadFloat( fovDot );
  931.     savefile->ReadFloat( fovCloseDot );
  932.     savefile->ReadFloat( fovCloseRange );
  933.     savefile->ReadVec3( eyeOffset );
  934.     savefile->ReadVec3( chestOffset );
  935.     savefile->ReadVec3( modelOffset );
  936.     savefile->ReadAngles( deltaViewAngles );
  937.  
  938.     savefile->ReadInt( pain_debounce_time );
  939.     savefile->ReadInt( pain_delay );
  940.  
  941.     savefile->ReadInt( num );
  942.     damageGroups.SetGranularity( 1 );
  943.     damageGroups.SetNum( num );
  944.     for( i = 0; i < num; i++ ) {
  945.         savefile->ReadString( damageGroups[ i ] );
  946.     }
  947.  
  948.     savefile->ReadInt( num );
  949.     damageScale.SetNum( num );
  950.     for( i = 0; i < num; i++ ) {
  951.         savefile->ReadFloat( damageScale[ i ] );
  952.     }
  953. //MCG
  954.     savefile->ReadBool( inDamageEvent );
  955.  
  956.     savefile->ReadBool( use_combat_bbox );
  957.  
  958.     savefile->ReadJoint( leftEyeJoint );
  959.     savefile->ReadJoint( rightEyeJoint );
  960.     savefile->ReadJoint( soundJoint );
  961.     savefile->ReadJoint( eyeOffsetJoint );    
  962.     savefile->ReadJoint( chestOffsetJoint );
  963.     savefile->ReadJoint( neckJoint );
  964.     savefile->ReadJoint( headJoint );
  965.  
  966.     walkIK.Restore( savefile );
  967.  
  968.     savefile->ReadString( animPrefix );
  969.     savefile->ReadString( painType );
  970.     savefile->ReadString( painAnim );
  971.     
  972.     savefile->ReadInt( blink_anim );
  973.     savefile->ReadInt( blink_time );
  974.     savefile->ReadInt( blink_min );
  975.     savefile->ReadInt( blink_max );
  976.  
  977.     headAnim.Restore( savefile );
  978.     torsoAnim.Restore( savefile );
  979.     legsAnim.Restore( savefile );
  980.  
  981.     stateThread.Restore( savefile, this );
  982.  
  983. // cnicholson: Restore unread var
  984.     // idEntityPtr<idAFAttachment>    head;
  985.     head.Restore(savefile);
  986.  
  987.     savefile->ReadBool( disablePain );
  988.     savefile->ReadBool( allowEyeFocus );
  989.     savefile->ReadBool( finalBoss );
  990.  
  991.     savefile->ReadInt( painTime );
  992.  
  993.     savefile->ReadInt( num );
  994.     for ( i = 0; i < num; i++ ) {
  995.         idAttachInfo &attach = attachments.Alloc();
  996.         attach.ent.Restore( savefile );
  997.         savefile->ReadInt( attach.channel );
  998.     }
  999.  
  1000. // RAVEN BEGIN
  1001. // bdube: added
  1002.     vehicleController.Restore ( savefile );
  1003.  
  1004.     savefile->ReadInt ( flashlightHandle );
  1005.     savefile->ReadJoint ( flashlightJoint );
  1006.     savefile->ReadVec3 ( flashlightOffset );
  1007.     savefile->ReadRenderLight ( flashlight );
  1008.     if ( flashlightHandle != -1 ) {        
  1009.         flashlightHandle = gameRenderWorld->AddLightDef( &flashlight );
  1010.     }
  1011.  
  1012.     savefile->ReadInt( deathPushTime );
  1013.     savefile->ReadVec3( deathPushForce );
  1014.     savefile->ReadJoint( deathPushJoint );
  1015.  
  1016. // mekberg: update this
  1017.     FlashlightUpdate( );
  1018. // RAVEN END
  1019. }
  1020.  
  1021. /*
  1022. ================
  1023. idActor::Hide
  1024. ================
  1025. */
  1026. void idActor::Hide( void ) {
  1027.     idEntity *ent;
  1028.     idEntity *next;
  1029.  
  1030.     idAFEntity_Base::Hide();
  1031.     if ( head.GetEntity() ) {
  1032.         head.GetEntity()->Hide();
  1033.     }
  1034.  
  1035.     for( ent = GetNextTeamEntity(); ent != NULL; ent = next ) {
  1036.         next = ent->GetNextTeamEntity();
  1037.         if ( ent->GetBindMaster() == this ) {
  1038.             ent->Hide();
  1039. // RAVEN BEGIN
  1040. // jnewquist: Use accessor for static class type 
  1041.             if ( ent->IsType( idLight::GetClassType() ) ) {
  1042. // RAVEN END
  1043.                 static_cast<idLight *>( ent )->Off();
  1044.             }
  1045.         }
  1046.     }
  1047.     UnlinkCombat();
  1048. }
  1049.  
  1050. /*
  1051. ================
  1052. idActor::Show
  1053. ================
  1054. */
  1055. void idActor::Show( void ) {
  1056.     idEntity *ent;
  1057.     idEntity *next;
  1058.  
  1059.     idAFEntity_Base::Show();
  1060.     if ( head.GetEntity() ) {
  1061.         head.GetEntity()->Show();
  1062.     }
  1063.     for( ent = GetNextTeamEntity(); ent != NULL; ent = next ) {
  1064.         next = ent->GetNextTeamEntity();
  1065.         if ( ent->GetBindMaster() == this ) {
  1066.             ent->Show();
  1067. // RAVEN BEGIN
  1068. // jnewquist: Use accessor for static class type 
  1069.             if ( ent->IsType( idLight::GetClassType() ) ) {
  1070. // RAVEN END
  1071.                 static_cast<idLight *>( ent )->On();
  1072.             }
  1073.         }
  1074.     }
  1075.     LinkCombat();
  1076. }
  1077.  
  1078. /*
  1079. ==============
  1080. idActor::GetDefaultSurfaceType
  1081. ==============
  1082. */
  1083. int    idActor::GetDefaultSurfaceType( void ) const {
  1084.     return SURFTYPE_FLESH;
  1085. }
  1086.  
  1087. /*
  1088. ================
  1089. idActor::ProjectOverlay
  1090. ================
  1091. */
  1092. void idActor::ProjectOverlay( const idVec3 &origin, const idVec3 &dir, float size, const char *material ) {
  1093.     idEntity *ent;
  1094.     idEntity *next;
  1095.  
  1096.     idEntity::ProjectOverlay( origin, dir, size, material );
  1097.  
  1098.     for( ent = GetNextTeamEntity(); ent != NULL; ent = next ) {
  1099.         next = ent->GetNextTeamEntity();
  1100.         if ( ent->GetBindMaster() == this ) {
  1101.             if ( ent->fl.takedamage && ent->spawnArgs.GetBool( "bleed" ) ) {
  1102.                 ent->ProjectOverlay( origin, dir, size, material );
  1103.             }
  1104.         }
  1105.     }
  1106. }
  1107.  
  1108. /*
  1109. ================
  1110. idActor::LoadAF
  1111. ================
  1112. */
  1113. bool idActor::LoadAF( const char* keyname, bool purgeAF /* = false */ ) {
  1114.     idStr fileName;
  1115.  
  1116.     if ( !keyname || !*keyname ) {
  1117.         keyname = "ragdoll";
  1118.     }
  1119.  
  1120.     if ( !spawnArgs.GetString( keyname, "*unknown*", fileName ) || !fileName.Length() ) {
  1121.         return false;
  1122.     }
  1123.     af.SetAnimator( GetAnimator() );
  1124.     return af.Load( this, fileName, purgeAF );
  1125. }
  1126.  
  1127. /*
  1128. =====================
  1129. idActor::SetupBody
  1130. =====================
  1131. */
  1132. void idActor::SetupBody( void ) {
  1133.     const char*        jointname;
  1134.     idAnimator*        headAnimator;
  1135.     float            height;
  1136.  
  1137.     animator.ClearAllAnims( gameLocal.time, 0 );
  1138.     animator.ClearAllJoints();
  1139.  
  1140.     // Cache the head entity pointer and determine which animator to use
  1141.     idAFAttachment *headEnt = head.GetEntity();
  1142.     if ( headEnt ) {
  1143.         headAnimator = headEnt->GetAnimator ( );
  1144.     } else {
  1145.         headAnimator = GetAnimator( );
  1146.     }
  1147.     
  1148.     // Get left eye joint
  1149.     if ( !headEnt || !headEnt->spawnArgs.GetString ( "joint_leftEye", "", &jointname ) ) {        
  1150.         jointname = spawnArgs.GetString( "joint_leftEye" );
  1151.     }
  1152.     leftEyeJoint = headAnimator->GetJointHandle( jointname );
  1153.  
  1154.     // Get right eye joint
  1155.     if ( !headEnt || !headEnt->spawnArgs.GetString ( "joint_rightEye", "", &jointname ) ) {        
  1156.         jointname = spawnArgs.GetString( "joint_rightEye" );
  1157.     }
  1158.     rightEyeJoint = headAnimator->GetJointHandle( jointname );
  1159.                 
  1160.     // If head height is specified, just use that
  1161.     if ( spawnArgs.GetFloat ( "eye_height", "0", height ) ) {
  1162.         SetEyeHeight ( height );
  1163.     } else { 
  1164.         // See if there is an eye offset joint specified, if not just use the left eye joint
  1165.         if ( !headEnt || !headEnt->spawnArgs.GetString ( "joint_eyeOffset", "", &jointname ) ) {        
  1166.             jointname = spawnArgs.GetString( "joint_eyeOffset" );
  1167.         }
  1168.         // Get the eye offset joint
  1169.         eyeOffsetJoint = headAnimator->GetJointHandle ( jointname );
  1170.     }
  1171.  
  1172.     // If eye height is specified, just use that
  1173.     if ( spawnArgs.GetFloat ( "chest_height", "0", height ) ) {
  1174.         SetChestHeight ( height );
  1175.     } else { 
  1176.         // See if there is an eye offset joint specified, if not just use the left eye joint
  1177.         spawnArgs.GetString ( "joint_chestOffset", "", &jointname );
  1178.         // Get the chest offset joint
  1179.         chestOffsetJoint = animator.GetJointHandle ( jointname );
  1180.     }
  1181.  
  1182.     // Get the neck joint
  1183.     spawnArgs.GetString ( "joint_look_neck", "", &jointname );
  1184.     neckJoint = animator.GetJointHandle ( jointname );
  1185.  
  1186.     // Get the head joint
  1187.     spawnArgs.GetString ( "joint_look_head", "", &jointname );
  1188.     headJoint = animator.GetJointHandle ( jointname );
  1189.  
  1190.     headAnim.Init ( this, &animator, ANIMCHANNEL_HEAD );
  1191.     torsoAnim.Init( this, &animator, ANIMCHANNEL_TORSO );
  1192.     legsAnim.Init( this, &animator, ANIMCHANNEL_LEGS );
  1193. }
  1194.  
  1195. /*
  1196. =====================
  1197. idActor::CheckBlink
  1198. =====================
  1199. */
  1200. void idActor::CheckBlink( void ) {
  1201.     // check if it's time to blink
  1202.     if ( !blink_anim || ( health <= 0 ) || ( blink_time > gameLocal.time ) || !fl.allowAutoBlink ) {
  1203.         return;
  1204.     }
  1205.  
  1206.     idAnimator *animator = head.GetEntity() ? head->GetAnimator() : &this->animator;
  1207.     animator->PlayAnim( ANIMCHANNEL_EYELIDS, blink_anim, gameLocal.time, 1 );
  1208.  
  1209.     // set the next blink time
  1210.     blink_time = gameLocal.time + blink_min + gameLocal.random.RandomFloat() * ( blink_max - blink_min );
  1211. }
  1212.  
  1213. /*
  1214. ================
  1215. idActor::GetPhysicsToVisualTransform
  1216. ================
  1217. */
  1218. bool idActor::GetPhysicsToVisualTransform( idVec3 &origin, idMat3 &axis ) {
  1219.     if ( af.IsActive() ) {
  1220.         af.GetPhysicsToVisualTransform( origin, axis );
  1221.         return true;
  1222.     }
  1223. // RAVEN BEGIN
  1224. // bdube: position player in seat (nmckenzie: copy and paste from the player version of this call)
  1225.     if ( vehicleController.IsDriving ( ) ) {
  1226.         vehicleController.GetDriverPosition ( origin, axis );
  1227.         return true;
  1228.     }
  1229. // RAVEN END
  1230.  
  1231.     origin = modelOffset;
  1232.     axis = viewAxis;
  1233.     return true;
  1234. }
  1235.  
  1236. /*
  1237. ================
  1238. idActor::GetPhysicsToSoundTransform
  1239. ================
  1240. */
  1241. bool idActor::GetPhysicsToSoundTransform( idVec3 &origin, idMat3 &axis ) {
  1242.     if ( soundJoint != INVALID_JOINT ) {
  1243.         animator.GetJointTransform( soundJoint, gameLocal.time, origin, axis );
  1244.         origin += modelOffset;
  1245.         axis = viewAxis;
  1246.     } else {
  1247.         origin = GetPhysics()->GetGravityNormal() * -eyeOffset.z;
  1248.         axis.Identity();
  1249.     }
  1250.     return true;
  1251. }
  1252.  
  1253. /***********************************************************************
  1254.  
  1255.     script state management
  1256.  
  1257. ***********************************************************************/
  1258.  
  1259. /*
  1260. ================
  1261. idActor::ShutdownThreads
  1262. ================
  1263. */
  1264. void idActor::ShutdownThreads( void ) {
  1265.     headAnim.Shutdown();
  1266.     torsoAnim.Shutdown();
  1267.     legsAnim.Shutdown();
  1268. }
  1269.  
  1270. /*
  1271. =====================
  1272. idActor::OnStateThreadClear
  1273. =====================
  1274. */
  1275. void idActor::OnStateThreadClear( const char *statename, int flags ) {
  1276. }
  1277.  
  1278. /*
  1279. =====================
  1280. idActor::SetState
  1281. =====================
  1282. */
  1283. void idActor::SetState( const char *statename, int flags ) {
  1284.     OnStateThreadClear( statename, flags );
  1285.     stateThread.SetState ( statename, 0, 0, flags );
  1286. }
  1287.  
  1288. /*
  1289. =====================
  1290. idActor::PostState
  1291. =====================
  1292. */
  1293. void idActor::PostState ( const char* statename, int delay, int flags ) {
  1294.     if ( SRESULT_OK != stateThread.PostState ( statename, 0, delay, flags ) ) {
  1295.         gameLocal.Error ( "unknown state '%s' on entity '%s'", statename, GetName() );
  1296.     }
  1297. }
  1298.  
  1299. /*
  1300. =====================
  1301. idActor::InterruptState
  1302. =====================
  1303. */
  1304. void idActor::InterruptState ( const char* statename, int delay, int flags ) {
  1305.     if ( SRESULT_OK != stateThread.InterruptState ( statename, 0, delay, flags ) ) {
  1306.         gameLocal.Error ( "unknown state '%s' on entity '%s'", statename, GetName() );
  1307.     }
  1308. }
  1309.  
  1310. /*
  1311. =====================
  1312. idActor::UpdateState
  1313. =====================
  1314. */
  1315. void idActor::UpdateState ( void ) {
  1316.     stateThread.Execute ( );
  1317. }
  1318.  
  1319. /***********************************************************************
  1320.  
  1321.     vision
  1322.  
  1323. ***********************************************************************/
  1324.  
  1325. /*
  1326. =====================
  1327. idActor::setFov
  1328. =====================
  1329. */
  1330. void idActor::SetFOV( float fov, float fovClose ) {
  1331.     fovDot = idMath::Cos( DEG2RAD( fov * 0.5f ) );
  1332.     fovCloseDot = idMath::Cos( DEG2RAD( fovClose * 0.5f ) );
  1333. }
  1334.  
  1335. /*
  1336. =====================
  1337. idActor::SetEyeHeight
  1338. =====================
  1339. */
  1340. void idActor::SetEyeHeight( float height ) {
  1341.     eyeOffset = GetPhysics()->GetGravityNormal() * -height;
  1342. }
  1343.  
  1344. /*
  1345. =====================
  1346. idActor::EyeHeight
  1347. =====================
  1348. */
  1349. float idActor::EyeHeight( void ) const {
  1350.     return eyeOffset.z;
  1351. }
  1352.  
  1353. /*
  1354. =====================
  1355. idActor::SetChestHeight
  1356. =====================
  1357. */
  1358. void idActor::SetChestHeight( float height ) {
  1359.     chestOffset = GetPhysics()->GetGravityNormal() * -height;
  1360. }
  1361.  
  1362. /*
  1363. =====================
  1364. idActor::GetEyePosition
  1365. =====================
  1366. */
  1367. idVec3 idActor::GetEyePosition( void ) const {
  1368.     return GetPhysics()->GetOrigin() + eyeOffset * viewAxis;
  1369. }
  1370.  
  1371. /*
  1372. =====================
  1373. idActor::GetChestPosition
  1374. =====================
  1375. */
  1376. idVec3 idActor::GetChestPosition ( void ) const {
  1377.     return GetPhysics()->GetOrigin() + chestOffset * viewAxis;
  1378. }
  1379.  
  1380. // RAVEN BEGIN
  1381. // bdube: flashlights
  1382.  
  1383. /*
  1384. =====================
  1385. idActor::GetGroundEntity
  1386. =====================
  1387. */
  1388. idEntity* idActor::GetGroundEntity( void ) const {
  1389.     return static_cast<idPhysics_Actor*>(GetPhysics())->GetGroundEntity();
  1390. }
  1391.  
  1392. /*
  1393. =====================
  1394. idActor::Present
  1395. =====================
  1396. */
  1397. void idActor::Present( void ) {
  1398.     idAFEntity_Gibbable::Present();
  1399.  
  1400.     FlashlightUpdate();
  1401. }
  1402.  
  1403. /*
  1404. =====================
  1405. idActor::Event_Teleport
  1406. =====================
  1407. */
  1408. void idActor::Event_Teleport( idVec3 &newPos, idVec3 &newAngles ) {
  1409.     Teleport ( newPos, newAngles.ToAngles(), NULL );
  1410. }
  1411.  
  1412. /*
  1413. =====================
  1414. idActor::Event_EnterVehicle
  1415. =====================
  1416. */
  1417. void idActor::Event_EnterVehicle ( idEntity* vehicle ) {
  1418.     if ( IsInVehicle ( ) ) {
  1419.         return;
  1420.     }
  1421.     EnterVehicle ( vehicle );
  1422. }
  1423.  
  1424. /*
  1425. =====================
  1426. idActor::Event_ExitVehicle
  1427. =====================
  1428. */
  1429. void idActor::Event_ExitVehicle ( bool force ) {
  1430.     if ( !IsInVehicle ( ) ) {
  1431.         return;
  1432.     }
  1433.     ExitVehicle ( force );
  1434. }
  1435.  
  1436. /*
  1437. =====================
  1438. idActor::Event_PreExitVehicle
  1439. =====================
  1440. */
  1441. void idActor::Event_PreExitVehicle ( bool force ) {
  1442.     if ( !IsInVehicle ( ) ) {
  1443.         return;
  1444.     }
  1445.  
  1446.     // call the script func regardless of the fact that we may not be getting out just yet.
  1447.     // this allows things in the script to happen before ejection actually occurs (such as screen fades).
  1448.     vehicleController.GetVehicle()->OnExit();
  1449.  
  1450.     // this is done because having an exit delay when the player is dead was causing bustedness if you died in the walker
  1451.     //    specifically the restart menu would not appear if you were still in the walker
  1452.     if ( health > 0 ) {
  1453.         PostEventMS( &AI_PostExitVehicle, vehicleController.GetVehicle()->spawnArgs.GetInt( "exit_vehicle_delay" ), force );
  1454.     }
  1455.     else {
  1456.         ExitVehicle(true);
  1457.     }
  1458. }
  1459.  
  1460. /*
  1461. =====================
  1462. idActor::Event_Flashlight
  1463. =====================
  1464. */
  1465. void idActor::Event_Flashlight( bool on ) {    
  1466.     if ( on ) {
  1467.         FlashlightUpdate(true);
  1468.     } else {
  1469.         if ( flashlightHandle != -1 ) {
  1470.             gameRenderWorld->FreeLightDef ( flashlightHandle );
  1471.             flashlightHandle = -1;
  1472.         }
  1473.  
  1474.         if ( spawnArgs.GetString( "flashlight_flaresurf", NULL ) ) {
  1475.             HideSurface( spawnArgs.GetString( "flashlight_flaresurf", NULL ) );
  1476.         }
  1477.         if ( spawnArgs.GetString( "fx_flashlight", NULL ) ) {
  1478.             StopEffect( "fx_flashlight", true );
  1479.         }
  1480.     }
  1481. }
  1482.  
  1483. /*
  1484. =====================
  1485. idActor::FlashlightUpdate
  1486. =====================
  1487. */
  1488. void idActor::FlashlightUpdate ( bool forceOn ) {
  1489.  
  1490.     // Dont do anything if flashlight is off and its not being forced on
  1491.     if ( !forceOn && flashlightHandle == -1 ) {
  1492.         return;
  1493.     }
  1494.  
  1495.     if ( !flashlight.lightRadius[0] || flashlightJoint == INVALID_JOINT ) {
  1496.         return;
  1497.     }
  1498.  
  1499.     if ( forceOn && flashlightHandle == -1 ) {
  1500.         //first time turning it on
  1501.         if ( spawnArgs.GetString( "flashlight_flaresurf", NULL ) ) {
  1502.             ShowSurface( spawnArgs.GetString( "flashlight_flaresurf", NULL ) );
  1503.         }
  1504.         if ( spawnArgs.GetString( "fx_flashlight", NULL ) ) {
  1505.             PlayEffect( "fx_flashlight", flashlightJoint, true );
  1506.         }
  1507.     }
  1508.  
  1509.     // the flash has an explicit joint for locating it
  1510.     GetJointWorldTransform ( flashlightJoint, gameLocal.time, flashlight.origin, flashlight.axis );
  1511.     flashlight.origin += flashlightOffset * flashlight.axis;
  1512.     
  1513.     if ( flashlightHandle != -1 ) {
  1514.         gameRenderWorld->UpdateLightDef( flashlightHandle, &flashlight );
  1515.     } else {
  1516.         flashlightHandle = gameRenderWorld->AddLightDef( &flashlight );
  1517.     }
  1518.  
  1519. }
  1520.  
  1521. // RAVEN END
  1522.  
  1523. /*
  1524. =====================
  1525. idActor::GetViewPos
  1526. =====================
  1527. */
  1528. void idActor::GetViewPos( idVec3 &origin, idMat3 &axis ) const {
  1529.     origin = GetEyePosition();
  1530.     axis = viewAxis;
  1531. }
  1532.  
  1533. /*
  1534. =====================
  1535. idActor::CheckFOV
  1536. =====================
  1537. */
  1538. bool idActor::CheckFOV( const idVec3 &pos, float ang ) const {
  1539.     float testAng = ( ang != -1.0f ) ? idMath::Cos( DEG2RAD( ang * 0.5f ) ) : fovDot;
  1540.     if ( testAng == 1.0f ) {
  1541.         return true;
  1542.     }
  1543.  
  1544.     if(!GetPhysics()) {
  1545.         return false;
  1546.     }
  1547.     
  1548.     float    dot;
  1549.     float    dist;
  1550.     idVec3    delta;
  1551.     
  1552.     delta = pos - GetEyePosition();
  1553.     dist = delta.LengthFast();
  1554.  
  1555.     //NOTE!!!
  1556.     //This logic is BACKWARDS, but it's too late in the project
  1557.     //for me to feel comfortable fixing this.  It SHOULD be:
  1558.     //if ( ang == -1.0f )
  1559.     // - MCG
  1560.     if ( ang != -1.0f )
  1561.     {//not overriding dot test value
  1562.         if (dist<fovCloseRange) {
  1563.             testAng = fovCloseDot;    // allow a wider FOV if close enough
  1564.         }
  1565.     }
  1566.  
  1567.     // get our gravity normal
  1568.     const idVec3 &gravityDir = GetPhysics()->GetGravityNormal();
  1569.  
  1570.     // infinite vertical vision, so project it onto our orientation plane
  1571.     delta -= gravityDir * ( gravityDir * delta );
  1572.  
  1573.     delta.Normalize();
  1574.     dot = viewAxis[ 0 ] * delta;
  1575.  
  1576.     return ( dot >= testAng );
  1577. }
  1578.  
  1579. /*
  1580. =====================
  1581. idActor::HasFOV
  1582. =====================
  1583. */
  1584.  
  1585. bool idActor::HasFOV( idEntity *ent )
  1586. {
  1587.     // Fixme: Make this do something, anything.
  1588.     return true;
  1589. }
  1590. // RAVEN END
  1591.  
  1592. /*
  1593. =====================
  1594. idActor::CanSee
  1595. =====================
  1596. */
  1597. bool idActor::CanSee( const idEntity *ent, bool useFov ) const {
  1598.     return CanSeeFrom ( GetEyePosition ( ), ent, useFov );
  1599. }
  1600.  
  1601. /*
  1602. =====================
  1603. idActor::CanSeeFrom
  1604. =====================
  1605. */
  1606. bool idActor::CanSeeFrom ( const idVec3& from, const idEntity *ent, bool useFov ) const {
  1607.     idVec3 toPos;
  1608.  
  1609.     if ( !ent || ent->IsHidden() ) {
  1610.         return false;
  1611.     }
  1612.  
  1613.     if ( ent->IsType( idActor::Type ) ) {
  1614.         toPos  = ((idActor*)ent)->GetEyePosition();
  1615.     } else {
  1616.         toPos = ent->GetPhysics()->GetAbsBounds().GetCenter ( );
  1617.     }
  1618.  
  1619.     return CanSeeFrom ( from, toPos, useFov );
  1620. }
  1621.  
  1622. bool idActor::CanSeeFrom ( const idVec3& from, const idVec3& toPos, bool useFov ) const {
  1623.     trace_t tr;
  1624.  
  1625.     if ( useFov && !CheckFOV( toPos ) ) {
  1626.         return false;
  1627.     }
  1628.     if ( g_perfTest_aiNoVisTrace.GetBool() ) {
  1629.         return true;
  1630.     }
  1631.     gameLocal.TracePoint( this, tr, from, toPos, MASK_OPAQUE, this );
  1632.     if ( tr.fraction >= 1.0f ) { // || ( gameLocal.GetTraceEntity( tr ) == ent ) ) {
  1633.         return true;
  1634.     }
  1635.  
  1636.     return false;
  1637. }
  1638.  
  1639. /*
  1640. =====================
  1641. idActor::GetRenderView
  1642. =====================
  1643. */
  1644. renderView_t *idActor::GetRenderView() {
  1645.     renderView_t *rv = idEntity::GetRenderView();
  1646.     rv->viewaxis = viewAxis;
  1647.     rv->vieworg = GetEyePosition();
  1648.     return rv;
  1649. }
  1650.  
  1651. /***********************************************************************
  1652.  
  1653.     Model/Ragdoll
  1654.  
  1655. ***********************************************************************/
  1656.  
  1657. /*
  1658. ================
  1659. idActor::SetCombatModel
  1660. ================
  1661. */
  1662. void idActor::SetCombatModel( void ) {
  1663.     idAFAttachment *headEnt;
  1664.  
  1665. // RAVEN BEGIN
  1666. // bdube: set the combat model reguardless
  1667.     if ( 1 ) { // !use_combat_bbox ) {
  1668. // RAVEN END
  1669.         if ( combatModel ) {
  1670.             combatModel->Unlink();
  1671.             combatModel->LoadModel( modelDefHandle );
  1672.         } else {
  1673. // RAVEN BEGIN
  1674. // mwhitlock: Dynamic memory consolidation
  1675.             RV_PUSH_HEAP_MEM(this);
  1676. // RAVEN END
  1677.             combatModel = new idClipModel( modelDefHandle );
  1678. // RAVEN BEGIN
  1679. // mwhitlock: Dynamic memory consolidation
  1680.             RV_POP_HEAP();
  1681. // RAVEN END
  1682.         }
  1683.  
  1684.         headEnt = head.GetEntity();
  1685.         if ( headEnt ) {
  1686.             headEnt->SetCombatModel();
  1687.         }
  1688.     }
  1689. }
  1690.  
  1691. /*
  1692. ================
  1693. idActor::GetCombatModel
  1694. ================
  1695. */
  1696. idClipModel *idActor::GetCombatModel( void ) const {
  1697.     return combatModel;
  1698. }
  1699.  
  1700. /*
  1701. ================
  1702. idActor::LinkCombat
  1703. ================
  1704. */
  1705. void idActor::LinkCombat( void ) {
  1706.     idAFAttachment *headEnt;
  1707.  
  1708.     if ( fl.hidden || use_combat_bbox ) {
  1709.         return;
  1710.     }
  1711.  
  1712.     if ( combatModel ) {
  1713. // RAVEN BEGIN
  1714. // ddynerman: multiple clip worlds
  1715.         combatModel->Link( this, 0, renderEntity.origin, renderEntity.axis, modelDefHandle );
  1716. // RAVEN END
  1717.     }
  1718.     headEnt = head.GetEntity();
  1719.     if ( headEnt ) {
  1720.         headEnt->LinkCombat();
  1721.     }
  1722. }
  1723.  
  1724. /*
  1725. ================
  1726. idActor::UnlinkCombat
  1727. ================
  1728. */
  1729. void idActor::UnlinkCombat( void ) {
  1730.     idAFAttachment *headEnt;
  1731.  
  1732.     if ( combatModel ) {
  1733.         combatModel->Unlink();
  1734.     }
  1735.     headEnt = head.GetEntity();
  1736.     if ( headEnt ) {
  1737.         headEnt->UnlinkCombat();
  1738.     }
  1739. }
  1740.  
  1741. /*
  1742. ================
  1743. idActor::StartRagdoll
  1744. ================
  1745. */
  1746. bool idActor::StartRagdoll( void ) {
  1747.     float slomoStart, slomoEnd;
  1748.     float jointFrictionDent, jointFrictionDentStart, jointFrictionDentEnd;
  1749.     float contactFrictionDent, contactFrictionDentStart, contactFrictionDentEnd;
  1750.  
  1751.     // if no AF loaded
  1752.     if ( !af.IsLoaded() ) {
  1753.         return false;
  1754.     }
  1755.  
  1756.     // if the AF is already active
  1757.     if ( af.IsActive() ) {
  1758.         return true;
  1759.     }
  1760.  
  1761.     // Raise the origin up 5 units to help ensure the ragdoll doesnt start in the ground
  1762.     GetPhysics()->SetOrigin( GetPhysics()->GetOrigin() + GetPhysics()->GetGravityNormal() * -5.0f );
  1763.     UpdateModelTransform();
  1764.  
  1765.     // disable the monster bounding box
  1766.     GetPhysics()->DisableClip();
  1767.  
  1768.     af.StartFromCurrentPose( spawnArgs.GetInt( "velocityTime", "0" ) );
  1769.  
  1770.     slomoStart = MS2SEC( gameLocal.time ) + spawnArgs.GetFloat( "ragdoll_slomoStart", "-1.6" );
  1771.     slomoEnd = MS2SEC( gameLocal.time ) + spawnArgs.GetFloat( "ragdoll_slomoEnd", "0.8" );
  1772.  
  1773.     // do the first part of the death in slow motion
  1774.     af.GetPhysics()->SetTimeScaleRamp( slomoStart, slomoEnd );
  1775.  
  1776.     jointFrictionDent = spawnArgs.GetFloat( "ragdoll_jointFrictionDent", "0.1" );
  1777.     jointFrictionDentStart = MS2SEC( gameLocal.time ) + spawnArgs.GetFloat( "ragdoll_jointFrictionStart", "0.2" );
  1778.     jointFrictionDentEnd = MS2SEC( gameLocal.time ) + spawnArgs.GetFloat( "ragdoll_jointFrictionEnd", "1.2" );
  1779.  
  1780.     // set joint friction dent
  1781.     af.GetPhysics()->SetJointFrictionDent( jointFrictionDent, jointFrictionDentStart, jointFrictionDentEnd );
  1782.  
  1783.     contactFrictionDent = spawnArgs.GetFloat( "ragdoll_contactFrictionDent", "0.1" );
  1784.     contactFrictionDentStart = MS2SEC( gameLocal.time ) + spawnArgs.GetFloat( "ragdoll_contactFrictionStart", "1.0" );
  1785.     contactFrictionDentEnd = MS2SEC( gameLocal.time ) + spawnArgs.GetFloat( "ragdoll_contactFrictionEnd", "2.0" );
  1786.  
  1787.     // set contact friction dent
  1788.     af.GetPhysics()->SetContactFrictionDent( contactFrictionDent, contactFrictionDentStart, contactFrictionDentEnd );
  1789.  
  1790.     // drop any items the actor is holding
  1791.     idList<idEntity *> list;
  1792.     idMoveableItem::DropItems( this, "death", &list );
  1793.     for ( int i = 0; i < list.Num(); i++ ) {
  1794.         if ( list[i] && list[i]->GetPhysics() )
  1795.         {
  1796.             idVec3 velocity;
  1797.             float pitchDir = gameLocal.random.CRandomFloat()>0.0f?1.0f:-1.0f;
  1798.             float yawDir = gameLocal.random.CRandomFloat()>0.0f?1.0f:-1.0f;
  1799.             float rollDir = gameLocal.random.CRandomFloat()>0.0f?1.0f:-1.0f;
  1800.             velocity.Set( pitchDir*((gameLocal.random.RandomFloat() * 200.0f) + 50.0f),
  1801.                             yawDir*((gameLocal.random.RandomFloat() * 200.0f) + 50.0f),
  1802.                             (gameLocal.random.RandomFloat() * 300.0f) + 100.0f );
  1803.             list[i]->GetPhysics()->SetAngularVelocity( idVec3( pitchDir*((gameLocal.random.RandomFloat() * 6.0f) + 2.0f),
  1804.                                                             yawDir*((gameLocal.random.RandomFloat() * 6.0f) + 2.0f),
  1805.                                                             rollDir*((gameLocal.random.RandomFloat() * 10.0f) + 3.0f)));
  1806.             if ( gibbed ) {
  1807.                 //only throw them if we end up gibbed?
  1808.                 list[i]->GetPhysics()->SetLinearVelocity( velocity );
  1809.             }
  1810.         }
  1811.     }
  1812.  
  1813.     // drop any articulated figures the actor is holding
  1814.     idAFEntity_Base::DropAFs( this, "death", NULL );
  1815.  
  1816.     RemoveAttachments();
  1817.  
  1818. // RAVEN BEGIN
  1819. // bdube: evaluate one ragdoll frame
  1820.     RunPhysics();
  1821. // RAVEN END
  1822.  
  1823.     return true;
  1824. }
  1825.  
  1826. /*
  1827. ================
  1828. idActor::StopRagdoll
  1829. ================
  1830. */
  1831. void idActor::StopRagdoll( void ) {
  1832.     if ( af.IsActive() ) {
  1833.         af.Stop();
  1834.     }
  1835. }
  1836.  
  1837. /*
  1838. ================
  1839. idActor::UpdateAnimationControllers
  1840. ================
  1841. */
  1842. bool idActor::UpdateAnimationControllers( void ) {
  1843.  
  1844.     if ( af.IsActive() ) {
  1845.         return idAFEntity_Gibbable::UpdateAnimationControllers();
  1846.     } else {
  1847.         animator.ClearAFPose();
  1848.     }
  1849.  
  1850.     if ( walkIK.IsInitialized() ) {
  1851.         walkIK.Evaluate();
  1852.         return true;
  1853.     }
  1854.  
  1855.     idMat3              axis;
  1856.     idAnimatedEntity* headEnt = head.GetEntity( );
  1857.     if ( !headEnt ) {
  1858.         headEnt = this;
  1859.     }
  1860.     
  1861.     // Dynamically update the eye offset if a joint was specified
  1862.     if ( eyeOffsetJoint != INVALID_JOINT ) {
  1863.         headEnt->GetJointWorldTransform( eyeOffsetJoint, gameLocal.time, eyeOffset, axis );
  1864.         eyeOffset = (eyeOffset - GetPhysics()->GetOrigin()) * viewAxis.Transpose( );
  1865.     }    
  1866.  
  1867.     if ( DebugFilter( ai_debugMove ) ) { // RED = Eye Pos & orientation
  1868.         gameRenderWorld->DebugArrow( colorRed, GetEyePosition(), GetEyePosition() + viewAxis[ 0 ] * 32.0f, 4, gameLocal.msec );
  1869.     }
  1870.  
  1871.     // Dynamically update the chest offset if a joint was specified
  1872.     if ( chestOffsetJoint != INVALID_JOINT ) {
  1873.         GetJointWorldTransform( chestOffsetJoint, gameLocal.time, chestOffset, axis );
  1874.         chestOffset = ( chestOffset - GetPhysics()->GetOrigin() ) * viewAxis.Transpose();
  1875.     }
  1876.  
  1877.     if ( DebugFilter( ai_debugMove ) ) { // RED = Eye Pos & orientation
  1878.         gameRenderWorld->DebugArrow( colorPink, GetChestPosition(), GetChestPosition() + viewAxis[ 0 ] * 32.0f, 4, gameLocal.msec );
  1879.     }
  1880.  
  1881.     return false;
  1882. }
  1883.  
  1884. /*
  1885. ================
  1886. idActor::RemoveAttachments
  1887. ================
  1888. */
  1889. void idActor::RemoveAttachments( void ) {
  1890.     int i;
  1891.     idEntity *ent;
  1892.  
  1893.     // remove any attached entities
  1894.     for( i = 0; i < attachments.Num(); i++ ) {
  1895.         ent = attachments[ i ].ent.GetEntity();
  1896.         if ( ent && ent->spawnArgs.GetBool( "remove" ) ) {
  1897.             ent->PostEventMS( &EV_Remove, 0 );
  1898.         }
  1899.     }
  1900. }
  1901.  
  1902. /*
  1903. ================
  1904. idActor::Attach
  1905. ================
  1906. */
  1907. void idActor::Attach( idEntity *ent ) {
  1908.     idVec3            origin;
  1909.     idMat3            axis;
  1910.     jointHandle_t    joint;
  1911.     idStr            jointName;
  1912.     idAttachInfo    &attach = attachments.Alloc();
  1913.     idAngles        angleOffset;
  1914.     idVec3            originOffset;
  1915.  
  1916.     jointName = ent->spawnArgs.GetString( "joint" );
  1917.     joint = animator.GetJointHandle( jointName );
  1918.     if ( joint == INVALID_JOINT ) {
  1919.         gameLocal.Error( "Joint '%s' not found for attaching '%s' on '%s'", jointName.c_str(), ent->GetClassname(), name.c_str() );
  1920.     }
  1921.  
  1922.     angleOffset = ent->spawnArgs.GetAngles( "angles" );
  1923.     originOffset = ent->spawnArgs.GetVector( "origin" );
  1924.  
  1925.     attach.channel = animator.GetChannelForJoint( joint );
  1926.     GetJointWorldTransform( joint, gameLocal.time, origin, axis );
  1927.     attach.ent = ent;
  1928.  
  1929.     ent->SetOrigin( origin + originOffset * renderEntity.axis );
  1930.     idMat3 rotate = angleOffset.ToMat3();
  1931.     idMat3 newAxis = rotate * axis;
  1932.     ent->SetAxis( newAxis );
  1933.     ent->BindToJoint( this, joint, true );
  1934.     ent->cinematic = cinematic;
  1935. }
  1936.  
  1937. idEntity* idActor::FindAttachment( const char* attachmentName )
  1938. {
  1939.     idEntity *ent = NULL;
  1940.     const char* fullName = va("idAFAttachment_%s",attachmentName);
  1941.     // find the specified attachment
  1942.     for( int i = 0; i < attachments.Num(); i++ ) {
  1943.         ent = attachments[ i ].ent.GetEntity();
  1944.         if ( ent && !ent->name.CmpPrefix(fullName) ) {
  1945.             return ent;
  1946.         }
  1947.     }
  1948.     return NULL;
  1949. }
  1950.  
  1951. void idActor::HideAttachment( const char* attachmentName )
  1952. {
  1953.     idEntity *ent = FindAttachment( attachmentName );
  1954.     if ( ent )
  1955.     {
  1956.         ent->Hide();
  1957.     }
  1958. }
  1959.  
  1960. void idActor::ShowAttachment( const char* attachmentName )
  1961. {
  1962.     idEntity *ent = FindAttachment( attachmentName );
  1963.     if ( ent )
  1964.     {
  1965.         ent->Show();
  1966.     }
  1967. }
  1968.  
  1969. /*
  1970. ================
  1971. idActor::Teleport
  1972. ================
  1973. */
  1974. void idActor::Teleport( const idVec3 &origin, const idAngles &angles, idEntity *destination ) {
  1975.     GetPhysics()->SetOrigin( origin + idVec3( 0, 0, CM_CLIP_EPSILON ) );
  1976.     GetPhysics()->SetLinearVelocity( vec3_origin );
  1977.  
  1978.     viewAxis = angles.ToMat3();
  1979.  
  1980.     UpdateVisuals();
  1981.  
  1982.     if ( !IsHidden() ) {
  1983.         // kill anything at the new position
  1984.         gameLocal.KillBox( this );
  1985.     }
  1986. }
  1987.  
  1988. /*
  1989. ================
  1990. idActor::GetDeltaViewAngles
  1991. ================
  1992. */
  1993. const idAngles &idActor::GetDeltaViewAngles( void ) const {
  1994.     return deltaViewAngles;
  1995. }
  1996.  
  1997. /*
  1998. ================
  1999. idActor::SetDeltaViewAngles
  2000. ================
  2001. */
  2002. void idActor::SetDeltaViewAngles( const idAngles &delta ) {
  2003.     deltaViewAngles = delta;
  2004. }
  2005.  
  2006. /*
  2007. ================
  2008. idActor::HasEnemies
  2009. ================
  2010. */
  2011. bool idActor::HasEnemies( void ) const {
  2012.     idActor *ent;
  2013.  
  2014.     for( ent = enemyList.Next(); ent != NULL; ent = ent->enemyNode.Next() ) {
  2015.         if ( !ent->fl.hidden ) {
  2016.             return true;
  2017.         }
  2018.     }
  2019.  
  2020.     return false;
  2021. }
  2022.  
  2023. /*
  2024. ================
  2025. idActor::ClosestEnemyToPoint
  2026. ================
  2027. */
  2028. idActor *idActor::ClosestEnemyToPoint( const idVec3 &pos, float maxRange, bool returnFirst, bool checkPVS ) {
  2029.     idActor        *ent;
  2030.     idActor        *bestEnt;
  2031.     float        bestDistSquared;
  2032.     float        distSquared;
  2033.     idVec3        delta;
  2034.     pvsHandle_t pvs;
  2035.     
  2036.     //just to supress the compiler warning
  2037.     pvs.i = 0;
  2038.  
  2039.     if ( checkPVS ) {
  2040.         // Setup our local variables used in the search
  2041.         pvs     = gameLocal.pvs.SetupCurrentPVS( GetPVSAreas(), GetNumPVSAreas() );
  2042.     }
  2043.  
  2044.     bestDistSquared = maxRange?(maxRange*maxRange):idMath::INFINITY;
  2045.     bestEnt = NULL;
  2046.     for( ent = enemyList.Next(); ent != NULL; ent = ent->enemyNode.Next() ) {
  2047.         if ( ent->fl.hidden ) {
  2048.             continue;
  2049.         }
  2050.         delta = ent->GetPhysics()->GetOrigin() - pos;
  2051.         distSquared = delta.LengthSqr();
  2052.         if ( distSquared < bestDistSquared ) {
  2053.             if ( checkPVS ) {
  2054.                 // If this enemy isnt in the same pvps then use them as a backup
  2055.                 if ( pvs.i > 0 
  2056.                     && pvs.i < MAX_CURRENT_PVS
  2057.                     && !gameLocal.pvs.InCurrentPVS( pvs, ent->GetPVSAreas(), ent->GetNumPVSAreas() ) ) {
  2058.                     continue;
  2059.                 }
  2060.             }
  2061.             bestEnt = ent;
  2062.             bestDistSquared = distSquared;
  2063.             if ( returnFirst ) {
  2064.                 break;
  2065.             }
  2066.         }
  2067.     }
  2068.  
  2069.     if ( checkPVS ) {
  2070.         gameLocal.pvs.FreeCurrentPVS( pvs );
  2071.     }
  2072.     return bestEnt;
  2073. }
  2074.  
  2075. /*
  2076. ================
  2077. idActor::EnemyWithMostHealth
  2078. ================
  2079. */
  2080. idActor *idActor::EnemyWithMostHealth() {
  2081.     idActor        *ent;
  2082.     idActor        *bestEnt;
  2083.  
  2084.     int most = -9999;
  2085.     bestEnt = NULL;
  2086.     for( ent = enemyList.Next(); ent != NULL; ent = ent->enemyNode.Next() ) {
  2087.         if ( !ent->fl.hidden && ( ent->health > most ) ) {
  2088.             bestEnt = ent;
  2089.             most = ent->health;
  2090.         }
  2091.     }
  2092.     return bestEnt;
  2093. }
  2094.  
  2095. /*
  2096. ================
  2097. idActor::OnLadder
  2098. ================
  2099. */
  2100. bool idActor::OnLadder( void ) const {
  2101.     return false;
  2102. }
  2103.  
  2104. /*
  2105. ==============
  2106. idActor::GetAASLocation
  2107. ==============
  2108. */
  2109. void idActor::GetAASLocation( idAAS *aas, idVec3 &pos, int &areaNum ) const {
  2110.     idVec3        size;
  2111.     idBounds    bounds;
  2112.  
  2113.     GetFloorPos( 64.0f, pos );
  2114.     if ( !aas ) {
  2115.         areaNum = 0;
  2116.         return;
  2117.     }
  2118.     
  2119.     size = aas->GetSettings()->boundingBoxes[0][1];
  2120.     bounds[0] = -size;
  2121.     size.z = 32.0f;
  2122.     bounds[1] = size;
  2123.  
  2124.     areaNum = aas->PointReachableAreaNum( pos, bounds, AREA_REACHABLE_WALK );
  2125.     if ( areaNum ) {
  2126.         aas->PushPointIntoAreaNum( areaNum, pos );
  2127.     }
  2128. }
  2129.  
  2130. /***********************************************************************
  2131.  
  2132.     animation state
  2133.  
  2134. ***********************************************************************/
  2135.  
  2136. /*
  2137. =====================
  2138. idActor::StopAnimState
  2139. =====================
  2140. */
  2141. void idActor::StopAnimState ( int channel ) {
  2142.     GetAnimState ( channel ).Shutdown ( );
  2143. }
  2144.  
  2145. /*
  2146. =====================
  2147. idActor::PostAnimState
  2148. =====================
  2149. */
  2150. void idActor::PostAnimState ( int channel, const char* statename, int blendFrames, int delay, int flags ) {
  2151.     GetAnimState ( channel ).PostState ( statename, blendFrames, delay, flags );
  2152. }
  2153.  
  2154. /*
  2155. =====================
  2156. idActor::SetAnimState
  2157. =====================
  2158. */
  2159. void idActor::SetAnimState( int channel, const char *statename, int blendFrames, int flags ) {
  2160.     switch ( channel ) {
  2161.         case ANIMCHANNEL_HEAD :
  2162.             headAnim.GetStateThread().Clear ( );
  2163.             break;
  2164.             
  2165.         case ANIMCHANNEL_TORSO :
  2166.             torsoAnim.GetStateThread().Clear ( );
  2167.             legsAnim.Enable( blendFrames );
  2168.             break;
  2169.  
  2170.         case ANIMCHANNEL_LEGS :
  2171.             legsAnim.GetStateThread().Clear ( );
  2172.             torsoAnim.Enable( blendFrames );
  2173.             break;
  2174.     }        
  2175.  
  2176.     OnStateChange ( channel );
  2177.     
  2178.     PostAnimState ( channel, statename, blendFrames, flags );
  2179. }
  2180.  
  2181. /*
  2182. =====================
  2183. idActor::OnStateChange
  2184. =====================
  2185. */
  2186. void idActor::OnStateChange ( int channel ) {
  2187.     allowEyeFocus = true;
  2188.  
  2189.     // Only clear eye focus on head channel change
  2190.     if ( channel == ANIMCHANNEL_HEAD ) {
  2191.         return;
  2192.     }
  2193.  
  2194.     disablePain = false;
  2195. }
  2196.  
  2197. /*
  2198. =====================
  2199. idActor::OnFriendlyFire
  2200. =====================
  2201. */
  2202. void idActor::OnFriendlyFire ( idActor* attacker ) {
  2203. }
  2204.  
  2205. /*
  2206. =====================
  2207. idActor::UpdateAnimState
  2208. =====================
  2209. */
  2210. void idActor::UpdateAnimState( void ) {
  2211. // RAVEN BEGIN
  2212. // jnewquist: Tag scope and callees to track allocations using "new".
  2213.     MEM_SCOPED_TAG(tag,MA_ANIM);
  2214. // RAVEN END
  2215.     headAnim.UpdateState();
  2216.     torsoAnim.UpdateState();
  2217.     legsAnim.UpdateState();
  2218. }
  2219.  
  2220. /*
  2221. =====================
  2222. idActor::GetAnim
  2223. =====================
  2224. */
  2225. int idActor::GetAnim( int channel, const char *animname, bool forcePrefix ) {
  2226.     int            anim;
  2227.     const char *temp;
  2228.     idAnimator *animatorPtr;
  2229.  
  2230.     if ( channel == ANIMCHANNEL_HEAD ) {
  2231.         if ( !head.GetEntity() ) {
  2232.             return 0;
  2233.         }
  2234.         animatorPtr = head.GetEntity()->GetAnimator();
  2235.     } else {
  2236.         animatorPtr = &animator;
  2237.     }
  2238.  
  2239.     // Allow for anim substitution
  2240.     animname = spawnArgs.GetString ( va("anim %s", animname ), animname );
  2241.  
  2242.     if ( animPrefix.Length() ) {
  2243.         temp = va( "%s_%s", animPrefix.c_str(), animname );
  2244.         anim = animatorPtr->GetAnim( temp );
  2245.         if ( anim ) {
  2246.             return anim;
  2247.         } else if ( forcePrefix ) {
  2248.             return NULL;
  2249.         }
  2250.     }
  2251.  
  2252.     anim = animatorPtr->GetAnim( animname );
  2253.  
  2254.     return anim;
  2255. }
  2256.  
  2257. /*
  2258. ===============
  2259. idActor::SyncAnimChannels
  2260. ===============
  2261. */
  2262. void idActor::SyncAnimChannels( int channel, int syncToChannel, int blendFrames ) {
  2263.     idAnimator        *headAnimator;
  2264.     idAFAttachment    *headEnt;
  2265.     int                anim;
  2266.     idAnimBlend        *syncAnim;
  2267.     int                starttime;
  2268.     int                blendTime;
  2269.     int                cycle;
  2270.  
  2271.     blendTime = FRAME2MS( blendFrames );
  2272.     if ( channel == ANIMCHANNEL_HEAD ) {
  2273.         headEnt = head.GetEntity();
  2274.         if ( headEnt ) {
  2275.             headAnimator = headEnt->GetAnimator();
  2276.             syncAnim = animator.CurrentAnim( syncToChannel );
  2277.             if ( syncAnim ) {
  2278.                 anim = headAnimator->GetAnim( syncAnim->AnimFullName() );
  2279.                 if ( !anim ) {
  2280.                     anim = headAnimator->GetAnim( syncAnim->AnimName() );
  2281.                 }
  2282.                 if ( anim ) {
  2283.                     cycle = animator.CurrentAnim( syncToChannel )->GetCycleCount();
  2284.                     starttime = animator.CurrentAnim( syncToChannel )->GetStartTime();
  2285.                     headAnimator->PlayAnim( ANIMCHANNEL_LEGS, anim, gameLocal.time, blendTime );
  2286.                     headAnimator->CurrentAnim( ANIMCHANNEL_LEGS )->SetCycleCount( cycle );
  2287.                     headAnimator->CurrentAnim( ANIMCHANNEL_LEGS )->SetStartTime( starttime );
  2288.                 } else {
  2289.                     headEnt->PlayIdleAnim( ANIMCHANNEL_LEGS, blendTime );
  2290.                 }
  2291.             }
  2292.         }
  2293.     } else if ( syncToChannel == ANIMCHANNEL_HEAD ) {
  2294.         headEnt = head.GetEntity();
  2295.         if ( headEnt ) {
  2296.             headAnimator = headEnt->GetAnimator();
  2297.             syncAnim = headAnimator->CurrentAnim( ANIMCHANNEL_LEGS );
  2298.             if ( syncAnim ) {
  2299.                 anim = GetAnim( channel, syncAnim->AnimFullName() );
  2300.                 if ( !anim ) {
  2301.                     anim = GetAnim( channel, syncAnim->AnimName() );
  2302.                 }
  2303.                 if ( anim ) {
  2304.                     cycle = headAnimator->CurrentAnim( ANIMCHANNEL_LEGS )->GetCycleCount();
  2305.                     starttime = headAnimator->CurrentAnim( ANIMCHANNEL_LEGS )->GetStartTime();
  2306.                     animator.PlayAnim( channel, anim, gameLocal.time, blendTime );
  2307.                     animator.CurrentAnim( channel )->SetCycleCount( cycle );
  2308.                     animator.CurrentAnim( channel )->SetStartTime( starttime );
  2309.                 }
  2310.             }
  2311.         }
  2312.     } else {
  2313.         animator.SyncAnimChannels( channel, syncToChannel, gameLocal.time, blendTime );
  2314.     }
  2315. }
  2316.  
  2317. /***********************************************************************
  2318.  
  2319.     Damage
  2320.  
  2321. ***********************************************************************/
  2322.  
  2323. /*
  2324. ============
  2325. idActor::Gib
  2326. ============
  2327. */
  2328. void idActor::Gib( const idVec3 &dir, const char *damageDefName ) {
  2329.     // for multiplayer we use client-side models
  2330.     if ( gameLocal.isMultiplayer ) {
  2331.         return;
  2332.     }
  2333.     // only gib once
  2334.     if ( gibbed ) {
  2335.         return;
  2336.     }
  2337.     idAFEntity_Gibbable::Gib( dir, damageDefName );
  2338.     if ( head.GetEntity() ) {
  2339.         head.GetEntity()->Hide();
  2340.     }
  2341.     StopSound( SND_CHANNEL_VOICE, false );
  2342.     
  2343.     gameLocal.PlayEffect ( spawnArgs, "fx_gib", GetPhysics()->GetOrigin(), GetPhysics()->GetAxis() );
  2344. }
  2345.  
  2346. void idActor::CheckDeathObjectives( void )
  2347. {
  2348.     idPlayer *player = gameLocal.GetLocalPlayer();
  2349.  
  2350.     if ( !player || !player->GetObjectiveHud() ) {
  2351.         return;
  2352.     }
  2353.  
  2354.     if ( spawnArgs.GetString( "objectivetitle_failed", NULL ) ) {
  2355.         player->GetObjectiveHud()->SetStateString( "objective", "2" );
  2356.         player->GetObjectiveHud()->SetStateString( "objectivetext", common->GetLocalizedString( spawnArgs.GetString( "objectivetext_failed" ) ) );
  2357.         player->GetObjectiveHud()->SetStateString( "objectivetitle", common->GetLocalizedString( spawnArgs.GetString( "objectivetitle_failed" ) ) );
  2358.  
  2359.         player->FailObjective( spawnArgs.GetString( "objectivetitle_failed" ) );
  2360.     }
  2361.  
  2362.     if ( spawnArgs.GetString( "objectivetitle_completed", NULL ) ) {
  2363.         player->GetObjectiveHud()->SetStateString( "objective", "2" );
  2364.         player->GetObjectiveHud()->SetStateString( "objectivetext", common->GetLocalizedString( spawnArgs.GetString( "objectivetext_completed" ) ) );
  2365.         player->GetObjectiveHud()->SetStateString( "objectivetitle", common->GetLocalizedString( spawnArgs.GetString( "objectivetitle_completed" ) ) );
  2366.  
  2367.         player->CompleteObjective( spawnArgs.GetString( "objectivetitle_completed" ) );
  2368.     }
  2369. }
  2370. /*
  2371. ============
  2372. idActor::Damage
  2373.  
  2374. this        entity that is being damaged
  2375. inflictor    entity that is causing the damage
  2376. attacker    entity that caused the inflictor to damage targ
  2377.     example: this=monster, inflictor=rocket, attacker=player
  2378.  
  2379. dir            direction of the attack for knockback in global space
  2380. point        point at which the damage is being inflicted, used for headshots
  2381. damage        amount of damage being inflicted
  2382.  
  2383. inflictor, attacker, dir, and point can be NULL for environmental effects
  2384.  
  2385. Bleeding wounds and surface overlays are applied in the collision code that
  2386. calls Damage()
  2387. ============
  2388. */
  2389. void idActor::Damage( idEntity *inflictor, idEntity *attacker, const idVec3 &dir, 
  2390.                       const char *damageDefName, const float damageScale, const int location ) {
  2391.     if ( !fl.takedamage ) {
  2392.         return;
  2393.     }
  2394.  
  2395.     if ( !inflictor ) {
  2396.         inflictor = gameLocal.world;
  2397.     }
  2398.     if ( !attacker ) {
  2399.         attacker = gameLocal.world;
  2400.     }
  2401.  
  2402.     const idDict *damageDef = gameLocal.FindEntityDefDict( damageDefName, false );
  2403.     if ( !damageDef ) {
  2404.         gameLocal.Error( "Unknown damageDef '%s'", damageDefName );
  2405.     }
  2406.  
  2407.     int    damage = damageDef->GetInt( "damage" ) * damageScale;
  2408.     damage = GetDamageForLocation( damage, location );
  2409.  
  2410.     // friendly fire damage
  2411.     bool noDmgFeedback = false;
  2412.     if ( attacker->IsType ( idActor::Type ) && static_cast<idActor*>(attacker)->team == team ) {
  2413.         
  2414.         OnFriendlyFire ( static_cast<idActor*>(attacker) );
  2415.         
  2416.         // jshepard:
  2417.         // if the player deals friendly fire damage it is reduced to 0. If the damage is splash damage,
  2418.         // then the victim should use a pain anim.
  2419.         if( static_cast<idPlayer*>( attacker ) == gameLocal.GetLocalPlayer() )    {
  2420.             
  2421.             //play pain (maybe one day a special anim?) for damages that have the cower keyword
  2422.             if ( damageDef->GetBool( "cower" ))    {
  2423.                 Pain( inflictor, attacker, damage, dir, location );
  2424.             }
  2425.             
  2426.             //reduce the damage
  2427.             damage = 0;
  2428.             noDmgFeedback = true;
  2429.         }        
  2430.  
  2431.         // reduce friendly fire damage by the teamscale
  2432.         damage = floor( damage * damageDef->GetFloat ( "teamScale", "0.5" ) );
  2433.  
  2434.  
  2435.     }
  2436.  
  2437.     if ( !IsType( idPlayer::GetClassType() ) && attacker->IsType( idAI::GetClassType() ) ) {
  2438.         if ( ((idAI*)attacker)->aifl.killerGuard ) {
  2439.             //Hard-coded to do lots of damage
  2440.             damage = 100;
  2441.         }
  2442.     }
  2443.  
  2444.     if ( !noDmgFeedback ) {
  2445.         // inform the attacker that they hit someone
  2446.         attacker->DamageFeedback( this, inflictor, damage );
  2447.     }
  2448.  
  2449. // RAVEN BEGIN
  2450. // jnewquist: FIXME - Was this removed from Xenon intentionally?
  2451. #ifdef _XENON
  2452.     // singleplayer stat reporting.
  2453.     if(!gameLocal.isMultiplayer) {
  2454.         int methodOfDeath = -1;
  2455.         // jnewquist: Use accessor for static class type 
  2456.         if ( inflictor->IsType( idProjectile::GetClassType() ) ) {
  2457.         // RAVEN END
  2458.             methodOfDeath = static_cast<idProjectile*>(inflictor)->methodOfDeath;
  2459.         } else if ( inflictor->IsType( idPlayer::GetClassType() ) ) {
  2460.             // hitscan weapon
  2461.             methodOfDeath = static_cast<idPlayer*>(inflictor)->GetCurrentWeapon();
  2462.         }
  2463.         if( methodOfDeath != -1 && attacker && attacker->IsType( idActor::Type ) ) {
  2464. // jnewquist: Fix Xenon compile warning
  2465.             statManager->WeaponHit( static_cast<idActor*> (attacker) , this, methodOfDeath, !!damage );
  2466.         }
  2467.     }
  2468. #endif
  2469. // RAVEN END
  2470.  
  2471. // RAVEN BEGIN
  2472. // MCG - added damage over time
  2473.     if ( !inDamageEvent ) {
  2474.         if ( damageDef->GetFloat( "dot_duration" ) ) {
  2475.             int endTime;
  2476.             if ( damageDef->GetFloat( "dot_duration" ) == -1 ) {
  2477.                 endTime = -1;
  2478.             } else {
  2479.                 endTime = gameLocal.GetTime() + SEC2MS(damageDef->GetFloat( "dot_duration" ));
  2480.             }
  2481.             int interval = SEC2MS(damageDef->GetFloat( "dot_interval", "0" ));
  2482.             if ( endTime == -1 || gameLocal.GetTime() + interval <= endTime ) {//post it again
  2483.                 PostEventMS( &EV_DamageOverTime, interval, endTime, interval, inflictor, attacker, dir, damageDefName, damageScale, location );
  2484.             }
  2485.             if ( damageDef->GetString( "fx_dot", NULL ) ) {
  2486.                 ProcessEvent( &EV_DamageOverTimeEffect, endTime, interval, damageDefName );
  2487.             }
  2488.             if ( damageDef->GetString( "snd_dot_start", NULL ) ) {
  2489.                 StartSound ( "snd_dot_start", SND_CHANNEL_ANY, 0, false, NULL );
  2490.             }
  2491.         }
  2492.     }
  2493. // RAVEN END
  2494.  
  2495.     if ( damage > 0 ) {
  2496.         int oldHealth = health;
  2497.         AdjustHealthByDamage ( damage );
  2498.         if ( health <= 0 ) {
  2499.             if ( health < -999 ) {
  2500.                 health = -999;
  2501.             }
  2502.             //annoying hack for StartRagdoll
  2503.             bool saveGibbed = gibbed;
  2504.             if ( ( health < -20 ) && spawnArgs.GetBool( "gib" ) && damageDef->GetBool( "gib" ) ) {
  2505.                 gibbed = true;
  2506.             }
  2507.             Killed( inflictor, attacker, damage, dir, location );
  2508.             gibbed = saveGibbed;
  2509.             if ( ( health < -20 ) && spawnArgs.GetBool( "gib" ) && damageDef->GetBool( "gib" ) ) {
  2510.                 Gib( dir, damageDefName );
  2511.             }
  2512.  
  2513.             if ( oldHealth > 0 && !gibbed ) {    
  2514.                   float pushScale = 1.0f;
  2515.                   if ( inflictor && inflictor->IsType ( idPlayer::GetClassType() ) ) {
  2516.                       pushScale = static_cast<idPlayer*>(inflictor)->PowerUpModifier ( PMOD_PROJECTILE_DEATHPUSH );
  2517.                   }
  2518.                   InitDeathPush ( dir, location, damageDef, pushScale );
  2519.               }
  2520.         } else {
  2521.             painType = damageDef->GetString ( "pain" );
  2522.             Pain( inflictor, attacker, damage, dir, location );
  2523.         }
  2524.     } else {
  2525.         // don't accumulate knockback
  2526.         /*
  2527.         if ( af.IsLoaded() ) {
  2528.             // clear impacts
  2529.             af.Rest();
  2530.  
  2531.             // physics is turned off by calli/ng af.Rest()
  2532.             BecomeActive( TH_PHYSICS );
  2533.         }
  2534.         */
  2535.     }
  2536. }
  2537.  
  2538. /*
  2539. =====================
  2540. idActor::InitDeathPush
  2541. =====================
  2542. */
  2543. void idActor::InitDeathPush ( const idVec3& dir, int location, const idDict* damageDict, float pushScale ) {
  2544.     idVec2    forceMin;
  2545.     idVec2    forceMax;
  2546.  
  2547.     if( !af.IsActive() ) {
  2548.         return;
  2549.     }
  2550.     
  2551.     if ( deathPushTime > gameLocal.time ) { 
  2552.         return;
  2553.     }
  2554.     
  2555.     if ( !damageDict->GetInt ( "deathPush", "0", deathPushTime ) || deathPushTime <= 0 ) {
  2556.         return;
  2557.     }
  2558.     
  2559.     damageDict->GetVec2( "deathPushMin", "", forceMin );    
  2560.     damageDict->GetVec2( "deathPushMax", "", forceMax );    
  2561.  
  2562. /*
  2563.     forceMin *= (pushScale * GetPhysics()->GetMass());
  2564.     forceMax *= (pushScale * GetPhysics()->GetMass());
  2565. */
  2566.     forceMin *= (pushScale);
  2567.     forceMax *= (pushScale);
  2568.  
  2569.     deathPushForce = dir;
  2570.     deathPushForce.Normalize ( );
  2571.     deathPushForce = rvRandom::flrand ( forceMin.x, forceMax.x ) * deathPushForce + 
  2572.             -rvRandom::flrand ( forceMin.y, forceMax.y ) * GetPhysics()->GetGravityNormal ( );
  2573.     
  2574.     deathPushTime += gameLocal.time;
  2575.     deathPushJoint = (jointHandle_t) location;
  2576. }
  2577.  
  2578. /*
  2579. =====================
  2580. idActor::DeathPush
  2581. =====================
  2582. */
  2583. void idActor::DeathPush ( void ) {
  2584.     if ( deathPushTime <= gameLocal.time ) {
  2585.         return;
  2586.     }
  2587.  
  2588.     idVec3 center;
  2589.     center = GetPhysics()->GetAbsBounds ( ).GetCenter();
  2590.  
  2591.     GetPhysics()->ApplyImpulse ( 0, center, -0.5f * GetPhysics()->GetMass () * MS2SEC(gameLocal.GetMSec()) * GetPhysics()->GetGravity ( ) );
  2592.     
  2593.     if ( deathPushJoint != INVALID_JOINT ) {
  2594.         idVec3 origin;
  2595.         idMat3 axis;
  2596.         GetJointWorldTransform ( deathPushJoint, gameLocal.time, origin, axis );
  2597.         GetPhysics()->ApplyImpulse ( 0, origin, deathPushForce );
  2598.     } else {
  2599.         GetPhysics()->ApplyImpulse ( 0, center, deathPushForce );
  2600.     }
  2601. }
  2602.  
  2603. /*
  2604. =====================
  2605. idActor::SkipImpulse
  2606. =====================
  2607. */
  2608. bool idActor::SkipImpulse( idEntity* ent, int id ) {    
  2609.     return idAFEntity_Gibbable::SkipImpulse( ent, id ) || health <= 0 || gibbed || ent->IsType( idActor::GetClassType() ) || ent->IsType( idProjectile::GetClassType() );
  2610. }
  2611.  
  2612. /*
  2613. =====================
  2614. idActor::AddDamageEffect
  2615. =====================
  2616. */
  2617. void idActor::AddDamageEffect( const trace_t &collision, const idVec3 &velocity, const char *damageDefName, idEntity* inflictor ) {
  2618.     if ( !gameLocal.isMultiplayer && inflictor && inflictor->IsType ( idActor::GetClassType ( ) ) ) {
  2619.         if ( static_cast<idActor*>(inflictor)->team == team ) {
  2620.             return;
  2621.         }
  2622.     }
  2623.     idAFEntity_Gibbable::AddDamageEffect( collision, velocity, damageDefName, inflictor );
  2624. }
  2625.  
  2626. /*
  2627. =====================
  2628. idActor::ClearPain
  2629. =====================
  2630. */
  2631. void idActor::ClearPain( void ) {
  2632.     pain_debounce_time = 0;
  2633. }
  2634.  
  2635. /*
  2636. =====================
  2637. idActor::Pain
  2638. =====================
  2639. */
  2640. bool idActor::Pain( idEntity *inflictor, idEntity *attacker, int damage, const idVec3 &dir, int location ) {
  2641.     if ( af.IsLoaded() ) {
  2642.         // clear impacts
  2643.         af.Rest();
  2644.  
  2645.         // physics is turned off by calling af.Rest()
  2646.         BecomeActive( TH_PHYSICS );
  2647.     }
  2648.  
  2649.     if ( gameLocal.time < pain_debounce_time ) {
  2650.         return false;
  2651.     }
  2652.     
  2653.     // No pain if being hit by a friendly target
  2654.     // jshepard: friendly targets can now cause pain
  2655. /*
  2656.     if ( attacker && attacker->IsType ( idActor::GetClassType ( ) ) ) {
  2657.         if ( static_cast<idActor*>( attacker )->team == team ) {
  2658.             return false;
  2659.         }
  2660.     }
  2661. */
  2662.  
  2663.     // don't play pain sounds more than necessary
  2664.     pain_debounce_time = gameLocal.time + pain_delay;
  2665.  
  2666.     float f;
  2667. // RAVEN BEGIN
  2668. // mekberg: fixed divide by zero
  2669.     float spawnHealth = spawnArgs.GetFloat ( "health", "1" );
  2670.     if (spawnHealth<1.0f) {
  2671.         spawnHealth = 1.0f;        // more devide by zero nonsense
  2672.     }
  2673.     f = (float)damage / spawnHealth;
  2674. // RAVEN END
  2675.     if ( f > 0.75f ) {
  2676.         StartSound( "snd_pain_huge", SND_CHANNEL_VOICE, 0, false, NULL );
  2677.     } else if ( f > 0.5f ) {
  2678.         StartSound( "snd_pain_large", SND_CHANNEL_VOICE, 0, false, NULL );
  2679.     } else if ( f > 0.25f ) {
  2680.         StartSound( "snd_pain_medium", SND_CHANNEL_VOICE, 0, false, NULL );
  2681.     } else {
  2682.         StartSound( "snd_pain_small", SND_CHANNEL_VOICE, 0, false, NULL );
  2683.     }
  2684.  
  2685.     if ( disablePain || ( gameLocal.time < painTime ) ) {
  2686.         // don't play a pain anim
  2687.         return false;
  2688.     }
  2689.  
  2690.     // set the pain anim
  2691.     idStr damageGroup = GetDamageGroup( location );
  2692.  
  2693.     painAnim.Clear ( );
  2694.  
  2695.     // If we have both a damage group and a pain type then check that combination first
  2696.     if ( damageGroup.Length ( ) && painType.Length ( ) ) {
  2697.         painAnim = va ( "pain_%s_%s", painType.c_str(), damageGroup.c_str() );
  2698.         if ( !animator.HasAnim ( painAnim ) ) {
  2699.             painAnim.Clear ( );
  2700.         }
  2701.     }
  2702.     
  2703.     // Do we have a pain anim for just the pain type?
  2704.     if ( !painAnim.Length ( ) && painType.Length ( ) ) {
  2705.         painAnim = va ( "pain_%s", painType.c_str() );
  2706.         if ( !animator.HasAnim ( painAnim ) ) {
  2707.             painAnim.Clear ( );
  2708.         }
  2709.     }
  2710.  
  2711.     // Do we have a pain anim for just the damage group?
  2712.     if ( !painAnim.Length ( ) && damageGroup.Length ( ) ) {
  2713.         painAnim = va ( "pain_%s", damageGroup.c_str() );
  2714.         if ( !animator.HasAnim ( painAnim ) ) {
  2715.             painAnim.Clear ( );
  2716.         }
  2717.     }    
  2718.  
  2719.     if ( !painAnim.Length() ) {
  2720.         painAnim = "pain";
  2721.     }
  2722.  
  2723.     if ( g_debugDamage.GetBool() ) {
  2724.         gameLocal.Printf( "Damage: joint: '%s', zone '%s', anim '%s'\n", animator.GetJointName( ( jointHandle_t )location ), 
  2725.             damageGroup.c_str(), painAnim.c_str() );
  2726.     }
  2727.  
  2728.     return true;
  2729. }
  2730.  
  2731. /*
  2732. =====================
  2733. idActor::SpawnGibs
  2734. =====================
  2735. */
  2736. void idActor::SpawnGibs( const idVec3 &dir, const char *damageDefName ) {
  2737.     idAFEntity_Gibbable::SpawnGibs( dir, damageDefName );
  2738.     RemoveAttachments();
  2739. }
  2740.  
  2741. /*
  2742. =====================
  2743. idActor::SetupDamageGroups
  2744.  
  2745. FIXME: only store group names once and store an index for each joint
  2746. =====================
  2747. */
  2748. void idActor::SetupDamageGroups( void ) {
  2749.     int                        i;
  2750.     const idKeyValue        *arg;
  2751.     idStr                    groupname;
  2752.     idList<jointHandle_t>    jointList;
  2753.     int                        jointnum;
  2754.     float                    scale;
  2755.  
  2756.     // create damage zones
  2757.     damageGroups.SetNum( animator.NumJoints() );
  2758.     arg = spawnArgs.MatchPrefix( "damage_zone ", NULL );
  2759.     while ( arg ) {
  2760.         groupname = arg->GetKey();
  2761.         groupname.Strip( "damage_zone " );
  2762.         animator.GetJointList( arg->GetValue(), jointList );
  2763.         for( i = 0; i < jointList.Num(); i++ ) {
  2764.             jointnum = jointList[ i ];
  2765.             damageGroups[ jointnum ] = groupname;
  2766.         }
  2767.         jointList.Clear();
  2768.         arg = spawnArgs.MatchPrefix( "damage_zone ", arg );
  2769.     }
  2770.  
  2771.     // initilize the damage zones to normal damage
  2772.     damageScale.SetNum( animator.NumJoints() );
  2773.     for( i = 0; i < damageScale.Num(); i++ ) {
  2774.         damageScale[ i ] = 1.0f;
  2775.     }
  2776.  
  2777.     // set the percentage on damage zones
  2778.     arg = spawnArgs.MatchPrefix( "damage_scale ", NULL );
  2779.     while ( arg ) {
  2780.         scale = atof( arg->GetValue() );
  2781.         groupname = arg->GetKey();
  2782.         groupname.Strip( "damage_scale " );
  2783.         for( i = 0; i < damageScale.Num(); i++ ) {
  2784.             if ( damageGroups[ i ] == groupname ) {
  2785.                 damageScale[ i ] = scale;
  2786.             }
  2787.         }
  2788.         arg = spawnArgs.MatchPrefix( "damage_scale ", arg );
  2789.     }
  2790. }
  2791.  
  2792. /*
  2793. =====================
  2794. idActor::GetDamageForLocation
  2795. =====================
  2796. */
  2797. int idActor::GetDamageForLocation( int damage, int location ) {
  2798.     if ( ( location < 0 ) || ( location >= damageScale.Num() ) ) {
  2799.         return damage;
  2800.     }
  2801.  
  2802.     return (int)ceil( damage * damageScale[ location ] );
  2803. }
  2804.  
  2805. /*
  2806. =====================
  2807. idActor::GetDamageGroup
  2808. =====================
  2809. */
  2810. const char *idActor::GetDamageGroup( int location ) {
  2811.     if ( ( location < 0 ) || ( location >= damageGroups.Num() ) ) {
  2812.         return "";
  2813.     }
  2814.  
  2815.     return damageGroups[ location ];
  2816. }
  2817.  
  2818.  
  2819. // RAVEN BEGIN
  2820. // bdube: added for vehicle
  2821. /*
  2822. ==============
  2823. idActor::ExitVehicle
  2824. ==============
  2825. */
  2826. bool idActor::ExitVehicle ( bool force ) {
  2827.     idMat3    axis;            
  2828.     idVec3    origin;
  2829.  
  2830.     if ( !IsInVehicle ( ) ) {
  2831.         return false;
  2832.     }
  2833.  
  2834.     if ( vehicleController.GetVehicle()->IsLocked() ) {
  2835.         if ( force ) {
  2836.             vehicleController.GetVehicle()->Unlock();
  2837.         } else {
  2838.             return false;
  2839.         }
  2840.     }
  2841.  
  2842.     if( !vehicleController.FindClearExitPoint(origin, axis) ) {
  2843.         if ( force ) {
  2844.             origin = GetPhysics()->GetOrigin() + idVec3( spawnArgs.GetVector( "forced_exit_offset", "-100 0 0" ) );
  2845.             axis = GetPhysics()->GetAxis();
  2846.         } else {
  2847.             return false;
  2848.         }
  2849.     }
  2850.  
  2851.     vehicleController.Eject ( force );
  2852.  
  2853.     GetPhysics()->SetOrigin( origin );
  2854.     viewAxis = axis[0].ToMat3();
  2855.     GetPhysics()->SetAxis( mat3_identity );
  2856.     GetPhysics()->SetLinearVelocity( vec3_origin );
  2857.     
  2858.     return true;
  2859. }
  2860.  
  2861. /*
  2862. =====================
  2863. idActor::EnterVehicle
  2864. =====================
  2865. */
  2866. bool idActor::EnterVehicle ( idEntity* ent ) {
  2867. // RAVEN BEGIN
  2868. // jnewquist: Use accessor for static class type 
  2869.     if ( IsInVehicle ( ) || !ent->IsType ( rvVehicle::GetClassType() ) ) {
  2870. // RAVEN END
  2871.         return false ;
  2872.     }    
  2873.  
  2874.     // Get in the vehicle    
  2875.     if ( !vehicleController.Drive ( static_cast<rvVehicle*>(ent), this ) ) {
  2876.         return false;
  2877.     }
  2878.     
  2879.     return true;
  2880. }
  2881.  
  2882. // RAVEN END
  2883.  
  2884.  
  2885. /***********************************************************************
  2886.  
  2887.     Events
  2888.  
  2889. ***********************************************************************/
  2890.  
  2891. /*
  2892. =====================
  2893. idActor::FootStep
  2894. =====================
  2895. */
  2896. void idActor::FootStep ( void ) {
  2897.     const char*                sound;
  2898.     const rvDeclMatType*    materialType;
  2899.  
  2900.     if ( !GetPhysics()->HasGroundContacts() ) {
  2901.         return;
  2902.     }
  2903.  
  2904.     // start footstep sound based on material type
  2905.     materialType = GetPhysics()->GetContact( 0 ).materialType;
  2906.     sound         = NULL;
  2907.     
  2908.     // Sound based on material type?
  2909.     if ( materialType ) {
  2910.         sound = spawnArgs.GetString( va( "snd_footstep_%s", materialType->GetName() ) );
  2911.     }
  2912.     if ( !sound || !*sound ) {
  2913.         sound = spawnArgs.GetString( "snd_footstep" );
  2914.     }
  2915.     
  2916.     // If we have a sound then play it
  2917.     if ( sound && *sound ) {
  2918.         StartSoundShader( declManager->FindSound( sound ), SND_CHANNEL_BODY, 0, false, NULL );
  2919.     }
  2920. }
  2921.  
  2922. /*
  2923. =====================
  2924. idActor::Event_EnableEyeFocus
  2925. =====================
  2926. */
  2927. void idActor::Event_EnableEyeFocus( void ) {
  2928.     allowEyeFocus = true;
  2929.     blink_time = gameLocal.time + blink_min + gameLocal.random.RandomFloat() * ( blink_max - blink_min );
  2930. }
  2931.  
  2932. /*
  2933. =====================
  2934. idActor::Event_DisableEyeFocus
  2935. =====================
  2936. */
  2937. void idActor::Event_DisableEyeFocus( void ) {
  2938.     allowEyeFocus = false;
  2939.     
  2940.     idEntity *headEnt = head.GetEntity();
  2941.     if ( headEnt ) {
  2942.         headEnt->GetAnimator()->Clear( ANIMCHANNEL_EYELIDS, gameLocal.time, FRAME2MS( 2 ) );
  2943.     } else {
  2944.         animator.Clear( ANIMCHANNEL_EYELIDS, gameLocal.time, FRAME2MS( 2 ) );
  2945.     }
  2946. }
  2947.  
  2948. /*
  2949. =====================
  2950. idActor::Event_EnableBlink
  2951. =====================
  2952. */
  2953. void idActor::Event_EnableBlink( void ) {
  2954.     blink_time = gameLocal.time + blink_min + gameLocal.random.RandomFloat() * ( blink_max - blink_min );
  2955. }
  2956.  
  2957. /*
  2958. =====================
  2959. idActor::Event_DisableBlink
  2960. =====================
  2961. */
  2962. void idActor::Event_DisableBlink( void ) {
  2963.     blink_time = 0x7FFFFFFF;
  2964. }
  2965.  
  2966. /*
  2967. ===============
  2968. idActor::Event_Footstep
  2969. ===============
  2970. */
  2971. void idActor::Event_Footstep( void ) {
  2972.     FootStep ( );
  2973. }
  2974.  
  2975. /*
  2976. =====================
  2977. idActor::Event_EnableWalkIK
  2978. =====================
  2979. */
  2980. void idActor::Event_EnableWalkIK( void ) {
  2981.     walkIK.EnableAll();
  2982. }
  2983.  
  2984. /*
  2985. =====================
  2986. idActor::Event_DisableWalkIK
  2987. =====================
  2988. */
  2989. void idActor::Event_DisableWalkIK( void ) {
  2990.     walkIK.DisableAll();
  2991. }
  2992.  
  2993. /*
  2994. =====================
  2995. idActor::Event_EnableLegIK
  2996. =====================
  2997. */
  2998. void idActor::Event_EnableLegIK( int num ) {
  2999.     walkIK.EnableLeg( num );
  3000. }
  3001.  
  3002. /*
  3003. =====================
  3004. idActor::Event_DisableLegIK
  3005. =====================
  3006. */
  3007. void idActor::Event_DisableLegIK( int num ) {
  3008.     walkIK.DisableLeg( num );
  3009. }
  3010.  
  3011. /*
  3012. =====================
  3013. idActor::Event_PreventPain
  3014. =====================
  3015. */
  3016. void idActor::Event_PreventPain( float duration ) {
  3017.     painTime = gameLocal.time + SEC2MS( duration );
  3018. }
  3019.  
  3020. /*
  3021. ===============
  3022. idActor::Event_DisablePain
  3023. ===============
  3024. */
  3025. void idActor::Event_DisablePain( void ) {
  3026. // RAVEN BEGIN
  3027. // bdube: reversed var
  3028.     disablePain = true;
  3029. // RAVEN END
  3030. }
  3031.  
  3032. /*
  3033. ===============
  3034. idActor::Event_EnablePain
  3035. ===============
  3036. */
  3037. void idActor::Event_EnablePain( void ) {
  3038. // RAVEN BEGIN
  3039. // bdube: reversed var
  3040.     disablePain = false;
  3041. // RAVEN END
  3042. }
  3043.  
  3044. /*
  3045. =====================
  3046. idActor::Event_SetAnimPrefix
  3047. =====================
  3048. */
  3049. void idActor::Event_SetAnimPrefix( const char *prefix ) {
  3050.     animPrefix = prefix;
  3051. }
  3052.  
  3053. /*
  3054. ===============
  3055. idActor::Event_StopAnim
  3056. ===============
  3057. */
  3058. void idActor::Event_StopAnim( int channel, int frames ) {
  3059.     switch( channel ) {
  3060.     case ANIMCHANNEL_HEAD :
  3061.         headAnim.StopAnim( frames );
  3062.         break;
  3063.  
  3064.     case ANIMCHANNEL_TORSO :
  3065.         torsoAnim.StopAnim( frames );
  3066.         break;
  3067.  
  3068.     case ANIMCHANNEL_LEGS :
  3069.         legsAnim.StopAnim( frames );
  3070.         break;
  3071.  
  3072.     default:
  3073.         gameLocal.Error( "Unknown anim group" );
  3074.         break;
  3075.     }
  3076. }
  3077.  
  3078. /*
  3079. ===============
  3080. idActor::Event_PlayAnim
  3081. ===============
  3082. */
  3083. void idActor::Event_PlayAnim( int channel, const char *animname ) {
  3084.     idThread::ReturnFloat( MS2SEC(PlayAnim(channel, animname, -1)) );
  3085. }
  3086.  
  3087. /*
  3088. ===============
  3089. idActor::Event_PlayCycle
  3090. ===============
  3091. */
  3092. void idActor::Event_PlayCycle( int channel, const char *animname ) {
  3093.     PlayCycle ( channel, animname, -1 );
  3094.     idThread::ReturnInt( true );
  3095. }
  3096.  
  3097. /*
  3098. =====================
  3099. idAI::DebugFilter
  3100. =====================
  3101. */
  3102. bool idActor::DebugFilter ( const idCVar& test )  const {
  3103.     return ( health>0 && (test.GetBool() || test.GetInteger()>0) && (!ai_debugFilterString.GetString()[0] || !stricmp( name.c_str(), ai_debugFilterString.GetString() )));
  3104. }
  3105.  
  3106. /*
  3107. ===============
  3108. idActor::Event_IdleAnim
  3109. ===============
  3110. */
  3111. void idActor::Event_IdleAnim( int channel, const char *animname ) {
  3112.     int anim;
  3113.     
  3114.     anim = GetAnim( channel, animname );    
  3115.     if ( !anim ) {
  3116.         if ( ( channel == ANIMCHANNEL_HEAD ) && head.GetEntity() ) {
  3117.             gameLocal.Warning( "missing '%s' animation on '%s' (%s)", animname, name.c_str(), spawnArgs.GetString( "def_head", "" ) );
  3118.         } else {
  3119.             gameLocal.Warning( "missing '%s' animation on '%s' (%s)", animname, name.c_str(), GetEntityDefName() );
  3120.         }
  3121.  
  3122.         switch( channel ) {
  3123.         case ANIMCHANNEL_HEAD :
  3124.             headAnim.BecomeIdle();
  3125.             break;
  3126.  
  3127.         case ANIMCHANNEL_TORSO :
  3128.             torsoAnim.BecomeIdle();
  3129.             break;
  3130.  
  3131.         case ANIMCHANNEL_LEGS :
  3132.             legsAnim.BecomeIdle();
  3133.             break;
  3134.  
  3135.         default:
  3136.             gameLocal.Error( "Unknown anim group" );
  3137.         }
  3138.  
  3139.         idThread::ReturnInt( false );
  3140.         return;
  3141.     }
  3142.  
  3143.     switch( channel ) {
  3144.     case ANIMCHANNEL_HEAD :
  3145.         headAnim.BecomeIdle();
  3146.         if ( torsoAnim.GetAnimFlags().prevent_idle_override ) {
  3147.             // don't sync to torso body if it doesn't override idle anims
  3148.             headAnim.CycleAnim( anim );
  3149.         } else if ( torsoAnim.IsIdle() && legsAnim.IsIdle() ) {
  3150.             // everything is idle, so play the anim on the head and copy it to the torso and legs
  3151.             headAnim.CycleAnim( anim );
  3152.             torsoAnim.animBlendFrames = headAnim.lastAnimBlendFrames;
  3153.             SyncAnimChannels( ANIMCHANNEL_TORSO, ANIMCHANNEL_HEAD, headAnim.lastAnimBlendFrames );
  3154.             legsAnim.animBlendFrames = headAnim.lastAnimBlendFrames;
  3155.             SyncAnimChannels( ANIMCHANNEL_LEGS, ANIMCHANNEL_HEAD, headAnim.lastAnimBlendFrames );
  3156.         } else if ( torsoAnim.IsIdle() ) {
  3157.             // sync the head and torso to the legs
  3158.             SyncAnimChannels( ANIMCHANNEL_HEAD, ANIMCHANNEL_LEGS, headAnim.animBlendFrames );
  3159.             torsoAnim.animBlendFrames = headAnim.lastAnimBlendFrames;
  3160.             SyncAnimChannels( ANIMCHANNEL_TORSO, ANIMCHANNEL_LEGS, torsoAnim.animBlendFrames );
  3161.         } else {
  3162.             // sync the head to the torso
  3163.             SyncAnimChannels( ANIMCHANNEL_HEAD, ANIMCHANNEL_TORSO, headAnim.animBlendFrames );
  3164.         }
  3165.         break;
  3166.  
  3167.     case ANIMCHANNEL_TORSO :
  3168.         torsoAnim.BecomeIdle();
  3169.         if ( legsAnim.GetAnimFlags().prevent_idle_override ) {
  3170.             // don't sync to legs if legs anim doesn't override idle anims
  3171.             torsoAnim.CycleAnim( anim );
  3172.         } else if ( legsAnim.IsIdle() ) {
  3173.             // play the anim in both legs and torso
  3174.             torsoAnim.CycleAnim( anim );
  3175.             legsAnim.animBlendFrames = torsoAnim.lastAnimBlendFrames;
  3176.             SyncAnimChannels( ANIMCHANNEL_LEGS, ANIMCHANNEL_TORSO, torsoAnim.lastAnimBlendFrames );
  3177.         } else {
  3178.             // sync the anim to the legs
  3179.             SyncAnimChannels( ANIMCHANNEL_TORSO, ANIMCHANNEL_LEGS, torsoAnim.animBlendFrames );
  3180.         }
  3181.  
  3182.         if ( headAnim.IsIdle() ) {
  3183.             SyncAnimChannels( ANIMCHANNEL_HEAD, ANIMCHANNEL_TORSO, torsoAnim.lastAnimBlendFrames );
  3184.         }
  3185.         break;
  3186.  
  3187.     case ANIMCHANNEL_LEGS :
  3188.         legsAnim.BecomeIdle();
  3189.         if ( torsoAnim.GetAnimFlags().prevent_idle_override ) {
  3190.             // don't sync to torso if torso anim doesn't override idle anims
  3191.             legsAnim.CycleAnim( anim );
  3192.         } else if ( torsoAnim.IsIdle() ) {
  3193.             // play the anim in both legs and torso
  3194.             legsAnim.CycleAnim( anim );
  3195.             torsoAnim.animBlendFrames = legsAnim.lastAnimBlendFrames;
  3196.             SyncAnimChannels( ANIMCHANNEL_TORSO, ANIMCHANNEL_LEGS, legsAnim.lastAnimBlendFrames );
  3197.             if ( headAnim.IsIdle() ) {
  3198.                 SyncAnimChannels( ANIMCHANNEL_HEAD, ANIMCHANNEL_LEGS, legsAnim.lastAnimBlendFrames );
  3199.             }
  3200.         } else {
  3201.             // sync the anim to the torso
  3202.             SyncAnimChannels( ANIMCHANNEL_LEGS, ANIMCHANNEL_TORSO, legsAnim.animBlendFrames );
  3203.         }
  3204.         break;
  3205.  
  3206.     default:
  3207.         gameLocal.Error( "Unknown anim group" );
  3208.     }
  3209.  
  3210.     idThread::ReturnInt( true );
  3211. }
  3212.  
  3213. /*
  3214. ================
  3215. idActor::Event_SetSyncedAnimWeight
  3216. ================
  3217. */
  3218. void idActor::Event_SetSyncedAnimWeight( int channel, int anim, float weight ) {
  3219.     idEntity *headEnt;
  3220.  
  3221.     headEnt = head.GetEntity();
  3222.     switch( channel ) {
  3223.     case ANIMCHANNEL_HEAD :
  3224.         if ( headEnt ) {
  3225.             animator.CurrentAnim( ANIMCHANNEL_LEGS )->SetSyncedAnimWeight( anim, weight );
  3226.         } else {
  3227.             animator.CurrentAnim( ANIMCHANNEL_HEAD )->SetSyncedAnimWeight( anim, weight );
  3228.         }
  3229.         if ( torsoAnim.IsIdle() ) {
  3230.             animator.CurrentAnim( ANIMCHANNEL_TORSO )->SetSyncedAnimWeight( anim, weight );
  3231.             if ( legsAnim.IsIdle() ) {
  3232.                 animator.CurrentAnim( ANIMCHANNEL_LEGS )->SetSyncedAnimWeight( anim, weight );
  3233.             }
  3234.         }
  3235.         break;
  3236.  
  3237.     case ANIMCHANNEL_TORSO :
  3238.         animator.CurrentAnim( ANIMCHANNEL_TORSO )->SetSyncedAnimWeight( anim, weight );
  3239.         if ( legsAnim.IsIdle() ) {
  3240.             animator.CurrentAnim( ANIMCHANNEL_LEGS )->SetSyncedAnimWeight( anim, weight );
  3241.         }
  3242.         if ( headEnt && headAnim.IsIdle() ) {
  3243.             headEnt->GetAnimator()->CurrentAnim( ANIMCHANNEL_LEGS )->SetSyncedAnimWeight( anim, weight );
  3244.         }
  3245.         break;
  3246.  
  3247.     case ANIMCHANNEL_LEGS :
  3248.         animator.CurrentAnim( ANIMCHANNEL_LEGS )->SetSyncedAnimWeight( anim, weight );
  3249.         if ( torsoAnim.IsIdle() ) {
  3250.             animator.CurrentAnim( ANIMCHANNEL_TORSO )->SetSyncedAnimWeight( anim, weight );
  3251.             if ( headEnt && headAnim.IsIdle() ) {
  3252.                 headEnt->GetAnimator()->CurrentAnim( ANIMCHANNEL_LEGS )->SetSyncedAnimWeight( anim, weight );
  3253.             }
  3254.         }
  3255.         break;
  3256.  
  3257.     default:
  3258.         gameLocal.Error( "Unknown anim group" );
  3259.     }
  3260. }
  3261.  
  3262. /*
  3263. ===============
  3264. idActor::Event_OverrideAnim
  3265. ===============
  3266. */
  3267. void idActor::Event_OverrideAnim( int channel ) {
  3268.     switch( channel ) {
  3269.     case ANIMCHANNEL_HEAD :
  3270.         headAnim.Disable();
  3271.         if ( !torsoAnim.IsIdle() ) {
  3272.             SyncAnimChannels( ANIMCHANNEL_HEAD, ANIMCHANNEL_TORSO, torsoAnim.lastAnimBlendFrames );
  3273.         } else {
  3274.             SyncAnimChannels( ANIMCHANNEL_HEAD, ANIMCHANNEL_LEGS, legsAnim.lastAnimBlendFrames );
  3275.         }
  3276.         break;
  3277.  
  3278.     case ANIMCHANNEL_TORSO :
  3279.         torsoAnim.Disable();
  3280.         SyncAnimChannels( ANIMCHANNEL_TORSO, ANIMCHANNEL_LEGS, legsAnim.lastAnimBlendFrames );
  3281.         if ( headAnim.IsIdle() ) {
  3282.             SyncAnimChannels( ANIMCHANNEL_HEAD, ANIMCHANNEL_TORSO, torsoAnim.lastAnimBlendFrames );
  3283.         }
  3284.         break;
  3285.  
  3286.     case ANIMCHANNEL_LEGS :
  3287.         legsAnim.Disable();
  3288.         SyncAnimChannels( ANIMCHANNEL_LEGS, ANIMCHANNEL_TORSO, torsoAnim.lastAnimBlendFrames );
  3289.         break;
  3290.  
  3291.     default:
  3292.         gameLocal.Error( "Unknown anim group" );
  3293.         break;
  3294.     }
  3295. }
  3296.  
  3297. /*
  3298. ===============
  3299. idActor::Event_EnableAnim
  3300. ===============
  3301. */
  3302. void idActor::Event_EnableAnim( int channel, int blendFrames ) {
  3303.     switch( channel ) {
  3304.     case ANIMCHANNEL_HEAD :
  3305.         headAnim.Enable( blendFrames );
  3306.         break;
  3307.  
  3308.     case ANIMCHANNEL_TORSO :
  3309.         torsoAnim.Enable( blendFrames );
  3310.         break;
  3311.  
  3312.     case ANIMCHANNEL_LEGS :
  3313.         legsAnim.Enable( blendFrames );
  3314.         break;
  3315.  
  3316.     default:
  3317.         gameLocal.Error( "Unknown anim group" );
  3318.         break;
  3319.     }
  3320. }
  3321.  
  3322. /*
  3323. ===============
  3324. idActor::Event_SetBlendFrames
  3325. ===============
  3326. */
  3327. void idActor::Event_SetBlendFrames( int channel, int blendFrames ) {
  3328.     switch( channel ) {
  3329.     case ANIMCHANNEL_HEAD :
  3330.         headAnim.animBlendFrames = blendFrames;
  3331.         headAnim.lastAnimBlendFrames = blendFrames;
  3332.         break;
  3333.  
  3334.     case ANIMCHANNEL_TORSO :
  3335.         torsoAnim.animBlendFrames = blendFrames;
  3336.         torsoAnim.lastAnimBlendFrames = blendFrames;
  3337.         break;
  3338.  
  3339.     case ANIMCHANNEL_LEGS :
  3340.         legsAnim.animBlendFrames = blendFrames;
  3341.         legsAnim.lastAnimBlendFrames = blendFrames;
  3342.         break;
  3343.  
  3344.     default:
  3345.         gameLocal.Error( "Unknown anim group" );
  3346.         break;
  3347.     }
  3348. }
  3349.  
  3350. /*
  3351. ===============
  3352. idActor::Event_GetBlendFrames
  3353. ===============
  3354. */
  3355. void idActor::Event_GetBlendFrames( int channel ) {
  3356.     switch( channel ) {
  3357.     case ANIMCHANNEL_HEAD :
  3358.         idThread::ReturnInt( headAnim.animBlendFrames );
  3359.         break;
  3360.  
  3361.     case ANIMCHANNEL_TORSO :
  3362.         idThread::ReturnInt( torsoAnim.animBlendFrames );
  3363.         break;
  3364.  
  3365.     case ANIMCHANNEL_LEGS :
  3366.         idThread::ReturnInt( legsAnim.animBlendFrames );
  3367.         break;
  3368.  
  3369.     default:
  3370.         gameLocal.Error( "Unknown anim group" );
  3371.         break;
  3372.     }
  3373. }
  3374.  
  3375. /*
  3376. ================
  3377. idActor::Event_HasEnemies
  3378. ================
  3379. */
  3380. void idActor::Event_HasEnemies( void ) {
  3381.     bool hasEnemy;
  3382.  
  3383.     hasEnemy = HasEnemies();
  3384.     idThread::ReturnInt( hasEnemy );
  3385. }
  3386.  
  3387. /*
  3388. ================
  3389. idActor::Event_NextEnemy
  3390. ================
  3391. */
  3392. void idActor::Event_NextEnemy( idEntity *ent ) {
  3393.     idActor *actor;
  3394.  
  3395.     if ( !ent || ( ent == this ) ) {
  3396.         actor = enemyList.Next();
  3397.     } else {
  3398.         if ( !ent->IsType( idActor::Type ) ) {
  3399.             gameLocal.Error( "'%s' cannot be an enemy", ent->name.c_str() );
  3400.         }
  3401.  
  3402.         actor = static_cast<idActor *>( ent );
  3403.         if ( actor->enemyNode.ListHead() != &enemyList ) {
  3404.             gameLocal.Error( "'%s' is not in '%s' enemy list", actor->name.c_str(), name.c_str() );
  3405.         }
  3406.     }
  3407.  
  3408.     for( ; actor != NULL; actor = actor->enemyNode.Next() ) {
  3409.         if ( !actor->fl.hidden ) {
  3410.             idThread::ReturnEntity( actor );
  3411.             return;
  3412.         }
  3413.     }
  3414.  
  3415.     idThread::ReturnEntity( NULL );
  3416. }
  3417.  
  3418. /*
  3419. ================
  3420. idActor::Event_ClosestEnemyToPoint
  3421. ================
  3422. */
  3423. void idActor::Event_ClosestEnemyToPoint( const idVec3 &pos ) {
  3424.     idActor *bestEnt = ClosestEnemyToPoint( pos );
  3425.     idThread::ReturnEntity( bestEnt );
  3426. }
  3427.  
  3428. /*
  3429. ================
  3430. idActor::Event_StopSound
  3431. ================
  3432. */
  3433. void idActor::Event_StopSound( int channel, int netSync ) {
  3434.     if ( channel == SND_CHANNEL_VOICE ) {
  3435.         idEntity *headEnt = head.GetEntity();
  3436.         if ( headEnt ) {
  3437.             headEnt->StopSound( channel, ( netSync != 0 ) );
  3438.         }
  3439.     }
  3440.     StopSound( channel, ( netSync != 0 ) );
  3441. }
  3442.  
  3443. /*
  3444. =====================
  3445. idActor::Event_GetHead
  3446. =====================
  3447. */
  3448. void idActor::Event_GetHead( void ) {
  3449.     idThread::ReturnEntity( head.GetEntity() );
  3450. }
  3451.  
  3452. // RAVEN BEGIN
  3453. // jshepard: added
  3454. /*
  3455. =====================
  3456. idActor::Event_SetAnimRate
  3457. =====================
  3458. */
  3459. void idActor::Event_SetAnimRate( float multiplier ) {
  3460.     animator.SetPlaybackRate(multiplier);
  3461. }
  3462.  
  3463.  
  3464. /*
  3465. ===============================================================================
  3466.  
  3467.     Wait States 
  3468.  
  3469. ===============================================================================
  3470. */
  3471.  
  3472. /*
  3473. ================
  3474. idActor::State_Wait_Frame
  3475.  
  3476. Stop a state thread for a single frame
  3477. ================
  3478. */
  3479. stateResult_t idActor::State_Wait_Frame ( const stateParms_t& parms ) {
  3480.     return SRESULT_DONE_WAIT;
  3481. }
  3482.  
  3483. /*
  3484. ================
  3485. idActor::State_Wait_LegsAnim
  3486.  
  3487. Stop a state thread until the animation running on the legs channel is finished
  3488. ================
  3489. */
  3490. stateResult_t idActor::State_Wait_LegsAnim ( const stateParms_t& parms ) {
  3491.     if ( !AnimDone ( ANIMCHANNEL_LEGS, parms.blendFrames ) ) {
  3492.         return SRESULT_WAIT;
  3493.     }
  3494.     return SRESULT_DONE;
  3495. }
  3496.  
  3497. /*
  3498. ================
  3499. idActor::State_Wait_TorsoAnim
  3500.  
  3501. Stop a state thread until the animation running on the torso channel is finished
  3502. ================
  3503. */
  3504. stateResult_t idActor::State_Wait_TorsoAnim ( const stateParms_t& parms ) {
  3505.     if ( !AnimDone ( ANIMCHANNEL_TORSO, parms.blendFrames ) ) {
  3506.         return SRESULT_WAIT;
  3507.     }
  3508.     return SRESULT_DONE;
  3509. }
  3510.  
  3511. /*
  3512. ================
  3513. idActor::PlayAnim
  3514. ================
  3515. */
  3516. int idActor::PlayAnim ( int channel, const char *animname, int blendFrames ) {
  3517.     animFlags_t    flags;
  3518.     idEntity *headEnt;
  3519.     int    anim;
  3520.  
  3521.     if ( blendFrames != -1 ) {
  3522.         Event_SetBlendFrames ( channel, blendFrames );
  3523.     }
  3524.     
  3525.     anim = GetAnim( channel, animname );
  3526.  
  3527.     if( ai_animShow.GetBool() ){
  3528.         gameLocal.DPrintf( "Playing animation '%s' on '%s' (%s)\n", animname, name.c_str(), spawnArgs.GetString( "head", "" ) );
  3529.     }
  3530.  
  3531.     if ( !anim ) {
  3532.         if ( ( channel == ANIMCHANNEL_HEAD ) && head.GetEntity() ) {
  3533.             gameLocal.Warning( "missing '%s' animation on '%s' (%s)", animname, name.c_str(), spawnArgs.GetString( "def_head", "" ) );
  3534.         } else {
  3535.             gameLocal.Warning( "missing '%s' animation on '%s' (%s)", animname, name.c_str(), GetEntityDefName() );
  3536.         }
  3537.         return 0;
  3538.     }
  3539.  
  3540.     switch( channel ) {
  3541.     case ANIMCHANNEL_HEAD :
  3542.         headEnt = head.GetEntity();
  3543.         if ( headEnt ) {
  3544.             headAnim.idleAnim = false;
  3545.             headAnim.PlayAnim( anim );
  3546.             flags = headAnim.GetAnimFlags();
  3547.             if ( !flags.prevent_idle_override ) {
  3548.                 if ( torsoAnim.IsIdle() ) {
  3549.                     torsoAnim.animBlendFrames = headAnim.lastAnimBlendFrames;
  3550.                     SyncAnimChannels( ANIMCHANNEL_TORSO, ANIMCHANNEL_HEAD, headAnim.lastAnimBlendFrames );
  3551.                     if ( legsAnim.IsIdle() ) {
  3552.                         legsAnim.animBlendFrames = headAnim.lastAnimBlendFrames;
  3553.                         SyncAnimChannels( ANIMCHANNEL_LEGS, ANIMCHANNEL_HEAD, headAnim.lastAnimBlendFrames );
  3554.                     }
  3555.                 }
  3556.             }
  3557.         }
  3558.         break;
  3559.  
  3560.     case ANIMCHANNEL_TORSO :
  3561.         torsoAnim.idleAnim = false;
  3562.         torsoAnim.PlayAnim( anim );
  3563.         flags = torsoAnim.GetAnimFlags();
  3564.         if ( !flags.prevent_idle_override ) {
  3565.             if ( headAnim.IsIdle() ) {
  3566.                 headAnim.animBlendFrames = torsoAnim.lastAnimBlendFrames;
  3567.                 SyncAnimChannels( ANIMCHANNEL_HEAD, ANIMCHANNEL_TORSO, torsoAnim.lastAnimBlendFrames );
  3568.             }
  3569.             if ( legsAnim.IsIdle() ) {
  3570.                 legsAnim.animBlendFrames = torsoAnim.lastAnimBlendFrames;
  3571.                 SyncAnimChannels( ANIMCHANNEL_LEGS, ANIMCHANNEL_TORSO, torsoAnim.lastAnimBlendFrames );
  3572.             }
  3573.         }
  3574.         break;
  3575.  
  3576.     case ANIMCHANNEL_LEGS :
  3577.         legsAnim.idleAnim = false;
  3578.         legsAnim.PlayAnim( anim );
  3579.         flags = legsAnim.GetAnimFlags();
  3580.         if ( !flags.prevent_idle_override ) {
  3581.             if ( torsoAnim.IsIdle() ) {
  3582.                 torsoAnim.animBlendFrames = legsAnim.lastAnimBlendFrames;
  3583.                 SyncAnimChannels( ANIMCHANNEL_TORSO, ANIMCHANNEL_LEGS, legsAnim.lastAnimBlendFrames );
  3584.                 if ( headAnim.IsIdle() ) {
  3585.                     headAnim.animBlendFrames = legsAnim.lastAnimBlendFrames;
  3586.                     SyncAnimChannels( ANIMCHANNEL_HEAD, ANIMCHANNEL_LEGS, legsAnim.lastAnimBlendFrames );
  3587.                 }
  3588.             }
  3589.         }
  3590.         break;
  3591.  
  3592.     default :
  3593.         gameLocal.Error( "Unknown anim group" );
  3594.         break;
  3595.     }
  3596.     
  3597.     return animator.CurrentAnim( channel )->Length();
  3598. }
  3599.  
  3600. /*
  3601. ================
  3602. idActor::PlayCycle
  3603. ================
  3604. */
  3605. bool idActor::PlayCycle ( int channel, const char *animname, int blendFrames ) {
  3606.     animFlags_t    flags;
  3607.     int            anim;
  3608.  
  3609.     if ( blendFrames != -1 ) {
  3610.         Event_SetBlendFrames ( channel, blendFrames );
  3611.     }
  3612.     
  3613.     anim = GetAnim( channel, animname );
  3614.     if ( !anim ) {
  3615.         if ( ( channel == ANIMCHANNEL_HEAD ) && head.GetEntity() ) {
  3616.             gameLocal.Warning( "missing '%s' animation on '%s' (%s)", animname, name.c_str(), spawnArgs.GetString( "def_head", "" ) );
  3617.         } else {
  3618.             gameLocal.Warning( "missing '%s' animation on '%s' (%s)", animname, name.c_str(), GetEntityDefName() );
  3619.         }
  3620.         return false;
  3621.     }
  3622.  
  3623.     switch( channel ) {
  3624.     case ANIMCHANNEL_HEAD :
  3625.         headAnim.idleAnim = false;
  3626.         headAnim.CycleAnim( anim );
  3627.         flags = headAnim.GetAnimFlags();
  3628.         if ( !flags.prevent_idle_override ) {
  3629.             if ( torsoAnim.IsIdle() && legsAnim.IsIdle() ) {
  3630.                 torsoAnim.animBlendFrames = headAnim.lastAnimBlendFrames;
  3631.                 SyncAnimChannels( ANIMCHANNEL_TORSO, ANIMCHANNEL_HEAD, headAnim.lastAnimBlendFrames );
  3632.                 legsAnim.animBlendFrames = headAnim.lastAnimBlendFrames;
  3633.                 SyncAnimChannels( ANIMCHANNEL_LEGS, ANIMCHANNEL_HEAD, headAnim.lastAnimBlendFrames );
  3634.             }
  3635.         }
  3636.         break;
  3637.  
  3638.     case ANIMCHANNEL_TORSO :
  3639.         torsoAnim.idleAnim = false;
  3640.         torsoAnim.CycleAnim( anim );
  3641.         flags = torsoAnim.GetAnimFlags();
  3642.         if ( !flags.prevent_idle_override ) {
  3643.             if ( headAnim.IsIdle() ) {
  3644.                 headAnim.animBlendFrames = torsoAnim.lastAnimBlendFrames;
  3645.                 SyncAnimChannels( ANIMCHANNEL_HEAD, ANIMCHANNEL_TORSO, torsoAnim.lastAnimBlendFrames );
  3646.             }
  3647.             if ( legsAnim.IsIdle() ) {
  3648.                 legsAnim.animBlendFrames = torsoAnim.lastAnimBlendFrames;
  3649.                 SyncAnimChannels( ANIMCHANNEL_LEGS, ANIMCHANNEL_TORSO, torsoAnim.lastAnimBlendFrames );
  3650.             }
  3651.         }
  3652.         break;
  3653.  
  3654.     case ANIMCHANNEL_LEGS :
  3655.         legsAnim.idleAnim = false;
  3656.         legsAnim.CycleAnim( anim );
  3657.         flags = legsAnim.GetAnimFlags();
  3658.         if ( !flags.prevent_idle_override ) {
  3659.             if ( torsoAnim.IsIdle() ) {
  3660.                 torsoAnim.animBlendFrames = legsAnim.lastAnimBlendFrames;
  3661.                 SyncAnimChannels( ANIMCHANNEL_TORSO, ANIMCHANNEL_LEGS, legsAnim.lastAnimBlendFrames );
  3662.                 if ( headAnim.IsIdle() ) {
  3663.                     headAnim.animBlendFrames = legsAnim.lastAnimBlendFrames;
  3664.                     SyncAnimChannels( ANIMCHANNEL_HEAD, ANIMCHANNEL_LEGS, legsAnim.lastAnimBlendFrames );
  3665.                 }
  3666.             }
  3667.         }
  3668.         break;
  3669.  
  3670.     default:
  3671.         gameLocal.Error( "Unknown anim group" );
  3672.     }
  3673.     
  3674.     return true;
  3675. }
  3676.  
  3677. void idActor::IdleAnim ( int channel, const char *name, int blendFrames ) {
  3678.     Event_SetBlendFrames ( channel, blendFrames );
  3679.     Event_IdleAnim ( channel, name );
  3680. }
  3681.  
  3682. void idActor::OverrideAnim ( int channel ) {
  3683.     Event_OverrideAnim ( channel );
  3684. }
  3685.  
  3686. idAnimState& idActor::GetAnimState ( int channel ) {
  3687.     switch ( channel ) {
  3688.         case ANIMCHANNEL_LEGS:        return legsAnim;
  3689.         case ANIMCHANNEL_TORSO:        return torsoAnim;
  3690.         case ANIMCHANNEL_HEAD:        return headAnim;
  3691.         default:
  3692.             gameLocal.Error( "idActor::GetAnimState: Unknown anim channel" );
  3693.             return torsoAnim;
  3694.     }
  3695. }
  3696.  
  3697. void idActor::DisableAnimState ( int channel ) {
  3698.     Event_OverrideAnim ( channel );
  3699. //    GetAnimState ( channel ).Disable ( );
  3700. }
  3701.  
  3702. void idActor::EnableAnimState ( int channel ) {
  3703.     GetAnimState ( channel ).Enable ( 4 );
  3704. }
  3705.  
  3706. bool idActor::HasAnim ( int channel, const char* animname, bool forcePrefix ) {
  3707.     return GetAnim( channel, animname, forcePrefix ) != NULL;
  3708. }
  3709.  
  3710. bool idActor::AnimDone ( int channel, int blendFrames ) {
  3711.     return GetAnimState( channel ).AnimDone ( blendFrames );
  3712. }
  3713.  
  3714. /*
  3715. =====================
  3716. idActor::GetDebugInfo
  3717. =====================
  3718. */
  3719. void idActor::GetDebugInfo ( debugInfoProc_t proc, void* userData ) {
  3720.     // Base class first
  3721.     idAFEntity_Gibbable::GetDebugInfo ( proc, userData );
  3722.  
  3723.     proc ( "idActor", "state",            stateThread.GetState()?stateThread.GetState()->state->name : "<none>", userData );
  3724.  
  3725.     proc ( "idActor", "legs_state",        legsAnim.GetStateThread().GetState()?legsAnim.GetStateThread().GetState()->state->name:"<none>", userData );
  3726.     proc ( "idActor", "legs_disable",    legsAnim.Disabled()?"true":"false", userData );
  3727.     proc ( "idActor", "legs_anim",        GetAnimator()->CurrentAnim ( ANIMCHANNEL_LEGS ) ? GetAnimator()->CurrentAnim ( ANIMCHANNEL_LEGS )->AnimName ( ) : "<none>", userData );
  3728.  
  3729.     proc ( "idActor", "torso_state",    torsoAnim.GetStateThread().GetState()?torsoAnim.GetStateThread().GetState()->state->name:"<none>", userData );
  3730.     proc ( "idActor", "torso_disabled",    torsoAnim.Disabled()?"true":"false", userData );
  3731.     proc ( "idActor", "torso_anim",        GetAnimator()->CurrentAnim ( ANIMCHANNEL_TORSO ) ? GetAnimator()->CurrentAnim ( ANIMCHANNEL_TORSO )->AnimName ( ) : "<none>", userData );
  3732.  
  3733.     proc ( "idActor", "head_state",        headAnim.GetStateThread().GetState()?headAnim.GetStateThread().GetState()->state->name:"<none>", userData );
  3734.     proc ( "idActor", "head_disabled",    headAnim.Disabled()?"true":"false", userData );
  3735.     proc ( "idActor", "head_anim",        GetAnimator()->CurrentAnim ( ANIMCHANNEL_HEAD ) ? GetAnimator()->CurrentAnim ( ANIMCHANNEL_HEAD )->AnimName ( ) : "<none>", userData );    
  3736.  
  3737.     proc ( "idActor", "painAnim",        painAnim.c_str(), userData );
  3738.     proc ( "idActor", "animPrefix",        animPrefix.c_str(), userData );
  3739. }
  3740.  
  3741. //MCG: damage over time
  3742. void idActor::Event_DamageOverTime ( int endTime, int interval, idEntity *inflictor, idEntity *attacker, idVec3 &dir,
  3743.                        const char *damageDefName, const float damageScale, int location ) {
  3744.     const idDeclEntityDef* damageDef = gameLocal.FindEntityDef( damageDefName, false );
  3745.     if ( damageDef ) {
  3746.         inDamageEvent = true;
  3747.         Damage( inflictor, attacker, dir, damageDefName, damageScale, location );
  3748.         inDamageEvent = false;
  3749.         if ( endTime == -1 || gameLocal.GetTime() + interval <= endTime ) {
  3750.             //post it again
  3751.             PostEventMS( &EV_DamageOverTime, interval, endTime, interval, inflictor, attacker, dir, damageDefName, damageScale, location );
  3752.         }
  3753.     }
  3754. }
  3755.  
  3756. void idActor::Event_DamageOverTimeEffect ( int endTime, int interval, const char *damageDefName ) {
  3757.     const idDeclEntityDef* damageDef = gameLocal.FindEntityDef( damageDefName, false );
  3758.     if ( damageDef ) {
  3759.         rvClientCrawlEffect* effect;
  3760.         effect = new rvClientCrawlEffect ( gameLocal.GetEffect ( damageDef->dict, "fx_dot" ), this, interval );
  3761.         effect->Play ( gameLocal.time, false );
  3762.         if ( endTime == -1 || gameLocal.GetTime() + interval <= endTime ) {
  3763.             //post it again
  3764.             PostEventMS( &EV_DamageOverTimeEffect, interval, endTime, interval, damageDefName );
  3765.         }
  3766.     }
  3767. }
  3768.  
  3769. // MCG: script-callable joint crawl effect
  3770. void idActor::Event_JointCrawlEffect ( const char *effectKeyName, float crawlSecs ) {
  3771.     if ( effectKeyName ) {
  3772.         rvClientCrawlEffect* effect;
  3773.         effect = new rvClientCrawlEffect( gameLocal.GetEffect ( spawnArgs, effectKeyName ), this, 100 );
  3774.         effect->Play ( gameLocal.GetTime(), false );
  3775.         crawlSecs -= 0.1f;
  3776.         if ( crawlSecs >= 0.1f ) {
  3777.             PostEventMS( &EV_JointCrawlEffect, 100, effectKeyName, crawlSecs );
  3778.         }
  3779.     }
  3780. }
  3781.  
  3782. idEntity* idActor::GetGroundElevator( idEntity* testElevator ) const {
  3783.     idEntity* groundEnt = GetGroundEntity();
  3784.     if ( !groundEnt ) {
  3785.         return NULL;
  3786.     }
  3787.     while ( groundEnt->GetBindMaster() ) {
  3788.         groundEnt = groundEnt->GetBindMaster();
  3789.     }
  3790.  
  3791.     if ( !groundEnt->IsType( idElevator::GetClassType() ) ) {
  3792.         return NULL;
  3793.     }
  3794.  
  3795.     if ( testElevator && groundEnt != testElevator ) {
  3796.         return groundEnt;
  3797.     }
  3798.  
  3799.     idEntity* traceEnt;
  3800.     idVec3 testPoint = GetPhysics()->GetOrigin();
  3801.     idVec3 testBottom;
  3802.     testPoint.z += 1.0f;
  3803.  
  3804.     for ( int x = 0; x < 2; x++ ) {
  3805.         testPoint.x = GetPhysics()->GetAbsBounds()[x].x;
  3806.         for ( int y = 0; y < 2; y++ ) {
  3807.             testPoint.y = GetPhysics()->GetAbsBounds()[y].y;
  3808.             testBottom = testPoint;
  3809.             testBottom.z -= 65.0f;
  3810.  
  3811.             trace_t tr;
  3812.             gameLocal.TracePoint( this, tr, testPoint, testBottom, GetPhysics()->GetClipMask(), this );
  3813.             traceEnt = gameLocal.FindEntity( tr.c.entityNum );
  3814.             if ( !traceEnt ) {
  3815.                 return NULL;
  3816.             }
  3817.             while ( traceEnt->GetBindMaster() ) {
  3818.                 traceEnt = traceEnt->GetBindMaster();
  3819.             }
  3820.             if ( traceEnt != groundEnt ) {
  3821.                 return traceEnt;
  3822.             }
  3823.             if ( testElevator && traceEnt != testElevator ) {
  3824.                 return traceEnt;
  3825.             }
  3826.         }
  3827.     }
  3828.  
  3829.     return groundEnt;
  3830. }
  3831.  
  3832. void idActor::GuidedProjectileIncoming( idGuidedProjectile *projectile )
  3833. {
  3834.     if ( IsInVehicle() )
  3835.     {
  3836.         if ( vehicleController.GetVehicle() )
  3837.         {
  3838.             vehicleController.GetVehicle()->GuidedProjectileIncoming( projectile );
  3839.         }
  3840.     }
  3841. }
  3842. // RAVEN END
  3843.