/*
 * Copyright (C) 1997-2001 Id Software, Inc.
 *
 * This program is free software; you can redistribute it and/or modify it under
 * the terms of the GNU General Public License as published by the Free
 * Software Foundation; either version 2 of the License, or (at your option)
 * any later version.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.
 *
 * See the GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License along with
 * this program; if not, write to the Free Software Foundation, Inc., 59
 * Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 *
 */
#include "g_local.h"



/*
 * ======================================================================
 *
 * INTERMISSION
 *
 * ======================================================================
 */

void
MoveClientToIntermission(edict_t * ent)
{
	if (deathmatch->value || coop->value)
		ent->client->showscores = true;
	VectorCopy(level.intermission_origin, ent->s.origin);
	ent->client->ps.pmove.origin[0] = level.intermission_origin[0] * 8;
	ent->client->ps.pmove.origin[1] = level.intermission_origin[1] * 8;
	ent->client->ps.pmove.origin[2] = level.intermission_origin[2] * 8;
	VectorCopy(level.intermission_angle, ent->client->ps.viewangles);
	ent->client->ps.pmove.pm_type = PM_FREEZE;
	ent->client->ps.gunindex = 0;
	ent->client->ps.blend[3] = 0;
	ent->client->ps.rdflags &= ~RDF_UNDERWATER;

	/* clean up powerup info */
	ent->client->quad_framenum = 0;
	ent->client->invincible_framenum = 0;
	ent->client->breather_framenum = 0;
	ent->client->enviro_framenum = 0;
	ent->client->grenade_blew_up = false;
	ent->client->grenade_time = 0;

	ent->viewheight = 0;
	ent->s.modelindex = 0;
	ent->s.modelindex2 = 0;
	ent->s.modelindex3 = 0;
	ent->s.modelindex = 0;
	ent->s.effects = 0;
	ent->s.sound = 0;
	ent->solid = SOLID_NOT;

	/* add the layout */

	if (deathmatch->value || coop->value) {
		DeathmatchScoreboardMessage(ent, NULL);
		gi.unicast(ent, true);
	}
}

void
BeginIntermission(edict_t * targ)
{
	int		i         , n;
	edict_t        *ent, *client;

	if (level.intermissiontime)
		return;		/* already activated */

	game.autosaved = false;

	/* respawn any dead clients */
	for (i = 0; i < maxclients->value; i++) {
		client = g_edicts + 1 + i;
		if (!client->inuse)
			continue;
		if (client->health <= 0)
			respawn(client);
	}

	level.intermissiontime = level.time;
	level.changemap = targ->map;

	if (strstr(level.changemap, "*")) {
		if (coop->value) {
			for (i = 0; i < maxclients->value; i++) {
				client = g_edicts + 1 + i;
				if (!client->inuse)
					continue;
				/* strip players of all keys between units */
				for (n = 0; n < MAX_ITEMS; n++) {
					if (itemlist[n].flags & IT_KEY)
						client->client->pers.inventory[n] = 0;
				}
			}
		}
	} else {
		if (!deathmatch->value) {
			level.exitintermission = 1;	/* go immediately to the
							 * next level */
			return;
		}
	}

	level.exitintermission = 0;

	/* find an intermission spot */
	ent = G_Find(NULL, FOFS(classname), "info_player_intermission");
	if (!ent) {		/* the map creator forgot to put in an
				 * intermission point... */
		ent = G_Find(NULL, FOFS(classname), "info_player_start");
		if (!ent)
			ent = G_Find(NULL, FOFS(classname), "info_player_deathmatch");
	} else {		/* chose one of four spots */
		i = rand() & 3;
		while (i--) {
			ent = G_Find(ent, FOFS(classname), "info_player_intermission");
			if (!ent)	/* wrap around the list */
				ent = G_Find(ent, FOFS(classname), "info_player_intermission");
		}
	}

	VectorCopy(ent->s.origin, level.intermission_origin);
	VectorCopy(ent->s.angles, level.intermission_angle);

	/* move all clients to the intermission point */
	for (i = 0; i < maxclients->value; i++) {
		client = g_edicts + 1 + i;
		if (!client->inuse)
			continue;
		MoveClientToIntermission(client);
	}
}

#ifdef GAME_MOD
/* <cooplayout/> Internal functions for compute the cooplayout data */
/* ================== */
//
/* ================== */
int
entArmor(edict_t * ent)
{
	gitem_t        *item;
	int		index     , iCells, iArmor;
	int		power_armor_type;

	power_armor_type = PowerArmorType(ent);
	if (power_armor_type) {
		iCells = ent->client->pers.inventory[ITEM_INDEX(FindItem("cells"))];
		if (iCells == 0) {	/* ran out of cells for power armor */
			ent->flags &= ~FL_POWER_ARMOR;
			power_armor_type = 0;;
		}
	}
	index = ArmorIndex(ent);
	if (power_armor_type && (!index || (level.framenum & 8)))
		iArmor = iCells;
	else if (index) {
		item = GetItemByIndex(index);
		iArmor = ent->client->pers.inventory[index];
	} else
		iArmor = 0;

	return iArmor;
}

/* <cooplayout> CoopScoreboardMessage (cooperative layout) */
/* ================== */
/* Display a layout for cooperative play */
/* ================== */
#define RANGE_1_METER    39	/* 1 meter in map unit */
void
CoopScoreboardMessage(edict_t * ent)
{
	gclient_t      *cl;
	edict_t        *cl_ent;
	char		string    [1400];
	int		health    , armor;
	int		i         , j, x, y;
	int		dist      , dir_h, dir_v;
	vec3_t		v;
	float		angle;
	char		szArrow   [8];

	string[0] = '\0';
	x = 160;
	y = 8;
	for (i = 0; i < game.maxclients; i++) {
		cl_ent = g_edicts + 1 + i;
		if (!cl_ent->inuse || game.clients[i].resp.spectator)
			continue;

		cl = &game.clients[i];

		health = max(cl_ent->health, 0);
		health = (min(health, 100) / 5) * 5;			/* bh0..5..10.. ..100 */
		armor = entArmor(cl_ent);
		armor = max(armor, 0);
		armor = (min(armor, 100) / 5) * 5;			/* ba0..5..10.. ..100 */

		j = strlen(string);
		if (cl_ent == ent) {					/* The player himself */
			Com_sprintf(string + j, sizeof(string) - j,
			    "xr -%i yt %i picn /players/%s_i.pcx "	/* face */
			    "xr -%i yt %i string2 \"%s\" "		/* name */
			    "xr -%i yt %i picn bh%i "			/* health */
			    "yt %i picn ba%i "				/* armor */
			    "xr -%i yt %i string2 \"%s\" ",		/* ping */
			    x, y, Info_ValueForKey(cl_ent->client->pers.userinfo, "skin"),
			    x - 34, y, cl_ent->client->pers.netname,
			    x - 35, y + 8, health,
			    y + 13, armor,
			    x - 82, y + 20, va("(%dms)", min(cl->ping, 999)));
		} else {
			VectorSubtract(cl_ent->s.origin, ent->s.origin, v);
			dist = (int)(VectorLength(v) / RANGE_1_METER);


			/* direction_V : up, down or same height */
			if (v[2] > 3 * RANGE_1_METER)
				dir_v = 1;
			else if (v[2] < -3 * RANGE_1_METER)
				dir_v = 2;
			else
				dir_v = 0;

			/* direction_H : left, right, front or back */
			if (fabs(v[0]) < RANGE_1_METER && fabs(v[1]) < RANGE_1_METER)
				dir_h = 0;	/* Too near, no direction */
			else {
				angle = vectoyaw(v) - ent->s.angles[YAW];
				if (angle < 0)
					angle += 360;
				else if (angle >= 360)
					angle -= 360;

				if (angle < 45)
					dir_h = 1;	/* front */
				else if (angle < 135)
					dir_h = 2;	/* left */
				else if (angle < 225)
					dir_h = 3;	/* back */
				else if (angle < 315)
					dir_h = 4;	/* right */
				else
					dir_h = 1;	/* front */
			}

			Com_sprintf(szArrow, sizeof(szArrow), "v%ih%i", dir_v, dir_h);
			Com_sprintf(string + j, sizeof(string) - j,
			    "xr -%i yt %i picn /players/%s_i.pcx "	/* face */
			    "xr -%i yt %i string \"%s\" "		/* name */
			    "xr -%i yt %i picn bh%i "			/* health */
			    "yt %i picn ba%i "				/* armor */
			    "yt %i picn %s "				/* directional arrow */
			    "xr -%i string \"%im (%dms)\" ",		/* distance + ping */
			    x, y, Info_ValueForKey(cl_ent->client->pers.userinfo, "skin"),
			    x - 34, y, cl_ent->client->pers.netname,
			    x - 35, y + 8, health,
			    y + 13, armor,
			    y + 20, szArrow,
			    x - 62, dist, min(cl->ping, 999));
		}
		x += 160;
	}

	if (string[0]) {
		gi.WriteByte(svc_layout);
		gi.WriteString(string);
	}
}
/* </cooplayout> */

