/*
   Copyright (C) 1997-2001 Id Software, Inc.

   This program is free software; you can redistribute it and/or
   modify it under the terms of the GNU General Public License
   as published by the Free Software Foundation; either version 2
   of the License, or (at your option) any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

   See the GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

 */
// cg_scoreboard.c -- fixed scoreboard layouts for gametypes


#include "cg_local.h"

extern cvar_t *cg_scoreboardStats;

extern cvar_t *cg_scoreboardFont;
extern cvar_t *cg_scoreboardWidthScale;

vec4_t whiteTransparent = { 1.0f, 1.0f, 1.0f, 0.5f };
vec4_t blueTransparent = { 0.0f, 0.0f, 1.0f, 0.5f };

vec4_t colorSCBBackground = { 0.25f, 0.25f, 0.25f, 1.0f };
#define SCB_BACKGROUND_ALPHA 0.25f

#if 0
#define SCB_TEAMNAME_PIXELWIDTH ( 192 * cg_scoreboardWidthScale->value )
#define SCB_PLAYERNAME_PIXELWIDTH ( 132 * cg_scoreboardWidthScale->value )
#define SCB_MEDIUMFIELD_PIXELWIDTH ( 72 * cg_scoreboardWidthScale->value )
#define SCB_SMALLFIELD_PIXELWIDTH ( 36 * cg_scoreboardWidthScale->value )
#define SCB_TINYFIELD_PIXELWIDTH ( 24 * cg_scoreboardWidthScale->value )
#else
#define SCB_TEAMNAME_PIXELWIDTH ( 211 * cg_scoreboardWidthScale->value )
#define SCB_PLAYERNAME_PIXELWIDTH ( 145 * cg_scoreboardWidthScale->value )
#define SCB_MEDIUMFIELD_PIXELWIDTH ( 83 * cg_scoreboardWidthScale->value )
#define SCB_SMALLFIELD_PIXELWIDTH ( 40 * cg_scoreboardWidthScale->value )
#define SCB_TINYFIELD_PIXELWIDTH ( 26 * cg_scoreboardWidthScale->value )
#endif

/*
   ================
   CG_DrawBigNumbersString
   ================
 */
static void CG_DrawBigNumbersString( int x, int y, int fontwidth, int fontheight, char *string, vec4_t color )
{
	unsigned int i;
	int num;

	if( !string || !string[0] )
		return;

	for( i = 0; i < strlen( string ); i++ )
	{
		if( string[i] == '-' )
		{
			num = STAT_MINUS;
		}
		else
		{
			num = string[i] - '0';
			if( num < 0 || num > 9 ) num = 0;
		}

		trap_R_DrawStretchPic( x + ( fontwidth*i ), y, fontwidth, fontheight, 0, 0, 1, 1, color, CG_MediaShader( cgs.media.sbNums[num] ) );
	}
}

/*
   ================
   CG_PingColor
   print pings -> ping colors : 0-49 = green, 50-99 = yellow, 100+ = red
   ================
 */
static vec4_t *CG_SetPingColor( int ping )
{
	if( ping >= 0 && ping < 50 )
		return &colorGreen;
	else if( ping >= 50 && ping < 90 )
		return &colorYellow;
	else if( ping >= 90 && ping < 120 )
		return &colorOrange;
	else
		return &colorRed;
}

//===============================================================
//
//		GENERIC SCOREBOARD TABS
//
//===============================================================

// it handles all the information for all gametypes, but not all of them
// will set every field of it.
typedef enum
{
	SCBTAB_PLAYERFFA,
	SCBTAB_PLAYERRACE,
	SCBTAB_PLAYERDUEL,
	SCBTAB_PLAYERTDM,
	SCBTAB_PLAYERCTF,
	SCBTAB_SPECTATOR,
	SCBTAB_CHALLENGER,
	SCBTAB_CONNECTING,
	MAX_SCBTABS
} scbtype_t;

typedef struct
{
	scbtype_t type;
	int playernum;
	int score;
	int ping;
	int kills;
	int teamkills;
	int deaths;
	int suicides;
	int team;
	int ready;
	int dead;       // wsw : imp : added to parse
	int playerclass;        // wsw : jal : only used in ca classed gametype
	qboolean coach;
	qboolean waiting;

	unsigned int race_time;
} scb_playertab_t;

static scb_playertab_t scb_players[MAX_CLIENTS];
static int scb_playercount;

// player stats
static int scb_player_stats[2*( WEAP_TOTAL-WEAP_GUNBLADE )]; // weak strong

//================
//SCB_ColorForPlayer
//================
static float *SCB_ColorForPlayer( scb_playertab_t *player )
{
	static vec4_t playerColorTemp;

	if( player->team && player->team >= TEAM_ALPHA )
	{
		CG_TeamColor( player->team, playerColorTemp );
	}
	else
	{
		VectorCopy( colorSCBBackground, playerColorTemp );
	}

	//set alpha
	if( ISVIEWERENTITY( player->playernum + 1 ) )
	{
		playerColorTemp[3] = 0.8f;
	}
	else
	{
		playerColorTemp[3] = SCB_BACKGROUND_ALPHA;
	}

	return playerColorTemp;
}

static void SCB_ParsePlayerStats( const char **s )
{
	int i, j, weak, strong;
	int shot_weak, hit_weak, shot_strong, hit_strong, hit_total, shot_total;
	unsigned int playerNum;

	if( !s || !*s )
		return;

	playerNum = CG_ParseValue( s );
	if( cg.frame.playerState.POVnum != playerNum + 1 )
		return;

	memset( scb_player_stats, -1, sizeof( scb_player_stats ) );
	j = 0;

#define STATS_PERCENT(hit,total) ((hit) > 0 ? ((hit) == (total) ? 100 : (min( (int)( floor( ( 100.0f*(hit) ) / ( (float)(total) ) + 0.5f ) ), 99 ))) : -1)

	for( i = WEAP_GUNBLADE; i < WEAP_TOTAL; i++ )
	{
		weak = j++;
		strong = j++;
		if( i == WEAP_SHOCKWAVE )
			continue;

		// total
		shot_total = CG_ParseValue( s );
		if( shot_total == 0 )
			continue;
		hit_total = hit_strong = CG_ParseValue( s );

		shot_strong = shot_total;
		hit_strong = hit_total;
		if( i == WEAP_LASERGUN || i == WEAP_ELECTROBOLT )
		{	// strong
			shot_strong = CG_ParseValue( s );
			if( shot_strong != shot_total )
				hit_strong = CG_ParseValue( s );
		}

		// weak
		shot_weak = shot_total - shot_strong;
		hit_weak = hit_total - hit_strong;

		scb_player_stats[weak] = STATS_PERCENT(hit_weak,shot_weak);
		scb_player_stats[strong] = STATS_PERCENT(hit_strong,shot_strong);
	}

#undef STATS_PERCENT
}

static void SCB_ParseFFAPlayerTab( const char **s )
{
	if( !s || !*s )
		return;

	memset( &scb_players[scb_playercount], 0, sizeof( scb_playertab_t ) );
	scb_players[scb_playercount].type = SCBTAB_PLAYERFFA;
	scb_players[scb_playercount].playernum = CG_ParseValue( s );
	scb_players[scb_playercount].score = CG_ParseValue( s );
	scb_players[scb_playercount].ping = CG_ParseValue( s );
	scb_players[scb_playercount].ready = CG_ParseValue( s );
	scb_playercount++;
}

static void SCB_ParseRACEPlayerTab( const char **s )
{
	if( !s || !*s )
		return;

	memset( &scb_players[scb_playercount], 0, sizeof( scb_playertab_t ) );
	scb_players[scb_playercount].type = SCBTAB_PLAYERRACE;
	scb_players[scb_playercount].playernum = CG_ParseValue( s );
	scb_players[scb_playercount].race_time = CG_ParseValue( s );
	scb_players[scb_playercount].ping = CG_ParseValue( s );
	scb_players[scb_playercount].ready = CG_ParseValue( s );
	scb_playercount++;
}

static void SCB_ParseDUELPlayerTab( const char **s )
{
	if( !s || !*s )
		return;

	memset( &scb_players[scb_playercount], 0, sizeof( scb_playertab_t ) );
	scb_players[scb_playercount].type = SCBTAB_PLAYERDUEL;
	scb_players[scb_playercount].team = CG_ParseValue( s );
	scb_players[scb_playercount].playernum = CG_ParseValue( s );
	scb_players[scb_playercount].score = CG_ParseValue( s );
	scb_players[scb_playercount].kills = CG_ParseValue( s );
	scb_players[scb_playercount].deaths = CG_ParseValue( s );
	scb_players[scb_playercount].suicides = CG_ParseValue( s );
	scb_players[scb_playercount].ping = CG_ParseValue( s );
	scb_playercount++;
}

static void SCB_ParseTDMPlayerTab( const char **s, int currentTeam )
{
	if( !s || !*s )
		return;

	memset( &scb_players[scb_playercount], 0, sizeof( scb_playertab_t ) );
	scb_players[scb_playercount].type = SCBTAB_PLAYERTDM;
	scb_players[scb_playercount].playernum = CG_ParseValue( s );
	scb_players[scb_playercount].score = CG_ParseValue( s );
	scb_players[scb_playercount].kills = CG_ParseValue( s );
	scb_players[scb_playercount].deaths = CG_ParseValue( s );
	scb_players[scb_playercount].suicides = CG_ParseValue( s );
	scb_players[scb_playercount].teamkills = CG_ParseValue( s );
	scb_players[scb_playercount].ping = CG_ParseValue( s );
	scb_players[scb_playercount].ready = CG_ParseValue( s );
	scb_players[scb_playercount].coach = CG_ParseValue( s );
	scb_players[scb_playercount].team = currentTeam;
	scb_playercount++;
}

static void SCB_ParseCTFPlayerTab( const char **s, int currentTeam )
{
	if( !s || !*s )
		return;

	memset( &scb_players[scb_playercount], 0, sizeof( scb_playertab_t ) );
	scb_players[scb_playercount].type = SCBTAB_PLAYERCTF;
	scb_players[scb_playercount].playernum = CG_ParseValue( s );
	scb_players[scb_playercount].score = CG_ParseValue( s );
	scb_players[scb_playercount].ping = CG_ParseValue( s );
	scb_players[scb_playercount].ready = CG_ParseValue( s );
	scb_players[scb_playercount].coach = CG_ParseValue( s );
	scb_players[scb_playercount].team = currentTeam;
	scb_playercount++;
}

// wsw : imp : exact copy of TDM parser
static void SCB_ParseCAPlayerTab( const char **s, int currentTeam )
{
	if( !s || !*s )
		return;

	memset( &scb_players[scb_playercount], 0, sizeof( scb_playertab_t ) );
	scb_players[scb_playercount].type = SCBTAB_PLAYERTDM;
	scb_players[scb_playercount].playernum = CG_ParseValue( s );
	scb_players[scb_playercount].score = CG_ParseValue( s );
	scb_players[scb_playercount].kills = CG_ParseValue( s ); // is given damage
	scb_players[scb_playercount].playerclass = CG_ParseValue( s );
	scb_players[scb_playercount].ping = CG_ParseValue( s );

	scb_players[scb_playercount].dead = CG_ParseValue( s );
	scb_players[scb_playercount].ready = CG_ParseValue( s );

	scb_players[scb_playercount].coach = CG_ParseValue( s );

	scb_players[scb_playercount].team = currentTeam;
	scb_playercount++;
}

static void SCB_ParseSpectatorTab( const char **s )
{
	if( !s || !*s )
		return;

	memset( &scb_players[scb_playercount], 0, sizeof( scb_playertab_t ) );
	scb_players[scb_playercount].type = SCBTAB_SPECTATOR;
	scb_players[scb_playercount].team = TEAM_SPECTATOR;
	scb_players[scb_playercount].playernum = CG_ParseValue( s );
	scb_players[scb_playercount].ping = CG_ParseValue( s );
	scb_players[scb_playercount].waiting = qfalse;
	scb_playercount++;
}

static void SCB_ParseConnectingPlayerTab( const char **s )
{
	if( !s || !*s )
		return;

	memset( &scb_players[scb_playercount], 0, sizeof( scb_playertab_t ) );
	scb_players[scb_playercount].type = SCBTAB_CONNECTING;
	scb_players[scb_playercount].team = TEAM_SPECTATOR;
	scb_players[scb_playercount].playernum = CG_ParseValue( s );
	scb_players[scb_playercount].ping = 0;
	scb_players[scb_playercount].waiting = qfalse;
	scb_playercount++;
}

static void SCB_ParseChallengerTab( const char **s )
{
	if( !s || !*s )
		return;

	memset( &scb_players[scb_playercount], 0, sizeof( scb_playertab_t ) );
	scb_players[scb_playercount].type = SCBTAB_CHALLENGER;
	scb_players[scb_playercount].team = TEAM_SPECTATOR;
	scb_players[scb_playercount].playernum = CG_ParseValue( s );
	scb_players[scb_playercount].ping = CG_ParseValue( s );
	scb_players[scb_playercount].waiting = qtrue;
	scb_playercount++;
}

#define SCB_FFA_PLAYERTAB_PIXELWIDTH ( SCB_PLAYERNAME_PIXELWIDTH+SCB_MEDIUMFIELD_PIXELWIDTH+SCB_SMALLFIELD_PIXELWIDTH )
static int SCB_DrawFFAPlayerTab( scb_playertab_t *player, int x, int y, struct mufont_s *font )
{
	int xoffset = 0;
	vec4_t *pingcolor;

	//draw the box
	trap_R_DrawStretchPic( x + xoffset, y, SCB_FFA_PLAYERTAB_PIXELWIDTH, trap_SCR_strHeight( font ),
	                       0, 0, 1, 1, SCB_ColorForPlayer( player ), cgs.shaderWhite );

	//print name
	trap_SCR_DrawStringWidth( x + xoffset, y, ALIGN_LEFT_TOP, cgs.clientInfo[player->playernum].name,
	                          SCB_PLAYERNAME_PIXELWIDTH, font, colorWhite );
	xoffset += SCB_PLAYERNAME_PIXELWIDTH;

	//print score
	xoffset += SCB_MEDIUMFIELD_PIXELWIDTH;
	trap_SCR_DrawStringWidth( x + xoffset, y, ALIGN_RIGHT_TOP, va( "%i", player->score ), SCB_MEDIUMFIELD_PIXELWIDTH,
	                          font, colorYellow );

	//print ping
	xoffset += SCB_SMALLFIELD_PIXELWIDTH;
	pingcolor = CG_SetPingColor( player->ping );
	trap_SCR_DrawStringWidth( x + xoffset, y, ALIGN_RIGHT_TOP, va( "%i", player->ping ), SCB_SMALLFIELD_PIXELWIDTH,
	                          font, *pingcolor );

	//print ready
	if( cg.frame.match.state == MATCH_STATE_WARMUP && player->ready )
	{
		xoffset += SCB_MEDIUMFIELD_PIXELWIDTH;
		trap_SCR_DrawStringWidth( x + xoffset, y, ALIGN_RIGHT_TOP, "READY", SCB_MEDIUMFIELD_PIXELWIDTH, font,
		                          colorGreen );
	}

	return trap_SCR_strHeight( font );
}

#define SCB_RACE_PLAYERTAB_PIXELWIDTH ( SCB_PLAYERNAME_PIXELWIDTH+SCB_MEDIUMFIELD_PIXELWIDTH+SCB_SMALLFIELD_PIXELWIDTH+SCB_MEDIUMFIELD_PIXELWIDTH )
static int SCB_DrawRACEPlayerTab( scb_playertab_t *player, int x, int y, struct mufont_s *font )
{
	static char string[MAX_STRING_CHARS];
	vec4_t *pingcolor;
	int xoffset = 0;
	unsigned int milli, min, sec;

	//draw the box
	trap_R_DrawStretchPic( x + xoffset, y, SCB_RACE_PLAYERTAB_PIXELWIDTH, trap_SCR_strHeight( font ),
	                       0, 0, 1, 1, SCB_ColorForPlayer( player ), cgs.shaderWhite );

	//print name
	Q_snprintfz( string, sizeof( string ), "%s", cgs.clientInfo[player->playernum].name );
	trap_SCR_DrawStringWidth( x + xoffset, y, ALIGN_LEFT_TOP, string, SCB_PLAYERNAME_PIXELWIDTH, font, colorWhite );
	xoffset += SCB_PLAYERNAME_PIXELWIDTH;

	//print best lap time
	if( !player->race_time )
	{
		xoffset += SCB_MEDIUMFIELD_PIXELWIDTH;
		trap_SCR_DrawStringWidth( x + xoffset, y, ALIGN_RIGHT_TOP, "no time", SCB_MEDIUMFIELD_PIXELWIDTH, font,
		                          colorYellow );
	}
	else
	{
		// convert time into MM:SS:mmm
		milli = player->race_time;
		min = milli / 60000;
		milli -= min * 60000;
		sec = milli / 1000;
		milli -= sec * 1000;
		xoffset += SCB_MEDIUMFIELD_PIXELWIDTH;
		Q_snprintfz( string, sizeof( string ), va( "%02i:%02i.%03i", min, sec, milli ) );
		trap_SCR_DrawStringWidth( x + xoffset, y, ALIGN_RIGHT_TOP, string, SCB_MEDIUMFIELD_PIXELWIDTH, font,
		                          colorYellow );
	}

	//print ping
	xoffset += SCB_SMALLFIELD_PIXELWIDTH;
	Q_snprintfz( string, sizeof( string ), "%3i", player->ping );
	pingcolor = CG_SetPingColor( player->ping );
	trap_SCR_DrawStringWidth( x + xoffset, y, ALIGN_RIGHT_TOP, string, SCB_SMALLFIELD_PIXELWIDTH, font, *pingcolor );

	//print in_race
	xoffset += SCB_MEDIUMFIELD_PIXELWIDTH;
	Q_snprintfz( string, sizeof( string ), "%s", player->ready == 1 ? "IN RACE" : "" );
	trap_SCR_DrawStringWidth( x + xoffset, y, ALIGN_RIGHT_TOP, string, SCB_MEDIUMFIELD_PIXELWIDTH, font, colorGreen );

	return trap_SCR_strHeight( font );
}

