thirtyflightsofloving/missionpack/p_hud.c
Knightmare66 608814c830 Fixed firing player weapon while using spycam/remote turret in default Lazarus and missionpack DLLs.
Fixed Tactician Gunner's flechettes going thru player bbox at point blank.
Made edict_t pointer arrays static in server, default Lazarus, and missionpack DLLs due to stack size concerns.
Added contact grenade mode for special monster flag for gunners in default Lazarus and missionpack DLLs.
2021-08-10 16:37:04 -04:00

853 lines
22 KiB
C

#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;
#ifdef KMQUAKE2_ENGINE_MOD
ent->client->ps.gunindex2 = 0;
#endif
ent->client->ps.blend[3] = 0;
ent->client->ps.rdflags &= ~RDF_UNDERWATER;
#ifdef KMQUAKE2_ENGINE_MOD
if (level.intermission_letterbox) // Knightmare- letterboxing
ent->client->ps.rdflags |= RDF_LETTERBOX;
#endif
// clean up powerup info
ent->client->quad_framenum = 0;
ent->client->quadfire_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->bfg_missfire = false; // Knightmare- added for Zaero EMP Nuke
ent->client->grenade_time = 0;
ent->client->ps.rdflags &= ~RDF_IRGOGGLES; // PGM
ent->client->ir_framenum = 0; // PGM
ent->client->nuke_framenum = 0; // PMM
ent->client->double_framenum = 0; // PMM
ent->viewheight = 0;
ent->s.modelindex = 0;
ent->s.modelindex2 = 0;
ent->s.modelindex3 = 0;
ent->s.modelindex4 = 0;
#ifdef KMQUAKE2_ENGINE_MOD
ent->s.modelindex5 = 0;
ent->s.modelindex6 = 0;
#endif
ent->s.effects = 0;
ent->s.sound = 0;
ent->solid = SOLID_NOT;
#ifdef JETPACK_MOD
ent->client->jetpack_framenum = 0;
#endif
// 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);
//Knightmare- end chasecam, set to restart-
//don't leave behind a player model
if (client->client->chasetoggle)
{
ChasecamRemove (client);
client->client->chasetoggle = 1;
}
}
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);
// Knightmare- letterboxing
if (!strcmp(ent->classname, "info_player_intermission"))
level.intermission_letterbox = (ent->spawnflags & 1);
else
level.intermission_letterbox = false;
// 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);
}
}
/*
==================
DeathmatchScoreboardMessage
==================
*/
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;
// 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++;
}
// print level name and exit rules
string[0] = 0;
stringlength = (int)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;
//===============
//ROGUE
// allow new DM games to override the tag picture
if (gamerules && gamerules->value)
{
if (DMGame.DogTag)
DMGame.DogTag(cl_ent, killer, &tag);
}
//ROGUE
//===============
if (tag)
{
Com_sprintf (entry, sizeof(entry),
"xv %i yv %i picn %s ",x+32, y, tag);
j = (int)strlen(entry);
if (stringlength + j > 1024)
break;
Com_strcpy (string + stringlength, sizeof(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 = (int)strlen(entry);
if (stringlength + j > 1024)
break;
Com_strcpy (string + stringlength, sizeof(string)-stringlength, entry);
stringlength += j;
}
gi.WriteByte (svc_layout);
gi.WriteString (string);
}
/*
==================
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)
{
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 (ent->client->menu)
PMenu_Close(ent);
if (ent->client->textdisplay)
Text_Close(ent);
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;
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);
}
//=======================================================================
void WhatIsIt (edict_t *ent)
{
float range;
int i, num;
static edict_t *touch[MAX_EDICTS]; // Knightmare- made static due to stack size
edict_t *who, *best;
trace_t tr;
vec3_t dir, end, entp, forward, mins, maxs, start, viewp;
/* Check for looking directly at a player or other non-trigger entity */
VectorCopy(ent->s.origin, start);
start[2] += ent->viewheight;
AngleVectors(ent->client->v_angle, forward, NULL, NULL);
VectorMA(start, WORLD_SIZE, forward, end); // was 8192
tr = gi.trace(start, NULL, NULL, end, ent, MASK_SHOT|CONTENTS_SLIME|CONTENTS_LAVA);
if (tr.ent > world)
{
if (tr.ent->common_name)
ent->client->whatsit = tr.ent->common_name;
// else
// ent->client->whatsit = tr.ent->classname;
return;
}
/* Check for looking directly at a pickup item */
VectorCopy(ent->s.origin,viewp);
viewp[2] += ent->viewheight;
AngleVectors(ent->client->v_angle, forward, NULL, NULL);
VectorSet(mins, MIN_WORLD_COORD, MIN_WORLD_COORD, MIN_WORLD_COORD); // was -4096, -4096, -4096
VectorSet(maxs, MAX_WORLD_COORD, MAX_WORLD_COORD, MAX_WORLD_COORD); // was 4096, 4096, 4096
num = gi.BoxEdicts (mins, maxs, touch, MAX_EDICTS, AREA_TRIGGERS);
best = NULL;
for (i=0 ; i<num ; i++)
{
who = touch[i];
if (!who->inuse)
continue;
if (!who->item)
continue;
if (!visible(ent,who))
continue;
if (!infront(ent,who))
continue;
VectorSubtract(who->s.origin,viewp,dir);
range = VectorLength(dir);
VectorMA(viewp, range, forward, entp);
if (entp[0] < who->s.origin[0] - 17) continue;
if (entp[1] < who->s.origin[1] - 17) continue;
if (entp[2] < who->s.origin[2] - 17) continue;
if (entp[0] > who->s.origin[0] + 17) continue;
if (entp[1] > who->s.origin[1] + 17) continue;
if (entp[2] > who->s.origin[2] + 17) continue;
best = who;
break;
}
if (best)
{
ent->client->whatsit = best->item->pickup_name;
return;
}
}
/*
===============
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;
#ifdef KMQUAKE2_ENGINE_MOD // for enhanced HUD
// ent->client->ps.stats[STAT_MAXHEALTH] = min(max(ent->client->pers.max_health, 0), 10000);
ent->client->ps.stats[STAT_MAXHEALTH] = min(max(ent->max_health, 0), 10000);
#endif
//
// 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;
#ifdef KMQUAKE2_ENGINE_MOD // for enhanced HUD
ent->client->ps.stats[STAT_MAXAMMO] = 0;
#endif
}
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];
#ifdef KMQUAKE2_ENGINE_MOD // for enhanced HUD
ent->client->ps.stats[STAT_MAXAMMO] = min(max(GetMaxAmmoByIndex(ent->client, ent->client->ammo_index), 0), 10000);
#endif
}
//
// 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_SHIELD|FL_POWER_SCREEN);
gi.sound(ent, CHAN_ITEM, gi.soundindex("misc/power2.wav"), 1, ATTN_NORM, 0);
power_armor_type = 0;
}
}
index = ArmorIndex (ent);
// Knightmare- show correct icon
if (power_armor_type && (!index || (level.framenum & 8) ) )
{ // flash between power armor and other armor icon
if (power_armor_type == POWER_ARMOR_SHIELD)
ent->client->ps.stats[STAT_ARMOR_ICON] = gi.imageindex ("i_powershield");
else // POWER_ARMOR_SCREEN
ent->client->ps.stats[STAT_ARMOR_ICON] = gi.imageindex ("i_powerscreen");
ent->client->ps.stats[STAT_ARMOR] = cells;
#ifdef KMQUAKE2_ENGINE_MOD // for enhanced HUD
ent->client->ps.stats[STAT_MAXARMOR] = min(max(ent->client->pers.max_cells, 0), 10000);
#endif
}
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];
#ifdef KMQUAKE2_ENGINE_MOD // for enhanced HUD
ent->client->ps.stats[STAT_MAXARMOR] = min(max(GetMaxArmorByIndex(index), 0), 10000);
#endif
}
else
{
ent->client->ps.stats[STAT_ARMOR_ICON] = 0;
ent->client->ps.stats[STAT_ARMOR] = 0;
#ifdef KMQUAKE2_ENGINE_MOD // for enhanced HUD
ent->client->ps.stats[STAT_MAXARMOR] = 0;
#endif
}
//
// 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;
#ifdef KMQUAKE2_ENGINE_MOD // for enhanced HUD
ent->client->ps.stats[STAT_TIMER_RANGE] = min(max((int)sk_quad_time->value, 0), 10000);
#endif
}
// RAFAEL
else if (ent->client->quadfire_framenum > level.framenum)
{
// note to self
// need to change imageindex
ent->client->ps.stats[STAT_TIMER_ICON] = gi.imageindex ("p_quadfire");
ent->client->ps.stats[STAT_TIMER] = (ent->client->quadfire_framenum - level.framenum)/10;
#ifdef KMQUAKE2_ENGINE_MOD // for enhanced HUD
ent->client->ps.stats[STAT_TIMER_RANGE] = min(max((int)sk_quad_fire_time->value, 0), 10000);
#endif
}
// PMM
else if (ent->client->double_framenum > level.framenum)
{
ent->client->ps.stats[STAT_TIMER_ICON] = gi.imageindex ("p_double");
ent->client->ps.stats[STAT_TIMER] = (ent->client->double_framenum - level.framenum)/10;
#ifdef KMQUAKE2_ENGINE_MOD // for enhanced HUD
ent->client->ps.stats[STAT_TIMER_RANGE] = min(max((int)sk_double_time->value, 0), 10000);
#endif
}
// PMM
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;
#ifdef KMQUAKE2_ENGINE_MOD // for enhanced HUD
ent->client->ps.stats[STAT_TIMER_RANGE] = min(max((int)sk_inv_time->value, 0), 10000);
#endif
}
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;
#ifdef KMQUAKE2_ENGINE_MOD // for enhanced HUD
ent->client->ps.stats[STAT_TIMER_RANGE] = min(max((int)sk_enviro_time->value, 0), 10000);
#endif
}
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;
#ifdef KMQUAKE2_ENGINE_MOD // for enhanced HUD
ent->client->ps.stats[STAT_TIMER_RANGE] = min(max((int)sk_breather_time->value, 0), 10000);
#endif
}
// PGM
else if (ent->client->owned_sphere)
{
int sphere_time;
if (ent->client->owned_sphere->spawnflags == 1) { // defender
ent->client->ps.stats[STAT_TIMER_ICON] = gi.imageindex ("p_defender");
sphere_time = sk_defender_time->value;
}
else if (ent->client->owned_sphere->spawnflags == 2) { // hunter
ent->client->ps.stats[STAT_TIMER_ICON] = gi.imageindex ("p_hunter");
sphere_time = sk_hunter_time->value;
}
else if (ent->client->owned_sphere->spawnflags == 4) { // vengeance
ent->client->ps.stats[STAT_TIMER_ICON] = gi.imageindex ("p_vengeance");
sphere_time = sk_vengeance_time->value;
}
else { // error case
ent->client->ps.stats[STAT_TIMER_ICON] = gi.imageindex ("i_fixme");
sphere_time = 0;
}
ent->client->ps.stats[STAT_TIMER] = (int)(ent->client->owned_sphere->wait - level.time);
#ifdef KMQUAKE2_ENGINE_MOD // for enhanced HUD
ent->client->ps.stats[STAT_TIMER_RANGE] = min(max(sphere_time, 0), 10000);
#endif
}
else if (ent->client->ir_framenum > level.framenum)
{
ent->client->ps.stats[STAT_TIMER_ICON] = gi.imageindex ("p_ir");
ent->client->ps.stats[STAT_TIMER] = (ent->client->ir_framenum - level.framenum)/10;
#ifdef KMQUAKE2_ENGINE_MOD // for enhanced HUD
ent->client->ps.stats[STAT_TIMER_RANGE] = min(max((int)sk_ir_time->value, 0), 10000);
#endif
}
// PGM
#ifdef JETPACK_MOD
else if ( (ent->client->jetpack) &&
(!ent->client->jetpack_infinite) &&
(ent->client->pers.inventory[fuel_index] >= 0) &&
(ent->client->pers.inventory[fuel_index] < 100000))
{
ent->client->ps.stats[STAT_TIMER_ICON] = gi.imageindex("p_jet");
ent->client->ps.stats[STAT_TIMER] = ent->client->pers.inventory[fuel_index];
#ifdef KMQUAKE2_ENGINE_MOD // for enhanced HUD
ent->client->ps.stats[STAT_TIMER_RANGE] = min(max(ent->client->pers.max_fuel, 0), 10000);
#endif
}
#endif
// added stasis generator support
else if (level.freeze)
{
ent->client->ps.stats[STAT_TIMER_ICON] = gi.imageindex ("p_freeze");
ent->client->ps.stats[STAT_TIMER] = sk_stasis_time->value - level.freezeframes/10; // was 30
#ifdef KMQUAKE2_ENGINE_MOD // for enhanced HUD
ent->client->ps.stats[STAT_TIMER_RANGE] = min(max((int)sk_stasis_time->value, 0), 10000);
#endif
}
else
{
ent->client->ps.stats[STAT_TIMER_ICON] = 0;
ent->client->ps.stats[STAT_TIMER] = 0;
#ifdef KMQUAKE2_ENGINE_MOD // for enhanced HUD
ent->client->ps.stats[STAT_TIMER_RANGE] = 0;
#endif
}
//
// 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;
// Lazarus vehicle/tracktrain
if (ent->vehicle && !(ent->vehicle->spawnflags & 16))
{
switch (ent->vehicle->moveinfo.state)
{
case -3: ent->client->ps.stats[STAT_SPEED] = gi.imageindex("speedr3"); break;
case -2: ent->client->ps.stats[STAT_SPEED] = gi.imageindex("speedr2"); break;
case -1: ent->client->ps.stats[STAT_SPEED] = gi.imageindex("speedr1"); break;
case 1: ent->client->ps.stats[STAT_SPEED] = gi.imageindex("speed1"); break;
case 2: ent->client->ps.stats[STAT_SPEED] = gi.imageindex("speed2"); break;
case 3: ent->client->ps.stats[STAT_SPEED] = gi.imageindex("speed3"); break;
default: ent->client->ps.stats[STAT_SPEED] = gi.imageindex("speed0"); break;
}
}
else
ent->client->ps.stats[STAT_SPEED] = 0;
// "whatsit"
if (world->effects & FX_WORLDSPAWN_WHATSIT)
{
if (ent->client->showscores || ent->client->showhelp || ent->client->showinventory)
ent->client->whatsit = NULL;
else if (!(level.framenum % 5)) // only update every 1/2 second
{
char *temp = ent->client->whatsit;
ent->client->whatsit = NULL;
WhatIsIt(ent);
if (ent->client->whatsit && !temp)
WhatsIt(ent);
}
}
else
ent->client->whatsit = NULL;
//
// 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;
#ifdef KMQUAKE2_ENGINE_MOD // for enhanced HUD
if (ent->client->pers.weapon) {
if (ITEM_INDEX(ent->client->pers.weapon) == hml_index) // homing rocket launcher has no icon
ent->client->ps.stats[STAT_WEAPON] = gi.imageindex (GetItemByIndex(rl_index)->icon);
else
ent->client->ps.stats[STAT_WEAPON] = gi.imageindex (ent->client->pers.weapon->icon);
}
else
ent->client->ps.stats[STAT_WEAPON] = 0;
#endif
ent->client->ps.stats[STAT_SPECTATOR] = 0;
if (ent->client->zoomed)
ent->client->ps.stats[STAT_ZOOM] = gi.imageindex("zoom");
else
ent->client->ps.stats[STAT_ZOOM] = 0;
// Zaero
if (ent->client->zCameraTrack)
{
ent->client->ps.stats[STAT_CAMERA_ICON] = gi.imageindex("i_visor");
ent->client->ps.stats[STAT_CAMERA_TIMER] = ent->client->pers.visorFrames/10;
#ifdef KMQUAKE2_ENGINE_MOD // for enhanced HUD
// ent->client->ps.stats[STAT_CAMERA_RANGE] = min(max((int)sk_visor_time->value, 0), 10000);
#endif
}
else {
ent->client->ps.stats[STAT_CAMERA_ICON] = 0;
#ifdef KMQUAKE2_ENGINE_MOD // for enhanced HUD
// ent->client->ps.stats[STAT_CAMERA_RANGE] = 0;
#endif
}
// end Zaero
}
/*
===============
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;
}