/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
Copyright (C) 2006 Pat Raynor <raynorpat@sbcglobal.net>

This file is part of the Fortress Evolution source code.

Fortress Evolution 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.

The Fortress Evolution source code 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 Fortress Evolution; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
===========================================================================
*/

#include "cg_local.h"
#include "../ui/ui_shared.h"

extern displayContextDef_t cgDC;
extern int HudGroupFlag;

// set in CG_ParseTeamInfo

//static int sortedTeamPlayers[TEAM_MAXOVERLAY];
//static int numSortedTeamPlayers;
int drawTeamOverlayModificationCount = -1;

//static char systemChat[256];
//static char teamChat1[256];
//static char teamChat2[256];

typedef enum _flag_status {
	FLAG_ATBASE = 0,
	FLAG_TAKEN,			// CTF
	FLAG_TAKEN_RED,		// One Flag CTF
	FLAG_TAKEN_BLUE,	// One Flag CTF
	FLAG_DROPPED
} flagStatus_t;

void CG_InitTeamChat(void) {
  memset(teamChat1, 0, sizeof(teamChat1));
  memset(teamChat2, 0, sizeof(teamChat2));
  memset(systemChat, 0, sizeof(systemChat));
}

void CG_SetPrintString(int type, const char *p) {
  if (type == SYSTEM_PRINT) {
    strcpy(systemChat, p);
  } else {
    strcpy(teamChat2, teamChat1);
    strcpy(teamChat1, p);
  }
}

void CG_CheckOrderPending(void) {
	if (cgs.gametype < GT_CTF) {
		return;
	}
	if (cgs.orderPending) {
		//clientInfo_t *ci = cgs.clientinfo + sortedTeamPlayers[cg_currentSelectedPlayer.integer];
		const char *p1, *p2, *b;
		p1 = p2 = b = NULL;
		switch (cgs.currentOrder) {
			case TEAMTASK_OFFENSE:
				p1 = VOICECHAT_ONOFFENSE;
				p2 = VOICECHAT_OFFENSE;
				b = "+button7; wait; -button7";
			break;
			case TEAMTASK_DEFENSE:
				p1 = VOICECHAT_ONDEFENSE;
				p2 = VOICECHAT_DEFEND;
				b = "+button8; wait; -button8";
			break;					
			case TEAMTASK_PATROL:
				p1 = VOICECHAT_ONPATROL;
				p2 = VOICECHAT_PATROL;
				b = "+button9; wait; -button9";
			break;
			case TEAMTASK_FOLLOW: 
				p1 = VOICECHAT_ONFOLLOW;
				p2 = VOICECHAT_FOLLOWME;
				b = "+button10; wait; -button10";
			break;
			case TEAMTASK_CAMP:
				p1 = VOICECHAT_ONCAMPING;
				p2 = VOICECHAT_CAMP;
			break;
			case TEAMTASK_RETRIEVE:
				p1 = VOICECHAT_ONGETFLAG;
				p2 = VOICECHAT_RETURNFLAG;
			break;
			case TEAMTASK_ESCORT:
				p1 = VOICECHAT_ONFOLLOWCARRIER;
				p2 = VOICECHAT_FOLLOWFLAGCARRIER;
			break;
		}

		if (cg_currentSelectedPlayer.integer == numSortedTeamPlayers) {
			// to everyone
			trap_SendConsoleCommand(va("cmd vsay_team %s\n", p2));
		} else {
			// for the player self
			if (sortedTeamPlayers[cg_currentSelectedPlayer.integer] == cg.snap->ps.clientNum && p1) {
				trap_SendConsoleCommand(va("teamtask %i\n", cgs.currentOrder));
				//trap_SendConsoleCommand(va("cmd say_team %s\n", p2));
				trap_SendConsoleCommand(va("cmd vsay_team %s\n", p1));
			} else if (p2) {
				//trap_SendConsoleCommand(va("cmd say_team %s, %s\n", ci->name,p));
				trap_SendConsoleCommand(va("cmd vtell %d %s\n", sortedTeamPlayers[cg_currentSelectedPlayer.integer], p2));
			}
		}
		if (b) {
			trap_SendConsoleCommand(b);
		}
		cgs.orderPending = qfalse;
	}
}

static void CG_SetSelectedPlayerName( void ) {
  if (cg_currentSelectedPlayer.integer >= 0 && cg_currentSelectedPlayer.integer < numSortedTeamPlayers) {
		clientInfo_t *ci = cgs.clientinfo + sortedTeamPlayers[cg_currentSelectedPlayer.integer];
	  if (ci) {
			trap_Cvar_Set("cg_selectedPlayerName", ci->name);
			trap_Cvar_Set("cg_selectedPlayer", va("%d", sortedTeamPlayers[cg_currentSelectedPlayer.integer]));
	  }
	} else {
		trap_Cvar_Set("cg_selectedPlayerName", "Everyone");
	}
}
int CG_GetSelectedPlayer( void ) {
	if (cg_currentSelectedPlayer.integer < 0 || cg_currentSelectedPlayer.integer >= numSortedTeamPlayers) {
		cg_currentSelectedPlayer.integer = 0;
	}
	return cg_currentSelectedPlayer.integer;
}

void CG_SelectNextPlayer( void ) {
	CG_CheckOrderPending();
	cg_currentSelectedPlayer.integer +=1;
	if (cg_currentSelectedPlayer.integer > numSortedTeamPlayers)
		cg_currentSelectedPlayer.integer = 0;
	CG_SetSelectedPlayerName();
}

void CG_SelectPrevPlayer( void ) {
	CG_CheckOrderPending();
	cg_currentSelectedPlayer.integer -=1;
	if (cg_currentSelectedPlayer.integer < 0)
		cg_currentSelectedPlayer.integer = numSortedTeamPlayers;
	CG_SetSelectedPlayerName();
}

static void CG_DrawPlayerArmorIcon( rectDef_t *rect, qboolean draw2D ) {
	centity_t	*cent;
	playerState_t	*ps;
	vec3_t		angles;
	vec3_t		origin;

  if ( cg_drawStatus.integer == 0 ) {
		return;
	}

	cent = &cg_entities[cg.snap->ps.clientNum];
	ps = &cg.snap->ps;

	if ( draw2D || ( !cg_draw3dIcons.integer && cg_drawIcons.integer) ) { // bk001206 - parentheses
		CG_DrawPic( rect->x, rect->y + rect->h/2 + 1, rect->w, rect->h, cgs.media.armorIcon );
  } else if (cg_draw3dIcons.integer) {
	  VectorClear( angles );
    origin[0] = 90;
  	origin[1] = 0;
  	origin[2] = -10;
  	angles[YAW] = ( cg.time & 2047 ) * 360 / 2048.0;
  
    CG_Draw3DModel( rect->x, rect->y, rect->w, rect->h, cgs.media.armorModel, 0, origin, angles );
  }

}

static void CG_DrawPlayerArmorValue(rectDef_t *rect, float scale, vec4_t color, qhandle_t shader, int textStyle) {
	char	num[16];
  int value;
	centity_t	*cent;
	playerState_t	*ps;

  cent = &cg_entities[cg.snap->ps.clientNum];
	ps = &cg.snap->ps;

	value = ps->stats[STAT_ARMOR];
  

	if (shader) {
    trap_R_SetColor( color );
		CG_DrawPic(rect->x, rect->y, rect->w, rect->h, shader);
	  trap_R_SetColor( NULL );
	} else {
		Com_sprintf (num, sizeof(num), "%i", value);
		value = CG_Text_Width(num, scale, 0);
	  CG_Text_Paint(rect->x + (rect->w - value) / 2, rect->y + rect->h, scale, color, num, 0, 0, textStyle);
	}
}

static void CG_DrawPlayerAmmoIcon( rectDef_t *rect, qboolean draw2D ) {
	centity_t	*cent;
	playerState_t	*ps;
	vec3_t		angles;
	vec3_t		origin;

	cent = &cg_entities[cg.snap->ps.clientNum];
	ps = &cg.snap->ps;

	if ( draw2D || (!cg_draw3dIcons.integer && cg_drawIcons.integer) ) { // bk001206 - parentheses
	  qhandle_t	icon;
    icon = cg_weapons[ cg.predictedPlayerState.weapon ].ammoIcon;
		if ( icon ) {
		  CG_DrawPic( rect->x, rect->y, rect->w, rect->h, icon );
		}
  } else if (cg_draw3dIcons.integer) {
  	if ( cent->currentState.weapon && cg_weapons[ cent->currentState.weapon ].ammoModel ) {
	    VectorClear( angles );
	  	origin[0] = 70;
  		origin[1] = 0;
  		origin[2] = 0;
  		angles[YAW] = 90 + 20 * sin( cg.time / 1000.0 );
  		CG_Draw3DModel( rect->x, rect->y, rect->w, rect->h, cg_weapons[ cent->currentState.weapon ].ammoModel, 0, origin, angles );
  	}
  }
}

static void CG_DrawPlayerAmmoValue(rectDef_t *rect, float scale, vec4_t color, qhandle_t shader, int textStyle) {
	char	num[16];
	int value;
	centity_t	*cent;
	playerState_t	*ps;

	cent = &cg_entities[cg.snap->ps.clientNum];
	ps = &cg.snap->ps;

	if ( cent->currentState.weapon ) {
		value = ps->ammo[cent->currentState.weapon];
		if ( value > -1 ) {
			if (shader) {
		    trap_R_SetColor( color );
				CG_DrawPic(rect->x, rect->y, rect->w, rect->h, shader);
			  trap_R_SetColor( NULL );
			} else {
				Com_sprintf (num, sizeof(num), "%i", value);
				value = CG_Text_Width(num, scale, 0);
				CG_Text_Paint(rect->x + (rect->w - value) / 2, rect->y + rect->h, scale, color, num, 0, 0, textStyle);
			}
		}
	}

}



static void CG_DrawPlayerHead(rectDef_t *rect, qboolean draw2D) {
	vec3_t		angles;
	float		size, stretch;
	float		frac;
	float		x = rect->x;

	VectorClear( angles );

	if ( cg.damageTime && cg.time - cg.damageTime < DAMAGE_TIME ) {
		frac = (float)(cg.time - cg.damageTime ) / DAMAGE_TIME;
		size = rect->w * 1.25 * ( 1.5 - frac * 0.5 );

		stretch = size - rect->w * 1.25;
		// kick in the direction of damage
		x -= stretch * 0.5 + cg.damageX * stretch * 0.5;

		cg.headStartYaw = 180 + cg.damageX * 45;

		cg.headEndYaw = 180 + 20 * cos( crandom()*M_PI );
		cg.headEndPitch = 5 * cos( crandom()*M_PI );

		cg.headStartTime = cg.time;
		cg.headEndTime = cg.time + 100 + random() * 2000;
	} else {
		if ( cg.time >= cg.headEndTime ) {
			// select a new head angle
			cg.headStartYaw = cg.headEndYaw;
			cg.headStartPitch = cg.headEndPitch;
			cg.headStartTime = cg.headEndTime;
			cg.headEndTime = cg.time + 100 + random() * 2000;

			cg.headEndYaw = 180 + 20 * cos( crandom()*M_PI );
			cg.headEndPitch = 5 * cos( crandom()*M_PI );
		}

		size = rect->w * 1.25;
	}

	// if the server was frozen for a while we may have a bad head start time
	if ( cg.headStartTime > cg.time ) {
		cg.headStartTime = cg.time;
	}

	frac = ( cg.time - cg.headStartTime ) / (float)( cg.headEndTime - cg.headStartTime );
	frac = frac * frac * ( 3 - 2 * frac );
	angles[YAW] = cg.headStartYaw + ( cg.headEndYaw - cg.headStartYaw ) * frac;
	angles[PITCH] = cg.headStartPitch + ( cg.headEndPitch - cg.headStartPitch ) * frac;

	CG_DrawHead( x, rect->y, rect->w, rect->h, cg.snap->ps.clientNum, angles );
}

static void CG_DrawSelectedPlayerHealth( rectDef_t *rect, float scale, vec4_t color, qhandle_t shader, int textStyle ) {
	clientInfo_t *ci;
	int value;
	char num[16];

  ci = cgs.clientinfo + sortedTeamPlayers[CG_GetSelectedPlayer()];
  if (ci) {
		if (shader) {
			trap_R_SetColor( color );
			CG_DrawPic(rect->x, rect->y, rect->w, rect->h, shader);
			trap_R_SetColor( NULL );
		} else {
			Com_sprintf (num, sizeof(num), "%i", ci->health);
		  value = CG_Text_Width(num, scale, 0);
		  CG_Text_Paint(rect->x + (rect->w - value) / 2, rect->y + rect->h, scale, color, num, 0, 0, textStyle);
		}
	}
}

