codemp/cgame/cg_draw.c

Go to the documentation of this file.
00001 // Copyright (C) 1999-2000 Id Software, Inc.
00002 //
00003 // cg_draw.c -- draw all of the graphical elements during
00004 // active (after loading) gameplay
00005 
00006 #include "cg_local.h"
00007 
00008 #include "bg_saga.h"
00009 
00010 #include "../ui/ui_shared.h"
00011 #include "../ui/ui_public.h"
00012 
00013 extern float CG_RadiusForCent( centity_t *cent );
00014 qboolean CG_WorldCoordToScreenCoordFloat(vec3_t worldCoord, float *x, float *y);
00015 qboolean CG_CalcMuzzlePoint( int entityNum, vec3_t muzzle );
00016 static void CG_DrawSiegeTimer(int timeRemaining, qboolean isMyTeam);
00017 static void CG_DrawSiegeDeathTimer( int timeRemaining );
00018 // nmckenzie: DUEL_HEALTH
00019 void CG_DrawDuelistHealth ( float x, float y, float w, float h, int duelist );
00020 
00021 // used for scoreboard
00022 extern displayContextDef_t cgDC;
00023 menuDef_t *menuScoreboard = NULL;
00024 vec4_t  bluehudtint = {0.5, 0.5, 1.0, 1.0};
00025 vec4_t  redhudtint = {1.0, 0.5, 0.5, 1.0};
00026 float   *hudTintColor;
00027 
00028 int sortedTeamPlayers[TEAM_MAXOVERLAY];
00029 int     numSortedTeamPlayers;
00030 
00031 int lastvalidlockdif;
00032 
00033 extern float zoomFov; //this has to be global client-side
00034 
00035 char systemChat[256];
00036 char teamChat1[256];
00037 char teamChat2[256];
00038 
00039 // The time at which you died and the time it will take for you to rejoin game.
00040 int cg_siegeDeathTime = 0;
00041 
00042 #define MAX_HUD_TICS 4
00043 const char *armorTicName[MAX_HUD_TICS] = 
00044 {
00045 "armor_tic1", 
00046 "armor_tic2", 
00047 "armor_tic3", 
00048 "armor_tic4", 
00049 };
00050 
00051 const char *healthTicName[MAX_HUD_TICS] = 
00052 {
00053 "health_tic1", 
00054 "health_tic2", 
00055 "health_tic3", 
00056 "health_tic4", 
00057 };
00058 
00059 const char *forceTicName[MAX_HUD_TICS] = 
00060 {
00061 "force_tic1", 
00062 "force_tic2", 
00063 "force_tic3", 
00064 "force_tic4", 
00065 };
00066 
00067 const char *ammoTicName[MAX_HUD_TICS] = 
00068 {
00069 "ammo_tic1", 
00070 "ammo_tic2", 
00071 "ammo_tic3", 
00072 "ammo_tic4", 
00073 };
00074 
00075 char *showPowersName[] = 
00076 {
00077         "HEAL2",//FP_HEAL
00078         "JUMP2",//FP_LEVITATION
00079         "SPEED2",//FP_SPEED
00080         "PUSH2",//FP_PUSH
00081         "PULL2",//FP_PULL
00082         "MINDTRICK2",//FP_TELEPTAHY
00083         "GRIP2",//FP_GRIP
00084         "LIGHTNING2",//FP_LIGHTNING
00085         "DARK_RAGE2",//FP_RAGE
00086         "PROTECT2",//FP_PROTECT
00087         "ABSORB2",//FP_ABSORB
00088         "TEAM_HEAL2",//FP_TEAM_HEAL
00089         "TEAM_REPLENISH2",//FP_TEAM_FORCE
00090         "DRAIN2",//FP_DRAIN
00091         "SEEING2",//FP_SEE
00092         "SABER_OFFENSE2",//FP_SABER_OFFENSE
00093         "SABER_DEFENSE2",//FP_SABER_DEFENSE
00094         "SABER_THROW2",//FP_SABERTHROW
00095         NULL
00096 };
00097 
00098 //Called from UI shared code. For now we'll just redirect to the normal anim load function.
00099 #include "../namespace_begin.h"
00100 
00101 
00102 int UI_ParseAnimationFile(const char *filename, animation_t *animset, qboolean isHumanoid) 
00103 {
00104         return BG_ParseAnimationFile(filename, animset, isHumanoid);
00105 }
00106 
00107 int MenuFontToHandle(int iMenuFont)
00108 {
00109         switch (iMenuFont)
00110         {
00111                 case FONT_SMALL:        return cgDC.Assets.qhSmallFont;
00112                 case FONT_SMALL2:       return cgDC.Assets.qhSmall2Font;
00113                 case FONT_MEDIUM:       return cgDC.Assets.qhMediumFont;
00114                 case FONT_LARGE:        return cgDC.Assets.qhMediumFont;//cgDC.Assets.qhBigFont;
00115                         //fixme? Big fonr isn't registered...?
00116         }
00117 
00118         return cgDC.Assets.qhMediumFont;
00119 }
00120 
00121 #include "../namespace_end.h"
00122 
00123 int CG_Text_Width(const char *text, float scale, int iMenuFont) 
00124 {
00125         int iFontIndex = MenuFontToHandle(iMenuFont);
00126 
00127         return trap_R_Font_StrLenPixels(text, iFontIndex, scale);
00128 }
00129 
00130 int CG_Text_Height(const char *text, float scale, int iMenuFont) 
00131 {
00132         int iFontIndex = MenuFontToHandle(iMenuFont);
00133 
00134         return trap_R_Font_HeightPixels(iFontIndex, scale);
00135 }
00136 
00137 #include "../qcommon/qfiles.h"  // for STYLE_BLINK etc
00138 void CG_Text_Paint(float x, float y, float scale, vec4_t color, const char *text, float adjust, int limit, int style, int iMenuFont) 
00139 {
00140         int iStyleOR = 0;
00141         int iFontIndex = MenuFontToHandle(iMenuFont);
00142         
00143         switch (style)
00144         {
00145         case  ITEM_TEXTSTYLE_NORMAL:                    iStyleOR = 0;break;                                     // JK2 normal text
00146         case  ITEM_TEXTSTYLE_BLINK:                             iStyleOR = STYLE_BLINK;break;           // JK2 fast blinking
00147         case  ITEM_TEXTSTYLE_PULSE:                             iStyleOR = STYLE_BLINK;break;           // JK2 slow pulsing
00148         case  ITEM_TEXTSTYLE_SHADOWED:                  iStyleOR = (int)STYLE_DROPSHADOW;break; // JK2 drop shadow ( need a color for this )
00149         case  ITEM_TEXTSTYLE_OUTLINED:                  iStyleOR = (int)STYLE_DROPSHADOW;break; // JK2 drop shadow ( need a color for this )
00150         case  ITEM_TEXTSTYLE_OUTLINESHADOWED:   iStyleOR = (int)STYLE_DROPSHADOW;break; // JK2 drop shadow ( need a color for this )
00151         case  ITEM_TEXTSTYLE_SHADOWEDMORE:              iStyleOR = (int)STYLE_DROPSHADOW;break; // JK2 drop shadow ( need a color for this )
00152         }
00153 
00154         trap_R_Font_DrawString( x,              // int ox
00155                                                         y,              // int oy
00156                                                         text,   // const char *text
00157                                                         color,  // paletteRGBA_c c
00158                                                         iStyleOR | iFontIndex,  // const int iFontHandle
00159                                                         !limit?-1:limit,                // iCharLimit (-1 = none)
00160                                                         scale   // const float scale = 1.0f
00161                                                         );
00162 }
00163 
00164 /*
00165 qboolean CG_WorldCoordToScreenCoord(vec3_t worldCoord, int *x, int *y)
00166 
00167   Take any world coord and convert it to a 2D virtual 640x480 screen coord
00168 */
00169 /*
00170 qboolean CG_WorldCoordToScreenCoordFloat(vec3_t worldCoord, float *x, float *y)
00171 {
00172         int     xcenter, ycenter;
00173         vec3_t  local, transformed;
00174 
00175 //      xcenter = cg.refdef.width / 2;//gives screen coords adjusted for resolution
00176 //      ycenter = cg.refdef.height / 2;//gives screen coords adjusted for resolution
00177         
00178         //NOTE: did it this way because most draw functions expect virtual 640x480 coords
00179         //      and adjust them for current resolution
00180         xcenter = 640 / 2;//gives screen coords in virtual 640x480, to be adjusted when drawn
00181         ycenter = 480 / 2;//gives screen coords in virtual 640x480, to be adjusted when drawn
00182 
00183         VectorSubtract (worldCoord, cg.refdef.vieworg, local);
00184 
00185         transformed[0] = DotProduct(local,vright);
00186         transformed[1] = DotProduct(local,vup);
00187         transformed[2] = DotProduct(local,vfwd);                
00188 
00189         // Make sure Z is not negative.
00190         if(transformed[2] < 0.01)
00191         {
00192                 return qfalse;
00193         }
00194         // Simple convert to screen coords.
00195         float xzi = xcenter / transformed[2] * (90.0/cg.refdef.fov_x);
00196         float yzi = ycenter / transformed[2] * (90.0/cg.refdef.fov_y);
00197 
00198         *x = xcenter + xzi * transformed[0];
00199         *y = ycenter - yzi * transformed[1];
00200 
00201         return qtrue;
00202 }
00203 
00204 qboolean CG_WorldCoordToScreenCoord( vec3_t worldCoord, int *x, int *y )
00205 {
00206         float   xF, yF;
00207         qboolean retVal = CG_WorldCoordToScreenCoordFloat( worldCoord, &xF, &yF );
00208         *x = (int)xF;
00209         *y = (int)yF;
00210         return retVal;
00211 }
00212 */
00213 
00214 /*
00215 ================
00216 CG_DrawZoomMask
00217 
00218 ================
00219 */
00220 static void CG_DrawZoomMask( void )
00221 {
00222         vec4_t          color1;
00223         float           level;
00224         static qboolean flip = qtrue;
00225 
00226 //      int ammo = cg_entities[0].gent->client->ps.ammo[weaponData[cent->currentState.weapon].ammoIndex];
00227         float cx, cy;
00228 //      int val[5];
00229         float max, fi;
00230 
00231         // Check for Binocular specific zooming since we'll want to render different bits in each case
00232         if ( cg.predictedPlayerState.zoomMode == 2 )
00233         {
00234                 int val, i;
00235                 float off;
00236 
00237                 // zoom level
00238                 level = (float)(80.0f - cg.predictedPlayerState.zoomFov) / 80.0f;
00239 
00240                 // ...so we'll clamp it
00241                 if ( level < 0.0f )
00242                 {
00243                         level = 0.0f;
00244                 }
00245                 else if ( level > 1.0f )
00246                 {
00247                         level = 1.0f;
00248                 }
00249 
00250                 // Using a magic number to convert the zoom level to scale amount
00251                 level *= 162.0f;
00252 
00253                 // draw blue tinted distortion mask, trying to make it as small as is necessary to fill in the viewable area
00254                 trap_R_SetColor( colorTable[CT_WHITE] );
00255                 CG_DrawPic( 34, 48, 570, 362, cgs.media.binocularStatic );
00256         
00257                 // Black out the area behind the numbers
00258                 trap_R_SetColor( colorTable[CT_BLACK]);
00259                 CG_DrawPic( 212, 367, 200, 40, cgs.media.whiteShader );
00260 
00261                 // Numbers should be kind of greenish
00262                 color1[0] = 0.2f;
00263                 color1[1] = 0.4f;
00264                 color1[2] = 0.2f;
00265                 color1[3] = 0.3f;
00266                 trap_R_SetColor( color1 );
00267 
00268                 // Draw scrolling numbers, use intervals 10 units apart--sorry, this section of code is just kind of hacked
00269                 //      up with a bunch of magic numbers.....
00270                 val = ((int)((cg.refdef.viewangles[YAW] + 180) / 10)) * 10;
00271                 off = (cg.refdef.viewangles[YAW] + 180) - val;
00272 
00273                 for ( i = -10; i < 30; i += 10 )
00274                 {
00275                         val -= 10;
00276 
00277                         if ( val < 0 )
00278                         {
00279                                 val += 360;
00280                         }
00281 
00282                         // we only want to draw the very far left one some of the time, if it's too far to the left it will
00283                         //      poke outside the mask.
00284                         if (( off > 3.0f && i == -10 ) || i > -10 )
00285                         {
00286                                 // draw the value, but add 200 just to bump the range up...arbitrary, so change it if you like
00287                                 CG_DrawNumField( 155 + i * 10 + off * 10, 374, 3, val + 200, 24, 14, NUM_FONT_CHUNKY, qtrue );
00288                                 CG_DrawPic( 245 + (i-1) * 10 + off * 10, 376, 6, 6, cgs.media.whiteShader );
00289                         }
00290                 }
00291 
00292                 CG_DrawPic( 212, 367, 200, 28, cgs.media.binocularOverlay );
00293 
00294                 color1[0] = sin( cg.time * 0.01f ) * 0.5f + 0.5f;
00295                 color1[0] = color1[0] * color1[0];
00296                 color1[1] = color1[0];
00297                 color1[2] = color1[0];
00298                 color1[3] = 1.0f;
00299 
00300                 trap_R_SetColor( color1 );
00301 
00302                 CG_DrawPic( 82, 94, 16, 16, cgs.media.binocularCircle );
00303 
00304                 // Flickery color
00305                 color1[0] = 0.7f + crandom() * 0.1f;
00306                 color1[1] = 0.8f + crandom() * 0.1f;
00307                 color1[2] = 0.7f + crandom() * 0.1f;
00308                 color1[3] = 1.0f;
00309                 trap_R_SetColor( color1 );
00310         
00311                 CG_DrawPic( 0, 0, 640, 480, cgs.media.binocularMask );
00312 
00313                 CG_DrawPic( 4, 282 - level, 16, 16, cgs.media.binocularArrow );
00314 
00315                 // The top triangle bit randomly flips 
00316                 if ( flip )
00317                 {
00318                         CG_DrawPic( 330, 60, -26, -30, cgs.media.binocularTri );
00319                 }
00320                 else
00321                 {
00322                         CG_DrawPic( 307, 40, 26, 30, cgs.media.binocularTri );
00323                 }
00324 
00325                 if ( random() > 0.98f && ( cg.time & 1024 ))
00326                 {
00327                         flip = !flip;
00328                 }
00329         }
00330         else if ( cg.predictedPlayerState.zoomMode)
00331         {
00332                 // disruptor zoom mode
00333                 level = (float)(50.0f - zoomFov) / 50.0f;//(float)(80.0f - zoomFov) / 80.0f;
00334 
00335                 // ...so we'll clamp it
00336                 if ( level < 0.0f )
00337                 {
00338                         level = 0.0f;
00339                 }
00340                 else if ( level > 1.0f )
00341                 {
00342                         level = 1.0f;
00343                 }
00344 
00345                 // Using a magic number to convert the zoom level to a rotation amount that correlates more or less with the zoom artwork. 
00346                 level *= 103.0f;
00347 
00348                 // Draw target mask
00349                 trap_R_SetColor( colorTable[CT_WHITE] );
00350                 CG_DrawPic( 0, 0, 640, 480, cgs.media.disruptorMask );
00351 
00352                 // apparently 99.0f is the full zoom level
00353                 if ( level >= 99 )
00354                 {
00355                         // Fully zoomed, so make the rotating insert pulse
00356                         color1[0] = 1.0f; 
00357                         color1[1] = 1.0f;
00358                         color1[2] = 1.0f;
00359                         color1[3] = 0.7f + sin( cg.time * 0.01f ) * 0.3f;
00360 
00361                         trap_R_SetColor( color1 );
00362                 }
00363 
00364                 // Draw rotating insert
00365                 CG_DrawRotatePic2( 320, 240, 640, 480, -level, cgs.media.disruptorInsert );
00366 
00367                 // Increase the light levels under the center of the target
00368 //              CG_DrawPic( 198, 118, 246, 246, cgs.media.disruptorLight );
00369 
00370                 // weirdness.....converting ammo to a base five number scale just to be geeky.
00371 /*              val[0] = ammo % 5;
00372                 val[1] = (ammo / 5) % 5;
00373                 val[2] = (ammo / 25) % 5;
00374                 val[3] = (ammo / 125) % 5;
00375                 val[4] = (ammo / 625) % 5;
00376                 
00377                 color1[0] = 0.2f;
00378                 color1[1] = 0.55f + crandom() * 0.1f;
00379                 color1[2] = 0.5f + crandom() * 0.1f;
00380                 color1[3] = 1.0f;
00381                 trap_R_SetColor( color1 );
00382 
00383                 for ( int t = 0; t < 5; t++ )
00384                 {
00385                         cx = 320 + sin( (t*10+45)/57.296f ) * 192;
00386                         cy = 240 + cos( (t*10+45)/57.296f ) * 192;
00387 
00388                         CG_DrawRotatePic2( cx, cy, 24, 38, 45 - t * 10, trap_R_RegisterShader( va("gfx/2d/char%d",val[4-t] )));
00389                 }
00390 */
00391                 //max = ( cg_entities[0].gent->health / 100.0f );
00392 
00393                 
00394                 if ( (cg.snap->ps.eFlags & EF_DOUBLE_AMMO) )
00395                 {
00396                         max = cg.snap->ps.ammo[weaponData[WP_DISRUPTOR].ammoIndex] / ((float)ammoData[weaponData[WP_DISRUPTOR].ammoIndex].max*2.0f);
00397                 }
00398                 else
00399                 {
00400                         max = cg.snap->ps.ammo[weaponData[WP_DISRUPTOR].ammoIndex] / (float)ammoData[weaponData[WP_DISRUPTOR].ammoIndex].max;
00401                 }
00402                 if ( max > 1.0f )
00403                 {
00404                         max = 1.0f;
00405                 }
00406 
00407                 color1[0] = (1.0f - max) * 2.0f; 
00408                 color1[1] = max * 1.5f;
00409                 color1[2] = 0.0f;
00410                 color1[3] = 1.0f;
00411 
00412                 // If we are low on health, make us flash
00413                 if ( max < 0.15f && ( cg.time & 512 ))
00414                 {
00415                         VectorClear( color1 );
00416                 }
00417 
00418                 if ( color1[0] > 1.0f )
00419                 {
00420                         color1[0] = 1.0f;
00421                 }
00422 
00423                 if ( color1[1] > 1.0f )
00424                 {
00425                         color1[1] = 1.0f;
00426                 }
00427 
00428                 trap_R_SetColor( color1 );
00429 
00430                 max *= 58.0f;
00431 
00432                 for (fi = 18.5f; fi <= 18.5f + max; fi+= 3 ) // going from 15 to 45 degrees, with 5 degree increments
00433                 {
00434                         cx = 320 + sin( (fi+90.0f)/57.296f ) * 190;
00435                         cy = 240 + cos( (fi+90.0f)/57.296f ) * 190;
00436 
00437                         CG_DrawRotatePic2( cx, cy, 12, 24, 90 - fi, cgs.media.disruptorInsertTick );
00438                 }
00439 
00440                 if ( cg.predictedPlayerState.weaponstate == WEAPON_CHARGING_ALT )
00441                 {
00442                         trap_R_SetColor( colorTable[CT_WHITE] );
00443 
00444                         // draw the charge level
00445                         max = ( cg.time - cg.predictedPlayerState.weaponChargeTime ) / ( 50.0f * 30.0f ); // bad hardcodedness 50 is disruptor charge unit and 30 is max charge units allowed.
00446 
00447                         if ( max > 1.0f )
00448                         {
00449                                 max = 1.0f;
00450                         }
00451 
00452                         trap_R_DrawStretchPic(257, 435, 134*max, 34, 0, 0, max, 1, cgs.media.disruptorChargeShader);
00453                 }
00454 //              trap_R_SetColor( colorTable[CT_WHITE] );
00455 //              CG_DrawPic( 0, 0, 640, 480, cgs.media.disruptorMask );
00456 
00457         }
00458 }
00459 
00460 
00461 /*
00462 ================
00463 CG_Draw3DModel
00464 
00465 ================
00466 */
00467 void CG_Draw3DModel( float x, float y, float w, float h, qhandle_t model, void *ghoul2, int g2radius, qhandle_t skin, vec3_t origin, vec3_t angles ) {
00468         refdef_t                refdef;
00469         refEntity_t             ent;
00470 
00471         if ( !cg_draw3dIcons.integer || !cg_drawIcons.integer ) {
00472                 return;
00473         }
00474 
00475         memset( &refdef, 0, sizeof( refdef ) );
00476 
00477         memset( &ent, 0, sizeof( ent ) );
00478         AnglesToAxis( angles, ent.axis );
00479         VectorCopy( origin, ent.origin );
00480         ent.hModel = model;
00481         ent.ghoul2 = ghoul2;
00482         ent.radius = g2radius;
00483         ent.customSkin = skin;
00484         ent.renderfx = RF_NOSHADOW;             // no stencil shadows
00485 
00486         refdef.rdflags = RDF_NOWORLDMODEL;
00487 
00488         AxisClear( refdef.viewaxis );
00489 
00490         refdef.fov_x = 30;
00491         refdef.fov_y = 30;
00492 
00493         refdef.x = x;
00494         refdef.y = y;
00495         refdef.width = w;
00496         refdef.height = h;
00497 
00498         refdef.time = cg.time;
00499 
00500         trap_R_ClearScene();
00501         trap_R_AddRefEntityToScene( &ent );
00502         trap_R_RenderScene( &refdef );
00503 }
00504 
00505 /*
00506 ================
00507 CG_DrawHead
00508 
00509 Used for both the status bar and the scoreboard
00510 ================
00511 */
00512 void CG_DrawHead( float x, float y, float w, float h, int clientNum, vec3_t headAngles ) 
00513 {
00514         clientInfo_t    *ci;
00515 
00516         if (clientNum >= MAX_CLIENTS)
00517         { //npc?
00518                 return;
00519         }
00520 
00521         ci = &cgs.clientinfo[ clientNum ];
00522 
00523         CG_DrawPic( x, y, w, h, ci->modelIcon );
00524 
00525         // if they are deferred, draw a cross out
00526         if ( ci->deferred ) 
00527         {
00528                 CG_DrawPic( x, y, w, h, cgs.media.deferShader );
00529         }
00530 }
00531 
00532 /*
00533 ================
00534 CG_DrawFlagModel
00535 
00536 Used for both the status bar and the scoreboard
00537 ================
00538 */
00539 void CG_DrawFlagModel( float x, float y, float w, float h, int team, qboolean force2D ) {
00540         qhandle_t               cm;
00541         float                   len;
00542         vec3_t                  origin, angles;
00543         vec3_t                  mins, maxs;
00544         qhandle_t               handle;
00545 
00546         if ( !force2D && cg_draw3dIcons.integer ) {
00547 
00548                 VectorClear( angles );
00549 
00550                 cm = cgs.media.redFlagModel;
00551 
00552                 // offset the origin y and z to center the flag
00553                 trap_R_ModelBounds( cm, mins, maxs );
00554 
00555                 origin[2] = -0.5 * ( mins[2] + maxs[2] );
00556                 origin[1] = 0.5 * ( mins[1] + maxs[1] );
00557 
00558                 // calculate distance so the flag nearly fills the box
00559                 // assume heads are taller than wide
00560                 len = 0.5 * ( maxs[2] - mins[2] );              
00561                 origin[0] = len / 0.268;        // len / tan( fov/2 )
00562 
00563                 angles[YAW] = 60 * sin( cg.time / 2000.0 );;
00564 
00565                 if( team == TEAM_RED ) {
00566                         handle = cgs.media.redFlagModel;
00567                 } else if( team == TEAM_BLUE ) {
00568                         handle = cgs.media.blueFlagModel;
00569                 } else if( team == TEAM_FREE ) {
00570                         handle = 0;//cgs.media.neutralFlagModel;
00571                 } else {
00572                         return;
00573                 }
00574                 CG_Draw3DModel( x, y, w, h, handle, NULL, 0, 0, origin, angles );
00575         } else if ( cg_drawIcons.integer ) {
00576                 gitem_t *item;
00577 
00578                 if( team == TEAM_RED ) {
00579                         item = BG_FindItemForPowerup( PW_REDFLAG );
00580                 } else if( team == TEAM_BLUE ) {
00581                         item = BG_FindItemForPowerup( PW_BLUEFLAG );
00582                 } else if( team == TEAM_FREE ) {
00583                         item = BG_FindItemForPowerup( PW_NEUTRALFLAG );
00584                 } else {
00585                         return;
00586                 }
00587                 if (item) {
00588                   CG_DrawPic( x, y, w, h, cg_items[ ITEM_INDEX(item) ].icon );
00589                 }
00590         }
00591 }
00592 
00593 /*
00594 ================
00595 DrawAmmo
00596 ================
00597 */
00598 void DrawAmmo()
00599 {
00600         int x, y;
00601 
00602         x = SCREEN_WIDTH-80;
00603         y = SCREEN_HEIGHT-80;
00604 
00605 }
00606 
00607 
00608 
00609 /*
00610 ================
00611 CG_DrawHealth
00612 ================
00613 */
00614 void CG_DrawHealth( menuDef_t *menuHUD )
00615 {
00616         vec4_t                  calcColor;
00617         playerState_t   *ps;
00618         int                             healthAmt;
00619         int                             i,currValue,inc;
00620         itemDef_t               *focusItem;
00621         float percent;
00622 
00623         // Can we find the menu?
00624         if (!menuHUD)
00625         {
00626                 return;
00627         }
00628 
00629         ps = &cg.snap->ps;
00630 
00631         // What's the health?
00632         healthAmt = ps->stats[STAT_HEALTH];
00633         if (healthAmt > ps->stats[STAT_MAX_HEALTH])
00634         {
00635                 healthAmt = ps->stats[STAT_MAX_HEALTH];
00636         }
00637 
00638 
00639         inc = (float) ps->stats[STAT_MAX_HEALTH] / MAX_HUD_TICS;
00640         currValue = healthAmt;
00641 
00642         // Print the health tics, fading out the one which is partial health
00643         for (i=(MAX_HUD_TICS-1);i>=0;i--)
00644         {
00645                 focusItem = Menu_FindItemByName(menuHUD, healthTicName[i]);
00646 
00647                 if (!focusItem) // This is bad
00648                 {
00649                         continue;
00650                 }
00651 
00652                 memcpy(calcColor, hudTintColor, sizeof(vec4_t));
00653 
00654                 if (currValue <= 0)     // don't show tic
00655                 {
00656                         break;
00657                 }
00658                 else if (currValue < inc)       // partial tic (alpha it out)
00659                 {
00660                         percent = (float) currValue / inc;
00661                         calcColor[3] *= percent;                // Fade it out
00662                 }
00663 
00664                 trap_R_SetColor( calcColor);
00665 
00666                 CG_DrawPic( 
00667                         focusItem->window.rect.x,
00668                         focusItem->window.rect.y,
00669                         focusItem->window.rect.w, 
00670                         focusItem->window.rect.h, 
00671                         focusItem->window.background
00672                         );
00673 
00674                 currValue -= inc;
00675         }
00676 
00677         // Print the mueric amount
00678         focusItem = Menu_FindItemByName(menuHUD, "healthamount");
00679         if (focusItem)
00680         {
00681                 // Print health amount
00682                 trap_R_SetColor( focusItem->window.foreColor ); 
00683 
00684                 CG_DrawNumField (
00685                         focusItem->window.rect.x, 
00686                         focusItem->window.rect.y, 
00687                         3, 
00688                         ps->stats[STAT_HEALTH], 
00689                         focusItem->window.rect.w, 
00690                         focusItem->window.rect.h, 
00691                         NUM_FONT_SMALL,
00692                         qfalse);
00693         }
00694 
00695 }
00696 
00697 /*
00698 ================
00699 CG_DrawArmor
00700 ================
00701 */
00702 void CG_DrawArmor( menuDef_t *menuHUD )
00703 {
00704         vec4_t                  calcColor;
00705         playerState_t   *ps;
00706         int                             armor, maxArmor;
00707         itemDef_t               *focusItem;
00708         float                   percent,quarterArmor;
00709         int                             i,currValue,inc;
00710 
00711         //ps = &cg.snap->ps;
00712         ps = &cg.predictedPlayerState;
00713 
00714         // Can we find the menu?
00715         if (!menuHUD)
00716         {
00717                 return;
00718         }
00719 
00720         armor = ps->stats[STAT_ARMOR];
00721         maxArmor = ps->stats[STAT_MAX_HEALTH];
00722 
00723         if (armor> maxArmor)
00724         {
00725                 armor = maxArmor;
00726         }
00727 
00728         currValue = armor;
00729         inc = (float) maxArmor / MAX_HUD_TICS;
00730 
00731         memcpy(calcColor, hudTintColor, sizeof(vec4_t));
00732         for (i=(MAX_HUD_TICS-1);i>=0;i--)
00733         {
00734                 focusItem = Menu_FindItemByName(menuHUD, armorTicName[i]);
00735 
00736                 if (!focusItem) // This is bad
00737                 {
00738                         continue;
00739                 }
00740 
00741                 memcpy(calcColor, hudTintColor, sizeof(vec4_t));
00742 
00743                 if (currValue <= 0)     // don't show tic
00744                 {
00745                         break;
00746                 }
00747                 else if (currValue < inc)       // partial tic (alpha it out)
00748                 {
00749                         percent = (float) currValue / inc;
00750                         calcColor[3] *= percent;
00751                 }
00752 
00753                 trap_R_SetColor( calcColor);
00754 
00755                 if ((i==(MAX_HUD_TICS-1)) && (currValue < inc))
00756                 {
00757                         if (cg.HUDArmorFlag)
00758                         {
00759                                 CG_DrawPic( 
00760                                         focusItem->window.rect.x,
00761                                         focusItem->window.rect.y,
00762                                         focusItem->window.rect.w, 
00763                                         focusItem->window.rect.h, 
00764                                         focusItem->window.background
00765                                         );
00766                         }
00767                 }
00768                 else 
00769                 {
00770                                 CG_DrawPic( 
00771                                         focusItem->window.rect.x,
00772                                         focusItem->window.rect.y,
00773                                         focusItem->window.rect.w, 
00774                                         focusItem->window.rect.h, 
00775                                         focusItem->window.background
00776                                         );
00777                 }
00778 
00779                 currValue -= inc;
00780         }
00781 
00782         focusItem = Menu_FindItemByName(menuHUD, "armoramount");
00783 
00784         if (focusItem)
00785         {
00786                 // Print armor amount
00787                 trap_R_SetColor( focusItem->window.foreColor ); 
00788 
00789                 CG_DrawNumField (
00790                         focusItem->window.rect.x, 
00791                         focusItem->window.rect.y, 
00792                         3, 
00793                         armor, 
00794                         focusItem->window.rect.w, 
00795                         focusItem->window.rect.h, 
00796                         NUM_FONT_SMALL,
00797                         qfalse);
00798         }
00799 
00800         // If armor is low, flash a graphic to warn the player
00801         if (armor)      // Is there armor? Draw the HUD Armor TIC
00802         {
00803                 quarterArmor = (float) (ps->stats[STAT_MAX_HEALTH] / 4.0f);
00804 
00805                 // Make tic flash if armor is at 25% of full armor
00806                 if (ps->stats[STAT_ARMOR] < quarterArmor)               // Do whatever the flash timer says
00807                 {
00808                         if (cg.HUDTickFlashTime < cg.time)                      // Flip at the same time
00809                         {
00810                                 cg.HUDTickFlashTime = cg.time + 400;
00811                                 if (cg.HUDArmorFlag)
00812                                 {
00813                                         cg.HUDArmorFlag = qfalse;
00814                                 }
00815                                 else
00816                                 {
00817                                         cg.HUDArmorFlag = qtrue;
00818                                 }
00819                         }
00820                 }
00821                 else
00822                 {
00823                         cg.HUDArmorFlag=qtrue;
00824                 }
00825         }
00826         else                                            // No armor? Don't show it.
00827         {
00828                 cg.HUDArmorFlag=qfalse;
00829         }
00830 
00831 }
00832 
00833 /*
00834 ================
00835 CG_DrawSaberStyle
00836 
00837 If the weapon is a light saber (which needs no ammo) then draw a graphic showing
00838 the saber style (fast, medium, strong)
00839 ================
00840 */
00841 static void CG_DrawSaberStyle( centity_t *cent, menuDef_t *menuHUD)
00842 {
00843         itemDef_t               *focusItem;
00844 
00845         if (!cent->currentState.weapon ) // We don't have a weapon right now
00846         {
00847                 return;
00848         }
00849 
00850         if ( cent->currentState.weapon != WP_SABER )
00851         {
00852                 return;
00853         }
00854 
00855         // Can we find the menu?
00856         if (!menuHUD)
00857         {
00858                 return;
00859         }
00860 
00861 
00862         // draw the current saber style in this window
00863         switch ( cg.predictedPlayerState.fd.saberDrawAnimLevel )
00864         {
00865         case 1://FORCE_LEVEL_1:
00866         case 5://FORCE_LEVEL_5://Tavion
00867 
00868                 focusItem = Menu_FindItemByName(menuHUD, "saberstyle_fast");
00869 
00870                 if (focusItem)
00871                 {
00872                         trap_R_SetColor( hudTintColor );
00873 
00874                         CG_DrawPic( 
00875                                 focusItem->window.rect.x,
00876                                 focusItem->window.rect.y,
00877                                 focusItem->window.rect.w, 
00878                                 focusItem->window.rect.h, 
00879                                 focusItem->window.background
00880                                 );
00881                 }
00882 
00883                 break;
00884         case 2://FORCE_LEVEL_2:
00885         case 6://SS_DUAL
00886         case 7://SS_STAFF
00887                 focusItem = Menu_FindItemByName(menuHUD, "saberstyle_medium");
00888 
00889                 if (focusItem)
00890                 {
00891                         trap_R_SetColor( hudTintColor );
00892 
00893                         CG_DrawPic( 
00894                                 focusItem->window.rect.x,
00895                                 focusItem->window.rect.y,
00896                                 focusItem->window.rect.w, 
00897                                 focusItem->window.rect.h, 
00898                                 focusItem->window.background
00899                                 );
00900                 }
00901                 break;
00902         case 3://FORCE_LEVEL_3:
00903         case 4://FORCE_LEVEL_4://Desann
00904                 focusItem = Menu_FindItemByName(menuHUD, "saberstyle_strong");
00905 
00906                 if (focusItem)
00907                 {
00908                         trap_R_SetColor( hudTintColor );
00909 
00910                         CG_DrawPic( 
00911                                 focusItem->window.rect.x,
00912                                 focusItem->window.rect.y,
00913                                 focusItem->window.rect.w, 
00914                                 focusItem->window.rect.h, 
00915                                 focusItem->window.background
00916                                 );
00917                 }
00918                 break;
00919         }
00920 
00921 }
00922 
00923 /*
00924 ================
00925 CG_DrawAmmo
00926 ================
00927 */
00928 static void CG_DrawAmmo( centity_t      *cent,menuDef_t *menuHUD)
00929 {
00930         playerState_t   *ps;
00931         int                             i;
00932         vec4_t                  calcColor;
00933         float                   value,inc = 0.0f,percent;
00934         itemDef_t               *focusItem;
00935 
00936         ps = &cg.snap->ps;
00937 
00938         // Can we find the menu?
00939         if (!menuHUD)
00940         {
00941                 return;
00942         }
00943 
00944         if (!cent->currentState.weapon ) // We don't have a weapon right now
00945         {
00946                 return;
00947         }
00948 
00949         value = ps->ammo[weaponData[cent->currentState.weapon].ammoIndex];
00950         if (value < 0)  // No ammo
00951         {
00952                 return;
00953         }
00954 
00955         focusItem = Menu_FindItemByName(menuHUD, "ammoamount");
00956         trap_R_SetColor( hudTintColor );
00957 
00958         if (weaponData[cent->currentState.weapon].energyPerShot == 0 &&
00959                 weaponData[cent->currentState.weapon].altEnergyPerShot == 0)
00960         { //just draw "infinite"
00961                 inc = 8 / MAX_HUD_TICS;
00962                 value = 8;
00963 
00964                 focusItem = Menu_FindItemByName(menuHUD, "ammoinfinite");
00965                 trap_R_SetColor( hudTintColor );
00966                 if (focusItem)
00967                 {
00968                         UI_DrawProportionalString(focusItem->window.rect.x, focusItem->window.rect.y, "--", NUM_FONT_SMALL, focusItem->window.foreColor);
00969                 }
00970         }
00971         else
00972         {
00973                 focusItem = Menu_FindItemByName(menuHUD, "ammoamount");
00974                 trap_R_SetColor( hudTintColor );
00975                 if (focusItem)
00976                 {
00977 
00978                         if ( (cent->currentState.eFlags & EF_DOUBLE_AMMO) )
00979                         {
00980                                 inc = (float) (ammoData[weaponData[cent->currentState.weapon].ammoIndex].max*2.0f) / MAX_HUD_TICS;
00981                         }
00982                         else
00983                         {
00984                                 inc = (float) ammoData[weaponData[cent->currentState.weapon].ammoIndex].max / MAX_HUD_TICS;
00985                         }
00986                         value =ps->ammo[weaponData[cent->currentState.weapon].ammoIndex];
00987 
00988                         CG_DrawNumField (
00989                                 focusItem->window.rect.x, 
00990                                 focusItem->window.rect.y, 
00991                                 3, 
00992                                 value, 
00993                                 focusItem->window.rect.w, 
00994                                 focusItem->window.rect.h, 
00995                                 NUM_FONT_SMALL,
00996                                 qfalse);
00997                 }
00998         }
00999 
01000         // Draw tics
01001         for (i=MAX_HUD_TICS-1;i>=0;i--)
01002         {
01003                 focusItem = Menu_FindItemByName(menuHUD, ammoTicName[i]);
01004 
01005                 if (!focusItem)
01006                 {
01007                         continue;
01008                 }
01009 
01010                 memcpy(calcColor, hudTintColor, sizeof(vec4_t));
01011 
01012                 if ( value <= 0 )       // done
01013                 {
01014                         break;
01015                 }
01016                 else if (value < inc)   // partial tic
01017                 {
01018                         percent = value / inc;
01019                         calcColor[3] = percent;
01020                 }
01021 
01022                 trap_R_SetColor( calcColor);
01023 
01024                 CG_DrawPic( 
01025                         focusItem->window.rect.x,
01026                         focusItem->window.rect.y,
01027                         focusItem->window.rect.w, 
01028                         focusItem->window.rect.h, 
01029                         focusItem->window.background
01030                         );
01031 
01032                 value -= inc;
01033         }
01034 
01035 }
01036 
01037 /*
01038 ================
01039 CG_DrawForcePower
01040 ================
01041 */
01042 void CG_DrawForcePower( menuDef_t *menuHUD )
01043 {
01044         int                             i;
01045         vec4_t                  calcColor;
01046         float                   value,inc,percent;
01047         itemDef_t               *focusItem;
01048         const int               maxForcePower = 100;
01049         qboolean        flash=qfalse;
01050 
01051         // Can we find the menu?
01052         if (!menuHUD)
01053         {
01054                 return;
01055         }
01056 
01057         // Make the hud flash by setting forceHUDTotalFlashTime above cg.time
01058         if (cg.forceHUDTotalFlashTime > cg.time )
01059         {
01060                 flash = qtrue;
01061                 if (cg.forceHUDNextFlashTime < cg.time) 
01062                 {
01063                         cg.forceHUDNextFlashTime = cg.time + 400;
01064                         trap_S_StartSound (NULL, 0, CHAN_LOCAL, cgs.media.noforceSound );
01065 
01066                         if (cg.forceHUDActive)
01067                         {
01068                                 cg.forceHUDActive = qfalse;
01069                         }
01070                         else
01071                         {
01072                                 cg.forceHUDActive = qtrue;
01073                         }
01074 
01075                 }
01076         }
01077         else    // turn HUD back on if it had just finished flashing time.
01078         {
01079                 cg.forceHUDNextFlashTime = 0;
01080                 cg.forceHUDActive = qtrue;
01081         }
01082 
01083 //      if (!cg.forceHUDActive)
01084 //      {
01085 //              return;
01086 //      }
01087 
01088         inc = (float)  maxForcePower / MAX_HUD_TICS;
01089         value = cg.snap->ps.fd.forcePower;
01090 
01091         for (i=MAX_HUD_TICS-1;i>=0;i--)
01092         {
01093                 focusItem = Menu_FindItemByName(menuHUD, forceTicName[i]);
01094 
01095                 if (!focusItem)
01096                 {
01097                         continue;
01098                 }
01099 
01100 //              memcpy(calcColor, hudTintColor, sizeof(vec4_t));
01101 
01102                 if ( value <= 0 )       // done
01103                 {
01104                         break;
01105                 }
01106                 else if (value < inc)   // partial tic
01107                 {
01108                         if (flash)
01109                         {
01110                                 memcpy(calcColor,  colorTable[CT_RED], sizeof(vec4_t));
01111                         }
01112                         else 
01113                         {
01114                                 memcpy(calcColor,  colorTable[CT_WHITE], sizeof(vec4_t));
01115                         }
01116 
01117                         percent = value / inc;
01118                         calcColor[3] = percent;
01119                 }
01120                 else
01121                 {
01122                         if (flash)
01123                         {
01124                                 memcpy(calcColor,  colorTable[CT_RED], sizeof(vec4_t));
01125                         }
01126                         else 
01127                         {
01128                                 memcpy(calcColor,  colorTable[CT_WHITE], sizeof(vec4_t));
01129                         }
01130                 }
01131 
01132                 trap_R_SetColor( calcColor);
01133 
01134                 CG_DrawPic( 
01135                         focusItem->window.rect.x,
01136                         focusItem->window.rect.y,
01137                         focusItem->window.rect.w, 
01138                         focusItem->window.rect.h, 
01139                         focusItem->window.background
01140                         );
01141 
01142                 value -= inc;
01143         }
01144 
01145         focusItem = Menu_FindItemByName(menuHUD, "forceamount");
01146 
01147         if (focusItem)
01148         {
01149                 // Print force amount
01150                 trap_R_SetColor( focusItem->window.foreColor ); 
01151 
01152                 CG_DrawNumField (
01153                         focusItem->window.rect.x, 
01154                         focusItem->window.rect.y, 
01155                         3, 
01156                         cg.snap->ps.fd.forcePower, 
01157                         focusItem->window.rect.w, 
01158                         focusItem->window.rect.h, 
01159                         NUM_FONT_SMALL,
01160                         qfalse);
01161         }
01162 }
01163 
01164 /*
01165 ================
01166 CG_DrawHUD
01167 ================
01168 */
01169 void CG_DrawHUD(centity_t       *cent)
01170 {
01171         menuDef_t       *menuHUD = NULL;
01172         itemDef_t       *focusItem = NULL;
01173         const char *scoreStr = NULL;
01174         int     scoreBias;
01175         char scoreBiasStr[16];
01176 
01177         if (cg_hudFiles.integer)
01178         {
01179                 int x = 0;
01180                 int y = SCREEN_HEIGHT-80;
01181                 char ammoString[64];
01182                 int weapX = x;
01183 
01184                 UI_DrawProportionalString( x+16, y+40, va( "%i", cg.snap->ps.stats[STAT_HEALTH] ),
01185                         UI_SMALLFONT|UI_DROPSHADOW, colorTable[CT_HUD_RED] );
01186 
01187                 UI_DrawProportionalString( x+18+14, y+40+14, va( "%i", cg.snap->ps.stats[STAT_ARMOR] ),
01188                         UI_SMALLFONT|UI_DROPSHADOW, colorTable[CT_HUD_GREEN] );
01189 
01190                 if (cg.snap->ps.weapon == WP_SABER)
01191                 {
01192                         if (cg.snap->ps.fd.saberDrawAnimLevel == SS_DUAL)
01193                         {
01194                                 Com_sprintf(ammoString, sizeof(ammoString), "AKIMBO");
01195                                 weapX += 16;
01196                         }
01197                         else if (cg.snap->ps.fd.saberDrawAnimLevel == SS_STAFF)
01198                         {
01199                                 Com_sprintf(ammoString, sizeof(ammoString), "STAFF");
01200                                 weapX += 16;
01201                         }
01202                         else if (cg.snap->ps.fd.saberDrawAnimLevel == FORCE_LEVEL_3)
01203                         {
01204                                 Com_sprintf(ammoString, sizeof(ammoString), "STRONG");
01205                                 weapX += 16;
01206                         }
01207                         else if (cg.snap->ps.fd.saberDrawAnimLevel == FORCE_LEVEL_2)
01208                         {
01209                                 Com_sprintf(ammoString, sizeof(ammoString), "MEDIUM");
01210                                 weapX += 16;
01211                         }
01212                         else
01213                         {
01214                                 Com_sprintf(ammoString, sizeof(ammoString), "FAST");
01215                         }
01216                 }
01217                 else
01218                 {
01219                         Com_sprintf(ammoString, sizeof(ammoString), "%i", cg.snap->ps.ammo[weaponData[cent->currentState.weapon].ammoIndex]);
01220                 }
01221                 
01222                 UI_DrawProportionalString( SCREEN_WIDTH-(weapX+16+32), y+40, va( "%s", ammoString ),
01223                         UI_SMALLFONT|UI_DROPSHADOW, colorTable[CT_HUD_ORANGE] );
01224 
01225                 UI_DrawProportionalString( SCREEN_WIDTH-(x+18+14+32), y+40+14, va( "%i", cg.snap->ps.fd.forcePower),
01226                         UI_SMALLFONT|UI_DROPSHADOW, colorTable[CT_ICON_BLUE] );
01227 
01228                 return;
01229         }
01230 
01231         if (cgs.gametype >= GT_TEAM && cgs.gametype != GT_SIEGE)
01232         {       // tint the hud items based on team
01233                 if (cg.snap->ps.persistant[PERS_TEAM] == TEAM_RED )
01234                         hudTintColor = redhudtint;
01235                 else if (cg.snap->ps.persistant[PERS_TEAM] == TEAM_BLUE )
01236                         hudTintColor = bluehudtint;
01237                 else // If we're not on a team for whatever reason, leave things as they are.
01238                         hudTintColor = colorTable[CT_WHITE];
01239         }
01240         else
01241         {       // tint the hud items white (dont' tint)
01242                 hudTintColor = colorTable[CT_WHITE];
01243         }
01244 
01245         // Draw the left HUD 
01246         menuHUD = Menus_FindByName("lefthud");
01247         if (menuHUD)
01248         {
01249                 itemDef_t *focusItem;
01250 
01251                 // Print scanline
01252                 focusItem = Menu_FindItemByName(menuHUD, "scanline");
01253                 if (focusItem)
01254                 {
01255                         trap_R_SetColor( hudTintColor );        
01256                         CG_DrawPic( 
01257                                 focusItem->window.rect.x, 
01258                                 focusItem->window.rect.y, 
01259                                 focusItem->window.rect.w, 
01260                                 focusItem->window.rect.h, 
01261                                 focusItem->window.background 
01262                                 );                      
01263                 }
01264 
01265                 // Print frame
01266                 focusItem = Menu_FindItemByName(menuHUD, "frame");
01267                 if (focusItem)
01268                 {
01269                         trap_R_SetColor( hudTintColor );        
01270                         CG_DrawPic( 
01271                                 focusItem->window.rect.x, 
01272                                 focusItem->window.rect.y, 
01273                                 focusItem->window.rect.w, 
01274                                 focusItem->window.rect.h, 
01275                                 focusItem->window.background 
01276                                 );                      
01277                 }
01278 
01279                 if (cg.predictedPlayerState.pm_type != PM_SPECTATOR)
01280                 {
01281                         CG_DrawArmor(menuHUD);
01282                         CG_DrawHealth(menuHUD);
01283                 }
01284         }
01285         else
01286         { 
01287                 //CG_Error("CG_ChatBox_ArrayInsert: unable to locate HUD menu file ");
01288         }
01289 
01290         //scoreStr = va("Score: %i", cgs.clientinfo[cg.snap->ps.clientNum].score);
01291         if ( cgs.gametype == GT_DUEL )
01292         {//A duel that requires more than one kill to knock the current enemy back to the queue
01293                 //show current kills out of how many needed
01294                 scoreStr = va("%s: %i/%i", CG_GetStringEdString("MP_INGAME", "SCORE"), cg.snap->ps.persistant[PERS_SCORE], cgs.fraglimit);
01295         }
01296         else if (0 && cgs.gametype < GT_TEAM )
01297         {       // This is a teamless mode, draw the score bias.
01298                 scoreBias = cg.snap->ps.persistant[PERS_SCORE] - cgs.scores1;
01299                 if (scoreBias == 0)
01300                 {       // We are the leader!
01301                         if (cgs.scores2 <= 0)
01302                         {       // Nobody to be ahead of yet.
01303                                 Com_sprintf(scoreBiasStr, sizeof(scoreBiasStr), "");
01304                         }
01305                         else
01306                         {
01307                                 scoreBias = cg.snap->ps.persistant[PERS_SCORE] - cgs.scores2;
01308                                 if (scoreBias == 0)
01309                                 {
01310                                         Com_sprintf(scoreBiasStr, sizeof(scoreBiasStr), " (Tie)");
01311                                 }
01312                                 else
01313                                 {
01314                                         Com_sprintf(scoreBiasStr, sizeof(scoreBiasStr), " (+%d)", scoreBias);
01315                                 }
01316                         }
01317                 }
01318                 else // if (scoreBias < 0)
01319                 {       // We are behind!
01320                         Com_sprintf(scoreBiasStr, sizeof(scoreBiasStr), " (%d)", scoreBias);
01321                 }
01322                 scoreStr = va("%s: %i%s", CG_GetStringEdString("MP_INGAME", "SCORE"), cg.snap->ps.persistant[PERS_SCORE], scoreBiasStr);
01323         }
01324         else
01325         {       // Don't draw a bias.
01326                 scoreStr = va("%s: %i", CG_GetStringEdString("MP_INGAME", "SCORE"), cg.snap->ps.persistant[PERS_SCORE]);
01327         }
01328 
01329         menuHUD = Menus_FindByName("righthud");
01330 
01331         if (menuHUD)
01332         {
01333                 if (cgs.gametype != GT_POWERDUEL)
01334                 {
01335                         focusItem = Menu_FindItemByName(menuHUD, "score_line");
01336                         if (focusItem)
01337                         {
01338                                 UI_DrawScaledProportionalString(
01339                                         focusItem->window.rect.x, 
01340                                         focusItem->window.rect.y, 
01341                                         scoreStr, 
01342                                         UI_RIGHT|UI_DROPSHADOW, 
01343                                         focusItem->window.foreColor, 
01344                                         0.7);
01345                         }
01346                 }
01347 
01348                 // Print scanline
01349                 focusItem = Menu_FindItemByName(menuHUD, "scanline");
01350                 if (focusItem)
01351                 {
01352                         trap_R_SetColor( hudTintColor );        
01353                         CG_DrawPic( 
01354                                 focusItem->window.rect.x, 
01355                                 focusItem->window.rect.y, 
01356                                 focusItem->window.rect.w, 
01357                                 focusItem->window.rect.h, 
01358                                 focusItem->window.background 
01359                                 );                      
01360                 }
01361 
01362                 focusItem = Menu_FindItemByName(menuHUD, "frame");
01363                 if (focusItem)
01364                 {
01365                         trap_R_SetColor( hudTintColor );        
01366                         CG_DrawPic( 
01367                                 focusItem->window.rect.x, 
01368                                 focusItem->window.rect.y, 
01369                                 focusItem->window.rect.w, 
01370                                 focusItem->window.rect.h, 
01371                                 focusItem->window.background 
01372                                 );                      
01373                 }
01374 
01375                 CG_DrawForcePower(menuHUD);
01376 
01377                 // Draw ammo tics or saber style
01378                 if ( cent->currentState.weapon == WP_SABER )
01379                 {
01380                         CG_DrawSaberStyle(cent,menuHUD);
01381                 }
01382                 else
01383                 {
01384                         CG_DrawAmmo(cent,menuHUD);
01385                 }
01386         }
01387         else
01388         { 
01389                 //CG_Error("CG_ChatBox_ArrayInsert: unable to locate HUD menu file ");
01390         }
01391 }
01392 
01393 #define MAX_SHOWPOWERS NUM_FORCE_POWERS
01394 
01395 qboolean ForcePower_Valid(int i)
01396 {
01397         if (i == FP_LEVITATION ||
01398                 i == FP_SABER_OFFENSE ||
01399                 i == FP_SABER_DEFENSE ||
01400                 i == FP_SABERTHROW)
01401         {
01402                 return qfalse;
01403         }
01404 
01405         if (cg.snap->ps.fd.forcePowersKnown & (1 << i))
01406         {
01407                 return qtrue;
01408         }
01409         
01410         return qfalse;
01411 }
01412 
01413 /*
01414 ===================
01415 CG_DrawForceSelect
01416 ===================
01417 */
01418 #ifdef _XBOX
01419 extern bool CL_ExtendSelectTime(void);
01420 #endif
01421 void CG_DrawForceSelect( void ) 
01422 {
01423         int             i;
01424         int             count;
01425         int             smallIconSize,bigIconSize;
01426         int             holdX,x,y,x2,y2,pad,length;
01427         int             sideLeftIconCnt,sideRightIconCnt;
01428         int             sideMax,holdCount,iconCnt;
01429         int             yOffset = 0;
01430 
01431 
01432         x2 = 0;
01433         y2 = 0;
01434 
01435         // don't display if dead
01436         if ( cg.snap->ps.stats[STAT_HEALTH] <= 0 ) 
01437         {
01438                 return;
01439         }
01440 
01441         if ((cg.forceSelectTime+WEAPON_SELECT_TIME)<cg.time)    // Time is up for the HUD to display
01442         {
01443                 cg.forceSelect = cg.snap->ps.fd.forcePowerSelected;
01444                 return;
01445         }
01446 
01447         if (!cg.snap->ps.fd.forcePowersKnown)
01448         {
01449                 return;
01450         }
01451 
01452 #ifdef _XBOX
01453         if(CL_ExtendSelectTime()) {
01454                 cg.forceSelectTime = cg.time;
01455         }
01456         yOffset = -50;
01457 #endif
01458 
01459         // count the number of powers owned
01460         count = 0;
01461 
01462         for (i=0;i < NUM_FORCE_POWERS;++i)
01463         {
01464                 if (ForcePower_Valid(i))
01465                 {
01466                         count++;
01467                 }
01468         }
01469 
01470         if (count == 0) // If no force powers, don't display
01471         {
01472                 return;
01473         }
01474 
01475         sideMax = 3;    // Max number of icons on the side
01476 
01477         // Calculate how many icons will appear to either side of the center one
01478         holdCount = count - 1;  // -1 for the center icon
01479         if (holdCount == 0)                     // No icons to either side
01480         {
01481                 sideLeftIconCnt = 0;
01482                 sideRightIconCnt = 0;
01483         }
01484         else if (count > (2*sideMax))   // Go to the max on each side
01485         {
01486                 sideLeftIconCnt = sideMax;
01487                 sideRightIconCnt = sideMax;
01488         }
01489         else                                                    // Less than max, so do the calc
01490         {
01491                 sideLeftIconCnt = holdCount/2;
01492                 sideRightIconCnt = holdCount - sideLeftIconCnt;
01493         }
01494 
01495         smallIconSize = 30;
01496         bigIconSize = 60;
01497         pad = 12;
01498 
01499         x = 320;
01500         y = 425;
01501 
01502         // Background
01503         length = (sideLeftIconCnt * smallIconSize) + (sideLeftIconCnt*pad) +
01504                         bigIconSize + (sideRightIconCnt * smallIconSize) + (sideRightIconCnt*pad) + 12;
01505         
01506         i = BG_ProperForceIndex(cg.forceSelect) - 1;
01507         if (i < 0)
01508         {
01509                 i = MAX_SHOWPOWERS;
01510         }
01511 
01512         trap_R_SetColor(NULL);
01513         // Work backwards from current icon
01514         holdX = x - ((bigIconSize/2) + pad + smallIconSize);
01515         for (iconCnt=1;iconCnt<(sideLeftIconCnt+1);i--)
01516         {
01517                 if (i < 0)
01518                 {
01519                         i = MAX_SHOWPOWERS;
01520                 }
01521 
01522                 if (!ForcePower_Valid(forcePowerSorted[i]))     // Does he have this power?
01523                 {
01524                         continue;
01525                 }
01526 
01527                 ++iconCnt;                                      // Good icon
01528 
01529                 if (cgs.media.forcePowerIcons[forcePowerSorted[i]])
01530                 {
01531                         CG_DrawPic( holdX, y + yOffset, smallIconSize, smallIconSize, cgs.media.forcePowerIcons[forcePowerSorted[i]] ); 
01532                         holdX -= (smallIconSize+pad);
01533                 }
01534         }
01535 
01536         if (ForcePower_Valid(cg.forceSelect))
01537         {
01538                 // Current Center Icon
01539                 if (cgs.media.forcePowerIcons[cg.forceSelect])
01540                 {
01541                         CG_DrawPic( x-(bigIconSize/2), (y-((bigIconSize-smallIconSize)/2)) + yOffset, bigIconSize, bigIconSize, cgs.media.forcePowerIcons[cg.forceSelect] ); //only cache the icon for display
01542                 }
01543         }
01544 
01545         i = BG_ProperForceIndex(cg.forceSelect) + 1;
01546         if (i>MAX_SHOWPOWERS)
01547         {
01548                 i = 0;
01549         }
01550 
01551         // Work forwards from current icon
01552         holdX = x + (bigIconSize/2) + pad;
01553         for (iconCnt=1;iconCnt<(sideRightIconCnt+1);i++)
01554         {
01555                 if (i>MAX_SHOWPOWERS)
01556                 {
01557                         i = 0;
01558                 }
01559 
01560                 if (!ForcePower_Valid(forcePowerSorted[i]))     // Does he have this power?
01561                 {
01562                         continue;
01563                 }
01564 
01565                 ++iconCnt;                                      // Good icon
01566 
01567                 if (cgs.media.forcePowerIcons[forcePowerSorted[i]])
01568                 {
01569                         CG_DrawPic( holdX, y + yOffset, smallIconSize, smallIconSize, cgs.media.forcePowerIcons[forcePowerSorted[i]] ); //only cache the icon for display
01570                         holdX += (smallIconSize+pad);
01571                 }
01572         }
01573 
01574         if ( showPowersName[cg.forceSelect] ) 
01575         {
01576                 UI_DrawProportionalString(320, y + 30 + yOffset, CG_GetStringEdString("SP_INGAME", showPowersName[cg.forceSelect]), UI_CENTER | UI_SMALLFONT, colorTable[CT_ICON_BLUE]);
01577         }
01578 }
01579 
01580 /*
01581 ===================
01582 CG_DrawInventorySelect
01583 ===================
01584 */
01585 void CG_DrawInvenSelect( void ) 
01586 {
01587         int                             i;
01588         int                             sideMax,holdCount,iconCnt;
01589         int                             smallIconSize,bigIconSize;
01590         int                             sideLeftIconCnt,sideRightIconCnt;
01591         int                             count;
01592         int                             holdX,x,y,y2,pad;
01593         int                             height;
01594         float                   addX;
01595 
01596         // don't display if dead
01597         if ( cg.snap->ps.stats[STAT_HEALTH] <= 0 ) 
01598         {
01599                 return;
01600         }
01601 
01602         if ((cg.invenSelectTime+WEAPON_SELECT_TIME)<cg.time)    // Time is up for the HUD to display
01603         {
01604                 return;
01605         }
01606 
01607         if (!cg.snap->ps.stats[STAT_HOLDABLE_ITEM] || !cg.snap->ps.stats[STAT_HOLDABLE_ITEMS])
01608         {
01609                 return;
01610         }
01611 
01612 #ifdef _XBOX
01613         if(CL_ExtendSelectTime()) {
01614                 cg.invenSelectTime = cg.time;
01615         }
01616 #endif
01617 
01618         if (cg.itemSelect == -1)
01619         {
01620                 cg.itemSelect = bg_itemlist[cg.snap->ps.stats[STAT_HOLDABLE_ITEM]].giTag;
01621         }
01622 
01623 //const int bits = cg.snap->ps.stats[ STAT_ITEMS ];
01624 
01625         // count the number of items owned
01626         count = 0;
01627         for ( i = 0 ; i < HI_NUM_HOLDABLE ; i++ ) 
01628         {
01629                 if (/*CG_InventorySelectable(i) && inv_icons[i]*/
01630                         (cg.snap->ps.stats[STAT_HOLDABLE_ITEMS] & (1 << i)) ) 
01631                 {
01632                         count++;
01633                 }
01634         }
01635 
01636         if (!count)
01637         {
01638                 y2 = 0; //err?
01639                 UI_DrawProportionalString(320, y2 + 22, "EMPTY INVENTORY", UI_CENTER | UI_SMALLFONT, colorTable[CT_ICON_BLUE]);
01640                 return;
01641         }
01642 
01643         sideMax = 3;    // Max number of icons on the side
01644 
01645         // Calculate how many icons will appear to either side of the center one
01646         holdCount = count - 1;  // -1 for the center icon
01647         if (holdCount == 0)                     // No icons to either side
01648         {
01649                 sideLeftIconCnt = 0;
01650                 sideRightIconCnt = 0;
01651         }
01652         else if (count > (2*sideMax))   // Go to the max on each side
01653         {
01654                 sideLeftIconCnt = sideMax;
01655                 sideRightIconCnt = sideMax;
01656         }
01657         else                                                    // Less than max, so do the calc
01658         {
01659                 sideLeftIconCnt = holdCount/2;
01660                 sideRightIconCnt = holdCount - sideLeftIconCnt;
01661         }
01662 
01663         i = cg.itemSelect - 1;
01664         if (i<0)
01665         {
01666                 i = HI_NUM_HOLDABLE-1;
01667         }
01668 
01669         smallIconSize = 40;
01670         bigIconSize = 80;
01671         pad = 16;
01672 
01673         x = 320;
01674         y = 410;
01675 
01676         // Left side ICONS
01677         // Work backwards from current icon
01678         holdX = x - ((bigIconSize/2) + pad + smallIconSize);
01679         height = smallIconSize * cg.iconHUDPercent;
01680         addX = (float) smallIconSize * .75;
01681 
01682         for (iconCnt=0;iconCnt<sideLeftIconCnt;i--)
01683         {
01684                 if (i<0)
01685                 {
01686                         i = HI_NUM_HOLDABLE-1;
01687                 }
01688 
01689                 if ( !(cg.snap->ps.stats[STAT_HOLDABLE_ITEMS] & (1 << i)) || i == cg.itemSelect )
01690                 {
01691                         continue;
01692                 }
01693 
01694                 ++iconCnt;                                      // Good icon
01695 
01696                 if (!BG_IsItemSelectable(&cg.predictedPlayerState, i))
01697                 {
01698                         continue;
01699                 }
01700 
01701                 if (cgs.media.invenIcons[i])
01702                 {
01703                         trap_R_SetColor(NULL);
01704                         CG_DrawPic( holdX, y+10, smallIconSize, smallIconSize, cgs.media.invenIcons[i] );
01705 
01706                         trap_R_SetColor(colorTable[CT_ICON_BLUE]);
01707                         /*CG_DrawNumField (holdX + addX, y + smallIconSize, 2, cg.snap->ps.inventory[i], 6, 12, 
01708                                 NUM_FONT_SMALL,qfalse);
01709                                 */
01710 
01711                         holdX -= (smallIconSize+pad);
01712                 }
01713         }
01714 
01715         // Current Center Icon
01716         height = bigIconSize * cg.iconHUDPercent;
01717         if (cgs.media.invenIcons[cg.itemSelect] && BG_IsItemSelectable(&cg.predictedPlayerState, cg.itemSelect))
01718         {
01719                 int itemNdex;
01720                 trap_R_SetColor(NULL);
01721                 CG_DrawPic( x-(bigIconSize/2), (y-((bigIconSize-smallIconSize)/2))+10, bigIconSize, bigIconSize, cgs.media.invenIcons[cg.itemSelect] );
01722                 addX = (float) bigIconSize * .75;
01723                 trap_R_SetColor(colorTable[CT_ICON_BLUE]);
01724                 /*CG_DrawNumField ((x-(bigIconSize/2)) + addX, y, 2, cg.snap->ps.inventory[cg.inventorySelect], 6, 12, 
01725                         NUM_FONT_SMALL,qfalse);*/
01726 
01727                 itemNdex = BG_GetItemIndexByTag(cg.itemSelect, IT_HOLDABLE);
01728                 if (bg_itemlist[itemNdex].classname)
01729                 {
01730                         vec4_t  textColor = { .312f, .75f, .621f, 1.0f };
01731                         char    text[1024];
01732                         char    upperKey[1024];
01733 
01734                         strcpy(upperKey, bg_itemlist[itemNdex].classname);
01735                         
01736                         if ( trap_SP_GetStringTextString( va("SP_INGAME_%s",Q_strupr(upperKey)), text, sizeof( text )))
01737                         {
01738                                 UI_DrawProportionalString(320, y+45, text, UI_CENTER | UI_SMALLFONT, textColor);
01739                         }
01740                         else
01741                         {
01742                                 UI_DrawProportionalString(320, y+45, bg_itemlist[itemNdex].classname, UI_CENTER | UI_SMALLFONT, textColor);
01743                         }
01744                 }
01745         }
01746 
01747         i = cg.itemSelect + 1;
01748         if (i> HI_NUM_HOLDABLE-1)
01749         {
01750                 i = 0;
01751         }
01752 
01753         // Right side ICONS
01754         // Work forwards from current icon
01755         holdX = x + (bigIconSize/2) + pad;
01756         height = smallIconSize * cg.iconHUDPercent;
01757         addX = (float) smallIconSize * .75;
01758         for (iconCnt=0;iconCnt<sideRightIconCnt;i++)
01759         {
01760                 if (i> HI_NUM_HOLDABLE-1)
01761                 {
01762                         i = 0;
01763                 }
01764 
01765                 if ( !(cg.snap->ps.stats[STAT_HOLDABLE_ITEMS] & (1 << i)) || i == cg.itemSelect )
01766                 {
01767                         continue;
01768                 }
01769 
01770                 ++iconCnt;                                      // Good icon
01771 
01772                 if (!BG_IsItemSelectable(&cg.predictedPlayerState, i))
01773                 {
01774                         continue;
01775                 }
01776 
01777                 if (cgs.media.invenIcons[i])
01778                 {
01779                         trap_R_SetColor(NULL);
01780                         CG_DrawPic( holdX, y+10, smallIconSize, smallIconSize, cgs.media.invenIcons[i] );
01781 
01782                         trap_R_SetColor(colorTable[CT_ICON_BLUE]);
01783                         /*CG_DrawNumField (holdX + addX, y + smallIconSize, 2, cg.snap->ps.inventory[i], 6, 12, 
01784                                 NUM_FONT_SMALL,qfalse);*/
01785 
01786                         holdX += (smallIconSize+pad);
01787                 }
01788         }
01789 }
01790 
01791 int cg_targVeh = ENTITYNUM_NONE;
01792 int cg_targVehLastTime = 0;
01793 qboolean CG_CheckTargetVehicle( centity_t **pTargetVeh, float *alpha )
01794 {
01795         int targetNum = ENTITYNUM_NONE;
01796         centity_t       *targetVeh = NULL;
01797         
01798         if ( !pTargetVeh || !alpha )
01799         {//hey, where are my pointers?
01800                 return qfalse;
01801         }
01802 
01803         *alpha = 1.0f;
01804 
01805         //FIXME: need to clear all of these when you die?
01806         if ( cg.predictedPlayerState.rocketLockIndex < ENTITYNUM_WORLD )
01807         {
01808                 targetNum = cg.predictedPlayerState.rocketLockIndex;
01809         }
01810         else if ( cg.crosshairVehNum < ENTITYNUM_WORLD 
01811                 && cg.time - cg.crosshairVehTime < 3000 )
01812         {//crosshair was on a vehicle in the last 3 seconds
01813                 targetNum = cg.crosshairVehNum;
01814         }
01815     else if ( cg.crosshairClientNum < ENTITYNUM_WORLD )
01816         {
01817                 targetNum = cg.crosshairClientNum;
01818         }
01819 
01820         if ( targetNum < MAX_CLIENTS )
01821         {//real client
01822                 if ( cg_entities[targetNum].currentState.m_iVehicleNum >= MAX_CLIENTS )
01823                 {//in a vehicle
01824                         targetNum = cg_entities[targetNum].currentState.m_iVehicleNum;
01825                 }
01826         }
01827     if ( targetNum < ENTITYNUM_WORLD 
01828                 && targetNum >= MAX_CLIENTS )
01829         {
01830                 centity_t *targetVeh = &cg_entities[targetNum];
01831                 if ( targetVeh->currentState.NPC_class == CLASS_VEHICLE 
01832                         && targetVeh->m_pVehicle
01833                         && targetVeh->m_pVehicle->m_pVehicleInfo
01834                         && targetVeh->m_pVehicle->m_pVehicleInfo->type == VH_FIGHTER )
01835                 {//it's a vehicle
01836                         cg_targVeh = targetNum;
01837                         cg_targVehLastTime = cg.time;
01838                         *alpha = 1.0f;
01839                 }
01840                 else
01841                 {
01842                         targetVeh = NULL;
01843                 }
01844         }
01845         if ( !targetVeh )
01846         {
01847                 if ( cg_targVehLastTime && cg.time - cg_targVehLastTime < 3000 )
01848                 {
01849                         targetVeh = &cg_entities[cg_targVeh];;
01850                         if ( cg.time-cg_targVehLastTime < 1000 )
01851                         {//stay at full alpha for 1 sec after lose them from crosshair
01852                                 *alpha = 1.0f;
01853                         }
01854                         else
01855                         {//fade out over 2 secs
01856                                 *alpha = 1.0f-((cg.time-cg_targVehLastTime-1000)/2000.0f);
01857                         }
01858                 }
01859         }
01860         if ( targetVeh )
01861         {
01862                 *pTargetVeh = targetVeh;
01863                 return qtrue;
01864         }
01865         return qfalse;
01866 }
01867 
01868 #define MAX_VHUD_SHIELD_TICS 12
01869 #define MAX_VHUD_SPEED_TICS 5
01870 #define MAX_VHUD_ARMOR_TICS 5
01871 #define MAX_VHUD_AMMO_TICS 5
01872 
01873 float CG_DrawVehicleShields( const menuDef_t    *menuHUD, const centity_t *veh )
01874 {
01875         int                             i;
01876         char                    itemName[64];
01877         float                   inc, currValue,maxShields;
01878         vec4_t                  calcColor;
01879         itemDef_t               *item;
01880         float                   percShields;
01881 
01882         item = Menu_FindItemByName((menuDef_t   *) menuHUD, "armorbackground");
01883 
01884         if (item)
01885         {
01886                 trap_R_SetColor( item->window.foreColor );
01887                 CG_DrawPic( 
01888                         item->window.rect.x, 
01889                         item->window.rect.y, 
01890                         item->window.rect.w, 
01891                         item->window.rect.h, 
01892                         item->window.background );
01893         }
01894 
01895         maxShields = veh->m_pVehicle->m_pVehicleInfo->shields;
01896         currValue = cg.predictedVehicleState.stats[STAT_ARMOR];
01897         percShields = (float)currValue/(float)maxShields;
01898         // Print all the tics of the shield graphic
01899         // Look at the amount of health left and show only as much of the graphic as there is health.
01900         // Use alpha to fade out partial section of health
01901         inc = (float) maxShields / MAX_VHUD_ARMOR_TICS;
01902         for (i=1;i<=MAX_VHUD_ARMOR_TICS;i++)
01903         {
01904                 sprintf( itemName, "armor_tic%d",       i );
01905 
01906                 item = Menu_FindItemByName((menuDef_t *) menuHUD, itemName);
01907 
01908                 if (!item)
01909                 {
01910                         continue;
01911                 }
01912 
01913                 memcpy(calcColor, item->window.foreColor, sizeof(vec4_t));
01914 
01915                 if (currValue <= 0)     // don't show tic
01916                 {
01917                         break;
01918                 }
01919                 else if (currValue < inc)       // partial tic (alpha it out)
01920                 {
01921                         float percent = currValue / inc;
01922                         calcColor[3] *= percent;                // Fade it out
01923                 }
01924 
01925                 trap_R_SetColor( calcColor);
01926 
01927                 CG_DrawPic( 
01928                         item->window.rect.x, 
01929                         item->window.rect.y, 
01930                         item->window.rect.w, 
01931                         item->window.rect.h, 
01932                         item->window.background );
01933 
01934                 currValue -= inc;
01935         }
01936 
01937         return percShields;
01938 }
01939 
01940 int cg_vehicleAmmoWarning = 0;
01941 int cg_vehicleAmmoWarningTime = 0;
01942 void CG_DrawVehicleAmmo( const menuDef_t *menuHUD, const centity_t *veh )
01943 {
01944         int i;
01945         char itemName[64];
01946         float inc, currValue,maxAmmo;
01947         vec4_t  calcColor;
01948         itemDef_t       *item;
01949 
01950         item = Menu_FindItemByName((menuDef_t *) menuHUD, "ammobackground");
01951 
01952         if (item)
01953         {
01954                 trap_R_SetColor( item->window.foreColor );
01955                 CG_DrawPic( 
01956                         item->window.rect.x, 
01957                         item->window.rect.y, 
01958                         item->window.rect.w, 
01959                         item->window.rect.h, 
01960                         item->window.background );
01961         }
01962 
01963         maxAmmo = veh->m_pVehicle->m_pVehicleInfo->weapon[0].ammoMax;
01964         currValue = cg.predictedVehicleState.ammo[0];
01965         
01966         inc = (float) maxAmmo / MAX_VHUD_AMMO_TICS;
01967         for (i=1;i<=MAX_VHUD_AMMO_TICS;i++)
01968         {
01969                 sprintf( itemName, "ammo_tic%d",        i );
01970 
01971                 item = Menu_FindItemByName((menuDef_t *)menuHUD, itemName);
01972 
01973                 if (!item)
01974                 {
01975                         continue;
01976                 }
01977 
01978                 if ( cg_vehicleAmmoWarningTime > cg.time 
01979                         && cg_vehicleAmmoWarning == 0 )
01980                 {
01981                         memcpy(calcColor, g_color_table[ColorIndex(COLOR_RED)], sizeof(vec4_t));
01982                         calcColor[3] = sin(cg.time*0.005)*0.5f+0.5f;
01983                 }
01984                 else
01985                 {
01986                         memcpy(calcColor, item->window.foreColor, sizeof(vec4_t));
01987 
01988                         if (currValue <= 0)     // don't show tic
01989                         {
01990                                 break;
01991                         }
01992                         else if (currValue < inc)       // partial tic (alpha it out)
01993                         {
01994                                 float percent = currValue / inc;
01995                                 calcColor[3] *= percent;                // Fade it out
01996                         }
01997                 }
01998 
01999                 trap_R_SetColor( calcColor);
02000 
02001                 CG_DrawPic( 
02002                         item->window.rect.x, 
02003                         item->window.rect.y, 
02004                         item->window.rect.w, 
02005                         item->window.rect.h, 
02006                         item->window.background );
02007 
02008                 currValue -= inc;
02009         }
02010 }
02011 
02012 
02013 void CG_DrawVehicleAmmoUpper( const menuDef_t *menuHUD, const centity_t *veh )
02014 {
02015         int                     i;
02016         char            itemName[64];
02017         float           inc, currValue,maxAmmo;
02018         vec4_t          calcColor;
02019         itemDef_t       *item;
02020 
02021         item = Menu_FindItemByName((menuDef_t *)menuHUD, "ammoupperbackground");
02022 
02023         if (item)
02024         {
02025                 trap_R_SetColor( item->window.foreColor );
02026                 CG_DrawPic( 
02027                         item->window.rect.x, 
02028                         item->window.rect.y, 
02029                         item->window.rect.w, 
02030                         item->window.rect.h, 
02031                         item->window.background );
02032         }
02033 
02034         maxAmmo = veh->m_pVehicle->m_pVehicleInfo->weapon[0].ammoMax;
02035         currValue = cg.predictedVehicleState.ammo[0];
02036 
02037         inc = (float) maxAmmo / MAX_VHUD_AMMO_TICS;
02038         for (i=1;i<MAX_VHUD_AMMO_TICS;i++)
02039         {
02040                 sprintf( itemName, "ammoupper_tic%d",   i );
02041 
02042                 item = Menu_FindItemByName((menuDef_t *)menuHUD, itemName);
02043 
02044                 if (!item)
02045                 {
02046                         continue;
02047                 }
02048 
02049                 if ( cg_vehicleAmmoWarningTime > cg.time 
02050                         && cg_vehicleAmmoWarning == 0 )
02051                 {
02052                         memcpy(calcColor, g_color_table[ColorIndex(COLOR_RED)], sizeof(vec4_t));
02053                         calcColor[3] = sin(cg.time*0.005)*0.5f+0.5f;
02054                 }
02055                 else
02056                 {
02057                         memcpy(calcColor, item->window.foreColor, sizeof(vec4_t));
02058 
02059                         if (currValue <= 0)     // don't show tic
02060                         {
02061                                 break;
02062                         }
02063                         else if (currValue < inc)       // partial tic (alpha it out)
02064                         {
02065                                 float percent = currValue / inc;
02066                                 calcColor[3] *= percent;                // Fade it out
02067                         }
02068                 }
02069 
02070                 trap_R_SetColor( calcColor);
02071 
02072                 CG_DrawPic( 
02073                         item->window.rect.x, 
02074                         item->window.rect.y, 
02075                         item->window.rect.w, 
02076                         item->window.rect.h, 
02077                         item->window.background );
02078 
02079                 currValue -= inc;
02080         }
02081 }
02082 
02083 
02084 void CG_DrawVehicleAmmoLower( const menuDef_t *menuHUD, const centity_t *veh )
02085 {
02086         int                             i;
02087         char                    itemName[64];
02088         float                   inc, currValue,maxAmmo;
02089         vec4_t                  calcColor;
02090         itemDef_t               *item;
02091 
02092 
02093         item = Menu_FindItemByName((menuDef_t *)menuHUD, "ammolowerbackground");
02094 
02095         if (item)
02096         {
02097                 trap_R_SetColor( item->window.foreColor );
02098                 CG_DrawPic( 
02099                         item->window.rect.x, 
02100                         item->window.rect.y, 
02101                         item->window.rect.w, 
02102                         item->window.rect.h, 
02103                         item->window.background );
02104         }
02105 
02106         maxAmmo = veh->m_pVehicle->m_pVehicleInfo->weapon[1].ammoMax;
02107         currValue = cg.predictedVehicleState.ammo[1];
02108 
02109         inc = (float) maxAmmo / MAX_VHUD_AMMO_TICS;
02110         for (i=1;i<MAX_VHUD_AMMO_TICS;i++)
02111         {
02112                 sprintf( itemName, "ammolower_tic%d",   i );
02113 
02114                 item = Menu_FindItemByName((menuDef_t *)menuHUD, itemName);
02115 
02116                 if (!item)
02117                 {
02118                         continue;
02119                 }
02120 
02121                 if ( cg_vehicleAmmoWarningTime > cg.time 
02122                         && cg_vehicleAmmoWarning == 1 )
02123                 {
02124                         memcpy(calcColor, g_color_table[ColorIndex(COLOR_RED)], sizeof(vec4_t));
02125                         calcColor[3] = sin(cg.time*0.005)*0.5f+0.5f;
02126                 }
02127                 else
02128                 {
02129                         memcpy(calcColor, item->window.foreColor, sizeof(vec4_t));
02130 
02131                         if (currValue <= 0)     // don't show tic
02132                         {
02133                                 break;
02134                         }
02135                         else if (currValue < inc)       // partial tic (alpha it out)
02136                         {
02137                                 float percent = currValue / inc;
02138                                 calcColor[3] *= percent;                // Fade it out
02139                         }
02140                 }
02141 
02142                 trap_R_SetColor( calcColor);
02143 
02144                 CG_DrawPic( 
02145                         item->window.rect.x, 
02146                         item->window.rect.y, 
02147                         item->window.rect.w, 
02148                         item->window.rect.h, 
02149                         item->window.background );
02150 
02151                 currValue -= inc;
02152         }
02153 }
02154 
02155 // The HUD.menu file has the graphic print with a negative height, so it will print from the bottom up.
02156 void CG_DrawVehicleTurboRecharge( const menuDef_t       *menuHUD, const centity_t *veh )
02157 {
02158         itemDef_t       *item;
02159         int                     height;
02160 
02161         item = Menu_FindItemByName( (menuDef_t  *) menuHUD, "turborecharge");
02162 
02163         if (item)
02164         {
02165                 float percent=0.0f;
02166                 int diff = ( cg.time - veh->m_pVehicle->m_iTurboTime );
02167 
02168                 height = item->window.rect.h;
02169 
02170                 if (diff > veh->m_pVehicle->m_pVehicleInfo->turboRecharge)
02171                 {
02172                         percent = 1.0f;
02173                         trap_R_SetColor( colorTable[CT_GREEN] );
02174                 }
02175                 else 
02176                 {
02177                         percent = (float) diff / veh->m_pVehicle->m_pVehicleInfo->turboRecharge;
02178                         if (percent < 0.0f)
02179                         {
02180                                 percent = 0.0f;
02181                         }
02182                         trap_R_SetColor( colorTable[CT_RED] );
02183                 }
02184 
02185                 height *= percent;
02186 
02187                 CG_DrawPic( 
02188                         item->window.rect.x, 
02189                         item->window.rect.y, 
02190                         item->window.rect.w, 
02191                         height, 
02192                         cgs.media.whiteShader); 
02193         }
02194 }
02195 
02196 qboolean cg_drawLink = qfalse;
02197 void CG_DrawVehicleWeaponsLinked( const menuDef_t       *menuHUD, const centity_t *veh )
02198 {
02199         qboolean drawLink = qfalse;
02200         if ( veh->m_pVehicle
02201                 && veh->m_pVehicle->m_pVehicleInfo
02202                 && (veh->m_pVehicle->m_pVehicleInfo->weapon[0].linkable == 2|| veh->m_pVehicle->m_pVehicleInfo->weapon[1].linkable == 2) )
02203         {//weapon is always linked
02204                 drawLink = qtrue;
02205         }
02206         else
02207         {
02208 //MP way:
02209                 //must get sent over network
02210                 if ( cg.predictedVehicleState.vehWeaponsLinked )
02211                 {
02212                         drawLink = qtrue;
02213                 }
02214 //NOTE: below is SP way
02215 /*
02216                 //just cheat it
02217                 if ( veh->gent->m_pVehicle->weaponStatus[0].linked
02218                         || veh->gent->m_pVehicle->weaponStatus[1].linked )
02219                 {
02220                         drawLink = qtrue;
02221                 }
02222 */
02223         }
02224 
02225         if ( cg_drawLink != drawLink )
02226         {//state changed, play sound
02227                 cg_drawLink = drawLink;
02228                 trap_S_StartSound (NULL, cg.predictedPlayerState.clientNum, CHAN_LOCAL, trap_S_RegisterSound( "sound/vehicles/common/linkweaps.wav" ) );
02229         }
02230 
02231         if ( drawLink )
02232         {
02233                 itemDef_t       *item;
02234 
02235                 item = Menu_FindItemByName( (menuDef_t  *) menuHUD, "weaponslinked");
02236 
02237                 if (item)
02238                 {
02239                         trap_R_SetColor( colorTable[CT_CYAN] );
02240 
02241                                 CG_DrawPic( 
02242                                 item->window.rect.x, 
02243                                 item->window.rect.y, 
02244                                 item->window.rect.w, 
02245                                 item->window.rect.h, 
02246                                 cgs.media.whiteShader); 
02247                 }
02248         }
02249 }
02250 
02251 void CG_DrawVehicleSpeed( const menuDef_t       *menuHUD, const centity_t *veh )
02252 {
02253         int i;
02254         char itemName[64];
02255         float inc, currValue,maxSpeed;
02256         vec4_t          calcColor;
02257         itemDef_t       *item;
02258 
02259         item = Menu_FindItemByName((menuDef_t *) menuHUD, "speedbackground");
02260 
02261         if (item)
02262         {
02263                 trap_R_SetColor( item->window.foreColor );
02264                 CG_DrawPic( 
02265                         item->window.rect.x, 
02266                         item->window.rect.y, 
02267                         item->window.rect.w, 
02268                         item->window.rect.h, 
02269                         item->window.background );
02270         }
02271 
02272         maxSpeed = veh->m_pVehicle->m_pVehicleInfo->speedMax;
02273         currValue = cg.predictedVehicleState.speed;
02274 
02275 
02276         // Print all the tics of the shield graphic
02277         // Look at the amount of health left and show only as much of the graphic as there is health.
02278         // Use alpha to fade out partial section of health
02279         inc = (float) maxSpeed / MAX_VHUD_SPEED_TICS;
02280         for (i=1;i<=MAX_VHUD_SPEED_TICS;i++)
02281         {
02282                 sprintf( itemName, "speed_tic%d",       i );
02283 
02284                 item = Menu_FindItemByName((menuDef_t *)menuHUD, itemName);
02285 
02286                 if (!item)
02287                 {
02288                         continue;
02289                 }
02290 
02291                 if ( cg.time > veh->m_pVehicle->m_iTurboTime )
02292                 {
02293                         memcpy(calcColor, item->window.foreColor, sizeof(vec4_t));
02294                 }
02295                 else    // In turbo mode
02296                 {
02297                         if (cg.VHUDFlashTime < cg.time) 
02298                         {
02299                                 cg.VHUDFlashTime = cg.time + 200;
02300                                 if (cg.VHUDTurboFlag)
02301                                 {
02302                                         cg.VHUDTurboFlag = qfalse;
02303                                 }
02304                                 else
02305                                 {
02306                                         cg.VHUDTurboFlag = qtrue;
02307                                 }
02308                         }
02309 
02310                         if (cg.VHUDTurboFlag)
02311                         {
02312                                 memcpy(calcColor, colorTable[CT_LTRED1], sizeof(vec4_t));
02313                         }
02314                         else
02315                         {
02316                                 memcpy(calcColor, item->window.foreColor, sizeof(vec4_t));
02317                         }  
02318                 }
02319 
02320 
02321                 if (currValue <= 0)     // don't show tic
02322                 {
02323                         break;
02324                 }
02325                 else if (currValue < inc)       // partial tic (alpha it out)
02326                 {
02327                         float percent = currValue / inc;
02328                         calcColor[3] *= percent;                // Fade it out
02329                 }
02330 
02331                 trap_R_SetColor( calcColor);
02332 
02333                 CG_DrawPic( 
02334                         item->window.rect.x, 
02335                         item->window.rect.y, 
02336                         item->window.rect.w, 
02337                         item->window.rect.h, 
02338                         item->window.background );
02339 
02340                 currValue -= inc;
02341         }
02342 }
02343 
02344 void CG_DrawVehicleArmor( const menuDef_t *menuHUD, const centity_t *veh )
02345 {
02346         int                     i;
02347         vec4_t          calcColor;
02348         char            itemName[64];
02349         float           inc, currValue,maxArmor;
02350         itemDef_t       *item;
02351 
02352         maxArmor = veh->m_pVehicle->m_pVehicleInfo->armor;
02353         currValue = cg.predictedVehicleState.stats[STAT_HEALTH];
02354 
02355         item = Menu_FindItemByName( (menuDef_t  *) menuHUD, "shieldbackground");
02356 
02357         if (item)
02358         {
02359                 trap_R_SetColor( item->window.foreColor );
02360                 CG_DrawPic( 
02361                         item->window.rect.x, 
02362                         item->window.rect.y, 
02363                         item->window.rect.w, 
02364                         item->window.rect.h, 
02365                         item->window.background );
02366         }
02367 
02368 
02369         // Print all the tics of the shield graphic
02370         // Look at the amount of health left and show only as much of the graphic as there is health.
02371         // Use alpha to fade out partial section of health
02372         inc = (float) maxArmor / MAX_VHUD_SHIELD_TICS;
02373         for (i=1;i <= MAX_VHUD_SHIELD_TICS;i++)
02374         {
02375                 sprintf( itemName, "shield_tic%d",      i );
02376 
02377                 item = Menu_FindItemByName((menuDef_t   *) menuHUD, itemName);
02378 
02379                 if (!item)
02380                 {
02381                         continue;
02382                 }
02383 
02384 
02385                 memcpy(calcColor, item->window.foreColor, sizeof(vec4_t));
02386 
02387                 if (currValue <= 0)     // don't show tic
02388                 {
02389                         break;
02390                 }
02391                 else if (currValue < inc)       // partial tic (alpha it out)
02392                 {
02393                         float percent = currValue / inc;
02394                         calcColor[3] *= percent;                // Fade it out
02395                 }
02396 
02397                 trap_R_SetColor( calcColor);
02398 
02399                 CG_DrawPic( 
02400                         item->window.rect.x, 
02401                         item->window.rect.y, 
02402                         item->window.rect.w, 
02403                         item->window.rect.h, 
02404                         item->window.background );
02405 
02406                 currValue -= inc;
02407         }
02408 }
02409 
02410 enum
02411 {
02412         VEH_DAMAGE_FRONT=0,
02413         VEH_DAMAGE_BACK,
02414         VEH_DAMAGE_LEFT,
02415         VEH_DAMAGE_RIGHT,
02416 };
02417 
02418 typedef struct 
02419 {
02420         char    *itemName;
02421         short   heavyDamage;
02422         short   lightDamage;
02423 } veh_damage_t;
02424 
02425 veh_damage_t vehDamageData[4] = 
02426 {
02427 "vehicle_front",SHIPSURF_DAMAGE_FRONT_HEAVY,SHIPSURF_DAMAGE_FRONT_LIGHT,
02428 "vehicle_back",SHIPSURF_DAMAGE_BACK_HEAVY,SHIPSURF_DAMAGE_BACK_LIGHT,
02429 "vehicle_left",SHIPSURF_DAMAGE_LEFT_HEAVY,SHIPSURF_DAMAGE_LEFT_LIGHT,
02430 "vehicle_right",SHIPSURF_DAMAGE_RIGHT_HEAVY,SHIPSURF_DAMAGE_RIGHT_LIGHT,
02431 };
02432 
02433 // Draw health graphic for given part of vehicle
02434 void CG_DrawVehicleDamage(const centity_t *veh,int brokenLimbs,const menuDef_t  *menuHUD,float alpha,int index)
02435 {
02436         itemDef_t               *item;
02437         int                             colorI;
02438         vec4_t                  color;
02439         int                             graphicHandle=0;
02440 
02441         item = Menu_FindItemByName((menuDef_t *)menuHUD, vehDamageData[index].itemName);
02442         if (item)
02443         {
02444                 if (brokenLimbs & (1<<vehDamageData[index].heavyDamage))
02445                 {
02446                         colorI = CT_RED;
02447                         if (brokenLimbs & (1<<vehDamageData[index].lightDamage))
02448                         {
02449                                 colorI = CT_DKGREY;
02450                         }
02451                 }
02452                 else if (brokenLimbs & (1<<vehDamageData[index].lightDamage))
02453                 {
02454                         colorI = CT_YELLOW;
02455                 }
02456                 else
02457                 {
02458                         colorI = CT_GREEN;
02459                 }
02460 
02461                 VectorCopy4 ( colorTable[colorI], color );
02462                 color[3] = alpha;
02463                 trap_R_SetColor( color );
02464 
02465                 switch ( index )
02466                 {
02467                         case VEH_DAMAGE_FRONT :
02468                                 graphicHandle = veh->m_pVehicle->m_pVehicleInfo->iconFrontHandle;
02469                                 break;
02470                         case VEH_DAMAGE_BACK :
02471                                 graphicHandle = veh->m_pVehicle->m_pVehicleInfo->iconBackHandle;
02472                                 break;
02473                         case VEH_DAMAGE_LEFT :
02474                                 graphicHandle = veh->m_pVehicle->m_pVehicleInfo->iconLeftHandle;
02475                                 break;
02476                         case VEH_DAMAGE_RIGHT :
02477                                 graphicHandle = veh->m_pVehicle->m_pVehicleInfo->iconRightHandle;
02478                                 break;
02479                 }
02480 
02481                 if (graphicHandle)
02482                 {
02483                         CG_DrawPic( 
02484                                 item->window.rect.x, 
02485                                 item->window.rect.y, 
02486                                 item->window.rect.w, 
02487                                 item->window.rect.h, 
02488                                 graphicHandle );
02489                 }
02490         }
02491 }
02492 
02493 
02494 // Used on both damage indicators :  player vehicle and the vehicle the player is locked on 
02495 void CG_DrawVehicleDamageHUD(const centity_t *veh,int brokenLimbs,float percShields,char *menuName, float alpha)
02496 {
02497         menuDef_t               *menuHUD;
02498         itemDef_t               *item;
02499         vec4_t                  color;
02500 
02501         menuHUD = Menus_FindByName(menuName);
02502 
02503         if ( !menuHUD )
02504         {
02505                 return;
02506         }
02507 
02508         item = Menu_FindItemByName(menuHUD, "background");
02509         if (item)
02510         {
02511                 if (veh->m_pVehicle->m_pVehicleInfo->dmgIndicBackgroundHandle)
02512                 {
02513                         if ( veh->damageTime > cg.time )
02514                         {//ship shields currently taking damage
02515                                 //NOTE: cent->damageAngle can be accessed to get the direction from the ship origin to the impact point (in 3-D space)
02516                                 float perc = 1.0f - ((veh->damageTime - cg.time) / 2000.0f/*MIN_SHIELD_TIME*/);
02517                                 if ( perc < 0.0f )
02518                                 {
02519                                         perc = 0.0f;
02520                                 }
02521                                 else if ( perc > 1.0f )
02522                                 {
02523                                         perc = 1.0f;
02524                                 }
02525                                 color[0] = item->window.foreColor[0];//flash red
02526                                 color[1] = item->window.foreColor[1]*perc;//fade other colors back in over time
02527                                 color[2] = item->window.foreColor[2]*perc;//fade other colors back in over time
02528                                 color[3] = item->window.foreColor[3];//always normal alpha
02529                                 trap_R_SetColor( color );
02530                         }
02531                         else
02532                         {
02533                                 trap_R_SetColor( item->window.foreColor );
02534                         }
02535 
02536                         CG_DrawPic( 
02537                                 item->window.rect.x, 
02538                                 item->window.rect.y, 
02539                                 item->window.rect.w, 
02540                                 item->window.rect.h, 
02541                                 veh->m_pVehicle->m_pVehicleInfo->dmgIndicBackgroundHandle );
02542                 }
02543         }
02544 
02545         item = Menu_FindItemByName(menuHUD, "outer_frame");
02546         if (item)
02547         {
02548                 if (veh->m_pVehicle->m_pVehicleInfo->dmgIndicFrameHandle)
02549                 {
02550                         trap_R_SetColor( item->window.foreColor );
02551                         CG_DrawPic( 
02552                                 item->window.rect.x, 
02553                                 item->window.rect.y, 
02554                                 item->window.rect.w, 
02555                                 item->window.rect.h, 
02556                                 veh->m_pVehicle->m_pVehicleInfo->dmgIndicFrameHandle );
02557                 }
02558         }
02559 
02560         item = Menu_FindItemByName(menuHUD, "shields");
02561         if (item)
02562         {
02563                 if (veh->m_pVehicle->m_pVehicleInfo->dmgIndicShieldHandle)
02564                 {
02565                         VectorCopy4 ( colorTable[CT_HUD_GREEN], color );
02566                         color[3] = percShields;
02567                         trap_R_SetColor( color );
02568                         CG_DrawPic( 
02569                                 item->window.rect.x, 
02570                                 item->window.rect.y, 
02571                                 item->window.rect.w, 
02572                                 item->window.rect.h, 
02573                                 veh->m_pVehicle->m_pVehicleInfo->dmgIndicShieldHandle );
02574                 }
02575         }
02576 
02577         //TODO: if we check nextState.brokenLimbs & prevState.brokenLimbs, we can tell when a damage flag has been added and flash that part of the ship
02578         //FIXME: when ship explodes, either stop drawing ship or draw all parts black
02579         CG_DrawVehicleDamage(veh,brokenLimbs,menuHUD,alpha,VEH_DAMAGE_FRONT);
02580         CG_DrawVehicleDamage(veh,brokenLimbs,menuHUD,alpha,VEH_DAMAGE_BACK);
02581         CG_DrawVehicleDamage(veh,brokenLimbs,menuHUD,alpha,VEH_DAMAGE_LEFT);
02582         CG_DrawVehicleDamage(veh,brokenLimbs,menuHUD,alpha,VEH_DAMAGE_RIGHT);
02583 }
02584 
02585 qboolean CG_DrawVehicleHud( const centity_t *cent )
02586 {
02587         itemDef_t               *item;
02588         menuDef_t               *menuHUD;
02589         playerState_t   *ps;
02590         centity_t               *veh;
02591         float                   shieldPerc,alpha;
02592         
02593         menuHUD = Menus_FindByName("swoopvehiclehud");
02594         if (!menuHUD)
02595         {
02596                 return qtrue;   // Draw player HUD
02597         }
02598 
02599         ps = &cg.predictedPlayerState;
02600 
02601         if (!ps || !(ps->m_iVehicleNum))
02602         {
02603                 return qtrue;   // Draw player HUD
02604         }
02605         veh = &cg_entities[ps->m_iVehicleNum];
02606 
02607         if ( !veh )
02608         {
02609                 return qtrue;   // Draw player HUD
02610         }
02611 
02612         CG_DrawVehicleTurboRecharge( menuHUD, veh );
02613         CG_DrawVehicleWeaponsLinked( menuHUD, veh );
02614 
02615         item = Menu_FindItemByName(menuHUD, "leftframe");
02616 
02617         // Draw frame
02618         if (item)
02619         {
02620                 trap_R_SetColor( item->window.foreColor );
02621                 CG_DrawPic( 
02622                         item->window.rect.x, 
02623                         item->window.rect.y, 
02624                         item->window.rect.w, 
02625                         item->window.rect.h, 
02626                         item->window.background );
02627         }
02628 
02629         item = Menu_FindItemByName(menuHUD, "rightframe");
02630 
02631         if (item)
02632         {
02633                 trap_R_SetColor( item->window.foreColor );
02634                 CG_DrawPic( 
02635                         item->window.rect.x, 
02636                         item->window.rect.y, 
02637                         item->window.rect.w, 
02638                         item->window.rect.h, 
02639                         item->window.background );
02640         }
02641 
02642 
02643         CG_DrawVehicleArmor( menuHUD, veh );
02644 
02645         // Get animal hud for speed
02646 //      if (veh->m_pVehicle->m_pVehicleInfo->type == VH_ANIMAL)
02647 //      {
02648 //              menuHUD = Menus_FindByName("tauntaunhud");
02649 //      }
02650         
02651 
02652         CG_DrawVehicleSpeed( menuHUD, veh );
02653 
02654         // Revert to swoophud
02655 //      if (veh->m_pVehicle->m_pVehicleInfo->type == VH_ANIMAL)
02656 //      {
02657 //              menuHUD = Menus_FindByName("swoopvehiclehud");
02658 //      }
02659 
02660 //      if (veh->m_pVehicle->m_pVehicleInfo->type == VH_ANIMAL)
02661 //      {
02662                 shieldPerc = CG_DrawVehicleShields( menuHUD, veh );
02663 //      }
02664 
02665         if (veh->m_pVehicle->m_pVehicleInfo->weapon[0].ID && !veh->m_pVehicle->m_pVehicleInfo->weapon[1].ID)
02666         {
02667                 CG_DrawVehicleAmmo( menuHUD, veh );
02668         }
02669         else if (veh->m_pVehicle->m_pVehicleInfo->weapon[0].ID && veh->m_pVehicle->m_pVehicleInfo->weapon[1].ID)
02670         {
02671                 CG_DrawVehicleAmmoUpper( menuHUD, veh );
02672                 CG_DrawVehicleAmmoLower( menuHUD, veh );
02673         }
02674 
02675         // If he's hidden, he must be in a vehicle
02676         if (veh->m_pVehicle->m_pVehicleInfo->hideRider)
02677         {
02678                 CG_DrawVehicleDamageHUD(veh,cg.predictedVehicleState.brokenLimbs,shieldPerc,"vehicledamagehud",1.0f);
02679 
02680                 // Has he targeted an enemy?
02681                 if (CG_CheckTargetVehicle( &veh, &alpha ))
02682                 {
02683                         CG_DrawVehicleDamageHUD(veh,veh->currentState.brokenLimbs,((float)veh->currentState.activeForcePass/10.0f),"enemyvehicledamagehud",alpha);
02684                 }
02685 
02686                 return qfalse;  // Don't draw player HUD
02687         }
02688 
02689         return qtrue;   // Draw player HUD
02690 
02691 }
02692 
02693 /*
02694 ================
02695 CG_DrawStats
02696 
02697 ================
02698 */
02699 static void CG_DrawStats( void ) 
02700 {
02701         centity_t               *cent;
02702         playerState_t   *ps;
02703         qboolean                drawHUD = qtrue;
02704 /*      playerState_t   *ps;
02705         vec3_t                  angles;
02706 //      vec3_t          origin;
02707 
02708         if ( cg_drawStatus.integer == 0 ) {
02709                 return;
02710         }
02711 */
02712         cent = &cg_entities[cg.snap->ps.clientNum];
02713 /*      ps = &cg.snap->ps;
02714 
02715         VectorClear( angles );
02716 
02717         // Do start
02718         if (!cg.interfaceStartupDone)
02719         {
02720                 CG_InterfaceStartup();
02721         }
02722 
02723         cgi_UI_MenuPaintAll();*/
02724 
02725         if ( cent )
02726         {
02727                 ps = &cg.predictedPlayerState;
02728 
02729                 if ( (ps->m_iVehicleNum ) )     // In a vehicle???
02730                 {
02731                         drawHUD = CG_DrawVehicleHud( cent );
02732                 }
02733         }
02734 
02735         if (drawHUD)
02736         {
02737                 CG_DrawHUD(cent);
02738         }
02739 
02740         /*CG_DrawArmor(cent);
02741         CG_DrawHealth(cent);
02742         CG_DrawAmmo(cent);
02743 
02744         CG_DrawTalk(cent);*/
02745 }
02746 
02747 /*
02748 ===================
02749 CG_DrawPickupItem
02750 ===================
02751 */
02752 static void CG_DrawPickupItem( void ) {
02753         int             value;
02754         float   *fadeColor;
02755 
02756         value = cg.itemPickup;
02757         if ( value && cg_items[ value ].icon != -1 ) 
02758         {
02759                 fadeColor = CG_FadeColor( cg.itemPickupTime, 3000 );
02760                 if ( fadeColor ) 
02761                 {
02762                         CG_RegisterItemVisuals( value );
02763                         trap_R_SetColor( fadeColor );
02764                         CG_DrawPic( 573, 320, ICON_SIZE, ICON_SIZE, cg_items[ value ].icon );
02765                         trap_R_SetColor( NULL );
02766                 }
02767         }
02768 }
02769 
02770 /*
02771 ================
02772 CG_DrawTeamBackground
02773 
02774 ================
02775 */
02776 void CG_DrawTeamBackground( int x, int y, int w, int h, float alpha, int team )
02777 {
02778         vec4_t          hcolor;
02779 
02780         hcolor[3] = alpha;
02781         if ( team == TEAM_RED ) {
02782                 hcolor[0] = 1;
02783                 hcolor[1] = .2f;
02784                 hcolor[2] = .2f;
02785         } else if ( team == TEAM_BLUE ) {
02786                 hcolor[0] = .2f;
02787                 hcolor[1] = .2f;
02788                 hcolor[2] = 1;
02789         } else {
02790                 return;
02791         }
02792 //      trap_R_SetColor( hcolor );
02793 
02794         CG_FillRect ( x, y, w, h, hcolor );
02795 //      CG_DrawPic( x, y, w, h, cgs.media.teamStatusBar );
02796         trap_R_SetColor( NULL );
02797 }
02798 
02799 
02800 /*
02801 ===========================================================================================
02802 
02803   UPPER RIGHT CORNER
02804 
02805 ===========================================================================================
02806 */
02807 
02808 /*
02809 ================
02810 CG_DrawMiniScoreboard
02811 ================
02812 */
02813 static float CG_DrawMiniScoreboard ( float y ) 
02814 {
02815         char temp[MAX_QPATH];
02816         int xOffset = 0;
02817 
02818 #ifdef _XBOX
02819         xOffset = -40;
02820 #endif
02821 
02822         if ( !cg_drawScores.integer )
02823         {
02824                 return y;
02825         }
02826 
02827         if (cgs.gametype == GT_SIEGE)
02828         { //don't bother with this in siege
02829                 return y;
02830         }
02831 
02832         if ( cgs.gametype >= GT_TEAM )
02833         {
02834                 strcpy ( temp, va("%s: ", CG_GetStringEdString("MP_INGAME", "RED")));
02835                 Q_strcat ( temp, MAX_QPATH, cgs.scores1==SCORE_NOT_PRESENT?"-":(va("%i",cgs.scores1)) );
02836                 Q_strcat ( temp, MAX_QPATH, va(" %s: ", CG_GetStringEdString("MP_INGAME", "BLUE")) );
02837                 Q_strcat ( temp, MAX_QPATH, cgs.scores2==SCORE_NOT_PRESENT?"-":(va("%i",cgs.scores2)) );
02838 
02839                 CG_Text_Paint( 630 - CG_Text_Width ( temp, 0.7f, FONT_MEDIUM ) + xOffset, y, 0.7f, colorWhite, temp, 0, 0, ITEM_TEXTSTYLE_SHADOWEDMORE, FONT_MEDIUM );
02840                 y += 15;
02841         }
02842         else
02843         {
02844                 /*
02845                 strcpy ( temp, "1st: " );
02846                 Q_strcat ( temp, MAX_QPATH, cgs.scores1==SCORE_NOT_PRESENT?"-":(va("%i",cgs.scores1)) );
02847                 
02848                 Q_strcat ( temp, MAX_QPATH, " 2nd: " );
02849                 Q_strcat ( temp, MAX_QPATH, cgs.scores2==SCORE_NOT_PRESENT?"-":(va("%i",cgs.scores2)) );
02850                 
02851                 CG_Text_Paint( 630 - CG_Text_Width ( temp, 0.7f, FONT_SMALL ), y, 0.7f, colorWhite, temp, 0, 0, ITEM_TEXTSTYLE_SHADOWEDMORE, FONT_MEDIUM );
02852                 y += 15;
02853                 */
02854                 //rww - no longer doing this. Since the attacker now shows who is first, we print the score there.
02855         }               
02856         
02857 
02858         return y;
02859 }
02860 
02861 /*
02862 ================
02863 CG_DrawEnemyInfo
02864 ================
02865 */
02866 static float CG_DrawEnemyInfo ( float y ) 
02867 {
02868         float           size;
02869         int                     clientNum;
02870         const char      *title;
02871         clientInfo_t    *ci;
02872         int xOffset = 0;
02873 
02874         if (!cg.snap)
02875         {
02876                 return y;
02877         }
02878 
02879 #ifdef _XBOX
02880         xOffset = -40;
02881 #endif
02882 
02883         if ( !cg_drawEnemyInfo.integer ) 
02884         {
02885                 return y;
02886         }
02887 
02888         if ( cg.predictedPlayerState.stats[STAT_HEALTH] <= 0 ) 
02889         {
02890                 return y;
02891         }
02892         
02893         if (cgs.gametype == GT_POWERDUEL)
02894         { //just get out of here then
02895                 return y;
02896         }
02897 
02898         if ( cgs.gametype == GT_JEDIMASTER )
02899         {
02900                 //title = "Jedi Master";
02901                 title = CG_GetStringEdString("MP_INGAME", "MASTERY7");
02902                 clientNum = cgs.jediMaster;
02903 
02904                 if ( clientNum < 0 )
02905                 {
02906                         //return y;
02907 //                      title = "Get Saber!";
02908                         title = CG_GetStringEdString("MP_INGAME", "GET_SABER");
02909 
02910 
02911                         size = ICON_SIZE * 1.25;
02912                         y += 5;
02913 
02914                         CG_DrawPic( 640 - size - 12 + xOffset, y, size, size, cgs.media.weaponIcons[WP_SABER] );
02915 
02916                         y += size;
02917 
02918                         /*
02919                         CG_Text_Paint( 630 - CG_Text_Width ( ci->name, 0.7f, FONT_MEDIUM ), y, 0.7f, colorWhite, ci->name, 0, 0, 0, FONT_MEDIUM );
02920                         y += 15;
02921                         */
02922 
02923                         CG_Text_Paint( 630 - CG_Text_Width ( title, 0.7f, FONT_MEDIUM ) + xOffset, y, 0.7f, colorWhite, title, 0, 0, 0, FONT_MEDIUM );
02924 
02925                         return y + BIGCHAR_HEIGHT + 2;
02926                 }
02927         }
02928         else if ( cg.snap->ps.duelInProgress )
02929         {
02930 //              title = "Dueling";
02931                 title = CG_GetStringEdString("MP_INGAME", "DUELING");
02932                 clientNum = cg.snap->ps.duelIndex;
02933         }
02934         else if ( cgs.gametype == GT_DUEL && cgs.clientinfo[cg.snap->ps.clientNum].team != TEAM_SPECTATOR)
02935         {
02936                 title = CG_GetStringEdString("MP_INGAME", "DUELING");
02937                 if (cg.snap->ps.clientNum == cgs.duelist1)
02938                 {
02939                         clientNum = cgs.duelist2; //if power duel, should actually draw both duelists 2 and 3 I guess
02940                 }
02941                 else if (cg.snap->ps.clientNum == cgs.duelist2)
02942                 {
02943                         clientNum = cgs.duelist1;
02944                 }
02945                 else if (cg.snap->ps.clientNum == cgs.duelist3)
02946                 {
02947                         clientNum = cgs.duelist1;
02948                 }
02949                 else
02950                 {
02951                         return y;
02952                 }
02953         }
02954         else
02955         {
02956                 /*
02957                 title = "Attacker";
02958                 clientNum = cg.predictedPlayerState.persistant[PERS_ATTACKER];
02959 
02960                 if ( clientNum < 0 || clientNum >= MAX_CLIENTS || clientNum == cg.snap->ps.clientNum ) 
02961                 {
02962                         return y;
02963                 }
02964 
02965                 if ( cg.time - cg.attackerTime > ATTACKER_HEAD_TIME ) 
02966                 {
02967                         cg.attackerTime = 0;
02968                         return y;
02969                 }
02970                 */
02971                 //As of current, we don't want to draw the attacker. Instead, draw whoever is in first place.
02972                 if (cgs.duelWinner < 0 || cgs.duelWinner >= MAX_CLIENTS)
02973                 {
02974                         return y;
02975                 }
02976 
02977 
02978                 title = va("%s: %i",CG_GetStringEdString("MP_INGAME", "LEADER"), cgs.scores1);
02979 
02980                 /*
02981                 if (cgs.scores1 == 1)
02982                 {
02983                         title = va("%i kill", cgs.scores1);
02984                 }
02985                 else
02986                 {
02987                         title = va("%i kills", cgs.scores1);
02988                 }
02989                 */
02990                 clientNum = cgs.duelWinner;
02991         }
02992 
02993         if ( clientNum >= MAX_CLIENTS || !(&cgs.clientinfo[ clientNum ]) )
02994         {
02995                 return y;
02996         }
02997 
02998         ci = &cgs.clientinfo[ clientNum ];
02999 
03000         size = ICON_SIZE * 1.25;
03001         y += 5;
03002 
03003         if ( ci->modelIcon )
03004         {
03005                 CG_DrawPic( 640 - size - 5 + xOffset, y, size, size, ci->modelIcon );
03006         }
03007 
03008         y += size;
03009 
03010 //      CG_Text_Paint( 630 - CG_Text_Width ( ci->name, 0.7f, FONT_MEDIUM ) + xOffset, y, 0.7f, colorWhite, ci->name, 0, 0, 0, FONT_MEDIUM );
03011         CG_Text_Paint( 630 - CG_Text_Width ( ci->name, 1.0f, FONT_SMALL2 ) + xOffset, y, 1.0f, colorWhite, ci->name, 0, 0, 0, FONT_SMALL2 );
03012 
03013         y += 15;
03014 //      CG_Text_Paint( 630 - CG_Text_Width ( title, 0.7f, FONT_MEDIUM ) + xOffset, y, 0.7f, colorWhite, title, 0, 0, 0, FONT_MEDIUM );
03015         CG_Text_Paint( 630 - CG_Text_Width ( title, 1.0f, FONT_SMALL2 ) + xOffset, y, 1.0f, colorWhite, title, 0, 0, 0, FONT_SMALL2 );
03016 
03017         if ( (cgs.gametype == GT_DUEL || cgs.gametype == GT_POWERDUEL) && cgs.clientinfo[cg.snap->ps.clientNum].team != TEAM_SPECTATOR)
03018         {//also print their score
03019                 char text[1024];
03020                 y += 15;
03021                 Com_sprintf(text, sizeof(text), "%i/%i", cgs.clientinfo[clientNum].score, cgs.fraglimit );
03022                 CG_Text_Paint( 630 - CG_Text_Width ( text, 0.7f, FONT_MEDIUM ) + xOffset, y, 0.7f, colorWhite, text, 0, 0, 0, FONT_MEDIUM );
03023         }
03024 
03025 // nmckenzie: DUEL_HEALTH - fixme - need checks and such here.  And this is coded to duelist 1 right now, which is wrongly.
03026         if ( cgs.showDuelHealths >= 2)
03027         {
03028                 y += 15;
03029                 if ( cgs.duelist1 == clientNum )
03030                 {
03031                         CG_DrawDuelistHealth ( 640 - size - 5 + xOffset, y, 64, 8, 1 );
03032                 }
03033                 else if ( cgs.duelist2 == clientNum )
03034                 {
03035                         CG_DrawDuelistHealth ( 640 - size - 5 + xOffset, y, 64, 8, 2 );
03036                 }
03037         }
03038 
03039         return y + BIGCHAR_HEIGHT + 2;
03040 }
03041 
03042 /*
03043 ==================
03044 CG_DrawSnapshot
03045 ==================
03046 */
03047 static float CG_DrawSnapshot( float y ) {
03048         char            *s;
03049         int                     w;
03050         int                     xOffset = 0;
03051 
03052 #ifdef _XBOX
03053         xOffset = -40;
03054 #endif
03055 
03056         s = va( "time:%i snap:%i cmd:%i", cg.snap->serverTime, 
03057                 cg.latestSnapshotNum, cgs.serverCommandSequence );
03058         w = CG_DrawStrlen( s ) * BIGCHAR_WIDTH;
03059 
03060         CG_DrawBigString( 635 - w + xOffset, y + 2, s, 1.0F);
03061 
03062         return y + BIGCHAR_HEIGHT + 4;
03063 }
03064 
03065 /*
03066 ==================
03067 CG_DrawFPS
03068 ==================
03069 */
03070 #define FPS_FRAMES      16
03071 static float CG_DrawFPS( float y ) {
03072         char            *s;
03073         int                     w;
03074         static unsigned short previousTimes[FPS_FRAMES];
03075         static unsigned short index;
03076         static int      previous, lastupdate;
03077         int             t, i, fps, total;
03078         unsigned short frameTime;
03079 #ifdef _XBOX
03080         const int               xOffset = -40;
03081 #else
03082         const int               xOffset = 0;
03083 #endif
03084 
03085 
03086         // don't use serverTime, because that will be drifting to
03087         // correct for internet lag changes, timescales, timedemos, etc
03088         t = trap_Milliseconds();
03089         frameTime = t - previous;
03090         previous = t;
03091         if (t - lastupdate > 50)        //don't sample faster than this
03092         {
03093                 lastupdate = t;
03094                 previousTimes[index % FPS_FRAMES] = frameTime;
03095                 index++;
03096         }
03097         // average multiple frames together to smooth changes out a bit
03098         total = 0;
03099         for ( i = 0 ; i < FPS_FRAMES ; i++ ) {
03100                 total += previousTimes[i];
03101         }
03102         if ( !total ) {
03103                 total = 1;
03104         }
03105         fps = 1000 * FPS_FRAMES / total;
03106 
03107         s = va( "%ifps", fps );
03108         w = CG_DrawStrlen( s ) * BIGCHAR_WIDTH;
03109 
03110         CG_DrawBigString( 635 - w + xOffset, y + 2, s, 1.0F);
03111 
03112         return y + BIGCHAR_HEIGHT + 4;
03113 }
03114 
03115 // nmckenzie: DUEL_HEALTH
03116 #define MAX_HEALTH_FOR_IFACE    100
03117 void CG_DrawHealthBarRough (float x, float y, int width, int height, float ratio, const float *color1, const float *color2)
03118 {
03119         float midpoint, remainder;
03120         float color3[4] = {1, 0, 0, .7f};
03121 
03122         midpoint = width * ratio - 1;
03123         remainder = width - midpoint;
03124         color3[0] = color1[0] * 0.5f;
03125 
03126         assert(!(height%4));//this won't line up otherwise.
03127         CG_DrawRect(x + 1,                      y + height/2-1,  midpoint,      1,         height/4+1,  color1);        // creme-y filling.
03128         CG_DrawRect(x + midpoint,       y + height/2-1,  remainder,     1,         height/4+1,  color3);        // used-up-ness.
03129         CG_DrawRect(x,                          y,                               width,         height, 1,                      color2);        // hard crispy shell
03130 }
03131 
03132 void CG_DrawDuelistHealth ( float x, float y, float w, float h, int duelist )
03133 {
03134         float   duelHealthColor[4] = {1, 0, 0, 0.7f};
03135         float   healthSrc = 0.0f;
03136         float   ratio;
03137 
03138         if ( duelist == 1 )
03139         {
03140                 healthSrc = cgs.duelist1health;
03141         }
03142         else if (duelist == 2 )
03143         {
03144                 healthSrc = cgs.duelist2health;
03145         }
03146 
03147         ratio = healthSrc / MAX_HEALTH_FOR_IFACE;
03148         if ( ratio > 1.0f )
03149         {
03150                 ratio = 1.0f;
03151         }
03152         if ( ratio < 0.0f )
03153         {
03154                 ratio = 0.0f;
03155         }
03156         duelHealthColor[0] = (ratio * 0.2f) + 0.5f;
03157 
03158         CG_DrawHealthBarRough (x, y, w, h, ratio, duelHealthColor, colorTable[CT_WHITE]);       // new art for this?  I'm not crazy about how this looks.
03159 }
03160 
03161 /*
03162 =====================
03163 CG_DrawRadar
03164 =====================
03165 */
03166 //#define RADAR_RANGE                           2500
03167 float   cg_radarRange = 2500.0f;
03168 
03169 #define RADAR_RADIUS                    60
03170 #define RADAR_X                                 (580 - RADAR_RADIUS)
03171 //#define RADAR_Y                                       10 //dynamic based on passed Y val
03172 #define RADAR_CHAT_DURATION             6000
03173 static int radarLockSoundDebounceTime = 0;
03174 static int impactSoundDebounceTime = 0;
03175 #define RADAR_MISSILE_RANGE                                     3000.0f
03176 #define RADAR_ASTEROID_RANGE                            10000.0f
03177 #define RADAR_MIN_ASTEROID_SURF_WARN_DIST       1200.0f
03178 
03179 float CG_DrawRadar ( float y )
03180 {
03181         vec4_t                  color;
03182         vec4_t                  teamColor;
03183         float                   arrow_w;
03184         float                   arrow_h;
03185         clientInfo_t    *cl;
03186         clientInfo_t    *local;
03187         int                             i;
03188         float                   arrowBaseScale;
03189         float                   zScale;
03190         int                             xOffset = 0;
03191 
03192         if (!cg.snap)
03193         {
03194                 return y;
03195         }
03196 
03197 #ifdef _XBOX
03198         xOffset = -40;
03199 #endif
03200 
03201         // Make sure the radar should be showing
03202         if ( cg.snap->ps.stats[STAT_HEALTH] <= 0 )
03203         {
03204                 return y;
03205         }
03206 
03207         if ( (cg.predictedPlayerState.pm_flags & PMF_FOLLOW) || cg.predictedPlayerState.persistant[PERS_TEAM] == TEAM_SPECTATOR )
03208         {
03209                 return y;
03210         }
03211 
03212         local = &cgs.clientinfo[ cg.snap->ps.clientNum ];
03213         if ( !local->infoValid )
03214         {
03215                 return y;
03216         }
03217 
03218         // Draw the radar background image
03219         color[0] = color[1] = color[2] = 1.0f;
03220         color[3] = 0.6f;
03221         trap_R_SetColor ( color );
03222         CG_DrawPic( RADAR_X + xOffset, y, RADAR_RADIUS*2, RADAR_RADIUS*2, cgs.media.radarShader );
03223 
03224         //Always green for your own team.
03225         VectorCopy ( g_color_table[ColorIndex(COLOR_GREEN)], teamColor );
03226         teamColor[3] = 1.0f;
03227 
03228         // Draw all of the radar entities.  Draw them backwards so players are drawn last
03229         for ( i = cg.radarEntityCount -1 ; i >= 0 ; i-- ) 
03230         {       
03231                 vec3_t          dirLook;        
03232                 vec3_t          dirPlayer;
03233                 float           angleLook;
03234                 float           anglePlayer;
03235                 float           angle;
03236                 float           distance, actualDist;
03237                 centity_t*      cent;
03238 
03239                 cent = &cg_entities[cg.radarEntities[i]];
03240 
03241                 // Get the distances first
03242                 VectorSubtract ( cg.predictedPlayerState.origin, cent->lerpOrigin, dirPlayer );         
03243                 dirPlayer[2] = 0;
03244                 actualDist = distance = VectorNormalize ( dirPlayer );
03245 
03246                 if ( distance > cg_radarRange * 0.8f) 
03247                 {
03248                         if ( (cent->currentState.eFlags & EF_RADAROBJECT)//still want to draw the direction
03249                                 || ( cent->currentState.eType==ET_NPC//FIXME: draw last, with players...
03250                                         && cent->currentState.NPC_class == CLASS_VEHICLE 
03251                                         && cent->currentState.speed > 0 ) )//always draw vehicles
03252                         { 
03253                                 distance = cg_radarRange*0.8f;
03254                         }
03255                         else
03256                         {
03257                                 continue;
03258                         }
03259                 }
03260 
03261                 distance  = distance / cg_radarRange;
03262                 distance *= RADAR_RADIUS;
03263 
03264                 AngleVectors ( cg.predictedPlayerState.viewangles, dirLook, NULL, NULL );
03265 
03266                 dirLook[2] = 0;
03267                 anglePlayer = atan2(dirPlayer[0],dirPlayer[1]);         
03268                 VectorNormalize ( dirLook );
03269                 angleLook = atan2(dirLook[0],dirLook[1]);
03270                 angle = angleLook - anglePlayer;
03271 
03272                 switch ( cent->currentState.eType )
03273                 {
03274                         default:
03275                                 {
03276                                         float  x;
03277                                         float  ly;
03278                                         qhandle_t shader;
03279                                         vec4_t    color;
03280 
03281                                         x = (float)RADAR_X + (float)RADAR_RADIUS + (float)sin (angle) * distance;
03282                                         ly = y + (float)RADAR_RADIUS + (float)cos (angle) * distance;
03283 
03284                                         arrowBaseScale = 9.0f;
03285                                         shader = 0;
03286                                         zScale = 1.0f;
03287 
03288                                         //we want to scale the thing up/down based on the relative Z (up/down) positioning
03289                                         if (cent->lerpOrigin[2] > cg.predictedPlayerState.origin[2])
03290                                         { //higher, scale up (between 16 and 24)
03291                                                 float dif = (cent->lerpOrigin[2] - cg.predictedPlayerState.origin[2]);
03292                                                 
03293                                                 //max out to 1.5x scale at 512 units above local player's height
03294                                                 dif /= 1024.0f;
03295                                                 if (dif > 0.5f)
03296                                                 {
03297                                                         dif = 0.5f;
03298                                                 }
03299                                                 zScale += dif;
03300                                         }
03301                                         else if (cent->lerpOrigin[2] < cg.predictedPlayerState.origin[2])
03302                                         { //lower, scale down (between 16 and 8)
03303                                                 float dif = (cg.predictedPlayerState.origin[2] - cent->lerpOrigin[2]);
03304 
03305                                                 //half scale at 512 units below local player's height
03306                                                 dif /= 1024.0f;
03307                                                 if (dif > 0.5f)
03308                                                 {
03309                                                         dif = 0.5f;
03310                                                 }
03311                                                 zScale -= dif;
03312                                         }
03313 
03314                                         arrowBaseScale *= zScale;
03315 
03316                                         if (cent->currentState.brokenLimbs)
03317                                         { //slightly misleading to use this value, but don't want to add more to entstate.
03318                                                 //any ent with brokenLimbs non-0 and on radar is an objective ent.
03319                                                 //brokenLimbs is literal team value.
03320                                                 char objState[1024];
03321                                                 int complete;
03322 
03323                                                 //we only want to draw it if the objective for it is not complete.
03324                                                 //frame represents objective num.
03325                                                 trap_Cvar_VariableStringBuffer(va("team%i_objective%i", cent->currentState.brokenLimbs, cent->currentState.frame), objState, 1024);
03326 
03327                                                 complete = atoi(objState);
03328 
03329                                                 if (!complete)
03330                                                 {
03331                                                 
03332                                                         // generic enemy index specifies a shader to use for the radar entity.
03333                                                         if ( cent->currentState.genericenemyindex )
03334                                                         {
03335                                                                 color[0] = color[1] = color[2] = color[3] = 1.0f;
03336                                                                 shader = cgs.gameIcons[cent->currentState.genericenemyindex];
03337                                                         }
03338                                                         else
03339                                                         {
03340                                                                 if (cg.snap &&
03341                                                                         cent->currentState.brokenLimbs == cg.snap->ps.persistant[PERS_TEAM])
03342                                                                 {
03343                                                                         VectorCopy ( g_color_table[ColorIndex(COLOR_RED)], color );
03344                                                                 }
03345                                                                 else
03346                                                                 {
03347                                                                         VectorCopy ( g_color_table[ColorIndex(COLOR_GREEN)], color );
03348                                                                 }
03349 
03350                                                                 shader = cgs.media.siegeItemShader;
03351                                                         }
03352                                                 }
03353                                         }
03354                                         else
03355                                         {
03356                                                 color[0] = color[1] = color[2] = color[3] = 1.0f;
03357                                                 
03358                                                 // generic enemy index specifies a shader to use for the radar entity.
03359                                                 if ( cent->currentState.genericenemyindex )
03360                                                 {
03361                                                         shader = cgs.gameIcons[cent->currentState.genericenemyindex];
03362                                                 }
03363                                                 else
03364                                                 {
03365                                                         shader = cgs.media.siegeItemShader;
03366                                                 }
03367                                         
03368                                         }
03369 
03370                                         if ( shader )
03371                                         {
03372                                                 // Pulse the alpha if time2 is set.  time2 gets set when the entity takes pain
03373                                                 if ( (cent->currentState.time2 && cg.time - cent->currentState.time2 < 5000) ||
03374                                                         (cent->currentState.time2 == 0xFFFFFFFF) )
03375                                                 {                                                               
03376                                                         if ( (cg.time / 200) & 1 )
03377                                                         {
03378                                                                 color[3] = 0.1f + 0.9f * (float) (cg.time % 200) / 200.0f;
03379                                                         }
03380                                                         else
03381                                                         {
03382                                                                 color[3] = 1.0f - 0.9f * (float) (cg.time % 200) / 200.0f;
03383                                                         }                                       
03384                                                 }
03385 
03386                                                 trap_R_SetColor ( color );
03387                                                 CG_DrawPic ( x - 4 + xOffset, ly - 4, arrowBaseScale, arrowBaseScale, shader );
03388                                         }
03389                                 }
03390                                 break;
03391 
03392                         case ET_NPC://FIXME: draw last, with players...
03393                                 if ( cent->currentState.NPC_class == CLASS_VEHICLE 
03394                                         && cent->currentState.speed > 0 )
03395                                 {
03396                                         if ( cent->m_pVehicle && cent->m_pVehicle->m_pVehicleInfo->radarIconHandle )
03397                                         {
03398                                                 float  x;
03399                                                 float  ly;
03400                         
03401                                                 x = (float)RADAR_X + (float)RADAR_RADIUS + (float)sin (angle) * distance;
03402                                                 ly = y + (float)RADAR_RADIUS + (float)cos (angle) * distance;
03403 
03404                                                 arrowBaseScale = 9.0f;
03405                                                 zScale = 1.0f;
03406 
03407                                                 //we want to scale the thing up/down based on the relative Z (up/down) positioning
03408                                                 if (cent->lerpOrigin[2] > cg.predictedPlayerState.origin[2])
03409                                                 { //higher, scale up (between 16 and 24)
03410                                                         float dif = (cent->lerpOrigin[2] - cg.predictedPlayerState.origin[2]);
03411                                                         
03412                                                         //max out to 1.5x scale at 512 units above local player's height
03413                                                         dif /= 4096.0f;
03414                                                         if (dif > 0.5f)
03415                                                         {
03416                                                                 dif = 0.5f;
03417                                                         }
03418                                                         zScale += dif;
03419                                                 }
03420                                                 else if (cent->lerpOrigin[2] < cg.predictedPlayerState.origin[2])
03421                                                 { //lower, scale down (between 16 and 8)
03422                                                         float dif = (cg.predictedPlayerState.origin[2] - cent->lerpOrigin[2]);
03423 
03424                                                         //half scale at 512 units below local player's height
03425                                                         dif /= 4096.0f;
03426                                                         if (dif > 0.5f)
03427                                                         {
03428                                                                 dif = 0.5f;
03429                                                         }
03430                                                         zScale -= dif;
03431                                                 }
03432 
03433                                                 arrowBaseScale *= zScale;
03434 
03435                                                 if ( cent->currentState.m_iVehicleNum //vehicle has a driver
03436                                                         && cgs.clientinfo[ cent->currentState.m_iVehicleNum-1 ].infoValid )
03437                                                 {
03438                                                         if ( cgs.clientinfo[ cent->currentState.m_iVehicleNum-1 ].team == local->team )
03439                                                         {
03440                                                                 trap_R_SetColor ( teamColor );
03441                                                         }
03442                                                         else
03443                                                         {
03444                                                                 trap_R_SetColor ( g_color_table[ColorIndex(COLOR_RED)] );
03445                                                         }
03446                                                 }
03447                                                 else
03448                                                 {
03449                                                         trap_R_SetColor ( NULL );
03450                                                 }
03451                                                 CG_DrawPic ( x - 4 + xOffset, ly - 4, arrowBaseScale, arrowBaseScale, cent->m_pVehicle->m_pVehicleInfo->radarIconHandle );
03452                                         }
03453                                 }
03454                                 break; //maybe do something?
03455 
03456                         case ET_MOVER:
03457                                 if ( cent->currentState.speed//the mover's size, actually
03458                                         && actualDist < (cent->currentState.speed+RADAR_ASTEROID_RANGE)
03459                                         && cg.predictedPlayerState.m_iVehicleNum )
03460                                 {//a mover that's close to me and I'm in a vehicle
03461                                         qboolean mayImpact = qfalse;
03462                                         float surfaceDist = (actualDist-cent->currentState.speed);
03463                                         if ( surfaceDist < 0.0f )
03464                                         {
03465                                                 surfaceDist = 0.0f;
03466                                         }
03467                                         if ( surfaceDist < RADAR_MIN_ASTEROID_SURF_WARN_DIST )
03468                                         {//always warn!
03469                                                 mayImpact = qtrue;
03470                                         }
03471                                         else
03472                                         {//not close enough to always warn, yet, so check its direction
03473                                                 vec3_t  asteroidPos, myPos, moveDir;
03474                                                 int             predictTime, timeStep = 500;
03475                                                 float   newDist;
03476                                                 for ( predictTime = timeStep; predictTime < 5000; predictTime+=timeStep )
03477                                                 {
03478                                                         //asteroid dir, speed, size, + my dir & speed...
03479                                                         BG_EvaluateTrajectory( &cent->currentState.pos, cg.time+predictTime, asteroidPos );
03480                                                         //FIXME: I don't think it's calcing "myPos" correctly
03481                                                         AngleVectors( cg.predictedVehicleState.viewangles, moveDir, NULL, NULL );
03482                                                         VectorMA( cg.predictedVehicleState.origin, cg.predictedVehicleState.speed*predictTime/1000.0f, moveDir, myPos );
03483                                                         newDist = Distance( myPos, asteroidPos );
03484                                                         if ( (newDist-cent->currentState.speed) <= RADAR_MIN_ASTEROID_SURF_WARN_DIST )//200.0f )
03485                                                         {//heading for an impact within the next 5 seconds
03486                                                                 mayImpact = qtrue;
03487                                                                 break;
03488                                                         }
03489                                                 }
03490                                         }
03491                                         if ( mayImpact )
03492                                         {//possible collision
03493                                                 vec4_t  asteroidColor = {0.5f,0.5f,0.5f,1.0f};
03494                                                 float  x;
03495                                                 float  ly;
03496                                                 float asteroidScale = (cent->currentState.speed/2000.0f);//average asteroid radius?
03497                                                 if ( actualDist > RADAR_ASTEROID_RANGE )
03498                                                 {
03499                                                         actualDist = RADAR_ASTEROID_RANGE;
03500                                                 }
03501                                                 distance = (actualDist/RADAR_ASTEROID_RANGE)*RADAR_RADIUS;
03502 
03503                                                 x = (float)RADAR_X + (float)RADAR_RADIUS + (float)sin (angle) * distance;
03504                                                 ly = y + (float)RADAR_RADIUS + (float)cos (angle) * distance;
03505                                                 
03506                                                 if ( asteroidScale > 3.0f )
03507                                                 {
03508                                                         asteroidScale = 3.0f;
03509                                                 }
03510                                                 else if ( asteroidScale < 0.2f )
03511                                                 {
03512                                                         asteroidScale = 0.2f;
03513                                                 }
03514                                                 arrowBaseScale = (9.0f*asteroidScale);
03515                                                 if ( impactSoundDebounceTime < cg.time )
03516                                                 {
03517                                                         vec3_t  soundOrg;
03518                                                         if ( surfaceDist > RADAR_ASTEROID_RANGE*0.66f )
03519                                                         {
03520                                                                 impactSoundDebounceTime = cg.time + 1000;
03521                                                         }
03522                                                         else if ( surfaceDist > RADAR_ASTEROID_RANGE/3.0f )
03523                                                         {
03524                                                                 impactSoundDebounceTime = cg.time + 400;
03525                                                         }
03526                                                         else 
03527                                                         {
03528                                                                 impactSoundDebounceTime = cg.time + 100;
03529                                                         }
03530                                                         VectorMA( cg.refdef.vieworg, -500.0f*(surfaceDist/RADAR_ASTEROID_RANGE), dirPlayer, soundOrg );
03531                                                         trap_S_StartSound( soundOrg, ENTITYNUM_WORLD, CHAN_AUTO, trap_S_RegisterSound( "sound/vehicles/common/impactalarm.wav" ) );
03532                                                 }
03533                                                 //brighten it the closer it is
03534                                                 if ( surfaceDist > RADAR_ASTEROID_RANGE*0.66f )
03535                                                 {
03536                                                         asteroidColor[0] = asteroidColor[1] = asteroidColor[2] = 0.7f;
03537                                                 }
03538                                                 else if ( surfaceDist > RADAR_ASTEROID_RANGE/3.0f )
03539                                                 {
03540                                                         asteroidColor[0] = asteroidColor[1] = asteroidColor[2] = 0.85f;
03541                                                 }
03542                                                 else 
03543                                                 {
03544                                                         asteroidColor[0] = asteroidColor[1] = asteroidColor[2] = 1.0f;
03545                                                 }
03546                                                 //alpha out the longer it's been since it was considered dangerous
03547                                                 if ( (cg.time-impactSoundDebounceTime) > 100 )
03548                                                 {
03549                                                         asteroidColor[3] = (float)((cg.time-impactSoundDebounceTime)-100)/900.0f;
03550                                                 }
03551 
03552                                                 trap_R_SetColor ( asteroidColor );
03553                                                 CG_DrawPic ( x - 4 + xOffset, ly - 4, arrowBaseScale, arrowBaseScale, trap_R_RegisterShaderNoMip( "gfx/menus/radar/asteroid" ) );
03554                                         }
03555                                 }
03556                                 break;
03557 
03558                         case ET_MISSILE:
03559                                 if ( //cent->currentState.weapon == WP_ROCKET_LAUNCHER &&//a rocket
03560                                         cent->currentState.owner > MAX_CLIENTS //belongs to an NPC
03561                                         && cg_entities[cent->currentState.owner].currentState.NPC_class == CLASS_VEHICLE )
03562                                 {//a rocket belonging to an NPC, FIXME: only tracking rockets!
03563                                         float  x;
03564                                         float  ly;
03565                 
03566                                         x = (float)RADAR_X + (float)RADAR_RADIUS + (float)sin (angle) * distance;
03567                                         ly = y + (float)RADAR_RADIUS + (float)cos (angle) * distance;
03568 
03569                                         arrowBaseScale = 3.0f;
03570                                         if ( cg.predictedPlayerState.m_iVehicleNum )
03571                                         {//I'm in a vehicle
03572                                                 //if it's targetting me, then play an alarm sound if I'm in a vehicle
03573                                                 if ( cent->currentState.otherEntityNum == cg.predictedPlayerState.clientNum || cent->currentState.otherEntityNum == cg.predictedPlayerState.m_iVehicleNum )
03574                                                 {
03575                                                         if ( radarLockSoundDebounceTime < cg.time )
03576                                                         {
03577                                                                 vec3_t  soundOrg;
03578                                                                 int             alarmSound;
03579                                                                 if ( actualDist > RADAR_MISSILE_RANGE * 0.66f )
03580                                                                 {
03581                                                                         radarLockSoundDebounceTime = cg.time + 1000;
03582                                                                         arrowBaseScale = 3.0f;
03583                                                                         alarmSound = trap_S_RegisterSound( "sound/vehicles/common/lockalarm1.wav" );
03584                                                                 }
03585                                                                 else if ( actualDist > RADAR_MISSILE_RANGE/3.0f )
03586                                                                 {
03587                                                                         radarLockSoundDebounceTime = cg.time + 500;
03588                                                                         arrowBaseScale = 6.0f;
03589                                                                         alarmSound = trap_S_RegisterSound( "sound/vehicles/common/lockalarm2.wav" );
03590                                                                 }
03591                                                                 else
03592                                                                 {
03593                                                                         radarLockSoundDebounceTime = cg.time + 250;
03594                                                                         arrowBaseScale = 9.0f;
03595                                                                         alarmSound = trap_S_RegisterSound( "sound/vehicles/common/lockalarm3.wav" );
03596                                                                 }
03597                                                                 if ( actualDist > RADAR_MISSILE_RANGE )
03598                                                                 {
03599                                                                         actualDist = RADAR_MISSILE_RANGE;
03600                                                                 }
03601                                                                 VectorMA( cg.refdef.vieworg, -500.0f*(actualDist/RADAR_MISSILE_RANGE), dirPlayer, soundOrg );
03602                                                                 trap_S_StartSound( soundOrg, ENTITYNUM_WORLD, CHAN_AUTO, alarmSound );
03603                                                         }
03604                                                 }
03605                                         }
03606                                         zScale = 1.0f;
03607 
03608                                         //we want to scale the thing up/down based on the relative Z (up/down) positioning
03609                                         if (cent->lerpOrigin[2] > cg.predictedPlayerState.origin[2])
03610                                         { //higher, scale up (between 16 and 24)
03611                                                 float dif = (cent->lerpOrigin[2] - cg.predictedPlayerState.origin[2]);
03612                                                 
03613                                                 //max out to 1.5x scale at 512 units above local player's height
03614                                                 dif /= 1024.0f;
03615                                                 if (dif > 0.5f)
03616                                                 {
03617                                                         dif = 0.5f;
03618                                                 }
03619                                                 zScale += dif;
03620                                         }
03621                                         else if (cent->lerpOrigin[2] < cg.predictedPlayerState.origin[2])
03622                                         { //lower, scale down (between 16 and 8)
03623                                                 float dif = (cg.predictedPlayerState.origin[2] - cent->lerpOrigin[2]);
03624 
03625                                                 //half scale at 512 units below local player's height
03626                                                 dif /= 1024.0f;
03627                                                 if (dif > 0.5f)
03628                                                 {
03629                                                         dif = 0.5f;
03630                                                 }
03631                                                 zScale -= dif;
03632                                         }
03633 
03634                                         arrowBaseScale *= zScale;
03635 
03636                                         if ( cent->currentState.owner >= MAX_CLIENTS//missile owned by an NPC
03637                                                 && cg_entities[cent->currentState.owner].currentState.NPC_class == CLASS_VEHICLE//NPC is a vehicle
03638                                                 && cg_entities[cent->currentState.owner].currentState.m_iVehicleNum <= MAX_CLIENTS//Vehicle has a player driver
03639                                                 && cgs.clientinfo[cg_entities[cent->currentState.owner].currentState.m_iVehicleNum-1].infoValid ) //player driver is valid
03640                                         {
03641                                                 cl = &cgs.clientinfo[cg_entities[cent->currentState.owner].currentState.m_iVehicleNum-1];
03642                                                 if ( cl->team == local->team )
03643                                                 {
03644                                                         trap_R_SetColor ( teamColor );
03645                                                 }
03646                                                 else
03647                                                 {
03648                                                         trap_R_SetColor ( g_color_table[ColorIndex(COLOR_RED)] );
03649                                                 }
03650                                         }
03651                                         else
03652                                         {
03653                                                 trap_R_SetColor ( NULL );
03654                                         }
03655                                         CG_DrawPic ( x - 4 + xOffset, ly - 4, arrowBaseScale, arrowBaseScale, cgs.media.mAutomapRocketIcon );
03656                                 }
03657                                 break;
03658 
03659                         case ET_PLAYER:
03660                         {
03661                                 vec4_t color;
03662 
03663                                 cl = &cgs.clientinfo[ cent->currentState.number ];
03664 
03665                                 // not valid then dont draw it
03666                                 if ( !cl->infoValid ) 
03667                                 {       
03668                                         continue;
03669                                 }
03670 
03671                                 VectorCopy4 ( teamColor, color );
03672 
03673                                 arrowBaseScale = 16.0f;
03674                                 zScale = 1.0f;
03675 
03676                                 // Pulse the radar icon after a voice message
03677                                 if ( cent->vChatTime + 2000 > cg.time )
03678                                 {
03679                                         float f = (cent->vChatTime + 2000 - cg.time) / 3000.0f;
03680                                         arrowBaseScale = 16.0f + 4.0f * f;
03681                                         color[0] = teamColor[0] + (1.0f - teamColor[0]) * f;
03682                                         color[1] = teamColor[1] + (1.0f - teamColor[1]) * f;
03683                                         color[2] = teamColor[2] + (1.0f - teamColor[2]) * f;
03684                                 }
03685 
03686                                 trap_R_SetColor ( color );
03687 
03688                                 //we want to scale the thing up/down based on the relative Z (up/down) positioning
03689                                 if (cent->lerpOrigin[2] > cg.predictedPlayerState.origin[2])
03690                                 { //higher, scale up (between 16 and 32)
03691                                         float dif = (cent->lerpOrigin[2] - cg.predictedPlayerState.origin[2]);
03692                                         
03693                                         //max out to 2x scale at 1024 units above local player's height
03694                                         dif /= 1024.0f;
03695                                         if (dif > 1.0f)
03696                                         {
03697                                                 dif = 1.0f;
03698                                         }
03699                                         zScale += dif;
03700                                 }
03701                 else if (cent->lerpOrigin[2] < cg.predictedPlayerState.origin[2])
03702                                 { //lower, scale down (between 16 and 8)
03703                                         float dif = (cg.predictedPlayerState.origin[2] - cent->lerpOrigin[2]);
03704 
03705                                         //half scale at 512 units below local player's height
03706                                         dif /= 1024.0f;
03707                                         if (dif > 0.5f)
03708                                         {
03709                                                 dif = 0.5f;
03710                                         }
03711                                         zScale -= dif;
03712                                 }
03713 
03714                                 arrowBaseScale *= zScale;
03715 
03716                                 arrow_w = arrowBaseScale * RADAR_RADIUS / 128;
03717                                 arrow_h = arrowBaseScale * RADAR_RADIUS / 128;
03718 
03719                                 CG_DrawRotatePic2( RADAR_X + RADAR_RADIUS + sin (angle) * distance + xOffset,
03720                                                                    y + RADAR_RADIUS + cos (angle) * distance, 
03721                                                                    arrow_w, arrow_h, 
03722                                                                    (360 - cent->lerpAngles[YAW]) + cg.predictedPlayerState.viewangles[YAW], cgs.media.mAutomapPlayerIcon );
03723                                 break;
03724                         }
03725                 }
03726         }
03727 
03728         arrowBaseScale = 16.0f;
03729 
03730         arrow_w = arrowBaseScale * RADAR_RADIUS / 128;
03731         arrow_h = arrowBaseScale * RADAR_RADIUS / 128;
03732 
03733         trap_R_SetColor ( colorWhite );
03734         CG_DrawRotatePic2( RADAR_X + RADAR_RADIUS + xOffset, y + RADAR_RADIUS, arrow_w, arrow_h, 
03735                                            0, cgs.media.mAutomapPlayerIcon );
03736 
03737         return y+(RADAR_RADIUS*2);
03738 }
03739 
03740 /*
03741 =================
03742 CG_DrawTimer
03743 =================
03744 */
03745 static float CG_DrawTimer( float y ) {
03746         char            *s;
03747         int                     w;
03748         int                     mins, seconds, tens;
03749         int                     msec;
03750         int                     xOffset = 0;
03751 
03752 #ifdef _XBOX
03753         xOffset = -40;
03754 #endif
03755 
03756         msec = cg.time - cgs.levelStartTime;
03757 
03758         seconds = msec / 1000;
03759         mins = seconds / 60;
03760         seconds -= mins * 60;
03761         tens = seconds / 10;
03762         seconds -= tens * 10;
03763 
03764         s = va( "%i:%i%i", mins, tens, seconds );
03765         w = CG_DrawStrlen( s ) * BIGCHAR_WIDTH;
03766 
03767         CG_DrawBigString( 635 - w + xOffset, y + 2, s, 1.0F);
03768 
03769         return y + BIGCHAR_HEIGHT + 4;
03770 }
03771 
03772 
03773 /*
03774 =================
03775 CG_DrawTeamOverlay
03776 =================
03777 */
03778 extern const char *CG_GetLocationString(const char *loc); //cg_main.c
03779 static float CG_DrawTeamOverlay( float y, qboolean right, qboolean upper ) {
03780         int x, w, h, xx;
03781         int i, j, len;
03782         const char *p;
03783         vec4_t          hcolor;
03784         int pwidth, lwidth;
03785         int plyrs;
03786         char st[16];
03787         clientInfo_t *ci;
03788         gitem_t *item;
03789         int ret_y, count;
03790         int xOffset = 0;
03791 
03792 #ifdef _XBOX
03793         xOffset = -40;
03794 #endif
03795 
03796         if ( !cg_drawTeamOverlay.integer ) {
03797                 return y;
03798         }
03799 
03800         if ( cg.snap->ps.persistant[PERS_TEAM] != TEAM_RED && cg.snap->ps.persistant[PERS_TEAM] != TEAM_BLUE ) {
03801                 return y; // Not on any team
03802         }
03803 
03804         plyrs = 0;
03805 
03806         // max player name width
03807         pwidth = 0;
03808         count = (numSortedTeamPlayers > 8) ? 8 : numSortedTeamPlayers;
03809         for (i = 0; i < count; i++) {
03810                 ci = cgs.clientinfo + sortedTeamPlayers[i];
03811                 if ( ci->infoValid && ci->team == cg.snap->ps.persistant[PERS_TEAM]) {
03812                         plyrs++;
03813                         len = CG_DrawStrlen(ci->name);
03814                         if (len > pwidth)
03815                                 pwidth = len;
03816                 }
03817         }
03818 
03819         if (!plyrs)
03820                 return y;
03821 
03822         if (pwidth > TEAM_OVERLAY_MAXNAME_WIDTH)
03823                 pwidth = TEAM_OVERLAY_MAXNAME_WIDTH;
03824 
03825         // max location name width
03826         lwidth = 0;
03827         for (i = 1; i < MAX_LOCATIONS; i++) {
03828                 p = CG_GetLocationString(CG_ConfigString(CS_LOCATIONS+i));
03829                 if (p && *p) {
03830                         len = CG_DrawStrlen(p);
03831                         if (len > lwidth)
03832                                 lwidth = len;
03833                 }
03834         }
03835 
03836         if (lwidth > TEAM_OVERLAY_MAXLOCATION_WIDTH)
03837                 lwidth = TEAM_OVERLAY_MAXLOCATION_WIDTH;
03838 
03839         w = (pwidth + lwidth + 4 + 7) * TINYCHAR_WIDTH;
03840 
03841         if ( right )
03842                 x = 640 - w;
03843         else
03844                 x = 0;
03845 
03846         h = plyrs * TINYCHAR_HEIGHT;
03847 
03848         if ( upper ) {
03849                 ret_y = y + h;
03850         } else {
03851                 y -= h;
03852                 ret_y = y;
03853         }
03854 
03855         if ( cg.snap->ps.persistant[PERS_TEAM] == TEAM_RED ) {
03856                 hcolor[0] = 1.0f;
03857                 hcolor[1] = 0.0f;
03858                 hcolor[2] = 0.0f;
03859                 hcolor[3] = 0.33f;
03860         } else { // if ( cg.snap->ps.persistant[PERS_TEAM] == TEAM_BLUE )
03861                 hcolor[0] = 0.0f;
03862                 hcolor[1] = 0.0f;
03863                 hcolor[2] = 1.0f;
03864                 hcolor[3] = 0.33f;
03865         }
03866         trap_R_SetColor( hcolor );
03867         CG_DrawPic( x + xOffset, y, w, h, cgs.media.teamStatusBar );
03868         trap_R_SetColor( NULL );
03869 
03870         for (i = 0; i < count; i++) {
03871                 ci = cgs.clientinfo + sortedTeamPlayers[i];
03872                 if ( ci->infoValid && ci->team == cg.snap->ps.persistant[PERS_TEAM]) {
03873 
03874                         hcolor[0] = hcolor[1] = hcolor[2] = hcolor[3] = 1.0;
03875 
03876                         xx = x + TINYCHAR_WIDTH;
03877 
03878                         CG_DrawStringExt( xx + xOffset, y,
03879                                 ci->name, hcolor, qfalse, qfalse,
03880                                 TINYCHAR_WIDTH, TINYCHAR_HEIGHT, TEAM_OVERLAY_MAXNAME_WIDTH);
03881 
03882                         if (lwidth) {
03883                                 p = CG_GetLocationString(CG_ConfigString(CS_LOCATIONS+ci->location));
03884                                 if (!p || !*p)
03885                                         p = "unknown";
03886                                 len = CG_DrawStrlen(p);
03887                                 if (len > lwidth)
03888                                         len = lwidth;
03889 
03890 //                              xx = x + TINYCHAR_WIDTH * 2 + TINYCHAR_WIDTH * pwidth + 
03891 //                                      ((lwidth/2 - len/2) * TINYCHAR_WIDTH);
03892                                 xx = x + TINYCHAR_WIDTH * 2 + TINYCHAR_WIDTH * pwidth;
03893                                 CG_DrawStringExt( xx + xOffset, y,
03894                                         p, hcolor, qfalse, qfalse, TINYCHAR_WIDTH, TINYCHAR_HEIGHT,
03895                                         TEAM_OVERLAY_MAXLOCATION_WIDTH);
03896                         }
03897 
03898                         CG_GetColorForHealth( ci->health, ci->armor, hcolor );
03899 
03900                         Com_sprintf (st, sizeof(st), "%3i %3i", ci->health,     ci->armor);
03901 
03902                         xx = x + TINYCHAR_WIDTH * 3 + 
03903                                 TINYCHAR_WIDTH * pwidth + TINYCHAR_WIDTH * lwidth;
03904 
03905                         CG_DrawStringExt( xx + xOffset, y,
03906                                 st, hcolor, qfalse, qfalse,
03907                                 TINYCHAR_WIDTH, TINYCHAR_HEIGHT, 0 );
03908 
03909                         // draw weapon icon
03910                         xx += TINYCHAR_WIDTH * 3;
03911 
03912                         if ( cg_weapons[ci->curWeapon].weaponIcon ) {
03913                                 CG_DrawPic( xx + xOffset, y, TINYCHAR_WIDTH, TINYCHAR_HEIGHT, 
03914                                         cg_weapons[ci->curWeapon].weaponIcon );
03915                         } else {
03916                                 CG_DrawPic( xx + xOffset, y, TINYCHAR_WIDTH, TINYCHAR_HEIGHT, 
03917                                         cgs.media.deferShader );
03918                         }
03919 
03920                         // Draw powerup icons
03921                         if (right) {
03922                                 xx = x;
03923                         } else {
03924                                 xx = x + w - TINYCHAR_WIDTH;
03925                         }
03926                         for (j = 0; j <= PW_NUM_POWERUPS; j++) {
03927                                 if (ci->powerups & (1 << j)) {
03928 
03929                                         item = BG_FindItemForPowerup( j );
03930 
03931                                         if (item) {
03932                                                 CG_DrawPic( xx + xOffset, y, TINYCHAR_WIDTH, TINYCHAR_HEIGHT, 
03933                                                 trap_R_RegisterShader( item->icon ) );
03934                                                 if (right) {
03935                                                         xx -= TINYCHAR_WIDTH;
03936                                                 } else {
03937                                                         xx += TINYCHAR_WIDTH;
03938                                                 }
03939                                         }
03940                                 }
03941                         }
03942 
03943                         y += TINYCHAR_HEIGHT;
03944                 }
03945         }
03946 
03947         return ret_y;
03948 //#endif
03949 }
03950 
03951 
03952 static void CG_DrawPowerupIcons(int y)
03953 {
03954         int j;
03955         int ico_size = 64;
03956         //int y = ico_size/2;
03957         int xOffset = 0;
03958         gitem_t *item;
03959 
03960 #ifdef _XBOX
03961         xOffset = -40;
03962 #endif
03963 
03964         if (!cg.snap)
03965         {
03966                 return;
03967         }
03968 
03969         y += 16;
03970 
03971         for (j = 0; j <= PW_NUM_POWERUPS; j++)
03972         {
03973                 if (cg.snap->ps.powerups[j] > cg.time)
03974                 {
03975                         int secondsleft = (cg.snap->ps.powerups[j] - cg.time)/1000;
03976 
03977                         item = BG_FindItemForPowerup( j );
03978 
03979                         if (item)
03980                         {
03981                                 int icoShader = 0;
03982                                 if (cgs.gametype == GT_CTY && (j == PW_REDFLAG || j == PW_BLUEFLAG))
03983                                 {
03984                                         if (j == PW_REDFLAG)
03985                                         {
03986                                                 icoShader = trap_R_RegisterShaderNoMip( "gfx/hud/mpi_rflag_ys" );
03987                                         }
03988                                         else
03989                                         {
03990                                                 icoShader = trap_R_RegisterShaderNoMip( "gfx/hud/mpi_bflag_ys" );
03991                                         }
03992                                 }
03993                                 else
03994                                 {
03995                                         icoShader = trap_R_RegisterShader( item->icon );
03996                                 }
03997 
03998                                 CG_DrawPic( (640-(ico_size*1.1)) + xOffset, y, ico_size, ico_size, icoShader );
03999         
04000                                 y += ico_size;
04001 
04002                                 if (j != PW_REDFLAG && j != PW_BLUEFLAG && secondsleft < 999)
04003                                 {
04004                                         UI_DrawProportionalString((640-(ico_size*1.1))+(ico_size/2) + xOffset, y-8, va("%i", secondsleft), UI_CENTER | UI_BIGFONT | UI_DROPSHADOW, colorTable[CT_WHITE]);
04005                                 }
04006 
04007                                 y += (ico_size/3);
04008                         }
04009                 }
04010         }
04011 }
04012 
04013 
04014 /*
04015 =====================
04016 CG_DrawUpperRight
04017 
04018 =====================
04019 */
04020 static void CG_DrawUpperRight( void ) {
04021         float   y;
04022 
04023 #ifdef _XBOX
04024         y = 50;
04025 #else
04026         y = 0;
04027 #endif
04028 
04029         trap_R_SetColor( colorTable[CT_WHITE] );
04030 
04031         if ( cgs.gametype >= GT_TEAM && cg_drawTeamOverlay.integer == 1 ) {
04032                 y = CG_DrawTeamOverlay( y, qtrue, qtrue );
04033         } 
04034         if ( cg_drawSnapshot.integer ) {
04035                 y = CG_DrawSnapshot( y );
04036         }
04037 
04038         if ( cg_drawFPS.integer ) {
04039                 y = CG_DrawFPS( y );
04040         }
04041         if ( cg_drawTimer.integer ) {
04042                 y = CG_DrawTimer( y );
04043         }
04044 
04045         if ( ( cgs.gametype >= GT_TEAM || cg.predictedPlayerState.m_iVehicleNum )
04046                 && cg_drawRadar.integer )
04047         {//draw Radar in Siege mode or when in a vehicle of any kind
04048                 y = CG_DrawRadar ( y );
04049         }
04050 
04051         y = CG_DrawEnemyInfo ( y );
04052 
04053         y = CG_DrawMiniScoreboard ( y );
04054 
04055         CG_DrawPowerupIcons(y);
04056 }
04057 
04058 /*
04059 ===================
04060 CG_DrawReward
04061 ===================
04062 */
04063 #ifdef JK2AWARDS
04064 static void CG_DrawReward( void ) { 
04065         float   *color;
04066         int             i, count;
04067         float   x, y;
04068         char    buf[32];
04069 
04070         if ( !cg_drawRewards.integer ) {
04071                 return;
04072         }
04073 
04074         color = CG_FadeColor( cg.rewardTime, REWARD_TIME );
04075         if ( !color ) {
04076                 if (cg.rewardStack > 0) {
04077                         for(i = 0; i < cg.rewardStack; i++) {
04078                                 cg.rewardSound[i] = cg.rewardSound[i+1];
04079                                 cg.rewardShader[i] = cg.rewardShader[i+1];
04080                                 cg.rewardCount[i] = cg.rewardCount[i+1];
04081                         }
04082                         cg.rewardTime = cg.time;
04083                         cg.rewardStack--;
04084                         color = CG_FadeColor( cg.rewardTime, REWARD_TIME );
04085                         trap_S_StartLocalSound(cg.rewardSound[0], CHAN_ANNOUNCER);
04086                 } else {
04087                         return;
04088                 }
04089         }
04090 
04091         trap_R_SetColor( color );
04092 
04093         /*
04094         count = cg.rewardCount[0]/10;                           // number of big rewards to draw
04095 
04096         if (count) {
04097                 y = 4;
04098                 x = 320 - count * ICON_SIZE;
04099                 for ( i = 0 ; i < count ; i++ ) {
04100                         CG_DrawPic( x, y, (ICON_SIZE*2)-4, (ICON_SIZE*2)-4, cg.rewardShader[0] );
04101                         x += (ICON_SIZE*2);
04102                 }
04103         }
04104 
04105         count = cg.rewardCount[0] - count*10;           // number of small rewards to draw
04106         */
04107 
04108         if ( cg.rewardCount[0] >= 10 ) {
04109                 y = 56;
04110                 x = 320 - ICON_SIZE/2;
04111                 CG_DrawPic( x, y, ICON_SIZE-4, ICON_SIZE-4, cg.rewardShader[0] );
04112                 Com_sprintf(buf, sizeof(buf), "%d", cg.rewardCount[0]);
04113                 x = ( SCREEN_WIDTH - SMALLCHAR_WIDTH * CG_DrawStrlen( buf ) ) / 2;
04114                 CG_DrawStringExt( x, y+ICON_SIZE, buf, color, qfalse, qtrue,
04115                                                                 SMALLCHAR_WIDTH, SMALLCHAR_HEIGHT, 0 );
04116         }
04117         else {
04118 
04119                 count = cg.rewardCount[0];
04120 
04121                 y = 56;
04122                 x = 320 - count * ICON_SIZE/2;
04123                 for ( i = 0 ; i < count ; i++ ) {
04124                         CG_DrawPic( x, y, ICON_SIZE-4, ICON_SIZE-4, cg.rewardShader[0] );
04125                         x += ICON_SIZE;
04126                 }
04127         }
04128         trap_R_SetColor( NULL );
04129 }
04130 #endif
04131 
04132 
04133 /*
04134 ===============================================================================
04135 
04136 LAGOMETER
04137 
04138 ===============================================================================
04139 */
04140 
04141 #define LAG_SAMPLES             128
04142 
04143 
04144 typedef struct {
04145         int             frameSamples[LAG_SAMPLES];
04146         int             frameCount;
04147         int             snapshotFlags[LAG_SAMPLES];
04148         int             snapshotSamples[LAG_SAMPLES];
04149         int             snapshotCount;
04150 } lagometer_t;
04151 
04152 lagometer_t             lagometer;
04153 
04154 /*
04155 ==============
04156 CG_AddLagometerFrameInfo
04157 
04158 Adds the current interpolate / extrapolate bar for this frame
04159 ==============
04160 */
04161 void CG_AddLagometerFrameInfo( void ) {
04162         int                     offset;
04163 
04164         offset = cg.time - cg.latestSnapshotTime;
04165         lagometer.frameSamples[ lagometer.frameCount & ( LAG_SAMPLES - 1) ] = offset;
04166         lagometer.frameCount++;
04167 }
04168 
04169 /*
04170 ==============
04171 CG_AddLagometerSnapshotInfo
04172 
04173 Each time a snapshot is received, log its ping time and
04174 the number of snapshots that were dropped before it.
04175 
04176 Pass NULL for a dropped packet.
04177 ==============
04178 */
04179 void CG_AddLagometerSnapshotInfo( snapshot_t *snap ) {
04180         // dropped packet
04181         if ( !snap ) {
04182                 lagometer.snapshotSamples[ lagometer.snapshotCount & ( LAG_SAMPLES - 1) ] = -1;
04183                 lagometer.snapshotCount++;
04184                 return;
04185         }
04186 
04187         // add this snapshot's info
04188         lagometer.snapshotSamples[ lagometer.snapshotCount & ( LAG_SAMPLES - 1) ] = snap->ping;
04189         lagometer.snapshotFlags[ lagometer.snapshotCount & ( LAG_SAMPLES - 1) ] = snap->snapFlags;
04190         lagometer.snapshotCount++;
04191 }
04192 
04193 /*
04194 ==============
04195 CG_DrawDisconnect
04196 
04197 Should we draw something differnet for long lag vs no packets?
04198 ==============
04199 */
04200 static void CG_DrawDisconnect( void ) {
04201         float           x, y;
04202         int                     cmdNum;
04203         usercmd_t       cmd;
04204         const char              *s;
04205         int                     w;  // bk010215 - FIXME char message[1024];
04206 
04207         if (cg.mMapChange)
04208         {                       
04209                 s = CG_GetStringEdString("MP_INGAME", "SERVER_CHANGING_MAPS");  // s = "Server Changing Maps";                  
04210                 w = CG_DrawStrlen( s ) * BIGCHAR_WIDTH;
04211                 CG_DrawBigString( 320 - w/2, 100, s, 1.0F);
04212 
04213                 s = CG_GetStringEdString("MP_INGAME", "PLEASE_WAIT");   // s = "Please wait...";
04214                 w = CG_DrawStrlen( s ) * BIGCHAR_WIDTH;
04215                 CG_DrawBigString( 320 - w/2, 200, s, 1.0F);
04216                 return;
04217         }
04218 
04219         // draw the phone jack if we are completely past our buffers
04220         cmdNum = trap_GetCurrentCmdNumber() - CMD_BACKUP + 1;
04221         trap_GetUserCmd( cmdNum, &cmd );
04222         if ( cmd.serverTime <= cg.snap->ps.commandTime
04223                 || cmd.serverTime > cg.time ) { // special check for map_restart // bk 0102165 - FIXME
04224                 return;
04225         }
04226 
04227         // also add text in center of screen
04228         s = CG_GetStringEdString("MP_INGAME", "CONNECTION_INTERRUPTED"); // s = "Connection Interrupted"; // bk 010215 - FIXME
04229         w = CG_DrawStrlen( s ) * BIGCHAR_WIDTH;
04230         CG_DrawBigString( 320 - w/2, 100, s, 1.0F);
04231 
04232         // blink the icon
04233         if ( ( cg.time >> 9 ) & 1 ) {
04234                 return;
04235         }
04236 
04237         x = 640 - 48;
04238         y = 480 - 48;
04239 
04240         CG_DrawPic( x, y, 48, 48, trap_R_RegisterShader("gfx/2d/net.tga" ) );
04241 }
04242 
04243 
04244 #define MAX_LAGOMETER_PING      900
04245 #define MAX_LAGOMETER_RANGE     300
04246 
04247 /*
04248 ==============
04249 CG_DrawLagometer
04250 ==============
04251 */
04252 static void CG_DrawLagometer( void ) {
04253         int             a, x, y, i;
04254         float   v;
04255         float   ax, ay, aw, ah, mid, range;
04256         int             color;
04257         float   vscale;
04258 
04259         if ( !cg_lagometer.integer || cgs.localServer ) {
04260                 CG_DrawDisconnect();
04261                 return;
04262         }
04263 
04264         //
04265         // draw the graph
04266         //
04267         x = 640 - 48;
04268         y = 480 - 144;
04269 
04270         trap_R_SetColor( NULL );
04271         CG_DrawPic( x, y, 48, 48, cgs.media.lagometerShader );
04272 
04273         ax = x;
04274         ay = y;
04275         aw = 48;
04276         ah = 48;
04277 
04278         color = -1;
04279         range = ah / 3;
04280         mid = ay + range;
04281 
04282         vscale = range / MAX_LAGOMETER_RANGE;
04283 
04284         // draw the frame interpoalte / extrapolate graph
04285         for ( a = 0 ; a < aw ; a++ ) {
04286                 i = ( lagometer.frameCount - 1 - a ) & (LAG_SAMPLES - 1);
04287                 v = lagometer.frameSamples[i];
04288                 v *= vscale;
04289                 if ( v > 0 ) {
04290                         if ( color != 1 ) {
04291                                 color = 1;
04292                                 trap_R_SetColor( g_color_table[ColorIndex(COLOR_YELLOW)] );
04293                         }
04294                         if ( v > range ) {
04295                                 v = range;
04296                         }
04297                         trap_R_DrawStretchPic ( ax + aw - a, mid - v, 1, v, 0, 0, 0, 0, cgs.media.whiteShader );
04298                 } else if ( v < 0 ) {
04299                         if ( color != 2 ) {
04300                                 color = 2;
04301                                 trap_R_SetColor( g_color_table[ColorIndex(COLOR_BLUE)] );
04302                         }
04303                         v = -v;
04304                         if ( v > range ) {
04305                                 v = range;
04306                         }
04307                         trap_R_DrawStretchPic( ax + aw - a, mid, 1, v, 0, 0, 0, 0, cgs.media.whiteShader );
04308                 }
04309         }
04310 
04311         // draw the snapshot latency / drop graph
04312         range = ah / 2;
04313         vscale = range / MAX_LAGOMETER_PING;
04314 
04315         for ( a = 0 ; a < aw ; a++ ) {
04316                 i = ( lagometer.snapshotCount - 1 - a ) & (LAG_SAMPLES - 1);
04317                 v = lagometer.snapshotSamples[i];
04318                 if ( v > 0 ) {
04319                         if ( lagometer.snapshotFlags[i] & SNAPFLAG_RATE_DELAYED ) {
04320                                 if ( color != 5 ) {
04321                                         color = 5;      // YELLOW for rate delay
04322                                         trap_R_SetColor( g_color_table[ColorIndex(COLOR_YELLOW)] );
04323                                 }
04324                         } else {
04325                                 if ( color != 3 ) {
04326                                         color = 3;
04327                                         trap_R_SetColor( g_color_table[ColorIndex(COLOR_GREEN)] );
04328                                 }
04329                         }
04330                         v = v * vscale;
04331                         if ( v > range ) {
04332                                 v = range;
04333                         }
04334                         trap_R_DrawStretchPic( ax + aw - a, ay + ah - v, 1, v, 0, 0, 0, 0, cgs.media.whiteShader );
04335                 } else if ( v < 0 ) {
04336                         if ( color != 4 ) {
04337                                 color = 4;              // RED for dropped snapshots
04338                                 trap_R_SetColor( g_color_table[ColorIndex(COLOR_RED)] );
04339                         }
04340                         trap_R_DrawStretchPic( ax + aw - a, ay + ah - range, 1, range, 0, 0, 0, 0, cgs.media.whiteShader );
04341                 }
04342         }
04343 
04344         trap_R_SetColor( NULL );
04345 
04346         if ( cg_nopredict.integer || cg_synchronousClients.integer ) {
04347                 CG_DrawBigString( ax, ay, "snc", 1.0 );
04348         }
04349 
04350         CG_DrawDisconnect();
04351 }
04352 
04353 void CG_DrawSiegeMessage( const char *str, int objectiveScreen )
04354 {
04355 //      if (!( trap_Key_GetCatcher() & KEYCATCH_UI ))
04356         {
04357                 trap_OpenUIMenu(UIMENU_CLOSEALL);
04358                 trap_Cvar_Set("cg_siegeMessage", str);
04359                 if (objectiveScreen)
04360                 {
04361                         trap_OpenUIMenu(UIMENU_SIEGEOBJECTIVES);
04362                 }
04363                 else
04364                 {
04365                         trap_OpenUIMenu(UIMENU_SIEGEMESSAGE);
04366                 }
04367         }
04368 }
04369 
04370 void CG_DrawSiegeMessageNonMenu( const char *str )
04371 {
04372         char    text[1024];
04373         if (str[0]=='@')
04374         {       
04375                 trap_SP_GetStringTextString(str+1, text, sizeof(text));
04376                 str = text;
04377         }
04378         CG_CenterPrint(str, SCREEN_HEIGHT * 0.30, BIGCHAR_WIDTH);
04379 }
04380 
04381 /*
04382 ===============================================================================
04383 
04384 CENTER PRINTING
04385 
04386 ===============================================================================
04387 */
04388 
04389 
04390 /*
04391 ==============
04392 CG_CenterPrint
04393 
04394 Called for important messages that should stay in the center of the screen
04395 for a few moments
04396 ==============
04397 */
04398 void CG_CenterPrint( const char *str, int y, int charWidth ) {
04399         char    *s;
04400 
04401         Q_strncpyz( cg.centerPrint, str, sizeof(cg.centerPrint) );
04402 
04403         cg.centerPrintTime = cg.time;
04404         cg.centerPrintY = y;
04405         cg.centerPrintCharWidth = charWidth;
04406 
04407         // count the number of lines for centering
04408         cg.centerPrintLines = 1;
04409         s = cg.centerPrint;
04410         while( *s ) {
04411                 if (*s == '\n')
04412                         cg.centerPrintLines++;
04413                 s++;
04414         }
04415 }
04416 
04417 
04418 /*
04419 ===================
04420 CG_DrawCenterString
04421 ===================
04422 */
04423 static void CG_DrawCenterString( void ) {
04424         char    *start;
04425         int             l;
04426         int             x, y, w;
04427         int h;
04428         float   *color;
04429         const float scale = 1.0; //0.5
04430 
04431         if ( !cg.centerPrintTime ) {
04432                 return;
04433         }
04434 
04435         color = CG_FadeColor( cg.centerPrintTime, 1000 * cg_centertime.value );
04436         if ( !color ) {
04437                 return;
04438         }
04439 
04440         trap_R_SetColor( color );
04441 
04442         start = cg.centerPrint;
04443 
04444         y = cg.centerPrintY - cg.centerPrintLines * BIGCHAR_HEIGHT / 2;
04445 
04446         while ( 1 ) {
04447                 char linebuffer[1024];
04448 
04449                 for ( l = 0; l < 50; l++ ) {
04450                         if ( !start[l] || start[l] == '\n' ) {
04451                                 break;
04452                         }
04453                         linebuffer[l] = start[l];
04454                 }
04455                 linebuffer[l] = 0;
04456 
04457                 w = CG_Text_Width(linebuffer, scale, FONT_MEDIUM);
04458                 h = CG_Text_Height(linebuffer, scale, FONT_MEDIUM);
04459                 x = (SCREEN_WIDTH - w) / 2;
04460                 CG_Text_Paint(x, y + h, scale, color, linebuffer, 0, 0, ITEM_TEXTSTYLE_SHADOWEDMORE, FONT_MEDIUM);
04461                 y += h + 6;
04462 
04463                 while ( *start && ( *start != '\n' ) ) {
04464                         start++;
04465                 }
04466                 if ( !*start ) {
04467                         break;
04468                 }
04469                 start++;
04470         }
04471 
04472         trap_R_SetColor( NULL );
04473 }
04474 
04475 
04476 
04477 /*
04478 ================================================================================
04479 
04480 CROSSHAIR
04481 
04482 ================================================================================
04483 */
04484 
04485 #define HEALTH_WIDTH            50.0f
04486 #define HEALTH_HEIGHT           5.0f
04487 
04488 //see if we can draw some extra info on this guy based on our class
04489 void CG_DrawSiegeInfo(centity_t *cent, float chX, float chY, float chW, float chH)
04490 {
04491         siegeExtended_t *se = &cg_siegeExtendedData[cent->currentState.number];
04492         clientInfo_t *ci;
04493         const char *configstring, *v;
04494         siegeClass_t *siegeClass;
04495         vec4_t aColor;
04496         vec4_t bColor;
04497         vec4_t cColor;
04498         float x;
04499         float y;
04500         float percent;
04501         int ammoMax;
04502 
04503         assert(cent->currentState.number < MAX_CLIENTS);
04504 
04505         if (se->lastUpdated > cg.time)
04506         { //strange, shouldn't happen
04507                 return;
04508         }
04509         
04510         if ((cg.time - se->lastUpdated) > 10000)
04511         { //if you haven't received a status update on this guy in 10 seconds, forget about it
04512                 return;
04513         }
04514 
04515         if (cent->currentState.eFlags & EF_DEAD)
04516         { //he's dead, don't display info on him
04517                 return;
04518         }
04519 
04520         if (cent->currentState.weapon != se->weapon)
04521         { //data is invalidated until it syncs back again
04522                 return;
04523         }
04524 
04525         ci = &cgs.clientinfo[cent->currentState.number];
04526         if (ci->team != cg.predictedPlayerState.persistant[PERS_TEAM])
04527         { //not on the same team
04528                 return;
04529         }
04530 
04531         configstring = CG_ConfigString( cg.predictedPlayerState.clientNum + CS_PLAYERS );
04532         v = Info_ValueForKey( configstring, "siegeclass" );
04533 
04534         if (!v || !v[0])
04535         { //don't have siege class in info?
04536                 return;
04537         }
04538 
04539         siegeClass = BG_SiegeFindClassByName(v);
04540 
04541         if (!siegeClass)
04542         { //invalid
04543                 return;
04544         }
04545 
04546     if (!(siegeClass->classflags & (1<<CFL_STATVIEWER)))
04547         { //doesn't really have the ability to see others' stats
04548                 return;
04549         }
04550 
04551         x = chX+((chW/2)-(HEALTH_WIDTH/2));
04552         y = (chY+chH) + 8.0f;
04553         percent = ((float)se->health/(float)se->maxhealth)*HEALTH_WIDTH;
04554 
04555         //color of the bar
04556         aColor[0] = 0.0f;
04557         aColor[1] = 1.0f;
04558         aColor[2] = 0.0f;
04559         aColor[3] = 0.4f;
04560 
04561         //color of the border
04562         bColor[0] = 0.0f;
04563         bColor[1] = 0.0f;
04564         bColor[2] = 0.0f;
04565         bColor[3] = 0.3f;
04566 
04567         //color of greyed out "missing health"
04568         cColor[0] = 0.5f;
04569         cColor[1] = 0.5f;
04570         cColor[2] = 0.5f;
04571         cColor[3] = 0.4f;
04572 
04573         //draw the background (black)
04574         CG_DrawRect(x, y, HEALTH_WIDTH, HEALTH_HEIGHT, 1.0f, colorTable[CT_BLACK]);
04575 
04576         //now draw the part to show how much health there is in the color specified
04577         CG_FillRect(x+1.0f, y+1.0f, percent-1.0f, HEALTH_HEIGHT-1.0f, aColor);
04578 
04579         //then draw the other part greyed out
04580         CG_FillRect(x+percent, y+1.0f, HEALTH_WIDTH-percent-1.0f, HEALTH_HEIGHT-1.0f, cColor);
04581 
04582 
04583         //now draw his ammo
04584         ammoMax = ammoData[weaponData[cent->currentState.weapon].ammoIndex].max;
04585         if ( (cent->currentState.eFlags & EF_DOUBLE_AMMO) )
04586         {
04587                 ammoMax *= 2;
04588         }
04589 
04590         x = chX+((chW/2)-(HEALTH_WIDTH/2));
04591         y = (chY+chH) + HEALTH_HEIGHT + 10.0f;
04592 
04593         if (!weaponData[cent->currentState.weapon].energyPerShot &&
04594                 !weaponData[cent->currentState.weapon].altEnergyPerShot)
04595         { //a weapon that takes no ammo, so show full
04596                 percent = HEALTH_WIDTH;
04597         }
04598         else
04599         {
04600                 percent = ((float)se->ammo/(float)ammoMax)*HEALTH_WIDTH;
04601         }
04602 
04603         //color of the bar
04604         aColor[0] = 1.0f;
04605         aColor[1] = 1.0f;
04606         aColor[2] = 0.0f;
04607         aColor[3] = 0.4f;
04608 
04609         //color of the border
04610         bColor[0] = 0.0f;
04611         bColor[1] = 0.0f;
04612         bColor[2] = 0.0f;
04613         bColor[3] = 0.3f;
04614 
04615         //color of greyed out "missing health"
04616         cColor[0] = 0.5f;
04617         cColor[1] = 0.5f;
04618         cColor[2] = 0.5f;
04619         cColor[3] = 0.4f;
04620 
04621         //draw the background (black)
04622         CG_DrawRect(x, y, HEALTH_WIDTH, HEALTH_HEIGHT, 1.0f, colorTable[CT_BLACK]);
04623 
04624         //now draw the part to show how much health there is in the color specified
04625         CG_FillRect(x+1.0f, y+1.0f, percent-1.0f, HEALTH_HEIGHT-1.0f, aColor);
04626 
04627         //then draw the other part greyed out
04628         CG_FillRect(x+percent, y+1.0f, HEALTH_WIDTH-percent-1.0f, HEALTH_HEIGHT-1.0f, cColor);
04629 }
04630 
04631 //draw the health bar based on current "health" and maxhealth
04632 void CG_DrawHealthBar(centity_t *cent, float chX, float chY, float chW, float chH)
04633 {
04634         vec4_t aColor;
04635         vec4_t bColor;
04636         vec4_t cColor;
04637         float x = chX+((chW/2)-(HEALTH_WIDTH/2));
04638         float y = (chY+chH) + 8.0f;
04639         float percent = ((float)cent->currentState.health/(float)cent->currentState.maxhealth)*HEALTH_WIDTH;
04640         if (percent <= 0)
04641         {
04642                 return;
04643         }
04644 
04645         //color of the bar
04646         if (!cent->currentState.teamowner || cgs.gametype < GT_TEAM)
04647         { //not owned by a team or teamplay
04648                 aColor[0] = 1.0f;
04649                 aColor[1] = 1.0f;
04650                 aColor[2] = 0.0f;
04651                 aColor[3] = 0.4f;
04652         }
04653         else if (cent->currentState.teamowner == cg.predictedPlayerState.persistant[PERS_TEAM])
04654         { //owned by my team
04655                 aColor[0] = 0.0f;
04656                 aColor[1] = 1.0f;
04657                 aColor[2] = 0.0f;
04658                 aColor[3] = 0.4f;
04659         }
04660         else
04661         { //hostile
04662                 aColor[0] = 1.0f;
04663                 aColor[1] = 0.0f;
04664                 aColor[2] = 0.0f;
04665                 aColor[3] = 0.4f;
04666         }
04667 
04668         //color of the border
04669         bColor[0] = 0.0f;
04670         bColor[1] = 0.0f;
04671         bColor[2] = 0.0f;
04672         bColor[3] = 0.3f;
04673 
04674         //color of greyed out "missing health"
04675         cColor[0] = 0.5f;
04676         cColor[1] = 0.5f;
04677         cColor[2] = 0.5f;
04678         cColor[3] = 0.4f;
04679 
04680         //draw the background (black)
04681         CG_DrawRect(x, y, HEALTH_WIDTH, HEALTH_HEIGHT, 1.0f, colorTable[CT_BLACK]);
04682 
04683         //now draw the part to show how much health there is in the color specified
04684         CG_FillRect(x+1.0f, y+1.0f, percent-1.0f, HEALTH_HEIGHT-1.0f, aColor);
04685 
04686         //then draw the other part greyed out
04687         CG_FillRect(x+percent, y+1.0f, HEALTH_WIDTH-percent-1.0f, HEALTH_HEIGHT-1.0f, cColor);
04688 }
04689 
04690 //same routine (at least for now), draw progress of a "hack" or whatever
04691 void CG_DrawHaqrBar(float chX, float chY, float chW, float chH)
04692 {
04693         vec4_t aColor;
04694         vec4_t bColor;
04695         vec4_t cColor;
04696         float x = chX+((chW/2)-(HEALTH_WIDTH/2));
04697         float y = (chY+chH) + 8.0f;
04698         float percent = (((float)cg.predictedPlayerState.hackingTime-(float)cg.time)/(float)cg.predictedPlayerState.hackingBaseTime)*HEALTH_WIDTH;
04699 
04700         if (percent > HEALTH_WIDTH ||
04701                 percent < 1.0f)
04702         {
04703                 return;
04704         }
04705 
04706         //color of the bar
04707         aColor[0] = 1.0f;
04708         aColor[1] = 1.0f;
04709         aColor[2] = 0.0f;
04710         aColor[3] = 0.4f;
04711 
04712         //color of the border
04713         bColor[0] = 0.0f;
04714         bColor[1] = 0.0f;
04715         bColor[2] = 0.0f;
04716         bColor[3] = 0.3f;
04717 
04718         //color of greyed out done area
04719         cColor[0] = 0.5f;
04720         cColor[1] = 0.5f;
04721         cColor[2] = 0.5f;
04722         cColor[3] = 0.1f;
04723 
04724         //draw the background (black)
04725         CG_DrawRect(x, y, HEALTH_WIDTH, HEALTH_HEIGHT, 1.0f, colorTable[CT_BLACK]);
04726 
04727         //now draw the part to show how much health there is in the color specified
04728         CG_FillRect(x+1.0f, y+1.0f, percent-1.0f, HEALTH_HEIGHT-1.0f, aColor);
04729 
04730         //then draw the other part greyed out
04731         CG_FillRect(x+percent, y+1.0f, HEALTH_WIDTH-percent-1.0f, HEALTH_HEIGHT-1.0f, cColor);
04732 
04733         //draw the hacker icon
04734         CG_DrawPic(x, y-HEALTH_WIDTH, HEALTH_WIDTH, HEALTH_WIDTH, cgs.media.hackerIconShader);
04735 }
04736 
04737 //generic timing bar
04738 int cg_genericTimerBar = 0;
04739 int cg_genericTimerDur = 0;
04740 vec4_t cg_genericTimerColor;
04741 #define CGTIMERBAR_H                    50.0f
04742 #define CGTIMERBAR_W                    10.0f
04743 #define CGTIMERBAR_X                    (SCREEN_WIDTH-CGTIMERBAR_W-120.0f)
04744 #define CGTIMERBAR_Y                    (SCREEN_HEIGHT-CGTIMERBAR_H-20.0f)
04745 void CG_DrawGenericTimerBar(void)
04746 {
04747         vec4_t aColor;
04748         vec4_t bColor;
04749         vec4_t cColor;
04750         float x = CGTIMERBAR_X;
04751         float y = CGTIMERBAR_Y;
04752         float percent = ((float)(cg_genericTimerBar-cg.time)/(float)cg_genericTimerDur)*CGTIMERBAR_H;
04753 
04754         if (percent > CGTIMERBAR_H)
04755         {
04756                 return;
04757         }
04758 
04759         if (percent < 0.1f)
04760         {
04761                 percent = 0.1f;
04762         }
04763 
04764         //color of the bar
04765         aColor[0] = cg_genericTimerColor[0];
04766         aColor[1] = cg_genericTimerColor[1];
04767         aColor[2] = cg_genericTimerColor[2];
04768         aColor[3] = cg_genericTimerColor[3];
04769 
04770         //color of the border
04771         bColor[0] = 0.0f;
04772         bColor[1] = 0.0f;
04773         bColor[2] = 0.0f;
04774         bColor[3] = 0.3f;
04775 
04776         //color of greyed out "missing fuel"
04777         cColor[0] = 0.5f;
04778         cColor[1] = 0.5f;
04779         cColor[2] = 0.5f;
04780         cColor[3] = 0.1f;
04781 
04782         //draw the background (black)
04783         CG_DrawRect(x, y, CGTIMERBAR_W, CGTIMERBAR_H, 1.0f, colorTable[CT_BLACK]);
04784 
04785         //now draw the part to show how much health there is in the color specified
04786         CG_FillRect(x+1.0f, y+1.0f+(CGTIMERBAR_H-percent), CGTIMERBAR_W-2.0f, CGTIMERBAR_H-1.0f-(CGTIMERBAR_H-percent), aColor);
04787 
04788         //then draw the other part greyed out
04789         CG_FillRect(x+1.0f, y+1.0f, CGTIMERBAR_W-2.0f, CGTIMERBAR_H-percent, cColor);
04790 }
04791 
04792 /*
04793 =================
04794 CG_DrawCrosshair
04795 =================
04796 */
04797 
04798 #ifdef _XBOX
04799 int cg_crossHairStatus = 0;
04800 #endif
04801 
04802 float cg_crosshairPrevPosX = 0;
04803 float cg_crosshairPrevPosY = 0;
04804 #define CRAZY_CROSSHAIR_MAX_ERROR_X     (100.0f*640.0f/480.0f)
04805 #define CRAZY_CROSSHAIR_MAX_ERROR_Y     (100.0f)
04806 void CG_LerpCrosshairPos( float *x, float *y )
04807 {
04808         if ( cg_crosshairPrevPosX )
04809         {//blend from old pos
04810                 float maxMove = 30.0f * ((float)cg.frametime/500.0f) * 640.0f/480.0f;
04811                 float xDiff = (*x - cg_crosshairPrevPosX);
04812                 if ( fabs(xDiff) > CRAZY_CROSSHAIR_MAX_ERROR_X )
04813                 {
04814                         maxMove = CRAZY_CROSSHAIR_MAX_ERROR_X;
04815                 }
04816                 if ( xDiff > maxMove )
04817                 {
04818                         *x = cg_crosshairPrevPosX + maxMove;
04819                 }
04820                 else if ( xDiff < -maxMove )
04821                 {
04822                         *x = cg_crosshairPrevPosX - maxMove;
04823                 }
04824         }
04825         cg_crosshairPrevPosX = *x;
04826 
04827         if ( cg_crosshairPrevPosY )
04828         {//blend from old pos
04829                 float maxMove = 30.0f * ((float)cg.frametime/500.0f);
04830                 float yDiff = (*y - cg_crosshairPrevPosY);
04831                 if ( fabs(yDiff) > CRAZY_CROSSHAIR_MAX_ERROR_Y )
04832                 {
04833                         maxMove = CRAZY_CROSSHAIR_MAX_ERROR_X;
04834                 }
04835                 if ( yDiff > maxMove )
04836                 {
04837                         *y = cg_crosshairPrevPosY + maxMove;
04838                 }
04839                 else if ( yDiff < -maxMove )
04840                 {
04841                         *y = cg_crosshairPrevPosY - maxMove;
04842                 }
04843         }
04844         cg_crosshairPrevPosY = *y;
04845 }
04846 
04847 vec3_t cg_crosshairPos={0,0,0};
04848 static void CG_DrawCrosshair( vec3_t worldPoint, int chEntValid ) {
04849         float           w, h;
04850         qhandle_t       hShader = 0;
04851         float           f;
04852         float           x, y;
04853         qboolean        corona = qfalse;
04854         vec4_t          ecolor = {0,0,0,0};
04855         centity_t       *crossEnt = NULL;
04856         float           chX, chY;
04857 
04858 #ifdef _XBOX
04859         cg_crossHairStatus = 0;
04860 #endif
04861 
04862         if ( worldPoint )
04863         {
04864                 VectorCopy( worldPoint, cg_crosshairPos );
04865         }
04866 
04867         if ( !cg_drawCrosshair.integer ) 
04868         {
04869                 return;
04870         }
04871 
04872         if (cg.snap->ps.fallingToDeath)
04873         {
04874                 return;
04875         }
04876 
04877         if ( cg.predictedPlayerState.zoomMode != 0 )
04878         {//not while scoped
04879                 return;
04880         }
04881 
04882         if ( cg_crosshairHealth.integer )
04883         {
04884                 vec4_t          hcolor;
04885 
04886                 CG_ColorForHealth( hcolor );
04887                 trap_R_SetColor( hcolor );
04888         }
04889         else
04890         {
04891                 //set color based on what kind of ent is under crosshair
04892                 if ( cg.crosshairClientNum >= ENTITYNUM_WORLD )
04893                 {
04894                         trap_R_SetColor( NULL );
04895                 }
04896                 //rwwFIXMEFIXME: Write this a different way, it's getting a bit too sloppy looking
04897                 else if (chEntValid &&
04898                         (cg_entities[cg.crosshairClientNum].currentState.number < MAX_CLIENTS ||
04899                         cg_entities[cg.crosshairClientNum].currentState.eType == ET_NPC ||
04900                         cg_entities[cg.crosshairClientNum].currentState.shouldtarget ||
04901                         cg_entities[cg.crosshairClientNum].currentState.health || //always show ents with health data under crosshair
04902                         (cg_entities[cg.crosshairClientNum].currentState.eType == ET_MOVER && cg_entities[cg.crosshairClientNum].currentState.bolt1 && cg.predictedPlayerState.weapon == WP_SABER) ||
04903                         (cg_entities[cg.crosshairClientNum].currentState.eType == ET_MOVER && cg_entities[cg.crosshairClientNum].currentState.teamowner)))
04904                 {
04905                         crossEnt = &cg_entities[cg.crosshairClientNum];
04906 
04907                         if ( crossEnt->currentState.powerups & (1 <<PW_CLOAKED) )
04908                         { //don't show up for cloaked guys
04909                                 ecolor[0] = 1.0;//R
04910                                 ecolor[1] = 1.0;//G
04911                                 ecolor[2] = 1.0;//B
04912                         }
04913                         else if ( crossEnt->currentState.number < MAX_CLIENTS )
04914                         {
04915                                 if (cgs.gametype >= GT_TEAM &&
04916                                         cgs.clientinfo[crossEnt->currentState.number].team == cgs.clientinfo[cg.snap->ps.clientNum].team )
04917                                 {
04918                                         //Allies are green
04919                                         ecolor[0] = 0.0;//R
04920                                         ecolor[1] = 1.0;//G
04921                                         ecolor[2] = 0.0;//B
04922                                 }
04923                                 else
04924                                 {
04925                                         if (cgs.gametype == GT_POWERDUEL &&
04926                                                 cgs.clientinfo[crossEnt->currentState.number].duelTeam == cgs.clientinfo[cg.snap->ps.clientNum].duelTeam)
04927                                         { //on the same duel team in powerduel, so he's a friend
04928                                                 ecolor[0] = 0.0;//R
04929                                                 ecolor[1] = 1.0;//G
04930                                                 ecolor[2] = 0.0;//B
04931                                         }
04932                                         else
04933                                         { //Enemies are red
04934                                                 ecolor[0] = 1.0;//R
04935                                                 ecolor[1] = 0.0;//G
04936                                                 ecolor[2] = 0.0;//B
04937 #ifdef _XBOX
04938                                                 cg_crossHairStatus = 1;
04939 #endif
04940                                         }
04941                                 }
04942 
04943                                 if (cg.snap->ps.duelInProgress)
04944                                 {
04945                                         if (crossEnt->currentState.number != cg.snap->ps.duelIndex)
04946                                         { //grey out crosshair for everyone but your foe if you're in a duel
04947                                                 ecolor[0] = 0.4;
04948                                                 ecolor[1] = 0.4;
04949                                                 ecolor[2] = 0.4;
04950                                         }
04951                                 }
04952                                 else if (crossEnt->currentState.bolt1)
04953                                 { //this fellow is in a duel. We just checked if we were in a duel above, so
04954                                   //this means we aren't and he is. Which of course means our crosshair greys out over him.
04955                                         ecolor[0] = 0.4;
04956                                         ecolor[1] = 0.4;
04957                                         ecolor[2] = 0.4;
04958                                 }
04959                         }
04960                         else if (crossEnt->currentState.shouldtarget || crossEnt->currentState.eType == ET_NPC)
04961                         {
04962                                 //VectorCopy( crossEnt->startRGBA, ecolor );
04963                                 if ( !ecolor[0] && !ecolor[1] && !ecolor[2] )
04964                                 {
04965                                         // We really don't want black, so set it to yellow
04966                                         ecolor[0] = 1.0F;//R
04967                                         ecolor[1] = 0.8F;//G
04968                                         ecolor[2] = 0.3F;//B
04969                                 }
04970 
04971                                 if (crossEnt->currentState.eType == ET_NPC)
04972                                 {
04973                                         int plTeam;
04974                                         if (cgs.gametype == GT_SIEGE)
04975                                         {
04976                                                 plTeam = cg.predictedPlayerState.persistant[PERS_TEAM];
04977                                         }
04978                                         else
04979                                         {
04980                                                 plTeam = NPCTEAM_PLAYER;
04981                                         }
04982 
04983                                         if ( crossEnt->currentState.powerups & (1 <<PW_CLOAKED) )
04984                                         {
04985                                                 ecolor[0] = 1.0;//R
04986                                                 ecolor[1] = 1.0;//G
04987                                                 ecolor[2] = 1.0;//B
04988                                         }
04989                                         else if ( !crossEnt->currentState.teamowner )
04990                                         { //not on a team
04991                                                 if (!crossEnt->currentState.teamowner ||
04992                                                         crossEnt->currentState.NPC_class == CLASS_VEHICLE)
04993                                                 { //neutral
04994                                                         if (crossEnt->currentState.owner < MAX_CLIENTS)
04995                                                         { //base color on who is pilotting this thing
04996                                                                 clientInfo_t *ci = &cgs.clientinfo[crossEnt->currentState.owner];
04997 
04998                                                                 if (cgs.gametype >= GT_TEAM && ci->team == cg.predictedPlayerState.persistant[PERS_TEAM])
04999                                                                 { //friendly
05000                                                                         ecolor[0] = 0.0;//R
05001                                                                         ecolor[1] = 1.0;//G
05002                                                                         ecolor[2] = 0.0;//B
05003                                                                 }
05004                                                                 else
05005                                                                 { //hostile
05006                                                                         ecolor[0] = 1.0;//R
05007                                                                         ecolor[1] = 0.0;//G
05008                                                                         ecolor[2] = 0.0;//B
05009 #ifdef _XBOX
05010                                                                         cg_crossHairStatus = 1;
05011 #endif
05012                                                                 }
05013                                                         }
05014                                                         else
05015                                                         { //unmanned
05016                                                                 ecolor[0] = 1.0;//R
05017                                                                 ecolor[1] = 1.0;//G
05018                                                                 ecolor[2] = 0.0;//B
05019                                                         }
05020                                                 }
05021                                                 else
05022                                                 {
05023                                                         ecolor[0] = 1.0;//R
05024                                                         ecolor[1] = 0.0;//G
05025                                                         ecolor[2] = 0.0;//B
05026 #ifdef _XBOX
05027                                                         cg_crossHairStatus = 1;
05028 #endif
05029                                                 }
05030                                         }
05031                                         else if ( crossEnt->currentState.teamowner != plTeam )
05032                                         {// on enemy team
05033                                                 ecolor[0] = 1.0;//R
05034                                                 ecolor[1] = 0.0;//G
05035                                                 ecolor[2] = 0.0;//B
05036 #ifdef _XBOX
05037                                                 cg_crossHairStatus = 1;
05038 #endif
05039                                         }
05040                                         else
05041                                         { //a friend
05042                                                 ecolor[0] = 0.0;//R
05043                                                 ecolor[1] = 1.0;//G
05044                                                 ecolor[2] = 0.0;//B
05045                                         }
05046                                 }
05047                                 else if ( crossEnt->currentState.teamowner == TEAM_RED
05048                                         || crossEnt->currentState.teamowner == TEAM_BLUE )
05049                                 {
05050                                         if (cgs.gametype < GT_TEAM)
05051                                         { //not teamplay, just neutral then
05052                                                 ecolor[0] = 1.0;//R
05053                                                 ecolor[1] = 1.0;//G
05054                                                 ecolor[2] = 0.0;//B
05055                                         }
05056                                         else if ( crossEnt->currentState.teamowner != cgs.clientinfo[cg.snap->ps.clientNum].team )
05057                                         { //on the enemy team
05058                                                 ecolor[0] = 1.0;//R
05059                                                 ecolor[1] = 0.0;//G
05060                                                 ecolor[2] = 0.0;//B
05061 #ifdef _XBOX
05062                                                 cg_crossHairStatus = 1;
05063 #endif
05064                                         }
05065                                         else
05066                                         { //on my team
05067                                                 ecolor[0] = 0.0;//R
05068                                                 ecolor[1] = 1.0;//G
05069                                                 ecolor[2] = 0.0;//B
05070                                         }
05071                                 }
05072                                 else if (crossEnt->currentState.owner == cg.snap->ps.clientNum ||
05073                                         (cgs.gametype >= GT_TEAM && crossEnt->currentState.teamowner == cgs.clientinfo[cg.snap->ps.clientNum].team))
05074                                 {
05075                                         ecolor[0] = 0.0;//R
05076                                         ecolor[1] = 1.0;//G
05077                                         ecolor[2] = 0.0;//B
05078                                 }
05079                                 else if (crossEnt->currentState.teamowner == 16 ||
05080                                         (cgs.gametype >= GT_TEAM && crossEnt->currentState.teamowner && crossEnt->currentState.teamowner != cgs.clientinfo[cg.snap->ps.clientNum].team))
05081                                 {
05082                                         ecolor[0] = 1.0;//R
05083                                         ecolor[1] = 0.0;//G
05084                                         ecolor[2] = 0.0;//B
05085 #ifdef _XBOX
05086                                         cg_crossHairStatus = 1;
05087 #endif
05088                                 }
05089                         }
05090                         else if (crossEnt->currentState.eType == ET_MOVER && crossEnt->currentState.bolt1 && cg.predictedPlayerState.weapon == WP_SABER)
05091                         { //can push/pull this mover. Only show it if we're using the saber.
05092                                 ecolor[0] = 0.2f;
05093                                 ecolor[1] = 0.5f;
05094                                 ecolor[2] = 1.0f;
05095 
05096                                 corona = qtrue;
05097                         }
05098                         else if (crossEnt->currentState.eType == ET_MOVER && crossEnt->currentState.teamowner)
05099                         { //a team owns this - if it's my team green, if not red, if not teamplay then yellow
05100                                 if (cgs.gametype < GT_TEAM)
05101                                 {
05102                                         ecolor[0] = 1.0;//R
05103                                         ecolor[1] = 1.0;//G
05104                                         ecolor[2] = 0.0;//B
05105                                 }
05106                 else if (cg.predictedPlayerState.persistant[PERS_TEAM] != crossEnt->currentState.teamowner)
05107                                 { //not my team
05108                                         ecolor[0] = 1.0;//R
05109                                         ecolor[1] = 0.0;//G
05110                                         ecolor[2] = 0.0;//B
05111 #ifdef _XBOX
05112                                         cg_crossHairStatus = 1;
05113 #endif
05114                                 }
05115                                 else
05116                                 { //my team
05117                                         ecolor[0] = 0.0;//R
05118                                         ecolor[1] = 1.0;//G
05119                                         ecolor[2] = 0.0;//B
05120                                 }
05121                         }
05122                         else if (crossEnt->currentState.health)
05123                         {
05124                                 if (!crossEnt->currentState.teamowner || cgs.gametype < GT_TEAM)
05125                                 { //not owned by a team or teamplay
05126                                         ecolor[0] = 1.0f;
05127                                         ecolor[1] = 1.0f;
05128                                         ecolor[2] = 0.0f;
05129                                 }
05130                                 else if (crossEnt->currentState.teamowner == cg.predictedPlayerState.persistant[PERS_TEAM])
05131                                 { //owned by my team
05132                                         ecolor[0] = 0.0f;
05133                                         ecolor[1] = 1.0f;
05134                                         ecolor[2] = 0.0f;
05135                                 }
05136                                 else
05137                                 { //hostile
05138                                         ecolor[0] = 1.0f;
05139                                         ecolor[1] = 0.0f;
05140                                         ecolor[2] = 0.0f;
05141 #ifdef _XBOX
05142                                         cg_crossHairStatus = 1;
05143 #endif
05144                                 }
05145                         }
05146 
05147                         ecolor[3] = 1.0;
05148 
05149                         trap_R_SetColor( ecolor );
05150                 }
05151         }
05152 
05153         if ( cg.predictedPlayerState.m_iVehicleNum )
05154         {//I'm in a vehicle
05155                 centity_t *vehCent = &cg_entities[cg.predictedPlayerState.m_iVehicleNum];
05156             if ( vehCent 
05157                         && vehCent->m_pVehicle 
05158                         && vehCent->m_pVehicle->m_pVehicleInfo 
05159                         && vehCent->m_pVehicle->m_pVehicleInfo->crosshairShaderHandle )
05160                 {
05161                         hShader = vehCent->m_pVehicle->m_pVehicleInfo->crosshairShaderHandle;
05162                 }
05163                 //bigger by default
05164                 w = cg_crosshairSize.value*2.0f;
05165                 h = w;
05166         }
05167         else
05168         {
05169                 w = h = cg_crosshairSize.value;
05170         }
05171 
05172         // pulse the size of the crosshair when picking up items
05173         f = cg.time - cg.itemPickupBlendTime;
05174         if ( f > 0 && f < ITEM_BLOB_TIME ) {
05175                 f /= ITEM_BLOB_TIME;
05176                 w *= ( 1 + f );
05177                 h *= ( 1 + f );
05178         }
05179 
05180         if ( worldPoint && VectorLength( worldPoint ) )
05181         {
05182                 if ( !CG_WorldCoordToScreenCoordFloat( worldPoint, &x, &y ) )
05183                 {//off screen, don't draw it
05184                         return;
05185                 }
05186                 //CG_LerpCrosshairPos( &x, &y );
05187                 x -= 320;
05188                 y -= 240;
05189         }
05190         else
05191         {
05192                 x = cg_crosshairX.integer;
05193                 y = cg_crosshairY.integer;
05194         }
05195 
05196         if ( !hShader )
05197         {
05198                 hShader = cgs.media.crosshairShader[ cg_drawCrosshair.integer % NUM_CROSSHAIRS ];
05199         }
05200 
05201         chX = x + cg.refdef.x + 0.5 * (640 - w);
05202         chY = y + cg.refdef.y + 0.5 * (480 - h);
05203         trap_R_DrawStretchPic( chX, chY, w, h, 0, 0, 1, 1, hShader );
05204 
05205         //draw a health bar directly under the crosshair if we're looking at something
05206         //that takes damage
05207         if (crossEnt &&
05208                 crossEnt->currentState.maxhealth)
05209         {
05210                 CG_DrawHealthBar(crossEnt, chX, chY, w, h);
05211                 chY += HEALTH_HEIGHT*2;
05212         }
05213         else if (crossEnt && crossEnt->currentState.number < MAX_CLIENTS)
05214         {
05215                 if (cgs.gametype == GT_SIEGE)
05216                 {
05217                         CG_DrawSiegeInfo(crossEnt, chX, chY, w, h);
05218                         chY += HEALTH_HEIGHT*4;
05219                 }
05220                 if (cg.crosshairVehNum && cg.time == cg.crosshairVehTime)
05221                 { //it was in the crosshair this frame
05222                         centity_t *hisVeh = &cg_entities[cg.crosshairVehNum];
05223 
05224                         if (hisVeh->currentState.eType == ET_NPC &&
05225                                 hisVeh->currentState.NPC_class == CLASS_VEHICLE &&
05226                                 hisVeh->currentState.maxhealth &&
05227                                 hisVeh->m_pVehicle)
05228                         { //draw the health for this vehicle
05229                                 CG_DrawHealthBar(hisVeh, chX, chY, w, h);
05230                                 chY += HEALTH_HEIGHT*2;
05231                         }
05232                 }
05233         }
05234 
05235         if (cg.predictedPlayerState.hackingTime)
05236         { //hacking something
05237                 CG_DrawHaqrBar(chX, chY, w, h);
05238         }
05239 
05240         if (cg_genericTimerBar > cg.time)
05241         { //draw generic timing bar, can be used for whatever
05242                 CG_DrawGenericTimerBar();
05243         }
05244 
05245         if ( corona ) // drawing extra bits
05246         {
05247                 ecolor[3] = 0.5f;
05248                 ecolor[0] = ecolor[1] = ecolor[2] = (1 - ecolor[3]) * ( sin( cg.time * 0.001f ) * 0.08f + 0.35f ); // don't draw full color
05249                 ecolor[3] = 1.0f;
05250 
05251                 trap_R_SetColor( ecolor );
05252 
05253                 w *= 2.0f;
05254                 h *= 2.0f;
05255 
05256                 trap_R_DrawStretchPic( x + cg.refdef.x + 0.5 * (640 - w), 
05257                         y + cg.refdef.y + 0.5 * (480 - h), 
05258                         w, h, 0, 0, 1, 1, cgs.media.forceCoronaShader );
05259         }
05260 }
05261 
05262 qboolean CG_WorldCoordToScreenCoordFloat(vec3_t worldCoord, float *x, float *y)
05263 {
05264         float   xcenter, ycenter;
05265         vec3_t  local, transformed;
05266         vec3_t  vfwd;
05267         vec3_t  vright;
05268         vec3_t  vup;
05269         float xzi;
05270         float yzi;
05271 
05272 //      xcenter = cg.refdef.width / 2;//gives screen coords adjusted for resolution
05273 //      ycenter = cg.refdef.height / 2;//gives screen coords adjusted for resolution
05274         
05275         //NOTE: did it this way because most draw functions expect virtual 640x480 coords
05276         //      and adjust them for current resolution
05277         xcenter = 640.0f / 2.0f;//gives screen coords in virtual 640x480, to be adjusted when drawn
05278         ycenter = 480.0f / 2.0f;//gives screen coords in virtual 640x480, to be adjusted when drawn
05279 
05280         AngleVectors (cg.refdef.viewangles, vfwd, vright, vup);
05281 
05282         VectorSubtract (worldCoord, cg.refdef.vieworg, local);
05283 
05284         transformed[0] = DotProduct(local,vright);
05285         transformed[1] = DotProduct(local,vup);
05286         transformed[2] = DotProduct(local,vfwd);                
05287 
05288         // Make sure Z is not negative.
05289         if(transformed[2] < 0.01f)
05290         {
05291                 return qfalse;
05292         }
05293 
05294         xzi = xcenter / transformed[2] * (96.0f/cg.refdef.fov_x);
05295         yzi = ycenter / transformed[2] * (102.0f/cg.refdef.fov_y);
05296 
05297         *x = xcenter + xzi * transformed[0];
05298         *y = ycenter - yzi * transformed[1];
05299 
05300         return qtrue;
05301 }
05302 
05303 qboolean CG_WorldCoordToScreenCoord( vec3_t worldCoord, int *x, int *y )
05304 {
05305         float   xF, yF;
05306         qboolean retVal = CG_WorldCoordToScreenCoordFloat( worldCoord, &xF, &yF );
05307         *x = (int)xF;
05308         *y = (int)yF;
05309         return retVal;
05310 }
05311 
05312 /*
05313 ====================
05314 CG_SaberClashFlare
05315 ====================
05316 */
05317 int cg_saberFlashTime = 0;
05318 vec3_t cg_saberFlashPos = {0, 0, 0};
05319 void CG_SaberClashFlare( void ) 
05320 {
05321         int                             t, maxTime = 150;
05322         vec3_t dif;
05323         vec3_t color;
05324         int x,y;
05325         float v, len;
05326         trace_t tr;
05327 
05328         t = cg.time - cg_saberFlashTime;
05329 
05330         if ( t <= 0 || t >= maxTime ) 
05331         {
05332                 return;
05333         }
05334 
05335         // Don't do clashes for things that are behind us
05336         VectorSubtract( cg_saberFlashPos, cg.refdef.vieworg, dif );
05337 
05338         if ( DotProduct( dif, cg.refdef.viewaxis[0] ) < 0.2 )
05339         {
05340                 return;
05341         }
05342 
05343         CG_Trace( &tr, cg.refdef.vieworg, NULL, NULL, cg_saberFlashPos, -1, CONTENTS_SOLID );
05344 
05345         if ( tr.fraction < 1.0f )
05346         {
05347                 return;
05348         }
05349 
05350         len = VectorNormalize( dif );
05351 
05352         // clamp to a known range
05353         /*
05354         if ( len > 800 )
05355         {
05356                 len = 800;
05357         }
05358         */
05359         if ( len > 1200 )
05360         {
05361                 return;
05362         }
05363 
05364         v = ( 1.0f - ((float)t / maxTime )) * ((1.0f - ( len / 800.0f )) * 2.0f + 0.35f);
05365         if (v < 0.001f)
05366         {
05367                 v = 0.001f;
05368         }
05369 
05370         CG_WorldCoordToScreenCoord( cg_saberFlashPos, &x, &y );
05371 
05372         VectorSet( color, 0.8f, 0.8f, 0.8f );
05373         trap_R_SetColor( color );
05374 
05375         CG_DrawPic( x - ( v * 300 ), y - ( v * 300 ),
05376                                 v * 600, v * 600,
05377                                 trap_R_RegisterShader( "gfx/effects/saberFlare" ));
05378 }
05379 
05380 void CG_DottedLine( float x1, float y1, float x2, float y2, float dotSize, int numDots, vec4_t color, float alpha )
05381 {
05382         float x, y, xDiff, yDiff, xStep, yStep;
05383         vec4_t colorRGBA;
05384         int dotNum = 0;
05385 
05386         VectorCopy4( color, colorRGBA );
05387         colorRGBA[3] = alpha;
05388 
05389         trap_R_SetColor( colorRGBA );
05390 
05391         xDiff = x2-x1;
05392         yDiff = y2-y1;
05393         xStep = xDiff/(float)numDots;
05394         yStep = yDiff/(float)numDots;
05395 
05396         for ( dotNum = 0; dotNum < numDots; dotNum++ )
05397         {
05398                 x = x1 + (xStep*dotNum) - (dotSize*0.5f);
05399                 y = y1 + (yStep*dotNum) - (dotSize*0.5f);
05400 
05401                 CG_DrawPic( x, y, dotSize, dotSize, cgs.media.whiteShader );
05402         }
05403 }
05404 
05405 void CG_BracketEntity( centity_t *cent, float radius )
05406 {
05407         trace_t tr;
05408         vec3_t dif;
05409         float   len, size, lineLength, lineWidth;
05410         float   x,      y;
05411         clientInfo_t *local;
05412         qboolean isEnemy = qfalse;
05413 
05414         VectorSubtract( cent->lerpOrigin, cg.refdef.vieworg, dif );
05415         len = VectorNormalize( dif );
05416 
05417         if ( cg.crosshairClientNum != cent->currentState.clientNum
05418                 && (!cg.snap||cg.snap->ps.rocketLockIndex!= cent->currentState.clientNum) )
05419         {//if they're the entity you're locking onto or under your crosshair, always draw bracket
05420                 //Hmm... for now, if they're closer than 2000, don't bracket?
05421                 if ( len < 2000.0f )
05422                 {
05423                         return;
05424                 }
05425 
05426                 CG_Trace( &tr, cg.refdef.vieworg, NULL, NULL, cent->lerpOrigin, -1, CONTENTS_OPAQUE );
05427 
05428                 //don't bracket if can't see them
05429                 if ( tr.fraction < 1.0f )
05430                 {
05431                         return;
05432                 }
05433         }
05434 
05435         if ( !CG_WorldCoordToScreenCoordFloat(cent->lerpOrigin, &x, &y) )
05436         {//off-screen, don't draw it
05437                 return;
05438         }
05439 
05440         //just to see if it's centered
05441         //CG_DrawPic( x-2, y-2, 4, 4, cgs.media.whiteShader );
05442 
05443         local = &cgs.clientinfo[cg.snap->ps.clientNum];
05444         if ( cent->currentState.m_iVehicleNum //vehicle has a driver
05445                 && cgs.clientinfo[ cent->currentState.m_iVehicleNum-1 ].infoValid )
05446         {
05447                 if ( cgs.gametype < GT_TEAM )
05448                 {//ffa?
05449                         isEnemy = qtrue;
05450                         trap_R_SetColor ( g_color_table[ColorIndex(COLOR_RED)] );
05451                 }
05452                 else if ( cgs.clientinfo[ cent->currentState.m_iVehicleNum-1 ].team == local->team )
05453                 {
05454                         trap_R_SetColor ( g_color_table[ColorIndex(COLOR_GREEN)] );
05455                 }
05456                 else
05457                 {
05458                         isEnemy = qtrue;
05459                         trap_R_SetColor ( g_color_table[ColorIndex(COLOR_RED)] );
05460                 }
05461         }
05462         else if ( cent->currentState.teamowner )
05463         {
05464                 if ( cgs.gametype < GT_TEAM )
05465                 {//ffa?
05466                         isEnemy = qtrue;
05467                         trap_R_SetColor ( g_color_table[ColorIndex(COLOR_RED)] );
05468                 }
05469                 else if ( cent->currentState.teamowner != cg.predictedPlayerState.persistant[PERS_TEAM] )
05470                 {// on enemy team
05471                         isEnemy = qtrue;
05472                         trap_R_SetColor ( g_color_table[ColorIndex(COLOR_RED)] );
05473                 }
05474                 else
05475                 { //a friend
05476                         trap_R_SetColor ( g_color_table[ColorIndex(COLOR_GREEN)] );
05477                 }
05478         }
05479         else
05480         {//FIXME: if we want to ever bracket anything besides vehicles (like siege objectives we want to blow up), we should handle the coloring here
05481                 trap_R_SetColor ( NULL );
05482         }
05483         
05484         if ( len <= 1.0f )
05485         {//super-close, max out at 400 times radius (which is HUGE)
05486                 size = radius*400.0f;
05487         }
05488         else
05489         {//scale by dist
05490                 size = radius*(400.0f/len);
05491         }
05492 
05493         if ( size < 1.0f )
05494         {
05495                 size = 1.0f;
05496         }
05497         
05498         //length scales with dist
05499         lineLength = (size*0.1f);
05500         if ( lineLength < 0.5f )
05501         {//always visible
05502                 lineLength = 0.5f;
05503         }
05504         //always visible width
05505         lineWidth = 1.0f;
05506 
05507         x -= (size*0.5f);
05508         y -= (size*0.5f);
05509 
05510         /*
05511         if ( x >= 0 && x <= 640
05512                 && y >= 0 && y <= 480 )
05513         */
05514         {//brackets would be drawn on the screen, so draw them
05515         //upper left corner
05516                 //horz
05517         CG_DrawPic( x, y, lineLength, lineWidth, cgs.media.whiteShader );
05518                 //vert
05519         CG_DrawPic( x, y, lineWidth, lineLength, cgs.media.whiteShader );
05520         //upper right corner
05521                 //horz
05522         CG_DrawPic( x+size-lineLength, y, lineLength, lineWidth, cgs.media.whiteShader );
05523                 //vert
05524         CG_DrawPic( x+size-lineWidth, y, lineWidth, lineLength, cgs.media.whiteShader );
05525         //lower left corner
05526                 //horz
05527         CG_DrawPic( x, y+size-lineWidth, lineLength, lineWidth, cgs.media.whiteShader );
05528                 //vert
05529         CG_DrawPic( x, y+size-lineLength, lineWidth, lineLength, cgs.media.whiteShader );
05530         //lower right corner
05531                 //horz
05532         CG_DrawPic( x+size-lineLength, y+size-lineWidth, lineLength, lineWidth, cgs.media.whiteShader );
05533                 //vert
05534         CG_DrawPic( x+size-lineWidth, y+size-lineLength, lineWidth, lineLength, cgs.media.whiteShader );
05535         }
05536         //Lead Indicator...
05537         if ( cg_drawVehLeadIndicator.integer )
05538         {//draw the lead indicator
05539                 if ( isEnemy )
05540                 {//an enemy object
05541                         if ( cent->currentState.NPC_class == CLASS_VEHICLE )
05542                         {//enemy vehicle
05543                                 if ( !VectorCompare( cent->currentState.pos.trDelta, vec3_origin ) )
05544                                 {//enemy vehicle is moving
05545                                         if ( cg.predictedPlayerState.m_iVehicleNum )
05546                                         {//I'm in a vehicle
05547                                                 centity_t               *veh = &cg_entities[cg.predictedPlayerState.m_iVehicleNum];
05548                                                 if ( veh //vehicle cent
05549                                                         && veh->m_pVehicle//vehicle
05550                                                         && veh->m_pVehicle->m_pVehicleInfo//vehicle stats
05551                                                         && veh->m_pVehicle->m_pVehicleInfo->weapon[0].ID > VEH_WEAPON_BASE )//valid vehicle weapon
05552                                                 {
05553                                                         vehWeaponInfo_t *vehWeapon = &g_vehWeaponInfo[veh->m_pVehicle->m_pVehicleInfo->weapon[0].ID];
05554                                                         if ( vehWeapon 
05555                                                                 && vehWeapon->bIsProjectile//primary weapon's shot is a projectile
05556                                                                 && !vehWeapon->bHasGravity//primary weapon's shot is not affected by gravity
05557                                                                 && !vehWeapon->fHoming//primary weapon's shot is not homing
05558                                                                 && vehWeapon->fSpeed )//primary weapon's shot has speed
05559                                                         {//our primary weapon's projectile has a speed
05560                                                                 vec3_t vehDiff, vehLeadPos;
05561                                                                 float vehDist, eta;
05562                                                                 float leadX, leadY;
05563                                                                 
05564                                                                 VectorSubtract( cent->lerpOrigin, cg.predictedVehicleState.origin, vehDiff );
05565                                                                 vehDist = VectorNormalize( vehDiff );
05566                                                                 eta = (vehDist/vehWeapon->fSpeed);//how many seconds it would take for my primary weapon's projectile to get from my ship to theirs
05567                                                                 //now extrapolate their position that number of seconds into the future based on their velocity
05568                                                                 VectorMA( cent->lerpOrigin, eta, cent->currentState.pos.trDelta, vehLeadPos );
05569                                                                 //now we have where we should be aiming at, project that onto the screen at a 2D co-ord
05570                                                                 if ( !CG_WorldCoordToScreenCoordFloat(cent->lerpOrigin, &x, &y) )
05571                                                                 {//off-screen, don't draw it
05572                                                                         return;
05573                                                                 }
05574                                                                 if ( !CG_WorldCoordToScreenCoordFloat(vehLeadPos, &leadX, &leadY) )
05575                                                                 {//off-screen, don't draw it
05576                                                                         //just draw the line
05577                                                                         CG_DottedLine( x, y, leadX, leadY, 1, 10, g_color_table[ColorIndex(COLOR_RED)], 0.5f );
05578                                                                         return;
05579                                                                 }
05580                                                                 //draw a line from the ship's cur pos to the lead pos
05581                                                                 CG_DottedLine( x, y, leadX, leadY, 1, 10, g_color_table[ColorIndex(COLOR_RED)], 0.5f );
05582                                                                 //now draw the lead indicator
05583                                                                 trap_R_SetColor ( g_color_table[ColorIndex(COLOR_RED)] );
05584                                                                 CG_DrawPic( leadX-8, leadY-8, 16, 16, trap_R_RegisterShader( "gfx/menus/radar/lead" ) );
05585                                                         }
05586                                                 }
05587                                         }
05588                                 }
05589                         }
05590                 }
05591         }
05592 }
05593 
05594 qboolean CG_InFighter( void )
05595 {
05596         if ( cg.predictedPlayerState.m_iVehicleNum )
05597         {//I'm in a vehicle
05598                 centity_t *vehCent = &cg_entities[cg.predictedPlayerState.m_iVehicleNum];
05599             if ( vehCent 
05600                         && vehCent->m_pVehicle 
05601                         && vehCent->m_pVehicle->m_pVehicleInfo
05602                         && vehCent->m_pVehicle->m_pVehicleInfo->type == VH_FIGHTER )
05603                 {//I'm in a fighter
05604                         return qtrue;
05605                 }
05606         }
05607         return qfalse;
05608 }
05609 
05610 qboolean CG_InATST( void )
05611 {
05612         if ( cg.predictedPlayerState.m_iVehicleNum )
05613         {//I'm in a vehicle
05614                 centity_t *vehCent = &cg_entities[cg.predictedPlayerState.m_iVehicleNum];
05615             if ( vehCent 
05616                         && vehCent->m_pVehicle 
05617                         && vehCent->m_pVehicle->m_pVehicleInfo
05618                         && vehCent->m_pVehicle->m_pVehicleInfo->type == VH_WALKER )
05619                 {//I'm in an atst
05620                         return qtrue;
05621                 }
05622         }
05623         return qfalse;
05624 }
05625 
05626 void CG_DrawBracketedEntities( void )
05627 {
05628         int i;
05629         for ( i = 0; i < cg.bracketedEntityCount; i++ ) 
05630         {       
05631                 centity_t *cent = &cg_entities[cg.bracketedEntities[i]];
05632                 CG_BracketEntity( cent, CG_RadiusForCent( cent ) );
05633         }
05634 }
05635 
05636 //--------------------------------------------------------------
05637 static void CG_DrawHolocronIcons(void)
05638 //--------------------------------------------------------------
05639 {
05640         int icon_size = 40;
05641         int i = 0;
05642         int startx = 10;
05643         int starty = 10;//SCREEN_HEIGHT - icon_size*3;
05644 
05645         int endx = icon_size;
05646         int endy = icon_size;
05647 
05648         if (cg.snap->ps.zoomMode)
05649         { //don't display over zoom mask
05650                 return;
05651         }
05652 
05653         if (cgs.clientinfo[cg.snap->ps.clientNum].team == TEAM_SPECTATOR)
05654         {
05655                 return;
05656         }
05657 
05658         while (i < NUM_FORCE_POWERS)
05659         {
05660                 if (cg.snap->ps.holocronBits & (1 << forcePowerSorted[i]))
05661                 {
05662                         CG_DrawPic( startx, starty, endx, endy, cgs.media.forcePowerIcons[forcePowerSorted[i]]);
05663                         starty += (icon_size+2); //+2 for spacing
05664                         if ((starty+icon_size) >= SCREEN_HEIGHT-80)
05665                         {
05666                                 starty = 10;//SCREEN_HEIGHT - icon_size*3;
05667                                 startx += (icon_size+2);
05668                         }
05669                 }
05670 
05671                 i++;
05672         }
05673 }
05674 
05675 static qboolean CG_IsDurationPower(int power)
05676 {
05677         if (power == FP_HEAL ||
05678                 power == FP_SPEED ||
05679                 power == FP_TELEPATHY ||
05680                 power == FP_RAGE ||
05681                 power == FP_PROTECT ||
05682                 power == FP_ABSORB ||
05683                 power == FP_SEE)
05684         {
05685                 return qtrue;
05686         }
05687 
05688         return qfalse;
05689 }
05690 
05691 //--------------------------------------------------------------
05692 static void CG_DrawActivePowers(void)
05693 //--------------------------------------------------------------
05694 {
05695         int icon_size = 40;
05696         int i = 0;
05697         int startx = icon_size*2+16;
05698         int starty = SCREEN_HEIGHT - icon_size*2;
05699 
05700         int endx = icon_size;
05701         int endy = icon_size;
05702 
05703         if (cg.snap->ps.zoomMode)
05704         { //don't display over zoom mask
05705                 return;
05706         }
05707 
05708         if (cgs.clientinfo[cg.snap->ps.clientNum].team == TEAM_SPECTATOR)
05709         {
05710                 return;
05711         }
05712 
05713         while (i < NUM_FORCE_POWERS)
05714         {
05715                 if ((cg.snap->ps.fd.forcePowersActive & (1 << forcePowerSorted[i])) &&
05716                         CG_IsDurationPower(forcePowerSorted[i]))
05717                 {
05718                         CG_DrawPic( startx, starty, endx, endy, cgs.media.forcePowerIcons[forcePowerSorted[i]]);
05719                         startx += (icon_size+2); //+2 for spacing
05720                         if ((startx+icon_size) >= SCREEN_WIDTH-80)
05721                         {
05722                                 startx = icon_size*2+16;
05723                                 starty += (icon_size+2);
05724                         }
05725                 }
05726 
05727                 i++;
05728         }
05729 
05730         //additionally, draw an icon force force rage recovery
05731         if (cg.snap->ps.fd.forceRageRecoveryTime > cg.time)
05732         {
05733                 CG_DrawPic( startx, starty, endx, endy, cgs.media.rageRecShader);
05734         }
05735 }
05736 
05737 //--------------------------------------------------------------
05738 static void CG_DrawRocketLocking( int lockEntNum, int lockTime )
05739 //--------------------------------------------------------------
05740 {
05741         int             cx, cy;
05742         vec3_t  org;
05743         static  int oldDif = 0;
05744         centity_t *cent = &cg_entities[lockEntNum];
05745         vec4_t color={0.0f,0.0f,0.0f,0.0f};
05746         float lockTimeInterval = ((cgs.gametype==GT_SIEGE)?2400.0f:1200.0f)/16.0f;
05747         //FIXME: if in a vehicle, use the vehicle's lockOnTime...
05748         int dif = (cg.time - cg.snap->ps.rocketLockTime)/lockTimeInterval;
05749         int i;
05750 
05751         if (!cg.snap->ps.rocketLockTime)
05752         {
05753                 return;
05754         }
05755 
05756         if (cgs.clientinfo[cg.snap->ps.clientNum].team == TEAM_SPECTATOR)
05757         {
05758                 return;
05759         }
05760 
05761         if ( cg.snap->ps.m_iVehicleNum )
05762         {//driving a vehicle
05763                 centity_t *veh = &cg_entities[cg.snap->ps.m_iVehicleNum];
05764                 if ( veh->m_pVehicle )
05765                 {
05766                         vehWeaponInfo_t *vehWeapon = NULL;
05767                         if ( cg.predictedVehicleState.weaponstate == WEAPON_CHARGING_ALT )
05768                         {
05769                                 if ( veh->m_pVehicle->m_pVehicleInfo->weapon[1].ID > VEH_WEAPON_BASE 
05770                                         && veh->m_pVehicle->m_pVehicleInfo->weapon[1].ID < MAX_VEH_WEAPONS )
05771                                 {
05772                                         vehWeapon = &g_vehWeaponInfo[veh->m_pVehicle->m_pVehicleInfo->weapon[1].ID];
05773                                 }
05774                         }
05775                         else
05776                         {
05777                                 if ( veh->m_pVehicle->m_pVehicleInfo->weapon[0].ID > VEH_WEAPON_BASE 
05778                                         && veh->m_pVehicle->m_pVehicleInfo->weapon[0].ID < MAX_VEH_WEAPONS )
05779                                 {
05780                                         vehWeapon = &g_vehWeaponInfo[veh->m_pVehicle->m_pVehicleInfo->weapon[0].ID];
05781                                 }
05782                         }
05783                         if ( vehWeapon != NULL )
05784                         {//we are trying to lock on with a valid vehicle weapon, so use *its* locktime, not the hard-coded one
05785                                 if ( !vehWeapon->iLockOnTime )
05786                                 {//instant lock-on
05787                                         dif = 10.0f;
05788                                 }
05789                                 else
05790                                 {//use the custom vehicle lockOnTime
05791                                         lockTimeInterval = (vehWeapon->iLockOnTime/16.0f);
05792                                         dif = (cg.time - cg.snap->ps.rocketLockTime)/lockTimeInterval;
05793                                 }
05794                         }
05795                 }
05796         }
05797         //We can't check to see in pmove if players are on the same team, so we resort
05798         //to just not drawing the lock if a teammate is the locked on ent
05799         if (cg.snap->ps.rocketLockIndex >= 0 &&
05800                 cg.snap->ps.rocketLockIndex < ENTITYNUM_NONE)
05801         {
05802                 clientInfo_t *ci = NULL;
05803 
05804                 if (cg.snap->ps.rocketLockIndex < MAX_CLIENTS)
05805                 {
05806                         ci = &cgs.clientinfo[cg.snap->ps.rocketLockIndex];
05807                 }
05808                 else
05809                 {
05810                         ci = cg_entities[cg.snap->ps.rocketLockIndex].npcClient;
05811                 }
05812 
05813                 if (ci)
05814                 {
05815                         if (ci->team == cgs.clientinfo[cg.snap->ps.clientNum].team)
05816                         {
05817                                 if (cgs.gametype >= GT_TEAM)
05818                                 {
05819                                         return;
05820                                 }
05821                         }
05822                         else if (cgs.gametype >= GT_TEAM)
05823                         {
05824                                 centity_t *hitEnt = &cg_entities[cg.snap->ps.rocketLockIndex];
05825                                 if (hitEnt->currentState.eType == ET_NPC &&
05826                                         hitEnt->currentState.NPC_class == CLASS_VEHICLE &&
05827                                         hitEnt->currentState.owner < ENTITYNUM_WORLD)
05828                                 { //this is a vehicle, if it has a pilot and that pilot is on my team, then...
05829                                         if (hitEnt->currentState.owner < MAX_CLIENTS)
05830                                         {
05831                                                 ci = &cgs.clientinfo[hitEnt->currentState.owner];
05832                                         }
05833                                         else
05834                                         {
05835                                                 ci = cg_entities[hitEnt->currentState.owner].npcClient;
05836                                         }
05837                                         if (ci && ci->team == cgs.clientinfo[cg.snap->ps.clientNum].team)
05838                                         {
05839                                                 return;
05840                                         }
05841                                 }
05842                         }
05843                 }
05844         }
05845 
05846         if (cg.snap->ps.rocketLockTime != -1)
05847         {
05848                 lastvalidlockdif = dif;
05849         }
05850         else
05851         {
05852                 dif = lastvalidlockdif;
05853         }
05854 
05855         if ( !cent )
05856         {
05857                 return;
05858         }
05859 
05860         VectorCopy( cent->lerpOrigin, org );
05861 
05862         if ( CG_WorldCoordToScreenCoord( org, &cx, &cy ))
05863         {
05864                 // we care about distance from enemy to eye, so this is good enough
05865                 float sz = Distance( cent->lerpOrigin, cg.refdef.vieworg ) / 1024.0f; 
05866                 
05867                 if ( sz > 1.0f )
05868                 {
05869                         sz = 1.0f;
05870                 }
05871                 else if ( sz < 0.0f )
05872                 {
05873                         sz = 0.0f;
05874                 }
05875 
05876                 sz = (1.0f - sz) * (1.0f - sz) * 32 + 6;
05877 
05878                 cy += sz * 0.5f;
05879                 
05880                 if ( dif < 0 )
05881                 {
05882                         oldDif = 0;
05883                         return;
05884                 }
05885                 else if ( dif > 8 )
05886                 {
05887                         dif = 8;
05888                 }
05889 
05890                 // do sounds
05891                 if ( oldDif != dif )
05892                 {
05893                         if ( dif == 8 )
05894                         {
05895                                 if ( cg.snap->ps.m_iVehicleNum )
05896                                 {
05897                                         trap_S_StartSound( org, 0, CHAN_AUTO, trap_S_RegisterSound( "sound/vehicles/weapons/common/lock.wav" ));
05898                                 }
05899                                 else
05900                                 {
05901                                         trap_S_StartSound( org, 0, CHAN_AUTO, trap_S_RegisterSound( "sound/weapons/rocket/lock.wav" ));
05902                                 }
05903                         }
05904                         else
05905                         {
05906                                 if ( cg.snap->ps.m_iVehicleNum )
05907                                 {
05908                                         trap_S_StartSound( org, 0, CHAN_AUTO, trap_S_RegisterSound( "sound/vehicles/weapons/common/tick.wav" ));
05909                                 }
05910                                 else
05911                                 {
05912                                         trap_S_StartSound( org, 0, CHAN_AUTO, trap_S_RegisterSound( "sound/weapons/rocket/tick.wav" ));
05913                                 }
05914                         }
05915                 }
05916 
05917                 oldDif = dif;
05918 
05919                 for ( i = 0; i < dif; i++ )
05920                 {
05921                         color[0] = 1.0f;
05922                         color[1] = 0.0f;
05923                         color[2] = 0.0f;
05924                         color[3] = 0.1f * i + 0.2f;
05925 
05926                         trap_R_SetColor( color );
05927 
05928                         // our slices are offset by about 45 degrees.
05929                         CG_DrawRotatePic( cx - sz, cy - sz, sz, sz, i * 45.0f, trap_R_RegisterShaderNoMip( "gfx/2d/wedge" ));
05930                 }
05931 
05932                 // we are locked and loaded baby
05933                 if ( dif == 8 )
05934                 {
05935                         color[0] = color[1] = color[2] = sin( cg.time * 0.05f ) * 0.5f + 0.5f;
05936                         color[3] = 1.0f; // this art is additive, so the alpha value does nothing
05937 
05938                         trap_R_SetColor( color );
05939 
05940                         CG_DrawPic( cx - sz, cy - sz * 2, sz * 2, sz * 2, trap_R_RegisterShaderNoMip( "gfx/2d/lock" ));
05941                 }
05942         }
05943 }
05944 
05945 extern void CG_CalcVehMuzzle(Vehicle_t *pVeh, centity_t *ent, int muzzleNum);
05946 qboolean CG_CalcVehicleMuzzlePoint( int entityNum, vec3_t start, vec3_t d_f, vec3_t d_rt, vec3_t d_up)
05947 {
05948         centity_t *vehCent = &cg_entities[entityNum];
05949         if ( vehCent->m_pVehicle && vehCent->m_pVehicle->m_pVehicleInfo->type == VH_WALKER )
05950         {//draw from barrels
05951                 VectorCopy( vehCent->lerpOrigin, start );
05952                 start[2] += vehCent->m_pVehicle->m_pVehicleInfo->height-DEFAULT_MINS_2-48;
05953                 AngleVectors( vehCent->lerpAngles, d_f, d_rt, d_up );
05954                 /*
05955                 mdxaBone_t              boltMatrix;
05956                 int                             bolt;
05957                 vec3_t                  yawOnlyAngles;
05958                 
05959                 VectorSet( yawOnlyAngles, 0, vehCent->lerpAngles[YAW], 0 );
05960 
05961                 bolt = trap_G2API_AddBolt( vehCent->ghoul2, 0, "*flash1");
05962                 trap_G2API_GetBoltMatrix( vehCent->ghoul2, 0, bolt, &boltMatrix, 
05963                                                                         yawOnlyAngles, vehCent->lerpOrigin, cg.time, 
05964                                                                         NULL, vehCent->modelScale );
05965 
05966                 // work the matrix axis stuff into the original axis and origins used.
05967                 BG_GiveMeVectorFromMatrix( &boltMatrix, ORIGIN, start );
05968                 BG_GiveMeVectorFromMatrix( &boltMatrix, POSITIVE_X, d_f );
05969                 VectorClear( d_rt );//don't really need this, do we?
05970                 VectorClear( d_up );//don't really need this, do we?
05971                 */
05972         }
05973         else
05974         {
05975                 //check to see if we're a turret gunner on this vehicle
05976                 if ( cg.predictedPlayerState.generic1 )//as a passenger
05977                 {//passenger in a vehicle
05978                         if ( vehCent->m_pVehicle
05979                                 && vehCent->m_pVehicle->m_pVehicleInfo 
05980                                 && vehCent->m_pVehicle->m_pVehicleInfo->maxPassengers )
05981                         {//a vehicle capable of carrying passengers
05982                                 int turretNum;
05983                                 for ( turretNum = 0; turretNum < MAX_VEHICLE_TURRETS; turretNum++ )
05984                                 {
05985                                         if ( vehCent->m_pVehicle->m_pVehicleInfo->turret[turretNum].iAmmoMax )
05986                                         {// valid turret
05987                                                 if ( vehCent->m_pVehicle->m_pVehicleInfo->turret[turretNum].passengerNum == cg.predictedPlayerState.generic1 )
05988                                                 {//I control this turret
05989                                                         //Go through all muzzles, average their positions and directions and use the result for crosshair trace
05990                                                         int vehMuzzle, numMuzzles = 0;
05991                                                         vec3_t  muzzlesAvgPos={0},muzzlesAvgDir={0};
05992                                                         int     i;
05993 
05994                                                         for ( i = 0; i < MAX_VEHICLE_TURRET_MUZZLES; i++ )
05995                                                         {
05996                                                                 vehMuzzle = vehCent->m_pVehicle->m_pVehicleInfo->turret[turretNum].iMuzzle[i];
05997                                                                 if ( vehMuzzle )
05998                                                                 {
05999                                                                         vehMuzzle -= 1;
06000                                                                         CG_CalcVehMuzzle( vehCent->m_pVehicle, vehCent, vehMuzzle );
06001                                                                         VectorAdd( muzzlesAvgPos, vehCent->m_pVehicle->m_vMuzzlePos[vehMuzzle], muzzlesAvgPos );
06002                                                                         VectorAdd( muzzlesAvgDir, vehCent->m_pVehicle->m_vMuzzleDir[vehMuzzle], muzzlesAvgDir );
06003                                                                         numMuzzles++;
06004                                                                 }
06005                                                                 if ( numMuzzles )
06006                                                                 {
06007                                                                         VectorScale( muzzlesAvgPos, 1.0f/(float)numMuzzles, start );
06008                                                                         VectorScale( muzzlesAvgDir, 1.0f/(float)numMuzzles, d_f );
06009                                                                         VectorClear( d_rt );
06010                                                                         VectorClear( d_up );
06011                                                                         return qtrue;
06012                                                                 }
06013                                                         }
06014                                                 }
06015                                         }
06016                                 }
06017                         }
06018                 }
06019                 VectorCopy( vehCent->lerpOrigin, start );
06020                 AngleVectors( vehCent->lerpAngles, d_f, d_rt, d_up );
06021         }
06022         return qfalse;
06023 }
06024 
06025 //calc the muzzle point from the e-web itself
06026 void CG_CalcEWebMuzzlePoint(centity_t *cent, vec3_t start, vec3_t d_f, vec3_t d_rt, vec3_t d_up)
06027 {
06028         int bolt = trap_G2API_AddBolt(cent->ghoul2, 0, "*cannonflash");
06029 
06030         assert(bolt != -1);
06031 
06032         if (bolt != -1)
06033         {
06034                 mdxaBone_t boltMatrix;
06035 
06036                 trap_G2API_GetBoltMatrix_NoRecNoRot(cent->ghoul2, 0, bolt, &boltMatrix, cent->lerpAngles, cent->lerpOrigin, cg.time, NULL, cent->modelScale);
06037                 BG_GiveMeVectorFromMatrix(&boltMatrix, ORIGIN, start);
06038                 BG_GiveMeVectorFromMatrix(&boltMatrix, NEGATIVE_X, d_f);
06039 
06040                 //these things start the shot a little inside the bbox to assure not starting in something solid
06041                 VectorMA(start, -16.0f, d_f, start);
06042 
06043                 //I guess
06044                 VectorClear( d_rt );//don't really need this, do we?
06045                 VectorClear( d_up );//don't really need this, do we?
06046         }
06047 }
06048 
06049 /*
06050 =================
06051 CG_`Entity
06052 =================
06053 */
06054 #define MAX_XHAIR_DIST_ACCURACY 20000.0f
06055 static void CG_ScanForCrosshairEntity( void ) {
06056         trace_t         trace;
06057         vec3_t          start, end;
06058         int                     content;
06059         int                     ignore;
06060         qboolean        bVehCheckTraceFromCamPos = qfalse;
06061 
06062         ignore = cg.predictedPlayerState.clientNum;
06063 
06064         if ( cg_dynamicCrosshair.integer )
06065         {
06066                 vec3_t d_f, d_rt, d_up;
06067                 /*
06068                 if ( cg.snap->ps.weapon == WP_NONE || 
06069                         cg.snap->ps.weapon == WP_SABER || 
06070                         cg.snap->ps.weapon == WP_STUN_BATON)
06071                 {
06072                         VectorCopy( cg.refdef.vieworg, start );
06073                         AngleVectors( cg.refdef.viewangles, d_f, d_rt, d_up );
06074                 }
06075                 else
06076                 */
06077                 //For now we still want to draw the crosshair in relation to the player's world coordinates
06078                 //even if we have a melee weapon/no weapon.
06079                 if ( cg.predictedPlayerState.m_iVehicleNum && (cg.predictedPlayerState.eFlags&EF_NODRAW) )
06080                 {//we're *inside* a vehicle
06081                         //do the vehicle's crosshair instead
06082                         centity_t *veh = &cg_entities[cg.predictedPlayerState.m_iVehicleNum];
06083                         qboolean gunner = qfalse;
06084 
06085                         //if (veh->currentState.owner == cg.predictedPlayerState.clientNum)
06086                         { //the pilot
06087                                 ignore = cg.predictedPlayerState.m_iVehicleNum;
06088                                 gunner = CG_CalcVehicleMuzzlePoint(cg.predictedPlayerState.m_iVehicleNum, start, d_f, d_rt, d_up);
06089                         }
06090                         /*
06091                         else
06092                         { //a passenger
06093                                 ignore = cg.predictedPlayerState.m_iVehicleNum;
06094                                 VectorCopy( veh->lerpOrigin, start );
06095                                 AngleVectors( veh->lerpAngles, d_f, d_rt, d_up );
06096                                 VectorMA(start, 32.0f, d_f, start); //super hack
06097                         }
06098                         */
06099                         if ( veh->m_pVehicle 
06100                                 && veh->m_pVehicle->m_pVehicleInfo 
06101                                 && veh->m_pVehicle->m_pVehicleInfo->type == VH_FIGHTER 
06102                                 && cg.distanceCull > MAX_XHAIR_DIST_ACCURACY 
06103                                 && !gunner )
06104                         {       
06105                                 //NOTE: on huge maps, the crosshair gets inaccurate at close range, 
06106                                 //              so we'll do an extra G2 trace from the cg.refdef.vieworg
06107                                 //              to see if we hit anything closer and auto-aim at it if so
06108                                 bVehCheckTraceFromCamPos = qtrue;
06109                         }
06110                 }
06111                 else if (cg.snap && cg.snap->ps.weapon == WP_EMPLACED_GUN && cg.snap->ps.emplacedIndex &&
06112                         cg_entities[cg.snap->ps.emplacedIndex].ghoul2 && cg_entities[cg.snap->ps.emplacedIndex].currentState.weapon == WP_NONE)
06113                 { //locked into our e-web, calc the muzzle from it
06114                         CG_CalcEWebMuzzlePoint(&cg_entities[cg.snap->ps.emplacedIndex], start, d_f, d_rt, d_up);
06115                 }
06116                 else
06117                 {
06118                         if (cg.snap && cg.snap->ps.weapon == WP_EMPLACED_GUN && cg.snap->ps.emplacedIndex)
06119                         {
06120                                 vec3_t pitchConstraint;
06121 
06122                                 ignore = cg.snap->ps.emplacedIndex;
06123 
06124                                 VectorCopy(cg.refdef.viewangles, pitchConstraint);
06125 
06126                                 if (cg.renderingThirdPerson)
06127                                 {
06128                                         VectorCopy(cg.predictedPlayerState.viewangles, pitchConstraint);
06129                                 }
06130                                 else
06131                                 {
06132                                         VectorCopy(cg.refdef.viewangles, pitchConstraint);
06133                                 }
06134 
06135                                 if (pitchConstraint[PITCH] > 40)
06136                                 {
06137                                         pitchConstraint[PITCH] = 40;
06138                                 }
06139 
06140                                 AngleVectors( pitchConstraint, d_f, d_rt, d_up );
06141                         }
06142                         else
06143                         {
06144                                 vec3_t pitchConstraint;
06145 
06146                                 if (cg.renderingThirdPerson)
06147                                 {
06148                                         VectorCopy(cg.predictedPlayerState.viewangles, pitchConstraint);
06149                                 }
06150                                 else
06151                                 {
06152                                         VectorCopy(cg.refdef.viewangles, pitchConstraint);
06153                                 }
06154 
06155                                 AngleVectors( pitchConstraint, d_f, d_rt, d_up );
06156                         }
06157                         CG_CalcMuzzlePoint(cg.snap->ps.clientNum, start);
06158                 }
06159 
06160                 VectorMA( start, cg.distanceCull, d_f, end );
06161         }
06162         else
06163         {
06164                 VectorCopy( cg.refdef.vieworg, start );
06165                 VectorMA( start, 131072, cg.refdef.viewaxis[0], end );
06166         }
06167 
06168         if ( cg_dynamicCrosshair.integer && cg_dynamicCrosshairPrecision.integer )
06169         { //then do a trace with ghoul2 models in mind
06170                 CG_G2Trace( &trace, start, vec3_origin, vec3_origin, end, 
06171                         ignore, CONTENTS_SOLID|CONTENTS_BODY );
06172                 if ( bVehCheckTraceFromCamPos )
06173                 {
06174                         //NOTE: this MUST stay up to date with the method used in WP_VehCheckTraceFromCamPos
06175                         centity_t *veh = &cg_entities[cg.predictedPlayerState.m_iVehicleNum];
06176                         trace_t extraTrace;
06177                         vec3_t  viewDir2End, extraEnd;
06178                         float   minAutoAimDist = Distance( veh->lerpOrigin, cg.refdef.vieworg ) + (veh->m_pVehicle->m_pVehicleInfo->length/2.0f) + 200.0f;
06179 
06180                         VectorSubtract( end, cg.refdef.vieworg, viewDir2End );
06181                         VectorNormalize( viewDir2End );
06182                         VectorMA( cg.refdef.vieworg, MAX_XHAIR_DIST_ACCURACY, viewDir2End, extraEnd );
06183                         CG_G2Trace( &extraTrace, cg.refdef.vieworg, vec3_origin, vec3_origin, extraEnd, 
06184                                 ignore, CONTENTS_SOLID|CONTENTS_BODY );
06185                         if ( !extraTrace.allsolid
06186                                 && !extraTrace.startsolid )
06187                         {
06188                                 if ( extraTrace.fraction < 1.0f )
06189                                 {
06190                                         if ( (extraTrace.fraction*MAX_XHAIR_DIST_ACCURACY) > minAutoAimDist )
06191                                         {
06192                                                 if ( ((extraTrace.fraction*MAX_XHAIR_DIST_ACCURACY)-Distance( veh->lerpOrigin, cg.refdef.vieworg )) < (trace.fraction*cg.distanceCull) )
06193                                                 {//this trace hit *something* that's closer than the thing the main trace hit, so use this result instead
06194                                                         memcpy( &trace, &extraTrace, sizeof( trace_t ) );
06195                                                 }
06196                                         }
06197                                 }
06198                         }
06199                 }
06200         }
06201         else
06202         {
06203                 CG_Trace( &trace, start, vec3_origin, vec3_origin, end, 
06204                         ignore, CONTENTS_SOLID|CONTENTS_BODY );
06205         }
06206 
06207         if (trace.entityNum < MAX_CLIENTS)
06208         {
06209                 if (CG_IsMindTricked(cg_entities[trace.entityNum].currentState.trickedentindex,
06210                         cg_entities[trace.entityNum].currentState.trickedentindex2,
06211                         cg_entities[trace.entityNum].currentState.trickedentindex3,
06212                         cg_entities[trace.entityNum].currentState.trickedentindex4,
06213                         cg.snap->ps.clientNum))
06214                 {
06215                         if (cg.crosshairClientNum == trace.entityNum)
06216                         {
06217                                 cg.crosshairClientNum = ENTITYNUM_NONE;
06218                                 cg.crosshairClientTime = 0;
06219                         }
06220 
06221                         CG_DrawCrosshair(trace.endpos, 0);
06222 
06223                         return; //this entity is mind-tricking the current client, so don't render it
06224                 }
06225         }
06226 
06227         if (cg.snap->ps.persistant[PERS_TEAM] != TEAM_SPECTATOR)
06228         {
06229                 if (trace.entityNum < /*MAX_CLIENTS*/ENTITYNUM_WORLD)
06230                 {
06231                         cg.crosshairClientNum = trace.entityNum;
06232                         cg.crosshairClientTime = cg.time;
06233 
06234                         if (cg.crosshairClientNum < ENTITYNUM_WORLD)
06235                         {
06236                                 centity_t *veh = &cg_entities[cg.crosshairClientNum];
06237 
06238                                 if (veh->currentState.eType == ET_NPC &&
06239                                         veh->currentState.NPC_class == CLASS_VEHICLE &&
06240                                         veh->currentState.owner < MAX_CLIENTS)
06241                                 { //draw the name of the pilot then
06242                                         cg.crosshairClientNum = veh->currentState.owner;
06243                                         cg.crosshairVehNum = veh->currentState.number;
06244                                         cg.crosshairVehTime = cg.time;
06245                                 }
06246                         }
06247 
06248                         CG_DrawCrosshair(trace.endpos, 1);
06249                 }
06250                 else
06251                 {
06252                         CG_DrawCrosshair(trace.endpos, 0);
06253                 }
06254         }
06255 
06256 //      if ( trace.entityNum >= MAX_CLIENTS ) {
06257 //              return;
06258 //      }
06259 
06260         // if the player is in fog, don't show it
06261         content = trap_CM_PointContents( trace.endpos, 0 );
06262         if ( content & CONTENTS_FOG ) {
06263                 return;
06264         }
06265 
06266         // update the fade timer
06267         cg.crosshairClientNum = trace.entityNum;
06268         cg.crosshairClientTime = cg.time;
06269 }
06270 
06271 void CG_SanitizeString( char *in, char *out )
06272 {
06273         int i = 0;
06274         int r = 0;
06275 
06276         while (in[i])
06277         {
06278                 if (i >= 128-1)
06279                 { //the ui truncates the name here..
06280                         break;
06281                 }
06282 
06283                 if (in[i] == '^')
06284                 {
06285                         if (in[i+1] >= 48 && //'0'
06286                                 in[i+1] <= 57) //'9'
06287                         { //only skip it if there's a number after it for the color
06288                                 i += 2;
06289                                 continue;
06290                         }
06291                         else
06292                         { //just skip the ^
06293                                 i++;
06294                                 continue;
06295                         }
06296                 }
06297 
06298                 if (in[i] < 32)
06299                 {
06300                         i++;
06301                         continue;
06302                 }
06303 
06304                 out[r] = in[i];
06305                 r++;
06306                 i++;
06307         }
06308         out[r] = 0;
06309 }
06310 
06311 /*
06312 =====================
06313 CG_DrawCrosshairNames
06314 =====================
06315 */
06316 static void CG_DrawCrosshairNames( void ) {
06317         float           *color;
06318         vec4_t          tcolor;
06319         char            *name;
06320         char            sanitized[1024];
06321         int                     baseColor;
06322         qboolean        isVeh = qfalse;
06323 
06324         if ( !cg_drawCrosshair.integer ) {
06325                 return;
06326         }
06327 
06328         // scan the known entities to see if the crosshair is sighted on one
06329         CG_ScanForCrosshairEntity();
06330 
06331         if ( !cg_drawCrosshairNames.integer ) {
06332                 return;
06333         }
06334         //rww - still do the trace, our dynamic crosshair depends on it
06335 
06336         if (cg.crosshairClientNum < ENTITYNUM_WORLD)
06337         {
06338                 centity_t *veh = &cg_entities[cg.crosshairClientNum];
06339 
06340                 if (veh->currentState.eType == ET_NPC &&
06341                         veh->currentState.NPC_class == CLASS_VEHICLE &&
06342                         veh->currentState.owner < MAX_CLIENTS)
06343                 { //draw the name of the pilot then
06344                         cg.crosshairClientNum = veh->currentState.owner;
06345                         cg.crosshairVehNum = veh->currentState.number;
06346                         cg.crosshairVehTime = cg.time;
06347                         isVeh = qtrue; //so we know we're drawing the pilot's name
06348                 }
06349         }
06350 
06351         if (cg.crosshairClientNum >= MAX_CLIENTS)
06352         {
06353                 return;
06354         }
06355 
06356         if (cg_entities[cg.crosshairClientNum].currentState.powerups & (1 << PW_CLOAKED))
06357         {
06358                 return;
06359         }
06360 
06361         // draw the name of the player being looked at
06362         color = CG_FadeColor( cg.crosshairClientTime, 1000 );
06363         if ( !color ) {
06364                 trap_R_SetColor( NULL );
06365                 return;
06366         }
06367 
06368         name = cgs.clientinfo[ cg.crosshairClientNum ].name;
06369 
06370         if (cgs.gametype >= GT_TEAM)
06371         {
06372                 //if (cgs.gametype == GT_SIEGE)
06373                 if (1)
06374                 { //instead of team-based we'll make it oriented based on which team we're on
06375                         if (cgs.clientinfo[cg.crosshairClientNum].team == cg.predictedPlayerState.persistant[PERS_TEAM])
06376                         {
06377                                 baseColor = CT_GREEN;
06378                         }
06379                         else
06380                         {
06381                                 baseColor = CT_RED;
06382                         }
06383                 }
06384                 else
06385                 {
06386                         if (cgs.clientinfo[cg.crosshairClientNum].team == TEAM_RED)
06387                         {
06388                                 baseColor = CT_RED;
06389                         }
06390                         else
06391                         {
06392                                 baseColor = CT_BLUE;
06393                         }
06394                 }
06395         }
06396         else
06397         {
06398                 //baseColor = CT_WHITE;
06399                 if (cgs.gametype == GT_POWERDUEL &&
06400                         cgs.clientinfo[cg.snap->ps.clientNum].team != TEAM_SPECTATOR &&
06401                         cgs.clientinfo[cg.crosshairClientNum].duelTeam == cgs.clientinfo[cg.predictedPlayerState.clientNum].duelTeam)
06402                 { //on the same duel team in powerduel, so he's a friend
06403                         baseColor = CT_GREEN;
06404                 }
06405                 else
06406                 {
06407                         baseColor = CT_RED; //just make it red in nonteam modes since everyone is hostile and crosshair will be red on them too
06408                 }
06409         }
06410 
06411         if (cg.snap->ps.duelInProgress)
06412         {
06413                 if (cg.crosshairClientNum != cg.snap->ps.duelIndex)
06414                 { //grey out crosshair for everyone but your foe if you're in a duel
06415                         baseColor = CT_BLACK;
06416                 }
06417         }
06418         else if (cg_entities[cg.crosshairClientNum].currentState.bolt1)
06419         { //this fellow is in a duel. We just checked if we were in a duel above, so
06420           //this means we aren't and he is. Which of course means our crosshair greys out over him.
06421                 baseColor = CT_BLACK;
06422         }
06423 
06424         tcolor[0] = colorTable[baseColor][0];
06425         tcolor[1] = colorTable[baseColor][1];
06426         tcolor[2] = colorTable[baseColor][2];
06427         tcolor[3] = color[3]*0.5f;
06428 
06429         CG_SanitizeString(name, sanitized);
06430 
06431         if (isVeh)
06432         {
06433                 char str[MAX_STRING_CHARS];
06434                 Com_sprintf(str, MAX_STRING_CHARS, "%s (pilot)", sanitized);
06435                 UI_DrawProportionalString(320, 170, str, UI_CENTER, tcolor);
06436         }
06437         else
06438         {
06439                 UI_DrawProportionalString(320, 170, sanitized, UI_CENTER, tcolor);
06440         }
06441 
06442         trap_R_SetColor( NULL );
06443 }
06444 
06445 
06446 //==============================================================================
06447 
06448 /*
06449 =================
06450 CG_DrawSpectator
06451 =================
06452 */
06453 static void CG_DrawSpectator(void) 
06454 {       
06455         const char* s;
06456 
06457         s = CG_GetStringEdString("MP_INGAME", "SPECTATOR");
06458         if ((cgs.gametype == GT_DUEL || cgs.gametype == GT_POWERDUEL) &&
06459                 cgs.duelist1 != -1 &&
06460                 cgs.duelist2 != -1)
06461         {
06462                 char text[1024];
06463                 int size = 64;
06464 
06465                 if (cgs.gametype == GT_POWERDUEL && cgs.duelist3 != -1)
06466                 {
06467                         Com_sprintf(text, sizeof(text), "%s^7 %s %s^7 %s %s", cgs.clientinfo[cgs.duelist1].name, CG_GetStringEdString("MP_INGAME", "SPECHUD_VERSUS"), cgs.clientinfo[cgs.duelist2].name, CG_GetStringEdString("MP_INGAME", "AND"), cgs.clientinfo[cgs.duelist3].name);
06468                 }
06469                 else
06470                 {
06471                         Com_sprintf(text, sizeof(text), "%s^7 %s %s", cgs.clientinfo[cgs.duelist1].name, CG_GetStringEdString("MP_INGAME", "SPECHUD_VERSUS"), cgs.clientinfo[cgs.duelist2].name);
06472                 }
06473                 CG_Text_Paint ( 320 - CG_Text_Width ( text, 1.0f, 3 ) / 2, 420, 1.0f, colorWhite, text, 0, 0, 0, 3 );
06474 
06475                 trap_R_SetColor( colorTable[CT_WHITE] );
06476                 if ( cgs.clientinfo[cgs.duelist1].modelIcon )
06477                 {
06478                         CG_DrawPic( 10, SCREEN_HEIGHT-(size*1.5), size, size, cgs.clientinfo[cgs.duelist1].modelIcon );
06479                 }
06480                 if ( cgs.clientinfo[cgs.duelist2].modelIcon )
06481                 {
06482                         CG_DrawPic( SCREEN_WIDTH-size-10, SCREEN_HEIGHT-(size*1.5), size, size, cgs.clientinfo[cgs.duelist2].modelIcon );
06483                 }
06484 
06485 // nmckenzie: DUEL_HEALTH
06486                 if (cgs.gametype == GT_DUEL)
06487                 {
06488                         if ( cgs.showDuelHealths >= 1)
06489                         {       // draw the healths on the two guys - how does this interact with power duel, though?
06490                                 CG_DrawDuelistHealth ( 10, SCREEN_HEIGHT-(size*1.5) - 12, 64, 8, 1 );
06491                                 CG_DrawDuelistHealth ( SCREEN_WIDTH-size-10, SCREEN_HEIGHT-(size*1.5) - 12, 64, 8, 2 );
06492                         }
06493                 }
06494 
06495                 if (cgs.gametype != GT_POWERDUEL)
06496                 {
06497                         Com_sprintf(text, sizeof(text), "%i/%i", cgs.clientinfo[cgs.duelist1].score, cgs.fraglimit );
06498                         CG_Text_Paint( 42 - CG_Text_Width( text, 1.0f, 2 ) / 2, SCREEN_HEIGHT-(size*1.5) + 64, 1.0f, colorWhite, text, 0, 0, 0, 2 );
06499 
06500                         Com_sprintf(text, sizeof(text), "%i/%i", cgs.clientinfo[cgs.duelist2].score, cgs.fraglimit );
06501                         CG_Text_Paint( SCREEN_WIDTH-size+22 - CG_Text_Width( text, 1.0f, 2 ) / 2, SCREEN_HEIGHT-(size*1.5) + 64, 1.0f, colorWhite, text, 0, 0, 0, 2 );
06502                 }
06503 
06504                 if (cgs.gametype == GT_POWERDUEL && cgs.duelist3 != -1)
06505                 {
06506                         if ( cgs.clientinfo[cgs.duelist3].modelIcon )
06507                         {
06508                                 CG_DrawPic( SCREEN_WIDTH-size-10, SCREEN_HEIGHT-(size*2.8), size, size, cgs.clientinfo[cgs.duelist3].modelIcon );
06509                         }
06510                 }
06511         }
06512         else
06513         {
06514                 CG_Text_Paint ( 320 - CG_Text_Width ( s, 1.0f, 3 ) / 2, 420, 1.0f, colorWhite, s, 0, 0, 0, 3 );
06515         }
06516 
06517         if ( cgs.gametype == GT_DUEL || cgs.gametype == GT_POWERDUEL ) 
06518         {
06519                 s = CG_GetStringEdString("MP_INGAME", "WAITING_TO_PLAY");       // "waiting to play";
06520                 CG_Text_Paint ( 320 - CG_Text_Width ( s, 1.0f, 3 ) / 2, 440, 1.0f, colorWhite, s, 0, 0, 0, 3 );
06521         }
06522         else //if ( cgs.gametype >= GT_TEAM ) 
06523         {
06524                 //s = "press ESC and use the JOIN menu to play";
06525                 s = CG_GetStringEdString("MP_INGAME", "SPEC_CHOOSEJOIN");
06526                 CG_Text_Paint ( 320 - CG_Text_Width ( s, 1.0f, 3 ) / 2, 440, 1.0f, colorWhite, s, 0, 0, 0, 3 );
06527         }
06528 }
06529 
06530 /*
06531 =================
06532 CG_DrawVote
06533 =================
06534 */
06535 static void CG_DrawVote(void) {
06536         const char      *s;
06537         int             sec;
06538         char                                                    sYes[20];
06539         char                                                    sNo[20];
06540         char                                                    sVote[20];
06541         char                                                    sCmd[100];
06542         const char*                                             sParm = 0;
06543 
06544         if ( !cgs.voteTime ) {
06545                 return;
06546         }
06547 
06548         // play a talk beep whenever it is modified
06549         if ( cgs.voteModified ) {
06550                 cgs.voteModified = qfalse;
06551 //              trap_S_StartLocalSound( cgs.media.talkSound, CHAN_LOCAL_SOUND );
06552         }
06553 
06554         sec = ( VOTE_TIME - ( cg.time - cgs.voteTime ) ) / 1000;
06555         if ( sec < 0 ) {
06556                 sec = 0;
06557         }
06558 
06559         if (strncmp(cgs.voteString, "map_restart", 11)==0)
06560         {
06561                 trap_SP_GetStringTextString("MENUS_RESTART_MAP", sCmd, sizeof(sCmd) );
06562         }
06563         else if (strncmp(cgs.voteString, "vstr nextmap", 12)==0)
06564         {
06565                 trap_SP_GetStringTextString("MENUS_NEXT_MAP", sCmd, sizeof(sCmd) );
06566         }
06567         else if (strncmp(cgs.voteString, "g_doWarmup", 10)==0)
06568         {
06569                 trap_SP_GetStringTextString("MENUS_WARMUP", sCmd, sizeof(sCmd) );
06570         }
06571         else if (strncmp(cgs.voteString, "g_gametype", 10)==0)
06572         {
06573                 trap_SP_GetStringTextString("MENUS_GAME_TYPE", sCmd, sizeof(sCmd) );
06574                 if      ( stricmp("Free For All", cgs.voteString+11)==0 ) 
06575                 {
06576                         sParm = CG_GetStringEdString("MENUS", "FREE_FOR_ALL");
06577                 }
06578                 else if ( stricmp("Duel", cgs.voteString+11)==0 ) 
06579                 {
06580                         sParm = CG_GetStringEdString("MENUS", "DUEL");
06581                 }
06582                 else if ( stricmp("Holocron FFA", cgs.voteString+11)==0  ) 
06583                 {
06584                         sParm = CG_GetStringEdString("MENUS", "HOLOCRON_FFA");
06585                 }
06586                 else if ( stricmp("Power Duel", cgs.voteString+11)==0  ) 
06587                 {
06588                         sParm = CG_GetStringEdString("MENUS", "POWERDUEL");
06589                 }
06590                 else if ( stricmp("Team FFA", cgs.voteString+11)==0  ) 
06591                 {
06592                         sParm = CG_GetStringEdString("MENUS", "TEAM_FFA");
06593                 }
06594                 else if ( stricmp("Siege", cgs.voteString+11)==0  ) 
06595                 {
06596                         sParm = CG_GetStringEdString("MENUS", "SIEGE");
06597                 }
06598                 else if ( stricmp("Capture the Flag", cgs.voteString+11)==0  ) 
06599                 {
06600                         sParm = CG_GetStringEdString("MENUS", "CAPTURE_THE_FLAG");
06601                 }
06602                 else if ( stricmp("Capture the Ysalamiri", cgs.voteString+11)==0  ) 
06603                 {
06604                         sParm = CG_GetStringEdString("MENUS", "CAPTURE_THE_YSALIMARI");
06605                 } 
06606         }
06607         else if (strncmp(cgs.voteString, "map", 3)==0)
06608         {
06609                 trap_SP_GetStringTextString("MENUS_NEW_MAP", sCmd, sizeof(sCmd) );
06610                 sParm = cgs.voteString+4;
06611         }
06612         else if (strncmp(cgs.voteString, "kick", 4)==0)
06613         {
06614                 trap_SP_GetStringTextString("MENUS_KICK_PLAYER", sCmd, sizeof(sCmd) );
06615                 sParm = cgs.voteString+5;
06616         }
06617 
06618 
06619 
06620         trap_SP_GetStringTextString("MENUS_VOTE", sVote, sizeof(sVote) );
06621         trap_SP_GetStringTextString("MENUS_YES", sYes, sizeof(sYes) );
06622         trap_SP_GetStringTextString("MENUS_NO",  sNo,  sizeof(sNo) );
06623 
06624         if (sParm && sParm[0])
06625         {
06626                 s = va("%s(%i):<%s %s> %s:%i %s:%i", sVote, sec, sCmd, sParm, sYes, cgs.voteYes, sNo, cgs.voteNo);
06627         }
06628         else
06629         {
06630                 s = va("%s(%i):<%s> %s:%i %s:%i",    sVote, sec, sCmd,        sYes, cgs.voteYes, sNo, cgs.voteNo);
06631         }
06632         CG_DrawSmallString( 4, 58, s, 1.0F );
06633         s = CG_GetStringEdString("MP_INGAME", "OR_PRESS_ESC_THEN_CLICK_VOTE");  //      s = "or press ESC then click Vote";
06634         CG_DrawSmallString( 4, 58 + SMALLCHAR_HEIGHT + 2, s, 1.0F );
06635 }
06636 
06637 /*
06638 =================
06639 CG_DrawTeamVote
06640 =================
06641 */
06642 static void CG_DrawTeamVote(void) {
06643         char    *s;
06644         int             sec, cs_offset;
06645 
06646         if ( cgs.clientinfo->team == TEAM_RED )
06647                 cs_offset = 0;
06648         else if ( cgs.clientinfo->team == TEAM_BLUE )
06649                 cs_offset = 1;
06650         else
06651                 return;
06652 
06653         if ( !cgs.teamVoteTime[cs_offset] ) {
06654                 return;
06655         }
06656 
06657         // play a talk beep whenever it is modified
06658         if ( cgs.teamVoteModified[cs_offset] ) {
06659                 cgs.teamVoteModified[cs_offset] = qfalse;
06660 //              trap_S_StartLocalSound( cgs.media.talkSound, CHAN_LOCAL_SOUND );
06661         }
06662 
06663         sec = ( VOTE_TIME - ( cg.time - cgs.teamVoteTime[cs_offset] ) ) / 1000;
06664         if ( sec < 0 ) {
06665                 sec = 0;
06666         }
06667         if (strstr(cgs.teamVoteString[cs_offset], "leader"))
06668         {
06669                 int i = 0;
06670 
06671                 while (cgs.teamVoteString[cs_offset][i] && cgs.teamVoteString[cs_offset][i] != ' ')
06672                 {
06673                         i++;
06674                 }
06675 
06676                 if (cgs.teamVoteString[cs_offset][i] == ' ')
06677                 {
06678                         int voteIndex = 0;
06679                         char voteIndexStr[256];
06680 
06681                         i++;
06682 
06683                         while (cgs.teamVoteString[cs_offset][i])
06684                         {
06685                                 voteIndexStr[voteIndex] = cgs.teamVoteString[cs_offset][i];
06686                                 voteIndex++;
06687                                 i++;
06688                         }
06689                         voteIndexStr[voteIndex] = 0;
06690 
06691                         voteIndex = atoi(voteIndexStr);
06692 
06693                         s = va("TEAMVOTE(%i):(Make %s the new team leader) yes:%i no:%i", sec, cgs.clientinfo[voteIndex].name,
06694                                                                         cgs.teamVoteYes[cs_offset], cgs.teamVoteNo[cs_offset] );
06695                 }
06696                 else
06697                 {
06698                         s = va("TEAMVOTE(%i):%s yes:%i no:%i", sec, cgs.teamVoteString[cs_offset],
06699                                                                         cgs.teamVoteYes[cs_offset], cgs.teamVoteNo[cs_offset] );
06700                 }
06701         }
06702         else
06703         {
06704                 s = va("TEAMVOTE(%i):%s yes:%i no:%i", sec, cgs.teamVoteString[cs_offset],
06705                                                                 cgs.teamVoteYes[cs_offset], cgs.teamVoteNo[cs_offset] );
06706         }
06707         CG_DrawSmallString( 4, 90, s, 1.0F );
06708 }
06709 
06710 static qboolean CG_DrawScoreboard() {
06711         return CG_DrawOldScoreboard();
06712 #if 0
06713         static qboolean firstTime = qtrue;
06714         float fade, *fadeColor;
06715 
06716         if (menuScoreboard) {
06717                 menuScoreboard->window.flags &= ~WINDOW_FORCED;
06718         }
06719         if (cg_paused.integer) {
06720                 cg.deferredPlayerLoading = 0;
06721                 firstTime = qtrue;
06722                 return qfalse;
06723         }
06724 
06725         // should never happen in Team Arena
06726         if (cgs.gametype == GT_SINGLE_PLAYER && cg.predictedPlayerState.pm_type == PM_INTERMISSION ) {
06727                 cg.deferredPlayerLoading = 0;
06728                 firstTime = qtrue;
06729                 return qfalse;
06730         }
06731 
06732         // don't draw scoreboard during death while warmup up
06733         if ( cg.warmup && !cg.showScores ) {
06734                 return qfalse;
06735         }
06736 
06737         if ( cg.showScores || cg.predictedPlayerState.pm_type == PM_DEAD || cg.predictedPlayerState.pm_type == PM_INTERMISSION ) {
06738                 fade = 1.0;
06739                 fadeColor = colorWhite;
06740         } else {
06741                 fadeColor = CG_FadeColor( cg.scoreFadeTime, FADE_TIME );
06742                 if ( !fadeColor ) {
06743                         // next time scoreboard comes up, don't print killer
06744                         cg.deferredPlayerLoading = 0;
06745                         cg.killerName[0] = 0;
06746                         firstTime = qtrue;
06747                         return qfalse;
06748                 }
06749                 fade = *fadeColor;
06750         }                                                                                                                                                                         
06751 
06752 
06753         if (menuScoreboard == NULL) {
06754                 if ( cgs.gametype >= GT_TEAM ) {
06755                         menuScoreboard = Menus_FindByName("teamscore_menu");
06756                 } else {
06757                         menuScoreboard = Menus_FindByName("score_menu");
06758                 }
06759         }
06760 
06761         if (menuScoreboard) {
06762                 if (firstTime) {
06763                         CG_SetScoreSelection(menuScoreboard);
06764                         firstTime = qfalse;
06765                 }
06766                 Menu_Paint(menuScoreboard, qtrue);
06767         }
06768 
06769         // load any models that have been deferred
06770         if ( ++cg.deferredPlayerLoading > 10 ) {
06771                 CG_LoadDeferredPlayers();
06772         }
06773 
06774         return qtrue;
06775 #endif
06776 }
06777 
06778 /*
06779 =================
06780 CG_DrawIntermission
06781 =================
06782 */
06783 static void CG_DrawIntermission( void ) {
06784 //      int key;
06785         //if (cg_singlePlayer.integer) {
06786         //      CG_DrawCenterString();
06787         //      return;
06788         //}
06789         cg.scoreFadeTime = cg.time;
06790         cg.scoreBoardShowing = CG_DrawScoreboard();
06791 }
06792 
06793 /*
06794 =================
06795 CG_DrawFollow
06796 =================
06797 */
06798 static qboolean CG_DrawFollow( void ) 
06799 {
06800         const char      *s;
06801 
06802         if ( !(cg.snap->ps.pm_flags & PMF_FOLLOW) ) 
06803         {
06804                 return qfalse;
06805         }
06806 
06807 //      s = "following";
06808         if (cgs.gametype == GT_POWERDUEL)
06809         {
06810                 clientInfo_t *ci = &cgs.clientinfo[ cg.snap->ps.clientNum ];
06811 
06812                 if (ci->duelTeam == DUELTEAM_LONE)
06813                 {
06814                         s = CG_GetStringEdString("MP_INGAME", "FOLLOWINGLONE");
06815                 }
06816                 else if (ci->duelTeam == DUELTEAM_DOUBLE)
06817                 {
06818                         s = CG_GetStringEdString("MP_INGAME", "FOLLOWINGDOUBLE");
06819                 }
06820                 else
06821                 {
06822                         s = CG_GetStringEdString("MP_INGAME", "FOLLOWING");
06823                 }
06824         }
06825         else
06826         {
06827                 s = CG_GetStringEdString("MP_INGAME", "FOLLOWING");
06828         }
06829 
06830         CG_Text_Paint ( 320 - CG_Text_Width ( s, 1.0f, FONT_MEDIUM ) / 2, 60, 1.0f, colorWhite, s, 0, 0, 0, FONT_MEDIUM );
06831 
06832         s = cgs.clientinfo[ cg.snap->ps.clientNum ].name;
06833         CG_Text_Paint ( 320 - CG_Text_Width ( s, 2.0f, FONT_MEDIUM ) / 2, 80, 2.0f, colorWhite, s, 0, 0, 0, FONT_MEDIUM );
06834 
06835         return qtrue;
06836 }
06837 
06838 #if 0
06839 static void CG_DrawTemporaryStats()
06840 { //placeholder for testing (draws ammo and force power)
06841         char s[512];
06842 
06843         if (!cg.snap)
06844         {
06845                 return;
06846         }
06847 
06848         sprintf(s, "Force: %i", cg.snap->ps.fd.forcePower);
06849 
06850         CG_DrawBigString(SCREEN_WIDTH-164, SCREEN_HEIGHT-dmgIndicSize, s, 1.0f);
06851 
06852         sprintf(s, "Ammo: %i", cg.snap->ps.ammo[weaponData[cg.snap->ps.weapon].ammoIndex]);
06853 
06854         CG_DrawBigString(SCREEN_WIDTH-164, SCREEN_HEIGHT-112, s, 1.0f);
06855 
06856         sprintf(s, "Health: %i", cg.snap->ps.stats[STAT_HEALTH]);
06857 
06858         CG_DrawBigString(8, SCREEN_HEIGHT-dmgIndicSize, s, 1.0f);
06859 
06860         sprintf(s, "Armor: %i", cg.snap->ps.stats[STAT_ARMOR]);
06861 
06862         CG_DrawBigString(8, SCREEN_HEIGHT-112, s, 1.0f);
06863 }
06864 #endif
06865 
06866 /*
06867 =================
06868 CG_DrawAmmoWarning
06869 =================
06870 */
06871 static void CG_DrawAmmoWarning( void ) {
06872 #if 0
06873         const char      *s;
06874         int                     w;
06875 
06876         if (!cg_drawStatus.integer)
06877         {
06878                 return;
06879         }
06880 
06881         if ( cg_drawAmmoWarning.integer == 0 ) {
06882                 return;
06883         }
06884 
06885         if ( !cg.lowAmmoWarning ) {
06886                 return;
06887         }
06888 
06889         if ( cg.lowAmmoWarning == 2 ) {
06890                 s = "OUT OF AMMO";
06891         } else {
06892                 s = "LOW AMMO WARNING";
06893         }
06894         w = CG_DrawStrlen( s ) * BIGCHAR_WIDTH;
06895         CG_DrawBigString(320 - w / 2, 64, s, 1.0F);
06896 #endif
06897 }
06898 
06899 
06900 
06901 /*
06902 =================
06903 CG_DrawWarmup
06904 =================
06905 */
06906 static void CG_DrawWarmup( void ) {
06907         int                     w;
06908         int                     sec;
06909         int                     i;
06910         float scale;
06911         int                     cw;
06912         const char      *s;
06913 
06914         sec = cg.warmup;
06915         if ( !sec ) {
06916                 return;
06917         }
06918 
06919         if ( sec < 0 ) {
06920 //              s = "Waiting for players";              
06921                 s = CG_GetStringEdString("MP_INGAME", "WAITING_FOR_PLAYERS");
06922                 w = CG_DrawStrlen( s ) * BIGCHAR_WIDTH;
06923                 CG_DrawBigString(320 - w / 2, 24, s, 1.0F);
06924                 cg.warmupCount = 0;
06925                 return;
06926         }
06927 
06928         if (cgs.gametype == GT_DUEL || cgs.gametype == GT_POWERDUEL)
06929         {
06930                 // find the two active players
06931                 clientInfo_t    *ci1, *ci2, *ci3;
06932 
06933                 ci1 = NULL;
06934                 ci2 = NULL;
06935                 ci3 = NULL;
06936 
06937                 if (cgs.gametype == GT_POWERDUEL)
06938                 {
06939                         if (cgs.duelist1 != -1)
06940                         {
06941                                 ci1 = &cgs.clientinfo[cgs.duelist1];
06942                         }
06943                         if (cgs.duelist2 != -1)
06944                         {
06945                                 ci2 = &cgs.clientinfo[cgs.duelist2];
06946                         }
06947                         if (cgs.duelist3 != -1)
06948                         {
06949                                 ci3 = &cgs.clientinfo[cgs.duelist3];
06950                         }
06951                 }
06952                 else
06953                 {
06954                         for ( i = 0 ; i < cgs.maxclients ; i++ ) {
06955                                 if ( cgs.clientinfo[i].infoValid && cgs.clientinfo[i].team == TEAM_FREE ) {
06956                                         if ( !ci1 ) {
06957                                                 ci1 = &cgs.clientinfo[i];
06958                                         } else {
06959                                                 ci2 = &cgs.clientinfo[i];
06960                                         }
06961                                 }
06962                         }
06963                 }
06964                 if ( ci1 && ci2 )
06965                 {
06966                         if (ci3)
06967                         {
06968                                 s = va( "%s vs %s and %s", ci1->name, ci2->name, ci3->name );
06969                         }
06970                         else
06971                         {
06972                                 s = va( "%s vs %s", ci1->name, ci2->name );
06973                         }
06974                         w = CG_Text_Width(s, 0.6f, FONT_MEDIUM);
06975                         CG_Text_Paint(320 - w / 2, 60, 0.6f, colorWhite, s, 0, 0, ITEM_TEXTSTYLE_SHADOWEDMORE,FONT_MEDIUM);
06976                 }
06977         } else {
06978                 if ( cgs.gametype == GT_FFA ) {
06979                         s = CG_GetStringEdString("MENUS", "FREE_FOR_ALL");//"Free For All";
06980                 } else if ( cgs.gametype == GT_HOLOCRON ) {
06981                         s = CG_GetStringEdString("MENUS", "HOLOCRON_FFA");//"Holocron FFA";
06982                 } else if ( cgs.gametype == GT_JEDIMASTER ) {
06983                         s = CG_GetStringEdString("MENUS", "POWERDUEL");//"Jedi Master";??
06984                 } else if ( cgs.gametype == GT_TEAM ) {
06985                         s = CG_GetStringEdString("MENUS", "TEAM_FFA");//"Team FFA";
06986                 } else if ( cgs.gametype == GT_SIEGE ) {
06987                         s = CG_GetStringEdString("MENUS", "SIEGE");//"Siege";
06988                 } else if ( cgs.gametype == GT_CTF ) {
06989                         s = CG_GetStringEdString("MENUS", "CAPTURE_THE_FLAG");//"Capture the Flag";
06990                 } else if ( cgs.gametype == GT_CTY ) {
06991                         s = CG_GetStringEdString("MENUS", "CAPTURE_THE_YSALIMARI");//"Capture the Ysalamiri";
06992                 } else {
06993                         s = "";
06994                 }
06995                 w = CG_Text_Width(s, 1.5f, FONT_MEDIUM);
06996                 CG_Text_Paint(320 - w / 2, 90, 1.5f, colorWhite, s, 0, 0, ITEM_TEXTSTYLE_SHADOWEDMORE,FONT_MEDIUM);
06997         }
06998 
06999         sec = ( sec - cg.time ) / 1000;
07000         if ( sec < 0 ) {
07001                 cg.warmup = 0;
07002                 sec = 0;
07003         }
07004 //      s = va( "Starts in: %i", sec + 1 );
07005         s = va( "%s: %i",CG_GetStringEdString("MP_INGAME", "STARTS_IN"), sec + 1 );
07006         if ( sec != cg.warmupCount ) {
07007                 cg.warmupCount = sec;
07008 
07009                 if (cgs.gametype != GT_SIEGE)
07010                 {
07011                         switch ( sec ) {
07012                         case 0:
07013                                 trap_S_StartLocalSound( cgs.media.count1Sound, CHAN_ANNOUNCER );
07014                                 break;
07015                         case 1:
07016                                 trap_S_StartLocalSound( cgs.media.count2Sound, CHAN_ANNOUNCER );
07017                                 break;
07018                         case 2:
07019                                 trap_S_StartLocalSound( cgs.media.count3Sound, CHAN_ANNOUNCER );
07020                                 break;
07021                         default:
07022                                 break;
07023                         }
07024                 }
07025         }
07026         scale = 0.45f;
07027         switch ( cg.warmupCount ) {
07028         case 0:
07029                 cw = 28;
07030                 scale = 1.25f;
07031                 break;
07032         case 1:
07033                 cw = 24;
07034                 scale = 1.15f;
07035                 break;
07036         case 2:
07037                 cw = 20;
07038                 scale = 1.05f;
07039                 break;
07040         default:
07041                 cw = 16;
07042                 scale = 0.9f;
07043                 break;
07044         }
07045 
07046         w = CG_Text_Width(s, scale, FONT_MEDIUM);
07047         CG_Text_Paint(320 - w / 2, 125, scale, colorWhite, s, 0, 0, ITEM_TEXTSTYLE_SHADOWEDMORE, FONT_MEDIUM);
07048 }
07049 
07050 //==================================================================================
07051 /* 
07052 =================
07053 CG_DrawTimedMenus
07054 =================
07055 */
07056 void CG_DrawTimedMenus() {
07057         if (cg.voiceTime) {
07058                 int t = cg.time - cg.voiceTime;
07059                 if ( t > 2500 ) {
07060                         Menus_CloseByName("voiceMenu");
07061                         trap_Cvar_Set("cl_conXOffset", "0");
07062                         cg.voiceTime = 0;
07063                 }
07064         }
07065 }
07066 
07067 void CG_DrawFlagStatus()
07068 {
07069         int myFlagTakenShader = 0;
07070         int theirFlagShader = 0;
07071         int team = 0;
07072         int startDrawPos = 2;
07073         int ico_size = 32;
07074 
07075         if (!cg.snap)
07076         {
07077                 return;
07078         }
07079 
07080         if (cgs.gametype != GT_CTF && cgs.gametype != GT_CTY)
07081         {
07082                 return;
07083         }
07084 
07085         team = cg.snap->ps.persistant[PERS_TEAM];
07086 
07087         if (cgs.gametype == GT_CTY)
07088         {
07089                 if (team == TEAM_RED)
07090                 {
07091                         myFlagTakenShader = trap_R_RegisterShaderNoMip( "gfx/hud/mpi_rflag_x" );
07092                         theirFlagShader = trap_R_RegisterShaderNoMip( "gfx/hud/mpi_bflag_ys" );
07093                 }
07094                 else
07095                 {
07096                         myFlagTakenShader = trap_R_RegisterShaderNoMip( "gfx/hud/mpi_bflag_x" );
07097                         theirFlagShader = trap_R_RegisterShaderNoMip( "gfx/hud/mpi_rflag_ys" );
07098                 }
07099         }
07100         else
07101         {
07102                 if (team == TEAM_RED)
07103                 {
07104                         myFlagTakenShader = trap_R_RegisterShaderNoMip( "gfx/hud/mpi_rflag_x" );
07105                         theirFlagShader = trap_R_RegisterShaderNoMip( "gfx/hud/mpi_bflag" );
07106                 }
07107                 else
07108                 {
07109                         myFlagTakenShader = trap_R_RegisterShaderNoMip( "gfx/hud/mpi_bflag_x" );
07110                         theirFlagShader = trap_R_RegisterShaderNoMip( "gfx/hud/mpi_rflag" );
07111                 }
07112         }
07113 
07114         if (CG_YourTeamHasFlag())
07115         {
07116                 //CG_DrawPic( startDrawPos, 330, ico_size, ico_size, theirFlagShader );
07117                 CG_DrawPic( 2, 330-startDrawPos, ico_size, ico_size, theirFlagShader );
07118                 startDrawPos += ico_size+2;
07119         }
07120 
07121         if (CG_OtherTeamHasFlag())
07122         {
07123                 //CG_DrawPic( startDrawPos, 330, ico_size, ico_size, myFlagTakenShader );
07124                 CG_DrawPic( 2, 330-startDrawPos, ico_size, ico_size, myFlagTakenShader );
07125         }
07126 }
07127 
07128 //draw meter showing jetpack fuel when it's not full
07129 #define JPFUELBAR_H                     100.0f
07130 #define JPFUELBAR_W                     20.0f
07131 #define JPFUELBAR_X                     (SCREEN_WIDTH-JPFUELBAR_W-8.0f)
07132 #define JPFUELBAR_Y                     260.0f
07133 void CG_DrawJetpackFuel(void)
07134 {
07135         vec4_t aColor;
07136         vec4_t bColor;
07137         vec4_t cColor;
07138         float x = JPFUELBAR_X;
07139         float y = JPFUELBAR_Y;
07140         float percent = ((float)cg.snap->ps.jetpackFuel/100.0f)*JPFUELBAR_H;
07141 
07142         if (percent > JPFUELBAR_H)
07143         {
07144                 return;
07145         }
07146 
07147         if (percent < 0.1f)
07148         {
07149                 percent = 0.1f;
07150         }
07151 
07152         //color of the bar
07153         aColor[0] = 0.5f;
07154         aColor[1] = 0.0f;
07155         aColor[2] = 0.0f;
07156         aColor[3] = 0.8f;
07157 
07158         //color of the border
07159         bColor[0] = 0.0f;
07160         bColor[1] = 0.0f;
07161         bColor[2] = 0.0f;
07162         bColor[3] = 0.3f;
07163 
07164         //color of greyed out "missing fuel"
07165         cColor[0] = 0.5f;
07166         cColor[1] = 0.5f;
07167         cColor[2] = 0.5f;
07168         cColor[3] = 0.1f;
07169 
07170         //draw the background (black)
07171         CG_DrawRect(x, y, JPFUELBAR_W, JPFUELBAR_H, 1.0f, colorTable[CT_BLACK]);
07172 
07173         //now draw the part to show how much health there is in the color specified
07174         CG_FillRect(x+1.0f, y+1.0f+(JPFUELBAR_H-percent), JPFUELBAR_W-1.0f, JPFUELBAR_H-1.0f-(JPFUELBAR_H-percent), aColor);
07175 
07176         //then draw the other part greyed out
07177         CG_FillRect(x+1.0f, y+1.0f, JPFUELBAR_W-1.0f, JPFUELBAR_H-percent, cColor);
07178 }
07179 
07180 //draw meter showing e-web health when it is in use
07181 #define EWEBHEALTH_H                    100.0f
07182 #define EWEBHEALTH_W                    20.0f
07183 #define EWEBHEALTH_X                    (SCREEN_WIDTH-EWEBHEALTH_W-8.0f)
07184 #define EWEBHEALTH_Y                    290.0f
07185 void CG_DrawEWebHealth(void)
07186 {
07187         vec4_t aColor;
07188         vec4_t bColor;
07189         vec4_t cColor;
07190         float x = EWEBHEALTH_X;
07191         float y = EWEBHEALTH_Y;
07192         centity_t *eweb = &cg_entities[cg.predictedPlayerState.emplacedIndex];
07193         float percent = ((float)eweb->currentState.health/eweb->currentState.maxhealth)*EWEBHEALTH_H;
07194 
07195         if (percent > EWEBHEALTH_H)
07196         {
07197                 return;
07198         }
07199 
07200         if (percent < 0.1f)
07201         {
07202                 percent = 0.1f;
07203         }
07204 
07205         //kind of hacky, need to pass a coordinate in here
07206         if (cg.snap->ps.jetpackFuel < 100)
07207         {
07208                 x -= (JPFUELBAR_W+8.0f);
07209         }
07210         if (cg.snap->ps.cloakFuel < 100)
07211         {
07212                 x -= (JPFUELBAR_W+8.0f);
07213         }
07214 
07215         //color of the bar
07216         aColor[0] = 0.5f;
07217         aColor[1] = 0.0f;
07218         aColor[2] = 0.0f;
07219         aColor[3] = 0.8f;
07220 
07221         //color of the border
07222         bColor[0] = 0.0f;
07223         bColor[1] = 0.0f;
07224         bColor[2] = 0.0f;
07225         bColor[3] = 0.3f;
07226 
07227         //color of greyed out "missing fuel"
07228         cColor[0] = 0.5f;
07229         cColor[1] = 0.5f;
07230         cColor[2] = 0.5f;
07231         cColor[3] = 0.1f;
07232 
07233         //draw the background (black)
07234         CG_DrawRect(x, y, EWEBHEALTH_W, EWEBHEALTH_H, 1.0f, colorTable[CT_BLACK]);
07235 
07236         //now draw the part to show how much health there is in the color specified
07237         CG_FillRect(x+1.0f, y+1.0f+(EWEBHEALTH_H-percent), EWEBHEALTH_W-1.0f, EWEBHEALTH_H-1.0f-(EWEBHEALTH_H-percent), aColor);
07238 
07239         //then draw the other part greyed out
07240         CG_FillRect(x+1.0f, y+1.0f, EWEBHEALTH_W-1.0f, EWEBHEALTH_H-percent, cColor);
07241 }
07242 
07243 //draw meter showing cloak fuel when it's not full
07244 #define CLFUELBAR_H                     100.0f
07245 #define CLFUELBAR_W                     20.0f
07246 #define CLFUELBAR_X                     (SCREEN_WIDTH-CLFUELBAR_W-8.0f)
07247 #define CLFUELBAR_Y                     260.0f
07248 void CG_DrawCloakFuel(void)
07249 {
07250         vec4_t aColor;
07251         vec4_t bColor;
07252         vec4_t cColor;
07253         float x = CLFUELBAR_X;
07254         float y = CLFUELBAR_Y;
07255         float percent = ((float)cg.snap->ps.cloakFuel/100.0f)*CLFUELBAR_H;
07256 
07257         if (percent > CLFUELBAR_H)
07258         {
07259                 return;
07260         }
07261 
07262         if ( cg.snap->ps.jetpackFuel < 100 )
07263         {//if drawing jetpack fuel bar too, then move this over...?
07264                 x -= (JPFUELBAR_W+8.0f);
07265         }
07266 
07267         if (percent < 0.1f)
07268         {
07269                 percent = 0.1f;
07270         }
07271 
07272         //color of the bar
07273         aColor[0] = 0.0f;
07274         aColor[1] = 0.0f;
07275         aColor[2] = 0.6f;
07276         aColor[3] = 0.8f;
07277 
07278         //color of the border
07279         bColor[0] = 0.0f;
07280         bColor[1] = 0.0f;
07281         bColor[2] = 0.0f;
07282         bColor[3] = 0.3f;
07283 
07284         //color of greyed out "missing fuel"
07285         cColor[0] = 0.1f;
07286         cColor[1] = 0.1f;
07287         cColor[2] = 0.3f;
07288         cColor[3] = 0.1f;
07289 
07290         //draw the background (black)
07291         CG_DrawRect(x, y, CLFUELBAR_W, CLFUELBAR_H, 1.0f, colorTable[CT_BLACK]);
07292 
07293         //now draw the part to show how much fuel there is in the color specified
07294         CG_FillRect(x+1.0f, y+1.0f+(CLFUELBAR_H-percent), CLFUELBAR_W-1.0f, CLFUELBAR_H-1.0f-(CLFUELBAR_H-percent), aColor);
07295 
07296         //then draw the other part greyed out
07297         CG_FillRect(x+1.0f, y+1.0f, CLFUELBAR_W-1.0f, CLFUELBAR_H-percent, cColor);
07298 }
07299 
07300 int cgRageTime = 0;
07301 int cgRageFadeTime = 0;
07302 float cgRageFadeVal = 0;
07303 
07304 int cgRageRecTime = 0;
07305 int cgRageRecFadeTime = 0;
07306 float cgRageRecFadeVal = 0;
07307 
07308 int cgAbsorbTime = 0;
07309 int cgAbsorbFadeTime = 0;
07310 float cgAbsorbFadeVal = 0;
07311 
07312 int cgProtectTime = 0;
07313 int cgProtectFadeTime = 0;
07314 float cgProtectFadeVal = 0;
07315 
07316 int cgYsalTime = 0;
07317 int cgYsalFadeTime = 0;
07318 float cgYsalFadeVal = 0;
07319 
07320 qboolean gCGHasFallVector = qfalse;
07321 vec3_t gCGFallVector;
07322 
07323 /*
07324 =================
07325 CG_Draw2D
07326 =================
07327 */
07328 extern int cgSiegeRoundState;
07329 extern int cgSiegeRoundTime;
07330 
07331 extern int team1Timed;
07332 extern int team2Timed;
07333 
07334 int cg_beatingSiegeTime = 0;
07335 
07336 int cgSiegeRoundBeganTime = 0;
07337 int cgSiegeRoundCountTime = 0;
07338 
07339 static void CG_DrawSiegeTimer(int timeRemaining, qboolean isMyTeam)
07340 { //rwwFIXMEFIXME: Make someone make assets and use them.
07341   //this function is pretty much totally placeholder.
07342 //      int x = 0;
07343 //      int y = SCREEN_HEIGHT-160;
07344         int fColor = 0;
07345         int minutes = 0;
07346         int seconds = 0;
07347         char timeStr[1024];
07348         menuDef_t       *menuHUD = NULL;
07349         itemDef_t       *item = NULL;
07350 
07351         menuHUD = Menus_FindByName("mp_timer");
07352         if (!menuHUD)
07353         {
07354                 return;
07355         }
07356 
07357         item = Menu_FindItemByName(menuHUD, "frame");
07358 
07359         if (item)
07360         {
07361                 trap_R_SetColor( item->window.foreColor );
07362                 CG_DrawPic( 
07363                         item->window.rect.x, 
07364                         item->window.rect.y, 
07365                         item->window.rect.w, 
07366                         item->window.rect.h, 
07367                         item->window.background );
07368         }
07369 
07370         seconds = timeRemaining;
07371 
07372         while (seconds >= 60)
07373         {
07374                 minutes++;
07375                 seconds -= 60;
07376         }
07377 
07378         strcpy(timeStr, va( "%i:%02i", minutes, seconds ));
07379 
07380         if (isMyTeam)
07381         {
07382                 fColor = CT_HUD_RED;
07383         }
07384         else
07385         {
07386                 fColor = CT_HUD_GREEN;
07387         }
07388 
07389 //      trap_Cvar_Set("ui_siegeTimer", timeStr);
07390 
07391 //      UI_DrawProportionalString( x+16, y+40, timeStr,
07392 //              UI_SMALLFONT|UI_DROPSHADOW, colorTable[fColor] );
07393 
07394         item = Menu_FindItemByName(menuHUD, "timer");
07395         if (item)
07396         {
07397                 UI_DrawProportionalString( 
07398                         item->window.rect.x, 
07399                         item->window.rect.y, 
07400                         timeStr,
07401                         UI_SMALLFONT|UI_DROPSHADOW, 
07402                         colorTable[fColor] );
07403         }
07404 
07405 }
07406 
07407 static void CG_DrawSiegeDeathTimer( int timeRemaining )
07408 {
07409         int minutes = 0;
07410         int seconds = 0;
07411         char timeStr[1024];
07412         menuDef_t       *menuHUD = NULL;
07413         itemDef_t       *item = NULL;
07414 
07415         menuHUD = Menus_FindByName("mp_timer");
07416         if (!menuHUD)
07417         {
07418                 return;
07419         }
07420 
07421         item = Menu_FindItemByName(menuHUD, "frame");
07422 
07423         if (item)
07424         {
07425                 trap_R_SetColor( item->window.foreColor );
07426                 CG_DrawPic( 
07427                         item->window.rect.x, 
07428                         item->window.rect.y, 
07429                         item->window.rect.w, 
07430                         item->window.rect.h, 
07431                         item->window.background );
07432         }
07433 
07434         seconds = timeRemaining;
07435 
07436         while (seconds >= 60)
07437         {
07438                 minutes++;
07439                 seconds -= 60;
07440         }
07441 
07442         if (seconds < 10)
07443         {
07444                 strcpy(timeStr, va( "%i:0%i", minutes, seconds ));
07445         }
07446         else
07447         {
07448                 strcpy(timeStr, va( "%i:%i", minutes, seconds ));
07449         }
07450 
07451         item = Menu_FindItemByName(menuHUD, "deathtimer");
07452         if (item)
07453         {
07454                 UI_DrawProportionalString( 
07455                         item->window.rect.x, 
07456                         item->window.rect.y, 
07457                         timeStr,
07458                         UI_SMALLFONT|UI_DROPSHADOW, 
07459                         item->window.foreColor );
07460         }
07461         
07462 }
07463 
07464 int cgSiegeEntityRender = 0;
07465 
07466 static void CG_DrawSiegeHUDItem(void)
07467 {
07468         void *g2;
07469         qhandle_t handle;
07470         vec3_t origin, angles;
07471         vec3_t mins, maxs;
07472         float len;
07473         centity_t *cent = &cg_entities[cgSiegeEntityRender];
07474 
07475         if (cent->ghoul2)
07476         {
07477                 g2 = cent->ghoul2;
07478                 handle = 0;
07479         }
07480         else
07481         {
07482                 handle = cgs.gameModels[cent->currentState.modelindex];
07483                 g2 = NULL;
07484         }
07485 
07486         if (handle)
07487         {
07488                 trap_R_ModelBounds( handle, mins, maxs );
07489         }
07490         else
07491         {
07492                 VectorSet(mins, -16, -16, -20);
07493                 VectorSet(maxs, 16, 16, 32);
07494         }
07495 
07496         origin[2] = -0.5 * ( mins[2] + maxs[2] );
07497         origin[1] = 0.5 * ( mins[1] + maxs[1] );
07498         len = 0.5 * ( maxs[2] - mins[2] );              
07499         origin[0] = len / 0.268;
07500 
07501         VectorClear(angles);
07502         angles[YAW] = cg.autoAngles[YAW];
07503 
07504         CG_Draw3DModel( 8, 8, 64, 64, handle, g2, cent->currentState.g2radius, 0, origin, angles );
07505 
07506         cgSiegeEntityRender = 0; //reset for next frame
07507 }
07508 
07509 /*====================================
07510 chatbox functionality -rww
07511 ====================================*/
07512 #define CHATBOX_CUTOFF_LEN      550
07513 #define CHATBOX_FONT_HEIGHT     20
07514 
07515 //utility func, insert a string into a string at the specified
07516 //place (assuming this will not overflow the buffer)
07517 void CG_ChatBox_StrInsert(char *buffer, int place, char *str)
07518 {
07519         int insLen = strlen(str);
07520         int i = strlen(buffer);
07521         int k = 0;
07522 
07523         buffer[i+insLen+1] = 0; //terminate the string at its new length
07524         while (i >= place)
07525         {
07526                 buffer[i+insLen] = buffer[i];
07527                 i--;
07528         }
07529 
07530         i++;
07531         while (k < insLen)
07532         {
07533                 buffer[i] = str[k];
07534                 i++;
07535                 k++;
07536         }
07537 }
07538 
07539 //add chatbox string
07540 void CG_ChatBox_AddString(char *chatStr)
07541 {
07542         chatBoxItem_t *chat = &cg.chatItems[cg.chatItemActive];
07543         float chatLen;
07544 
07545         if (cg_chatBox.integer<=0)
07546         { //don't bother then.
07547                 return;
07548         }
07549 
07550         memset(chat, 0, sizeof(chatBoxItem_t));
07551 
07552         if (strlen(chatStr) > sizeof(chat->string))
07553         { //too long, terminate at proper len.
07554                 chatStr[sizeof(chat->string)-1] = 0;
07555         }
07556 
07557         strcpy(chat->string, chatStr);
07558         chat->time = cg.time + cg_chatBox.integer;
07559 
07560         chat->lines = 1;
07561 
07562         chatLen = CG_Text_Width(chat->string, 1.0f, FONT_SMALL);
07563         if (chatLen > CHATBOX_CUTOFF_LEN)
07564         { //we have to break it into segments...
07565         int i = 0;
07566                 int lastLinePt = 0;
07567                 char s[2];
07568 
07569                 chatLen = 0;
07570                 while (chat->string[i])
07571                 {
07572                         s[0] = chat->string[i];
07573                         s[1] = 0;
07574                         chatLen += CG_Text_Width(s, 0.65f, FONT_SMALL);
07575 
07576                         if (chatLen >= CHATBOX_CUTOFF_LEN)
07577                         {
07578                                 int j = i;
07579                                 while (j > 0 && j > lastLinePt)
07580                                 {
07581                                         if (chat->string[j] == ' ')
07582                                         {
07583                                                 break;
07584                                         }
07585                                         j--;
07586                                 }
07587                                 if (chat->string[j] == ' ')
07588                                 {
07589                                         i = j;
07590                                 }
07591 
07592                 chat->lines++;
07593                                 CG_ChatBox_StrInsert(chat->string, i, "\n");
07594                                 i++;
07595                                 chatLen = 0;
07596                                 lastLinePt = i+1;
07597                         }
07598                         i++;
07599                 }
07600         }
07601 
07602         cg.chatItemActive++;
07603         if (cg.chatItemActive >= MAX_CHATBOX_ITEMS)
07604         {
07605                 cg.chatItemActive = 0;
07606         }
07607 }
07608 
07609 //insert item into array (rearranging the array if necessary)
07610 void CG_ChatBox_ArrayInsert(chatBoxItem_t **array, int insPoint, int maxNum, chatBoxItem_t *item)
07611 {
07612     if (array[insPoint])
07613         { //recursively call, to move everything up to the top
07614                 if (insPoint+1 >= maxNum)
07615                 {
07616                         CG_Error("CG_ChatBox_ArrayInsert: Exceeded array size");
07617                 }
07618                 CG_ChatBox_ArrayInsert(array, insPoint+1, maxNum, array[insPoint]);
07619         }
07620 
07621         //now that we have moved anything that would be in this slot up, insert what we want into the slot
07622         array[insPoint] = item;
07623 }
07624 
07625 //go through all the chat strings and draw them if they are not yet expired
07626 static CGAME_INLINE void CG_ChatBox_DrawStrings(void)
07627 {
07628         chatBoxItem_t *drawThese[MAX_CHATBOX_ITEMS];
07629         int numToDraw = 0;
07630         int linesToDraw = 0;
07631         int i = 0;
07632         int x = 30;
07633         int y = cg.scoreBoardShowing ? 475 : cg_chatBoxHeight.integer;
07634         float fontScale = 0.65f;
07635 
07636         if (!cg_chatBox.integer)
07637         {
07638                 return;
07639         }
07640 
07641         memset(drawThese, 0, sizeof(drawThese));
07642 
07643         while (i < MAX_CHATBOX_ITEMS)
07644         {
07645                 if (cg.chatItems[i].time >= cg.time)
07646                 {
07647                         int check = numToDraw;
07648                         int insertionPoint = numToDraw;
07649 
07650                         while (check >= 0)
07651                         {
07652                                 if (drawThese[check] &&
07653                                         cg.chatItems[i].time < drawThese[check]->time)
07654                                 { //insert here
07655                                         insertionPoint = check;
07656                                 }
07657                                 check--;
07658                         }
07659                         CG_ChatBox_ArrayInsert(drawThese, insertionPoint, MAX_CHATBOX_ITEMS, &cg.chatItems[i]);
07660                         numToDraw++;
07661                         linesToDraw += cg.chatItems[i].lines;
07662                 }
07663                 i++;
07664         }
07665 
07666         if (!numToDraw)
07667         { //nothing, then, just get out of here now.
07668                 return;
07669         }
07670 
07671         //move initial point up so we draw bottom-up (visually)
07672         y -= (CHATBOX_FONT_HEIGHT*fontScale)*linesToDraw;
07673 
07674         //we have the items we want to draw, just quickly loop through them now
07675         i = 0;
07676         while (i < numToDraw)
07677         {
07678                 CG_Text_Paint(x, y, fontScale, colorWhite, drawThese[i]->string, 0, 0, ITEM_TEXTSTYLE_OUTLINED, FONT_SMALL );
07679                 y += ((CHATBOX_FONT_HEIGHT*fontScale)*drawThese[i]->lines);
07680                 i++;
07681         }
07682 }
07683 
07684 static void CG_Draw2DScreenTints( void )
07685 {
07686         float                   rageTime, rageRecTime, absorbTime, protectTime, ysalTime;
07687         vec4_t                  hcolor;
07688         if (cgs.clientinfo[cg.snap->ps.clientNum].team != TEAM_SPECTATOR)
07689         {
07690                 if (cg.snap->ps.fd.forcePowersActive & (1 << FP_RAGE))
07691                 {
07692                         if (!cgRageTime)
07693                         {
07694                                 cgRageTime = cg.time;
07695                         }
07696                         
07697                         rageTime = (float)(cg.time - cgRageTime);
07698                         
07699                         rageTime /= 9000;
07700                         
07701                         if (rageTime < 0)
07702                         {
07703                                 rageTime = 0;
07704                         }
07705                         if (rageTime > 0.15)
07706                         {
07707                                 rageTime = 0.15;
07708                         }
07709                         
07710                         hcolor[3] = rageTime;
07711                         hcolor[0] = 0.7;
07712                         hcolor[1] = 0;
07713                         hcolor[2] = 0;
07714                         
07715                         if (!cg.renderingThirdPerson)
07716                         {
07717                                 CG_DrawRect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_WIDTH*SCREEN_HEIGHT, hcolor);
07718                         }
07719                         
07720                         cgRageFadeTime = 0;
07721                         cgRageFadeVal = 0;
07722                 }
07723                 else if (cgRageTime)
07724                 {
07725                         if (!cgRageFadeTime)
07726                         {
07727                                 cgRageFadeTime = cg.time;
07728                                 cgRageFadeVal = 0.15;
07729                         }
07730                         
07731                         rageTime = cgRageFadeVal;
07732                         
07733                         cgRageFadeVal -= (cg.time - cgRageFadeTime)*0.000005;
07734                         
07735                         if (rageTime < 0)
07736                         {
07737                                 rageTime = 0;
07738                         }
07739                         if (rageTime > 0.15)
07740                         {
07741                                 rageTime = 0.15;
07742                         }
07743                         
07744                         if (cg.snap->ps.fd.forceRageRecoveryTime > cg.time)
07745                         {
07746                                 float checkRageRecTime = rageTime;
07747                                 
07748                                 if (checkRageRecTime < 0.15)
07749                                 {
07750                                         checkRageRecTime = 0.15;
07751                                 }
07752                                 
07753                                 hcolor[3] = checkRageRecTime;
07754                                 hcolor[0] = rageTime*4;
07755                                 if (hcolor[0] < 0.2)
07756                                 {
07757                                         hcolor[0] = 0.2;
07758                                 }
07759                                 hcolor[1] = 0.2;
07760                                 hcolor[2] = 0.2;
07761                         }
07762                         else
07763                         {
07764                                 hcolor[3] = rageTime;
07765                                 hcolor[0] = 0.7;
07766                                 hcolor[1] = 0;
07767                                 hcolor[2] = 0;
07768                         }
07769                         
07770                         if (!cg.renderingThirdPerson && rageTime)
07771                         {
07772                                 CG_DrawRect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_WIDTH*SCREEN_HEIGHT, hcolor);
07773                         }
07774                         else
07775                         {
07776                                 if (cg.snap->ps.fd.forceRageRecoveryTime > cg.time)
07777                                 {
07778                                         hcolor[3] = 0.15;
07779                                         hcolor[0] = 0.2;
07780                                         hcolor[1] = 0.2;
07781                                         hcolor[2] = 0.2;
07782                                         CG_DrawRect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_WIDTH*SCREEN_HEIGHT, hcolor);
07783                                 }
07784                                 cgRageTime = 0;
07785                         }
07786                 }
07787                 else if (cg.snap->ps.fd.forceRageRecoveryTime > cg.time)
07788                 {
07789                         if (!cgRageRecTime)
07790                         {
07791                                 cgRageRecTime = cg.time;
07792                         }
07793                         
07794                         rageRecTime = (float)(cg.time - cgRageRecTime);
07795                         
07796                         rageRecTime /= 9000;
07797                         
07798                         if (rageRecTime < 0.15)//0)
07799                         {
07800                                 rageRecTime = 0.15;//0;
07801                         }
07802                         if (rageRecTime > 0.15)
07803                         {
07804                                 rageRecTime = 0.15;
07805                         }
07806                         
07807                         hcolor[3] = rageRecTime;
07808                         hcolor[0] = 0.2;
07809                         hcolor[1] = 0.2;
07810                         hcolor[2] = 0.2;
07811                         
07812                         if (!cg.renderingThirdPerson)
07813                         {
07814                                 CG_DrawRect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_WIDTH*SCREEN_HEIGHT, hcolor);
07815                         }
07816                         
07817                         cgRageRecFadeTime = 0;
07818                         cgRageRecFadeVal = 0;
07819                 }
07820                 else if (cgRageRecTime)
07821                 {
07822                         if (!cgRageRecFadeTime)
07823                         {
07824                                 cgRageRecFadeTime = cg.time;
07825                                 cgRageRecFadeVal = 0.15;
07826                         }
07827                         
07828                         rageRecTime = cgRageRecFadeVal;
07829                         
07830                         cgRageRecFadeVal -= (cg.time - cgRageRecFadeTime)*0.000005;
07831                         
07832                         if (rageRecTime < 0)
07833                         {
07834                                 rageRecTime = 0;
07835                         }
07836                         if (rageRecTime > 0.15)
07837                         {
07838                                 rageRecTime = 0.15;
07839                         }
07840                         
07841                         hcolor[3] = rageRecTime;
07842                         hcolor[0] = 0.2;
07843                         hcolor[1] = 0.2;
07844                         hcolor[2] = 0.2;
07845                         
07846                         if (!cg.renderingThirdPerson && rageRecTime)
07847                         {
07848                                 CG_DrawRect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_WIDTH*SCREEN_HEIGHT, hcolor);
07849                         }
07850                         else
07851                         {
07852                                 cgRageRecTime = 0;
07853                         }
07854                 }
07855                 
07856                 if (cg.snap->ps.fd.forcePowersActive & (1 << FP_ABSORB))
07857                 {
07858                         if (!cgAbsorbTime)
07859                         {
07860                                 cgAbsorbTime = cg.time;
07861                         }
07862                         
07863                         absorbTime = (float)(cg.time - cgAbsorbTime);
07864                         
07865                         absorbTime /= 9000;
07866                         
07867                         if (absorbTime < 0)
07868                         {
07869                                 absorbTime = 0;
07870                         }
07871                         if (absorbTime > 0.15)
07872                         {
07873                                 absorbTime = 0.15;
07874                         }
07875                         
07876                         hcolor[3] = absorbTime/2;
07877                         hcolor[0] = 0;
07878                         hcolor[1] = 0;
07879                         hcolor[2] = 0.7;
07880                         
07881                         if (!cg.renderingThirdPerson)
07882                         {
07883                                 CG_DrawRect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_WIDTH*SCREEN_HEIGHT, hcolor);
07884                         }
07885                         
07886                         cgAbsorbFadeTime = 0;
07887                         cgAbsorbFadeVal = 0;
07888                 }
07889                 else if (cgAbsorbTime)
07890                 {
07891                         if (!cgAbsorbFadeTime)
07892                         {
07893                                 cgAbsorbFadeTime = cg.time;
07894                                 cgAbsorbFadeVal = 0.15;
07895                         }
07896                         
07897                         absorbTime = cgAbsorbFadeVal;
07898                         
07899                         cgAbsorbFadeVal -= (cg.time - cgAbsorbFadeTime)*0.000005;
07900                         
07901                         if (absorbTime < 0)
07902                         {
07903                                 absorbTime = 0;
07904                         }
07905                         if (absorbTime > 0.15)
07906                         {
07907                                 absorbTime = 0.15;
07908                         }
07909                         
07910                         hcolor[3] = absorbTime/2;
07911                         hcolor[0] = 0;
07912                         hcolor[1] = 0;
07913                         hcolor[2] = 0.7;
07914                         
07915                         if (!cg.renderingThirdPerson && absorbTime)
07916                         {
07917                                 CG_DrawRect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_WIDTH*SCREEN_HEIGHT, hcolor);
07918                         }
07919                         else
07920                         {
07921                                 cgAbsorbTime = 0;
07922                         }
07923                 }
07924                 
07925                 if (cg.snap->ps.fd.forcePowersActive & (1 << FP_PROTECT))
07926                 {
07927                         if (!cgProtectTime)
07928                         {
07929                                 cgProtectTime = cg.time;
07930                         }
07931                         
07932                         protectTime = (float)(cg.time - cgProtectTime);
07933                         
07934                         protectTime /= 9000;
07935                         
07936                         if (protectTime < 0)
07937                         {
07938                                 protectTime = 0;
07939                         }
07940                         if (protectTime > 0.15)
07941                         {
07942                                 protectTime = 0.15;
07943                         }
07944                         
07945                         hcolor[3] = protectTime/2;
07946                         hcolor[0] = 0;
07947                         hcolor[1] = 0.7;
07948                         hcolor[2] = 0;
07949                         
07950                         if (!cg.renderingThirdPerson)
07951                         {
07952                                 CG_DrawRect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_WIDTH*SCREEN_HEIGHT, hcolor);
07953                         }
07954                         
07955                         cgProtectFadeTime = 0;
07956                         cgProtectFadeVal = 0;
07957                 }
07958                 else if (cgProtectTime)
07959                 {
07960                         if (!cgProtectFadeTime)
07961                         {
07962                                 cgProtectFadeTime = cg.time;
07963                                 cgProtectFadeVal = 0.15;
07964                         }
07965                         
07966                         protectTime = cgProtectFadeVal;
07967                         
07968                         cgProtectFadeVal -= (cg.time - cgProtectFadeTime)*0.000005;
07969                         
07970                         if (protectTime < 0)
07971                         {
07972                                 protectTime = 0;
07973                         }
07974                         if (protectTime > 0.15)
07975                         {
07976                                 protectTime = 0.15;
07977                         }
07978                         
07979                         hcolor[3] = protectTime/2;
07980                         hcolor[0] = 0;
07981                         hcolor[1] = 0.7;
07982                         hcolor[2] = 0;
07983                         
07984                         if (!cg.renderingThirdPerson && protectTime)
07985                         {
07986                                 CG_DrawRect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_WIDTH*SCREEN_HEIGHT, hcolor);
07987                         }
07988                         else
07989                         {
07990                                 cgProtectTime = 0;
07991                         }
07992                 }
07993                 
07994                 if (cg.snap->ps.rocketLockIndex != ENTITYNUM_NONE && (cg.time - cg.snap->ps.rocketLockTime) > 0)
07995                 {
07996                         CG_DrawRocketLocking( cg.snap->ps.rocketLockIndex, cg.snap->ps.rocketLockTime );
07997                 }
07998                 
07999                 if (BG_HasYsalamiri(cgs.gametype, &cg.snap->ps))
08000                 {
08001                         if (!cgYsalTime)
08002                         {
08003                                 cgYsalTime = cg.time;
08004                         }
08005                         
08006                         ysalTime = (float)(cg.time - cgYsalTime);
08007                         
08008                         ysalTime /= 9000;
08009                         
08010                         if (ysalTime < 0)
08011                         {
08012                                 ysalTime = 0;
08013                         }
08014                         if (ysalTime > 0.15)
08015                         {
08016                                 ysalTime = 0.15;
08017                         }
08018                         
08019                         hcolor[3] = ysalTime/2;
08020                         hcolor[0] = 0.7;
08021                         hcolor[1] = 0.7;
08022                         hcolor[2] = 0;
08023                         
08024                         if (!cg.renderingThirdPerson)
08025                         {
08026                                 CG_DrawRect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_WIDTH*SCREEN_HEIGHT, hcolor);
08027                         }
08028                         
08029                         cgYsalFadeTime = 0;
08030                         cgYsalFadeVal = 0;
08031                 }
08032                 else if (cgYsalTime)
08033                 {
08034                         if (!cgYsalFadeTime)
08035                         {
08036                                 cgYsalFadeTime = cg.time;
08037                                 cgYsalFadeVal = 0.15;
08038                         }
08039                         
08040                         ysalTime = cgYsalFadeVal;
08041                         
08042                         cgYsalFadeVal -= (cg.time - cgYsalFadeTime)*0.000005;
08043                         
08044                         if (ysalTime < 0)
08045                         {
08046                                 ysalTime = 0;
08047                         }
08048                         if (ysalTime > 0.15)
08049                         {
08050                                 ysalTime = 0.15;
08051                         }
08052                         
08053                         hcolor[3] = ysalTime/2;
08054                         hcolor[0] = 0.7;
08055                         hcolor[1] = 0.7;
08056                         hcolor[2] = 0;
08057                         
08058                         if (!cg.renderingThirdPerson && ysalTime)
08059                         {
08060                                 CG_DrawRect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_WIDTH*SCREEN_HEIGHT, hcolor);
08061                         }
08062                         else
08063                         {
08064                                 cgYsalTime = 0;
08065                         }
08066                 }
08067         }
08068 
08069         if ( (cg.refdef.viewContents&CONTENTS_LAVA) )
08070         {//tint screen red
08071                 float phase = cg.time / 1000.0 * WAVE_FREQUENCY * M_PI * 2;
08072                 hcolor[3] = 0.5 + (0.15f*sin( phase ));
08073                 hcolor[0] = 0.7f;
08074                 hcolor[1] = 0;
08075                 hcolor[2] = 0;
08076                 
08077                 CG_DrawRect( 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_WIDTH*SCREEN_HEIGHT, hcolor  );
08078         }
08079         else if ( (cg.refdef.viewContents&CONTENTS_SLIME) )
08080         {//tint screen green
08081                 float phase = cg.time / 1000.0 * WAVE_FREQUENCY * M_PI * 2;
08082                 hcolor[3] = 0.4 + (0.1f*sin( phase ));
08083                 hcolor[0] = 0;
08084                 hcolor[1] = 0.7f;
08085                 hcolor[2] = 0;
08086                 
08087                 CG_DrawRect( 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_WIDTH*SCREEN_HEIGHT, hcolor  );
08088         }
08089         else if ( (cg.refdef.viewContents&CONTENTS_WATER) )
08090         {//tint screen light blue -- FIXME: don't do this if CONTENTS_FOG? (in case someone *does* make a water shader with fog in it?)
08091                 float phase = cg.time / 1000.0 * WAVE_FREQUENCY * M_PI * 2;
08092                 hcolor[3] = 0.3 + (0.05f*sin( phase ));
08093                 hcolor[0] = 0;
08094                 hcolor[1] = 0.2f;
08095                 hcolor[2] = 0.8;
08096                 
08097                 CG_DrawRect( 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_WIDTH*SCREEN_HEIGHT, hcolor  );
08098         }
08099 }
08100 
08101 static void CG_Draw2D( void ) {
08102         float                   inTime = cg.invenSelectTime+WEAPON_SELECT_TIME;
08103         float                   wpTime = cg.weaponSelectTime+WEAPON_SELECT_TIME;
08104         float                   fallTime; 
08105         float                   bestTime;
08106         int                             drawSelect = 0;
08107 
08108         // if we are taking a levelshot for the menu, don't draw anything
08109         if ( cg.levelShot ) {
08110                 return;
08111         }
08112 
08113         if (cgs.clientinfo[cg.snap->ps.clientNum].team == TEAM_SPECTATOR)
08114         {
08115                 cgRageTime = 0;
08116                 cgRageFadeTime = 0;
08117                 cgRageFadeVal = 0;
08118 
08119                 cgRageRecTime = 0;
08120                 cgRageRecFadeTime = 0;
08121                 cgRageRecFadeVal = 0;
08122 
08123                 cgAbsorbTime = 0;
08124                 cgAbsorbFadeTime = 0;
08125                 cgAbsorbFadeVal = 0;
08126 
08127                 cgProtectTime = 0;
08128                 cgProtectFadeTime = 0;
08129                 cgProtectFadeVal = 0;
08130 
08131                 cgYsalTime = 0;
08132                 cgYsalFadeTime = 0;
08133                 cgYsalFadeVal = 0;
08134         }
08135 
08136         if ( cg_draw2D.integer == 0 ) {
08137                 return;
08138         }
08139 
08140         if ( cg.snap->ps.pm_type == PM_INTERMISSION ) {
08141                 CG_DrawIntermission();
08142                 CG_ChatBox_DrawStrings();
08143                 return;
08144         }
08145 
08146         CG_Draw2DScreenTints();
08147 
08148         if (cg.snap->ps.rocketLockIndex != ENTITYNUM_NONE && (cg.time - cg.snap->ps.rocketLockTime) > 0)
08149         {
08150                 CG_DrawRocketLocking( cg.snap->ps.rocketLockIndex, cg.snap->ps.rocketLockTime );
08151         }
08152 
08153         if (cg.snap->ps.holocronBits)
08154         {
08155                 CG_DrawHolocronIcons();
08156         }
08157         if (cg.snap->ps.fd.forcePowersActive || cg.snap->ps.fd.forceRageRecoveryTime > cg.time)
08158         {
08159                 CG_DrawActivePowers();
08160         }
08161 
08162         if (cg.snap->ps.jetpackFuel < 100)
08163         { //draw it as long as it isn't full
08164         CG_DrawJetpackFuel();        
08165         }
08166         if (cg.snap->ps.cloakFuel < 100)
08167         { //draw it as long as it isn't full
08168                 CG_DrawCloakFuel();
08169         }
08170         if (cg.predictedPlayerState.emplacedIndex > 0)
08171         {
08172                 centity_t *eweb = &cg_entities[cg.predictedPlayerState.emplacedIndex];
08173 
08174                 if (eweb->currentState.weapon == WP_NONE)
08175                 { //using an e-web, draw its health
08176                         CG_DrawEWebHealth();
08177                 }
08178         }
08179 
08180         // Draw this before the text so that any text won't get clipped off
08181         CG_DrawZoomMask();
08182 
08183 /*
08184         if (cg.cameraMode) {
08185                 return;
08186         }
08187 */
08188         if ( cg.snap->ps.persistant[PERS_TEAM] == TEAM_SPECTATOR ) {
08189                 CG_DrawSpectator();
08190                 CG_DrawCrosshair(NULL, 0);
08191                 CG_DrawCrosshairNames();
08192                 CG_SaberClashFlare();
08193         } else {
08194                 // don't draw any status if dead or the scoreboard is being explicitly shown
08195                 if ( !cg.showScores && cg.snap->ps.stats[STAT_HEALTH] > 0 ) {
08196 
08197                         if ( /*cg_drawStatus.integer*/0 ) {
08198                                 //Reenable if stats are drawn with menu system again
08199                                 Menu_PaintAll();
08200                                 CG_DrawTimedMenus();
08201                         }
08202       
08203                         //CG_DrawTemporaryStats();
08204 
08205                         CG_DrawAmmoWarning();
08206 
08207                         CG_DrawCrosshairNames();
08208 
08209                         if (cg_drawStatus.integer)
08210                         {
08211                                 CG_DrawIconBackground();
08212                         }
08213 
08214                         if (inTime > wpTime)
08215                         {
08216                                 drawSelect = 1;
08217                                 bestTime = cg.invenSelectTime;
08218                         }
08219                         else //only draw the most recent since they're drawn in the same place
08220                         {
08221                                 drawSelect = 2;
08222                                 bestTime = cg.weaponSelectTime;
08223                         }
08224 
08225                         if (cg.forceSelectTime > bestTime)
08226                         {
08227                                 drawSelect = 3;
08228                         }
08229 
08230                         switch(drawSelect)
08231                         {
08232                         case 1:
08233                                 CG_DrawInvenSelect();
08234                                 break;
08235                         case 2:
08236                                 CG_DrawWeaponSelect();
08237                                 break;
08238                         case 3:
08239                                 CG_DrawForceSelect();
08240                                 break;
08241                         default:
08242                                 break;
08243                         }
08244 
08245                         if (cg_drawStatus.integer)
08246                         {
08247                                 //Powerups now done with upperright stuff
08248                                 //CG_DrawPowerupIcons();
08249 
08250                                 CG_DrawFlagStatus();
08251                         }
08252 
08253                         CG_SaberClashFlare();
08254 
08255                         if (cg_drawStatus.integer)
08256                         {
08257                                 CG_DrawStats();
08258                         }
08259 
08260                         CG_DrawPickupItem();
08261                         //Do we want to use this system again at some point?
08262                         //CG_DrawReward();
08263                 }
08264     
08265         }
08266 
08267         if (cg.snap->ps.fallingToDeath)
08268         {
08269                 vec4_t  hcolor;
08270 
08271                 fallTime = (float)(cg.time - cg.snap->ps.fallingToDeath);
08272 
08273                 fallTime /= (FALL_FADE_TIME/2);
08274 
08275                 if (fallTime < 0)
08276                 {
08277                         fallTime = 0;
08278                 }
08279                 if (fallTime > 1)
08280                 {
08281                         fallTime = 1;
08282                 }
08283 
08284                 hcolor[3] = fallTime;
08285                 hcolor[0] = 0;
08286                 hcolor[1] = 0;
08287                 hcolor[2] = 0;
08288 
08289                 CG_DrawRect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_WIDTH*SCREEN_HEIGHT, hcolor);
08290 
08291                 if (!gCGHasFallVector)
08292                 {
08293                         VectorCopy(cg.snap->ps.origin, gCGFallVector);
08294                         gCGHasFallVector = qtrue;
08295                 }
08296         }
08297         else
08298         {
08299                 if (gCGHasFallVector)
08300                 {
08301                         gCGHasFallVector = qfalse;
08302                         VectorClear(gCGFallVector);
08303                 }
08304         }
08305 
08306         CG_DrawVote();
08307         CG_DrawTeamVote();
08308 
08309         CG_DrawLagometer();
08310         
08311 
08312         if (!cg_paused.integer) {
08313                 CG_DrawBracketedEntities();
08314                 CG_DrawUpperRight();
08315         }
08316 
08317         if ( !CG_DrawFollow() ) {
08318                 CG_DrawWarmup();
08319         }
08320 
08321         if (cgSiegeRoundState)
08322         {
08323                 char pStr[1024];
08324                 int rTime = 0;
08325 
08326                 //cgSiegeRoundBeganTime = 0;
08327 
08328                 switch (cgSiegeRoundState)
08329                 {
08330                 case 1:
08331                         CG_CenterPrint(CG_GetStringEdString("MP_INGAME", "WAITING_FOR_PLAYERS"), SCREEN_HEIGHT * 0.30, BIGCHAR_WIDTH);
08332                         break;
08333                 case 2:
08334                         rTime = (SIEGE_ROUND_BEGIN_TIME - (cg.time - cgSiegeRoundTime));
08335                 
08336                         if (rTime < 0)
08337                         {
08338                                 rTime = 0;
08339                         }
08340                         if (rTime > SIEGE_ROUND_BEGIN_TIME)
08341                         {
08342                                 rTime = SIEGE_ROUND_BEGIN_TIME;
08343                         }
08344 
08345                         rTime /= 1000;
08346 
08347                         rTime += 1;
08348 
08349                         if (rTime < 1)
08350                         {
08351                                 rTime = 1;
08352                         }
08353 
08354                         if (rTime <= 3 && rTime != cgSiegeRoundCountTime)
08355                         {
08356                                 cgSiegeRoundCountTime = rTime;
08357 
08358                                 switch (rTime)
08359                                 {
08360                                 case 1:
08361                                         trap_S_StartLocalSound( cgs.media.count1Sound, CHAN_ANNOUNCER );
08362                                         break;
08363                                 case 2:
08364                                         trap_S_StartLocalSound( cgs.media.count2Sound, CHAN_ANNOUNCER );
08365                                         break;
08366                                 case 3:
08367                                         trap_S_StartLocalSound( cgs.media.count3Sound, CHAN_ANNOUNCER );
08368                                         break;
08369                                 default:
08370                                         break;
08371                                 }
08372                         }
08373 
08374                         strcpy(pStr, va("%s %i...", CG_GetStringEdString("MP_INGAME", "ROUNDBEGINSIN"), rTime));
08375                         CG_CenterPrint(pStr, SCREEN_HEIGHT * 0.30, BIGCHAR_WIDTH);
08376                         //same
08377                         break;
08378                 default:
08379                         break;
08380                 }
08381 
08382                 cgSiegeEntityRender = 0;
08383         }
08384         else if (cgSiegeRoundTime)
08385         {
08386                 CG_CenterPrint("", SCREEN_HEIGHT * 0.30, BIGCHAR_WIDTH);
08387                 cgSiegeRoundTime = 0;
08388 
08389                 //cgSiegeRoundBeganTime = cg.time;
08390                 cgSiegeEntityRender = 0;
08391         }
08392         else if (cgSiegeRoundBeganTime)
08393         { //Draw how much time is left in the round based on local info.
08394                 int timedTeam = TEAM_FREE;
08395                 int timedValue = 0;
08396 
08397                 if (cgSiegeEntityRender)
08398                 { //render the objective item model since this client has it
08399                         CG_DrawSiegeHUDItem();
08400                 }
08401 
08402                 if (team1Timed)
08403                 {
08404                         timedTeam = TEAM_RED; //team 1
08405                         if (cg_beatingSiegeTime)
08406                         {
08407                                 timedValue = cg_beatingSiegeTime;
08408                         }
08409                         else
08410                         {
08411                                 timedValue = team1Timed;
08412                         }
08413                 }
08414                 else if (team2Timed)
08415                 {
08416                         timedTeam = TEAM_BLUE; //team 2
08417                         if (cg_beatingSiegeTime)
08418                         {
08419                                 timedValue = cg_beatingSiegeTime;
08420                         }
08421                         else
08422                         {
08423                                 timedValue = team2Timed;
08424                         }
08425                 }
08426 
08427                 if (timedTeam != TEAM_FREE)
08428                 { //one of the teams has a timer
08429                         int timeRemaining;
08430                         qboolean isMyTeam = qfalse;
08431 
08432                         if (cgs.siegeTeamSwitch && !cg_beatingSiegeTime)
08433                         { //in switchy mode but not beating a time, so count up.
08434                                 timeRemaining = (cg.time-cgSiegeRoundBeganTime);
08435                                 if (timeRemaining < 0)
08436                                 {
08437                                         timeRemaining = 0;
08438                                 }
08439                         }
08440                         else
08441                         {
08442                                 timeRemaining = (((cgSiegeRoundBeganTime)+timedValue) - cg.time);
08443                         }
08444 
08445                         if (timeRemaining > timedValue)
08446                         {
08447                                 timeRemaining = timedValue;
08448                         }
08449                         else if (timeRemaining < 0)
08450                         {
08451                                 timeRemaining = 0;
08452                         }
08453 
08454                         if (timeRemaining)
08455                         {
08456                                 timeRemaining /= 1000;
08457                         }
08458 
08459                         if (cg.predictedPlayerState.persistant[PERS_TEAM] == timedTeam)
08460                         { //the team that's timed is the one this client is on
08461                                 isMyTeam = qtrue;
08462                         }
08463 
08464                         CG_DrawSiegeTimer(timeRemaining, isMyTeam);
08465                 }
08466         }
08467         else
08468         {
08469                 cgSiegeEntityRender = 0;
08470         }
08471 
08472         if ( cg_siegeDeathTime )
08473         {
08474                 int timeRemaining = ( cg_siegeDeathTime - cg.time );
08475 
08476                 if ( timeRemaining < 0 )
08477                 {
08478                         timeRemaining = 0;
08479                         cg_siegeDeathTime = 0;
08480                 }
08481 
08482                 if ( timeRemaining )
08483                 {
08484                         timeRemaining /= 1000;
08485                 }
08486 
08487                 CG_DrawSiegeDeathTimer( timeRemaining );
08488         }
08489 
08490         // don't draw center string if scoreboard is up
08491         cg.scoreBoardShowing = CG_DrawScoreboard();
08492         if ( !cg.scoreBoardShowing) {
08493                 CG_DrawCenterString();
08494         }
08495         
08496         // always draw chat
08497         CG_ChatBox_DrawStrings();
08498 }
08499 
08500 
08501 static void CG_DrawTourneyScoreboard() {
08502 }
08503 
08504 /*
08505 =====================
08506 CG_DrawActive
08507 
08508 Perform all drawing needed to completely fill the screen
08509 =====================
08510 */
08511 void CG_DrawActive( stereoFrame_t stereoView ) {
08512         float           separation;
08513         vec3_t          baseOrg;
08514 
08515         // optionally draw the info screen instead
08516         if ( !cg.snap ) {
08517                 CG_DrawInformation();
08518                 return;
08519         }
08520 
08521         // optionally draw the tournement scoreboard instead
08522         if ( cg.snap->ps.persistant[PERS_TEAM] == TEAM_SPECTATOR &&
08523                 ( cg.snap->ps.pm_flags & PMF_SCOREBOARD ) ) {
08524                 CG_DrawTourneyScoreboard();
08525                 return;
08526         }
08527 
08528         switch ( stereoView ) {
08529         case STEREO_CENTER:
08530                 separation = 0;
08531                 break;
08532         case STEREO_LEFT:
08533                 separation = -cg_stereoSeparation.value / 2;
08534                 break;
08535         case STEREO_RIGHT:
08536                 separation = cg_stereoSeparation.value / 2;
08537                 break;
08538         default:
08539                 separation = 0;
08540                 CG_Error( "CG_DrawActive: Undefined stereoView" );
08541         }
08542 
08543 
08544         // clear around the rendered view if sized down
08545         CG_TileClear();
08546 
08547         // offset vieworg appropriately if we're doing stereo separation
08548         VectorCopy( cg.refdef.vieworg, baseOrg );
08549         if ( separation != 0 ) {
08550                 VectorMA( cg.refdef.vieworg, -separation, cg.refdef.viewaxis[1], cg.refdef.vieworg );
08551         }
08552 
08553         cg.refdef.rdflags |= RDF_DRAWSKYBOX;
08554 
08555         // draw 3D view
08556         trap_R_RenderScene( &cg.refdef );
08557 
08558         // restore original viewpoint if running stereo
08559         if ( separation != 0 ) {
08560                 VectorCopy( baseOrg, cg.refdef.vieworg );
08561         }
08562 
08563         // draw status bar and other floating elements
08564         CG_Draw2D();
08565 }
08566 
08567 
08568