// Copyright (C) 2001-2002 Raven Software.
//
// cg_scoreboard -- draw the scoreboard on top of the game screen
#include "cg_local.h"


#define SB_HEADER			86
#define SB_TOP				(SB_HEADER+32)

// Where the status bar starts, so we don't overwrite it
#define SB_STATUSBAR		420

#define SB_MAXCLIENTS_NORMAL  12
#define SB_MAXCLIENTS_MORE	  26
#define SB_MAXCLIENTS_ALOT	  32

// Used when interleaved
#define SB_HEADER_WIDTH		(580)
#define SB_HEADER_HEIGHT	30
#define SB_HEADER_X			((640-SB_HEADER_WIDTH)/2)
#define SB_HEADER_Y			86
#define SB_SCORELINE_X		(SB_HEADER_X+30)
#define SB_SCORELINE_Y		120
#define SB_SCORELINE_WIDTH	(SB_HEADER_WIDTH-60)
#define SB_NAME_X			(SB_SCORELINE_X)
#define SB_SCORE_X			(SB_SCORELINE_X+287)
#define SB_KILLS_X			(SB_SCORELINE_X+335)
#define SB_DEATHS_X			(SB_SCORELINE_X+384)
#define	SB_PING_X			(SB_SCORELINE_X+440)
#define SB_TIME_X			(SB_SCORELINE_X+489)

int		sb_lineHeight;
int		sb_maxClients;
float	sb_nameFontScale;
float	sb_numberFontScale;
float	sb_readyFontScale;

/*
=================
CG_DrawClientScore
=================
*/
static void CG_DrawClientScore( float x, float y, float w, score_t* score, float* color )
{
	clientInfo_t*	ci;
	vec4_t			dataColor;
	vec4_t			nameColor;
	const char*		s;
	float			f;

	nameColor[3] = dataColor[3] = 1.0f;
	
	// Validate the score
	if ( score->client < 0 || score->client >= cgs.maxclients ) 
	{
		Com_Printf( "Bad score->client: %i\n", score->client );
		return;
	}

	// Convienience	
	ci = &cgs.clientinfo[score->client];

	CG_DrawPic ( x - 5, y, w, sb_lineHeight, cgs.media.scoreboardLine );

	// highlight your position
	if ( score->client == cg.snap->ps.clientNum ) 
	{
		vec4_t hcolor;

		hcolor[0] = 1.0f;
		hcolor[1] = 1.0f;
		hcolor[2] = 1.0f;
		hcolor[3] = .10f;

		CG_FillRect( x - 5, y, w, sb_lineHeight, hcolor );

		VectorSet ( nameColor, 1.0f, 1.0f, 1.0f );
		VectorSet ( dataColor, 0.5f, 0.5f, 0.5f );
	}
	else if ( (cg.snap->ps.pm_type == PM_DEAD) && score->client == cg.snap->ps.persistant[PERS_ATTACKER] )
	{
		vec4_t hcolor;

		hcolor[0] = 1.0f;
		hcolor[1] = 1.0f;
		hcolor[2] = 1.0f;
		hcolor[3] = .10f;

		CG_FillRect( x - 5, y, w, sb_lineHeight, hcolor );

		VectorCopy ( color, nameColor );
		VectorSet ( dataColor, 0.5f, 0.5f, 0.5f );
	}
	else
	{
		VectorCopy ( color, nameColor );
		VectorSet ( dataColor, 0.3f, 0.3f, 0.3f );

		if ( ci->ghost )
		{
			VectorScale ( nameColor, 0.6f, nameColor );
		}
	}

	CG_DrawText( x, y, cgs.media.hudFont, sb_nameFontScale, nameColor, ci->name, 24, DT_OUTLINE );

	s = va("%i", score->score );
	f = trap_R_GetTextWidth ( s, cgs.media.hudFont, sb_nameFontScale, 0 );
	CG_DrawText( x + w - 10 - f, y, cgs.media.hudFont, sb_nameFontScale, nameColor, va("%i", score->score), 0, DT_OUTLINE );

	// Draw skull if dead and not in intermission
	if ( cg.snap->ps.pm_type == PM_INTERMISSION  )
	{
		if ( cg.snap->ps.stats[ STAT_CLIENTS_READY ] & ( 1 << score->client ) )
		{
			vec3_t deadColor;
			deadColor[0] = 0.60f;
			deadColor[1] = 0.60f;
			deadColor[2] = 0.60f;
			deadColor[3] = 1.0f;
			CG_DrawText( x + w - 70, y + 3, cgs.media.hudFont, sb_readyFontScale, deadColor, "READY", 0, DT_OUTLINE );
		}
	}
	else if ( ci->ghost )
	{
		CG_DrawPic ( x + w - 70, y + 1, sb_numberFontScale * 0.8f, sb_numberFontScale * 0.8f, cgs.media.deadShader );			
	}
	// Draw any gametype items the guy is carrying
	else
	{
		float xx = x + w - 70;
		int   i;
		for ( i = 0; i < MAX_GAMETYPE_ITEMS; i ++ )
		{
			centity_t* cent;

			cent = CG_GetEntity ( score->client);

			// No have item, no draw it
			if ( !(ci->gametypeitems & (1<<i) ) )
			{
				continue;
			}

			if ( !cg_items[MODELINDEX_GAMETYPE_ITEM+i].icon )
			{
				continue;
			}

			CG_DrawPic ( xx, y + 1, sb_numberFontScale * 0.8f, sb_numberFontScale * 0.8f, cg_items[MODELINDEX_GAMETYPE_ITEM+i].icon );

			xx += sb_numberFontScale;
		}
	}		


	s = va("%i/%i", score->kills, score->deaths);
	f = trap_R_GetTextWidth ( s, cgs.media.hudFont, sb_readyFontScale, 0 );
	CG_DrawText( x + w - 10 - f, y + sb_numberFontScale, cgs.media.hudFont, sb_readyFontScale, dataColor, s, 0, 0 );

	CG_DrawText( x, y + sb_numberFontScale, cgs.media.hudFont, sb_readyFontScale, dataColor, va("id: %i", score->client ), 0, 0 );
	CG_DrawText( x + 40, y + sb_numberFontScale, cgs.media.hudFont, sb_readyFontScale, dataColor, va("ping: %i", score->ping ), 0, 0 );
	CG_DrawText( x + 95, y + sb_numberFontScale, cgs.media.hudFont, sb_readyFontScale, dataColor, va("time: %i", score->time ), 0, 0 );

	if ( score->teamkillDamage )
	{
		CG_DrawText( x + 150, y + sb_numberFontScale, cgs.media.hudFont, sb_readyFontScale, dataColor, va("tk: %i%%", score->teamkillDamage ), 0, 0 );
	}
}

