codemp/cgame/cg_ents.c

Go to the documentation of this file.
00001 // Copyright (C) 1999-2000 Id Software, Inc.
00002 //
00003 // cg_ents.c -- present snapshot entities, happens every single frame
00004 
00005 #include "cg_local.h"
00006 /*
00007 Ghoul2 Insert Start
00008 */
00009 #include "..\game\q_shared.h"
00010 #include "..\ghoul2\g2.h"
00011 /*
00012 Ghoul2 Insert end
00013 */
00014 
00015 extern qboolean CG_InFighter( void );
00016 static void CG_Missile( centity_t *cent );
00017 
00018 /*
00019 ======================
00020 CG_PositionEntityOnTag
00021 
00022 Modifies the entities position and axis by the given
00023 tag location
00024 ======================
00025 */
00026 void CG_PositionEntityOnTag( refEntity_t *entity, const refEntity_t *parent, 
00027                                                         qhandle_t parentModel, char *tagName ) {
00028         int                             i;
00029         orientation_t   lerped;
00030         
00031         // lerp the tag
00032         trap_R_LerpTag( &lerped, parentModel, parent->oldframe, parent->frame,
00033                 1.0 - parent->backlerp, tagName );
00034 
00035         // FIXME: allow origin offsets along tag?
00036         VectorCopy( parent->origin, entity->origin );
00037         for ( i = 0 ; i < 3 ; i++ ) {
00038                 VectorMA( entity->origin, lerped.origin[i], parent->axis[i], entity->origin );
00039         }
00040 
00041         // had to cast away the const to avoid compiler problems...
00042         MatrixMultiply( lerped.axis, ((refEntity_t *)parent)->axis, entity->axis );
00043         entity->backlerp = parent->backlerp;
00044 }
00045 
00046 
00047 /*
00048 ======================
00049 CG_PositionRotatedEntityOnTag
00050 
00051 Modifies the entities position and axis by the given
00052 tag location
00053 ======================
00054 */
00055 void CG_PositionRotatedEntityOnTag( refEntity_t *entity, const refEntity_t *parent, 
00056                                                         qhandle_t parentModel, char *tagName ) {
00057         int                             i;
00058         orientation_t   lerped;
00059         vec3_t                  tempAxis[3];
00060 
00061 //AxisClear( entity->axis );
00062         // lerp the tag
00063         trap_R_LerpTag( &lerped, parentModel, parent->oldframe, parent->frame,
00064                 1.0 - parent->backlerp, tagName );
00065 
00066         // FIXME: allow origin offsets along tag?
00067         VectorCopy( parent->origin, entity->origin );
00068         for ( i = 0 ; i < 3 ; i++ ) {
00069                 VectorMA( entity->origin, lerped.origin[i], parent->axis[i], entity->origin );
00070         }
00071 
00072         // had to cast away the const to avoid compiler problems...
00073         MatrixMultiply( entity->axis, lerped.axis, tempAxis );
00074         MatrixMultiply( tempAxis, ((refEntity_t *)parent)->axis, entity->axis );
00075 }
00076 
00077 
00078 
00079 /*
00080 ==========================================================================
00081 
00082 FUNCTIONS CALLED EACH FRAME
00083 
00084 ==========================================================================
00085 */
00086 
00087 //only need to use the CG_S_ system when you want a looping sound that isn't going to add itself
00088 //via trap each frame. Such as ones generated by events.
00089 /*
00090 ======================
00091 CG_SetEntitySoundPosition
00092 
00093 Also called by event processing code
00094 ======================
00095 */
00096 void CG_SetEntitySoundPosition( centity_t *cent ) {
00097         if ( cent->currentState.solid == SOLID_BMODEL )
00098         {
00099                 vec3_t  origin;
00100                 float   *v;
00101 
00102                 v = cgs.inlineModelMidpoints[ cent->currentState.modelindex ];
00103                 VectorAdd( cent->lerpOrigin, v, origin );
00104                 trap_S_UpdateEntityPosition( cent->currentState.number, origin );
00105         }
00106         else
00107         {
00108                 trap_S_UpdateEntityPosition( cent->currentState.number, cent->lerpOrigin );
00109         }
00110 }
00111 
00112 /*
00113 ==================
00114 CG_S_AddLoopingSound
00115 
00116 Set the current looping sounds on the entity.
00117 ==================
00118 */
00119 void CG_S_AddLoopingSound(int entityNum, const vec3_t origin, const vec3_t velocity, sfxHandle_t sfx)
00120 {
00121         centity_t *cent = &cg_entities[entityNum];
00122         cgLoopSound_t *cSound = NULL;
00123         int i = 0;
00124         qboolean alreadyPlaying = qfalse;
00125 
00126         //first see if we're already looping this sound handle.
00127         while (i < cent->numLoopingSounds)
00128         {
00129                 cSound = &cent->loopingSound[i];
00130 
00131                 if (cSound->sfx == sfx)
00132                 {
00133                         alreadyPlaying = qtrue;
00134                         break;
00135                 }
00136         }
00137         
00138         if (alreadyPlaying && cSound)
00139         { //if this is the case, just update the properties of the looping sound and return.
00140                 VectorCopy(origin, cSound->origin);
00141                 VectorCopy(velocity, cSound->velocity);
00142         }
00143         else if (cent->numLoopingSounds >= MAX_CG_LOOPSOUNDS)
00144         { //Just don't add it then I suppose.
00145 #ifdef _XBOX    // We decreased this number, so I'd like to know if it gets overflowed
00146                 Com_Printf( S_COLOR_YELLOW "Warning: MAX_CG_LOOPSOUNDS exceeded!!\n" );
00147 #endif
00148                 return;
00149         }
00150 
00151         //Add a new looping sound.
00152         cSound = &cent->loopingSound[cent->numLoopingSounds];
00153 
00154         cSound->entityNum = entityNum;
00155         VectorCopy(origin, cSound->origin);
00156         VectorCopy(velocity, cSound->velocity);
00157         cSound->sfx = sfx;
00158 
00159         cent->numLoopingSounds++;
00160 }
00161 
00162 /*
00163 ==================
00164 CG_S_AddLoopingSound
00165 
00166 For now just redirect, might eventually do something different.
00167 ==================
00168 */
00169 void CG_S_AddRealLoopingSound(int entityNum, const vec3_t origin, const vec3_t velocity, sfxHandle_t sfx)
00170 {
00171         CG_S_AddLoopingSound(entityNum, origin, velocity, sfx);
00172 }
00173 
00174 /*
00175 ==================
00176 CG_S_AddLoopingSound
00177 
00178 Clear looping sounds.
00179 ==================
00180 */
00181 void CG_S_StopLoopingSound(int entityNum, sfxHandle_t sfx)
00182 {
00183         centity_t *cent = &cg_entities[entityNum];
00184         cgLoopSound_t *cSound;
00185 
00186         if (sfx == -1)
00187         { //clear all the looping sounds on the entity
00188                 cent->numLoopingSounds = 0;
00189         }
00190         else
00191         { //otherwise, clear only the specified looping sound
00192                 int i = 0;
00193 
00194                 while (i < cent->numLoopingSounds)
00195                 {
00196                         cSound = &cent->loopingSound[i];
00197 
00198                         if (cSound->sfx == sfx)
00199                         { //remove it then
00200                                 int x = i+1;
00201 
00202                                 while (x < cent->numLoopingSounds)
00203                                 {
00204                                         memcpy(&cent->loopingSound[x-1], &cent->loopingSound[x], sizeof(cent->loopingSound[x]));
00205                                         x++;
00206                                 }
00207                                 cent->numLoopingSounds--;
00208                         }
00209 
00210                         i++;
00211                 }
00212         }
00213         //trap_S_StopLoopingSound(entityNum);
00214 }
00215 
00216 /*
00217 ==================
00218 CG_S_UpdateLoopingSounds
00219 
00220 Update any existing looping sounds on the entity.
00221 ==================
00222 */
00223 void CG_S_UpdateLoopingSounds(int entityNum)
00224 {
00225         centity_t *cent = &cg_entities[entityNum];
00226         cgLoopSound_t *cSound;
00227         vec3_t lerpOrg;
00228         float *v;
00229         int i = 0;
00230 
00231         if (!cent->numLoopingSounds)
00232         {
00233                 return;
00234         }
00235 
00236         if (cent->currentState.eType == ET_MOVER)
00237         {
00238                 v = cgs.inlineModelMidpoints[ cent->currentState.modelindex ];
00239                 VectorAdd( cent->lerpOrigin, v, lerpOrg );
00240         }
00241         else
00242         {
00243                 VectorCopy(cent->lerpOrigin, lerpOrg);
00244         }
00245 
00246         while (i < cent->numLoopingSounds)
00247         {
00248                 cSound = &cent->loopingSound[i];
00249 
00250                 //trap_S_AddLoopingSound(entityNum, cSound->origin, cSound->velocity, cSound->sfx);
00251                 //I guess just keep using lerpOrigin for now,
00252                 trap_S_AddLoopingSound(entityNum, lerpOrg, cSound->velocity, cSound->sfx);
00253                 i++;
00254         }
00255 }
00256 
00257 /*
00258 ==================
00259 CG_EntityEffects
00260 
00261 Add continuous entity effects, like local entity emission and lighting
00262 ==================
00263 */
00264 static void CG_EntityEffects( centity_t *cent ) {
00265 
00266         // update sound origins
00267         CG_SetEntitySoundPosition( cent );
00268 
00269         // add loop sound
00270         if ( cent->currentState.loopSound || (cent->currentState.loopIsSoundset && cent->currentState.number >= MAX_CLIENTS) ) {
00271                 sfxHandle_t realSoundIndex = -1;
00272                         
00273                 if (cent->currentState.loopIsSoundset && cent->currentState.number >= MAX_CLIENTS)
00274                 { //If this is so, then first get our soundset from the index, and loopSound actually contains which part of the set to
00275                   //use rather than a sound index (BMS_START [0], BMS_MID [1], or BMS_END [2]). Typically loop sounds will be BMS_MID.
00276                         const char *soundSet;
00277                         
00278                         soundSet = CG_ConfigString( CS_AMBIENT_SET + cent->currentState.soundSetIndex );
00279 
00280                         if (soundSet && soundSet[0])
00281                         {
00282                                 realSoundIndex = trap_AS_GetBModelSound(soundSet, cent->currentState.loopSound);
00283                         }
00284                 }
00285                 else
00286                 {
00287                         realSoundIndex = cgs.gameSounds[ cent->currentState.loopSound ];
00288                 }
00289 
00290                 //rww - doors and things with looping sounds have a crazy origin (being brush models and all)
00291                 if (realSoundIndex != -1)
00292                 {
00293                         if ( cent->currentState.solid == SOLID_BMODEL )
00294                         {
00295                                 vec3_t  origin;
00296                                 float   *v;
00297 
00298                                 v = cgs.inlineModelMidpoints[ cent->currentState.modelindex ];
00299                                 VectorAdd( cent->lerpOrigin, v, origin );
00300                                 trap_S_AddLoopingSound( cent->currentState.number, origin, vec3_origin, 
00301                                         realSoundIndex );
00302                         }
00303                         else if (cent->currentState.eType != ET_SPEAKER) {
00304                                 trap_S_AddLoopingSound( cent->currentState.number, cent->lerpOrigin, vec3_origin, 
00305                                         realSoundIndex );
00306                         } else {
00307                                 trap_S_AddRealLoopingSound( cent->currentState.number, cent->lerpOrigin, vec3_origin, 
00308                                         realSoundIndex );
00309                         }
00310                 }
00311         }
00312 
00313 
00314         // constant light glow
00315         if ( cent->currentState.constantLight ) {
00316                 int             cl;
00317                 int             i, r, g, b;
00318 
00319                 cl = cent->currentState.constantLight;
00320                 r = cl & 255;
00321                 g = ( cl >> 8 ) & 255;
00322                 b = ( cl >> 16 ) & 255;
00323                 i = ( ( cl >> 24 ) & 255 ) * 4;
00324                 trap_R_AddLightToScene( cent->lerpOrigin, i, r, g, b );
00325         }
00326 
00327 }
00328 
00329 localEntity_t *FX_AddOrientedLine(vec3_t start, vec3_t end, vec3_t normal, float stScale, float scale,
00330                                                                   float dscale, float startalpha, float endalpha, float killTime, qhandle_t shader)
00331 {
00332         localEntity_t   *le;
00333         
00334 #ifdef _DEBUG
00335         if (!shader)
00336         {
00337                 Com_Printf("FX_AddLine: NULL shader\n");
00338         }
00339 #endif
00340 
00341         le = CG_AllocLocalEntity();
00342         le->leType = LE_OLINE;
00343 
00344         le->startTime = cg.time;
00345         le->endTime = le->startTime + killTime;
00346         le->data.line.width = scale;
00347         le->data.line.dwidth = dscale;
00348 
00349         le->alpha = startalpha;
00350         le->dalpha = endalpha - startalpha;
00351 
00352         le->refEntity.data.line.stscale = stScale;
00353         le->refEntity.data.line.width = scale;
00354 
00355         le->refEntity.customShader = shader;
00356 
00357         // set origin
00358         VectorCopy ( start, le->refEntity.origin);
00359         VectorCopy ( end, le->refEntity.oldorigin );
00360 
00361         AxisClear(le->refEntity.axis);
00362         VectorCopy( normal, le->refEntity.axis[0] );
00363         RotateAroundDirection( le->refEntity.axis, 0); // le->refEntity.data.sprite.rotation ); This is roll in quad land
00364 
00365         le->refEntity.shaderRGBA[0] = 0xff;
00366         le->refEntity.shaderRGBA[1] = 0xff;
00367         le->refEntity.shaderRGBA[2] = 0xff;
00368         le->refEntity.shaderRGBA[3] = 0xff;
00369 
00370         le->color[0] = 1.0;
00371         le->color[1] = 1.0;
00372         le->color[2] = 1.0;
00373         le->color[3] = 1.0;
00374         le->lifeRate = 1.0 / ( le->endTime - le->startTime );
00375 
00376         return(le);
00377 }
00378 
00379 void FX_DrawPortableShield(centity_t *cent)
00380 {
00381         //rww - this code differs a bit from the draw code in EF, I don't know why I had to do
00382         //it this way yet it worked in EF the other way.
00383 
00384         int                             xaxis, height, posWidth, negWidth, team;
00385         vec3_t                  start, end, normal;
00386         localEntity_t   *le;
00387         qhandle_t               shader;
00388         char                    buf[1024];
00389 
00390         trap_Cvar_VariableStringBuffer("cl_paused", buf, sizeof(buf));
00391 
00392         if (atoi(buf))
00393         { //rww - fix to keep from rendering repeatedly while HUD menu is up
00394                 return;
00395         }
00396 
00397         if (cent->currentState.eFlags & EF_NODRAW)
00398         {
00399                 return;
00400         }
00401 
00402         // decode the data stored in time2
00403         xaxis = ((cent->currentState.time2 >> 24) & 1);
00404         height = ((cent->currentState.time2 >> 16) & 255);
00405         posWidth = ((cent->currentState.time2 >> 8) & 255);
00406         negWidth = (cent->currentState.time2 & 255);
00407 
00408         team = (cent->currentState.otherEntityNum2);
00409 
00410         VectorClear(normal);
00411 
00412         VectorCopy(cent->lerpOrigin, start);
00413         VectorCopy(cent->lerpOrigin, end);
00414 
00415         if (xaxis) // drawing along x-axis
00416         {
00417                 start[0] -= negWidth;
00418                 end[0] += posWidth;
00419         }
00420         else
00421         {
00422                 start[1] -= negWidth;
00423                 end[1] += posWidth;
00424         }
00425 
00426         normal[0] = 1;
00427         normal[1] = 1;
00428 
00429         start[2] += height/2;
00430         end[2] += height/2;
00431 
00432         if (team == TEAM_RED)
00433         {
00434                 if (cent->currentState.trickedentindex)
00435                 {
00436                         shader = trap_R_RegisterShader( "gfx/misc/red_dmgshield" );
00437                 }
00438                 else
00439                 {
00440                         shader = trap_R_RegisterShader( "gfx/misc/red_portashield" );
00441                 }
00442         }
00443         else
00444         {
00445                 if (cent->currentState.trickedentindex)
00446                 {
00447                         shader = trap_R_RegisterShader( "gfx/misc/blue_dmgshield" );
00448                 }
00449                 else
00450                 {
00451                         shader = trap_R_RegisterShader( "gfx/misc/blue_portashield" );
00452                 }
00453         }
00454 
00455         le = FX_AddOrientedLine(start, end, normal, 1.0f, height, 0.0f, 1.0f, 1.0f, 50.0, shader);
00456 }
00457 
00458 /*
00459 ==================
00460 CG_Special
00461 ==================
00462 */
00463 void CG_Special( centity_t *cent ) {
00464         entityState_t           *s1;
00465 
00466         s1 = &cent->currentState;
00467 
00468         if (!s1)
00469         {
00470                 return;
00471         }
00472 
00473         // if set to invisible, skip
00474         if (!s1->modelindex) {
00475                 return;
00476         }
00477 
00478         if (s1->modelindex == HI_SHIELD) 
00479         {       // The portable shield should go through a different rendering function.
00480                 FX_DrawPortableShield(cent);
00481                 return;
00482         }
00483 }
00484 
00485 /*
00486 Ghoul2 Insert Start
00487 */
00488 
00489 // Copy the ghoul2 data into the ref ent correctly
00490 void CG_SetGhoul2Info( refEntity_t *ent, centity_t *cent)
00491 {
00492 
00493         ent->ghoul2 = cent->ghoul2;
00494         VectorCopy( cent->modelScale, ent->modelScale);
00495         ent->radius = cent->radius;
00496         VectorCopy (cent->lerpAngles, ent->angles);
00497 }
00498 
00499 
00500 
00501 // create 8 new points on screen around a model so we can see it's bounding box
00502 void CG_CreateBBRefEnts(entityState_t *s1, vec3_t origin )
00503 {
00504 /* 
00505 //g2r
00506 #if _DEBUG
00507         refEntity_t             point[8];
00508         int                             i;
00509         vec3_t                  angles = {0,0,0};
00510 
00511         for (i=0; i<8; i++)
00512         {
00513                 memset (&point[i], 0, sizeof(refEntity_t));
00514                 point[i].reType = RT_SPRITE;
00515                 point[i].radius = 1;
00516                 point[i].customShader = trap_R_RegisterShader("textures/tests/circle");
00517                 point[i].shaderRGBA[0] = 255;
00518                 point[i].shaderRGBA[1] = 255;
00519                 point[i].shaderRGBA[2] = 255;
00520                 point[i].shaderRGBA[3] = 255;
00521 
00522                 AnglesToAxis( angles, point[i].axis );
00523 
00524                 // now, we need to put the correct origins into each origin from the mins and max's
00525                 switch(i)
00526                 {
00527                 case 0:
00528                         VectorCopy(s1->mins, point[i].origin);
00529                         break;
00530                 case 1:
00531                         VectorCopy(s1->mins, point[i].origin);
00532                         point[i].origin[0] = s1->maxs[0];
00533                         break;
00534                 case 2:
00535                         VectorCopy(s1->mins, point[i].origin);
00536                         point[i].origin[1] = s1->maxs[1];
00537                         break;
00538                 case 3:
00539                         VectorCopy(s1->mins, point[i].origin);
00540                         point[i].origin[0] = s1->maxs[0];
00541                         point[i].origin[1] = s1->maxs[1];
00542                         break;
00543                 case 4:
00544                         VectorCopy(s1->maxs, point[i].origin);
00545                         break;
00546                 case 5:
00547                         VectorCopy(s1->maxs, point[i].origin);
00548                         point[i].origin[0] = s1->mins[0];
00549                         break;
00550                 case 6:
00551                         VectorCopy(s1->maxs, point[i].origin);
00552                         point[i].origin[1] = s1->mins[1];
00553                         break;
00554                 case 7:
00555                         VectorCopy(s1->maxs, point[i].origin);
00556                         point[i].origin[0] = s1->mins[0];
00557                         point[i].origin[1] = s1->mins[1];
00558                         break;
00559                 }
00560 
00561                 // add the original origin to each point and then stuff them out there
00562                 VectorAdd(point[i].origin, origin, point[i].origin);
00563 
00564                 trap_R_AddRefEntityToScene (&point[i]);
00565         }
00566 #endif
00567         */
00568 }
00569 
00570 // write in the axis and stuff
00571 void G2_BoltToGhoul2Model(centity_t *cent, refEntity_t *ent)
00572 {
00573                 // extract the wraith ID from the bolt info
00574         int modelNum = cent->boltInfo >> MODEL_SHIFT;
00575         int boltNum     = cent->boltInfo >> BOLT_SHIFT;
00576         int     entNum = cent->boltInfo >> ENTITY_SHIFT;
00577         mdxaBone_t              boltMatrix;
00578         
00579         modelNum &= MODEL_AND;
00580         boltNum &= BOLT_AND;
00581         entNum &= ENTITY_AND;
00582 
00583 
00584         //NOTENOTE I put this here because the cgs.gamemodels array no longer gets initialized.
00585         assert(0);              
00586 
00587 
00588         // go away and get me the bolt position for this frame please
00589         trap_G2API_GetBoltMatrix(cent->ghoul2, modelNum, boltNum, &boltMatrix, cg_entities[entNum].currentState.angles, cg_entities[entNum].currentState.origin, cg.time, cgs.gameModels, cent->modelScale);
00590 
00591         // set up the axis and origin we need for the actual effect spawning
00592         ent->origin[0] = boltMatrix.matrix[0][3];
00593         ent->origin[1] = boltMatrix.matrix[1][3];
00594         ent->origin[2] = boltMatrix.matrix[2][3];
00595 
00596         ent->axis[0][0] = boltMatrix.matrix[0][0];
00597         ent->axis[0][1] = boltMatrix.matrix[1][0];
00598         ent->axis[0][2] = boltMatrix.matrix[2][0];
00599 
00600         ent->axis[1][0] = boltMatrix.matrix[0][1];
00601         ent->axis[1][1] = boltMatrix.matrix[1][1];
00602         ent->axis[1][2] = boltMatrix.matrix[2][1];
00603 
00604         ent->axis[2][0] = boltMatrix.matrix[0][2];
00605         ent->axis[2][1] = boltMatrix.matrix[1][2];
00606         ent->axis[2][2] = boltMatrix.matrix[2][2];
00607 }
00608 
00609 void ScaleModelAxis(refEntity_t *ent)
00610 
00611 {               // scale the model should we need to
00612                 if (ent->modelScale[0] && ent->modelScale[0] != 1.0f)
00613                 {
00614                         VectorScale( ent->axis[0], ent->modelScale[0] , ent->axis[0] );
00615                         ent->nonNormalizedAxes = qtrue;
00616                 }
00617                 if (ent->modelScale[1] && ent->modelScale[1] != 1.0f)
00618                 {
00619                         VectorScale( ent->axis[1], ent->modelScale[1] , ent->axis[1] );
00620                         ent->nonNormalizedAxes = qtrue;
00621                 }
00622                 if (ent->modelScale[2] && ent->modelScale[2] != 1.0f)
00623                 {
00624                         VectorScale( ent->axis[2], ent->modelScale[2] , ent->axis[2] );
00625                         ent->nonNormalizedAxes = qtrue;
00626                 }
00627 }
00628 /*
00629 Ghoul2 Insert End
00630 */
00631 
00632 char *forceHolocronModels[] = {
00633         "models/map_objects/mp/lt_heal.md3",            //FP_HEAL,
00634         "models/map_objects/mp/force_jump.md3",         //FP_LEVITATION,
00635         "models/map_objects/mp/force_speed.md3",        //FP_SPEED,
00636         "models/map_objects/mp/force_push.md3",         //FP_PUSH,
00637         "models/map_objects/mp/force_pull.md3",         //FP_PULL,
00638         "models/map_objects/mp/lt_telepathy.md3",       //FP_TELEPATHY,
00639         "models/map_objects/mp/dk_grip.md3",            //FP_GRIP,
00640         "models/map_objects/mp/dk_lightning.md3",       //FP_LIGHTNING,
00641         "models/map_objects/mp/dk_rage.md3",            //FP_RAGE,
00642         "models/map_objects/mp/lt_protect.md3",         //FP_PROTECT,
00643         "models/map_objects/mp/lt_absorb.md3",          //FP_ABSORB,
00644         "models/map_objects/mp/lt_healother.md3",       //FP_TEAM_HEAL,
00645         "models/map_objects/mp/dk_powerother.md3",      //FP_TEAM_FORCE,
00646         "models/map_objects/mp/dk_drain.md3",           //FP_DRAIN,
00647         "models/map_objects/mp/force_sight.md3",        //FP_SEE,
00648         "models/map_objects/mp/saber_attack.md3",       //FP_SABER_OFFENSE,
00649         "models/map_objects/mp/saber_defend.md3",       //FP_SABER_DEFENSE,
00650         "models/map_objects/mp/saber_throw.md3"         //FP_SABERTHROW
00651 };
00652 
00653 void CG_Disintegration(centity_t *cent, refEntity_t *ent)
00654 {
00655         vec3_t tempAng, hitLoc;
00656         float tempLength;
00657 
00658         VectorCopy(cent->currentState.origin2, hitLoc);
00659 
00660         VectorSubtract( hitLoc, ent->origin, ent->oldorigin );
00661         
00662         tempLength = VectorNormalize( ent->oldorigin );
00663         vectoangles( ent->oldorigin, tempAng );
00664         tempAng[YAW] -= cent->lerpAngles[YAW];
00665         AngleVectors( tempAng, ent->oldorigin, NULL, NULL );
00666         VectorScale( ent->oldorigin, tempLength, ent->oldorigin );
00667 
00668         ent->endTime = cent->dustTrailTime;
00669 
00670         ent->renderfx |= RF_DISINTEGRATE2;
00671         ent->customShader = cgs.media.disruptorShader;
00672         trap_R_AddRefEntityToScene( ent );
00673 
00674         ent->renderfx &= ~(RF_DISINTEGRATE2);
00675         ent->renderfx |= (RF_DISINTEGRATE1);
00676         ent->customShader = 0;
00677         trap_R_AddRefEntityToScene( ent );
00678 
00679         if ( cg.time - ent->endTime < 1000 && (cg_timescale.value * cg_timescale.value * random()) > 0.05f )
00680         {
00681                 vec3_t fxOrg, fxDir;
00682                 mdxaBone_t      boltMatrix;
00683                 int torsoBolt = trap_G2API_AddBolt(cent->ghoul2, 0, "lower_lumbar");
00684 
00685                 VectorSet(fxDir, 0, 1, 0);
00686 
00687                 trap_G2API_GetBoltMatrix( cent->ghoul2, 0, torsoBolt, &boltMatrix, cent->lerpAngles, cent->lerpOrigin, cg.time, 
00688                                 cgs.gameModels, cent->modelScale);
00689                                 BG_GiveMeVectorFromMatrix( &boltMatrix, ORIGIN, fxOrg );
00690 
00691                 VectorMA( fxOrg, -18, cg.refdef.viewaxis[0], fxOrg );
00692                 fxOrg[2] += crandom() * 20;
00693                 trap_FX_PlayEffectID( cgs.effects.mDisruptorDeathSmoke, fxOrg, fxDir, -1, -1 );
00694 
00695                 if ( random() > 0.5f )
00696                 {
00697                         trap_FX_PlayEffectID( cgs.effects.mDisruptorDeathSmoke, fxOrg, fxDir, -1, -1 );
00698                 }
00699         }
00700 }
00701 
00702 extern int cgSiegeEntityRender;
00703 static qboolean CG_RenderTimeEntBolt(centity_t *cent)
00704 {
00705         int clientNum = cent->currentState.boltToPlayer-1;
00706         centity_t *cl;
00707         mdxaBone_t matrix;
00708         vec3_t boltOrg, boltAng;
00709         int getBolt = -1;
00710 
00711         if (clientNum >= MAX_CLIENTS || clientNum < 0)
00712         {
00713                 assert(0);
00714                 return qfalse;
00715         }
00716 
00717         cl = &cg_entities[clientNum];
00718 
00719         if (!cl->ghoul2)
00720         {
00721                 assert(0);
00722                 return qfalse;
00723         }
00724 
00725         if (clientNum == cg.predictedPlayerState.clientNum &&
00726                 !cg.renderingThirdPerson)
00727         { //If in first person and you have it then render the thing spinning around on your hud.
00728                 cgSiegeEntityRender = cent->currentState.number; //set it to render at the end of the frame.
00729                 return qfalse;
00730         }
00731 
00732         getBolt = trap_G2API_AddBolt(cl->ghoul2, 0, "lhand");
00733 
00734         trap_G2API_GetBoltMatrix(cl->ghoul2, 0, getBolt, &matrix, cl->turAngles, cl->lerpOrigin, cg.time, cgs.gameModels, cl->modelScale);
00735 
00736         BG_GiveMeVectorFromMatrix(&matrix, ORIGIN, boltOrg);
00737         BG_GiveMeVectorFromMatrix(&matrix, NEGATIVE_Y, boltAng);
00738         vectoangles(boltAng, boltAng);
00739         boltAng[PITCH] = boltAng[ROLL] = 0;
00740 
00741         VectorCopy(boltOrg, cent->lerpOrigin);
00742         VectorCopy(boltAng, cent->lerpAngles);
00743 
00744         return qtrue;
00745 }
00746 
00747 /*
00748 static void CG_SiegeEntRenderAboveHead(centity_t *cent)
00749 {
00750         int clientNum = cent->currentState.boltToPlayer-1;
00751         centity_t *cl;
00752         refEntity_t ent;
00753         vec3_t renderAngles;
00754 
00755         if (clientNum >= MAX_CLIENTS || clientNum < 0)
00756         {
00757                 assert(0);
00758                 return;
00759         }
00760 
00761         cl = &cg_entities[clientNum];
00762 
00763         memset(&ent, 0, sizeof(ent));
00764 
00765         //Set the angles to the global auto rotating ones, and the origin to slightly above the client
00766         VectorCopy(cg.autoAngles, renderAngles);
00767         AnglesToAxis( renderAngles, ent.axis );
00768         VectorCopy(cl->lerpOrigin, ent.origin);
00769         ent.origin[2] += 50;
00770 
00771         //Set the model (ghoul2 or md3/other)
00772         if (cent->ghoul2)
00773         {
00774                 ent.ghoul2 = cent->ghoul2;
00775                 ent.hModel = 0;
00776         }
00777         else
00778         {
00779                 ent.ghoul2 = NULL;
00780                 ent.hModel = cgs.gameModels[cent->currentState.modelindex];
00781         }
00782 
00783         //Scale it up
00784         ent.modelScale[0] = 1.5f;
00785         ent.modelScale[1] = 1.5f;
00786         ent.modelScale[2] = 1.5f;
00787         ScaleModelAxis(&ent);
00788 
00789         //Make it transparent
00790         ent.renderfx = RF_FORCE_ENT_ALPHA;
00791         ent.shaderRGBA[0] = ent.shaderRGBA[1] = ent.shaderRGBA[2] = 255;
00792         ent.shaderRGBA[3] = 100;
00793 
00794         //And finally add it
00795         trap_R_AddRefEntityToScene(&ent);
00796 }
00797 */
00798 
00799 void CG_AddRadarEnt(centity_t *cent) 
00800 {
00801         if (cg.radarEntityCount == sizeof(cg.radarEntities)/sizeof(cg.radarEntities[0]))
00802         {       
00803 #ifdef _DEBUG
00804                 Com_Printf("^3Warning: CG_AddRadarEnt full. (%d max)\n", sizeof(cg.radarEntities)/sizeof(cg.radarEntities[0]));
00805 #endif
00806                 return;
00807         }
00808         cg.radarEntities[cg.radarEntityCount++] = cent->currentState.number;
00809 }
00810 
00811 void CG_AddBracketedEnt(centity_t *cent) 
00812 {
00813         if (cg.bracketedEntityCount == sizeof(cg.bracketedEntities)/sizeof(cg.bracketedEntities[0]))
00814         {       
00815 #ifdef _DEBUG
00816                 Com_Printf("^3Warning: CG_AddBracketedEnt full. (%d max)\n", sizeof(cg.radarEntities)/sizeof(cg.bracketedEntities[0]));
00817 #endif
00818                 return;
00819         }
00820         cg.bracketedEntities[cg.bracketedEntityCount++] = cent->currentState.number;
00821 }
00822 /*
00823 ==================
00824 CG_General
00825 ==================
00826 */
00827 void CG_G2ServerBoneAngles(centity_t *cent);
00828 
00829 #include "../namespace_begin.h"
00830 extern qboolean BG_GetRootSurfNameWithVariant( void *ghoul2, const char *rootSurfName, char *returnSurfName, int returnSize );
00831 #include "../namespace_end.h"
00832 
00833 static void CG_General( centity_t *cent ) {
00834         refEntity_t                     ent;
00835         entityState_t           *s1;
00836         float                           val;
00837         int                                     beamID;
00838         vec3_t                          beamOrg;
00839         mdxaBone_t                      matrix;
00840         qboolean                        doNotSetModel = qfalse;
00841 
00842         if (cent->currentState.modelGhoul2 == 127)
00843         { //not ready to be drawn or initialized..
00844                 return;
00845         }
00846 
00847         if (cent->ghoul2 && !cent->currentState.modelGhoul2 && cent->currentState.eType != ET_BODY &&
00848                 cent->currentState.number >= MAX_CLIENTS)
00849         { //this is a bad thing
00850                 if (trap_G2_HaveWeGhoul2Models(cent->ghoul2))
00851                 {
00852                         trap_G2API_CleanGhoul2Models(&(cent->ghoul2));
00853                 }
00854         }
00855         
00856         if (cent->currentState.eFlags & EF_RADAROBJECT)
00857         {
00858                 CG_AddRadarEnt(cent);
00859         }
00860         if (cent->currentState.eFlags2 & EF2_BRACKET_ENTITY)
00861         {
00862                 if ( CG_InFighter() )
00863                 {//only bracken when in a fighter
00864                         CG_AddBracketedEnt(cent);
00865                 }
00866         }
00867         
00868         if (cent->currentState.boltToPlayer)
00869         { //Shove it into the player's left hand then.
00870                 centity_t *pl = &cg_entities[cent->currentState.boltToPlayer-1];
00871                 if (CG_IsMindTricked(pl->currentState.trickedentindex,
00872                         pl->currentState.trickedentindex2,
00873                         pl->currentState.trickedentindex3,
00874                         pl->currentState.trickedentindex4,
00875                         cg.predictedPlayerState.clientNum))
00876                 { //don't show if this guy is mindtricking
00877             return;
00878                 }
00879                 if (!CG_RenderTimeEntBolt(cent))
00880                 { //If this function returns qfalse we shouldn't render this ent at all.
00881                         if (cent->currentState.boltToPlayer > 0 &&
00882                                 cent->currentState.boltToPlayer <= MAX_CLIENTS)
00883                         {
00884                                 VectorCopy(pl->lerpOrigin, cent->lerpOrigin);
00885 
00886                                 if (cent->currentState.eFlags & EF_CLIENTSMOOTH)
00887                                 { //if it's set to smooth keep the smoothed lerp origin updated, as we don't want to smooth while bolted.
00888                                         VectorCopy(cent->lerpOrigin, cent->turAngles);
00889                                 }
00890                         }
00891                         return;
00892                 }
00893 
00894                 if (cent->currentState.eFlags & EF_CLIENTSMOOTH)
00895                 { //if it's set to smooth keep the smoothed lerp origin updated, as we don't want to smooth while bolted.
00896                         VectorCopy(cent->lerpOrigin, cent->turAngles);
00897                 }
00898 
00899 /* disabled for now
00900                 if (pl->currentState.number != cg.predictedPlayerState.clientNum)
00901                 { //don't render thing above head to self
00902                         CG_SiegeEntRenderAboveHead(cent);
00903                 }
00904 */
00905         }
00906         else if (cent->currentState.eFlags & EF_CLIENTSMOOTH)
00907         {
00908                 if (cent->currentState.groundEntityNum >= ENTITYNUM_WORLD)
00909                 {
00910                         float smoothFactor = 0.5f*cg_timescale.value;
00911                         int k = 0;
00912                         vec3_t posDif;
00913 
00914                         //Use origin smoothing since dismembered limbs use ExPhys
00915                         if (DistanceSquared(cent->turAngles,cent->lerpOrigin)>18000.0f)
00916                         {
00917                                 VectorCopy(cent->lerpOrigin, cent->turAngles);
00918                         }
00919 
00920                         VectorSubtract(cent->lerpOrigin, cent->turAngles, posDif);
00921                         
00922                         for (k=0;k<3;k++)
00923                         {
00924                                 cent->turAngles[k]=(cent->turAngles[k]+posDif[k]*smoothFactor);
00925                                 cent->lerpOrigin[k]=cent->turAngles[k];
00926                         }
00927                 }
00928                 else
00929                 { //if we're sitting on an entity like a moving plat then we don't want to smooth either
00930                         VectorCopy(cent->lerpOrigin, cent->turAngles);
00931                 }
00932         }
00933 
00934         //rww - now do ragdoll stuff
00935         if (cent->ghoul2 &&
00936                 (cent->currentState.eType == ET_BODY || (cent->currentState.eFlags & EF_RAG)))
00937         {
00938                 if (!(cent->currentState.eFlags & EF_NODRAW) &&
00939                         !(cent->currentState.eFlags & EF_DISINTEGRATION) &&
00940                         cent->bodyFadeTime <= cg.time)
00941                 {
00942                         vec3_t forcedAngles;
00943 
00944                         VectorClear(forcedAngles);
00945                         forcedAngles[YAW] = cent->lerpAngles[YAW];
00946 
00947                         CG_RagDoll(cent, forcedAngles);
00948                 }
00949         }
00950         else if (cent->isRagging)
00951         {
00952                 cent->isRagging = qfalse;
00953 
00954                 if (cent->ghoul2 && trap_G2_HaveWeGhoul2Models(cent->ghoul2))
00955                 { //May not be valid, in the case of a ragged entity being removed and a non-g2 ent filling its slot.
00956                         trap_G2API_SetRagDoll(cent->ghoul2, NULL); //calling with null parms resets to no ragdoll.
00957                 }
00958         }
00959 
00960         if (cent->currentState.boneOrient && cent->ghoul2)
00961         { //server sent us some bone angles to use
00962                 CG_G2ServerBoneAngles(cent);
00963         }
00964 
00965         if ((cent->currentState.eFlags & EF_G2ANIMATING) && cent->ghoul2)
00966         { //mini-animation routine for general objects that want to play quick ghoul2 anims
00967                 //obviously lacks much of the functionality contained in player/npc animation.
00968                 //we actually use torsoAnim as the start frame and legsAnim as the end frame and
00969                 //always play the anim on the root bone.
00970                 if (cent->currentState.torsoAnim != cent->pe.torso.animationNumber ||
00971                         cent->currentState.legsAnim != cent->pe.legs.animationNumber ||
00972                         cent->currentState.torsoFlip != cent->pe.torso.lastFlip)
00973                 {
00974                         trap_G2API_SetBoneAnim(cent->ghoul2, 0, "model_root", cent->currentState.torsoAnim,
00975                                 cent->currentState.legsAnim, (BONE_ANIM_OVERRIDE_FREEZE|BONE_ANIM_BLEND), 1.0f, cg.time, -1, 100);
00976 
00977                         cent->pe.torso.animationNumber = cent->currentState.torsoAnim;
00978                         cent->pe.legs.animationNumber = cent->currentState.legsAnim;
00979                         cent->pe.torso.lastFlip = cent->currentState.torsoFlip;
00980                 }
00981         }
00982 
00983         memset (&ent, 0, sizeof(ent));
00984 
00985         ent.shaderRGBA[0] = cent->currentState.customRGBA[0];
00986         ent.shaderRGBA[1] = cent->currentState.customRGBA[1];
00987         ent.shaderRGBA[2] = cent->currentState.customRGBA[2];
00988         ent.shaderRGBA[3] = cent->currentState.customRGBA[3];
00989 
00990         if (cent->currentState.modelGhoul2 >= G2_MODELPART_HEAD &&
00991                 cent->currentState.modelGhoul2 <= G2_MODELPART_RLEG &&
00992                 /*cent->currentState.modelindex < MAX_CLIENTS &&*/
00993                 cent->currentState.weapon == G2_MODEL_PART)
00994         { //special case for client limbs
00995                 centity_t *clEnt;
00996                 int dismember_settings = cg_dismember.integer;
00997                 float smoothFactor = 0.5f*cg_timescale.value;
00998                 int k = 0;
00999                 vec3_t posDif;
01000                 
01001                 doNotSetModel = qtrue;
01002 
01003                 if (cent->currentState.modelindex >= 0)
01004                 {
01005                         clEnt = &cg_entities[cent->currentState.modelindex];
01006                 }
01007                 else
01008                 {
01009                         clEnt = &cg_entities[cent->currentState.otherEntityNum2];
01010                 }
01011 
01012                 if (!dismember_settings)
01013                 { //This client does not wish to see dismemberment.
01014                         return;
01015                 }
01016 
01017                 if (dismember_settings < 2 && (cent->currentState.modelGhoul2 == G2_MODELPART_HEAD || cent->currentState.modelGhoul2 == G2_MODELPART_WAIST))
01018                 { //dismember settings are not high enough to display decaps and torso slashes
01019                         return;
01020                 }
01021 
01022                 if (!cent->ghoul2)
01023                 {
01024                         const char *limbBone;
01025                         const char *rotateBone;
01026                         char    limbName[MAX_QPATH];
01027                         char    stubName[MAX_QPATH];
01028                         char    limbCapName[MAX_QPATH];
01029                         char    stubCapName[MAX_QPATH];
01030                         char *limbTagName;
01031                         char *stubTagName;
01032                         int limb_anim;
01033                         int newBolt;
01034                         int limbBit = (1 << (cent->currentState.modelGhoul2-10));
01035 
01036                         if (clEnt && (clEnt->torsoBolt & limbBit))
01037                         { //already have this limb missing!
01038                                 return;
01039                         }
01040 
01041 
01042                         if (clEnt && !(clEnt->currentState.eFlags & EF_DEAD))
01043                         { //death flag hasn't made it through yet for the limb owner, we cannot create the limb until he's flagged as dead
01044                                 return;
01045                         }
01046 
01047                         if (clEnt && (!BG_InDeathAnim(clEnt->currentState.torsoAnim) || !BG_InDeathAnim(clEnt->pe.torso.animationNumber)))
01048                         { //don't make it unless we're in an actual death anim already
01049                                 if (clEnt->currentState.torsoAnim != BOTH_RIGHTHANDCHOPPEDOFF)
01050                                 { //exception
01051                                         return;
01052                                 }
01053                         }
01054 
01055                         cent->bolt4 = -1;
01056                         cent->trailTime = 0;
01057 
01058                         if (cent->currentState.modelGhoul2 == G2_MODELPART_HEAD)
01059                         {
01060                                 limbBone = "cervical";
01061                                 rotateBone = "cranium";
01062                                 Q_strncpyz( limbName , "head", sizeof( limbName  ) );
01063                                 Q_strncpyz( limbCapName, "head_cap_torso", sizeof( limbCapName ) );
01064                                 Q_strncpyz( stubCapName, "torso_cap_head", sizeof( stubCapName ) );
01065                                 limbTagName = "*head_cap_torso";
01066                                 stubTagName = "*torso_cap_head";
01067                                 limb_anim = BOTH_DISMEMBER_HEAD1;
01068                         }
01069                         else if (cent->currentState.modelGhoul2 == G2_MODELPART_WAIST)
01070                         {
01071                                 limbBone = "pelvis";
01072 
01073                                 if (clEnt->localAnimIndex <= 1)
01074                                 { //humanoid/rtrooper
01075                                         rotateBone = "thoracic";
01076                                 }
01077                                 else
01078                                 {
01079                                         rotateBone = "pelvis";
01080                                 }
01081                                 Q_strncpyz( limbName, "torso", sizeof( limbName ) );
01082                                 Q_strncpyz( limbCapName, "torso_cap_hips", sizeof( limbCapName ) );
01083                                 Q_strncpyz( stubCapName, "hips_cap_torso", sizeof( stubCapName ) );
01084                                 limbTagName = "*torso_cap_hips";
01085                                 stubTagName = "*hips_cap_torso";
01086                                 limb_anim = BOTH_DISMEMBER_TORSO1;
01087                         }
01088                         else if (cent->currentState.modelGhoul2 == G2_MODELPART_LARM)
01089                         {
01090                                 limbBone = "lhumerus";
01091                                 rotateBone = "lradius";
01092                                 BG_GetRootSurfNameWithVariant( clEnt->ghoul2, "l_arm", limbName, sizeof(limbName) );
01093                                 BG_GetRootSurfNameWithVariant( clEnt->ghoul2, "torso", stubName, sizeof(stubName) );
01094                                 Com_sprintf( limbCapName, sizeof( limbCapName ), "%s_cap_torso", limbName );
01095                                 Com_sprintf( stubCapName, sizeof( stubCapName), "%s_cap_l_arm", stubName );
01096                                 limbTagName = "*l_arm_cap_torso";
01097                                 stubTagName = "*torso_cap_l_arm";
01098                                 limb_anim = BOTH_DISMEMBER_LARM;
01099                         }
01100                         else if (cent->currentState.modelGhoul2 == G2_MODELPART_RARM)
01101                         {
01102                                 limbBone = "rhumerus";
01103                                 rotateBone = "rradius";
01104                                 BG_GetRootSurfNameWithVariant( clEnt->ghoul2, "r_arm", limbName, sizeof(limbName) );
01105                                 BG_GetRootSurfNameWithVariant( clEnt->ghoul2, "torso", stubName, sizeof(stubName) );
01106                                 Com_sprintf( limbCapName, sizeof( limbCapName ), "%s_cap_torso", limbName );
01107                                 Com_sprintf( stubCapName, sizeof( stubCapName), "%s_cap_r_arm", stubName );
01108                                 limbTagName = "*r_arm_cap_torso";
01109                                 stubTagName = "*torso_cap_r_arm";
01110                                 limb_anim = BOTH_DISMEMBER_RARM;
01111                         }
01112                         else if (cent->currentState.modelGhoul2 == G2_MODELPART_RHAND)
01113                         {
01114                                 limbBone = "rradiusX";
01115                                 rotateBone = "rhand";
01116                                 BG_GetRootSurfNameWithVariant( clEnt->ghoul2, "r_hand", limbName, sizeof(limbName) );
01117                                 BG_GetRootSurfNameWithVariant( clEnt->ghoul2, "r_arm", stubName, sizeof(stubName) );
01118                                 Com_sprintf( limbCapName, sizeof( limbCapName ), "%s_cap_r_arm", limbName );
01119                                 Com_sprintf( stubCapName, sizeof( stubCapName), "%s_cap_r_hand", stubName );
01120                                 limbTagName = "*r_hand_cap_r_arm";
01121                                 stubTagName = "*r_arm_cap_r_hand";
01122                                 limb_anim = BOTH_DISMEMBER_RARM;
01123                         }
01124                         else if (cent->currentState.modelGhoul2 == G2_MODELPART_LLEG)
01125                         {
01126                                 limbBone = "lfemurYZ";
01127                                 rotateBone = "ltibia";
01128                                 BG_GetRootSurfNameWithVariant( clEnt->ghoul2, "l_leg", limbName, sizeof(limbName) );
01129                                 BG_GetRootSurfNameWithVariant( clEnt->ghoul2, "hips", stubName, sizeof(stubName) );
01130                                 Com_sprintf( limbCapName, sizeof( limbCapName ), "%s_cap_hips", limbName );
01131                                 Com_sprintf( stubCapName, sizeof( stubCapName), "%s_cap_l_leg", stubName );
01132                                 limbTagName = "*l_leg_cap_hips";
01133                                 stubTagName = "*hips_cap_l_leg";
01134                                 limb_anim = BOTH_DISMEMBER_LLEG;
01135                         }
01136                         else if (cent->currentState.modelGhoul2 == G2_MODELPART_RLEG)
01137                         {
01138                                 limbBone = "rfemurYZ";
01139                                 rotateBone = "rtibia";
01140                                 BG_GetRootSurfNameWithVariant( clEnt->ghoul2, "r_leg", limbName, sizeof(limbName) );
01141                                 BG_GetRootSurfNameWithVariant( clEnt->ghoul2, "hips", stubName, sizeof(stubName) );
01142                                 Com_sprintf( limbCapName, sizeof( limbCapName ), "%s_cap_hips", limbName );
01143                                 Com_sprintf( stubCapName, sizeof( stubCapName), "%s_cap_r_leg", stubName );
01144                                 limbTagName = "*r_leg_cap_hips";
01145                                 stubTagName = "*hips_cap_r_leg";
01146                                 limb_anim = BOTH_DISMEMBER_RLEG;
01147                         }
01148                         else
01149                         {//umm... just default to the right leg, I guess (same as on server)
01150                                 limbBone = "rfemurYZ";
01151                                 rotateBone = "rtibia";
01152                                 BG_GetRootSurfNameWithVariant( clEnt->ghoul2, "r_leg", limbName, sizeof(limbName) );
01153                                 BG_GetRootSurfNameWithVariant( clEnt->ghoul2, "hips", stubName, sizeof(stubName) );
01154                                 Com_sprintf( limbCapName, sizeof( limbCapName ), "%s_cap_hips", limbName );
01155                                 Com_sprintf( stubCapName, sizeof( stubCapName), "%s_cap_r_leg", stubName );
01156                                 limbTagName = "*r_leg_cap_hips";
01157                                 stubTagName = "*hips_cap_r_leg";
01158                                 limb_anim = BOTH_DISMEMBER_RLEG;
01159                         }
01160 
01161                         if (clEnt && clEnt->ghoul2)
01162                         {
01163                                 if (trap_G2API_HasGhoul2ModelOnIndex(&(clEnt->ghoul2), 2))
01164                                 { //don't want to bother dealing with a second saber on limbs and stuff, just remove the thing
01165                                         trap_G2API_RemoveGhoul2Model(&(clEnt->ghoul2), 2);
01166                                 }
01167 
01168                                 if (trap_G2API_HasGhoul2ModelOnIndex(&(clEnt->ghoul2), 3))
01169                                 { //turn off jetpack also I suppose
01170                                         trap_G2API_RemoveGhoul2Model(&(clEnt->ghoul2), 3);
01171                                 }
01172 
01173                                 if (clEnt->localAnimIndex <= 0)
01174                                 { //humanoid
01175                                         trap_G2API_SetBoneAngles(clEnt->ghoul2, 0, "model_root", vec3_origin, BONE_ANGLES_POSTMULT, POSITIVE_X, NEGATIVE_Y, NEGATIVE_Z, cgs.gameModels, 100, cg.time);
01176                                         trap_G2API_SetBoneAngles(clEnt->ghoul2, 0, "pelvis", vec3_origin, BONE_ANGLES_POSTMULT, POSITIVE_X, NEGATIVE_Y, NEGATIVE_Z, cgs.gameModels, 0, cg.time); 
01177                                         trap_G2API_SetBoneAngles(clEnt->ghoul2, 0, "thoracic", vec3_origin, BONE_ANGLES_POSTMULT, POSITIVE_X, NEGATIVE_Y, NEGATIVE_Z, cgs.gameModels, 0, cg.time); 
01178                                         trap_G2API_SetBoneAngles(clEnt->ghoul2, 0, "upper_lumbar", vec3_origin, BONE_ANGLES_POSTMULT, POSITIVE_X, NEGATIVE_Y, NEGATIVE_Z, cgs.gameModels, 100, cg.time);
01179                                         trap_G2API_SetBoneAngles(clEnt->ghoul2, 0, "lower_lumbar", vec3_origin, BONE_ANGLES_POSTMULT, POSITIVE_X, NEGATIVE_Y, NEGATIVE_Z, cgs.gameModels, 100, cg.time);
01180                                         trap_G2API_SetBoneAngles(clEnt->ghoul2, 0, "cranium", vec3_origin, BONE_ANGLES_POSTMULT, POSITIVE_Z, NEGATIVE_Y, POSITIVE_X, cgs.gameModels, 100, cg.time);
01181                                 }
01182                                 else
01183                                 {
01184                                         trap_G2API_SetBoneAngles(clEnt->ghoul2, 0, "model_root", vec3_origin, BONE_ANGLES_POSTMULT, POSITIVE_X, NEGATIVE_Y, NEGATIVE_Z, cgs.gameModels, 100, cg.time);
01185                                         trap_G2API_SetBoneAngles(clEnt->ghoul2, 0, "pelvis", vec3_origin, BONE_ANGLES_POSTMULT, POSITIVE_X, NEGATIVE_Y, NEGATIVE_Z, cgs.gameModels, 0, cg.time); 
01186                                         trap_G2API_SetBoneAngles(clEnt->ghoul2, 0, "upper_lumbar", vec3_origin, BONE_ANGLES_POSTMULT, POSITIVE_X, NEGATIVE_Y, NEGATIVE_Z, cgs.gameModels, 100, cg.time);
01187                                         trap_G2API_SetBoneAngles(clEnt->ghoul2, 0, "lower_lumbar", vec3_origin, BONE_ANGLES_POSTMULT, POSITIVE_X, NEGATIVE_Y, NEGATIVE_Z, cgs.gameModels, 100, cg.time);
01188                                 }
01189 
01190                                 trap_G2API_DuplicateGhoul2Instance(clEnt->ghoul2, &cent->ghoul2);
01191                         }
01192 
01193                         if (!cent->ghoul2)
01194                         {
01195                                 return;
01196                         }
01197 
01198                         newBolt = trap_G2API_AddBolt( cent->ghoul2, 0, limbTagName );
01199                         if ( newBolt != -1 )
01200                         {
01201                                 vec3_t boltOrg, boltAng;
01202 
01203                                 trap_G2API_GetBoltMatrix(cent->ghoul2, 0, newBolt, &matrix, cent->lerpAngles, cent->lerpOrigin, cg.time, cgs.gameModels, cent->modelScale);
01204 
01205                                 BG_GiveMeVectorFromMatrix(&matrix, ORIGIN, bol