/*
 * ================== DeathmatchScoreboardMessage
 *
 * ==================
 */
void
NewDeathmatchScoreboardMessage(edict_t * ent, edict_t * killer)
{
	char		entry     [1024];
	char		string    [1400];
	int		stringlength = 0;
	int		i         , j, k;
	int		sorted     [MAX_CLIENTS];
	int		sortedscores[MAX_CLIENTS];
	int		score     , total;
	int		picnum;
	int		x         , y;
	gclient_t      *cl;
	edict_t        *cl_ent;
	char           *tag;

#ifdef WITH_ACEBOT
	/* ACEBOT_ADD */
	if (ent->is_bot)
		return;
	/* ACEBOT_END */
#endif

	/* sort the clients by score */
	total = 0;
	for (i = 0; i < game.maxclients; i++) {
		cl_ent = g_edicts + 1 + i;

		if (!cl_ent->inuse || game.clients[i].resp.spectator)
			continue;

		score = game.clients[i].resp.score;
		for (j = 0; j < total; j++) {
			if (score > sortedscores[j])
				break;
		}

		for (k = total; k > j; k--) {
			sorted[k] = sorted[k - 1];
			sortedscores[k] = sortedscores[k - 1];
		}

		sorted[j] = i;
		sortedscores[j] = score;
		total++;
	}

	Com_sprintf(entry, sizeof(entry),
	    "xv 32 yv 16 string2 \"Player\" "
	    "xv 168 yv 16 string2 \"Frags\" "
	    "xv 216 yv 16 string2 \"Ping\" "
	    "xv 256 yv 16 string2 \"Time\" "
	    "xv 32 yv 24 string2 \"--------------------------------\" ");
	j = strlen(entry);
	if (stringlength + j < 1024) {
		strcpy(string + stringlength, entry);
		stringlength += j;
	}
	if (total > 25)
		total = 25;

	for (i = 0; i < total; i++) {
		cl = &game.clients[sorted[i]];
		cl_ent = g_edicts + 1 + sorted[i];
		picnum = gi.imageindex("i_fixme");

		x = 32;
		y = 32 + 8 * i;

		/* add a dogtag */
		if (cl_ent == ent)
			tag = ">";
		else if (cl_ent == killer)
			tag = "X>";
		else
			tag = NULL;

		if (tag) {
			Com_sprintf(entry, sizeof(entry),
			    "xv 8 yv %i string \"%s\" ",
			    y, tag);

			j = strlen(entry);
			if (stringlength + j > 1024)
				break;

			strcpy(string + stringlength, entry);
			stringlength += j;

		}
		Com_sprintf(entry, sizeof(entry),
		    "xv 32 yv %i string2 \"%s\" "
		    "xv 152 yv %i string \"%3i   %3i  %3i\" ",
		    y, cl->pers.netname,
		    y, cl->resp.score,
		    cl->ping,
		    (level.framenum - cl->resp.enterframe) / 600);

		j = strlen(entry);
		if (stringlength + j > 1024)
			break;

		strcpy(string + stringlength, entry);
		stringlength += j;

	}
	gi.WriteByte(svc_layout);
	gi.WriteString(string);
}