static void CG_DrawSelectedPlayerArmor( rectDef_t *rect, float scale, vec4_t color, qhandle_t shader, int textStyle ) {
	clientInfo_t *ci;
	int value;
	char num[16];
  ci = cgs.clientinfo + sortedTeamPlayers[CG_GetSelectedPlayer()];
  if (ci) {
    if (ci->armor > 0) {
			if (shader) {
				trap_R_SetColor( color );
				CG_DrawPic(rect->x, rect->y, rect->w, rect->h, shader);
				trap_R_SetColor( NULL );
			} else {
				Com_sprintf (num, sizeof(num), "%i", ci->armor);
				value = CG_Text_Width(num, scale, 0);
				CG_Text_Paint(rect->x + (rect->w - value) / 2, rect->y + rect->h, scale, color, num, 0, 0, textStyle);
			}
		}
 	}
}

qhandle_t CG_StatusHandle(int task)
{
	qhandle_t       h = cgs.media.assaultShader;

	switch (task)
	{
		case TEAMTASK_OFFENSE:
			h = cgs.media.assaultShader;
			break;
		case TEAMTASK_DEFENSE:
			h = cgs.media.defendShader;
			break;
		case TEAMTASK_PATROL:
			h = cgs.media.patrolShader;
			break;
		case TEAMTASK_FOLLOW:
			h = cgs.media.followShader;
			break;
		case TEAMTASK_CAMP:
			h = cgs.media.campShader;
			break;
		case TEAMTASK_RETRIEVE:
			h = cgs.media.retrieveShader;
			break;
		case TEAMTASK_ESCORT:
			h = cgs.media.escortShader;
			break;
		default:
			h = cgs.media.assaultShader;
			break;
	}
	return h;
}

static void CG_DrawSelectedPlayerStatus(rectDef_t * rect)
{
	clientInfo_t   *ci = cgs.clientinfo + sortedTeamPlayers[CG_GetSelectedPlayer()];

	if(ci)
	{
		qhandle_t       h;

		if(cgs.orderPending)
		{
			// blink the icon
			if(cg.time > cgs.orderTime - 2500 && (cg.time >> 9) & 1)
				return;

			h = CG_StatusHandle(cgs.currentOrder);
		}
		else
		{
			h = CG_StatusHandle(ci->teamTask);
		}
		CG_DrawPic(rect->x, rect->y, rect->w, rect->h, h);
	}
}


static void CG_DrawPlayerStatus(rectDef_t * rect)
{
	clientInfo_t   *ci = &cgs.clientinfo[cg.snap->ps.clientNum];

	if(ci)
	{
		qhandle_t       h = CG_StatusHandle(ci->teamTask);

		CG_DrawPic(rect->x, rect->y, rect->w, rect->h, h);
	}
}

static void CG_DrawSelectedPlayerName( rectDef_t *rect, float scale, vec4_t color, qboolean voice, int textStyle) {
	clientInfo_t *ci;
  ci = cgs.clientinfo + ((voice) ? cgs.currentVoiceClient : sortedTeamPlayers[CG_GetSelectedPlayer()]);
  if (ci) {
    CG_Text_Paint(rect->x, rect->y + rect->h, scale, color, ci->name, 0, 0, textStyle);
  }
}

static void CG_DrawSelectedPlayerLocation( rectDef_t *rect, float scale, vec4_t color, int textStyle ) {
	clientInfo_t *ci;
  ci = cgs.clientinfo + sortedTeamPlayers[CG_GetSelectedPlayer()];
  if (ci) {
		const char *p = CG_ConfigString(CS_LOCATIONS + ci->location);
		if (!p || !*p) {
			p = "unknown";
		}
    CG_Text_Paint(rect->x, rect->y + rect->h, scale, color, p, 0, 0, textStyle);
  }
}

static void CG_DrawPlayerLocation( rectDef_t *rect, float scale, vec4_t color, int textStyle  ) {
	clientInfo_t *ci = &cgs.clientinfo[cg.snap->ps.clientNum];
  if (ci) {
		const char *p = CG_ConfigString(CS_LOCATIONS + ci->location);
		if (!p || !*p) {
			p = "unknown";
		}
    CG_Text_Paint(rect->x, rect->y + rect->h, scale, color, p, 0, 0, textStyle);
  }
}



static void CG_DrawSelectedPlayerWeapon( rectDef_t *rect ) {
	clientInfo_t *ci;

  ci = cgs.clientinfo + sortedTeamPlayers[CG_GetSelectedPlayer()];
  if (ci) {
	  if ( cg_weapons[ci->curWeapon].weaponIcon ) {
	    CG_DrawPic( rect->x, rect->y, rect->w, rect->h, cg_weapons[ci->curWeapon].weaponIcon );
		} else {
  	  CG_DrawPic( rect->x, rect->y, rect->w, rect->h, cgs.media.deferShader);
    }
  }
}

static void CG_DrawPlayerScore( rectDef_t *rect, float scale, vec4_t color, qhandle_t shader, int textStyle ) {
  char num[16];
  int value = cg.snap->ps.persistant[PERS_SCORE];

	if (shader) {
		trap_R_SetColor( color );
		CG_DrawPic(rect->x, rect->y, rect->w, rect->h, shader);
		trap_R_SetColor( NULL );
	} else {
		Com_sprintf (num, sizeof(num), "%i", value);
		value = CG_Text_Width(num, scale, 0);
	  CG_Text_Paint(rect->x + (rect->w - value) / 2, rect->y + rect->h, scale, color, num, 0, 0, textStyle);
	}
}

static void CG_DrawPlayerItem( rectDef_t *rect, float scale, qboolean draw2D) {
	int		value;
  vec3_t origin, angles;

	value = cg.snap->ps.stats[STAT_HOLDABLE_ITEM];
	if ( value ) {
		CG_RegisterItemVisuals( value );

		if (qtrue) {
		  CG_RegisterItemVisuals( value );
		  CG_DrawPic( rect->x, rect->y, rect->w, rect->h, cg_items[ value ].icon );
		} else {
 			VectorClear( angles );
			origin[0] = 90;
  		origin[1] = 0;
   		origin[2] = -10;
  		angles[YAW] = ( cg.time & 2047 ) * 360 / 2048.0;
			CG_Draw3DModel(rect->x, rect->y, rect->w, rect->h, cg_items[ value ].models[0], 0, origin, angles );
		}
	}

}


static void CG_DrawSelectedPlayerPowerup( rectDef_t *rect, qboolean draw2D ) {
	clientInfo_t *ci;
  int j;
  float x, y;

  ci = cgs.clientinfo + sortedTeamPlayers[CG_GetSelectedPlayer()];
  if (ci) {
    x = rect->x;
    y = rect->y;

		for (j = 0; j < PW_NUM_POWERUPS; j++) {
			if (ci->powerups & (1 << j)) {
				gitem_t	*item;
				item = BG_FindItemForPowerup( j );
				if (item) {
				  CG_DrawPic( x, y, rect->w, rect->h, trap_R_RegisterShader( item->icon ) );
					x += 3;
					y += 3;
          return;
				}
			}
		}

  }
}


static void CG_DrawSelectedPlayerHead( rectDef_t *rect, qboolean draw2D, qboolean voice ) {
	clipHandle_t	cm;
	clientInfo_t	*ci;
	float			len;
	vec3_t			origin;
	vec3_t			mins, maxs, angles;


  ci = cgs.clientinfo + ((voice) ? cgs.currentVoiceClient : sortedTeamPlayers[CG_GetSelectedPlayer()]);

  if (ci) {
  	if ( cg_draw3dIcons.integer ) {
	  	cm = ci->headModel;
  		if ( !cm ) {
  			return;
	  	}

  		// offset the origin y and z to center the head
  		trap_R_ModelBounds( cm, mins, maxs );

	  	origin[2] = -0.5 * ( mins[2] + maxs[2] );
  		origin[1] = 0.5 * ( mins[1] + maxs[1] );

	  	// calculate distance so the head nearly fills the box
  		// assume heads are taller than wide
  		len = 0.7 * ( maxs[2] - mins[2] );		
  		origin[0] = len / 0.268;	// len / tan( fov/2 )

  		// allow per-model tweaking
  		VectorAdd( origin, ci->headOffset, origin );

    	angles[PITCH] = 0;
    	angles[YAW] = 180;
    	angles[ROLL] = 0;
  	
      CG_Draw3DModel( rect->x, rect->y, rect->w, rect->h, ci->headModel, ci->headSkin, origin, angles );
  	} else if ( cg_drawIcons.integer ) {
	  	CG_DrawPic( rect->x, rect->y, rect->w, rect->h, ci->modelIcon );
  	}

  	// if they are deferred, draw a cross out
  	if ( ci->deferred ) {
  		CG_DrawPic( rect->x, rect->y, rect->w, rect->h, cgs.media.deferShader );
  	}
  }

}


static void CG_DrawPlayerHealth(rectDef_t *rect, float scale, vec4_t color, qhandle_t shader, int textStyle ) {
	playerState_t	*ps;
  int value;
	char	num[16];

	ps = &cg.snap->ps;

	value = ps->stats[STAT_HEALTH];

	if (shader) {
		trap_R_SetColor( color );
		CG_DrawPic(rect->x, rect->y, rect->w, rect->h, shader);
		trap_R_SetColor( NULL );
	} else {
		Com_sprintf (num, sizeof(num), "%i", value);
	  value = CG_Text_Width(num, scale, 0);
	  CG_Text_Paint(rect->x + (rect->w - value) / 2, rect->y + rect->h, scale, color, num, 0, 0, textStyle);
	}
}


static void CG_DrawRedScore(rectDef_t *rect, float scale, vec4_t color, qhandle_t shader, int textStyle ) {
	int value;
	char num[16];
	if ( cgs.scores1 == SCORE_NOT_PRESENT ) {
		Com_sprintf (num, sizeof(num), "-");
	}
	else {
		Com_sprintf (num, sizeof(num), "%i", cgs.scores1);
	}
	value = CG_Text_Width(num, scale, 0);
	CG_Text_Paint(rect->x + rect->w - value, rect->y + rect->h, scale, color, num, 0, 0, textStyle);
}

static void CG_DrawBlueScore(rectDef_t *rect, float scale, vec4_t color, qhandle_t shader, int textStyle ) {
	int value;
	char num[16];

	if ( cgs.scores2 == SCORE_NOT_PRESENT ) {
		Com_sprintf (num, sizeof(num), "-");
	}
	else {
		Com_sprintf (num, sizeof(num), "%i", cgs.scores2);
	}
	value = CG_Text_Width(num, scale, 0);
	CG_Text_Paint(rect->x + rect->w - value, rect->y + rect->h, scale, color, num, 0, 0, textStyle);
}

// FIXME: team name support
static void CG_DrawRedName(rectDef_t *rect, float scale, vec4_t color, int textStyle ) {
  CG_Text_Paint(rect->x, rect->y + rect->h, scale, color, cg_redTeamName.string , 0, 0, textStyle);
}

static void CG_DrawBlueName(rectDef_t *rect, float scale, vec4_t color, int textStyle ) {
  CG_Text_Paint(rect->x, rect->y + rect->h, scale, color, cg_blueTeamName.string, 0, 0, textStyle);
}

static void CG_DrawBlueFlagName(rectDef_t *rect, float scale, vec4_t color, int textStyle ) {
  int i;
  for ( i = 0 ; i < cgs.maxclients ; i++ ) {
	  if ( cgs.clientinfo[i].infoValid && cgs.clientinfo[i].team == TEAM_RED  && cgs.clientinfo[i].powerups & ( 1<< PW_BLUEFLAG )) {
      CG_Text_Paint(rect->x, rect->y + rect->h, scale, color, cgs.clientinfo[i].name, 0, 0, textStyle);
      return;
    }
  }
}

static void CG_DrawBlueFlagStatus(rectDef_t *rect, qhandle_t shader) {
	if (cgs.gametype != GT_CTF && cgs.gametype != GT_1FCTF) {
		if (cgs.gametype == GT_HARVESTER) {
		  vec4_t color = {0, 0, 1, 1};
		  trap_R_SetColor(color);
	    CG_DrawPic( rect->x, rect->y, rect->w, rect->h, cgs.media.blueCubeIcon );
		  trap_R_SetColor(NULL);
		}
		return;
	}
  if (shader) {
		CG_DrawPic( rect->x, rect->y, rect->w, rect->h, shader );
  } else {
	  gitem_t *item = BG_FindItemForPowerup( PW_BLUEFLAG );
    if (item) {
		  vec4_t color = {0, 0, 1, 1};
		  trap_R_SetColor(color);
	    if( cgs.blueflag >= 0 && cgs.blueflag <= 2 ) {
		    CG_DrawPic( rect->x, rect->y, rect->w, rect->h, cgs.media.flagShaders[cgs.blueflag] );
			} else {
		    CG_DrawPic( rect->x, rect->y, rect->w, rect->h, cgs.media.flagShaders[0] );
			}
		  trap_R_SetColor(NULL);
	  }
  }
}