static int SCB_DrawDUELPlayerTab( scb_playertab_t *player, int x, int y, qboolean isright, struct mufont_s *font )
{
	vec4_t tabcolor;
	vec4_t *pingcolor;
	int xname, alignname;
	int xscore;
	int scorewidth;
	int xstats;
	int xoffset = 0, yoffset = 0;
	int scoreCharSize = 48;
	struct	mufont_s *tittleFont = cgs.fontSystemBig;

	if( !player || player->team < TEAM_ALPHA || player->team > GS_MAX_TEAMS )
		return 0;

	CG_TeamColor( player->team, tabcolor );
	tabcolor[3] = SCB_BACKGROUND_ALPHA; //transparent

	scorewidth = scoreCharSize *strlen( va( "%i", player->score ) );

	if( !isright ) //left side tab
	{
		xscore = x - ( scorewidth + 8 ); // 8 is a space between tabs
		xname = x - ( scorewidth + 16 );
		alignname = ALIGN_RIGHT_BOTTOM;

		//draw box
		trap_R_DrawStretchPic( 0, y + scoreCharSize - (int)trap_SCR_strHeight( tittleFont ), x,
		                       (int)trap_SCR_strHeight( tittleFont ), 0, 0, 1, 1, tabcolor, cgs.shaderWhite );

		xstats = x - ( 16 + 2 * SCB_MEDIUMFIELD_PIXELWIDTH + 2 * SCB_SMALLFIELD_PIXELWIDTH );
	}
	else //right side tab
	{
		xscore = x + 8;
		xname = x + scorewidth + 16;
		alignname = ALIGN_LEFT_BOTTOM;

		//draw box
		trap_R_DrawStretchPic( x, y + scoreCharSize - (int)trap_SCR_strHeight( tittleFont ), cg.view.refdef.width - x,
		                       (int)trap_SCR_strHeight( tittleFont ), 0, 0, 1, 1, tabcolor, cgs.shaderWhite );

		xstats = x + 16;
	}

	yoffset = 0;

	// print score box
	CG_DrawBigNumbersString( xscore, y+yoffset, scoreCharSize, scoreCharSize, va( "%i", player->score ), colorWhite );
	yoffset += scoreCharSize;

	// print name
	trap_SCR_DrawStringWidth( xname, y + yoffset, alignname, cgs.clientInfo[player->playernum].name,
	                          SCB_TEAMNAME_PIXELWIDTH, tittleFont, colorWhite );

	// headers
	x = xstats;
	xoffset = 0;

	xoffset += SCB_SMALLFIELD_PIXELWIDTH;
	trap_SCR_DrawStringWidth( x+xoffset, y+yoffset, ALIGN_RIGHT_TOP, "Kills", SCB_SMALLFIELD_PIXELWIDTH, font,
	                          colorMdGrey );

	xoffset += SCB_MEDIUMFIELD_PIXELWIDTH;
	trap_SCR_DrawStringWidth( x+xoffset, y+yoffset, ALIGN_RIGHT_TOP, "Deaths", SCB_MEDIUMFIELD_PIXELWIDTH, font,
	                          colorMdGrey );

	xoffset += SCB_MEDIUMFIELD_PIXELWIDTH;
	trap_SCR_DrawStringWidth( x+xoffset, y+yoffset, ALIGN_RIGHT_TOP, "Suicides", SCB_MEDIUMFIELD_PIXELWIDTH, font,
	                          colorMdGrey );

	xoffset += SCB_SMALLFIELD_PIXELWIDTH;
	trap_SCR_DrawStringWidth( x+xoffset, y+yoffset, ALIGN_RIGHT_TOP, "Ping", SCB_SMALLFIELD_PIXELWIDTH, font,
	                          colorMdGrey );

	yoffset += trap_SCR_strHeight( font );

	x = xstats;
	xoffset = 0;

	//print kills
	xoffset += SCB_SMALLFIELD_PIXELWIDTH;
	trap_SCR_DrawStringWidth( x + xoffset, y + yoffset, ALIGN_RIGHT_TOP, va( "%i", player->kills ),
	                          SCB_SMALLFIELD_PIXELWIDTH, font, colorYellow );

	//print deaths
	xoffset += SCB_MEDIUMFIELD_PIXELWIDTH;
	trap_SCR_DrawStringWidth( x + xoffset, y + yoffset, ALIGN_RIGHT_TOP, va( "%i", player->deaths ),
	                          SCB_MEDIUMFIELD_PIXELWIDTH, font, colorWhite );

	//print suicides
	xoffset += SCB_MEDIUMFIELD_PIXELWIDTH;
	trap_SCR_DrawStringWidth( x + xoffset, y + yoffset, ALIGN_RIGHT_TOP, va( "%i", player->suicides ),
	                          SCB_MEDIUMFIELD_PIXELWIDTH, font, colorWhite );

	//print ping
	pingcolor = CG_SetPingColor( player->ping );
	xoffset += SCB_SMALLFIELD_PIXELWIDTH;
	trap_SCR_DrawStringWidth( x + xoffset, y + yoffset, ALIGN_RIGHT_TOP, va( "%i", player->ping ),
	                          SCB_SMALLFIELD_PIXELWIDTH, font, *pingcolor );

	//print ready in green
	if( cg.frame.match.state == MATCH_STATE_WARMUP && player->ready )
	{
		if( !isright )
		{
			trap_SCR_DrawString( x, y, ALIGN_RIGHT_TOP, "R ", font, colorGreen );
		}
		else
		{
			trap_SCR_DrawString( x + xoffset, y, ALIGN_LEFT_TOP, " R", font, colorGreen );
		}
	}

	return yoffset;
}

#define SCB_TDM_PLAYERTAB_PIXELWIDTH ( SCB_PLAYERNAME_PIXELWIDTH+SCB_SMALLFIELD_PIXELWIDTH+SCB_SMALLFIELD_PIXELWIDTH+SCB_SMALLFIELD_PIXELWIDTH )
static int SCB_DrawTDMPlayerTab( scb_playertab_t *player, int x, int y, qboolean isright, struct mufont_s *font )
{
	vec4_t *pingcolor;
	int net, xoffset = 0;

	//draw the box
	trap_R_DrawStretchPic( x + xoffset, y, SCB_TDM_PLAYERTAB_PIXELWIDTH, trap_SCR_strHeight( font ),
	                       0, 0, 1, 1, SCB_ColorForPlayer( player ), cgs.shaderWhite );

	//print name
	if( player->coach )
	{
		trap_SCR_DrawStringWidth( x + xoffset, y, ALIGN_LEFT_TOP, va( S_COLOR_GREY "[COACH]" S_COLOR_WHITE "%s", cgs.clientInfo[player->playernum].name ),
		                          SCB_PLAYERNAME_PIXELWIDTH, font, colorWhite );
	}
	else
	{
		trap_SCR_DrawStringWidth( x + xoffset, y, ALIGN_LEFT_TOP, cgs.clientInfo[player->playernum].name,
		                          SCB_PLAYERNAME_PIXELWIDTH, font, colorWhite );
	}

	xoffset += SCB_PLAYERNAME_PIXELWIDTH;

	// print score in yellow
	xoffset += SCB_SMALLFIELD_PIXELWIDTH;
	trap_SCR_DrawStringWidth( x + xoffset, y, ALIGN_RIGHT_TOP, va( "%i", player->score ), SCB_SMALLFIELD_PIXELWIDTH,
	                          font, colorYellow );

	// print netto frags in orange
	net = player->kills - player->teamkills - player->deaths;
	xoffset += SCB_SMALLFIELD_PIXELWIDTH;
	trap_SCR_DrawStringWidth( x + xoffset, y, ALIGN_RIGHT_TOP, va( "%i", net ), SCB_SMALLFIELD_PIXELWIDTH, font,
	                          ( net < 0 ) ? colorRed : colorOrange );

	// print pings
	pingcolor = CG_SetPingColor( player->ping );
	xoffset += SCB_SMALLFIELD_PIXELWIDTH;
	trap_SCR_DrawStringWidth( x + xoffset, y, ALIGN_RIGHT_TOP, va( "%i", player->ping ), SCB_SMALLFIELD_PIXELWIDTH,
	                          font, *pingcolor );

	//print ready in green
	if( cg.frame.match.state == MATCH_STATE_WARMUP && player->ready )
	{
		if( !isright )
		{
			trap_SCR_DrawString( x, y, ALIGN_RIGHT_TOP, "R ", font, colorGreen );
		}
		else
		{
			trap_SCR_DrawString( x + xoffset, y, ALIGN_LEFT_TOP, " R", font, colorGreen );
		}
	}

	return trap_SCR_strHeight( font );
}

#define SCB_CA_PLAYERTAB_PIXELWIDTH ( SCB_PLAYERNAME_PIXELWIDTH+SCB_SMALLFIELD_PIXELWIDTH+SCB_SMALLFIELD_PIXELWIDTH+SCB_SMALLFIELD_PIXELWIDTH )
static int SCB_DrawCAPlayerTab( scb_playertab_t *player, int x, int y, qboolean isright, struct mufont_s *font )
{
	vec4_t *pingcolor;
	int net, xoffset = 0;
	qboolean dead;
	char playername[64];

	dead = ( cg.frame.match.state != MATCH_STATE_WARMUP && player->dead );

	//draw the box
	trap_R_DrawStretchPic( x + xoffset, y, SCB_TDM_PLAYERTAB_PIXELWIDTH, trap_SCR_strHeight( font ),
	                       0, 0, 1, 1, SCB_ColorForPlayer( player ), cgs.shaderWhite );

	if( player->coach )
	{
		dead = qfalse;
		Q_snprintfz( playername, sizeof( playername ), S_COLOR_GREY " [COACH]" S_COLOR_WHITE " %s", cgs.clientInfo[player->playernum].name );
	}
	else
	{
		// print class if classbased (out of the box)
		switch( player->playerclass - 1 )
		{
		case 0:
			Q_snprintfz( playername, sizeof( playername ), S_COLOR_ORANGE "G" S_COLOR_WHITE " %s", cgs.clientInfo[player->playernum].name );
			break;
		case 1:
			Q_snprintfz( playername, sizeof( playername ), S_COLOR_ORANGE "C" S_COLOR_WHITE " %s", cgs.clientInfo[player->playernum].name );
			break;
		case 2:
			Q_snprintfz( playername, sizeof( playername ), S_COLOR_ORANGE "S" S_COLOR_WHITE " %s", cgs.clientInfo[player->playernum].name );
			break;
		default:
			Q_strncpyz( playername, cgs.clientInfo[player->playernum].name, sizeof( playername ) );
			break;
		}
	}

	//print name
	if( dead )
	{
		trap_SCR_DrawStringWidth( x + xoffset, y, ALIGN_LEFT_TOP,
		                          COM_RemoveColorTokensExt( playername, qtrue ), SCB_PLAYERNAME_PIXELWIDTH, font,
		                          whiteTransparent );
	}
	else
	{
		trap_SCR_DrawStringWidth( x + xoffset, y, ALIGN_LEFT_TOP, playername,
		                          SCB_PLAYERNAME_PIXELWIDTH, font, colorWhite );
	}
	xoffset += SCB_PLAYERNAME_PIXELWIDTH;

	// print score in yellow
	xoffset += SCB_SMALLFIELD_PIXELWIDTH;
	trap_SCR_DrawStringWidth( x + xoffset, y, ALIGN_RIGHT_TOP, va( "%i", player->score ), SCB_SMALLFIELD_PIXELWIDTH,
	                         font, ( dead ? whiteTransparent : colorYellow ) );

	// print given damage in orange
	net = player->kills;
	xoffset += SCB_SMALLFIELD_PIXELWIDTH;
	trap_SCR_DrawStringWidth( x + xoffset, y, ALIGN_RIGHT_TOP, va( "%i", net ), SCB_SMALLFIELD_PIXELWIDTH, font,
	                         ( dead ? whiteTransparent : ( ( net < 0 ) ? colorRed : colorOrange ) ) );

	// print pings
	pingcolor = CG_SetPingColor( player->ping );
	xoffset += SCB_SMALLFIELD_PIXELWIDTH;
	trap_SCR_DrawStringWidth( x + xoffset, y, ALIGN_RIGHT_TOP, va( "%i", player->ping ), SCB_SMALLFIELD_PIXELWIDTH,
	                         font, ( dead ? whiteTransparent : *pingcolor ) );

	//print ready in green
	if( cg.frame.match.state == MATCH_STATE_WARMUP && player->ready )
	{
		if( !isright )
		{
			trap_SCR_DrawString( x, y, ALIGN_RIGHT_TOP, "R ", font, colorGreen );
		}
		else
		{
			trap_SCR_DrawString( x + xoffset, y, ALIGN_LEFT_TOP, " R", font, colorGreen );
		}
	}

	return trap_SCR_strHeight( font );
}

