00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026 #include "cg_local.h"
00027
00028 #ifdef MISSIONPACK
00029 #include "../ui/ui_shared.h"
00030
00031
00032 extern displayContextDef_t cgDC;
00033 menuDef_t *menuScoreboard = NULL;
00034 #else
00035 int drawTeamOverlayModificationCount = -1;
00036 #endif
00037
00038 int sortedTeamPlayers[TEAM_MAXOVERLAY];
00039 int numSortedTeamPlayers;
00040
00041 char systemChat[256];
00042 char teamChat1[256];
00043 char teamChat2[256];
00044
00045 #ifdef MISSIONPACK
00046
00047 int CG_Text_Width(const char *text, float scale, int limit) {
00048 int count,len;
00049 float out;
00050 glyphInfo_t *glyph;
00051 float useScale;
00052
00053
00054 const char *s = text;
00055 fontInfo_t *font = &cgDC.Assets.textFont;
00056 if (scale <= cg_smallFont.value) {
00057 font = &cgDC.Assets.smallFont;
00058 } else if (scale > cg_bigFont.value) {
00059 font = &cgDC.Assets.bigFont;
00060 }
00061 useScale = scale * font->glyphScale;
00062 out = 0;
00063 if (text) {
00064 len = strlen(text);
00065 if (limit > 0 && len > limit) {
00066 len = limit;
00067 }
00068 count = 0;
00069 while (s && *s && count < len) {
00070 if ( Q_IsColorString(s) ) {
00071 s += 2;
00072 continue;
00073 } else {
00074 glyph = &font->glyphs[(int)*s];
00075 out += glyph->xSkip;
00076 s++;
00077 count++;
00078 }
00079 }
00080 }
00081 return out * useScale;
00082 }
00083
00084 int CG_Text_Height(const char *text, float scale, int limit) {
00085 int len, count;
00086 float max;
00087 glyphInfo_t *glyph;
00088 float useScale;
00089
00090
00091 const char *s = text;
00092 fontInfo_t *font = &cgDC.Assets.textFont;
00093 if (scale <= cg_smallFont.value) {
00094 font = &cgDC.Assets.smallFont;
00095 } else if (scale > cg_bigFont.value) {
00096 font = &cgDC.Assets.bigFont;
00097 }
00098 useScale = scale * font->glyphScale;
00099 max = 0;
00100 if (text) {
00101 len = strlen(text);
00102 if (limit > 0 && len > limit) {
00103 len = limit;
00104 }
00105 count = 0;
00106 while (s && *s && count < len) {
00107 if ( Q_IsColorString(s) ) {
00108 s += 2;
00109 continue;
00110 } else {
00111 glyph = &font->glyphs[(int)*s];
00112 if (max < glyph->height) {
00113 max = glyph->height;
00114 }
00115 s++;
00116 count++;
00117 }
00118 }
00119 }
00120 return max * useScale;
00121 }
00122
00123 void CG_Text_PaintChar(float x, float y, float width, float height, float scale, float s, float t, float s2, float t2, qhandle_t hShader) {
00124 float w, h;
00125 w = width * scale;
00126 h = height * scale;
00127 CG_AdjustFrom640( &x, &y, &w, &h );
00128 trap_R_DrawStretchPic( x, y, w, h, s, t, s2, t2, hShader );
00129 }
00130
00131 void CG_Text_Paint(float x, float y, float scale, vec4_t color, const char *text, float adjust, int limit, int style) {
00132 int len, count;
00133 vec4_t newColor;
00134 glyphInfo_t *glyph;
00135 float useScale;
00136 fontInfo_t *font = &cgDC.Assets.textFont;
00137 if (scale <= cg_smallFont.value) {
00138 font = &cgDC.Assets.smallFont;
00139 } else if (scale > cg_bigFont.value) {
00140 font = &cgDC.Assets.bigFont;
00141 }
00142 useScale = scale * font->glyphScale;
00143 if (text) {
00144
00145
00146 const char *s = text;
00147 trap_R_SetColor( color );
00148 memcpy(&newColor[0], &color[0], sizeof(vec4_t));
00149 len = strlen(text);
00150 if (limit > 0 && len > limit) {
00151 len = limit;
00152 }
00153 count = 0;
00154 while (s && *s && count < len) {
00155 glyph = &font->glyphs[(int)*s];
00156
00157
00158 if ( Q_IsColorString( s ) ) {
00159 memcpy( newColor, g_color_table[ColorIndex(*(s+1))], sizeof( newColor ) );
00160 newColor[3] = color[3];
00161 trap_R_SetColor( newColor );
00162 s += 2;
00163 continue;
00164 } else {
00165 float yadj = useScale * glyph->top;
00166 if (style == ITEM_TEXTSTYLE_SHADOWED || style == ITEM_TEXTSTYLE_SHADOWEDMORE) {
00167 int ofs = style == ITEM_TEXTSTYLE_SHADOWED ? 1 : 2;
00168 colorBlack[3] = newColor[3];
00169 trap_R_SetColor( colorBlack );
00170 CG_Text_PaintChar(x + ofs, y - yadj + ofs,
00171 glyph->imageWidth,
00172 glyph->imageHeight,
00173 useScale,
00174 glyph->s,
00175 glyph->t,
00176 glyph->s2,
00177 glyph->t2,
00178 glyph->glyph);
00179 colorBlack[3] = 1.0;
00180 trap_R_SetColor( newColor );
00181 }
00182 CG_Text_PaintChar(x, y - yadj,
00183 glyph->imageWidth,
00184 glyph->imageHeight,
00185 useScale,
00186 glyph->s,
00187 glyph->t,
00188 glyph->s2,
00189 glyph->t2,
00190 glyph->glyph);
00191
00192 x += (glyph->xSkip * useScale) + adjust;
00193 s++;
00194 count++;
00195 }
00196 }
00197 trap_R_SetColor( NULL );
00198 }
00199 }
00200
00201
00202 #endif
00203
00204
00205
00206
00207
00208
00209
00210
00211 #ifndef MISSIONPACK
00212 static void CG_DrawField (int x, int y, int width, int value) {
00213 char num[16], *ptr;
00214 int l;
00215 int frame;
00216
00217 if ( width < 1 ) {
00218 return;
00219 }
00220
00221
00222 if ( width > 5 ) {
00223 width = 5;
00224 }
00225
00226 switch ( width ) {
00227 case 1:
00228 value = value > 9 ? 9 : value;
00229 value = value < 0 ? 0 : value;
00230 break;
00231 case 2:
00232 value = value > 99 ? 99 : value;
00233 value = value < -9 ? -9 : value;
00234 break;
00235 case 3:
00236 value = value > 999 ? 999 : value;
00237 value = value < -99 ? -99 : value;
00238 break;
00239 case 4:
00240 value = value > 9999 ? 9999 : value;
00241 value = value < -999 ? -999 : value;
00242 break;
00243 }
00244
00245 Com_sprintf (num, sizeof(num), "%i", value);
00246 l = strlen(num);
00247 if (l > width)
00248 l = width;
00249 x += 2 + CHAR_WIDTH*(width - l);
00250
00251 ptr = num;
00252 while (*ptr && l)
00253 {
00254 if (*ptr == '-')
00255 frame = STAT_MINUS;
00256 else
00257 frame = *ptr -'0';
00258
00259 CG_DrawPic( x,y, CHAR_WIDTH, CHAR_HEIGHT, cgs.media.numberShaders[frame] );
00260 x += CHAR_WIDTH;
00261 ptr++;
00262 l--;
00263 }
00264 }
00265 #endif // MISSIONPACK
00266
00267
00268
00269
00270
00271
00272
00273 void CG_Draw3DModel( float x, float y, float w, float h, qhandle_t model, qhandle_t skin, vec3_t origin, vec3_t angles ) {
00274 refdef_t refdef;
00275 refEntity_t ent;
00276
00277 if ( !cg_draw3dIcons.integer || !cg_drawIcons.integer ) {
00278 return;
00279 }
00280
00281 CG_AdjustFrom640( &x, &y, &w, &h );
00282
00283 memset( &refdef, 0, sizeof( refdef ) );
00284
00285 memset( &ent, 0, sizeof( ent ) );
00286 AnglesToAxis( angles, ent.axis );
00287 VectorCopy( origin, ent.origin );
00288 ent.hModel = model;
00289 ent.customSkin = skin;
00290 ent.renderfx = RF_NOSHADOW;
00291
00292 refdef.rdflags = RDF_NOWORLDMODEL;
00293
00294 AxisClear( refdef.viewaxis );
00295
00296 refdef.fov_x = 30;
00297 refdef.fov_y = 30;
00298
00299 refdef.x = x;
00300 refdef.y = y;
00301 refdef.width = w;
00302 refdef.height = h;
00303
00304 refdef.time = cg.time;
00305
00306 trap_R_ClearScene();
00307 trap_R_AddRefEntityToScene( &ent );
00308 trap_R_RenderScene( &refdef );
00309 }
00310
00311
00312
00313
00314
00315
00316
00317
00318 void CG_DrawHead( float x, float y, float w, float h, int clientNum, vec3_t headAngles ) {
00319 clipHandle_t cm;
00320 clientInfo_t *ci;
00321 float len;
00322 vec3_t origin;
00323 vec3_t mins, maxs;
00324
00325 ci = &cgs.clientinfo[ clientNum ];
00326
00327 if ( cg_draw3dIcons.integer ) {
00328 cm = ci->headModel;
00329 if ( !cm ) {
00330 return;
00331 }
00332
00333
00334 trap_R_ModelBounds( cm, mins, maxs );
00335
00336 origin[2] = -0.5 * ( mins[2] + maxs[2] );
00337 origin[1] = 0.5 * ( mins[1] + maxs[1] );
00338
00339
00340
00341 len = 0.7 * ( maxs[2] - mins[2] );
00342 origin[0] = len / 0.268;
00343
00344
00345 VectorAdd( origin, ci->headOffset, origin );
00346
00347 CG_Draw3DModel( x, y, w, h, ci->headModel, ci->headSkin, origin, headAngles );
00348 } else if ( cg_drawIcons.integer ) {
00349 CG_DrawPic( x, y, w, h, ci->modelIcon );
00350 }
00351
00352
00353 if ( ci->deferred ) {
00354 CG_DrawPic( x, y, w, h, cgs.media.deferShader );
00355 }
00356 }
00357
00358
00359
00360
00361
00362
00363
00364
00365 void CG_DrawFlagModel( float x, float y, float w, float h, int team, qboolean force2D ) {
00366 qhandle_t cm;
00367 float len;
00368 vec3_t origin, angles;
00369 vec3_t mins, maxs;
00370 qhandle_t handle;
00371
00372 if ( !force2D && cg_draw3dIcons.integer ) {
00373
00374 VectorClear( angles );
00375
00376 cm = cgs.media.redFlagModel;
00377
00378
00379 trap_R_ModelBounds( cm, mins, maxs );
00380
00381 origin[2] = -0.5 * ( mins[2] + maxs[2] );
00382 origin[1] = 0.5 * ( mins[1] + maxs[1] );
00383
00384
00385
00386 len = 0.5 * ( maxs[2] - mins[2] );
00387 origin[0] = len / 0.268;
00388
00389 angles[YAW] = 60 * sin( cg.time / 2000.0 );;
00390
00391 if( team == TEAM_RED ) {
00392 handle = cgs.media.redFlagModel;
00393 } else if( team == TEAM_BLUE ) {
00394 handle = cgs.media.blueFlagModel;
00395 } else if( team == TEAM_FREE ) {
00396 handle = cgs.media.neutralFlagModel;
00397 } else {
00398 return;
00399 }
00400 CG_Draw3DModel( x, y, w, h, handle, 0, origin, angles );
00401 } else if ( cg_drawIcons.integer ) {
00402 gitem_t *item;
00403
00404 if( team == TEAM_RED ) {
00405 item = BG_FindItemForPowerup( PW_REDFLAG );
00406 } else if( team == TEAM_BLUE ) {
00407 item = BG_FindItemForPowerup( PW_BLUEFLAG );
00408 } else if( team == TEAM_FREE ) {
00409 item = BG_FindItemForPowerup( PW_NEUTRALFLAG );
00410 } else {
00411 return;
00412 }
00413 if (item) {
00414 CG_DrawPic( x, y, w, h, cg_items[ ITEM_INDEX(item) ].icon );
00415 }
00416 }
00417 }
00418
00419
00420
00421
00422
00423
00424
00425 #ifndef MISSIONPACK
00426
00427 static void CG_DrawStatusBarHead( float x ) {
00428 vec3_t angles;
00429 float size, stretch;
00430 float frac;
00431
00432 VectorClear( angles );
00433
00434 if ( cg.damageTime && cg.time - cg.damageTime < DAMAGE_TIME ) {
00435 frac = (float)(cg.time - cg.damageTime ) / DAMAGE_TIME;
00436 size = ICON_SIZE * 1.25 * ( 1.5 - frac * 0.5 );
00437
00438 stretch = size - ICON_SIZE * 1.25;
00439
00440 x -= stretch * 0.5 + cg.damageX * stretch * 0.5;
00441
00442 cg.headStartYaw = 180 + cg.damageX * 45;
00443
00444 cg.headEndYaw = 180 + 20 * cos( crandom()*M_PI );
00445 cg.headEndPitch = 5 * cos( crandom()*M_PI );
00446
00447 cg.headStartTime = cg.time;
00448 cg.headEndTime = cg.time + 100 + random() * 2000;
00449 } else {
00450 if ( cg.time >= cg.headEndTime ) {
00451
00452 cg.headStartYaw = cg.headEndYaw;
00453 cg.headStartPitch = cg.headEndPitch;
00454 cg.headStartTime = cg.headEndTime;
00455 cg.headEndTime = cg.time + 100 + random() * 2000;
00456
00457 cg.headEndYaw = 180 + 20 * cos( crandom()*M_PI );
00458 cg.headEndPitch = 5 * cos( crandom()*M_PI );
00459 }
00460
00461 size = ICON_SIZE * 1.25;
00462 }
00463
00464
00465 if ( cg.headStartTime > cg.time ) {
00466 cg.headStartTime = cg.time;
00467 }
00468
00469 frac = ( cg.time - cg.headStartTime ) / (float)( cg.headEndTime - cg.headStartTime );
00470 frac = frac * frac * ( 3 - 2 * frac );
00471 angles[YAW] = cg.headStartYaw + ( cg.headEndYaw - cg.headStartYaw ) * frac;
00472 angles[PITCH] = cg.headStartPitch + ( cg.headEndPitch - cg.headStartPitch ) * frac;
00473
00474 CG_DrawHead( x, 480 - size, size, size,
00475 cg.snap->ps.clientNum, angles );
00476 }
00477 #endif // MISSIONPACK
00478
00479
00480
00481
00482
00483
00484
00485 #ifndef MISSIONPACK
00486 static void CG_DrawStatusBarFlag( float x, int team ) {
00487 CG_DrawFlagModel( x, 480 - ICON_SIZE, ICON_SIZE, ICON_SIZE, team, qfalse );
00488 }
00489 #endif // MISSIONPACK
00490
00491
00492
00493
00494
00495
00496
00497 void CG_DrawTeamBackground( int x, int y, int w, int h, float alpha, int team )
00498 {
00499 vec4_t hcolor;
00500
00501 hcolor[3] = alpha;
00502 if ( team == TEAM_RED ) {
00503 hcolor[0] = 1;
00504 hcolor[1] = 0;
00505 hcolor[2] = 0;
00506 } else if ( team == TEAM_BLUE ) {
00507 hcolor[0] = 0;
00508 hcolor[1] = 0;
00509 hcolor[2] = 1;
00510 } else {
00511 return;
00512 }
00513 trap_R_SetColor( hcolor );
00514 CG_DrawPic( x, y, w, h, cgs.media.teamStatusBar );
00515 trap_R_SetColor( NULL );
00516 }
00517
00518
00519
00520
00521
00522
00523
00524 #ifndef MISSIONPACK
00525 static void CG_DrawStatusBar( void ) {
00526 int color;
00527 centity_t *cent;
00528 playerState_t *ps;
00529 int value;
00530 vec4_t hcolor;
00531 vec3_t angles;
00532 vec3_t origin;
00533 #ifdef MISSIONPACK
00534 qhandle_t handle;
00535 #endif
00536 static float colors[4][4] = {
00537
00538 { 1.0f, 0.69f, 0.0f, 1.0f },
00539 { 1.0f, 0.2f, 0.2f, 1.0f },
00540 { 0.5f, 0.5f, 0.5f, 1.0f },
00541 { 1.0f, 1.0f, 1.0f, 1.0f } };
00542
00543 if ( cg_drawStatus.integer == 0 ) {
00544 return;
00545 }
00546
00547
00548 CG_DrawTeamBackground( 0, 420, 640, 60, 0.33f, cg.snap->ps.persistant[PERS_TEAM] );
00549
00550 cent = &cg_entities[cg.snap->ps.clientNum];
00551 ps = &cg.snap->ps;
00552
00553 VectorClear( angles );
00554
00555
00556 if ( cent->currentState.weapon && cg_weapons[ cent->currentState.weapon ].ammoModel ) {
00557 origin[0] = 70;
00558 origin[1] = 0;
00559 origin[2] = 0;
00560 angles[YAW] = 90 + 20 * sin( cg.time / 1000.0 );
00561 CG_Draw3DModel( CHAR_WIDTH*3 + TEXT_ICON_SPACE, 432, ICON_SIZE, ICON_SIZE,
00562 cg_weapons[ cent->currentState.weapon ].ammoModel, 0, origin, angles );
00563 }
00564
00565 CG_DrawStatusBarHead( 185 + CHAR_WIDTH*3 + TEXT_ICON_SPACE );
00566
00567 if( cg.predictedPlayerState.powerups[PW_REDFLAG] ) {
00568 CG_DrawStatusBarFlag( 185 + CHAR_WIDTH*3 + TEXT_ICON_SPACE + ICON_SIZE, TEAM_RED );
00569 } else if( cg.predictedPlayerState.powerups[PW_BLUEFLAG] ) {
00570 CG_DrawStatusBarFlag( 185 + CHAR_WIDTH*3 + TEXT_ICON_SPACE + ICON_SIZE, TEAM_BLUE );
00571 } else if( cg.predictedPlayerState.powerups[PW_NEUTRALFLAG] ) {
00572 CG_DrawStatusBarFlag( 185 + CHAR_WIDTH*3 + TEXT_ICON_SPACE + ICON_SIZE, TEAM_FREE );
00573 }
00574
00575 if ( ps->stats[ STAT_ARMOR ] ) {
00576 origin[0] = 90;
00577 origin[1] = 0;
00578 origin[2] = -10;
00579 angles[YAW] = ( cg.time & 2047 ) * 360 / 2048.0;
00580 CG_Draw3DModel( 370 + CHAR_WIDTH*3 + TEXT_ICON_SPACE, 432, ICON_SIZE, ICON_SIZE,
00581 cgs.media.armorModel, 0, origin, angles );
00582 }
00583 #ifdef MISSIONPACK
00584 if( cgs.gametype == GT_HARVESTER ) {
00585 origin[0] = 90;
00586 origin[1] = 0;
00587 origin[2] = -10;
00588 angles[YAW] = ( cg.time & 2047 ) * 360 / 2048.0;
00589 if( cg.snap->ps.persistant[PERS_TEAM] == TEAM_BLUE ) {
00590 handle = cgs.media.redCubeModel;
00591 } else {
00592 handle = cgs.media.blueCubeModel;
00593 }
00594 CG_Draw3DModel( 640 - (TEXT_ICON_SPACE + ICON_SIZE), 416, ICON_SIZE, ICON_SIZE, handle, 0, origin, angles );
00595 }
00596 #endif
00597
00598
00599
00600 if ( cent->currentState.weapon ) {
00601 value = ps->ammo[cent->currentState.weapon];
00602 if ( value > -1 ) {
00603 if ( cg.predictedPlayerState.weaponstate == WEAPON_FIRING
00604 && cg.predictedPlayerState.weaponTime > 100 ) {
00605
00606 color = 2;
00607 } else {
00608 if ( value >= 0 ) {
00609 color = 0;
00610 } else {
00611 color = 1;
00612 }
00613 }
00614 trap_R_SetColor( colors[color] );
00615
00616 CG_DrawField (0, 432, 3, value);
00617 trap_R_SetColor( NULL );
00618
00619
00620 if ( !cg_draw3dIcons.integer && cg_drawIcons.integer ) {
00621 qhandle_t icon;
00622
00623 icon = cg_weapons[ cg.predictedPlayerState.weapon ].ammoIcon;
00624 if ( icon ) {
00625 CG_DrawPic( CHAR_WIDTH*3 + TEXT_ICON_SPACE, 432, ICON_SIZE, ICON_SIZE, icon );
00626 }
00627 }
00628 }
00629 }
00630
00631
00632
00633
00634 value = ps->stats[STAT_HEALTH];
00635 if ( value > 100 ) {
00636 trap_R_SetColor( colors[3] );
00637 } else if (value > 25) {
00638 trap_R_SetColor( colors[0] );
00639 } else if (value > 0) {
00640 color = (cg.time >> 8) & 1;
00641 trap_R_SetColor( colors[color] );
00642 } else {
00643 trap_R_SetColor( colors[1] );
00644 }
00645
00646
00647 CG_DrawField ( 185, 432, 3, value);
00648 CG_ColorForHealth( hcolor );
00649 trap_R_SetColor( hcolor );
00650
00651
00652
00653
00654
00655 value = ps->stats[STAT_ARMOR];
00656 if (value > 0 ) {
00657 trap_R_SetColor( colors[0] );
00658 CG_DrawField (370, 432, 3, value);
00659 trap_R_SetColor( NULL );
00660
00661 if ( !cg_draw3dIcons.integer && cg_drawIcons.integer ) {
00662 CG_DrawPic( 370 + CHAR_WIDTH*3 + TEXT_ICON_SPACE, 432, ICON_SIZE, ICON_SIZE, cgs.media.armorIcon );
00663 }
00664
00665 }
00666 #ifdef MISSIONPACK
00667
00668
00669
00670 if( cgs.gametype == GT_HARVESTER ) {
00671 value = ps->generic1;
00672 if( value > 99 ) {
00673 value = 99;
00674 }
00675 trap_R_SetColor( colors[0] );
00676 CG_DrawField (640 - (CHAR_WIDTH*2 + TEXT_ICON_SPACE + ICON_SIZE), 432, 2, value);
00677 trap_R_SetColor( NULL );
00678
00679 if ( !cg_draw3dIcons.integer && cg_drawIcons.integer ) {
00680 if( cg.snap->ps.persistant[PERS_TEAM] == TEAM_BLUE ) {
00681 handle = cgs.media.redCubeIcon;
00682 } else {
00683 handle = cgs.media.blueCubeIcon;
00684 }
00685 CG_DrawPic( 640 - (TEXT_ICON_SPACE + ICON_SIZE), 432, ICON_SIZE, ICON_SIZE, handle );
00686 }
00687 }
00688 #endif
00689 }
00690 #endif
00691
00692
00693
00694
00695
00696
00697
00698
00699
00700
00701
00702
00703
00704
00705
00706 static float CG_DrawAttacker( float y ) {
00707 int t;
00708 float size;
00709 vec3_t angles;
00710 const char *info;
00711 const char *name;
00712 int clientNum;
00713
00714 if ( cg.predictedPlayerState.stats[STAT_HEALTH] <= 0 ) {
00715 return y;
00716 }
00717
00718 if ( !cg.attackerTime ) {
00719 return y;
00720 }
00721
00722 clientNum = cg.predictedPlayerState.persistant[PERS_ATTACKER];
00723 if ( clientNum < 0 || clientNum >= MAX_CLIENTS || clientNum == cg.snap->ps.clientNum ) {
00724 return y;
00725 }
00726
00727 t = cg.time - cg.attackerTime;
00728 if ( t > ATTACKER_HEAD_TIME ) {
00729 cg.attackerTime = 0;
00730 return y;
00731 }
00732
00733 size = ICON_SIZE * 1.25;
00734
00735 angles[PITCH] = 0;
00736 angles[YAW] = 180;
00737 angles[ROLL] = 0;
00738 CG_DrawHead( 640 - size, y, size, size, clientNum, angles );
00739
00740 info = CG_ConfigString( CS_PLAYERS + clientNum );
00741 name = Info_ValueForKey( info, "n" );
00742 y += size;
00743 CG_DrawBigString( 640 - ( Q_PrintStrlen( name ) * BIGCHAR_WIDTH), y, name, 0.5 );
00744
00745 return y + BIGCHAR_HEIGHT + 2;
00746 }
00747
00748
00749
00750
00751
00752
00753 static float CG_DrawSnapshot( float y ) {
00754 char *s;
00755 int w;
00756
00757 s = va( "time:%i snap:%i cmd:%i", cg.snap->serverTime,
00758 cg.latestSnapshotNum, cgs.serverCommandSequence );
00759 w = CG_DrawStrlen( s ) * BIGCHAR_WIDTH;
00760
00761 CG_DrawBigString( 635 - w, y + 2, s, 1.0F);
00762
00763 return y + BIGCHAR_HEIGHT + 4;
00764 }
00765
00766
00767
00768
00769
00770
00771 #define FPS_FRAMES 4
00772 static float CG_DrawFPS( float y ) {
00773 char *s;
00774 int w;
00775 static int previousTimes[FPS_FRAMES];
00776 static int index;
00777 int i, total;
00778 int fps;
00779 static int previous;
00780 int t, frameTime;
00781
00782
00783
00784 t = trap_Milliseconds();
00785 frameTime = t - previous;
00786 previous = t;
00787
00788 previousTimes[index % FPS_FRAMES] = frameTime;
00789 index++;
00790 if ( index > FPS_FRAMES ) {
00791
00792 total = 0;
00793 for ( i = 0 ; i < FPS_FRAMES ; i++ ) {
00794 total += previousTimes[i];
00795 }
00796 if ( !total ) {
00797 total = 1;
00798 }
00799 fps = 1000 * FPS_FRAMES / total;
00800
00801 s = va( "%ifps", fps );
00802 w = CG_DrawStrlen( s ) * BIGCHAR_WIDTH;
00803
00804 CG_DrawBigString( 635 - w, y + 2, s, 1.0F);
00805 }
00806
00807 return y + BIGCHAR_HEIGHT + 4;
00808 }
00809
00810
00811
00812
00813
00814
00815 static float CG_DrawTimer( float y ) {
00816 char *s;
00817 int w;
00818 int mins, seconds, tens;
00819 int msec;
00820
00821 msec = cg.time - cgs.levelStartTime;
00822
00823 seconds = msec / 1000;
00824 mins = seconds / 60;
00825 seconds -= mins * 60;
00826 tens = seconds / 10;
00827 seconds -= tens * 10;
00828
00829 s = va( "%i:%i%i", mins, tens, seconds );
00830 w = CG_DrawStrlen( s ) * BIGCHAR_WIDTH;
00831
00832 CG_DrawBigString( 635 - w, y + 2, s, 1.0F);
00833
00834 return y + BIGCHAR_HEIGHT + 4;
00835 }
00836
00837
00838
00839
00840
00841
00842
00843
00844 static float CG_DrawTeamOverlay( float y, qboolean right, qboolean upper ) {
00845 int x, w, h, xx;
00846 int i, j, len;
00847 const char *p;
00848 vec4_t hcolor;
00849 int pwidth, lwidth;
00850 int plyrs;
00851 char st[16];
00852 clientInfo_t *ci;
00853 gitem_t *item;
00854 int ret_y, count;
00855
00856 if ( !cg_drawTeamOverlay.integer ) {
00857 return y;
00858 }
00859
00860 if ( cg.snap->ps.persistant[PERS_TEAM] != TEAM_RED && cg.snap->ps.persistant[PERS_TEAM] != TEAM_BLUE ) {
00861 return y;
00862 }
00863
00864 plyrs = 0;
00865
00866
00867 pwidth = 0;
00868 count = (numSortedTeamPlayers > 8) ? 8 : numSortedTeamPlayers;
00869 for (i = 0; i < count; i++) {
00870 ci = cgs.clientinfo + sortedTeamPlayers[i];
00871 if ( ci->infoValid && ci->team == cg.snap->ps.persistant[PERS_TEAM]) {
00872 plyrs++;
00873 len = CG_DrawStrlen(ci->name);
00874 if (len > pwidth)
00875 pwidth = len;
00876 }
00877 }
00878
00879 if (!plyrs)
00880 return y;
00881
00882 if (pwidth > TEAM_OVERLAY_MAXNAME_WIDTH)
00883 pwidth = TEAM_OVERLAY_MAXNAME_WIDTH;
00884
00885
00886 lwidth = 0;
00887 for (i = 1; i < MAX_LOCATIONS; i++) {
00888 p = CG_ConfigString(CS_LOCATIONS + i);
00889 if (p && *p) {
00890 len = CG_DrawStrlen(p);
00891 if (len > lwidth)
00892 lwidth = len;
00893 }
00894 }
00895
00896 if (lwidth > TEAM_OVERLAY_MAXLOCATION_WIDTH)
00897 lwidth = TEAM_OVERLAY_MAXLOCATION_WIDTH;
00898
00899 w = (pwidth + lwidth + 4 + 7) * TINYCHAR_WIDTH;
00900
00901 if ( right )
00902 x = 640 - w;
00903 else
00904 x = 0;
00905
00906 h = plyrs * TINYCHAR_HEIGHT;
00907
00908 if ( upper ) {
00909 ret_y = y + h;
00910 } else {
00911 y -= h;
00912 ret_y = y;
00913 }
00914
00915 if ( cg.snap->ps.persistant[PERS_TEAM] == TEAM_RED ) {
00916 hcolor[0] = 1.0f;
00917 hcolor[1] = 0.0f;
00918 hcolor[2] = 0.0f;
00919 hcolor[3] = 0.33f;
00920 } else {
00921 hcolor[0] = 0.0f;
00922 hcolor[1] = 0.0f;
00923 hcolor[2] = 1.0f;
00924 hcolor[3] = 0.33f;
00925 }
00926 trap_R_SetColor( hcolor );
00927 CG_DrawPic( x, y, w, h, cgs.media.teamStatusBar );
00928 trap_R_SetColor( NULL );
00929
00930 for (i = 0; i < count; i++) {
00931 ci = cgs.clientinfo + sortedTeamPlayers[i];
00932 if ( ci->infoValid && ci->team == cg.snap->ps.persistant[PERS_TEAM]) {
00933
00934 hcolor[0] = hcolor[1] = hcolor[2] = hcolor[3] = 1.0;
00935
00936 xx = x + TINYCHAR_WIDTH;
00937
00938 CG_DrawStringExt( xx, y,
00939 ci->name, hcolor, qfalse, qfalse,
00940 TINYCHAR_WIDTH, TINYCHAR_HEIGHT, TEAM_OVERLAY_MAXNAME_WIDTH);
00941
00942 if (lwidth) {
00943 p = CG_ConfigString(CS_LOCATIONS + ci->location);
00944 if (!p || !*p)
00945 p = "unknown";
00946 len = CG_DrawStrlen(p);
00947 if (len > lwidth)
00948 len = lwidth;
00949
00950
00951
00952 xx = x + TINYCHAR_WIDTH * 2 + TINYCHAR_WIDTH * pwidth;
00953 CG_DrawStringExt( xx, y,
00954 p, hcolor, qfalse, qfalse, TINYCHAR_WIDTH, TINYCHAR_HEIGHT,
00955 TEAM_OVERLAY_MAXLOCATION_WIDTH);
00956 }
00957
00958 CG_GetColorForHealth( ci->health, ci->armor, hcolor );
00959
00960 Com_sprintf (st, sizeof(st), "%3i %3i", ci->health, ci->armor);
00961
00962 xx = x + TINYCHAR_WIDTH * 3 +
00963 TINYCHAR_WIDTH * pwidth + TINYCHAR_WIDTH * lwidth;
00964
00965 CG_DrawStringExt( xx, y,
00966 st, hcolor, qfalse, qfalse,
00967 TINYCHAR_WIDTH, TINYCHAR_HEIGHT, 0 );
00968
00969
00970 xx += TINYCHAR_WIDTH * 3;
00971
00972 if ( cg_weapons[ci->curWeapon].weaponIcon ) {
00973 CG_DrawPic( xx, y, TINYCHAR_WIDTH, TINYCHAR_HEIGHT,
00974 cg_weapons[ci->curWeapon].weaponIcon );
00975 } else {
00976 CG_DrawPic( xx, y, TINYCHAR_WIDTH, TINYCHAR_HEIGHT,
00977 cgs.media.deferShader );
00978 }
00979
00980
00981 if (right) {
00982 xx = x;
00983 } else {
00984 xx = x + w - TINYCHAR_WIDTH;
00985 }
00986 for (j = 0; j <= PW_NUM_POWERUPS; j++) {
00987 if (ci->powerups & (1 << j)) {
00988
00989 item = BG_FindItemForPowerup( j );
00990
00991 if (item) {
00992 CG_DrawPic( xx, y, TINYCHAR_WIDTH, TINYCHAR_HEIGHT,
00993 trap_R_RegisterShader( item->icon ) );
00994 if (right) {
00995 xx -= TINYCHAR_WIDTH;
00996 } else {
00997 xx += TINYCHAR_WIDTH;
00998 }
00999 }
01000 }
01001 }
01002
01003 y += TINYCHAR_HEIGHT;
01004 }
01005 }
01006
01007 return ret_y;
01008
01009 }
01010
01011
01012
01013
01014
01015
01016
01017
01018 static void CG_DrawUpperRight( void ) {
01019 float y;
01020
01021 y = 0;
01022
01023 if ( cgs.gametype >= GT_TEAM && cg_drawTeamOverlay.integer == 1 ) {
01024 y = CG_DrawTeamOverlay( y, qtrue, qtrue );
01025 }
01026 if ( cg_drawSnapshot.integer ) {
01027 y = CG_DrawSnapshot( y );
01028 }
01029 if ( cg_drawFPS.integer ) {
01030 y = CG_DrawFPS( y );
01031 }
01032 if ( cg_drawTimer.integer ) {
01033 y = CG_DrawTimer( y );
01034 }
01035 if ( cg_drawAttacker.integer ) {
01036 y = CG_DrawAttacker( y );
01037 }
01038
01039 }
01040
01041
01042
01043
01044
01045
01046
01047
01048
01049
01050
01051
01052
01053
01054
01055
01056 #ifndef MISSIONPACK
01057 static float CG_DrawScores( float y ) {
01058 const char *s;
01059 int s1, s2, score;
01060 int x, w;
01061 int v;
01062 vec4_t color;
01063 float y1;
01064 gitem_t *item;
01065
01066 s1 = cgs.scores1;
01067 s2 = cgs.scores2;
01068
01069 y -= BIGCHAR_HEIGHT + 8;
01070
01071 y1 = y;
01072
01073
01074 if ( cgs.gametype >= GT_TEAM ) {
01075 x = 640;
01076 color[0] = 0.0f;
01077 color[1] = 0.0f;
01078 color[2] = 1.0f;
01079 color[3] = 0.33f;
01080 s = va( "%2i", s2 );
01081 w = CG_DrawStrlen( s ) * BIGCHAR_WIDTH + 8;
01082 x -= w;
01083 CG_FillRect( x, y-4, w, BIGCHAR_HEIGHT+8, color );
01084 if ( cg.snap->ps.persistant[PERS_TEAM] == TEAM_BLUE ) {
01085 CG_DrawPic( x, y-4, w, BIGCHAR_HEIGHT+8, cgs.media.selectShader );
01086 }
01087 CG_DrawBigString( x + 4, y, s, 1.0F);
01088
01089 if ( cgs.gametype == GT_CTF ) {
01090
01091 item = BG_FindItemForPowerup( PW_BLUEFLAG );
01092
01093 if (item) {
01094 y1 = y - BIGCHAR_HEIGHT - 8;
01095 if( cgs.blueflag >= 0 && cgs.blueflag <= 2 ) {
01096 CG_DrawPic( x, y1-4, w, BIGCHAR_HEIGHT+8, cgs.media.blueFlagShader[cgs.blueflag] );
01097 }
01098 }
01099 }
01100 color[0] = 1.0f;
01101 color[1] = 0.0f;
01102 color[2] = 0.0f;
01103 color[3] = 0.33f;
01104 s = va( "%2i", s1 );
01105 w = CG_DrawStrlen( s ) * BIGCHAR_WIDTH + 8;
01106 x -= w;
01107 CG_FillRect( x, y-4, w, BIGCHAR_HEIGHT+8, color );
01108 if ( cg.snap->ps.persistant[PERS_TEAM] == TEAM_RED ) {
01109 CG_DrawPic( x, y-4, w, BIGCHAR_HEIGHT+8, cgs.media.selectShader );
01110 }
01111 CG_DrawBigString( x + 4, y, s, 1.0F);
01112
01113 if ( cgs.gametype == GT_CTF ) {
01114
01115 item = BG_FindItemForPowerup( PW_REDFLAG );
01116
01117 if (item) {
01118 y1 = y - BIGCHAR_HEIGHT - 8;
01119 if( cgs.redflag >= 0 && cgs.redflag <= 2 ) {
01120 CG_DrawPic( x, y1-4, w, BIGCHAR_HEIGHT+8, cgs.media.redFlagShader[cgs.redflag] );
01121 }
01122 }
01123 }
01124
01125 #ifdef MISSIONPACK
01126 if ( cgs.gametype == GT_1FCTF ) {
01127
01128 item = BG_FindItemForPowerup( PW_NEUTRALFLAG );
01129
01130 if (item) {
01131 y1 = y - BIGCHAR_HEIGHT - 8;
01132 if( cgs.flagStatus >= 0 && cgs.flagStatus <= 3 ) {
01133 CG_DrawPic( x, y1-4, w, BIGCHAR_HEIGHT+8, cgs.media.flagShader[cgs.flagStatus] );
01134 }
01135 }
01136 }
01137 #endif
01138 if ( cgs.gametype >= GT_CTF ) {
01139 v = cgs.capturelimit;
01140 } else {
01141 v = cgs.fraglimit;
01142 }
01143 if ( v ) {
01144 s = va( "%2i", v );
01145 w = CG_DrawStrlen( s ) * BIGCHAR_WIDTH + 8;
01146 x -= w;
01147 CG_DrawBigString( x + 4, y, s, 1.0F);
01148 }
01149
01150 } else {
01151 qboolean spectator;
01152
01153 x = 640;
01154 score = cg.snap->ps.persistant[PERS_SCORE];
01155 spectator = ( cg.snap->ps.persistant[PERS_TEAM] == TEAM_SPECTATOR );
01156
01157
01158 if ( s1 != score ) {
01159 s2 = score;
01160 }
01161 if ( s2 != SCORE_NOT_PRESENT ) {
01162 s = va( "%2i", s2 );
01163 w = CG_DrawStrlen( s ) * BIGCHAR_WIDTH + 8;
01164 x -= w;
01165 if ( !spectator && score == s2 && score != s1 ) {
01166 color[0] = 1.0f;
01167 color[1] = 0.0f;
01168 color[2] = 0.0f;
01169 color[3] = 0.33f;
01170 CG_FillRect( x, y-4, w, BIGCHAR_HEIGHT+8, color );
01171 CG_DrawPic( x, y-4, w, BIGCHAR_HEIGHT+8, cgs.media.selectShader );
01172 } else {
01173 color[0] = 0.5f;
01174 color[1] = 0.5f;
01175 color[2] = 0.5f;
01176 color[3] = 0.33f;
01177 CG_FillRect( x, y-4, w, BIGCHAR_HEIGHT+8, color );
01178 }
01179 CG_DrawBigString( x + 4, y, s, 1.0F);
01180 }
01181
01182
01183 if ( s1 != SCORE_NOT_PRESENT ) {
01184 s = va( "%2i", s1 );
01185 w = CG_DrawStrlen( s ) * BIGCHAR_WIDTH + 8;
01186 x -= w;
01187 if ( !spectator && score == s1 ) {
01188 color[0] = 0.0f;
01189 color[1] = 0.0f;
01190 color[2] = 1.0f;
01191 color[3] = 0.33f;
01192 CG_FillRect( x, y-4, w, BIGCHAR_HEIGHT+8, color );
01193 CG_DrawPic( x, y-4, w, BIGCHAR_HEIGHT+8, cgs.media.selectShader );
01194 } else {
01195 color[0] = 0.5f;
01196 color[1] = 0.5f;
01197 color[2] = 0.5f;
01198 color[3] = 0.33f;
01199 CG_FillRect( x, y-4, w, BIGCHAR_HEIGHT+8, color );
01200 }
01201 CG_DrawBigString( x + 4, y, s, 1.0F);
01202 }
01203
01204 if ( cgs.fraglimit ) {
01205 s = va( "%2i", cgs.fraglimit );
01206 w = CG_DrawStrlen( s ) * BIGCHAR_WIDTH + 8;
01207 x -= w;
01208 CG_DrawBigString( x + 4, y, s, 1.0F);
01209 }
01210
01211 }
01212
01213 return y1 - 8;
01214 }
01215 #endif // MISSIONPACK
01216
01217
01218
01219
01220
01221
01222 #ifndef MISSIONPACK
01223 static float CG_DrawPowerups( float y ) {
01224 int sorted[MAX_POWERUPS];
01225 int sortedTime[MAX_POWERUPS];
01226 int i, j, k;
01227 int active;
01228 playerState_t *ps;
01229 int t;
01230 gitem_t *item;
01231 int x;
01232 int color;
01233 float size;
01234 float f;
01235 static float colors[2][4] = {
01236 { 0.2f, 1.0f, 0.2f, 1.0f } ,
01237 { 1.0f, 0.2f, 0.2f, 1.0f }
01238 };
01239
01240 ps = &cg.snap->ps;
01241
01242 if ( ps->stats[STAT_HEALTH] <= 0 ) {
01243 return y;
01244 }
01245
01246
01247 active = 0;
01248 for ( i = 0 ; i < MAX_POWERUPS ; i++ ) {
01249 if ( !ps->powerups[ i ] ) {
01250 continue;
01251 }
01252 t = ps->powerups[ i ] - cg.time;
01253
01254