/*
=================
CG_TeamScoreboard
=================
*/
static int CG_TeamScoreboard( float x, float y, float w, team_t team ) 
{
	int				i;
	int				skipped;
	float			color[4];
	int				count;
	clientInfo_t	*ci;
	const char*		s;
	int				players;
	qboolean		drawnClient;

	// Do we make sure the current client is drawn?
	drawnClient = qtrue;
	if ( cg.scores [ cg.snap->ps.clientNum ].team == team )
	{
		drawnClient = qfalse;
	}

	// Determine the color for this team
	switch ( team )
	{
		case TEAM_RED:
			VectorCopy4 ( g_color_table[ColorIndex(COLOR_RED)], color );
			break;

		case TEAM_BLUE:
			VectorCopy4 ( g_color_table[ColorIndex(COLOR_BLUE)], color );
			break;

		case TEAM_FREE:
			VectorCopy4 ( g_color_table[ColorIndex(COLOR_GREEN)], color );
			break;

		case TEAM_SPECTATOR:
		default:
			VectorCopy4 ( colorWhite, color );
			break;
	}

	// Draw as many clients as we can for this team
	for ( skipped = -1, count = 0, i = 0 ; i < cg.numScores && count < sb_maxClients ; i++ ) 
	{
		score_t*	score;

		score = &cg.scores[i];
		ci    = &cgs.clientinfo[ score->client ];

		if ( team != score->team ) 
		{
			continue;
		}

		if ( count == sb_maxClients - 1 && !drawnClient )
		{
			if ( score->client != cg.snap->ps.clientNum )
			{
				skipped = i;
				continue;
			}
			
			drawnClient = qtrue; 
		}

		CG_DrawClientScore( x, y + SB_HEADER_HEIGHT + sb_lineHeight * count, w, score, color );

		count++;
	}

	if ( skipped != -1 &&  count < sb_maxClients )
	{
		CG_DrawClientScore( x, y + SB_HEADER_HEIGHT + sb_lineHeight * count, w, &cg.scores[skipped], color );

		count++;
	}

	s = "";
	switch ( team )
	{
		case TEAM_RED:
			s = "RED TEAM";
			players = ui_info_redcount.integer;
			break;

		case TEAM_BLUE:
			s = "BLUE TEAM";
			players = ui_info_bluecount.integer;
			break;

		case TEAM_FREE:
			s = "PLAYERS";
			players = ui_info_freecount.integer;
			break;

		default:
		case TEAM_SPECTATOR:
			s = "SPECTATORS";
			players = ui_info_speccount.integer;
			break;
	}

	// Use the same team color here, but alpha it a bit.
	color[3] = 0.6f;

	// Draw the header information for this team
	CG_DrawPic ( x - 5, y, w, 25, cgs.media.scoreboardHeader );
	CG_FillRect( x - 5, y, w, 25, color );
	CG_DrawText ( x, y, cgs.media.hudFont, 0.40f, colorWhite, va("%s", s), 0, 0 );
	CG_DrawText ( x, y + 13, cgs.media.hudFont, 0.30f, colorWhite, va("players: %d", players), 0, 0 );

	// Draw the totals if this is the red or blue team
	if ( (team == TEAM_RED || team == TEAM_BLUE))
	{
		const char* s;
		float		f;

		s = va("%d",(cg.teamScores[team-TEAM_RED]));
		f = trap_R_GetTextWidth ( s, cgs.media.hudFont, 0.43f, 0 );
		CG_DrawText ( x + w - 10 - f, y, cgs.media.hudFont, 0.43f, colorWhite, s, 0, DT_OUTLINE );
	}

	if ( count )
	{
		CG_DrawPic ( x - 5, y + SB_HEADER_HEIGHT + sb_lineHeight * count, w, sb_lineHeight, cgs.media.scoreboardFooter );
	}
	
	y = count * sb_lineHeight + y + 10;

	if ( y > cg.scoreBoardBottom )
	{
		cg.scoreBoardBottom = y;
	}

	return y;
}

