Advertisement
Guest User

Untitled

a guest
Sep 21st, 2017
98
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 59.35 KB | None | 0 0
  1. /*
  2. ===========================================================================
  3. Copyright (C) 1999-2005 Id Software, Inc.
  4.  
  5. This file is part of Quake III Arena source code.
  6.  
  7. Quake III Arena source code is free software; you can redistribute it
  8. and/or modify it under the terms of the GNU General Public License as
  9. published by the Free Software Foundation; either version 2 of the License,
  10. or (at your option) any later version.
  11.  
  12. Quake III Arena source code is distributed in the hope that it will be
  13. useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15. GNU General Public License for more details.
  16.  
  17. You should have received a copy of the GNU General Public License
  18. along with Quake III Arena source code; if not, write to the Free Software
  19. Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  20. ===========================================================================
  21. */
  22. //
  23. // cg_draw.c -- draw all of the graphical elements during
  24. // active (after loading) gameplay
  25.  
  26. #include "cg_local.h"
  27.  
  28. #ifdef MISSIONPACK
  29. #include "../ui/ui_shared.h"
  30.  
  31. // used for scoreboard
  32. extern displayContextDef_t cgDC;
  33. menuDef_t *menuScoreboard = NULL;
  34. #else
  35. int drawTeamOverlayModificationCount = -1;
  36. #endif
  37.  
  38. int sortedTeamPlayers[TEAM_MAXOVERLAY];
  39. int numSortedTeamPlayers;
  40.  
  41. char systemChat[256];
  42. char teamChat1[256];
  43. char teamChat2[256];
  44.  
  45. #ifdef MISSIONPACK
  46.  
  47. int CG_Text_Width(const char *text, float scale, int limit) {
  48.   int count,len;
  49.     float out;
  50.     glyphInfo_t *glyph;
  51.     float useScale;
  52. // FIXME: see ui_main.c, same problem
  53. //  const unsigned char *s = text;
  54.     const char *s = text;
  55.     fontInfo_t *font = &cgDC.Assets.textFont;
  56.     if (scale <= cg_smallFont.value) {
  57.         font = &cgDC.Assets.smallFont;
  58.     } else if (scale > cg_bigFont.value) {
  59.         font = &cgDC.Assets.bigFont;
  60.     }
  61.     useScale = scale * font->glyphScale;
  62.   out = 0;
  63.   if (text) {
  64.     len = strlen(text);
  65.         if (limit > 0 && len > limit) {
  66.             len = limit;
  67.         }
  68.         count = 0;
  69.         while (s && *s && count < len) {
  70.             if ( Q_IsColorString(s) ) {
  71.                 s += 2;
  72.                 continue;
  73.             } else {
  74.                 glyph = &font->glyphs[(int)*s]; // TTimo: FIXME: getting nasty warnings without the cast, hopefully this doesn't break the VM build
  75.                 out += glyph->xSkip;
  76.                 s++;
  77.                 count++;
  78.             }
  79.     }
  80.   }
  81.   return out * useScale;
  82. }
  83.  
  84. int CG_Text_Height(const char *text, float scale, int limit) {
  85.   int len, count;
  86.     float max;
  87.     glyphInfo_t *glyph;
  88.     float useScale;
  89. // TTimo: FIXME
  90. //  const unsigned char *s = text;
  91.     const char *s = text;
  92.     fontInfo_t *font = &cgDC.Assets.textFont;
  93.     if (scale <= cg_smallFont.value) {
  94.         font = &cgDC.Assets.smallFont;
  95.     } else if (scale > cg_bigFont.value) {
  96.         font = &cgDC.Assets.bigFont;
  97.     }
  98.     useScale = scale * font->glyphScale;
  99.   max = 0;
  100.   if (text) {
  101.     len = strlen(text);
  102.         if (limit > 0 && len > limit) {
  103.             len = limit;
  104.         }
  105.         count = 0;
  106.         while (s && *s && count < len) {
  107.             if ( Q_IsColorString(s) ) {
  108.                 s += 2;
  109.                 continue;
  110.             } else {
  111.                 glyph = &font->glyphs[(int)*s]; // TTimo: FIXME: getting nasty warnings without the cast, hopefully this doesn't break the VM build
  112.           if (max < glyph->height) {
  113.               max = glyph->height;
  114.               }
  115.                 s++;
  116.                 count++;
  117.             }
  118.     }
  119.   }
  120.   return max * useScale;
  121. }
  122.  
  123. 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) {
  124.   float w, h;
  125.   w = width * scale;
  126.   h = height * scale;
  127.   CG_AdjustFrom640( &x, &y, &w, &h );
  128.   trap_R_DrawStretchPic( x, y, w, h, s, t, s2, t2, hShader );
  129. }
  130.  
  131. void CG_Text_Paint(float x, float y, float scale, vec4_t color, const char *text, float adjust, int limit, int style) {
  132.   int len, count;
  133.     vec4_t newColor;
  134.     glyphInfo_t *glyph;
  135.     float useScale;
  136.     fontInfo_t *font = &cgDC.Assets.textFont;
  137.     if (scale <= cg_smallFont.value) {
  138.         font = &cgDC.Assets.smallFont;
  139.     } else if (scale > cg_bigFont.value) {
  140.         font = &cgDC.Assets.bigFont;
  141.     }
  142.     useScale = scale * font->glyphScale;
  143.   if (text) {
  144. // TTimo: FIXME
  145. //      const unsigned char *s = text;
  146.         const char *s = text;
  147.         trap_R_SetColor( color );
  148.         memcpy(&newColor[0], &color[0], sizeof(vec4_t));
  149.     len = strlen(text);
  150.         if (limit > 0 && len > limit) {
  151.             len = limit;
  152.         }
  153.         count = 0;
  154.         while (s && *s && count < len) {
  155.             glyph = &font->glyphs[(int)*s]; // TTimo: FIXME: getting nasty warnings without the cast, hopefully this doesn't break the VM build
  156.       //int yadj = Assets.textFont.glyphs[text[i]].bottom + Assets.textFont.glyphs[text[i]].top;
  157.       //float yadj = scale * (Assets.textFont.glyphs[text[i]].imageHeight - Assets.textFont.glyphs[text[i]].height);
  158.             if ( Q_IsColorString( s ) ) {
  159.                 memcpy( newColor, g_color_table[ColorIndex(*(s+1))], sizeof( newColor ) );
  160.                 newColor[3] = color[3];
  161.                 trap_R_SetColor( newColor );
  162.                 s += 2;
  163.                 continue;
  164.             } else {
  165.                 float yadj = useScale * glyph->top;
  166.                 if (style == ITEM_TEXTSTYLE_SHADOWED || style == ITEM_TEXTSTYLE_SHADOWEDMORE) {
  167.                     int ofs = style == ITEM_TEXTSTYLE_SHADOWED ? 1 : 2;
  168.                     colorBlack[3] = newColor[3];
  169.                     trap_R_SetColor( colorBlack );
  170.                     CG_Text_PaintChar(x + ofs, y - yadj + ofs,
  171.                                                         glyph->imageWidth,
  172.                                                         glyph->imageHeight,
  173.                                                         useScale,
  174.                                                         glyph->s,
  175.                                                         glyph->t,
  176.                                                         glyph->s2,
  177.                                                         glyph->t2,
  178.                                                         glyph->glyph);
  179.                     colorBlack[3] = 1.0;
  180.                     trap_R_SetColor( newColor );
  181.                 }
  182.                 CG_Text_PaintChar(x, y - yadj,
  183.                                                     glyph->imageWidth,
  184.                                                     glyph->imageHeight,
  185.                                                     useScale,
  186.                                                     glyph->s,
  187.                                                     glyph->t,
  188.                                                     glyph->s2,
  189.                                                     glyph->t2,
  190.                                                     glyph->glyph);
  191.                 // CG_DrawPic(x, y - yadj, scale * cgDC.Assets.textFont.glyphs[text[i]].imageWidth, scale * cgDC.Assets.textFont.glyphs[text[i]].imageHeight, cgDC.Assets.textFont.glyphs[text[i]].glyph);
  192.                 x += (glyph->xSkip * useScale) + adjust;
  193.                 s++;
  194.                 count++;
  195.             }
  196.     }
  197.       trap_R_SetColor( NULL );
  198.   }
  199. }
  200.  
  201.  
  202. #endif
  203.  
  204. /*
  205. ==============
  206. CG_DrawField
  207.  
  208. Draws large numbers for status bar and powerups
  209. ==============
  210. */
  211. #ifndef MISSIONPACK
  212. static void CG_DrawField (int x, int y, int width, int value) {
  213.     char    num[16], *ptr;
  214.     int     l;
  215.     int     frame;
  216.  
  217.     if ( width < 1 ) {
  218.         return;
  219.     }
  220.  
  221.     // draw number string
  222.     if ( width > 5 ) {
  223.         width = 5;
  224.     }
  225.  
  226.     switch ( width ) {
  227.     case 1:
  228.         value = value > 9 ? 9 : value;
  229.         value = value < 0 ? 0 : value;
  230.         break;
  231.     case 2:
  232.         value = value > 99 ? 99 : value;
  233.         value = value < -9 ? -9 : value;
  234.         break;
  235.     case 3:
  236.         value = value > 999 ? 999 : value;
  237.         value = value < -99 ? -99 : value;
  238.         break;
  239.     case 4:
  240.         value = value > 9999 ? 9999 : value;
  241.         value = value < -999 ? -999 : value;
  242.         break;
  243.     }
  244.  
  245.     Com_sprintf (num, sizeof(num), "%i", value);
  246.     l = strlen(num);
  247.     if (l > width)
  248.         l = width;
  249.     x += 2 + CHAR_WIDTH*(width - l);
  250.  
  251.     ptr = num;
  252.     while (*ptr && l)
  253.     {
  254.         if (*ptr == '-')
  255.             frame = STAT_MINUS;
  256.         else
  257.             frame = *ptr -'0';
  258.  
  259.         CG_DrawPic( x,y, CHAR_WIDTH, CHAR_HEIGHT, cgs.media.numberShaders[frame] );
  260.         x += CHAR_WIDTH;
  261.         ptr++;
  262.         l--;
  263.     }
  264. }
  265. #endif // MISSIONPACK
  266.  
  267. /*
  268. ================
  269. CG_Draw3DModel
  270.  
  271. ================
  272. */
  273. void CG_Draw3DModel( float x, float y, float w, float h, qhandle_t model, qhandle_t skin, vec3_t origin, vec3_t angles ) {
  274.     refdef_t        refdef;
  275.     refEntity_t     ent;
  276.  
  277.     if ( !cg_draw3dIcons.integer || !cg_drawIcons.integer ) {
  278.         return;
  279.     }
  280.  
  281.     CG_AdjustFrom640( &x, &y, &w, &h );
  282.  
  283.     memset( &refdef, 0, sizeof( refdef ) );
  284.  
  285.     memset( &ent, 0, sizeof( ent ) );
  286.     AnglesToAxis( angles, ent.axis );
  287.     VectorCopy( origin, ent.origin );
  288.     ent.hModel = model;
  289.     ent.customSkin = skin;
  290.     ent.renderfx = RF_NOSHADOW;     // no stencil shadows
  291.  
  292.     refdef.rdflags = RDF_NOWORLDMODEL;
  293.  
  294.     AxisClear( refdef.viewaxis );
  295.  
  296.     refdef.fov_x = 30;
  297.     refdef.fov_y = 30;
  298.  
  299.     refdef.x = x;
  300.     refdef.y = y;
  301.     refdef.width = w;
  302.     refdef.height = h;
  303.  
  304.     refdef.time = cg.time;
  305.  
  306.     trap_R_ClearScene();
  307.     trap_R_AddRefEntityToScene( &ent );
  308.     trap_R_RenderScene( &refdef );
  309. }
  310.  
  311. /*
  312. ================
  313. CG_DrawHead
  314.  
  315. Used for both the status bar and the scoreboard
  316. ================
  317. */
  318. void CG_DrawHead( float x, float y, float w, float h, int clientNum, vec3_t headAngles ) {
  319.     clipHandle_t    cm;
  320.     clientInfo_t    *ci;
  321.     float           len;
  322.     vec3_t          origin;
  323.     vec3_t          mins, maxs;
  324.  
  325.     ci = &cgs.clientinfo[ clientNum ];
  326.  
  327.     if ( cg_draw3dIcons.integer ) {
  328.         cm = ci->headModel;
  329.         if ( !cm ) {
  330.             return;
  331.         }
  332.  
  333.         // offset the origin y and z to center the head
  334.         trap_R_ModelBounds( cm, mins, maxs );
  335.  
  336.         origin[2] = -0.5 * ( mins[2] + maxs[2] );
  337.         origin[1] = 0.5 * ( mins[1] + maxs[1] );
  338.  
  339.         // calculate distance so the head nearly fills the box
  340.         // assume heads are taller than wide
  341.         len = 0.7 * ( maxs[2] - mins[2] );     
  342.         origin[0] = len / 0.268;    // len / tan( fov/2 )
  343.  
  344.         // allow per-model tweaking
  345.         VectorAdd( origin, ci->headOffset, origin );
  346.  
  347.         CG_Draw3DModel( x, y, w, h, ci->headModel, ci->headSkin, origin, headAngles );
  348.     } else if ( cg_drawIcons.integer ) {
  349.         CG_DrawPic( x, y, w, h, ci->modelIcon );
  350.     }
  351.  
  352.     // if they are deferred, draw a cross out
  353.     if ( ci->deferred ) {
  354.         CG_DrawPic( x, y, w, h, cgs.media.deferShader );
  355.     }
  356. }
  357.  
  358. /*
  359. ================
  360. CG_DrawFlagModel
  361.  
  362. Used for both the status bar and the scoreboard
  363. ================
  364. */
  365. void CG_DrawFlagModel( float x, float y, float w, float h, int team, qboolean force2D ) {
  366.     qhandle_t       cm;
  367.     float           len;
  368.     vec3_t          origin, angles;
  369.     vec3_t          mins, maxs;
  370.     qhandle_t       handle;
  371.  
  372.     if ( !force2D && cg_draw3dIcons.integer ) {
  373.  
  374.         VectorClear( angles );
  375.  
  376.         cm = cgs.media.redFlagModel;
  377.  
  378.         // offset the origin y and z to center the flag
  379.         trap_R_ModelBounds( cm, mins, maxs );
  380.  
  381.         origin[2] = -0.5 * ( mins[2] + maxs[2] );
  382.         origin[1] = 0.5 * ( mins[1] + maxs[1] );
  383.  
  384.         // calculate distance so the flag nearly fills the box
  385.         // assume heads are taller than wide
  386.         len = 0.5 * ( maxs[2] - mins[2] );     
  387.         origin[0] = len / 0.268;    // len / tan( fov/2 )
  388.  
  389.         angles[YAW] = 60 * sin( cg.time / 2000.0 );;
  390.  
  391.         if( team == TEAM_RED ) {
  392.             handle = cgs.media.redFlagModel;
  393.         } else if( team == TEAM_BLUE ) {
  394.             handle = cgs.media.blueFlagModel;
  395.         } else if( team == TEAM_FREE ) {
  396.             handle = cgs.media.neutralFlagModel;
  397.         } else {
  398.             return;
  399.         }
  400.         CG_Draw3DModel( x, y, w, h, handle, 0, origin, angles );
  401.     } else if ( cg_drawIcons.integer ) {
  402.         gitem_t *item;
  403.  
  404.         if( team == TEAM_RED ) {
  405.             item = BG_FindItemForPowerup( PW_REDFLAG );
  406.         } else if( team == TEAM_BLUE ) {
  407.             item = BG_FindItemForPowerup( PW_BLUEFLAG );
  408.         } else if( team == TEAM_FREE ) {
  409.             item = BG_FindItemForPowerup( PW_NEUTRALFLAG );
  410.         } else {
  411.             return;
  412.         }
  413.         if (item) {
  414.           CG_DrawPic( x, y, w, h, cg_items[ ITEM_INDEX(item) ].icon );
  415.         }
  416.     }
  417. }
  418.  
  419. /*
  420. ================
  421. CG_DrawStatusBarHead
  422.  
  423. ================
  424. */
  425. #ifndef MISSIONPACK
  426.  
  427. static void CG_DrawStatusBarHead( float x ) {
  428.     vec3_t      angles;
  429.     float       size, stretch;
  430.     float       frac;
  431.  
  432.     VectorClear( angles );
  433.  
  434.     if ( cg.damageTime && cg.time - cg.damageTime < DAMAGE_TIME ) {
  435.         frac = (float)(cg.time - cg.damageTime ) / DAMAGE_TIME;
  436.         size = ICON_SIZE * 1.25 * ( 1.5 - frac * 0.5 );
  437.  
  438.         stretch = size - ICON_SIZE * 1.25;
  439.         // kick in the direction of damage
  440.         x -= stretch * 0.5 + cg.damageX * stretch * 0.5;
  441.  
  442.         cg.headStartYaw = 180 + cg.damageX * 45;
  443.  
  444.         cg.headEndYaw = 180 + 20 * cos( crandom()*M_PI );
  445.         cg.headEndPitch = 5 * cos( crandom()*M_PI );
  446.  
  447.         cg.headStartTime = cg.time;
  448.         cg.headEndTime = cg.time + 100 + random() * 2000;
  449.     } else {
  450.         if ( cg.time >= cg.headEndTime ) {
  451.             // select a new head angle
  452.             cg.headStartYaw = cg.headEndYaw;
  453.             cg.headStartPitch = cg.headEndPitch;
  454.             cg.headStartTime = cg.headEndTime;
  455.             cg.headEndTime = cg.time + 100 + random() * 2000;
  456.  
  457.             cg.headEndYaw = 180 + 20 * cos( crandom()*M_PI );
  458.             cg.headEndPitch = 5 * cos( crandom()*M_PI );
  459.         }
  460.  
  461.         size = ICON_SIZE * 1.25;
  462.     }
  463.  
  464.     // if the server was frozen for a while we may have a bad head start time
  465.     if ( cg.headStartTime > cg.time ) {
  466.         cg.headStartTime = cg.time;
  467.     }
  468.  
  469.     frac = ( cg.time - cg.headStartTime ) / (float)( cg.headEndTime - cg.headStartTime );
  470.     frac = frac * frac * ( 3 - 2 * frac );
  471.     angles[YAW] = cg.headStartYaw + ( cg.headEndYaw - cg.headStartYaw ) * frac;
  472.     angles[PITCH] = cg.headStartPitch + ( cg.headEndPitch - cg.headStartPitch ) * frac;
  473.  
  474.     CG_DrawHead( x, 480 - size, size, size,
  475.                 cg.snap->ps.clientNum, angles );
  476. }
  477. #endif // MISSIONPACK
  478.  
  479. /*
  480. ================
  481. CG_DrawStatusBarFlag
  482.  
  483. ================
  484. */
  485. #ifndef MISSIONPACK
  486. static void CG_DrawStatusBarFlag( float x, int team ) {
  487.     CG_DrawFlagModel( x, 480 - ICON_SIZE, ICON_SIZE, ICON_SIZE, team, qfalse );
  488. }
  489. #endif // MISSIONPACK
  490.  
  491. /*
  492. ================
  493. CG_DrawTeamBackground
  494.  
  495. ================
  496. */
  497. void CG_DrawTeamBackground( int x, int y, int w, int h, float alpha, int team )
  498. {
  499.     vec4_t      hcolor;
  500.  
  501.     hcolor[3] = alpha;
  502.     if ( team == TEAM_RED ) {
  503.         hcolor[0] = 1;
  504.         hcolor[1] = 0;
  505.         hcolor[2] = 0;
  506.     } else if ( team == TEAM_BLUE ) {
  507.         hcolor[0] = 0;
  508.         hcolor[1] = 0;
  509.         hcolor[2] = 1;
  510.     } else {
  511.         return;
  512.     }
  513.     trap_R_SetColor( hcolor );
  514.     CG_DrawPic( x, y, w, h, cgs.media.teamStatusBar );
  515.     trap_R_SetColor( NULL );
  516. }
  517.  
  518. /*
  519. ================
  520. CG_DrawStatusBar
  521.  
  522. ================
  523. */
  524. #ifndef MISSIONPACK
  525. static void CG_DrawStatusBar( void ) {
  526.     int         color;
  527.     centity_t   *cent;
  528.     playerState_t   *ps;
  529.     int         value;
  530.     vec4_t      hcolor;
  531.     vec3_t      angles;
  532.     vec3_t      origin;
  533.  
  534.     static float colors[4][4] = {
  535. //      { 0.2, 1.0, 0.2, 1.0 } , { 1.0, 0.2, 0.2, 1.0 }, {0.5, 0.5, 0.5, 1} };
  536.         { 1.0f, 0.69f, 0.0f, 1.0f },    // normal
  537.         { 1.0f, 0.2f, 0.2f, 1.0f },     // low health
  538.         { 0.5f, 0.5f, 0.5f, 1.0f },     // weapon firing
  539.         { 1.0f, 1.0f, 1.0f, 1.0f } };   // health > 100
  540.  
  541.     if ( cg_drawStatus.integer == 0 ) {
  542.         return;
  543.     }
  544.  
  545.     // draw the team background
  546.     CG_DrawTeamBackground( 0, 420, 640, 60, 0.33f, cg.snap->ps.persistant[PERS_TEAM] );
  547.  
  548.     cent = &cg_entities[cg.snap->ps.clientNum];
  549.     ps = &cg.snap->ps;
  550.  
  551.     VectorClear( angles );
  552.  
  553.     // draw any 3D icons first, so the changes back to 2D are minimized
  554.     if ( cent->currentState.weapon && cg_weapons[ cent->currentState.weapon ].ammoModel ) {
  555.         origin[0] = 70;
  556.         origin[1] = 0;
  557.         origin[2] = 0;
  558.         angles[YAW] = 90 + 20 * sin( cg.time / 1000.0 );
  559.         CG_Draw3DModel( CHAR_WIDTH*3 + TEXT_ICON_SPACE, 432, ICON_SIZE, ICON_SIZE,
  560.                        cg_weapons[ cent->currentState.weapon ].ammoModel, 0, origin, angles );
  561.     }
  562.  
  563.     CG_DrawStatusBarHead( 185 + CHAR_WIDTH*3 + TEXT_ICON_SPACE );
  564.  
  565.     if( cg.predictedPlayerState.powerups[PW_REDFLAG] ) {
  566.         CG_DrawStatusBarFlag( 185 + CHAR_WIDTH*3 + TEXT_ICON_SPACE + ICON_SIZE, TEAM_RED );
  567.     } else if( cg.predictedPlayerState.powerups[PW_BLUEFLAG] ) {
  568.         CG_DrawStatusBarFlag( 185 + CHAR_WIDTH*3 + TEXT_ICON_SPACE + ICON_SIZE, TEAM_BLUE );
  569.     } else if( cg.predictedPlayerState.powerups[PW_NEUTRALFLAG] ) {
  570.         CG_DrawStatusBarFlag( 185 + CHAR_WIDTH*3 + TEXT_ICON_SPACE + ICON_SIZE, TEAM_FREE );
  571.     }
  572.  
  573.     if ( ps->stats[ STAT_ARMOR ] ) {
  574.         origin[0] = 90;
  575.         origin[1] = 0;
  576.         origin[2] = -10;
  577.         angles[YAW] = ( cg.time & 2047 ) * 360 / 2048.0;
  578.         CG_Draw3DModel( 370 + CHAR_WIDTH*3 + TEXT_ICON_SPACE, 432, ICON_SIZE, ICON_SIZE,
  579.                        cgs.media.armorModel, 0, origin, angles );
  580.     }
  581.     //
  582.     // ammo
  583.     //
  584.     if ( cent->currentState.weapon ) {
  585.         value = ps->ammo[cent->currentState.weapon];
  586.         if ( value > -1 ) {
  587.             if ( cg.predictedPlayerState.weaponstate == WEAPON_FIRING
  588.                 && cg.predictedPlayerState.weaponTime > 100 ) {
  589.                 // draw as dark grey when reloading
  590.                 color = 2;  // dark grey
  591.             } else {
  592.                 if ( value >= 0 ) {
  593.                     color = 0;  // green
  594.                 } else {
  595.                     color = 1;  // red
  596.                 }
  597.             }
  598.             trap_R_SetColor( colors[color] );
  599.            
  600.             CG_DrawField (0, 432, 3, value);
  601.             trap_R_SetColor( NULL );
  602.  
  603.             // if we didn't draw a 3D icon, draw a 2D icon for ammo
  604.             if ( !cg_draw3dIcons.integer && cg_drawIcons.integer ) {
  605.                 qhandle_t   icon;
  606.  
  607.                 icon = cg_weapons[ cg.predictedPlayerState.weapon ].ammoIcon;
  608.                 if ( icon ) {
  609.                     CG_DrawPic( CHAR_WIDTH*3 + TEXT_ICON_SPACE, 432, ICON_SIZE, ICON_SIZE, icon );
  610.                 }
  611.             }
  612.         }
  613.     }
  614.  
  615.     //
  616.     // health
  617.     //
  618.     value = ps->stats[STAT_HEALTH];
  619.     if ( value > 100 ) {
  620.         trap_R_SetColor( colors[3] );       // white
  621.     } else if (value > 25) {
  622.         trap_R_SetColor( colors[0] );   // green
  623.     } else if (value > 0) {
  624.         color = (cg.time >> 8) & 1; // flash
  625.         trap_R_SetColor( colors[color] );
  626.     } else {
  627.         trap_R_SetColor( colors[1] );   // red
  628.     }
  629.  
  630.     // stretch the health up when taking damage
  631.     CG_DrawField ( 185, 432, 3, value);
  632.     CG_ColorForHealth( hcolor );
  633.     trap_R_SetColor( hcolor );
  634.  
  635.  
  636.     //
  637.     // armor
  638.     //
  639.     value = ps->stats[STAT_ARMOR];
  640.     if (value > 0 ) {
  641.         trap_R_SetColor( colors[0] );
  642.         CG_DrawField (370, 432, 3, value);
  643.         trap_R_SetColor( NULL );
  644.         // if we didn't draw a 3D icon, draw a 2D icon for armor
  645.         if ( !cg_draw3dIcons.integer && cg_drawIcons.integer ) {
  646.             CG_DrawPic( 370 + CHAR_WIDTH*3 + TEXT_ICON_SPACE, 432, ICON_SIZE, ICON_SIZE, cgs.media.armorIcon );
  647.         }
  648.  
  649.     }
  650. }
  651. #endif
  652.  
  653. /*
  654. ===========================================================================================
  655.  
  656.   UPPER RIGHT CORNER
  657.  
  658. ===========================================================================================
  659. */
  660.  
  661. /*
  662. ================
  663. CG_DrawAttacker
  664.  
  665. ================
  666. */
  667. static float CG_DrawAttacker( float y ) {
  668.     int         t;
  669.     float       size;
  670.     vec3_t      angles;
  671.     const char  *info;
  672.     const char  *name;
  673.     int         clientNum;
  674.  
  675.     if ( cg.predictedPlayerState.stats[STAT_HEALTH] <= 0 ) {
  676.         return y;
  677.     }
  678.  
  679.     if ( !cg.attackerTime ) {
  680.         return y;
  681.     }
  682.  
  683.     clientNum = cg.predictedPlayerState.persistant[PERS_ATTACKER];
  684.     if ( clientNum < 0 || clientNum >= MAX_CLIENTS || clientNum == cg.snap->ps.clientNum ) {
  685.         return y;
  686.     }
  687.  
  688.     t = cg.time - cg.attackerTime;
  689.     if ( t > ATTACKER_HEAD_TIME ) {
  690.         cg.attackerTime = 0;
  691.         return y;
  692.     }
  693.  
  694.     size = ICON_SIZE * 1.25;
  695.  
  696.     angles[PITCH] = 0;
  697.     angles[YAW] = 180;
  698.     angles[ROLL] = 0;
  699.     CG_DrawHead( 640 - size, y, size, size, clientNum, angles );
  700.  
  701.     info = CG_ConfigString( CS_PLAYERS + clientNum );
  702.     name = Info_ValueForKey(  info, "n" );
  703.     y += size;
  704.     CG_DrawBigString( 640 - ( Q_PrintStrlen( name ) * BIGCHAR_WIDTH), y, name, 0.5 );
  705.  
  706.     return y + BIGCHAR_HEIGHT + 2;
  707. }
  708.  
  709. /*
  710. ==================
  711. CG_DrawSnapshot
  712. ==================
  713. */
  714. static float CG_DrawSnapshot( float y ) {
  715.     char        *s;
  716.     int         w;
  717.  
  718.     s = va( "time:%i snap:%i cmd:%i", cg.snap->serverTime,
  719.         cg.latestSnapshotNum, cgs.serverCommandSequence );
  720.     w = CG_DrawStrlen( s ) * BIGCHAR_WIDTH;
  721.  
  722.     CG_DrawBigString( 635 - w, y + 2, s, 1.0F);
  723.  
  724.     return y + BIGCHAR_HEIGHT + 4;
  725. }
  726.  
  727. /*
  728. ==================
  729. CG_DrawFPS
  730. ==================
  731. */
  732. #define FPS_FRAMES  4
  733. static float CG_DrawFPS( float y ) {
  734.     char        *s;
  735.     int         w;
  736.     static int  previousTimes[FPS_FRAMES];
  737.     static int  index;
  738.     int     i, total;
  739.     int     fps;
  740.     static  int previous;
  741.     int     t, frameTime;
  742.  
  743.     // don't use serverTime, because that will be drifting to
  744.     // correct for internet lag changes, timescales, timedemos, etc
  745.     t = trap_Milliseconds();
  746.     frameTime = t - previous;
  747.     previous = t;
  748.  
  749.     previousTimes[index % FPS_FRAMES] = frameTime;
  750.     index++;
  751.     if ( index > FPS_FRAMES ) {
  752.         // average multiple frames together to smooth changes out a bit
  753.         total = 0;
  754.         for ( i = 0 ; i < FPS_FRAMES ; i++ ) {
  755.             total += previousTimes[i];
  756.         }
  757.         if ( !total ) {
  758.             total = 1;
  759.         }
  760.         fps = 1000 * FPS_FRAMES / total;
  761.  
  762.         s = va( "%ifps", fps );
  763.         w = CG_DrawStrlen( s ) * BIGCHAR_WIDTH;
  764.  
  765.         CG_DrawBigString( 635 - w, y + 2, s, 1.0F);
  766.     }
  767.  
  768.     return y + BIGCHAR_HEIGHT + 4;
  769. }
  770.  
  771. /*
  772. =================
  773. CG_DrawTimer
  774. =================
  775. */
  776. static float CG_DrawTimer( float y ) {
  777.     char        *s;
  778.     int         w;
  779.     int         mins, seconds, tens;
  780.     int         msec;
  781.  
  782.     msec = cg.time - cgs.levelStartTime;
  783.  
  784.     seconds = msec / 1000;
  785.     mins = seconds / 60;
  786.     seconds -= mins * 60;
  787.     tens = seconds / 10;
  788.     seconds -= tens * 10;
  789.  
  790.     s = va( "%i:%i%i", mins, tens, seconds );
  791.     w = CG_DrawStrlen( s ) * BIGCHAR_WIDTH;
  792.  
  793.     CG_DrawBigString( 635 - w, y + 2, s, 1.0F);
  794.  
  795.     return y + BIGCHAR_HEIGHT + 4;
  796. }
  797.  
  798.  
  799. /*
  800. =================
  801. CG_DrawTeamOverlay
  802. =================
  803. */
  804.  
  805. static float CG_DrawTeamOverlay( float y, qboolean right, qboolean upper ) {
  806.     int x, w, h, xx;
  807.     int i, j, len;
  808.     const char *p;
  809.     vec4_t      hcolor;
  810.     int pwidth, lwidth;
  811.     int plyrs;
  812.     char st[16];
  813.     clientInfo_t *ci;
  814.     gitem_t *item;
  815.     int ret_y, count;
  816.  
  817.     if ( !cg_drawTeamOverlay.integer ) {
  818.         return y;
  819.     }
  820.  
  821.     if ( cg.snap->ps.persistant[PERS_TEAM] != TEAM_RED && cg.snap->ps.persistant[PERS_TEAM] != TEAM_BLUE ) {
  822.         return y; // Not on any team
  823.     }
  824.  
  825.     plyrs = 0;
  826.  
  827.     // max player name width
  828.     pwidth = 0;
  829.     count = (numSortedTeamPlayers > 8) ? 8 : numSortedTeamPlayers;
  830.     for (i = 0; i < count; i++) {
  831.         ci = cgs.clientinfo + sortedTeamPlayers[i];
  832.         if ( ci->infoValid && ci->team == cg.snap->ps.persistant[PERS_TEAM]) {
  833.             plyrs++;
  834.             len = CG_DrawStrlen(ci->name);
  835.             if (len > pwidth)
  836.                 pwidth = len;
  837.         }
  838.     }
  839.  
  840.     if (!plyrs)
  841.         return y;
  842.  
  843.     if (pwidth > TEAM_OVERLAY_MAXNAME_WIDTH)
  844.         pwidth = TEAM_OVERLAY_MAXNAME_WIDTH;
  845.  
  846.     // max location name width
  847.     lwidth = 0;
  848.     for (i = 1; i < MAX_LOCATIONS; i++) {
  849.         p = CG_ConfigString(CS_LOCATIONS + i);
  850.         if (p && *p) {
  851.             len = CG_DrawStrlen(p);
  852.             if (len > lwidth)
  853.                 lwidth = len;
  854.         }
  855.     }
  856.  
  857.     if (lwidth > TEAM_OVERLAY_MAXLOCATION_WIDTH)
  858.         lwidth = TEAM_OVERLAY_MAXLOCATION_WIDTH;
  859.  
  860.     w = (pwidth + lwidth + 4 + 7) * TINYCHAR_WIDTH;
  861.  
  862.     if ( right )
  863.         x = 640 - w;
  864.     else
  865.         x = 0;
  866.  
  867.     h = plyrs * TINYCHAR_HEIGHT;
  868.  
  869.     if ( upper ) {
  870.         ret_y = y + h;
  871.     } else {
  872.         y -= h;
  873.         ret_y = y;
  874.     }
  875.  
  876.     if ( cg.snap->ps.persistant[PERS_TEAM] == TEAM_RED ) {
  877.         hcolor[0] = 1.0f;
  878.         hcolor[1] = 0.0f;
  879.         hcolor[2] = 0.0f;
  880.         hcolor[3] = 0.33f;
  881.     } else { // if ( cg.snap->ps.persistant[PERS_TEAM] == TEAM_BLUE )
  882.         hcolor[0] = 0.0f;
  883.         hcolor[1] = 0.0f;
  884.         hcolor[2] = 1.0f;
  885.         hcolor[3] = 0.33f;
  886.     }
  887.     trap_R_SetColor( hcolor );
  888.     CG_DrawPic( x, y, w, h, cgs.media.teamStatusBar );
  889.     trap_R_SetColor( NULL );
  890.  
  891.     for (i = 0; i < count; i++) {
  892.         ci = cgs.clientinfo + sortedTeamPlayers[i];
  893.         if ( ci->infoValid && ci->team == cg.snap->ps.persistant[PERS_TEAM]) {
  894.  
  895.             hcolor[0] = hcolor[1] = hcolor[2] = hcolor[3] = 1.0;
  896.  
  897.             xx = x + TINYCHAR_WIDTH;
  898.  
  899.             CG_DrawStringExt( xx, y,
  900.                 ci->name, hcolor, qfalse, qfalse,
  901.                 TINYCHAR_WIDTH, TINYCHAR_HEIGHT, TEAM_OVERLAY_MAXNAME_WIDTH);
  902.  
  903.             if (lwidth) {
  904.                 p = CG_ConfigString(CS_LOCATIONS + ci->location);
  905.                 if (!p || !*p)
  906.                     p = "unknown";
  907.                 len = CG_DrawStrlen(p);
  908.                 if (len > lwidth)
  909.                     len = lwidth;
  910.  
  911. //              xx = x + TINYCHAR_WIDTH * 2 + TINYCHAR_WIDTH * pwidth +
  912. //                  ((lwidth/2 - len/2) * TINYCHAR_WIDTH);
  913.                 xx = x + TINYCHAR_WIDTH * 2 + TINYCHAR_WIDTH * pwidth;
  914.                 CG_DrawStringExt( xx, y,
  915.                     p, hcolor, qfalse, qfalse, TINYCHAR_WIDTH, TINYCHAR_HEIGHT,
  916.                     TEAM_OVERLAY_MAXLOCATION_WIDTH);
  917.             }
  918.  
  919.             CG_GetColorForHealth( ci->health, ci->armor, hcolor );
  920.  
  921.             Com_sprintf (st, sizeof(st), "%3i %3i", ci->health, ci->armor);
  922.  
  923.             xx = x + TINYCHAR_WIDTH * 3 +
  924.                 TINYCHAR_WIDTH * pwidth + TINYCHAR_WIDTH * lwidth;
  925.  
  926.             CG_DrawStringExt( xx, y,
  927.                 st, hcolor, qfalse, qfalse,
  928.                 TINYCHAR_WIDTH, TINYCHAR_HEIGHT, 0 );
  929.  
  930.             // draw weapon icon
  931.             xx += TINYCHAR_WIDTH * 3;
  932.  
  933.             if ( cg_weapons[ci->curWeapon].weaponIcon ) {
  934.                 CG_DrawPic( xx, y, TINYCHAR_WIDTH, TINYCHAR_HEIGHT,
  935.                     cg_weapons[ci->curWeapon].weaponIcon );
  936.             } else {
  937.                 CG_DrawPic( xx, y, TINYCHAR_WIDTH, TINYCHAR_HEIGHT,
  938.                     cgs.media.deferShader );
  939.             }
  940.  
  941.             // Draw powerup icons
  942.             if (right) {
  943.                 xx = x;
  944.             } else {
  945.                 xx = x + w - TINYCHAR_WIDTH;
  946.             }
  947.             for (j = 0; j <= PW_NUM_POWERUPS; j++) {
  948.                 if (ci->powerups & (1 << j)) {
  949.  
  950.                     item = BG_FindItemForPowerup( j );
  951.  
  952.                     if (item) {
  953.                         CG_DrawPic( xx, y, TINYCHAR_WIDTH, TINYCHAR_HEIGHT,
  954.                         trap_R_RegisterShader( item->icon ) );
  955.                         if (right) {
  956.                             xx -= TINYCHAR_WIDTH;
  957.                         } else {
  958.                             xx += TINYCHAR_WIDTH;
  959.                         }
  960.                     }
  961.                 }
  962.             }
  963.  
  964.             y += TINYCHAR_HEIGHT;
  965.         }
  966.     }
  967.  
  968.     return ret_y;
  969. //#endif
  970. }
  971.  
  972.  
  973. /*
  974. =====================
  975. CG_DrawUpperRight
  976.  
  977. =====================
  978. */
  979. static void CG_DrawUpperRight( void ) {
  980.     float   y;
  981.  
  982.     y = 0;
  983.  
  984.     if ( cgs.gametype >= GT_TEAM && cg_drawTeamOverlay.integer == 1 ) {
  985.         y = CG_DrawTeamOverlay( y, qtrue, qtrue );
  986.     }
  987.     if ( cg_drawSnapshot.integer ) {
  988.         y = CG_DrawSnapshot( y );
  989.     }
  990.     if ( cg_drawFPS.integer ) {
  991.         y = CG_DrawFPS( y );
  992.     }
  993.     if ( cg_drawTimer.integer ) {
  994.         y = CG_DrawTimer( y );
  995.     }
  996.     if ( cg_drawAttacker.integer ) {
  997.         y = CG_DrawAttacker( y );
  998.     }
  999.  
  1000. }
  1001.  
  1002. /*
  1003. ===========================================================================================
  1004.  
  1005.   LOWER RIGHT CORNER
  1006.  
  1007. ===========================================================================================
  1008. */
  1009.  
  1010. /*
  1011. =================
  1012. CG_DrawScores
  1013.  
  1014. Draw the small two score display
  1015. =================
  1016. */
  1017. #ifndef MISSIONPACK
  1018. static float CG_DrawScores( float y ) {
  1019.     const char  *s;
  1020.     int         s1, s2, score;
  1021.     int         x, w;
  1022.     int         v;
  1023.     vec4_t      color;
  1024.     float       y1;
  1025.     gitem_t     *item;
  1026.  
  1027.     s1 = cgs.scores1;
  1028.     s2 = cgs.scores2;
  1029.  
  1030.     y -=  BIGCHAR_HEIGHT + 8;
  1031.  
  1032.     y1 = y;
  1033.  
  1034.     // draw from the right side to left
  1035.     if ( cgs.gametype >= GT_TEAM ) {
  1036.         x = 640;
  1037.         color[0] = 0.0f;
  1038.         color[1] = 0.0f;
  1039.         color[2] = 1.0f;
  1040.         color[3] = 0.33f;
  1041.         s = va( "%2i", s2 );
  1042.         w = CG_DrawStrlen( s ) * BIGCHAR_WIDTH + 8;
  1043.         x -= w;
  1044.         CG_FillRect( x, y-4,  w, BIGCHAR_HEIGHT+8, color );
  1045.         if ( cg.snap->ps.persistant[PERS_TEAM] == TEAM_BLUE ) {
  1046.             CG_DrawPic( x, y-4, w, BIGCHAR_HEIGHT+8, cgs.media.selectShader );
  1047.         }
  1048.         CG_DrawBigString( x + 4, y, s, 1.0F);
  1049.  
  1050.         if ( cgs.gametype == GT_CTF ) {
  1051.             // Display flag status
  1052.             item = BG_FindItemForPowerup( PW_BLUEFLAG );
  1053.  
  1054.             if (item) {
  1055.                 y1 = y - BIGCHAR_HEIGHT - 8;
  1056.                 if( cgs.blueflag >= 0 && cgs.blueflag <= 2 ) {
  1057.                     CG_DrawPic( x, y1-4, w, BIGCHAR_HEIGHT+8, cgs.media.blueFlagShader[cgs.blueflag] );
  1058.                 }
  1059.             }
  1060.         }
  1061.         color[0] = 1.0f;
  1062.         color[1] = 0.0f;
  1063.         color[2] = 0.0f;
  1064.         color[3] = 0.33f;
  1065.         s = va( "%2i", s1 );
  1066.         w = CG_DrawStrlen( s ) * BIGCHAR_WIDTH + 8;
  1067.         x -= w;
  1068.         CG_FillRect( x, y-4,  w, BIGCHAR_HEIGHT+8, color );
  1069.         if ( cg.snap->ps.persistant[PERS_TEAM] == TEAM_RED ) {
  1070.             CG_DrawPic( x, y-4, w, BIGCHAR_HEIGHT+8, cgs.media.selectShader );
  1071.         }
  1072.         CG_DrawBigString( x + 4, y, s, 1.0F);
  1073.  
  1074.         if ( cgs.gametype == GT_CTF ) {
  1075.             // Display flag status
  1076.             item = BG_FindItemForPowerup( PW_REDFLAG );
  1077.  
  1078.             if (item) {
  1079.                 y1 = y - BIGCHAR_HEIGHT - 8;
  1080.                 if( cgs.redflag >= 0 && cgs.redflag <= 2 ) {
  1081.                     CG_DrawPic( x, y1-4, w, BIGCHAR_HEIGHT+8, cgs.media.redFlagShader[cgs.redflag] );
  1082.                 }
  1083.             }
  1084.         }
  1085.  
  1086.         if ( cgs.gametype >= GT_CTF ) {
  1087.             v = cgs.capturelimit;
  1088.         } else {
  1089.             v = cgs.fraglimit;
  1090.         }
  1091.         if ( v ) {
  1092.             s = va( "%2i", v );
  1093.             w = CG_DrawStrlen( s ) * BIGCHAR_WIDTH + 8;
  1094.             x -= w;
  1095.             CG_DrawBigString( x + 4, y, s, 1.0F);
  1096.         }
  1097.  
  1098.     } else {
  1099.         qboolean    spectator;
  1100.  
  1101.         x = 640;
  1102.         score = cg.snap->ps.persistant[PERS_SCORE];
  1103.         spectator = ( cg.snap->ps.persistant[PERS_TEAM] == TEAM_SPECTATOR );
  1104.  
  1105.         // always show your score in the second box if not in first place
  1106.         if ( s1 != score ) {
  1107.             s2 = score;
  1108.         }
  1109.         if ( s2 != SCORE_NOT_PRESENT ) {
  1110.             s = va( "%2i", s2 );
  1111.             w = CG_DrawStrlen( s ) * BIGCHAR_WIDTH + 8;
  1112.             x -= w;
  1113.             if ( !spectator && score == s2 && score != s1 ) {
  1114.                 color[0] = 1.0f;
  1115.                 color[1] = 0.0f;
  1116.                 color[2] = 0.0f;
  1117.                 color[3] = 0.33f;
  1118.                 CG_FillRect( x, y-4,  w, BIGCHAR_HEIGHT+8, color );
  1119.                 CG_DrawPic( x, y-4, w, BIGCHAR_HEIGHT+8, cgs.media.selectShader );
  1120.             } else {
  1121.                 color[0] = 0.5f;
  1122.                 color[1] = 0.5f;
  1123.                 color[2] = 0.5f;
  1124.                 color[3] = 0.33f;
  1125.                 CG_FillRect( x, y-4,  w, BIGCHAR_HEIGHT+8, color );
  1126.             }  
  1127.             CG_DrawBigString( x + 4, y, s, 1.0F);
  1128.         }
  1129.  
  1130.         // first place
  1131.         if ( s1 != SCORE_NOT_PRESENT ) {
  1132.             s = va( "%2i", s1 );
  1133.             w = CG_DrawStrlen( s ) * BIGCHAR_WIDTH + 8;
  1134.             x -= w;
  1135.             if ( !spectator && score == s1 ) {
  1136.                 color[0] = 0.0f;
  1137.                 color[1] = 0.0f;
  1138.                 color[2] = 1.0f;
  1139.                 color[3] = 0.33f;
  1140.                 CG_FillRect( x, y-4,  w, BIGCHAR_HEIGHT+8, color );
  1141.                 CG_DrawPic( x, y-4, w, BIGCHAR_HEIGHT+8, cgs.media.selectShader );
  1142.             } else {
  1143.                 color[0] = 0.5f;
  1144.                 color[1] = 0.5f;
  1145.                 color[2] = 0.5f;
  1146.                 color[3] = 0.33f;
  1147.                 CG_FillRect( x, y-4,  w, BIGCHAR_HEIGHT+8, color );
  1148.             }  
  1149.             CG_DrawBigString( x + 4, y, s, 1.0F);
  1150.         }
  1151.  
  1152.         if ( cgs.fraglimit ) {
  1153.             s = va( "%2i", cgs.fraglimit );
  1154.             w = CG_DrawStrlen( s ) * BIGCHAR_WIDTH + 8;
  1155.             x -= w;
  1156.             CG_DrawBigString( x + 4, y, s, 1.0F);
  1157.         }
  1158.  
  1159.     }
  1160.  
  1161.     return y1 - 8;
  1162. }
  1163. #endif // MISSIONPACK
  1164.  
  1165. /*
  1166. ================
  1167. CG_DrawPowerups
  1168. ================
  1169. */
  1170. #ifndef MISSIONPACK
  1171. static float CG_DrawPowerups( float y ) {
  1172.     int     sorted[MAX_POWERUPS];
  1173.     int     sortedTime[MAX_POWERUPS];
  1174.     int     i, j, k;
  1175.     int     active;
  1176.     playerState_t   *ps;
  1177.     int     t;
  1178.     gitem_t *item;
  1179.     int     x;
  1180.     int     color;
  1181.     float   size;
  1182.     float   f;
  1183.     static float colors[2][4] = {
  1184.     { 0.2f, 1.0f, 0.2f, 1.0f } ,
  1185.     { 1.0f, 0.2f, 0.2f, 1.0f }
  1186.   };
  1187.  
  1188.     ps = &cg.snap->ps;
  1189.  
  1190.     if ( ps->stats[STAT_HEALTH] <= 0 ) {
  1191.         return y;
  1192.     }
  1193.  
  1194.     // sort the list by time remaining
  1195.     active = 0;
  1196.     for ( i = 0 ; i < MAX_POWERUPS ; i++ ) {
  1197.         if ( !ps->powerups[ i ] ) {
  1198.             continue;
  1199.         }
  1200.         t = ps->powerups[ i ] - cg.time;
  1201.         // ZOID--don't draw if the power up has unlimited time (999 seconds)
  1202.         // This is true of the CTF flags
  1203.         if ( t < 0 || t > 999000) {
  1204.             continue;
  1205.         }
  1206.  
  1207.         // insert into the list
  1208.         for ( j = 0 ; j < active ; j++ ) {
  1209.             if ( sortedTime[j] >= t ) {
  1210.                 for ( k = active - 1 ; k >= j ; k-- ) {
  1211.                     sorted[k+1] = sorted[k];
  1212.                     sortedTime[k+1] = sortedTime[k];
  1213.                 }
  1214.                 break;
  1215.             }
  1216.         }
  1217.         sorted[j] = i;
  1218.         sortedTime[j] = t;
  1219.         active++;
  1220.     }
  1221.  
  1222.     // draw the icons and timers
  1223.     x = 640 - ICON_SIZE - CHAR_WIDTH * 2;
  1224.     for ( i = 0 ; i < active ; i++ ) {
  1225.         item = BG_FindItemForPowerup( sorted[i] );
  1226.  
  1227.     if (item) {
  1228.  
  1229.           color = 1;
  1230.  
  1231.           y -= ICON_SIZE;
  1232.  
  1233.           trap_R_SetColor( colors[color] );
  1234.           CG_DrawField( x, y, 2, sortedTime[ i ] / 1000 );
  1235.  
  1236.           t = ps->powerups[ sorted[i] ];
  1237.           if ( t - cg.time >= POWERUP_BLINKS * POWERUP_BLINK_TIME ) {
  1238.               trap_R_SetColor( NULL );
  1239.           } else {
  1240.               vec4_t    modulate;
  1241.  
  1242.               f = (float)( t - cg.time ) / POWERUP_BLINK_TIME;
  1243.               f -= (int)f;
  1244.               modulate[0] = modulate[1] = modulate[2] = modulate[3] = f;
  1245.               trap_R_SetColor( modulate );
  1246.           }
  1247.  
  1248.           if ( cg.powerupActive == sorted[i] &&
  1249.               cg.time - cg.powerupTime < PULSE_TIME ) {
  1250.               f = 1.0 - ( ( (float)cg.time - cg.powerupTime ) / PULSE_TIME );
  1251.               size = ICON_SIZE * ( 1.0 + ( PULSE_SCALE - 1.0 ) * f );
  1252.           } else {
  1253.               size = ICON_SIZE;
  1254.           }
  1255.  
  1256.           CG_DrawPic( 640 - size, y + ICON_SIZE / 2 - size / 2,
  1257.               size, size, trap_R_RegisterShader( item->icon ) );
  1258.     }
  1259.     }
  1260.     trap_R_SetColor( NULL );
  1261.  
  1262.     return y;
  1263. }
  1264. #endif // MISSIONPACK
  1265.  
  1266. /*
  1267. =====================
  1268. CG_DrawLowerRight
  1269.  
  1270. =====================
  1271. */
  1272. #ifndef MISSIONPACK
  1273. static void CG_DrawLowerRight( void ) {
  1274.     float   y;
  1275.  
  1276.     y = 480 - ICON_SIZE;
  1277.  
  1278.     if ( cgs.gametype >= GT_TEAM && cg_drawTeamOverlay.integer == 2 ) {
  1279.         y = CG_DrawTeamOverlay( y, qtrue, qfalse );
  1280.     }
  1281.  
  1282.     y = CG_DrawScores( y );
  1283.     y = CG_DrawPowerups( y );
  1284. }
  1285. #endif // MISSIONPACK
  1286.  
  1287. /*
  1288. ===================
  1289. CG_DrawPickupItem
  1290. ===================
  1291. */
  1292. #ifndef MISSIONPACK
  1293. static int CG_DrawPickupItem( int y ) {
  1294.     int     value;
  1295.     float   *fadeColor;
  1296.  
  1297.     if ( cg.snap->ps.stats[STAT_HEALTH] <= 0 ) {
  1298.         return y;
  1299.     }
  1300.  
  1301.     y -= ICON_SIZE;
  1302.  
  1303.     value = cg.itemPickup;
  1304.     if ( value ) {
  1305.         fadeColor = CG_FadeColor( cg.itemPickupTime, 3000 );
  1306.         if ( fadeColor ) {
  1307.             CG_RegisterItemVisuals( value );
  1308.             trap_R_SetColor( fadeColor );
  1309.             CG_DrawPic( 8, y, ICON_SIZE, ICON_SIZE, cg_items[ value ].icon );
  1310.             CG_DrawBigString( ICON_SIZE + 16, y + (ICON_SIZE/2 - BIGCHAR_HEIGHT/2), bg_itemlist[ value ].pickup_name, fadeColor[0] );
  1311.             trap_R_SetColor( NULL );
  1312.         }
  1313.     }
  1314.    
  1315.     return y;
  1316. }
  1317. #endif // MISSIONPACK
  1318.  
  1319. /*
  1320. =====================
  1321. CG_DrawLowerLeft
  1322.  
  1323. =====================
  1324. */
  1325. #ifndef MISSIONPACK
  1326. static void CG_DrawLowerLeft( void ) {
  1327.     float   y;
  1328.  
  1329.     y = 480 - ICON_SIZE;
  1330.  
  1331.     if ( cgs.gametype >= GT_TEAM && cg_drawTeamOverlay.integer == 3 ) {
  1332.         y = CG_DrawTeamOverlay( y, qfalse, qfalse );
  1333.     }
  1334.  
  1335.  
  1336.     y = CG_DrawPickupItem( y );
  1337. }
  1338. #endif // MISSIONPACK
  1339.  
  1340.  
  1341. //===========================================================================================
  1342.  
  1343. /*
  1344. =================
  1345. CG_DrawTeamInfo
  1346. =================
  1347. */
  1348. #ifndef MISSIONPACK
  1349. static void CG_DrawTeamInfo( void ) {
  1350.     int w, h;
  1351.     int i, len;
  1352.     vec4_t      hcolor;
  1353.     int     chatHeight;
  1354.  
  1355. #define CHATLOC_Y 420 // bottom end
  1356. #define CHATLOC_X 0
  1357.  
  1358.     if (cg_teamChatHeight.integer < TEAMCHAT_HEIGHT)
  1359.         chatHeight = cg_teamChatHeight.integer;
  1360.     else
  1361.         chatHeight = TEAMCHAT_HEIGHT;
  1362.     if (chatHeight <= 0)
  1363.         return; // disabled
  1364.  
  1365.     if (cgs.teamLastChatPos != cgs.teamChatPos) {
  1366.         if (cg.time - cgs.teamChatMsgTimes[cgs.teamLastChatPos % chatHeight] > cg_teamChatTime.integer) {
  1367.             cgs.teamLastChatPos++;
  1368.         }
  1369.  
  1370.         h = (cgs.teamChatPos - cgs.teamLastChatPos) * TINYCHAR_HEIGHT;
  1371.  
  1372.         w = 0;
  1373.  
  1374.         for (i = cgs.teamLastChatPos; i < cgs.teamChatPos; i++) {
  1375.             len = CG_DrawStrlen(cgs.teamChatMsgs[i % chatHeight]);
  1376.             if (len > w)
  1377.                 w = len;
  1378.         }
  1379.         w *= TINYCHAR_WIDTH;
  1380.         w += TINYCHAR_WIDTH * 2;
  1381.  
  1382.         if ( cg.snap->ps.persistant[PERS_TEAM] == TEAM_RED ) {
  1383.             hcolor[0] = 1.0f;
  1384.             hcolor[1] = 0.0f;
  1385.             hcolor[2] = 0.0f;
  1386.             hcolor[3] = 0.33f;
  1387.         } else if ( cg.snap->ps.persistant[PERS_TEAM] == TEAM_BLUE ) {
  1388.             hcolor[0] = 0.0f;
  1389.             hcolor[1] = 0.0f;
  1390.             hcolor[2] = 1.0f;
  1391.             hcolor[3] = 0.33f;
  1392.         } else {
  1393.             hcolor[0] = 0.0f;
  1394.             hcolor[1] = 1.0f;
  1395.             hcolor[2] = 0.0f;
  1396.             hcolor[3] = 0.33f;
  1397.         }
  1398.  
  1399.         trap_R_SetColor( hcolor );
  1400.         CG_DrawPic( CHATLOC_X, CHATLOC_Y - h, 640, h, cgs.media.teamStatusBar );
  1401.         trap_R_SetColor( NULL );
  1402.  
  1403.         hcolor[0] = hcolor[1] = hcolor[2] = 1.0f;
  1404.         hcolor[3] = 1.0f;
  1405.  
  1406.         for (i = cgs.teamChatPos - 1; i >= cgs.teamLastChatPos; i--) {
  1407.             CG_DrawStringExt( CHATLOC_X + TINYCHAR_WIDTH,
  1408.                 CHATLOC_Y - (cgs.teamChatPos - i)*TINYCHAR_HEIGHT,
  1409.                 cgs.teamChatMsgs[i % chatHeight], hcolor, qfalse, qfalse,
  1410.                 TINYCHAR_WIDTH, TINYCHAR_HEIGHT, 0 );
  1411.         }
  1412.     }
  1413. }
  1414. #endif // MISSIONPACK
  1415.  
  1416. /*
  1417. ===================
  1418. CG_DrawHoldableItem
  1419. ===================
  1420. */
  1421. #ifndef MISSIONPACK
  1422. static void CG_DrawHoldableItem( void ) {
  1423.     int     value;
  1424.  
  1425.     value = cg.snap->ps.stats[STAT_HOLDABLE_ITEM];
  1426.     if ( value ) {
  1427.         CG_RegisterItemVisuals( value );
  1428.         CG_DrawPic( 640-ICON_SIZE, (SCREEN_HEIGHT-ICON_SIZE)/2, ICON_SIZE, ICON_SIZE, cg_items[ value ].icon );
  1429.     }
  1430.  
  1431. }
  1432. #endif // MISSIONPACK
  1433.  
  1434. #ifdef MISSIONPACK
  1435. /*
  1436. ===================
  1437. CG_DrawPersistantPowerup
  1438. ===================
  1439. */
  1440. #if 0 // sos001208 - DEAD
  1441. static void CG_DrawPersistantPowerup( void ) {
  1442.     int     value;
  1443.  
  1444.     value = cg.snap->ps.stats[STAT_PERSISTANT_POWERUP];
  1445.     if ( value ) {
  1446.         CG_RegisterItemVisuals( value );
  1447.         CG_DrawPic( 640-ICON_SIZE, (SCREEN_HEIGHT-ICON_SIZE)/2 - ICON_SIZE, ICON_SIZE, ICON_SIZE, cg_items[ value ].icon );
  1448.     }
  1449. }
  1450. #endif
  1451. #endif // MISSIONPACK
  1452.  
  1453.  
  1454. /*
  1455. ===================
  1456. CG_DrawReward
  1457. ===================
  1458. */
  1459. static void CG_DrawReward( void ) {
  1460.     float   *color;
  1461.     int     i, count;
  1462.     float   x, y;
  1463.     char    buf[32];
  1464.  
  1465.     if ( !cg_drawRewards.integer ) {
  1466.         return;
  1467.     }
  1468.  
  1469.     color = CG_FadeColor( cg.rewardTime, REWARD_TIME );
  1470.     if ( !color ) {
  1471.         if (cg.rewardStack > 0) {
  1472.             for(i = 0; i < cg.rewardStack; i++) {
  1473.                 cg.rewardSound[i] = cg.rewardSound[i+1];
  1474.                 cg.rewardShader[i] = cg.rewardShader[i+1];
  1475.                 cg.rewardCount[i] = cg.rewardCount[i+1];
  1476.             }
  1477.             cg.rewardTime = cg.time;
  1478.             cg.rewardStack--;
  1479.             color = CG_FadeColor( cg.rewardTime, REWARD_TIME );
  1480.             trap_S_StartLocalSound(cg.rewardSound[0], CHAN_ANNOUNCER);
  1481.         } else {
  1482.             return;
  1483.         }
  1484.     }
  1485.  
  1486.     trap_R_SetColor( color );
  1487.  
  1488.     /*
  1489.     count = cg.rewardCount[0]/10;               // number of big rewards to draw
  1490.  
  1491.     if (count) {
  1492.         y = 4;
  1493.         x = 320 - count * ICON_SIZE;
  1494.         for ( i = 0 ; i < count ; i++ ) {
  1495.             CG_DrawPic( x, y, (ICON_SIZE*2)-4, (ICON_SIZE*2)-4, cg.rewardShader[0] );
  1496.             x += (ICON_SIZE*2);
  1497.         }
  1498.     }
  1499.  
  1500.     count = cg.rewardCount[0] - count*10;       // number of small rewards to draw
  1501.     */
  1502.  
  1503.     if ( cg.rewardCount[0] >= 10 ) {
  1504.         y = 56;
  1505.         x = 320 - ICON_SIZE/2;
  1506.         CG_DrawPic( x, y, ICON_SIZE-4, ICON_SIZE-4, cg.rewardShader[0] );
  1507.         Com_sprintf(buf, sizeof(buf), "%d", cg.rewardCount[0]);
  1508.         x = ( SCREEN_WIDTH - SMALLCHAR_WIDTH * CG_DrawStrlen( buf ) ) / 2;
  1509.         CG_DrawStringExt( x, y+ICON_SIZE, buf, color, qfalse, qtrue,
  1510.                                 SMALLCHAR_WIDTH, SMALLCHAR_HEIGHT, 0 );
  1511.     }
  1512.     else {
  1513.  
  1514.         count = cg.rewardCount[0];
  1515.  
  1516.         y = 56;
  1517.         x = 320 - count * ICON_SIZE/2;
  1518.         for ( i = 0 ; i < count ; i++ ) {
  1519.             CG_DrawPic( x, y, ICON_SIZE-4, ICON_SIZE-4, cg.rewardShader[0] );
  1520.             x += ICON_SIZE;
  1521.         }
  1522.     }
  1523.     trap_R_SetColor( NULL );
  1524. }
  1525.  
  1526.  
  1527. /*
  1528. ===============================================================================
  1529.  
  1530. LAGOMETER
  1531.  
  1532. ===============================================================================
  1533. */
  1534.  
  1535. #define LAG_SAMPLES     128
  1536.  
  1537.  
  1538. typedef struct {
  1539.     int     frameSamples[LAG_SAMPLES];
  1540.     int     frameCount;
  1541.     int     snapshotFlags[LAG_SAMPLES];
  1542.     int     snapshotSamples[LAG_SAMPLES];
  1543.     int     snapshotCount;
  1544. } lagometer_t;
  1545.  
  1546. lagometer_t     lagometer;
  1547.  
  1548. /*
  1549. ==============
  1550. CG_AddLagometerFrameInfo
  1551.  
  1552. Adds the current interpolate / extrapolate bar for this frame
  1553. ==============
  1554. */
  1555. void CG_AddLagometerFrameInfo( void ) {
  1556.     int         offset;
  1557.  
  1558.     offset = cg.time - cg.latestSnapshotTime;
  1559.     lagometer.frameSamples[ lagometer.frameCount & ( LAG_SAMPLES - 1) ] = offset;
  1560.     lagometer.frameCount++;
  1561. }
  1562.  
  1563. /*
  1564. ==============
  1565. CG_AddLagometerSnapshotInfo
  1566.  
  1567. Each time a snapshot is received, log its ping time and
  1568. the number of snapshots that were dropped before it.
  1569.  
  1570. Pass NULL for a dropped packet.
  1571. ==============
  1572. */
  1573. void CG_AddLagometerSnapshotInfo( snapshot_t *snap ) {
  1574.     // dropped packet
  1575.     if ( !snap ) {
  1576.         lagometer.snapshotSamples[ lagometer.snapshotCount & ( LAG_SAMPLES - 1) ] = -1;
  1577.         lagometer.snapshotCount++;
  1578.         return;
  1579.     }
  1580.  
  1581.     // add this snapshot's info
  1582.     lagometer.snapshotSamples[ lagometer.snapshotCount & ( LAG_SAMPLES - 1) ] = snap->ping;
  1583.     lagometer.snapshotFlags[ lagometer.snapshotCount & ( LAG_SAMPLES - 1) ] = snap->snapFlags;
  1584.     lagometer.snapshotCount++;
  1585. }
  1586.  
  1587. /*
  1588. ==============
  1589. CG_DrawDisconnect
  1590.  
  1591. Should we draw something differnet for long lag vs no packets?
  1592. ==============
  1593. */
  1594. static void CG_DrawDisconnect( void ) {
  1595.     float       x, y;
  1596.     int         cmdNum;
  1597.     usercmd_t   cmd;
  1598.     const char      *s;
  1599.     int         w;
  1600.  
  1601.     // draw the phone jack if we are completely past our buffers
  1602.     cmdNum = trap_GetCurrentCmdNumber() - CMD_BACKUP + 1;
  1603.     trap_GetUserCmd( cmdNum, &cmd );
  1604.     if ( cmd.serverTime <= cg.snap->ps.commandTime
  1605.         || cmd.serverTime > cg.time ) { // special check for map_restart
  1606.         return;
  1607.     }
  1608.  
  1609.     // also add text in center of screen
  1610.     s = "Connection Interrupted";
  1611.     w = CG_DrawStrlen( s ) * BIGCHAR_WIDTH;
  1612.     CG_DrawBigString( 320 - w/2, 100, s, 1.0F);
  1613.  
  1614.     // blink the icon
  1615.     if ( ( cg.time >> 9 ) & 1 ) {
  1616.         return;
  1617.     }
  1618.  
  1619.     x = 640 - 48;
  1620.     y = 480 - 48;
  1621.  
  1622.     CG_DrawPic( x, y, 48, 48, trap_R_RegisterShader("gfx/2d/net.tga" ) );
  1623. }
  1624.  
  1625.  
  1626. #define MAX_LAGOMETER_PING  900
  1627. #define MAX_LAGOMETER_RANGE 300
  1628.  
  1629. /*
  1630. ==============
  1631. CG_DrawLagometer
  1632. ==============
  1633. */
  1634. static void CG_DrawLagometer( void ) {
  1635.     int     a, x, y, i;
  1636.     float   v;
  1637.     float   ax, ay, aw, ah, mid, range;
  1638.     int     color;
  1639.     float   vscale;
  1640.  
  1641.     if ( !cg_lagometer.integer || cgs.localServer ) {
  1642.         CG_DrawDisconnect();
  1643.         return;
  1644.     }
  1645.  
  1646.     //
  1647.     // draw the graph
  1648.     //
  1649. #ifdef MISSIONPACK
  1650.     x = 640 - 48;
  1651.     y = 480 - 144;
  1652. #else
  1653.     x = 640 - 48;
  1654.     y = 480 - 48;
  1655. #endif
  1656.  
  1657.     trap_R_SetColor( NULL );
  1658.     CG_DrawPic( x, y, 48, 48, cgs.media.lagometerShader );
  1659.  
  1660.     ax = x;
  1661.     ay = y;
  1662.     aw = 48;
  1663.     ah = 48;
  1664.     CG_AdjustFrom640( &ax, &ay, &aw, &ah );
  1665.  
  1666.     color = -1;
  1667.     range = ah / 3;
  1668.     mid = ay + range;
  1669.  
  1670.     vscale = range / MAX_LAGOMETER_RANGE;
  1671.  
  1672.     // draw the frame interpoalte / extrapolate graph
  1673.     for ( a = 0 ; a < aw ; a++ ) {
  1674.         i = ( lagometer.frameCount - 1 - a ) & (LAG_SAMPLES - 1);
  1675.         v = lagometer.frameSamples[i];
  1676.         v *= vscale;
  1677.         if ( v > 0 ) {
  1678.             if ( color != 1 ) {
  1679.                 color = 1;
  1680.                 trap_R_SetColor( g_color_table[ColorIndex(COLOR_YELLOW)] );
  1681.             }
  1682.             if ( v > range ) {
  1683.                 v = range;
  1684.             }
  1685.             trap_R_DrawStretchPic ( ax + aw - a, mid - v, 1, v, 0, 0, 0, 0, cgs.media.whiteShader );
  1686.         } else if ( v < 0 ) {
  1687.             if ( color != 2 ) {
  1688.                 color = 2;
  1689.                 trap_R_SetColor( g_color_table[ColorIndex(COLOR_BLUE)] );
  1690.             }
  1691.             v = -v;
  1692.             if ( v > range ) {
  1693.                 v = range;
  1694.             }
  1695.             trap_R_DrawStretchPic( ax + aw - a, mid, 1, v, 0, 0, 0, 0, cgs.media.whiteShader );
  1696.         }
  1697.     }
  1698.  
  1699.     // draw the snapshot latency / drop graph
  1700.     range = ah / 2;
  1701.     vscale = range / MAX_LAGOMETER_PING;
  1702.  
  1703.     for ( a = 0 ; a < aw ; a++ ) {
  1704.         i = ( lagometer.snapshotCount - 1 - a ) & (LAG_SAMPLES - 1);
  1705.         v = lagometer.snapshotSamples[i];
  1706.         if ( v > 0 ) {
  1707.             if ( lagometer.snapshotFlags[i] & SNAPFLAG_RATE_DELAYED ) {
  1708.                 if ( color != 5 ) {
  1709.                     color = 5;  // YELLOW for rate delay
  1710.                     trap_R_SetColor( g_color_table[ColorIndex(COLOR_YELLOW)] );
  1711.                 }
  1712.             } else {
  1713.                 if ( color != 3 ) {
  1714.                     color = 3;
  1715.                     trap_R_SetColor( g_color_table[ColorIndex(COLOR_GREEN)] );
  1716.                 }
  1717.             }
  1718.             v = v * vscale;
  1719.             if ( v > range ) {
  1720.                 v = range;
  1721.             }
  1722.             trap_R_DrawStretchPic( ax + aw - a, ay + ah - v, 1, v, 0, 0, 0, 0, cgs.media.whiteShader );
  1723.         } else if ( v < 0 ) {
  1724.             if ( color != 4 ) {
  1725.                 color = 4;      // RED for dropped snapshots
  1726.                 trap_R_SetColor( g_color_table[ColorIndex(COLOR_RED)] );
  1727.             }
  1728.             trap_R_DrawStretchPic( ax + aw - a, ay + ah - range, 1, range, 0, 0, 0, 0, cgs.media.whiteShader );
  1729.         }
  1730.     }
  1731.  
  1732.     trap_R_SetColor( NULL );
  1733.  
  1734.     if ( cg_nopredict.integer || cg_synchronousClients.integer ) {
  1735.         CG_DrawBigString( ax, ay, "snc", 1.0 );
  1736.     }
  1737.  
  1738.     CG_DrawDisconnect();
  1739. }
  1740.  
  1741.  
  1742.  
  1743. /*
  1744. ===============================================================================
  1745.  
  1746. CENTER PRINTING
  1747.  
  1748. ===============================================================================
  1749. */
  1750.  
  1751.  
  1752. /*
  1753. ==============
  1754. CG_CenterPrint
  1755.  
  1756. Called for important messages that should stay in the center of the screen
  1757. for a few moments
  1758. ==============
  1759. */
  1760. void CG_CenterPrint( const char *str, int y, int charWidth ) {
  1761.     char    *s;
  1762.  
  1763.     Q_strncpyz( cg.centerPrint, str, sizeof(cg.centerPrint) );
  1764.  
  1765.     cg.centerPrintTime = cg.time;
  1766.     cg.centerPrintY = y;
  1767.     cg.centerPrintCharWidth = charWidth;
  1768.  
  1769.     // count the number of lines for centering
  1770.     cg.centerPrintLines = 1;
  1771.     s = cg.centerPrint;
  1772.     while( *s ) {
  1773.         if (*s == '\n')
  1774.             cg.centerPrintLines++;
  1775.         s++;
  1776.     }
  1777. }
  1778.  
  1779.  
  1780. /*
  1781. ===================
  1782. CG_DrawCenterString
  1783. ===================
  1784. */
  1785. static void CG_DrawCenterString( void ) {
  1786.     char    *start;
  1787.     int     l;
  1788.     int     x, y, w;
  1789. #ifdef MISSIONPACK
  1790.     int h;
  1791. #endif
  1792.     float   *color;
  1793.  
  1794.     if ( !cg.centerPrintTime ) {
  1795.         return;
  1796.     }
  1797.  
  1798.     color = CG_FadeColor( cg.centerPrintTime, 1000 * cg_centertime.value );
  1799.     if ( !color ) {
  1800.         return;
  1801.     }
  1802.  
  1803.     trap_R_SetColor( color );
  1804.  
  1805.     start = cg.centerPrint;
  1806.  
  1807.     y = cg.centerPrintY - cg.centerPrintLines * BIGCHAR_HEIGHT / 2;
  1808.  
  1809.     while ( 1 ) {
  1810.         char linebuffer[1024];
  1811.  
  1812.         for ( l = 0; l < 50; l++ ) {
  1813.             if ( !start[l] || start[l] == '\n' ) {
  1814.                 break;
  1815.             }
  1816.             linebuffer[l] = start[l];
  1817.         }
  1818.         linebuffer[l] = 0;
  1819.  
  1820. #ifdef MISSIONPACK
  1821.         w = CG_Text_Width(linebuffer, 0.5, 0);
  1822.         h = CG_Text_Height(linebuffer, 0.5, 0);
  1823.         x = (SCREEN_WIDTH - w) / 2;
  1824.         CG_Text_Paint(x, y + h, 0.5, color, linebuffer, 0, 0, ITEM_TEXTSTYLE_SHADOWEDMORE);
  1825.         y += h + 6;
  1826. #else
  1827.         w = cg.centerPrintCharWidth * CG_DrawStrlen( linebuffer );
  1828.  
  1829.         x = ( SCREEN_WIDTH - w ) / 2;
  1830.  
  1831.         CG_DrawStringExt( x, y, linebuffer, color, qfalse, qtrue,
  1832.             cg.centerPrintCharWidth, (int)(cg.centerPrintCharWidth * 1.5), 0 );
  1833.  
  1834.         y += cg.centerPrintCharWidth * 1.5;
  1835. #endif
  1836.         while ( *start && ( *start != '\n' ) ) {
  1837.             start++;
  1838.         }
  1839.         if ( !*start ) {
  1840.             break;
  1841.         }
  1842.         start++;
  1843.     }
  1844.  
  1845.     trap_R_SetColor( NULL );
  1846. }
  1847.  
  1848.  
  1849.  
  1850. /*
  1851. ================================================================================
  1852.  
  1853. CROSSHAIR
  1854.  
  1855. ================================================================================
  1856. */
  1857.  
  1858.  
  1859. /*
  1860. =================
  1861. CG_DrawCrosshair
  1862. =================
  1863. */
  1864. static void CG_DrawCrosshair(void) {
  1865.     float       w, h;
  1866.     qhandle_t   hShader;
  1867.     float       f;
  1868.     float       x, y;
  1869.     int         ca;
  1870.  
  1871.     if ( !cg_drawCrosshair.integer ) {
  1872.         return;
  1873.     }
  1874.  
  1875.     if ( cg.snap->ps.persistant[PERS_TEAM] == TEAM_SPECTATOR) {
  1876.         return;
  1877.     }
  1878.  
  1879.     if ( cg.renderingThirdPerson ) {
  1880.         return;
  1881.     }
  1882.  
  1883.     // set color based on health
  1884.     if ( cg_crosshairHealth.integer ) {
  1885.         vec4_t      hcolor;
  1886.  
  1887.         CG_ColorForHealth( hcolor );
  1888.         trap_R_SetColor( hcolor );
  1889.     } else {
  1890.         trap_R_SetColor( NULL );
  1891.     }
  1892.  
  1893.     w = h = cg_crosshairSize.value;
  1894.  
  1895.     // pulse the size of the crosshair when picking up items
  1896.     f = cg.time - cg.itemPickupBlendTime;
  1897.     if ( f > 0 && f < ITEM_BLOB_TIME ) {
  1898.         f /= ITEM_BLOB_TIME;
  1899.         w *= ( 1 + f );
  1900.         h *= ( 1 + f );
  1901.     }
  1902.  
  1903.     x = cg_crosshairX.integer;
  1904.     y = cg_crosshairY.integer;
  1905.     CG_AdjustFrom640( &x, &y, &w, &h );
  1906.  
  1907.     ca = cg_drawCrosshair.integer;
  1908.     if (ca < 0) {
  1909.         ca = 0;
  1910.     }
  1911.     hShader = cgs.media.crosshairShader[ ca % NUM_CROSSHAIRS ];
  1912.  
  1913.     trap_R_DrawStretchPic( x + cg.refdef.x + 0.5 * (cg.refdef.width - w),
  1914.         y + cg.refdef.y + 0.5 * (cg.refdef.height - h),
  1915.         w, h, 0, 0, 1, 1, hShader );
  1916. }
  1917.  
  1918.  
  1919.  
  1920. /*
  1921. =================
  1922. CG_ScanForCrosshairEntity
  1923. =================
  1924. */
  1925. static void CG_ScanForCrosshairEntity( void ) {
  1926.     trace_t     trace;
  1927.     vec3_t      start, end;
  1928.     int         content;
  1929.  
  1930.     VectorCopy( cg.refdef.vieworg, start );
  1931.     VectorMA( start, 131072, cg.refdef.viewaxis[0], end );
  1932.  
  1933.     CG_Trace( &trace, start, vec3_origin, vec3_origin, end,
  1934.         cg.snap->ps.clientNum, CONTENTS_SOLID|CONTENTS_BODY );
  1935.     if ( trace.entityNum >= MAX_CLIENTS ) {
  1936.         return;
  1937.     }
  1938.  
  1939.     // if the player is in fog, don't show it
  1940.     content = trap_CM_PointContents( trace.endpos, 0 );
  1941.     if ( content & CONTENTS_FOG ) {
  1942.         return;
  1943.     }
  1944.  
  1945.     // if the player is invisible, don't show it
  1946.     if ( cg_entities[ trace.entityNum ].currentState.powerups & ( 1 << PW_INVIS ) ) {
  1947.         return;
  1948.     }
  1949.  
  1950.     // update the fade timer
  1951.     cg.crosshairClientNum = trace.entityNum;
  1952.     cg.crosshairClientTime = cg.time;
  1953. }
  1954.  
  1955.  
  1956. /*
  1957. =====================
  1958. CG_DrawCrosshairNames
  1959. =====================
  1960. */
  1961. static void CG_DrawCrosshairNames( void ) {
  1962.     float       *color;
  1963.     char        *name;
  1964.     float       w;
  1965.  
  1966.     if ( !cg_drawCrosshair.integer ) {
  1967.         return;
  1968.     }
  1969.     if ( !cg_drawCrosshairNames.integer ) {
  1970.         return;
  1971.     }
  1972.     if ( cg.renderingThirdPerson ) {
  1973.         return;
  1974.     }
  1975.  
  1976.     // scan the known entities to see if the crosshair is sighted on one
  1977.     CG_ScanForCrosshairEntity();
  1978.  
  1979.     // draw the name of the player being looked at
  1980.     color = CG_FadeColor( cg.crosshairClientTime, 1000 );
  1981.     if ( !color ) {
  1982.         trap_R_SetColor( NULL );
  1983.         return;
  1984.     }
  1985.  
  1986.     name = cgs.clientinfo[ cg.crosshairClientNum ].name;
  1987. #ifdef MISSIONPACK
  1988.     color[3] *= 0.5f;
  1989.     w = CG_Text_Width(name, 0.3f, 0);
  1990.     CG_Text_Paint( 320 - w / 2, 190, 0.3f, color, name, 0, 0, ITEM_TEXTSTYLE_SHADOWED);
  1991. #else
  1992.     w = CG_DrawStrlen( name ) * BIGCHAR_WIDTH;
  1993.     CG_DrawBigString( 320 - w / 2, 170, name, color[3] * 0.5f );
  1994. #endif
  1995.     trap_R_SetColor( NULL );
  1996. }
  1997.  
  1998.  
  1999. //==============================================================================
  2000.  
  2001. /*
  2002. =================
  2003. CG_DrawSpectator
  2004. =================
  2005. */
  2006. static void CG_DrawSpectator(void) {
  2007.     CG_DrawBigString(320 - 9 * 8, 440, "SPECTATOR", 1.0F);
  2008.     if ( cgs.gametype == GT_TOURNAMENT ) {
  2009.         CG_DrawBigString(320 - 15 * 8, 460, "waiting to play", 1.0F);
  2010.     }
  2011.     else if ( cgs.gametype >= GT_TEAM ) {
  2012.         CG_DrawBigString(320 - 39 * 8, 460, "press ESC and use the JOIN menu to play", 1.0F);
  2013.     }
  2014. }
  2015.  
  2016. /*
  2017. =================
  2018. CG_DrawVote
  2019. =================
  2020. */
  2021. static void CG_DrawVote(void) {
  2022.     char    *s;
  2023.     int     sec;
  2024.  
  2025.     if ( !cgs.voteTime ) {
  2026.         return;
  2027.     }
  2028.  
  2029.     // play a talk beep whenever it is modified
  2030.     if ( cgs.voteModified ) {
  2031.         cgs.voteModified = qfalse;
  2032.         trap_S_StartLocalSound( cgs.media.talkSound, CHAN_LOCAL_SOUND );
  2033.     }
  2034.  
  2035.     sec = ( VOTE_TIME - ( cg.time - cgs.voteTime ) ) / 1000;
  2036.     if ( sec < 0 ) {
  2037.         sec = 0;
  2038.     }
  2039. #ifdef MISSIONPACK
  2040.     s = va("VOTE(%i):%s yes:%i no:%i", sec, cgs.voteString, cgs.voteYes, cgs.voteNo);
  2041.     CG_DrawSmallString( 0, 58, s, 1.0F );
  2042.     s = "or press ESC then click Vote";
  2043.     CG_DrawSmallString( 0, 58 + SMALLCHAR_HEIGHT + 2, s, 1.0F );
  2044. #else
  2045.     s = va("VOTE(%i):%s yes:%i no:%i", sec, cgs.voteString, cgs.voteYes, cgs.voteNo );
  2046.     CG_DrawSmallString( 0, 58, s, 1.0F );
  2047. #endif
  2048. }
  2049.  
  2050. /*
  2051. =================
  2052. CG_DrawTeamVote
  2053. =================
  2054. */
  2055. static void CG_DrawTeamVote(void) {
  2056.     char    *s;
  2057.     int     sec, cs_offset;
  2058.  
  2059.     if ( cgs.clientinfo->team == TEAM_RED )
  2060.         cs_offset = 0;
  2061.     else if ( cgs.clientinfo->team == TEAM_BLUE )
  2062.         cs_offset = 1;
  2063.     else
  2064.         return;
  2065.  
  2066.     if ( !cgs.teamVoteTime[cs_offset] ) {
  2067.         return;
  2068.     }
  2069.  
  2070.     // play a talk beep whenever it is modified
  2071.     if ( cgs.teamVoteModified[cs_offset] ) {
  2072.         cgs.teamVoteModified[cs_offset] = qfalse;
  2073.         trap_S_StartLocalSound( cgs.media.talkSound, CHAN_LOCAL_SOUND );
  2074.     }
  2075.  
  2076.     sec = ( VOTE_TIME - ( cg.time - cgs.teamVoteTime[cs_offset] ) ) / 1000;
  2077.     if ( sec < 0 ) {
  2078.         sec = 0;
  2079.     }
  2080.     s = va("TEAMVOTE(%i):%s yes:%i no:%i", sec, cgs.teamVoteString[cs_offset],
  2081.                             cgs.teamVoteYes[cs_offset], cgs.teamVoteNo[cs_offset] );
  2082.     CG_DrawSmallString( 0, 90, s, 1.0F );
  2083. }
  2084.  
  2085.  
  2086. static qboolean CG_DrawScoreboard( void ) {
  2087. #ifdef MISSIONPACK
  2088.     static qboolean firstTime = qtrue;
  2089.     float fade, *fadeColor;
  2090.  
  2091.     if (menuScoreboard) {
  2092.         menuScoreboard->window.flags &= ~WINDOW_FORCED;
  2093.     }
  2094.     if (cg_paused.integer) {
  2095.         cg.deferredPlayerLoading = 0;
  2096.         firstTime = qtrue;
  2097.         return qfalse;
  2098.     }
  2099.  
  2100.     // should never happen in Team Arena
  2101.     if (cgs.gametype == GT_SINGLE_PLAYER && cg.predictedPlayerState.pm_type == PM_INTERMISSION ) {
  2102.         cg.deferredPlayerLoading = 0;
  2103.         firstTime = qtrue;
  2104.         return qfalse;
  2105.     }
  2106.  
  2107.     // don't draw scoreboard during death while warmup up
  2108.     if ( cg.warmup && !cg.showScores ) {
  2109.         return qfalse;
  2110.     }
  2111.  
  2112.     if ( cg.showScores || cg.predictedPlayerState.pm_type == PM_DEAD || cg.predictedPlayerState.pm_type == PM_INTERMISSION ) {
  2113.         fade = 1.0;
  2114.         fadeColor = colorWhite;
  2115.     } else {
  2116.         fadeColor = CG_FadeColor( cg.scoreFadeTime, FADE_TIME );
  2117.         if ( !fadeColor ) {
  2118.             // next time scoreboard comes up, don't print killer
  2119.             cg.deferredPlayerLoading = 0;
  2120.             cg.killerName[0] = 0;
  2121.             firstTime = qtrue;
  2122.             return qfalse;
  2123.         }
  2124.         fade = *fadeColor;
  2125.     }                                                                                    
  2126.  
  2127.  
  2128.     if (menuScoreboard == NULL) {
  2129.         if ( cgs.gametype >= GT_TEAM ) {
  2130.             menuScoreboard = Menus_FindByName("teamscore_menu");
  2131.         } else {
  2132.             menuScoreboard = Menus_FindByName("score_menu");
  2133.         }
  2134.     }
  2135.  
  2136.     if (menuScoreboard) {
  2137.         if (firstTime) {
  2138.             CG_SetScoreSelection(menuScoreboard);
  2139.             firstTime = qfalse;
  2140.         }
  2141.         Menu_Paint(menuScoreboard, qtrue);
  2142.     }
  2143.  
  2144.     // load any models that have been deferred
  2145.     if ( ++cg.deferredPlayerLoading > 10 ) {
  2146.         CG_LoadDeferredPlayers();
  2147.     }
  2148.  
  2149.     return qtrue;
  2150. #else
  2151.     return CG_DrawOldScoreboard();
  2152. #endif
  2153. }
  2154.  
  2155. /*
  2156. =================
  2157. CG_DrawIntermission
  2158. =================
  2159. */
  2160. static void CG_DrawIntermission( void ) {
  2161. //  int key;
  2162. #ifdef MISSIONPACK
  2163.     //if (cg_singlePlayer.integer) {
  2164.     //  CG_DrawCenterString();
  2165.     //  return;
  2166.     //}
  2167. #else
  2168.     if ( cgs.gametype == GT_SINGLE_PLAYER ) {
  2169.         CG_DrawCenterString();
  2170.         return;
  2171.     }
  2172. #endif
  2173.     cg.scoreFadeTime = cg.time;
  2174.     cg.scoreBoardShowing = CG_DrawScoreboard();
  2175. }
  2176.  
  2177. /*
  2178. =================
  2179. CG_DrawFollow
  2180. =================
  2181. */
  2182. static qboolean CG_DrawFollow( void ) {
  2183.     float       x;
  2184.     vec4_t      color;
  2185.     const char  *name;
  2186.  
  2187.     if ( !(cg.snap->ps.pm_flags & PMF_FOLLOW) ) {
  2188.         return qfalse;
  2189.     }
  2190.     color[0] = 1;
  2191.     color[1] = 1;
  2192.     color[2] = 1;
  2193.     color[3] = 1;
  2194.  
  2195.  
  2196.     CG_DrawBigString( 320 - 9 * 8, 24, "following", 1.0F );
  2197.  
  2198.     name = cgs.clientinfo[ cg.snap->ps.clientNum ].name;
  2199.  
  2200.     x = 0.5 * ( 640 - GIANT_WIDTH * CG_DrawStrlen( name ) );
  2201.  
  2202.     CG_DrawStringExt( x, 40, name, color, qtrue, qtrue, GIANT_WIDTH, GIANT_HEIGHT, 0 );
  2203.  
  2204.     return qtrue;
  2205. }
  2206.  
  2207.  
  2208.  
  2209. /*
  2210. =================
  2211. CG_DrawAmmoWarning
  2212. =================
  2213. */
  2214. static void CG_DrawAmmoWarning( void ) {
  2215.     const char  *s;
  2216.     int         w;
  2217.  
  2218.     if ( cg_drawAmmoWarning.integer == 0 ) {
  2219.         return;
  2220.     }
  2221.  
  2222.     if ( !cg.lowAmmoWarning ) {
  2223.         return;
  2224.     }
  2225.  
  2226.     if ( cg.lowAmmoWarning == 2 ) {
  2227.         s = "OUT OF AMMO";
  2228.     } else {
  2229.         s = "LOW AMMO WARNING";
  2230.     }
  2231.     w = CG_DrawStrlen( s ) * BIGCHAR_WIDTH;
  2232.     CG_DrawBigString(320 - w / 2, 64, s, 1.0F);
  2233. }
  2234.  
  2235.  
  2236. #ifdef MISSIONPACK
  2237. /*
  2238. =================
  2239. CG_DrawProxWarning
  2240. =================
  2241. */
  2242. static void CG_DrawProxWarning( void ) {
  2243.     char s [32];
  2244.     int         w;
  2245.   static int proxTime;
  2246.   static int proxCounter;
  2247.   static int proxTick;
  2248.  
  2249.     if( !(cg.snap->ps.eFlags & EF_TICKING ) ) {
  2250.     proxTime = 0;
  2251.         return;
  2252.     }
  2253.  
  2254.   if (proxTime == 0) {
  2255.     proxTime = cg.time + 5000;
  2256.     proxCounter = 5;
  2257.     proxTick = 0;
  2258.   }
  2259.  
  2260.   if (cg.time > proxTime) {
  2261.     proxTick = proxCounter--;
  2262.     proxTime = cg.time + 1000;
  2263.   }
  2264.  
  2265.   if (proxTick != 0) {
  2266.     Com_sprintf(s, sizeof(s), "INTERNAL COMBUSTION IN: %i", proxTick);
  2267.   } else {
  2268.     Com_sprintf(s, sizeof(s), "YOU HAVE BEEN MINED");
  2269.   }
  2270.  
  2271.     w = CG_DrawStrlen( s ) * BIGCHAR_WIDTH;
  2272.     CG_DrawBigStringColor( 320 - w / 2, 64 + BIGCHAR_HEIGHT, s, g_color_table[ColorIndex(COLOR_RED)] );
  2273. }
  2274. #endif
  2275.  
  2276.  
  2277. /*
  2278. =================
  2279. CG_DrawWarmup
  2280. =================
  2281. */
  2282. static void CG_DrawWarmup( void ) {
  2283.     int         w;
  2284.     int         sec;
  2285.     int         i;
  2286.     float scale;
  2287.     clientInfo_t    *ci1, *ci2;
  2288.     int         cw;
  2289.     const char  *s;
  2290.  
  2291.     sec = cg.warmup;
  2292.     if ( !sec ) {
  2293.         return;
  2294.     }
  2295.  
  2296.     if ( sec < 0 ) {
  2297.         s = "Waiting for players";     
  2298.         w = CG_DrawStrlen( s ) * BIGCHAR_WIDTH;
  2299.         CG_DrawBigString(320 - w / 2, 24, s, 1.0F);
  2300.         cg.warmupCount = 0;
  2301.         return;
  2302.     }
  2303.  
  2304.     if (cgs.gametype == GT_TOURNAMENT) {
  2305.         // find the two active players
  2306.         ci1 = NULL;
  2307.         ci2 = NULL;
  2308.         for ( i = 0 ; i < cgs.maxclients ; i++ ) {
  2309.             if ( cgs.clientinfo[i].infoValid && cgs.clientinfo[i].team == TEAM_FREE ) {
  2310.                 if ( !ci1 ) {
  2311.                     ci1 = &cgs.clientinfo[i];
  2312.                 } else {
  2313.                     ci2 = &cgs.clientinfo[i];
  2314.                 }
  2315.             }
  2316.         }
  2317.  
  2318.         if ( ci1 && ci2 ) {
  2319.             s = va( "%s vs %s", ci1->name, ci2->name );
  2320. #ifdef MISSIONPACK
  2321.             w = CG_Text_Width(s, 0.6f, 0);
  2322.             CG_Text_Paint(320 - w / 2, 60, 0.6f, colorWhite, s, 0, 0, ITEM_TEXTSTYLE_SHADOWEDMORE);
  2323. #else
  2324.             w = CG_DrawStrlen( s );
  2325.             if ( w > 640 / GIANT_WIDTH ) {
  2326.                 cw = 640 / w;
  2327.             } else {
  2328.                 cw = GIANT_WIDTH;
  2329.             }
  2330.             CG_DrawStringExt( 320 - w * cw/2, 20,s, colorWhite,
  2331.                     qfalse, qtrue, cw, (int)(cw * 1.5f), 0 );
  2332. #endif
  2333.         }
  2334.     } else {
  2335.         if ( cgs.gametype == GT_FFA ) {
  2336.             s = "Free For All";
  2337.         } else if ( cgs.gametype == GT_TEAM ) {
  2338.             s = "Team Deathmatch";
  2339.         } else if ( cgs.gametype == GT_CTF ) {
  2340.             s = "Capture the Flag";
  2341. #ifdef MISSIONPACK
  2342.         } else if ( cgs.gametype == GT_1FCTF ) {
  2343.             s = "One Flag CTF";
  2344.         } else if ( cgs.gametype == GT_OBELISK ) {
  2345.             s = "Overload";
  2346.         } else if ( cgs.gametype == GT_HARVESTER ) {
  2347.             s = "Harvester";
  2348. #endif
  2349.         } else {
  2350.             s = "";
  2351.         }
  2352. #ifdef MISSIONPACK
  2353.         w = CG_Text_Width(s, 0.6f, 0);
  2354.         CG_Text_Paint(320 - w / 2, 90, 0.6f, colorWhite, s, 0, 0, ITEM_TEXTSTYLE_SHADOWEDMORE);
  2355. #else
  2356.         w = CG_DrawStrlen( s );
  2357.         if ( w > 640 / GIANT_WIDTH ) {
  2358.             cw = 640 / w;
  2359.         } else {
  2360.             cw = GIANT_WIDTH;
  2361.         }
  2362.         CG_DrawStringExt( 320 - w * cw/2, 25,s, colorWhite,
  2363.                 qfalse, qtrue, cw, (int)(cw * 1.1f), 0 );
  2364. #endif
  2365.     }
  2366.  
  2367.     sec = ( sec - cg.time ) / 1000;
  2368.     if ( sec < 0 ) {
  2369.         cg.warmup = 0;
  2370.         sec = 0;
  2371.     }
  2372.     s = va( "Starts in: %i", sec + 1 );
  2373.     if ( sec != cg.warmupCount ) {
  2374.         cg.warmupCount = sec;
  2375.         switch ( sec ) {
  2376.         case 0:
  2377.             trap_S_StartLocalSound( cgs.media.count1Sound, CHAN_ANNOUNCER );
  2378.             break;
  2379.         case 1:
  2380.             trap_S_StartLocalSound( cgs.media.count2Sound, CHAN_ANNOUNCER );
  2381.             break;
  2382.         case 2:
  2383.             trap_S_StartLocalSound( cgs.media.count3Sound, CHAN_ANNOUNCER );
  2384.             break;
  2385.         default:
  2386.             break;
  2387.         }
  2388.     }
  2389.     scale = 0.45f;
  2390.     switch ( cg.warmupCount ) {
  2391.     case 0:
  2392.         cw = 28;
  2393.         scale = 0.54f;
  2394.         break;
  2395.     case 1:
  2396.         cw = 24;
  2397.         scale = 0.51f;
  2398.         break;
  2399.     case 2:
  2400.         cw = 20;
  2401.         scale = 0.48f;
  2402.         break;
  2403.     default:
  2404.         cw = 16;
  2405.         scale = 0.45f;
  2406.         break;
  2407.     }
  2408.  
  2409. #ifdef MISSIONPACK
  2410.         w = CG_Text_Width(s, scale, 0);
  2411.         CG_Text_Paint(320 - w / 2, 125, scale, colorWhite, s, 0, 0, ITEM_TEXTSTYLE_SHADOWEDMORE);
  2412. #else
  2413.     w = CG_DrawStrlen( s );
  2414.     CG_DrawStringExt( 320 - w * cw/2, 70, s, colorWhite,
  2415.             qfalse, qtrue, cw, (int)(cw * 1.5), 0 );
  2416. #endif
  2417. }
  2418.  
  2419. //==================================================================================
  2420. #ifdef MISSIONPACK
  2421. /*
  2422. =================
  2423. CG_DrawTimedMenus
  2424. =================
  2425. */
  2426. void CG_DrawTimedMenus( void ) {
  2427.     if (cg.voiceTime) {
  2428.         int t = cg.time - cg.voiceTime;
  2429.         if ( t > 2500 ) {
  2430.             Menus_CloseByName("voiceMenu");
  2431.             trap_Cvar_Set("cl_conXOffset", "0");
  2432.             cg.voiceTime = 0;
  2433.         }
  2434.     }
  2435. }
  2436. #endif
  2437. /*
  2438. =================
  2439. CG_Draw2D
  2440. =================
  2441. */
  2442. static void CG_Draw2D( void ) {
  2443. #ifdef MISSIONPACK
  2444.     if (cgs.orderPending && cg.time > cgs.orderTime) {
  2445.         CG_CheckOrderPending();
  2446.     }
  2447. #endif
  2448.     // if we are taking a levelshot for the menu, don't draw anything
  2449.     if ( cg.levelShot ) {
  2450.         return;
  2451.     }
  2452.  
  2453.     if ( cg_draw2D.integer == 0 ) {
  2454.         return;
  2455.     }
  2456.  
  2457.     if ( cg.snap->ps.pm_type == PM_INTERMISSION ) {
  2458.         CG_DrawIntermission();
  2459.         return;
  2460.     }
  2461.  
  2462. /*
  2463.     if (cg.cameraMode) {
  2464.         return;
  2465.     }
  2466. */
  2467.     if ( cg.snap->ps.persistant[PERS_TEAM] == TEAM_SPECTATOR ) {
  2468.         CG_DrawSpectator();
  2469.         CG_DrawCrosshair();
  2470.         CG_DrawCrosshairNames();
  2471.     } else {
  2472.         // don't draw any status if dead or the scoreboard is being explicitly shown
  2473.         if ( !cg.showScores && cg.snap->ps.stats[STAT_HEALTH] > 0 ) {
  2474.  
  2475. #ifdef MISSIONPACK
  2476.             if ( cg_drawStatus.integer ) {
  2477.                 Menu_PaintAll();
  2478.                 CG_DrawTimedMenus();
  2479.             }
  2480. #else
  2481.             CG_DrawStatusBar();
  2482. #endif
  2483.      
  2484.             CG_DrawAmmoWarning();
  2485.  
  2486. #ifdef MISSIONPACK
  2487.             CG_DrawProxWarning();
  2488. #endif      
  2489.             CG_DrawCrosshair();
  2490.             CG_DrawCrosshairNames();
  2491.             CG_DrawWeaponSelect();
  2492.  
  2493. #ifndef MISSIONPACK
  2494.             CG_DrawHoldableItem();
  2495. #else
  2496.             //CG_DrawPersistantPowerup();
  2497. #endif
  2498.             CG_DrawReward();
  2499.         }
  2500.    
  2501.         if ( cgs.gametype >= GT_TEAM ) {
  2502. #ifndef MISSIONPACK
  2503.             CG_DrawTeamInfo();
  2504. #endif
  2505.         }
  2506.     }
  2507.  
  2508.     CG_DrawVote();
  2509.     CG_DrawTeamVote();
  2510.  
  2511.     CG_DrawLagometer();
  2512.  
  2513. #ifdef MISSIONPACK
  2514.     if (!cg_paused.integer) {
  2515.         CG_DrawUpperRight();
  2516.     }
  2517. #else
  2518.     CG_DrawUpperRight();
  2519. #endif
  2520.  
  2521. #ifndef MISSIONPACK
  2522.     CG_DrawLowerRight();
  2523.     CG_DrawLowerLeft();
  2524. #endif
  2525.  
  2526.     if ( !CG_DrawFollow() ) {
  2527.         CG_DrawWarmup();
  2528.     }
  2529.  
  2530.     // don't draw center string if scoreboard is up
  2531.     cg.scoreBoardShowing = CG_DrawScoreboard();
  2532.     if ( !cg.scoreBoardShowing) {
  2533.         CG_DrawCenterString();
  2534.     }
  2535. }
  2536.  
  2537.  
  2538. static void CG_DrawTourneyScoreboard( void ) {
  2539. #ifdef MISSIONPACK
  2540. #else
  2541.     CG_DrawOldTourneyScoreboard();
  2542. #endif
  2543. }
  2544.  
  2545. /*
  2546. =====================
  2547. CG_DrawActive
  2548.  
  2549. Perform all drawing needed to completely fill the screen
  2550. =====================
  2551. */
  2552. void CG_DrawActive( stereoFrame_t stereoView ) {
  2553.     float       separation;
  2554.     vec3_t      baseOrg;
  2555.  
  2556.     // optionally draw the info screen instead
  2557.     if ( !cg.snap ) {
  2558.         CG_DrawInformation();
  2559.         return;
  2560.     }
  2561.  
  2562.     // optionally draw the tournement scoreboard instead
  2563.     if ( cg.snap->ps.persistant[PERS_TEAM] == TEAM_SPECTATOR &&
  2564.         ( cg.snap->ps.pm_flags & PMF_SCOREBOARD ) ) {
  2565.         CG_DrawTourneyScoreboard();
  2566.         return;
  2567.     }
  2568.  
  2569.     switch ( stereoView ) {
  2570.     case STEREO_CENTER:
  2571.         separation = 0;
  2572.         break;
  2573.     case STEREO_LEFT:
  2574.         separation = -cg_stereoSeparation.value / 2;
  2575.         break;
  2576.     case STEREO_RIGHT:
  2577.         separation = cg_stereoSeparation.value / 2;
  2578.         break;
  2579.     default:
  2580.         separation = 0;
  2581.         CG_Error( "CG_DrawActive: Undefined stereoView" );
  2582.     }
  2583.  
  2584.  
  2585.     // clear around the rendered view if sized down
  2586.     CG_TileClear();
  2587.  
  2588.     // offset vieworg appropriately if we're doing stereo separation
  2589.     VectorCopy( cg.refdef.vieworg, baseOrg );
  2590.     if ( separation != 0 ) {
  2591.         VectorMA( cg.refdef.vieworg, -separation, cg.refdef.viewaxis[1], cg.refdef.vieworg );
  2592.     }
  2593.  
  2594.     // draw 3D view
  2595.     trap_R_RenderScene( &cg.refdef );
  2596.  
  2597.     // restore original viewpoint if running stereo
  2598.     if ( separation != 0 ) {
  2599.         VectorCopy( baseOrg, cg.refdef.vieworg );
  2600.     }
  2601.  
  2602.     // draw status bar and other floating elements
  2603.     CG_Draw2D();
  2604. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement