00001
00002
00003
00004
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
00019 void CG_DrawDuelistHealth ( float x, float y, float w, float h, int duelist );
00020
00021
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;
00034
00035 char systemChat[256];
00036 char teamChat1[256];
00037 char teamChat2[256];
00038
00039
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",
00078 "JUMP2",
00079 "SPEED2",
00080 "PUSH2",
00081 "PULL2",
00082 "MINDTRICK2",
00083 "GRIP2",
00084 "LIGHTNING2",
00085 "DARK_RAGE2",
00086 "PROTECT2",
00087 "ABSORB2",
00088 "TEAM_HEAL2",
00089 "TEAM_REPLENISH2",
00090 "DRAIN2",
00091 "SEEING2",
00092 "SABER_OFFENSE2",
00093 "SABER_DEFENSE2",
00094 "SABER_THROW2",
00095 NULL
00096 };
00097
00098
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;
00115
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"
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;
00146 case ITEM_TEXTSTYLE_BLINK: iStyleOR = STYLE_BLINK;break;
00147 case ITEM_TEXTSTYLE_PULSE: iStyleOR = STYLE_BLINK;break;
00148 case ITEM_TEXTSTYLE_SHADOWED: iStyleOR = (int)STYLE_DROPSHADOW;break;
00149 case ITEM_TEXTSTYLE_OUTLINED: iStyleOR = (int)STYLE_DROPSHADOW;break;
00150 case ITEM_TEXTSTYLE_OUTLINESHADOWED: iStyleOR = (int)STYLE_DROPSHADOW;break;
00151 case ITEM_TEXTSTYLE_SHADOWEDMORE: iStyleOR = (int)STYLE_DROPSHADOW;break;
00152 }
00153
00154 trap_R_Font_DrawString( x,
00155 y,
00156 text,
00157 color,
00158 iStyleOR | iFontIndex,
00159 !limit?-1:limit,
00160 scale
00161 );
00162 }
00163
00164
00165
00166
00167
00168
00169
00170
00171
00172
00173
00174
00175
00176
00177
00178
00179
00180
00181
00182
00183
00184
00185
00186
00187
00188
00189
00190
00191
00192
00193
00194
00195
00196
00197
00198
00199
00200
00201
00202
00203
00204
00205
00206
00207
00208
00209
00210
00211
00212
00213
00214
00215
00216
00217
00218
00219
00220 static void CG_DrawZoomMask( void )
00221 {
00222 vec4_t color1;
00223 float level;
00224 static qboolean flip = qtrue;
00225
00226
00227 float cx, cy;
00228
00229 float max, fi;
00230
00231
00232 if ( cg.predictedPlayerState.zoomMode == 2 )
00233 {
00234 int val, i;
00235 float off;
00236
00237
00238 level = (float)(80.0f - cg.predictedPlayerState.zoomFov) / 80.0f;
00239
00240
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
00251 level *= 162.0f;
00252
00253
00254 trap_R_SetColor( colorTable[CT_WHITE] );
00255 CG_DrawPic( 34, 48, 570, 362, cgs.media.binocularStatic );
00256
00257
00258 trap_R_SetColor( colorTable[CT_BLACK]);
00259 CG_DrawPic( 212, 367, 200, 40, cgs.media.whiteShader );
00260
00261
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
00269
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
00283
00284 if (( off > 3.0f && i == -10 ) || i > -10 )
00285 {
00286
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
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
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
00333 level = (float)(50.0f - zoomFov) / 50.0f;
00334
00335
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
00346 level *= 103.0f;
00347
00348
00349 trap_R_SetColor( colorTable[CT_WHITE] );
00350 CG_DrawPic( 0, 0, 640, 480, cgs.media.disruptorMask );
00351
00352
00353 if ( level >= 99 )
00354 {
00355
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
00365 CG_DrawRotatePic2( 320, 240, 640, 480, -level, cgs.media.disruptorInsert );
00366
00367
00368
00369
00370
00371
00372
00373
00374
00375
00376
00377
00378
00379
00380
00381
00382
00383
00384
00385
00386
00387
00388
00389
00390
00391
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
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 )
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
00445 max = ( cg.time - cg.predictedPlayerState.weaponChargeTime ) / ( 50.0f * 30.0f );
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
00455
00456
00457 }
00458 }
00459
00460
00461
00462
00463
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;
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
00508
00509
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 {
00518 return;
00519 }
00520
00521 ci = &cgs.clientinfo[ clientNum ];
00522
00523 CG_DrawPic( x, y, w, h, ci->modelIcon );
00524
00525
00526 if ( ci->deferred )
00527 {
00528 CG_DrawPic( x, y, w, h, cgs.media.deferShader );
00529 }
00530 }
00531
00532
00533
00534
00535
00536
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
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
00559
00560 len = 0.5 * ( maxs[2] - mins[2] );
00561 origin[0] = len / 0.268;
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;
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
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
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
00624 if (!menuHUD)
00625 {
00626 return;
00627 }
00628
00629 ps = &cg.snap->ps;
00630
00631
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
00643 for (i=(MAX_HUD_TICS-1);i>=0;i--)
00644 {
00645 focusItem = Menu_FindItemByName(menuHUD, healthTicName[i]);
00646
00647 if (!focusItem)
00648 {
00649 continue;
00650 }
00651
00652 memcpy(calcColor, hudTintColor, sizeof(vec4_t));
00653
00654 if (currValue <= 0)
00655 {
00656 break;
00657 }
00658 else if (currValue < inc)
00659 {
00660 percent = (float) currValue / inc;
00661 calcColor[3] *= percent;
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
00678 focusItem = Menu_FindItemByName(menuHUD, "healthamount");
00679 if (focusItem)
00680 {
00681
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
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
00712 ps = &cg.predictedPlayerState;
00713
00714
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)
00737 {
00738 continue;
00739 }
00740
00741 memcpy(calcColor, hudTintColor, sizeof(vec4_t));
00742
00743 if (currValue <= 0)
00744 {
00745 break;
00746 }
00747 else if (currValue < inc)
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
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
00801 if (armor)
00802 {
00803 quarterArmor = (float) (ps->stats[STAT_MAX_HEALTH] / 4.0f);
00804
00805
00806 if (ps->stats[STAT_ARMOR] < quarterArmor)
00807 {
00808 if (cg.HUDTickFlashTime < cg.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
00827 {
00828 cg.HUDArmorFlag=qfalse;
00829 }
00830
00831 }
00832
00833
00834
00835
00836
00837
00838
00839
00840
00841 static void CG_DrawSaberStyle( centity_t *cent, menuDef_t *menuHUD)
00842 {
00843 itemDef_t *focusItem;
00844
00845 if (!cent->currentState.weapon )
00846 {
00847 return;
00848 }
00849
00850 if ( cent->currentState.weapon != WP_SABER )
00851 {
00852 return;
00853 }
00854
00855
00856 if (!menuHUD)
00857 {
00858 return;
00859 }
00860
00861
00862
00863 switch ( cg.predictedPlayerState.fd.saberDrawAnimLevel )
00864 {
00865 case 1:
00866 case 5:
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:
00885 case 6:
00886 case 7:
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:
00903 case 4:
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
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
00939 if (!menuHUD)
00940 {
00941 return;
00942 }
00943
00944 if (!cent->currentState.weapon )
00945 {
00946 return;
00947 }
00948
00949 value = ps->ammo[weaponData[cent->currentState.weapon].ammoIndex];
00950 if (value < 0)
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 {
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
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 )
01013 {
01014 break;
01015 }
01016 else if (value < inc)
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
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
01052 if (!menuHUD)
01053 {
01054 return;
01055 }
01056
01057
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
01078 {
01079 cg.forceHUDNextFlashTime = 0;
01080 cg.forceHUDActive = qtrue;
01081 }
01082
01083
01084
01085
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
01101
01102 if ( value <= 0 )
01103 {
01104 break;
01105 }
01106 else if (value < inc)
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
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
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 {
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
01238 hudTintColor = colorTable[CT_WHITE];
01239 }
01240 else
01241 {
01242 hudTintColor = colorTable[CT_WHITE];
01243 }
01244
01245
01246 menuHUD = Menus_FindByName("lefthud");
01247 if (menuHUD)
01248 {
01249 itemDef_t *focusItem;
01250
01251
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
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
01288 }
01289
01290
01291 if ( cgs.gametype == GT_DUEL )
01292 {
01293
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 {
01298 scoreBias = cg.snap->ps.persistant[PERS_SCORE] - cgs.scores1;
01299 if (scoreBias == 0)
01300 {
01301 if (cgs.scores2 <= 0)
01302 {
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
01319 {
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 {
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
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
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
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
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
01436 if ( cg.snap->ps.stats[STAT_HEALTH] <= 0 )
01437 {
01438 return;
01439 }
01440
01441 if ((cg.forceSelectTime+WEAPON_SELECT_TIME)<cg.time)
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
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)
01471 {
01472 return;
01473 }
01474
01475 sideMax = 3;
01476
01477
01478 holdCount = count - 1;
01479 if (holdCount == 0)
01480 {
01481 sideLeftIconCnt = 0;
01482 sideRightIconCnt = 0;
01483 }
01484 else if (count > (2*sideMax))
01485 {
01486 sideLeftIconCnt = sideMax;
01487 sideRightIconCnt = sideMax;
01488 }
01489 else
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
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
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]))
01523 {
01524 continue;
01525 }
01526
01527 ++iconCnt;
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
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] );
01542 }
01543 }
01544
01545 i = BG_ProperForceIndex(cg.forceSelect) + 1;
01546 if (i>MAX_SHOWPOWERS)
01547 {
01548 i = 0;
01549 }
01550
01551
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]))
01561 {
01562 continue;
01563 }
01564
01565 ++iconCnt;
01566
01567 if (cgs.media.forcePowerIcons[forcePowerSorted[i]])
01568 {
01569 CG_DrawPic( holdX, y + yOffset, smallIconSize, smallIconSize, cgs.media.forcePowerIcons[forcePowerSorted[i]] );
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
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
01597 if ( cg.snap->ps.stats[STAT_HEALTH] <= 0 )
01598 {
01599 return;
01600 }
01601
01602 if ((cg.invenSelectTime+WEAPON_SELECT_TIME)<cg.time)
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
01624
01625
01626 count = 0;
01627 for ( i = 0 ; i < HI_NUM_HOLDABLE ; i++ )
01628 {
01629 if (
01630 (cg.snap->ps.stats[STAT_HOLDABLE_ITEMS] & (1 << i)) )
01631 {
01632 count++;
01633 }
01634 }
01635
01636 if (!count)
01637 {
01638 y2 = 0;
01639 UI_DrawProportionalString(320, y2 + 22, "EMPTY INVENTORY", UI_CENTER | UI_SMALLFONT, colorTable[CT_ICON_BLUE]);
01640 return;
01641 }
01642
01643 sideMax = 3;
01644
01645
01646 holdCount = count - 1;
01647 if (holdCount == 0)
01648 {
01649 sideLeftIconCnt = 0;
01650 sideRightIconCnt = 0;
01651 }
01652 else if (count > (2*sideMax))
01653 {
01654 sideLeftIconCnt = sideMax;
01655 sideRightIconCnt = sideMax;
01656 }
01657 else
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
01677
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;
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
01708
01709
01710
01711 holdX -= (smallIconSize+pad);
01712 }
01713 }
01714
01715
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
01725
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
01754
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;
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
01784
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 {
01800 return qfalse;
01801 }
01802
01803 *alpha = 1.0f;
01804
01805
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 {
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 {
01822 if ( cg_entities[targetNum].currentState.m_iVehicleNum >= MAX_CLIENTS )
01823 {
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 {
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 {
01852 *alpha = 1.0f;
01853 }
01854 else
01855 {
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
01899
01900
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)
01916 {
01917 break;
01918 }
01919 else if (currValue < inc)
01920 {
01921 float percent = currValue / inc;
01922 calcColor[3] *= percent;
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)
01989 {
01990 break;
01991 }
01992 else if (currValue < inc)
01993 {
01994 float percent = currValue / inc;
01995 calcColor[3] *= percent;
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)
02060 {
02061 break;
02062 }
02063 else if (currValue < inc)
02064 {
02065 float percent = currValue / inc;
02066 calcColor[3] *= percent;
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)
02132 {
02133 break;
02134 }
02135 else if (currValue < inc)
02136 {
02137 float percent = currValue / inc;
02138 calcColor[3] *= percent;
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
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 {
02204 drawLink = qtrue;
02205 }
02206 else
02207 {
02208
02209
02210 if ( cg.predictedVehicleState.vehWeaponsLinked )
02211 {
02212 drawLink = qtrue;
02213 }
02214
02215
02216
02217
02218
02219
02220
02221
02222
02223 }
02224
02225 if ( cg_drawLink != drawLink )
02226 {
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
02277
02278
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
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)
02322 {
02323 break;
02324 }
02325 else if (currValue < inc)
02326 {
02327 float percent = currValue / inc;
02328 calcColor[3] *= percent;
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
02370
02371
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)
02388 {
02389 break;
02390 }
02391 else if (currValue < inc)
02392 {
02393 float percent = currValue / inc;
02394 calcColor[3] *= percent;
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
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
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 {
02515
02516 float perc = 1.0f - ((veh->damageTime - cg.time) / 2000.0f);
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];
02526 color[1] = item->window.foreColor[1]*perc;
02527 color[2] = item->window.foreColor[2]*perc;
02528 color[3] = item->window.foreColor[3];
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
02578
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;
02597 }
02598
02599 ps = &cg.predictedPlayerState;
02600
02601 if (!ps || !(ps->m_iVehicleNum))
02602 {
02603 return qtrue;
02604 }
02605 veh = &cg_entities[ps->m_iVehicleNum];
02606
02607 if ( !veh )
02608 {
02609 return qtrue;
02610 }
02611
02612 CG_DrawVehicleTurboRecharge( menuHUD, veh );
02613 CG_DrawVehicleWeaponsLinked( menuHUD, veh );
02614
02615 item = Menu_FindItemByName(menuHUD, "leftframe");
02616
02617
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
02646
02647
02648
02649
02650
02651
02652 CG_DrawVehicleSpeed( menuHUD, veh );
02653
02654
02655
02656
02657
02658
02659
02660
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
02676 if (veh->m_pVehicle->m_pVehicleInfo->hideRider)
02677 {
02678 CG_DrawVehicleDamageHUD(veh,cg.predictedVehicleState.brokenLimbs,shieldPerc,"vehicledamagehud",1.0f);
02679
02680
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;
02687 }
02688
02689 return qtrue;
02690
02691 }
02692
02693
02694
02695
02696
02697
02698
02699 static void CG_DrawStats( void )
02700 {
02701 centity_t *cent;
02702 playerState_t *ps;
02703 qboolean drawHUD = qtrue;
02704
02705
02706
02707
02708
02709
02710
02711
02712 cent = &cg_entities[cg.snap->ps.clientNum];
02713
02714
02715
02716
02717
02718
02719
02720
02721
02722
02723
02724
02725 if ( cent )
02726 {
02727 ps = &cg.predictedPlayerState;
02728
02729 if ( (ps->m_iVehicleNum ) )
02730 {
02731 drawHUD = CG_DrawVehicleHud( cent );
02732 }
02733 }
02734
02735 if (drawHUD)
02736 {
02737 CG_DrawHUD(cent);
02738 }
02739
02740
02741
02742
02743
02744
02745 }
02746
02747
02748
02749
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
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
02793
02794 CG_FillRect ( x, y, w, h, hcolor );
02795
02796 trap_R_SetColor( NULL );
02797 }
02798
02799
02800
02801
02802
02803
02804
02805
02806
02807
02808
02809
02810
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 {
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
02846
02847
02848
02849
02850
02851
02852
02853
02854
02855 }
02856
02857
02858 return y;
02859 }
02860
02861
02862
02863
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 {
02895 return y;
02896 }
02897
02898 if ( cgs.gametype == GT_JEDIMASTER )
02899 {
02900
02901 title = CG_GetStringEdString("MP_INGAME", "MASTERY7");
02902 clientNum = cgs.jediMaster;
02903
02904 if ( clientNum < 0 )
02905 {
02906
02907
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
02920
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
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;
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
02958
02959
02960
02961
02962
02963
02964
02965
02966
02967
02968
02969
02970
02971
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
02982
02983
02984
02985
02986
02987
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
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
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 {
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
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
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
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
03087
03088 t = trap_Milliseconds();
03089 frameTime = t - previous;
03090 previous = t;
03091 if (t - lastupdate > 50)
03092 {
03093 lastupdate = t;
03094 previousTimes[index % FPS_FRAMES] = frameTime;
03095 index++;
03096 }
03097
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
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));
03127 CG_DrawRect(x + 1, y + height/2-1, midpoint, 1, height/4+1, color1);
03128 CG_DrawRect(x + midpoint, y + height/2-1, remainder, 1, height/4+1, color3);
03129 CG_DrawRect(x, y, width, height, 1, color2);
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]);
03159 }
03160
03161
03162
03163
03164
03165
03166
03167 float cg_radarRange = 2500.0f;
03168
03169 #define RADAR_RADIUS 60
03170 #define RADAR_X (580 - RADAR_RADIUS)
03171
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
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
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
03225 VectorCopy ( g_color_table[ColorIndex(COLOR_GREEN)], teamColor );
03226 teamColor[3] = 1.0f;
03227
03228
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
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)
03249 || ( cent->currentState.eType==ET_NPC
03250 && cent->currentState.NPC_class == CLASS_VEHICLE
03251 && cent->currentState.speed > 0 ) )
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
03289 if (cent->lerpOrigin[2] > cg.predictedPlayerState.origin[2])
03290 {
03291 float dif = (cent->lerpOrigin[2] - cg.predictedPlayerState.origin[2]);
03292
03293
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 {
03303 float dif = (cg.predictedPlayerState.origin[2] - cent->lerpOrigin[2]);
03304
03305
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 {
03318
03319
03320 char objState[1024];
03321 int complete;
03322
03323
03324
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
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
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
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:
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
03408 if (cent->lerpOrigin[2] > cg.predictedPlayerState.origin[2])
03409 {
03410 float dif = (cent->lerpOrigin[2] - cg.predictedPlayerState.origin[2]);
03411
03412
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 {
03422 float dif = (cg.predictedPlayerState.origin[2] - cent->lerpOrigin[2]);
03423
03424
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
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;
03455
03456 case ET_MOVER:
03457 if ( cent->currentState.speed
03458 && actualDist < (cent->currentState.speed+RADAR_ASTEROID_RANGE)
03459 && cg.predictedPlayerState.m_iVehicleNum )
03460 {
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 {
03469 mayImpact = qtrue;
03470 }
03471 else
03472 {
03473 vec3_t asteroidPos, myPos, moveDir;
03474 int predictTime, timeStep = 500;
03475 float newDist;
03476 for ( predictTime = timeStep; predictTime < 5000; predictTime+=timeStep )
03477 {
03478
03479 BG_EvaluateTrajectory( ¢->currentState.pos, cg.time+predictTime, asteroidPos );
03480
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 )
03485 {
03486 mayImpact = qtrue;
03487 break;
03488 }
03489 }
03490 }
03491 if ( mayImpact )
03492 {
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);
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
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
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 (
03560 cent->currentState.owner > MAX_CLIENTS
03561 && cg_entities[cent->currentState.owner].currentState.NPC_class == CLASS_VEHICLE )
03562 {
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 {
03572
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
03609 if (cent->lerpOrigin[2] > cg.predictedPlayerState.origin[2])
03610 {
03611 float dif = (cent->lerpOrigin[2] - cg.predictedPlayerState.origin[2]);
03612
03613
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 {
03623 float dif = (cg.predictedPlayerState.origin[2] - cent->lerpOrigin[2]);
03624
03625
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
03637 && cg_entities[cent->currentState.owner].currentState.NPC_class == CLASS_VEHICLE
03638 && cg_entities[cent->currentState.owner].currentState.m_iVehicleNum <= MAX_CLIENTS
03639 && cgs.clientinfo[cg_entities[cent->currentState.owner].currentState.m_iVehicleNum-1].infoValid )
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
03666 if ( !cl->infoValid )
03667 {
03668 continue;
03669 }
03670
03671 VectorCopy4 ( teamColor, color );
03672
03673 arrowBaseScale = 16.0f;
03674 zScale = 1.0f;
03675
03676
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
03689 if (cent->lerpOrigin[2] > cg.predictedPlayerState.origin[2])
03690 {
03691 float dif = (cent->lerpOrigin[2] - cg.predictedPlayerState.origin[2]);
03692
03693
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 {
03703 float dif = (cg.predictedPlayerState.origin[2] - cent->lerpOrigin[2]);
03704
03705
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
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
03776
03777
03778 extern const char *CG_GetLocationString(const char *loc);
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;
03802 }
03803
03804 plyrs = 0;
03805
03806
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
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 {
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
03891
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
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
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
03949 }
03950
03951
03952 static void CG_DrawPowerupIcons(int y)
03953 {
03954 int j;
03955 int ico_size = 64;
03956
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
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 {
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
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
04095
04096
04097
04098
04099
04100
04101
04102
04103
04104
04105
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
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
04157
04158
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
04172
04173
04174
04175
04176
04177
04178
04179 void CG_AddLagometerSnapshotInfo( snapshot_t *snap ) {
04180
04181 if ( !snap ) {
04182 lagometer.snapshotSamples[ lagometer.snapshotCount & ( LAG_SAMPLES - 1) ] = -1;
04183 lagometer.snapshotCount++;
04184 return;
04185 }
04186
04187
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
04196
04197
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;
04206
04207 if (cg.mMapChange)
04208 {
04209 s = CG_GetStringEdString("MP_INGAME", "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");
04214 w = CG_DrawStrlen( s ) * BIGCHAR_WIDTH;
04215 CG_DrawBigString( 320 - w/2, 200, s, 1.0F);
04216 return;
04217 }
04218
04219
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 ) {
04224 return;
04225 }
04226
04227
04228 s = CG_GetStringEdString("MP_INGAME", "CONNECTION_INTERRUPTED");
04229 w = CG_DrawStrlen( s ) * BIGCHAR_WIDTH;
04230 CG_DrawBigString( 320 - w/2, 100, s, 1.0F);
04231
04232
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
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
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
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
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;
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;
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
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
04385
04386
04387
04388
04389
04390
04391
04392
04393
04394
04395
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
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
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;
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
04481
04482
04483
04484
04485 #define HEALTH_WIDTH 50.0f
04486 #define HEALTH_HEIGHT 5.0f
04487
04488
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 {
04507 return;
04508 }
04509
04510 if ((cg.time - se->lastUpdated) > 10000)
04511 {
04512 return;
04513 }
04514
04515 if (cent->currentState.eFlags & EF_DEAD)
04516 {
04517 return;
04518 }
04519
04520 if (cent->currentState.weapon != se->weapon)
04521 {
04522 return;
04523 }
04524
04525 ci = &cgs.clientinfo[cent->currentState.number];
04526 if (ci->team != cg.predictedPlayerState.persistant[PERS_TEAM])
04527 {
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 {
04536 return;
04537 }
04538
04539 siegeClass = BG_SiegeFindClassByName(v);
04540
04541 if (!siegeClass)
04542 {
04543 return;
04544 }
04545
04546 if (!(siegeClass->classflags & (1<<CFL_STATVIEWER)))
04547 {
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
04556 aColor[0] = 0.0f;
04557 aColor[1] = 1.0f;
04558 aColor[2] = 0.0f;
04559 aColor[3] = 0.4f;
04560
04561
04562 bColor[0] = 0.0f;
04563 bColor[1] = 0.0f;
04564 bColor[2] = 0.0f;
04565 bColor[3] = 0.3f;
04566
04567
04568 cColor[0] = 0.5f;
04569 cColor[1] = 0.5f;
04570 cColor[2] = 0.5f;
04571 cColor[3] = 0.4f;
04572
04573
04574 CG_DrawRect(x, y, HEALTH_WIDTH, HEALTH_HEIGHT, 1.0f, colorTable[CT_BLACK]);
04575
04576
04577 CG_FillRect(x+1.0f, y+1.0f, percent-1.0f, HEALTH_HEIGHT-1.0f, aColor);
04578
04579
04580 CG_FillRect(x+percent, y+1.0f, HEALTH_WIDTH-percent-1.0f, HEALTH_HEIGHT-1.0f, cColor);
04581
04582
04583
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 {
04596 percent = HEALTH_WIDTH;
04597 }
04598 else
04599 {
04600 percent = ((float)se->ammo/(float)ammoMax)*HEALTH_WIDTH;
04601 }
04602
04603
04604 aColor[0] = 1.0f;
04605 aColor[1] = 1.0f;
04606 aColor[2] = 0.0f;
04607 aColor[3] = 0.4f;
04608
04609
04610 bColor[0] = 0.0f;
04611 bColor[1] = 0.0f;
04612 bColor[2] = 0.0f;
04613 bColor[3] = 0.3f;
04614
04615
04616 cColor[0] = 0.5f;
04617 cColor[1] = 0.5f;
04618 cColor[2] = 0.5f;
04619 cColor[3] = 0.4f;
04620
04621
04622 CG_DrawRect(x, y, HEALTH_WIDTH, HEALTH_HEIGHT, 1.0f, colorTable[CT_BLACK]);
04623
04624
04625 CG_FillRect(x+1.0f, y+1.0f, percent-1.0f, HEALTH_HEIGHT-1.0f, aColor);
04626
04627
04628 CG_FillRect(x+percent, y+1.0f, HEALTH_WIDTH-percent-1.0f, HEALTH_HEIGHT-1.0f, cColor);
04629 }
04630
04631
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
04646 if (!cent->currentState.teamowner || cgs.gametype < GT_TEAM)
04647 {
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 {
04655 aColor[0] = 0.0f;
04656 aColor[1] = 1.0f;
04657 aColor[2] = 0.0f;
04658 aColor[3] = 0.4f;
04659 }
04660 else
04661 {
04662 aColor[0] = 1.0f;
04663 aColor[1] = 0.0f;
04664 aColor[2] = 0.0f;
04665 aColor[3] = 0.4f;
04666 }
04667
04668
04669 bColor[0] = 0.0f;
04670 bColor[1] = 0.0f;
04671 bColor[2] = 0.0f;
04672 bColor[3] = 0.3f;
04673
04674
04675 cColor[0] = 0.5f;
04676 cColor[1] = 0.5f;
04677 cColor[2] = 0.5f;
04678 cColor[3] = 0.4f;
04679
04680
04681 CG_DrawRect(x, y, HEALTH_WIDTH, HEALTH_HEIGHT, 1.0f, colorTable[CT_BLACK]);
04682
04683
04684 CG_FillRect(x+1.0f, y+1.0f, percent-1.0f, HEALTH_HEIGHT-1.0f, aColor);
04685
04686
04687 CG_FillRect(x+percent, y+1.0f, HEALTH_WIDTH-percent-1.0f, HEALTH_HEIGHT-1.0f, cColor);
04688 }
04689
04690
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
04707 aColor[0] = 1.0f;
04708 aColor[1] = 1.0f;
04709 aColor[2] = 0.0f;
04710 aColor[3] = 0.4f;
04711
04712
04713 bColor[0] = 0.0f;
04714 bColor[1] = 0.0f;
04715 bColor[2] = 0.0f;
04716 bColor[3] = 0.3f;
04717
04718
04719 cColor[0] = 0.5f;
04720 cColor[1] = 0.5f;
04721 cColor[2] = 0.5f;
04722 cColor[3] = 0.1f;
04723
04724
04725 CG_DrawRect(x, y, HEALTH_WIDTH, HEALTH_HEIGHT, 1.0f, colorTable[CT_BLACK]);
04726
04727
04728 CG_FillRect(x+1.0f, y+1.0f, percent-1.0f, HEALTH_HEIGHT-1.0f, aColor);
04729
04730
04731 CG_FillRect(x+percent, y+1.0f, HEALTH_WIDTH-percent-1.0f, HEALTH_HEIGHT-1.0f, cColor);
04732
04733
04734 CG_DrawPic(x, y-HEALTH_WIDTH, HEALTH_WIDTH, HEALTH_WIDTH, cgs.media.hackerIconShader);
04735 }
04736
04737
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
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
04771 bColor[0] = 0.0f;
04772 bColor[1] = 0.0f;
04773 bColor[2] = 0.0f;
04774 bColor[3] = 0.3f;
04775
04776
04777 cColor[0] = 0.5f;
04778 cColor[1] = 0.5f;
04779 cColor[2] = 0.5f;
04780 cColor[3] = 0.1f;
04781
04782
04783 CG_DrawRect(x, y, CGTIMERBAR_W, CGTIMERBAR_H, 1.0f, colorTable[CT_BLACK]);
04784
04785
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
04789 CG_FillRect(x+1.0f, y+1.0f, CGTIMERBAR_W-2.0f, CGTIMERBAR_H-percent, cColor);
04790 }
04791
04792
04793
04794
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 {
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 {
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 {
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
04892 if ( cg.crosshairClientNum >= ENTITYNUM_WORLD )
04893 {
04894 trap_R_SetColor( NULL );
04895 }
04896
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 ||
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 {
04909 ecolor[0] = 1.0;
04910 ecolor[1] = 1.0;
04911 ecolor[2] = 1.0;
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
04919 ecolor[0] = 0.0;
04920 ecolor[1] = 1.0;
04921 ecolor[2] = 0.0;
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 {
04928 ecolor[0] = 0.0;
04929 ecolor[1] = 1.0;
04930 ecolor[2] = 0.0;
04931 }
04932 else
04933 {
04934 ecolor[0] = 1.0;
04935 ecolor[1] = 0.0;
04936 ecolor[2] = 0.0;
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 {
04947 ecolor[0] = 0.4;
04948 ecolor[1] = 0.4;
04949 ecolor[2] = 0.4;
04950 }
04951 }
04952 else if (crossEnt->currentState.bolt1)
04953 {
04954
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
04963 if ( !ecolor[0] && !ecolor[1] && !ecolor[2] )
04964 {
04965
04966 ecolor[0] = 1.0F;
04967 ecolor[1] = 0.8F;
04968 ecolor[2] = 0.3F;
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;
04986 ecolor[1] = 1.0;
04987 ecolor[2] = 1.0;
04988 }
04989 else if ( !crossEnt->currentState.teamowner )
04990 {
04991 if (!crossEnt->currentState.teamowner ||
04992 crossEnt->currentState.NPC_class == CLASS_VEHICLE)
04993 {
04994 if (crossEnt->currentState.owner < MAX_CLIENTS)
04995 {
04996 clientInfo_t *ci = &cgs.clientinfo[crossEnt->currentState.owner];
04997
04998 if (cgs.gametype >= GT_TEAM && ci->team == cg.predictedPlayerState.persistant[PERS_TEAM])
04999 {
05000 ecolor[0] = 0.0;
05001 ecolor[1] = 1.0;
05002 ecolor[2] = 0.0;
05003 }
05004 else
05005 {
05006 ecolor[0] = 1.0;
05007 ecolor[1] = 0.0;
05008 ecolor[2] = 0.0;
05009 #ifdef _XBOX
05010 cg_crossHairStatus = 1;
05011 #endif
05012 }
05013 }
05014 else
05015 {
05016 ecolor[0] = 1.0;
05017 ecolor[1] = 1.0;
05018 ecolor[2] = 0.0;
05019 }
05020 }
05021 else
05022 {
05023 ecolor[0] = 1.0;
05024 ecolor[1] = 0.0;
05025 ecolor[2] = 0.0;
05026 #ifdef _XBOX
05027 cg_crossHairStatus = 1;
05028 #endif
05029 }
05030 }
05031 else if ( crossEnt->currentState.teamowner != plTeam )
05032 {
05033 ecolor[0] = 1.0;
05034 ecolor[1] = 0.0;
05035 ecolor[2] = 0.0;
05036 #ifdef _XBOX
05037 cg_crossHairStatus = 1;
05038 #endif
05039 }
05040 else
05041 {
05042 ecolor[0] = 0.0;
05043 ecolor[1] = 1.0;
05044 ecolor[2] = 0.0;
05045 }
05046 }
05047 else if ( crossEnt->currentState.teamowner == TEAM_RED
05048 || crossEnt->currentState.teamowner == TEAM_BLUE )
05049 {
05050 if (cgs.gametype < GT_TEAM)
05051 {
05052 ecolor[0] = 1.0;
05053 ecolor[1] = 1.0;
05054 ecolor[2] = 0.0;
05055 }
05056 else if ( crossEnt->currentState.teamowner != cgs.clientinfo[cg.snap->ps.clientNum].team )
05057 {
05058 ecolor[0] = 1.0;
05059 ecolor[1] = 0.0;
05060 ecolor[2] = 0.0;
05061 #ifdef _XBOX
05062 cg_crossHairStatus = 1;
05063 #endif
05064 }
05065 else
05066 {
05067 ecolor[0] = 0.0;
05068 ecolor[1] = 1.0;
05069 ecolor[2] = 0.0;
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;
05076 ecolor[1] = 1.0;
05077 ecolor[2] = 0.0;
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;
05083 ecolor[1] = 0.0;
05084 ecolor[2] = 0.0;
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 {
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 {
05100 if (cgs.gametype < GT_TEAM)
05101 {
05102 ecolor[0] = 1.0;
05103 ecolor[1] = 1.0;
05104 ecolor[2] = 0.0;
05105 }
05106 else if (cg.predictedPlayerState.persistant[PERS_TEAM] != crossEnt->currentState.teamowner)
05107 {
05108 ecolor[0] = 1.0;
05109 ecolor[1] = 0.0;
05110 ecolor[2] = 0.0;
05111 #ifdef _XBOX
05112 cg_crossHairStatus = 1;
05113 #endif
05114 }
05115 else
05116 {
05117 ecolor[0] = 0.0;
05118 ecolor[1] = 1.0;
05119 ecolor[2] = 0.0;
05120 }
05121 }
05122 else if (crossEnt->currentState.health)
05123 {
05124 if (!crossEnt->currentState.teamowner || cgs.gametype < GT_TEAM)
05125 {
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 {
05132 ecolor[0] = 0.0f;
05133 ecolor[1] = 1.0f;
05134 ecolor[2] = 0.0f;
05135 }
05136 else
05137 {
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 {
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
05164 w = cg_crosshairSize.value*2.0f;
05165 h = w;
05166 }
05167 else
05168 {
05169 w = h = cg_crosshairSize.value;
05170 }
05171
05172
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 {
05184 return;
05185 }
05186
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
05206
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 {
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 {
05229 CG_DrawHealthBar(hisVeh, chX, chY, w, h);
05230 chY += HEALTH_HEIGHT*2;
05231 }
05232 }
05233 }
05234
05235 if (cg.predictedPlayerState.hackingTime)
05236 {
05237 CG_DrawHaqrBar(chX, chY, w, h);
05238 }
05239
05240 if (cg_genericTimerBar > cg.time)
05241 {
05242 CG_DrawGenericTimerBar();
05243 }
05244
05245 if ( corona )
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 );
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
05273
05274
05275
05276
05277 xcenter = 640.0f / 2.0f;
05278 ycenter = 480.0f / 2.0f;
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
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
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
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
05353
05354
05355
05356
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