// Copyright (C) 2001-2002 Raven Software.
//
// cg_newdraw.c --

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

extern displayContextDef_t cgDC;

static float healthColors[4][4] = 
{
  { 1.0f, 0.69f, 0.0f, 1.0f } ,		// normal
  { 1.0f, 0.2f, 0.2f, 1.0f },		// low health
  { 0.5f, 0.5f, 0.5f, 1.0f},		// weapon firing
  { 1.0f, 1.0f, 1.0f, 1.0f } 		// health > 100
};

static void CG_DrawPlayerLocation( rectDef_t *rect, float scale, vec4_t color, int textStyle  ) 
{
	clientInfo_t *ci = &cgs.clientinfo[cg.snap->ps.clientNum];
	const char   *s;
  
	if (!ci)
	{
		return;
	}
	
	s = CG_ConfigString(CS_LOCATIONS + ci->location);

	if (!s || !*s) 
	{
		s = "unknown";
	}

    CG_DrawText(rect->x, rect->y + rect->h, cgs.media.hudFont, scale, color, s, 0, 0 );
}

//==============================================================================
//	CG_DrawPlayerSniperBullet
//==============================================================================
static void CG_DrawPlayerSniperBullet ( rectDef_t* rect, qhandle_t shader, int bullet )
{
	// Dont draw the bullet if the player doesnt have enough ammo
	if ( bullet > cg.predictedPlayerState.clip[ATTACK_NORMAL][WP_MSG90A1] )
	{
		return;
	}

	CG_DrawStretchPic ( rect->x, rect->y, rect->w, rect->h, 0, 0, 1, 1, NULL, shader );
}

//==============================================================================
//	CG_DrawPlayerSniperMagnification
//==============================================================================
static void CG_DrawPlayerSniperMagnification ( rectDef_t *rect, qhandle_t font, float scale, vec4_t color )
{
	const char* mag;

	switch ( cg.predictedPlayerState.zoomFov )
	{
		default:
		case 20:	mag = "5x";			break;
		case 10:	mag = "10x";		break;
		case 5:		mag = "20x";		break;
	}	

	// Center the text
	CG_DrawText (rect->x, rect->y, font, scale, color, mag, 0, 0 );
}

//==============================================================================
//	CG_DrawPlayerWeaponName
//==============================================================================
static void CG_DrawPlayerWeaponName ( rectDef_t *rect, qhandle_t font, float scale, vec4_t color  )
{
	float		width;
	const char*	name;

	if( cg.weaponSelect > WP_NONE )
	{
		// Equipped weapon
		name = weaponData[cg.weaponSelect].classname;
	}
	else
	{
		// No weapon equipped.
		name = "NONE";
	}

	// Get the width of the text so we can center it
	width = trap_R_GetTextWidth ( name, font, scale, 0 );
	
	// Center the text
	CG_DrawText (rect->x + (rect->w - width) / 2, rect->y + rect->h, font, scale, color, name, 0, 0 );
}

//==============================================================================
//	CG_DrawPlayerWeaponName
//==============================================================================
static void CG_DrawPlayerAltWeaponName ( rectDef_t *rect, qhandle_t font, float scale, vec4_t color )
{
	float		width;
	const char*	name;

	if( cg.weaponSelect > WP_NONE )
	{
		// Equipped weapon
		name = weaponData[cg.weaponSelect].attack[ATTACK_ALTERNATE].name;
	}
	else
	{
		// No weapon equipped.
		name = "NONE";
	}

	// Get the width of the text so we can center it
	width = trap_R_GetTextWidth ( name, font, scale, 0 );
	
	// Center the text
	CG_DrawText (rect->x + (rect->w - width) / 2, rect->y + rect->h, font, scale, color, name, 0, 0 );
}

//==============================================================================
//	CG_DrawPlayerWeaponAmmo
//==============================================================================
static void CG_DrawPlayerWeaponAmmo(rectDef_t *rect, qhandle_t font, float scale, vec4_t color )
{
	const char *ammo;
	int			value;
	float		width;

	// If the client doenst have a selected weapon then dont draw the ammo
	if ( cg.weaponSelect <= WP_NONE ) 
		return;

	// Retrieve the ammo value
	value = cg.predictedPlayerState.ammo[weaponData[cg.weaponSelect].attack[ATTACK_NORMAL].ammoIndex];

	// If the ammo value is crazy then dont display it
	if ( value <= -1 )
		return;

	// Build the ammo string padded with zeros
	ammo = va ( "%03d", value );

	// Retrive the width of the ammo string so it can be centered
	width = trap_R_GetTextWidth (ammo, font, scale, 0 );

	// Draw the ammo string centered
	CG_DrawText (rect->x + (rect->w - width) / 2, rect->y + rect->h, font, scale, color, ammo, 0, 0 );
}

//==============================================================================
//	CG_DrawPlayerAltWeaponAmmo
//==============================================================================
static void CG_DrawPlayerAltWeaponAmmo(rectDef_t *rect, qhandle_t font, float scale, vec4_t color )
{
	const char *ammo;
	int			value;
	float		width;

	// If the client doenst have a selected weapon then dont draw the ammo
	if ( cg.weaponSelect <= WP_NONE ) 
		return;

	// If the selected weapon doesn't have an altclip, don't draw.
	if(weaponData[cg.weaponSelect].attack[ATTACK_ALTERNATE].clipSize<=0)
		return;

	// Retrieve the ammo value
	value  = cg.predictedPlayerState.ammo[weaponData[cg.weaponSelect].attack[ATTACK_ALTERNATE].ammoIndex];
	value += cg.predictedPlayerState.clip[ATTACK_ALTERNATE][cg.weaponSelect];
	
	// If the ammo value is crazy then dont display it
	if ( value <= -1 )
		return;

	// Build the ammo string padded with zeros
	ammo = va ( "%03d", value );

	// Retrive the width of the ammo string so it can be centered
	width = trap_R_GetTextWidth (ammo, font, scale, 0 );

	// Draw the ammo string centered
	CG_DrawText (rect->x + (rect->w - width) / 2, rect->y + rect->h, font, scale, color, ammo, 0, 0 );
}

//==============================================================================
//	CG_DrawPlayerAltWeaponAmmoIcon
//==============================================================================
static void CG_DrawPlayerAltWeaponAmmoIcon(rectDef_t *rect, vec4_t color )
{
	vec4_t fade;

	// If the client doenst have a selected weapon then dont draw the ammo icon
	if ( cg.weaponSelect <= WP_NONE ) 
		return;

	// If there is no loaded icon then dont draw it
	if ( !cg_weapons[cg.weaponSelect].attack[ATTACK_ALTERNATE].ammoIcon )
	{
		return;
	}

	// Fade out the icon if there isnt anything in the alt clip
	fade[0] = color[0];
	fade[1] = color[1];
	fade[2] = color[2];
	fade[3] = color[3] * (cg.predictedPlayerState.clip[ATTACK_ALTERNATE][cg.weaponSelect]?1:0.20f);

	trap_R_SetColor ( fade );

	// Draw the icon
	CG_DrawPic ( rect->x, rect->y, rect->w, rect->h, cg_weapons[cg.weaponSelect].attack[ATTACK_ALTERNATE].ammoIcon );

	// Back to no color
	trap_R_SetColor ( NULL );
}

//==============================================================================
//	CG_DrawPlayerWeaponClip
//==============================================================================
static void CG_DrawPlayerWeaponClip (rectDef_t *rect, qhandle_t font, float scale, vec4_t color )
{
	const char *clip;
	int			value;
	float		width;

	// If the client doenst have a selected weapon then dont draw the ammo
	if ( cg.weaponSelect <= WP_NONE ) 
		return;

	// Retrieve the ammo value
	value = cg.predictedPlayerState.clip[ATTACK_NORMAL][cg.weaponSelect];

	// If the ammo value is crazy then dont display it
	if ( value <= -1 )
		return;

	// Build the clip string padded with zeros
	clip = va ( "%02d", value );

	// Retrive the width of the clip string so it can be centered
	width = trap_R_GetTextWidth (clip, font, scale, 0 );

	// Draw the clip string centered
	CG_DrawText (rect->x + (rect->w - width) / 2, rect->y + rect->h, font, scale, color, clip, 0, 0 );
}

//==============================================================================
//	CG_DrawPlayerWeaponMode
//==============================================================================
static void CG_DrawPlayerWeaponMode ( rectDef_t *rect, qhandle_t font, float scale, vec4_t color )
{
	float		width;
	const char*	mode;
	int			curMode;

	// Use the current fire mode for this weapon, if its undefined then find what it will
	// be once its set
	curMode = cg.predictedPlayerState.firemode[cg.weaponSelect];
	if ( curMode == WP_FIREMODE_NONE )
	{
		curMode = BG_FindFireMode ( cg.weaponSelect, ATTACK_NORMAL, WP_FIREMODE_AUTO );
	}

	// TODO: Retrieve the real mode
	switch ( curMode )
	{
		case WP_FIREMODE_NONE:
			mode = "";
			break;
		case WP_FIREMODE_AUTO:
			mode = "AUTO";
			break;
		case WP_FIREMODE_BURST:
			mode = "BURST";
			break;
		case WP_FIREMODE_SINGLE:
			mode = "SINGLE";
			break;
		default:
			// This shouldn't happen.
			assert(0);
			mode = "";
	}

	// Get the width of the text so we can center it
	width = trap_R_GetTextWidth ( mode, font, scale, 0 );
	
	// Center the text
	CG_DrawText (rect->x + (rect->w - width) / 2, rect->y + rect->h, font, scale, color, mode, 0, 0 );
}

//==============================================================================
//	CG_DrawUseIcon
//==============================================================================
void CG_DrawUseIcon ( rectDef_t* rect )
{
	// If not in a use zone then dont bother
	if ( !(cg.predictedPlayerState.pm_flags & PMF_CAN_USE ) )
	{
		return;
	}

	CG_DrawStretchPic ( rect->x, rect->y, rect->w, rect->h,0, 0, 1, 1, NULL, 
						cgs.gameIcons [ cg.predictedPlayerState.stats[STAT_USEICON] ] );

	if ( cg.predictedPlayerState.stats[STAT_USETIME] )
	{
		float w = 98.0f * (float)cg.predictedPlayerState.stats[STAT_USETIME] / (float)cg.predictedPlayerState.stats[STAT_USETIME_MAX];
		CG_DrawRect ( rect->x + rect->h + 10, rect->y + 9, 100, rect->h - 18, 1, colorWhite );
		CG_FillRect ( rect->x + rect->h + 11, rect->y + 10, w, rect->h - 20, colorRed );
		CG_DrawRect ( rect->x + rect->h + 11, rect->y + 10, w, rect->h - 20, 1, colorBlack );
	}
}

//==============================================================================
//	CG_DrawPlayerGametypeItems
//==============================================================================
void CG_DrawPlayerGametypeItems ( rectDef_t* rect )
{
	float x;
	int	  i;

	// If not in a use zone then dont bother
	if ( cg.predictedPlayerState.pm_flags & PMF_CAN_USE )
	{
		return;
	}

	x = rect->x;

	for ( i = 0; i < MAX_GAMETYPE_ITEMS; i ++ )
	{
		// Doesnt have this mission item
		if ( !(cg.predictedPlayerState.stats[STAT_GAMETYPE_ITEMS] & (1<<i)) )
		{
			continue;
		}

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

		CG_DrawPic ( x, rect->y, rect->w, rect->h, cg_items[i+MODELINDEX_GAMETYPE_ITEM].icon );
	
		x += 2;
	}
}

//==============================================================================
//	CG_DrawPlayerArmor
//==============================================================================
void CG_DrawPlayerArmor ( rectDef_t* rect )
{
	float x;
	float w;

	// Draw the icon
	trap_R_SetColor ( NULL ); 

	w = rect->w;
	x = rect->x;
			
	for ( ; w >= rect->h; w -= rect->h, x += rect->h )
	{
		CG_DrawPic ( x, rect->y - rect->h, rect->h, rect->h, cgs.media.armorShader );
	}

	if ( w )
	{
		CG_DrawStretchPic ( x, rect->y - rect->h, w, rect->h,
							0, 0, w/rect->h, 1.0f, NULL, cgs.media.armorShader );
	}
}


