TUTORIAL 24 - Hud scoreboard
by HeffX
Ok, so Quake 3 Arena has a nice detailed scoreboard.
But what if you just need your score and your place on the scoreboard?
It's a bit irritating to break from the action to check them, so that's why
I had this idea. This tutorial will let you add a mini scoreboard right in
your hud.
First, we need to know where we want it, I thought it would be a good idea to
place it under that little score display in the lower right corner of the screen.
However, this display is a little low so we'll place this display higher. So, let's find
that piece of code. Set cgame as your active configuration and open up cg_draw.c.
We want it in the lower right corner, that code starts somewhere at line 796.
Ok! Let's start coding.
1. Adding the new function(s)
First, let's place the code, that places the mini scoreboard on the screen,
above of CG_DrawScores:
/*
=================
CG_DrawMiniScore
Draw the small scoreboard display
=================
*/
void CG_DrawMiniScore( int y, score_t *score, qboolean smallfont ) {
char string[1024];
float hcolor[4];
float color[4];
clientInfo_t *ci;
int x;
int w;
int sw;
int sh;
const char *s;
ci = &cgs.clientinfo[score->client];
// draw the score line
// Use S_COLOR_WHITE so colored names don't change score color.
Com_sprintf(string, sizeof(string),
"%s "S_COLOR_WHITE" %3i", ci->name, score->score);
// colorize line
if ( ci->team == TEAM_BLUE ) {
hcolor[0] = 0;
hcolor[1] = 0;
hcolor[2] = 1;
} else if ( ci->team == TEAM_RED ) {
hcolor[0] = 1;
hcolor[1] = 0;
hcolor[2] = 0;
} else {
hcolor[0] = 0.7;
hcolor[1] = 0.7;
hcolor[2] = 0.7;
}
hcolor[3] = 0.33;
if(smallfont)
{
sw = TINYCHAR_WIDTH;
sh = TINYCHAR_HEIGHT;
}
else
{
sw = SMALLCHAR_WIDTH;
sh = SMALLCHAR_HEIGHT;
}
x = 640;
s = va( "%s", string );
w = CG_DrawStrlen( s ) * sw + 8;
x -= w;
CG_FillRect( x+1, y, w, sh+1, hcolor );
if(smallfont)
{
color[0] = color[1] = color[2] = color[3] = 1.0;
CG_DrawStringExt( x, y, string, color, qtrue, qfalse, TINYCHAR_WIDTH, TINYCHAR_HEIGHT, 0 );
}
else
{
CG_DrawSmallString( x, y, string, 1.0 );
}
}
int CG_MakeMiniScoreboard( int y)
{
int i;
score_t *score;
int count;
int players;
clientInfo_t *ci;
qboolean smallfont;
int lineHeight;
players = 0;
count = 0;
for ( i = 0 ; i < cg.numScores ; i++ )
{
score = &cg.scores[i];
ci = &cgs.clientinfo[ score->client ];
if ( score->client < 0 || score->client >= cgs.maxclients ) {
Com_Printf( "Bad score->client: %i\n", score->client );
return 0;
}
// Don't show connecting people or spectators
if ( score->ping == -1 || ci->team == TEAM_SPECTATOR ) {
continue;
}
players++;
}
if (!players)
return 0;
if(players > 7) {
lineHeight = (TINYCHAR_HEIGHT - 4)*2+1;
smallfont = qtrue;
}
else {
lineHeight = (SMALLCHAR_HEIGHT - 8)*2+1;
smallfont = qfalse;
}
// draw (at most) the top 11 players
for ( i = 0 ; i < cg.numScores && count < 11 ; i++ )
{
score = &cg.scores[i];
ci = &cgs.clientinfo[ score->client ];
if ( score->ping == -1 || ci->team == TEAM_SPECTATOR ) {
continue;
}
CG_DrawMiniScore( y + lineHeight * count, score, smallfont);
count++;
}
return count;
}
/*
=================
CG_DrawScores
Draw the small two score display
=================
*/
static float CG_DrawScores( float y )
{
Now, let's break it down:
CG_DrawMiniScore : Places it on the screen.
If teamplay
is on it make the lines team colored,
else just white.
CG_MakeMiniScoreboard : Set's everything up.
As you can see from the comments,
it doesn't show connecting and
spectating people.
It calls CG_DrawMiniScore to write
every client's score down.
2. Calling the function
So! Now we have the code to place it on the screen, now we need
to call it somewhere, but first, place the display higher so
the scoreboard fits under.
static float CG_DrawScores( float y )
{
const char *s;
int s1, s2, score;
int x, w;
int v;
vec4_t color;
float y1;
gitem_t *item;
s1 = cgs.scores1;
s2 = cgs.scores2;
y -= BIGCHAR_HEIGHT + 8;
y -= BIGCHAR_HEIGHT * 14;
y1 = y;
Now for the call:
Go to the bottom of CG_DrawScores and place
this code:
if ( cgs.fraglimit ) {
s = va( "%2i", cgs.fraglimit );
w = CG_DrawStrlen( s ) * BIGCHAR_WIDTH + 8;
x -= w;
CG_DrawBigString( x + 4, y, s, 1.0F);
}
}
if ( cg.scoresRequestTime + 5000 < cg.time )
{
// the scores are more than five seconds out of date,
// so request new ones
cg.scoresRequestTime = cg.time;
trap_SendClientCommand( "score" );
}
CG_MakeMiniScoreboard( y + ((BIGCHAR_HEIGHT - 8)*2)+8 );
return y1 - 8;
}
The first part of this piece of code, updates the scores (every 5 sec.).
Then it does the call. If you want the scores to be updated faster, I think 2 seconds is the minimum.
3. Compile...
Now compile and run! Remember, it's client side,
so you can use it on any server that has pure server off.
I made the mini scoreboard for my own mod (P.U.F.F),
just wanted to mention that.
This tuturial is (c) Mike "HeffX" Willems.
|