mirror of
https://github.com/yquake2/yquake2remaster.git
synced 2025-02-21 11:21:52 +00:00
game: sync rogue player code
This commit is contained in:
parent
5103bd6f72
commit
5c87db6e88
7 changed files with 338 additions and 2412 deletions
6
Makefile
6
Makefile
|
@ -1523,9 +1523,9 @@ ROGUE_OBJS_ = \
|
||||||
src/game/monster/widow/widow.o \
|
src/game/monster/widow/widow.o \
|
||||||
src/game/monster/widow/widow2.o \
|
src/game/monster/widow/widow2.o \
|
||||||
src/game/player/client.o \
|
src/game/player/client.o \
|
||||||
src/rogue/player/hud.o \
|
src/game/player/hud.o \
|
||||||
src/rogue/player/trail.o \
|
src/game/player/trail.o \
|
||||||
src/rogue/player/view.o \
|
src/game/player/view.o \
|
||||||
src/game/player/weapon.o \
|
src/game/player/weapon.o \
|
||||||
src/rogue/savegame/savegame.o
|
src/rogue/savegame/savegame.o
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 1997-2001 Id Software, Inc.
|
* Copyright (C) 1997-2001 Id Software, Inc.
|
||||||
|
* Copyright (c) ZeniMax Media Inc.
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* 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
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
@ -292,11 +293,16 @@ ED_CallSpawn(edict_t *ent)
|
||||||
}
|
}
|
||||||
|
|
||||||
char *
|
char *
|
||||||
ED_NewString(char *string)
|
ED_NewString(const char *string)
|
||||||
{
|
{
|
||||||
char *newb, *new_p;
|
char *newb, *new_p;
|
||||||
int i, l;
|
int i, l;
|
||||||
|
|
||||||
|
if (!string)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
l = strlen(string) + 1;
|
l = strlen(string) + 1;
|
||||||
|
|
||||||
newb = gi.TagMalloc(l, TAG_LEVEL);
|
newb = gi.TagMalloc(l, TAG_LEVEL);
|
||||||
|
@ -332,16 +338,21 @@ ED_NewString(char *string)
|
||||||
* the binary values in an edict
|
* the binary values in an edict
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
ED_ParseField(char *key, char *value, edict_t *ent)
|
ED_ParseField(const char *key, const char *value, edict_t *ent)
|
||||||
{
|
{
|
||||||
field_t *f;
|
field_t *f;
|
||||||
byte *b;
|
byte *b;
|
||||||
float v;
|
float v;
|
||||||
vec3_t vec;
|
vec3_t vec;
|
||||||
|
|
||||||
|
if (!ent || !value || !key)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
for (f = fields; f->name; f++)
|
for (f = fields; f->name; f++)
|
||||||
{
|
{
|
||||||
if (!Q_stricmp(f->name, key))
|
if (!(f->flags & FFL_NOSPAWN) && !Q_strcasecmp(f->name, (char *)key))
|
||||||
{
|
{
|
||||||
/* found it */
|
/* found it */
|
||||||
if (f->flags & FFL_SPAWNTEMP)
|
if (f->flags & FFL_SPAWNTEMP)
|
||||||
|
@ -365,13 +376,13 @@ ED_ParseField(char *key, char *value, edict_t *ent)
|
||||||
((float *)(b + f->ofs))[2] = vec[2];
|
((float *)(b + f->ofs))[2] = vec[2];
|
||||||
break;
|
break;
|
||||||
case F_INT:
|
case F_INT:
|
||||||
*(int *)(b + f->ofs) = atoi(value);
|
*(int *)(b + f->ofs) = (int)strtol(value, (char **)NULL, 10);
|
||||||
break;
|
break;
|
||||||
case F_FLOAT:
|
case F_FLOAT:
|
||||||
*(float *)(b + f->ofs) = atof(value);
|
*(float *)(b + f->ofs) = (float)strtod(value, (char **)NULL);
|
||||||
break;
|
break;
|
||||||
case F_ANGLEHACK:
|
case F_ANGLEHACK:
|
||||||
v = atof(value);
|
v = (float)strtod(value, (char **)NULL);
|
||||||
((float *)(b + f->ofs))[0] = 0;
|
((float *)(b + f->ofs))[0] = 0;
|
||||||
((float *)(b + f->ofs))[1] = v;
|
((float *)(b + f->ofs))[1] = v;
|
||||||
((float *)(b + f->ofs))[2] = 0;
|
((float *)(b + f->ofs))[2] = 0;
|
||||||
|
@ -391,7 +402,7 @@ ED_ParseField(char *key, char *value, edict_t *ent)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Parses an edict out of the given string,
|
* Parses an edict out of the given string,
|
||||||
* returning the new position ed should be
|
* returning the new position. ed should be
|
||||||
* a properly initialized empty edict.
|
* a properly initialized empty edict.
|
||||||
*/
|
*/
|
||||||
char *
|
char *
|
||||||
|
@ -399,10 +410,16 @@ ED_ParseEdict(char *data, edict_t *ent)
|
||||||
{
|
{
|
||||||
qboolean init;
|
qboolean init;
|
||||||
char keyname[256];
|
char keyname[256];
|
||||||
char *com_token;
|
const char *com_token;
|
||||||
|
|
||||||
|
if (!ent)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
init = false;
|
init = false;
|
||||||
memset(&st, 0, sizeof(st));
|
memset(&st, 0, sizeof(st));
|
||||||
|
st.skyautorotate = 1;
|
||||||
|
|
||||||
/* go through all the dictionary pairs */
|
/* go through all the dictionary pairs */
|
||||||
while (1)
|
while (1)
|
||||||
|
@ -420,7 +437,7 @@ ED_ParseEdict(char *data, edict_t *ent)
|
||||||
gi.error("ED_ParseEntity: EOF without closing brace");
|
gi.error("ED_ParseEntity: EOF without closing brace");
|
||||||
}
|
}
|
||||||
|
|
||||||
strncpy(keyname, com_token, sizeof(keyname) - 1);
|
Q_strlcpy(keyname, com_token, sizeof(keyname));
|
||||||
|
|
||||||
/* parse value */
|
/* parse value */
|
||||||
com_token = COM_Parse(&data);
|
com_token = COM_Parse(&data);
|
||||||
|
@ -437,9 +454,9 @@ ED_ParseEdict(char *data, edict_t *ent)
|
||||||
|
|
||||||
init = true;
|
init = true;
|
||||||
|
|
||||||
/* keynames with a leading underscore are used
|
/* keynames with a leading underscore are
|
||||||
for utility comments, and are immediately
|
used for utility comments, and are
|
||||||
discarded by quake */
|
immediately discarded by quake */
|
||||||
if (keyname[0] == '_')
|
if (keyname[0] == '_')
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
|
@ -462,6 +479,77 @@ ED_ParseEdict(char *data, edict_t *ent)
|
||||||
* All but the first will have the FL_TEAMSLAVE flag set.
|
* All but the first will have the FL_TEAMSLAVE flag set.
|
||||||
* All but the last will have the teamchain field set to the next one
|
* All but the last will have the teamchain field set to the next one
|
||||||
*/
|
*/
|
||||||
|
static void
|
||||||
|
G_FixTeams(void)
|
||||||
|
{
|
||||||
|
edict_t *e, *e2, *chain;
|
||||||
|
int i, j;
|
||||||
|
int c, c2;
|
||||||
|
|
||||||
|
c = 0;
|
||||||
|
c2 = 0;
|
||||||
|
|
||||||
|
for (i = 1, e = g_edicts + i; i < globals.num_edicts; i++, e++)
|
||||||
|
{
|
||||||
|
if (!e->inuse)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!e->team)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!strcmp(e->classname, "func_train"))
|
||||||
|
{
|
||||||
|
if (e->flags & FL_TEAMSLAVE)
|
||||||
|
{
|
||||||
|
chain = e;
|
||||||
|
e->teammaster = e;
|
||||||
|
e->teamchain = NULL;
|
||||||
|
e->flags &= ~FL_TEAMSLAVE;
|
||||||
|
c++;
|
||||||
|
c2++;
|
||||||
|
|
||||||
|
for (j = 1, e2 = g_edicts + j;
|
||||||
|
j < globals.num_edicts;
|
||||||
|
j++, e2++)
|
||||||
|
{
|
||||||
|
if (e2 == e)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!e2->inuse)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!e2->team)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!strcmp(e->team, e2->team))
|
||||||
|
{
|
||||||
|
c2++;
|
||||||
|
chain->teamchain = e2;
|
||||||
|
e2->teammaster = e;
|
||||||
|
e2->teamchain = NULL;
|
||||||
|
chain = e2;
|
||||||
|
e2->flags |= FL_TEAMSLAVE;
|
||||||
|
e2->movetype = MOVETYPE_PUSH;
|
||||||
|
e2->speed = e->speed;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
gi.dprintf("%i teams repaired\n", c);
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
G_FindTeams(void)
|
G_FindTeams(void)
|
||||||
{
|
{
|
||||||
|
@ -522,6 +610,8 @@ G_FindTeams(void)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
G_FixTeams();
|
||||||
|
|
||||||
gi.dprintf("%i teams with %i entities.\n", c, c2);
|
gi.dprintf("%i teams with %i entities.\n", c, c2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -534,10 +624,15 @@ SpawnEntities(const char *mapname, char *entities, const char *spawnpoint)
|
||||||
{
|
{
|
||||||
edict_t *ent;
|
edict_t *ent;
|
||||||
int inhibit;
|
int inhibit;
|
||||||
char *com_token;
|
const char *com_token;
|
||||||
int i;
|
int i;
|
||||||
float skill_level;
|
float skill_level;
|
||||||
|
|
||||||
|
if (!mapname || !entities || !spawnpoint)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
skill_level = floor(skill->value);
|
skill_level = floor(skill->value);
|
||||||
|
|
||||||
if (skill_level < 0)
|
if (skill_level < 0)
|
||||||
|
@ -562,8 +657,8 @@ SpawnEntities(const char *mapname, char *entities, const char *spawnpoint)
|
||||||
memset(&level, 0, sizeof(level));
|
memset(&level, 0, sizeof(level));
|
||||||
memset(g_edicts, 0, game.maxentities * sizeof(g_edicts[0]));
|
memset(g_edicts, 0, game.maxentities * sizeof(g_edicts[0]));
|
||||||
|
|
||||||
strncpy(level.mapname, mapname, sizeof(level.mapname) - 1);
|
Q_strlcpy(level.mapname, mapname, sizeof(level.mapname));
|
||||||
strncpy(game.spawnpoint, spawnpoint, sizeof(game.spawnpoint) - 1);
|
Q_strlcpy(game.spawnpoint, spawnpoint, sizeof(game.spawnpoint));
|
||||||
|
|
||||||
/* set client fields on player ents */
|
/* set client fields on player ents */
|
||||||
for (i = 0; i < game.maxclients; i++)
|
for (i = 0; i < game.maxclients; i++)
|
||||||
|
@ -603,12 +698,34 @@ SpawnEntities(const char *mapname, char *entities, const char *spawnpoint)
|
||||||
|
|
||||||
/* yet another map hack */
|
/* yet another map hack */
|
||||||
if (!Q_stricmp(level.mapname, "command") &&
|
if (!Q_stricmp(level.mapname, "command") &&
|
||||||
!Q_stricmp(ent->classname,
|
!Q_stricmp(ent->classname, "trigger_once") &&
|
||||||
"trigger_once") && !Q_stricmp(ent->model, "*27"))
|
!Q_stricmp(ent->model, "*27"))
|
||||||
{
|
{
|
||||||
ent->spawnflags &= ~SPAWNFLAG_NOT_HARD;
|
ent->spawnflags &= ~SPAWNFLAG_NOT_HARD;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ahh, the joys of map hacks .. */
|
||||||
|
if (!Q_stricmp(level.mapname, "rhangar2") &&
|
||||||
|
!Q_stricmp(ent->classname, "func_door_rotating") &&
|
||||||
|
ent->targetname && !Q_stricmp(ent->targetname, "t265"))
|
||||||
|
{
|
||||||
|
ent->spawnflags &= ~SPAWNFLAG_NOT_COOP;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!Q_stricmp(level.mapname, "rhangar2") &&
|
||||||
|
!Q_stricmp(ent->classname, "trigger_always") &&
|
||||||
|
ent->target && !Q_stricmp(ent->target, "t265"))
|
||||||
|
{
|
||||||
|
ent->spawnflags |= SPAWNFLAG_NOT_COOP;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!Q_stricmp(level.mapname, "rhangar2") &&
|
||||||
|
!Q_stricmp(ent->classname, "func_wall") &&
|
||||||
|
!Q_stricmp(ent->model, "*15"))
|
||||||
|
{
|
||||||
|
ent->spawnflags |= SPAWNFLAG_NOT_COOP;
|
||||||
|
}
|
||||||
|
|
||||||
/* remove things (except the world) from
|
/* remove things (except the world) from
|
||||||
different skill levels or deathmatch */
|
different skill levels or deathmatch */
|
||||||
if (ent != g_edicts)
|
if (ent != g_edicts)
|
||||||
|
|
|
@ -60,6 +60,12 @@ MoveClientToIntermission(edict_t *ent)
|
||||||
ent->client->quadfire_framenum = 0;
|
ent->client->quadfire_framenum = 0;
|
||||||
ent->client->trap_blew_up = false;
|
ent->client->trap_blew_up = false;
|
||||||
ent->client->trap_time = 0;
|
ent->client->trap_time = 0;
|
||||||
|
ent->client->ir_framenum = 0;
|
||||||
|
ent->client->nuke_framenum = 0;
|
||||||
|
ent->client->double_framenum = 0;
|
||||||
|
|
||||||
|
ent->client->ps.rdflags &= ~RDF_IRGOGGLES;
|
||||||
|
|
||||||
|
|
||||||
ent->viewheight = 0;
|
ent->viewheight = 0;
|
||||||
ent->s.modelindex = 0;
|
ent->s.modelindex = 0;
|
||||||
|
@ -307,6 +313,15 @@ DeathmatchScoreboardMessage(edict_t *ent, edict_t *killer)
|
||||||
tag = NULL;
|
tag = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* allow new DM games to override the tag picture */
|
||||||
|
if (gamerules && gamerules->value)
|
||||||
|
{
|
||||||
|
if (DMGame.DogTag)
|
||||||
|
{
|
||||||
|
DMGame.DogTag(cl_ent, killer, &tag);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (tag)
|
if (tag)
|
||||||
{
|
{
|
||||||
Com_sprintf(entry, sizeof(entry),
|
Com_sprintf(entry, sizeof(entry),
|
||||||
|
@ -342,6 +357,9 @@ DeathmatchScoreboardMessage(edict_t *ent, edict_t *killer)
|
||||||
gi.WriteString(string);
|
gi.WriteString(string);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Draw help computer.
|
||||||
|
*/
|
||||||
void
|
void
|
||||||
HelpComputerMessage(edict_t *ent)
|
HelpComputerMessage(edict_t *ent)
|
||||||
{
|
{
|
||||||
|
@ -391,6 +409,9 @@ HelpComputerMessage(edict_t *ent)
|
||||||
gi.WriteString(string);
|
gi.WriteString(string);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Display the current help message
|
||||||
|
*/
|
||||||
void
|
void
|
||||||
InventoryMessage(edict_t *ent)
|
InventoryMessage(edict_t *ent)
|
||||||
{
|
{
|
||||||
|
@ -494,6 +515,12 @@ G_SetStats(edict_t *ent)
|
||||||
ent->client->ps.stats[STAT_TIMER] =
|
ent->client->ps.stats[STAT_TIMER] =
|
||||||
(ent->client->quad_framenum - level.framenum) / 10;
|
(ent->client->quad_framenum - level.framenum) / 10;
|
||||||
}
|
}
|
||||||
|
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;
|
||||||
|
}
|
||||||
else if (ent->client->quadfire_framenum > level.framenum)
|
else if (ent->client->quadfire_framenum > level.framenum)
|
||||||
{
|
{
|
||||||
ent->client->ps.stats[STAT_TIMER_ICON] = gi.imageindex("p_quadfire");
|
ent->client->ps.stats[STAT_TIMER_ICON] = gi.imageindex("p_quadfire");
|
||||||
|
@ -519,6 +546,35 @@ G_SetStats(edict_t *ent)
|
||||||
ent->client->ps.stats[STAT_TIMER] =
|
ent->client->ps.stats[STAT_TIMER] =
|
||||||
(ent->client->breather_framenum - level.framenum) / 10;
|
(ent->client->breather_framenum - level.framenum) / 10;
|
||||||
}
|
}
|
||||||
|
else if (ent->client->owned_sphere)
|
||||||
|
{
|
||||||
|
if (ent->client->owned_sphere->spawnflags == 1) /* defender */
|
||||||
|
{
|
||||||
|
ent->client->ps.stats[STAT_TIMER_ICON] =
|
||||||
|
gi.imageindex("p_defender");
|
||||||
|
}
|
||||||
|
else if (ent->client->owned_sphere->spawnflags == 2) /* hunter */
|
||||||
|
{
|
||||||
|
ent->client->ps.stats[STAT_TIMER_ICON] = gi.imageindex("p_hunter");
|
||||||
|
}
|
||||||
|
else if (ent->client->owned_sphere->spawnflags == 4) /* vengeance */
|
||||||
|
{
|
||||||
|
ent->client->ps.stats[STAT_TIMER_ICON] =
|
||||||
|
gi.imageindex("p_vengeance");
|
||||||
|
}
|
||||||
|
else /* error case */
|
||||||
|
{
|
||||||
|
ent->client->ps.stats[STAT_TIMER_ICON] = gi.imageindex("i_fixme");
|
||||||
|
}
|
||||||
|
|
||||||
|
ent->client->ps.stats[STAT_TIMER] =
|
||||||
|
(int)(ent->client->owned_sphere->wait - level.time);
|
||||||
|
}
|
||||||
|
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; }
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
ent->client->ps.stats[STAT_TIMER_ICON] = 0;
|
ent->client->ps.stats[STAT_TIMER_ICON] = 0;
|
||||||
|
|
|
@ -281,6 +281,12 @@ SV_CalcViewOffset(edict_t *ent)
|
||||||
float delta;
|
float delta;
|
||||||
vec3_t v;
|
vec3_t v;
|
||||||
|
|
||||||
|
if (!ent)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* base angles */
|
/* base angles */
|
||||||
angles = ent->client->ps.kick_angles;
|
angles = ent->client->ps.kick_angles;
|
||||||
|
|
||||||
|
@ -289,8 +295,17 @@ SV_CalcViewOffset(edict_t *ent)
|
||||||
{
|
{
|
||||||
VectorClear(angles);
|
VectorClear(angles);
|
||||||
|
|
||||||
|
if (ent->flags & FL_SAM_RAIMI)
|
||||||
|
{
|
||||||
|
ent->client->ps.viewangles[ROLL] = 0;
|
||||||
|
ent->client->ps.viewangles[PITCH] = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
ent->client->ps.viewangles[ROLL] = 40;
|
ent->client->ps.viewangles[ROLL] = 40;
|
||||||
ent->client->ps.viewangles[PITCH] = -15;
|
ent->client->ps.viewangles[PITCH] = -15;
|
||||||
|
}
|
||||||
|
|
||||||
ent->client->ps.viewangles[YAW] = ent->client->killer_yaw;
|
ent->client->ps.viewangles[YAW] = ent->client->killer_yaw;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -352,6 +367,8 @@ SV_CalcViewOffset(edict_t *ent)
|
||||||
angles[ROLL] += delta;
|
angles[ROLL] += delta;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* =================================== */
|
||||||
|
|
||||||
/* base origin */
|
/* base origin */
|
||||||
VectorClear(v);
|
VectorClear(v);
|
||||||
|
|
||||||
|
@ -419,12 +436,21 @@ SV_CalcGunOffset(edict_t *ent)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
float delta;
|
float delta;
|
||||||
|
static gitem_t *heatbeam;
|
||||||
|
|
||||||
if (!ent)
|
if (!ent)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!heatbeam)
|
||||||
|
{
|
||||||
|
heatbeam = FindItemByClassname("weapon_plasmabeam");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* heatbeam shouldn't bob so the beam looks right */
|
||||||
|
if (ent->client->pers.weapon != heatbeam)
|
||||||
|
{
|
||||||
/* gun angles from bobbing */
|
/* gun angles from bobbing */
|
||||||
ent->client->ps.gunangles[ROLL] = xyspeed * bobfracsin * 0.005;
|
ent->client->ps.gunangles[ROLL] = xyspeed * bobfracsin * 0.005;
|
||||||
ent->client->ps.gunangles[YAW] = xyspeed * bobfracsin * 0.01;
|
ent->client->ps.gunangles[YAW] = xyspeed * bobfracsin * 0.01;
|
||||||
|
@ -440,7 +466,8 @@ SV_CalcGunOffset(edict_t *ent)
|
||||||
/* gun angles from delta movement */
|
/* gun angles from delta movement */
|
||||||
for (i = 0; i < 3; i++)
|
for (i = 0; i < 3; i++)
|
||||||
{
|
{
|
||||||
delta = ent->client->oldviewangles[i] - ent->client->ps.viewangles[i];
|
delta = ent->client->oldviewangles[i] -
|
||||||
|
ent->client->ps.viewangles[i];
|
||||||
|
|
||||||
if (delta > 180)
|
if (delta > 180)
|
||||||
{
|
{
|
||||||
|
@ -469,6 +496,14 @@ SV_CalcGunOffset(edict_t *ent)
|
||||||
|
|
||||||
ent->client->ps.gunangles[i] += 0.2 * delta;
|
ent->client->ps.gunangles[i] += 0.2 * delta;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (i = 0; i < 3; i++)
|
||||||
|
{
|
||||||
|
ent->client->ps.gunangles[i] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* gun height */
|
/* gun height */
|
||||||
VectorClear(ent->client->ps.gunoffset);
|
VectorClear(ent->client->ps.gunoffset);
|
||||||
|
@ -563,6 +598,21 @@ SV_CalcBlend(edict_t *ent)
|
||||||
SV_AddBlend(0, 0, 1, 0.08, ent->client->ps.blend);
|
SV_AddBlend(0, 0, 1, 0.08, ent->client->ps.blend);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (ent->client->double_framenum > level.framenum)
|
||||||
|
{
|
||||||
|
remaining = ent->client->double_framenum - level.framenum;
|
||||||
|
|
||||||
|
if (remaining == 30) /* beginning to fade */
|
||||||
|
{
|
||||||
|
gi.sound(ent, CHAN_ITEM, gi.soundindex("misc/ddamage2.wav"),
|
||||||
|
1, ATTN_NORM, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((remaining > 30) || (remaining & 4))
|
||||||
|
{
|
||||||
|
SV_AddBlend(0.9, 0.7, 0, 0.08, ent->client->ps.blend);
|
||||||
|
}
|
||||||
|
}
|
||||||
else if (ent->client->quadfire_framenum > level.framenum)
|
else if (ent->client->quadfire_framenum > level.framenum)
|
||||||
{
|
{
|
||||||
remaining = ent->client->quadfire_framenum - level.framenum;
|
remaining = ent->client->quadfire_framenum - level.framenum;
|
||||||
|
@ -624,6 +674,32 @@ SV_CalcBlend(edict_t *ent)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ent->client->nuke_framenum > level.framenum)
|
||||||
|
{
|
||||||
|
float brightness;
|
||||||
|
brightness = (ent->client->nuke_framenum - level.framenum) / 20.0;
|
||||||
|
SV_AddBlend(1, 1, 1, brightness, ent->client->ps.blend);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ent->client->ir_framenum > level.framenum)
|
||||||
|
{
|
||||||
|
remaining = ent->client->ir_framenum - level.framenum;
|
||||||
|
|
||||||
|
if ((remaining > 30) || (remaining & 4))
|
||||||
|
{
|
||||||
|
ent->client->ps.rdflags |= RDF_IRGOGGLES;
|
||||||
|
SV_AddBlend(1, 0, 0, 0.2, ent->client->ps.blend);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ent->client->ps.rdflags &= ~RDF_IRGOGGLES;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ent->client->ps.rdflags &= ~RDF_IRGOGGLES;
|
||||||
|
}
|
||||||
|
|
||||||
/* add for damage */
|
/* add for damage */
|
||||||
if (ent->client->damage_alpha > 0)
|
if (ent->client->damage_alpha > 0)
|
||||||
{
|
{
|
||||||
|
@ -991,6 +1067,8 @@ G_SetClientEffects(edict_t *ent)
|
||||||
}
|
}
|
||||||
|
|
||||||
ent->s.effects = 0;
|
ent->s.effects = 0;
|
||||||
|
|
||||||
|
/* player is always ir visible, even dead. */
|
||||||
ent->s.renderfx = RF_IR_VISIBLE;
|
ent->s.renderfx = RF_IR_VISIBLE;
|
||||||
|
|
||||||
if ((ent->health <= 0) || level.intermissiontime)
|
if ((ent->health <= 0) || level.intermissiontime)
|
||||||
|
@ -998,6 +1076,19 @@ G_SetClientEffects(edict_t *ent)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ent->flags & FL_DISGUISED)
|
||||||
|
{
|
||||||
|
ent->s.renderfx |= RF_USE_DISGUISE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (gamerules && gamerules->value)
|
||||||
|
{
|
||||||
|
if (DMGame.PlayerEffects)
|
||||||
|
{
|
||||||
|
DMGame.PlayerEffects(ent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (ent->powerarmor_time > level.time)
|
if (ent->powerarmor_time > level.time)
|
||||||
{
|
{
|
||||||
pa_type = PowerArmorType(ent);
|
pa_type = PowerArmorType(ent);
|
||||||
|
@ -1023,6 +1114,16 @@ G_SetClientEffects(edict_t *ent)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ent->client->double_framenum > level.framenum)
|
||||||
|
{
|
||||||
|
remaining = ent->client->double_framenum - level.framenum;
|
||||||
|
|
||||||
|
if ((remaining > 30) || (remaining & 4))
|
||||||
|
{
|
||||||
|
ent->s.effects |= EF_DOUBLE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (ent->client->quadfire_framenum > level.framenum)
|
if (ent->client->quadfire_framenum > level.framenum)
|
||||||
{
|
{
|
||||||
remaining = ent->client->quadfire_framenum - level.framenum;
|
remaining = ent->client->quadfire_framenum - level.framenum;
|
||||||
|
@ -1033,6 +1134,17 @@ G_SetClientEffects(edict_t *ent)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ((ent->client->owned_sphere) &&
|
||||||
|
(ent->client->owned_sphere->spawnflags == 1))
|
||||||
|
{
|
||||||
|
ent->s.effects |= EF_HALF_DAMAGE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ent->client->tracker_pain_framenum > level.framenum)
|
||||||
|
{
|
||||||
|
ent->s.effects |= EF_TRACKERTRAIL;
|
||||||
|
}
|
||||||
|
|
||||||
if (ent->client->invincible_framenum > level.framenum)
|
if (ent->client->invincible_framenum > level.framenum)
|
||||||
{
|
{
|
||||||
remaining = ent->client->invincible_framenum - level.framenum;
|
remaining = ent->client->invincible_framenum - level.framenum;
|
||||||
|
@ -1416,13 +1528,9 @@ ClientEndServerFrame(edict_t *ent)
|
||||||
}
|
}
|
||||||
|
|
||||||
G_CheckChaseStats(ent);
|
G_CheckChaseStats(ent);
|
||||||
|
|
||||||
G_SetClientEvent(ent);
|
G_SetClientEvent(ent);
|
||||||
|
|
||||||
G_SetClientEffects(ent);
|
G_SetClientEffects(ent);
|
||||||
|
|
||||||
G_SetClientSound(ent);
|
G_SetClientSound(ent);
|
||||||
|
|
||||||
G_SetClientFrame(ent);
|
G_SetClientFrame(ent);
|
||||||
|
|
||||||
VectorCopy(ent->velocity, ent->client->oldvelocity);
|
VectorCopy(ent->velocity, ent->client->oldvelocity);
|
||||||
|
|
|
@ -1,677 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (C) 1997-2001 Id Software, Inc.
|
|
||||||
* Copyright (c) ZeniMax Media 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.
|
|
||||||
*
|
|
||||||
* =======================================================================
|
|
||||||
*
|
|
||||||
* HUD, deathmatch scoreboard, help computer and intermission stuff.
|
|
||||||
*
|
|
||||||
* =======================================================================
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "../header/local.h"
|
|
||||||
|
|
||||||
void
|
|
||||||
MoveClientToIntermission(edict_t *ent)
|
|
||||||
{
|
|
||||||
if (!ent)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
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->client->ps.rdflags &= ~RDF_IRGOGGLES;
|
|
||||||
ent->client->ir_framenum = 0;
|
|
||||||
ent->client->nuke_framenum = 0;
|
|
||||||
ent->client->double_framenum = 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;
|
|
||||||
|
|
||||||
gi.linkentity(ent);
|
|
||||||
|
|
||||||
/* 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 (!targ)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
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 < game.num_items; n++)
|
|
||||||
{
|
|
||||||
if (itemlist[n].flags & IT_KEY)
|
|
||||||
{
|
|
||||||
client->client->pers.inventory[n] = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
client->client->pers.power_cubes = 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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
DeathmatchScoreboardMessage(edict_t *ent, edict_t *killer /* can be NULL */)
|
|
||||||
{
|
|
||||||
char entry[1024];
|
|
||||||
char string[1400];
|
|
||||||
int stringlength;
|
|
||||||
int i, j, k;
|
|
||||||
int sorted[MAX_CLIENTS];
|
|
||||||
int sortedscores[MAX_CLIENTS];
|
|
||||||
int score, total;
|
|
||||||
int x, y;
|
|
||||||
gclient_t *cl;
|
|
||||||
edict_t *cl_ent;
|
|
||||||
char *tag;
|
|
||||||
|
|
||||||
if (!ent)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 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 = 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];
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* allow new DM games to override the tag picture */
|
|
||||||
if (gamerules && gamerules->value)
|
|
||||||
{
|
|
||||||
if (DMGame.DogTag)
|
|
||||||
{
|
|
||||||
DMGame.DogTag(cl_ent, killer, &tag);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Draw help computer.
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
HelpComputerMessage(edict_t *ent)
|
|
||||||
{
|
|
||||||
char string[1024];
|
|
||||||
char *sk;
|
|
||||||
|
|
||||||
if (!ent)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (skill->value == SKILL_EASY)
|
|
||||||
{
|
|
||||||
sk = "easy";
|
|
||||||
}
|
|
||||||
else if (skill->value == SKILL_MEDIUM)
|
|
||||||
{
|
|
||||||
sk = "medium";
|
|
||||||
}
|
|
||||||
else if (skill->value == SKILL_HARD)
|
|
||||||
{
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Display the current help message
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
InventoryMessage(edict_t *ent)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
|
|
||||||
if (!ent)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
gi.WriteByte(svc_inventory);
|
|
||||||
|
|
||||||
for (i = 0; i < MAX_ITEMS; i++)
|
|
||||||
{
|
|
||||||
gi.WriteShort(ent->client->pers.inventory[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ======================================================================= */
|
|
||||||
|
|
||||||
void
|
|
||||||
G_SetStats(edict_t *ent)
|
|
||||||
{
|
|
||||||
gitem_t *item;
|
|
||||||
int index, cells;
|
|
||||||
int power_armor_type;
|
|
||||||
|
|
||||||
if (!ent)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* health */
|
|
||||||
ent->client->ps.stats[STAT_HEALTH_ICON] = level.pic_health;
|
|
||||||
ent->client->ps.stats[STAT_HEALTH] = (ent->health < -99) ? -99 : ent->health;
|
|
||||||
|
|
||||||
/* ammo */
|
|
||||||
if (!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];
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 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->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;
|
|
||||||
}
|
|
||||||
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 if (ent->client->owned_sphere)
|
|
||||||
{
|
|
||||||
if (ent->client->owned_sphere->spawnflags == 1) /* defender */
|
|
||||||
{
|
|
||||||
ent->client->ps.stats[STAT_TIMER_ICON] =
|
|
||||||
gi.imageindex("p_defender");
|
|
||||||
}
|
|
||||||
else if (ent->client->owned_sphere->spawnflags == 2) /* hunter */
|
|
||||||
{
|
|
||||||
ent->client->ps.stats[STAT_TIMER_ICON] = gi.imageindex("p_hunter");
|
|
||||||
}
|
|
||||||
else if (ent->client->owned_sphere->spawnflags == 4) /* vengeance */
|
|
||||||
{
|
|
||||||
ent->client->ps.stats[STAT_TIMER_ICON] =
|
|
||||||
gi.imageindex("p_vengeance");
|
|
||||||
}
|
|
||||||
else /* error case */
|
|
||||||
{
|
|
||||||
ent->client->ps.stats[STAT_TIMER_ICON] = gi.imageindex("i_fixme");
|
|
||||||
}
|
|
||||||
|
|
||||||
ent->client->ps.stats[STAT_TIMER] =
|
|
||||||
(int)(ent->client->owned_sphere->wait - level.time);
|
|
||||||
}
|
|
||||||
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; }
|
|
||||||
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)
|
|
||||||
{
|
|
||||||
cvar_t *gun;
|
|
||||||
gun = gi.cvar("cl_gun", "2", 0);
|
|
||||||
|
|
||||||
if (gun->value != 2)
|
|
||||||
{
|
|
||||||
ent->client->ps.stats[STAT_HELPICON] = gi.imageindex(ent->client->pers.weapon->icon);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ent->client->ps.stats[STAT_HELPICON] = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ent->client->ps.stats[STAT_HELPICON] = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
ent->client->ps.stats[STAT_SPECTATOR] = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
G_CheckChaseStats(edict_t *ent)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
gclient_t *cl;
|
|
||||||
|
|
||||||
if (!ent)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
G_SetSpectatorStats(edict_t *ent)
|
|
||||||
{
|
|
||||||
if (!ent)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,176 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (C) 1997-2001 Id Software, Inc.
|
|
||||||
* Copyright (c) ZeniMax Media 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.
|
|
||||||
*
|
|
||||||
* =======================================================================
|
|
||||||
*
|
|
||||||
* The player trail, used by monsters to locate the player.
|
|
||||||
*
|
|
||||||
* =======================================================================
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "../header/local.h"
|
|
||||||
|
|
||||||
/*
|
|
||||||
* This is a circular list containing the a list of points of where
|
|
||||||
* the player has been recently. It is used by monsters for pursuit.
|
|
||||||
*
|
|
||||||
* .origin the spot
|
|
||||||
* .owner forward link
|
|
||||||
* .aiment backward link
|
|
||||||
*/
|
|
||||||
|
|
||||||
#define NEXT(n) (((n) + 1) & (TRAIL_LENGTH - 1))
|
|
||||||
#define PREV(n) (((n) - 1) & (TRAIL_LENGTH - 1))
|
|
||||||
|
|
||||||
#define TRAIL_LENGTH 8
|
|
||||||
|
|
||||||
edict_t *trail[TRAIL_LENGTH];
|
|
||||||
int trail_head;
|
|
||||||
qboolean trail_active = false;
|
|
||||||
|
|
||||||
void
|
|
||||||
PlayerTrail_Init(void)
|
|
||||||
{
|
|
||||||
int n;
|
|
||||||
|
|
||||||
if (deathmatch->value)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (n = 0; n < TRAIL_LENGTH; n++)
|
|
||||||
{
|
|
||||||
trail[n] = G_Spawn();
|
|
||||||
trail[n]->classname = "player_trail";
|
|
||||||
}
|
|
||||||
|
|
||||||
trail_head = 0;
|
|
||||||
trail_active = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
PlayerTrail_Add(vec3_t spot)
|
|
||||||
{
|
|
||||||
vec3_t temp;
|
|
||||||
|
|
||||||
if (!trail_active)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
VectorCopy(spot, trail[trail_head]->s.origin);
|
|
||||||
|
|
||||||
trail[trail_head]->timestamp = level.time;
|
|
||||||
|
|
||||||
VectorSubtract(spot, trail[PREV(trail_head)]->s.origin, temp);
|
|
||||||
trail[trail_head]->s.angles[1] = vectoyaw(temp);
|
|
||||||
|
|
||||||
trail_head = NEXT(trail_head);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
PlayerTrail_New(vec3_t spot)
|
|
||||||
{
|
|
||||||
if (!trail_active)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
PlayerTrail_Init();
|
|
||||||
PlayerTrail_Add(spot);
|
|
||||||
}
|
|
||||||
|
|
||||||
edict_t *
|
|
||||||
PlayerTrail_PickFirst(edict_t *self)
|
|
||||||
{
|
|
||||||
int marker;
|
|
||||||
int n;
|
|
||||||
|
|
||||||
if (!self)
|
|
||||||
{
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!trail_active)
|
|
||||||
{
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (marker = trail_head, n = TRAIL_LENGTH; n; n--)
|
|
||||||
{
|
|
||||||
if (trail[marker]->timestamp <= self->monsterinfo.trail_time)
|
|
||||||
{
|
|
||||||
marker = NEXT(marker);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (visible(self, trail[marker]))
|
|
||||||
{
|
|
||||||
return trail[marker];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (visible(self, trail[PREV(marker)]))
|
|
||||||
{
|
|
||||||
return trail[PREV(marker)];
|
|
||||||
}
|
|
||||||
|
|
||||||
return trail[marker];
|
|
||||||
}
|
|
||||||
|
|
||||||
edict_t *
|
|
||||||
PlayerTrail_PickNext(edict_t *self)
|
|
||||||
{
|
|
||||||
int marker;
|
|
||||||
int n;
|
|
||||||
|
|
||||||
if (!self)
|
|
||||||
{
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!trail_active)
|
|
||||||
{
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (marker = trail_head, n = TRAIL_LENGTH; n; n--)
|
|
||||||
{
|
|
||||||
if (trail[marker]->timestamp <= self->monsterinfo.trail_time)
|
|
||||||
{
|
|
||||||
marker = NEXT(marker);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return trail[marker];
|
|
||||||
}
|
|
||||||
|
|
||||||
edict_t *
|
|
||||||
PlayerTrail_LastSpot(void)
|
|
||||||
{
|
|
||||||
return trail[PREV(trail_head)];
|
|
||||||
}
|
|
File diff suppressed because it is too large
Load diff
Loading…
Reference in a new issue