#define SCB_CTF_PLAYERTAB_PIXELWIDTH ( SCB_PLAYERNAME_PIXELWIDTH+SCB_SMALLFIELD_PIXELWIDTH+SCB_SMALLFIELD_PIXELWIDTH )
static int SCB_DrawCTFPlayerTab( scb_playertab_t *player, int x, int y, qboolean isright, struct mufont_s *font )
{
	vec4_t *pingcolor;
	int xoffset = 0;

	//draw the box
	trap_R_DrawStretchPic( x + xoffset, y, SCB_CTF_PLAYERTAB_PIXELWIDTH, trap_SCR_strHeight( font ),
	                       0, 0, 1, 1, SCB_ColorForPlayer( player ), cgs.shaderWhite );

	//print name
	if( player->coach )
	{
		trap_SCR_DrawStringWidth( x + xoffset, y, ALIGN_LEFT_TOP, va( S_COLOR_GREY "[COACH]" S_COLOR_WHITE "%s", cgs.clientInfo[player->playernum].name ),
		                          SCB_PLAYERNAME_PIXELWIDTH, font, colorBlue );
	}
	else
	{
		trap_SCR_DrawStringWidth( x + xoffset, y, ALIGN_LEFT_TOP, cgs.clientInfo[player->playernum].name,
		                          SCB_PLAYERNAME_PIXELWIDTH, font, colorWhite );
	}
	xoffset += SCB_PLAYERNAME_PIXELWIDTH;

	// print score in yellow
	xoffset += SCB_SMALLFIELD_PIXELWIDTH;
	trap_SCR_DrawStringWidth( x + xoffset, y, ALIGN_RIGHT_TOP, va( "%i", player->score ), SCB_SMALLFIELD_PIXELWIDTH,
	                          font, colorYellow );

	// print pings
	pingcolor = CG_SetPingColor( player->ping );
	xoffset += SCB_SMALLFIELD_PIXELWIDTH;
	trap_SCR_DrawStringWidth( x + xoffset, y, ALIGN_RIGHT_TOP, va( "%i", player->ping ), SCB_SMALLFIELD_PIXELWIDTH,
	                          font, *pingcolor );

	//print ready in green
	if( cg.frame.match.state == MATCH_STATE_WARMUP && player->ready )
	{
		if( !isright )
		{
			trap_SCR_DrawString( x, y, ALIGN_RIGHT_TOP, "R ", font, colorGreen );
		}
		else
		{
			trap_SCR_DrawString( x + xoffset, y, ALIGN_LEFT_TOP, " R", font, colorGreen );
		}
	}

	return trap_SCR_strHeight( font );
}

#define SCB_SPECTATORTAB_PIXELWIDTH ( SCB_PLAYERNAME_PIXELWIDTH+SCB_SMALLFIELD_PIXELWIDTH )
static int SCB_DrawSpectatorTab( scb_playertab_t *player, int x, int y, int align, struct mufont_s *font )
{
	int xoffset = 0;

	x = CG_HorizontalAlignForWidth( x, align, SCB_PLAYERNAME_PIXELWIDTH + SCB_SMALLFIELD_PIXELWIDTH );
	y = CG_VerticalAlignForHeight( y, align, trap_SCR_strHeight( font ) );

	xoffset += SCB_PLAYERNAME_PIXELWIDTH;

	trap_SCR_DrawStringWidth( x + xoffset, y, ALIGN_RIGHT_TOP, cgs.clientInfo[player->playernum].name,
	                          SCB_PLAYERNAME_PIXELWIDTH, font, colorWhite );

	xoffset += SCB_SMALLFIELD_PIXELWIDTH;
	trap_SCR_DrawStringWidth( x + xoffset, y, ALIGN_RIGHT_TOP, va( "%i", player->ping ),
	                          SCB_SMALLFIELD_PIXELWIDTH, font, colorWhite );

	return trap_SCR_strHeight( font );
}

static int SCB_DrawChallengerTab( scb_playertab_t *player, int x, int y, int align, struct mufont_s *font )
{
	if( !player || player->type != SCBTAB_CHALLENGER )
		return 0;

	return SCB_DrawSpectatorTab( player, x, y, align, font );
}

static int SCB_DrawConnectingPlayerTab( scb_playertab_t *player, int x, int y, int align, struct mufont_s *font )
{
	int xoffset = 0;

	x = CG_HorizontalAlignForWidth( x, align, SCB_PLAYERNAME_PIXELWIDTH + SCB_SMALLFIELD_PIXELWIDTH );
	y = CG_VerticalAlignForHeight( y, align, trap_SCR_strHeight( font ) );

	xoffset += SCB_PLAYERNAME_PIXELWIDTH;
	trap_SCR_DrawStringWidth( x + xoffset, y, ALIGN_RIGHT_TOP, cgs.clientInfo[player->playernum].name,
	                          SCB_PLAYERNAME_PIXELWIDTH, font, colorWhite );

	xoffset += SCB_SMALLFIELD_PIXELWIDTH;
	trap_SCR_DrawStringWidth( x + xoffset, y, ALIGN_RIGHT_TOP, "...", SCB_SMALLFIELD_PIXELWIDTH, font, colorMdGrey );

	return trap_SCR_strHeight( font );
}

static void SCB_DrawSpectators( int x, int y )
{
	struct mufont_s *font = cgs.fontSystemSmall;
	int i, j, xoffset, yoffset, yoffsettemp;
	int xoffset2[3];
	qboolean challengers = qfalse, spectators = qfalse;

	// Center the Waiting to play
	xoffset = 0;
	yoffset = 0;
	yoffsettemp = 0;

	// Columns
	xoffset2[0] = -SCB_SPECTATORTAB_PIXELWIDTH - 10;
	xoffset2[1] = 0;
	xoffset2[2] = SCB_SPECTATORTAB_PIXELWIDTH + 10;

	// check if there is anyone in the challengers list
	for( i = 0; i < scb_playercount; i++ )
	{
		if( scb_players[i].type == SCBTAB_CHALLENGER )
		{
			yoffset += trap_SCR_strHeight( font );
			challengers = qtrue;
			break;
		}
	}

	if( challengers )
	{
		trap_SCR_DrawString( x + xoffset, y + yoffset, ALIGN_CENTER_TOP, "Challengers", font, colorMdGrey );
		yoffset += trap_SCR_strHeight( font );
		j = 0;

		// draw challengers tabs
		for( i = 0; i < scb_playercount; i++ )
		{
			if( scb_players[i].type == SCBTAB_CHALLENGER )
			{
				yoffsettemp = SCB_DrawChallengerTab( &scb_players[i], x + xoffset2[j % 3], y + yoffset, ALIGN_CENTER_TOP, font );

				if( j % 3 == 2 )
				{
					yoffset += yoffsettemp;
				}

				j++;
			}
		}

		if( j % 3 != 0 )
		{
			yoffset += yoffsettemp;
		}
	}

	// check if there is anyone in the spectators list
	for( i = 0; i < scb_playercount; i++ )
	{
		if( scb_players[i].type == SCBTAB_SPECTATOR || scb_players[i].type == SCBTAB_CONNECTING )
		{
			spectators = qtrue;
			yoffset += trap_SCR_strHeight( font );
			break;
		}
	}

	if( spectators )
	{
#if 0
		char spectatorsString[MAX_STRING_CHARS];
		size_t len;
		char *name;
		int fullwidth, rectwidth = SCB_SPECTATORTAB_PIXELWIDTH * 3;
		static float fscroll = 0.0f;

		spectatorsString[0] = 0;
		len = 0;

		Q_strncatz( spectatorsString, va( "%sSpectators%s - ", S_COLOR_YELLOW, S_COLOR_WHITE ), MAX_STRING_CHARS );
		len = strlen( spectatorsString );

		for( i = 0; i < scb_playercount; i++ )
		{
			if( scb_players[i].type != SCBTAB_CONNECTING && scb_players[i].type != SCBTAB_SPECTATOR )
				continue;

			name = cgs.clientInfo[scb_players[i].playernum].name;
			if( name[0] )
			{
				len += strlen( name ) + 7; // 3 spaces + line + 3 ping characters
				if( len >= MAX_STRING_CHARS )
					break;

				Q_strncatz( spectatorsString, name, MAX_STRING_CHARS );
				if( scb_players[i].type == SCBTAB_CONNECTING )
					Q_strncatz( spectatorsString, " ... - ", MAX_STRING_CHARS );
				else
					Q_strncatz( spectatorsString, va( " %3i - ", scb_players[i].ping ), MAX_STRING_CHARS );
			}
		}

		if( i )
		{
			fullwidth = trap_SCR_strWidth( spectatorsString, font, 0 );
			fscroll -= ( cg.frameTime * 50 );
			if( fscroll + fullwidth < 0 )
				fscroll = rectwidth;

			xoffset = -( rectwidth * 0.5 ); // draw centered

			trap_SCR_DrawClampString( x + xoffset + (int)fscroll, y + yoffset, spectatorsString,
			                          x + xoffset, y + yoffset, x + xoffset + rectwidth, y + yoffset + trap_SCR_strHeight( font ),
			                          font, colorWhite );
		}
#else
		trap_SCR_DrawString( x + xoffset, y + yoffset, ALIGN_CENTER_TOP, "Spectators", font, colorMdGrey );
		yoffset += trap_SCR_strHeight( font );
		j = 0;

		// draw spectator tabs
		for( i = 0; i < scb_playercount; i++ )
		{
			if( scb_players[i].type == SCBTAB_CONNECTING || scb_players[i].type == SCBTAB_SPECTATOR )
			{
				if( scb_players[i].type == SCBTAB_CONNECTING )
				{
					yoffsettemp = SCB_DrawConnectingPlayerTab( &scb_players[i], x + xoffset2[j % 3], y + yoffset, ALIGN_CENTER_TOP, font );
				}
				else
				{
					yoffsettemp = SCB_DrawSpectatorTab( &scb_players[i], x + xoffset2[j % 3], y + yoffset, ALIGN_CENTER_TOP, font );
				}

				if( j % 3 == 2 )
				{
					yoffset += yoffsettemp;
				}

				j++;
			}
		}

		if( j % 3 != 0 )
		{
			yoffset += yoffsettemp;
		}
#endif
	}
}