static void CG_DrawBlueFlagHead(rectDef_t *rect) {
  int i;
  for ( i = 0 ; i < cgs.maxclients ; i++ ) {
	  if ( cgs.clientinfo[i].infoValid && cgs.clientinfo[i].team == TEAM_RED  && cgs.clientinfo[i].powerups & ( 1<< PW_BLUEFLAG )) {
      vec3_t angles;
      VectorClear( angles );
 		  angles[YAW] = 180 + 20 * sin( cg.time / 650.0 );;
      CG_DrawHead( rect->x, rect->y, rect->w, rect->h, 0,angles );
      return;
    }
  }
}

static void CG_DrawRedFlagName(rectDef_t *rect, float scale, vec4_t color, int textStyle ) {
  int i;
  for ( i = 0 ; i < cgs.maxclients ; i++ ) {
	  if ( cgs.clientinfo[i].infoValid && cgs.clientinfo[i].team == TEAM_BLUE  && cgs.clientinfo[i].powerups & ( 1<< PW_REDFLAG )) {
      CG_Text_Paint(rect->x, rect->y + rect->h, scale, color, cgs.clientinfo[i].name, 0, 0, textStyle);
      return;
    }
  }
}

static void CG_DrawRedFlagStatus(rectDef_t *rect, qhandle_t shader) {
	if (cgs.gametype != GT_CTF && cgs.gametype != GT_1FCTF) {
		if (cgs.gametype == GT_HARVESTER) {
		  vec4_t color = {1, 0, 0, 1};
		  trap_R_SetColor(color);
	    CG_DrawPic( rect->x, rect->y, rect->w, rect->h, cgs.media.redCubeIcon );
		  trap_R_SetColor(NULL);
		}
		return;
	}
  if (shader) {
		CG_DrawPic( rect->x, rect->y, rect->w, rect->h, shader );
  } else {
	  gitem_t *item = BG_FindItemForPowerup( PW_REDFLAG );
    if (item) {
		  vec4_t color = {1, 0, 0, 1};
		  trap_R_SetColor(color);
	    if( cgs.redflag >= 0 && cgs.redflag <= 2) {
		    CG_DrawPic( rect->x, rect->y, rect->w, rect->h, cgs.media.flagShaders[cgs.redflag] );
			} else {
		    CG_DrawPic( rect->x, rect->y, rect->w, rect->h, cgs.media.flagShaders[0] );
			}
		  trap_R_SetColor(NULL);
	  }
  }
}

static void CG_DrawRedFlagHead(rectDef_t *rect) {
  int i;
  for ( i = 0 ; i < cgs.maxclients ; i++ ) {
	  if ( cgs.clientinfo[i].infoValid && cgs.clientinfo[i].team == TEAM_BLUE  && cgs.clientinfo[i].powerups & ( 1<< PW_REDFLAG )) {
      vec3_t angles;
      VectorClear( angles );
 		  angles[YAW] = 180 + 20 * sin( cg.time / 650.0 );;
      CG_DrawHead( rect->x, rect->y, rect->w, rect->h, 0,angles );
      return;
    }
  }
}

static void CG_HarvesterSkulls(rectDef_t *rect, float scale, vec4_t color, qboolean force2D, int textStyle ) {
	char num[16];
	vec3_t origin, angles;
	qhandle_t handle;
	int value = cg.snap->ps.generic1;

	if (cgs.gametype != GT_HARVESTER) {
		return;
	}

	if( value > 99 ) {
		value = 99;
	}

	Com_sprintf (num, sizeof(num), "%i", value);
	value = CG_Text_Width(num, scale, 0);
	CG_Text_Paint(rect->x + (rect->w - value), rect->y + rect->h, scale, color, num, 0, 0, textStyle);

	if (cg_drawIcons.integer) {
		if (!force2D && cg_draw3dIcons.integer) {
			VectorClear(angles);
			origin[0] = 90;
			origin[1] = 0;
			origin[2] = -10;
			angles[YAW] = ( cg.time & 2047 ) * 360 / 2048.0;
			if( cg.snap->ps.persistant[PERS_TEAM] == TEAM_BLUE ) {
				handle = cgs.media.redCubeModel;
			} else {
				handle = cgs.media.blueCubeModel;
			}
			CG_Draw3DModel( rect->x, rect->y, 35, 35, handle, 0, origin, angles );
		} else {
			if( cg.snap->ps.persistant[PERS_TEAM] == TEAM_BLUE ) {
				handle = cgs.media.redCubeIcon;
			} else {
				handle = cgs.media.blueCubeIcon;
			}
			CG_DrawPic( rect->x + 3, rect->y + 16, 20, 20, handle );
		}
	}
}

static void CG_OneFlagStatus(rectDef_t *rect) {
	if (cgs.gametype != GT_1FCTF) {
		return;
	} else {
		gitem_t *item = BG_FindItemForPowerup( PW_NEUTRALFLAG );
		if (item) {
			if( cgs.flagStatus >= 0 && cgs.flagStatus <= 4 ) {
				vec4_t color = {1, 1, 1, 1};
				int index = 0;
				if (cgs.flagStatus == FLAG_TAKEN_RED) {
					color[1] = color[2] = 0;
					index = 1;
				} else if (cgs.flagStatus == FLAG_TAKEN_BLUE) {
					color[0] = color[1] = 0;
					index = 1;
				} else if (cgs.flagStatus == FLAG_DROPPED) {
					index = 2;
				}
			  trap_R_SetColor(color);
				CG_DrawPic( rect->x, rect->y, rect->w, rect->h, cgs.media.flagShaders[index] );
			}
		}
	}
}

static void CG_DrawTeamColor(rectDef_t *rect, vec4_t color) {
	CG_DrawTeamBackground(rect->x, rect->y, rect->w, rect->h, color[3], cg.snap->ps.persistant[PERS_TEAM]);
}

static void CG_DrawAreaPowerUp(rectDef_t *rect, int align, float special, float scale, vec4_t color) {
	char num[16];
	int		sorted[MAX_POWERUPS];
	int		sortedTime[MAX_POWERUPS];
	int		i, j, k, w;
	int		active;
	playerState_t	*ps;
	int		t;
	gitem_t	*item;
	float	f;
	rectDef_t r2;
	float *inc;
	r2.x = rect->x;
	r2.y = rect->y;
	r2.w = rect->w;
	r2.h = rect->h;

	inc = (align == HUD_VERTICAL) ? &r2.y : &r2.x;

	ps = &cg.snap->ps;

	if ( ps->stats[STAT_HEALTH] <= 0 ) {
		return;
	}

	// sort the list by time remaining
	active = 0;
	for ( i = 0 ; i < MAX_POWERUPS ; i++ ) {
		if ( !ps->powerups[ i ] ) {
			continue;
		}
		t = ps->powerups[ i ] - cg.time;
		// ZOID--don't draw if the power up has unlimited time (999 seconds)
		// This is true of the CTF flags
		if ( t <= 0 || t >= 999000) {
			continue;
		}

		// insert into the list
		for ( j = 0 ; j < active ; j++ ) {
			if ( sortedTime[j] >= t ) {
				for ( k = active - 1 ; k >= j ; k-- ) {
					sorted[k+1] = sorted[k];
					sortedTime[k+1] = sortedTime[k];
				}
				break;
			}
		}
		sorted[j] = i;
		sortedTime[j] = t;
		active++;
	}

	// draw the icons and timers
	for ( i = 0 ; i < active ; i++ ) {
		item = BG_FindItemForPowerup( sorted[i] );

		if (item) {
			t = ps->powerups[ sorted[i] ];
			if ( t - cg.time >= POWERUP_BLINKS * POWERUP_BLINK_TIME ) {
				trap_R_SetColor( NULL );
			} else {
				vec4_t	modulate;

				f = (float)( t - cg.time ) / POWERUP_BLINK_TIME;
				f -= (int)f;
				modulate[0] = modulate[1] = modulate[2] = modulate[3] = f;
				trap_R_SetColor( modulate );
			}

			CG_DrawPic( r2.x, r2.y, r2.w * .75, r2.h, trap_R_RegisterShader( item->icon ) );

			Com_sprintf (num, sizeof(num), "%i", sortedTime[i] / 1000);
			w = ((r2.w * .75) - CG_Text_Width( num, scale, 0 ))/2;
			CG_Text_Paint(r2.x + w + 1, r2.y + r2.h, scale, color, num, 0, 0, 0);
			*inc += r2.w + special;
		}

	}
	trap_R_SetColor( NULL );

}

float CG_GetValue(int ownerDraw) {
	centity_t	*cent;
 	clientInfo_t *ci;
	playerState_t	*ps;

  cent = &cg_entities[cg.snap->ps.clientNum];
	ps = &cg.snap->ps;

  switch (ownerDraw) {
  case CG_SELECTEDPLAYER_ARMOR:
    ci = cgs.clientinfo + sortedTeamPlayers[CG_GetSelectedPlayer()];
    return ci->armor;
    break;
  case CG_SELECTEDPLAYER_HEALTH:
    ci = cgs.clientinfo + sortedTeamPlayers[CG_GetSelectedPlayer()];
    return ci->health;
    break;
  case CG_PLAYER_ARMOR_VALUE:
		return ps->stats[STAT_ARMOR];
    break;
  case CG_PLAYER_AMMO_VALUE:
		if ( cent->currentState.weapon ) {
		  return ps->ammo[cent->currentState.weapon];
		}
    break;
  case CG_PLAYER_SCORE:
	  return cg.snap->ps.persistant[PERS_SCORE];
    break;
  case CG_PLAYER_HEALTH:
		return ps->stats[STAT_HEALTH];
    break;
  case CG_RED_SCORE:
		return cgs.scores1;
    break;
  case CG_BLUE_SCORE:
		return cgs.scores2;
    break;
  default:
    break;
  }
	return -1;
}

qboolean CG_OtherTeamHasFlag(void) {
	if (cgs.gametype == GT_CTF || cgs.gametype == GT_1FCTF) {
		int team = cg.snap->ps.persistant[PERS_TEAM];
		if (cgs.gametype == GT_1FCTF) {
			if (team == TEAM_RED && cgs.flagStatus == FLAG_TAKEN_BLUE) {
				return qtrue;
			} else if (team == TEAM_BLUE && cgs.flagStatus == FLAG_TAKEN_RED) {
				return qtrue;
			} else {
				return qfalse;
			}
		} else {
			if (team == TEAM_RED && cgs.redflag == FLAG_TAKEN) {
				return qtrue;
			} else if (team == TEAM_BLUE && cgs.blueflag == FLAG_TAKEN) {
				return qtrue;
			} else {
				return qfalse;
			}
		}
	}
	return qfalse;
}

qboolean CG_YourTeamHasFlag(void) {
	if (cgs.gametype == GT_CTF || cgs.gametype == GT_1FCTF) {
		int team = cg.snap->ps.persistant[PERS_TEAM];
		if (cgs.gametype == GT_1FCTF) {
			if (team == TEAM_RED && cgs.flagStatus == FLAG_TAKEN_RED) {
				return qtrue;
			} else if (team == TEAM_BLUE && cgs.flagStatus == FLAG_TAKEN_BLUE) {
				return qtrue;
			} else {
				return qfalse;
			}
		} else {
			if (team == TEAM_RED && cgs.blueflag == FLAG_TAKEN) {
				return qtrue;
			} else if (team == TEAM_BLUE && cgs.redflag == FLAG_TAKEN) {
				return qtrue;
			} else {
				return qfalse;
			}
		}
	}
	return qfalse;
}