#endif
void
DeathmatchScoreboardMessage(edict_t * ent, edict_t * killer)
{
	char		entry     [1024];
	char		string    [1400];
	int		stringlength;
	int		i         , j, k;
	int		sorted     [MAX_CLIENTS];
	int		sortedscores[MAX_CLIENTS];
	int		score     , total;
	int		picnum;
	int		x         , y;
	gclient_t      *cl;
	edict_t        *cl_ent;
	char           *tag;

#ifdef WITH_ACEBOT
	/* ACEBOT_ADD */
	if (ent->is_bot)
		return;
	/* ACEBOT_END */
#endif
#ifdef GAME_MOD
	if (opt_dm_scoreboard->value) {
		if (coop->value)
			CoopScoreboardMessage(ent);
		else
			NewDeathmatchScoreboardMessage(ent, ent->enemy);
	} 
	else {
		total = 0;
		for (i = 0; i < game.maxclients; i++) {
			cl_ent = g_edicts + 1 + i;
			if (!cl_ent->inuse || game.clients[i].resp.spectator)
				continue;
			score = game.clients[i].resp.score;
			for (j = 0; j < total; j++) {
				if (score > sortedscores[j])
					break;
			}
			for (k = total; k > j; k--) {
				sorted[k] = sorted[k - 1];
				sortedscores[k] = sortedscores[k - 1];
			}
			sorted[j] = i;
			sortedscores[j] = score;
			total++;
		}

#else
	total = 0;
	for (i = 0; i < game.maxclients; i++) {
		cl_ent = g_edicts + 1 + i;
		if (!cl_ent->inuse || game.clients[i].resp.spectator)
			continue;
		score = game.clients[i].resp.score;
		for (j = 0; j < total; j++) {
			if (score > sortedscores[j])
				break;
		}
		for (k = total; k > j; k--) {
			sorted[k] = sorted[k - 1];
			sortedscores[k] = sortedscores[k - 1];
		}
		sorted[j] = i;
		sortedscores[j] = score;
		total++;
	}
#endif
	/* print level name and exit rules */
	string[0] = 0;

	stringlength = strlen(string);

	/* add the clients in sorted order */
	if (total > 12)
		total = 12;

	for (i = 0; i < total; i++) {
		cl = &game.clients[sorted[i]];
		cl_ent = g_edicts + 1 + sorted[i];

		picnum = gi.imageindex("i_fixme");
		x = (i >= 6) ? 160 : 0;
		y = 32 + 32 * (i % 6);

		/* add a dogtag */
		if (cl_ent == ent)
			tag = "tag1";
		else if (cl_ent == killer)
			tag = "tag2";
		else
			tag = NULL;
		if (tag) {
			Com_sprintf(entry, sizeof(entry),
			    "xv %i yv %i picn %s ", x + 32, y, tag);
			j = strlen(entry);
			if (stringlength + j > 1024)
				break;
			strcpy(string + stringlength, entry);
			stringlength += j;
		}
		/* send the layout */
		Com_sprintf(entry, sizeof(entry),
		    "client %i %i %i %i %i %i ",
		    x, y, sorted[i], cl->resp.score, cl->ping, (level.framenum - cl->resp.enterframe) / 600);
		j = strlen(entry);
		if (stringlength + j > 1024)
			break;
		strcpy(string + stringlength, entry);
		stringlength += j;
	}

	gi.WriteByte(svc_layout);
	gi.WriteString(string);
#ifdef GAME_MOD
}

#endif
}