static int SCB_DrawPlayerStats( int x, int y )
{
	struct mufont_s *font = cgs.fontSystemSmall;
	int xoffset, yoffset, lines;
	int i, j, num_weapons, weap, xpos, width, done;
	gitem_t *it;
	char string[MAX_STRING_CHARS];
	vec4_t color = { 0.5, 0.5, 0.5, 0.5f };

	// dont display stats
	if( !cg_scoreboardStats->integer )
		return 0;

	// total number of weapon
	num_weapons = WEAP_TOTAL-WEAP_GUNBLADE;

	width = ( SCB_TINYFIELD_PIXELWIDTH + 2 * SCB_SMALLFIELD_PIXELWIDTH ) * 2 + SCB_SMALLFIELD_PIXELWIDTH;

	xpos = -8 * SCB_TINYFIELD_PIXELWIDTH/2;

	// Center the box
	xoffset = xpos;
	yoffset = trap_SCR_strHeight( font );

	// Room for header, it's actually written later if we have atleast one stat
	yoffset += trap_SCR_strHeight( font );

	lines = 0;
	for( i = 0; i < num_weapons; )
	{
		xoffset = xpos;

		// two weapons per line
		for( j = 0, done = 0; done < 2 && i + j < num_weapons; j++ )
		{
			weap = WEAP_GUNBLADE + i + j;

			if( scb_player_stats[2*( i+j )] == -1 && scb_player_stats[2*( i+j )+1] == -1 )
				continue;

			it = GS_FindItemByTag( weap );

			// short name
			//trap_R_DrawStretchPic( x + xoffset, y + yoffset, trap_SCR_strHeight(font), trap_SCR_strHeight(font),
			//	0, 0, 1, 1, colorWhite, CG_MediaShader(cgs.media.shaderWeaponIcon[i+j]) );
			Q_snprintfz( string, sizeof( string ), "%s%2s", it->color, it->short_name );
			trap_SCR_DrawStringWidth( x + xoffset, y + yoffset, ALIGN_LEFT_TOP, string, SCB_TINYFIELD_PIXELWIDTH, font, colorWhite );
			xoffset += SCB_TINYFIELD_PIXELWIDTH;

			if( weap == WEAP_LASERGUN || weap == WEAP_ELECTROBOLT )
			{
				// weak percent
				if( scb_player_stats[2*( i+j )] != -1 )
				{
					Q_snprintfz( string, sizeof( string ), "%2d%c", scb_player_stats[2*( i+j )], '%' );
					trap_SCR_DrawStringWidth( x + xoffset, y + yoffset, ALIGN_LEFT_TOP, string, SCB_SMALLFIELD_PIXELWIDTH, font, colorWhite );
				}
				xoffset += SCB_SMALLFIELD_PIXELWIDTH;

				// strong percent
				if( scb_player_stats[2*( i+j )+1] != -1 )
				{
					Q_snprintfz( string, sizeof( string ), "%2d%c", scb_player_stats[2*( i+j )+1], '%' );
					trap_SCR_DrawStringWidth( x + xoffset, y + yoffset, ALIGN_LEFT_TOP, string, SCB_SMALLFIELD_PIXELWIDTH, font, colorWhite );
				}
				xoffset += SCB_SMALLFIELD_PIXELWIDTH;
			}
			else
			{
				Q_snprintfz( string, sizeof( string ), "%2d%c", scb_player_stats[2*( i+j )+1], '%' );
				trap_SCR_DrawStringWidth( x + xoffset + SCB_SMALLFIELD_PIXELWIDTH, y + yoffset, ALIGN_CENTER_TOP, string, 2*SCB_SMALLFIELD_PIXELWIDTH, font, colorWhite );
				xoffset += 2*SCB_SMALLFIELD_PIXELWIDTH;
			}

			// separator
			xoffset += SCB_SMALLFIELD_PIXELWIDTH;
			done++;
		}

		// next line
		if( done > 0 )
		{
			lines++;
			yoffset += trap_SCR_strHeight( font );
		}

		i += j;
	}

	if( lines )
	{
		// if we drow anything, draw header and box too
		xoffset = xpos;
		yoffset = trap_SCR_strHeight( font );

		// header
		trap_SCR_DrawStringWidth( x + xoffset, y + yoffset, ALIGN_LEFT_TOP, "Weapon stats", width, font, colorMdGrey );
		yoffset += trap_SCR_strHeight( font );

		// box
		trap_R_DrawStretchPic( x + xoffset - SCB_TINYFIELD_PIXELWIDTH/2, y + yoffset, width + SCB_TINYFIELD_PIXELWIDTH,
		                       lines * trap_SCR_strHeight( font ), 0, 0, 1, 1, color, cgs.shaderWhite );

		return ( trap_SCR_strHeight( font ) * ( 2+lines ) );
	}
	else
	{
		return 0;
	}
}

//===============================================================
//
//		DUEL SCOREBOARD
//
//===============================================================

//================
//CG_UpdateDUELScoreboard
//================
static void CG_UpdateDUELScoreboard( const char *s )
{
	char *token;

	//take out the layout id
	token = COM_Parse( &s );
	if( !token[0] ) return;

	scb_playercount = 0;

	while( s )
	{
		token = COM_Parse( &s );

		if( !Q_stricmp( token, "&g" ) )
		{                        //read game name tab
		}
		else if( !Q_stricmp( token, "&p" ) )
		{                             //read a player tab
			SCB_ParseDUELPlayerTab( &s );
		}
		else if( !Q_stricmp( token, "&w" ) )
		{                             // read a waiting list player tab
			SCB_ParseChallengerTab( &s );
		}
		else if( !Q_stricmp( token, "&s" ) )
		{                             // read a spectator tab
			SCB_ParseSpectatorTab( &s );
		}
		else if( !Q_stricmp( token, "&c" ) )
		{
			SCB_ParseConnectingPlayerTab( &s );
		}
		else if( !Q_stricmp( token, "&z" ) )
		{
			SCB_ParsePlayerStats( &s );
		}
	}
}

//================
//CG_DrawDUELScoreboard
//================
static void CG_DrawDUELScoreboard( int x, int y, struct mufont_s *font )
{
	int i, xoffset, yoffset, ymaxoffset = 0;
	qboolean rightside = qfalse;

	//draw player tabs
	for( i = 0; i < scb_playercount; i++ )
	{
		yoffset = 0;
		if( rightside )
		{
			xoffset = 8;
		}
		else
		{
			xoffset = -8;
		}

		if( scb_players[i].type == SCBTAB_PLAYERDUEL )
			yoffset += SCB_DrawDUELPlayerTab( &scb_players[i], x + xoffset, y + yoffset, rightside, font );
		if( yoffset > ymaxoffset )
			ymaxoffset = yoffset;

		rightside = !rightside;
	}

	xoffset = 0;

	yoffset = ymaxoffset + trap_SCR_strHeight( font );
	yoffset += SCB_DrawPlayerStats( x + xoffset, y + yoffset );
	SCB_DrawSpectators( x + xoffset, y + yoffset );
}


//===============================================================
//
//		DM SCOREBOARD
//
//===============================================================

//================
//CG_UpdateDMScoreboard
//================
static void CG_UpdateDMScoreboard( const char *s )
{
	char *token;

	//take out the layout id
	token = COM_Parse( &s );
	if( !token[0] ) return;

	scb_playercount = 0;

	while( s )
	{
		token = COM_Parse( &s );

		if( !Q_stricmp( token, "&g" ) ) //read game name tab
		{
		}
		else if( !Q_stricmp( token, "&p" ) )
		{                             //read a player tab
			SCB_ParseFFAPlayerTab( &s );
		}
		else if( !Q_stricmp( token, "&w" ) )
		{                             // read a waiting list player tab
			SCB_ParseChallengerTab( &s );
		}
		else if( !Q_stricmp( token, "&s" ) )
		{                             //read a player tab
			SCB_ParseSpectatorTab( &s );
		}
		else if( !Q_stricmp( token, "&c" ) )
		{
			SCB_ParseConnectingPlayerTab( &s );
		}
		else if( !Q_stricmp( token, "&z" ) )
		{
			SCB_ParsePlayerStats( &s );
		}
	}
}


//================
//CG_DrawDMScoreboard
//================
static void CG_DrawDMScoreboard( int x, int y, struct mufont_s *font )
{
	int i, xoffset, yoffset;

	yoffset = 0;
	xoffset = -SCB_FFA_PLAYERTAB_PIXELWIDTH/2;

	//print name
	trap_SCR_DrawStringWidth( x + xoffset, y, ALIGN_LEFT_TOP, "Name", SCB_PLAYERNAME_PIXELWIDTH, font, colorMdGrey );
	xoffset += SCB_PLAYERNAME_PIXELWIDTH;

	//print score
	xoffset += SCB_MEDIUMFIELD_PIXELWIDTH;
	trap_SCR_DrawStringWidth( x + xoffset, y, ALIGN_RIGHT_TOP, "Score", SCB_MEDIUMFIELD_PIXELWIDTH, font, colorMdGrey );

	//print ping
	xoffset += SCB_SMALLFIELD_PIXELWIDTH;
	trap_SCR_DrawStringWidth( x + xoffset, y, ALIGN_RIGHT_TOP, "Ping", SCB_SMALLFIELD_PIXELWIDTH, font, colorMdGrey );

	yoffset += trap_SCR_strHeight( font );
	xoffset = -SCB_FFA_PLAYERTAB_PIXELWIDTH/2;

	//draw players
	for( i = 0; i < scb_playercount; i++ )
	{
		if( scb_players[i].type == SCBTAB_PLAYERFFA )
			yoffset += SCB_DrawFFAPlayerTab( &scb_players[i], x + xoffset, y + yoffset, font );
	}

	xoffset = 0;

	yoffset += trap_SCR_strHeight( font );
	yoffset += SCB_DrawPlayerStats( x + xoffset, y + yoffset );
	SCB_DrawSpectators( x + xoffset, y + yoffset );
}

//===============================================================
//
//		RACE SCOREBOARD
//
//===============================================================

//================
//CG_UpdateDMScoreboard
//================
static void CG_UpdateRACEScoreboard( const char *s )
{
	char *token;

	//take out the layout id
	token = COM_Parse( &s );
	if( !token[0] ) return;

	scb_playercount = 0;

	while( s )
	{
		token = COM_Parse( &s );

		if( !Q_stricmp( token, "&g" ) )
		{                        //read game name tab
		}
		else if( !Q_stricmp( token, "&p" ) )
		{                             //read a player tab
			SCB_ParseRACEPlayerTab( &s );
		}
		else if( !Q_stricmp( token, "&w" ) )
		{                             // read a waiting list player tab
			SCB_ParseChallengerTab( &s );
		}
		else if( !Q_stricmp( token, "&s" ) )
		{                             //read a player tab
			SCB_ParseSpectatorTab( &s );
		}
		else if( !Q_stricmp( token, "&c" ) )
		{
			SCB_ParseConnectingPlayerTab( &s );
		}
	}
}