static void CG_DrawPlayerScore( rectDef_t *rect, qhandle_t font, float scale, vec4_t color )
{
	const char* s;

	s = va("%03d",cg.snap->ps.persistant[PERS_SCORE]);

	CG_DrawText(rect->x + (rect->w - trap_R_GetTextWidth(s,font,scale,0)) / 2, rect->y + rect->h, font, scale, color, s, 0, 0 );
}

static void CG_DrawRedScore(rectDef_t *rect, qhandle_t font, float scale, vec4_t color ) 
{
	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 = trap_R_GetTextWidth (num, font, scale, 0);

	CG_DrawText (rect->x + rect->w - value, rect->y + rect->h, font, scale, color, num, 0, 0 );
}

static void CG_DrawBlueScore(rectDef_t *rect, qhandle_t font, float scale, vec4_t color ) 
{
	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 = trap_R_GetTextWidth(num, font, scale, 0 );
	CG_DrawText(rect->x + rect->w - value, rect->y + rect->h, font, scale, color, num, 0, 0 );
}

#define MSECS_PER_FRAME (1000.0 / 60.0)
#define HUD_FADE_SPEED 0.05

float TimeAdjustHUDVal(float mainVal, float dstVal, float factor)
{
	mainVal = mainVal * (1.0 - factor) + dstVal * factor;
	
	//once we get close enough, just finish up
	if(fabs(mainVal - dstVal) < .01)
	{	// if we don't have this, the last few pixels take FOREVER
		mainVal = dstVal;
	}

	return mainVal;
}

void HandleHUDSegment(float *floorVal, float *ceilVal, float dstVal, float factor)
{
	if(dstVal < *floorVal)
	{
		*floorVal = dstVal;
	}
	else if(dstVal > *floorVal)
	{
		*floorVal = TimeAdjustHUDVal(*floorVal, dstVal, factor);
	}

	if(dstVal > *ceilVal)
	{
		*ceilVal = dstVal;
	}
	else if(dstVal < *ceilVal)
	{
		*ceilVal = TimeAdjustHUDVal(*ceilVal, dstVal, factor);
	}
}

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

	cent = CG_GetEntity ( cg.snap->ps.clientNum );
	ps = &cg.snap->ps;

	switch (ownerDraw) 
	{
		case CG_PLAYER_WEAPON_AMMO:
			if ( cent->currentState.weapon ) 
			{
				return ps->ammo[weaponData[cent->currentState.weapon].attack[ATTACK_NORMAL].ammoIndex];
			}
			break;

		case CG_PLAYER_SCORE:
			return cg.snap->ps.persistant[PERS_SCORE];
		
		case CG_PLAYER_HEALTH:
			return ((float) ps->stats[STAT_HEALTH] * 0.01f) + 0.01f;

		case CG_PLAYER_HEALTH_FADE:
		{
			static float healthEdge = 0.0;
			static float healthFull = 0.0;

			float curHealth    = ps->stats[STAT_HEALTH] * 0.01;
			float adjustFactor = (cg.frametime / MSECS_PER_FRAME) * HUD_FADE_SPEED;
	
			HandleHUDSegment(&healthEdge, &healthFull, curHealth, adjustFactor);

			if ( healthFull < 0 )
				healthFull = 0;

			return healthFull;
		}

		case CG_PLAYER_ARMOR_FADE:
		{
			static float armorEdge = 0.0;
			static float armorFull = 0.0;

			float curArmor     = ps->stats[STAT_ARMOR] * 0.01;
			float adjustFactor = (cg.frametime / MSECS_PER_FRAME) * HUD_FADE_SPEED;
	
			HandleHUDSegment(&armorEdge, &armorFull, curArmor, adjustFactor);

			if ( armorFull < 0 )
				armorFull = 0;

			return armorFull;
		}

		case CG_PLAYER_ARMOR:
			return ((float) ps->stats[STAT_ARMOR] * 0.01f);;

		case CG_RED_SCORE:
			return cgs.scores1;
			break;
		
		case CG_BLUE_SCORE:
			return cgs.scores2;
			break;
	
		default:
			break;
	}
	
	return -1;
}