/*
 * ================== DeathmatchScoreboard
 *
 * Draw instead of help message. Note that it isn't that hard to overflow the
 * 1400 byte message limit! ==================
 */
void
DeathmatchScoreboard(edict_t * ent)
{
#ifdef WITH_ACEBOT
	/* ACEBOT_ADD */
	if (ent->is_bot)
		return;
	/* ACEBOT_END */
#endif
	DeathmatchScoreboardMessage(ent, ent->enemy);
	gi.unicast(ent, true);
}


/*
 * ================== Cmd_Score_f
 *
 * Display the scoreboard ==================
 */
void
Cmd_Score_f(edict_t * ent)
{
	ent->client->showinventory = false;
	ent->client->showhelp = false;

	if (!deathmatch->value && !coop->value)
		return;

	if (ent->client->showscores) {
		ent->client->showscores = false;
		return;
	}
	ent->client->showscores = true;
	DeathmatchScoreboard(ent);
}


/*
 * ================== HelpComputer
 *
 * Draw help computer. ==================
 */

void
HelpComputer(edict_t * ent)
{
	char		string    [1024];
	char           *sk;

#ifdef WITH_ACEBOT
	/* ACEBOT_ADD */
	if (ent->is_bot)
		return;
	/* ACEBOT_END */
#endif

	if (skill->value == 0)
		sk = "easy";
	else if (skill->value == 1)
		sk = "medium";
	else if (skill->value == 2)
		sk = "hard";
	else
		sk = "hard+";

	/* send the layout */
	Com_sprintf(string, sizeof(string),
	    "xv 32 yv 8 picn help "	/* background */
	    "xv 202 yv 12 string2 \"%s\" "	/* skill */
	    "xv 0 yv 24 cstring2 \"%s\" "	/* level name */
	    "xv 0 yv 54 cstring2 \"%s\" "	/* help 1 */
	    "xv 0 yv 110 cstring2 \"%s\" "	/* help 2 */
	    "xv 50 yv 164 string2 \" kills     goals    secrets\" "
	    "xv 50 yv 172 string2 \"%3i/%3i     %i/%i       %i/%i\" ",
	    sk,
	    level.level_name,
	    game.helpmessage1,
	    game.helpmessage2,
	    level.killed_monsters, level.total_monsters,
	    level.found_goals, level.total_goals,
	    level.found_secrets, level.total_secrets);

	gi.WriteByte(svc_layout);
	gi.WriteString(string);
	gi.unicast(ent, true);
}


/*
 * ================== Cmd_Help_f
 *
 * Display the current help message ==================
 */
void
Cmd_Help_f(edict_t * ent)
{
	/* this is for backwards compatability */
	if (deathmatch->value) {
		Cmd_Score_f(ent);
		return;
	}
	ent->client->showinventory = false;
	ent->client->showscores = false;

	if (ent->client->showhelp && (ent->client->pers.game_helpchanged == game.helpchanged)) {
		ent->client->showhelp = false;
		return;
	}
	ent->client->showhelp = true;
	ent->client->pers.helpchanged = 0;
	HelpComputer(ent);
}