//================
//CG_DrawRACEScoreboard
//================
static void CG_DrawRACEScoreboard( int x, int y, struct mufont_s *font )
{
	int i, xoffset = 0, yoffset;

	//yoffset at middle of the screen
	yoffset = 0;
	xoffset = -( SCB_FFA_PLAYERTAB_PIXELWIDTH/2 );

	//draw players
	for( i = 0; i < scb_playercount; i++ )
	{
		if( scb_players[i].type == SCBTAB_PLAYERRACE )
			yoffset += SCB_DrawRACEPlayerTab( &scb_players[i], x + xoffset, y + yoffset, font );
	}

	yoffset += trap_SCR_strHeight( font );
	SCB_DrawSpectators( x, y + yoffset );
}

//===============================================================
//
//		TDM SCOREBOARD
//
//===============================================================

typedef struct
{
	int teamnum;
	int teamscore;
	qboolean updated;

} cg_tdm_scoreboard_teams_t;

static cg_tdm_scoreboard_teams_t tdmteams[GS_MAX_TEAMS];

static int CG_DrawTeamTab( int team, int x, int y, qboolean isright, struct mufont_s *font )
{
	vec4_t teamcolor;
	char string[MAX_STRING_CHARS];
	int xname, alignname;
	int xscore;
	int scorewidth, scoreCharSize = 48;
	int xstats;
	int i;
	int yoffset = 0;
	struct mufont_s *tittleFont = cgs.fontSystemBig;

	CG_TeamColor( team, teamcolor );

	Q_snprintfz( string, sizeof( string ), "%i", tdmteams[team].teamscore );
	scorewidth = scoreCharSize *strlen( string );

	teamcolor[3] = SCB_BACKGROUND_ALPHA; // make transparent

	if( !isright ) //left side tab
	{
		xscore = x - ( scorewidth + 8 ); // 8 is a space between tabs
		xname = x - ( scorewidth + 16 );
		alignname = ALIGN_RIGHT_BOTTOM;

		//draw box
		trap_R_DrawStretchPic( 0, y+scoreCharSize, x, //width
		                       -( (int)trap_SCR_strHeight( tittleFont ) ), //height
		                       0, 0, 1, 1, teamcolor, cgs.shaderWhite );

		xstats = x - 16 - SCB_TDM_PLAYERTAB_PIXELWIDTH;

	}
	else
	{    //right side tab

		xscore = x + 8;
		xname = x + scorewidth + 16;
		alignname = ALIGN_LEFT_BOTTOM;

		//draw box
		trap_R_DrawStretchPic( x, y+scoreCharSize, cg.view.refdef.width - x, //width
		                       -( (int)trap_SCR_strHeight( tittleFont ) ), //height
		                       0, 0, 1, 1, teamcolor, cgs.shaderWhite );

		xstats = x + 16;
	}

	teamcolor[3] = 1.0f; // make solid

	yoffset = 0;

	// print score box
	CG_DrawBigNumbersString( xscore, y+yoffset, scoreCharSize, scoreCharSize, va( "%i", tdmteams[team].teamscore ), colorWhite );
	yoffset += scoreCharSize;

	// print name
	Q_snprintfz( string, sizeof( string ), "%s%s", GS_TeamName( team ), S_COLOR_WHITE );
	trap_SCR_DrawStringWidth( xname, y + yoffset, alignname, string, SCB_TEAMNAME_PIXELWIDTH, tittleFont, colorWhite );

	// print players header
	{
		int xheaderoffset = 0;
		trap_SCR_DrawString( xstats+xheaderoffset, y+yoffset, ALIGN_LEFT_TOP, "Name", font, colorMdGrey );
		xheaderoffset += SCB_PLAYERNAME_PIXELWIDTH;
		xheaderoffset += SCB_SMALLFIELD_PIXELWIDTH; // we align right, so, offset before writting
		trap_SCR_DrawString( xstats+xheaderoffset, y+yoffset, ALIGN_RIGHT_TOP, "Score", font, colorMdGrey );
		xheaderoffset += SCB_SMALLFIELD_PIXELWIDTH;
		trap_SCR_DrawString( xstats+xheaderoffset, y+yoffset, ALIGN_RIGHT_TOP, "Net", font, colorMdGrey );
		xheaderoffset += SCB_SMALLFIELD_PIXELWIDTH;
		trap_SCR_DrawString( xstats+xheaderoffset, y+yoffset, ALIGN_RIGHT_TOP, "Ping", font, colorMdGrey );
		//xheaderoffset += SCB_SMALLFIELD_PIXELWIDTH;

		yoffset += trap_SCR_strHeight( font );
	}

	// print all players of this team
	for( i = 0; i < scb_playercount; i++ )
	{
		if( scb_players[i].team == team )
		{
			yoffset += SCB_DrawTDMPlayerTab( &scb_players[i], xstats, y+yoffset, isright, font );
		}
	}

	return yoffset;
}

//================
//CG_UpdateTDMScoreboard
//================
static void CG_UpdateTDMScoreboard( const char *s )
{
	char *token;
	int i, cteam = 0;

	//take out the layout id
	token = COM_Parse( &s );
	if( !token[0] ) return;

	for( i = 0; i < GS_MAX_TEAMS; i++ )
		tdmteams[i].updated = qfalse;

	scb_playercount = 0;

	while( s )
	{
		token = COM_Parse( &s );

		if( !Q_stricmp( token, "&t" ) ) //read a team tab
		{
			cteam = CG_ParseValue( &s );
			if( cteam < 0 || cteam > GS_MAX_TEAMS )
				CG_Error( "Invalid team value in CTF Scoreboard" );

			tdmteams[cteam].teamnum = cteam;
			tdmteams[cteam].teamscore = CG_ParseValue( &s );
			tdmteams[cteam].updated = qtrue;
		}
		else if( !Q_stricmp( token, "&p" ) )
		{                             //read a player tab
			SCB_ParseTDMPlayerTab( &s, cteam );
		}
		else if( !Q_stricmp( token, "&w" ) )
		{                             // read a waiting list player tab
			SCB_ParseChallengerTab( &s );
		}
		else if( !Q_stricmp( token, "&s" ) )
		{                             //read a spectator tab
			SCB_ParseSpectatorTab( &s );
		}
		else if( !Q_stricmp( token, "&c" ) )
		{
			SCB_ParseConnectingPlayerTab( &s );
		}
		else if( !Q_stricmp( token, "&z" ) )
		{
			SCB_ParsePlayerStats( &s );
		}
	}
}

//================
//CG_DrawTDMScoreboard
//================
static void CG_DrawTDMScoreboard( int x, int y, struct mufont_s *font )
{
	int i, xoffset = 0, yoffset, ymaxoffset = 0;
	qboolean rightside = qfalse;

	//draw team tabs
	for( i = 0; i < GS_MAX_TEAMS; i++ )
	{
		if( !tdmteams[i].updated )
		{
			continue;
		}

		yoffset = 0;
		if( rightside )
		{
			xoffset = 8;
		}
		else
		{
			xoffset = -8;
		}

		yoffset += CG_DrawTeamTab( i, x + xoffset, y + yoffset, rightside, font );
		rightside = !rightside;
		if( yoffset > ymaxoffset )
			ymaxoffset = yoffset;

		xoffset = 0;
	}

	// so we draw the spectators below the teammembers
	// we do know how many players the biggest team has.
	yoffset = ymaxoffset + trap_SCR_strHeight( font );
	yoffset += SCB_DrawPlayerStats( x + xoffset, y + yoffset );
	SCB_DrawSpectators( x + xoffset, y + yoffset );
}


//===============================================================
//
//		CA SCOREBOARD
//
//===============================================================

// wsw : imp : exact copy of the TDM scoreboard

/*typedef struct
   {
    int			teamnum;
    int			teamscore;
    qboolean	updated;

   }cg_tdm_scoreboard_teams_t;

   static cg_tdm_scoreboard_teams_t tdmteams[GS_MAX_TEAMS];
 */
static int CG_DrawTeamTabCA( int team, int x, int y, qboolean isright, struct mufont_s *font )
{
	vec4_t teamcolor;
	char string[MAX_STRING_CHARS];
	int xname, alignname;
	int xscore;
	int scorewidth, scoreCharSize = 48;
	int xstats;
	int i;
	int yoffset = 0;
	struct mufont_s *tittleFont = cgs.fontSystemBig;

	CG_TeamColor( team, teamcolor );

	Q_snprintfz( string, sizeof( string ), "%i", tdmteams[team].teamscore );
	scorewidth = scoreCharSize *strlen( string );

	teamcolor[3] = SCB_BACKGROUND_ALPHA; // make transparent

	if( !isright ) //left side tab
	{
		xscore = x - ( scorewidth + 8 ); // 8 is a space between tabs
		xname = x - ( scorewidth + 16 );
		alignname = ALIGN_RIGHT_BOTTOM;

		//draw box
		trap_R_DrawStretchPic( 0, y+scoreCharSize, x, //width
		                       -( (int)trap_SCR_strHeight( tittleFont ) ), //height
		                       0, 0, 1, 1, teamcolor, cgs.shaderWhite );

		xstats = x - 16 - SCB_TDM_PLAYERTAB_PIXELWIDTH;

	}
	else
	{    //right side tab

		xscore = x + 8;
		xname = x + scorewidth + 16;
		alignname = ALIGN_LEFT_BOTTOM;

		//draw box
		trap_R_DrawStretchPic( x, y+scoreCharSize, cg.view.refdef.width - x, //width
		                       -( (int)trap_SCR_strHeight( tittleFont ) ), //height
		                       0, 0, 1, 1, teamcolor, cgs.shaderWhite );

		xstats = x + 16;
	}

	teamcolor[3] = 1.0f; // make solid

	yoffset = 0;

	// print score box
	CG_DrawBigNumbersString( xscore, y+yoffset, scoreCharSize, scoreCharSize, va( "%i", tdmteams[team].teamscore ), colorWhite );
	yoffset += scoreCharSize;

	// print name
	Q_snprintfz( string, sizeof( string ), "%s%s", GS_TeamName( team ), S_COLOR_WHITE );
	trap_SCR_DrawStringWidth( xname, y + yoffset, alignname, string, SCB_TEAMNAME_PIXELWIDTH, tittleFont, colorWhite );

	// print players header
	{
		int xheaderoffset = 0;
		trap_SCR_DrawString( xstats+xheaderoffset, y+yoffset, ALIGN_LEFT_TOP, "Name", font, colorMdGrey );
		xheaderoffset += SCB_PLAYERNAME_PIXELWIDTH;
		xheaderoffset += SCB_SMALLFIELD_PIXELWIDTH; // we align right, so, offset before writting
		trap_SCR_DrawString( xstats+xheaderoffset, y+yoffset, ALIGN_RIGHT_TOP, "Score", font, colorMdGrey );
		xheaderoffset += SCB_SMALLFIELD_PIXELWIDTH;
		trap_SCR_DrawString( xstats+xheaderoffset, y+yoffset, ALIGN_RIGHT_TOP, "Dmg", font, colorMdGrey ); // FIXME: "Damage" is overlapped with "Score" :P
		xheaderoffset += SCB_SMALLFIELD_PIXELWIDTH;
		trap_SCR_DrawString( xstats+xheaderoffset, y+yoffset, ALIGN_RIGHT_TOP, "Ping", font, colorMdGrey );
		//xheaderoffset += SCB_SMALLFIELD_PIXELWIDTH;

		yoffset += trap_SCR_strHeight( font );
	}

	// print all players of this team
	for( i = 0; i < scb_playercount; i++ )
	{
		if( scb_players[i].team == team )
		{
			yoffset += SCB_DrawCAPlayerTab( &scb_players[i], xstats, y+yoffset, isright, font ); // wsw : imp : the only change is this func
		}
	}

	return yoffset;
}

