mirror of
https://github.com/yquake2/yquake2remaster.git
synced 2025-02-16 17:11:03 +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/widow2.o \
|
||||
src/game/player/client.o \
|
||||
src/rogue/player/hud.o \
|
||||
src/rogue/player/trail.o \
|
||||
src/rogue/player/view.o \
|
||||
src/game/player/hud.o \
|
||||
src/game/player/trail.o \
|
||||
src/game/player/view.o \
|
||||
src/game/player/weapon.o \
|
||||
src/rogue/savegame/savegame.o
|
||||
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
/*
|
||||
* 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
|
||||
|
@ -292,11 +293,16 @@ ED_CallSpawn(edict_t *ent)
|
|||
}
|
||||
|
||||
char *
|
||||
ED_NewString(char *string)
|
||||
ED_NewString(const char *string)
|
||||
{
|
||||
char *newb, *new_p;
|
||||
int i, l;
|
||||
|
||||
if (!string)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
l = strlen(string) + 1;
|
||||
|
||||
newb = gi.TagMalloc(l, TAG_LEVEL);
|
||||
|
@ -332,16 +338,21 @@ ED_NewString(char *string)
|
|||
* the binary values in an edict
|
||||
*/
|
||||
void
|
||||
ED_ParseField(char *key, char *value, edict_t *ent)
|
||||
ED_ParseField(const char *key, const char *value, edict_t *ent)
|
||||
{
|
||||
field_t *f;
|
||||
byte *b;
|
||||
float v;
|
||||
vec3_t vec;
|
||||
|
||||
if (!ent || !value || !key)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
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 */
|
||||
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];
|
||||
break;
|
||||
case F_INT:
|
||||
*(int *)(b + f->ofs) = atoi(value);
|
||||
*(int *)(b + f->ofs) = (int)strtol(value, (char **)NULL, 10);
|
||||
break;
|
||||
case F_FLOAT:
|
||||
*(float *)(b + f->ofs) = atof(value);
|
||||
*(float *)(b + f->ofs) = (float)strtod(value, (char **)NULL);
|
||||
break;
|
||||
case F_ANGLEHACK:
|
||||
v = atof(value);
|
||||
v = (float)strtod(value, (char **)NULL);
|
||||
((float *)(b + f->ofs))[0] = 0;
|
||||
((float *)(b + f->ofs))[1] = v;
|
||||
((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,
|
||||
* returning the new position ed should be
|
||||
* returning the new position. ed should be
|
||||
* a properly initialized empty edict.
|
||||
*/
|
||||
char *
|
||||
|
@ -399,10 +410,16 @@ ED_ParseEdict(char *data, edict_t *ent)
|
|||
{
|
||||
qboolean init;
|
||||
char keyname[256];
|
||||
char *com_token;
|
||||
const char *com_token;
|
||||
|
||||
if (!ent)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
init = false;
|
||||
memset(&st, 0, sizeof(st));
|
||||
st.skyautorotate = 1;
|
||||
|
||||
/* go through all the dictionary pairs */
|
||||
while (1)
|
||||
|
@ -420,7 +437,7 @@ ED_ParseEdict(char *data, edict_t *ent)
|
|||
gi.error("ED_ParseEntity: EOF without closing brace");
|
||||
}
|
||||
|
||||
strncpy(keyname, com_token, sizeof(keyname) - 1);
|
||||
Q_strlcpy(keyname, com_token, sizeof(keyname));
|
||||
|
||||
/* parse value */
|
||||
com_token = COM_Parse(&data);
|
||||
|
@ -437,9 +454,9 @@ ED_ParseEdict(char *data, edict_t *ent)
|
|||
|
||||
init = true;
|
||||
|
||||
/* keynames with a leading underscore are used
|
||||
for utility comments, and are immediately
|
||||
discarded by quake */
|
||||
/* keynames with a leading underscore are
|
||||
used for utility comments, and are
|
||||
immediately discarded by quake */
|
||||
if (keyname[0] == '_')
|
||||
{
|
||||
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 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
|
||||
G_FindTeams(void)
|
||||
{
|
||||
|
@ -522,6 +610,8 @@ G_FindTeams(void)
|
|||
}
|
||||
}
|
||||
|
||||
G_FixTeams();
|
||||
|
||||
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;
|
||||
int inhibit;
|
||||
char *com_token;
|
||||
const char *com_token;
|
||||
int i;
|
||||
float skill_level;
|
||||
|
||||
if (!mapname || !entities || !spawnpoint)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
skill_level = floor(skill->value);
|
||||
|
||||
if (skill_level < 0)
|
||||
|
@ -562,8 +657,8 @@ SpawnEntities(const char *mapname, char *entities, const char *spawnpoint)
|
|||
memset(&level, 0, sizeof(level));
|
||||
memset(g_edicts, 0, game.maxentities * sizeof(g_edicts[0]));
|
||||
|
||||
strncpy(level.mapname, mapname, sizeof(level.mapname) - 1);
|
||||
strncpy(game.spawnpoint, spawnpoint, sizeof(game.spawnpoint) - 1);
|
||||
Q_strlcpy(level.mapname, mapname, sizeof(level.mapname));
|
||||
Q_strlcpy(game.spawnpoint, spawnpoint, sizeof(game.spawnpoint));
|
||||
|
||||
/* set client fields on player ents */
|
||||
for (i = 0; i < game.maxclients; i++)
|
||||
|
@ -603,12 +698,34 @@ SpawnEntities(const char *mapname, char *entities, const char *spawnpoint)
|
|||
|
||||
/* yet another map hack */
|
||||
if (!Q_stricmp(level.mapname, "command") &&
|
||||
!Q_stricmp(ent->classname,
|
||||
"trigger_once") && !Q_stricmp(ent->model, "*27"))
|
||||
!Q_stricmp(ent->classname, "trigger_once") &&
|
||||
!Q_stricmp(ent->model, "*27"))
|
||||
{
|
||||
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
|
||||
different skill levels or deathmatch */
|
||||
if (ent != g_edicts)
|
||||
|
|
|
@ -60,6 +60,12 @@ MoveClientToIntermission(edict_t *ent)
|
|||
ent->client->quadfire_framenum = 0;
|
||||
ent->client->trap_blew_up = false;
|
||||
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->s.modelindex = 0;
|
||||
|
@ -307,6 +313,15 @@ DeathmatchScoreboardMessage(edict_t *ent, edict_t *killer)
|
|||
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),
|
||||
|
@ -342,6 +357,9 @@ DeathmatchScoreboardMessage(edict_t *ent, edict_t *killer)
|
|||
gi.WriteString(string);
|
||||
}
|
||||
|
||||
/*
|
||||
* Draw help computer.
|
||||
*/
|
||||
void
|
||||
HelpComputerMessage(edict_t *ent)
|
||||
{
|
||||
|
@ -391,6 +409,9 @@ HelpComputerMessage(edict_t *ent)
|
|||
gi.WriteString(string);
|
||||
}
|
||||
|
||||
/*
|
||||
* Display the current help message
|
||||
*/
|
||||
void
|
||||
InventoryMessage(edict_t *ent)
|
||||
{
|
||||
|
@ -494,6 +515,12 @@ G_SetStats(edict_t *ent)
|
|||
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->quadfire_framenum > level.framenum)
|
||||
{
|
||||
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->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;
|
||||
|
|
|
@ -281,6 +281,12 @@ SV_CalcViewOffset(edict_t *ent)
|
|||
float delta;
|
||||
vec3_t v;
|
||||
|
||||
if (!ent)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/* base angles */
|
||||
angles = ent->client->ps.kick_angles;
|
||||
|
||||
|
@ -289,8 +295,17 @@ SV_CalcViewOffset(edict_t *ent)
|
|||
{
|
||||
VectorClear(angles);
|
||||
|
||||
ent->client->ps.viewangles[ROLL] = 40;
|
||||
ent->client->ps.viewangles[PITCH] = -15;
|
||||
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[PITCH] = -15;
|
||||
}
|
||||
|
||||
ent->client->ps.viewangles[YAW] = ent->client->killer_yaw;
|
||||
}
|
||||
else
|
||||
|
@ -352,6 +367,8 @@ SV_CalcViewOffset(edict_t *ent)
|
|||
angles[ROLL] += delta;
|
||||
}
|
||||
|
||||
/* =================================== */
|
||||
|
||||
/* base origin */
|
||||
VectorClear(v);
|
||||
|
||||
|
@ -419,55 +436,73 @@ SV_CalcGunOffset(edict_t *ent)
|
|||
{
|
||||
int i;
|
||||
float delta;
|
||||
static gitem_t *heatbeam;
|
||||
|
||||
if (!ent)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
/* gun angles from bobbing */
|
||||
ent->client->ps.gunangles[ROLL] = xyspeed * bobfracsin * 0.005;
|
||||
ent->client->ps.gunangles[YAW] = xyspeed * bobfracsin * 0.01;
|
||||
|
||||
if (bobcycle & 1)
|
||||
if (!heatbeam)
|
||||
{
|
||||
ent->client->ps.gunangles[ROLL] = -ent->client->ps.gunangles[ROLL];
|
||||
ent->client->ps.gunangles[YAW] = -ent->client->ps.gunangles[YAW];
|
||||
heatbeam = FindItemByClassname("weapon_plasmabeam");
|
||||
}
|
||||
|
||||
ent->client->ps.gunangles[PITCH] = xyspeed * bobfracsin * 0.005;
|
||||
|
||||
/* gun angles from delta movement */
|
||||
for (i = 0; i < 3; i++)
|
||||
/* heatbeam shouldn't bob so the beam looks right */
|
||||
if (ent->client->pers.weapon != heatbeam)
|
||||
{
|
||||
delta = ent->client->oldviewangles[i] - ent->client->ps.viewangles[i];
|
||||
/* gun angles from bobbing */
|
||||
ent->client->ps.gunangles[ROLL] = xyspeed * bobfracsin * 0.005;
|
||||
ent->client->ps.gunangles[YAW] = xyspeed * bobfracsin * 0.01;
|
||||
|
||||
if (delta > 180)
|
||||
if (bobcycle & 1)
|
||||
{
|
||||
delta -= 360;
|
||||
ent->client->ps.gunangles[ROLL] = -ent->client->ps.gunangles[ROLL];
|
||||
ent->client->ps.gunangles[YAW] = -ent->client->ps.gunangles[YAW];
|
||||
}
|
||||
|
||||
if (delta < -180)
|
||||
{
|
||||
delta += 360;
|
||||
}
|
||||
ent->client->ps.gunangles[PITCH] = xyspeed * bobfracsin * 0.005;
|
||||
|
||||
if (delta > 45)
|
||||
/* gun angles from delta movement */
|
||||
for (i = 0; i < 3; i++)
|
||||
{
|
||||
delta = 45;
|
||||
}
|
||||
delta = ent->client->oldviewangles[i] -
|
||||
ent->client->ps.viewangles[i];
|
||||
|
||||
if (delta < -45)
|
||||
if (delta > 180)
|
||||
{
|
||||
delta -= 360;
|
||||
}
|
||||
|
||||
if (delta < -180)
|
||||
{
|
||||
delta += 360;
|
||||
}
|
||||
|
||||
if (delta > 45)
|
||||
{
|
||||
delta = 45;
|
||||
}
|
||||
|
||||
if (delta < -45)
|
||||
{
|
||||
delta = -45;
|
||||
}
|
||||
|
||||
if (i == YAW)
|
||||
{
|
||||
ent->client->ps.gunangles[ROLL] += 0.1 * delta;
|
||||
}
|
||||
|
||||
ent->client->ps.gunangles[i] += 0.2 * delta;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (i = 0; i < 3; i++)
|
||||
{
|
||||
delta = -45;
|
||||
ent->client->ps.gunangles[i] = 0;
|
||||
}
|
||||
|
||||
if (i == YAW)
|
||||
{
|
||||
ent->client->ps.gunangles[ROLL] += 0.1 * delta;
|
||||
}
|
||||
|
||||
ent->client->ps.gunangles[i] += 0.2 * delta;
|
||||
}
|
||||
|
||||
/* gun height */
|
||||
|
@ -563,6 +598,21 @@ SV_CalcBlend(edict_t *ent)
|
|||
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)
|
||||
{
|
||||
remaining = ent->client->quadfire_framenum - level.framenum;
|
||||
|
@ -570,7 +620,7 @@ SV_CalcBlend(edict_t *ent)
|
|||
if (remaining == 30) /* beginning to fade */
|
||||
{
|
||||
gi.sound(ent, CHAN_ITEM, gi.soundindex("items/quadfire2.wav"),
|
||||
1, ATTN_NORM, 0);
|
||||
1, ATTN_NORM, 0);
|
||||
}
|
||||
|
||||
if ((remaining > 30) || (remaining & 4))
|
||||
|
@ -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 */
|
||||
if (ent->client->damage_alpha > 0)
|
||||
{
|
||||
|
@ -991,6 +1067,8 @@ G_SetClientEffects(edict_t *ent)
|
|||
}
|
||||
|
||||
ent->s.effects = 0;
|
||||
|
||||
/* player is always ir visible, even dead. */
|
||||
ent->s.renderfx = RF_IR_VISIBLE;
|
||||
|
||||
if ((ent->health <= 0) || level.intermissiontime)
|
||||
|
@ -998,6 +1076,19 @@ G_SetClientEffects(edict_t *ent)
|
|||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
remaining = ent->client->invincible_framenum - level.framenum;
|
||||
|
@ -1416,13 +1528,9 @@ ClientEndServerFrame(edict_t *ent)
|
|||
}
|
||||
|
||||
G_CheckChaseStats(ent);
|
||||
|
||||
G_SetClientEvent(ent);
|
||||
|
||||
G_SetClientEffects(ent);
|
||||
|
||||
G_SetClientSound(ent);
|
||||
|
||||
G_SetClientFrame(ent);
|
||||
|
||||
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