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

  1.  
  2. #include "../idlib/precompiled.h"
  3. #pragma hdrstop
  4.  
  5. #include "Game_local.h"
  6. #include "Projectile.h"
  7.  
  8. /*
  9. ===============================================================================
  10.  
  11.   idMultiModelAF
  12.  
  13. ===============================================================================
  14. */
  15.  
  16. CLASS_DECLARATION( idEntity, idMultiModelAF )
  17. END_CLASS
  18.  
  19. /*
  20. ================
  21. idMultiModelAF::Spawn
  22. ================
  23. */
  24. void idMultiModelAF::Spawn( void ) {
  25.     physicsObj.SetSelf( this );
  26. }
  27.  
  28. /*
  29. ================
  30. idMultiModelAF::~idMultiModelAF
  31. ================
  32. */
  33. idMultiModelAF::~idMultiModelAF( void ) {
  34.     int i;
  35.  
  36.     for ( i = 0; i < modelDefHandles.Num(); i++ ) {
  37.         if ( modelDefHandles[i] != -1 ) {
  38.             gameRenderWorld->FreeEntityDef( modelDefHandles[i] );
  39.             modelDefHandles[i] = -1;
  40.         }
  41.     }
  42.     
  43.     SetPhysics( NULL );    
  44. }
  45.  
  46. /*
  47. ================
  48. idMultiModelAF::SetModelForId
  49. ================
  50. */
  51. void idMultiModelAF::SetModelForId( int id, const idStr &modelName ) {
  52.     modelHandles.AssureSize( id+1, NULL );
  53.     modelDefHandles.AssureSize( id+1, -1 );
  54.     modelHandles[id] = renderModelManager->FindModel( modelName );
  55. }
  56.  
  57. /*
  58. ================
  59. idMultiModelAF::Present
  60. ================
  61. */
  62. void idMultiModelAF::Present( void ) {
  63.     int i;
  64.  
  65.     // don't present to the renderer if the entity hasn't changed
  66.     if ( !( thinkFlags & TH_UPDATEVISUALS ) ) {
  67.         return;
  68.     }
  69.     BecomeInactive( TH_UPDATEVISUALS );
  70.  
  71.     for ( i = 0; i < modelHandles.Num(); i++ ) {
  72.  
  73.         if ( !modelHandles[i] ) {
  74.             continue;
  75.         }
  76.  
  77.         renderEntity.origin = physicsObj.GetOrigin( i );
  78.         renderEntity.axis = physicsObj.GetAxis( i );
  79.         renderEntity.hModel = modelHandles[i];
  80.         renderEntity.bodyId = i;
  81.  
  82.         // add to refresh list
  83.         if ( modelDefHandles[i] == -1 ) {
  84.             modelDefHandles[i] = gameRenderWorld->AddEntityDef( &renderEntity );
  85.         } else {
  86.             gameRenderWorld->UpdateEntityDef( modelDefHandles[i], &renderEntity );
  87.         }
  88.     }
  89. }
  90.  
  91. /*
  92. ================
  93. idMultiModelAF::Think
  94. ================
  95. */
  96. void idMultiModelAF::Think( void ) {
  97.     RunPhysics();
  98.     Present();
  99. }
  100.  
  101.  
  102. /*
  103. ===============================================================================
  104.  
  105.   idChain
  106.  
  107. ===============================================================================
  108. */
  109.  
  110. CLASS_DECLARATION( idMultiModelAF, idChain )
  111. END_CLASS
  112.  
  113. /*
  114. ================
  115. idChain::BuildChain
  116.  
  117.   builds a chain hanging down from the ceiling
  118.   the highest link is a child of the link below it etc.
  119.   this allows an object to be attached to multiple chains while keeping a single tree structure
  120. ================
  121. */
  122. void idChain::BuildChain( const idStr &name, const idVec3 &origin, float linkLength, float linkWidth, float density, int numLinks, bool bindToWorld ) {
  123.     int i;
  124.     float halfLinkLength = linkLength * 0.5f;
  125.     idTraceModel trm;
  126.     idClipModel *clip;
  127.     idAFBody *body, *lastBody;
  128.     idAFConstraint_BallAndSocketJoint *bsj;
  129.     idAFConstraint_UniversalJoint *uj;
  130.     idVec3 org;
  131.  
  132.     // create a trace model
  133.     trm = idTraceModel( linkLength, linkWidth );
  134.     trm.Translate( -trm.offset );
  135.  
  136.     org = origin - idVec3( 0, 0, halfLinkLength );
  137.  
  138.     lastBody = NULL;
  139.     for ( i = 0; i < numLinks; i++ ) {
  140.  
  141.         // add body
  142. // RAVEN BEGIN
  143. // mwhitlock: Dynamic memory consolidation
  144.         RV_PUSH_HEAP_MEM(this);
  145. // RAVEN END
  146.         clip = new idClipModel( trm );
  147. // RAVEN BEGIN
  148. // mwhitlock: Dynamic memory consolidation
  149.         RV_POP_HEAP();
  150. // RAVEN END
  151.         clip->SetContents( CONTENTS_SOLID );
  152. // RAVEN BEGIN
  153. // ddynerman: multiple clip worlds
  154.         clip->Link( this, 0, org, mat3_identity );
  155. // RAVEN END
  156. // RAVEN BEGIN
  157. // mwhitlock: Dynamic memory consolidation
  158.         RV_PUSH_HEAP_MEM(this);
  159. // RAVEN END
  160.         body = new idAFBody( name + idStr(i), clip, density );
  161. // RAVEN BEGIN
  162. // mwhitlock: Dynamic memory consolidation
  163.         RV_POP_HEAP();
  164. // RAVEN END
  165.         physicsObj.AddBody( body );
  166.  
  167.         // visual model for body
  168.         SetModelForId( physicsObj.GetBodyId( body ), spawnArgs.GetString( "model" ) );
  169.  
  170.         // add constraint
  171.         if ( bindToWorld ) {
  172.             if ( !lastBody ) {
  173. // RAVEN BEGIN
  174. // mwhitlock: Dynamic memory consolidation
  175.                 RV_PUSH_HEAP_MEM(this);
  176. // RAVEN END
  177.                 uj = new idAFConstraint_UniversalJoint( name + idStr(i), body, lastBody );
  178. // RAVEN BEGIN
  179. // mwhitlock: Dynamic memory consolidation
  180.                 RV_POP_HEAP();
  181. // RAVEN END
  182.                 uj->SetShafts( idVec3( 0, 0, -1 ), idVec3( 0, 0, 1 ) );
  183.                 //uj->SetConeLimit( idVec3( 0, 0, -1 ), 30.0f );
  184.                 //uj->SetPyramidLimit( idVec3( 0, 0, -1 ), idVec3( 1, 0, 0 ), 90.0f, 30.0f );
  185.             }
  186.             else {
  187. // RAVEN BEGIN
  188. // mwhitlock: Dynamic memory consolidation
  189.                 RV_PUSH_HEAP_MEM(this);
  190. // RAVEN END
  191.                 uj = new idAFConstraint_UniversalJoint( name + idStr(i), lastBody, body );
  192. // RAVEN BEGIN
  193. // mwhitlock: Dynamic memory consolidation
  194.                 RV_POP_HEAP();
  195. // RAVEN END
  196.                 uj->SetShafts( idVec3( 0, 0, 1 ), idVec3( 0, 0, -1 ) );
  197.                 //uj->SetConeLimit( idVec3( 0, 0, 1 ), 30.0f );
  198.             }
  199.             uj->SetAnchor( org + idVec3( 0, 0, halfLinkLength ) );
  200.             uj->SetFriction( 0.9f );
  201.             physicsObj.AddConstraint( uj );
  202.         }
  203.         else {
  204.             if ( lastBody ) {
  205. // RAVEN BEGIN
  206. // mwhitlock: Dynamic memory consolidation
  207.                 RV_PUSH_HEAP_MEM(this);
  208. // RAVEN END
  209.                 bsj = new idAFConstraint_BallAndSocketJoint( "joint" + idStr(i), lastBody, body );
  210. // RAVEN BEGIN
  211. // mwhitlock: Dynamic memory consolidation
  212.                 RV_POP_HEAP();
  213. // RAVEN END
  214.                 bsj->SetAnchor( org + idVec3( 0, 0, halfLinkLength ) );
  215.                 bsj->SetConeLimit( idVec3( 0, 0, 1 ), 60.0f, idVec3( 0, 0, 1 ) );
  216.                 physicsObj.AddConstraint( bsj );
  217.             }
  218.         }
  219.  
  220.         org[2] -= linkLength;
  221.  
  222.         lastBody = body;
  223.     }
  224. }
  225.  
  226. /*
  227. ================
  228. idChain::Spawn
  229. ================
  230. */
  231. void idChain::Spawn( void ) {
  232.     int numLinks;
  233.     float length, linkLength, linkWidth, density;
  234.     bool drop;
  235.     idVec3 origin;
  236.  
  237.     spawnArgs.GetBool( "drop", "0", drop );
  238.     spawnArgs.GetInt( "links", "3", numLinks );
  239.     spawnArgs.GetFloat( "length", idStr( numLinks * 32.0f ), length );
  240.     spawnArgs.GetFloat( "width", "8", linkWidth );
  241.     spawnArgs.GetFloat( "density", "0.2", density );
  242.     linkLength = length / numLinks;
  243.     origin = GetPhysics()->GetOrigin();
  244.  
  245.     // initialize physics
  246.     physicsObj.SetSelf( this );
  247.     physicsObj.SetGravity( gameLocal.GetGravity() );
  248.     physicsObj.SetClipMask( MASK_SOLID | CONTENTS_BODY );
  249.     SetPhysics( &physicsObj );
  250.  
  251.     BuildChain( "link", origin, linkLength, linkWidth, density, numLinks, !drop );
  252. }
  253.  
  254. /*
  255. ===============================================================================
  256.  
  257.   idAFAttachment
  258.  
  259. ===============================================================================
  260. */
  261.  
  262. const idEventDef EV_ClearAnims( "clearAnims" );
  263.  
  264. CLASS_DECLARATION( idAnimatedEntity, idAFAttachment )
  265. // RAVEN BEGIN
  266. // jshepard: we'd like these to animate.
  267.         EVENT( AI_PlayAnim,                idAFAttachment::Event_PlayAnim )
  268.         EVENT( AI_PlayCycle,            idAFAttachment::Event_PlayCycle )
  269.         EVENT( EV_ClearAnims,            idAFAttachment::Event_ClearAnims )
  270. // RAVEN END
  271. END_CLASS
  272.  
  273. /*
  274. =====================
  275. idAFAttachment::idAFAttachment
  276. =====================
  277. */
  278. idAFAttachment::idAFAttachment( void ) {
  279.     body            = NULL;
  280.     combatModel        = NULL;
  281.     idleAnim        = 0;
  282.     damageJoint        = INVALID_JOINT;
  283.  
  284. // RAVEN BEGIN
  285. // jscott: Lip Syncing variables
  286.     lipSyncAnim        = 0;            
  287.     lipSyncData        = NULL;            
  288.     soundJoint        = INVALID_JOINT;
  289. // MCG
  290.     noPlayerImpactFX = false;
  291. // RAVEN END
  292. }
  293.  
  294. /*
  295. =====================
  296. idAFAttachment::~idAFAttachment
  297. =====================
  298. */
  299. idAFAttachment::~idAFAttachment( void ) {
  300.  
  301.     StopSound( SND_CHANNEL_ANY, false );
  302.  
  303.     delete combatModel;
  304.     combatModel = NULL;
  305.  
  306. // RAVEN BEGIN
  307.     EndLipSyncing();
  308. // RAVEN END
  309. }
  310.  
  311. /*
  312. =====================
  313. idAFAttachment::Spawn
  314. =====================
  315. */
  316. void idAFAttachment::Spawn( void ) {
  317.     idStr    jointName;
  318.  
  319.     idleAnim = animator.GetAnim( "idle" );
  320.  
  321. // RAVEN BEGIN
  322.     // Init the lip sync data
  323.     lipSyncAnim = 0;
  324.     if( spawnArgs.GetInt( "uses_lip_syncing", "0" ) ) {
  325.         lipSyncAnim = animator.GetAnim( "lipsync" );
  326.     }
  327.  
  328.     // Grab the joint to play sounds off
  329.     soundJoint = INVALID_JOINT;
  330.     spawnArgs.GetString( "sound_bone", "", jointName );
  331.  
  332.     // Do we want a bone to play sounds on?
  333.     if( jointName.Length() ) {
  334.  
  335.         // Try to find the specified bone
  336.         soundJoint = animator.GetJointHandle( jointName );
  337.  
  338.         if ( soundJoint == INVALID_JOINT ) {
  339.             // The def specified a bone for this and we can't find it - warn them.
  340.             gameLocal.Warning( "idAnimated '%s' at (%s): cannot find joint '%s' for sound playback", name.c_str(), GetPhysics()->GetOrigin().ToString(0), jointName.c_str() );
  341.         }
  342.     }
  343.  
  344.     noPlayerImpactFX = spawnArgs.GetBool( "noPlayerImpactFX", "0" );
  345. // RAVEN END
  346. }
  347.  
  348. /*
  349. =====================
  350. idAFAttachment::InitCopyJoints
  351. =====================
  352. */
  353. void idAFAttachment::InitCopyJoints ( void ) {
  354.     copyJoints_t        copyJoint;
  355.     const idKeyValue*    kv;
  356.     const char*            jointName;
  357.     idAnimator*            bodyAnimator;
  358.  
  359.     if ( !body ) {
  360.         return;
  361.     }
  362.     
  363.     bodyAnimator = body->GetAnimator ( );
  364.  
  365.     // set up the list of joints to copy to the head
  366.     for( kv = spawnArgs.MatchPrefix( "copy_joint", NULL ); kv != NULL; kv = spawnArgs.MatchPrefix( "copy_joint", kv ) ) {
  367.         if ( kv->GetValue() == "" ) {
  368.             // probably clearing out inherited key, so skip it
  369.             continue;
  370.         }
  371.  
  372.         if ( !body->spawnArgs.GetString ( va("copy_joint_world %s", kv->GetValue().c_str() ), kv->GetValue().c_str(), &jointName ) ) {
  373.             copyJoint.mod = JOINTMOD_LOCAL_OVERRIDE;            
  374.             body->spawnArgs.GetString ( va("copy_joint %s", kv->GetValue().c_str() ), kv->GetValue().c_str(), &jointName );
  375.         } else {
  376.             copyJoint.mod = JOINTMOD_WORLD_OVERRIDE;
  377.         }
  378.         
  379.         copyJoint.from = bodyAnimator->GetJointHandle ( jointName );
  380.         if ( copyJoint.from == INVALID_JOINT ) {
  381.             gameLocal.Warning( "Unknown copy_joint '%s' on entity %s", jointName, name.c_str() );
  382.             continue;
  383.         }
  384.  
  385.         copyJoint.to = animator.GetJointHandle( kv->GetValue() );
  386.         if ( copyJoint.to == INVALID_JOINT ) {
  387.             gameLocal.Warning( "Unknown copy_joint '%s' on head of entity %s", kv->GetValue().c_str(), name.c_str() );
  388.             continue;
  389.         }
  390.  
  391.         copyJoints.Append( copyJoint );
  392.     }
  393. }
  394.  
  395. /*
  396. =====================
  397. idAFAttachment::CopyJointsFromBody
  398. =====================
  399. */
  400. void idAFAttachment::CopyJointsFromBody ( void ) {
  401.     MEM_SCOPED_TAG(tag,MA_ANIM);
  402.  
  403.     idAnimator*    bodyAnimator;
  404.     int            i;
  405.     idMat3        mat;
  406.     idMat3        axis;
  407.     idVec3        pos;
  408.     
  409.     if ( !body ) {
  410.         return;
  411.     }
  412.     bodyAnimator = body->GetAnimator();
  413.  
  414.     // copy the animation from the body to the head
  415.     for( i = 0; i < copyJoints.Num(); i++ ) {
  416.         if ( copyJoints[ i ].mod == JOINTMOD_WORLD_OVERRIDE ) {
  417.             mat = GetPhysics()->GetAxis().Transpose();
  418.             body->GetJointWorldTransform( copyJoints[ i ].from, gameLocal.time, pos, axis );
  419.             pos -= GetPhysics()->GetOrigin();
  420.             animator.SetJointPos( copyJoints[ i ].to, copyJoints[ i ].mod, pos * mat );
  421.             animator.SetJointAxis( copyJoints[ i ].to, copyJoints[ i ].mod, axis * mat );
  422.         } else {
  423.             bodyAnimator->GetJointLocalTransform( copyJoints[ i ].from, gameLocal.time, pos, axis );
  424.             animator.SetJointPos( copyJoints[ i ].to, copyJoints[ i ].mod, pos );
  425.             animator.SetJointAxis( copyJoints[ i ].to, copyJoints[ i ].mod, axis );
  426.         }
  427.     }    
  428. }
  429.  
  430. /*
  431. =====================
  432. idAFAttachment::SetBody
  433. =====================
  434. */
  435. void idAFAttachment::SetBody( idAnimatedEntity *bodyEnt, const char *model, jointHandle_t _damageJoint ) {
  436.     body = bodyEnt;
  437.     damageJoint = _damageJoint;
  438.     SetModel( model );
  439.     fl.takedamage = true;
  440.  
  441.     spawnArgs.SetBool( "bleed", body->spawnArgs.GetBool( "bleed" ) );
  442. }
  443.  
  444. /*
  445. =====================
  446. idAFAttachment::ClearBody
  447. =====================
  448. */
  449. void idAFAttachment::ClearBody( void ) {
  450.     body = NULL;
  451.     damageJoint = INVALID_JOINT;
  452.     Hide();
  453. }
  454.  
  455. /*
  456. =====================
  457. idAFAttachment::GetBody
  458. =====================
  459. */
  460. idEntity *idAFAttachment::GetBody( void ) const {
  461.     return body;
  462. }
  463.  
  464. /*
  465. ================
  466. idAFAttachment::Save
  467.  
  468. archive object for savegame file
  469. ================
  470. */
  471. void idAFAttachment::Save( idSaveGame *savefile ) const {
  472.     int i;
  473.  
  474.     body.Save ( savefile );
  475.     savefile->WriteInt( idleAnim );
  476.     savefile->WriteJoint( damageJoint );
  477.     savefile->WriteJoint( soundJoint );
  478.  
  479. // RAVEN BEGIN
  480. // jscott: for lipsyncing
  481.     savefile->WriteInt( lipSyncAnim );
  482. // RAVEN END
  483.  
  484.     savefile->WriteInt( copyJoints.Num() );
  485.     for( i = 0; i < copyJoints.Num(); i++ ) {
  486.         savefile->WriteInt( copyJoints[i].mod );
  487.         savefile->WriteJoint( copyJoints[i].from );
  488.         savefile->WriteJoint( copyJoints[i].to );
  489.     }
  490.  
  491.     bool hadCombatModel = false;
  492.     if ( combatModel ) {
  493.         hadCombatModel = true;
  494.     }
  495.     savefile->WriteBool( hadCombatModel );
  496.  
  497.     savefile->WriteBool( noPlayerImpactFX );
  498. }
  499.  
  500. /*
  501. ================
  502. idAFAttachment::Restore
  503.  
  504. unarchives object from save game file
  505. ================
  506. */
  507. void idAFAttachment::Restore( idRestoreGame *savefile ) {
  508.     body.Restore ( savefile );
  509.     savefile->ReadInt( idleAnim );
  510.     savefile->ReadJoint( damageJoint );
  511.     savefile->ReadJoint( soundJoint );
  512.  
  513. // RAVEN BEGIN
  514. // jscott: for lipsyncing
  515.     savefile->ReadInt( lipSyncAnim );
  516. // jscott: difficult to start a sound mid sentence and impossible to sync up the timing with the animation
  517.     lipSyncData = NULL;
  518. // RAVEN END
  519.  
  520.     int i;
  521.     int num;
  522.     savefile->ReadInt( num );
  523.     copyJoints.SetNum( num );
  524.     for( i = 0; i < num; i++ ) {
  525.         int val;
  526.         savefile->ReadInt( val );
  527.         copyJoints[i].mod = static_cast<jointModTransform_t>( val );
  528.         savefile->ReadJoint( copyJoints[i].from );
  529.         savefile->ReadJoint( copyJoints[i].to );
  530.     }
  531.  
  532.     bool hadCombatModel;
  533.     savefile->ReadBool( hadCombatModel );
  534.     if ( hadCombatModel ) {
  535.         SetCombatModel();
  536.         LinkCombat();
  537.     }
  538.  
  539.     savefile->ReadBool( noPlayerImpactFX );
  540.  
  541.     lipSyncAnim = 0;
  542.     if( spawnArgs.GetInt( "uses_lip_syncing", "0" ) ) {
  543.         lipSyncAnim = animator.GetAnim( "lipsync" );
  544.     }
  545. }
  546.  
  547. /*
  548. ================
  549. idAFAttachment::Hide
  550. ================
  551. */
  552. void idAFAttachment::Hide( void ) {
  553.     idEntity::Hide();
  554.     UnlinkCombat();
  555. }
  556.  
  557. /*
  558. ================
  559. idAFAttachment::Show
  560. ================
  561. */
  562. void idAFAttachment::Show( void ) {
  563.     idEntity::Show();
  564.     LinkCombat();
  565. }
  566.  
  567. /*
  568. ============
  569. idAFAttachment::Damage
  570.  
  571. Pass damage to body at the bindjoint
  572. ============
  573. */
  574. void idAFAttachment::Damage( idEntity *inflictor, idEntity *attacker, const idVec3 &dir, 
  575.     const char *damageDefName, const float damageScale, const int location ) {
  576.     
  577.     if ( body ) {
  578.         body->Damage( inflictor, attacker, dir, damageDefName, damageScale, damageJoint );
  579.     }
  580. }
  581.  
  582. /*
  583. ================
  584. idAFAttachment::AddDamageEffect
  585. ================
  586. */
  587. void idAFAttachment::AddDamageEffect( const trace_t &collision, const idVec3 &velocity, const char *damageDefName, idEntity* inflictor ) {
  588.     if ( body ) {
  589.         trace_t c = collision;
  590.         c.c.id = JOINT_HANDLE_TO_CLIPMODEL_ID( damageJoint );
  591.         body->AddDamageEffect( c, velocity, damageDefName, inflictor );
  592.     }
  593. }
  594.  
  595. /*
  596. ================
  597. idAFAttachment::GetImpactInfo
  598. ================
  599. */
  600. void idAFAttachment::GetImpactInfo( idEntity *ent, int id, const idVec3 &point, impactInfo_t *info ) {
  601.     if ( body ) {
  602.         body->GetImpactInfo( ent, JOINT_HANDLE_TO_CLIPMODEL_ID( damageJoint ), point, info );
  603.     } else {
  604.         idEntity::GetImpactInfo( ent, id, point, info );
  605.     }
  606. }
  607.  
  608. /*
  609. ================
  610. idAFAttachment::CanPlayImpactEffect
  611. ================
  612. */
  613. bool idAFAttachment::CanPlayImpactEffect ( idEntity* attacker, idEntity* target ) {
  614.     if ( ( noPlayerImpactFX && GetNoPlayerImpactFX( ) ) && attacker && attacker->IsType( idPlayer::GetClassType() ) ) {
  615.         return false;
  616.     }
  617.  
  618.     return idAnimatedEntity::CanPlayImpactEffect( attacker, target );
  619. }
  620.  
  621. /*
  622. ================
  623. idAFAttachment::GetNoPlayerImpactFX
  624. ================
  625. */
  626. bool idAFAttachment::GetNoPlayerImpactFX( void ) {
  627.     if ( GetTeamMaster( ) && this != GetTeamMaster( ) && GetTeamMaster( )->IsType( idAFEntity_Base::GetClassType( ) ) ) {
  628.         return static_cast<idAFEntity_Base*>( GetTeamMaster( ) )->GetNoPlayerImpactFX( );
  629.     } else {
  630.         return noPlayerImpactFX;
  631.     }
  632. }
  633.  
  634. /*
  635. ================
  636. idAFAttachment::ApplyImpulse
  637. ================
  638. */
  639. void idAFAttachment::ApplyImpulse( idEntity *ent, int id, const idVec3 &point, const idVec3 &impulse, bool splash ) {
  640.     if ( body ) {
  641.         body->ApplyImpulse( ent, JOINT_HANDLE_TO_CLIPMODEL_ID( damageJoint ), point, impulse );
  642.     } else {
  643.         idEntity::ApplyImpulse( ent, id, point, impulse );
  644.     }
  645. }
  646.  
  647. /*
  648. ================
  649. idAFAttachment::AddForce
  650. ================
  651. */
  652. void idAFAttachment::AddForce( idEntity *ent, int id, const idVec3 &point, const idVec3 &force ) {
  653.     if ( body ) {
  654.         body->AddForce( ent, JOINT_HANDLE_TO_CLIPMODEL_ID( damageJoint ), point, force );
  655.     } else {
  656.         idEntity::AddForce( ent, id, point, force );
  657.     }
  658. }
  659.  
  660. /*
  661. ================
  662. idAFAttachment::PlayIdleAnim
  663. ================
  664. */
  665. // RAVEN BEGIN
  666. // bdube: added channel
  667. void idAFAttachment::PlayIdleAnim( int channel, int blendTime ) {
  668.     if ( idleAnim && ( idleAnim != animator.CurrentAnim( channel )->AnimNum() ) ) {
  669.         animator.CycleAnim( channel, idleAnim, gameLocal.time, blendTime );
  670.     }
  671. // RAVEN END
  672. }
  673.  
  674. /*
  675. ================
  676. idAfAttachment::Think
  677. ================
  678. */
  679. void idAFAttachment::Think( void ) {
  680. // RAVEN BEGIN
  681. // jscott: Lip sync main code
  682.     HandleLipSync();
  683. // RAVEN END
  684.  
  685.     idAnimatedEntity::Think();
  686. }
  687.  
  688. // RAVEN BEGIN
  689. /*
  690. ===============
  691. idAnimated::GetPhysicsToSoundTransform
  692. ===============
  693. */
  694. bool idAFAttachment::GetPhysicsToSoundTransform( idVec3 &origin, idMat3 &axis ) {
  695.     if ( soundJoint != INVALID_JOINT ) {
  696.         animator.GetJointTransform( soundJoint, gameLocal.time, origin, axis );
  697.         axis = GetPhysics()->GetAxis();
  698.     } else {
  699.         origin = GetPhysics()->GetOrigin();
  700.         axis = GetPhysics()->GetAxis();
  701.     }
  702.  
  703.     return true;
  704. }
  705. // RAVEN END
  706.  
  707. /*
  708. ================
  709. idAFAttachment::UpdateAnimationControllers
  710. ================
  711. */
  712. bool idAFAttachment::UpdateAnimationControllers( void ) {
  713.     CopyJointsFromBody( );
  714.     return idAnimatedEntity::UpdateAnimationControllers( );
  715. }
  716.  
  717. /*
  718. ================
  719. idAFAttachment::SetCombatModel
  720. ================
  721. */
  722. void idAFAttachment::SetCombatModel( void ) {
  723.     if ( combatModel ) {
  724.         combatModel->Unlink();
  725.         combatModel->LoadModel( modelDefHandle );
  726.     } else {
  727. // RAVEN BEGIN
  728. // mwhitlock: Dynamic memory consolidation
  729.         RV_PUSH_HEAP_MEM(this);
  730. // RAVEN END
  731.         combatModel = new idClipModel( modelDefHandle );
  732. // RAVEN BEGIN
  733. // mwhitlock: Dynamic memory consolidation
  734.         RV_POP_HEAP();
  735. // RAVEN END
  736.     }
  737.     combatModel->SetOwner( body );
  738. }
  739.  
  740. /*
  741. ================
  742. idAFAttachment::GetCombatModel
  743. ================
  744. */
  745. idClipModel *idAFAttachment::GetCombatModel( void ) const {
  746.     return combatModel;
  747. }
  748.  
  749. /*
  750. ================
  751. idAFAttachment::LinkCombat
  752. ================
  753. */
  754. void idAFAttachment::LinkCombat( void ) {
  755.     if ( fl.hidden ) {
  756.         return;
  757.     }
  758.  
  759.     if ( combatModel ) {
  760. // RAVEN BEGIN
  761. // ddynerman: multiple clip worlds
  762.         combatModel->Link( this, 0, renderEntity.origin, renderEntity.axis, modelDefHandle );
  763. // RAVEN END
  764.     }
  765. }
  766.  
  767. /*
  768. ================
  769. idAFAttachment::UnlinkCombat
  770. ================
  771. */
  772. void idAFAttachment::UnlinkCombat( void ) {
  773.     if ( combatModel ) {
  774.         combatModel->Unlink();
  775.     }
  776. }
  777.  
  778. // RAVEN BEGIN
  779. // bdube: return the body entity for damage
  780. /*
  781. ================
  782. idAFAttachment::GetDamageEntity
  783. ================
  784. */
  785. idEntity* idAFAttachment::GetDamageEntity ( void ) { 
  786.     return body ? body : this;
  787. }
  788.  
  789. // jshepard: we need to animate these
  790. /*
  791. ================
  792. idAFAttachment::Event_PlayAnim
  793. ================
  794. */
  795. void idAFAttachment::Event_PlayAnim ( int channel, const char *animname ) {
  796.     int anim;
  797.     float animTime;
  798.     float blendFrames = 4;
  799.  
  800.     anim = animator.GetAnim( animname );
  801.     if ( !anim ) {
  802.         gameLocal.Warning( "missing '%s' animation on '%s' (%s)", animname, name.c_str(), GetEntityDefName() );
  803.         animator.Clear( channel, gameLocal.time, FRAME2MS( blendFrames ) );
  804.         idThread::ReturnFloat( false );
  805.     } else {
  806.         animator.PlayAnim( channel, anim, gameLocal.time, FRAME2MS( blendFrames ) );
  807.         animTime = animator.CurrentAnim( channel )->GetEndTime();
  808.         idThread::ReturnFloat( MS2SEC( animTime - gameLocal.time ) );
  809.     }
  810.     blendFrames = 0;
  811. }
  812.  
  813. // jdischler: and we want cycling, too.
  814. /*
  815. ===============
  816. idAFAttachment::Event_PlayCycle
  817. ===============
  818. */
  819. void idAFAttachment::Event_PlayCycle( int channel, const char *animname ) {
  820.     int anim;
  821.     float animTime;
  822.     float blendFrames = 4;
  823.  
  824.     anim = animator.GetAnim( animname );
  825.     if ( !anim ) {
  826.         gameLocal.Warning( "missing '%s' animation on '%s' (%s)", animname, name.c_str(), GetEntityDefName() );
  827.         animator.Clear( channel, gameLocal.time, FRAME2MS( blendFrames ) );
  828.     } else {
  829.         animator.CycleAnim( channel, anim, gameLocal.time, FRAME2MS( blendFrames ) );
  830.         animTime = animator.CurrentAnim( channel )->GetEndTime();
  831.     }
  832.     blendFrames = 0;
  833. }
  834.  
  835. /*
  836. ================
  837. idAFAttachment::Event_ClearAnims
  838.  
  839. Clears any animation running on the idAFAttachment
  840. ================
  841. */
  842. void idAFAttachment::Event_ClearAnims( void ) {
  843.     //animator.ClearAllAnims( gameLocal.time, 100 );
  844.     animator.Clear( ANIMCHANNEL_ALL, gameLocal.time, 0 );
  845. }
  846.  
  847. // RAVEN END
  848.  
  849. /*
  850. ===============================================================================
  851.  
  852.   idAFEntity_Base
  853.  
  854. ===============================================================================
  855. */
  856.  
  857. const idEventDef EV_SetConstraintPosition( "SetConstraintPosition", "sv" );
  858. // RAVEN BEGIN
  859. // kfuller: added
  860. const idEventDef EV_TPose( "tpose", NULL );
  861. // RAVEN END
  862.  
  863. CLASS_DECLARATION( idAnimatedEntity, idAFEntity_Base )
  864.     EVENT( EV_SetConstraintPosition,    idAFEntity_Base::Event_SetConstraintPosition )
  865. END_CLASS
  866.  
  867. static const float BOUNCE_SOUND_MIN_VELOCITY    = 80.0f;
  868. static const float BOUNCE_SOUND_MAX_VELOCITY    = 200.0f;
  869.  
  870. /*
  871. ================
  872. idAFEntity_Base::idAFEntity_Base
  873. ================
  874. */
  875. idAFEntity_Base::idAFEntity_Base( void ) {
  876.     combatModel = NULL;
  877.     combatModelContents = 0;
  878.     nextSoundTime = 0;
  879.     spawnOrigin.Zero();
  880.     spawnAxis.Identity();
  881.     noPlayerImpactFX = false;
  882. }
  883.  
  884. /*
  885. ================
  886. idAFEntity_Base::~idAFEntity_Base
  887. ================
  888. */
  889. idAFEntity_Base::~idAFEntity_Base( void ) {
  890.     delete combatModel;
  891.     combatModel = NULL;
  892. }
  893.  
  894. /*
  895. ================
  896. idAFEntity_Base::Save
  897. ================
  898. */
  899. void idAFEntity_Base::Save( idSaveGame *savefile ) const {
  900.     savefile->WriteBool( noPlayerImpactFX );
  901.     savefile->WriteInt( combatModelContents );
  902.     savefile->WriteClipModel( combatModel );
  903.     savefile->WriteVec3( spawnOrigin );
  904.     savefile->WriteMat3( spawnAxis );
  905.     savefile->WriteInt( nextSoundTime );
  906.     af.Save( savefile );
  907. }
  908.  
  909. /*
  910. ================
  911. idAFEntity_Base::Restore
  912. ================
  913. */
  914. void idAFEntity_Base::Restore( idRestoreGame *savefile ) {
  915.     savefile->ReadBool( noPlayerImpactFX );
  916.     savefile->ReadInt( combatModelContents );
  917.     savefile->ReadClipModel( combatModel );
  918.     savefile->ReadVec3( spawnOrigin );
  919.     savefile->ReadMat3( spawnAxis );
  920.     savefile->ReadInt( nextSoundTime );
  921.     LinkCombat();
  922.  
  923.     af.Restore( savefile );
  924. }
  925.  
  926. /*
  927. ================
  928. idAFEntity_Base::Spawn
  929. ================
  930. */
  931. void idAFEntity_Base::Spawn( void ) {
  932.     spawnOrigin = GetPhysics()->GetOrigin();
  933.     spawnAxis = GetPhysics()->GetAxis();
  934.     nextSoundTime = 0;
  935.  
  936.     noPlayerImpactFX = spawnArgs.GetBool( "noPlayerImpactFX", "0" );
  937. }
  938.  
  939. /*
  940. ================
  941. idAFEntity_Base::LoadAF
  942. ================
  943. */
  944. bool idAFEntity_Base::LoadAF( const char* keyname ) {
  945.     idStr fileName;
  946.     
  947.     if ( !keyname || !*keyname ) {
  948.         keyname = "articulatedFigure";
  949.     }
  950.  
  951.     if ( !spawnArgs.GetString( keyname, "*unknown*", fileName ) ) {
  952.         return false;
  953.     }
  954.  
  955.     af.SetAnimator( GetAnimator() );
  956.     if ( !af.Load( this, fileName ) ) {
  957.         gameLocal.Error( "idAFEntity_Base::LoadAF: Couldn't load af file '%s' on entity '%s'", fileName.c_str(), name.c_str() );
  958.     }
  959.  
  960.     af.Start();
  961.  
  962.     af.GetPhysics()->Rotate( spawnAxis.ToRotation() );
  963.     af.GetPhysics()->Translate( spawnOrigin );
  964.  
  965.     LoadState( spawnArgs );
  966.  
  967.     af.UpdateAnimation();
  968.     animator.CreateFrame( gameLocal.time, true );
  969.     UpdateVisuals();
  970.  
  971.     return true;
  972. }
  973.  
  974. /*
  975. ================
  976. idAFEntity_Base::Think
  977. ================
  978. */
  979. void idAFEntity_Base::Think( void ) {
  980.     RunPhysics();
  981.     UpdateAnimation();
  982.     if ( thinkFlags & TH_UPDATEVISUALS ) {
  983.         Present();
  984.         LinkCombat();
  985.     }
  986.  
  987. // RAVEN BEGIN
  988. // kfuller: added
  989.     if (spawnArgs.GetBool("touchtriggers")) {
  990.         TouchTriggers();
  991.     }
  992.  
  993. // rjohnson: added check to see if we no longer need to think!
  994.     if (GetPhysics()->IsAtRest() && !animator.IsAnimating( gameLocal.time, true ) ) {
  995.         BecomeInactive( TH_ANIMATE );
  996.     }
  997. // RAVEN END
  998. }
  999.  
  1000. /*
  1001. ================
  1002. idAFEntity_Base::BodyForClipModelId
  1003. ================
  1004. */
  1005. int idAFEntity_Base::BodyForClipModelId( int id ) const {
  1006.     return af.BodyForClipModelId( id );
  1007. }
  1008.  
  1009. /*
  1010. ================
  1011. idAFEntity_Base::SaveState
  1012. ================
  1013. */
  1014. void idAFEntity_Base::SaveState( idDict &args ) const {
  1015.     const idKeyValue *kv;
  1016.  
  1017.     // save the ragdoll pose
  1018.     af.SaveState( args );
  1019.  
  1020.     // save all the bind constraints
  1021.     kv = spawnArgs.MatchPrefix( "bindConstraint ", NULL );
  1022.     while ( kv ) {
  1023.         args.Set( kv->GetKey(), kv->GetValue() );
  1024.         kv = spawnArgs.MatchPrefix( "bindConstraint ", kv );
  1025.     }
  1026.  
  1027.     // save the bind if it exists
  1028.     kv = spawnArgs.FindKey( "bind" );
  1029.     if ( kv ) {
  1030.         args.Set( kv->GetKey(), kv->GetValue() );
  1031.     }
  1032.     kv = spawnArgs.FindKey( "bindToJoint" );
  1033.     if ( kv ) {
  1034.         args.Set( kv->GetKey(), kv->GetValue() );
  1035.     }
  1036.     kv = spawnArgs.FindKey( "bindToBody" );
  1037.     if ( kv ) {
  1038.         args.Set( kv->GetKey(), kv->GetValue() );
  1039.     }
  1040. }
  1041.  
  1042. /*
  1043. ================
  1044. idAFEntity_Base::LoadState
  1045. ================
  1046. */
  1047. void idAFEntity_Base::LoadState( const idDict &args ) {
  1048.     af.LoadState( args );
  1049. }
  1050.  
  1051. /*
  1052. ================
  1053. idAFEntity_Base::AddBindConstraints
  1054. ================
  1055. */
  1056. void idAFEntity_Base::AddBindConstraints( void ) {
  1057.     af.AddBindConstraints();
  1058. }
  1059.  
  1060. /*
  1061. ================
  1062. idAFEntity_Base::RemoveBindConstraints
  1063. ================
  1064. */
  1065. void idAFEntity_Base::RemoveBindConstraints( void ) {
  1066.     af.RemoveBindConstraints();
  1067. }
  1068.  
  1069. /*
  1070. ================
  1071. idAFEntity_Base::GetImpactInfo
  1072. ================
  1073. */
  1074. void idAFEntity_Base::GetImpactInfo( idEntity *ent, int id, const idVec3 &point, impactInfo_t *info ) {
  1075.     if ( af.IsActive() ) {
  1076.         af.GetImpactInfo( ent, id, point, info );
  1077.     } else {
  1078.         idEntity::GetImpactInfo( ent, id, point, info );
  1079.     }
  1080. }
  1081.  
  1082. /*
  1083. ================
  1084. idAFEntity_Base::ApplyImpulse
  1085. ================
  1086. */
  1087. void idAFEntity_Base::ApplyImpulse( idEntity *ent, int id, const idVec3 &point, const idVec3 &impulse, bool splash ) {
  1088.     if ( !splash && ( noPlayerImpactFX || GetNoPlayerImpactFX( ) ) ) {
  1089.         if ( ent->IsType( idPlayer::GetClassType() ) )
  1090.         {//player
  1091.             return;
  1092.         }
  1093.         if ( ent->IsType( idProjectile::GetClassType() ) )
  1094.         {//projectile
  1095.             if ( ((idProjectile*)ent)->GetOwner() && ((idProjectile*)ent)->GetOwner()->IsType( idPlayer::GetClassType() ) )
  1096.             {//owned by player
  1097.                 return;
  1098.             }
  1099.         }
  1100.     }
  1101.  
  1102.     if ( af.IsLoaded() ) {
  1103.         af.ApplyImpulse( ent, id, point, impulse );
  1104.     }
  1105.     if ( !af.IsActive() ) {
  1106.         idEntity::ApplyImpulse( ent, id, point, impulse );
  1107.     }
  1108. }
  1109.  
  1110. /*
  1111. ================
  1112. idAFEntity_Base::AddForce
  1113. ================
  1114. */
  1115. void idAFEntity_Base::AddForce( idEntity *ent, int id, const idVec3 &point, const idVec3 &force ) {
  1116.     if ( af.IsLoaded() ) {
  1117.         af.AddForce( ent, id, point, force );
  1118.     }
  1119.     if ( !af.IsActive() ) {
  1120.         idEntity::AddForce( ent, id, point, force );
  1121.     }
  1122. }
  1123.  
  1124. bool idAFEntity_Base::CanPlayImpactEffect ( idEntity* attacker, idEntity* target ) {
  1125.     if ( ( noPlayerImpactFX && GetNoPlayerImpactFX( ) ) && attacker && attacker->IsType( idPlayer::GetClassType() ) ) {
  1126.         return false;
  1127.     }
  1128.  
  1129.     return idAnimatedEntity::CanPlayImpactEffect( attacker, target );
  1130. }
  1131.  
  1132. /*
  1133. ================
  1134. idAFEntity_Base::Collide
  1135. ================
  1136. */
  1137. bool idAFEntity_Base::Collide( const trace_t &collision, const idVec3 &velocity ) {
  1138.     float v, f;
  1139.  
  1140.     if ( af.IsActive() ) {
  1141.         v = -( velocity * collision.c.normal );
  1142.         if ( v > BOUNCE_SOUND_MIN_VELOCITY && gameLocal.time > nextSoundTime ) {
  1143. // RAVEN BEGIN
  1144. // jscott: fixed negative sqrt call
  1145.             if( v > BOUNCE_SOUND_MAX_VELOCITY ) {
  1146.                 f = 1.0f;
  1147.             } else if( v <= BOUNCE_SOUND_MIN_VELOCITY ) {
  1148.                 f = 0.0f;
  1149.             } else {
  1150.                 f = ( v - BOUNCE_SOUND_MIN_VELOCITY ) * ( 1.0f / ( BOUNCE_SOUND_MAX_VELOCITY - BOUNCE_SOUND_MIN_VELOCITY ) );
  1151.             }
  1152. // RAVEN END
  1153.             if ( StartSound( "snd_bounce", SND_CHANNEL_ANY, 0, false, NULL ) ) {
  1154.                 // don't set the volume unless there is a bounce sound as it overrides the entire channel
  1155.                 // which causes footsteps on ai's to not honor their shader parms
  1156.                 SetSoundVolume( f );
  1157.             }
  1158.             nextSoundTime = gameLocal.time + 500;
  1159.         }
  1160.     }
  1161.  
  1162.     return false;
  1163. }
  1164.  
  1165. /*
  1166. ================
  1167. idAFEntity_Base::GetPhysicsToVisualTransform
  1168. ================
  1169. */
  1170. bool idAFEntity_Base::GetPhysicsToVisualTransform( idVec3 &origin, idMat3 &axis ) {
  1171.     if ( af.IsActive() ) {
  1172.         af.GetPhysicsToVisualTransform( origin, axis );
  1173.         return true;
  1174.     }
  1175.     return idEntity::GetPhysicsToVisualTransform( origin, axis );
  1176. }
  1177.  
  1178. /*
  1179. ================
  1180. idAFEntity_Base::UpdateAnimationControllers
  1181. ================
  1182. */
  1183. bool idAFEntity_Base::UpdateAnimationControllers( void ) {
  1184.     if ( af.IsActive() ) {
  1185.         if ( af.UpdateAnimation() ) {
  1186.             return true;
  1187.         }
  1188.     }
  1189.     return false;
  1190. }
  1191.  
  1192. /*
  1193. ================
  1194. idAFEntity_Base::SetCombatModel
  1195. ================
  1196. */
  1197. void idAFEntity_Base::SetCombatModel( void ) {
  1198.     if ( combatModel ) {
  1199.         combatModel->Unlink();
  1200.         combatModel->LoadModel( modelDefHandle );
  1201.     } else {
  1202. // RAVEN BEGIN
  1203. // mwhitlock: Dynamic memory consolidation
  1204.         RV_PUSH_HEAP_MEM(this);
  1205. // RAVEN END
  1206.         combatModel = new idClipModel( modelDefHandle );
  1207. // RAVEN BEGIN
  1208. // mwhitlock: Dynamic memory consolidation
  1209.         RV_POP_HEAP();
  1210. // RAVEN END
  1211.     }
  1212. }
  1213.  
  1214. /*
  1215. ================
  1216. idAFEntity_Base::GetCombatModel
  1217. ================
  1218. */
  1219. idClipModel *idAFEntity_Base::GetCombatModel( void ) const {
  1220.     return combatModel;
  1221. }
  1222.  
  1223. /*
  1224. ================
  1225. idAFEntity_Base::SetCombatContents
  1226. ================
  1227. */
  1228. void idAFEntity_Base::SetCombatContents( bool enable ) {
  1229.     assert( combatModel );
  1230.     if ( enable && combatModelContents ) {
  1231.         assert( !combatModel->GetContents() );
  1232.         combatModel->SetContents( combatModelContents );
  1233.         combatModelContents = 0;
  1234.     } else if ( !enable && combatModel->GetContents() ) {
  1235.         assert( !combatModelContents );
  1236.         combatModelContents = combatModel->GetContents();
  1237.         combatModel->SetContents( 0 );
  1238.     }
  1239. }
  1240.  
  1241. /*
  1242. ================
  1243. idAFEntity_Base::LinkCombat
  1244. ================
  1245. */
  1246. void idAFEntity_Base::LinkCombat( void ) {
  1247.     if ( fl.hidden ) {
  1248.         return;
  1249.     }
  1250.     if ( combatModel ) {
  1251. // RAVEN BEGIN
  1252. // ddynerman: multiple clip worlds
  1253.         combatModel->Link( this, 0, renderEntity.origin, renderEntity.axis, modelDefHandle );
  1254. // RAVEN END
  1255.     }
  1256. }
  1257.  
  1258. /*
  1259. ================
  1260. idAFEntity_Base::UnlinkCombat
  1261. ================
  1262. */
  1263. void idAFEntity_Base::UnlinkCombat( void ) {
  1264.     if ( combatModel ) {
  1265.         combatModel->Unlink();
  1266.     }
  1267. }
  1268.  
  1269. /*
  1270. ================
  1271. idAFEntity_Base::FreeModelDef
  1272. ================
  1273. */
  1274. void idAFEntity_Base::FreeModelDef( void ) {
  1275.     UnlinkCombat();
  1276.     idEntity::FreeModelDef();
  1277. }
  1278.  
  1279. /*
  1280. ===============
  1281. idAFEntity_Base::ShowEditingDialog
  1282. ===============
  1283. */
  1284. void idAFEntity_Base::ShowEditingDialog( void ) {
  1285.     common->InitTool( EDITOR_AF, &spawnArgs );
  1286. }
  1287.  
  1288. /*
  1289. ================
  1290. idAFEntity_Base::DropAFs
  1291.  
  1292.   The entity should have the following key/value pairs set:
  1293.     "def_drop<type>AF"        "af def"
  1294.     "drop<type>Skin"        "skin name"
  1295.   To drop multiple articulated figures the following key/value pairs can be used:
  1296.     "def_drop<type>AF*"        "af def"
  1297.   where * is an aribtrary string.
  1298. ================
  1299. */
  1300. void idAFEntity_Base::DropAFs( idEntity *ent, const char *type, idList<idEntity *> *list ) {
  1301.     const idKeyValue *kv;
  1302.     const char *skinName;
  1303.     idEntity *newEnt;
  1304.     idAFEntity_Base *af;
  1305.     idDict args;
  1306.     const idDeclSkin *skin;
  1307.  
  1308.     // drop the articulated figures
  1309.     kv = ent->spawnArgs.MatchPrefix( va( "def_drop%sAF", type ), NULL );
  1310.     while ( kv ) {
  1311.  
  1312.         args.Set( "classname", kv->GetValue() );
  1313.         gameLocal.SpawnEntityDef( args, &newEnt );
  1314.  
  1315.         if ( newEnt && newEnt->IsType( idAFEntity_Base::Type ) ) {
  1316.             af = static_cast<idAFEntity_Base *>(newEnt);
  1317.             af->GetPhysics()->SetOrigin( ent->GetPhysics()->GetOrigin() );
  1318.             af->GetPhysics()->SetAxis( ent->GetPhysics()->GetAxis() );
  1319.             af->af.SetupPose( ent, gameLocal.time );
  1320.             if ( list ) {
  1321.                 list->Append( af );
  1322.             }
  1323.         }
  1324.  
  1325.         kv = ent->spawnArgs.MatchPrefix( va( "def_drop%sAF", type ), kv );
  1326.     }
  1327.  
  1328.     // change the skin to hide all the dropped articulated figures
  1329.     skinName = ent->spawnArgs.GetString( va( "skin_drop%s", type ) );
  1330.     if ( skinName[0] ) {
  1331.         skin = declManager->FindSkin( skinName );
  1332.         ent->SetSkin( skin );
  1333.     }
  1334. }
  1335.  
  1336. /*
  1337. ================
  1338. idAFEntity_Base::GetNoPlayerImpactFX
  1339. ================
  1340. */
  1341. bool idAFEntity_Base::GetNoPlayerImpactFX( void ) {
  1342.     if ( GetTeamMaster( ) && this != GetTeamMaster( ) && GetTeamMaster( )->IsType( idAFEntity_Base::GetClassType( ) ) ) {
  1343.         return static_cast<idAFEntity_Base*>( GetTeamMaster( ) )->GetNoPlayerImpactFX( );
  1344.     } else {
  1345.         return noPlayerImpactFX;
  1346.     }
  1347. }
  1348.  
  1349. /*
  1350. ================
  1351. idAFEntity_Base::Event_SetConstraintPosition
  1352. ================
  1353. */
  1354. void idAFEntity_Base::Event_SetConstraintPosition( const char *name, const idVec3 &pos ) {
  1355.     af.SetConstraintPosition( name, pos );
  1356. }
  1357.  
  1358. /*
  1359. ===============================================================================
  1360.  
  1361. idAFEntity_Gibbable
  1362.  
  1363. ===============================================================================
  1364. */
  1365.  
  1366. const idEventDef EV_Gib( "gib", "s" );
  1367. const idEventDef EV_Gibbed( "<gibbed>" );
  1368.  
  1369. CLASS_DECLARATION( idAFEntity_Base, idAFEntity_Gibbable )
  1370.     EVENT( EV_Gib,        idAFEntity_Gibbable::Event_Gib )
  1371.     EVENT( EV_Gibbed,    idAFEntity_Base::Event_Remove )
  1372. END_CLASS
  1373.  
  1374.  
  1375. /*
  1376. ================
  1377. idAFEntity_Gibbable::idAFEntity_Gibbable
  1378. ================
  1379. */
  1380. idAFEntity_Gibbable::idAFEntity_Gibbable( void ) {
  1381.     skeletonModel = NULL;
  1382.     skeletonModelDefHandle = -1;
  1383.     gibbed = false;
  1384. }
  1385.  
  1386. /*
  1387. ================
  1388. idAFEntity_Gibbable::~idAFEntity_Gibbable
  1389. ================
  1390. */
  1391. idAFEntity_Gibbable::~idAFEntity_Gibbable() {
  1392.     if ( skeletonModelDefHandle != -1 ) {
  1393.         gameRenderWorld->FreeEntityDef( skeletonModelDefHandle );
  1394.         skeletonModelDefHandle = -1;
  1395.     }
  1396. }
  1397.  
  1398. /*
  1399. ================
  1400. idAFEntity_Gibbable::Save
  1401. ================
  1402. */
  1403. void idAFEntity_Gibbable::Save( idSaveGame *savefile ) const {
  1404.     savefile->WriteBool( gibbed );
  1405.     savefile->WriteBool( combatModel != NULL );
  1406. }
  1407.  
  1408. /*
  1409. ================
  1410. idAFEntity_Gibbable::Restore
  1411. ================
  1412. */
  1413. void idAFEntity_Gibbable::Restore( idRestoreGame *savefile ) {
  1414.     bool hasCombatModel;
  1415.  
  1416.     savefile->ReadBool( gibbed );
  1417.     savefile->ReadBool( hasCombatModel );
  1418.  
  1419.     InitSkeletonModel();
  1420.  
  1421.     if ( hasCombatModel ) {
  1422.         SetCombatModel();
  1423.         LinkCombat();
  1424.     }
  1425. }
  1426.  
  1427. /*
  1428. ================
  1429. idAFEntity_Gibbable::Spawn
  1430. ================
  1431. */
  1432. void idAFEntity_Gibbable::Spawn( void ) {
  1433.     InitSkeletonModel();
  1434.  
  1435.     gibbed = false;
  1436. }
  1437.  
  1438. /*
  1439. ================
  1440. idAFEntity_Gibbable::InitSkeletonModel
  1441. ================
  1442. */
  1443. void idAFEntity_Gibbable::InitSkeletonModel( void ) {
  1444.     const char *modelName;
  1445.     const idDeclModelDef *modelDef;
  1446.  
  1447.     skeletonModel = NULL;
  1448.     skeletonModelDefHandle = -1;
  1449.  
  1450.     modelName = spawnArgs.GetString( "model_gib" );
  1451.  
  1452.     modelDef = NULL;
  1453.     if ( modelName[0] != '\0' ) {
  1454.         modelDef = static_cast<const idDeclModelDef *>( declManager->FindType( DECL_MODELDEF, modelName, false ) );
  1455.         if ( modelDef ) {
  1456.             skeletonModel = modelDef->ModelHandle();
  1457.         } else {
  1458.             skeletonModel = renderModelManager->FindModel( modelName );
  1459.         }
  1460.         if ( skeletonModel != NULL && renderEntity.hModel != NULL ) {
  1461.             if ( skeletonModel->NumJoints() != renderEntity.hModel->NumJoints() ) {
  1462.                 gameLocal.Error( "gib model '%s' has different number of joints than model '%s'",
  1463.                                     skeletonModel->Name(), renderEntity.hModel->Name() );
  1464.             }
  1465.         }
  1466.     }
  1467. }
  1468.  
  1469. /*
  1470. ================
  1471. idAFEntity_Gibbable::Present
  1472. ================
  1473. */
  1474. void idAFEntity_Gibbable::Present( void ) {
  1475.     renderEntity_t skeleton;
  1476.  
  1477.     if ( !gameLocal.isNewFrame ) {
  1478.         return;
  1479.     }
  1480.  
  1481.     // don't present to the renderer if the entity hasn't changed
  1482.     if ( !( thinkFlags & TH_UPDATEVISUALS ) ) {
  1483.         return;
  1484.     }
  1485.  
  1486.     // update skeleton model
  1487.     if ( gibbed && !IsHidden() && skeletonModel != NULL ) {
  1488.         skeleton = renderEntity;
  1489.         skeleton.hModel = skeletonModel;
  1490.         // add to refresh list
  1491.         if ( skeletonModelDefHandle == -1 ) {
  1492.             skeletonModelDefHandle = gameRenderWorld->AddEntityDef( &skeleton );
  1493.         } else {
  1494.             gameRenderWorld->UpdateEntityDef( skeletonModelDefHandle, &skeleton );
  1495.         }
  1496.     }
  1497.  
  1498.     idEntity::Present();
  1499. }
  1500.  
  1501. /*
  1502. ================
  1503. idAFEntity_Gibbable::Damage
  1504. ================
  1505. */
  1506. void idAFEntity_Gibbable::Damage( idEntity *inflictor, idEntity *attacker, const idVec3 &dir, const char *damageDefName, const float damageScale, const int location ) {
  1507.     if ( !fl.takedamage ) {
  1508.         return;
  1509.     }
  1510.     idAFEntity_Base::Damage( inflictor, attacker, dir, damageDefName, damageScale, location );
  1511.     if ( health < -20 && spawnArgs.GetBool( "gib" ) ) {
  1512.         Gib( dir, damageDefName );
  1513.     }
  1514. }
  1515.  
  1516. /*
  1517. =====================
  1518. idAFEntity_Gibbable::SpawnGibs
  1519. =====================
  1520. */
  1521. void idAFEntity_Gibbable::SpawnGibs( const idVec3 &dir, const char *damageDefName ) {
  1522.     int i;
  1523.     bool gibNonSolid;
  1524.     idVec3 entityCenter, velocity;
  1525.     idList<idEntity *> list;
  1526.  
  1527.     assert( !gameLocal.isClient );
  1528.  
  1529. // RAVEN BEGIN
  1530. // ddynerman: added false as 2nd parameter, otherwise def will be created
  1531.     const idDict *damageDef = gameLocal.FindEntityDefDict( damageDefName, false );
  1532. // RAVEN END
  1533.     if ( !damageDef ) {
  1534.         gameLocal.Error( "Unknown damageDef '%s'", damageDefName );
  1535.     }
  1536.  
  1537.     // spawn gib articulated figures
  1538.     idAFEntity_Base::DropAFs( this, "gib", &list );
  1539.  
  1540.     // spawn gib items
  1541.     idMoveableItem::DropItems( this, "gib", &list );
  1542.  
  1543.     // blow out the gibs in the given direction away from the center of the entity
  1544.     entityCenter = GetPhysics()->GetAbsBounds().GetCenter();
  1545.     gibNonSolid = damageDef->GetBool( "gibNonSolid" );
  1546.     for ( i = 0; i < list.Num(); i++ ) {
  1547.         if ( gibNonSolid ) {
  1548.             list[i]->GetPhysics()->SetContents( 0 );
  1549.             list[i]->GetPhysics()->SetClipMask( 0 );
  1550.             list[i]->GetPhysics()->UnlinkClip();
  1551.             list[i]->GetPhysics()->PutToRest();
  1552.         } else {
  1553.             list[i]->GetPhysics()->SetContents( CONTENTS_CORPSE );
  1554.             list[i]->GetPhysics()->SetClipMask( CONTENTS_SOLID );
  1555.             velocity = list[i]->GetPhysics()->GetAbsBounds().GetCenter() - entityCenter;
  1556.             velocity.NormalizeFast();
  1557.             velocity += ( i & 1 ) ? dir : -dir;
  1558.             list[i]->GetPhysics()->SetLinearVelocity( velocity * 225.0f );
  1559.         }
  1560.         list[i]->GetRenderEntity()->noShadow = true;
  1561.         list[i]->GetRenderEntity()->shaderParms[ SHADERPARM_TIME_OF_DEATH ] = gameLocal.time * 0.001f;
  1562. // RAVEN BEGIN
  1563. // dluetscher: reduced the gib lifetime from 4. to 1.5
  1564.         list[i]->PostEventSec( &EV_Remove, 1.5f );
  1565. // RAVEN END
  1566.     }
  1567. }
  1568.  
  1569. /*
  1570. ============
  1571. idAFEntity_Gibbable::Gib
  1572. ============
  1573. */
  1574. void idAFEntity_Gibbable::Gib( const idVec3 &dir, const char *damageDefName ) {
  1575.     // only gib once
  1576.     if ( gibbed ) {
  1577.         return;
  1578.     }
  1579.  
  1580. // RAVEN BEGIN
  1581. // ddynerman: added false as 2nd parameter, otherwise def will be created
  1582.     const idDict *damageDef = gameLocal.FindEntityDefDict( damageDefName, false );
  1583. // RAVEN END
  1584.     if ( !damageDef ) {
  1585.         gameLocal.Error( "Unknown damageDef '%s'", damageDefName );
  1586.     }
  1587.  
  1588.     if ( damageDef->GetBool( "gibNonSolid" ) ) {
  1589.         GetAFPhysics()->SetContents( 0 );
  1590.         GetAFPhysics()->SetClipMask( 0 );
  1591.         GetAFPhysics()->UnlinkClip();
  1592.         GetAFPhysics()->PutToRest();
  1593.     } else {
  1594.         GetAFPhysics()->SetContents( CONTENTS_CORPSE );
  1595.         GetAFPhysics()->SetClipMask( CONTENTS_SOLID );
  1596.     }
  1597.  
  1598.     UnlinkCombat();
  1599. // RAVEN BEGIN
  1600. // mekberg: changed from g_bloodEffects to g_decals
  1601.     if ( g_decals.GetBool() ) {
  1602. // RAVEN END
  1603.         if ( gameLocal.time > gameLocal.GetGibTime() ) {
  1604.             gameLocal.SetGibTime( gameLocal.time + GIB_DELAY );
  1605.             SpawnGibs( dir, damageDefName );
  1606.             renderEntity.noShadow = true;
  1607.             renderEntity.shaderParms[ SHADERPARM_TIME_OF_DEATH ] = gameLocal.time * 0.001f;
  1608.             StartSound( "snd_gibbed", SND_CHANNEL_ANY, 0, false, NULL );
  1609.             gibbed = true;
  1610.         }
  1611.     } else {
  1612.         gibbed = true;
  1613.     }
  1614.  
  1615. // RAVEN BEGIN
  1616. // bdube: default is to remove the character immediately
  1617.     PostEventSec( &EV_Gibbed, spawnArgs.GetFloat ( "gibRemoveDelay", "0" ) );
  1618. // RAVEN END
  1619. }
  1620.  
  1621. /*
  1622. ============
  1623. idAFEntity_Gibbable::Event_Gib
  1624. ============
  1625. */
  1626. void idAFEntity_Gibbable::Event_Gib( const char *damageDefName ) {
  1627.     Gib( idVec3( 0, 0, 1 ), damageDefName );
  1628. }
  1629.  
  1630. /*
  1631. ===============================================================================
  1632.  
  1633.   idAFEntity_Generic
  1634.  
  1635. ===============================================================================
  1636. */
  1637.  
  1638. CLASS_DECLARATION( idAFEntity_Gibbable, idAFEntity_Generic )
  1639.     EVENT( EV_Activate,            idAFEntity_Generic::Event_Activate )
  1640. END_CLASS
  1641.  
  1642. /*
  1643. ================
  1644. idAFEntity_Generic::idAFEntity_Generic
  1645. ================
  1646. */
  1647. idAFEntity_Generic::idAFEntity_Generic( void ) {
  1648.     keepRunningPhysics = false;
  1649. }
  1650.  
  1651. /*
  1652. ================
  1653. idAFEntity_Generic::~idAFEntity_Generic
  1654. ================
  1655. */
  1656. idAFEntity_Generic::~idAFEntity_Generic( void ) {
  1657. }
  1658.  
  1659. /*
  1660. ================
  1661. idAFEntity_Generic::Save
  1662. ================
  1663. */
  1664. void idAFEntity_Generic::Save( idSaveGame *savefile ) const {
  1665.     savefile->WriteBool( keepRunningPhysics );
  1666. }
  1667.  
  1668. /*
  1669. ================
  1670. idAFEntity_Generic::Restore
  1671. ================
  1672. */
  1673. void idAFEntity_Generic::Restore( idRestoreGame *savefile ) {
  1674.     savefile->ReadBool( keepRunningPhysics );
  1675. }
  1676.  
  1677. /*
  1678. ================
  1679. idAFEntity_Generic::Think
  1680. ================
  1681. */
  1682. void idAFEntity_Generic::Think( void ) {
  1683.     idAFEntity_Base::Think();
  1684.  
  1685.     if ( keepRunningPhysics ) {
  1686.         BecomeActive( TH_PHYSICS );
  1687.     }
  1688. }
  1689.  
  1690. /*
  1691. ================
  1692. idAFEntity_Generic::Spawn
  1693. ================
  1694. */
  1695. void idAFEntity_Generic::Spawn( void ) {
  1696.     if ( !LoadAF() ) {
  1697.         gameLocal.Error( "Couldn't load af file on entity '%s'", name.c_str() );
  1698.     }
  1699.  
  1700.     SetCombatModel();
  1701.  
  1702.     SetPhysics( af.GetPhysics() );
  1703.  
  1704. // RAVEN BEGIN
  1705. // kfuller: we just put the guy to rest so don't be affected by an attractor
  1706. /*
  1707.     const char *attractor = spawnArgs.GetString("attractor");
  1708.     if (attractor && attractor[0]) {
  1709.         rvRagdollAttractor *attractorEnt = dynamic_cast<rvRagdollAttractor*>(gameLocal.FindEntity(attractor));
  1710.         if (attractorEnt) {
  1711.             attractorEnt->RemoveAttractee(entityNumber);
  1712.         } else {
  1713.             gameLocal.Warning("idAFEntity::LoadAF -- failed to find attractor '%s'", attractor);
  1714.         }
  1715.     }
  1716. */
  1717. // RAVEN END
  1718.  
  1719.     af.GetPhysics()->PutToRest();
  1720.     if ( !spawnArgs.GetBool( "nodrop", "0" ) ) {
  1721.         af.GetPhysics()->Activate();
  1722.     }
  1723.  
  1724.     fl.takedamage = true;
  1725. }
  1726.  
  1727. /*
  1728. ================
  1729. idAFEntity_Generic::Event_Activate
  1730. ================
  1731. */
  1732. void idAFEntity_Generic::Event_Activate( idEntity *activator ) {
  1733.     float delay;
  1734.     idVec3 init_velocity, init_avelocity;
  1735.  
  1736.     Show();
  1737.  
  1738.     af.GetPhysics()->EnableImpact();
  1739.     af.GetPhysics()->Activate();
  1740.  
  1741.     spawnArgs.GetVector( "init_velocity", "0 0 0", init_velocity );
  1742.     spawnArgs.GetVector( "init_avelocity", "0 0 0", init_avelocity );
  1743.  
  1744.     delay = spawnArgs.GetFloat( "init_velocityDelay", "0" );
  1745.     if ( delay == 0.0f ) {
  1746.         af.GetPhysics()->SetLinearVelocity( init_velocity );
  1747.     } else {
  1748.         PostEventSec( &EV_SetLinearVelocity, delay, init_velocity );
  1749.     }
  1750.  
  1751.     delay = spawnArgs.GetFloat( "init_avelocityDelay", "0" );
  1752.     if ( delay == 0.0f ) {
  1753.         af.GetPhysics()->SetAngularVelocity( init_avelocity );
  1754.     } else {
  1755.         PostEventSec( &EV_SetAngularVelocity, delay, init_avelocity );
  1756.     }
  1757. }
  1758.  
  1759.  
  1760. /*
  1761. ===============================================================================
  1762.  
  1763.   idAFEntity_WithAttachedHead
  1764.  
  1765. ===============================================================================
  1766. */
  1767.  
  1768. CLASS_DECLARATION( idAFEntity_Gibbable, idAFEntity_WithAttachedHead )
  1769.     EVENT( EV_Gib,                idAFEntity_WithAttachedHead::Event_Gib )
  1770.     EVENT( EV_Activate,            idAFEntity_WithAttachedHead::Event_Activate )
  1771. END_CLASS
  1772.  
  1773. /*
  1774. ================
  1775. idAFEntity_WithAttachedHead::idAFEntity_WithAttachedHead
  1776. ================
  1777. */
  1778. idAFEntity_WithAttachedHead::idAFEntity_WithAttachedHead() {
  1779.     head = NULL;
  1780. }
  1781.  
  1782. /*
  1783. ================
  1784. idAFEntity_WithAttachedHead::~idAFEntity_WithAttachedHead
  1785. ================
  1786. */
  1787. idAFEntity_WithAttachedHead::~idAFEntity_WithAttachedHead() {
  1788.     if ( head.GetEntity() ) {
  1789.         head.GetEntity()->ClearBody();
  1790.         head.GetEntity()->PostEventMS( &EV_Remove, 0 );
  1791.     }
  1792. }
  1793.  
  1794. /*
  1795. ================
  1796. idAFEntity_WithAttachedHead::Spawn
  1797. ================
  1798. */
  1799. void idAFEntity_WithAttachedHead::Spawn( void ) {
  1800.     SetupHead();
  1801.  
  1802.     LoadAF();
  1803.  
  1804.     SetCombatModel();
  1805.  
  1806.     SetPhysics( af.GetPhysics() );
  1807.  
  1808.     af.GetPhysics()->PutToRest();
  1809.     if ( !spawnArgs.GetBool( "nodrop", "0" ) ) {
  1810.         af.GetPhysics()->Activate();
  1811.     }
  1812.  
  1813.     fl.takedamage = true;
  1814.  
  1815.     if ( head.GetEntity() ) {
  1816.         int anim = head.GetEntity()->GetAnimator()->GetAnim( "dead" );
  1817.  
  1818.         if ( anim ) {
  1819. // RAVEN BEGIN
  1820.             frameBlend_t frameBlend = { 0, 0, 0, 1.0f, 0 };
  1821.             head.GetEntity()->GetAnimator()->SetFrame( ANIMCHANNEL_ALL, anim, frameBlend );
  1822. // RAVEN END
  1823.         }
  1824.     }
  1825.  
  1826.  
  1827.     idEntity *headEnt = head.GetEntity();
  1828.     idAnimator *headAnimator;
  1829.     if ( headEnt ) {
  1830.         headAnimator = headEnt->GetAnimator();
  1831.     } else {
  1832.         headAnimator = &animator;
  1833.     }
  1834. }
  1835.  
  1836. /*
  1837. ================
  1838. idAFEntity_WithAttachedHead::Save
  1839. ================
  1840. */
  1841. void idAFEntity_WithAttachedHead::Save( idSaveGame *savefile ) const {
  1842.     head.Save( savefile );
  1843. }
  1844.  
  1845. /*
  1846. ================
  1847. idAFEntity_WithAttachedHead::Restore
  1848. ================
  1849. */
  1850. void idAFEntity_WithAttachedHead::Restore( idRestoreGame *savefile ) {
  1851.     head.Restore( savefile );
  1852. }
  1853.  
  1854. /*
  1855. ================
  1856. idAFEntity_WithAttachedHead::SetupHead
  1857. ================
  1858. */
  1859. void idAFEntity_WithAttachedHead::SetupHead( const char* headDefName ) {
  1860.     idAFAttachment        *headEnt;
  1861.     idStr                jointName;
  1862.     jointHandle_t        joint;
  1863.     const idKeyValue    *sndKV;
  1864.  
  1865.     if ( gameLocal.isClient && head.GetEntity() == NULL ) {
  1866.         return;
  1867.     }
  1868.  
  1869.     // If we don't pass in a specific head model, try looking it up
  1870.     if( !headDefName[ 0 ] ) {
  1871.         headDefName = spawnArgs.GetString( "def_head", "" );        
  1872.     } 
  1873.  
  1874.     if ( headDefName[ 0 ] ) {
  1875.         jointName = spawnArgs.GetString( "joint_head" );
  1876.         joint = animator.GetJointHandle( jointName );
  1877.         if ( joint == INVALID_JOINT ) {
  1878.             gameLocal.Error( "Joint '%s' not found for 'joint_head' on '%s'", jointName.c_str(), name.c_str() );
  1879.         }
  1880.  
  1881.         // copy any sounds in case we have frame commands on the head
  1882.         idDict    args;
  1883.         sndKV = spawnArgs.MatchPrefix( "snd_", NULL );
  1884.         while( sndKV ) {
  1885.             args.Set( sndKV->GetKey(), sndKV->GetValue() );
  1886.             sndKV = spawnArgs.MatchPrefix( "snd_", sndKV );
  1887.         }
  1888.  
  1889.         if ( !gameLocal.isClient ) {
  1890.             args.Set( "classname", headDefName );
  1891.             if( !gameLocal.SpawnEntityDef( args, ( idEntity ** )&headEnt ) ) {
  1892.                 gameLocal.Warning( "idActor::SetupHead() - Unknown head model '%s'\n", headDefName );
  1893.                 return;
  1894.             }
  1895.             headEnt->spawnArgs.Set( "classname", headDefName );
  1896.  
  1897.             headEnt->SetName( va( "%s_head", name.c_str() ) );
  1898.             headEnt->SetBody ( this, headDefName, joint );
  1899.             head = headEnt;
  1900.         } else {
  1901.             // we got our spawnid from the server
  1902.             headEnt = head.GetEntity();
  1903.             headEnt->GetRenderEntity()->suppressSurfaceInViewID = entityNumber + 1;
  1904.         }
  1905.         
  1906.         headEnt->BindToJoint( this, joint, true );
  1907.         headEnt->GetPhysics()->SetOrigin( vec3_origin );        
  1908.         headEnt->GetPhysics()->SetAxis( mat3_identity );
  1909.         
  1910.         head->InitCopyJoints ( );
  1911.     } else if ( head ) {
  1912.         head->PostEventMS( &EV_Remove, 0 );
  1913.         head = NULL;
  1914.     }
  1915. }
  1916.  
  1917. /*
  1918. ================
  1919. idAFEntity_WithAttachedHead::Think
  1920. ================
  1921. */
  1922. void idAFEntity_WithAttachedHead::Think( void ) {
  1923.     idAFEntity_Base::Think();
  1924. }
  1925.  
  1926. /*
  1927. ================
  1928. idAFEntity_WithAttachedHead::LinkCombat
  1929. ================
  1930. */
  1931. void idAFEntity_WithAttachedHead::LinkCombat( void ) {
  1932.     idAFAttachment *headEnt;
  1933.  
  1934.     if ( fl.hidden ) {
  1935.         return;
  1936.     }
  1937.  
  1938.     if ( combatModel ) {
  1939. // RAVEN BEGIN
  1940. // ddynerman: multiple clip worlds
  1941.         combatModel->Link( this, 0, renderEntity.origin, renderEntity.axis, modelDefHandle );
  1942. // RAVEN END
  1943.     }
  1944.     headEnt = head.GetEntity();
  1945.     if ( headEnt ) {
  1946.         headEnt->LinkCombat();
  1947.     }
  1948. }
  1949.  
  1950. /*
  1951. ================
  1952. idAFEntity_WithAttachedHead::UnlinkCombat
  1953. ================
  1954. */
  1955. void idAFEntity_WithAttachedHead::UnlinkCombat( void ) {
  1956.     idAFAttachment *headEnt;
  1957.  
  1958.     if ( combatModel ) {
  1959.         combatModel->Unlink();
  1960.     }
  1961.     headEnt = head.GetEntity();
  1962.     if ( headEnt ) {
  1963.         headEnt->UnlinkCombat();
  1964.     }
  1965. }
  1966.  
  1967. /*
  1968. ================
  1969. idAFEntity_WithAttachedHead::Hide
  1970. ================
  1971. */
  1972. void idAFEntity_WithAttachedHead::Hide( void ) {
  1973.     idAFEntity_Base::Hide();
  1974.     if ( head.GetEntity() ) {
  1975.         head.GetEntity()->Hide();
  1976.     }
  1977.     UnlinkCombat();
  1978. }
  1979.  
  1980. /*
  1981. ================
  1982. idAFEntity_WithAttachedHead::Show
  1983. ================
  1984. */
  1985. void idAFEntity_WithAttachedHead::Show( void ) {
  1986.     idAFEntity_Base::Show();
  1987.     if ( head.GetEntity() ) {
  1988.         head.GetEntity()->Show();
  1989.     }
  1990.     LinkCombat();
  1991. }
  1992.  
  1993. /*
  1994. ================
  1995. idAFEntity_WithAttachedHead::ProjectOverlay
  1996. ================
  1997. */
  1998. void idAFEntity_WithAttachedHead::ProjectOverlay( const idVec3 &origin, const idVec3 &dir, float size, const char *material ) {
  1999.  
  2000.     idEntity::ProjectOverlay( origin, dir, size, material );
  2001.  
  2002.     if ( head.GetEntity() ) {
  2003.         head.GetEntity()->ProjectOverlay( origin, dir, size, material );
  2004.     }
  2005. }
  2006.  
  2007. /*
  2008. ============
  2009. idAFEntity_WithAttachedHead::Gib
  2010. ============
  2011. */
  2012. void idAFEntity_WithAttachedHead::Gib( const idVec3 &dir, const char *damageDefName ) {
  2013.     // only gib once
  2014.     if ( gibbed ) {
  2015.         return;
  2016.     }
  2017.     idAFEntity_Gibbable::Gib( dir, damageDefName );
  2018.     if ( head.GetEntity() ) {
  2019.         head.GetEntity()->Hide();
  2020.     }
  2021. }
  2022.  
  2023. /*
  2024. ============
  2025. idAFEntity_WithAttachedHead::Event_Gib
  2026. ============
  2027. */
  2028. void idAFEntity_WithAttachedHead::Event_Gib( const char *damageDefName ) {
  2029.     Gib( idVec3( 0, 0, 1 ), damageDefName );
  2030. }
  2031.  
  2032. /*
  2033. ================
  2034. idAFEntity_WithAttachedHead::Event_Activate
  2035. ================
  2036. */
  2037. void idAFEntity_WithAttachedHead::Event_Activate( idEntity *activator ) {
  2038.     float delay;
  2039.     idVec3 init_velocity, init_avelocity;
  2040.  
  2041.     Show();
  2042.  
  2043.     af.GetPhysics()->EnableImpact();
  2044.     af.GetPhysics()->Activate();
  2045.  
  2046.     spawnArgs.GetVector( "init_velocity", "0 0 0", init_velocity );
  2047.     spawnArgs.GetVector( "init_avelocity", "0 0 0", init_avelocity );
  2048.  
  2049.     delay = spawnArgs.GetFloat( "init_velocityDelay", "0" );
  2050.     if ( delay == 0.0f ) {
  2051.         af.GetPhysics()->SetLinearVelocity( init_velocity );
  2052.     } else {
  2053.         PostEventSec( &EV_SetLinearVelocity, delay, init_velocity );
  2054.     }
  2055.  
  2056.     delay = spawnArgs.GetFloat( "init_avelocityDelay", "0" );
  2057.     if ( delay == 0.0f ) {
  2058.         af.GetPhysics()->SetAngularVelocity( init_avelocity );
  2059.     } else {
  2060.         PostEventSec( &EV_SetAngularVelocity, delay, init_avelocity );
  2061.     }
  2062. }
  2063.  
  2064.  
  2065. /*
  2066. ===============================================================================
  2067.  
  2068.   idAFEntity_Vehicle
  2069.  
  2070. ===============================================================================
  2071. */
  2072.  
  2073. CLASS_DECLARATION( idAFEntity_Base, idAFEntity_Vehicle )
  2074. END_CLASS
  2075.  
  2076. /*
  2077. ================
  2078. idAFEntity_Vehicle::idAFEntity_Vehicle
  2079. ================
  2080. */
  2081. idAFEntity_Vehicle::idAFEntity_Vehicle( void ) {
  2082.     player                = NULL;
  2083.     eyesJoint            = INVALID_JOINT;
  2084.     steeringWheelJoint    = INVALID_JOINT;
  2085.     wheelRadius            = 0.0f;
  2086.     steerAngle            = 0.0f;
  2087.     steerSpeed            = 0.0f;
  2088. //    dustSmoke            = NULL;
  2089. }
  2090.  
  2091. /*
  2092. ================
  2093. idAFEntity_Vehicle::Spawn
  2094. ================
  2095. */
  2096. void idAFEntity_Vehicle::Spawn( void ) {
  2097.     const char *eyesJointName = spawnArgs.GetString( "eyesJoint", "eyes" );
  2098.     const char *steeringWheelJointName = spawnArgs.GetString( "steeringWheelJoint", "steeringWheel" );
  2099.  
  2100.     LoadAF();
  2101.  
  2102.     SetCombatModel();
  2103.  
  2104.     SetPhysics( af.GetPhysics() );
  2105.  
  2106.     fl.takedamage = true;
  2107.  
  2108.     if ( !eyesJointName[0] ) {
  2109.         gameLocal.Error( "idAFEntity_Vehicle '%s' no eyes joint specified", name.c_str() );
  2110.     }
  2111.     eyesJoint = animator.GetJointHandle( eyesJointName );
  2112.     if ( !steeringWheelJointName[0] ) {
  2113.         gameLocal.Error( "idAFEntity_Vehicle '%s' no steering wheel joint specified", name.c_str() );
  2114.     }
  2115.     steeringWheelJoint = animator.GetJointHandle( steeringWheelJointName );
  2116.  
  2117.     spawnArgs.GetFloat( "wheelRadius", "20", wheelRadius );
  2118.     spawnArgs.GetFloat( "steerSpeed", "5", steerSpeed ); 
  2119.  
  2120.     player = NULL;
  2121.     steerAngle = 0.0f;
  2122.  
  2123. /*
  2124.     const char *smokeName = spawnArgs.GetString( "smoke_vehicle_dust", "muzzlesmoke" );
  2125.     if ( *smokeName != '\0' ) {
  2126.         dustSmoke = static_cast<const idDeclParticle *>( declManager->FindType( DECL_PARTICLE, smokeName ) );
  2127.     }
  2128. */
  2129. }
  2130.  
  2131. /*
  2132. ================
  2133. idAFEntity_Vehicle::Use
  2134. ================
  2135. */
  2136. void idAFEntity_Vehicle::Use( idPlayer *other ) {
  2137.     idVec3 origin;
  2138.     idMat3 axis;
  2139.  
  2140.     if ( player ) {
  2141.         if ( player == other ) {
  2142.             other->Unbind();
  2143.             player = NULL;
  2144.  
  2145.             af.GetPhysics()->SetComeToRest( true );
  2146.         }
  2147.     }
  2148.     else {
  2149.         player = other;
  2150.         animator.GetJointTransform( eyesJoint, gameLocal.time, origin, axis );
  2151.         origin = renderEntity.origin + origin * renderEntity.axis;
  2152.         player->GetPhysics()->SetOrigin( origin );
  2153.         player->BindToBody( this, 0, true );
  2154.  
  2155.         af.GetPhysics()->SetComeToRest( false );
  2156.         af.GetPhysics()->Activate();
  2157.     }
  2158. }
  2159.  
  2160. /*
  2161. ================
  2162. idAFEntity_Vehicle::GetSteerAngle
  2163. ================
  2164. */
  2165. float idAFEntity_Vehicle::GetSteerAngle( void ) {
  2166.     float idealSteerAngle, angleDelta;
  2167.  
  2168.     idealSteerAngle = player->usercmd.rightmove * ( 30.0f / 128.0f );
  2169.     angleDelta = idealSteerAngle - steerAngle;
  2170.  
  2171.     if ( angleDelta > steerSpeed ) {
  2172.         steerAngle += steerSpeed;
  2173.     } else if ( angleDelta < -steerSpeed ) {
  2174.         steerAngle -= steerSpeed;
  2175.     } else {
  2176.         steerAngle = idealSteerAngle;
  2177.     }
  2178.  
  2179.     return steerAngle;
  2180. }
  2181.  
  2182.  
  2183. /*
  2184. ===============================================================================
  2185.  
  2186.   idAFEntity_VehicleFourWheels
  2187.  
  2188. ===============================================================================
  2189. */
  2190.  
  2191. CLASS_DECLARATION( idAFEntity_Vehicle, idAFEntity_VehicleFourWheels )
  2192. END_CLASS
  2193.  
  2194.  
  2195. /*
  2196. ================
  2197. idAFEntity_VehicleFourWheels::idAFEntity_VehicleFourWheels
  2198. ================
  2199. */
  2200. idAFEntity_VehicleFourWheels::idAFEntity_VehicleFourWheels( void ) {
  2201.     int i;
  2202.  
  2203.     for ( i = 0; i < 4; i++ ) {
  2204.         wheels[i]        = NULL;
  2205.         wheelJoints[i]    = INVALID_JOINT;
  2206.         wheelAngles[i]    = 0.0f;
  2207.     }
  2208.     steering[0]            = NULL;
  2209.     steering[1]            = NULL;
  2210. }
  2211.  
  2212. /*
  2213. ================
  2214. idAFEntity_VehicleFourWheels::Spawn
  2215. ================
  2216. */
  2217. void idAFEntity_VehicleFourWheels::Spawn( void ) {
  2218.     int i;
  2219.     static const char *wheelBodyKeys[] = {
  2220.         "wheelBodyFrontLeft",
  2221.         "wheelBodyFrontRight",
  2222.         "wheelBodyRearLeft",
  2223.         "wheelBodyRearRight"
  2224.     };
  2225.     static const char *wheelJointKeys[] = {
  2226.         "wheelJointFrontLeft",
  2227.         "wheelJointFrontRight",
  2228.         "wheelJointRearLeft",
  2229.         "wheelJointRearRight"
  2230.     };
  2231.     static const char *steeringHingeKeys[] = {
  2232.         "steeringHingeFrontLeft",
  2233.         "steeringHingeFrontRight",
  2234.     };
  2235.  
  2236.     const char *wheelBodyName, *wheelJointName, *steeringHingeName;
  2237.  
  2238.     for ( i = 0; i < 4; i++ ) {
  2239.         wheelBodyName = spawnArgs.GetString( wheelBodyKeys[i], "" );
  2240.         if ( !wheelBodyName[0] ) {
  2241.             gameLocal.Error( "idAFEntity_VehicleFourWheels '%s' no '%s' specified", name.c_str(), wheelBodyKeys[i] );
  2242.         }
  2243.         wheels[i] = af.GetPhysics()->GetBody( wheelBodyName );
  2244.         if ( !wheels[i] ) {
  2245.             gameLocal.Error( "idAFEntity_VehicleFourWheels '%s' can't find wheel body '%s'", name.c_str(), wheelBodyName );
  2246.         }
  2247.         wheelJointName = spawnArgs.GetString( wheelJointKeys[i], "" );
  2248.         if ( !wheelJointName[0] ) {
  2249.             gameLocal.Error( "idAFEntity_VehicleFourWheels '%s' no '%s' specified", name.c_str(), wheelJointKeys[i] );
  2250.         }
  2251.         wheelJoints[i] = animator.GetJointHandle( wheelJointName );
  2252.         if ( wheelJoints[i] == INVALID_JOINT ) {
  2253.             gameLocal.Error( "idAFEntity_VehicleFourWheels '%s' can't find wheel joint '%s'", name.c_str(), wheelJointName );
  2254.         }
  2255.     }
  2256.  
  2257.     for ( i = 0; i < 2; i++ ) {
  2258.         steeringHingeName = spawnArgs.GetString( steeringHingeKeys[i], "" );
  2259.         if ( !steeringHingeName[0] ) {
  2260.             gameLocal.Error( "idAFEntity_VehicleFourWheels '%s' no '%s' specified", name.c_str(), steeringHingeKeys[i] );
  2261.         }
  2262.         steering[i] = static_cast<idAFConstraint_Hinge *>(af.GetPhysics()->GetConstraint( steeringHingeName ));
  2263.         if ( !steering[i] ) {
  2264.             gameLocal.Error( "idAFEntity_VehicleFourWheels '%s': can't find steering hinge '%s'", name.c_str(), steeringHingeName );
  2265.         }
  2266.     }
  2267.  
  2268.     memset( wheelAngles, 0, sizeof( wheelAngles ) );
  2269.     BecomeActive( TH_THINK );
  2270. }
  2271.  
  2272. /*
  2273. ================
  2274. idAFEntity_VehicleFourWheels::Think
  2275. ================
  2276. */
  2277. void idAFEntity_VehicleFourWheels::Think( void ) {
  2278.     int i;
  2279.     float force = 0.0f, velocity = 0.0f, steerAngle = 0.0f;
  2280.     idVec3 origin;
  2281.     idMat3 axis;
  2282.     idRotation rotation;
  2283.  
  2284.     if ( thinkFlags & TH_THINK ) {
  2285.  
  2286.         if ( player ) {
  2287.             // capture the input from a player
  2288.             velocity = g_vehicleVelocity.GetFloat();
  2289.             if ( player->usercmd.forwardmove < 0 ) {
  2290.                 velocity = -velocity;
  2291.             }
  2292.             force = idMath::Fabs( player->usercmd.forwardmove * g_vehicleForce.GetFloat() ) * (1.0f / 128.0f);
  2293.             steerAngle = GetSteerAngle();
  2294.         }
  2295.  
  2296.         // update the wheel motor force
  2297.         for ( i = 0; i < 2; i++ ) {
  2298.             wheels[2+i]->SetContactMotorVelocity( velocity );
  2299.             wheels[2+i]->SetContactMotorForce( force );
  2300.         }
  2301.  
  2302.         // adjust wheel velocity for better steering because there are no differentials between the wheels
  2303.         if ( steerAngle < 0.0f ) {
  2304.             wheels[2]->SetContactMotorVelocity( velocity * 0.5f );
  2305.         }
  2306.         else if ( steerAngle > 0.0f ) {
  2307.             wheels[3]->SetContactMotorVelocity( velocity * 0.5f );
  2308.         }
  2309.  
  2310.         // update the wheel steering
  2311.         steering[0]->SetSteerAngle( steerAngle );
  2312.         steering[1]->SetSteerAngle( steerAngle );
  2313.         for ( i = 0; i < 2; i++ ) {
  2314.             steering[i]->SetSteerSpeed( 3.0f );
  2315.         }
  2316.  
  2317.         // update the steering wheel
  2318.         animator.GetJointTransform( steeringWheelJoint, gameLocal.time, origin, axis );
  2319.         rotation.SetVec( axis[2] );
  2320.         rotation.SetAngle( -steerAngle );
  2321.         animator.SetJointAxis( steeringWheelJoint, JOINTMOD_WORLD, rotation.ToMat3() );
  2322.  
  2323.         // run the physics
  2324.         RunPhysics();
  2325.  
  2326.         // rotate the wheels visually
  2327.         for ( i = 0; i < 4; i++ ) {
  2328.             if ( force == 0.0f ) {
  2329.                 velocity = wheels[i]->GetLinearVelocity() * wheels[i]->GetWorldAxis()[0];
  2330.             }
  2331. // RAVEN BEGIN
  2332. // bdube: msec to GetMsec
  2333.             wheelAngles[i] += velocity * MS2SEC( gameLocal.GetMSec() ) / wheelRadius;
  2334. // RAVEN END
  2335.             // give the wheel joint an additional rotation about the wheel axis
  2336.             rotation.SetAngle( RAD2DEG( wheelAngles[i] ) );
  2337.             axis = af.GetPhysics()->GetAxis( 0 );
  2338.             rotation.SetVec( (wheels[i]->GetWorldAxis() * axis.Transpose())[2] );
  2339.             animator.SetJointAxis( wheelJoints[i], JOINTMOD_WORLD, rotation.ToMat3() );
  2340.         }
  2341.  
  2342. /*
  2343.         // spawn dust particle effects
  2344.         if ( force != 0.0f && !( gameLocal.framenum & 7 ) ) {
  2345.             int numContacts;
  2346.             idAFConstraint_Contact *contacts[2];
  2347.             for ( i = 0; i < 4; i++ ) {
  2348.                 numContacts = af.GetPhysics()->GetBodyContactConstraints( wheels[i]->GetClipModel()->GetId(), contacts, 2 );
  2349.                 for ( int j = 0; j < numContacts; j++ ) {
  2350.                     gameLocal.smokeParticles->EmitSmoke( dustSmoke, gameLocal.time, gameLocal.random.RandomFloat(), contacts[j]->GetContact().point, contacts[j]->GetContact().normal.ToMat3() );
  2351.                 }
  2352.             }
  2353.         }
  2354. */
  2355.     }
  2356.  
  2357.     UpdateAnimation();
  2358.     if ( thinkFlags & TH_UPDATEVISUALS ) {
  2359.         Present();
  2360.         LinkCombat();
  2361.     }
  2362. }
  2363.  
  2364.  
  2365. /*
  2366. ===============================================================================
  2367.  
  2368.   idAFEntity_VehicleSixWheels
  2369.  
  2370. ===============================================================================
  2371. */
  2372.  
  2373. CLASS_DECLARATION( idAFEntity_Vehicle, idAFEntity_VehicleSixWheels )
  2374. END_CLASS
  2375.  
  2376.     /*
  2377. ================
  2378. idAFEntity_VehicleSixWheels::idAFEntity_VehicleSixWheels
  2379. ================
  2380. */
  2381. idAFEntity_VehicleSixWheels::idAFEntity_VehicleSixWheels( void ) {
  2382.     int i;
  2383.  
  2384.     for ( i = 0; i < 6; i++ ) {
  2385.         wheels[i]        = NULL;
  2386.         wheelJoints[i]    = INVALID_JOINT;
  2387.         wheelAngles[i]    = 0.0f;
  2388.     }
  2389.     steering[0]            = NULL;
  2390.     steering[1]            = NULL;
  2391.     steering[2]            = NULL;
  2392.     steering[3]            = NULL;
  2393. }
  2394.  
  2395. /*
  2396. ================
  2397. idAFEntity_VehicleSixWheels::Spawn
  2398. ================
  2399. */
  2400. void idAFEntity_VehicleSixWheels::Spawn( void ) {
  2401.     int i;
  2402.     static const char *wheelBodyKeys[] = {
  2403.         "wheelBodyFrontLeft",
  2404.         "wheelBodyFrontRight",
  2405.         "wheelBodyMiddleLeft",
  2406.         "wheelBodyMiddleRight",
  2407.         "wheelBodyRearLeft",
  2408.         "wheelBodyRearRight"
  2409.     };
  2410.     static const char *wheelJointKeys[] = {
  2411.         "wheelJointFrontLeft",
  2412.         "wheelJointFrontRight",
  2413.         "wheelJointMiddleLeft",
  2414.         "wheelJointMiddleRight",
  2415.         "wheelJointRearLeft",
  2416.         "wheelJointRearRight"
  2417.     };
  2418.     static const char *steeringHingeKeys[] = {
  2419.         "steeringHingeFrontLeft",
  2420.         "steeringHingeFrontRight",
  2421.         "steeringHingeRearLeft",
  2422.         "steeringHingeRearRight"
  2423.     };
  2424.  
  2425.     const char *wheelBodyName, *wheelJointName, *steeringHingeName;
  2426.  
  2427.     for ( i = 0; i < 6; i++ ) {
  2428.         wheelBodyName = spawnArgs.GetString( wheelBodyKeys[i], "" );
  2429.         if ( !wheelBodyName[0] ) {
  2430.             gameLocal.Error( "idAFEntity_VehicleSixWheels '%s' no '%s' specified", name.c_str(), wheelBodyKeys[i] );
  2431.         }
  2432.         wheels[i] = af.GetPhysics()->GetBody( wheelBodyName );
  2433.         if ( !wheels[i] ) {
  2434.             gameLocal.Error( "idAFEntity_VehicleSixWheels '%s' can't find wheel body '%s'", name.c_str(), wheelBodyName );
  2435.         }
  2436.         wheelJointName = spawnArgs.GetString( wheelJointKeys[i], "" );
  2437.         if ( !wheelJointName[0] ) {
  2438.             gameLocal.Error( "idAFEntity_VehicleSixWheels '%s' no '%s' specified", name.c_str(), wheelJointKeys[i] );
  2439.         }
  2440.         wheelJoints[i] = animator.GetJointHandle( wheelJointName );
  2441.         if ( wheelJoints[i] == INVALID_JOINT ) {
  2442.             gameLocal.Error( "idAFEntity_VehicleSixWheels '%s' can't find wheel joint '%s'", name.c_str(), wheelJointName );
  2443.         }
  2444.     }
  2445.  
  2446.     for ( i = 0; i < 4; i++ ) {
  2447.         steeringHingeName = spawnArgs.GetString( steeringHingeKeys[i], "" );
  2448.         if ( !steeringHingeName[0] ) {
  2449.             gameLocal.Error( "idAFEntity_VehicleSixWheels '%s' no '%s' specified", name.c_str(), steeringHingeKeys[i] );
  2450.         }
  2451.         steering[i] = static_cast<idAFConstraint_Hinge *>(af.GetPhysics()->GetConstraint( steeringHingeName ));
  2452.         if ( !steering[i] ) {
  2453.             gameLocal.Error( "idAFEntity_VehicleSixWheels '%s': can't find steering hinge '%s'", name.c_str(), steeringHingeName );
  2454.         }
  2455.     }
  2456.  
  2457.     memset( wheelAngles, 0, sizeof( wheelAngles ) );
  2458.     BecomeActive( TH_THINK );
  2459. }
  2460.  
  2461. /*
  2462. ================
  2463. idAFEntity_VehicleSixWheels::Think
  2464. ================
  2465. */
  2466. void idAFEntity_VehicleSixWheels::Think( void ) {
  2467.     int i;
  2468.     float force = 0.0f, velocity = 0.0f, steerAngle = 0.0f;
  2469.     idVec3 origin;
  2470.     idMat3 axis;
  2471.     idRotation rotation;
  2472.  
  2473.     if ( thinkFlags & TH_THINK ) {
  2474.  
  2475.         if ( player ) {
  2476.             // capture the input from a player
  2477.             velocity = g_vehicleVelocity.GetFloat();
  2478.             if ( player->usercmd.forwardmove < 0 ) {
  2479.                 velocity = -velocity;
  2480.             }
  2481.             force = idMath::Fabs( player->usercmd.forwardmove * g_vehicleForce.GetFloat() ) * (1.0f / 128.0f);
  2482.             steerAngle = GetSteerAngle();
  2483.         }
  2484.  
  2485.         // update the wheel motor force
  2486.         for ( i = 0; i < 6; i++ ) {
  2487.             wheels[i]->SetContactMotorVelocity( velocity );
  2488.             wheels[i]->SetContactMotorForce( force );
  2489.         }
  2490.  
  2491.         // adjust wheel velocity for better steering because there are no differentials between the wheels
  2492.         if ( steerAngle < 0.0f ) {
  2493.             for ( i = 0; i < 3; i++ ) {
  2494.                 wheels[(i<<1)]->SetContactMotorVelocity( velocity * 0.5f );
  2495.             }
  2496.         }
  2497.         else if ( steerAngle > 0.0f ) {
  2498.             for ( i = 0; i < 3; i++ ) {
  2499.                 wheels[1+(i<<1)]->SetContactMotorVelocity( velocity * 0.5f );
  2500.             }
  2501.         }
  2502.  
  2503.         // update the wheel steering
  2504.         steering[0]->SetSteerAngle( steerAngle );
  2505.         steering[1]->SetSteerAngle( steerAngle );
  2506.         steering[2]->SetSteerAngle( -steerAngle );
  2507.         steering[3]->SetSteerAngle( -steerAngle );
  2508.         for ( i = 0; i < 4; i++ ) {
  2509.             steering[i]->SetSteerSpeed( 3.0f );
  2510.         }
  2511.  
  2512.         // update the steering wheel
  2513.         animator.GetJointTransform( steeringWheelJoint, gameLocal.time, origin, axis );
  2514.         rotation.SetVec( axis[2] );
  2515.         rotation.SetAngle( -steerAngle );
  2516.         animator.SetJointAxis( steeringWheelJoint, JOINTMOD_WORLD, rotation.ToMat3() );
  2517.  
  2518.         // run the physics
  2519.         RunPhysics();
  2520.  
  2521.         // rotate the wheels visually
  2522.         for ( i = 0; i < 6; i++ ) {
  2523.             if ( force == 0.0f ) {
  2524.                 velocity = wheels[i]->GetLinearVelocity() * wheels[i]->GetWorldAxis()[0];
  2525.             }
  2526. // RAVEN BEGIN
  2527. // bdube: msec to GetMsec
  2528.             wheelAngles[i] += velocity * MS2SEC( gameLocal.GetMSec() ) / wheelRadius;
  2529. // RAVEN END
  2530.             // give the wheel joint an additional rotation about the wheel axis
  2531.             rotation.SetAngle( RAD2DEG( wheelAngles[i] ) );
  2532.             axis = af.GetPhysics()->GetAxis( 0 );
  2533.             rotation.SetVec( (wheels[i]->GetWorldAxis() * axis.Transpose())[2] );
  2534.             animator.SetJointAxis( wheelJoints[i], JOINTMOD_WORLD, rotation.ToMat3() );
  2535.         }
  2536.  
  2537. /*
  2538.         // spawn dust particle effects
  2539.         if ( force != 0.0f && !( gameLocal.framenum & 7 ) ) {
  2540.             int numContacts;
  2541.             idAFConstraint_Contact *contacts[2];
  2542.             for ( i = 0; i < 6; i++ ) {
  2543.                 numContacts = af.GetPhysics()->GetBodyContactConstraints( wheels[i]->GetClipModel()->GetId(), contacts, 2 );
  2544.                 for ( int j = 0; j < numContacts; j++ ) {
  2545.                     gameLocal.smokeParticles->EmitSmoke( dustSmoke, gameLocal.time, gameLocal.random.RandomFloat(), contacts[j]->GetContact().point, contacts[j]->GetContact().normal.ToMat3() );
  2546.                 }
  2547.             }
  2548.         }
  2549. */
  2550.     }
  2551.  
  2552.     UpdateAnimation();
  2553.     if ( thinkFlags & TH_UPDATEVISUALS ) {
  2554.         Present();
  2555.         LinkCombat();
  2556.     }
  2557. }
  2558.  
  2559.  
  2560. /*
  2561. ===============================================================================
  2562.  
  2563.   idAFEntity_SteamPipe
  2564.  
  2565. ===============================================================================
  2566. */
  2567.  
  2568. CLASS_DECLARATION( idAFEntity_Base, idAFEntity_SteamPipe )
  2569. END_CLASS
  2570.  
  2571.  
  2572. /*
  2573. ================
  2574. idAFEntity_SteamPipe::idAFEntity_SteamPipe
  2575. ================
  2576. */
  2577. idAFEntity_SteamPipe::idAFEntity_SteamPipe( void ) {
  2578.     steamBody            = 0;
  2579.     steamForce            = 0.0f;
  2580.     steamUpForce        = 0.0f;
  2581.     steamModelDefHandle    = -1;
  2582.     memset( &steamRenderEntity, 0, sizeof( steamRenderEntity ) );
  2583. }
  2584.  
  2585. /*
  2586. ================
  2587. idAFEntity_SteamPipe::~idAFEntity_SteamPipe
  2588. ================
  2589. */
  2590. idAFEntity_SteamPipe::~idAFEntity_SteamPipe( void ) {
  2591.     if ( steamModelDefHandle >= 0 ){
  2592.         gameRenderWorld->FreeEntityDef( steamModelDefHandle );
  2593.     }
  2594. }
  2595.  
  2596. /*
  2597. ================
  2598. idAFEntity_SteamPipe::Save
  2599. ================
  2600. */
  2601. void idAFEntity_SteamPipe::Save( idSaveGame *savefile ) const {
  2602. }
  2603.  
  2604. /*
  2605. ================
  2606. idAFEntity_SteamPipe::Restore
  2607. ================
  2608. */
  2609. void idAFEntity_SteamPipe::Restore( idRestoreGame *savefile ) {
  2610.     Spawn();
  2611. }
  2612.  
  2613. /*
  2614. ================
  2615. idAFEntity_SteamPipe::Spawn
  2616. ================
  2617. */
  2618. void idAFEntity_SteamPipe::Spawn( void ) {
  2619.     idVec3 steamDir;
  2620.     const char *steamBodyName;
  2621.  
  2622.     LoadAF();
  2623.  
  2624.     SetCombatModel();
  2625.  
  2626.     SetPhysics( af.GetPhysics() );
  2627.  
  2628.     fl.takedamage = true;
  2629.  
  2630.     steamBodyName = spawnArgs.GetString( "steamBody", "" );
  2631.     steamForce = spawnArgs.GetFloat( "steamForce", "2000" );
  2632.     steamUpForce = spawnArgs.GetFloat( "steamUpForce", "10" );
  2633.     steamDir = af.GetPhysics()->GetAxis( steamBody )[2];
  2634.     steamBody = af.GetPhysics()->GetBodyId( steamBodyName );
  2635.     force.SetPosition( af.GetPhysics(), steamBody, af.GetPhysics()->GetOrigin( steamBody ) );
  2636.     force.SetForce( steamDir * -steamForce );
  2637.  
  2638.     InitSteamRenderEntity();
  2639.  
  2640.     BecomeActive( TH_THINK );
  2641. }
  2642.  
  2643. /*
  2644. ================
  2645. idAFEntity_SteamPipe::InitSteamRenderEntity
  2646. ================
  2647. */
  2648. void idAFEntity_SteamPipe::InitSteamRenderEntity( void ) {
  2649.     const char    *temp;
  2650.     const idDeclModelDef *modelDef;
  2651.  
  2652.     memset( &steamRenderEntity, 0, sizeof( steamRenderEntity ) );
  2653.     steamRenderEntity.shaderParms[ SHADERPARM_RED ]        = 1.0f;
  2654.     steamRenderEntity.shaderParms[ SHADERPARM_GREEN ]    = 1.0f;
  2655.     steamRenderEntity.shaderParms[ SHADERPARM_BLUE ]    = 1.0f;
  2656.     modelDef = NULL;
  2657.     temp = spawnArgs.GetString ( "model_steam" );
  2658.     if ( *temp != '\0' ) {
  2659.         if ( !strstr( temp, "." ) ) {
  2660.             modelDef = static_cast<const idDeclModelDef *>( declManager->FindType( DECL_MODELDEF, temp, false ) );
  2661.             if ( modelDef ) {
  2662.                 steamRenderEntity.hModel = modelDef->ModelHandle();
  2663.             }
  2664.         }
  2665.  
  2666.         if ( !steamRenderEntity.hModel ) {
  2667.             steamRenderEntity.hModel = renderModelManager->FindModel( temp );
  2668.         }
  2669.  
  2670.         if ( steamRenderEntity.hModel ) {
  2671.             steamRenderEntity.bounds = steamRenderEntity.hModel->Bounds( &steamRenderEntity );
  2672.         } else {
  2673.             steamRenderEntity.bounds.Zero();
  2674.         }
  2675.         steamRenderEntity.origin = af.GetPhysics()->GetOrigin( steamBody );
  2676.         steamRenderEntity.axis = af.GetPhysics()->GetAxis( steamBody );
  2677.         steamModelDefHandle = gameRenderWorld->AddEntityDef( &steamRenderEntity );
  2678.     }
  2679. }
  2680.  
  2681. /*
  2682. ================
  2683. idAFEntity_SteamPipe::Think
  2684. ================
  2685. */
  2686. void idAFEntity_SteamPipe::Think( void ) {
  2687.     idVec3 steamDir;
  2688.  
  2689.     if ( thinkFlags & TH_THINK ) {
  2690.         steamDir.x = gameLocal.random.CRandomFloat() * steamForce;
  2691.         steamDir.y = gameLocal.random.CRandomFloat() * steamForce;
  2692.         steamDir.z = steamUpForce;
  2693.         force.SetForce( steamDir );
  2694.         force.Evaluate( gameLocal.time );
  2695.         //gameRenderWorld->DebugArrow( colorWhite, af.GetPhysics()->GetOrigin( steamBody ), af.GetPhysics()->GetOrigin( steamBody ) - 10.0f * steamDir, 4 );
  2696.     }
  2697.  
  2698.     if ( steamModelDefHandle >= 0 ){
  2699.         steamRenderEntity.origin = af.GetPhysics()->GetOrigin( steamBody );
  2700.         steamRenderEntity.axis = af.GetPhysics()->GetAxis( steamBody );
  2701.         gameRenderWorld->UpdateEntityDef( steamModelDefHandle, &steamRenderEntity );
  2702.     }
  2703.  
  2704.     idAFEntity_Base::Think();
  2705. }
  2706.  
  2707.  
  2708. /*
  2709. ===============================================================================
  2710.  
  2711.   idAFEntity_ClawFourFingers
  2712.  
  2713. ===============================================================================
  2714. */
  2715.  
  2716. const idEventDef EV_SetFingerAngle( "setFingerAngle", "f" );
  2717. const idEventDef EV_StopFingers( "stopFingers" );
  2718.  
  2719. CLASS_DECLARATION( idAFEntity_Base, idAFEntity_ClawFourFingers )
  2720.     EVENT( EV_SetFingerAngle,        idAFEntity_ClawFourFingers::Event_SetFingerAngle )
  2721.     EVENT( EV_StopFingers,            idAFEntity_ClawFourFingers::Event_StopFingers )
  2722. END_CLASS
  2723.  
  2724. static const char *clawConstraintNames[] = {
  2725.     "claw1", "claw2", "claw3", "claw4"
  2726. };
  2727.  
  2728. /*
  2729. ================
  2730. idAFEntity_ClawFourFingers::idAFEntity_ClawFourFingers
  2731. ================
  2732. */
  2733. idAFEntity_ClawFourFingers::idAFEntity_ClawFourFingers( void ) {
  2734.     fingers[0]    = NULL;
  2735.     fingers[1]    = NULL;
  2736.     fingers[2]    = NULL;
  2737.     fingers[3]    = NULL;
  2738. }
  2739.  
  2740. /*
  2741. ================
  2742. idAFEntity_ClawFourFingers::Save
  2743. ================
  2744. */
  2745. void idAFEntity_ClawFourFingers::Save( idSaveGame *savefile ) const {
  2746.     int i;
  2747.  
  2748.     for ( i = 0; i < 4; i++ ) {
  2749.         fingers[i]->Save( savefile );
  2750.     }
  2751. }
  2752.  
  2753. /*
  2754. ================
  2755. idAFEntity_ClawFourFingers::Restore
  2756. ================
  2757. */
  2758. void idAFEntity_ClawFourFingers::Restore( idRestoreGame *savefile ) {
  2759.     int i;
  2760.  
  2761.     for ( i = 0; i < 4; i++ ) {
  2762.         fingers[i] = static_cast<idAFConstraint_Hinge *>(af.GetPhysics()->GetConstraint( clawConstraintNames[i] ));
  2763.         fingers[i]->Restore( savefile );
  2764.     }
  2765.  
  2766.     SetCombatModel();
  2767.     LinkCombat();
  2768. }
  2769.  
  2770. /*
  2771. ================
  2772. idAFEntity_ClawFourFingers::Spawn
  2773. ================
  2774. */
  2775. void idAFEntity_ClawFourFingers::Spawn( void ) {
  2776.     int i;
  2777.  
  2778.     LoadAF();
  2779.  
  2780.     SetCombatModel();
  2781.  
  2782.     af.GetPhysics()->LockWorldConstraints( true );
  2783.     af.GetPhysics()->SetForcePushable( true );
  2784.     SetPhysics( af.GetPhysics() );
  2785.  
  2786.     fl.takedamage = true;
  2787.  
  2788.     for ( i = 0; i < 4; i++ ) {
  2789.         fingers[i] = static_cast<idAFConstraint_Hinge *>(af.GetPhysics()->GetConstraint( clawConstraintNames[i] ));
  2790.         if ( !fingers[i] ) {
  2791.             gameLocal.Error( "idClaw_FourFingers '%s': can't find claw constraint '%s'", name.c_str(), clawConstraintNames[i] );
  2792.         }
  2793.     }
  2794. }
  2795.  
  2796. /*
  2797. ================
  2798. idAFEntity_ClawFourFingers::Event_SetFingerAngle
  2799. ================
  2800. */
  2801. void idAFEntity_ClawFourFingers::Event_SetFingerAngle( float angle ) {
  2802.     int i;
  2803.  
  2804.     for ( i = 0; i < 4; i++ ) {
  2805.         fingers[i]->SetSteerAngle( angle );
  2806.         fingers[i]->SetSteerSpeed( 0.5f );
  2807.     }
  2808.     af.GetPhysics()->Activate();
  2809. }
  2810.  
  2811. /*
  2812. ================
  2813. idAFEntity_ClawFourFingers::Event_StopFingers
  2814. ================
  2815. */
  2816. void idAFEntity_ClawFourFingers::Event_StopFingers( void ) {
  2817.     int i;
  2818.  
  2819.     for ( i = 0; i < 4; i++ ) {
  2820.         fingers[i]->SetSteerAngle( fingers[i]->GetAngle() );
  2821.     }
  2822. }
  2823.  
  2824.  
  2825. /*
  2826. ===============================================================================
  2827.  
  2828.   editor support routines
  2829.  
  2830. ===============================================================================
  2831. */
  2832.  
  2833.  
  2834. /*
  2835. ================
  2836. idGameEdit::AF_SpawnEntity
  2837. ================
  2838. */
  2839. bool idGameEdit::AF_SpawnEntity( const char *fileName ) {
  2840.     idDict args;
  2841.     idPlayer *player;
  2842.     idAFEntity_Generic *ent;
  2843.     const idDeclAF *af;
  2844.     idVec3 org;
  2845.     float yaw;
  2846.  
  2847.     player = gameLocal.GetLocalPlayer();
  2848.     if ( !player || !gameLocal.CheatsOk( false ) ) {
  2849.         return false;
  2850.     }
  2851.  
  2852.     af = static_cast<const idDeclAF *>( declManager->FindType( DECL_AF, fileName ) );
  2853.     if ( !af ) {
  2854.         return false;
  2855.     }
  2856.  
  2857.     yaw = player->viewAngles.yaw;
  2858.     args.Set( "angle", va( "%f", yaw + 180 ) );
  2859.     org = player->GetPhysics()->GetOrigin() + idAngles( 0, yaw, 0 ).ToForward() * 80 + idVec3( 0, 0, 1 );
  2860.     args.Set( "origin", org.ToString() );
  2861.     args.Set( "spawnclass", "idAFEntity_Generic" );
  2862.     if ( af->model[0] ) {
  2863.         args.Set( "model", af->model.c_str() );
  2864.     } else {
  2865.         args.Set( "model", fileName );
  2866.     }
  2867.     if ( af->skin[0] ) {
  2868.         args.Set( "skin", af->skin.c_str() );
  2869.     }
  2870.     args.Set( "articulatedFigure", fileName );
  2871.     args.Set( "nodrop", "1" );
  2872. // RAVEN BEGIN
  2873. // jnewquist: Use accessor for static class type 
  2874.     ent = static_cast<idAFEntity_Generic *>(gameLocal.SpawnEntityType( idAFEntity_Generic::GetClassType(), &args));
  2875. // RAVEN END
  2876.  
  2877.     // always update this entity
  2878.     ent->BecomeActive( TH_THINK );
  2879.     ent->KeepRunningPhysics();
  2880.     ent->fl.forcePhysicsUpdate = true;
  2881.  
  2882.     player->dragEntity.SetSelected( ent );
  2883.  
  2884.     return true;
  2885. }
  2886.  
  2887. /*
  2888. ================
  2889. idGameEdit::AF_UpdateEntities
  2890. ================
  2891. */
  2892. void idGameEdit::AF_UpdateEntities( const char *fileName ) {
  2893.     idEntity *ent;
  2894.     idAFEntity_Base *af;
  2895.     idStr name;
  2896.  
  2897.     name = fileName;
  2898.     name.StripFileExtension();
  2899.  
  2900.     // reload any idAFEntity_Generic which uses the given articulated figure file
  2901.     for( ent = gameLocal.spawnedEntities.Next(); ent != NULL; ent = ent->spawnNode.Next() ) {
  2902. // RAVEN BEGIN
  2903. // jnewquist: Use accessor for static class type 
  2904.         if ( ent->IsType( idAFEntity_Base::GetClassType() ) ) {
  2905. // RAVEN END
  2906.             af = static_cast<idAFEntity_Base *>(ent);
  2907.             if ( name.Icmp( af->GetAFName() ) == 0 ) {
  2908.                 af->LoadAF();
  2909.                 af->GetAFPhysics()->PutToRest();
  2910.             }
  2911.         }
  2912.     }
  2913. }
  2914.  
  2915. /*
  2916. ================
  2917. idGameEdit::AF_UndoChanges
  2918. ================
  2919. */
  2920. void idGameEdit::AF_UndoChanges( void ) {
  2921.     int i, c;
  2922.     idEntity *ent;
  2923.     idAFEntity_Base *af;
  2924.     idDeclAF *decl;
  2925.  
  2926.     c = declManager->GetNumDecls( DECL_AF );
  2927.     for ( i = 0; i < c; i++ ) {
  2928.         decl = static_cast<idDeclAF *>( const_cast<idDecl *>( declManager->DeclByIndex( DECL_AF, i, false ) ) );
  2929.         if ( !decl->modified ) {
  2930.             continue;
  2931.         }
  2932.  
  2933.         decl->Invalidate();
  2934.         declManager->FindType( DECL_AF, decl->GetName() );
  2935.  
  2936.         // reload all AF entities using the file
  2937.         for( ent = gameLocal.spawnedEntities.Next(); ent != NULL; ent = ent->spawnNode.Next() ) {
  2938. // RAVEN BEGIN
  2939. // jnewquist: Use accessor for static class type 
  2940.             if ( ent->IsType( idAFEntity_Base::GetClassType() ) ) {
  2941. // RAVEN END
  2942.                 af = static_cast<idAFEntity_Base *>(ent);
  2943.                 if ( idStr::Icmp( decl->GetName(), af->GetAFName() ) == 0 ) {
  2944.                     af->LoadAF();
  2945.                 }
  2946.             }
  2947.         }
  2948.     }
  2949. }
  2950.  
  2951. /*
  2952. ================
  2953. GetJointTransform
  2954. ================
  2955. */
  2956. typedef struct {
  2957.     renderEntity_t *ent;
  2958.     const idMD5Joint *joints;
  2959. } jointTransformData_t;
  2960.  
  2961. static bool GetJointTransform( void *model, const idJointMat *frame, const char *jointName, idVec3 &origin, idMat3 &axis ) {
  2962.     int i;
  2963.     jointTransformData_t *data = reinterpret_cast<jointTransformData_t *>(model);
  2964.  
  2965.     for ( i = 0; i < data->ent->numJoints; i++ ) {
  2966.         if ( data->joints[i].name.Icmp( jointName ) == 0 ) {
  2967.             break;
  2968.         }
  2969.     }
  2970.     if ( i >= data->ent->numJoints ) {
  2971.         return false;
  2972.     }
  2973.     origin = frame[i].ToVec3();
  2974.     axis = frame[i].ToMat3();
  2975.     return true;
  2976. }
  2977.  
  2978. /*
  2979. ================
  2980. GetArgString
  2981. ================
  2982. */
  2983. static const char *GetArgString( const idDict &args, const idDict *defArgs, const char *key ) {
  2984.     const char *s;
  2985.  
  2986.     s = args.GetString( key );
  2987.     if ( !s[0] && defArgs ) {
  2988.         s = defArgs->GetString( key );
  2989.     }
  2990.     return s;
  2991. }
  2992.  
  2993. /*
  2994. ================
  2995. idGameEdit::AF_CreateMesh
  2996. ================
  2997. */
  2998. idRenderModel *idGameEdit::AF_CreateMesh( const idDict &args, idVec3 &meshOrigin, idMat3 &meshAxis, bool &poseIsSet ) {
  2999.     int i, jointNum;
  3000.     const idDeclAF *af;
  3001.     const idDeclAF_Body *fb = NULL;
  3002.     renderEntity_t ent;
  3003.     idVec3 origin, *bodyOrigin, *newBodyOrigin, *modifiedOrigin;
  3004.     idMat3 axis, *bodyAxis, *newBodyAxis, *modifiedAxis;
  3005.     declAFJointMod_t *jointMod;
  3006.     idAngles angles;
  3007.     const idDict *defArgs;
  3008.     const idKeyValue *arg;
  3009.     idStr name;
  3010.     jointTransformData_t data;
  3011.     const char *classname, *afName, *modelName;
  3012.     idRenderModel *md5;
  3013.     const idDeclModelDef *modelDef;
  3014.     const idMD5Anim *MD5anim;
  3015.     const idMD5Joint *MD5joint;
  3016.     const idMD5Joint *MD5joints;
  3017.     int numMD5joints;
  3018.     idJointMat *originalJoints;
  3019.     int parentNum;
  3020.  
  3021.     poseIsSet = false;
  3022.     meshOrigin.Zero();
  3023.     meshAxis.Identity();
  3024.  
  3025.     classname = args.GetString( "classname" );
  3026.     defArgs = gameLocal.FindEntityDefDict( classname );
  3027.  
  3028.     // get the articulated figure
  3029.     afName = GetArgString( args, defArgs, "articulatedFigure" );
  3030.     af = static_cast<const idDeclAF *>( declManager->FindType( DECL_AF, afName ) );
  3031.     if ( !af ) {
  3032.         return NULL;
  3033.     }
  3034.  
  3035.     // get the md5 model
  3036.     modelName = GetArgString( args, defArgs, "model" );
  3037.     modelDef = static_cast< const idDeclModelDef *>( declManager->FindType( DECL_MODELDEF, modelName, false ) );
  3038.     if ( !modelDef ) {
  3039.         return NULL;
  3040.     }
  3041.  
  3042.     // make sure model hasn't been purged
  3043.     if ( modelDef->ModelHandle() && !modelDef->ModelHandle()->IsLoaded() ) {
  3044.         modelDef->ModelHandle()->LoadModel();
  3045.     }
  3046.  
  3047.     // get the md5
  3048.     md5 = modelDef->ModelHandle();
  3049.     if ( !md5 || md5->IsDefaultModel() ) {
  3050.         return NULL;
  3051.     }
  3052.  
  3053.     // get the articulated figure pose anim
  3054.     int animNum = modelDef->GetAnim( "af_pose" );
  3055.     if ( !animNum ) {
  3056.         return NULL;
  3057.     }
  3058.     const idAnim *anim = modelDef->GetAnim( animNum );
  3059.     if ( !anim ) {
  3060.         return NULL;
  3061.     }
  3062.     MD5anim = anim->MD5Anim( 0 );
  3063.     MD5joints = md5->GetJoints();
  3064.     numMD5joints = md5->NumJoints();
  3065.  
  3066.     // setup a render entity
  3067.     memset( &ent, 0, sizeof( ent ) );
  3068.     ent.customSkin = modelDef->GetSkin();
  3069.     ent.bounds.Clear();
  3070.     ent.numJoints = numMD5joints;
  3071.     ent.joints = ( idJointMat * )_alloca16( ent.numJoints * sizeof( *ent.joints ) );
  3072.  
  3073.     // create animation from of the af_pose
  3074.     ANIM_CreateAnimFrame( md5, MD5anim, ent.numJoints, ent.joints, 1, modelDef->GetVisualOffset(), false );
  3075.  
  3076.     // buffers to store the initial origin and axis for each body
  3077.     bodyOrigin = (idVec3 *) _alloca16( af->bodies.Num() * sizeof( idVec3 ) );
  3078.     bodyAxis = (idMat3 *) _alloca16( af->bodies.Num() * sizeof( idMat3 ) );
  3079.     newBodyOrigin = (idVec3 *) _alloca16( af->bodies.Num() * sizeof( idVec3 ) );
  3080.     newBodyAxis = (idMat3 *) _alloca16( af->bodies.Num() * sizeof( idMat3 ) );
  3081.  
  3082.     // finish the AF positions
  3083.     data.ent = &ent;
  3084.     data.joints = MD5joints;
  3085.     af->Finish( GetJointTransform, ent.joints, &data );
  3086.  
  3087.     // get the initial origin and axis for each AF body
  3088.     for ( i = 0; i < af->bodies.Num(); i++ ) {
  3089.         fb = af->bodies[i];
  3090.  
  3091.         if ( fb->modelType == TRM_BONE ) {
  3092.             // axis of bone trace model
  3093.             axis[2] = fb->v2.ToVec3() - fb->v1.ToVec3();
  3094.             axis[2].Normalize();
  3095.             axis[2].NormalVectors( axis[0], axis[1] );
  3096.             axis[1] = -axis[1];
  3097.         } else {
  3098.             axis = fb->angles.ToMat3();
  3099.         }
  3100.  
  3101.         newBodyOrigin[i] = bodyOrigin[i] = fb->origin.ToVec3();
  3102.         newBodyAxis[i] = bodyAxis[i] = axis;
  3103.     }
  3104.  
  3105.     // get any new body transforms stored in the key/value pairs
  3106.     for ( arg = args.MatchPrefix( "body ", NULL ); arg; arg = args.MatchPrefix( "body ", arg ) ) {
  3107.         name = arg->GetKey();
  3108.         name.Strip( "body " );
  3109.         for ( i = 0; i < af->bodies.Num(); i++ ) {
  3110.             fb = af->bodies[i];
  3111.             if ( fb->name.Icmp( name ) == 0 ) {
  3112.                 break;
  3113.             }
  3114.         }
  3115.         if ( i >= af->bodies.Num() ) {
  3116.             continue;
  3117.         }
  3118.         sscanf( arg->GetValue(), "%f %f %f %f %f %f", &origin.x, &origin.y, &origin.z, &angles.pitch, &angles.yaw, &angles.roll );
  3119.  
  3120.         if ( fb->jointName.Icmp( "origin" ) == 0 ) {
  3121.             meshAxis = bodyAxis[i].Transpose() * angles.ToMat3();
  3122.             meshOrigin = origin - bodyOrigin[i] * meshAxis;
  3123.             poseIsSet = true;
  3124.         } else {
  3125.             newBodyOrigin[i] = origin;
  3126.             newBodyAxis[i] = angles.ToMat3();
  3127.         }
  3128.     }
  3129.  
  3130.     // save the original joints
  3131.     originalJoints = ( idJointMat * )_alloca16( numMD5joints * sizeof( originalJoints[0] ) );
  3132. // RAVEN BEGIN
  3133. // JSinger: Changed to call optimized memcpy
  3134.     SIMDProcessor->Memcpy( originalJoints, ent.joints, numMD5joints * sizeof( originalJoints[0] ) );
  3135. // RAVEN END
  3136.  
  3137.     // buffer to store the joint mods
  3138.     jointMod = (declAFJointMod_t *) _alloca16( numMD5joints * sizeof( declAFJointMod_t ) );
  3139.     memset( jointMod, -1, numMD5joints * sizeof( declAFJointMod_t ) );
  3140.     modifiedOrigin = (idVec3 *) _alloca16( numMD5joints * sizeof( idVec3 ) );
  3141.     memset( modifiedOrigin, 0, numMD5joints * sizeof( idVec3 ) );
  3142.     modifiedAxis = (idMat3 *) _alloca16( numMD5joints * sizeof( idMat3 ) );
  3143.     memset( modifiedAxis, 0, numMD5joints * sizeof( idMat3 ) );
  3144.  
  3145.     // get all the joint modifications
  3146.     for ( i = 0; i < af->bodies.Num(); i++ ) {
  3147.         fb = af->bodies[i];
  3148.  
  3149.         if ( fb->jointName.Icmp( "origin" ) == 0 ) {
  3150.             continue;
  3151.         }
  3152.  
  3153.         for ( jointNum = 0; jointNum < numMD5joints; jointNum++ ) {
  3154.             if ( MD5joints[jointNum].name.Icmp( fb->jointName ) == 0 ) {
  3155.                 break;
  3156.             }
  3157.         }
  3158.  
  3159.         if ( jointNum >= 0 && jointNum < ent.numJoints ) {
  3160.             jointMod[ jointNum ] = fb->jointMod;
  3161.             modifiedAxis[ jointNum ] = ( bodyAxis[i] * originalJoints[jointNum].ToMat3().Transpose() ).Transpose() * ( newBodyAxis[i] * meshAxis.Transpose() );
  3162.             // FIXME: calculate correct modifiedOrigin
  3163.             modifiedOrigin[ jointNum ] = originalJoints[ jointNum ].ToVec3();
  3164.          }
  3165.     }
  3166.  
  3167.     // apply joint modifications to the skeleton
  3168.     MD5joint = MD5joints + 1;
  3169.     for( i = 1; i < numMD5joints; i++, MD5joint++ ) {
  3170.  
  3171.         parentNum = MD5joint->parent - MD5joints;
  3172.         idMat3 parentAxis = originalJoints[ parentNum ].ToMat3();
  3173.         idMat3 localm = originalJoints[i].ToMat3() * parentAxis.Transpose();
  3174.         idVec3 localt = ( originalJoints[i].ToVec3() - originalJoints[ parentNum ].ToVec3() ) * parentAxis.Transpose();
  3175.  
  3176.         switch( jointMod[i] ) {
  3177.             case DECLAF_JOINTMOD_ORIGIN: {
  3178.                 ent.joints[ i ].SetRotation( localm * ent.joints[ parentNum ].ToMat3() );
  3179.                 ent.joints[ i ].SetTranslation( modifiedOrigin[ i ] );
  3180.                 break;
  3181.             }
  3182.             case DECLAF_JOINTMOD_AXIS: {
  3183.                 ent.joints[ i ].SetRotation( modifiedAxis[ i ] );
  3184.                 ent.joints[ i ].SetTranslation( ent.joints[ parentNum ].ToVec3() + localt * ent.joints[ parentNum ].ToMat3() );
  3185.                 break;
  3186.             }
  3187.             case DECLAF_JOINTMOD_BOTH: {
  3188.                 ent.joints[ i ].SetRotation( modifiedAxis[ i ] );
  3189.                 ent.joints[ i ].SetTranslation( modifiedOrigin[ i ] );
  3190.                 break;
  3191.             }
  3192.             default: {
  3193.                 ent.joints[ i ].SetRotation( localm * ent.joints[ parentNum ].ToMat3() );
  3194.                 ent.joints[ i ].SetTranslation( ent.joints[ parentNum ].ToVec3() + localt * ent.joints[ parentNum ].ToMat3() );
  3195.                 break;
  3196.             }
  3197.         }
  3198.     }
  3199.  
  3200.     // instantiate a mesh using the joint information from the render entity
  3201.     return md5->InstantiateDynamicModel( &ent, NULL, NULL );
  3202. }
  3203.  
  3204. // RAVEN BEGIN
  3205. // bdube: af attractors
  3206.  
  3207. /*
  3208. ===============================================================================
  3209.  
  3210.   rvAFAttractor
  3211.  
  3212. ===============================================================================
  3213. */
  3214.  
  3215. CLASS_DECLARATION( idEntity, rvAFAttractor )
  3216. END_CLASS
  3217.  
  3218. // RAVEN END
  3219.