mirror of
https://github.com/blendogames/thirtyflightsofloving.git
synced 2024-11-15 00:41:21 +00:00
9481c7c513
Changed Zaero and 3ZB2 game DLLs to use WORLD_SIZE for various calculations instead of 8192. Cleaned up string handling in 3ZB2 game DLL. Added func_plat2, func_door_secret2, and func_force_wall from Rogue to 3ZB2 game DLL. Added alternate attack contact explode for grenade launcher in 3ZB2 game DLL. Added awakening2 game DLL source.
842 lines
22 KiB
C
842 lines
22 KiB
C
// p_hud.c
|
|
|
|
#include "g_local.h"
|
|
|
|
/*
|
|
======================================================================
|
|
|
|
INTERMISSION
|
|
|
|
======================================================================
|
|
*/
|
|
|
|
void MoveClientToIntermission(edict_t *ent)
|
|
{
|
|
ent->client->showscores = true; //CW
|
|
|
|
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;
|
|
|
|
// 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;
|
|
//CW++
|
|
ent->client->show_gausscharge = false;
|
|
ent->client->show_gausstarget = 0;
|
|
ent->client->gauss_dmg = 0;
|
|
ent->client->gauss_framenum = 0;
|
|
|
|
ent->client->antibeam_framenum = 0;
|
|
ent->client->frozen_framenum = 0;
|
|
ent->client->siphon_framenum = 0;
|
|
ent->client->needle_framenum = 0;
|
|
ent->client->haste_framenum = 0;
|
|
|
|
ent->client->mod_changeteam = false;
|
|
ent->burning = false;
|
|
ent->disintegrated = false;
|
|
ent->tractored = false;
|
|
|
|
ent->client->agm_charge = 0;
|
|
ent->client->agm_showcharge = false;
|
|
ent->client->agm_tripped = false;
|
|
ent->client->agm_on = false;
|
|
ent->client->agm_push = false;
|
|
ent->client->agm_pull = false;
|
|
ent->client->held_by_agm = false;
|
|
ent->client->flung_by_agm = false;
|
|
ent->client->thrown_by_agm = false;
|
|
ent->client->agm_target = NULL;
|
|
ent->client->agm_enemy = NULL;
|
|
|
|
if (ent->client->ctf_grapple)
|
|
CTFResetGrapple(ent->client->ctf_grapple);
|
|
//CW--
|
|
|
|
ent->viewheight = 0;
|
|
ent->s.modelindex = 0;
|
|
ent->s.modelindex2 = 0;
|
|
ent->s.modelindex3 = 0;
|
|
ent->s.modelindex4 = 0; //CW
|
|
#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;
|
|
|
|
// Add the layout.
|
|
|
|
//Maj++
|
|
// don't unicast() to bots!
|
|
if (ent->isabot)
|
|
return;
|
|
//Maj--
|
|
|
|
DeathmatchScoreboardMessage(ent, NULL); //CW
|
|
gi.unicast(ent, true);
|
|
}
|
|
|
|
void BeginIntermission(edict_t *targ)
|
|
{
|
|
edict_t *ent;
|
|
edict_t *client;
|
|
edict_t *wep_ent; //CW++
|
|
int i;
|
|
|
|
if (level.intermissiontime)
|
|
return; // already activated
|
|
|
|
//ZOID++
|
|
if ((int)sv_gametype->value > G_FFA) //CW
|
|
CTFCalcScores();
|
|
//ZOID--
|
|
|
|
game.autosaved = false;
|
|
|
|
// Respawn any dead clients.
|
|
|
|
for (i = 0; i < (int)maxclients->value; ++i)
|
|
{
|
|
client = g_edicts + 1 + i;
|
|
if (!client->inuse)
|
|
continue;
|
|
|
|
if (client->health < 1)
|
|
Respawn(client);
|
|
}
|
|
|
|
level.intermissiontime = level.time;
|
|
level.changemap = targ->map;
|
|
level.exitintermission = 0; //CW
|
|
|
|
// 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);
|
|
|
|
//CW++
|
|
// Remove weapon entities to avoid server crashes due to delayed player deaths.
|
|
|
|
for (i = 0; i < globals.num_edicts; ++i)
|
|
{
|
|
wep_ent = &g_edicts[i];
|
|
|
|
if (!wep_ent->inuse)
|
|
continue;
|
|
|
|
if ((wep_ent->die == Trap_DieFromDamage) || (wep_ent->die == C4_DieFromDamage))
|
|
{
|
|
TList_DelNode(wep_ent);
|
|
G_FreeEdict(wep_ent);
|
|
}
|
|
|
|
if (wep_ent->wep_proj)
|
|
G_FreeEdict(wep_ent);
|
|
}
|
|
//CW--
|
|
|
|
// Move all clients to the intermission point.
|
|
|
|
for (i = 0; i < (int)maxclients->value; ++i)
|
|
{
|
|
client = g_edicts + 1 + i;
|
|
if (!client->inuse)
|
|
continue;
|
|
//CW++
|
|
if (client->isabot)
|
|
continue;
|
|
//CW--
|
|
|
|
MoveClientToIntermission(client);
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
==================
|
|
DeathmatchScoreboardMessage
|
|
|
|
==================
|
|
*/
|
|
void DeathmatchScoreboardMessage(edict_t *ent, edict_t *killer)
|
|
{
|
|
gclient_t *cl;
|
|
edict_t *cl_ent;
|
|
char entry[1024];
|
|
char string[1400];
|
|
char *tag;
|
|
char entry2[64]; //CW++
|
|
int stringlength;
|
|
int i, j, k;
|
|
int sorted[MAX_CLIENTS];
|
|
int sortedscores[MAX_CLIENTS];
|
|
int score;
|
|
int total;
|
|
int picnum;
|
|
int x, y;
|
|
|
|
//CW++
|
|
if (ent->client->showscores || ent->client->showinventory)
|
|
{
|
|
if (ent->client->show_gausstarget)
|
|
ent->client->show_gausstarget = 2;
|
|
}
|
|
|
|
if (ent->client->showscores)
|
|
{
|
|
//CW--
|
|
|
|
//ZOID++
|
|
if (sv_gametype->value == G_CTF) //CW
|
|
{
|
|
CTFScoreboardMessage(ent, killer);
|
|
return;
|
|
}
|
|
//ZOID--
|
|
|
|
//CW++
|
|
else if ((sv_gametype->value == G_TDM) || (sv_gametype->value == G_ASLT))
|
|
{
|
|
TDMScoreboardMessage(ent, killer);
|
|
return;
|
|
}
|
|
//CW--
|
|
|
|
// sort the clients by score
|
|
total = 0;
|
|
for (i = 0; i < game.maxclients; i++)
|
|
{
|
|
cl_ent = g_edicts + 1 + i;
|
|
if (!cl_ent->inuse)
|
|
continue;
|
|
//CW++
|
|
if (cl_ent->client->spectator)
|
|
continue;
|
|
//CW--
|
|
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++;
|
|
}
|
|
|
|
//CW++
|
|
// Add spectators to the end of the list.
|
|
|
|
for (i = 0; i < game.maxclients; i++)
|
|
{
|
|
cl_ent = g_edicts + 1 + i;
|
|
if (!cl_ent->inuse)
|
|
continue;
|
|
if (!cl_ent->client->spectator)
|
|
continue;
|
|
|
|
sorted[total] = i;
|
|
sortedscores[total] = 0;
|
|
total++;
|
|
}
|
|
//CW--
|
|
|
|
// 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;
|
|
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;
|
|
|
|
// strcpy(string + stringlength, entry);
|
|
Com_strcpy(string + stringlength, sizeof(string)-stringlength, entry);
|
|
stringlength += j;
|
|
}
|
|
|
|
// send the layout
|
|
//CW++
|
|
if (cl->spectator)
|
|
{
|
|
Com_sprintf(entry, sizeof(entry), "xv %d yv %d string2 \"%s\" ", x+32, y, cl->pers.netname);
|
|
Com_sprintf(entry2, sizeof(entry2), "xv %d yv %d string \"(Spectator)\" ", x+32, y+8);
|
|
Com_strcat(entry, sizeof(entry), entry2);
|
|
if (cl->chase_target)
|
|
{
|
|
Com_sprintf(entry2, sizeof(entry2), "xv %d yv %d string \"Watching:\" ", x+32, y+16);
|
|
Com_strcat(entry, sizeof(entry), entry2);
|
|
Com_sprintf(entry2, sizeof(entry2), "xv %d yv %d string \"%s\" ", x+32, y+24, cl->chase_target->client->pers.netname);
|
|
Com_strcat(entry, sizeof(entry), entry2);
|
|
}
|
|
}
|
|
else
|
|
//CW--
|
|
Com_sprintf(entry, sizeof(entry), "client %i %i %i %i %i %i ", x, y, sorted[i], cl->resp.score, cl->ping, (int)((level.framenum - cl->resp.enterframe)/600));
|
|
j = (int)strlen(entry);
|
|
if (stringlength + j > 1024)
|
|
break;
|
|
|
|
// strcpy(string + stringlength, entry);
|
|
Com_strcpy(string + stringlength, sizeof(string)-stringlength,entry);
|
|
stringlength += j;
|
|
}
|
|
|
|
//CW++
|
|
}
|
|
else
|
|
*string = 0;
|
|
|
|
if (ent->client->show_gausstarget & 1)
|
|
ShowGaussTarget(ent, string, sizeof(string));
|
|
//CW--
|
|
|
|
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)
|
|
{
|
|
//Maj++
|
|
// don't unicast() to bots!
|
|
if (ent->isabot)
|
|
return;
|
|
//Maj--
|
|
|
|
DeathmatchScoreboardMessage(ent, ent->enemy);
|
|
gi.unicast(ent, true);
|
|
}
|
|
|
|
|
|
/*
|
|
==================
|
|
Cmd_Score_f
|
|
|
|
Display the scoreboard
|
|
==================
|
|
*/
|
|
void Cmd_Score_f(edict_t *ent)
|
|
{
|
|
//CW++
|
|
if (ent->isabot)
|
|
return;
|
|
//CW--
|
|
|
|
ent->client->showinventory = false;
|
|
ent->client->showhelp = false;
|
|
|
|
//ZOID++
|
|
if (ent->client->menu)
|
|
PMenu_Close(ent);
|
|
//ZOID--
|
|
|
|
if (ent->client->showscores)
|
|
{
|
|
ent->client->showscores = false;
|
|
ent->client->update_chase = true;
|
|
|
|
//CW++
|
|
if (ent->client->show_gausstarget & 2)
|
|
ent->client->show_gausstarget = 1;
|
|
//CW--
|
|
return;
|
|
}
|
|
|
|
ent->client->showscores = true;
|
|
DeathmatchScoreboard(ent);
|
|
}
|
|
|
|
|
|
//=======================================================================
|
|
|
|
//CW++
|
|
/*
|
|
===============
|
|
SetWepIDView
|
|
|
|
This is a modified version of the CTFSetIDView() function written by Zoid.
|
|
===============
|
|
*/
|
|
void SetWepIDView(edict_t *ent)
|
|
{
|
|
edict_t *index;
|
|
edict_t *check;
|
|
vec3_t forward;
|
|
vec3_t start;
|
|
vec3_t dir;
|
|
float dp_best = 0.0;
|
|
float dp;
|
|
float range;
|
|
qboolean finished = false;
|
|
|
|
// If the player has no C4 or Traps, don't bother.
|
|
|
|
if (!ent->next_node)
|
|
{
|
|
ent->client->ps.stats[STAT_CTF_ID_VIEW_COLOR] = 0;
|
|
return;
|
|
}
|
|
|
|
// Only check every few frames.
|
|
|
|
if (level.time - ent->client->resp.id_trap_time < TRAP_ID_CHECKTIME)
|
|
return;
|
|
|
|
// Cycle through the player's linked list of C4 and Trap entities to determine which
|
|
// visible entity (if any) is closest to the player's facing direction.
|
|
|
|
ent->client->resp.id_trap_time = level.time;
|
|
ent->client->ps.stats[STAT_CTF_ID_VIEW_COLOR] = 0;
|
|
AngleVectors(ent->client->v_angle, forward, NULL, NULL);
|
|
start[0] = ent->s.origin[0];
|
|
start[1] = ent->s.origin[1];
|
|
start[2] = ent->s.origin[2] + ent->viewheight;
|
|
|
|
index = ent->next_node;
|
|
while (index && !finished)
|
|
{
|
|
check = index;
|
|
if (index->next_node)
|
|
index = index->next_node;
|
|
else
|
|
finished = true;
|
|
|
|
VectorSubtract(check->s.origin, start, dir);
|
|
range = VectorLength(dir);
|
|
VectorNormalize(dir);
|
|
dp = DotProduct(forward, dir);
|
|
if ((dp > dp_best) && (range < TRAP_ID_RANGE) && visible(ent, check))
|
|
dp_best = dp;
|
|
}
|
|
|
|
if (dp_best > TRAP_ID_DOTPRODUCT)
|
|
ent->client->ps.stats[STAT_CTF_ID_VIEW_COLOR] = gi.imageindex("i_no");
|
|
}
|
|
//CW--
|
|
|
|
/*
|
|
===============
|
|
G_SetStats
|
|
===============
|
|
*/
|
|
void G_SetStats(edict_t *ent)
|
|
{
|
|
gitem_t *item;
|
|
int index;
|
|
int cells = 0; //CW
|
|
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->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);
|
|
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
|
|
//CW++
|
|
// Show weapon charges before powerups.
|
|
|
|
if (ent->client->show_gausscharge)
|
|
{
|
|
ent->client->ps.stats[STAT_TIMER_ICON] = gi.imageindex("a_blaster");
|
|
if (ent->client->pers.inventory[ent->client->ammo_index] > 0)
|
|
{
|
|
ent->client->gauss_dmg = (int)((level.framenum - ent->client->gauss_framenum) / (10.0 * sv_gauss_damage_rate->value));
|
|
ent->client->gauss_dmg *= (int)sv_gauss_damage_step->value;
|
|
ent->client->gauss_dmg += (int)sv_gauss_damage_base->value;
|
|
}
|
|
else
|
|
ent->client->gauss_dmg = (int)sv_gauss_damage_base->value;
|
|
|
|
if (ent->client->gauss_dmg > sv_gauss_damage_max->value)
|
|
ent->client->gauss_dmg = (int)sv_gauss_damage_max->value;
|
|
|
|
ent->client->ps.stats[STAT_TIMER] = ent->client->gauss_dmg;
|
|
#ifdef KMQUAKE2_ENGINE_MOD // for enhanced HUD
|
|
ent->client->ps.stats[STAT_TIMER_RANGE] = min(max((int)sv_gauss_damage_max->value, 0), 10000);
|
|
#endif
|
|
}
|
|
else if (ent->client->agm_showcharge)
|
|
{
|
|
if (ent->client->agm_tripped)
|
|
ent->client->ps.stats[STAT_TIMER_ICON] = gi.imageindex("a_refuse");
|
|
else
|
|
ent->client->ps.stats[STAT_TIMER_ICON] = gi.imageindex("a_agm");
|
|
ent->client->ps.stats[STAT_TIMER] = ent->client->agm_charge;
|
|
#ifdef KMQUAKE2_ENGINE_MOD // for enhanced HUD
|
|
ent->client->ps.stats[STAT_TIMER_RANGE] = 100;
|
|
#endif
|
|
}
|
|
//CW--
|
|
else 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(QUAD_TIMEOUT_FRAMES / 10, 0), 10000);
|
|
#endif
|
|
}
|
|
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(INVINCIBLE_TIMEOUT_FRAMES / 10, 0), 10000);
|
|
#endif
|
|
}
|
|
//CW++
|
|
else if (ent->client->siphon_framenum > level.framenum)
|
|
{
|
|
ent->client->ps.stats[STAT_TIMER_ICON] = gi.imageindex("p_siphon");
|
|
ent->client->ps.stats[STAT_TIMER] = (ent->client->siphon_framenum - level.framenum) / 10;
|
|
#ifdef KMQUAKE2_ENGINE_MOD // for enhanced HUD
|
|
ent->client->ps.stats[STAT_TIMER_RANGE] = min(max(SIPHON_TIMEOUT_FRAMES / 10, 0), 10000);
|
|
#endif
|
|
}
|
|
else if (ent->client->needle_framenum > level.framenum)
|
|
{
|
|
ent->client->ps.stats[STAT_TIMER_ICON] = gi.imageindex("p_needle");
|
|
ent->client->ps.stats[STAT_TIMER] = (ent->client->needle_framenum - level.framenum) / 10;
|
|
#ifdef KMQUAKE2_ENGINE_MOD // for enhanced HUD
|
|
ent->client->ps.stats[STAT_TIMER_RANGE] = min(max(NEEDLE_TIMEOUT_FRAMES / 10, 0), 10000);
|
|
#endif
|
|
}
|
|
else if (ent->client->haste_framenum > level.framenum)
|
|
{
|
|
ent->client->ps.stats[STAT_TIMER_ICON] = gi.imageindex("p_haste");
|
|
ent->client->ps.stats[STAT_TIMER] = (ent->client->haste_framenum - level.framenum) / 10;
|
|
#ifdef KMQUAKE2_ENGINE_MOD // for enhanced HUD
|
|
ent->client->ps.stats[STAT_TIMER_RANGE] = min(max(HASTE_TIMEOUT_FRAMES / 10, 0), 10000);
|
|
#endif
|
|
}
|
|
//CW--
|
|
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(ENVIROSUIT_TIMEOUT_FRAMES / 10, 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(BREATHER_TIMEOUT_FRAMES / 10, 0), 10000);
|
|
#endif
|
|
}
|
|
//CW++
|
|
else if (ent->client->antibeam_framenum > level.framenum)
|
|
{
|
|
ent->client->ps.stats[STAT_TIMER_ICON] = gi.imageindex("k_datacd");
|
|
ent->client->ps.stats[STAT_TIMER] = (ent->client->antibeam_framenum - level.framenum) / 10;
|
|
#ifdef KMQUAKE2_ENGINE_MOD // for enhanced HUD
|
|
ent->client->ps.stats[STAT_TIMER_RANGE] = min(max(ANTIBEAM_TIMEOUT_FRAMES / 10, 0), 10000);
|
|
#endif
|
|
}
|
|
//CW--
|
|
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->pers.selected_item) //CW
|
|
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 ((ent->client->pers.health <= 0) || level.intermissiontime || ent->client->showscores || ent->client->show_gausstarget) //CW
|
|
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->resp.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.0)) && 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) {
|
|
ent->client->ps.stats[STAT_WEAPON] = gi.imageindex (ent->client->pers.weapon->icon);
|
|
}
|
|
else
|
|
ent->client->ps.stats[STAT_WEAPON] = 0;
|
|
#endif
|
|
|
|
//ZOID++
|
|
SetCTFStats(ent);
|
|
//ZOID--
|
|
|
|
//CW++
|
|
if (((int)sv_gametype->value == G_FFA) && ent->client->resp.id_trap)
|
|
SetWepIDView(ent);
|
|
//CW--
|
|
}
|
|
|
|
//CW++
|
|
/*
|
|
==================
|
|
ShowGaussTarget
|
|
|
|
Helpful hints for the implementation of this code
|
|
were given by Damien "Yaya" Slee.
|
|
==================
|
|
*/
|
|
void ShowGaussTarget (edict_t *ent, char *string, size_t stringSize)
|
|
{
|
|
edict_t *cl_ent;
|
|
edict_t *targ = NULL;
|
|
vec3_t targ_vec;
|
|
vec3_t forward;
|
|
vec3_t right;
|
|
vec3_t offset;
|
|
vec3_t start;
|
|
vec3_t vec;
|
|
vec3_t t_ang;
|
|
char str_temp[64];
|
|
float dist;
|
|
float min_dist = WORLD_SIZE; // was 8192.0
|
|
int x = 999;
|
|
int y = 999;
|
|
int i;
|
|
|
|
// Display the targeting area overlay.
|
|
|
|
Com_sprintf(str_temp, sizeof(str_temp), "xv 32 yv -4 picn g_scan ");
|
|
if ((strlen(string) + strlen(str_temp)) < 1024)
|
|
// strcat(string, str_temp);
|
|
Com_strcat(string, stringSize, str_temp);
|
|
|
|
// Search through the list of entities to determine if any live players are in front of us.
|
|
// For multiple targets, select the nearest one.
|
|
|
|
AngleVectors(ent->client->v_angle, forward, right, NULL);
|
|
VectorSet(offset, 24.0, 8.0, ent->viewheight-5.0); // NB: should be same as offset in Weapon_GaussPistol_Fire()
|
|
P_ProjectSource(ent->client, ent->s.origin, offset, forward, right, start);
|
|
|
|
for (i = 0; i < globals.num_edicts; ++i)
|
|
{
|
|
cl_ent = &g_edicts[i];
|
|
|
|
if (!cl_ent->client)
|
|
continue;
|
|
if (!cl_ent->inuse)
|
|
continue;
|
|
if (cl_ent->movetype == MOVETYPE_NOCLIP)
|
|
continue;
|
|
if (cl_ent == ent)
|
|
continue;
|
|
if (cl_ent->health < 1)
|
|
continue;
|
|
if (((int)sv_gametype->value > G_FFA) && (ent->client->resp.ctf_team == cl_ent->client->resp.ctf_team))
|
|
continue;
|
|
|
|
VectorSubtract(cl_ent->s.origin, start, vec);
|
|
if ((dist = VectorLength(vec)) > sv_gauss_scan_range->value)
|
|
continue;
|
|
|
|
VectorNormalize(vec);
|
|
if (DotProduct(vec, forward) > 0.75)
|
|
{
|
|
if (dist < min_dist)
|
|
{
|
|
targ = cl_ent;
|
|
VectorCopy(vec, targ_vec);
|
|
min_dist = dist;
|
|
}
|
|
}
|
|
}
|
|
|
|
// If a valid target has been found, check that it is within the scanner's field-of-view,
|
|
// and if so, position the tracking reticle over them.
|
|
|
|
if (targ != NULL)
|
|
{
|
|
vectoangles(targ_vec, t_ang);
|
|
x = (int)(GAUSS_AIMCAL * sin(DEG2RAD((ent->client->v_angle[1] - t_ang[1]))));
|
|
y = (int)(GAUSS_AIMCAL * sin(DEG2RAD((t_ang[0] - ent->client->v_angle[0]))));
|
|
}
|
|
else
|
|
return;
|
|
|
|
if ((abs(x) < 70) && (abs(y) < 70))
|
|
{
|
|
Com_sprintf(str_temp, sizeof(str_temp), "xv %i yv %i picn g_targ ", 136+x, 100+y);
|
|
if ((strlen(string) + strlen(str_temp)) < 1024)
|
|
// strcat(string, str_temp);
|
|
Com_strcat(string, stringSize, str_temp);
|
|
|
|
if (level.time > targ->delay)
|
|
{
|
|
targ->delay = level.time + 2.0;
|
|
if (targ->target_ent && targ->target_ent->client && targ->target_ent->client->spycam)
|
|
{
|
|
unicastSound(targ->target_ent, gi.soundindex("weapons/gauss/warn.wav"), 1.0); //r1,CW
|
|
targ->target_ent->delay = level.time + 2.0;
|
|
}
|
|
else
|
|
unicastSound(targ, gi.soundindex("weapons/gauss/warn.wav"), 1.0); //r1,CW
|
|
}
|
|
}
|
|
}
|
|
//CW--
|