#ifdef GAME_MOD
void
HelpComputerMin(edict_t * ent)
{
	char		string    [1024];

#ifdef WITH_ACEBOT
	if (ent->is_bot)
		return;
#endif

	/* send the layout */
	Com_sprintf(string, sizeof(string),
	    "xv 0 (yv) cstring2 \"%s\" "
	    "xv 1 (yv) string2 \"%3i/%3i",
	    game.helpmessage2, level.killed_monsters, level.total_monsters);

	gi.WriteByte(svc_layout);
	gi.WriteString(string);
	gi.unicast(ent, true);
}
void
Cmd_HelpMin_f(edict_t * ent)
{
	/* this is for backwards compatability */
	if (deathmatch->value) {
		Cmd_Score_f(ent);
		return;
	}
	ent->client->showinventory = false;
	ent->client->showscores = false;

	if (ent->client->showhelp && (ent->client->pers.game_helpchanged == game.helpchanged)) {
		ent->client->showhelp = false;
		return;
	}
	ent->client->showhelp = true;
	ent->client->pers.helpchanged = 0;
	HelpComputerMin(ent);
}
#endif


/* ======================================================================= */

/*
 * =============== G_SetStats ===============
 */
void
G_SetStats(edict_t * ent)
{
	gitem_t        *item;
	int		index     , cells;
	int		power_armor_type;

	/* health */
	ent->client->ps.stats[STAT_HEALTH_ICON] = level.pic_health;
	ent->client->ps.stats[STAT_HEALTH] = ent->health;

	/* ammo */
	if (!ent->client->ammo_index	/* || !ent->client->pers.inventory[ent->client->ammo_index] */ ) {
		ent->client->ps.stats[STAT_AMMO_ICON] = 0;
		ent->client->ps.stats[STAT_AMMO] = 0;
	} else {
		item = &itemlist[ent->client->ammo_index];
		ent->client->ps.stats[STAT_AMMO_ICON] = gi.imageindex(item->icon);
		ent->client->ps.stats[STAT_AMMO] = ent->client->pers.inventory[ent->client->ammo_index];
	}

	cells = 0;

	/* armor */
	power_armor_type = PowerArmorType(ent);
	if (power_armor_type) {
		cells = ent->client->pers.inventory[ITEM_INDEX(FindItem("cells"))];
		if (cells == 0) {	/* ran out of cells for power armor */
			ent->flags &= ~FL_POWER_ARMOR;
			gi.sound(ent, CHAN_ITEM, gi.soundindex("misc/power2.wav"), 1, ATTN_NORM, 0);
			power_armor_type = 0;;
		}
	}
	index = ArmorIndex(ent);
	if (power_armor_type && (!index || (level.framenum & 8))) {	/* flash between power
									 * armor and other armor
									 * icon */
		ent->client->ps.stats[STAT_ARMOR_ICON] = gi.imageindex("i_powershield");
		ent->client->ps.stats[STAT_ARMOR] = cells;
	} else if (index) {
		item = GetItemByIndex(index);
		ent->client->ps.stats[STAT_ARMOR_ICON] = gi.imageindex(item->icon);
		ent->client->ps.stats[STAT_ARMOR] = ent->client->pers.inventory[index];
	} else {
		ent->client->ps.stats[STAT_ARMOR_ICON] = 0;
		ent->client->ps.stats[STAT_ARMOR] = 0;
	}


	/* pickup message */
	if (level.time > ent->client->pickup_msg_time) {
		ent->client->ps.stats[STAT_PICKUP_ICON] = 0;
		ent->client->ps.stats[STAT_PICKUP_STRING] = 0;
	}
	
	/* timers */
	if (ent->client->quad_framenum > level.framenum) {
		ent->client->ps.stats[STAT_TIMER_ICON] = gi.imageindex("p_quad");
		ent->client->ps.stats[STAT_TIMER] = (ent->client->quad_framenum - level.framenum) / 10;
	} else if (ent->client->invincible_framenum > level.framenum) {
		ent->client->ps.stats[STAT_TIMER_ICON] = gi.imageindex("p_invulnerability");
		ent->client->ps.stats[STAT_TIMER] = (ent->client->invincible_framenum - level.framenum) / 10;
	} else if (ent->client->enviro_framenum > level.framenum) {
		ent->client->ps.stats[STAT_TIMER_ICON] = gi.imageindex("p_envirosuit");
		ent->client->ps.stats[STAT_TIMER] = (ent->client->enviro_framenum - level.framenum) / 10;
	} else if (ent->client->breather_framenum > level.framenum) {
		ent->client->ps.stats[STAT_TIMER_ICON] = gi.imageindex("p_rebreather");
		ent->client->ps.stats[STAT_TIMER] = (ent->client->breather_framenum - level.framenum) / 10;
	} else {
		ent->client->ps.stats[STAT_TIMER_ICON] = 0;
		ent->client->ps.stats[STAT_TIMER] = 0;
	}

	/* selected item */
	if (ent->client->pers.selected_item == -1)
		ent->client->ps.stats[STAT_SELECTED_ICON] = 0;
	else
		ent->client->ps.stats[STAT_SELECTED_ICON] = gi.imageindex(itemlist[ent->client->pers.selected_item].icon);

	ent->client->ps.stats[STAT_SELECTED_ITEM] = ent->client->pers.selected_item;

	/* layouts */
	ent->client->ps.stats[STAT_LAYOUTS] = 0;

	if (deathmatch->value) {
		if (ent->client->pers.health <= 0 || level.intermissiontime
		    || ent->client->showscores)
			ent->client->ps.stats[STAT_LAYOUTS] |= 1;
		if (ent->client->showinventory && ent->client->pers.health > 0)
			ent->client->ps.stats[STAT_LAYOUTS] |= 2;
	} else {
		if (ent->client->showscores || ent->client->showhelp)
			ent->client->ps.stats[STAT_LAYOUTS] |= 1;
		if (ent->client->showinventory && ent->client->pers.health > 0)
			ent->client->ps.stats[STAT_LAYOUTS] |= 2;
	}

	/* frags */
	ent->client->ps.stats[STAT_FRAGS] = ent->client->resp.score;

	/* help icon / current weapon if not shown */
	if (ent->client->pers.helpchanged && (level.framenum & 8))
		ent->client->ps.stats[STAT_HELPICON] = gi.imageindex("i_help");
	else if ((ent->client->pers.hand == CENTER_HANDED || ent->client->ps.fov > 91)
	    && ent->client->pers.weapon)
		ent->client->ps.stats[STAT_HELPICON] = gi.imageindex(ent->client->pers.weapon->icon);
	else
		ent->client->ps.stats[STAT_HELPICON] = 0;

	ent->client->ps.stats[STAT_SPECTATOR] = 0;
}

