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, boltOrg);
01206                                 BG_GiveMeVectorFromMatrix(&matrix, NEGATIVE_Y, boltAng);
01207 
01208                                 trap_FX_PlayEffectID(cgs.effects.mBlasterSmoke, boltOrg, boltAng, -1, -1);
01209                         }
01210 
01211                         cent->bolt4 = newBolt;
01212 
01213                         trap_G2API_SetRootSurface(cent->ghoul2, 0, limbName);
01214 
01215                         trap_G2API_SetNewOrigin(cent->ghoul2, trap_G2API_AddBolt(cent->ghoul2, 0, rotateBone));
01216 
01217                         trap_G2API_SetSurfaceOnOff(cent->ghoul2, limbCapName, 0);
01218 
01219                         trap_G2API_SetSurfaceOnOff(clEnt->ghoul2, limbName, 0x00000100);
01220                         trap_G2API_SetSurfaceOnOff(clEnt->ghoul2, stubCapName, 0);
01221 
01222                         newBolt = trap_G2API_AddBolt( clEnt->ghoul2, 0, stubTagName );
01223                         if ( newBolt != -1 )
01224                         {
01225                                 vec3_t boltOrg, boltAng;
01226 
01227                                 trap_G2API_GetBoltMatrix(clEnt->ghoul2, 0, newBolt, &matrix, clEnt->lerpAngles, clEnt->lerpOrigin, cg.time, cgs.gameModels, clEnt->modelScale);
01228 
01229                                 BG_GiveMeVectorFromMatrix(&matrix, ORIGIN, boltOrg);
01230                                 BG_GiveMeVectorFromMatrix(&matrix, NEGATIVE_Y, boltAng);
01231 
01232                                 trap_FX_PlayEffectID(cgs.effects.mBlasterSmoke, boltOrg, boltAng, -1, -1);
01233                         }
01234 
01235                         if (cent->currentState.modelGhoul2 == G2_MODELPART_RARM || cent->currentState.modelGhoul2 == G2_MODELPART_RHAND || cent->currentState.modelGhoul2 == G2_MODELPART_WAIST)
01236                         { //Cut his weapon holding arm off, so remove the weapon
01237                                 if (trap_G2API_HasGhoul2ModelOnIndex(&(clEnt->ghoul2), 1))
01238                                 {
01239                                         trap_G2API_RemoveGhoul2Model(&(clEnt->ghoul2), 1);
01240                                 }
01241                         }
01242 
01243                         clEnt->torsoBolt |= limbBit; //reinit model after copying limbless one to queue
01244                         //This causes issues after respawning.. just keep track of limbs cut/made on server or something.
01245                         /*
01246                         if (cent->currentState.modelGhoul2 == G2_MODELPART_WAIST)
01247                         {
01248                                 clEnt->torsoBolt |= (1 << (G2_MODELPART_HEAD-10));
01249                                 clEnt->torsoBolt |= (1 << (G2_MODELPART_RARM-10));
01250                                 clEnt->torsoBolt |= (1 << (G2_MODELPART_LARM-10));
01251                                 clEnt->torsoBolt |= (1 << (G2_MODELPART_RHAND-10));
01252                         }
01253                         else if (cent->currentState.modelGhoul2 == G2_MODELPART_RARM)
01254                         {
01255                                 clEnt->torsoBolt |= (1 << (G2_MODELPART_RHAND-10));
01256                         }
01257                         */
01258 
01259                         VectorCopy(cent->lerpOrigin, cent->turAngles);
01260                 //      return;
01261                 }
01262 
01263                 //Use origin smoothing since dismembered limbs use ExPhys
01264                 if (DistanceSquared(cent->turAngles,cent->lerpOrigin)>18000.0f)
01265                 {
01266                         VectorCopy(cent->lerpOrigin, cent->turAngles);
01267                 }
01268 
01269                 VectorSubtract(cent->lerpOrigin, cent->turAngles, posDif);
01270                 
01271                 for (k=0;k<3;k++)
01272                 {
01273                         cent->turAngles[k]=(cent->turAngles[k]+posDif[k]*smoothFactor);
01274                         cent->lerpOrigin[k]=cent->turAngles[k];
01275                 }
01276 
01277                 if (cent->ghoul2 && cent->bolt4 != -1 && cent->trailTime < cg.time)
01278                 {
01279                         if ( cent->bolt4 != -1 && 
01280                                 (cent->currentState.pos.trDelta[0] || cent->currentState.pos.trDelta[1] || cent->currentState.pos.trDelta[2]) )
01281                         {
01282                                 vec3_t boltOrg, boltAng;
01283 
01284                                 trap_G2API_GetBoltMatrix(cent->ghoul2, 0, cent->bolt4, &matrix, cent->lerpAngles, cent->lerpOrigin, cg.time, cgs.gameModels, cent->modelScale);
01285 
01286                                 BG_GiveMeVectorFromMatrix(&matrix, ORIGIN, boltOrg);
01287                                 BG_GiveMeVectorFromMatrix(&matrix, NEGATIVE_Y, boltAng);
01288 
01289                                 if (!boltAng[0] && !boltAng[1] && !boltAng[2])
01290                                 {
01291                                         boltAng[1] = 1;
01292                                 }
01293                                 trap_FX_PlayEffectID(cgs.effects.mBlasterSmoke, boltOrg, boltAng, -1, -1);
01294 
01295                                 cent->trailTime = cg.time + 400;
01296                         }
01297                 }
01298 
01299                 ent.radius = cent->currentState.g2radius;
01300                 ent.hModel = 0;
01301         }
01302 
01303         if (cent->currentState.number >= MAX_CLIENTS &&
01304                 cent->currentState.activeForcePass == NUM_FORCE_POWERS+1&&
01305                 cent->currentState.NPC_class != CLASS_VEHICLE )
01306         {
01307                 vec3_t                          empAngles;
01308                 centity_t                       *empOwn;
01309 
01310                 empOwn = &cg_entities[cent->currentState.emplacedOwner];
01311 
01312                 if (cg.snap->ps.clientNum == empOwn->currentState.number &&
01313                         !cg.renderingThirdPerson)
01314                 {
01315                         VectorCopy(cg.refdef.viewangles, empAngles);
01316                 }
01317                 else
01318                 {
01319                         VectorCopy(empOwn->lerpAngles, empAngles);
01320                 }
01321 
01322                 if (empAngles[PITCH] > 40)
01323                 {
01324                         empAngles[PITCH] = 40;
01325                 }
01326                 empAngles[YAW] -= cent->currentState.angles[YAW];
01327 
01328                 trap_G2API_SetBoneAngles( cent->ghoul2, 0, "Bone02", empAngles, BONE_ANGLES_REPLACE, NEGATIVE_Y, NEGATIVE_X, POSITIVE_Z, NULL, 0, cg.time); 
01329         }
01330 
01331         s1 = &cent->currentState;
01332 
01333         // if set to invisible, skip
01334         if ((!s1->modelindex) && !(trap_G2_HaveWeGhoul2Models(cent->ghoul2))) 
01335         {
01336                 return;
01337         }
01338 
01339         if ( ( s1->eFlags & EF_NODRAW ) ) 
01340         {
01341                 return;
01342         }
01343 
01344         // set frame
01345         if ( s1->eFlags & EF_SHADER_ANIM )
01346         {
01347                 // Deliberately setting it up so that shader anim will completely override any kind of model animation frame setting.
01348                 ent.renderfx|=RF_SETANIMINDEX;
01349                 ent.skinNum = s1->frame;
01350         }
01351         else
01352         {
01353                 ent.frame = s1->frame;
01354         }
01355         ent.oldframe = ent.frame;
01356         ent.backlerp = 0;
01357 
01358 /*
01359 Ghoul2 Insert Start
01360 */
01361         CG_SetGhoul2Info(&ent, cent);
01362 
01363 /*
01364 Ghoul2 Insert End
01365 */
01366         VectorCopy( cent->lerpOrigin, ent.origin);
01367         VectorCopy( cent->lerpOrigin, ent.oldorigin);
01368 
01369         if (cent->currentState.modelGhoul2)
01370         { //If the game says this guy uses a ghoul2 model and the g2 instance handle is null, then initialize it
01371                 if (!cent->ghoul2 && !cent->currentState.bolt1)
01372                 {
01373                         char skinName[MAX_QPATH];
01374                         const char *modelName = CG_ConfigString( CS_MODELS+cent->currentState.modelindex );
01375                         int l;
01376                         int skin = 0;
01377 
01378                         trap_G2API_InitGhoul2Model(&cent->ghoul2, modelName, 0, 0, 0, 0, 0);
01379                         if (cent->ghoul2 && trap_G2API_SkinlessModel(cent->ghoul2, 0))
01380                         { //well, you'd never want a skinless model, so try to get his skin...
01381                                 Q_strncpyz(skinName, modelName, MAX_QPATH);
01382                                 l = strlen(skinName);
01383                                 while (l > 0 && skinName[l] != '/')
01384                                 { //parse back to first /
01385                                         l--;
01386                                 }
01387                                 if (skinName[l] == '/')
01388                                 { //got it
01389                                         l++;
01390                                         skinName[l] = 0;
01391                                         Q_strcat(skinName, MAX_QPATH, "model_default.skin");
01392                 
01393                                         skin = trap_R_RegisterSkin(skinName);
01394                                 }
01395                                 trap_G2API_SetSkin(cent->ghoul2, 0, skin, skin);
01396                         }
01397                 }
01398                 else if (cent->currentState.bolt1)
01399                 {
01400                         TurretClientRun(cent);
01401                 }
01402 
01403                 if (cent->ghoul2)
01404                 { //give us a proper radius
01405                         ent.radius = cent->currentState.g2radius;
01406                 }
01407         }
01408 
01409         if (s1->eType == ET_BODY)
01410         { //bodies should have a radius as well
01411                 ent.radius = cent->currentState.g2radius;
01412 
01413                 if (cent->ghoul2)
01414                 { //all bodies should already have a ghoul2 instance. Use it to set the torso/head angles to 0.
01415                         cent->lerpAngles[PITCH] = 0;
01416                         cent->lerpAngles[ROLL] = 0;
01417                         trap_G2API_SetBoneAngles(cent->ghoul2, 0, "pelvis", vec3_origin, BONE_ANGLES_POSTMULT, POSITIVE_X, NEGATIVE_Y, NEGATIVE_Z, cgs.gameModels, 0, cg.time); 
01418                         trap_G2API_SetBoneAngles(cent->ghoul2, 0, "thoracic", vec3_origin, BONE_ANGLES_POSTMULT, POSITIVE_X, NEGATIVE_Y, NEGATIVE_Z, cgs.gameModels, 0, cg.time); 
01419                         trap_G2API_SetBoneAngles(cent->ghoul2, 0, "upper_lumbar", vec3_origin, BONE_ANGLES_POSTMULT, POSITIVE_X, NEGATIVE_Y, NEGATIVE_Z, cgs.gameModels, 100, cg.time);
01420                         trap_G2API_SetBoneAngles(cent->ghoul2, 0, "lower_lumbar", vec3_origin, BONE_ANGLES_POSTMULT, POSITIVE_X, NEGATIVE_Y, NEGATIVE_Z, cgs.gameModels, 100, cg.time);
01421                         trap_G2API_SetBoneAngles(cent->ghoul2, 0, "cranium", vec3_origin, BONE_ANGLES_POSTMULT, POSITIVE_Z, NEGATIVE_Y, POSITIVE_X, cgs.gameModels, 100, cg.time);
01422                 }
01423         }
01424 
01425         if (s1->eType == ET_HOLOCRON && s1->modelindex < -100)
01426         { //special render, it's a holocron
01427                 //Using actual models now:
01428                 ent.hModel = trap_R_RegisterModel(forceHolocronModels[s1->modelindex+128]);
01429 
01430                 //Rotate them
01431                 VectorCopy( cg.autoAngles, cent->lerpAngles );
01432                 AxisCopy( cg.autoAxis, ent.axis );
01433         }
01434         else if (!doNotSetModel)
01435         {
01436                 ent.hModel = cgs.gameModels[s1->modelindex];
01437         }
01438 
01439         // player model
01440         if (s1->number == cg.snap->ps.clientNum) {
01441                 ent.renderfx |= RF_THIRD_PERSON;        // only draw from mirrors
01442         }
01443 
01444         // convert angles to axis
01445         AnglesToAxis( cent->lerpAngles, ent.axis );
01446 
01447         if (cent->currentState.iModelScale)
01448         { //if the server says we have a custom scale then set it now.
01449                 cent->modelScale[0] = cent->modelScale[1] = cent->modelScale[2] = cent->currentState.iModelScale/100.0f;
01450                 VectorCopy(cent->modelScale, ent.modelScale);
01451                 ScaleModelAxis(&ent);
01452         }
01453         else
01454         {
01455                 VectorClear(cent->modelScale);
01456         }
01457 
01458         if ( cent->currentState.time > cg.time && cent->currentState.weapon == WP_EMPLACED_GUN )
01459         {
01460                 // make the gun pulse red to warn about it exploding
01461                 val = (1.0f - (float)(cent->currentState.time - cg.time) / 3200.0f ) * 0.3f;
01462 
01463                 ent.customShader = trap_R_RegisterShader( "gfx/effects/turretflashdie" );
01464                 ent.shaderRGBA[0] = (sin( cg.time * 0.04f ) * val * 0.4f + val) * 255;
01465                 ent.shaderRGBA[1] = ent.shaderRGBA[2] = 0;
01466 
01467                 ent.shaderRGBA[3] = 100;
01468                 trap_R_AddRefEntityToScene( &ent );
01469                 ent.customShader = 0;
01470         }
01471         else if ( cent->currentState.time == -1 && cent->currentState.weapon == WP_EMPLACED_GUN)
01472         {
01473                 ent.customShader = trap_R_RegisterShader( "models/map_objects/imp_mine/turret_chair_dmg.tga" );
01474                 //trap_R_AddRefEntityToScene( &ent );
01475         }
01476 
01477         if ((cent->currentState.eFlags & EF_DISINTEGRATION) && cent->currentState.eType == ET_BODY)
01478         {
01479                 if (!cent->dustTrailTime)
01480                 {
01481                         cent->dustTrailTime = cg.time;
01482                 }
01483 
01484                 CG_Disintegration(cent, &ent);
01485                 return;
01486         }
01487         else if (cent->currentState.eType == ET_BODY)
01488         {
01489                 if (cent->bodyFadeTime > cg.time)
01490                 {
01491                         qboolean lightSide = cent->teamPowerType;
01492                         vec3_t hitLoc, tempAng;
01493                         float tempLength;
01494                         int curTimeDif = ((cg.time + 60000) - cent->bodyFadeTime);
01495                         int tMult = curTimeDif*0.08;
01496 
01497                         ent.renderfx |= RF_FORCE_ENT_ALPHA;
01498 
01499                         /*
01500                         if (!cent->bodyHeight)
01501                         {
01502                                 cent->bodyHeight = ent.origin[2];
01503                         }
01504                         */
01505 
01506                         if (curTimeDif*0.1 > 254)
01507                         {
01508                                 ent.shaderRGBA[3] = 0;
01509                         }
01510                         else
01511                         {
01512                                 ent.shaderRGBA[3] = (254 - tMult);
01513                         }
01514 
01515                         if (ent.shaderRGBA[3] >= 1)
01516                         { //add the transparent body section
01517                                 trap_R_AddRefEntityToScene (&ent);
01518                         }
01519 
01520                         ent.renderfx &= ~RF_FORCE_ENT_ALPHA;
01521                         ent.renderfx |= RF_RGB_TINT;
01522 
01523                         if (tMult > 200)
01524                         { //begin the disintegration effect
01525                                 ent.shaderRGBA[3] = 200;
01526                                 if (!cent->dustTrailTime)
01527                                 {
01528                                         cent->dustTrailTime = cg.time;
01529                                         if (lightSide)
01530                                         {
01531                                                 trap_S_StartSound ( NULL, cent->currentState.number, CHAN_AUTO, trap_S_RegisterSound("sound/weapons/force/see.wav") );
01532                                         }
01533                                         else
01534                                         {
01535                                                 trap_S_StartSound ( NULL, cent->currentState.number, CHAN_AUTO, trap_S_RegisterSound("sound/weapons/force/lightning") );
01536                                         }
01537                                 }
01538                                 ent.endTime = cent->dustTrailTime;
01539                                 ent.renderfx |= RF_DISINTEGRATE2;
01540                         }
01541                         else
01542                         { //set the alpha on the to-be-disintegrated layer
01543                                 ent.shaderRGBA[3] = tMult;
01544                                 if (ent.shaderRGBA[3] < 1)
01545                                 {
01546                                         ent.shaderRGBA[3] = 1;
01547                                 }
01548                         }
01549                         //Set everything up on the disint ref
01550                         ent.shaderRGBA[0] = ent.shaderRGBA[1] = ent.shaderRGBA[2] = ent.shaderRGBA[3];
01551                         VectorCopy(cent->lerpOrigin, hitLoc);
01552 
01553                         VectorSubtract( hitLoc, ent.origin, ent.oldorigin );
01554                         
01555                         tempLength = VectorNormalize( ent.oldorigin );
01556                         vectoangles( ent.oldorigin, tempAng );
01557                         tempAng[YAW] -= cent->lerpAngles[YAW];
01558                         AngleVectors( tempAng, ent.oldorigin, NULL, NULL );
01559                         VectorScale( ent.oldorigin, tempLength, ent.oldorigin );
01560 
01561                         if (lightSide)
01562                         { //might be temporary, dunno.
01563                                 ent.customShader = cgs.media.playerShieldDamage;
01564                         }
01565                         else
01566                         {
01567                                 ent.customShader = cgs.media.redSaberGlowShader;
01568                         }
01569 
01570                         //slowly move the glowing part upward, out of the fading body
01571                         /*
01572                         cent->bodyHeight += 0.4f;
01573                         ent.origin[2] = cent->bodyHeight;
01574                         */
01575 
01576                         trap_R_AddRefEntityToScene( &ent );
01577                         ent.renderfx &= ~RF_DISINTEGRATE2;
01578                         ent.customShader = 0;
01579 
01580                         if (curTimeDif < 3400)
01581                         {
01582                                 if (lightSide)
01583                                 {
01584                                         if (curTimeDif < 2200)
01585                                         { //probably temporary
01586                                                 trap_S_StartSound ( NULL, cent->currentState.number, CHAN_AUTO, trap_S_RegisterSound( "sound/weapons/saber/saberhum1.wav" ) );
01587                                         }
01588                                 }
01589                                 else
01590                                 { //probably temporary as well
01591                                         ent.renderfx |= RF_RGB_TINT;
01592                                         ent.shaderRGBA[0] = 255;
01593                                         ent.shaderRGBA[1] = ent.shaderRGBA[2] = 0;
01594                                         ent.shaderRGBA[3] = 255;
01595                                         if ( rand() & 1 )
01596                                         {
01597                                                 ent.customShader = cgs.media.electricBodyShader;        
01598                                         }
01599                                         else
01600                                         {
01601                                                 ent.customShader = cgs.media.electricBody2Shader;
01602                                         }
01603                                         if ( random() > 0.9f )
01604                                         {
01605                                                 trap_S_StartSound ( NULL, cent->currentState.number, CHAN_AUTO, cgs.media.crackleSound );
01606                                         }
01607                                         trap_R_AddRefEntityToScene( &ent );
01608                                 }
01609                         }
01610 
01611                         return;
01612                 }
01613                 else
01614                 {
01615                         cent->dustTrailTime = 0;
01616                 }
01617         }
01618 
01619         if (cent->currentState.modelGhoul2 &&
01620                 !ent.ghoul2 &&
01621                 !ent.hModel)
01622         {
01623                 return;
01624         }
01625 
01626         // add to refresh list
01627         trap_R_AddRefEntityToScene (&ent);
01628 
01629         if (cent->bolt3 == 999)
01630         { //this is an in-flight saber being rendered manually
01631                 vec3_t org;
01632                 float wv;
01633                 int i;
01634                 addspriteArgStruct_t fxSArgs;
01635                 //refEntity_t sRef;
01636                 //memcpy( &sRef, &ent, sizeof( sRef ) );
01637 
01638                 ent.customShader = cgs.media.solidWhite;
01639                 ent.renderfx = RF_RGB_TINT;
01640                 wv = sin( cg.time * 0.003f ) * 0.08f + 0.1f;
01641                 ent.shaderRGBA[0] = wv * 255;
01642                 ent.shaderRGBA[1] = wv * 255;
01643                 ent.shaderRGBA[2] = wv * 0;
01644                 trap_R_AddRefEntityToScene (&ent);
01645 
01646                 for ( i = -4; i < 10; i += 1 )
01647                 {
01648                         VectorMA( ent.origin, -i, ent.axis[2], org );
01649 
01650                         VectorCopy(org, fxSArgs.origin);
01651                         VectorClear(fxSArgs.vel);
01652                         VectorClear(fxSArgs.accel);
01653                         fxSArgs.scale = 5.5f;
01654                         fxSArgs.dscale = 5.5f;
01655                         fxSArgs.sAlpha = wv;
01656                         fxSArgs.eAlpha = wv;
01657                         fxSArgs.rotation = 0.0f;
01658                         fxSArgs.bounce = 0.0f;
01659                         fxSArgs.life = 1.0f;
01660                         fxSArgs.shader = cgs.media.yellowDroppedSaberShader;
01661                         fxSArgs.flags = 0x08000000;
01662 
01663                         //trap_FX_AddSprite( org, NULL, NULL, 5.5f, 5.5f, wv, wv, 0.0f, 0.0f, 1.0f, cgs.media.yellowSaberGlowShader, 0x08000000 );
01664                         trap_FX_AddSprite(&fxSArgs);
01665                 }
01666         }
01667         else if (cent->currentState.trickedentindex3)
01668         { //holocron special effects
01669                 vec3_t org;
01670                 float wv;
01671                 addspriteArgStruct_t fxSArgs;
01672                 //refEntity_t sRef;
01673                 //memcpy( &sRef, &ent, sizeof( sRef ) );
01674 
01675                 ent.customShader = cgs.media.solidWhite;
01676                 ent.renderfx = RF_RGB_TINT;
01677                 wv = sin( cg.time * 0.005f ) * 0.08f + 0.1f; //* 0.08f + 0.1f;
01678 
01679                 if (cent->currentState.trickedentindex3 == 1)
01680                 { //dark
01681                         ent.shaderRGBA[0] = wv*255;
01682                         ent.shaderRGBA[1] = 0;
01683                         ent.shaderRGBA[2] = 0;
01684                 }
01685                 else if (cent->currentState.trickedentindex3 == 2)
01686                 { //light
01687                         ent.shaderRGBA[0] = wv*255;
01688                         ent.shaderRGBA[1] = wv*255;
01689                         ent.shaderRGBA[2] = wv*255;
01690                 }
01691                 else
01692                 { //neutral
01693                         if ((s1->modelindex+128) == FP_SABER_OFFENSE ||
01694                                 (s1->modelindex+128) == FP_SABER_DEFENSE ||
01695                                 (s1->modelindex+128) == FP_SABERTHROW)
01696                         { //saber power
01697                                 ent.shaderRGBA[0] = 0;
01698                                 ent.shaderRGBA[1] = wv*255;
01699                                 ent.shaderRGBA[2] = 0;
01700                         }
01701                         else
01702                         {
01703                                 ent.shaderRGBA[0] = 0;
01704                                 ent.shaderRGBA[1] = wv*255;
01705                                 ent.shaderRGBA[2] = wv*255;
01706                         }
01707                 }
01708 
01709                 ent.modelScale[0] = 1.1;
01710                 ent.modelScale[1] = 1.1;
01711                 ent.modelScale[2] = 1.1;
01712 
01713                 ent.origin[2] -= 2;
01714                 ScaleModelAxis(&ent);
01715 
01716                 trap_R_AddRefEntityToScene (&ent);
01717                 
01718                 VectorMA( ent.origin, 1, ent.axis[2], org );
01719 
01720                 org[2] += 18;
01721 
01722                 wv = sin( cg.time * 0.002f ) * 0.08f + 0.1f; //* 0.08f + 0.1f;
01723 
01724                 VectorCopy(org, fxSArgs.origin);
01725                 VectorClear(fxSArgs.vel);
01726                 VectorClear(fxSArgs.accel);
01727                 fxSArgs.scale = wv*120;//16.0f;
01728                 fxSArgs.dscale = wv*120;//16.0f;
01729                 fxSArgs.sAlpha = wv*12;
01730                 fxSArgs.eAlpha = wv*12;
01731                 fxSArgs.rotation = 0.0f;
01732                 fxSArgs.bounce = 0.0f;
01733                 fxSArgs.life = 1.0f;
01734 
01735                 fxSArgs.flags = 0x08000000|0x00000001;
01736 
01737                 if (cent->currentState.trickedentindex3 == 1)
01738                 { //dark
01739                         fxSArgs.sAlpha *= 3;
01740                         fxSArgs.eAlpha *= 3;
01741                         fxSArgs.shader = cgs.media.redSaberGlowShader;
01742                         trap_FX_AddSprite(&fxSArgs);
01743                 }
01744                 else if (cent->currentState.trickedentindex3 == 2)
01745                 { //light
01746                         fxSArgs.sAlpha *= 1.5;
01747                         fxSArgs.eAlpha *= 1.5;
01748                         fxSArgs.shader = cgs.media.redSaberGlowShader;
01749                         trap_FX_AddSprite(&fxSArgs);
01750                         fxSArgs.shader = cgs.media.greenSaberGlowShader;
01751                         trap_FX_AddSprite(&fxSArgs);
01752                         fxSArgs.shader = cgs.media.blueSaberGlowShader;
01753                         trap_FX_AddSprite(&fxSArgs);
01754                 }
01755                 else
01756                 { //neutral
01757                         if ((s1->modelindex+128) == FP_SABER_OFFENSE ||
01758                                 (s1->modelindex+128) == FP_SABER_DEFENSE ||
01759                                 (s1->modelindex+128) == FP_SABERTHROW)
01760                         { //saber power
01761                                 fxSArgs.sAlpha *= 1.5;
01762                                 fxSArgs.eAlpha *= 1.5;
01763                                 fxSArgs.shader = cgs.media.greenSaberGlowShader;
01764                                 trap_FX_AddSprite(&fxSArgs);
01765                         }
01766                         else
01767                         {
01768                                 fxSArgs.sAlpha *= 0.5;
01769                                 fxSArgs.eAlpha *= 0.5;
01770                                 fxSArgs.shader = cgs.media.greenSaberGlowShader;
01771                                 trap_FX_AddSprite(&fxSArgs);
01772                                 fxSArgs.shader = cgs.media.blueSaberGlowShader;
01773                                 trap_FX_AddSprite(&fxSArgs);
01774                         }
01775                 }
01776         }
01777 
01778         if ( cent->currentState.time == -1 && cent->currentState.weapon == WP_TRIP_MINE && (cent->currentState.eFlags & EF_FIRING) )
01779         { //if force sight is active, render the laser multiple times up to the force sight level to increase visibility
01780                 if (cent->currentState.bolt2 == 1)
01781                 {
01782                         VectorMA( ent.origin, 6.6f, ent.axis[0], beamOrg );// forward
01783                         beamID = cgs.effects.tripmineGlowFX;
01784                         trap_FX_PlayEffectID( beamID, beamOrg, cent->currentState.pos.trDelta, -1, -1 );
01785                 }
01786                 else
01787                 {
01788                         int i = 0;
01789 
01790                         VectorMA( ent.origin, 6.6f, ent.axis[0], beamOrg );// forward
01791                         beamID = cgs.effects.tripmineLaserFX;
01792 
01793                         if (cg.snap->ps.fd.forcePowersActive & (1 << FP_SEE))
01794                         {
01795                                 i = cg.snap->ps.fd.forcePowerLevel[FP_SEE];
01796 
01797                                 while (i > 0)
01798                                 {
01799                                         trap_FX_PlayEffectID( beamID, beamOrg, cent->currentState.pos.trDelta, -1, -1 );
01800                                         trap_FX_PlayEffectID( beamID, beamOrg, cent->currentState.pos.trDelta, -1, -1 );
01801                                         i--;
01802                                 }
01803                         }
01804 
01805                         trap_FX_PlayEffectID( beamID, beamOrg, cent->currentState.pos.trDelta, -1, -1 );
01806                 }
01807         }
01808 /*
01809 Ghoul2 Insert Start
01810 */
01811 
01812         if (cg_debugBB.integer)
01813         {
01814                 CG_CreateBBRefEnts(s1, cent->lerpOrigin);
01815         }
01816 /*
01817 Ghoul2 Insert End
01818 */
01819 }
01820 
01821 /*
01822 ==================
01823 CG_Speaker
01824 
01825 Speaker entities can automatically play sounds
01826 ==================
01827 */
01828 static void CG_Speaker( centity_t *cent ) {
01829         if (cent->currentState.trickedentindex)
01830         {
01831                 CG_S_StopLoopingSound(cent->currentState.number, -1);
01832         }
01833 
01834         if ( ! cent->currentState.clientNum ) { // FIXME: use something other than clientNum...
01835                 return;         // not auto triggering
01836         }
01837 
01838         if ( cg.time < cent->miscTime ) {
01839                 return;
01840         }
01841 
01842         trap_S_StartSound (NULL, cent->currentState.number, CHAN_ITEM, cgs.gameSounds[cent->currentState.eventParm] );
01843 
01844         //      ent->s.frame = ent->wait * 10;
01845         //      ent->s.clientNum = ent->random * 10;
01846         cent->miscTime = cg.time + cent->currentState.frame * 100 + cent->currentState.clientNum * 100 * crandom();
01847 }
01848 
01849 qboolean CG_GreyItem(int type, int tag, int plSide)
01850 {
01851         if (type == IT_POWERUP &&
01852                 (tag == PW_FORCE_ENLIGHTENED_LIGHT || tag == PW_FORCE_ENLIGHTENED_DARK))
01853         {
01854                 if (plSide == FORCE_LIGHTSIDE)
01855                 {
01856                         if (tag == PW_FORCE_ENLIGHTENED_DARK)
01857                         {
01858                                 return qtrue;
01859                         }
01860                 }
01861                 else if (plSide == FORCE_DARKSIDE)
01862                 {
01863                         if (tag == PW_FORCE_ENLIGHTENED_LIGHT)
01864                         {
01865                                 return qtrue;
01866                         }
01867                 }
01868         }
01869 
01870         return qfalse;
01871 }
01872 
01873 /*
01874 ==================
01875 CG_Item
01876 ==================
01877 */
01878 static void CG_Item( centity_t *cent ) {
01879         refEntity_t             ent;
01880         entityState_t   *es;
01881         gitem_t                 *item;
01882         int                             msec;
01883         float                   scale;
01884         weaponInfo_t    *wi;
01885 
01886         es = &cent->currentState;
01887         if ( es->modelindex >= bg_numItems ) {
01888                 CG_Error( "Bad item index %i on entity", es->modelindex );
01889         }
01890 
01891 /*
01892 Ghoul2 Insert Start
01893 */
01894 
01895         if ((es->eFlags & EF_NODRAW) && (es->eFlags & EF_ITEMPLACEHOLDER))
01896         {
01897                 es->eFlags &= ~EF_NODRAW;
01898         }
01899 
01900         if ( !es->modelindex ) 
01901         {
01902                 return;
01903         }
01904 
01905         item = &bg_itemlist[ es->modelindex ];
01906 
01907         if ((item->giType == IT_WEAPON || item->giType == IT_POWERUP) &&
01908                 !(cent->currentState.eFlags & EF_DROPPEDWEAPON) &&
01909                 !cg_simpleItems.integer)
01910         {
01911                 vec3_t uNorm;
01912                 qboolean doGrey;
01913                 
01914                 VectorClear(uNorm);
01915 
01916                 uNorm[2] = 1;
01917 
01918                 memset( &ent, 0, sizeof( ent ) );
01919 
01920                 ent.customShader = 0;
01921                 VectorCopy(cent->lerpOrigin, ent.origin);
01922                 VectorCopy( cent->currentState.angles, cent->lerpAngles );
01923                 AnglesToAxis(cent->lerpAngles, ent.axis);
01924                 ent.hModel = cgs.media.itemHoloModel;
01925 
01926                 doGrey = CG_GreyItem(item->giType, item->giTag, cg.snap->ps.fd.forceSide);
01927 
01928                 if (doGrey)
01929                 {
01930                         ent.renderfx |= RF_RGB_TINT;
01931 
01932                         ent.shaderRGBA[0] = 150;
01933                         ent.shaderRGBA[1] = 150;
01934                         ent.shaderRGBA[2] = 150;
01935                 }
01936 
01937                 trap_R_AddRefEntityToScene(&ent);
01938 
01939                 if (!doGrey)
01940                 {
01941                         trap_FX_PlayEffectID(cgs.effects.itemCone, ent.origin, uNorm, -1, -1);
01942                 }
01943         }
01944 
01945         // if set to invisible, skip
01946         if ( ( es->eFlags & EF_NODRAW ) ) 
01947         {
01948                 return;
01949         }
01950 /*
01951 Ghoul2 Insert End
01952 */
01953 
01954         if ( cg_simpleItems.integer && item->giType != IT_TEAM ) {
01955                 memset( &ent, 0, sizeof( ent ) );
01956                 ent.reType = RT_SPRITE;
01957                 VectorCopy( cent->lerpOrigin, ent.origin );
01958                 ent.radius = 14;
01959                 ent.customShader = cg_items[es->modelindex].icon;
01960                 ent.shaderRGBA[0] = 255;
01961                 ent.shaderRGBA[1] = 255;
01962                 ent.shaderRGBA[2] = 255;
01963 
01964                 ent.origin[2] += 16;
01965 
01966                 if (item->giType != IT_POWERUP || item->giTag != PW_FORCE_BOON)
01967                 {
01968                         ent.renderfx |= RF_FORCE_ENT_ALPHA;
01969                 }
01970 
01971                 if ( es->eFlags & EF_ITEMPLACEHOLDER )
01972                 {
01973                         if (item->giType == IT_POWERUP && item->giTag == PW_FORCE_BOON)
01974                         {
01975                                 return;
01976                         }
01977                         ent.shaderRGBA[0] = 200;
01978                         ent.shaderRGBA[1] = 200;
01979                         ent.shaderRGBA[2] = 200;
01980                         ent.shaderRGBA[3] = 150 + sin(cg.time*0.01)*30;
01981                 }
01982                 else
01983                 {
01984                         ent.shaderRGBA[3] = 255;
01985                 }
01986 
01987                 if (CG_GreyItem(item->giType, item->giTag, cg.snap->ps.fd.forceSide))
01988                 {
01989                         ent.shaderRGBA[0] = 100;
01990                         ent.shaderRGBA[1] = 100;
01991                         ent.shaderRGBA[2] = 100;
01992 
01993                         ent.shaderRGBA[3] = 200;
01994 
01995                         if (item->giTag == PW_FORCE_ENLIGHTENED_LIGHT)
01996                         {
01997                                 ent.customShader = trap_R_RegisterShader("gfx/misc/mp_light_enlight_disable");
01998                         }
01999                         else
02000                         {
02001                                 ent.customShader = trap_R_RegisterShader("gfx/misc/mp_dark_enlight_disable");
02002                         }
02003                 }
02004                 trap_R_AddRefEntityToScene(&ent);
02005                 return;
02006         }
02007 
02008         if ((item->giType == IT_WEAPON || item->giType == IT_POWERUP) &&
02009                 !(cent->currentState.eFlags & EF_DROPPEDWEAPON))
02010         {
02011                 cent->lerpOrigin[2] += 16;
02012         }
02013 
02014         if ((!(cent->currentState.eFlags & EF_DROPPEDWEAPON) || item->giType == IT_POWERUP) &&
02015                 (item->giType == IT_WEAPON || item->giType == IT_POWERUP))
02016         {
02017                 // items bob up and down continuously
02018                 scale = 0.005 + cent->currentState.number * 0.00001;
02019                 cent->lerpOrigin[2] += 4 + cos( ( cg.time + 1000 ) *  scale ) * 4;
02020         }
02021         else
02022         {
02023                 if (item->giType == IT_HOLDABLE)
02024                 {
02025                         if (item->giTag == HI_SEEKER)
02026                         {
02027                                 cent->lerpOrigin[2] += 5;
02028                         }
02029                         if (item->giTag == HI_SHIELD)
02030                         {
02031                                 cent->lerpOrigin[2] += 2;
02032                         }
02033                         if (item->giTag == HI_BINOCULARS)
02034                         {
02035                                 cent->lerpOrigin[2] += 2;
02036                         }
02037                 }
02038                 if (item->giType == IT_HEALTH)
02039                 {
02040                         cent->lerpOrigin[2] += 2;
02041                 }
02042                 if (item->giType == IT_ARMOR)
02043                 {
02044                         if (item->quantity == 100)
02045                         {
02046                                 cent->lerpOrigin[2] += 7;
02047                         }
02048                 }
02049         }
02050 
02051         memset (&ent, 0, sizeof(ent));
02052 
02053         if ( (!(cent->currentState.eFlags & EF_DROPPEDWEAPON) || item->giType == IT_POWERUP) &&
02054                 (item->giType == IT_WEAPON || item->giType == IT_POWERUP) )
02055         { //only weapons and powerups rotate now
02056                 // autorotate at one of two speeds
02057                 VectorCopy( cg.autoAngles, cent->lerpAngles );
02058                 AxisCopy( cg.autoAxis, ent.axis );
02059         }
02060         else
02061         {
02062                 VectorCopy( cent->currentState.angles, cent->lerpAngles );
02063                 AnglesToAxis(cent->lerpAngles, ent.axis);
02064         }
02065 
02066         wi = NULL;
02067         // the weapons have their origin where they attatch to player
02068         // models, so we need to offset them or they will rotate
02069         // eccentricly
02070         if (!(cent->currentState.eFlags & EF_DROPPEDWEAPON))
02071         {
02072                 if ( item->giType == IT_WEAPON ) {
02073                         wi = &cg_weapons[item->giTag];
02074                         cent->lerpOrigin[0] -= 
02075                                 wi->weaponMidpoint[0] * ent.axis[0][0] +
02076                                 wi->weaponMidpoint[1] * ent.axis[1][0] +
02077                                 wi->weaponMidpoint[2] * ent.axis[2][0];
02078                         cent->lerpOrigin[1] -= 
02079                                 wi->weaponMidpoint[0] * ent.axis[0][1] +
02080                                 wi->weaponMidpoint[1] * ent.axis[1][1] +
02081                                 wi->weaponMidpoint[2] * ent.axis[2][1];
02082                         cent->lerpOrigin[2] -= 
02083                                 wi->weaponMidpoint[0] * ent.axis[0][2] +
02084                                 wi->weaponMidpoint[1] * ent.axis[1][2] +
02085                                 wi->weaponMidpoint[2] * ent.axis[2][2];
02086 
02087                         cent->lerpOrigin[2] += 8;       // an extra height boost
02088                 }
02089         }
02090         else
02091         {
02092                 wi = &cg_weapons[item->giTag];
02093 
02094                 switch(item->giTag)
02095                 {
02096                 case WP_BLASTER:
02097                         cent->lerpOrigin[2] -= 12;
02098                         break;
02099                 case WP_DISRUPTOR:
02100                         cent->lerpOrigin[2] -= 13;
02101                         break;
02102                 case WP_BOWCASTER:
02103                         cent->lerpOrigin[2] -= 16;
02104                         break;
02105                 case WP_REPEATER:
02106                         cent->lerpOrigin[2] -= 12;
02107                         break;
02108                 case WP_DEMP2:
02109                         cent->lerpOrigin[2] -= 10;
02110                         break;
02111                 case WP_FLECHETTE:
02112                         cent->lerpOrigin[2] -= 6;
02113                         break;
02114                 case WP_ROCKET_LAUNCHER:
02115                         cent->lerpOrigin[2] -= 11;
02116                         break;
02117                 case WP_THERMAL:
02118                         cent->lerpOrigin[2] -= 12;
02119                         break;
02120                 case WP_TRIP_MINE:
02121                         cent->lerpOrigin[2] -= 16;
02122                         break;
02123                 case WP_DET_PACK:
02124                         cent->lerpOrigin[2] -= 16;
02125                         break;
02126                 default:
02127                         cent->lerpOrigin[2] -= 8;
02128                         break;
02129                 }
02130         }
02131 
02132         ent.hModel = cg_items[es->modelindex].models[0];
02133 /*
02134 Ghoul2 Insert Start
02135 */
02136         ent.ghoul2 = cg_items[es->modelindex].g2Models[0];
02137         ent.radius = cg_items[es->modelindex].radius[0];
02138         VectorCopy (cent->lerpAngles, ent.angles);
02139 /*
02140 Ghoul2 Insert End
02141 */
02142         VectorCopy( cent->lerpOrigin, ent.origin);
02143         VectorCopy( cent->lerpOrigin, ent.oldorigin);
02144 
02145         ent.nonNormalizedAxes = qfalse;
02146 
02147         // if just respawned, slowly scale up
02148         
02149         msec = cg.time - cent->miscTime;
02150 
02151         if (CG_GreyItem(item->giType, item->giTag, cg.snap->ps.fd.forceSide))
02152         {
02153                 ent.renderfx |= RF_RGB_TINT;
02154 
02155                 ent.shaderRGBA[0] = 150;
02156                 ent.shaderRGBA[1] = 150;
02157                 ent.shaderRGBA[2] = 150;
02158 
02159                 ent.renderfx |= RF_FORCE_ENT_ALPHA;
02160 
02161                 ent.shaderRGBA[3] = 200;
02162 
02163                 if (item->giTag == PW_FORCE_ENLIGHTENED_LIGHT)
02164                 {
02165                         ent.customShader = trap_R_RegisterShader("gfx/misc/mp_light_enlight_disable");
02166                 }
02167                 else
02168                 {
02169                         ent.customShader = trap_R_RegisterShader("gfx/misc/mp_dark_enlight_disable");
02170                 }
02171 
02172                 trap_R_AddRefEntityToScene( &ent );
02173                 return;
02174         }
02175 
02176         if ( es->eFlags & EF_ITEMPLACEHOLDER )          // item has been picked up
02177         {
02178                 if ( es->eFlags & EF_DEAD )                             // if item had been droped, don't show at all
02179                         return;
02180 
02181                 ent.renderfx |= RF_RGB_TINT;
02182                 ent.shaderRGBA[0] = 0;
02183                 ent.shaderRGBA[1] = 200;
02184                 ent.shaderRGBA[2] = 85;
02185                 ent.customShader = cgs.media.itemRespawningPlaceholder;
02186         }
02187 
02188         // increase the size of the weapons when they are presented as items
02189         if ( item->giType == IT_WEAPON ) {
02190                 VectorScale( ent.axis[0], 1.5, ent.axis[0] );
02191                 VectorScale( ent.axis[1], 1.5, ent.axis[1] );
02192                 VectorScale( ent.axis[2], 1.5, ent.axis[2] );
02193                 ent.nonNormalizedAxes = qtrue;
02194                 //trap_S_AddLoopingSound( cent->currentState.number, cent->lerpOrigin, vec3_origin, cgs.media.weaponHoverSound );
02195         }
02196 
02197         if (!(cent->currentState.eFlags & EF_DROPPEDWEAPON) &&
02198                 (item->giType == IT_WEAPON || item->giType == IT_POWERUP))
02199         {
02200                 ent.renderfx |= RF_MINLIGHT;
02201         }
02202 
02203         if (item->giType != IT_TEAM && msec >= 0 && msec < ITEM_SCALEUP_TIME && !(es->eFlags & EF_ITEMPLACEHOLDER) && !(es->eFlags & EF_DROPPEDWEAPON)) 
02204         {       // if just respawned, fade in, but don't do this for flags.
02205                 float alpha;
02206                 int a;
02207                 
02208                 alpha = (float)msec / ITEM_SCALEUP_TIME;
02209                 a = alpha * 255.0;
02210                 if (a <= 0)
02211                         a=1;
02212 
02213                 ent.shaderRGBA[3] = a;
02214                 if (item->giType != IT_POWERUP || item->giTag != PW_FORCE_BOON)
02215                 { //boon model uses a different blending mode for the sprite inside and doesn't look proper with this method
02216                         ent.renderfx |= RF_FORCE_ENT_ALPHA;
02217                 }
02218                 trap_R_AddRefEntityToScene(&ent);
02219                 
02220                 ent.renderfx &= ~RF_FORCE_ENT_ALPHA;
02221         
02222                 // Now draw the static shader over it.
02223                 // Alpha in over half the time, out over half.
02224                 
02225                 //alpha = sin(M_PI*alpha);
02226                 a = alpha * 255.0;
02227 
02228                 a = 255 - a;
02229 
02230                 if (a <= 0)
02231                         a=1;
02232                 if (a > 255)
02233                         a=255;
02234 
02235                 ent.customShader = cgs.media.itemRespawningRezOut;
02236 
02237                 /*
02238                 ent.shaderRGBA[0] = 0;
02239                 ent.shaderRGBA[1] = a;
02240                 ent.shaderRGBA[2] = a-100;
02241 
02242                 if (ent.shaderRGBA[2] < 0)
02243                 {
02244                         ent.shaderRGBA[2] = 0;
02245                 }
02246                 */
02247 
02248                 /*
02249                 ent.shaderRGBA[0] =
02250                 ent.shaderRGBA[1] =
02251                 ent.shaderRGBA[2] = a;
02252                 */
02253 
02254                 ent.renderfx |= RF_RGB_TINT;
02255                 ent.shaderRGBA[0] = 0;
02256                 ent.shaderRGBA[1] = 200;
02257                 ent.shaderRGBA[2] = 85;
02258 
02259                 trap_R_AddRefEntityToScene( &ent );
02260         }
02261         else
02262         {       // add to refresh list  -- normal item
02263                 if (item->giType == IT_TEAM &&
02264                         (item->giTag == PW_REDFLAG || item->giTag == PW_BLUEFLAG))
02265                 {
02266                         ent.modelScale[0] = 0.7;
02267                         ent.modelScale[1] = 0.7;
02268                         ent.modelScale[2] = 0.7;
02269                         ScaleModelAxis(&ent);
02270                 }
02271                 trap_R_AddRefEntityToScene(&ent);
02272         }
02273 
02274         //rww - As far as I can see, this is useless.
02275         /*
02276         if ( item->giType == IT_WEAPON && wi->barrelModel ) {
02277                 refEntity_t     barrel;
02278 
02279                 memset( &barrel, 0, sizeof( barrel ) );
02280 
02281                 barrel.hModel = wi->barrelModel;
02282 
02283                 VectorCopy( ent.lightingOrigin, barrel.lightingOrigin );
02284                 barrel.shadowPlane = ent.shadowPlane;
02285                 barrel.renderfx = ent.renderfx;
02286 
02287                 barrel.customShader = ent.customShader;
02288 
02289                 CG_PositionRotatedEntityOnTag( &barrel, &ent, wi->weaponModel, "tag_barrel" );
02290 
02291                 AxisCopy( ent.axis, barrel.axis );
02292                 barrel.nonNormalizedAxes = ent.nonNormalizedAxes;
02293 
02294                 trap_R_AddRefEntityToScene( &barrel );
02295         }
02296         */
02297 
02298         // accompanying rings / spheres for powerups
02299         if ( !cg_simpleItems.integer ) 
02300         {
02301                 vec3_t spinAngles;
02302 
02303                 VectorClear( spinAngles );
02304 
02305                 if ( item->giType == IT_HEALTH || item->giType == IT_POWERUP )
02306                 {
02307                         if ( ( ent.hModel = cg_items[es->modelindex].models[1] ) != 0 )
02308                         {
02309                                 if ( item->giType == IT_POWERUP )
02310                                 {
02311                                         ent.origin[2] += 12;
02312                                         spinAngles[1] = ( cg.time & 1023 ) * 360 / -1024.0f;
02313                                 }
02314                                 AnglesToAxis( spinAngles, ent.axis );
02315                                 
02316                                 trap_R_AddRefEntityToScene( &ent );
02317                         }
02318                 }
02319         }
02320 }
02321 
02322 //============================================================================
02323 
02324 void CG_CreateDistortionTrailPart(centity_t *cent, float scale, vec3_t pos)
02325 {
02326         refEntity_t ent;
02327         vec3_t ang;
02328         float vLen;
02329 
02330         if (!cg_renderToTextureFX.integer)
02331         {
02332                 return;
02333         }
02334         memset( &ent, 0, sizeof( ent ) );
02335 
02336         VectorCopy( pos, ent.origin );
02337 
02338         VectorSubtract(ent.origin, cg.refdef.vieworg, ent.axis[0]);
02339         vLen = VectorLength(ent.axis[0]);
02340         if (VectorNormalize(ent.axis[0]) <= 0.1f)
02341         {       // Entity is right on vieworg.  quit.
02342                 return;
02343         }
02344 
02345         VectorCopy(cent->lerpAngles, ang);
02346         ang[PITCH] += 90.0f;
02347         AnglesToAxis(ang, ent.axis);
02348 
02349         //radius must be a power of 2, and is the actual captured texture size
02350         if (vLen < 512)
02351         {
02352                 ent.radius = 256;
02353         }
02354         else if (vLen < 1024)
02355         {
02356                 ent.radius = 128;
02357         }
02358         else if (vLen < 2048)
02359         {
02360                 ent.radius = 64;
02361         }
02362         else
02363         {
02364                 ent.radius = 32;
02365         }
02366 
02367         ent.modelScale[0] = scale;
02368         ent.modelScale[1] = scale;
02369         ent.modelScale[2] = scale*16.0f;
02370         ScaleModelAxis(&ent);
02371 
02372         ent.hModel = trap_R_RegisterModel("models/weapons2/merr_sonn/trailmodel.md3");
02373         ent.customShader = cgs.media.itemRespawningRezOut;//cgs.media.cloakedShader;//cgs.media.halfShieldShader;       
02374 
02375 #if 1
02376         ent.renderfx = (RF_DISTORTION|RF_FORCE_ENT_ALPHA);
02377         ent.shaderRGBA[0] = 255.0f;
02378         ent.shaderRGBA[1] = 255.0f;
02379         ent.shaderRGBA[2] = 255.0f;
02380         ent.shaderRGBA[3] = 100.0f;
02381 #else //no alpha
02382         ent.renderfx = RF_DISTORTION;
02383 #endif
02384 
02385         trap_R_AddRefEntityToScene( &ent );
02386 }
02387 
02388 //distortion trail effect for rockets -rww
02389 /*
02390 static void CG_DistortionTrail( centity_t *cent )
02391 {
02392         vec3_t fwd;
02393         vec3_t pos;
02394         float overallScale = 4.0f;
02395 
02396         VectorCopy(cent->currentState.pos.trDelta, fwd);
02397         VectorNormalize(fwd);
02398 
02399         VectorMA(cent->lerpOrigin, -8.0f*overallScale, fwd, pos);
02400         CG_CreateDistortionTrailPart(cent, 0.5f*overallScale, pos);
02401         VectorMA(cent->lerpOrigin, -12.0f*overallScale, fwd, pos);
02402         CG_CreateDistortionTrailPart(cent, 0.6f*overallScale, pos);
02403         VectorMA(cent->lerpOrigin, -16.0f*overallScale, fwd, pos);
02404         CG_CreateDistortionTrailPart(cent, 0.7f*overallScale, pos);
02405         VectorMA(cent->lerpOrigin, -20.0f*overallScale, fwd, pos);
02406         CG_CreateDistortionTrailPart(cent, 0.8f*overallScale, pos);
02407         VectorMA(cent->lerpOrigin, -30.0f*overallScale, fwd, pos);
02408         CG_CreateDistortionTrailPart(cent, 0.9f*overallScale, pos);
02409         VectorMA(cent->lerpOrigin, -40.0f*overallScale, fwd, pos);
02410         CG_CreateDistortionTrailPart(cent, 1.0f*overallScale, pos);
02411 }
02412 */
02413 
02414 /*
02415 ===============
02416 CG_Missile
02417 ===============
02418 */
02419 static void CG_Missile( centity_t *cent ) {
02420         refEntity_t                     ent;
02421         entityState_t           *s1;
02422         const weaponInfo_t              *weapon;
02423 //      int     col;
02424 
02425         s1 = &cent->currentState;
02426         if ( s1->weapon > WP_NUM_WEAPONS && s1->weapon != G2_MODEL_PART ) {
02427                 s1->weapon = 0;
02428         }
02429 
02430         if (cent->ghoul2 && s1->weapon == G2_MODEL_PART)
02431         {
02432                 weapon = &cg_weapons[WP_SABER];
02433         }
02434         else
02435         {
02436                 weapon = &cg_weapons[s1->weapon];
02437         }
02438 
02439         if (cent->currentState.eFlags & EF_RADAROBJECT)
02440         {
02441                 CG_AddRadarEnt(cent);
02442         }
02443 
02444         if (s1->weapon == WP_SABER)
02445         {
02446                 if ((cent->currentState.modelindex != cent->serverSaberHitIndex || !cent->ghoul2) && !(s1->eFlags & EF_NODRAW))
02447                 { //no g2, or server changed the model we are using
02448                         const char *saberModel = CG_ConfigString( CS_MODELS+cent->currentState.modelindex );
02449 
02450                         cent->serverSaberHitIndex = cent->currentState.modelindex;
02451 
02452                         if (cent->ghoul2)
02453                         { //clean if we already have one (because server changed model string index)
02454                                 trap_G2API_CleanGhoul2Models(&(cent->ghoul2));
02455                                 cent->ghoul2 = 0;
02456                         }
02457 
02458                         if (saberModel && saberModel[0])
02459                         {
02460                                 trap_G2API_InitGhoul2Model(&cent->ghoul2, saberModel, 0, 0, 0, 0, 0);
02461                         }
02462                         else
02463                         {
02464                                 trap_G2API_InitGhoul2Model(&cent->ghoul2, "models/weapons2/saber/saber_w.glm", 0, 0, 0, 0, 0);
02465                         }
02466                         return;
02467                 }
02468                 else if (s1->eFlags & EF_NODRAW)
02469                 {
02470                         return;
02471                 }
02472         }
02473 
02474         if (cent->ghoul2)
02475         { //give us a proper radius
02476                 ent.radius = cent->currentState.g2radius;
02477         }
02478 
02479         // calculate the axis
02480         VectorCopy( s1->angles, cent->lerpAngles);
02481 
02482         if ( s1->otherEntityNum2 && s1->weapon != WP_SABER )
02483         {//using an over-ridden trail effect!
02484                 vec3_t forward;
02485 
02486                 if ( VectorNormalize2( cent->currentState.pos.trDelta, forward ) == 0.0f )
02487                 {
02488                         forward[2] = 1.0f;
02489                 }
02490                 if ((s1->eFlags&EF_JETPACK_ACTIVE)//hack so we know we're a vehicle Weapon shot
02491                         && (g_vehWeaponInfo[s1->otherEntityNum2].iShotFX
02492                                 || g_vehWeaponInfo[s1->otherEntityNum2].iModel != NULL_HANDLE) )
02493                 { //a vehicle with an override for the weapon trail fx or model
02494                         trap_FX_PlayEffectID( g_vehWeaponInfo[s1->otherEntityNum2].iShotFX, cent->lerpOrigin, forward, -1, -1 );
02495                         if ( g_vehWeaponInfo[s1->otherEntityNum2].iLoopSound )
02496                         {
02497                                 vec3_t  velocity;
02498                                 BG_EvaluateTrajectoryDelta( &cent->currentState.pos, cg.time, velocity );
02499                                 trap_S_AddLoopingSound( cent->currentState.number, cent->lerpOrigin, velocity, g_vehWeaponInfo[s1->otherEntityNum2].iLoopSound );
02500                         }
02501                         //add custom model
02502                         if ( g_vehWeaponInfo[s1->otherEntityNum2].iModel == NULL_HANDLE )
02503                         {
02504                                 return;
02505                         }
02506                 }
02507                 else
02508                 {//a regular missile
02509                         trap_FX_PlayEffectID( cgs.gameEffects[s1->otherEntityNum2], cent->lerpOrigin, forward, -1, -1 );
02510                         if ( s1->loopSound )
02511                         {
02512                                 vec3_t  velocity;
02513                                 BG_EvaluateTrajectoryDelta( &cent->currentState.pos, cg.time, velocity );
02514                                 trap_S_AddLoopingSound( cent->currentState.number, cent->lerpOrigin, velocity, s1->loopSound );
02515                         }
02516                         //FIXME: if has a custom model, too, then set it and do rest of code below?
02517                         return;
02518                 }
02519         }
02520         else if ( cent->currentState.eFlags & EF_ALT_FIRING )
02521         {
02522                 // add trails
02523                 if ( weapon->altMissileTrailFunc )  
02524                 {
02525                         weapon->altMissileTrailFunc( cent, weapon );
02526                 }
02527 
02528                 // add dynamic light
02529                 if ( weapon->altMissileDlight ) 
02530                 {
02531                         trap_R_AddLightToScene(cent->lerpOrigin, weapon->altMissileDlight, 
02532                                 weapon->altMissileDlightColor[0], weapon->altMissileDlightColor[1], weapon->altMissileDlightColor[2] );
02533                 }
02534 
02535                 // add missile sound
02536                 if ( weapon->altMissileSound ) {
02537                         vec3_t  velocity;
02538 
02539                         BG_EvaluateTrajectoryDelta( &cent->currentState.pos, cg.time, velocity );
02540 
02541                         trap_S_AddLoopingSound( cent->currentState.number, cent->lerpOrigin, velocity, weapon->altMissileSound );
02542                 }
02543 
02544                 //Don't draw something without a model
02545                 if ( weapon->altMissileModel == NULL_HANDLE )
02546                         return;
02547         }
02548         else
02549         {
02550                 // add trails
02551                 if ( weapon->missileTrailFunc )  
02552                 {
02553                         weapon->missileTrailFunc( cent, weapon );
02554                 }
02555 
02556                 // add dynamic light
02557                 if ( weapon->missileDlight ) 
02558                 {
02559                         trap_R_AddLightToScene(cent->lerpOrigin, weapon->missileDlight, 
02560                                 weapon->missileDlightColor[0], weapon->missileDlightColor[1], weapon->missileDlightColor[2] );
02561                 }
02562 
02563                 // add missile sound
02564                 if ( weapon->missileSound ) 
02565                 {
02566                         vec3_t  velocity;
02567 
02568                         BG_EvaluateTrajectoryDelta( &cent->currentState.pos, cg.time, velocity );
02569 
02570                         trap_S_AddLoopingSound( cent->currentState.number, cent->lerpOrigin, velocity, weapon->missileSound );
02571                 }
02572 
02573                 //Don't draw something without a model
02574                 if ( weapon->missileModel == NULL_HANDLE && s1->weapon != WP_SABER && s1->weapon != G2_MODEL_PART ) //saber uses ghoul2 model, doesn't matter
02575                         return;
02576         }
02577 
02578         // create the render entity
02579         memset (&ent, 0, sizeof(ent));
02580         VectorCopy( cent->lerpOrigin, ent.origin);
02581         VectorCopy( cent->lerpOrigin, ent.oldorigin);
02582 /*
02583 Ghoul2 Insert Start
02584 */
02585         CG_SetGhoul2Info(&ent, cent);  
02586 
02587 /*
02588 Ghoul2 Insert End
02589 */
02590 
02591         // flicker between two skins
02592         ent.skinNum = cg.clientFrame & 1;
02593         ent.renderfx = /*weapon->missileRenderfx | */RF_NOSHADOW;
02594 
02595         if ( !(s1->eFlags&EF_JETPACK_ACTIVE) )
02596         {
02597                 if (s1->weapon != WP_SABER && s1->weapon != G2_MODEL_PART)
02598                 {
02599                         //if ( cent->currentState.eFlags | EF_ALT_FIRING )
02600                         //rww - why was this like this?
02601                         if ( cent->currentState.eFlags & EF_ALT_FIRING )
02602                         {
02603                                 ent.hModel = weapon->altMissileModel;
02604                         }
02605                         else
02606                         {
02607                                 ent.hModel = weapon->missileModel;
02608                         }
02609                 }
02610         }
02611         //add custom model
02612         else
02613         {
02614                 if ( g_vehWeaponInfo[s1->otherEntityNum2].iModel != NULL_HANDLE )
02615                 {
02616                         ent.hModel = g_vehWeaponInfo[s1->otherEntityNum2].iModel;
02617                 }
02618                 else
02619                 {//wtf?  how did we get here?
02620                         return;
02621                 }
02622         }
02623 
02624         // spin as it moves
02625         if ( s1->apos.trType != TR_INTERPOLATE )
02626         {
02627                 // convert direction of travel into axis
02628                 if ( VectorNormalize2( s1->pos.trDelta, ent.axis[0] ) == 0 ) {
02629                         ent.axis[0][2] = 1;
02630                 }
02631 
02632                 // spin as it moves
02633                 if ( s1->pos.trType != TR_STATIONARY ) 
02634                 {
02635                         if ( s1->eFlags & EF_MISSILE_STICK )
02636                         {
02637                                 RotateAroundDirection( ent.axis, cg.time * 0.5f );//Did this so regular missiles don't get broken
02638                         }
02639                         else
02640                         {
02641                                 RotateAroundDirection( ent.axis, cg.time * 0.25f );//JFM:FLOAT FIX
02642                         }
02643                 } 
02644                 else 
02645                 {
02646                         if ( s1->eFlags & EF_MISSILE_STICK )
02647                         {
02648                                 RotateAroundDirection( ent.axis, (float)s1->pos.trTime * 0.5f );
02649                         }
02650                         else
02651                         {
02652                                 RotateAroundDirection( ent.axis, (float)s1->time );
02653                         }
02654                 }
02655         }
02656         else
02657         {
02658                 AnglesToAxis( cent->lerpAngles, ent.axis );
02659         }
02660 
02661         if (s1->weapon == WP_SABER)
02662         {
02663                 ent.radius = s1->g2radius;
02664         }
02665 
02666         // add to refresh list, possibly with quad glow
02667         CG_AddRefEntityWithPowerups( &ent, s1, TEAM_FREE );
02668 
02669         if (s1->weapon == WP_SABER && cgs.gametype == GT_JEDIMASTER)
02670         { //in jedimaster always make the saber glow when on the ground
02671                 vec3_t org;
02672                 float wv;
02673                 int i;
02674                 addspriteArgStruct_t fxSArgs;
02675                 //refEntity_t sRef;
02676                 //memcpy( &sRef, &ent, sizeof( sRef ) );
02677 
02678                 ent.customShader = cgs.media.solidWhite;
02679                 ent.renderfx = RF_RGB_TINT;
02680                 wv = sin( cg.time * 0.003f ) * 0.08f + 0.1f;
02681                 ent.shaderRGBA[0] = wv * 255;
02682                 ent.shaderRGBA[1] = wv * 255;
02683                 ent.shaderRGBA[2] = wv * 0;
02684                 trap_R_AddRefEntityToScene (&ent);
02685 
02686                 for ( i = -4; i < 10; i += 1 )
02687                 {
02688                         VectorMA( ent.origin, -i, ent.axis[2], org );
02689 
02690                         VectorCopy(org, fxSArgs.origin);
02691                         VectorClear(fxSArgs.vel);
02692                         VectorClear(fxSArgs.accel);
02693                         fxSArgs.scale = 5.5f;
02694                         fxSArgs.dscale = 5.5f;
02695                         fxSArgs.sAlpha = wv;
02696                         fxSArgs.eAlpha = wv;
02697                         fxSArgs.rotation = 0.0f;
02698                         fxSArgs.bounce = 0.0f;
02699                         fxSArgs.life = 1.0f;
02700                         fxSArgs.shader = cgs.media.yellowDroppedSaberShader;
02701                         fxSArgs.flags = 0x08000000;
02702 
02703                         //trap_FX_AddSprite( org, NULL, NULL, 5.5f, 5.5f, wv, wv, 0.0f, 0.0f, 1.0f, cgs.media.yellowSaberGlowShader, 0x08000000 );
02704                         trap_FX_AddSprite(&fxSArgs);
02705                 }
02706 
02707                 if (cgs.gametype == GT_JEDIMASTER)
02708                 {
02709                         ent.shaderRGBA[0] = 255;
02710                         ent.shaderRGBA[1] = 255;
02711                         ent.shaderRGBA[2] = 0;
02712 
02713                         ent.renderfx |= RF_DEPTHHACK;
02714                         ent.customShader = cgs.media.forceSightBubble;
02715                 
02716                         trap_R_AddRefEntityToScene( &ent );
02717                 }
02718         }
02719 
02720         if ( s1->eFlags & EF_FIRING )
02721         {//special code for adding the beam to the attached tripwire mine
02722                 vec3_t  beamOrg;
02723 
02724                 VectorMA( ent.origin, 8, ent.axis[0], beamOrg );// forward
02725                 trap_FX_PlayEffectID( cgs.effects.mTripMineLaster, beamOrg, ent.axis[0], -1, -1 );
02726         }
02727 }
02728 
02729 int     CG_BMS_START = 0;
02730 int     CG_BMS_MID = 1;
02731 int     CG_BMS_END = 2;
02732 
02733 /*
02734 -------------------------
02735 CG_PlayDoorLoopSound
02736 -------------------------
02737 */
02738 
02739 void CG_PlayDoorLoopSound( centity_t *cent )
02740 {
02741         sfxHandle_t     sfx;
02742         const char *soundSet;
02743         vec3_t  origin;
02744         float   *v;
02745 
02746         if ( !cent->currentState.soundSetIndex )
02747         {
02748                 return;
02749         }
02750 
02751         soundSet = CG_ConfigString( CS_AMBIENT_SET + cent->currentState.soundSetIndex );
02752 
02753         if (!soundSet || !soundSet[0])
02754         {
02755                 return;
02756         }
02757 
02758         sfx = trap_AS_GetBModelSound( soundSet, CG_BMS_MID );
02759 
02760         if ( sfx == -1 )
02761         {
02762                 return;
02763         }
02764 
02765         if (cent->currentState.eType == ET_MOVER) //shouldn't be in here otherwise, but just in case.
02766         {
02767                 v = cgs.inlineModelMidpoints[ cent->currentState.modelindex ];
02768                 VectorAdd( cent->lerpOrigin, v, origin );
02769         }
02770         else
02771         {
02772                 VectorCopy(cent->lerpOrigin, origin);
02773         }
02774 
02775         //ent->s.loopSound = sfx;
02776         CG_S_AddRealLoopingSound(cent->currentState.number, origin, vec3_origin, sfx);
02777 }
02778 
02779 /*
02780 -------------------------
02781 CG_PlayDoorSound
02782 -------------------------
02783 */
02784 
02785 void CG_PlayDoorSound( centity_t *cent, int type )
02786 {
02787         sfxHandle_t     sfx;
02788         const char *soundSet;
02789 
02790         if ( !cent->currentState.soundSetIndex )
02791         {
02792                 return;
02793         }
02794 
02795         soundSet = CG_ConfigString( CS_AMBIENT_SET + cent->currentState.soundSetIndex );
02796 
02797         if (!soundSet || !soundSet[0])
02798         {
02799                 return;
02800         }
02801 
02802         sfx = trap_AS_GetBModelSound( soundSet, type );
02803 
02804         if ( sfx == -1 )
02805         {
02806                 return;
02807         }
02808 
02809         trap_S_StartSound( NULL, cent->currentState.number, CHAN_AUTO, sfx );
02810 }
02811 
02812 /*
02813 ===============
02814 CG_Mover
02815 ===============
02816 */
02817 static void CG_Mover( centity_t *cent ) {
02818         refEntity_t                     ent;
02819         entityState_t           *s1;
02820 
02821         s1 = &cent->currentState;
02822 
02823         // create the render entity
02824         memset (&ent, 0, sizeof(ent));
02825 
02826         if ( (cent->currentState.eFlags2&EF2_HYPERSPACE) )
02827         {//I'm the hyperspace brush
02828                 qboolean drawMe = qfalse;
02829                 if ( cg.predictedPlayerState.m_iVehicleNum
02830                         && cg.predictedVehicleState.hyperSpaceTime
02831                         && (cg.time-cg.predictedVehicleState.hyperSpaceTime) < HYPERSPACE_TIME
02832                         && (cg.time-cg.predictedVehicleState.hyperSpaceTime) > 1000 )
02833                 {
02834                         if ( cg.snap 
02835                                 && cg.snap->ps.pm_type == PM_INTERMISSION )
02836                         {//in the intermission, stop drawing hyperspace ent
02837                         }
02838                         else if ( (cg.predictedVehicleState.eFlags2&EF2_HYPERSPACE) )
02839                         {//actually hyperspacing now
02840                                 float timeFrac = ((float)(cg.time-cg.predictedVehicleState.hyperSpaceTime-1000))/(HYPERSPACE_TIME-1000);
02841                                 if ( timeFrac < (HYPERSPACE_TELEPORT_FRAC+0.1f) )
02842                                 {//still in hyperspace or just popped out
02843                                         const float     alpha = timeFrac<0.5f?timeFrac/0.5f:1.0f;
02844                                         drawMe = qtrue;
02845                                         VectorMA( cg.refdef.vieworg, 1000.0f+((1.0f-timeFrac)*1000.0f), cg.refdef.viewaxis[0], cent->lerpOrigin );
02846                                         VectorSet( cent->lerpAngles, cg.refdef.viewangles[PITCH], cg.refdef.viewangles[YAW]-90.0f, 0 );//cos( ( cg.time + 1000 ) *  scale ) * 4 );
02847                                         ent.shaderRGBA[0] = ent.shaderRGBA[1] = ent.shaderRGBA[2] = 255;
02848                                         ent.shaderRGBA[3] = alpha*255;
02849                                 }
02850                         }
02851                 }
02852                 if ( !drawMe )
02853                 {//else, never draw
02854                         return;
02855                 }
02856         }
02857 
02858         if (cent->currentState.eFlags & EF_RADAROBJECT)
02859         {
02860                 CG_AddRadarEnt(cent);
02861         }
02862 
02863         VectorCopy( cent->lerpOrigin, ent.origin);
02864         VectorCopy( cent->lerpOrigin, ent.oldorigin);
02865         AnglesToAxis( cent->lerpAngles, ent.axis );
02866 
02867         ent.renderfx = RF_NOSHADOW;
02868 /*
02869 Ghoul2 Insert Start
02870 */
02871 
02872         CG_SetGhoul2Info(&ent, cent);  
02873 /*
02874 Ghoul2 Insert End
02875 */
02876         // flicker between two skins (FIXME?)
02877         ent.skinNum = ( cg.time >> 6 ) & 1;
02878 
02879         // get the model, either as a bmodel or a modelindex
02880         if ( s1->solid == SOLID_BMODEL ) 
02881         {
02882                 ent.hModel = cgs.inlineDrawModel[s1->modelindex];
02883         } 
02884         else 
02885         {
02886                 ent.hModel = cgs.gameModels[s1->modelindex];
02887         }
02888 
02889         if ( s1->eFlags & EF_SHADER_ANIM )
02890         {
02891                 ent.renderfx|=RF_SETANIMINDEX;
02892                 ent.skinNum = s1->frame;
02893                 //ent.shaderTime = cg.time*0.001f - s1->frame/s1->time;//NOTE: s1->time is number of frames
02894         }
02895 
02896         // add to refresh list
02897         trap_R_AddRefEntityToScene(&ent);
02898 
02899         // add the secondary model
02900         if ( s1->modelindex2 ) 
02901         {
02902                 ent.skinNum = 0;
02903                 ent.hModel = cgs.gameModels[s1->modelindex2];
02904                 if (s1->iModelScale)
02905                 { //custom model2 scale
02906                         ent.modelScale[0] = ent.modelScale[1] = ent.modelScale[2] = s1->iModelScale/100.0f;
02907                         ScaleModelAxis(&ent);
02908                 }
02909                 trap_R_AddRefEntityToScene(&ent);
02910         }
02911 
02912 }
02913 
02914 /*
02915 ===============
02916 CG_Beam
02917 
02918 Also called as an event
02919 ===============
02920 */
02921 void CG_Beam( centity_t *cent ) {
02922         refEntity_t                     ent;
02923         entityState_t           *s1;
02924 
02925         s1 = &cent->currentState;
02926 
02927         // create the render entity
02928         memset (&ent, 0, sizeof(ent));
02929         VectorCopy( s1->pos.trBase, ent.origin );
02930         VectorCopy( s1->origin2, ent.oldorigin );
02931         AxisClear( ent.axis );
02932         ent.reType = RT_BEAM;
02933 
02934         ent.renderfx = RF_NOSHADOW;
02935 /*
02936 Ghoul2 Insert Start
02937 */
02938         CG_SetGhoul2Info(&ent, cent);  
02939 
02940 /*
02941 Ghoul2 Insert End
02942 */
02943         // add to refresh list
02944         trap_R_AddRefEntityToScene(&ent);
02945 }
02946 
02947 
02948 /*
02949 ===============
02950 CG_Portal
02951 ===============
02952 */
02953 static void CG_Portal( centity_t *cent ) {
02954         refEntity_t                     ent;
02955         entityState_t           *s1;
02956 
02957         s1 = &cent->currentState;
02958 
02959         // create the render entity
02960         memset (&ent, 0, sizeof(ent));
02961         VectorCopy( cent->lerpOrigin, ent.origin );
02962         VectorCopy( s1->origin2, ent.oldorigin );
02963         ByteToDir( s1->eventParm, ent.axis[0] );
02964         PerpendicularVector( ent.axis[1], ent.axis[0] );
02965 
02966         // negating this tends to get the directions like they want
02967         // we really should have a camera roll value
02968         VectorSubtract( vec3_origin, ent.axis[1], ent.axis[1] );
02969 
02970         CrossProduct( ent.axis[0], ent.axis[1], ent.axis[2] );
02971         ent.reType = RT_PORTALSURFACE;
02972         ent.oldframe = s1->powerups;
02973         ent.frame = s1->frame;          // rotation speed
02974         ent.skinNum = s1->clientNum/256.0 * 360;        // roll offset
02975 /*
02976 Ghoul2 Insert Start
02977 */
02978         CG_SetGhoul2Info(&ent, cent);  
02979 /*
02980 Ghoul2 Insert End
02981 */
02982         // add to refresh list
02983         trap_R_AddRefEntityToScene(&ent);
02984 }
02985 
02986 
02987 /*
02988 =========================
02989 CG_AdjustPositionForMover
02990 
02991 Also called by client movement prediction code
02992 =========================
02993 */
02994 void CG_AdjustPositionForMover( const vec3_t in, int moverNum, int fromTime, int toTime, vec3_t out ) {
02995         centity_t       *cent;
02996         vec3_t  oldOrigin, origin, deltaOrigin;
02997         vec3_t  oldAngles, angles, deltaAngles;
02998 
02999         if ( moverNum <= 0 || moverNum >= ENTITYNUM_MAX_NORMAL ) {
03000                 VectorCopy( in, out );
03001                 return;
03002         }
03003 
03004         cent = &cg_entities[ moverNum ];
03005         if ( cent->currentState.eType != ET_MOVER ) {
03006                 VectorCopy( in, out );
03007                 return;
03008         }
03009 
03010         BG_EvaluateTrajectory( &cent->currentState.pos, fromTime, oldOrigin );
03011         BG_EvaluateTrajectory( &cent->currentState.apos, fromTime, oldAngles );
03012 
03013         BG_EvaluateTrajectory( &cent->currentState.pos, toTime, origin );
03014         BG_EvaluateTrajectory( &cent->currentState.apos, toTime, angles );
03015 
03016         VectorSubtract( origin, oldOrigin, deltaOrigin );
03017         VectorSubtract( angles, oldAngles, deltaAngles );
03018 
03019         VectorAdd( in, deltaOrigin, out );
03020 
03021         // FIXME: origin change when on a rotating object
03022 }
03023 
03024 /*
03025 =============================
03026 CG_InterpolateEntityPosition
03027 =============================
03028 */
03029 static void CG_InterpolateEntityPosition( centity_t *cent ) {
03030         vec3_t          current, next;
03031         float           f;
03032 
03033         // it would be an internal error to find an entity that interpolates without
03034         // a snapshot ahead of the current one
03035         if ( cg.nextSnap == NULL ) {
03036                 CG_Error( "CG_InterpoateEntityPosition: cg.nextSnap == NULL" );
03037         }
03038 
03039         f = cg.frameInterpolation;
03040 
03041         // this will linearize a sine or parabolic curve, but it is important
03042         // to not extrapolate player positions if more recent data is available
03043         BG_EvaluateTrajectory( &cent->currentState.pos, cg.snap->serverTime, current );
03044         BG_EvaluateTrajectory( &cent->nextState.pos, cg.nextSnap->serverTime, next );
03045 
03046         cent->lerpOrigin[0] = current[0] + f * ( next[0] - current[0] );
03047         cent->lerpOrigin[1] = current[1] + f * ( next[1] - current[1] );
03048         cent->lerpOrigin[2] = current[2] + f * ( next[2] - current[2] );
03049 
03050         BG_EvaluateTrajectory( &cent->currentState.apos, cg.snap->serverTime, current );
03051         BG_EvaluateTrajectory( &cent->nextState.apos, cg.nextSnap->serverTime, next );
03052 
03053         cent->lerpAngles[0] = LerpAngle( current[0], next[0], f );
03054         cent->lerpAngles[1] = LerpAngle( current[1], next[1], f );
03055         cent->lerpAngles[2] = LerpAngle( current[2], next[2], f );
03056 }
03057 
03058 /*
03059 ===============
03060 CG_CalcEntityLerpPositions
03061 
03062 ===============
03063 */
03064 void CG_CalcEntityLerpPositions( centity_t *cent ) {
03065         qboolean goAway = qfalse;
03066 
03067         // if this player does not want to see extrapolated players
03068         if ( !cg_smoothClients.integer ) {
03069                 // make sure the clients use TR_INTERPOLATE
03070                 if ( cent->currentState.number < MAX_CLIENTS ) {
03071                         cent->currentState.pos.trType = TR_INTERPOLATE;
03072                         cent->nextState.pos.trType = TR_INTERPOLATE;
03073                 }
03074         }
03075 
03076         if (cg.predictedPlayerState.m_iVehicleNum &&
03077                 cg.predictedPlayerState.m_iVehicleNum == cent->currentState.number &&
03078                 cent->currentState.eType == ET_NPC && cent->currentState.NPC_class == CLASS_VEHICLE)
03079         { //special case for vehicle we are riding
03080                 centity_t *veh = &cg_entities[cg.predictedPlayerState.m_iVehicleNum];
03081 
03082                 if (veh->currentState.owner == cg.predictedPlayerState.clientNum)
03083                 { //only do this if the vehicle is pilotted by this client and predicting properly
03084                         BG_EvaluateTrajectory( &cent->currentState.pos, cg.time, cent->lerpOrigin );
03085                         BG_EvaluateTrajectory( &cent->currentState.apos, cg.time, cent->lerpAngles );
03086                         return;
03087                 }
03088         }
03089 
03090         if ( cent->interpolate && cent->currentState.pos.trType == TR_INTERPOLATE ) {
03091                 CG_InterpolateEntityPosition( cent );
03092                 return;
03093         }
03094 
03095         // first see if we can interpolate between two snaps for
03096         // linear extrapolated clients
03097         if ( cent->interpolate && cent->currentState.pos.trType == TR_LINEAR_STOP &&
03098                                                                                         cent->currentState.number < MAX_CLIENTS) {
03099                 CG_InterpolateEntityPosition( cent );
03100                 goAway = qtrue;
03101         }
03102         else if (cent->interpolate &&
03103                 cent->currentState.eType == ET_NPC && cent->currentState.NPC_class == CLASS_VEHICLE)
03104         {
03105                 CG_InterpolateEntityPosition( cent );
03106                 goAway = qtrue;
03107         }
03108         else
03109         {
03110                 // just use the current frame and evaluate as best we can
03111                 BG_EvaluateTrajectory( &cent->currentState.pos, cg.time, cent->lerpOrigin );
03112                 BG_EvaluateTrajectory( &cent->currentState.apos, cg.time, cent->lerpAngles );
03113         }
03114 
03115 #if 0
03116         if (cent->hasRagOffset && cent->ragOffsetTime < cg.time)
03117         { //take all of the offsets from last frame and normalize the total direction and add it in
03118                 vec3_t slideDir;
03119                 vec3_t preOffset;
03120                 vec3_t addedOffset;
03121                 vec3_t  playerMins = {-15, -15, DEFAULT_MINS_2};
03122                 vec3_t  playerMaxs = {15, 15, DEFAULT_MAXS_2};
03123                 trace_t tr;
03124 
03125                 //VectorSubtract(cent->lerpOrigin, callData->bonePos, slideDir);
03126                 VectorCopy(cent->ragOffsets, slideDir);
03127                 VectorNormalize(slideDir);
03128 
03129                 //Store it in case we want to go back
03130                 VectorCopy(cent->lerpOriginOffset, preOffset);
03131 
03132                 //just add a little at a time
03133                 VectorMA(cent->lerpOriginOffset, 0.4f, slideDir, cent->lerpOriginOffset);
03134 
03135                 if (VectorLength(cent->lerpOriginOffset) > 10.0f)
03136                 { //don't go too far away
03137                         VectorCopy(preOffset, cent->lerpOriginOffset);
03138                 }
03139                 else
03140                 {
03141                         //Let's trace there to make sure we can make it
03142                         VectorAdd(cent->lerpOrigin, cent->lerpOriginOffset, addedOffset);
03143                         CG_Trace(&tr, cent->lerpOrigin, playerMins, playerMaxs, addedOffset, cent->currentState.number, MASK_PLAYERSOLID);
03144 
03145                         if (tr.startsolid || tr.allsolid || tr.fraction != 1.0f)
03146                         { //can't get there
03147                                 VectorCopy(preOffset, cent->lerpOriginOffset);
03148                         }
03149                         else
03150                         {
03151                                 /*
03152                                 if (cent->lerpOriginOffset[2] > 4.0f)
03153                                 { //don't go too far off the ground
03154                                         cent->lerpOriginOffset[2] = 4.0f;
03155                                 }
03156                                 */
03157                                 //I guess I just don't want this happening.
03158                                 cent->lerpOriginOffset[2] = 0.0f;
03159                         }
03160                 }
03161 
03162                 //done with this bit
03163                 cent->hasRagOffset = qfalse;
03164                 VectorClear(cent->ragOffsets);
03165                 cent->ragOffsetTime = cg.time + 50;
03166         }
03167 
03168         //See if we should add in the offset for ragdoll
03169         if (cent->isRagging && ((cent->currentState.eFlags & EF_DEAD) || (cent->currentState.eFlags & EF_RAG)))
03170         {
03171                 VectorAdd(cent->lerpOrigin, cent->lerpOriginOffset, cent->lerpOrigin);
03172         }
03173 #endif
03174 
03175         if (goAway)
03176         {
03177                 return;
03178         }
03179 
03180         // adjust for riding a mover if it wasn't rolled into the predicted
03181         // player state
03182         if ( cent->currentState.number != cg.predictedPlayerState.clientNum ) {
03183                 CG_AdjustPositionForMover( cent->lerpOrigin, cent->currentState.groundEntityNum, 
03184                 cg.snap->serverTime, cg.time, cent->lerpOrigin );
03185         }
03186 }
03187 
03188 /*
03189 ===============
03190 CG_TeamBase
03191 ===============
03192 */
03193 static void CG_TeamBase( centity_t *cent ) {
03194         refEntity_t model;
03195         if ( cgs.gametype == GT_CTF || cgs.gametype == GT_CTY ) {
03196                 // show the flag base
03197                 memset(&model, 0, sizeof(model));
03198                 model.reType = RT_MODEL;
03199                 VectorCopy( cent->lerpOrigin, model.lightingOrigin );
03200                 VectorCopy( cent->lerpOrigin, model.origin );
03201                 AnglesToAxis( cent->currentState.angles, model.axis );
03202                 if ( cent->currentState.modelindex == TEAM_RED ) {
03203                         model.hModel = cgs.media.redFlagBaseModel;
03204                 }
03205                 else if ( cent->currentState.modelindex == TEAM_BLUE ) {
03206                         model.hModel = cgs.media.blueFlagBaseModel;
03207                 }
03208                 else {
03209                         model.hModel = cgs.media.neutralFlagBaseModel;
03210                 }
03211 
03212                 if (cent->currentState.eType != ET_NPC)
03213                 { //do not do this for g2animents
03214                         trap_R_AddRefEntityToScene( &model );
03215                 }
03216         }
03217 }
03218 
03219 void CG_G2Animated( centity_t *cent );
03220 
03221 static void CG_FX( centity_t *cent ) 
03222 {
03223         vec3_t                  fxDir;
03224         int                             efxIndex = 0;
03225         entityState_t   *s1;
03226         const char              *s;
03227 
03228         if (cent->miscTime > cg.time)
03229         {
03230                 return;
03231         }
03232 
03233         s1 = &cent->currentState;
03234 
03235         if (!s1)
03236         {
03237                 return;
03238         }
03239 
03240         if (s1->modelindex2 == FX_STATE_OFF)
03241         {       // fx not active
03242                 return;
03243         }
03244 
03245         if (s1->modelindex2 < FX_STATE_ONE_SHOT_LIMIT)
03246         {       // fx is single shot
03247                 if (cent->muzzleFlashTime == s1->modelindex2)
03248                 {
03249                         return;
03250                 }
03251 
03252                 cent->muzzleFlashTime = s1->modelindex2;
03253         }
03254 
03255         cent->miscTime = cg.time + s1->speed + random() * s1->time;
03256 
03257         AngleVectors(s1->angles, fxDir, 0, 0);
03258         
03259         if (!fxDir[0] && !fxDir[1] && !fxDir[2])
03260         {
03261                 fxDir[1] = 1;
03262         }
03263 
03264         if ( cgs.gameEffects[ s1->modelindex ] )
03265         {
03266                 efxIndex = cgs.gameEffects[s1->modelindex];
03267         }
03268         else
03269         {
03270                 s = CG_ConfigString( CS_EFFECTS + s1->modelindex );
03271                 if (s && s[0])
03272                 {
03273                         efxIndex = trap_FX_RegisterEffect(s);
03274                         cgs.gameEffects[s1->modelindex] = efxIndex;
03275                 }
03276         }
03277 
03278         if (efxIndex)
03279         {
03280                 if (s1->isPortalEnt)
03281                 {
03282                         trap_FX_PlayPortalEffectID(efxIndex, cent->lerpOrigin, fxDir, -1, -1 );
03283                 }
03284                 else
03285                 {
03286                         trap_FX_PlayEffectID(efxIndex, cent->lerpOrigin, fxDir, -1, -1 );
03287                 }
03288         }
03289 
03290 
03291 }
03292 
03293 
03294 /*
03295 ===============
03296 CG_AddCEntity
03297 
03298 ===============
03299 */
03300 static void CG_AddCEntity( centity_t *cent ) {
03301         // event-only entities will have been dealt with already
03302         if ( cent->currentState.eType >= ET_EVENTS ) {
03303                 return;
03304         }
03305 
03306         if (cg.predictedPlayerState.pm_type == PM_INTERMISSION)
03307         { //don't render anything then
03308                 if (cent->currentState.eType == ET_GENERAL ||
03309                         cent->currentState.eType == ET_PLAYER ||
03310                         cent->currentState.eType == ET_INVISIBLE)
03311                 {
03312                         return;
03313                 }
03314                 if ( cent->currentState.eType == ET_NPC )
03315                 {//NPC in intermission
03316                         if ( cent->currentState.NPC_class == CLASS_VEHICLE )
03317                         {//don't render vehicles in intermissions, allow other NPCs for scripts
03318                                 return;
03319                         }
03320                 }
03321         }
03322 
03323         // calculate the current origin
03324         CG_CalcEntityLerpPositions( cent );
03325 
03326         // add automatic effects
03327         CG_EntityEffects( cent );
03328 /*
03329 Ghoul2 Insert Start
03330 */
03331 
03332         // add local sound set if any
03333         if ( cent->currentState.soundSetIndex && cent->currentState.eType != ET_MOVER )
03334         {
03335                 const char *soundSet = CG_ConfigString( CS_AMBIENT_SET + cent->currentState.soundSetIndex );
03336 
03337                 if (soundSet && soundSet[0])
03338                 {
03339                         trap_S_AddLocalSet(soundSet, cg.refdef.vieworg, cent->lerpOrigin, cent->currentState.number, cg.time);
03340                 }
03341         }
03342 /*
03343 Ghoul2 Insert End
03344 */
03345         switch ( cent->currentState.eType ) {
03346         default:
03347                 CG_Error( "Bad entity type: %i\n", cent->currentState.eType );
03348                 break;
03349 
03350         case ET_FX:
03351                 CG_FX( cent );
03352                 break;
03353 
03354         case ET_INVISIBLE:
03355         case ET_PUSH_TRIGGER:
03356         case ET_TELEPORT_TRIGGER:
03357         case ET_TERRAIN:
03358                 break;
03359         case ET_GENERAL:
03360                 CG_General( cent );
03361                 break;
03362         case ET_PLAYER:
03363                 CG_Player( cent );
03364                 break;
03365         case ET_ITEM:
03366                 CG_Item( cent );
03367                 break;
03368         case ET_MISSILE:
03369                 CG_Missile( cent );
03370                 break;
03371         case ET_SPECIAL:
03372                 CG_Special( cent );
03373                 break;
03374         case ET_HOLOCRON:
03375                 CG_General( cent );
03376                 break;
03377         case ET_MOVER:
03378                 CG_Mover( cent );
03379                 break;
03380         case ET_BEAM:
03381                 CG_Beam( cent );
03382                 break;
03383         case ET_PORTAL:
03384                 CG_Portal( cent );
03385                 break;
03386         case ET_SPEAKER:
03387                 CG_Speaker( cent );
03388                 break;
03389         case ET_NPC: //An entity that wants to be able to use ghoul2 humanoid (and other) anims. Like a player, but not.
03390                 CG_G2Animated( cent );
03391                 break;
03392         case ET_TEAM:
03393                 CG_TeamBase( cent );
03394                 break;
03395         case ET_BODY:
03396                 CG_General( cent );
03397                 break;
03398         }
03399 }
03400 
03401 void CG_ManualEntityRender(centity_t *cent)
03402 {
03403         CG_AddCEntity(cent);
03404 }
03405 
03406 /*
03407 ===============
03408 CG_AddPacketEntities
03409 
03410 ===============
03411 */
03412 void CG_AddPacketEntities( qboolean isPortal ) {
03413         int                                     num;
03414         centity_t                       *cent;
03415         playerState_t           *ps;
03416 
03417         if (isPortal)
03418         {
03419                 for ( num = 0 ; num < cg.snap->numEntities ; num++ )
03420                 {
03421                         cent = &cg_entities[ cg.snap->entities[ num ].number ];
03422 
03423                         if (cent->currentState.isPortalEnt)
03424                         {
03425                                 CG_AddCEntity( cent );
03426                         }
03427                 }
03428                 return;
03429         }
03430 
03431         // set cg.frameInterpolation
03432         if ( cg.nextSnap ) {
03433                 int             delta;
03434 
03435                 delta = (cg.nextSnap->serverTime - cg.snap->serverTime);
03436                 if ( delta == 0 ) {
03437                         cg.frameInterpolation = 0;
03438                 } else {
03439                         cg.frameInterpolation = (float)( cg.time - cg.snap->serverTime ) / delta;
03440                 }
03441         } else {
03442                 cg.frameInterpolation = 0;      // actually, it should never be used, because 
03443                                                                         // no entities should be marked as interpolating
03444         }
03445 
03446         // the auto-rotating items will all have the same axis
03447         cg.autoAngles[0] = 0;
03448         cg.autoAngles[1] = ( cg.time & 2047 ) * 360 / 2048.0;
03449         cg.autoAngles[2] = 0;
03450 
03451         cg.autoAnglesFast[0] = 0;
03452         cg.autoAnglesFast[1] = ( cg.time & 1023 ) * 360 / 1024.0f;
03453         cg.autoAnglesFast[2] = 0;
03454 
03455         AnglesToAxis( cg.autoAngles, cg.autoAxis );
03456         AnglesToAxis( cg.autoAnglesFast, cg.autoAxisFast );
03457 
03458         // Reset radar entities
03459         cg.radarEntityCount = 0;
03460         cg.bracketedEntityCount = 0;
03461 
03462         // generate and add the entity from the playerstate
03463         ps = &cg.predictedPlayerState;
03464 
03465         CG_CheckPlayerG2Weapons(ps, &cg_entities[cg.predictedPlayerState.clientNum]);
03466         BG_PlayerStateToEntityState( ps, &cg_entities[cg.predictedPlayerState.clientNum].currentState, qfalse );
03467         
03468         if (cg.predictedPlayerState.m_iVehicleNum)
03469         { //add the vehicle I'm riding first
03470                 //BG_PlayerStateToEntityState( &cg.predictedVehicleState, &cg_entities[cg.predictedPlayerState.m_iVehicleNum].currentState, qfalse );
03471                 //cg_entities[cg.predictedPlayerState.m_iVehicleNum].currentState.eType = ET_NPC;
03472                 centity_t *veh = &cg_entities[cg.predictedPlayerState.m_iVehicleNum];
03473 
03474                 if (veh->currentState.owner == cg.predictedPlayerState.clientNum)
03475                 {
03476                         BG_PlayerStateToEntityState( &cg.predictedVehicleState, &veh->currentState, qfalse );
03477                         veh->currentState.eType = ET_NPC;
03478 
03479                         veh->currentState.pos.trType = TR_INTERPOLATE;
03480                 }
03481         CG_AddCEntity(veh);
03482                 veh->bodyHeight = cg.time; //indicate we have already been added
03483         }
03484 
03485         CG_AddCEntity( &cg_entities[cg.predictedPlayerState.clientNum] );
03486 
03487         /*
03488         // lerp the non-predicted value for lightning gun origins
03489         CG_CalcEntityLerpPositions( &cg_entities[ cg.snap->ps.clientNum ] );
03490         */
03491         //No longer have to do this.
03492 
03493         // add each entity sent over by the server
03494         for ( num = 0 ; num < cg.snap->numEntities ; num++ ) {
03495                 // Don't re-add ents that have been predicted.
03496                 if (cg.snap->entities[ num ].number != cg.snap->ps.clientNum)
03497                 {
03498                         cent = &cg_entities[ cg.snap->entities[ num ].number ];
03499                         if (cent->currentState.eType == ET_PLAYER &&
03500                                 cent->currentState.m_iVehicleNum)
03501                         { //add his veh first
03502                                 int j = 0;
03503 
03504                                 while (j < cg.snap->numEntities)
03505                                 {
03506                                         if (cg.snap->entities[j].number == cent->currentState.m_iVehicleNum)
03507                                         {
03508                                                 centity_t *veh = &cg_entities[cg.snap->entities[j].number];
03509 
03510                                                 CG_AddCEntity(veh);
03511                                                 veh->bodyHeight = cg.time; //indicate we have already been added
03512                                                 break;
03513                                         }
03514 
03515                                         j++;
03516                                 }
03517                         }
03518                         else if (cent->currentState.eType == ET_NPC &&
03519                                 cent->currentState.m_iVehicleNum &&
03520                                 cent->bodyHeight == cg.time)
03521                         { //never add a vehicle with a pilot, his pilot entity will get him added first.
03522                                 //if we were to add the vehicle after the pilot, the pilot's bolt would lag a frame behind.
03523                                 continue;
03524                         }
03525                         CG_AddCEntity( cent );
03526                 }
03527         }
03528 
03529         for(num=0;num<cg_numpermanents;num++)
03530         {
03531                 cent = cg_permanents[num];
03532                 if (cent->currentValid)
03533                 {
03534                         CG_AddCEntity( cent );
03535                 }
03536         }
03537 }
03538 
03539 void CG_ROFF_NotetrackCallback( centity_t *cent, const char *notetrack)
03540 {
03541         int i = 0, r = 0, objectID = 0, anglesGathered = 0, posoffsetGathered = 0;
03542         char type[256];
03543         char argument[512];
03544         char addlArg[512];
03545         char errMsg[256];
03546         char t[64];
03547         int addlArgs = 0;
03548         vec3_t parsedAngles, parsedOffset, useAngles, useOrigin, forward, right, up;
03549 
03550         if (!cent || !notetrack)
03551         {
03552                 return;
03553         }
03554 
03555         //notetrack = "effect effects/explosion1.efx 0+0+64 0-0-1";
03556 
03557         while (notetrack[i] && notetrack[i] != ' ')
03558         {
03559                 type[i] = notetrack[i];
03560                 i++;
03561         }
03562 
03563         type[i] = '\0';
03564 
03565         if (notetrack[i] != ' ')
03566         { //didn't pass in a valid notetrack type, or forgot the argument for it
03567                 return;
03568         }
03569 
03570         i++;
03571 
03572         while (notetrack[i] && notetrack[i] != ' ')
03573         {
03574                 argument[r] = notetrack[i];
03575                 r++;
03576                 i++;
03577         }
03578         argument[r] = '\0';
03579 
03580         if (!r)
03581         {
03582                 return;
03583         }
03584 
03585         if (notetrack[i] == ' ')
03586         { //additional arguments...
03587                 addlArgs = 1;
03588 
03589                 i++;
03590                 r = 0;
03591                 while (notetrack[i])
03592                 {
03593                         addlArg[r] = notetrack[i];
03594                         r++;
03595                         i++;
03596                 }
03597                 addlArg[r] = '\0';
03598         }
03599 
03600         if (strcmp(type, "effect") == 0)
03601         {
03602                 if (!addlArgs)
03603                 {
03604                         //sprintf(errMsg, "Offset position argument for 'effect' type is invalid.");
03605                         //goto functionend;
03606                         VectorClear(parsedOffset);
03607                         goto defaultoffsetposition;
03608                 }
03609 
03610                 i = 0;
03611 
03612                 while (posoffsetGathered < 3)
03613                 {
03614                         r = 0;
03615                         while (addlArg[i] && addlArg[i] != '+' && addlArg[i] != ' ')
03616                         {
03617                                 t[r] = addlArg[i];
03618                                 r++;
03619                                 i++;
03620                         }
03621                         t[r] = '\0';
03622                         i++;
03623                         if (!r)
03624                         { //failure..
03625                                 //sprintf(errMsg, "Offset position argument for 'effect' type is invalid.");
03626                                 //goto functionend;
03627                                 VectorClear(parsedOffset);
03628                                 i = 0;
03629                                 goto defaultoffsetposition;
03630                         }
03631                         parsedOffset[posoffsetGathered] = atof(t);
03632                         posoffsetGathered++;
03633                 }
03634 
03635                 if (posoffsetGathered < 3)
03636                 {
03637                         Com_sprintf(errMsg, sizeof(errMsg), "Offset position argument for 'effect' type is invalid.");
03638                         goto functionend;
03639                 }
03640 
03641                 i--;
03642 
03643                 if (addlArg[i] != ' ')
03644                 {
03645                         addlArgs = 0;
03646                 }
03647 
03648 defaultoffsetposition:
03649 
03650                 objectID = trap_FX_RegisterEffect(argument);
03651 
03652                 if (objectID)
03653                 {
03654                         if (addlArgs)
03655                         { //if there is an additional argument for an effect it is expected to be XANGLE-YANGLE-ZANGLE
03656                                 i++;
03657                                 while (anglesGathered < 3)
03658                                 {
03659                                         r = 0;
03660                                         while (addlArg[i] && addlArg[i] != '-')
03661                                         {
03662                                                 t[r] = addlArg[i];
03663                                                 r++;
03664                                                 i++;
03665                                         }
03666                                         t[r] = '\0';
03667                                         i++;
03668 
03669                                         if (!r)
03670                                         { //failed to get a new part of the vector
03671                                                 anglesGathered = 0;
03672                                                 break;
03673                                         }
03674 
03675                                         parsedAngles[anglesGathered] = atof(t);
03676                                         anglesGathered++;
03677                                 }
03678 
03679                                 if (anglesGathered)
03680                                 {
03681                                         VectorCopy(parsedAngles, useAngles);
03682                                 }
03683                                 else
03684                                 { //failed to parse angles from the extra argument provided..
03685                                         VectorCopy(cent->lerpAngles, useAngles);
03686                                 }
03687                         }
03688                         else
03689                         { //if no constant angles, play in direction entity is facing
03690                                 VectorCopy(cent->lerpAngles, useAngles);
03691                         }
03692 
03693                         AngleVectors(useAngles, forward, right, up);
03694 
03695                         VectorCopy(cent->lerpOrigin, useOrigin);
03696 
03697                         //forward
03698                         useOrigin[0] += forward[0]*parsedOffset[0];
03699                         useOrigin[1] += forward[1]*parsedOffset[0];
03700                         useOrigin[2] += forward[2]*parsedOffset[0];
03701 
03702                         //right
03703                         useOrigin[0] += right[0]*parsedOffset[1];
03704                         useOrigin[1] += right[1]*parsedOffset[1];
03705                         useOrigin[2] += right[2]*parsedOffset[1];
03706 
03707                         //up
03708                         useOrigin[0] += up[0]*parsedOffset[2];
03709                         useOrigin[1] += up[1]*parsedOffset[2];
03710                         useOrigin[2] += up[2]*parsedOffset[2];
03711 
03712                         trap_FX_PlayEffectID(objectID, useOrigin, useAngles, -1, -1);
03713                 }
03714         }
03715         else if (strcmp(type, "sound") == 0)
03716         {
03717                 objectID = trap_S_RegisterSound(argument);
03718                 trap_S_StartSound(cent->lerpOrigin, cent->currentState.number, CHAN_BODY, objectID);
03719         }
03720         else if (strcmp(type, "loop") == 0)
03721         { //handled server-side
03722                 return;
03723         }
03724         //else if ...
03725         else
03726         {
03727                 if (type[0])
03728                 {
03729                         Com_Printf("^3Warning: \"%s\" is an invalid ROFF notetrack function\n", type);
03730                 }
03731                 else
03732                 {
03733                         Com_Printf("^3Warning: Notetrack is missing function and/or arguments\n");
03734                 }
03735         }
03736 
03737         return;
03738 
03739 functionend:
03740         Com_Printf("^3Type-specific notetrack error: %s\n", errMsg);
03741         return;
03742 }
03743 
03744 void CG_Cube( vec3_t mins, vec3_t maxs, vec3_t color, float alpha ) 
03745 {
03746         vec3_t  rot={0,0,0};
03747         int             vec[3];
03748         int             axis, i;
03749         addpolyArgStruct_t apArgs;
03750 
03751         memset (&apArgs, 0, sizeof(apArgs));
03752 
03753         for ( axis = 0, vec[0] = 0, vec[1] = 1, vec[2] = 2; axis < 3; axis++, vec[0]++, vec[1]++, vec[2]++ )
03754         {
03755                 for ( i = 0; i < 3; i++ )
03756                 {
03757                         if ( vec[i] > 2 )
03758                         {
03759                                 vec[i] = 0;
03760                         }
03761                 }
03762 
03763                 apArgs.p[0][vec[1]] = mins[vec[1]];
03764                 apArgs.p[0][vec[2]] = mins[vec[2]];
03765 
03766                 apArgs.p[1][vec[1]] = mins[vec[1]];
03767                 apArgs.p[1][vec[2]] = maxs[vec[2]];
03768 
03769                 apArgs.p[2][vec[1]] = maxs[vec[1]];
03770                 apArgs.p[2][vec[2]] = maxs[vec[2]];
03771                 
03772                 apArgs.p[3][vec[1]] = maxs[vec[1]];
03773                 apArgs.p[3][vec[2]] = mins[vec[2]];
03774 
03775                 //- face
03776                 apArgs.p[0][vec[0]] = apArgs.p[1][vec[0]] = apArgs.p[2][vec[0]] = apArgs.p[3][vec[0]] = mins[vec[0]];
03777 
03778                 apArgs.numVerts = 4;
03779                 apArgs.alpha1 = apArgs.alpha2 = alpha;
03780                 VectorCopy( color, apArgs.rgb1 );
03781                 VectorCopy( color, apArgs.rgb2 );
03782                 VectorCopy( rot, apArgs.rotationDelta );
03783                 apArgs.killTime = cg.frametime;
03784                 apArgs.shader = cgs.media.solidWhite;
03785 
03786                 trap_FX_AddPoly( &apArgs );
03787 
03788                 //+ face
03789                 apArgs.p[0][vec[0]] = apArgs.p[1][vec[0]] = apArgs.p[2][vec[0]] = apArgs.p[3][vec[0]] = maxs[vec[0]];
03790 
03791                 trap_FX_AddPoly( &apArgs );
03792         }
03793 }