qboolean CG_OwnerDrawDisabled(int flags, const char* param ) 
{
	return qfalse;
}

qboolean CG_OwnerDrawVisible(int flags, const char* param ) 
{
	qboolean visible = qtrue;

	while ( visible )
	{
		// Player on the red team?
		if ( flags & CG_SHOW_ONREDTEAM )
		{
			visible = cg.predictedPlayerState.persistant[PERS_TEAM]==TEAM_RED?qtrue:qfalse;
			flags &= ~(CG_SHOW_ONREDTEAM);
			continue;
		}
		// Player on the blue team?
		else if ( flags & CG_SHOW_ONBLUETEAM )
		{
			visible = cg.predictedPlayerState.persistant[PERS_TEAM]==TEAM_BLUE?qtrue:qfalse;
			flags &= ~(CG_SHOW_ONBLUETEAM);
		}
		else if ( flags & CG_SHOW_HUD_NIGHTVISION )
		{
			visible = ((cg.predictedPlayerState.pm_flags & PMF_GOGGLES_ON) && cg.predictedPlayerState.stats[STAT_GOGGLES] == GOGGLES_NIGHTVISION && !(cg.predictedPlayerState.pm_flags&PMF_ZOOMED))? qtrue : qfalse;
			flags &= ~(CG_SHOW_HUD_NIGHTVISION);
		}
		else if ( flags & CG_SHOW_HUD_THERMAL )
		{
			visible = ((cg.predictedPlayerState.pm_flags & PMF_GOGGLES_ON) && cg.predictedPlayerState.stats[STAT_GOGGLES] == GOGGLES_INFRARED )? qtrue : qfalse;
			flags &= ~(CG_SHOW_HUD_THERMAL);
		}
		// Only draw the sniper scope when zoomed
		else if ( flags & CG_SHOW_HUD_SNIPERSCOPE )
		{
			visible = (cg.predictedPlayerState.pm_flags&PMF_ZOOMED)?qtrue:qfalse;
			flags &= ~(CG_SHOW_HUD_SNIPERSCOPE);
		}
		// Draw the health as long as we arent zoomed
		else if ( flags & CG_SHOW_HUD_HEALTH )
		{
			visible = cg.showScores ? qfalse : qtrue;
			flags &= ~(CG_SHOW_HUD_HEALTH);
		}
		// Timer
		else if ( flags & CG_SHOW_HUD_TIMER )
		{
			if ( cg.showScores )
			{
				visible = qfalse;
			}
			else if ( !cg_drawTimer.integer )
			{
				visible = qfalse;
			}

			flags &= ~(CG_SHOW_HUD_TIMER);
		}
		// Should the alternate weapon information be shown?
		else if (flags & (CG_SHOW_PLAYER_ALT_WEAPONINFO|CG_HIDE_PLAYER_ALT_WEAPONINFO) )
		{
			if ( cg.predictedPlayerState.pm_flags & PMF_ZOOMED )
			{
				visible = qfalse;
			}

			if ( cg.showScores )
			{
				visible = qfalse;
			}
			else
			{
				if ( !BG_WeaponHasAlternateAmmo ( cg.weaponSelect ) )
				{
					visible = qfalse;
				}

				// Dont show it if we dont have ammo 
				if ( !cg.predictedPlayerState.ammo[ weaponData[cg.weaponSelect].attack[ATTACK_ALTERNATE].ammoIndex ] &&
					 !cg.predictedPlayerState.clip[ATTACK_ALTERNATE][ cg.weaponSelect ] )
				{
					visible = qfalse;
				}

				// INvert the visible flag for hidden
				if ( flags & CG_HIDE_PLAYER_ALT_WEAPONINFO )
				{
					if ( cg.predictedPlayerState.pm_flags & PMF_ZOOMED )
					{
						visible = qfalse;
					}
					else
					{
						visible = !visible;
					}
				}
			}

			flags &= ~(CG_SHOW_PLAYER_ALT_WEAPONINFO|CG_HIDE_PLAYER_ALT_WEAPONINFO);	
		}
		// Draw the weapon info when we arent zoomed	
		else if ( flags & CG_SHOW_HUD_WEAPONINFO )
		{
			visible = (cg.showScores||(cg.predictedPlayerState.pm_flags&PMF_ZOOMED))?qfalse:qtrue;
			flags &= ~(CG_SHOW_HUD_WEAPONINFO);			
		}
		else if (flags & CG_SHOW_ANYTEAMGAME) 
		{
			if( !cgs.gametypeData->teams ) 
			{
				visible = qfalse;
			}

			flags &= ~(CG_SHOW_ANYTEAMGAME);	
		}
		else if (flags & CG_SHOW_ANYNONTEAMGAME) 
		{
			if( cgs.gametypeData->teams ) 
			{
				visible = qfalse;
			}

			flags &= ~(CG_SHOW_ANYNONTEAMGAME);	
		}
		else
		{
			break;
		}
	}

	return visible;
}

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

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