/*
=================
CG_DrawNormalScoreboard

Draws a scoreboard that has no teams
=================
*/
qboolean CG_DrawNormalScoreboard ( float y )
{
	cg.scoreBoardBottom = 0;

	// DRaw the game timer and the game type
	CG_DrawText ( 385,  y - 14, cgs.media.hudFont, 0.38f, colorLtGrey, "Game Time:", 0, DT_OUTLINE );
	CG_DrawTimer ( 455,  y - 14, cgs.media.hudFont, 0.38f, colorLtGrey, DT_OUTLINE, cg.time - cgs.levelStartTime );
	CG_DrawText ( 150,  y - 14, cgs.media.hudFont, 0.38f, colorLtGrey, cgs.gametypeData->displayName, 0, DT_OUTLINE );

	if ( ui_info_speccount.integer )
	{
		CG_FillRect ( 0, 470, 640, 10, colorBlack );
		CG_DrawText ( 5, 470, cgs.media.hudFont, 0.30f, colorWhite, va("SPECTATORS:   %s", cg.scoreBoardSpectators), 0, 0 );
	}

	if ( ui_info_freecount.integer > 10 ) 
	{
		sb_maxClients	   = 16;
		sb_lineHeight	   = 20;
		sb_nameFontScale   = 0.35f;
		sb_readyFontScale  = 0.30f;
		sb_numberFontScale = trap_R_GetTextHeight ( "W", cgs.media.hudFont, sb_nameFontScale, 0 );
	} 
	else
	{
		sb_maxClients	   = 10;
		sb_lineHeight	   = 30;
		sb_nameFontScale   = 0.43f;
		sb_readyFontScale  = 0.30f;
		sb_numberFontScale = trap_R_GetTextHeight ( "W", cgs.media.hudFont, sb_nameFontScale, 0 ) + 4;
	}

	CG_TeamScoreboard ( 150, y, 350, TEAM_FREE );

	return qtrue;
}

/*
=================
CG_DrawTeamScoreboard

Draw the normal in-game scoreboard
=================
*/
qboolean CG_DrawTeamScoreboard( float y ) 
{
	qboolean redFirst = qfalse;

	cg.scoreBoardBottom = 0;

	// DRaw the game timer and the game type
	CG_DrawText ( 470,  y - 14, cgs.media.hudFont, 0.38f, colorLtGrey, "Game Time:", 0, DT_OUTLINE );
	CG_DrawTimer ( 540,  y - 14, cgs.media.hudFont, 0.38f, colorLtGrey, DT_OUTLINE, cg.time - cgs.levelStartTime );
	CG_DrawText ( 60,  y - 14, cgs.media.hudFont, 0.38f, colorLtGrey, cgs.gametypeData->displayName, 0, DT_OUTLINE );

	if ( ui_info_speccount.integer )
	{
		CG_FillRect ( 0, 470, 640, 10, colorBlack );
		CG_DrawText ( 5, 470, cgs.media.hudFont, 0.30f, colorWhite, va("SPECTATORS:   %s", cg.scoreBoardSpectators), 0, 0 );
	}

	if ( ui_info_redcount.integer > 10 || ui_info_bluecount.integer > 10 ) 
	{
		sb_maxClients	   = 16;
		sb_lineHeight	   = 20;
		sb_nameFontScale   = 0.35f;
		sb_readyFontScale  = 0.30f;
		sb_numberFontScale = trap_R_GetTextHeight ( "W", cgs.media.hudFont, sb_nameFontScale, 0 );
	} 
	else
	{
		sb_maxClients	   = 10;
		sb_lineHeight	   = 30;
		sb_nameFontScale   = 0.43f;
		sb_readyFontScale  = 0.30f;
		sb_numberFontScale = trap_R_GetTextHeight ( "W", cgs.media.hudFont, sb_nameFontScale, 0 ) + 4;
	}

	// If there are more scores than the scoreboard can show then show the 
	// players team first rather than the winning team
	if ( cgs.clientinfo[cg.clientNum].team == TEAM_SPECTATOR )
	{
		if ( cg.teamScores[0] >= cg.teamScores[1] )
		{
			redFirst = qtrue;
		}
	}
	else if ( cgs.clientinfo[cg.clientNum].team == TEAM_RED )
	{
		redFirst = qtrue;
	}

	if ( redFirst ) 
	{
		CG_TeamScoreboard( 50, y, 265, TEAM_RED );
		CG_TeamScoreboard( 330, y, 265, TEAM_BLUE );
	}
	else
	{
		CG_TeamScoreboard( 330, y, 265, TEAM_RED );
		CG_TeamScoreboard( 50, y, 265, TEAM_BLUE );
	}

	return qtrue;
}