//================
//CG_UpdateCAScoreboard
//================
static void CG_UpdateCAScoreboard( const char *s )
{
	char *token;
	int i, cteam = 0;

	//take out the layout id
	token = COM_Parse( &s );
	if( !token[0] ) return;

	for( i = 0; i < GS_MAX_TEAMS; i++ )
		tdmteams[i].updated = qfalse;

	scb_playercount = 0;

	while( s )
	{
		token = COM_Parse( &s );

		if( !Q_stricmp( token, "&t" ) ) //read a team tab
		{
			cteam = CG_ParseValue( &s );
			if( cteam < 0 || cteam > GS_MAX_TEAMS )
				CG_Error( "Invalid team value in CTF Scoreboard" );

			tdmteams[cteam].teamnum = cteam;
			tdmteams[cteam].teamscore = CG_ParseValue( &s );
			tdmteams[cteam].updated = qtrue;
		}
		else if( !Q_stricmp( token, "&p" ) )
		{                             //read a player tab
			SCB_ParseCAPlayerTab( &s, cteam );
		}
		else if( !Q_stricmp( token, "&w" ) )
		{                             // read a waiting list player tab
			SCB_ParseChallengerTab( &s );
		}
		else if( !Q_stricmp( token, "&s" ) )
		{                             //read a spectator tab
			SCB_ParseSpectatorTab( &s );
		}
		else if( !Q_stricmp( token, "&c" ) )
		{
			SCB_ParseConnectingPlayerTab( &s );
		}
		else if( !Q_stricmp( token, "&z" ) )
		{
			SCB_ParsePlayerStats( &s );
		}
	}
}

//================
//CG_DrawCAScoreboard
//================
static void CG_DrawCAScoreboard( int x, int y, struct mufont_s *font )
{
	int i, xoffset = 0, yoffset, ymaxoffset = 0;
	qboolean rightside = qfalse;

	//draw team tabs
	for( i = 0; i < GS_MAX_TEAMS; i++ )
	{
		if( !tdmteams[i].updated )
			continue;

		yoffset = 0;
		xoffset = rightside ? 8 : -8;

		yoffset += CG_DrawTeamTabCA( i, x + xoffset, y + yoffset, rightside, font );
		rightside = !rightside;
		if( yoffset > ymaxoffset )
			ymaxoffset = yoffset;

		xoffset = 0;
	}

	// so we draw the spectators below the teammembers
	// we do know how many players the biggest team has.
	yoffset = ymaxoffset + trap_SCR_strHeight( font );
	yoffset += SCB_DrawPlayerStats( x + xoffset, y + yoffset );
	SCB_DrawSpectators( x + xoffset, y + yoffset );
}

//================
//CG_UpdateDAScoreboard
//================
static void CG_UpdateDAScoreboard( const char *s )
{
	char *token;

	//take out the layout id
	token = COM_Parse( &s );
	if( !token[0] ) return;

	scb_playercount = 0;

	while( s )
	{
		token = COM_Parse( &s );

		if( !Q_stricmp( token, "&g" ) )
		{                        //read game name tab
		}
		else if( !Q_stricmp( token, "&p" ) )
		{                             //read a player tab
			SCB_ParseDUELPlayerTab( &s );
		}
		else if( !Q_stricmp( token, "&w" ) )
		{                             // read a waiting list player tab
			SCB_ParseFFAPlayerTab( &s );
		}
		else if( !Q_stricmp( token, "&s" ) )
		{                             // read a spectator tab
			SCB_ParseSpectatorTab( &s );
		}
		else if( !Q_stricmp( token, "&c" ) )
		{
			SCB_ParseConnectingPlayerTab( &s );
		}
		else if( !Q_stricmp( token, "&z" ) )
		{
			SCB_ParsePlayerStats( &s );
		}
	}
}

//================
//CG_DrawDAScoreboard
//================
static void CG_DrawDAScoreboard( int x, int y, struct mufont_s *font )
{
	int i, xoffset = 0, yoffset = 0, ymaxoffset = 0;
	qboolean rightside = qfalse;

	
	//draw player tabs
	for( i = 0; i < scb_playercount; i++ )
	{
		yoffset = 0;
		if( rightside )
		{
			xoffset = 8;
		}
		else
		{
			xoffset = -8;
		}

		if( scb_players[i].type == SCBTAB_PLAYERDUEL )
			yoffset += SCB_DrawDUELPlayerTab( &scb_players[i], x + xoffset, y + yoffset, rightside, font );
		if( yoffset > ymaxoffset )
			ymaxoffset = yoffset;

		rightside = !rightside;
	} 

	yoffset = ymaxoffset + trap_SCR_strHeight( font );
	xoffset = -SCB_FFA_PLAYERTAB_PIXELWIDTH/2;

	//print name
	trap_SCR_DrawStringWidth( x + xoffset, y + yoffset, ALIGN_LEFT_TOP, "Name", SCB_PLAYERNAME_PIXELWIDTH, font, colorMdGrey );
	xoffset += SCB_PLAYERNAME_PIXELWIDTH;

	//print score
	xoffset += SCB_MEDIUMFIELD_PIXELWIDTH;
	trap_SCR_DrawStringWidth( x + xoffset, y + yoffset, ALIGN_RIGHT_TOP, "Score", SCB_MEDIUMFIELD_PIXELWIDTH, font, colorMdGrey );

	//print ping
	xoffset += SCB_SMALLFIELD_PIXELWIDTH;
	trap_SCR_DrawStringWidth( x + xoffset, y + yoffset, ALIGN_RIGHT_TOP, "Ping", SCB_SMALLFIELD_PIXELWIDTH, font, colorMdGrey );

	yoffset += trap_SCR_strHeight( font );
	xoffset = -SCB_FFA_PLAYERTAB_PIXELWIDTH/2;

	//draw players
	for( i = 2; i < scb_playercount; i++ )
	{
		if( scb_players[i].type == SCBTAB_PLAYERFFA )
			yoffset += SCB_DrawFFAPlayerTab( &scb_players[i], x + xoffset, y + yoffset, font );
	}

	xoffset = 0;

	//yoffset = ymaxoffset + trap_SCR_strHeight( font );
	yoffset += SCB_DrawPlayerStats( x + xoffset, y + yoffset );
	SCB_DrawSpectators( x + xoffset, y + yoffset );	
}

//===============================================================
//
//		CTF SCOREBOARD
//
//===============================================================

typedef struct
{
	int teamnum;
	int teamscore;
	int teamcaps;
	qboolean updated;

} cg_ctf_scoreboard_teams_t;

static cg_ctf_scoreboard_teams_t ctfteams[GS_MAX_TEAMS];

//================
// CG_DrawTeamTabCTF
//================
#define TAB_TEAM_MAX_NAME_LEN 16
static int CG_DrawTeamTabCTF( int team, int x, int y, qboolean isright, struct mufont_s *font )
{
	vec4_t teamcolor;
	char string[MAX_STRING_CHARS];
	int xname, alignname;
	int xscore;
	int scorewidth;
	int xstats;
	int scoreCharSize = 48;
	int i;
	int yoffset = 0;
	struct mufont_s *tittleFont = cgs.fontSystemBig;

	CG_TeamColor( team, teamcolor );

	Q_snprintfz( string, sizeof( string ), "%i", ctfteams[team].teamscore );
	scorewidth = scoreCharSize *strlen( string );

	teamcolor[3] = SCB_BACKGROUND_ALPHA; // make transparent

	if( !isright ) //left side tab
	{
		xscore = x - ( scorewidth + 8 ); // 8 is a space between tabs
		xname = x - ( scorewidth + 16 );
		alignname = ALIGN_RIGHT_BOTTOM;

		//draw box
		trap_R_DrawStretchPic( 0, y+scoreCharSize, x, //width
		                       -( (int)trap_SCR_strHeight( tittleFont ) ), //height
		                       0, 0, 1, 1, teamcolor, cgs.shaderWhite );

		xstats = x - 16 - SCB_CTF_PLAYERTAB_PIXELWIDTH;

	}
	else
	{    //right side tab
		xscore = x + 8;
		xname = x + scorewidth + 16;
		alignname = ALIGN_LEFT_BOTTOM;

		//draw box
		trap_R_DrawStretchPic( x, y+scoreCharSize, cg.view.refdef.width - x, //width
		                       -( (int)trap_SCR_strHeight( tittleFont ) ), //height
		                       0, 0, 1, 1, teamcolor, cgs.shaderWhite );

		xstats = x + 16;
	}

	teamcolor[3] = 1.0f; // make solid

	yoffset = 0;

	// print score box
	CG_DrawBigNumbersString( xscore, y+yoffset, scoreCharSize, scoreCharSize, va( "%i", ctfteams[team].teamcaps ), colorWhite );
	yoffset += scoreCharSize;

	// print name
	Q_snprintfz( string, sizeof( string ), "%s%s", GS_TeamName( team ), S_COLOR_WHITE );
	trap_SCR_DrawStringWidth( xname, y + yoffset, alignname, string, SCB_TEAMNAME_PIXELWIDTH, tittleFont, colorWhite );

	// print players header
	{
		int xheaderoffset = 0;
		trap_SCR_DrawString( xstats+xheaderoffset, y+yoffset, ALIGN_LEFT_TOP, "Name", font, colorMdGrey );
		xheaderoffset += SCB_PLAYERNAME_PIXELWIDTH;
		xheaderoffset += SCB_SMALLFIELD_PIXELWIDTH; // we align right, so, offset before writting
		trap_SCR_DrawString( xstats+xheaderoffset, y+yoffset, ALIGN_RIGHT_TOP, "Pnts", font, colorMdGrey );
		xheaderoffset += SCB_SMALLFIELD_PIXELWIDTH;
		trap_SCR_DrawString( xstats+xheaderoffset, y+yoffset, ALIGN_RIGHT_TOP, "Ping", font, colorMdGrey );
		//xheaderoffset += SCB_SMALLFIELD_PIXELWIDTH;

		yoffset += trap_SCR_strHeight( font );
	}

	// print all players of this team
	for( i = 0; i < scb_playercount; i++ )
	{
		if( scb_players[i].team == team )
			yoffset += SCB_DrawCTFPlayerTab( &scb_players[i], xstats, y+yoffset, isright, font );
	}

	return yoffset;
}