// Draw an entire row of weapons for the visual weapon selection menu

static void CG_DrawWeaponList(rectDef_t *rect, qhandle_t font, float scale, vec4_t color )
{
	static vec4_t	colorNormal		= { 0.5f, 0.5f, 0.5f, 0.8f };
	static vec4_t	colorShadow		= { 0.0f, 0.0f, 0.0f, 0.25f };
	static vec4_t	colorSelected	= { 204.0f / 255.0f, 222.0f / 255.0f, 159.0f / 255.0f, 0.925f };
	static vec4_t	colorDisabled   = { 0.4f, 0.4f, 0.4f, 0.8f };

	centity_t		*cent;
	playerState_t	*ps;
	qhandle_t		icon;
	int				weaponToDraw;
	int			x,y;
	int			w,h;
	int			i,wid;
	int			category, activeCategory;
	char		numStr[3];
	int			category_x[CAT_MAX];
	gitem_t		*item;
	const char	*s;


	vec4_t		colorDraw;

	rect->x = 20;
	rect->y = 65;
	rect->h = 320;

	// are we showing weapon menu?
	if (!cg.weaponMenuUp)
	{
		return;
	}

	cent = CG_GetEntity ( cg.snap->ps.clientNum );
	ps   = &cg.snap->ps;

	// If the menu was up during follow then turn it off
	if ( (ps->pm_flags & PMF_FOLLOW) || ps->pm_type == PM_SPECTATOR )
	{
		cg.weaponMenuUp = qfalse;
		return;
	}


	h = rect->h / CAT_MAX;
	w = h*2;  // we know that the weapon icons are a 2:1 aspect ratio

	activeCategory = -1;

	// start at left edge for all weapon categories 
	for (i=CAT_NONE; i<CAT_MAX; i++)
	{
		category_x[i] = rect->x + w;
	}

	for (weaponToDraw = WP_NONE + 1; weaponToDraw < WP_NUM_WEAPONS; weaponToDraw++ )
	{
		category = weaponData[weaponToDraw].category;

		x = category_x[category];
		y = rect->y + (category-1) * h;

		// found a weapon in this catagory
		if (weaponToDraw == cg.weaponMenuSelect)
		{	
			// this is the currently selected weapon, so draw in green
			Vector4Copy(colorSelected, colorDraw);
			activeCategory = category;
		}
		else if ( (ps->stats[STAT_WEAPONS] & ( 1 << weaponToDraw )) )
		{	
			int ammoCount = 0;
			
			ammoCount += ps->ammo[weaponData[weaponToDraw].attack[ATTACK_NORMAL].ammoIndex];
			ammoCount += ps->clip[ATTACK_NORMAL][weaponToDraw];
			ammoCount += ps->ammo[weaponData[weaponToDraw].attack[ATTACK_ALTERNATE].ammoIndex];
			ammoCount += ps->clip[ATTACK_ALTERNATE][weaponToDraw];

			if ( !ammoCount )
			{	
				if (CAT_GRENADE <= category)
				{	
					// no grenades means no grenades
					continue;
				}
				else
				{	
					// weapon has no ammo so show it disabled
					Vector4Copy(colorDisabled, colorDraw );
				}
			}
			else
			{	
				// draw in normal color
				Vector4Copy(colorNormal, colorDraw);
			}
		}
		else
		{	// don't have it, so don't draw
			continue;
		}

		icon = cg_weapons[ weaponToDraw ].weaponIcon;
		if (icon)
		{	
			// draw weapon icon
			if (CAT_GRENADE <= category)
			{	
				// draw square icons
				trap_R_SetColor( colorShadow );
				CG_DrawPic( x+2, y+2, h * 0.90f, h * 0.90f, icon );

				trap_R_SetColor( colorDraw );
				CG_DrawPic( x, y, h * 0.90f, h * 0.90f, icon );

				category_x[category] += h;
			}
			else
			{	
				// draw rectangular icons
				trap_R_SetColor( colorShadow );
				CG_DrawPic( x+2, y+2, w * 0.90f, h * 0.90f, icon );

				trap_R_SetColor( colorDraw );
				CG_DrawPic( x, y, w * 0.90f, h * 0.90f, icon );

				category_x[category] += w;
			}
		}

		trap_R_SetColor( NULL );
	}

	// show weapon catagory numbers
	for (i = CAT_NONE + 1; i < CAT_MAX; i++)
	{
		y = rect->y + (i - 1) * h;
		Com_sprintf(numStr, sizeof(numStr),"%d", i );
		wid = trap_R_GetTextWidth (numStr, font, 1.25f, 0 );
		if (i == activeCategory)
		{
			Vector4Copy(colorSelected, colorDraw);
		}
		else
		{
			Vector4Copy(colorNormal, colorDraw);
		}

		colorDraw[3] = 1.0f;

		CG_DrawText (rect->x + (w - wid) / 2 + 2, y, font, 0.6f, colorDraw, numStr, 0, DT_DROPSHADOW );
	}

	item = BG_FindWeaponItem ( cg.weaponMenuSelect );
	if ( item )
	{
		// Draw the selected weapons name
		s = va("Weapon: %s", item->pickup_name);
		w = trap_R_GetTextWidth ( s, cgs.media.hudFont, 0.43f, 0 );
		CG_DrawText ( 640 - rect->x - w, rect->y, cgs.media.hudFont, 0.43f, colorSelected, s, 0, 0  );

		// Draw the selected weapons ammo count
		if ( BG_WeaponHasAlternateAmmo ( cg.weaponMenuSelect ) )
		{
			s = va("Ammo: %i / %i", cg.predictedPlayerState.clip[ATTACK_NORMAL][cg.weaponMenuSelect] + cg.predictedPlayerState.ammo[weaponData[cg.weaponMenuSelect].attack[ATTACK_NORMAL].ammoIndex],
									cg.predictedPlayerState.clip[ATTACK_ALTERNATE][cg.weaponMenuSelect] + cg.predictedPlayerState.ammo[weaponData[cg.weaponMenuSelect].attack[ATTACK_ALTERNATE].ammoIndex]);
		}
		else
		{
			s = va("Ammo: %i", cg.predictedPlayerState.clip[ATTACK_NORMAL][cg.weaponMenuSelect] + cg.predictedPlayerState.ammo[weaponData[cg.weaponMenuSelect].attack[ATTACK_NORMAL].ammoIndex]);
		}

		w = trap_R_GetTextWidth ( s, cgs.media.hudFont, 0.43f, 0 );
		CG_DrawText ( 640 - rect->x - w, rect->y + 15, cgs.media.hudFont, 0.43f, colorSelected, s, 0, 0  );
	}
}

