Main Page | Class Hierarchy | Alphabetical List | Data Structures | Directories | File List | Data Fields | Globals

cg_scoreboard.c

Go to the documentation of this file.
00001 /*
00002 ===========================================================================
00003 Copyright (C) 1999-2005 Id Software, Inc.
00004 
00005 This file is part of Quake III Arena source code.
00006 
00007 Quake III Arena source code is free software; you can redistribute it
00008 and/or modify it under the terms of the GNU General Public License as
00009 published by the Free Software Foundation; either version 2 of the License,
00010 or (at your option) any later version.
00011 
00012 Quake III Arena source code is distributed in the hope that it will be
00013 useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
00014 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015 GNU General Public License for more details.
00016 
00017 You should have received a copy of the GNU General Public License
00018 along with Foobar; if not, write to the Free Software
00019 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
00020 ===========================================================================
00021 */
00022 //
00023 // cg_scoreboard -- draw the scoreboard on top of the game screen
00024 #include "cg_local.h"
00025 
00026 
00027 #define SCOREBOARD_X        (0)
00028 
00029 #define SB_HEADER           86
00030 #define SB_TOP              (SB_HEADER+32)
00031 
00032 // Where the status bar starts, so we don't overwrite it
00033 #define SB_STATUSBAR        420
00034 
00035 #define SB_NORMAL_HEIGHT    40
00036 #define SB_INTER_HEIGHT     16 // interleaved height
00037 
00038 #define SB_MAXCLIENTS_NORMAL  ((SB_STATUSBAR - SB_TOP) / SB_NORMAL_HEIGHT)
00039 #define SB_MAXCLIENTS_INTER   ((SB_STATUSBAR - SB_TOP) / SB_INTER_HEIGHT - 1)
00040 
00041 // Used when interleaved
00042 
00043 
00044 
00045 #define SB_LEFT_BOTICON_X   (SCOREBOARD_X+0)
00046 #define SB_LEFT_HEAD_X      (SCOREBOARD_X+32)
00047 #define SB_RIGHT_BOTICON_X  (SCOREBOARD_X+64)
00048 #define SB_RIGHT_HEAD_X     (SCOREBOARD_X+96)
00049 // Normal
00050 #define SB_BOTICON_X        (SCOREBOARD_X+32)
00051 #define SB_HEAD_X           (SCOREBOARD_X+64)
00052 
00053 #define SB_SCORELINE_X      112
00054 
00055 #define SB_RATING_WIDTH     (6 * BIGCHAR_WIDTH) // width 6
00056 #define SB_SCORE_X          (SB_SCORELINE_X + BIGCHAR_WIDTH) // width 6
00057 #define SB_RATING_X         (SB_SCORELINE_X + 6 * BIGCHAR_WIDTH) // width 6
00058 #define SB_PING_X           (SB_SCORELINE_X + 12 * BIGCHAR_WIDTH + 8) // width 5
00059 #define SB_TIME_X           (SB_SCORELINE_X + 17 * BIGCHAR_WIDTH + 8) // width 5
00060 #define SB_NAME_X           (SB_SCORELINE_X + 22 * BIGCHAR_WIDTH) // width 15
00061 
00062 // The new and improved score board
00063 //
00064 // In cases where the number of clients is high, the score board heads are interleaved
00065 // here's the layout
00066 
00067 //
00068 //  0   32   80  112  144   240  320  400   <-- pixel position
00069 //  bot head bot head score ping time name
00070 //  
00071 //  wins/losses are drawn on bot icon now
00072 
00073 static qboolean localClient; // true if local client has been displayed
00074 
00075 
00076                              /*
00077 =================
00078 CG_DrawScoreboard
00079 =================
00080 */
00081 static void CG_DrawClientScore( int y, score_t *score, float *color, float fade, qboolean largeFormat ) {
00082     char    string[1024];
00083     vec3_t  headAngles;
00084     clientInfo_t    *ci;
00085     int iconx, headx;
00086 
00087     if ( score->client < 0 || score->client >= cgs.maxclients ) {
00088         Com_Printf( "Bad score->client: %i\n", score->client );
00089         return;
00090     }
00091     
00092     ci = &cgs.clientinfo[score->client];
00093 
00094     iconx = SB_BOTICON_X + (SB_RATING_WIDTH / 2);
00095     headx = SB_HEAD_X + (SB_RATING_WIDTH / 2);
00096 
00097     // draw the handicap or bot skill marker (unless player has flag)
00098     if ( ci->powerups & ( 1 << PW_NEUTRALFLAG ) ) {
00099         if( largeFormat ) {
00100             CG_DrawFlagModel( iconx, y - ( 32 - BIGCHAR_HEIGHT ) / 2, 32, 32, TEAM_FREE, qfalse );
00101         }
00102         else {
00103             CG_DrawFlagModel( iconx, y, 16, 16, TEAM_FREE, qfalse );
00104         }
00105     } else if ( ci->powerups & ( 1 << PW_REDFLAG ) ) {
00106         if( largeFormat ) {
00107             CG_DrawFlagModel( iconx, y - ( 32 - BIGCHAR_HEIGHT ) / 2, 32, 32, TEAM_RED, qfalse );
00108         }
00109         else {
00110             CG_DrawFlagModel( iconx, y, 16, 16, TEAM_RED, qfalse );
00111         }
00112     } else if ( ci->powerups & ( 1 << PW_BLUEFLAG ) ) {
00113         if( largeFormat ) {
00114             CG_DrawFlagModel( iconx, y - ( 32 - BIGCHAR_HEIGHT ) / 2, 32, 32, TEAM_BLUE, qfalse );
00115         }
00116         else {
00117             CG_DrawFlagModel( iconx, y, 16, 16, TEAM_BLUE, qfalse );
00118         }
00119     } else {
00120         if ( ci->botSkill > 0 && ci->botSkill <= 5 ) {
00121             if ( cg_drawIcons.integer ) {
00122                 if( largeFormat ) {
00123                     CG_DrawPic( iconx, y - ( 32 - BIGCHAR_HEIGHT ) / 2, 32, 32, cgs.media.botSkillShaders[ ci->botSkill - 1 ] );
00124                 }
00125                 else {
00126                     CG_DrawPic( iconx, y, 16, 16, cgs.media.botSkillShaders[ ci->botSkill - 1 ] );
00127                 }
00128             }
00129         } else if ( ci->handicap < 100 ) {
00130             Com_sprintf( string, sizeof( string ), "%i", ci->handicap );
00131             if ( cgs.gametype == GT_TOURNAMENT )
00132                 CG_DrawSmallStringColor( iconx, y - SMALLCHAR_HEIGHT/2, string, color );
00133             else
00134                 CG_DrawSmallStringColor( iconx, y, string, color );
00135         }
00136 
00137         // draw the wins / losses
00138         if ( cgs.gametype == GT_TOURNAMENT ) {
00139             Com_sprintf( string, sizeof( string ), "%i/%i", ci->wins, ci->losses );
00140             if( ci->handicap < 100 && !ci->botSkill ) {
00141                 CG_DrawSmallStringColor( iconx, y + SMALLCHAR_HEIGHT/2, string, color );
00142             }
00143             else {
00144                 CG_DrawSmallStringColor( iconx, y, string, color );
00145             }
00146         }
00147     }
00148 
00149     // draw the face
00150     VectorClear( headAngles );
00151     headAngles[YAW] = 180;
00152     if( largeFormat ) {
00153         CG_DrawHead( headx, y - ( ICON_SIZE - BIGCHAR_HEIGHT ) / 2, ICON_SIZE, ICON_SIZE, 
00154             score->client, headAngles );
00155     }
00156     else {
00157         CG_DrawHead( headx, y, 16, 16, score->client, headAngles );
00158     }
00159 
00160 #ifdef MISSIONPACK
00161     // draw the team task
00162     if ( ci->teamTask != TEAMTASK_NONE ) {
00163         if ( ci->teamTask == TEAMTASK_OFFENSE ) {
00164             CG_DrawPic( headx + 48, y, 16, 16, cgs.media.assaultShader );
00165         }
00166         else if ( ci->teamTask == TEAMTASK_DEFENSE ) {
00167             CG_DrawPic( headx + 48, y, 16, 16, cgs.media.defendShader );
00168         }
00169     }
00170 #endif
00171     // draw the score line
00172     if ( score->ping == -1 ) {
00173         Com_sprintf(string, sizeof(string),
00174             " connecting    %s", ci->name);
00175     } else if ( ci->team == TEAM_SPECTATOR ) {
00176         Com_sprintf(string, sizeof(string),
00177             " SPECT %3i %4i %s", score->ping, score->time, ci->name);
00178     } else {
00179         Com_sprintf(string, sizeof(string),
00180             "%5i %4i %4i %s", score->score, score->ping, score->time, ci->name);
00181     }
00182 
00183     // highlight your position
00184     if ( score->client == cg.snap->ps.clientNum ) {
00185         float   hcolor[4];
00186         int     rank;
00187 
00188         localClient = qtrue;
00189 
00190         if ( cg.snap->ps.persistant[PERS_TEAM] == TEAM_SPECTATOR 
00191             || cgs.gametype >= GT_TEAM ) {
00192             rank = -1;
00193         } else {
00194             rank = cg.snap->ps.persistant[PERS_RANK] & ~RANK_TIED_FLAG;
00195         }
00196         if ( rank == 0 ) {
00197             hcolor[0] = 0;
00198             hcolor[1] = 0;
00199             hcolor[2] = 0.7f;
00200         } else if ( rank == 1 ) {
00201             hcolor[0] = 0.7f;
00202             hcolor[1] = 0;
00203             hcolor[2] = 0;
00204         } else if ( rank == 2 ) {
00205             hcolor[0] = 0.7f;
00206             hcolor[1] = 0.7f;
00207             hcolor[2] = 0;
00208         } else {
00209             hcolor[0] = 0.7f;
00210             hcolor[1] = 0.7f;
00211             hcolor[2] = 0.7f;
00212         }
00213 
00214         hcolor[3] = fade * 0.7;
00215         CG_FillRect( SB_SCORELINE_X + BIGCHAR_WIDTH + (SB_RATING_WIDTH / 2), y, 
00216             640 - SB_SCORELINE_X - BIGCHAR_WIDTH, BIGCHAR_HEIGHT+1, hcolor );
00217     }
00218 
00219     CG_DrawBigString( SB_SCORELINE_X + (SB_RATING_WIDTH / 2), y, string, fade );
00220 
00221     // add the "ready" marker for intermission exiting
00222     if ( cg.snap->ps.stats[ STAT_CLIENTS_READY ] & ( 1 << score->client ) ) {
00223         CG_DrawBigStringColor( iconx, y, "READY", color );
00224     }
00225 }
00226 
00227 /*
00228 =================
00229 CG_TeamScoreboard
00230 =================
00231 */
00232 static int CG_TeamScoreboard( int y, team_t team, float fade, int maxClients, int lineHeight ) {
00233     int     i;
00234     score_t *score;
00235     float   color[4];
00236     int     count;
00237     clientInfo_t    *ci;
00238 
00239     color[0] = color[1] = color[2] = 1.0;
00240     color[3] = fade;
00241 
00242     count = 0;
00243     for ( i = 0 ; i < cg.numScores && count < maxClients ; i++ ) {
00244         score = &cg.scores[i];
00245         ci = &cgs.clientinfo[ score->client ];
00246 
00247         if ( team != ci->team ) {
00248             continue;
00249         }
00250 
00251         CG_DrawClientScore( y + lineHeight * count, score, color, fade, lineHeight == SB_NORMAL_HEIGHT );
00252 
00253         count++;
00254     }
00255 
00256     return count;
00257 }
00258 
00259 /*
00260 =================
00261 CG_DrawScoreboard
00262 
00263 Draw the normal in-game scoreboard
00264 =================
00265 */
00266 qboolean CG_DrawOldScoreboard( void ) {
00267     int     x, y, w, i, n1, n2;
00268     float   fade;
00269     float   *fadeColor;
00270     char    *s;
00271     int maxClients;
00272     int lineHeight;
00273     int topBorderSize, bottomBorderSize;
00274 
00275     // don't draw amuthing if the menu or console is up
00276     if ( cg_paused.integer ) {
00277         cg.deferredPlayerLoading = 0;
00278         return qfalse;
00279     }
00280 
00281     if ( cgs.gametype == GT_SINGLE_PLAYER && cg.predictedPlayerState.pm_type == PM_INTERMISSION ) {
00282         cg.deferredPlayerLoading = 0;
00283         return qfalse;
00284     }
00285 
00286     // don't draw scoreboard during death while warmup up
00287     if ( cg.warmup && !cg.showScores ) {
00288         return qfalse;
00289     }
00290 
00291     if ( cg.showScores || cg.predictedPlayerState.pm_type == PM_DEAD ||
00292          cg.predictedPlayerState.pm_type == PM_INTERMISSION ) {
00293         fade = 1.0;
00294         fadeColor = colorWhite;
00295     } else {
00296         fadeColor = CG_FadeColor( cg.scoreFadeTime, FADE_TIME );
00297         
00298         if ( !fadeColor ) {
00299             // next time scoreboard comes up, don't print killer
00300             cg.deferredPlayerLoading = 0;
00301             cg.killerName[0] = 0;
00302             return qfalse;
00303         }
00304         fade = *fadeColor;
00305     }
00306 
00307 
00308     // fragged by ... line
00309     if ( cg.killerName[0] ) {
00310         s = va("Fragged by %s", cg.killerName );
00311         w = CG_DrawStrlen( s ) * BIGCHAR_WIDTH;
00312         x = ( SCREEN_WIDTH - w ) / 2;
00313         y = 40;
00314         CG_DrawBigString( x, y, s, fade );
00315     }
00316 
00317     // current rank
00318     if ( cgs.gametype < GT_TEAM) {
00319         if (cg.snap->ps.persistant[PERS_TEAM] != TEAM_SPECTATOR ) {
00320             s = va("%s place with %i",
00321                 CG_PlaceString( cg.snap->ps.persistant[PERS_RANK] + 1 ),
00322                 cg.snap->ps.persistant[PERS_SCORE] );
00323             w = CG_DrawStrlen( s ) * BIGCHAR_WIDTH;
00324             x = ( SCREEN_WIDTH - w ) / 2;
00325             y = 60;
00326             CG_DrawBigString( x, y, s, fade );
00327         }
00328     } else {
00329         if ( cg.teamScores[0] == cg.teamScores[1] ) {
00330             s = va("Teams are tied at %i", cg.teamScores[0] );
00331         } else if ( cg.teamScores[0] >= cg.teamScores[1] ) {
00332             s = va("Red leads %i to %i",cg.teamScores[0], cg.teamScores[1] );
00333         } else {
00334             s = va("Blue leads %i to %i",cg.teamScores[1], cg.teamScores[0] );
00335         }
00336 
00337         w = CG_DrawStrlen( s ) * BIGCHAR_WIDTH;
00338         x = ( SCREEN_WIDTH - w ) / 2;
00339         y = 60;
00340         CG_DrawBigString( x, y, s, fade );
00341     }
00342 
00343     // scoreboard
00344     y = SB_HEADER;
00345 
00346     CG_DrawPic( SB_SCORE_X + (SB_RATING_WIDTH / 2), y, 64, 32, cgs.media.scoreboardScore );
00347     CG_DrawPic( SB_PING_X - (SB_RATING_WIDTH / 2), y, 64, 32, cgs.media.scoreboardPing );
00348     CG_DrawPic( SB_TIME_X - (SB_RATING_WIDTH / 2), y, 64, 32, cgs.media.scoreboardTime );
00349     CG_DrawPic( SB_NAME_X - (SB_RATING_WIDTH / 2), y, 64, 32, cgs.media.scoreboardName );
00350 
00351     y = SB_TOP;
00352 
00353     // If there are more than SB_MAXCLIENTS_NORMAL, use the interleaved scores
00354     if ( cg.numScores > SB_MAXCLIENTS_NORMAL ) {
00355         maxClients = SB_MAXCLIENTS_INTER;
00356         lineHeight = SB_INTER_HEIGHT;
00357         topBorderSize = 8;
00358         bottomBorderSize = 16;
00359     } else {
00360         maxClients = SB_MAXCLIENTS_NORMAL;
00361         lineHeight = SB_NORMAL_HEIGHT;
00362         topBorderSize = 16;
00363         bottomBorderSize = 16;
00364     }
00365 
00366     localClient = qfalse;
00367 
00368     if ( cgs.gametype >= GT_TEAM ) {
00369         //
00370         // teamplay scoreboard
00371         //
00372         y += lineHeight/2;
00373 
00374         if ( cg.teamScores[0] >= cg.teamScores[1] ) {
00375             n1 = CG_TeamScoreboard( y, TEAM_RED, fade, maxClients, lineHeight );
00376             CG_DrawTeamBackground( 0, y - topBorderSize, 640, n1 * lineHeight + bottomBorderSize, 0.33f, TEAM_RED );
00377             y += (n1 * lineHeight) + BIGCHAR_HEIGHT;
00378             maxClients -= n1;
00379             n2 = CG_TeamScoreboard( y, TEAM_BLUE, fade, maxClients, lineHeight );
00380             CG_DrawTeamBackground( 0, y - topBorderSize, 640, n2 * lineHeight + bottomBorderSize, 0.33f, TEAM_BLUE );
00381             y += (n2 * lineHeight) + BIGCHAR_HEIGHT;
00382             maxClients -= n2;
00383         } else {
00384             n1 = CG_TeamScoreboard( y, TEAM_BLUE, fade, maxClients, lineHeight );
00385             CG_DrawTeamBackground( 0, y - topBorderSize, 640, n1 * lineHeight + bottomBorderSize, 0.33f, TEAM_BLUE );
00386             y += (n1 * lineHeight) + BIGCHAR_HEIGHT;
00387             maxClients -= n1;
00388             n2 = CG_TeamScoreboard( y, TEAM_RED, fade, maxClients, lineHeight );
00389             CG_DrawTeamBackground( 0, y - topBorderSize, 640, n2 * lineHeight + bottomBorderSize, 0.33f, TEAM_RED );
00390             y += (n2 * lineHeight) + BIGCHAR_HEIGHT;
00391             maxClients -= n2;
00392         }
00393         n1 = CG_TeamScoreboard( y, TEAM_SPECTATOR, fade, maxClients, lineHeight );
00394         y += (n1 * lineHeight) + BIGCHAR_HEIGHT;
00395 
00396     } else {
00397         //
00398         // free for all scoreboard
00399         //
00400         n1 = CG_TeamScoreboard( y, TEAM_FREE, fade, maxClients, lineHeight );
00401         y += (n1 * lineHeight) + BIGCHAR_HEIGHT;
00402         n2 = CG_TeamScoreboard( y, TEAM_SPECTATOR, fade, maxClients - n1, lineHeight );
00403         y += (n2 * lineHeight) + BIGCHAR_HEIGHT;
00404     }
00405 
00406     if (!localClient) {
00407         // draw local client at the bottom
00408         for ( i = 0 ; i < cg.numScores ; i++ ) {
00409             if ( cg.scores[i].client == cg.snap->ps.clientNum ) {
00410                 CG_DrawClientScore( y, &cg.scores[i], fadeColor, fade, lineHeight == SB_NORMAL_HEIGHT );
00411                 break;
00412             }
00413         }
00414     }
00415 
00416     // load any models that have been deferred
00417     if ( ++cg.deferredPlayerLoading > 10 ) {
00418         CG_LoadDeferredPlayers();
00419     }
00420 
00421     return qtrue;
00422 }
00423 
00424 //================================================================================
00425 
00426 /*
00427 ================
00428 CG_CenterGiantLine
00429 ================
00430 */
00431 static void CG_CenterGiantLine( float y, const char *string ) {
00432     float       x;
00433     vec4_t      color;
00434 
00435     color[0] = 1;
00436     color[1] = 1;
00437     color[2] = 1;
00438     color[3] = 1;
00439 
00440     x = 0.5 * ( 640 - GIANT_WIDTH * CG_DrawStrlen( string ) );
00441 
00442     CG_DrawStringExt( x, y, string, color, qtrue, qtrue, GIANT_WIDTH, GIANT_HEIGHT, 0 );
00443 }
00444 
00445 /*
00446 =================
00447 CG_DrawTourneyScoreboard
00448 
00449 Draw the oversize scoreboard for tournements
00450 =================
00451 */
00452 void CG_DrawOldTourneyScoreboard( void ) {
00453     const char      *s;
00454     vec4_t          color;
00455     int             min, tens, ones;
00456     clientInfo_t    *ci;
00457     int             y;
00458     int             i;
00459 
00460     // request more scores regularly
00461     if ( cg.scoresRequestTime + 2000 < cg.time ) {
00462         cg.scoresRequestTime = cg.time;
00463         trap_SendClientCommand( "score" );
00464     }
00465 
00466     color[0] = 1;
00467     color[1] = 1;
00468     color[2] = 1;
00469     color[3] = 1;
00470 
00471     // draw the dialog background
00472     color[0] = color[1] = color[2] = 0;
00473     color[3] = 1;
00474     CG_FillRect( 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, color );
00475 
00476     // print the mesage of the day
00477     s = CG_ConfigString( CS_MOTD );
00478     if ( !s[0] ) {
00479         s = "Scoreboard";
00480     }
00481 
00482     // print optional title
00483     CG_CenterGiantLine( 8, s );
00484 
00485     // print server time
00486     ones = cg.time / 1000;
00487     min = ones / 60;
00488     ones %= 60;
00489     tens = ones / 10;
00490     ones %= 10;
00491     s = va("%i:%i%i", min, tens, ones );
00492 
00493     CG_CenterGiantLine( 64, s );
00494 
00495 
00496     // print the two scores
00497 
00498     y = 160;
00499     if ( cgs.gametype >= GT_TEAM ) {
00500         //
00501         // teamplay scoreboard
00502         //
00503         CG_DrawStringExt( 8, y, "Red Team", color, qtrue, qtrue, GIANT_WIDTH, GIANT_HEIGHT, 0 );
00504         s = va("%i", cg.teamScores[0] );
00505         CG_DrawStringExt( 632 - GIANT_WIDTH * strlen(s), y, s, color, qtrue, qtrue, GIANT_WIDTH, GIANT_HEIGHT, 0 );
00506         
00507         y += 64;
00508 
00509         CG_DrawStringExt( 8, y, "Blue Team", color, qtrue, qtrue, GIANT_WIDTH, GIANT_HEIGHT, 0 );
00510         s = va("%i", cg.teamScores[1] );
00511         CG_DrawStringExt( 632 - GIANT_WIDTH * strlen(s), y, s, color, qtrue, qtrue, GIANT_WIDTH, GIANT_HEIGHT, 0 );
00512     } else {
00513         //
00514         // free for all scoreboard
00515         //
00516         for ( i = 0 ; i < MAX_CLIENTS ; i++ ) {
00517             ci = &cgs.clientinfo[i];
00518             if ( !ci->infoValid ) {
00519                 continue;
00520             }
00521             if ( ci->team != TEAM_FREE ) {
00522                 continue;
00523             }
00524 
00525             CG_DrawStringExt( 8, y, ci->name, color, qtrue, qtrue, GIANT_WIDTH, GIANT_HEIGHT, 0 );
00526             s = va("%i", ci->score );
00527             CG_DrawStringExt( 632 - GIANT_WIDTH * strlen(s), y, s, color, qtrue, qtrue, GIANT_WIDTH, GIANT_HEIGHT, 0 );
00528             y += 64;
00529         }
00530     }
00531 
00532 
00533 }
00534 

Generated on Thu Aug 25 12:37:24 2005 for Quake III Arena by  doxygen 1.3.9.1