//================
//CG_UpdateCTFScoreboard
//================
static void CG_UpdateCTFScoreboard( const char *s )
{
	char *token;
	int i, cteam = 0;

	//take out the layout id
	token = COM_Parse( &s );
	if( !token[0] ) return;

	for( i = 0; i < GS_MAX_TEAMS; i++ )
		ctfteams[i].updated = qfalse;

	scb_playercount = 0;

	while( s )
	{
		token = COM_Parse( &s );

		if( !Q_stricmp( token, "&t" ) ) //read a team tab
		{
			cteam = CG_ParseValue( &s );
			if( cteam < 0 || cteam > GS_MAX_TEAMS )
				CG_Error( "Invalid team value in CTF Scoreboard" );

			ctfteams[cteam].teamnum = cteam;
			ctfteams[cteam].teamscore = CG_ParseValue( &s );
			ctfteams[cteam].teamcaps = CG_ParseValue( &s );
			ctfteams[cteam].updated = qtrue;
		}
		else if( !Q_stricmp( token, "&p" ) )
		{                             //read a player tab
			SCB_ParseCTFPlayerTab( &s, cteam );
		}
		else if( !Q_stricmp( token, "&w" ) )
		{                             // read a waiting list player tab
			SCB_ParseChallengerTab( &s );
		}
		else if( !Q_stricmp( token, "&s" ) )
		{                             //read a spectator tab
			SCB_ParseSpectatorTab( &s );
		}
		else if( !Q_stricmp( token, "&c" ) )
		{
			SCB_ParseConnectingPlayerTab( &s );
		}
		else if( !Q_stricmp( token, "&z" ) )
		{
			SCB_ParsePlayerStats( &s );
		}
	}
}

//================
//CG_DrawCTFScoreboard
//================
static void CG_DrawCTFScoreboard( int x, int y, struct mufont_s *font )
{
	int t, xoffset, yoffset, ymaxoffset = 0;
	qboolean rightside = qfalse;

	//draw team tabs
	for( t = 0; t < GS_MAX_TEAMS; t++ )
	{
		if( t != TEAM_ALPHA && t != TEAM_BETA )  // forces drawing the team tabs
			continue;

		yoffset = 0;
		if( rightside )
		{
			xoffset = 8;
		}
		else
		{
			xoffset = -8;
		}

		yoffset += CG_DrawTeamTabCTF( t, x + xoffset, y + yoffset, rightside, font );
		if( yoffset > ymaxoffset )
			ymaxoffset = yoffset;
		rightside = !rightside;
		xoffset = 0;
	}

	// so we draw the spectators below the teammembers
	// we do know how many players the biggest team has.
	yoffset = ymaxoffset + trap_SCR_strHeight( font );
	yoffset += SCB_DrawPlayerStats( x, y + yoffset );
	SCB_DrawSpectators( x, y + yoffset );
}

//===============================================================
//
//		FIXED SCOREBOARD LAYOUT SCHEMES
//
//===============================================================

//  Layouts were great when Q2 didn't have a cgame, and still are
// great for the hud, but, since each mod has it's own cgame now,
// we don't need to send the design through the netcode anymore. It's
// enough for us now with sending the data, and use cgame for applying
// that data to a fixed layout desing

// Each layout can use it's own data format. To identify the string
// as a fixed layout I decided to use a short token, beginning with
// the 'and' character ( '&' ), and followed by a token of no more
// than six characters. The rest of the string is interpreted at
// it's own function, so the format it's particular to it.

char scoreboard_name[16];

typedef struct
{
	char *name;
	void ( *DrawScoreboard )( int xpos, int ypos, struct mufont_s *font );
	void ( *UpdateScoreboard )( const char *s );
} cg_scoreboard_templates_t;

cg_scoreboard_templates_t cg_scoreboards[] = {
	{ "&dms", CG_DrawDMScoreboard, CG_UpdateDMScoreboard },
	{ "&races", CG_DrawRACEScoreboard, CG_UpdateRACEScoreboard },
	{ "&duels", CG_DrawDUELScoreboard, CG_UpdateDUELScoreboard },
	{ "&tdms", CG_DrawTDMScoreboard, CG_UpdateTDMScoreboard },
	{ "&ctfs", CG_DrawCTFScoreboard, CG_UpdateCTFScoreboard },
	{ "&cas", CG_DrawCAScoreboard, CG_UpdateCAScoreboard },
	{ "&das", CG_DrawDAScoreboard, CG_UpdateDAScoreboard },
	{ NULL }
};

void CG_ToggleScores_f( void )
{
	if( cgs.demoPlaying || cg.frame.multipov || cgs.tv )
		cg.showScoreboard = !cg.showScoreboard;
	else
		trap_Cmd_ExecuteText( EXEC_NOW, "svscore" );
}

void CG_ScoresOn_f( void )
{
	if( cgs.demoPlaying || cg.frame.multipov || cgs.tv )
		cg.showScoreboard = qtrue;
	else
		trap_Cmd_ExecuteText( EXEC_NOW, "svscore 1" );
}

void CG_ScoresOff_f( void )
{
	if( cgs.demoPlaying || cg.frame.multipov || cgs.tv )
		cg.showScoreboard = qfalse;
	else
		trap_Cmd_ExecuteText( EXEC_NOW, "svscore 0" );
}

/*
   ================
   CG_DrawScoreboard
   ================
 */
void CG_DrawScoreboard( void )
{
	cg_scoreboard_templates_t *scboard;
	char title[20];
	int xpos, ypos;
	struct mufont_s	*font;

	font = trap_SCR_RegisterFont( cg_scoreboardFont->string );
	if( !font )
	{
		CG_Printf( "%sWarning: Invalid font in 'cg_scoreboardFont'. Reseting to default%s\n", S_COLOR_YELLOW, S_COLOR_WHITE );
		trap_Cvar_Set( "cg_scoreboardFont", cg_scoreboardFont->dvalue );
		font = trap_SCR_RegisterFont( cg_scoreboardFont->string );
		if( !font )
			CG_Error( "Couldn't load default scoreboard font \"%s\"", cg_scoreboardFont->dvalue );
	}

	//yoffset at middle of the screen
	xpos = (int)( cgs.vidWidth * 0.5 );
	ypos = (int)( cgs.vidHeight * 0.25 ) - 24;

	//title
	Q_snprintfz( title, sizeof( title ), "WARSOW %s",
	            GS_Gametype_ShortName( cg.frame.playerState.stats[STAT_GAMETYPE] ) );
	Q_strupr( title );
	trap_SCR_DrawString( xpos, ypos, ALIGN_CENTER_TOP, title, cgs.fontSystemBig, whiteTransparent );
	ypos += trap_SCR_strHeight( cgs.fontSystemBig );
	trap_SCR_DrawStringWidth( xpos, ypos, ALIGN_CENTER_TOP, cgs.configStrings[CS_HOSTNAME], cgs.vidWidth*0.75, cgs.fontSystemSmall, whiteTransparent );
	ypos += trap_SCR_strHeight( cgs.fontSystemSmall );


	if( scoreboard_name[0] != '&' )
	{                               //must begin with
		return;
	}

	for( scboard = cg_scoreboards; scboard->name; scboard++ )
	{
		if( !Q_stricmp( scboard->name, scoreboard_name ) )
		{
			scboard->DrawScoreboard( xpos, ypos, font );
			return;
		}
	}

	trap_SCR_DrawString( 16, 4*16, ALIGN_LEFT_TOP, "Invalid Scoreboard Template", cgs.fontSystemMedium, whiteTransparent );

	if( developer->integer )
		CG_Printf( "SCR_DrawScoreboard : Unrecognized scoreboard template\n" );
}

/*
   ================
   SCR_UpdateScoreboardMessage
   ================
 */
void SCR_UpdateScoreboardMessage( const char *string )
{
	char *tok;
	const char *ptr;
	cg_scoreboard_templates_t *scboard;

	if( !string || !string[0] )
		goto notfound;

	ptr = string;
	tok = COM_Parse( &ptr );
	if( !tok[0] )
		goto notfound;

	if( *tok != '&' )   //must begin with
		goto notfound;

	for( scboard = cg_scoreboards; scboard->name; scboard++ )
	{
		if( !Q_stricmp( scboard->name, tok ) )
		{
			Q_strncpyz( scoreboard_name, tok, sizeof( scoreboard_name ) );
			scboard->UpdateScoreboard( string );
			return;
		}
	}
notfound:
	// failed
	memset( scoreboard_name, 0, sizeof( scoreboard_name ) );
	if( developer->integer )
		CG_Printf( "SCR_UpdateScoreboard : Unrecognized scoreboard template\n" );
}

/*
   ================
   SCR_UpdatePlayerStatsMessage
   ================
 */
void SCR_UpdatePlayerStatsMessage( const char *string )
{
	SCB_ParsePlayerStats( &string );
}