/*
=================
CG_DrawScoreboard

Draws either a team or a normal scoreboard
=================
*/
qboolean CG_DrawScoreboard ( void )
{
	float y;
	float w;

	// don't draw amuthing if the menu or console is up
	if ( cg_paused.integer ) 
	{
		cg.deferredPlayerLoading = 0;
		return qfalse;
	}

	// don't draw scoreboard during death while warmup up
	if ( cg.warmup && !cg.showScores ) 
	{
		return qfalse;
	}

	if ( !cg.showScores										&& 
		 cg.predictedPlayerState.pm_type != PM_DEAD			&&
		 cg.predictedPlayerState.pm_type != PM_INTERMISSION    ) 
	{
		return qfalse;
	}

	// scoreboard
	y = 45;

	if ( cgs.gametypeData->teams )
	{
		if ( ui_info_redcount.integer < 10 && ui_info_bluecount.integer < 10 )
		{
			y += 50;
		}
	}
	else if ( ui_info_freecount.integer < 10 )
	{
		y += 50;
	}

	// Draw any gameover text
	if ( cgs.gameover[0] )
	{
		w = trap_R_GetTextWidth ( cgs.gameover, cgs.media.hudFont, 0.48f, 0 );
		CG_DrawText ( 320 - w / 2, y - 30, cgs.media.hudFont, 0.48f, colorWhite, cgs.gameover, 0, DT_OUTLINE );
	}
	else if ( cgs.gametypeMessageTime > cg.time )
	{
		w = trap_R_GetTextWidth ( cgs.gametypeMessage, cgs.media.hudFont, 0.48f, 0 );
		CG_DrawText ( 320 - w / 2, y - 30, cgs.media.hudFont, 0.48f, colorWhite, cgs.gametypeMessage, 0, DT_OUTLINE );
	}
	// Should we draw who killed you?
	else if ( cg.snap->ps.pm_type == PM_DEAD && 
			  cg.snap->ps.persistant[PERS_ATTACKER] < MAX_CLIENTS &&
			  cg.snap->ps.persistant[PERS_ATTACKER] != cg.snap->ps.clientNum )
	{
		const char* s;
		s = va("Killed by %s", cgs.clientinfo[cg.snap->ps.persistant[PERS_ATTACKER]].name );
		w = trap_R_GetTextWidth ( s, cgs.media.hudFont, 0.48f, 0 );
		CG_DrawText ( 320 - w / 2, y - 30, cgs.media.hudFont, 0.48f, colorWhite, s, 0, DT_OUTLINE );
	}
	else if ( cgs.gametypeData->teams )
	{
		const char* s;
		if ( cg.teamScores[0] == cg.teamScores[1] )
		{
			s = va ( "Game Tied at %d", cg.teamScores[0] );
		}
		else if ( cg.teamScores[0] > cg.teamScores[1] )
		{
			s = va ( "Red leads Blue by %d", cg.teamScores[0] - cg.teamScores[1] );
		}
		else
		{
			s = va ( "Blue leads Red by %d", cg.teamScores[1] - cg.teamScores[0] );
		}

		w = trap_R_GetTextWidth ( s, cgs.media.hudFont, 0.48f, 0 );
		CG_DrawText ( 320 - w / 2, y - 30, cgs.media.hudFont, 0.48f, colorWhite, s, 0, DT_OUTLINE );
	}		

	// load any models that have been deferred
	cg.deferredPlayerLoading++;

	if ( cgs.gametypeData->teams )
	{
		return CG_DrawTeamScoreboard ( y );
	}

	return CG_DrawNormalScoreboard ( y ); 
}