static void CG_DrawProgressBar(rectDef_t *rect, vec4_t color, float scale, int align, int textStyle, int special, float progress)
{
	float rimWidth = rect->h / 20.0f;
	float doneWidth, leftWidth;
	float tx, ty, tw, th;
	char textBuffer[8];
   
	if(rimWidth < 0.6f)
		rimWidth = 0.6f;

	if(special >= 0.0f)
		rimWidth = special;

	if(progress < 0.0f)
		progress = 0.0f;
	else if(progress > 1.0f)
		progress = 1.0f;
   
	doneWidth = (rect->w - 2 * rimWidth) * progress;
	leftWidth = (rect->w - 2 * rimWidth) - doneWidth;
   
	trap_R_SetColor( color );
   
	// draw rim and bar
	if( align == ITEM_ALIGN_RIGHT )
	{
		CG_DrawPic(rect->x, rect->y, rimWidth, rect->h, cgs.media.whiteShader);
		CG_DrawPic(rect->x + rimWidth, rect->y, leftWidth, rimWidth, cgs.media.whiteShader);
		CG_DrawPic(rect->x + rimWidth, rect->y + rect->h - rimWidth, leftWidth, rimWidth, cgs.media.whiteShader);
		CG_DrawPic(rect->x + rimWidth + leftWidth, rect->y, rimWidth + doneWidth, rect->h, cgs.media.whiteShader);
	}
	else
	{
		CG_DrawPic(rect->x, rect->y, rimWidth + doneWidth, rect->h, cgs.media.whiteShader);
		CG_DrawPic(rimWidth + rect->x + doneWidth, rect->y,	leftWidth, rimWidth, cgs.media.whiteShader);
		CG_DrawPic(rimWidth + rect->x + doneWidth, rect->y + rect->h - rimWidth, leftWidth, rimWidth, cgs.media.whiteShader);
		CG_DrawPic(rect->x + rect->w - rimWidth, rect->y, rimWidth, rect->h, cgs.media.whiteShader);
	}

	trap_R_SetColor( NULL );
             
	// draw text
	if(scale > 0.0)
	{
		Com_sprintf(textBuffer, sizeof(textBuffer), "%d%%", (int)(progress * 100));
		tw = CG_Text_Width(textBuffer, scale, 0);
		th = scale * 40.0f;
   
		switch(align)
		{
			case ITEM_ALIGN_LEFT:
				tx = rect->x + (rect->w / 10.0f);
				ty = rect->y + (rect->h / 2.0f) + (th / 2.0f);
				break;

			case ITEM_ALIGN_RIGHT:
				tx = rect->x + rect->w - ( rect->w / 10.0f ) - tw;
				ty = rect->y + ( rect->h / 2.0f ) + ( th / 2.0f );
				break;

			case ITEM_ALIGN_CENTER:
				tx = rect->x + ( rect->w / 2.0f ) - ( tw / 2.0f );
				ty = rect->y + ( rect->h / 2.0f ) + ( th / 2.0f );
				break;

			default:
				tx = ty = 0.0f;
		}
   
		CG_Text_Paint(tx, ty, scale, color, textBuffer, 0, 0, textStyle);
	}
}

static void CG_DrawProgressLabel(rectDef_t *rect, float text_x, float text_y, vec4_t color, float scale, int align, const char *s, float fraction)
{
	vec4_t white = {1.0f, 1.0f, 1.0f, 1.0f};
	float tx, tw = CG_Text_Width(s, scale, 0);

	switch(align)
	{
		case ITEM_ALIGN_LEFT:
			tx = 0.0f;
			break;

		case ITEM_ALIGN_RIGHT:
			tx = rect->w - tw;
			break;

		case ITEM_ALIGN_CENTER:
			tx = (rect->w / 2.0f) - (tw / 2.0f);
			break;

		default:
			tx = 0.0f;
	}
   
	if(fraction < 1.0f)
		CG_Text_Paint(rect->x + text_x + tx, rect->y + text_y, scale, white, s, 0, 0, ITEM_TEXTSTYLE_NORMAL);
	else
		CG_Text_Paint(rect->x + text_x + tx, rect->y + text_y, scale, color, s, 0, 0, ITEM_TEXTSTYLE_NEON);
}

static void CG_DrawMediaProgress(rectDef_t *rect, vec4_t color, float scale, int align, int textStyle, int special)
{
	CG_DrawProgressBar(rect, color, scale, align, textStyle, special, cg.mediaFraction);
}

static void CG_DrawMediaProgressLabel(rectDef_t *rect, float text_x, float text_y, vec4_t color, float scale, int align)
{
   CG_DrawProgressLabel(rect, text_x, text_y, color, scale, align, "Overall", cg.mediaFraction);
}

static void CG_DrawSoundProgress(rectDef_t *rect, vec4_t color, float scale, int align, int textStyle, int special)
{
	CG_DrawProgressBar(rect, color, scale, align, textStyle, special, cg.soundFraction);
}

static void CG_DrawSoundProgressLabel(rectDef_t *rect, float text_x, float text_y, vec4_t color, float scale, int align)
{
   CG_DrawProgressLabel(rect, text_x, text_y, color, scale, align, "Sound", cg.soundFraction);
}

static void CG_DrawGraphicProgress(rectDef_t *rect, vec4_t color, float scale, int align, int textStyle, int special)
{
   CG_DrawProgressBar(rect, color, scale, align, textStyle, special, cg.graphicFraction);
}

static void CG_DrawGraphicProgressLabel(rectDef_t *rect, float text_x, float text_y, vec4_t color, float scale, int align)
{
	CG_DrawProgressLabel(rect, text_x, text_y, color, scale, align, "Graphics", cg.graphicFraction);
}

static void CG_DrawLevelShot(rectDef_t *rect)
{
	const char *s;
	const char *info;
	qhandle_t levelshot;
	qhandle_t detail;
   
	info = CG_ConfigString( CS_SERVERINFO );
	s = Info_ValueForKey( info, "mapname" );
	levelshot = trap_R_RegisterShaderNoMip( va( "levelshots/%s.tga", s ) );
   
	if( !levelshot )
		levelshot = trap_R_RegisterShaderNoMip( "menu/art/unknownmap" );
   
	trap_R_SetColor( NULL );
	CG_DrawPic( rect->x, rect->y, rect->w, rect->h, levelshot );
   
	// blend a detail texture over it
	detail = trap_R_RegisterShader( "levelShotDetail" );
	CG_DrawPic( rect->x, rect->y, rect->w, rect->h, detail );
}

static void CG_DrawLoadingString(rectDef_t *rect, float text_x, float text_y, vec4_t color, float scale, int align, int textStyle, const char *s)
{
	float tw, th, tx;
	int pos, i;
	char buffer[1024];
	char *end;
   
	if(!s[0])
		return;
   
	strcpy(buffer, s);
	tw = CG_Text_Width(s, scale, 0);
	th = scale * 40.0f;

	pos = i = 0;
             
	while(pos < strlen(s))
	{
		strcpy(buffer, &s[pos]);
		tw = CG_Text_Width(buffer, scale, 0);

		while(tw > rect->w)
		{
			end = strrchr(buffer, ' ');
   
			if(end == NULL)
				break;
   
			*end = '\0';
			tw = CG_Text_Width( buffer, scale, 0 );
		}

		switch(align)
		{
			case ITEM_ALIGN_LEFT:
				tx = rect->x;
				break;

			case ITEM_ALIGN_RIGHT:
				tx = rect->x + rect->w - tw;
				break;

			case ITEM_ALIGN_CENTER:
				tx = rect->x + (rect->w / 2.0f) - (tw / 2.0f);
				break;

			default:
				tx = 0.0f;
		}
   
		CG_Text_Paint(tx + text_x, rect->y + text_y + i * ( th + 3 ), scale, color, buffer, 0, 0, textStyle);
   
		pos += strlen(buffer) + 1;
		i++;
	}
}

static void CG_DrawLevelName(rectDef_t *rect, float text_x, float text_y, vec4_t color, float scale, int align, int textStyle)
{
	const char *s;
   
	s = CG_ConfigString(CS_MESSAGE);

	CG_DrawLoadingString(rect, text_x, text_y, color, scale, align, textStyle, s);
}

static void CG_DrawMOTD(rectDef_t *rect, float text_x, float text_y, vec4_t color, float scale, int align, int textStyle)
{
	const char *s;
   
	s = CG_ConfigString(CS_MOTD);

	CG_DrawLoadingString(rect, text_x, text_y, color, scale, align, textStyle, s);
}

static void CG_DrawHostname(rectDef_t *rect, float text_x, float text_y, vec4_t color, float scale, int align, int textStyle)
{
	char buffer[1024];
	const char *info;

	info = CG_ConfigString(CS_SERVERINFO);
             
	Q_strncpyz(buffer, Info_ValueForKey(info, "sv_hostname"), 1024);
	Q_CleanStr(buffer);

	CG_DrawLoadingString(rect, text_x, text_y, color, scale, align, textStyle, buffer);
}

/*
=====================
CG_DrawXCrosshairNames
=====================
*/
static void CG_DrawXCrosshairNames(rectDef_t *rect, float scale, int textStyle)
{
	float   *color;
	char    *name;
	float   w, x;

	if(!(HudGroupFlag & XHAIRNAME))
		return;

	if(!cg_drawCrosshair.integer)
		return;
   
	if(!cg_drawCrosshairNames.integer)
		return;
   
	if(cg.renderingThirdPerson)
		return;

	// scan the known entities to see if the crosshair is sighted on one
	CG_ScanForCrosshairEntity();

	// draw the name of the player being looked at
	color = CG_FadeColor(cg.crosshairClientTime, 1000);
	if(!color)
	{
		trap_R_SetColor(NULL);
		return;
	}

	name = cgs.clientinfo[ cg.crosshairClientNum ].name;
	w = CG_Text_Width( name, scale, 0 );
	x = rect->x + rect->w / 2;
	CG_Text_Paint( x - w / 2, rect->y + rect->h, scale, color, name, 0, 0, textStyle );
	trap_R_SetColor( NULL );
}

/*
==============
DrawFieldPadded

Draws large numbers for status bar and powerups
==============
*/
static void CG_DrawFieldPadded(int x, int y, int width, int cw, int ch, int value)
{
	char num[ 16 ], *ptr;
	int l, orgL;
	int frame;
	int charWidth, charHeight;

	charWidth = cw;
	if(!charWidth)
		charWidth = CHAR_WIDTH;

	charHeight = ch;
	if(!charHeight)
		charWidth = CHAR_HEIGHT;

	if(width < 1)
	return;

	// draw number string
	if(width > 4)
		width = 4;

	switch( width )
	{
		case 1:
			value = value > 9 ? 9 : value;
			value = value < 0 ? 0 : value;
			break;
		case 2:
			value = value > 99 ? 99 : value;
			value = value < -9 ? -9 : value;
			break;
		case 3:
			value = value > 999 ? 999 : value;
			value = value < -99 ? -99 : value;
			break;
		case 4:
			value = value > 9999 ? 9999 : value;
			value = value < -999 ? -999 : value;
			break;
	}

	Com_sprintf(num, sizeof(num), "%d", value);
	l = strlen(num);
   
	if(l > width)
		l = width;
   
	orgL = l;
   
	x += 2;

	ptr = num;
	while(*ptr && l)
	{
		if(width > orgL)
		{
			CG_DrawPic(x,y, charWidth, charHeight, cgs.media.numberShaders[0]);
			width--;
			x += charWidth;
			continue;
		}
   
		if(*ptr == '-')
			frame = STAT_MINUS;
		else
			frame = *ptr - '0';

		CG_DrawPic(x,y, charWidth, charHeight, cgs.media.numberShaders[frame]);
		x += charWidth;
		ptr++;
		l--;
	}
}

/*
==============
CG_DrawField

Draws large numbers for status bar and powerups
==============
 */
static void CG_DrawField(int x, int y, int width, int cw, int ch, int value)
{
   char num[ 16 ], *ptr;
   int l;
   int frame;
   int charWidth, charHeight;

 charWidth = cw;
   if( !charWidth)
   charWidth = CHAR_WIDTH;

 charHeight = ch;
   if( !charHeight )
   charWidth = CHAR_HEIGHT;

 if( width < 1 )
   return;

 // draw number string
   if( width > 4 )
   width = 4;

 switch( width )
   {
   case 1:
   value = value > 9 ? 9 : value;
   value = value < 0 ? 0 : value;
   break;
   case 2:
   value = value > 99 ? 99 : value;
   value = value < -9 ? -9 : value;
   break;
   case 3:
   value = value > 999 ? 999 : value;
   value = value < -99 ? -99 : value;
   break;
   case 4:
   value = value > 9999 ? 9999 : value;
   value = value < -999 ? -999 : value;
   break;
   }

 Com_sprintf( num, sizeof( num ), "%d", value );
   l = strlen( num );
   
   if( l > width )
   l = width;
   
   x += 2 + charWidth * ( width - l );

 ptr = num;
   while( *ptr && l )
   {
   if( *ptr == '-' )
   frame = STAT_MINUS;
   else
   frame = *ptr -'0';

 CG_DrawPic( x,y, charWidth, charHeight, cgs.media.numberShaders[ frame ] );
   x += charWidth;
   ptr++;
   l--;
   }
   }

