home *** CD-ROM | disk | FTP | other *** search
/ Maximum CD 2000 March / maximum-cd-2000-03.iso / Quake3 Game Source / Q3AGameSource.exe / Main / cg_scoreboard.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-01-18  |  13.2 KB  |  497 lines

  1. // Copyright (C) 1999-2000 Id Software, Inc.
  2. //
  3. // cg_scoreboard -- draw the scoreboard on top of the game screen
  4. #include "cg_local.h"
  5.  
  6.  
  7. #define    SCOREBOARD_X        (16)
  8.  
  9. #define SB_HEADER            86
  10. #define SB_TOP                (SB_HEADER+32)
  11.  
  12. // Where the status bar starts, so we don't overwrite it
  13. #define SB_STATUSBAR        420
  14.  
  15. #define SB_NORMAL_HEIGHT    40
  16. #define SB_INTER_HEIGHT        16 // interleaved height
  17.  
  18. #define SB_MAXCLIENTS_NORMAL  ((SB_STATUSBAR - SB_TOP) / SB_NORMAL_HEIGHT)
  19. #define SB_MAXCLIENTS_INTER   ((SB_STATUSBAR - SB_TOP) / SB_INTER_HEIGHT - 1)
  20.  
  21. // Used when interleaved
  22.  
  23.  
  24.  
  25. #define SB_LEFT_BOTICON_X    (SCOREBOARD_X+0)
  26. #define SB_LEFT_HEAD_X        (SCOREBOARD_X+32)
  27. #define SB_RIGHT_BOTICON_X    (SCOREBOARD_X+64)
  28. #define SB_RIGHT_HEAD_X        (SCOREBOARD_X+96)
  29. // Normal
  30. #define SB_BOTICON_X        (SCOREBOARD_X+32)
  31. #define SB_HEAD_X            (SCOREBOARD_X+64)
  32.  
  33. #define SB_SCORELINE_X        128
  34.  
  35. #define SB_SCORE_X            (SB_SCORELINE_X + BIGCHAR_WIDTH) // width 6
  36. #define SB_PING_X            (SB_SCORELINE_X + 6 * BIGCHAR_WIDTH + 8) // width 5
  37. #define SB_TIME_X            (SB_SCORELINE_X + 11 * BIGCHAR_WIDTH + 8) // width 5
  38. #define SB_NAME_X            (SB_SCORELINE_X + 16 * BIGCHAR_WIDTH) // width 15
  39.  
  40. // The new and improved score board
  41. //
  42. // In cases where the number of clients is high, the score board heads are interleaved
  43. // here's the layout
  44.  
  45. //
  46. //    0   32   80  112  144   240  320  400   <-- pixel position
  47. //  bot head bot head score ping time name
  48. //  
  49. //  wins/losses are drawn on bot icon now
  50.  
  51. static qboolean localClient; // true if local client has been displayed
  52.  
  53.  
  54.                              /*
  55. =================
  56. CG_DrawScoreboard
  57. =================
  58. */
  59. static void CG_DrawClientScore( int y, score_t *score, float *color, float fade, qboolean largeFormat ) {
  60.     char    string[1024];
  61.     vec3_t    headAngles;
  62.     clientInfo_t    *ci;
  63.     int iconx, headx;
  64.  
  65.     if ( score->client < 0 || score->client >= cgs.maxclients ) {
  66.         Com_Printf( "Bad score->client: %i\n", score->client );
  67.         return;
  68.     }
  69.     
  70.     ci = &cgs.clientinfo[score->client];
  71.  
  72.     iconx = SB_BOTICON_X;
  73.     headx = SB_HEAD_X;
  74.  
  75.     // draw the handicap or bot skill marker (unless player has flag)
  76.     if ( ci->powerups & ( 1 << PW_REDFLAG ) ) {
  77.         if( largeFormat ) {
  78.             CG_DrawFlagModel( iconx, y - ( 32 - BIGCHAR_HEIGHT ) / 2, 32, 32, TEAM_RED );
  79.         }
  80.         else {
  81.             CG_DrawFlagModel( iconx, y, 16, 16, TEAM_RED );
  82.         }
  83.     } else if ( ci->powerups & ( 1 << PW_BLUEFLAG ) ) {
  84.         if( largeFormat ) {
  85.             CG_DrawFlagModel( iconx, y - ( 32 - BIGCHAR_HEIGHT ) / 2, 32, 32, TEAM_BLUE );
  86.         }
  87.         else {
  88.             CG_DrawFlagModel( iconx, y, 16, 16, TEAM_BLUE );
  89.         }
  90.     } else {
  91.         if ( ci->botSkill > 0 && ci->botSkill <= 5 ) {
  92.             if ( cg_drawIcons.integer ) {
  93.                 if( largeFormat ) {
  94.                     CG_DrawPic( iconx, y - ( 32 - BIGCHAR_HEIGHT ) / 2, 32, 32, cgs.media.botSkillShaders[ ci->botSkill - 1 ] );
  95.                 }
  96.                 else {
  97.                     CG_DrawPic( iconx, y, 16, 16, cgs.media.botSkillShaders[ ci->botSkill - 1 ] );
  98.                 }
  99.             }
  100.         } else if ( ci->handicap < 100 ) {
  101.             Com_sprintf( string, sizeof( string ), "%i", ci->handicap );
  102.             if ( cgs.gametype == GT_TOURNAMENT )
  103.                 CG_DrawSmallStringColor( iconx, y - SMALLCHAR_HEIGHT/2, string, color );
  104.             else
  105.                 CG_DrawSmallStringColor( iconx, y, string, color );
  106.         }
  107.  
  108.         // draw the wins / losses
  109.         if ( cgs.gametype == GT_TOURNAMENT ) {
  110.             Com_sprintf( string, sizeof( string ), "%i/%i", ci->wins, ci->losses );
  111.             if( ci->handicap < 100 && !ci->botSkill ) {
  112.                 CG_DrawSmallStringColor( iconx, y + SMALLCHAR_HEIGHT/2, string, color );
  113.             }
  114.             else {
  115.                 CG_DrawSmallStringColor( iconx, y, string, color );
  116.             }
  117.         }
  118.     }
  119.  
  120.     // draw the face
  121.     VectorClear( headAngles );
  122.     headAngles[YAW] = 180;
  123.     if( largeFormat ) {
  124.         CG_DrawHead( headx, y - ( ICON_SIZE - BIGCHAR_HEIGHT ) / 2, ICON_SIZE, ICON_SIZE, 
  125.             score->client, headAngles );
  126.     }
  127.     else {
  128.         CG_DrawHead( headx, y, 16, 16, score->client, headAngles );
  129.     }
  130.  
  131.     // draw the score line
  132.     if ( score->ping == -1 ) {
  133.         Com_sprintf(string, sizeof(string),
  134.             " connecting    %s", ci->name);
  135.     } else if ( ci->team == TEAM_SPECTATOR ) {
  136.         Com_sprintf(string, sizeof(string),
  137.             " SPECT %3i %4i %s", score->ping, score->time, ci->name);
  138.     } else {
  139.         Com_sprintf(string, sizeof(string),
  140.             "%5i %4i %4i %s", score->score, score->ping, score->time, ci->name);
  141.     }
  142.  
  143.     // highlight your position
  144.     if ( score->client == cg.snap->ps.clientNum ) {
  145.         float    hcolor[4];
  146.         int        rank;
  147.  
  148.         localClient = qtrue;
  149.  
  150.         if ( cg.snap->ps.persistant[PERS_TEAM] == TEAM_SPECTATOR 
  151.             || cgs.gametype >= GT_TEAM ) {
  152.             rank = -1;
  153.         } else {
  154.             rank = cg.snap->ps.persistant[PERS_RANK] & ~RANK_TIED_FLAG;
  155.         }
  156.         if ( rank == 0 ) {
  157.             hcolor[0] = 0;
  158.             hcolor[1] = 0;
  159.             hcolor[2] = 0.7;
  160.         } else if ( rank == 1 ) {
  161.             hcolor[0] = 0.7;
  162.             hcolor[1] = 0;
  163.             hcolor[2] = 0;
  164.         } else if ( rank == 2 ) {
  165.             hcolor[0] = 0.7;
  166.             hcolor[1] = 0.7;
  167.             hcolor[2] = 0;
  168.         } else {
  169.             hcolor[0] = 0.7;
  170.             hcolor[1] = 0.7;
  171.             hcolor[2] = 0.7;
  172.         }
  173.  
  174.         hcolor[3] = fade * 0.7;
  175.         CG_FillRect( SB_SCORELINE_X + BIGCHAR_WIDTH, y, 
  176.             640 - SB_SCORELINE_X - BIGCHAR_WIDTH, BIGCHAR_HEIGHT+1, hcolor );
  177.     }
  178.  
  179.     CG_DrawBigString( SB_SCORELINE_X, y, string, fade );
  180.  
  181.     // add the "ready" marker for intermission exiting
  182.     if ( cg.snap->ps.stats[ STAT_CLIENTS_READY ] & ( 1 << score->client ) ) {
  183.         CG_DrawBigStringColor( iconx, y, "READY", color );
  184.     }
  185. }
  186.  
  187. /*
  188. =================
  189. CG_TeamScoreboard
  190. =================
  191. */
  192. static int CG_TeamScoreboard( int y, team_t team, float fade, int maxClients, int lineHeight ) {
  193.     int        i;
  194.     score_t    *score;
  195.     float    color[4];
  196.     int        count;
  197.     clientInfo_t    *ci;
  198.  
  199.     color[0] = color[1] = color[2] = 1.0;
  200.     color[3] = fade;
  201.  
  202.     count = 0;
  203.  
  204.     for ( i = 0 ; i < cg.numScores && count < maxClients ; i++ ) {
  205.         score = &cg.scores[i];
  206.         ci = &cgs.clientinfo[ score->client ];
  207.  
  208.         if ( team != ci->team ) {
  209.             continue;
  210.         }
  211.  
  212.         CG_DrawClientScore( y + lineHeight * count, score, color, fade, lineHeight == SB_NORMAL_HEIGHT );
  213.  
  214.         count++;
  215.     }
  216.  
  217.     return count;
  218. }
  219.  
  220. /*
  221. =================
  222. CG_DrawScoreboard
  223.  
  224. Draw the normal in-game scoreboard
  225. =================
  226. */
  227. qboolean CG_DrawScoreboard( void ) {
  228.     int        x, y, w, i, n1, n2;
  229.     float    fade;
  230.     float    *fadeColor;
  231.     char    *s;
  232.     int maxClients;
  233.     int lineHeight;
  234.     int topBorderSize, bottomBorderSize;
  235.  
  236.     // don't draw amuthing if the menu or console is up
  237.     if ( cg_paused.integer ) {
  238.         cg.deferredPlayerLoading = 0;
  239.         return qfalse;
  240.     }
  241.  
  242.     if ( cgs.gametype == GT_SINGLE_PLAYER && cg.predictedPlayerState.pm_type == PM_INTERMISSION ) {
  243.         cg.deferredPlayerLoading = 0;
  244.         return qfalse;
  245.     }
  246.  
  247.     // don't draw scoreboard during death while warmup up
  248.     if ( cg.warmup && !cg.showScores ) {
  249.         return qfalse;
  250.     }
  251.  
  252.     if ( cg.showScores || cg.predictedPlayerState.pm_type == PM_DEAD ||
  253.          cg.predictedPlayerState.pm_type == PM_INTERMISSION ) {
  254.         fade = 1.0;
  255.         fadeColor = colorWhite;
  256.     } else {
  257.         fadeColor = CG_FadeColor( cg.scoreFadeTime, FADE_TIME );
  258.         
  259.         if ( !fadeColor ) {
  260.             // next time scoreboard comes up, don't print killer
  261.             cg.deferredPlayerLoading = 0;
  262.             cg.killerName[0] = 0;
  263.             return qfalse;
  264.         }
  265.         fade = *fadeColor;
  266.     }
  267.  
  268.  
  269.     // fragged by ... line
  270.     if ( cg.killerName[0] ) {
  271.         s = va("Fragged by %s", cg.killerName );
  272.         w = CG_DrawStrlen( s ) * BIGCHAR_WIDTH;
  273.         x = ( SCREEN_WIDTH - w ) / 2;
  274.         y = 40;
  275.         CG_DrawBigString( x, y, s, fade );
  276.     }
  277.  
  278.     // current rank
  279.     if ( cgs.gametype < GT_TEAM) {
  280.         if (cg.snap->ps.persistant[PERS_TEAM] != TEAM_SPECTATOR ) {
  281.             s = va("%s place with %i",
  282.                 CG_PlaceString( cg.snap->ps.persistant[PERS_RANK] + 1 ),
  283.                 cg.snap->ps.persistant[PERS_SCORE] );
  284.             w = CG_DrawStrlen( s ) * BIGCHAR_WIDTH;
  285.             x = ( SCREEN_WIDTH - w ) / 2;
  286.             y = 60;
  287.             CG_DrawBigString( x, y, s, fade );
  288.         }
  289.     } else {
  290.         if ( cg.teamScores[0] == cg.teamScores[1] ) {
  291.             s = va("Teams are tied at %i", cg.teamScores[0] );
  292.         } else if ( cg.teamScores[0] >= cg.teamScores[1] ) {
  293.             s = va("Red leads %i to %i",cg.teamScores[0], cg.teamScores[1] );
  294.         } else {
  295.             s = va("Blue leads %i to %i",cg.teamScores[1], cg.teamScores[0] );
  296.         }
  297.  
  298.         w = CG_DrawStrlen( s ) * BIGCHAR_WIDTH;
  299.         x = ( SCREEN_WIDTH - w ) / 2;
  300.         y = 60;
  301.         CG_DrawBigString( x, y, s, fade );
  302.     }
  303.  
  304.     // scoreboard
  305.     y = SB_HEADER;
  306.  
  307.     CG_DrawPic( SB_SCORE_X, y, 64, 32, cgs.media.scoreboardScore );
  308.     CG_DrawPic( SB_PING_X, y, 64, 32, cgs.media.scoreboardPing );
  309.     CG_DrawPic( SB_TIME_X, y, 64, 32, cgs.media.scoreboardTime );
  310.     CG_DrawPic( SB_NAME_X, y, 64, 32, cgs.media.scoreboardName );
  311.  
  312.  
  313.     y = SB_TOP;
  314.  
  315.     // If there are more than SB_MAXCLIENTS_NORMAL, use the interleaved scores
  316.     if ( cg.numScores > SB_MAXCLIENTS_NORMAL ) {
  317.         maxClients = SB_MAXCLIENTS_INTER;
  318.         lineHeight = SB_INTER_HEIGHT;
  319.         topBorderSize = 8;
  320.         bottomBorderSize = 16;
  321.     } else {
  322.         maxClients = SB_MAXCLIENTS_NORMAL;
  323.         lineHeight = SB_NORMAL_HEIGHT;
  324.         topBorderSize = 16;
  325.         bottomBorderSize = 16;
  326.     }
  327.  
  328.     localClient = qfalse;
  329.  
  330.     if ( cgs.gametype >= GT_TEAM ) {
  331.         //
  332.         // teamplay scoreboard
  333.         //
  334.         y += lineHeight/2;
  335.  
  336.         if ( cg.teamScores[0] >= cg.teamScores[1] ) {
  337.             n1 = CG_TeamScoreboard( y, TEAM_RED, fade, maxClients, lineHeight );
  338.             CG_DrawTeamBackground( 0, y - topBorderSize, 640, n1 * lineHeight + bottomBorderSize, 0.33, TEAM_RED );
  339.             y += (n1 * lineHeight) + BIGCHAR_HEIGHT;
  340.             maxClients -= n1;
  341.             n2 = CG_TeamScoreboard( y, TEAM_BLUE, fade, maxClients, lineHeight );
  342.             CG_DrawTeamBackground( 0, y - topBorderSize, 640, n2 * lineHeight + bottomBorderSize, 0.33, TEAM_BLUE );
  343.             y += (n2 * lineHeight) + BIGCHAR_HEIGHT;
  344.             maxClients -= n2;
  345.         } else {
  346.             n1 = CG_TeamScoreboard( y, TEAM_BLUE, fade, maxClients, lineHeight );
  347.             CG_DrawTeamBackground( 0, y - topBorderSize, 640, n1 * lineHeight + bottomBorderSize, 0.33, TEAM_BLUE );
  348.             y += (n1 * lineHeight) + BIGCHAR_HEIGHT;
  349.             maxClients -= n1;
  350.             n2 = CG_TeamScoreboard( y, TEAM_RED, fade, maxClients, lineHeight );
  351.             CG_DrawTeamBackground( 0, y - topBorderSize, 640, n2 * lineHeight + bottomBorderSize, 0.33, TEAM_RED );
  352.             y += (n2 * lineHeight) + BIGCHAR_HEIGHT;
  353.             maxClients -= n2;
  354.         }
  355.         n1 = CG_TeamScoreboard( y, TEAM_SPECTATOR, fade, maxClients, lineHeight );
  356.         y += (n1 * lineHeight) + BIGCHAR_HEIGHT;
  357.  
  358.     } else {
  359.         //
  360.         // free for all scoreboard
  361.         //
  362.         n1 = CG_TeamScoreboard( y, TEAM_FREE, fade, maxClients, lineHeight );
  363.         y += (n1 * lineHeight) + BIGCHAR_HEIGHT;
  364.         n2 = CG_TeamScoreboard( y, TEAM_SPECTATOR, fade, maxClients - n1, lineHeight );
  365.         y += (n2 * lineHeight) + BIGCHAR_HEIGHT;
  366.     }
  367.  
  368.     if (!localClient) {
  369.         // draw local client at the bottom
  370.         for ( i = 0 ; i < cg.numScores ; i++ ) {
  371.             if ( cg.scores[i].client == cg.snap->ps.clientNum ) {
  372.                 CG_DrawClientScore( y, &cg.scores[i], fadeColor, fade, lineHeight == SB_NORMAL_HEIGHT );
  373.                 break;
  374.             }
  375.         }
  376.     }
  377.  
  378.     // load any models that have been deferred
  379.     if ( ++cg.deferredPlayerLoading > 10 ) {
  380.         CG_LoadDeferredPlayers();
  381.     }
  382.  
  383.     return qtrue;
  384. }
  385.  
  386. //================================================================================
  387.  
  388. /*
  389. ================
  390. CG_CenterGiantLine
  391. ================
  392. */
  393. static void CG_CenterGiantLine( float y, const char *string ) {
  394.     float        x;
  395.     vec4_t        color;
  396.  
  397.     color[0] = 1;
  398.     color[1] = 1;
  399.     color[2] = 1;
  400.     color[3] = 1;
  401.  
  402.     x = 0.5 * ( 640 - GIANT_WIDTH * CG_DrawStrlen( string ) );
  403.  
  404.     CG_DrawStringExt( x, y, string, color, qtrue, qtrue, GIANT_WIDTH, GIANT_HEIGHT, 0 );
  405. }
  406.  
  407. /*
  408. =================
  409. CG_DrawTourneyScoreboard
  410.  
  411. Draw the oversize scoreboard for tournements
  412. =================
  413. */
  414. void CG_DrawTourneyScoreboard( void ) {
  415.     const char        *s;
  416.     vec4_t            color;
  417.     int                min, tens, ones;
  418.     clientInfo_t    *ci;
  419.     int                y;
  420.     int                i;
  421.  
  422.     // request more scores regularly
  423.     if ( cg.scoresRequestTime + 2000 < cg.time ) {
  424.         cg.scoresRequestTime = cg.time;
  425.         trap_SendClientCommand( "score" );
  426.     }
  427.  
  428.     color[0] = 1;
  429.     color[1] = 1;
  430.     color[2] = 1;
  431.     color[3] = 1;
  432.  
  433.     // draw the dialog background
  434.     color[0] = color[1] = color[2] = 0;
  435.     color[3] = 1;
  436.     CG_FillRect( 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, color );
  437.  
  438.     // print the mesage of the day
  439.     s = CG_ConfigString( CS_MOTD );
  440.     if ( !s[0] ) {
  441.         s = "Scoreboard";
  442.     }
  443.  
  444.     // print optional title
  445.     CG_CenterGiantLine( 8, s );
  446.  
  447.     // print server time
  448.     ones = cg.time / 1000;
  449.     min = ones / 60;
  450.     ones %= 60;
  451.     tens = ones / 10;
  452.     ones %= 10;
  453.     s = va("%i:%i%i", min, tens, ones );
  454.  
  455.     CG_CenterGiantLine( 64, s );
  456.  
  457.  
  458.     // print the two scores
  459.  
  460.     y = 160;
  461.     if ( cgs.gametype >= GT_TEAM ) {
  462.         //
  463.         // teamplay scoreboard
  464.         //
  465.         CG_DrawStringExt( 8, y, "Red Team", color, qtrue, qtrue, GIANT_WIDTH, GIANT_HEIGHT, 0 );
  466.         s = va("%i", cg.teamScores[0] );
  467.         CG_DrawStringExt( 632 - GIANT_WIDTH * strlen(s), y, s, color, qtrue, qtrue, GIANT_WIDTH, GIANT_HEIGHT, 0 );
  468.         
  469.         y += 64;
  470.  
  471.         CG_DrawStringExt( 8, y, "Blue Team", color, qtrue, qtrue, GIANT_WIDTH, GIANT_HEIGHT, 0 );
  472.         s = va("%i", cg.teamScores[1] );
  473.         CG_DrawStringExt( 632 - GIANT_WIDTH * strlen(s), y, s, color, qtrue, qtrue, GIANT_WIDTH, GIANT_HEIGHT, 0 );
  474.     } else {
  475.         //
  476.         // free for all scoreboard
  477.         //
  478.         for ( i = 0 ; i < MAX_CLIENTS ; i++ ) {
  479.             ci = &cgs.clientinfo[i];
  480.             if ( !ci->infoValid ) {
  481.                 continue;
  482.             }
  483.             if ( ci->team != TEAM_FREE ) {
  484.                 continue;
  485.             }
  486.  
  487.             CG_DrawStringExt( 8, y, ci->name, color, qtrue, qtrue, GIANT_WIDTH, GIANT_HEIGHT, 0 );
  488.             s = va("%i", ci->score );
  489.             CG_DrawStringExt( 632 - GIANT_WIDTH * strlen(s), y, s, color, qtrue, qtrue, GIANT_WIDTH, GIANT_HEIGHT, 0 );
  490.             y += 64;
  491.         }
  492.     }
  493.  
  494.  
  495. }
  496.  
  497.