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_WorldCoordToScreenCo