/*
==================
CG_DrawXFPS
==================
*/
//TA: personally i think this should be longer - it should really be a cvar
#define FPS_XFRAMES 20
#define FPS_STRING "fps"
static void CG_DrawXFPS(rectDef_t *rect, float text_x, float text_y, float scale, vec4_t color, int align, int textStyle, qboolean scalableText)
{
   char *s;
   int tx, w, totalWidth, strLength;
   static int previousTimes[ FPS_XFRAMES ];
   static int index;
   int i, total;
   int fps;
   static int previous;
   int t, frameTime;

 if(!(HudGroupFlag & UPPERIGHT))
   return;

 if( !cg_drawFPS.integer )
   return;
   
   // don't use serverTime, because that will be drifting to
   // correct for internet lag changes, timescales, timedemos, etc
   t = trap_Milliseconds( );
   frameTime = t - previous;
   previous = t;

 previousTimes[ index % FPS_XFRAMES ] = frameTime;
   index++;
   
   if( index > FPS_XFRAMES )
   {
   // average multiple frames together to smooth changes out a bit
   total = 0;
   
   for( i = 0 ; i < FPS_XFRAMES ; i++ )
   total += previousTimes[ i ];
   
   if( !total )
   total = 1;
   
   fps = 1000 * FPS_XFRAMES / total;

 s = va( "%d", fps );
   w = CG_Text_Width( "0", scale, 0 );
   strLength = CG_DrawStrlen( s );
   totalWidth = CG_Text_Width( FPS_STRING, scale, 0 ) + w * strLength;
   
   switch( align )
   {
   case ITEM_ALIGN_LEFT:
   tx = rect->x;
   break;

 case ITEM_ALIGN_RIGHT:
   tx = rect->x + rect->w - totalWidth;
   break;

 case ITEM_ALIGN_CENTER:
   tx = rect->x + ( rect->w / 2.0f ) - ( totalWidth / 2.0f );
   break;

 default:
   tx = 0.0f;
   }
   
   if( scalableText )
   {
   for( i = 0; i < strLength; i++ )
   {
   char c[ 2 ];

 c[ 0 ] = s[ i ];
   c[ 1 ] = '\0';
   
   CG_Text_Paint( text_x + tx + i * w, rect->y + text_y, scale, color, c, 0, 0, textStyle );
   }
   }
   else
   {
   trap_R_SetColor( color );
   CG_DrawField( rect->x, rect->y, 3, rect->w / 3, rect->h, fps );
   trap_R_SetColor( NULL );
   }
   
   if( scalableText )
   CG_Text_Paint( text_x + tx + i * w, rect->y + text_y, scale, color, FPS_STRING, 0, 0, textStyle );
   }
   }

/*
=================
CG_DrawTimerMins
=================
*/
static void CG_DrawTimerMins( rectDef_t *rect, vec4_t color )
{
   int mins, seconds;
   int msec;

 if(!(HudGroupFlag & UPPERIGHT))
   return;

 if( !cg_drawTimer.integer )
   return;

 msec = cg.time - cgs.levelStartTime;

 seconds = msec / 1000;
   mins = seconds / 60;
   seconds -= mins * 60;

 trap_R_SetColor( color );
   CG_DrawField( rect->x, rect->y, 3, rect->w / 3, rect->h, mins );
   trap_R_SetColor( NULL );
}      

/*
=================
CG_DrawTimerSecs
=================
*/
static void CG_DrawTimerSecs(rectDef_t *rect, vec4_t color)
{
   int mins, seconds;
   int msec;

 if(!(HudGroupFlag & UPPERIGHT))
   return;

 if( !cg_drawTimer.integer )
   return;

 msec = cg.time - cgs.levelStartTime;

 seconds = msec / 1000;
   mins = seconds / 60;
   seconds -= mins * 60;

 trap_R_SetColor( color );
   CG_DrawFieldPadded( rect->x, rect->y, 2, rect->w / 2, rect->h, seconds );
   trap_R_SetColor( NULL );
}       

/*
=================
CG_DrawTimer
=================
*/
static void CG_DrawTimer(rectDef_t *rect, float text_x, float text_y, float scale, vec4_t color, int align, int textStyle)
   {
   char *s;
   int i, tx, w, totalWidth, strLength;
   int mins, seconds, tens;
   int msec;

 if(!(HudGroupFlag & UPPERIGHT))
   return;

 if( !cg_drawTimer.integer )
   return;

 msec = cg.time - cgs.levelStartTime;

 seconds = msec / 1000;
   mins = seconds / 60;
   seconds -= mins * 60;
   tens = seconds / 10;
   seconds -= tens * 10;

 s = va( "%d:%d%d", mins, tens, seconds );
   w = CG_Text_Width( "0", scale, 0 );
   strLength = CG_DrawStrlen( s );
   totalWidth = w * strLength;
   
   switch( align )
   {
   case ITEM_ALIGN_LEFT:
   tx = rect->x;
   break;

 case ITEM_ALIGN_RIGHT:
   tx = rect->x + rect->w - totalWidth;
   break;

 case ITEM_ALIGN_CENTER:
   tx = rect->x + ( rect->w / 2.0f ) - ( totalWidth / 2.0f );
   break;

 default:
   tx = 0.0f;
   }

 for( i = 0; i < strLength; i++ )
   {
   char c[ 2 ];

 c[ 0 ] = s[ i ];
   c[ 1 ] = '\0';
   
   CG_Text_Paint( text_x + tx + i * w, rect->y + text_y, scale, color, c, 0, 0, textStyle );
   }
   }

/*
==================
CG_DrawXSnapshot
==================
*/
static void CG_DrawXSnapshot(rectDef_t *rect, float text_x, float text_y, float scale, vec4_t color, int align, int textStyle)
{
   char *s;
   int w, tx;

 if(!(HudGroupFlag & UPPERIGHT))
   return;

 if( !cg_drawSnapshot.integer )
   return;
   
   s = va( "time:%d snap:%d cmd:%d", cg.snap->serverTime,
   cg.latestSnapshotNum, cgs.serverCommandSequence );
   w = CG_Text_Width( s, scale, 0 );
   
   switch( align )
   {
   case ITEM_ALIGN_LEFT:
   tx = rect->x;
   break;

 case ITEM_ALIGN_RIGHT:
   tx = rect->x + rect->w - w;
   break;

 case ITEM_ALIGN_CENTER:
   tx = rect->x + ( rect->w / 2.0f ) - ( w / 2.0f );
   break;

 default:
   tx = 0.0f;
   }

 CG_Text_Paint( text_x + tx, rect->y + text_y, scale, color, s, 0, 0, textStyle );
}

#define LAG_SAMPLES 128

typedef struct
{
   int frameSamples[ LAG_SAMPLES ];
   int frameCount;
   int snapshotFlags[ LAG_SAMPLES ];
   int snapshotSamples[ LAG_SAMPLES ];
   int snapshotCount;
} lagometer_t;

lagometer_t lagometer;

/*
==============
CG_DrawXDisconnect

Should we draw something differnet for long lag vs no packets?
==============
*/
static void CG_DrawXDisconnect( void )
{
   float x, y;
   int cmdNum;
   usercmd_t cmd;
   const char *s;
   int w;
   vec4_t color = { 1.0f, 1.0f, 1.0f, 1.0f };

 // draw the phone jack if we are completely past our buffers
   cmdNum = trap_GetCurrentCmdNumber( ) - CMD_BACKUP + 1;
   trap_GetUserCmd( cmdNum, &cmd );
   
   // special check for map_restart
   if( cmd.serverTime <= cg.snap->ps.commandTime || cmd.serverTime > cg.time )
   return;

 // also add text in center of screen
   s = "Connection Interrupted";
   w = CG_Text_Width( s, 0.7f, 0 );
   CG_Text_Paint( 320 - w / 2, 100, 0.7f, color, s, 0, 0, ITEM_TEXTSTYLE_SHADOWED );

 // blink the icon
   if( ( cg.time >> 9 ) & 1 )
   return;

 x = 640 - 48;
   y = 480 - 48;

 CG_DrawPic( x, y, 48, 48, trap_R_RegisterShader( "gfx/2d/net.tga" ) );
}

#define MAX_LAGOMETER_PING 900
#define MAX_LAGOMETER_RANGE 300
#define PING_FRAMES 40

/*
==============
CG_DrawXLagometer
==============
*/
static void CG_DrawXLagometer(rectDef_t *rect, float text_x, float text_y, float scale, vec4_t textColor)
{
   int a, x, y, i;
   float v;
   float ax, ay, aw, ah, mid, range;
   int color;
   vec4_t adjustedColor;
   float vscale;
   vec4_t white = { 1.0f, 1.0f, 1.0f, 1.0f };

 if(!(HudGroupFlag & UPPERIGHT))
   return;

 if( cg.snap->ps.pm_type == PM_INTERMISSION )
   return;

 if( !cg_lagometer.integer )
   return;

 if( cg.demoPlayback )
   return;

 Vector4Copy( textColor, adjustedColor );
   adjustedColor[ 3 ] = 0.25f;
   
   trap_R_SetColor( adjustedColor );
   CG_DrawPic( rect->x, rect->y, rect->w, rect->h, cgs.media.whiteShader );
   trap_R_SetColor( NULL );
   
   //
   // draw the graph
   //
   ax = x = rect->x;
   ay = y = rect->y;
   aw = rect->w;
   ah = rect->h;

 trap_R_SetColor( NULL );

 CG_AdjustFrom640( &ax, &ay, &aw, &ah );

 color = -1;
   range = ah / 3;
   mid = ay + range;

 vscale = range / MAX_LAGOMETER_RANGE;

 // draw the frame interpoalte / extrapolate graph
   for( a = 0 ; a < aw ; a++ )
   {
   i = ( lagometer.frameCount - 1 - a ) & ( LAG_SAMPLES - 1 );
   v = lagometer.frameSamples[ i ];
   v *= vscale;
   
   if( v > 0 )
   {
   if( color != 1 )
   {
   color = 1;
   trap_R_SetColor( g_color_table[ ColorIndex( COLOR_YELLOW ) ] );
   }
   
   if( v > range )
   v = range;
   
   trap_R_DrawStretchPic( ax + aw - a, mid - v, 1, v, 0, 0, 0, 0, cgs.media.whiteShader );
   }
   else if( v < 0 )
   {
   if( color != 2 )
   {
   color = 2;
   trap_R_SetColor( g_color_table[ ColorIndex( COLOR_BLUE ) ] );
   }
   
   v = -v;
   if( v > range )
   v = range;
   
   trap_R_DrawStretchPic( ax + aw - a, mid, 1, v, 0, 0, 0, 0, cgs.media.whiteShader );
   }
   }

 // draw the snapshot latency / drop graph
   range = ah / 2;
   vscale = range / MAX_LAGOMETER_PING;

 for( a = 0 ; a < aw ; a++ )
   {
   i = ( lagometer.snapshotCount - 1 - a ) & ( LAG_SAMPLES - 1 );
   v = lagometer.snapshotSamples[ i ];
   
   if( v > 0 )
   {
   if( lagometer.snapshotFlags[ i ] & SNAPFLAG_RATE_DELAYED )
   {
   if( color != 5 )
   {
   color = 5; // YELLOW for rate delay
   trap_R_SetColor( g_color_table[ ColorIndex( COLOR_YELLOW ) ] );
   }
   }
   else
   {
   if( color != 3 )
   {
   color = 3;
   
   trap_R_SetColor( g_color_table[ ColorIndex( COLOR_GREEN ) ] );
   }
   }
   
   v = v * vscale;
   
   if( v > range )
   v = range;
   
   trap_R_DrawStretchPic( ax + aw - a, ay + ah - v, 1, v, 0, 0, 0, 0, cgs.media.whiteShader );
   }
   else if( v < 0 )
   {
   if( color != 4 )
   {
   color = 4; // RED for dropped snapshots
   trap_R_SetColor( g_color_table[ ColorIndex( COLOR_RED ) ] );
   }
   
   trap_R_DrawStretchPic( ax + aw - a, ay + ah - range, 1, range, 0, 0, 0, 0, cgs.media.whiteShader );
   }
   }

 trap_R_SetColor( NULL );

 if( cg_nopredict.integer || cg_synchronousClients.integer )
   CG_Text_Paint( ax, ay, 0.5, white, "snc", 0, 0, ITEM_TEXTSTYLE_NORMAL );
   else
   {
   static int previousPings[ PING_FRAMES ];
   static int index;
   int i, ping = 0;
   char *s;

 previousPings[ index++ ] = cg.snap->ping;
   index = index % PING_FRAMES;

 for( i = 0; i < PING_FRAMES; i++ )
   ping += previousPings[ i ];

 ping /= PING_FRAMES;
             
   s = va( "%d", ping );
   ax = rect->x + ( rect->w / 2.0f ) - ( CG_Text_Width( s, scale, 0 ) / 2.0f ) + text_x;
   ay = rect->y + ( rect->h / 2.0f ) + ( CG_Text_Height( s, scale, 0 ) / 2.0f ) + text_y;

 Vector4Copy( textColor, adjustedColor );
   adjustedColor[ 3 ] = 0.5f;
   CG_Text_Paint( ax, ay, scale, adjustedColor, s, 0, 0, ITEM_TEXTSTYLE_NORMAL );
   }

 CG_DrawXDisconnect( );
}