const char *CG_GetGameStatusText() 
{
	const char *s = "";

	if ( !cgs.gametypeData->teams ) 
	{
		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, qhandle_t font, float scale, vec4_t color ) 
{
	CG_DrawText (rect->x, rect->y + rect->h, font, scale, color, CG_GetGameStatusText(), 0 , 0 );
}

const char *CG_GameTypeString() 
{
	return cgs.gametypeData->displayName;
}

static void CG_DrawGameType(rectDef_t *rect, qhandle_t font, float scale, vec4_t color ) 
{
	CG_DrawText (rect->x, rect->y + rect->h, font, scale, color, CG_GameTypeString(), 0, 0  );
}

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, qhandle_t font, float scale, vec4_t color, qhandle_t shader, int textStyle, const char* param ) 
{
	rectDef_t rect;

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

	switch (ownerDraw) 
	{	
		case CG_USE_ICON:
			CG_DrawUseIcon ( &rect );
			break;

		case CG_PLAYER_GAMETYPE_ITEMS:
			CG_DrawPlayerGametypeItems ( &rect );
			break;

		case CG_PLAYER_ARMOR:
			CG_DrawPlayerArmor ( &rect );
			break;

		case CG_PLAYER_WEAPON_AMMO:
			CG_DrawPlayerWeaponAmmo(&rect, font, scale, color );
			break;

		case CG_PLAYER_WEAPON_CLIP:
			CG_DrawPlayerWeaponClip(&rect, font, scale, color );
			break;

		case CG_PLAYER_WEAPON_NAME:
			CG_DrawPlayerWeaponName(&rect, font, scale, color );
			break;

		case CG_PLAYER_ALT_WEAPON_NAME:
			CG_DrawPlayerAltWeaponName(&rect, font, scale, color );
			break;

		case CG_PLAYER_ALT_WEAPON_AMMO:
			CG_DrawPlayerAltWeaponAmmo(&rect, font, scale, color );
			break;

		case CG_PLAYER_ALT_WEAPON_AMMOICON:
			CG_DrawPlayerAltWeaponAmmoIcon ( &rect, color );
			break;

		case CG_PLAYER_WEAPON_MODE:
			CG_DrawPlayerWeaponMode(&rect, font, scale, color );
			break;

		case CG_PLAYER_SCORE:
			CG_DrawPlayerScore(&rect, font, scale, color );
			break;

		case CG_GAME_TYPE:
			CG_DrawGameType(&rect, font, scale, color );
			break;

		case CG_RED_SCORE:
			CG_DrawRedScore(&rect, font, scale, color );
			break;

		case CG_BLUE_SCORE:
			CG_DrawBlueScore(&rect, font, scale, color );
			break;

		case CG_GAME_STATUS:
			CG_DrawGameStatus(&rect, font, scale, color );
			break;

		case CG_1STPLACE:
			CG_Draw1stPlace(&rect, font, scale, color );
			break;

		case CG_2NDPLACE:
			CG_Draw2ndPlace(&rect, font, scale, color );
			break;

		case CG_WEAPON_LIST:
			CG_DrawWeaponList(&rect, font, scale, color );
			break;

		case CG_PLAYER_LOCATION:
			CG_DrawPlayerLocation(&rect, scale, color, textStyle);
			break;

		case CG_PLAYER_SNIPER_BULLET_1:
		case CG_PLAYER_SNIPER_BULLET_2:
		case CG_PLAYER_SNIPER_BULLET_3:
		case CG_PLAYER_SNIPER_BULLET_4:
		case CG_PLAYER_SNIPER_BULLET_5:
		case CG_PLAYER_SNIPER_BULLET_6:
			CG_DrawPlayerSniperBullet ( &rect, shader, ownerDraw - CG_PLAYER_SNIPER_BULLET_1 + 1);
			break;

		case CG_PLAYER_SNIPER_MAGNIFICATION:
			CG_DrawPlayerSniperMagnification ( &rect, font, scale, color );
			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.cursor;
	} 
	else if (n == CURSOR_SIZER) 
	{
		cgs.activeCursor = cgs.media.cursor;
	}

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

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

*/
void CG_EventHandling(int type) 
{
	cgs.eventHandling = type;  
}


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;
	}

	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);
		}
	}
}

void CG_RunMenuScript(const 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;
	}
}