/*
 * =============== G_CheckChaseStats ===============
 */
void
G_CheckChaseStats(edict_t * ent)
{
	int		i;
	gclient_t      *cl;

	for (i = 1; i <= maxclients->value; i++) {
		cl = g_edicts[i].client;
		if (!g_edicts[i].inuse || cl->chase_target != ent)
			continue;
		memcpy(cl->ps.stats, ent->client->ps.stats, sizeof(cl->ps.stats));
		G_SetSpectatorStats(g_edicts + i);
	}
}

/*
 * =============== G_SetSpectatorStats ===============
 */
void
G_SetSpectatorStats(edict_t * ent)
{
	gclient_t      *cl = ent->client;

	if (!cl->chase_target)
		G_SetStats(ent);

	cl->ps.stats[STAT_SPECTATOR] = 1;

	/* layouts are independant in spectator */
	cl->ps.stats[STAT_LAYOUTS] = 0;
	if (cl->pers.health <= 0 || level.intermissiontime || cl->showscores)
		cl->ps.stats[STAT_LAYOUTS] |= 1;
	if (cl->showinventory && cl->pers.health > 0)
		cl->ps.stats[STAT_LAYOUTS] |= 2;

	if (cl->chase_target && cl->chase_target->inuse)
		cl->ps.stats[STAT_CHASE] = CS_PLAYERSKINS +
		    (cl->chase_target - g_edicts) - 1;
	else
		cl->ps.stats[STAT_CHASE] = 0;
}