/*
==============
CG_DrawConsole
==============
*/
static void CG_DrawConsole(rectDef_t *rect, float text_x, float text_y, vec4_t color, float scale, int align, int textStyle)
{
   float x, y, w, h;

 //for some reason if these are stored locally occasionally rendering fails
   //even though they are both live until the end of the function, hence static
   //possible compiler bug??
   static menuDef_t dummyParent;
   static itemDef_t textItem;

 if(!(HudGroupFlag & XCONSOLE))
   return;

 //offset the text
   x = rect->x;
   y = rect->y;
   w = rect->w - ( 16 + ( 2 * text_x ) ); //16 to ensure text within frame
   h = rect->h;

 textItem.text = cg.consoleText;
             
   textItem.parent = &dummyParent;
   memcpy( textItem.window.foreColor, color, sizeof( vec4_t ) );
   textItem.window.flags = 0;

 switch( align )
   {
   case ITEM_ALIGN_LEFT:
   textItem.window.rect.x = x;
   break;

 case ITEM_ALIGN_RIGHT:
   textItem.window.rect.x = x + w;
   break;

 case ITEM_ALIGN_CENTER:
   textItem.window.rect.x = x + ( w / 2 );
   break;

 default:
   textItem.window.rect.x = x;
   break;
   }
   
   textItem.window.rect.y = y;
   textItem.window.rect.w = w;
   textItem.window.rect.h = h;
   textItem.window.borderSize = 0;
   textItem.textRect.x = 0;
   textItem.textRect.y = 0;
   textItem.textRect.w = 0;
   textItem.textRect.h = 0;
   textItem.textalignment = align;
   textItem.textalignx = text_x;
   textItem.textaligny = text_y;
   textItem.textscale = scale;
   textItem.textStyle = textStyle;

 //hack to utilise existing autowrap code
   Item_Text_AutoWrapped_Paint( &textItem ); 
}

/*
====================
CG_DrawXWeaponSelect
====================
*/
static void CG_DrawXWeaponSelect(rectDef_t *rect, int align, float special, float scale, vec4_t forecolor, int textStyle)
{
   rectDef_t r2;
   int i;
   int bits;
   int count;
   int x, y;
   float *color;

 if(!(HudGroupFlag & XWEAPONSELECT))
   return;

 r2.x = rect->x;
   r2.y = rect->y;
   r2.w = rect->w;
   r2.h = rect->h;

 if(special==0)
   special = 4;

 // don't display if dead
   if ( cg.predictedPlayerState.stats[STAT_HEALTH] <= 0 ) {
   return;
   }

 color = CG_FadeColor( cg.weaponSelectTime, WEAPON_SELECT_TIME );
   if ( !color ) {
   return;
   }
   trap_R_SetColor( color );

 // showing weapon select clears pickup item display, but not the blend blob
   cg.itemPickupTime = 0;

 // count the number of weapons owned
   bits = cg.snap->ps.stats[ STAT_WEAPONS ];
   count = 0;
   for ( i = 1 ; i < 16 ; i++ ) {
   if ( bits & ( 1 << i ) ) {
   count++;
   }
   }

 if (align == HUD_VERTICAL) {
   x = r2.x;
   y = r2.y; 
   }
   else {
   x = r2.x - count * (r2.w/2);
   y = r2.y;
   }

 for ( i = 1 ; i < 16 ; i++ ) {
   if ( !( bits & ( 1 << i ) ) ) {
   continue;
   }

 CG_RegisterWeapon( i );

 // draw weapon icon
   CG_DrawPic( x+special, y+special, r2.w-(special*2), r2.h-(special*2), cg_weapons[i].weaponIcon );

 // draw selection marker
   if ( i == cg.weaponSelect ) {
   CG_DrawPic( x, y, r2.w, r2.h, cgs.media.selectShader );
   }

 // no ammo cross on top
   if ( !cg.snap->ps.ammo[ i ] ) {
   CG_DrawPic( x+special, y+special, r2.w-(special*2), r2.h-(special*2), cgs.media.noammoShader );
   }

 if (align == HUD_VERTICAL) {
   y += r2.h;
   }
   else {
   x += r2.w;
   }
   }

 trap_R_SetColor( NULL );
}

/*
====================
CG_XCenterPrint
====================
*/
static void CG_XCenterPrint( rectDef_t *rect, float text_x, float text_y, float scale, vec4_t forecolor, int align, int textStyle )
{
   char *start;
   int l;
   int y, w;
   int tx ;
   float *color;

 
   if(!(HudGroupFlag & XCENTERPRINT))
   return;

 if ( !cg.centerPrintTime ) {
   return;
   }

 color = CG_FadeColor( cg.centerPrintTime, 1000 * cg_centertime.value );
   if ( !color ) {
   return;
   }

 trap_R_SetColor( color );

 start = cg.centerPrint;

 y = text_y;

 while ( 1 ) {
   char linebuffer[1024];

 for ( l = 0; l < 50; l++ ) {
   if ( !start[l] || start[l] == '\n' ) {
   break;
   }
   linebuffer[l] = start[l];
   }
   linebuffer[l] = 0;

 w = CG_Text_Width(linebuffer, scale, 0);
   switch( align )
   {
   case ITEM_ALIGN_LEFT:
   tx = rect->x + text_x;
   break;

 case ITEM_ALIGN_RIGHT:
   tx = rect->x - w + text_x;
   break;

 case ITEM_ALIGN_CENTER:
   tx = rect->x - ( w / 2.0f ) + text_x;
   break;

 default:
   tx = rect->x + text_x;
   }

 CG_Text_Paint(tx, rect->y + y, scale, color, linebuffer, 0, 0, textStyle);
   y += text_y;

 while ( *start && ( *start != '\n' ) ) {
   start++;
   }
   if ( !*start ) {
   break;
   }
   start++;
   }

 trap_R_SetColor( NULL );
}

// THINKABOUTME: should these be exclusive or inclusive.. 
qboolean CG_OwnerDrawVisible(int flags) {

	if (flags & CG_SHOW_TEAMINFO) {
		return (cg_currentSelectedPlayer.integer == numSortedTeamPlayers);
	}

	if (flags & CG_SHOW_NOTEAMINFO) {
		return !(cg_currentSelectedPlayer.integer == numSortedTeamPlayers);
	}

	if (flags & CG_SHOW_OTHERTEAMHASFLAG) {
		return CG_OtherTeamHasFlag();
	}

	if (flags & CG_SHOW_YOURTEAMHASENEMYFLAG) {
		return CG_YourTeamHasFlag();
	}

	if (flags & (CG_SHOW_BLUE_TEAM_HAS_REDFLAG | CG_SHOW_RED_TEAM_HAS_BLUEFLAG)) {
		if (flags & CG_SHOW_BLUE_TEAM_HAS_REDFLAG && (cgs.redflag == FLAG_TAKEN || cgs.flagStatus == FLAG_TAKEN_RED)) {
			return qtrue;
		} else if (flags & CG_SHOW_RED_TEAM_HAS_BLUEFLAG && (cgs.blueflag == FLAG_TAKEN || cgs.flagStatus == FLAG_TAKEN_BLUE)) {
			return qtrue;
		}
		return qfalse;
	}

	if (flags & CG_SHOW_ANYTEAMGAME) {
		if( cgs.gametype >= GT_TEAM) {
			return qtrue;
		}
	}

	if (flags & CG_SHOW_ANYNONTEAMGAME) {
		if( cgs.gametype < GT_TEAM) {
			return qtrue;
		}
	}

	if (flags & CG_SHOW_HARVESTER) {
		if( cgs.gametype == GT_HARVESTER ) {
			return qtrue;
    } else {
      return qfalse;
    }
	}

	if (flags & CG_SHOW_ONEFLAG) {
		if( cgs.gametype == GT_1FCTF ) {
			return qtrue;
    } else {
      return qfalse;
    }
	}

	if (flags & CG_SHOW_CTF) {
		if( cgs.gametype == GT_CTF ) {
			return qtrue;
		}
	}

	if (flags & CG_SHOW_OBELISK) {
		if( cgs.gametype == GT_OBELISK ) {
			return qtrue;
    } else {
      return qfalse;
    }
	}

	if (flags & CG_SHOW_HEALTHCRITICAL) {
		if (cg.snap->ps.stats[STAT_HEALTH] < 25) {
			return qtrue;
		}
	}

	if (flags & CG_SHOW_HEALTHOK) {
		if (cg.snap->ps.stats[STAT_HEALTH] >= 25) {
			return qtrue;
		}
	}

	if (flags & CG_SHOW_SINGLEPLAYER) {
		if( cgs.gametype == GT_SINGLE_PLAYER ) {
			return qtrue;
		}
	}

	if (flags & CG_SHOW_TOURNAMENT) {
		if( cgs.gametype == GT_TOURNAMENT ) {
			return qtrue;
		}
	}

	if (flags & CG_SHOW_DURINGINCOMINGVOICE) {
	}

	if (flags & CG_SHOW_IF_PLAYER_HAS_FLAG) {
		if (cg.snap->ps.powerups[PW_REDFLAG] || cg.snap->ps.powerups[PW_BLUEFLAG] || cg.snap->ps.powerups[PW_NEUTRALFLAG]) {
			return qtrue;
		}
	}
	return qfalse;
}



static void CG_DrawPlayerHasFlag(rectDef_t *rect, qboolean force2D) {
	int adj = (force2D) ? 0 : 2;
	if( cg.predictedPlayerState.powerups[PW_REDFLAG] ) {
  	CG_DrawFlagModel( rect->x + adj, rect->y + adj, rect->w - adj, rect->h - adj, TEAM_RED, force2D);
	} else if( cg.predictedPlayerState.powerups[PW_BLUEFLAG] ) {
  	CG_DrawFlagModel( rect->x + adj, rect->y + adj, rect->w - adj, rect->h - adj, TEAM_BLUE, force2D);
	} else if( cg.predictedPlayerState.powerups[PW_NEUTRALFLAG] ) {
  	CG_DrawFlagModel( rect->x + adj, rect->y + adj, rect->w - adj, rect->h - adj, TEAM_FREE, force2D);
	}
}

static void CG_DrawAreaSystemChat(rectDef_t *rect, float scale, vec4_t color, qhandle_t shader) {
  CG_Text_Paint(rect->x, rect->y + rect->h, scale, color, systemChat, 0, 0, 0);
}

static void CG_DrawAreaTeamChat(rectDef_t *rect, float scale, vec4_t color, qhandle_t shader) {
  CG_Text_Paint(rect->x, rect->y + rect->h, scale, color,teamChat1, 0, 0, 0);
}

static void CG_DrawAreaChat(rectDef_t *rect, float scale, vec4_t color, qhandle_t shader) {
  CG_Text_Paint(rect->x, rect->y + rect->h, scale, color, teamChat2, 0, 0, 0);
}

const char *CG_GetKillerText(void) {
	const char *s = "";
	if ( cg.killerName[0] ) {
		s = va("Fragged by %s", cg.killerName );
	}
	return s;
}


static void CG_DrawKiller(rectDef_t *rect, float scale, vec4_t color, qhandle_t shader, int textStyle ) {
	// fragged by ... line
	if ( cg.killerName[0] ) {
		int x = rect->x + rect->w / 2;
	  CG_Text_Paint(x - CG_Text_Width(CG_GetKillerText(), scale, 0) / 2, rect->y + rect->h, scale, color, CG_GetKillerText(), 0, 0, textStyle);
	}
	
}


static void CG_DrawCapFragLimit(rectDef_t *rect, float scale, vec4_t color, qhandle_t shader, int textStyle) {
	int limit = (cgs.gametype >= GT_CTF) ? cgs.capturelimit : cgs.fraglimit;
	CG_Text_Paint(rect->x, rect->y, scale, color, va("%2i", limit),0, 0, textStyle); 
}

static void CG_Draw1stPlace(rectDef_t *rect, float scale, vec4_t color, qhandle_t shader, int textStyle) {
	if (cgs.scores1 != SCORE_NOT_PRESENT) {
		CG_Text_Paint(rect->x, rect->y, scale, color, va("%2i", cgs.scores1),0, 0, textStyle); 
	}
}

static void CG_Draw2ndPlace(rectDef_t *rect, float scale, vec4_t color, qhandle_t shader, int textStyle) {
	if (cgs.scores2 != SCORE_NOT_PRESENT) {
		CG_Text_Paint(rect->x, rect->y, scale, color, va("%2i", cgs.scores2),0, 0, textStyle); 
	}
}

const char *CG_GetGameStatusText(void) {
	const char *s = "";
	if ( cgs.gametype < GT_TEAM) {
		if (cg.snap->ps.persistant[PERS_TEAM] != TEAM_SPECTATOR ) {
			s = va("%s place with %i",CG_PlaceString( cg.snap->ps.persistant[PERS_RANK] + 1 ),cg.snap->ps.persistant[PERS_SCORE] );
		}
	} else {
		if ( cg.teamScores[0] == cg.teamScores[1] ) {
			s = va("Teams are tied at %i", cg.teamScores[0] );
		} else if ( cg.teamScores[0] >= cg.teamScores[1] ) {
			s = va("Red leads Blue, %i to %i", cg.teamScores[0], cg.teamScores[1] );
		} else {
			s = va("Blue leads Red, %i to %i", cg.teamScores[1], cg.teamScores[0] );
		}
	}
	return s;
}
	
static void CG_DrawGameStatus(rectDef_t *rect, float scale, vec4_t color, qhandle_t shader, int textStyle ) {
	CG_Text_Paint(rect->x, rect->y + rect->h, scale, color, CG_GetGameStatusText(), 0, 0, textStyle);
}

const char *CG_GameTypeString(void) {
	if ( cgs.gametype == GT_FFA ) {
		return "Free For All";
	} else if ( cgs.gametype == GT_TEAM ) {
		return "Team Deathmatch";
	} else if ( cgs.gametype == GT_CTF ) {
		return "Capture the Flag";
	} else if ( cgs.gametype == GT_1FCTF ) {
		return "One Flag CTF";
	} else if ( cgs.gametype == GT_OBELISK ) {
		return "Overload";
	} else if ( cgs.gametype == GT_HARVESTER ) {
		return "Harvester";
	}
	return "";
}
static void CG_DrawGameType(rectDef_t *rect, float scale, vec4_t color, qhandle_t shader, int textStyle ) {
	CG_Text_Paint(rect->x, rect->y + rect->h, scale, color, CG_GameTypeString(), 0, 0, textStyle);
}

static void CG_Text_Paint_Limit(float *maxX, float x, float y, float scale, vec4_t color, const char* text, float adjust, int limit) {
  int len, count;
	vec4_t newColor;
	glyphInfo_t *glyph;
  if (text) {
// TTimo: FIXME
//    const unsigned char *s = text; // bk001206 - unsigned
    const char *s = text;
		float max = *maxX;
		float useScale;
		fontInfo_t *font = &cgDC.Assets.textFont;
		if (scale <= cg_smallFont.value) {
			font = &cgDC.Assets.smallFont;
		} else if (scale > cg_bigFont.value) {
			font = &cgDC.Assets.bigFont;
		}
		useScale = scale * font->glyphScale;
		trap_R_SetColor( color );
    len = strlen(text);					 
		if (limit > 0 && len > limit) {
			len = limit;
		}
		count = 0;
		while (s && *s && count < len) {
			glyph = &font->glyphs[(int)*s]; // TTimo: FIXME: getting nasty warnings without the cast, hopefully this doesn't break the VM build
			if ( Q_IsColorString( s ) ) {
				memcpy( newColor, g_color_table[ColorIndex(*(s+1))], sizeof( newColor ) );
				newColor[3] = color[3];
				trap_R_SetColor( newColor );
				s += 2;
				continue;
			} else {
	      float yadj = useScale * glyph->top;
				if (CG_Text_Width(s, useScale, 1) + x > max) {
					*maxX = 0;
					break;
				}
		    CG_Text_PaintChar(x, y - yadj, 
			                    glyph->imageWidth,
				                  glyph->imageHeight,
					                useScale, 
						              glyph->s,
							            glyph->t,
								          glyph->s2,
									        glyph->t2,
										      glyph->glyph);
	      x += (glyph->xSkip * useScale) + adjust;
				*maxX = x;
				count++;
				s++;
	    }
		}
	  trap_R_SetColor( NULL );
  }

}



#define PIC_WIDTH 12

void CG_DrawNewTeamInfo(rectDef_t *rect, float text_x, float text_y, float scale, vec4_t color, qhandle_t shader) {
	int xx;
	float y;
	int i, j, len, count;
	const char *p;
	vec4_t		hcolor;
	float pwidth, lwidth, maxx, leftOver;
	clientInfo_t *ci;
	gitem_t	*item;
	qhandle_t       h;

	// max player name width
	pwidth = 0;
	count = (numSortedTeamPlayers > 8) ? 8 : numSortedTeamPlayers;
	for (i = 0; i < count; i++) {
		ci = cgs.clientinfo + sortedTeamPlayers[i];
		if ( ci->infoValid && ci->team == cg.snap->ps.persistant[PERS_TEAM]) {
			len = CG_Text_Width( ci->name, scale, 0);
			if (len > pwidth)
				pwidth = len;
		}
	}

	// max location name width
	lwidth = 0;
	for (i = 1; i < MAX_LOCATIONS; i++) {
		p = CG_ConfigString(CS_LOCATIONS + i);
		if (p && *p) {
			len = CG_Text_Width(p, scale, 0);
			if (len > lwidth)
				lwidth = len;
		}
	}

	y = rect->y;

	for (i = 0; i < count; i++) {
		ci = cgs.clientinfo + sortedTeamPlayers[i];
		if ( ci->infoValid && ci->team == cg.snap->ps.persistant[PERS_TEAM]) {

			xx = rect->x + 1;
			for (j = 0; j <= PW_NUM_POWERUPS; j++) {
				if (ci->powerups & (1 << j)) {

					item = BG_FindItemForPowerup( j );

					if (item) {
						CG_DrawPic( xx, y, PIC_WIDTH, PIC_WIDTH, trap_R_RegisterShader( item->icon ) );
						xx += PIC_WIDTH;
					}
				}
			}

			// FIXME: max of 3 powerups shown properly
			xx = rect->x + (PIC_WIDTH * 3) + 2;

			CG_GetColorForHealth( ci->health, ci->armor, hcolor );
			trap_R_SetColor(hcolor);
			CG_DrawPic( xx, y + 1, PIC_WIDTH - 2, PIC_WIDTH - 2, cgs.media.heartShader );

			//Com_sprintf (st, sizeof(st), "%3i %3i", ci->health,	ci->armor);
			//CG_Text_Paint(xx, y + text_y, scale, hcolor, st, 0, 0); 

			// draw weapon icon
			xx += PIC_WIDTH + 1;

// weapon used is not that useful, use the space for task
#if 0
			if ( cg_weapons[ci->curWeapon].weaponIcon ) {
				CG_DrawPic( xx, y, PIC_WIDTH, PIC_WIDTH, cg_weapons[ci->curWeapon].weaponIcon );
			} else {
				CG_DrawPic( xx, y, PIC_WIDTH, PIC_WIDTH, cgs.media.deferShader );
			}
#endif

			trap_R_SetColor(NULL);

			if(cgs.orderPending)
			{
				// blink the icon
				if(cg.time > cgs.orderTime - 2500 && (cg.time >> 9) & 1)
				{
					h = 0;
				}
				else
				{
					h = CG_StatusHandle(cgs.currentOrder);
				}
			}
			else
			{
				h = CG_StatusHandle(ci->teamTask);
			}

			if(h)
			{
				CG_DrawPic(xx, y, PIC_WIDTH, PIC_WIDTH, h);
			}

			xx += PIC_WIDTH + 1;

			leftOver = rect->w - xx;
			maxx = xx + leftOver / 3;



			CG_Text_Paint_Limit(&maxx, xx, y + text_y, scale, color, ci->name, 0, 0); 

			p = CG_ConfigString(CS_LOCATIONS + ci->location);
			if (!p || !*p) {
				p = "unknown";
			}

			xx += leftOver / 3 + 2;
			maxx = rect->w - 4;

			CG_Text_Paint_Limit(&maxx, xx, y + text_y, scale, color, p, 0, 0); 
			y += text_y + 2;
			if ( y + text_y + 2 > rect->y + rect->h ) {
				break;
			}

		}
	}
}


void CG_DrawTeamSpectators(rectDef_t *rect, float scale, vec4_t color, qhandle_t shader) {
	if (cg.spectatorLen) {
		float maxX;

		if (cg.spectatorWidth == -1) {
			cg.spectatorWidth = 0;
			cg.spectatorPaintX = rect->x + 1;
			cg.spectatorPaintX2 = -1;
		}

		if (cg.spectatorOffset > cg.spectatorLen) {
			cg.spectatorOffset = 0;
			cg.spectatorPaintX = rect->x + 1;
			cg.spectatorPaintX2 = -1;
		}

		if (cg.time > cg.spectatorTime) {
			cg.spectatorTime = cg.time + 10;
			if (cg.spectatorPaintX <= rect->x + 2) {
				if (cg.spectatorOffset < cg.spectatorLen) {
					cg.spectatorPaintX += CG_Text_Width(&cg.spectatorList[cg.spectatorOffset], scale, 1) - 1;
					cg.spectatorOffset++;
				} else {
					cg.spectatorOffset = 0;
					if (cg.spectatorPaintX2 >= 0) {
						cg.spectatorPaintX = cg.spectatorPaintX2;
					} else {
						cg.spectatorPaintX = rect->x + rect->w - 2;
					}
					cg.spectatorPaintX2 = -1;
				}
			} else {
				cg.spectatorPaintX--;
				if (cg.spectatorPaintX2 >= 0) {
					cg.spectatorPaintX2--;
				}
			}
		}

		maxX = rect->x + rect->w - 2;
		CG_Text_Paint_Limit(&maxX, cg.spectatorPaintX, rect->y + rect->h - 3, scale, color, &cg.spectatorList[cg.spectatorOffset], 0, 0); 
		if (cg.spectatorPaintX2 >= 0) {
			float maxX2 = rect->x + rect->w - 2;
			CG_Text_Paint_Limit(&maxX2, cg.spectatorPaintX2, rect->y + rect->h - 3, scale, color, cg.spectatorList, 0, cg.spectatorOffset); 
		}
		if (cg.spectatorOffset && maxX > 0) {
			// if we have an offset ( we are skipping the first part of the string ) and we fit the string
			if (cg.spectatorPaintX2 == -1) {
						cg.spectatorPaintX2 = rect->x + rect->w - 2;
			}
		} else {
			cg.spectatorPaintX2 = -1;
		}

	}
}



void CG_DrawMedal(int ownerDraw, rectDef_t *rect, float scale, vec4_t color, qhandle_t shader) {
	score_t *score = &cg.scores[cg.selectedScore];
	float value = 0;
	char *text = NULL;
	color[3] = 0.25;

	switch (ownerDraw) {
		case CG_ACCURACY:
			value = score->accuracy;
			break;
		case CG_ASSISTS:
			value = score->assistCount;
			break;
		case CG_DEFEND:
			value = score->defendCount;
			break;
		case CG_EXCELLENT:
			value = score->excellentCount;
			break;
		case CG_IMPRESSIVE:
			value = score->impressiveCount;
			break;
		case CG_PERFECT:
			value = score->perfect;
			break;
		case CG_GAUNTLET:
			value = score->guantletCount;
			break;
		case CG_CAPTURES:
			value = score->captures;
			break;
	}

	if (value > 0) {
		if (ownerDraw != CG_PERFECT) {
			if (ownerDraw == CG_ACCURACY) {
				text = va("%i%%", (int)value);
				if (value > 50) {
					color[3] = 1.0;
				}
			} else {
				text = va("%i", (int)value);
				color[3] = 1.0;
			}
		} else {
			if (value) {
				color[3] = 1.0;
			}
			text = "Wow";
		}
	}

	trap_R_SetColor(color);
	CG_DrawPic( rect->x, rect->y, rect->w, rect->h, shader );

	if (text) {
		color[3] = 1.0;
		value = CG_Text_Width(text, scale, 0);
		CG_Text_Paint(rect->x + (rect->w - value) / 2, rect->y + rect->h + 10 , scale, color, text, 0, 0, 0);
	}
	trap_R_SetColor(NULL);

}
	
//
void CG_OwnerDraw(float x, float y, float w, float h, float text_x, float text_y, int ownerDraw, int ownerDrawFlags, int align, float special, float scale, vec4_t color, qhandle_t shader, int textStyle) {
	rectDef_t rect;

  if ( cg_drawStatus.integer == 0 ) {
		return;
	}

	//if (ownerDrawFlags != 0 && !CG_OwnerDrawVisible(ownerDrawFlags)) {
	//	return;
	//}

  rect.x = x;
  rect.y = y;
  rect.w = w;
  rect.h = h;

  switch (ownerDraw) {
  case CG_PLAYER_ARMOR_ICON:
    CG_DrawPlayerArmorIcon(&rect, ownerDrawFlags & CG_SHOW_2DONLY);
    break;
  case CG_PLAYER_ARMOR_ICON2D:
    CG_DrawPlayerArmorIcon(&rect, qtrue);
    break;
  case CG_PLAYER_ARMOR_VALUE:
    CG_DrawPlayerArmorValue(&rect, scale, color, shader, textStyle);
    break;
  case CG_PLAYER_AMMO_ICON:
    CG_DrawPlayerAmmoIcon(&rect, ownerDrawFlags & CG_SHOW_2DONLY);
    break;
  case CG_PLAYER_AMMO_ICON2D:
    CG_DrawPlayerAmmoIcon(&rect, qtrue);
    break;
  case CG_PLAYER_AMMO_VALUE:
    CG_DrawPlayerAmmoValue(&rect, scale, color, shader, textStyle);
    break;
  case CG_SELECTEDPLAYER_HEAD:
    CG_DrawSelectedPlayerHead(&rect, ownerDrawFlags & CG_SHOW_2DONLY, qfalse);
    break;
  case CG_VOICE_HEAD:
    CG_DrawSelectedPlayerHead(&rect, ownerDrawFlags & CG_SHOW_2DONLY, qtrue);
    break;
  case CG_VOICE_NAME:
    CG_DrawSelectedPlayerName(&rect, scale, color, qtrue, textStyle);
    break;
  case CG_SELECTEDPLAYER_STATUS:
    CG_DrawSelectedPlayerStatus(&rect);
    break;
  case CG_SELECTEDPLAYER_ARMOR:
    CG_DrawSelectedPlayerArmor(&rect, scale, color, shader, textStyle);
    break;
  case CG_SELECTEDPLAYER_HEALTH:
    CG_DrawSelectedPlayerHealth(&rect, scale, color, shader, textStyle);
    break;
  case CG_SELECTEDPLAYER_NAME:
    CG_DrawSelectedPlayerName(&rect, scale, color, qfalse, textStyle);
    break;
  case CG_SELECTEDPLAYER_LOCATION:
    CG_DrawSelectedPlayerLocation(&rect, scale, color, textStyle);
    break;
  case CG_SELECTEDPLAYER_WEAPON:
    CG_DrawSelectedPlayerWeapon(&rect);
    break;
  case CG_SELECTEDPLAYER_POWERUP:
    CG_DrawSelectedPlayerPowerup(&rect, ownerDrawFlags & CG_SHOW_2DONLY);
    break;
  case CG_PLAYER_HEAD:
    CG_DrawPlayerHead(&rect, ownerDrawFlags & CG_SHOW_2DONLY);
    break;
  case CG_PLAYER_ITEM:
    CG_DrawPlayerItem(&rect, scale, ownerDrawFlags & CG_SHOW_2DONLY);
    break;
  case CG_PLAYER_SCORE:
    CG_DrawPlayerScore(&rect, scale, color, shader, textStyle);
    break;
  case CG_PLAYER_HEALTH:
    CG_DrawPlayerHealth(&rect, scale, color, shader, textStyle);
    break;
  case CG_RED_SCORE:
    CG_DrawRedScore(&rect, scale, color, shader, textStyle);
    break;
  case CG_BLUE_SCORE:
    CG_DrawBlueScore(&rect, scale, color, shader, textStyle);
    break;
  case CG_RED_NAME:
    CG_DrawRedName(&rect, scale, color, textStyle);
    break;
  case CG_BLUE_NAME:
    CG_DrawBlueName(&rect, scale, color, textStyle);
    break;
  case CG_BLUE_FLAGHEAD:
    CG_DrawBlueFlagHead(&rect);
    break;
  case CG_BLUE_FLAGSTATUS:
    CG_DrawBlueFlagStatus(&rect, shader);
    break;
  case CG_BLUE_FLAGNAME:
    CG_DrawBlueFlagName(&rect, scale, color, textStyle);
    break;
  case CG_RED_FLAGHEAD:
    CG_DrawRedFlagHead(&rect);
    break;
  case CG_RED_FLAGSTATUS:
    CG_DrawRedFlagStatus(&rect, shader);
    break;
  case CG_RED_FLAGNAME:
    CG_DrawRedFlagName(&rect, scale, color, textStyle);
    break;
  case CG_HARVESTER_SKULLS:
    CG_HarvesterSkulls(&rect, scale, color, qfalse, textStyle);
    break;
  case CG_HARVESTER_SKULLS2D:
    CG_HarvesterSkulls(&rect, scale, color, qtrue, textStyle);
    break;
  case CG_ONEFLAG_STATUS:
    CG_OneFlagStatus(&rect);
    break;
  case CG_PLAYER_LOCATION:
    CG_DrawPlayerLocation(&rect, scale, color, textStyle);
    break;
  case CG_TEAM_COLOR:
    CG_DrawTeamColor(&rect, color);
    break;
  case CG_AREA_POWERUP:
	CG_DrawAreaPowerUp(&rect, align, special, scale, color);
    break;
  case CG_PLAYER_STATUS:
	CG_DrawPlayerStatus(&rect);
    break;
  case CG_PLAYER_HASFLAG:
    CG_DrawPlayerHasFlag(&rect, qfalse);
    break;
  case CG_PLAYER_HASFLAG2D:
    CG_DrawPlayerHasFlag(&rect, qtrue);
    break;
  case CG_AREA_SYSTEMCHAT:
    CG_DrawAreaSystemChat(&rect, scale, color, shader);
    break;
  case CG_AREA_TEAMCHAT:
    CG_DrawAreaTeamChat(&rect, scale, color, shader);
    break;
  case CG_AREA_CHAT:
    CG_DrawAreaChat(&rect, scale, color, shader);
    break;
  case CG_GAME_TYPE:
    CG_DrawGameType(&rect, scale, color, shader, textStyle);
    break;
  case CG_GAME_STATUS:
    CG_DrawGameStatus(&rect, scale, color, shader, textStyle);
		break;
  case CG_KILLER:
    CG_DrawKiller(&rect, scale, color, shader, textStyle);
		break;
	case CG_ACCURACY:
	case CG_ASSISTS:
	case CG_DEFEND:
	case CG_EXCELLENT:
	case CG_IMPRESSIVE:
	case CG_PERFECT:
	case CG_GAUNTLET:
	case CG_CAPTURES:
		CG_DrawMedal(ownerDraw, &rect, scale, color, shader);
		break;
  case CG_SPECTATORS:
		CG_DrawTeamSpectators(&rect, scale, color, shader);
		break;
  case CG_TEAMINFO:
		if (cg_currentSelectedPlayer.integer == numSortedTeamPlayers) {
			CG_DrawNewTeamInfo(&rect, text_x, text_y, scale, color, shader);
		}
		break;
  case CG_CAPFRAGLIMIT:
    CG_DrawCapFragLimit(&rect, scale, color, shader, textStyle);
		break;
  case CG_1STPLACE:
    CG_Draw1stPlace(&rect, scale, color, shader, textStyle);
		break;
  case CG_2NDPLACE:
    CG_Draw2ndPlace(&rect, scale, color, shader, textStyle);
		break;
    case CG_LOAD_LEVELSHOT:
      CG_DrawLevelShot( &rect );
      break;
    case CG_LOAD_MEDIA:
      CG_DrawMediaProgress( &rect, color, scale, align, textStyle, special );
      break;
    case CG_LOAD_MEDIA_LABEL:
      CG_DrawMediaProgressLabel( &rect, text_x, text_y, color, scale, align );
      break;
	case CG_LOAD_SOUND:
      CG_DrawSoundProgress( &rect, color, scale, align, textStyle, special );
      break;
    case CG_LOAD_SOUND_LABEL:
      CG_DrawSoundProgressLabel( &rect, text_x, text_y, color, scale, align );
      break;
	case CG_LOAD_GRAPHIC:
      CG_DrawGraphicProgress( &rect, color, scale, align, textStyle, special );
      break;
    case CG_LOAD_GRAPHIC_LABEL:
      CG_DrawGraphicProgressLabel( &rect, text_x, text_y, color, scale, align );
      break;
    case CG_LOAD_LEVELNAME:
      CG_DrawLevelName( &rect, text_x, text_y, color, scale, align, textStyle );
      break;
    case CG_LOAD_MOTD:
      CG_DrawMOTD( &rect, text_x, text_y, color, scale, align, textStyle );
      break;
    case CG_LOAD_HOSTNAME:
      CG_DrawHostname( &rect, text_x, text_y, color, scale, align, textStyle );
      break;
	case CG_PLAYER_CROSSHAIRNAMES:
      CG_DrawXCrosshairNames( &rect, scale, textStyle );
      break;
	case CG_FPS:
      CG_DrawXFPS( &rect, text_x, text_y, scale, color, align, textStyle, qtrue );
      break;
    case CG_FPS_FIXED:
      CG_DrawXFPS( &rect, text_x, text_y, scale, color, align, textStyle, qfalse );
      break;
	case CG_TIMER:
      CG_DrawTimer( &rect, text_x, text_y, scale, color, align, textStyle );
      break;
    case CG_TIMER_MINS:
      CG_DrawTimerMins( &rect, color );
      break;
    case CG_TIMER_SECS:
      CG_DrawTimerSecs( &rect, color );
      break;
	case CG_SNAPSHOT:
      CG_DrawXSnapshot( &rect, text_x, text_y, scale, color, align, textStyle );
      break;
	case CG_LAGOMETER:
      CG_DrawXLagometer( &rect, text_x, text_y, scale, color );
      break;
	case CG_CONSOLE:
      CG_DrawConsole( &rect, text_x, text_y, color, scale, align, textStyle );
      break;
	case CG_WEAPONSELECT:
	  CG_DrawXWeaponSelect(&rect, align, special, scale, color, textStyle);
      break;
	case CG_CENTERPRINT:
      CG_XCenterPrint( &rect, text_x, text_y, scale, color, align, textStyle);
      break;
  default:
    break;
  }
}

void CG_MouseEvent(int x, int y) {
	int n;

	if ( (cg.predictedPlayerState.pm_type == PM_NORMAL || cg.predictedPlayerState.pm_type == PM_SPECTATOR) && cg.showScores == qfalse) {
    trap_Key_SetCatcher(0);
		return;
	}

	cgs.cursorX+= x;
	if (cgs.cursorX < 0)
		cgs.cursorX = 0;
	else if (cgs.cursorX > 640)
		cgs.cursorX = 640;

	cgs.cursorY += y;
	if (cgs.cursorY < 0)
		cgs.cursorY = 0;
	else if (cgs.cursorY > 480)
		cgs.cursorY = 480;

	n = Display_CursorType(cgs.cursorX, cgs.cursorY);
	cgs.activeCursor = 0;
	if (n == CURSOR_ARROW) {
		cgs.activeCursor = cgs.media.selectCursor;
	} else if (n == CURSOR_SIZER) {
		cgs.activeCursor = cgs.media.sizeCursor;
	}

  if (cgs.capturedItem) {
	  Display_MouseMove(cgs.capturedItem, x, y);
  } else {
	  Display_MouseMove(NULL, cgs.cursorX, cgs.cursorY);
  }

}

/*
==================
CG_HideTeamMenus
==================

*/
void CG_HideTeamMenu( void ) {
  Menus_CloseByName("teamMenu");
  Menus_CloseByName("getMenu");
}

/*
==================
CG_ShowTeamMenus
==================

*/
void CG_ShowTeamMenu( void ) {
  Menus_OpenByName("teamMenu");
}




/*
==================
CG_EventHandling
==================
 type 0 - no event handling
      1 - team menu
      2 - hud editor

*/
void CG_EventHandling(int type) {
	cgs.eventHandling = type;
  if (type == CGAME_EVENT_NONE) {
    CG_HideTeamMenu();
  } else if (type == CGAME_EVENT_TEAMMENU) {
    //CG_ShowTeamMenu();
  } else if (type == CGAME_EVENT_SCOREBOARD) {
  }

}



void CG_KeyEvent(int key, qboolean down) {

	if (!down) {
		return;
	}

	if ( cg.predictedPlayerState.pm_type == PM_NORMAL || (cg.predictedPlayerState.pm_type == PM_SPECTATOR && cg.showScores == qfalse)) {
		CG_EventHandling(CGAME_EVENT_NONE);
    trap_Key_SetCatcher(0);
		return;
	}

  //if (key == trap_Key_GetKey("teamMenu") || !Display_CaptureItem(cgs.cursorX, cgs.cursorY)) {
    // if we see this then we should always be visible
  //  CG_EventHandling(CGAME_EVENT_NONE);
  //  trap_Key_SetCatcher(0);
  //}



  Display_HandleKey(key, down, cgs.cursorX, cgs.cursorY);

	if (cgs.capturedItem) {
		cgs.capturedItem = NULL;
	}	else {
		if (key == K_MOUSE2 && down) {
			cgs.capturedItem = Display_CaptureItem(cgs.cursorX, cgs.cursorY);
		}
	}
}

int CG_ClientNumFromName(const char *p) {
  int i;
  for (i = 0; i < cgs.maxclients; i++) {
    if (cgs.clientinfo[i].infoValid && Q_stricmp(cgs.clientinfo[i].name, p) == 0) {
      return i;
    }
  }
  return -1;
}

void CG_ShowResponseHead(void) {
  Menus_OpenByName("voiceMenu");
	trap_Cvar_Set("cl_conXOffset", "72");
	cg.voiceTime = cg.time;
}

void CG_RunMenuScript(char **args) {
}


void CG_GetTeamColor(vec4_t *color) {
  if (cg.snap->ps.persistant[PERS_TEAM] == TEAM_RED) {
    (*color)[0] = 1.0f;
    (*color)[3] = 0.25f;
    (*color)[1] = (*color)[2] = 0.0f;
  } else if (cg.snap->ps.persistant[PERS_TEAM] == TEAM_BLUE) {
    (*color)[0] = (*color)[1] = 0.0f;
    (*color)[2] = 1.0f;
    (*color)[3] = 0.25f;
  } else {
    (*color)[0] = (*color)[2] = 0.0f;
    (*color)[1] = 0.17f;
    (*color)[3] = 0.25f;
	}
}

