game: Sync game/header/game.h, game/header/local.h

This commit is contained in:
Denis Pauk 2023-10-18 19:40:55 +03:00
parent 748cc322b3
commit 7b50b2d89f
42 changed files with 3164 additions and 698 deletions

View file

@ -458,11 +458,6 @@ extern spawn_temp_t st;
extern int sm_meat_index; extern int sm_meat_index;
extern int snd_fry; extern int snd_fry;
extern int jacket_armor_index;
extern int combat_armor_index;
extern int body_armor_index;
// means of death // means of death
#define MOD_UNKNOWN 0 #define MOD_UNKNOWN 0
#define MOD_BLASTER 1 #define MOD_BLASTER 1

View file

@ -1632,7 +1632,7 @@ CTFResetGrapple(edict_t *self)
} }
gi.sound(self->owner, CHAN_RELIABLE + CHAN_WEAPON, gi.sound(self->owner, CHAN_RELIABLE + CHAN_WEAPON,
gi.soundindex( "weapons/grapple/grreset.wav"), volume, ATTN_NORM, 0); gi.soundindex("weapons/grapple/grreset.wav"), volume, ATTN_NORM, 0);
cl = self->owner->client; cl = self->owner->client;
cl->ctf_grapple = NULL; cl->ctf_grapple = NULL;
cl->ctf_grapplereleasetime = level.time; cl->ctf_grapplereleasetime = level.time;

View file

@ -984,7 +984,7 @@ body_die(edict_t *self, edict_t *inflictor, edict_t *attacker,
if (self->health < -40) if (self->health < -40)
{ {
gi.sound(self, CHAN_BODY, gi.soundindex( "misc/udeath.wav"), 1, ATTN_NORM, 0); gi.sound(self, CHAN_BODY, gi.soundindex("misc/udeath.wav"), 1, ATTN_NORM, 0);
for (n = 0; n < 4; n++) for (n = 0; n < 4; n++)
{ {

View file

@ -801,7 +801,7 @@ T_Damage(edict_t *targ, edict_t *inflictor, edict_t *attacker, vec3_t dir,
{ {
if (targ->pain_debounce_time < level.time) if (targ->pain_debounce_time < level.time)
{ {
gi.sound(targ, CHAN_ITEM, gi.soundindex( "items/protect4.wav"), 1, ATTN_NORM, 0); gi.sound(targ, CHAN_ITEM, gi.soundindex("items/protect4.wav"), 1, ATTN_NORM, 0);
targ->pain_debounce_time = level.time + 2; targ->pain_debounce_time = level.time + 2;
} }
@ -816,7 +816,7 @@ T_Damage(edict_t *targ, edict_t *inflictor, edict_t *attacker, vec3_t dir,
{ {
if (targ->pain_debounce_time < level.time) if (targ->pain_debounce_time < level.time)
{ {
gi.sound(targ, CHAN_ITEM, gi.soundindex( "items/protect4.wav"), 1, ATTN_NORM, 0); gi.sound(targ, CHAN_ITEM, gi.soundindex("items/protect4.wav"), 1, ATTN_NORM, 0);
targ->pain_debounce_time = level.time + 2; targ->pain_debounce_time = level.time + 2;
} }

View file

@ -17,6 +17,7 @@
qboolean Pickup_Weapon(edict_t *ent, edict_t *other); qboolean Pickup_Weapon(edict_t *ent, edict_t *other);
void Use_Weapon(edict_t *ent, gitem_t *inv); void Use_Weapon(edict_t *ent, gitem_t *inv);
void Use_Weapon2(edict_t *ent, gitem_t *inv);
void Drop_Weapon(edict_t *ent, gitem_t *inv); void Drop_Weapon(edict_t *ent, gitem_t *inv);
void Weapon_Blaster(edict_t *ent); void Weapon_Blaster(edict_t *ent);
@ -1426,7 +1427,7 @@ Use_PowerArmor(edict_t *ent, gitem_t *item)
if (ent->flags & FL_POWER_ARMOR) if (ent->flags & FL_POWER_ARMOR)
{ {
ent->flags &= ~FL_POWER_ARMOR; ent->flags &= ~FL_POWER_ARMOR;
gi.sound(ent, CHAN_AUTO, gi.soundindex( "misc/power2.wav"), 1, ATTN_NORM, 0); gi.sound(ent, CHAN_AUTO, gi.soundindex("misc/power2.wav"), 1, ATTN_NORM, 0);
} }
else else
{ {
@ -3589,6 +3590,28 @@ SP_item_health_mega(edict_t *self)
self->style = HEALTH_IGNORE_MAX | HEALTH_TIMED; self->style = HEALTH_IGNORE_MAX | HEALTH_TIMED;
} }
void
SP_item_foodcube(edict_t *self)
{
if (!self)
{
return;
}
if (deathmatch->value && ((int)dmflags->value & DF_NO_HEALTH))
{
G_FreeEdict(self);
return;
}
self->model = "models/objects/trapfx/tris.md2";
SpawnItem(self, FindItem("Health"));
self->spawnflags |= DROPPED_ITEM;
self->style = HEALTH_IGNORE_MAX;
gi.soundindex("items/s_health.wav");
self->classname = "foodcube";
}
void void
InitItems(void) InitItems(void)
{ {

View file

@ -1,8 +1,24 @@
/* /*
* Copyright (C) 1997-2001 Id Software, Inc.
* Copyright (c) ZeniMax Media Inc. * Copyright (c) ZeniMax Media Inc.
* Licensed under the GNU General Public License 2.0. *
*/ * 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.
*
* =======================================================================
* *
* Misc. utility functions for the game logic. * Misc. utility functions for the game logic.
* *
@ -13,10 +29,10 @@
#define MAXCHOICES 8 #define MAXCHOICES 8
vec3_t VEC_UP = {0, -1, 0}; static vec3_t VEC_UP = {0, -1, 0};
vec3_t MOVEDIR_UP = {0, 0, 1}; static vec3_t MOVEDIR_UP = {0, 0, 1};
vec3_t VEC_DOWN = {0, -2, 0}; static vec3_t VEC_DOWN = {0, -2, 0};
vec3_t MOVEDIR_DOWN = {0, 0, -1}; static vec3_t MOVEDIR_DOWN = {0, 0, -1};
void void
G_ProjectSource(vec3_t point, vec3_t distance, vec3_t forward, G_ProjectSource(vec3_t point, vec3_t distance, vec3_t forward,
@ -24,7 +40,8 @@ G_ProjectSource(vec3_t point, vec3_t distance, vec3_t forward,
{ {
result[0] = point[0] + forward[0] * distance[0] + right[0] * distance[1]; result[0] = point[0] + forward[0] * distance[0] + right[0] * distance[1];
result[1] = point[1] + forward[1] * distance[0] + right[1] * distance[1]; result[1] = point[1] + forward[1] * distance[0] + right[1] * distance[1];
result[2] = point[2] + forward[2] * distance[0] + right[2] * distance[1] + distance[2]; result[2] = point[2] + forward[2] * distance[0] + right[2] * distance[1] +
distance[2];
} }
void void
@ -40,14 +57,13 @@ G_ProjectSource2(vec3_t point, vec3_t distance, vec3_t forward,
} }
/* /*
* Searches all active entities for the next one that holds * Searches all active entities for the next
* the matching string at fieldofs (use the FOFS() macro) in * one that holds the matching string at fieldofs
* the structure. * (use the FOFS() macro) in the structure.
* *
* Searches beginning at the edict after from, or the beginning * Searches beginning at the edict after from, or
* if NULL. * the beginning. If NULL, NULL will be returned
* * if the end of the list is reached.
* NULL will be returned if the end of the list is reached.
*/ */
edict_t * edict_t *
G_Find(edict_t *from, int fieldofs, char *match) G_Find(edict_t *from, int fieldofs, char *match)
@ -92,7 +108,8 @@ G_Find(edict_t *from, int fieldofs, char *match)
} }
/* /*
* Returns entities that have origins within a spherical area * Returns entities that have origins
* within a spherical area
*/ */
edict_t * edict_t *
findradius(edict_t *from, vec3_t org, float rad) findradius(edict_t *from, vec3_t org, float rad)
@ -123,7 +140,8 @@ findradius(edict_t *from, vec3_t org, float rad)
for (j = 0; j < 3; j++) for (j = 0; j < 3; j++)
{ {
eorg[j] = org[j] - (from->s.origin[j] + (from->mins[j] + from->maxs[j]) * 0.5); eorg[j] = org[j] - (from->s.origin[j] +
(from->mins[j] + from->maxs[j]) * 0.5);
} }
if (VectorLength(eorg) > rad) if (VectorLength(eorg) > rad)
@ -195,14 +213,14 @@ findradius2(edict_t *from, vec3_t org, float rad)
} }
/* /*
* Searches all active entities for the next one that holds * Searches all active entities for
* the matching string at fieldofs (use the FOFS() macro) in * the next one that holds the matching
* the structure. * string at fieldofs (use the FOFS() macro)
* in the structure.
* *
* Searches beginning at the edict after from, or the beginning * Searches beginning at the edict after from,
* if NULL. * or the beginning. If NULL, NULL will be
* * returned if the end of the list is reached.
* NULL will be returned if the end of the list is reached.
*/ */
edict_t * edict_t *
G_PickTarget(char *targetname) G_PickTarget(char *targetname)
@ -240,7 +258,7 @@ G_PickTarget(char *targetname)
return NULL; return NULL;
} }
return choice[rand() % num_choices]; return choice[randk() % num_choices];
} }
void void
@ -256,17 +274,17 @@ Think_Delay(edict_t *ent)
} }
/* /*
* the global "activator" should be set to the entity that initiated the firing. * The global "activator" should be set to
* the entity that initiated the firing.
* *
* If self.delay is set, a DelayedUse entity will be created that will actually * If self.delay is set, a DelayedUse entity
* do the SUB_UseTargets after that many seconds have passed. * will be created that will actually do the
* SUB_UseTargets after that many seconds have passed.
* *
* Centerprints any self.message to the activator. * Centerprints any self.message to the activator.
* *
* Search for (string)targetname in all entities that * Search for (string)targetname in all entities that
* match (string)self.target and call their .use function * match (string)self.target and call their .use function
*
* ==============================
*/ */
void void
G_UseTargets(edict_t *ent, edict_t *activator) G_UseTargets(edict_t *ent, edict_t *activator)
@ -289,6 +307,11 @@ G_UseTargets(edict_t *ent, edict_t *activator)
t->think = Think_Delay; t->think = Think_Delay;
t->activator = activator; t->activator = activator;
if (!activator)
{
gi.dprintf("Think_Delay with no activator\n");
}
t->message = ent->message; t->message = ent->message;
t->target = ent->target; t->target = ent->target;
t->killtarget = ent->killtarget; t->killtarget = ent->killtarget;
@ -306,7 +329,8 @@ G_UseTargets(edict_t *ent, edict_t *activator)
} }
else else
{ {
gi.sound(activator, CHAN_AUTO, gi.soundindex("misc/talk1.wav"), 1, ATTN_NORM, 0); gi.sound(activator, CHAN_AUTO, gi.soundindex(
"misc/talk1.wav"), 1, ATTN_NORM, 0);
} }
} }
@ -398,8 +422,9 @@ tv(float x, float y, float z)
static vec3_t vecs[8]; static vec3_t vecs[8];
float *v; float *v;
/* use an array so that multiple tempvectors /* use an array so that multiple
won't collide for a while */ tempvectors won't collide
for a while */
v = vecs[index]; v = vecs[index];
index = (index + 1) & 7; index = (index + 1) & 7;
@ -468,18 +493,16 @@ vectoyaw(vec3_t vec)
float yaw; float yaw;
if (vec[PITCH] == 0) if (vec[PITCH] == 0)
{
if (vec[YAW] == 0)
{ {
yaw = 0; yaw = 0;
}
else if (vec[YAW] > 0) if (vec[YAW] > 0)
{ {
yaw = 90; yaw = 90;
} }
else else if (vec[YAW] < 0)
{ {
yaw = 270; yaw = -90;
} }
} }
else else
@ -559,7 +582,7 @@ vectoangles(vec3_t value1, vec3_t angles)
} }
else else
{ {
yaw = 270; yaw = -90;
} }
if (yaw < 0) if (yaw < 0)
@ -749,10 +772,20 @@ G_FreeEdict(edict_t *ed)
gi.unlinkentity(ed); /* unlink from world */ gi.unlinkentity(ed); /* unlink from world */
if (deathmatch->value || coop->value)
{
if ((ed - g_edicts) <= (maxclients->value + BODY_QUEUE_SIZE)) if ((ed - g_edicts) <= (maxclients->value + BODY_QUEUE_SIZE))
{ {
return; return;
} }
}
else
{
if ((ed - g_edicts) <= maxclients->value)
{
return;
}
}
memset(ed, 0, sizeof(*ed)); memset(ed, 0, sizeof(*ed));
ed->classname = "freed"; ed->classname = "freed";
@ -801,8 +834,10 @@ G_TouchTriggers(edict_t *ent)
} }
/* /*
* Call after linking a new trigger in during gameplay * Call after linking a new trigger
* to force all entities it covers to immediately touch it * in during gameplay to force all
* entities it covers to immediately
* touch it
*/ */
void void
G_TouchSolids(edict_t *ent) G_TouchSolids(edict_t *ent)
@ -815,7 +850,8 @@ G_TouchSolids(edict_t *ent)
return; return;
} }
num = gi.BoxEdicts(ent->absmin, ent->absmax, touch, MAX_EDICTS, AREA_SOLID); num = gi.BoxEdicts(ent->absmin, ent->absmax, touch,
MAX_EDICTS, AREA_SOLID);
/* be careful, it is possible to have an entity in this /* be careful, it is possible to have an entity in this
list removed before we get to it (killtriggered) */ list removed before we get to it (killtriggered) */
@ -841,8 +877,9 @@ G_TouchSolids(edict_t *ent)
} }
/* /*
* Kills all entities that would touch the proposed new positioning * Kills all entities that would touch the
* of ent. Ent should be unlinked before calling this! * proposed new positioning of ent. Ent s
* hould be unlinked before calling this!
*/ */
qboolean qboolean
KillBox(edict_t *ent) KillBox(edict_t *ent)
@ -856,8 +893,8 @@ KillBox(edict_t *ent)
while (1) while (1)
{ {
tr = gi.trace(ent->s.origin, ent->mins, ent->maxs, tr = gi.trace(ent->s.origin, ent->mins, ent->maxs, ent->s.origin,
ent->s.origin, NULL, MASK_PLAYERSOLID); NULL, MASK_PLAYERSOLID);
if (!tr.ent) if (!tr.ent)
{ {

File diff suppressed because it is too large Load diff

View file

@ -1,8 +1,24 @@
/* /*
* Copyright (C) 1997-2001 Id Software, Inc.
* Copyright (c) ZeniMax Media Inc. * Copyright (c) ZeniMax Media Inc.
* Licensed under the GNU General Public License 2.0. *
*/ * 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.
*
* =======================================================================
* *
* Here are the client, server and game are tied together. * Here are the client, server and game are tied together.
* *
@ -29,6 +45,8 @@
#define SVF_MONSTER 0x00000004 /* treat as CONTENTS_MONSTER for collision */ #define SVF_MONSTER 0x00000004 /* treat as CONTENTS_MONSTER for collision */
#define SVF_DAMAGEABLE 0x00000008 #define SVF_DAMAGEABLE 0x00000008
#define MAX_ENT_CLUSTERS 16
typedef enum typedef enum
{ {
SOLID_NOT, /* no interaction with other objects */ SOLID_NOT, /* no interaction with other objects */
@ -45,7 +63,6 @@ typedef struct link_s
struct link_s *prev, *next; struct link_s *prev, *next;
} link_t; } link_t;
#define MAX_ENT_CLUSTERS 16
typedef struct edict_s edict_t; typedef struct edict_s edict_t;
typedef struct gclient_s gclient_t; typedef struct gclient_s gclient_t;
@ -95,29 +112,34 @@ struct edict_s
typedef struct typedef struct
{ {
/* special messages */ /* special messages */
void (*bprintf)(int printlevel, char *fmt, ...); void (*bprintf)(int printlevel, const char *fmt, ...);
void (*dprintf)(char *fmt, ...); void (*dprintf)(const char *fmt, ...);
void (*cprintf)(edict_t *ent, int printlevel, char *fmt, ...); void (*cprintf)(edict_t *ent, int printlevel, const char *fmt, ...);
void (*centerprintf)(edict_t *ent, char *fmt, ...); void (*centerprintf)(edict_t *ent, const char *fmt, ...);
void (*sound)(edict_t *ent, int channel, int soundindex, float volume, float attenuation, float timeofs); void (*sound)(edict_t *ent, int channel, int soundindex, float volume,
void (*positioned_sound)(vec3_t origin, edict_t *ent, int channel, int soundinedex, float volume, float attenuation, float timeofs); float attenuation, float timeofs);
void (*positioned_sound)(vec3_t origin, edict_t *ent, int channel,
int soundinedex, float volume, float attenuation, float timeofs);
/* config strings hold all the index strings, the lightstyles, /* config strings hold all the index strings, the lightstyles,
and misc data like the sky definition and cdtrack. and misc data like the sky definition and cdtrack.
All of the current configstrings are sent to clients when All of the current configstrings are sent to clients when
they connect, and changes are sent to all connected clients. */ they connect, and changes are sent to all connected clients. */
void (*configstring)(int num, char *string); void (*configstring)(int num, const char *string);
void (*error)(char *fmt, ...);
/* the *index functions create configstrings and some internal server state */ YQ2_ATTR_NORETURN_FUNCPTR void (*error)(const char *fmt, ...);
int (*modelindex)(char *name);
int (*soundindex)(char *name);
int (*imageindex)(char *name);
void (*setmodel)(edict_t *ent, char *name); /* the *index functions create configstrings
and some internal server state */
int (*modelindex)(const char *name);
int (*soundindex)(const char *name);
int (*imageindex)(const char *name);
void (*setmodel)(edict_t *ent, const char *name);
/* collision detection */ /* collision detection */
trace_t (*trace)(vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end, edict_t *passent, int contentmask); trace_t (*trace)(vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end,
edict_t *passent, int contentmask);
int (*pointcontents)(vec3_t point); int (*pointcontents)(vec3_t point);
qboolean (*inPVS)(vec3_t p1, vec3_t p2); qboolean (*inPVS)(vec3_t p1, vec3_t p2);
qboolean (*inPHS)(vec3_t p1, vec3_t p2); qboolean (*inPHS)(vec3_t p1, vec3_t p2);
@ -129,7 +151,8 @@ typedef struct
solidity changes, it must be relinked. */ solidity changes, it must be relinked. */
void (*linkentity)(edict_t *ent); void (*linkentity)(edict_t *ent);
void (*unlinkentity)(edict_t *ent); /* call before removing an interactive edict */ void (*unlinkentity)(edict_t *ent); /* call before removing an interactive edict */
int (*BoxEdicts)(vec3_t mins, vec3_t maxs, edict_t **list, int maxcount, int areatype); int (*BoxEdicts)(vec3_t mins, vec3_t maxs, edict_t **list, int maxcount,
int areatype);
void (*Pmove)(pmove_t *pmove); /* player movement code common with client prediction */ void (*Pmove)(pmove_t *pmove); /* player movement code common with client prediction */
/* network messaging */ /* network messaging */
@ -140,7 +163,7 @@ typedef struct
void (*WriteShort)(int c); void (*WriteShort)(int c);
void (*WriteLong)(int c); void (*WriteLong)(int c);
void (*WriteFloat)(float f); void (*WriteFloat)(float f);
void (*WriteString)(char *s); void (*WriteString)(const char *s);
void (*WritePosition)(vec3_t pos); /* some fractional bits */ void (*WritePosition)(vec3_t pos); /* some fractional bits */
void (*WriteDir)(vec3_t pos); /* single byte encoded, very coarse */ void (*WriteDir)(vec3_t pos); /* single byte encoded, very coarse */
void (*WriteAngle)(float f); void (*WriteAngle)(float f);
@ -151,17 +174,18 @@ typedef struct
void (*FreeTags)(int tag); void (*FreeTags)(int tag);
/* console variable interaction */ /* console variable interaction */
cvar_t *(*cvar)(char *var_name, char *value, int flags); cvar_t *(*cvar)(const char *var_name, const char *value, int flags);
cvar_t *(*cvar_set)(char *var_name, char *value); cvar_t *(*cvar_set)(const char *var_name, const char *value);
cvar_t *(*cvar_forceset)(char *var_name, char *value); cvar_t *(*cvar_forceset)(const char *var_name, const char *value);
/* ClientCommand and ServerCommand parameter access */ /* ClientCommand and ServerCommand parameter access */
int (*argc)(void); int (*argc)(void);
char *(*argv)(int n); char *(*argv)(int n);
char *(*args)(void); /* concatenation of all argv >= 1 */ char *(*args)(void); /* concatenation of all argv >= 1 */
/* add commands to the server console as if they were typed in for map changing, etc */ /* add commands to the server console as if
void (*AddCommandString)(char *text); they were typed in for map changing, etc */
void (*AddCommandString)(const char *text);
void (*DebugGraph)(float value, int color); void (*DebugGraph)(float value, int color);
} game_import_t; } game_import_t;
@ -178,18 +202,20 @@ typedef struct
void (*Shutdown)(void); void (*Shutdown)(void);
/* each new level entered will cause a call to SpawnEntities */ /* each new level entered will cause a call to SpawnEntities */
void (*SpawnEntities)(char *mapname, char *entstring, char *spawnpoint); void (*SpawnEntities)(const char *mapname, char *entstring, const char *spawnpoint);
/* Read/Write Game is for storing persistant cross level information /* Read/Write Game is for storing persistant cross level information
about the world state and the clients. WriteGame is called every time about the world state and the clients.
a level is exited. ReadGame is called on a loadgame. */ WriteGame is called every time a level is exited.
void (*WriteGame)(char *filename, qboolean autosave); ReadGame is called on a loadgame. */
void (*ReadGame)(char *filename); void (*WriteGame)(const char *filename, qboolean autosave);
void (*ReadGame)(const char *filename);
/* ReadLevel is called after the default map /* ReadLevel is called after the default
information has been loaded with SpawnEntities */ map information has been loaded with
void (*WriteLevel)(char *filename); SpawnEntities */
void (*ReadLevel)(char *filename); void (*WriteLevel)(const char *filename);
void (*ReadLevel)(const char *filename);
qboolean (*ClientConnect)(edict_t *ent, char *userinfo); qboolean (*ClientConnect)(edict_t *ent, char *userinfo);
void (*ClientBegin)(edict_t *ent); void (*ClientBegin)(edict_t *ent);
@ -200,16 +226,17 @@ typedef struct
void (*RunFrame)(void); void (*RunFrame)(void);
/* ServerCommand will be called when an "sv <command>" command /* ServerCommand will be called when an "sv <command>"
is issued on the server console. The game can issue gi.argc() command is issued on the server console. The game can
gi.argv() commands to get the rest of the parameters */ issue gi.argc() / gi.argv() commands to get the rest
of the parameters */
void (*ServerCommand)(void); void (*ServerCommand)(void);
/* global variables shared between game and server */ /* global variables shared between game and server */
/* The edict array is allocated in the game dll so it can vary in /* The edict array is allocated in the game dll so it
size from one game to another. The size will be fixed when can vary in size from one game to another.
ge->Init() is called */ The size will be fixed when ge->Init() is called */
struct edict_s *edicts; struct edict_s *edicts;
int edict_size; int edict_size;
int num_edicts; /* current number, <= max_edicts */ int num_edicts; /* current number, <= max_edicts */

View file

@ -1,8 +1,24 @@
/* /*
* Copyright (C) 1997-2001 Id Software, Inc.
* Copyright (c) ZeniMax Media Inc. * Copyright (c) ZeniMax Media Inc.
* Licensed under the GNU General Public License 2.0. *
*/ * 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.
*
* =======================================================================
* *
* Main header file for the game module. * Main header file for the game module.
* *
@ -147,6 +163,7 @@ typedef enum
#define AI_COMBAT_POINT 0x00001000 #define AI_COMBAT_POINT 0x00001000
#define AI_MEDIC 0x00002000 #define AI_MEDIC 0x00002000
#define AI_RESURRECTING 0x00004000 #define AI_RESURRECTING 0x00004000
#define AI_IGNORE_PAIN 0x00008000
/* ROGUE */ /* ROGUE */
#define AI_WALK_WALLS 0x00008000 #define AI_WALK_WALLS 0x00008000
@ -216,7 +233,8 @@ typedef enum
MOVETYPE_FLY, MOVETYPE_FLY,
MOVETYPE_TOSS, /* gravity */ MOVETYPE_TOSS, /* gravity */
MOVETYPE_FLYMISSILE, /* extra size to monsters */ MOVETYPE_FLYMISSILE, /* extra size to monsters */
MOVETYPE_BOUNCE, MOVETYPE_BOUNCE, /* added this (the comma at the end of line) */
MOVETYPE_WALLBOUNCE,
MOVETYPE_NEWTOSS /* for deathball */ MOVETYPE_NEWTOSS /* for deathball */
} movetype_t; } movetype_t;
@ -229,6 +247,7 @@ typedef struct
int armor; int armor;
} gitem_armor_t; } gitem_armor_t;
/* gitem_t->flags */
#define IT_WEAPON 0x00000001 /* use makes active weapon */ #define IT_WEAPON 0x00000001 /* use makes active weapon */
#define IT_AMMO 0x00000002 #define IT_AMMO 0x00000002
#define IT_ARMOR 0x00000004 #define IT_ARMOR 0x00000004
@ -251,12 +270,13 @@ typedef struct
#define WEAP_HYPERBLASTER 9 #define WEAP_HYPERBLASTER 9
#define WEAP_RAILGUN 10 #define WEAP_RAILGUN 10
#define WEAP_BFG 11 #define WEAP_BFG 11
#define WEAP_PHALANX 12
#define WEAP_DISRUPTOR 12 #define WEAP_BOOMER 13
#define WEAP_ETFRIFLE 13 #define WEAP_DISRUPTOR 14
#define WEAP_PLASMA 14 #define WEAP_ETFRIFLE 15
#define WEAP_PROXLAUNCH 15 #define WEAP_PLASMA 16
#define WEAP_CHAINFIST 16 #define WEAP_PROXLAUNCH 17
#define WEAP_CHAINFIST 18
typedef struct gitem_s typedef struct gitem_s
{ {
@ -299,8 +319,9 @@ typedef struct
gclient_t *clients; /* [maxclients] */ gclient_t *clients; /* [maxclients] */
/* can't store spawnpoint in level, because it /* can't store spawnpoint in level, because
would get overwritten by the savegame restore */ it would get overwritten by the savegame
restore */
char spawnpoint[512]; /* needed for coop respawns */ char spawnpoint[512]; /* needed for coop respawns */
/* store latched cvars here that we want to get at often */ /* store latched cvars here that we want to get at often */
@ -371,6 +392,7 @@ typedef struct
/* world vars */ /* world vars */
char *sky; char *sky;
float skyrotate; float skyrotate;
int skyautorotate;
vec3_t skyaxis; vec3_t skyaxis;
char *nextmap; char *nextmap;
@ -445,7 +467,7 @@ typedef struct
void (*search)(edict_t *self); void (*search)(edict_t *self);
void (*walk)(edict_t *self); void (*walk)(edict_t *self);
void (*run)(edict_t *self); void (*run)(edict_t *self);
void (*dodge)(edict_t *self, edict_t *other, float eta, trace_t *tr); void (*dodge)(edict_t *self, edict_t *other, float eta);
void (*attack)(edict_t *self); void (*attack)(edict_t *self);
void (*melee)(edict_t *self); void (*melee)(edict_t *self);
void (*sight)(edict_t *self, edict_t *other); void (*sight)(edict_t *self, edict_t *other);
@ -508,10 +530,6 @@ extern spawn_temp_t st;
extern int sm_meat_index; extern int sm_meat_index;
extern int snd_fry; extern int snd_fry;
extern int jacket_armor_index;
extern int combat_armor_index;
extern int body_armor_index;
extern int debristhisframe; extern int debristhisframe;
extern int gibsthisframe; extern int gibsthisframe;
@ -550,6 +568,12 @@ extern int gibsthisframe;
#define MOD_TRIGGER_HURT 31 #define MOD_TRIGGER_HURT 31
#define MOD_HIT 32 #define MOD_HIT 32
#define MOD_TARGET_BLASTER 33 #define MOD_TARGET_BLASTER 33
#define MOD_RIPPER 34
#define MOD_PHALANX 35
#define MOD_BRAINTENTACLE 36
#define MOD_BLASTOFF 37
#define MOD_GEKK 38
#define MOD_TRAP 39
#define MOD_FRIENDLY_FIRE 0x8000000 #define MOD_FRIENDLY_FIRE 0x8000000
#define MOD_CHAINFIST 40 #define MOD_CHAINFIST 40
#define MOD_DISINTEGRATOR 41 #define MOD_DISINTEGRATOR 41
@ -589,6 +613,7 @@ extern cvar_t *maxentities;
extern cvar_t *deathmatch; extern cvar_t *deathmatch;
extern cvar_t *coop; extern cvar_t *coop;
extern cvar_t *coop_baseq2; /* treat spawnflags according to baseq2 rules */ extern cvar_t *coop_baseq2; /* treat spawnflags according to baseq2 rules */
extern cvar_t *coop_pickup_weapons;
extern cvar_t *coop_elevator_delay; extern cvar_t *coop_elevator_delay;
extern cvar_t *coop_pickup_weapons; extern cvar_t *coop_pickup_weapons;
extern cvar_t *dmflags; extern cvar_t *dmflags;
@ -597,10 +622,13 @@ extern cvar_t *fraglimit;
extern cvar_t *timelimit; extern cvar_t *timelimit;
extern cvar_t *password; extern cvar_t *password;
extern cvar_t *spectator_password; extern cvar_t *spectator_password;
extern cvar_t *needpass;
extern cvar_t *g_select_empty; extern cvar_t *g_select_empty;
extern cvar_t *dedicated; extern cvar_t *dedicated;
extern cvar_t *g_footsteps; extern cvar_t *g_footsteps;
extern cvar_t *g_monsterfootsteps;
extern cvar_t *g_fix_triggered; extern cvar_t *g_fix_triggered;
extern cvar_t *g_commanderbody_nogod;
extern cvar_t *filterban; extern cvar_t *filterban;
@ -639,6 +667,7 @@ extern cvar_t *g_disruptor;
extern cvar_t *aimfix; extern cvar_t *aimfix;
extern cvar_t *g_machinegun_norecoil; extern cvar_t *g_machinegun_norecoil;
extern cvar_t *g_swap_speed;
/* this is for the count of monsters */ /* this is for the count of monsters */
#define ENT_SLOTS_LEFT \ #define ENT_SLOTS_LEFT \
@ -659,8 +688,8 @@ extern cvar_t *g_machinegun_norecoil;
#define DROPPED_PLAYER_ITEM 0x00020000 #define DROPPED_PLAYER_ITEM 0x00020000
#define ITEM_TARGETS_USED 0x00040000 #define ITEM_TARGETS_USED 0x00040000
/* fields are needed for spawning from the entity string /* fields are needed for spawning from the entity
and saving / loading games */ string and saving / loading games */
#define FFL_SPAWNTEMP 1 #define FFL_SPAWNTEMP 1
#define FFL_NOSPAWN 2 #define FFL_NOSPAWN 2
@ -692,8 +721,16 @@ typedef struct
extern field_t fields[]; extern field_t fields[];
extern gitem_t itemlist[]; extern gitem_t itemlist[];
/* player/client.c */
void ClientBegin(edict_t *ent);
void ClientDisconnect(edict_t *ent);
void ClientUserinfoChanged(edict_t *ent, char *userinfo);
qboolean ClientConnect(edict_t *ent, char *userinfo);
void ClientThink(edict_t *ent, usercmd_t *cmd);
/* g_cmds.c */ /* g_cmds.c */
void Cmd_Help_f(edict_t *ent); void Cmd_Help_f(edict_t *ent);
void ClientCommand(edict_t *ent);
/* g_items.c */ /* g_items.c */
void PrecacheItem(gitem_t *it); void PrecacheItem(gitem_t *it);
@ -703,6 +740,7 @@ gitem_t *FindItem(char *pickup_name);
gitem_t *FindItemByClassname(char *classname); gitem_t *FindItemByClassname(char *classname);
#define ITEM_INDEX(x) ((x) - itemlist) #define ITEM_INDEX(x) ((x) - itemlist)
edict_t *Drop_Item(edict_t *ent, gitem_t *item); edict_t *Drop_Item(edict_t *ent, gitem_t *item);
void SetRespawn(edict_t *ent, float delay); void SetRespawn(edict_t *ent, float delay);
void ChangeWeapon(edict_t *ent); void ChangeWeapon(edict_t *ent);
@ -748,14 +786,18 @@ float vectoyaw2(vec3_t vec);
void vectoangles2(vec3_t vec, vec3_t angles); void vectoangles2(vec3_t vec, vec3_t angles);
edict_t *findradius2(edict_t *from, vec3_t org, float rad); edict_t *findradius2(edict_t *from, vec3_t org, float rad);
/* g_spawn.c */
void ED_CallSpawn(edict_t *ent);
/* g_combat.c */ /* g_combat.c */
qboolean OnSameTeam(edict_t *ent1, edict_t *ent2); qboolean OnSameTeam(edict_t *ent1, edict_t *ent2);
qboolean CanDamage(edict_t *targ, edict_t *inflictor); qboolean CanDamage(edict_t *targ, edict_t *inflictor);
void T_Damage(edict_t *targ, edict_t *inflictor, edict_t *attacker, vec3_t dir, void T_Damage(edict_t *targ, edict_t *inflictor, edict_t *attacker,
vec3_t point, vec3_t normal, int damage, int knockback, int dflags, int mod); vec3_t dir, vec3_t point, vec3_t normal, int damage,
void T_RadiusDamage(edict_t *inflictor, edict_t *attacker, float damage, edict_t *ignore, int knockback, int dflags, int mod);
float radius, int mod); void T_RadiusDamage(edict_t *inflictor, edict_t *attacker,
float damage, edict_t *ignore, float radius,
int mod);
void T_RadiusNukeDamage(edict_t *inflictor, edict_t *attacker, float damage, void T_RadiusNukeDamage(edict_t *inflictor, edict_t *attacker, float damage,
edict_t *ignore, float radius, int mod); edict_t *ignore, float radius, int mod);
void T_RadiusClassDamage(edict_t *inflictor, edict_t *attacker, float damage, void T_RadiusClassDamage(edict_t *inflictor, edict_t *attacker, float damage,
@ -777,24 +819,33 @@ void cleanupHealTarget(edict_t *ent);
#define DEFAULT_BULLET_VSPREAD 500 #define DEFAULT_BULLET_VSPREAD 500
#define DEFAULT_SHOTGUN_HSPREAD 1000 #define DEFAULT_SHOTGUN_HSPREAD 1000
#define DEFAULT_SHOTGUN_VSPREAD 500 #define DEFAULT_SHOTGUN_VSPREAD 500
#define DEFAULT_DEATHMATCH_SHOTGUN_COUNT 12
#define DEFAULT_SHOTGUN_COUNT 12 #define DEFAULT_SHOTGUN_COUNT 12
#define DEFAULT_SSHOTGUN_COUNT 20 #define DEFAULT_SSHOTGUN_COUNT 20
/* g_monster.c */ /* g_monster.c */
void monster_fire_bullet(edict_t *self, vec3_t start, vec3_t dir, int damage, void monster_fire_bullet(edict_t *self, vec3_t start, vec3_t dir, int damage,
int kick, int hspread, int vspread, int flashtype); int kick, int hspread, int vspread, int flashtype);
void monster_fire_shotgun(edict_t *self, vec3_t start, vec3_t aimdir, int damage, void monster_fire_shotgun(edict_t *self, vec3_t start, vec3_t aimdir,
int kick, int hspread, int vspread, int count, int flashtype); int damage, int kick, int hspread, int vspread, int count,
void monster_fire_blaster(edict_t *self, vec3_t start, vec3_t dir, int damage, int flashtype);
void monster_fire_blaster(edict_t *self, vec3_t start, vec3_t dir,
int damage, int speed, int flashtype, int effect);
void monster_fire_grenade(edict_t *self, vec3_t start, vec3_t aimdir,
int damage, int speed, int flashtype);
void monster_fire_rocket(edict_t *self, vec3_t start, vec3_t dir,
int damage, int speed, int flashtype);
void monster_fire_railgun(edict_t *self, vec3_t start, vec3_t aimdir,
int damage, int kick, int flashtype);
void monster_fire_bfg(edict_t *self, vec3_t start, vec3_t aimdir,
int damage, int speed, int kick, float damage_radius,
int flashtype);
void monster_fire_ionripper(edict_t *self, vec3_t start, vec3_t dir, int damage,
int speed, int flashtype, int effect); int speed, int flashtype, int effect);
void monster_fire_grenade(edict_t *self, vec3_t start, vec3_t aimdir, int damage, void monster_dabeam(edict_t *self);
int speed, int flashtype); void monster_fire_blueblaster(edict_t *self, vec3_t start, vec3_t dir, int damage,
void monster_fire_rocket(edict_t *self, vec3_t start, vec3_t dir, int damage, int speed, int flashtype, int effect);
int speed, int flashtype);
void monster_fire_railgun(edict_t *self, vec3_t start, vec3_t aimdir, int damage,
int kick, int flashtype);
void monster_fire_bfg(edict_t *self, vec3_t start, vec3_t aimdir, int damage,
int speed, int kick, float damage_radius, int flashtype);
void M_droptofloor(edict_t *ent); void M_droptofloor(edict_t *ent);
void monster_think(edict_t *self); void monster_think(edict_t *self);
void walkmonster_start(edict_t *self); void walkmonster_start(edict_t *self);
@ -811,8 +862,6 @@ void monster_fire_blaster2(edict_t *self, vec3_t start, vec3_t dir, int damage,
int speed, int flashtype, int effect); int speed, int flashtype, int effect);
void monster_fire_tracker(edict_t *self, vec3_t start, vec3_t dir, int damage, void monster_fire_tracker(edict_t *self, vec3_t start, vec3_t dir, int damage,
int speed, edict_t *enemy, int flashtype); int speed, edict_t *enemy, int flashtype);
void monster_fire_heat(edict_t *self, vec3_t start, vec3_t dir, vec3_t offset,
int damage, int kick, int flashtype);
void stationarymonster_start(edict_t *self); void stationarymonster_start(edict_t *self);
void monster_done_dodge(edict_t *self); void monster_done_dodge(edict_t *self);
@ -821,6 +870,8 @@ void ThrowHead(edict_t *self, char *gibname, int damage, int type);
void ThrowClientHead(edict_t *self, int damage); void ThrowClientHead(edict_t *self, int damage);
void ThrowGib(edict_t *self, char *gibname, int damage, int type); void ThrowGib(edict_t *self, char *gibname, int damage, int type);
void BecomeExplosion1(edict_t *self); void BecomeExplosion1(edict_t *self);
void ThrowHeadACID(edict_t *self, char *gibname, int damage, int type);
void ThrowGibACID(edict_t *self, char *gibname, int damage, int type);
/* g_ai.c */ /* g_ai.c */
void AI_SetSightClient(void); void AI_SetSightClient(void);
@ -852,10 +903,19 @@ void fire_grenade(edict_t *self, vec3_t start, vec3_t aimdir, int damage,
void fire_grenade2(edict_t *self, vec3_t start, vec3_t aimdir, int damage, void fire_grenade2(edict_t *self, vec3_t start, vec3_t aimdir, int damage,
int speed, float timer, float damage_radius, qboolean held); int speed, float timer, float damage_radius, qboolean held);
void fire_rocket(edict_t *self, vec3_t start, vec3_t dir, int damage, void fire_rocket(edict_t *self, vec3_t start, vec3_t dir, int damage,
int speed, float damage_radius, int radius_damage); int speed, float damage_radius,
int radius_damage);
void fire_rail(edict_t *self, vec3_t start, vec3_t aimdir, int damage, int kick); void fire_rail(edict_t *self, vec3_t start, vec3_t aimdir, int damage, int kick);
void fire_bfg(edict_t *self, vec3_t start, vec3_t dir, void fire_bfg(edict_t *self, vec3_t start, vec3_t dir, int damage,
int damage, int speed, float damage_radius); int speed, float damage_radius);
void fire_ionripper(edict_t *self, vec3_t start, vec3_t aimdir, int damage,
int speed, int effect);
void fire_blueblaster(edict_t *self, vec3_t start, vec3_t aimdir, int damage,
int speed, int effect);
void fire_plasma(edict_t *self, vec3_t start, vec3_t dir, int damage, int speed,
float damage_radius, int radius_damage);
void fire_trap(edict_t *self, vec3_t start, vec3_t aimdir, int damage,
int speed, float timer, float damage_radius, qboolean held);
/* g_ptrail.c */ /* g_ptrail.c */
void PlayerTrail_Init(void); void PlayerTrail_Init(void);
@ -918,6 +978,14 @@ void ChaseNext(edict_t *ent);
void ChasePrev(edict_t *ent); void ChasePrev(edict_t *ent);
void GetChaseTarget(edict_t *ent); void GetChaseTarget(edict_t *ent);
/* savegame */
void InitGame(void);
void ReadLevel(const char *filename);
void WriteLevel(const char *filename);
void ReadGame(const char *filename);
void WriteGame(const char *filename, qboolean autosave);
void SpawnEntities(const char *mapname, char *entities, const char *spawnpoint);
void fire_flechette(edict_t *self, vec3_t start, vec3_t dir, int damage, void fire_flechette(edict_t *self, vec3_t start, vec3_t dir, int damage,
int speed, int kick); int speed, int kick);
void fire_prox(edict_t *self, vec3_t start, vec3_t aimdir, int damage, void fire_prox(edict_t *self, vec3_t start, vec3_t aimdir, int damage,
@ -937,9 +1005,6 @@ void fire_tesla(edict_t *self, vec3_t start, vec3_t aimdir, int damage,
int speed); int speed);
void fire_blaster2(edict_t *self, vec3_t start, vec3_t aimdir, int damage, void fire_blaster2(edict_t *self, vec3_t start, vec3_t aimdir, int damage,
int speed, int effect, qboolean hyper); int speed, int effect, qboolean hyper);
void fire_heat(edict_t *self, vec3_t start, vec3_t aimdir, vec3_t offset,
int damage, int kick,
qboolean monster);
void fire_tracker(edict_t *self, vec3_t start, vec3_t dir, int damage, void fire_tracker(edict_t *self, vec3_t start, vec3_t dir, int damage,
int speed, edict_t *enemy); int speed, edict_t *enemy);
@ -1023,7 +1088,8 @@ typedef struct
qboolean connected; /* a loadgame will leave valid entities that qboolean connected; /* a loadgame will leave valid entities that
just don't have a connection yet */ just don't have a connection yet */
/* values saved and restored from edicts when changing levels */ /* values saved and restored from
edicts when changing levels */
int health; int health;
int max_health; int max_health;
int savedFlags; int savedFlags;
@ -1038,6 +1104,8 @@ typedef struct
int max_grenades; int max_grenades;
int max_cells; int max_cells;
int max_slugs; int max_slugs;
int max_magslug;
int max_trap;
gitem_t *weapon; gitem_t *weapon;
gitem_t *lastweapon; gitem_t *lastweapon;
@ -1139,6 +1207,10 @@ struct gclient_s
qboolean grenade_blew_up; qboolean grenade_blew_up;
float grenade_time; float grenade_time;
float quadfire_framenum;
qboolean trap_blew_up;
float trap_time;
int silencer_shots; int silencer_shots;
int weapon_sound; int weapon_sound;
@ -1232,7 +1304,7 @@ struct edict_s
float ideal_yaw; float ideal_yaw;
float nextthink; float nextthink;
void (*prethink) (edict_t *ent); void (*prethink)(edict_t *ent);
void (*think)(edict_t *self); void (*think)(edict_t *self);
void (*blocked)(edict_t *self, edict_t *other); /* move to moveinfo? */ void (*blocked)(edict_t *self, edict_t *other); /* move to moveinfo? */
void (*touch)(edict_t *self, edict_t *other, cplane_t *plane, void (*touch)(edict_t *self, edict_t *other, cplane_t *plane,
@ -1242,10 +1314,11 @@ struct edict_s
void (*die)(edict_t *self, edict_t *inflictor, edict_t *attacker, void (*die)(edict_t *self, edict_t *inflictor, edict_t *attacker,
int damage, vec3_t point); int damage, vec3_t point);
float touch_debounce_time; float touch_debounce_time; /* now also used by fixbots for timeouts when getting stuck */
float pain_debounce_time; float pain_debounce_time;
float damage_debounce_time; float damage_debounce_time;
float fly_sound_debounce_time; /* now also used by insane marines to store pain sound timeout */ float fly_sound_debounce_time; /* now also used by insane marines to store pain sound timeout */
/* and by fixbots for storing object_repair timeout when getting stuck */
float last_move_time; float last_move_time;
int health; int health;
@ -1296,6 +1369,7 @@ struct edict_s
vec3_t move_origin; vec3_t move_origin;
vec3_t move_angles; vec3_t move_angles;
/* move this to clientinfo? */
int light_level; int light_level;
int style; /* also used as areaportal number */ int style; /* also used as areaportal number */
@ -1305,6 +1379,8 @@ struct edict_s
moveinfo_t moveinfo; moveinfo_t moveinfo;
monsterinfo_t monsterinfo; monsterinfo_t monsterinfo;
int orders;
int plat2flags; int plat2flags;
vec3_t offset; vec3_t offset;
vec3_t gravityVector; vec3_t gravityVector;

View file

@ -710,7 +710,7 @@ hover_die(edict_t *self, edict_t *inflictor /* unused */, edict_t *attacker /* u
/* check for gib */ /* check for gib */
if (self->health <= self->gib_health) if (self->health <= self->gib_health)
{ {
gi.sound(self, CHAN_VOICE, gi.soundindex( "misc/udeath.wav"), 1, ATTN_NORM, 0); gi.sound(self, CHAN_VOICE, gi.soundindex("misc/udeath.wav"), 1, ATTN_NORM, 0);
for (n = 0; n < 2; n++) for (n = 0; n < 2; n++)
{ {

View file

@ -735,7 +735,7 @@ player_die(edict_t *self, edict_t *inflictor, edict_t *attacker,
if (!(self->flags & FL_NOGIB)) if (!(self->flags & FL_NOGIB))
{ {
/* gib (play sound at end of server frame) */ /* gib (play sound at end of server frame) */
self->sounds = gi.soundindex( "misc/udeath.wav"); self->sounds = gi.soundindex("misc/udeath.wav");
/* more meaty gibs for your dollar! */ /* more meaty gibs for your dollar! */
if ((deathmatch->value) && (self->health < -80)) if ((deathmatch->value) && (self->health < -80))
@ -1366,7 +1366,7 @@ body_die(edict_t *self, edict_t *inflictor /* unused */, edict_t *attacker /* un
if (self->health < -40) if (self->health < -40)
{ {
gi.sound(self, CHAN_BODY, gi.soundindex( "misc/udeath.wav"), 1, ATTN_NORM, 0); gi.sound(self, CHAN_BODY, gi.soundindex("misc/udeath.wav"), 1, ATTN_NORM, 0);
for (n = 0; n < 4; n++) for (n = 0; n < 4; n++)
{ {

View file

@ -427,7 +427,7 @@ G_SetStats(edict_t *ent)
{ {
/* ran out of cells for power armor */ /* ran out of cells for power armor */
ent->flags &= ~FL_POWER_ARMOR; ent->flags &= ~FL_POWER_ARMOR;
gi.sound(ent, CHAN_ITEM, gi.soundindex( "misc/power2.wav"), 1, ATTN_NORM, 0); gi.sound(ent, CHAN_ITEM, gi.soundindex("misc/power2.wav"), 1, ATTN_NORM, 0);
power_armor_type = 0; power_armor_type = 0;
} }
} }

View file

@ -40,9 +40,9 @@ gitem_armor_t jacketarmor_info = {25, 50, .30, .00, ARMOR_JACKET};
gitem_armor_t combatarmor_info = {50, 100, .60, .30, ARMOR_COMBAT}; gitem_armor_t combatarmor_info = {50, 100, .60, .30, ARMOR_COMBAT};
gitem_armor_t bodyarmor_info = {100, 200, .80, .60, ARMOR_BODY}; gitem_armor_t bodyarmor_info = {100, 200, .80, .60, ARMOR_BODY};
int jacket_armor_index; static int jacket_armor_index;
int combat_armor_index; static int combat_armor_index;
int body_armor_index; static int body_armor_index;
static int power_screen_index; static int power_screen_index;
static int power_shield_index; static int power_shield_index;
@ -2927,7 +2927,7 @@ SP_item_health(edict_t *self)
} }
/* /*
* QUAKED item_health_small (.3 .3 1) (-16 -16 -16) (16 16 16) * QUAKED item_health_small (.3 .3 1) (-16 -16 -16) (16 16 16) TRIGGER_SPAWN
*/ */
void void
SP_item_health_small(edict_t *self) SP_item_health_small(edict_t *self)
@ -2951,7 +2951,7 @@ SP_item_health_small(edict_t *self)
} }
/* /*
* QUAKED item_health_large (.3 .3 1) (-16 -16 -16) (16 16 16) * QUAKED item_health_large (.3 .3 1) (-16 -16 -16) (16 16 16) TRIGGER_SPAWN
*/ */
void void
SP_item_health_large(edict_t *self) SP_item_health_large(edict_t *self)
@ -2974,7 +2974,7 @@ SP_item_health_large(edict_t *self)
} }
/* /*
* QUAKED item_health_mega (.3 .3 1) (-16 -16 -16) (16 16 16) * QUAKED item_health_mega (.3 .3 1) (-16 -16 -16) (16 16 16) TRIGGER_SPAWN
*/ */
void void
SP_item_health_mega(edict_t *self) SP_item_health_mega(edict_t *self)

View file

@ -543,7 +543,7 @@ M_WorldEffects(edict_t *ent)
{ {
if (ent->flags & FL_INWATER) if (ent->flags & FL_INWATER)
{ {
gi.sound(ent, CHAN_BODY, gi.soundindex( "player/watr_out.wav"), gi.sound(ent, CHAN_BODY, gi.soundindex("player/watr_out.wav"),
1, ATTN_NORM, 0); 1, ATTN_NORM, 0);
ent->flags &= ~FL_INWATER; ent->flags &= ~FL_INWATER;
} }
@ -579,7 +579,7 @@ M_WorldEffects(edict_t *ent)
{ {
if (random() <= 0.5) if (random() <= 0.5)
{ {
gi.sound(ent, CHAN_BODY, gi.soundindex( "player/lava1.wav"), gi.sound(ent, CHAN_BODY, gi.soundindex("player/lava1.wav"),
1, ATTN_NORM, 0); 1, ATTN_NORM, 0);
} }
else else

View file

@ -1,8 +1,24 @@
/* /*
* Copyright (C) 1997-2001 Id Software, Inc.
* Copyright (c) ZeniMax Media Inc. * Copyright (c) ZeniMax Media Inc.
* Licensed under the GNU General Public License 2.0. *
*/ * 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.
*
* =======================================================================
* *
* Misc. utility functions for the game logic. * Misc. utility functions for the game logic.
* *
@ -13,13 +29,19 @@
#define MAXCHOICES 8 #define MAXCHOICES 8
static vec3_t VEC_UP = {0, -1, 0};
static vec3_t MOVEDIR_UP = {0, 0, 1};
static vec3_t VEC_DOWN = {0, -2, 0};
static vec3_t MOVEDIR_DOWN = {0, 0, -1};
void void
G_ProjectSource(vec3_t point, vec3_t distance, vec3_t forward, G_ProjectSource(vec3_t point, vec3_t distance, vec3_t forward,
vec3_t right, vec3_t result) vec3_t right, vec3_t result)
{ {
result[0] = point[0] + forward[0] * distance[0] + right[0] * distance[1]; result[0] = point[0] + forward[0] * distance[0] + right[0] * distance[1];
result[1] = point[1] + forward[1] * distance[0] + right[1] * distance[1]; result[1] = point[1] + forward[1] * distance[0] + right[1] * distance[1];
result[2] = point[2] + forward[2] * distance[0] + right[2] * distance[1] + distance[2]; result[2] = point[2] + forward[2] * distance[0] + right[2] * distance[1] +
distance[2];
} }
/* /*
@ -34,6 +56,11 @@ G_Find(edict_t *from, int fieldofs, char *match)
{ {
char *s; char *s;
if (!match)
{
return NULL;
}
if (!from) if (!from)
{ {
from = g_edicts; from = g_edicts;
@ -67,7 +94,8 @@ G_Find(edict_t *from, int fieldofs, char *match)
} }
/* /*
* Returns entities that have origins within a spherical area * Returns entities that have origins
* within a spherical area
*/ */
edict_t * edict_t *
findradius(edict_t *from, vec3_t org, float rad) findradius(edict_t *from, vec3_t org, float rad)
@ -338,11 +366,6 @@ get_normal_vector(const cplane_t *p, vec3_t normal)
} }
} }
vec3_t VEC_UP = {0, -1, 0};
vec3_t MOVEDIR_UP = {0, 0, 1};
vec3_t VEC_DOWN = {0, -2, 0};
vec3_t MOVEDIR_DOWN = {0, 0, -1};
void void
G_SetMovedir(vec3_t angles, vec3_t movedir) G_SetMovedir(vec3_t angles, vec3_t movedir)
{ {

View file

@ -1,8 +1,24 @@
/* /*
* Copyright (C) 1997-2001 Id Software, Inc.
* Copyright (c) ZeniMax Media Inc. * Copyright (c) ZeniMax Media Inc.
* Licensed under the GNU General Public License 2.0. *
*/ * 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.
*
* =======================================================================
* *
* Weapon support functions. * Weapon support functions.
* *
@ -48,7 +64,7 @@ check_dodge(edict_t *self, vec3_t start, vec3_t dir, int speed)
{ {
VectorSubtract(tr.endpos, start, v); VectorSubtract(tr.endpos, start, v);
eta = (VectorLength(v) - tr.ent->maxs[0]) / speed; eta = (VectorLength(v) - tr.ent->maxs[0]) / speed;
tr.ent->monsterinfo.dodge(tr.ent, self, eta); tr.ent->monsterinfo.dodge(tr.ent, self, eta, &tr);
} }
} }
@ -70,6 +86,7 @@ fire_hit(edict_t *self, vec3_t aim, int damage, int kick)
return false; return false;
} }
/* Lazarus: Paranoia check */
if (!self->enemy) if (!self->enemy)
{ {
return false; return false;
@ -86,12 +103,14 @@ fire_hit(edict_t *self, vec3_t aim, int damage, int kick)
if ((aim[1] > self->mins[0]) && (aim[1] < self->maxs[0])) if ((aim[1] > self->mins[0]) && (aim[1] < self->maxs[0]))
{ {
/* the hit is straight on so back the range up to the edge of their bbox */ /* the hit is straight on so back the
range up to the edge of their bbox */
range -= self->enemy->maxs[0]; range -= self->enemy->maxs[0];
} }
else else
{ {
/* this is a side hit so adjust the "right" value out to the edge of their bbox */ /* this is a side hit so adjust the "right"
value out to the edge of their bbox */
if (aim[1] < 0) if (aim[1] < 0)
{ {
aim[1] = self->enemy->mins[0]; aim[1] = self->enemy->mins[0];
@ -113,7 +132,8 @@ fire_hit(edict_t *self, vec3_t aim, int damage, int kick)
return false; return false;
} }
/* if it will hit any client/monster then hit the one we wanted to hit */ /* if it will hit any client/monster
then hit the one we wanted to hit */
if ((tr.ent->svflags & SVF_MONSTER) || (tr.ent->client)) if ((tr.ent->svflags & SVF_MONSTER) || (tr.ent->client))
{ {
tr.ent = self->enemy; tr.ent = self->enemy;
@ -127,8 +147,8 @@ fire_hit(edict_t *self, vec3_t aim, int damage, int kick)
VectorSubtract(point, self->enemy->s.origin, dir); VectorSubtract(point, self->enemy->s.origin, dir);
/* do the damage */ /* do the damage */
T_Damage(tr.ent, self, self, dir, point, vec3_origin, T_Damage(tr.ent, self, self, dir, point, vec3_origin, damage,
damage, kick / 2, DAMAGE_NO_KNOCKBACK, MOD_HIT); kick / 2, DAMAGE_NO_KNOCKBACK, MOD_HIT);
if (!(tr.ent->svflags & SVF_MONSTER) && (!tr.ent->client)) if (!(tr.ent->svflags & SVF_MONSTER) && (!tr.ent->client))
{ {
@ -150,7 +170,8 @@ fire_hit(edict_t *self, vec3_t aim, int damage, int kick)
} }
/* /*
* This is an internal support routine used for bullet/pellet based weapons. * This is an internal support routine
* used for bullet/pellet based weapons.
*/ */
void void
fire_lead(edict_t *self, vec3_t start, vec3_t aimdir, int damage, int kick, fire_lead(edict_t *self, vec3_t start, vec3_t aimdir, int damage, int kick,
@ -283,7 +304,8 @@ fire_lead(edict_t *self, vec3_t start, vec3_t aimdir, int damage, int kick,
} }
} }
/* if went through water, determine where the end and make a bubble trail */ /* if went through water, determine
where the end and make a bubble trail */
if (water) if (water)
{ {
vec3_t pos; vec3_t pos;
@ -313,8 +335,8 @@ fire_lead(edict_t *self, vec3_t start, vec3_t aimdir, int damage, int kick,
} }
/* /*
* Fires a single round. Used for machinegun and chaingun. * Fires a single round. Used for machinegun and
* Would be fine for pistols, rifles, etc.... * chaingun. Would be fine for pistols, rifles, etc....
*/ */
void void
fire_bullet(edict_t *self, vec3_t start, vec3_t aimdir, int damage, fire_bullet(edict_t *self, vec3_t start, vec3_t aimdir, int damage,
@ -325,12 +347,13 @@ fire_bullet(edict_t *self, vec3_t start, vec3_t aimdir, int damage,
return; return;
} }
fire_lead(self, start, aimdir, damage, kick, TE_GUNSHOT, fire_lead(self, start, aimdir, damage, kick, TE_GUNSHOT, hspread,
hspread, vspread, mod); vspread, mod);
} }
/* /*
* Shoots shotgun pellets. Used by shotgun and super shotgun. * Shoots shotgun pellets. Used
* by shotgun and super shotgun.
*/ */
void void
fire_shotgun(edict_t *self, vec3_t start, vec3_t aimdir, int damage, fire_shotgun(edict_t *self, vec3_t start, vec3_t aimdir, int damage,
@ -345,13 +368,14 @@ fire_shotgun(edict_t *self, vec3_t start, vec3_t aimdir, int damage,
for (i = 0; i < count; i++) for (i = 0; i < count; i++)
{ {
fire_lead(self, start, aimdir, damage, kick, fire_lead(self, start, aimdir, damage, kick, TE_SHOTGUN,
TE_SHOTGUN, hspread, vspread, mod); hspread, vspread, mod);
} }
} }
/* /*
* Fires a single blaster bolt. Used by the blaster and hyper blaster. * Fires a single blaster bolt.
* Used by the blaster and hyper blaster.
*/ */
void void
blaster_touch(edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf) blaster_touch(edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf)
@ -359,7 +383,7 @@ blaster_touch(edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf)
int mod; int mod;
vec3_t normal; vec3_t normal;
if (!self || !other) if (!self || !other) /* plane and surf can be NULL */
{ {
G_FreeEdict(self); G_FreeEdict(self);
return; return;
@ -376,7 +400,7 @@ blaster_touch(edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf)
return; return;
} }
if (self->owner->client) if (self->owner && self->owner->client)
{ {
PlayerNoise(self->owner, self->s.origin, PNOISE_IMPACT); PlayerNoise(self->owner, self->s.origin, PNOISE_IMPACT);
} }
@ -439,6 +463,7 @@ fire_blaster(edict_t *self, vec3_t start, vec3_t dir, int damage,
bolt->clipmask = MASK_SHOT; bolt->clipmask = MASK_SHOT;
bolt->solid = SOLID_BBOX; bolt->solid = SOLID_BBOX;
bolt->s.effects |= effect; bolt->s.effects |= effect;
bolt->s.renderfx |= RF_NOSHADOW;
VectorClear(bolt->mins); VectorClear(bolt->mins);
VectorClear(bolt->maxs); VectorClear(bolt->maxs);
bolt->s.modelindex = gi.modelindex("models/objects/laser/tris.md2"); bolt->s.modelindex = gi.modelindex("models/objects/laser/tris.md2");
@ -532,7 +557,7 @@ Grenade_Explode(edict_t *ent)
return; return;
} }
if (ent->owner->client) if (ent->owner && ent->owner->client)
{ {
PlayerNoise(ent->owner, ent->s.origin, PNOISE_IMPACT); PlayerNoise(ent->owner, ent->s.origin, PNOISE_IMPACT);
} }
@ -610,9 +635,9 @@ Grenade_Explode(edict_t *ent)
} }
void void
Grenade_Touch(edict_t *ent, edict_t *other, cplane_t *plane, csurface_t *surf) Grenade_Touch(edict_t *ent, edict_t *other, cplane_t *plane /* unused */, csurface_t *surf)
{ {
if (!ent || !other) if (!ent || !other) /* plane is unused, surf can be NULL */
{ {
G_FreeEdict(ent); G_FreeEdict(ent);
return; return;
@ -635,19 +660,19 @@ Grenade_Touch(edict_t *ent, edict_t *other, cplane_t *plane, csurface_t *surf)
{ {
if (random() > 0.5) if (random() > 0.5)
{ {
gi.sound(ent, CHAN_VOICE, gi.soundindex("weapons/hgrenb1a.wav"), gi.sound(ent, CHAN_VOICE, gi.soundindex(
1, ATTN_NORM, 0); "weapons/hgrenb1a.wav"), 1, ATTN_NORM, 0);
} }
else else
{ {
gi.sound(ent, CHAN_VOICE, gi.soundindex("weapons/hgrenb2a.wav"), gi.sound(ent, CHAN_VOICE, gi.soundindex(
1, ATTN_NORM, 0); "weapons/hgrenb2a.wav"), 1, ATTN_NORM, 0);
} }
} }
else else
{ {
gi.sound(ent, CHAN_VOICE, gi.soundindex("weapons/grenlb1b.wav"), gi.sound(ent, CHAN_VOICE, gi.soundindex(
1, ATTN_NORM, 0); "weapons/grenlb1b.wav"), 1, ATTN_NORM, 0);
} }
return; return;
@ -658,8 +683,8 @@ Grenade_Touch(edict_t *ent, edict_t *other, cplane_t *plane, csurface_t *surf)
} }
void void
fire_grenade(edict_t *self, vec3_t start, vec3_t aimdir, int damage, fire_grenade(edict_t *self, vec3_t start, vec3_t aimdir, int damage, int speed,
int speed, float timer, float damage_radius) float timer, float damage_radius)
{ {
edict_t *grenade; edict_t *grenade;
vec3_t dir; vec3_t dir;
@ -751,8 +776,8 @@ fire_grenade2(edict_t *self, vec3_t start, vec3_t aimdir, int damage,
} }
else else
{ {
gi.sound(self, CHAN_WEAPON, gi.soundindex("weapons/hgrent1a.wav"), gi.sound(self, CHAN_WEAPON, gi.soundindex(
1, ATTN_NORM, 0); "weapons/hgrent1a.wav"), 1, ATTN_NORM, 0);
gi.linkentity(grenade); gi.linkentity(grenade);
} }
} }
@ -764,7 +789,7 @@ rocket_touch(edict_t *ent, edict_t *other, cplane_t *plane, csurface_t *surf)
vec3_t normal; vec3_t normal;
int n; int n;
if (!ent || !other) if (!ent || !other) /* plane and surf can be NULL */
{ {
G_FreeEdict(ent); G_FreeEdict(ent);
return; return;
@ -781,7 +806,7 @@ rocket_touch(edict_t *ent, edict_t *other, cplane_t *plane, csurface_t *surf)
return; return;
} }
if (ent->owner->client) if (ent->owner && ent->owner->client)
{ {
PlayerNoise(ent->owner, ent->s.origin, PNOISE_IMPACT); PlayerNoise(ent->owner, ent->s.origin, PNOISE_IMPACT);
} }
@ -804,7 +829,7 @@ rocket_touch(edict_t *ent, edict_t *other, cplane_t *plane, csurface_t *surf)
if ((surf) && !(surf->flags & if ((surf) && !(surf->flags &
(SURF_WARP | SURF_TRANS33 | SURF_TRANS66 | SURF_FLOWING))) (SURF_WARP | SURF_TRANS33 | SURF_TRANS66 | SURF_FLOWING)))
{ {
n = rand() % 5; n = randk() % 5;
while (n--) while (n--)
{ {
@ -815,8 +840,8 @@ rocket_touch(edict_t *ent, edict_t *other, cplane_t *plane, csurface_t *surf)
} }
} }
T_RadiusDamage(ent, ent->owner, ent->radius_dmg, other, T_RadiusDamage(ent, ent->owner, ent->radius_dmg, other, ent->dmg_radius,
ent->dmg_radius, MOD_R_SPLASH); MOD_R_SPLASH);
gi.WriteByte(svc_temp_entity); gi.WriteByte(svc_temp_entity);
@ -910,6 +935,7 @@ fire_rail(edict_t *self, vec3_t start, vec3_t aimdir, int damage, int kick)
{ {
/* -added so rail goes through SOLID_BBOX entities (gibs, etc) */ /* -added so rail goes through SOLID_BBOX entities (gibs, etc) */
if ((tr.ent->svflags & SVF_MONSTER) || (tr.ent->client) || if ((tr.ent->svflags & SVF_MONSTER) || (tr.ent->client) ||
(tr.ent->svflags & SVF_DAMAGEABLE) ||
(tr.ent->solid == SOLID_BBOX)) (tr.ent->solid == SOLID_BBOX))
{ {
ignore = tr.ent; ignore = tr.ent;
@ -1029,7 +1055,7 @@ bfg_touch(edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf)
{ {
vec3_t normal; vec3_t normal;
if (!self || !other) if (!self || !other) /* plane and surf can be NULL */
{ {
G_FreeEdict(self); G_FreeEdict(self);
return; return;
@ -1046,7 +1072,7 @@ bfg_touch(edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf)
return; return;
} }
if (self->owner->client) if (self->owner && self->owner->client)
{ {
PlayerNoise(self->owner, self->s.origin, PNOISE_IMPACT); PlayerNoise(self->owner, self->s.origin, PNOISE_IMPACT);
} }
@ -1062,11 +1088,21 @@ bfg_touch(edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf)
T_RadiusDamage(self, self->owner, 200, other, 100, MOD_BFG_BLAST); T_RadiusDamage(self, self->owner, 200, other, 100, MOD_BFG_BLAST);
gi.sound(self, CHAN_VOICE, gi.soundindex("weapons/bfg__x1b.wav"), 1, ATTN_NORM, 0); gi.sound(self, CHAN_VOICE, gi.soundindex(
"weapons/bfg__x1b.wav"), 1, ATTN_NORM, 0);
self->solid = SOLID_NOT; self->solid = SOLID_NOT;
self->touch = NULL; self->touch = NULL;
VectorMA(self->s.origin, -1 * FRAMETIME, self->velocity, self->s.origin);
/* move it back a bit from walls so the effects aren't cut off */
if (!other->takedamage)
{
VectorNormalize(self->velocity);
VectorMA(self->s.origin, -40.0f, self->velocity, self->s.origin);
}
VectorClear(self->velocity); VectorClear(self->velocity);
self->s.modelindex = gi.modelindex("sprites/s_bfg3.sp2"); self->s.modelindex = gi.modelindex("sprites/s_bfg3.sp2");
self->s.frame = 0; self->s.frame = 0;
self->s.sound = 0; self->s.sound = 0;
@ -1075,6 +1111,8 @@ bfg_touch(edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf)
self->nextthink = level.time + FRAMETIME; self->nextthink = level.time + FRAMETIME;
self->enemy = other; self->enemy = other;
gi.linkentity(self);
gi.WriteByte(svc_temp_entity); gi.WriteByte(svc_temp_entity);
gi.WriteByte(TE_BFG_BIGEXPLOSION); gi.WriteByte(TE_BFG_BIGEXPLOSION);
gi.WritePosition(self->s.origin); gi.WritePosition(self->s.origin);
@ -1126,8 +1164,8 @@ bfg_think(edict_t *self)
continue; continue;
} }
if (!(ent->svflags & SVF_MONSTER) && (!ent->client) && if (!(ent->svflags & SVF_MONSTER) && !(ent->svflags & SVF_DAMAGEABLE) &&
(strcmp(ent->classname, "misc_explobox") != 0)) (!ent->client) && (strcmp(ent->classname, "misc_explobox") != 0))
{ {
continue; continue;
} }
@ -1155,12 +1193,13 @@ bfg_think(edict_t *self)
if ((tr.ent->takedamage) && !(tr.ent->flags & FL_IMMUNE_LASER) && if ((tr.ent->takedamage) && !(tr.ent->flags & FL_IMMUNE_LASER) &&
(tr.ent != self->owner)) (tr.ent != self->owner))
{ {
T_Damage(tr.ent, self, self->owner, dir, tr.endpos, T_Damage(tr.ent, self, self->owner, dir, tr.endpos, vec3_origin,
vec3_origin, dmg, 1, DAMAGE_ENERGY, MOD_BFG_LASER); dmg, 1, DAMAGE_ENERGY, MOD_BFG_LASER);
} }
/* if we hit something that's not a monster or player we're done */ /* if we hit something that's not a monster or player we're done */
if (!(tr.ent->svflags & SVF_MONSTER) && (!tr.ent->client)) if (!(tr.ent->svflags & SVF_MONSTER) &&
!(tr.ent->svflags & SVF_DAMAGEABLE) && (!tr.ent->client))
{ {
gi.WriteByte(svc_temp_entity); gi.WriteByte(svc_temp_entity);
gi.WriteByte(TE_LASER_SPARKS); gi.WriteByte(TE_LASER_SPARKS);

View file

@ -1,8 +1,24 @@
/* /*
* Copyright (C) 1997-2001 Id Software, Inc.
* Copyright (c) ZeniMax Media Inc. * Copyright (c) ZeniMax Media Inc.
* Licensed under the GNU General Public License 2.0. *
*/ * 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.
*
* =======================================================================
* *
* Here are the client, server and game are tied together. * Here are the client, server and game are tied together.
* *
@ -27,6 +43,7 @@
#define SVF_NOCLIENT 0x00000001 /* don't send entity to clients, even if it has effects */ #define SVF_NOCLIENT 0x00000001 /* don't send entity to clients, even if it has effects */
#define SVF_DEADMONSTER 0x00000002 /* treat as CONTENTS_DEADMONSTER for collision */ #define SVF_DEADMONSTER 0x00000002 /* treat as CONTENTS_DEADMONSTER for collision */
#define SVF_MONSTER 0x00000004 /* treat as CONTENTS_MONSTER for collision */ #define SVF_MONSTER 0x00000004 /* treat as CONTENTS_MONSTER for collision */
#define SVF_DAMAGEABLE 0x00000008
#define MAX_ENT_CLUSTERS 16 #define MAX_ENT_CLUSTERS 16
@ -74,6 +91,8 @@ struct edict_s
int headnode; /* unused if num_clusters != -1 */ int headnode; /* unused if num_clusters != -1 */
int areanum, areanum2; int areanum, areanum2;
/* ================================ */
int svflags; /* SVF_NOCLIENT, SVF_DEADMONSTER, SVF_MONSTER, etc */ int svflags; /* SVF_NOCLIENT, SVF_DEADMONSTER, SVF_MONSTER, etc */
vec3_t mins, maxs; vec3_t mins, maxs;
vec3_t absmin, absmax, size; vec3_t absmin, absmax, size;
@ -93,10 +112,10 @@ struct edict_s
typedef struct typedef struct
{ {
/* special messages */ /* special messages */
void (*bprintf)(int printlevel, char *fmt, ...); void (*bprintf)(int printlevel, const char *fmt, ...);
void (*dprintf)(char *fmt, ...); void (*dprintf)(const char *fmt, ...);
void (*cprintf)(edict_t *ent, int printlevel, char *fmt, ...); void (*cprintf)(edict_t *ent, int printlevel, const char *fmt, ...);
void (*centerprintf)(edict_t *ent, char *fmt, ...); void (*centerprintf)(edict_t *ent, const char *fmt, ...);
void (*sound)(edict_t *ent, int channel, int soundindex, float volume, void (*sound)(edict_t *ent, int channel, int soundindex, float volume,
float attenuation, float timeofs); float attenuation, float timeofs);
void (*positioned_sound)(vec3_t origin, edict_t *ent, int channel, void (*positioned_sound)(vec3_t origin, edict_t *ent, int channel,
@ -106,17 +125,17 @@ typedef struct
and misc data like the sky definition and cdtrack. and misc data like the sky definition and cdtrack.
All of the current configstrings are sent to clients when All of the current configstrings are sent to clients when
they connect, and changes are sent to all connected clients. */ they connect, and changes are sent to all connected clients. */
void (*configstring)(int num, char *string); void (*configstring)(int num, const char *string);
void (*error)(char *fmt, ...); YQ2_ATTR_NORETURN_FUNCPTR void (*error)(const char *fmt, ...);
/* the *index functions create configstrings /* the *index functions create configstrings
and some internal server state */ and some internal server state */
int (*modelindex)(char *name); int (*modelindex)(const char *name);
int (*soundindex)(char *name); int (*soundindex)(const char *name);
int (*imageindex)(char *name); int (*imageindex)(const char *name);
void (*setmodel)(edict_t *ent, char *name); void (*setmodel)(edict_t *ent, const char *name);
/* collision detection */ /* collision detection */
trace_t (*trace)(vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end, trace_t (*trace)(vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end,
@ -144,7 +163,7 @@ typedef struct
void (*WriteShort)(int c); void (*WriteShort)(int c);
void (*WriteLong)(int c); void (*WriteLong)(int c);
void (*WriteFloat)(float f); void (*WriteFloat)(float f);
void (*WriteString)(char *s); void (*WriteString)(const char *s);
void (*WritePosition)(vec3_t pos); /* some fractional bits */ void (*WritePosition)(vec3_t pos); /* some fractional bits */
void (*WriteDir)(vec3_t pos); /* single byte encoded, very coarse */ void (*WriteDir)(vec3_t pos); /* single byte encoded, very coarse */
void (*WriteAngle)(float f); void (*WriteAngle)(float f);
@ -155,9 +174,9 @@ typedef struct
void (*FreeTags)(int tag); void (*FreeTags)(int tag);
/* console variable interaction */ /* console variable interaction */
cvar_t *(*cvar)(char *var_name, char *value, int flags); cvar_t *(*cvar)(const char *var_name, const char *value, int flags);
cvar_t *(*cvar_set)(char *var_name, char *value); cvar_t *(*cvar_set)(const char *var_name, const char *value);
cvar_t *(*cvar_forceset)(char *var_name, char *value); cvar_t *(*cvar_forceset)(const char *var_name, const char *value);
/* ClientCommand and ServerCommand parameter access */ /* ClientCommand and ServerCommand parameter access */
int (*argc)(void); int (*argc)(void);
@ -166,7 +185,7 @@ typedef struct
/* add commands to the server console as if /* add commands to the server console as if
they were typed in for map changing, etc */ they were typed in for map changing, etc */
void (*AddCommandString)(char *text); void (*AddCommandString)(const char *text);
void (*DebugGraph)(float value, int color); void (*DebugGraph)(float value, int color);
} game_import_t; } game_import_t;
@ -183,20 +202,20 @@ typedef struct
void (*Shutdown)(void); void (*Shutdown)(void);
/* each new level entered will cause a call to SpawnEntities */ /* each new level entered will cause a call to SpawnEntities */
void (*SpawnEntities)(char *mapname, char *entstring, char *spawnpoint); void (*SpawnEntities)(const char *mapname, char *entstring, const char *spawnpoint);
/* Read/Write Game is for storing persistant cross level information /* Read/Write Game is for storing persistant cross level information
about the world state and the clients. about the world state and the clients.
WriteGame is called every time a level is exited. WriteGame is called every time a level is exited.
ReadGame is called on a loadgame. */ ReadGame is called on a loadgame. */
void (*WriteGame)(char *filename, qboolean autosave); void (*WriteGame)(const char *filename, qboolean autosave);
void (*ReadGame)(char *filename); void (*ReadGame)(const char *filename);
/* ReadLevel is called after the default /* ReadLevel is called after the default
map information has been loaded with map information has been loaded with
SpawnEntities */ SpawnEntities */
void (*WriteLevel)(char *filename); void (*WriteLevel)(const char *filename);
void (*ReadLevel)(char *filename); void (*ReadLevel)(const char *filename);
qboolean (*ClientConnect)(edict_t *ent, char *userinfo); qboolean (*ClientConnect)(edict_t *ent, char *userinfo);
void (*ClientBegin)(edict_t *ent); void (*ClientBegin)(edict_t *ent);

View file

@ -1,8 +1,24 @@
/* /*
* Copyright (C) 1997-2001 Id Software, Inc.
* Copyright (c) ZeniMax Media Inc. * Copyright (c) ZeniMax Media Inc.
* Licensed under the GNU General Public License 2.0. *
*/ * 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.
*
* =======================================================================
* *
* Main header file for the game module. * Main header file for the game module.
* *
@ -14,16 +30,16 @@
#include "shared.h" #include "shared.h"
/* define GAME_INCLUDE so that game.h does not define the /* define GAME_INCLUDE so that game.h does not define the
short, server-visible gclient_t and edict_t structures, short, server-visible gclient_t and edict_t structures,
because we define the full size ones in this file */ because we define the full size ones in this file */
#define GAME_INCLUDE #define GAME_INCLUDE
#include "game.h" #include "game.h"
/* the "gameversion" client command will print this plus compile date */ /* the "gameversion" client command will print this plus compile date */
#define GAMEVERSION "xatrix" #define GAMEVERSION "xatrix"
/* protocol bytes that can be directly added to messages */ /* protocol bytes that can be directly added to messages */
#define svc_muzzleflash 1 #define svc_muzzleflash 1
#define svc_muzzleflash2 2 #define svc_muzzleflash2 2
#define svc_temp_entity 3 #define svc_temp_entity 3
@ -31,19 +47,20 @@
#define svc_inventory 5 #define svc_inventory 5
#define svc_stufftext 11 #define svc_stufftext 11
/* ================================================================== */ /* ================================================================== */
/* view pitching times */ /* view pitching times */
#define DAMAGE_TIME 0.5 #define DAMAGE_TIME 0.5
#define FALL_TIME 0.3 #define FALL_TIME 0.3
/* these are set with checkboxes on each entity in the map editor */ /* these are set with checkboxes on each entity in the map editor */
#define SPAWNFLAG_NOT_EASY 0x00000100 #define SPAWNFLAG_NOT_EASY 0x00000100
#define SPAWNFLAG_NOT_MEDIUM 0x00000200 #define SPAWNFLAG_NOT_MEDIUM 0x00000200
#define SPAWNFLAG_NOT_HARD 0x00000400 #define SPAWNFLAG_NOT_HARD 0x00000400
#define SPAWNFLAG_NOT_DEATHMATCH 0x00000800 #define SPAWNFLAG_NOT_DEATHMATCH 0x00000800
#define SPAWNFLAG_NOT_COOP 0x00001000 #define SPAWNFLAG_NOT_COOP 0x00001000
/* edict->flags */
#define FL_FLY 0x00000001 #define FL_FLY 0x00000001
#define FL_SWIM 0x00000002 /* implied immunity to drowining */ #define FL_SWIM 0x00000002 /* implied immunity to drowining */
#define FL_IMMUNE_LASER 0x00000004 #define FL_IMMUNE_LASER 0x00000004
@ -60,14 +77,18 @@
#define FL_COOP_TAKEN 0x00002000 /* Another client has already taken it */ #define FL_COOP_TAKEN 0x00002000 /* Another client has already taken it */
#define FL_RESPAWN 0x80000000 /* used for item respawning */ #define FL_RESPAWN 0x80000000 /* used for item respawning */
#define FL_MECHANICAL 0x00002000 /* entity is mechanical, use sparks not blood */
#define FL_SAM_RAIMI 0x00004000 /* entity is in sam raimi cam mode */
#define FL_DISGUISED 0x00008000 /* entity is in disguise, monsters will not recognize. */
#define FL_NOGIB 0x00010000 /* player has been vaporized by a nuke, drop no gibs */
#define FRAMETIME 0.1 #define FRAMETIME 0.1
/* memory tags to allow dynamic memory to be cleaned up */ /* memory tags to allow dynamic memory to be cleaned up */
#define TAG_GAME 765 /* clear when unloading the dll */ #define TAG_GAME 765 /* clear when unloading the dll */
#define TAG_LEVEL 766 /* clear when loading a new level */ #define TAG_LEVEL 766 /* clear when loading a new level */
#define MELEE_DISTANCE 80 #define MELEE_DISTANCE 80
#define BODY_QUEUE_SIZE 8 #define BODY_QUEUE_SIZE 8
typedef enum typedef enum
@ -93,8 +114,11 @@ typedef enum
AMMO_GRENADES, AMMO_GRENADES,
AMMO_CELLS, AMMO_CELLS,
AMMO_SLUGS, AMMO_SLUGS,
AMMO_MAGSLUG,
AMMO_TRAP AMMO_FLECHETTES,
AMMO_TESLA,
AMMO_PROX,
AMMO_DISRUPTOR
} ammo_t; } ammo_t;
/* Maximum debris / gibs per frame */ /* Maximum debris / gibs per frame */
@ -135,11 +159,27 @@ typedef enum
#define AI_RESURRECTING 0x00004000 #define AI_RESURRECTING 0x00004000
#define AI_IGNORE_PAIN 0x00008000 #define AI_IGNORE_PAIN 0x00008000
/* ROGUE */
#define AI_WALK_WALLS 0x00008000
#define AI_MANUAL_STEERING 0x00010000
#define AI_TARGET_ANGER 0x00020000
#define AI_DODGING 0x00040000
#define AI_CHARGING 0x00080000
#define AI_HINT_PATH 0x00100000
#define AI_IGNORE_SHOTS 0x00200000
#define AI_DO_NOT_COUNT 0x00400000 /* set for healed monsters */
#define AI_SPAWNED_CARRIER 0x00800000 /* both do_not_count and spawned are set for spawned monsters */
#define AI_SPAWNED_MEDIC_C 0x01000000 /* both do_not_count and spawned are set for spawned monsters */
#define AI_SPAWNED_WIDOW 0x02000000 /* both do_not_count and spawned are set for spawned monsters */
#define AI_SPAWNED_MASK 0x03800000 /* mask to catch all three flavors of spawned */
#define AI_BLOCKED 0x04000000 /* used by blocked_checkattack: set to say I'm attacking while blocked */
/* (prevents run-attacks) */
/* monster attack state */ /* monster attack state */
#define AS_STRAIGHT 1 #define AS_STRAIGHT 1
#define AS_SLIDING 2 #define AS_SLIDING 2
#define AS_MELEE 3 #define AS_MELEE 3
#define AS_MISSILE 4 #define AS_MISSILE 4
#define AS_BLIND 5
/* armor types */ /* armor types */
#define ARMOR_NONE 0 #define ARMOR_NONE 0
@ -188,7 +228,8 @@ typedef enum
MOVETYPE_TOSS, /* gravity */ MOVETYPE_TOSS, /* gravity */
MOVETYPE_FLYMISSILE, /* extra size to monsters */ MOVETYPE_FLYMISSILE, /* extra size to monsters */
MOVETYPE_BOUNCE, /* added this (the comma at the end of line) */ MOVETYPE_BOUNCE, /* added this (the comma at the end of line) */
MOVETYPE_WALLBOUNCE MOVETYPE_WALLBOUNCE,
MOVETYPE_NEWTOSS /* for deathball */
} movetype_t; } movetype_t;
typedef struct typedef struct
@ -201,13 +242,15 @@ typedef struct
} gitem_armor_t; } gitem_armor_t;
/* gitem_t->flags */ /* gitem_t->flags */
#define IT_WEAPON 1 /* use makes active weapon */ #define IT_WEAPON 0x00000001 /* use makes active weapon */
#define IT_AMMO 2 #define IT_AMMO 0x00000002
#define IT_ARMOR 4 #define IT_ARMOR 0x00000004
#define IT_STAY_COOP 8 #define IT_STAY_COOP 0x00000008
#define IT_KEY 16 #define IT_KEY 0x00000010
#define IT_POWERUP 32 #define IT_POWERUP 0x00000020
#define IT_INSTANT_USE 64 /* item is insta-used on pickup if dmflag is set */ #define IT_MELEE 0x00000040
#define IT_NOT_GIVEABLE 0x00000080 /* item can not be given */
#define IT_INSTANT_USE 0x000000100 /* item is insta-used on pickup if dmflag is set */
/* gitem_t->weapmodel for weapons indicates model index */ /* gitem_t->weapmodel for weapons indicates model index */
#define WEAP_BLASTER 1 #define WEAP_BLASTER 1
@ -223,6 +266,11 @@ typedef struct
#define WEAP_BFG 11 #define WEAP_BFG 11
#define WEAP_PHALANX 12 #define WEAP_PHALANX 12
#define WEAP_BOOMER 13 #define WEAP_BOOMER 13
#define WEAP_DISRUPTOR 14
#define WEAP_ETFRIFLE 15
#define WEAP_PLASMA 16
#define WEAP_PROXLAUNCH 17
#define WEAP_CHAINFIST 18
typedef struct gitem_s typedef struct gitem_s
{ {
@ -260,13 +308,14 @@ typedef struct
{ {
char helpmessage1[512]; char helpmessage1[512];
char helpmessage2[512]; char helpmessage2[512];
int helpchanged; /* flash F1 icon if non 0, play sound int helpchanged; /* flash F1 icon if non 0, play sound */
and increment only if 1, 2, or 3 */ /* and increment only if 1, 2, or 3 */
gclient_t *clients; /* [maxclients] */ gclient_t *clients; /* [maxclients] */
/* can't store spawnpoint in level, because /* can't store spawnpoint in level, because
it would get overwritten by the savegame restore */ it would get overwritten by the savegame
restore */
char spawnpoint[512]; /* needed for coop respawns */ char spawnpoint[512]; /* needed for coop respawns */
/* store latched cvars here that we want to get at often */ /* store latched cvars here that we want to get at often */
@ -324,16 +373,20 @@ typedef struct
int body_que; /* dead bodies */ int body_que; /* dead bodies */
int power_cubes; /* ugly necessity for coop */ int power_cubes; /* ugly necessity for coop */
edict_t *disguise_violator;
int disguise_violation_framenum;
} level_locals_t; } level_locals_t;
/* spawn_temp_t is only used to hold entity field values that /* spawn_temp_t is only used to hold entity field values that
can be set from the editor, but aren't actualy present can be set from the editor, but aren't actualy present/
in edict_t during gameplay */ in edict_t during gameplay */
typedef struct typedef struct
{ {
/* world vars */ /* world vars */
char *sky; char *sky;
float skyrotate; float skyrotate;
int skyautorotate;
vec3_t skyaxis; vec3_t skyaxis;
char *nextmap; char *nextmap;
@ -399,7 +452,7 @@ typedef struct
typedef struct typedef struct
{ {
mmove_t *currentmove; mmove_t *currentmove;
int aiflags; unsigned int aiflags; /* unsigned, since we're close to the max */
int nextframe; int nextframe;
float scale; float scale;
@ -428,8 +481,40 @@ typedef struct
int power_armor_type; int power_armor_type;
int power_armor_power; int power_armor_power;
qboolean (*blocked)(edict_t *self, float dist);
float last_hint_time; /* last time the monster checked for hintpaths. */
edict_t *goal_hint; /* which hint_path we're trying to get to */
int medicTries;
edict_t *badMedic1, *badMedic2; /* these medics have declared this monster "unhealable" */
edict_t *healer; /* this is who is healing this monster */
void (*duck)(edict_t *self, float eta);
void (*unduck)(edict_t *self);
void (*sidestep)(edict_t *self);
float base_height;
float next_duck_time;
float duck_wait_time;
edict_t *last_player_enemy;
qboolean blindfire; /* will the monster blindfire? */
float blind_fire_delay;
vec3_t blind_fire_target;
/* used by the spawners to not spawn too much and keep track of #s of monsters spawned */
int monster_slots;
int monster_used;
edict_t *commander;
/* powerup timers, used by widow, our friend */
float quad_framenum;
float invincible_framenum;
float double_framenum;
} monsterinfo_t; } monsterinfo_t;
/* this determines how long to wait after a duck to duck again.
this needs to be longer than the time after the monster_duck_up
in all of the animation sequences */
#define DUCK_INTERVAL 0.5
extern game_locals_t game; extern game_locals_t game;
extern level_locals_t level; extern level_locals_t level;
extern game_import_t gi; extern game_import_t gi;
@ -484,6 +569,22 @@ extern int gibsthisframe;
#define MOD_GEKK 38 #define MOD_GEKK 38
#define MOD_TRAP 39 #define MOD_TRAP 39
#define MOD_FRIENDLY_FIRE 0x8000000 #define MOD_FRIENDLY_FIRE 0x8000000
#define MOD_CHAINFIST 40
#define MOD_DISINTEGRATOR 41
#define MOD_ETF_RIFLE 42
#define MOD_BLASTER2 43
#define MOD_HEATBEAM 44
#define MOD_TESLA 45
#define MOD_PROX 46
#define MOD_NUKE 47
#define MOD_VENGEANCE_SPHERE 48
#define MOD_HUNTER_SPHERE 49
#define MOD_DEFENDER_SPHERE 50
#define MOD_TRACKER 51
#define MOD_DBALL_CRUSH 52
#define MOD_DOPPLE_EXPLODE 53
#define MOD_DOPPLE_VENGEANCE 54
#define MOD_DOPPLE_HUNTER 55
/* Easier handling of AI skill levels */ /* Easier handling of AI skill levels */
#define SKILL_EASY 0 #define SKILL_EASY 0
@ -505,6 +606,8 @@ extern edict_t *g_edicts;
extern cvar_t *maxentities; extern cvar_t *maxentities;
extern cvar_t *deathmatch; extern cvar_t *deathmatch;
extern cvar_t *coop; extern cvar_t *coop;
extern cvar_t *coop_baseq2; /* treat spawnflags according to baseq2 rules */
extern cvar_t *coop_pickup_weapons;
extern cvar_t *coop_elevator_delay; extern cvar_t *coop_elevator_delay;
extern cvar_t *coop_pickup_weapons; extern cvar_t *coop_pickup_weapons;
extern cvar_t *dmflags; extern cvar_t *dmflags;
@ -517,7 +620,9 @@ extern cvar_t *needpass;
extern cvar_t *g_select_empty; extern cvar_t *g_select_empty;
extern cvar_t *dedicated; extern cvar_t *dedicated;
extern cvar_t *g_footsteps; extern cvar_t *g_footsteps;
extern cvar_t *g_monsterfootsteps;
extern cvar_t *g_fix_triggered; extern cvar_t *g_fix_triggered;
extern cvar_t *g_commanderbody_nogod;
extern cvar_t *filterban; extern cvar_t *filterban;
@ -544,23 +649,41 @@ extern cvar_t *flood_waitdelay;
extern cvar_t *sv_maplist; extern cvar_t *sv_maplist;
extern cvar_t *sv_stopspeed;
extern cvar_t *g_showlogic;
extern cvar_t *gamerules;
extern cvar_t *huntercam;
extern cvar_t *strong_mines;
extern cvar_t *randomrespawn;
extern cvar_t *g_disruptor;
extern cvar_t *aimfix; extern cvar_t *aimfix;
extern cvar_t *g_machinegun_norecoil; extern cvar_t *g_machinegun_norecoil;
extern cvar_t *g_swap_speed;
/* this is for the count of monsters */
#define ENT_SLOTS_LEFT \
(ent->monsterinfo.monster_slots - \
ent->monsterinfo.monster_used)
#define SELF_SLOTS_LEFT \
(self->monsterinfo.monster_slots - \
self->monsterinfo.monster_used)
#define world (&g_edicts[0]) #define world (&g_edicts[0])
/* item spawnflags */ /* item spawnflags */
#define ITEM_TRIGGER_SPAWN 0x00000001 #define ITEM_TRIGGER_SPAWN 0x00000001
#define ITEM_NO_TOUCH 0x00000002 #define ITEM_NO_TOUCH 0x00000002
/* 6 bits reserved for editor flags /* 6 bits reserved for editor flags */
8 bits used as power cube id bits /* 8 bits used as power cube id bits for coop games */
for coop games */
#define DROPPED_ITEM 0x00010000 #define DROPPED_ITEM 0x00010000
#define DROPPED_PLAYER_ITEM 0x00020000 #define DROPPED_PLAYER_ITEM 0x00020000
#define ITEM_TARGETS_USED 0x00040000 #define ITEM_TARGETS_USED 0x00040000
/* fields are needed for spawning from the /* fields are needed for spawning from the entity
entity string and saving / loading games */ string and saving / loading games */
#define FFL_SPAWNTEMP 1 #define FFL_SPAWNTEMP 1
#define FFL_NOSPAWN 2 #define FFL_NOSPAWN 2
@ -592,8 +715,16 @@ typedef struct
extern field_t fields[]; extern field_t fields[];
extern gitem_t itemlist[]; extern gitem_t itemlist[];
/* player/client.c */
void ClientBegin(edict_t *ent);
void ClientDisconnect(edict_t *ent);
void ClientUserinfoChanged(edict_t *ent, char *userinfo);
qboolean ClientConnect(edict_t *ent, char *userinfo);
void ClientThink(edict_t *ent, usercmd_t *cmd);
/* g_cmds.c */ /* g_cmds.c */
void Cmd_Help_f(edict_t *ent); void Cmd_Help_f(edict_t *ent);
void ClientCommand(edict_t *ent);
/* g_items.c */ /* g_items.c */
void PrecacheItem(gitem_t *it); void PrecacheItem(gitem_t *it);
@ -603,6 +734,7 @@ gitem_t *FindItem(char *pickup_name);
gitem_t *FindItemByClassname(char *classname); gitem_t *FindItemByClassname(char *classname);
#define ITEM_INDEX(x) ((x) - itemlist) #define ITEM_INDEX(x) ((x) - itemlist)
edict_t *Drop_Item(edict_t *ent, gitem_t *item); edict_t *Drop_Item(edict_t *ent, gitem_t *item);
void SetRespawn(edict_t *ent, float delay); void SetRespawn(edict_t *ent, float delay);
void ChangeWeapon(edict_t *ent); void ChangeWeapon(edict_t *ent);
@ -612,7 +744,8 @@ int ArmorIndex(edict_t *ent);
int PowerArmorType(edict_t *ent); int PowerArmorType(edict_t *ent);
gitem_t *GetItemByIndex(int index); gitem_t *GetItemByIndex(int index);
qboolean Add_Ammo(edict_t *ent, gitem_t *item, int count); qboolean Add_Ammo(edict_t *ent, gitem_t *item, int count);
void Touch_Item(edict_t *ent, edict_t *other, cplane_t *plane, csurface_t *surf); void Touch_Item(edict_t *ent, edict_t *other, cplane_t *plane,
csurface_t *surf);
/* g_utils.c */ /* g_utils.c */
qboolean KillBox(edict_t *ent); qboolean KillBox(edict_t *ent);
@ -641,14 +774,29 @@ void get_normal_vector(const cplane_t *p, vec3_t normal);
float vectoyaw(vec3_t vec); float vectoyaw(vec3_t vec);
void vectoangles(vec3_t vec, vec3_t angles); void vectoangles(vec3_t vec, vec3_t angles);
void G_ProjectSource2(vec3_t point, vec3_t distance, vec3_t forward, vec3_t right,
vec3_t up, vec3_t result);
float vectoyaw2(vec3_t vec);
void vectoangles2(vec3_t vec, vec3_t angles);
edict_t *findradius2(edict_t *from, vec3_t org, float rad);
/* g_spawn.c */
void ED_CallSpawn(edict_t *ent);
/* g_combat.c */ /* g_combat.c */
qboolean OnSameTeam(edict_t *ent1, edict_t *ent2); qboolean OnSameTeam(edict_t *ent1, edict_t *ent2);
qboolean CanDamage(edict_t *targ, edict_t *inflictor); qboolean CanDamage(edict_t *targ, edict_t *inflictor);
void T_Damage(edict_t *targ, edict_t *inflictor, edict_t *attacker, void T_Damage(edict_t *targ, edict_t *inflictor, edict_t *attacker,
vec3_t dir, vec3_t point, vec3_t normal, int damage, vec3_t dir, vec3_t point, vec3_t normal, int damage,
int knockback, int dflags, int mod); int knockback, int dflags, int mod);
void T_RadiusDamage(edict_t *inflictor, edict_t *attacker, float damage, void T_RadiusDamage(edict_t *inflictor, edict_t *attacker,
float damage, edict_t *ignore, float radius,
int mod);
void T_RadiusNukeDamage(edict_t *inflictor, edict_t *attacker, float damage,
edict_t *ignore, float radius, int mod); edict_t *ignore, float radius, int mod);
void T_RadiusClassDamage(edict_t *inflictor, edict_t *attacker, float damage,
char *ignoreClass, float radius, int mod);
void cleanupHealTarget(edict_t *ent);
/* damage flags */ /* damage flags */
#define DAMAGE_RADIUS 0x00000001 /* damage was indirect */ #define DAMAGE_RADIUS 0x00000001 /* damage was indirect */
@ -657,33 +805,37 @@ void T_RadiusDamage(edict_t *inflictor, edict_t *attacker, float damage,
#define DAMAGE_NO_KNOCKBACK 0x00000008 /* do not affect velocity, just view angles */ #define DAMAGE_NO_KNOCKBACK 0x00000008 /* do not affect velocity, just view angles */
#define DAMAGE_BULLET 0x00000010 /* damage is from a bullet (used for ricochets) */ #define DAMAGE_BULLET 0x00000010 /* damage is from a bullet (used for ricochets) */
#define DAMAGE_NO_PROTECTION 0x00000020 /* armor, shields, invulnerability, and godmode have no effect */ #define DAMAGE_NO_PROTECTION 0x00000020 /* armor, shields, invulnerability, and godmode have no effect */
#define DAMAGE_DESTROY_ARMOR 0x00000040 /* damage is done to armor and health. */
#define DAMAGE_NO_REG_ARMOR 0x00000080 /* damage skips regular armor */
#define DAMAGE_NO_POWER_ARMOR 0x00000100 /* damage skips power armor */
#define DEFAULT_BULLET_HSPREAD 300 #define DEFAULT_BULLET_HSPREAD 300
#define DEFAULT_BULLET_VSPREAD 500 #define DEFAULT_BULLET_VSPREAD 500
#define DEFAULT_SHOTGUN_HSPREAD 1000 #define DEFAULT_SHOTGUN_HSPREAD 1000
#define DEFAULT_SHOTGUN_VSPREAD 500 #define DEFAULT_SHOTGUN_VSPREAD 500
#define DEFAULT_DEATHMATCH_SHOTGUN_COUNT 12
#define DEFAULT_SHOTGUN_COUNT 12 #define DEFAULT_SHOTGUN_COUNT 12
#define DEFAULT_SSHOTGUN_COUNT 20 #define DEFAULT_SSHOTGUN_COUNT 20
/* g_monster.c */ /* g_monster.c */
void monster_fire_bullet(edict_t *self, vec3_t start, vec3_t dir, int damage, void monster_fire_bullet(edict_t *self, vec3_t start, vec3_t dir, int damage,
int kick, int hspread, int vspread, int flashtype); int kick, int hspread, int vspread, int flashtype);
void monster_fire_shotgun(edict_t *self, vec3_t start, vec3_t aimdir, int damage, void monster_fire_shotgun(edict_t *self, vec3_t start, vec3_t aimdir,
int kick, int hspread, int vspread, int count, int flashtype); int damage, int kick, int hspread, int vspread, int count,
void monster_fire_blaster(edict_t *self, vec3_t start, vec3_t dir, int damage, int flashtype);
int speed, int flashtype, int effect); void monster_fire_blaster(edict_t *self, vec3_t start, vec3_t dir,
void monster_fire_grenade(edict_t *self, vec3_t start, vec3_t aimdir, int damage, int damage, int speed, int flashtype, int effect);
int speed, int flashtype); void monster_fire_grenade(edict_t *self, vec3_t start, vec3_t aimdir,
void monster_fire_rocket(edict_t *self, vec3_t start, vec3_t dir, int damage, int damage, int speed, int flashtype);
int speed, int flashtype); void monster_fire_rocket(edict_t *self, vec3_t start, vec3_t dir,
void monster_fire_railgun(edict_t *self, vec3_t start, vec3_t aimdir, int damage, int damage, int speed, int flashtype);
int kick, int flashtype); void monster_fire_railgun(edict_t *self, vec3_t start, vec3_t aimdir,
void monster_fire_bfg(edict_t *self, vec3_t start, vec3_t aimdir, int damage, int damage, int kick, int flashtype);
int speed, int kick, float damage_radius, int flashtype); void monster_fire_bfg(edict_t *self, vec3_t start, vec3_t aimdir,
int damage, int speed, int kick, float damage_radius,
int flashtype);
void monster_fire_ionripper(edict_t *self, vec3_t start, vec3_t dir, int damage, void monster_fire_ionripper(edict_t *self, vec3_t start, vec3_t dir, int damage,
int speed, int flashtype, int effect); int speed, int flashtype, int effect);
void monster_fire_heat(edict_t *self, vec3_t start, vec3_t dir, int damage,
int speed, int flashtype);
void monster_dabeam(edict_t *self); void monster_dabeam(edict_t *self);
void monster_fire_blueblaster(edict_t *self, vec3_t start, vec3_t dir, int damage, void monster_fire_blueblaster(edict_t *self, vec3_t start, vec3_t dir, int damage,
int speed, int flashtype, int effect); int speed, int flashtype, int effect);
@ -700,6 +852,13 @@ qboolean M_CheckAttack(edict_t *self);
void M_FlyCheck(edict_t *self); void M_FlyCheck(edict_t *self);
void M_CheckGround(edict_t *ent); void M_CheckGround(edict_t *ent);
void monster_fire_blaster2(edict_t *self, vec3_t start, vec3_t dir, int damage,
int speed, int flashtype, int effect);
void monster_fire_tracker(edict_t *self, vec3_t start, vec3_t dir, int damage,
int speed, edict_t *enemy, int flashtype);
void stationarymonster_start(edict_t *self);
void monster_done_dodge(edict_t *self);
/* g_misc.c */ /* g_misc.c */
void ThrowHead(edict_t *self, char *gibname, int damage, int type); void ThrowHead(edict_t *self, char *gibname, int damage, int type);
void ThrowClientHead(edict_t *self, int damage); void ThrowClientHead(edict_t *self, int damage);
@ -710,6 +869,7 @@ void ThrowGibACID(edict_t *self, char *gibname, int damage, int type);
/* g_ai.c */ /* g_ai.c */
void AI_SetSightClient(void); void AI_SetSightClient(void);
void ai_stand(edict_t *self, float dist); void ai_stand(edict_t *self, float dist);
void ai_move(edict_t *self, float dist); void ai_move(edict_t *self, float dist);
void ai_walk(edict_t *self, float dist); void ai_walk(edict_t *self, float dist);
@ -744,8 +904,6 @@ void fire_bfg(edict_t *self, vec3_t start, vec3_t dir, int damage,
int speed, float damage_radius); int speed, float damage_radius);
void fire_ionripper(edict_t *self, vec3_t start, vec3_t aimdir, int damage, void fire_ionripper(edict_t *self, vec3_t start, vec3_t aimdir, int damage,
int speed, int effect); int speed, int effect);
void fire_heat(edict_t *self, vec3_t start, vec3_t dir, int damage, int speed,
float damage_radius, int radius_damage);
void fire_blueblaster(edict_t *self, vec3_t start, vec3_t aimdir, int damage, void fire_blueblaster(edict_t *self, vec3_t start, vec3_t aimdir, int damage,
int speed, int effect); int speed, int effect);
void fire_plasma(edict_t *self, vec3_t start, vec3_t dir, int damage, int speed, void fire_plasma(edict_t *self, vec3_t start, vec3_t dir, int damage, int speed,
@ -770,7 +928,7 @@ void InitClientResp(gclient_t *client);
void InitBodyQue(void); void InitBodyQue(void);
void ClientBeginServerFrame(edict_t *ent); void ClientBeginServerFrame(edict_t *ent);
/* g_player.c */ /* g_player.c */
void player_pain(edict_t *self, edict_t *other, float kick, int damage); void player_pain(edict_t *self, edict_t *other, float kick, int damage);
void player_die(edict_t *self, edict_t *inflictor, edict_t *attacker, void player_die(edict_t *self, edict_t *inflictor, edict_t *attacker,
int damage, vec3_t point); int damage, vec3_t point);
@ -814,7 +972,96 @@ void ChaseNext(edict_t *ent);
void ChasePrev(edict_t *ent); void ChasePrev(edict_t *ent);
void GetChaseTarget(edict_t *ent); void GetChaseTarget(edict_t *ent);
/* ============================================================================ */ /* savegame */
void InitGame(void);
void ReadLevel(const char *filename);
void WriteLevel(const char *filename);
void ReadGame(const char *filename);
void WriteGame(const char *filename, qboolean autosave);
void SpawnEntities(const char *mapname, char *entities, const char *spawnpoint);
void fire_flechette(edict_t *self, vec3_t start, vec3_t dir, int damage,
int speed, int kick);
void fire_prox(edict_t *self, vec3_t start, vec3_t aimdir, int damage,
int speed);
void fire_nuke(edict_t *self, vec3_t start, vec3_t aimdir, int speed);
void fire_flame(edict_t *self, vec3_t start, vec3_t aimdir, int damage,
int speed);
void fire_burst(edict_t *self, vec3_t start, vec3_t aimdir, int damage,
int speed);
void fire_maintain(edict_t *, edict_t *, vec3_t start, vec3_t aimdir,
int damage, int speed);
void fire_incendiary_grenade(edict_t *self, vec3_t start, vec3_t aimdir,
int damage, int speed, float timer, float damage_radius);
void fire_player_melee(edict_t *self, vec3_t start, vec3_t aim, int reach,
int damage, int kick, int quiet, int mod);
void fire_tesla(edict_t *self, vec3_t start, vec3_t aimdir, int damage,
int speed);
void fire_blaster2(edict_t *self, vec3_t start, vec3_t aimdir, int damage,
int speed, int effect, qboolean hyper);
void fire_tracker(edict_t *self, vec3_t start, vec3_t dir, int damage,
int speed, edict_t *enemy);
/* g_newai.c */
qboolean blocked_checkplat(edict_t *self, float dist);
qboolean blocked_checkjump(edict_t *self, float dist, float maxDown, float maxUp);
qboolean blocked_checknewenemy(edict_t *self);
qboolean monsterlost_checkhint(edict_t *self);
qboolean inback(edict_t *self, edict_t *other);
float realrange(edict_t *self, edict_t *other);
edict_t *SpawnBadArea(vec3_t mins, vec3_t maxs, float lifespan, edict_t *owner);
edict_t *CheckForBadArea(edict_t *ent);
qboolean MarkTeslaArea(edict_t *self, edict_t *tesla);
void InitHintPaths(void);
void PredictAim(edict_t *target, vec3_t start, float bolt_speed, qboolean eye_height,
float offset, vec3_t aimdir, vec3_t aimpoint);
qboolean below(edict_t *self, edict_t *other);
void drawbbox(edict_t *self);
void M_MonsterDodge(edict_t *self, edict_t *attacker, float eta, trace_t *tr);
void monster_duck_down(edict_t *self);
void monster_duck_hold(edict_t *self);
void monster_duck_up(edict_t *self);
qboolean has_valid_enemy(edict_t *self);
void TargetTesla(edict_t *self, edict_t *tesla);
void hintpath_stop(edict_t *self);
edict_t *PickCoopTarget(edict_t *self);
int CountPlayers(void);
void monster_jump_start(edict_t *self);
qboolean monster_jump_finished(edict_t *self);
/* g_sphere.c */
void Defender_Launch(edict_t *self);
void Vengeance_Launch(edict_t *self);
void Hunter_Launch(edict_t *self);
/* g_newdm.c */
void InitGameRules(void);
edict_t *DoRandomRespawn(edict_t *ent);
void PrecacheForRandomRespawn(void);
qboolean Tag_PickupToken(edict_t *ent, edict_t *other);
void Tag_DropToken(edict_t *ent, gitem_t *item);
void Tag_PlayerDeath(edict_t *targ, edict_t *inflictor, edict_t *attacker);
void fire_doppleganger(edict_t *ent, vec3_t start, vec3_t aimdir);
/* g_spawn.c */
edict_t *CreateMonster(vec3_t origin, vec3_t angles, char *classname);
edict_t *CreateFlyMonster(vec3_t origin, vec3_t angles, vec3_t mins,
vec3_t maxs, char *classname);
edict_t *CreateGroundMonster(vec3_t origin, vec3_t angles, vec3_t mins,
vec3_t maxs, char *classname, int height);
qboolean FindSpawnPoint(vec3_t startpoint, vec3_t mins, vec3_t maxs,
vec3_t spawnpoint, float maxMoveUp);
qboolean CheckSpawnPoint(vec3_t origin, vec3_t mins, vec3_t maxs);
qboolean CheckGroundSpawnPoint(vec3_t origin, vec3_t entMins, vec3_t entMaxs,
float height, float gravity);
void DetermineBBox(char *classname, vec3_t mins, vec3_t maxs);
void SpawnGrow_Spawn(vec3_t startpos, int size);
void Widowlegs_Spawn(vec3_t startpos, vec3_t angles);
/* p_client.c */
void RemoveAttackingPainDaemons(edict_t *self);
/* ============================================================================ */
/* client_t->anim_priority */ /* client_t->anim_priority */
#define ANIM_BASIC 0 /* stand / run */ #define ANIM_BASIC 0 /* stand / run */
@ -864,6 +1111,12 @@ typedef struct
int helpchanged; int helpchanged;
qboolean spectator; /* client is a spectator */ qboolean spectator; /* client is a spectator */
int max_tesla;
int max_prox;
int max_mines;
int max_flechettes;
int max_rounds;
} client_persistant_t; } client_persistant_t;
/* client data that stays across deathmatch respawns */ /* client data that stays across deathmatch respawns */
@ -878,8 +1131,7 @@ typedef struct
} client_respawn_t; } client_respawn_t;
/* this structure is cleared on each /* this structure is cleared on each
PutClientInServer(), except for PutClientInServer(), except for 'client->pers' */
'client->pers' */
struct gclient_s struct gclient_s
{ {
/* known to server */ /* known to server */
@ -966,16 +1218,21 @@ struct gclient_s
edict_t *chase_target; /* player we are chasing */ edict_t *chase_target; /* player we are chasing */
qboolean update_chase; /* need to update chase info? */ qboolean update_chase; /* need to update chase info? */
float double_framenum;
float ir_framenum;
float nuke_framenum;
float tracker_pain_framenum;
edict_t *owned_sphere; /* this points to the player's sphere */
}; };
struct edict_s struct edict_s
{ {
entity_state_t s; entity_state_t s;
struct gclient_s *client; /* NULL if not a player */ struct gclient_s *client; /* NULL if not a player the server expects the first part
of gclient_s to be a player_state_t but the rest of it is
/* the server expects the first part opaque */
of gclient_s to be a player_state_t
but the rest of it is opaque */
qboolean inuse; qboolean inuse;
int linkcount; int linkcount;
@ -996,8 +1253,8 @@ struct edict_s
int clipmask; int clipmask;
edict_t *owner; edict_t *owner;
/* DO NOT MODIFY ANYTHING ABOVE THIS, THE /* DO NOT MODIFY ANYTHING ABOVE THIS, THE SERVER */
SERVER EXPECTS THE FIELDS IN THAT ORDER! */ /* EXPECTS THE FIELDS IN THAT ORDER! */
/* ================================ */ /* ================================ */
@ -1032,8 +1289,8 @@ struct edict_s
vec3_t avelocity; vec3_t avelocity;
int mass; int mass;
float air_finished; float air_finished;
float gravity; /* per entity gravity multiplier (1.0 is float gravity; /* per entity gravity multiplier (1.0 is normal) */
normal) use for lowgrav artifact, flares */ /* use for lowgrav artifact, flares */
edict_t *goalentity; edict_t *goalentity;
edict_t *movetarget; edict_t *movetarget;
@ -1108,7 +1365,6 @@ struct edict_s
/* move this to clientinfo? */ /* move this to clientinfo? */
int light_level; int light_level;
int style; /* also used as areaportal number */ int style; /* also used as areaportal number */
gitem_t *item; /* for bonus items */ gitem_t *item; /* for bonus items */
@ -1118,6 +1374,63 @@ struct edict_s
monsterinfo_t monsterinfo; monsterinfo_t monsterinfo;
int orders; int orders;
int plat2flags;
vec3_t offset;
vec3_t gravityVector;
edict_t *bad_area;
edict_t *hint_chain;
edict_t *monster_hint_chain;
edict_t *target_hint_chain;
int hint_chain_id;
float lastMoveTime;
}; };
#define SPHERE_DEFENDER 0x0001
#define SPHERE_HUNTER 0x0002
#define SPHERE_VENGEANCE 0x0004
#define SPHERE_DOPPLEGANGER 0x0100
#define SPHERE_TYPE 0x00FF
#define SPHERE_FLAGS 0xFF00
/* deathmatch games */
#define RDM_TAG 2
#define RDM_DEATHBALL 3
typedef struct dm_game_rs
{
void (*GameInit)(void);
void (*PostInitSetup)(void);
void (*ClientBegin)(edict_t *ent);
void (*SelectSpawnPoint)(edict_t *ent, vec3_t origin, vec3_t angles);
void (*PlayerDeath)(edict_t *targ, edict_t *inflictor, edict_t *attacker);
void (*Score)(edict_t *attacker, edict_t *victim, int scoreChange);
void (*PlayerEffects)(edict_t *ent);
void (*DogTag)(edict_t *ent, edict_t *killer, char **pic);
void (*PlayerDisconnect)(edict_t *ent);
int (*ChangeDamage)(edict_t *targ, edict_t *attacker, int damage, int mod);
int (*ChangeKnockback)(edict_t *targ, edict_t *attacker, int knockback, int mod);
int (*CheckDMRules)(void);
} dm_game_rt;
extern dm_game_rt DMGame;
void Tag_GameInit(void);
void Tag_PostInitSetup(void);
void Tag_PlayerDeath(edict_t *targ, edict_t *inflictor, edict_t *attacker);
void Tag_Score(edict_t *attacker, edict_t *victim, int scoreChange);
void Tag_PlayerEffects(edict_t *ent);
void Tag_DogTag(edict_t *ent, edict_t *killer, char **pic);
void Tag_PlayerDisconnect(edict_t *ent);
int Tag_ChangeDamage(edict_t *targ, edict_t *attacker, int damage, int mod);
void DBall_GameInit(void);
void DBall_ClientBegin(edict_t *ent);
void DBall_SelectSpawnPoint(edict_t *ent, vec3_t origin, vec3_t angles);
int DBall_ChangeKnockback(edict_t *targ, edict_t *attacker, int knockback, int mod);
int DBall_ChangeDamage(edict_t *targ, edict_t *attacker, int damage, int mod);
void DBall_PostInitSetup(void);
int DBall_CheckDMRules(void);
#endif /* XATRIX_LOCAL_H */ #endif /* XATRIX_LOCAL_H */

View file

@ -471,7 +471,7 @@ berserk_die(edict_t *self, edict_t *inflictor /* unsued */, edict_t *attacker /*
if (self->health <= self->gib_health) if (self->health <= self->gib_health)
{ {
gi.sound(self, CHAN_VOICE, gi.soundindex( "misc/udeath.wav"), 1, ATTN_NORM, 0); gi.sound(self, CHAN_VOICE, gi.soundindex("misc/udeath.wav"), 1, ATTN_NORM, 0);
for (n = 0; n < 2; n++) for (n = 0; n < 2; n++)
{ {

View file

@ -414,7 +414,7 @@ G_SetStats(edict_t *ent)
{ {
/* ran out of cells for power armor */ /* ran out of cells for power armor */
ent->flags &= ~FL_POWER_ARMOR; ent->flags &= ~FL_POWER_ARMOR;
gi.sound(ent, CHAN_ITEM, gi.soundindex( "misc/power2.wav"), gi.sound(ent, CHAN_ITEM, gi.soundindex("misc/power2.wav"),
1, ATTN_NORM, 0); 1, ATTN_NORM, 0);
power_armor_type = 0; power_armor_type = 0;
} }

View file

@ -400,7 +400,7 @@ GetPCXPalette24to8(byte *d_8to24table, byte** d_16to8table)
if (!(*d_16to8table)) if (!(*d_16to8table))
{ {
Com_Error(ERR_FATAL, "%s: Couldn't allocate memory for d_16to8table", __func__); Com_Error(ERR_FATAL, "%s: Couldn't allocate memory for d_16to8table", __func__);
// code never returns after ERR_FATAL /* code never returns after ERR_FATAL */
return; return;
} }
@ -468,14 +468,14 @@ GetPCXPalette(byte **colormap, unsigned *d_8to24table)
int i; int i;
memcpy(d_8to24table, pic, 256 * 4); memcpy(d_8to24table, pic, 256 * 4);
d_8to24table[255] &= LittleLong(0xffffff); // 255 is transparent d_8to24table[255] &= LittleLong(0xffffff); /* 255 is transparent */
/* generate colormap */ /* generate colormap */
*colormap = malloc(256 * 320); *colormap = malloc(256 * 320);
if (!(*colormap)) if (!(*colormap))
{ {
Com_Error(ERR_FATAL, "%s: Couldn't allocate memory for colormap", __func__); Com_Error(ERR_FATAL, "%s: Couldn't allocate memory for colormap", __func__);
// code never returns after ERR_FATAL /* code never returns after ERR_FATAL */
return; return;
} }
@ -516,14 +516,14 @@ GetPCXPalette(byte **colormap, unsigned *d_8to24table)
d_8to24table[i] = LittleLong(v); d_8to24table[i] = LittleLong(v);
} }
d_8to24table[255] &= LittleLong(0xffffff); // 255 is transparent d_8to24table[255] &= LittleLong(0xffffff); /* 255 is transparent */
/* generate colormap */ /* generate colormap */
*colormap = malloc(256 * 320); *colormap = malloc(256 * 320);
if (!(*colormap)) if (!(*colormap))
{ {
Com_Error(ERR_FATAL, "%s: Couldn't allocate memory for colormap", __func__); Com_Error(ERR_FATAL, "%s: Couldn't allocate memory for colormap", __func__);
// code never returns after ERR_FATAL /* code never returns after ERR_FATAL */
return; return;
} }
@ -531,7 +531,7 @@ GetPCXPalette(byte **colormap, unsigned *d_8to24table)
return; return;
} }
for (i=0 ; i<256 ; i++) for (i = 0; i < 256; i++)
{ {
unsigned v; unsigned v;
int r, g, b; int r, g, b;

View file

@ -275,7 +275,7 @@ R_LoadPic8 (char *name, byte *pic, int width, int realwidth, int height, int rea
if (!image->pixels[0]) if (!image->pixels[0])
{ {
Com_Error(ERR_FATAL, "%s: Can't allocate image.", __func__); Com_Error(ERR_FATAL, "%s: Can't allocate image.", __func__);
// code never returns after ERR_FATAL /* code never returns after ERR_FATAL */
return NULL; return NULL;
} }
@ -339,7 +339,7 @@ R_LoadPic (char *name, byte *pic, int width, int realwidth, int height, int real
if (!pic8) if (!pic8)
{ {
Com_Error(ERR_FATAL, "%s: Can't allocate image.", __func__); Com_Error(ERR_FATAL, "%s: Can't allocate image.", __func__);
// code never returns after ERR_FATAL /* code never returns after ERR_FATAL */
return NULL; return NULL;
} }

View file

@ -2407,7 +2407,7 @@ SWimp_CreateRender(int width, int height)
if (!swap_buffers) if (!swap_buffers)
{ {
Com_Error(ERR_FATAL, "%s: Can't allocate swapbuffer.", __func__); Com_Error(ERR_FATAL, "%s: Can't allocate swapbuffer.", __func__);
// code never returns after ERR_FATAL /* code never returns after ERR_FATAL */
return; return;
} }
swap_frames[0] = swap_buffers; swap_frames[0] = swap_buffers;

View file

@ -293,7 +293,7 @@ R_InitCaches (void)
if (!sc_base) if (!sc_base)
{ {
Com_Error(ERR_FATAL, "%s: Can't allocate cache.", __func__); Com_Error(ERR_FATAL, "%s: Can't allocate cache.", __func__);
// code never returns after ERR_FATAL /* code never returns after ERR_FATAL */
return; return;
} }
sc_rover = sc_base; sc_rover = sc_base;

View file

@ -882,7 +882,8 @@ Returns number of mip levels and scales native resolution
if vk_picmip is set. Does not use power of 2 scaling. if vk_picmip is set. Does not use power of 2 scaling.
=============== ===============
*/ */
static uint32_t Vk_Upload32Native (byte *data, int width, int height, imagetype_t type, static uint32_t
Vk_Upload32Native(byte *data, int width, int height, imagetype_t type,
byte **texBuffer, int *upload_width, int *upload_height) byte **texBuffer, int *upload_width, int *upload_height)
{ {
int scaled_width = width, scaled_height = height; int scaled_width = width, scaled_height = height;
@ -1018,7 +1019,8 @@ Returns number of mip levels
=============== ===============
*/ */
static uint32_t Vk_Upload8 (const byte *data, int width, int height, imagetype_t type, static uint32_t
Vk_Upload8(const byte *data, int width, int height, imagetype_t type,
byte **texBuffer, int *upload_width, int *upload_height) byte **texBuffer, int *upload_width, int *upload_height)
{ {
unsigned *trans; unsigned *trans;
@ -1052,16 +1054,27 @@ static uint32_t Vk_Upload8 (const byte *data, int width, int height, imagetype_t
// to avoid alpha fringes // to avoid alpha fringes
// FIXME: do a full flood fill so mips work... // FIXME: do a full flood fill so mips work...
if (i > width && data[i - width] != 255) if (i > width && data[i - width] != 255)
{
p = data[i - width]; p = data[i - width];
}
else if (i < s - width && data[i + width] != 255) else if (i < s - width && data[i + width] != 255)
{
p = data[i + width]; p = data[i + width];
}
else if (i > 0 && data[i - 1] != 255) else if (i > 0 && data[i - 1] != 255)
{
p = data[i - 1]; p = data[i - 1];
}
else if (i < s - 1 && data[i + 1] != 255) else if (i < s - 1 && data[i + 1] != 255)
{
p = data[i + 1]; p = data[i + 1];
}
else else
{
p = 0; p = 0;
// copy rgb components }
/* copy rgb components */
((byte *)&trans[i])[0] = ((byte *)&d_8to24table[p])[0]; ((byte *)&trans[i])[0] = ((byte *)&d_8to24table[p])[0];
((byte *)&trans[i])[1] = ((byte *)&d_8to24table[p])[1]; ((byte *)&trans[i])[1] = ((byte *)&d_8to24table[p])[1];
((byte *)&trans[i])[2] = ((byte *)&d_8to24table[p])[2]; ((byte *)&trans[i])[2] = ((byte *)&d_8to24table[p])[2];
@ -1075,11 +1088,14 @@ static uint32_t Vk_Upload8 (const byte *data, int width, int height, imagetype_t
SmoothColorImage(trans, s, s >> 7); SmoothColorImage(trans, s, s >> 7);
} }
miplevel = Vk_Upload32Native((byte *)trans, width, height, type, texBuffer, upload_width, upload_height); miplevel = Vk_Upload32Native((byte *)trans, width, height, type, texBuffer,
upload_width, upload_height);
// Only free if *texBuffer isn't the image data we sent // Only free if *texBuffer isn't the image data we sent
if (!texBuffer || *texBuffer != (byte *)trans) if (!texBuffer || *texBuffer != (byte *)trans)
{
free(trans); free(trans);
}
return miplevel; return miplevel;
} }

View file

@ -31,6 +31,7 @@
qboolean Pickup_Weapon(edict_t *ent, edict_t *other); qboolean Pickup_Weapon(edict_t *ent, edict_t *other);
void Use_Weapon(edict_t *ent, gitem_t *inv); void Use_Weapon(edict_t *ent, gitem_t *inv);
void Use_Weapon2(edict_t *ent, gitem_t *inv);
void Drop_Weapon(edict_t *ent, gitem_t *inv); void Drop_Weapon(edict_t *ent, gitem_t *inv);
void Weapon_Blaster(edict_t *ent); void Weapon_Blaster(edict_t *ent);
@ -56,6 +57,8 @@ static int power_screen_index;
static int power_shield_index; static int power_shield_index;
void Use_Quad(edict_t *ent, gitem_t *item); void Use_Quad(edict_t *ent, gitem_t *item);
void Use_QuadFire(edict_t *ent, gitem_t *item);
static int quad_drop_timeout_hack; static int quad_drop_timeout_hack;
/* ====================================================================== */ /* ====================================================================== */
@ -587,7 +590,7 @@ Use_Invulnerability(edict_t *ent, gitem_t *item)
ent->client->invincible_framenum = level.framenum + 300; ent->client->invincible_framenum = level.framenum + 300;
} }
gi.sound(ent, CHAN_ITEM, gi.soundindex( "items/protect.wav"), 1, ATTN_NORM, 0); gi.sound(ent, CHAN_ITEM, gi.soundindex("items/protect.wav"), 1, ATTN_NORM, 0);
} }
/* ====================================================================== */ /* ====================================================================== */
@ -2681,6 +2684,28 @@ SP_item_health_mega(edict_t *self)
self->style = HEALTH_IGNORE_MAX | HEALTH_TIMED; self->style = HEALTH_IGNORE_MAX | HEALTH_TIMED;
} }
void
SP_item_foodcube(edict_t *self)
{
if (!self)
{
return;
}
if (deathmatch->value && ((int)dmflags->value & DF_NO_HEALTH))
{
G_FreeEdict(self);
return;
}
self->model = "models/objects/trapfx/tris.md2";
SpawnItem(self, FindItem("Health"));
self->spawnflags |= DROPPED_ITEM;
self->style = HEALTH_IGNORE_MAX;
gi.soundindex("items/s_health.wav");
self->classname = "foodcube";
}
void void
InitItems(void) InitItems(void)
{ {

View file

@ -349,11 +349,11 @@ trigger_key_use(edict_t *self, edict_t *other /* unused */,
self->touch_debounce_time = level.time + 5.0; self->touch_debounce_time = level.time + 5.0;
gi.centerprintf(activator, "You need the %s", self->item->pickup_name); gi.centerprintf(activator, "You need the %s", self->item->pickup_name);
gi.sound(activator, CHAN_AUTO, gi.soundindex( "misc/keytry.wav"), 1, ATTN_NORM, 0); gi.sound(activator, CHAN_AUTO, gi.soundindex("misc/keytry.wav"), 1, ATTN_NORM, 0);
return; return;
} }
gi.sound(activator, CHAN_AUTO, gi.soundindex( "misc/keyuse.wav"), 1, ATTN_NORM, 0); gi.sound(activator, CHAN_AUTO, gi.soundindex("misc/keyuse.wav"), 1, ATTN_NORM, 0);
if (coop->value) if (coop->value)
{ {

View file

@ -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
@ -28,6 +29,11 @@
#define MAXCHOICES 8 #define MAXCHOICES 8
static vec3_t VEC_UP = {0, -1, 0};
static vec3_t MOVEDIR_UP = {0, 0, 1};
static vec3_t VEC_DOWN = {0, -2, 0};
static vec3_t MOVEDIR_DOWN = {0, 0, -1};
void void
G_ProjectSource(vec3_t point, vec3_t distance, vec3_t forward, G_ProjectSource(vec3_t point, vec3_t distance, vec3_t forward,
vec3_t right, vec3_t result) vec3_t right, vec3_t result)
@ -38,6 +44,18 @@ G_ProjectSource(vec3_t point, vec3_t distance, vec3_t forward,
distance[2]; distance[2];
} }
void
G_ProjectSource2(vec3_t point, vec3_t distance, vec3_t forward,
vec3_t right, vec3_t up, vec3_t result)
{
result[0] = point[0] + forward[0] * distance[0] + right[0] * distance[1] +
up[0] * distance[2];
result[1] = point[1] + forward[1] * distance[0] + right[1] * distance[1] +
up[1] * distance[2];
result[2] = point[2] + forward[2] * distance[0] + right[2] * distance[1] +
up[2] * distance[2];
}
/* /*
* Searches all active entities for the next * Searches all active entities for the next
* one that holds the matching string at fieldofs * one that holds the matching string at fieldofs
@ -52,6 +70,11 @@ G_Find(edict_t *from, int fieldofs, char *match)
{ {
char *s; char *s;
if (!match)
{
return NULL;
}
if (!from) if (!from)
{ {
from = g_edicts; from = g_edicts;
@ -61,11 +84,6 @@ G_Find(edict_t *from, int fieldofs, char *match)
from++; from++;
} }
if (!match)
{
return NULL;
}
for ( ; from < &g_edicts[globals.num_edicts]; from++) for ( ; from < &g_edicts[globals.num_edicts]; from++)
{ {
if (!from->inuse) if (!from->inuse)
@ -137,6 +155,63 @@ findradius(edict_t *from, vec3_t org, float rad)
return NULL; return NULL;
} }
/*
* Returns entities that have origins within a spherical area
*/
edict_t *
findradius2(edict_t *from, vec3_t org, float rad)
{
/* rad must be positive */
vec3_t eorg;
int j;
if (!from)
{
from = g_edicts;
}
else
{
from++;
}
for ( ; from < &g_edicts[globals.num_edicts]; from++)
{
if (!from->inuse)
{
continue;
}
if (from->solid == SOLID_NOT)
{
continue;
}
if (!from->takedamage)
{
continue;
}
if (!(from->svflags & SVF_DAMAGEABLE))
{
continue;
}
for (j = 0; j < 3; j++)
{
eorg[j] = org[j] - (from->s.origin[j] + (from->mins[j] + from->maxs[j]) * 0.5);
}
if (VectorLength(eorg) > rad)
{
continue;
}
return from;
}
return NULL;
}
/* /*
* Searches all active entities for * Searches all active entities for
* the next one that holds the matching * the next one that holds the matching
@ -371,10 +446,18 @@ vtos(vec3_t v)
return s; return s;
} }
static vec3_t VEC_UP = {0, -1, 0}; void
static vec3_t MOVEDIR_UP = {0, 0, 1}; get_normal_vector(const cplane_t *p, vec3_t normal)
static vec3_t VEC_DOWN = {0, -2, 0}; {
static vec3_t MOVEDIR_DOWN = {0, 0, -1}; if (p)
{
VectorCopy(p->normal, normal);
}
else
{
VectorCopy(vec3_origin, normal);
}
}
void void
G_SetMovedir(vec3_t angles, vec3_t movedir) G_SetMovedir(vec3_t angles, vec3_t movedir)
@ -426,6 +509,39 @@ vectoyaw(vec3_t vec)
return yaw; return yaw;
} }
float
vectoyaw2(vec3_t vec)
{
float yaw;
if (vec[PITCH] == 0)
{
if (vec[YAW] == 0)
{
yaw = 0;
}
else if (vec[YAW] > 0)
{
yaw = 90;
}
else
{
yaw = 270;
}
}
else
{
yaw = (atan2(vec[YAW], vec[PITCH]) * 180 / M_PI);
if (yaw < 0)
{
yaw += 360;
}
}
return yaw;
}
void void
vectoangles(vec3_t value1, vec3_t angles) vectoangles(vec3_t value1, vec3_t angles)
{ {
@ -479,11 +595,69 @@ vectoangles(vec3_t value1, vec3_t angles)
angles[ROLL] = 0; angles[ROLL] = 0;
} }
void
vectoangles2(vec3_t value1, vec3_t angles)
{
float forward;
float yaw, pitch;
if ((value1[1] == 0) && (value1[0] == 0))
{
yaw = 0;
if (value1[2] > 0)
{
pitch = 90;
}
else
{
pitch = 270;
}
}
else
{
if (value1[0])
{
yaw = (atan2(value1[1], value1[0]) * 180 / M_PI);
}
else if (value1[1] > 0)
{
yaw = 90;
}
else
{
yaw = 270;
}
if (yaw < 0)
{
yaw += 360;
}
forward = sqrt(value1[0] * value1[0] + value1[1] * value1[1]);
pitch = (atan2(value1[2], forward) * 180 / M_PI);
if (pitch < 0)
{
pitch += 360;
}
}
angles[PITCH] = -pitch;
angles[YAW] = yaw;
angles[ROLL] = 0;
}
char * char *
G_CopyString(char *in) G_CopyString(char *in)
{ {
char *out; char *out;
if (!in)
{
return NULL;
}
out = gi.TagMalloc(strlen(in) + 1, TAG_LEVEL); out = gi.TagMalloc(strlen(in) + 1, TAG_LEVEL);
strcpy(out, in); strcpy(out, in);
return out; return out;
@ -492,10 +666,24 @@ G_CopyString(char *in)
void void
G_InitEdict(edict_t *e) G_InitEdict(edict_t *e)
{ {
if (!e)
{
return;
}
if (e->nextthink)
{
e->nextthink = 0;
}
e->inuse = true; e->inuse = true;
e->classname = "noclass"; e->classname = "noclass";
e->gravity = 1.0; e->gravity = 1.0;
e->s.number = e - g_edicts; e->s.number = e - g_edicts;
e->gravityVector[0] = 0.0;
e->gravityVector[1] = 0.0;
e->gravityVector[2] = -1.0;
} }
/* /*
@ -568,6 +756,11 @@ G_Spawn(void)
void void
G_FreeEdict(edict_t *ed) G_FreeEdict(edict_t *ed)
{ {
if (!ed)
{
return;
}
gi.unlinkentity(ed); /* unlink from world */ gi.unlinkentity(ed); /* unlink from world */
if (deathmatch->value || coop->value) if (deathmatch->value || coop->value)

View file

@ -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
@ -26,6 +27,8 @@
#include "header/local.h" #include "header/local.h"
extern void SP_item_foodcube(edict_t *best);
/* /*
* This is a support routine used when a client is firing * This is a support routine used when a client is firing
* a non-instant attack weapon. It checks to see if a * a non-instant attack weapon. It checks to see if a
@ -378,6 +381,7 @@ void
blaster_touch(edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf) blaster_touch(edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf)
{ {
int mod; int mod;
vec3_t normal;
if (!self || !other) /* plane and surf can be NULL */ if (!self || !other) /* plane and surf can be NULL */
{ {
@ -401,6 +405,8 @@ blaster_touch(edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf)
PlayerNoise(self->owner, self->s.origin, PNOISE_IMPACT); PlayerNoise(self->owner, self->s.origin, PNOISE_IMPACT);
} }
get_normal_vector(plane, normal);
if (other->takedamage) if (other->takedamage)
{ {
if (self->spawnflags & 1) if (self->spawnflags & 1)
@ -412,32 +418,15 @@ blaster_touch(edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf)
mod = MOD_BLASTER; mod = MOD_BLASTER;
} }
if (plane)
{
T_Damage(other, self, self->owner, self->velocity, self->s.origin, T_Damage(other, self, self->owner, self->velocity, self->s.origin,
plane->normal, self->dmg, 1, DAMAGE_ENERGY, mod); normal, self->dmg, 1, DAMAGE_ENERGY, mod);
}
else
{
T_Damage(other, self, self->owner, self->velocity, self->s.origin,
vec3_origin, self->dmg, 1, DAMAGE_ENERGY, mod);
}
} }
else else
{ {
gi.WriteByte(svc_temp_entity); gi.WriteByte(svc_temp_entity);
gi.WriteByte(TE_BLASTER); gi.WriteByte(TE_BLASTER);
gi.WritePosition(self->s.origin); gi.WritePosition(self->s.origin);
gi.WriteDir(normal);
if (!plane)
{
gi.WriteDir(vec3_origin);
}
else
{
gi.WriteDir(plane->normal);
}
gi.multicast(self->s.origin, MULTICAST_PVS); gi.multicast(self->s.origin, MULTICAST_PVS);
} }
@ -507,6 +496,56 @@ fire_blaster(edict_t *self, vec3_t start, vec3_t dir, int damage,
} }
} }
void
fire_blueblaster(edict_t *self, vec3_t start, vec3_t dir, int damage,
int speed, int effect)
{
edict_t *bolt;
trace_t tr;
if (!self)
{
return;
}
VectorNormalize(dir);
bolt = G_Spawn();
VectorCopy(start, bolt->s.origin);
VectorCopy(start, bolt->s.old_origin);
vectoangles(dir, bolt->s.angles);
VectorScale(dir, speed, bolt->velocity);
bolt->movetype = MOVETYPE_FLYMISSILE;
bolt->clipmask = MASK_SHOT;
bolt->solid = SOLID_BBOX;
bolt->s.effects |= effect;
VectorClear(bolt->mins);
VectorClear(bolt->maxs);
bolt->s.modelindex = gi.modelindex("models/objects/blaser/tris.md2");
bolt->s.sound = gi.soundindex("misc/lasfly.wav");
bolt->owner = self;
bolt->touch = blaster_touch;
bolt->nextthink = level.time + 2;
bolt->think = G_FreeEdict;
bolt->dmg = damage;
bolt->classname = "bolt";
gi.linkentity(bolt);
if (self->client)
{
check_dodge(self, bolt->s.origin, dir, speed);
}
tr = gi.trace(self->s.origin, NULL, NULL, bolt->s.origin, bolt, MASK_SHOT);
if (tr.fraction < 1.0)
{
VectorMA(bolt->s.origin, -10, dir, bolt->s.origin);
bolt->touch(bolt, tr.ent, NULL, NULL);
}
}
void void
Grenade_Explode(edict_t *ent) Grenade_Explode(edict_t *ent)
{ {
@ -747,6 +786,7 @@ void
rocket_touch(edict_t *ent, edict_t *other, cplane_t *plane, csurface_t *surf) rocket_touch(edict_t *ent, edict_t *other, cplane_t *plane, csurface_t *surf)
{ {
vec3_t origin; vec3_t origin;
vec3_t normal;
int n; int n;
if (!ent || !other) /* plane and surf can be NULL */ if (!ent || !other) /* plane and surf can be NULL */
@ -776,16 +816,10 @@ rocket_touch(edict_t *ent, edict_t *other, cplane_t *plane, csurface_t *surf)
if (other->takedamage) if (other->takedamage)
{ {
if (plane) get_normal_vector(plane, normal);
{
T_Damage(other, ent, ent->owner, ent->velocity, ent->s.origin, T_Damage(other, ent, ent->owner, ent->velocity, ent->s.origin,
plane->normal, ent->dmg, 0, 0, MOD_ROCKET); normal, ent->dmg, 0, 0, MOD_ROCKET);
}
else
{
T_Damage(other, ent, ent->owner, ent->velocity, ent->s.origin,
vec3_origin, ent->dmg, 0, 0, MOD_ROCKET);
}
} }
else else
{ {
@ -851,7 +885,7 @@ fire_rocket(edict_t *self, vec3_t start, vec3_t dir, int damage,
rocket->s.modelindex = gi.modelindex("models/objects/rocket/tris.md2"); rocket->s.modelindex = gi.modelindex("models/objects/rocket/tris.md2");
rocket->owner = self; rocket->owner = self;
rocket->touch = rocket_touch; rocket->touch = rocket_touch;
rocket->nextthink = level.time + 8000 / speed; rocket->nextthink = level.time + (8000.0f / (float)speed);
rocket->think = G_FreeEdict; rocket->think = G_FreeEdict;
rocket->dmg = damage; rocket->dmg = damage;
rocket->radius_dmg = radius_damage; rocket->radius_dmg = radius_damage;
@ -899,7 +933,9 @@ fire_rail(edict_t *self, vec3_t start, vec3_t aimdir, int damage, int kick)
} }
else else
{ {
/* -added so rail goes through SOLID_BBOX entities (gibs, etc) */
if ((tr.ent->svflags & SVF_MONSTER) || (tr.ent->client) || if ((tr.ent->svflags & SVF_MONSTER) || (tr.ent->client) ||
(tr.ent->svflags & SVF_DAMAGEABLE) ||
(tr.ent->solid == SOLID_BBOX)) (tr.ent->solid == SOLID_BBOX))
{ {
ignore = tr.ent; ignore = tr.ent;
@ -1000,8 +1036,8 @@ bfg_explode(edict_t *self)
gi.WriteByte(TE_BFG_EXPLOSION); gi.WriteByte(TE_BFG_EXPLOSION);
gi.WritePosition(ent->s.origin); gi.WritePosition(ent->s.origin);
gi.multicast(ent->s.origin, MULTICAST_PHS); gi.multicast(ent->s.origin, MULTICAST_PHS);
T_Damage(ent, self, self->owner, self->velocity, ent->s.origin, vec3_origin, T_Damage(ent, self, self->owner, self->velocity, ent->s.origin,
(int)points, 0, DAMAGE_ENERGY, MOD_BFG_EFFECT); vec3_origin, (int)points, 0, DAMAGE_ENERGY, MOD_BFG_EFFECT);
} }
} }
@ -1017,6 +1053,8 @@ bfg_explode(edict_t *self)
void void
bfg_touch(edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf) bfg_touch(edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf)
{ {
vec3_t normal;
if (!self || !other) /* plane and surf can be NULL */ if (!self || !other) /* plane and surf can be NULL */
{ {
G_FreeEdict(self); G_FreeEdict(self);
@ -1042,9 +1080,10 @@ bfg_touch(edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf)
/* core explosion - prevents firing it into the wall/floor */ /* core explosion - prevents firing it into the wall/floor */
if (other->takedamage) if (other->takedamage)
{ {
get_normal_vector(plane, normal);
T_Damage(other, self, self->owner, self->velocity, self->s.origin, T_Damage(other, self, self->owner, self->velocity, self->s.origin,
(plane) ? plane->normal : vec3_origin, normal, 200, 0, 0, MOD_BFG_BLAST);
200, 0, 0, MOD_BFG_BLAST);
} }
T_RadiusDamage(self, self->owner, 200, other, 100, MOD_BFG_BLAST); T_RadiusDamage(self, self->owner, 200, other, 100, MOD_BFG_BLAST);
@ -1125,8 +1164,8 @@ bfg_think(edict_t *self)
continue; continue;
} }
if (!(ent->svflags & SVF_MONSTER) && (!ent->client) && if (!(ent->svflags & SVF_MONSTER) && !(ent->svflags & SVF_DAMAGEABLE) &&
(strcmp(ent->classname, "misc_explobox") != 0)) (!ent->client) && (strcmp(ent->classname, "misc_explobox") != 0))
{ {
continue; continue;
} }
@ -1159,7 +1198,8 @@ bfg_think(edict_t *self)
} }
/* if we hit something that's not a monster or player we're done */ /* if we hit something that's not a monster or player we're done */
if (!(tr.ent->svflags & SVF_MONSTER) && (!tr.ent->client)) if (!(tr.ent->svflags & SVF_MONSTER) &&
!(tr.ent->svflags & SVF_DAMAGEABLE) && (!tr.ent->client))
{ {
gi.WriteByte(svc_temp_entity); gi.WriteByte(svc_temp_entity);
gi.WriteByte(TE_LASER_SPARKS); gi.WriteByte(TE_LASER_SPARKS);
@ -1210,7 +1250,7 @@ fire_bfg(edict_t *self, vec3_t start, vec3_t dir, int damage,
bfg->s.modelindex = gi.modelindex("sprites/s_bfg1.sp2"); bfg->s.modelindex = gi.modelindex("sprites/s_bfg1.sp2");
bfg->owner = self; bfg->owner = self;
bfg->touch = bfg_touch; bfg->touch = bfg_touch;
bfg->nextthink = level.time + 8000 / speed; bfg->nextthink = level.time + (8000.0f / (float)speed);
bfg->think = G_FreeEdict; bfg->think = G_FreeEdict;
bfg->radius_dmg = damage; bfg->radius_dmg = damage;
bfg->dmg_radius = damage_radius; bfg->dmg_radius = damage_radius;
@ -1229,3 +1269,604 @@ fire_bfg(edict_t *self, vec3_t start, vec3_t dir, int damage,
gi.linkentity(bfg); gi.linkentity(bfg);
} }
void
ionripper_sparks(edict_t *self)
{
if (!self)
{
return;
}
gi.WriteByte(svc_temp_entity);
gi.WriteByte(TE_WELDING_SPARKS);
gi.WriteByte(0);
gi.WritePosition(self->s.origin);
gi.WriteDir(vec3_origin);
gi.WriteByte(0xe4 + (rand() & 3));
gi.multicast(self->s.origin, MULTICAST_PVS);
G_FreeEdict(self);
}
void
ionripper_touch(edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf)
{
vec3_t normal;
if (!self || !other)
{
return;
}
if (other == self->owner)
{
return;
}
if (surf && (surf->flags & SURF_SKY))
{
G_FreeEdict(self);
return;
}
if (self->owner->client)
{
PlayerNoise(self->owner, self->s.origin, PNOISE_IMPACT);
}
if (other->takedamage)
{
get_normal_vector(plane, normal);
T_Damage(other, self, self->owner, self->velocity, self->s.origin,
normal, self->dmg, 1, DAMAGE_ENERGY, MOD_RIPPER);
G_FreeEdict(self);
}
}
void
fire_ionripper(edict_t *self, vec3_t start, vec3_t dir, int damage,
int speed, int effect)
{
edict_t *ion;
trace_t tr;
if (!self)
{
return;
}
VectorNormalize(dir);
ion = G_Spawn();
VectorCopy(start, ion->s.origin);
VectorCopy(start, ion->s.old_origin);
vectoangles(dir, ion->s.angles);
VectorScale(dir, speed, ion->velocity);
ion->movetype = MOVETYPE_WALLBOUNCE;
ion->clipmask = MASK_SHOT;
ion->solid = SOLID_BBOX;
ion->s.effects |= effect;
ion->s.renderfx |= RF_FULLBRIGHT;
VectorClear(ion->mins);
VectorClear(ion->maxs);
ion->s.modelindex = gi.modelindex("models/objects/boomrang/tris.md2");
ion->s.sound = gi.soundindex("misc/lasfly.wav");
ion->owner = self;
ion->touch = ionripper_touch;
ion->nextthink = level.time + 3;
ion->think = ionripper_sparks;
ion->dmg = damage;
ion->dmg_radius = 100;
gi.linkentity(ion);
if (self->client)
{
check_dodge(self, ion->s.origin, dir, speed);
}
tr = gi.trace(self->s.origin, NULL, NULL, ion->s.origin, ion, MASK_SHOT);
if (tr.fraction < 1.0)
{
VectorMA(ion->s.origin, -10, dir, ion->s.origin);
ion->touch(ion, tr.ent, NULL, NULL);
}
}
void
heat_think(edict_t *self)
{
edict_t *target = NULL;
edict_t *aquire = NULL;
vec3_t vec;
float len;
float oldlen = 0;
if (!self)
{
return;
}
/* aquire new target */
while ((target = findradius(target, self->s.origin, 1024)) != NULL)
{
if (self->owner == target)
{
continue;
}
if (!target->client)
{
continue;
}
if (target->health <= 0)
{
continue;
}
if (!infront(self, target))
{
continue;
}
if (!visible(self, target))
{
continue;
}
VectorSubtract(self->s.origin, target->s.origin, vec);
len = VectorLength(vec);
if ((!aquire) || (len < oldlen))
{
aquire = target;
oldlen = len;
}
}
if (aquire)
{
VectorSubtract(aquire->s.origin, self->s.origin, vec);
vectoangles(vec, self->s.angles);
VectorNormalize(vec);
VectorScale(vec, 500, self->velocity);
}
self->nextthink = level.time + 0.1;
}
void
fire_heat(edict_t *self, vec3_t start, vec3_t dir, int damage, int speed,
float damage_radius, int radius_damage)
{
edict_t *heat;
if (!self)
{
return;
}
heat = G_Spawn();
VectorCopy(start, heat->s.origin);
VectorCopy(dir, heat->movedir);
vectoangles(dir, heat->s.angles);
VectorScale(dir, speed, heat->velocity);
heat->movetype = MOVETYPE_FLYMISSILE;
heat->clipmask = MASK_SHOT;
heat->solid = SOLID_BBOX;
heat->s.effects |= EF_ROCKET;
VectorClear(heat->mins);
VectorClear(heat->maxs);
heat->s.modelindex = gi.modelindex("models/objects/rocket/tris.md2");
heat->owner = self;
heat->touch = rocket_touch;
heat->nextthink = level.time + 0.1;
heat->think = heat_think;
heat->dmg = damage;
heat->radius_dmg = radius_damage;
heat->dmg_radius = damage_radius;
heat->s.sound = gi.soundindex("weapons/rockfly.wav");
if (self->client)
{
check_dodge(self, heat->s.origin, dir, speed);
}
gi.linkentity(heat);
}
void
plasma_touch(edict_t *ent, edict_t *other, cplane_t *plane, csurface_t *surf)
{
vec3_t origin;
vec3_t normal;
if (!ent || !other)
{
return;
}
if (other == ent->owner)
{
return;
}
if (surf && (surf->flags & SURF_SKY))
{
G_FreeEdict(ent);
return;
}
if (ent->owner->client)
{
PlayerNoise(ent->owner, ent->s.origin, PNOISE_IMPACT);
}
/* calculate position for the explosion entity */
VectorMA(ent->s.origin, -0.02, ent->velocity, origin);
if (other->takedamage)
{
get_normal_vector(plane, normal);
T_Damage(other, ent, ent->owner, ent->velocity, ent->s.origin,
normal, ent->dmg, 0, 0, MOD_PHALANX);
}
T_RadiusDamage(ent, ent->owner, ent->radius_dmg, other,
ent->dmg_radius, MOD_PHALANX);
gi.WriteByte(svc_temp_entity);
gi.WriteByte(TE_PLASMA_EXPLOSION);
gi.WritePosition(origin);
gi.multicast(ent->s.origin, MULTICAST_PVS);
G_FreeEdict(ent);
}
void
fire_plasma(edict_t *self, vec3_t start, vec3_t dir, int damage,
int speed, float damage_radius, int radius_damage)
{
edict_t *plasma;
if (!self)
{
return;
}
plasma = G_Spawn();
VectorCopy(start, plasma->s.origin);
VectorCopy(dir, plasma->movedir);
vectoangles(dir, plasma->s.angles);
VectorScale(dir, speed, plasma->velocity);
plasma->movetype = MOVETYPE_FLYMISSILE;
plasma->clipmask = MASK_SHOT;
plasma->solid = SOLID_BBOX;
VectorClear(plasma->mins);
VectorClear(plasma->maxs);
plasma->owner = self;
plasma->touch = plasma_touch;
plasma->nextthink = level.time + (8000.0f / (float)speed);
plasma->think = G_FreeEdict;
plasma->dmg = damage;
plasma->radius_dmg = radius_damage;
plasma->dmg_radius = damage_radius;
plasma->s.sound = gi.soundindex("weapons/rockfly.wav");
plasma->s.modelindex = gi.modelindex("sprites/s_photon.sp2");
plasma->s.effects |= EF_PLASMA | EF_ANIM_ALLFAST;
if (self->client)
{
check_dodge(self, plasma->s.origin, dir, speed);
}
gi.linkentity(plasma);
}
void
Trap_Think(edict_t *ent)
{
edict_t *target = NULL;
edict_t *best = NULL;
vec3_t vec;
int len, i;
int oldlen = 8000;
vec3_t forward, right, up;
if (!ent)
{
return;
}
if (ent->timestamp < level.time)
{
BecomeExplosion1(ent);
return;
}
ent->nextthink = level.time + 0.1;
if (!ent->groundentity)
{
return;
}
/* ok lets do the blood effect */
if (ent->s.frame > 4)
{
if (ent->s.frame == 5)
{
if (ent->wait == 64)
{
gi.sound(ent, CHAN_VOICE, gi.soundindex("weapons/trapdown.wav"),
1, ATTN_IDLE, 0);
}
ent->wait -= 2;
ent->delay += level.time;
for (i = 0; i < 3; i++)
{
best = G_Spawn();
if (strcmp(ent->enemy->classname, "monster_gekk") == 0)
{
best->s.modelindex = gi.modelindex("models/objects/gekkgib/torso/tris.md2");
best->s.effects |= TE_GREENBLOOD;
}
else if (ent->mass > 200)
{
best->s.modelindex = gi.modelindex("models/objects/gibs/chest/tris.md2");
best->s.effects |= TE_BLOOD;
}
else
{
best->s.modelindex = gi.modelindex("models/objects/gibs/sm_meat/tris.md2");
best->s.effects |= TE_BLOOD;
}
AngleVectors(ent->s.angles, forward, right, up);
RotatePointAroundVector(vec, up, right, ((360.0 / 3) * i) + ent->delay);
VectorMA(vec, ent->wait / 2, vec, vec);
VectorAdd(vec, ent->s.origin, vec);
VectorAdd(vec, forward, best->s.origin);
best->s.origin[2] = ent->s.origin[2] + ent->wait;
VectorCopy(ent->s.angles, best->s.angles);
best->solid = SOLID_NOT;
best->s.effects |= EF_GIB;
best->takedamage = DAMAGE_YES;
best->movetype = MOVETYPE_TOSS;
best->svflags |= SVF_MONSTER;
best->deadflag = DEAD_DEAD;
VectorClear(best->mins);
VectorClear(best->maxs);
best->watertype = gi.pointcontents(best->s.origin);
if (best->watertype & MASK_WATER)
{
best->waterlevel = 1;
}
best->nextthink = level.time + 0.1;
best->think = G_FreeEdict;
gi.linkentity(best);
}
if (ent->wait < 19)
{
ent->s.frame++;
}
return;
}
ent->s.frame++;
if (ent->s.frame == 8)
{
ent->nextthink = level.time + 1.0;
ent->think = G_FreeEdict;
best = G_Spawn();
SP_item_foodcube(best);
VectorCopy(ent->s.origin, best->s.origin);
best->s.origin[2] += 16;
best->velocity[2] = 400;
best->count = ent->mass;
gi.linkentity(best);
return;
}
return;
}
ent->s.effects &= ~EF_TRAP;
if (ent->s.frame >= 4)
{
ent->s.effects |= EF_TRAP;
VectorClear(ent->mins);
VectorClear(ent->maxs);
}
if (ent->s.frame < 4)
{
ent->s.frame++;
}
while ((target = findradius(target, ent->s.origin, 256)) != NULL)
{
if (target == ent)
{
continue;
}
if (!(target->svflags & SVF_MONSTER) && !target->client)
{
continue;
}
if (target->health <= 0)
{
continue;
}
if (!visible(ent, target))
{
continue;
}
if (!best)
{
best = target;
continue;
}
VectorSubtract(ent->s.origin, target->s.origin, vec);
len = VectorLength(vec);
if (len < oldlen)
{
oldlen = len;
best = target;
}
}
/* pull the enemy in */
if (best)
{
vec3_t forward;
if (best->groundentity)
{
best->s.origin[2] += 1;
best->groundentity = NULL;
}
VectorSubtract(ent->s.origin, best->s.origin, vec);
len = VectorLength(vec);
if (best->client)
{
VectorNormalize(vec);
VectorMA(best->velocity, 250, vec, best->velocity);
}
else
{
best->ideal_yaw = vectoyaw(vec);
M_ChangeYaw(best);
AngleVectors(best->s.angles, forward, NULL, NULL);
VectorScale(forward, 256, best->velocity);
}
gi.sound(ent, CHAN_VOICE, gi.soundindex(
"weapons/trapsuck.wav"), 1, ATTN_IDLE, 0);
if (len < 32)
{
if (best->mass < 400)
{
T_Damage(best, ent, ent->owner, vec3_origin, best->s.origin,
vec3_origin, 100000, 1, 0, MOD_TRAP);
ent->enemy = best;
ent->wait = 64;
VectorCopy(ent->s.origin, ent->s.old_origin);
ent->timestamp = level.time + 30;
if (deathmatch->value)
{
ent->mass = best->mass / 4;
}
else
{
ent->mass = best->mass / 10;
}
/* ok spawn the food cube */
ent->s.frame = 5;
}
else
{
BecomeExplosion1(ent);
return;
}
}
}
}
void
fire_trap(edict_t *self, vec3_t start, vec3_t aimdir, int damage,
int speed, float timer, float damage_radius, qboolean held)
{
edict_t *trap;
vec3_t dir;
vec3_t forward, right, up;
if (!self)
{
return;
}
vectoangles(aimdir, dir);
AngleVectors(dir, forward, right, up);
trap = G_Spawn();
VectorCopy(start, trap->s.origin);
VectorScale(aimdir, speed, trap->velocity);
VectorMA(trap->velocity, 200 + crandom() * 10.0, up, trap->velocity);
VectorMA(trap->velocity, crandom() * 10.0, right, trap->velocity);
VectorSet(trap->avelocity, 0, 300, 0);
trap->movetype = MOVETYPE_BOUNCE;
trap->clipmask = MASK_SHOT;
trap->solid = SOLID_BBOX;
VectorSet(trap->mins, -4, -4, 0);
VectorSet(trap->maxs, 4, 4, 8);
trap->s.modelindex = gi.modelindex("models/weapons/z_trap/tris.md2");
trap->owner = self;
trap->nextthink = level.time + 1.0;
trap->think = Trap_Think;
trap->dmg = damage;
trap->dmg_radius = damage_radius;
trap->classname = "htrap";
trap->s.sound = gi.soundindex("weapons/traploop.wav");
if (held)
{
trap->spawnflags = 3;
}
else
{
trap->spawnflags = 1;
}
if (timer <= 0.0)
{
Grenade_Explode(trap);
}
else
{
gi.linkentity(trap);
}
trap->timestamp = level.time + 30;
}

View file

@ -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
@ -39,6 +40,7 @@
#define SVF_NOCLIENT 0x00000001 /* don't send entity to clients, even if it has effects */ #define SVF_NOCLIENT 0x00000001 /* don't send entity to clients, even if it has effects */
#define SVF_DEADMONSTER 0x00000002 /* treat as CONTENTS_DEADMONSTER for collision */ #define SVF_DEADMONSTER 0x00000002 /* treat as CONTENTS_DEADMONSTER for collision */
#define SVF_MONSTER 0x00000004 /* treat as CONTENTS_MONSTER for collision */ #define SVF_MONSTER 0x00000004 /* treat as CONTENTS_MONSTER for collision */
#define SVF_DAMAGEABLE 0x00000008
#define MAX_ENT_CLUSTERS 16 #define MAX_ENT_CLUSTERS 16
@ -86,6 +88,8 @@ struct edict_s
int headnode; /* unused if num_clusters != -1 */ int headnode; /* unused if num_clusters != -1 */
int areanum, areanum2; int areanum, areanum2;
/* ================================ */
int svflags; /* SVF_NOCLIENT, SVF_DEADMONSTER, SVF_MONSTER, etc */ int svflags; /* SVF_NOCLIENT, SVF_DEADMONSTER, SVF_MONSTER, etc */
vec3_t mins, maxs; vec3_t mins, maxs;
vec3_t absmin, absmax, size; vec3_t absmin, absmax, size;

View file

@ -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
@ -59,6 +60,7 @@
#define SPAWNFLAG_NOT_DEATHMATCH 0x00000800 #define SPAWNFLAG_NOT_DEATHMATCH 0x00000800
#define SPAWNFLAG_NOT_COOP 0x00001000 #define SPAWNFLAG_NOT_COOP 0x00001000
/* edict->flags */
#define FL_FLY 0x00000001 #define FL_FLY 0x00000001
#define FL_SWIM 0x00000002 /* implied immunity to drowining */ #define FL_SWIM 0x00000002 /* implied immunity to drowining */
#define FL_IMMUNE_LASER 0x00000004 #define FL_IMMUNE_LASER 0x00000004
@ -75,6 +77,11 @@
#define FL_COOP_TAKEN 0x00002000 /* Another client has already taken it */ #define FL_COOP_TAKEN 0x00002000 /* Another client has already taken it */
#define FL_RESPAWN 0x80000000 /* used for item respawning */ #define FL_RESPAWN 0x80000000 /* used for item respawning */
#define FL_MECHANICAL 0x00002000 /* entity is mechanical, use sparks not blood */
#define FL_SAM_RAIMI 0x00004000 /* entity is in sam raimi cam mode */
#define FL_DISGUISED 0x00008000 /* entity is in disguise, monsters will not recognize. */
#define FL_NOGIB 0x00010000 /* player has been vaporized by a nuke, drop no gibs */
#define FRAMETIME 0.1 #define FRAMETIME 0.1
/* memory tags to allow dynamic memory to be cleaned up */ /* memory tags to allow dynamic memory to be cleaned up */
@ -106,7 +113,12 @@ typedef enum
AMMO_ROCKETS, AMMO_ROCKETS,
AMMO_GRENADES, AMMO_GRENADES,
AMMO_CELLS, AMMO_CELLS,
AMMO_SLUGS AMMO_SLUGS,
AMMO_FLECHETTES,
AMMO_TESLA,
AMMO_PROX,
AMMO_DISRUPTOR
} ammo_t; } ammo_t;
/* Maximum debris / gibs per frame */ /* Maximum debris / gibs per frame */
@ -145,12 +157,29 @@ typedef enum
#define AI_COMBAT_POINT 0x00001000 #define AI_COMBAT_POINT 0x00001000
#define AI_MEDIC 0x00002000 #define AI_MEDIC 0x00002000
#define AI_RESURRECTING 0x00004000 #define AI_RESURRECTING 0x00004000
#define AI_IGNORE_PAIN 0x00008000
/* ROGUE */
#define AI_WALK_WALLS 0x00008000
#define AI_MANUAL_STEERING 0x00010000
#define AI_TARGET_ANGER 0x00020000
#define AI_DODGING 0x00040000
#define AI_CHARGING 0x00080000
#define AI_HINT_PATH 0x00100000
#define AI_IGNORE_SHOTS 0x00200000
#define AI_DO_NOT_COUNT 0x00400000 /* set for healed monsters */
#define AI_SPAWNED_CARRIER 0x00800000 /* both do_not_count and spawned are set for spawned monsters */
#define AI_SPAWNED_MEDIC_C 0x01000000 /* both do_not_count and spawned are set for spawned monsters */
#define AI_SPAWNED_WIDOW 0x02000000 /* both do_not_count and spawned are set for spawned monsters */
#define AI_SPAWNED_MASK 0x03800000 /* mask to catch all three flavors of spawned */
#define AI_BLOCKED 0x04000000 /* used by blocked_checkattack: set to say I'm attacking while blocked */
/* (prevents run-attacks) */
/* monster attack state */ /* monster attack state */
#define AS_STRAIGHT 1 #define AS_STRAIGHT 1
#define AS_SLIDING 2 #define AS_SLIDING 2
#define AS_MELEE 3 #define AS_MELEE 3
#define AS_MISSILE 4 #define AS_MISSILE 4
#define AS_BLIND 5
/* armor types */ /* armor types */
#define ARMOR_NONE 0 #define ARMOR_NONE 0
@ -198,7 +227,9 @@ typedef enum
MOVETYPE_FLY, MOVETYPE_FLY,
MOVETYPE_TOSS, /* gravity */ MOVETYPE_TOSS, /* gravity */
MOVETYPE_FLYMISSILE, /* extra size to monsters */ MOVETYPE_FLYMISSILE, /* extra size to monsters */
MOVETYPE_BOUNCE MOVETYPE_BOUNCE, /* added this (the comma at the end of line) */
MOVETYPE_WALLBOUNCE,
MOVETYPE_NEWTOSS /* for deathball */
} movetype_t; } movetype_t;
typedef struct typedef struct
@ -210,13 +241,16 @@ typedef struct
int armor; int armor;
} gitem_armor_t; } gitem_armor_t;
#define IT_WEAPON 1 /* use makes active weapon */ /* gitem_t->flags */
#define IT_AMMO 2 #define IT_WEAPON 0x00000001 /* use makes active weapon */
#define IT_ARMOR 4 #define IT_AMMO 0x00000002
#define IT_STAY_COOP 8 #define IT_ARMOR 0x00000004
#define IT_KEY 16 #define IT_STAY_COOP 0x00000008
#define IT_POWERUP 32 #define IT_KEY 0x00000010
#define IT_INSTANT_USE 64 /* item is insta-used on pickup if dmflag is set */ #define IT_POWERUP 0x00000020
#define IT_MELEE 0x00000040
#define IT_NOT_GIVEABLE 0x00000080 /* item can not be given */
#define IT_INSTANT_USE 0x000000100 /* item is insta-used on pickup if dmflag is set */
/* gitem_t->weapmodel for weapons indicates model index */ /* gitem_t->weapmodel for weapons indicates model index */
#define WEAP_BLASTER 1 #define WEAP_BLASTER 1
@ -230,6 +264,13 @@ typedef struct
#define WEAP_HYPERBLASTER 9 #define WEAP_HYPERBLASTER 9
#define WEAP_RAILGUN 10 #define WEAP_RAILGUN 10
#define WEAP_BFG 11 #define WEAP_BFG 11
#define WEAP_PHALANX 12
#define WEAP_BOOMER 13
#define WEAP_DISRUPTOR 14
#define WEAP_ETFRIFLE 15
#define WEAP_PLASMA 16
#define WEAP_PROXLAUNCH 17
#define WEAP_CHAINFIST 18
typedef struct gitem_s typedef struct gitem_s
{ {
@ -267,8 +308,8 @@ typedef struct
{ {
char helpmessage1[512]; char helpmessage1[512];
char helpmessage2[512]; char helpmessage2[512];
int helpchanged; /* flash F1 icon if non 0, play sound int helpchanged; /* flash F1 icon if non 0, play sound */
and increment only if 1, 2, or 3 */ /* and increment only if 1, 2, or 3 */
gclient_t *clients; /* [maxclients] */ gclient_t *clients; /* [maxclients] */
@ -332,10 +373,13 @@ typedef struct
int body_que; /* dead bodies */ int body_que; /* dead bodies */
int power_cubes; /* ugly necessity for coop */ int power_cubes; /* ugly necessity for coop */
edict_t *disguise_violator;
int disguise_violation_framenum;
} level_locals_t; } level_locals_t;
/* spawn_temp_t is only used to hold entity field values that /* spawn_temp_t is only used to hold entity field values that
can be set from the editor, but aren't actualy present can be set from the editor, but aren't actualy present/
in edict_t during gameplay */ in edict_t during gameplay */
typedef struct typedef struct
{ {
@ -408,7 +452,7 @@ typedef struct
typedef struct typedef struct
{ {
mmove_t *currentmove; mmove_t *currentmove;
int aiflags; unsigned int aiflags; /* unsigned, since we're close to the max */
int nextframe; int nextframe;
float scale; float scale;
@ -437,8 +481,40 @@ typedef struct
int power_armor_type; int power_armor_type;
int power_armor_power; int power_armor_power;
qboolean (*blocked)(edict_t *self, float dist);
float last_hint_time; /* last time the monster checked for hintpaths. */
edict_t *goal_hint; /* which hint_path we're trying to get to */
int medicTries;
edict_t *badMedic1, *badMedic2; /* these medics have declared this monster "unhealable" */
edict_t *healer; /* this is who is healing this monster */
void (*duck)(edict_t *self, float eta);
void (*unduck)(edict_t *self);
void (*sidestep)(edict_t *self);
float base_height;
float next_duck_time;
float duck_wait_time;
edict_t *last_player_enemy;
qboolean blindfire; /* will the monster blindfire? */
float blind_fire_delay;
vec3_t blind_fire_target;
/* used by the spawners to not spawn too much and keep track of #s of monsters spawned */
int monster_slots;
int monster_used;
edict_t *commander;
/* powerup timers, used by widow, our friend */
float quad_framenum;
float invincible_framenum;
float double_framenum;
} monsterinfo_t; } monsterinfo_t;
/* this determines how long to wait after a duck to duck again.
this needs to be longer than the time after the monster_duck_up
in all of the animation sequences */
#define DUCK_INTERVAL 0.5
extern game_locals_t game; extern game_locals_t game;
extern level_locals_t level; extern level_locals_t level;
extern game_import_t gi; extern game_import_t gi;
@ -486,7 +562,29 @@ extern int gibsthisframe;
#define MOD_TRIGGER_HURT 31 #define MOD_TRIGGER_HURT 31
#define MOD_HIT 32 #define MOD_HIT 32
#define MOD_TARGET_BLASTER 33 #define MOD_TARGET_BLASTER 33
#define MOD_RIPPER 34
#define MOD_PHALANX 35
#define MOD_BRAINTENTACLE 36
#define MOD_BLASTOFF 37
#define MOD_GEKK 38
#define MOD_TRAP 39
#define MOD_FRIENDLY_FIRE 0x8000000 #define MOD_FRIENDLY_FIRE 0x8000000
#define MOD_CHAINFIST 40
#define MOD_DISINTEGRATOR 41
#define MOD_ETF_RIFLE 42
#define MOD_BLASTER2 43
#define MOD_HEATBEAM 44
#define MOD_TESLA 45
#define MOD_PROX 46
#define MOD_NUKE 47
#define MOD_VENGEANCE_SPHERE 48
#define MOD_HUNTER_SPHERE 49
#define MOD_DEFENDER_SPHERE 50
#define MOD_TRACKER 51
#define MOD_DBALL_CRUSH 52
#define MOD_DOPPLE_EXPLODE 53
#define MOD_DOPPLE_VENGEANCE 54
#define MOD_DOPPLE_HUNTER 55
/* Easier handling of AI skill levels */ /* Easier handling of AI skill levels */
#define SKILL_EASY 0 #define SKILL_EASY 0
@ -495,7 +593,6 @@ extern int gibsthisframe;
#define SKILL_HARDPLUS 3 #define SKILL_HARDPLUS 3
extern int meansOfDeath; extern int meansOfDeath;
extern edict_t *g_edicts; extern edict_t *g_edicts;
#define FOFS(x) (size_t)&(((edict_t *)NULL)->x) #define FOFS(x) (size_t)&(((edict_t *)NULL)->x)
@ -509,8 +606,10 @@ extern edict_t *g_edicts;
extern cvar_t *maxentities; extern cvar_t *maxentities;
extern cvar_t *deathmatch; extern cvar_t *deathmatch;
extern cvar_t *coop; extern cvar_t *coop;
extern cvar_t *coop_baseq2; /* treat spawnflags according to baseq2 rules */
extern cvar_t *coop_pickup_weapons; extern cvar_t *coop_pickup_weapons;
extern cvar_t *coop_elevator_delay; extern cvar_t *coop_elevator_delay;
extern cvar_t *coop_pickup_weapons;
extern cvar_t *dmflags; extern cvar_t *dmflags;
extern cvar_t *skill; extern cvar_t *skill;
extern cvar_t *fraglimit; extern cvar_t *fraglimit;
@ -550,10 +649,28 @@ extern cvar_t *flood_waitdelay;
extern cvar_t *sv_maplist; extern cvar_t *sv_maplist;
extern cvar_t *sv_stopspeed;
extern cvar_t *g_showlogic;
extern cvar_t *gamerules;
extern cvar_t *huntercam;
extern cvar_t *strong_mines;
extern cvar_t *randomrespawn;
extern cvar_t *g_disruptor;
extern cvar_t *aimfix; extern cvar_t *aimfix;
extern cvar_t *g_machinegun_norecoil; extern cvar_t *g_machinegun_norecoil;
extern cvar_t *g_swap_speed; extern cvar_t *g_swap_speed;
/* this is for the count of monsters */
#define ENT_SLOTS_LEFT \
(ent->monsterinfo.monster_slots - \
ent->monsterinfo.monster_used)
#define SELF_SLOTS_LEFT \
(self->monsterinfo.monster_slots - \
self->monsterinfo.monster_used)
#define world (&g_edicts[0]) #define world (&g_edicts[0])
/* item spawnflags */ /* item spawnflags */
@ -627,7 +744,8 @@ int ArmorIndex(edict_t *ent);
int PowerArmorType(edict_t *ent); int PowerArmorType(edict_t *ent);
gitem_t *GetItemByIndex(int index); gitem_t *GetItemByIndex(int index);
qboolean Add_Ammo(edict_t *ent, gitem_t *item, int count); qboolean Add_Ammo(edict_t *ent, gitem_t *item, int count);
void Touch_Item(edict_t *ent, edict_t *other, cplane_t *plane, csurface_t *surf); void Touch_Item(edict_t *ent, edict_t *other, cplane_t *plane,
csurface_t *surf);
/* g_utils.c */ /* g_utils.c */
qboolean KillBox(edict_t *ent); qboolean KillBox(edict_t *ent);
@ -651,10 +769,17 @@ char *G_CopyString(char *in);
float *tv(float x, float y, float z); float *tv(float x, float y, float z);
char *vtos(vec3_t v); char *vtos(vec3_t v);
void get_normal_vector(const cplane_t *p, vec3_t normal);
float vectoyaw(vec3_t vec); float vectoyaw(vec3_t vec);
void vectoangles(vec3_t vec, vec3_t angles); void vectoangles(vec3_t vec, vec3_t angles);
void G_ProjectSource2(vec3_t point, vec3_t distance, vec3_t forward, vec3_t right,
vec3_t up, vec3_t result);
float vectoyaw2(vec3_t vec);
void vectoangles2(vec3_t vec, vec3_t angles);
edict_t *findradius2(edict_t *from, vec3_t org, float rad);
/* g_spawn.c */ /* g_spawn.c */
void ED_CallSpawn(edict_t *ent); void ED_CallSpawn(edict_t *ent);
@ -667,6 +792,11 @@ void T_Damage(edict_t *targ, edict_t *inflictor, edict_t *attacker,
void T_RadiusDamage(edict_t *inflictor, edict_t *attacker, void T_RadiusDamage(edict_t *inflictor, edict_t *attacker,
float damage, edict_t *ignore, float radius, float damage, edict_t *ignore, float radius,
int mod); int mod);
void T_RadiusNukeDamage(edict_t *inflictor, edict_t *attacker, float damage,
edict_t *ignore, float radius, int mod);
void T_RadiusClassDamage(edict_t *inflictor, edict_t *attacker, float damage,
char *ignoreClass, float radius, int mod);
void cleanupHealTarget(edict_t *ent);
/* damage flags */ /* damage flags */
#define DAMAGE_RADIUS 0x00000001 /* damage was indirect */ #define DAMAGE_RADIUS 0x00000001 /* damage was indirect */
@ -675,6 +805,9 @@ void T_RadiusDamage(edict_t *inflictor, edict_t *attacker,
#define DAMAGE_NO_KNOCKBACK 0x00000008 /* do not affect velocity, just view angles */ #define DAMAGE_NO_KNOCKBACK 0x00000008 /* do not affect velocity, just view angles */
#define DAMAGE_BULLET 0x00000010 /* damage is from a bullet (used for ricochets) */ #define DAMAGE_BULLET 0x00000010 /* damage is from a bullet (used for ricochets) */
#define DAMAGE_NO_PROTECTION 0x00000020 /* armor, shields, invulnerability, and godmode have no effect */ #define DAMAGE_NO_PROTECTION 0x00000020 /* armor, shields, invulnerability, and godmode have no effect */
#define DAMAGE_DESTROY_ARMOR 0x00000040 /* damage is done to armor and health. */
#define DAMAGE_NO_REG_ARMOR 0x00000080 /* damage skips regular armor */
#define DAMAGE_NO_POWER_ARMOR 0x00000100 /* damage skips power armor */
#define DEFAULT_BULLET_HSPREAD 300 #define DEFAULT_BULLET_HSPREAD 300
#define DEFAULT_BULLET_VSPREAD 500 #define DEFAULT_BULLET_VSPREAD 500
@ -701,6 +834,12 @@ void monster_fire_railgun(edict_t *self, vec3_t start, vec3_t aimdir,
void monster_fire_bfg(edict_t *self, vec3_t start, vec3_t aimdir, void monster_fire_bfg(edict_t *self, vec3_t start, vec3_t aimdir,
int damage, int speed, int kick, float damage_radius, int damage, int speed, int kick, float damage_radius,
int flashtype); int flashtype);
void monster_fire_ionripper(edict_t *self, vec3_t start, vec3_t dir, int damage,
int speed, int flashtype, int effect);
void monster_dabeam(edict_t *self);
void monster_fire_blueblaster(edict_t *self, vec3_t start, vec3_t dir, int damage,
int speed, int flashtype, int effect);
void M_droptofloor(edict_t *ent); void M_droptofloor(edict_t *ent);
void monster_think(edict_t *self); void monster_think(edict_t *self);
void walkmonster_start(edict_t *self); void walkmonster_start(edict_t *self);
@ -713,11 +852,20 @@ qboolean M_CheckAttack(edict_t *self);
void M_FlyCheck(edict_t *self); void M_FlyCheck(edict_t *self);
void M_CheckGround(edict_t *ent); void M_CheckGround(edict_t *ent);
void monster_fire_blaster2(edict_t *self, vec3_t start, vec3_t dir, int damage,
int speed, int flashtype, int effect);
void monster_fire_tracker(edict_t *self, vec3_t start, vec3_t dir, int damage,
int speed, edict_t *enemy, int flashtype);
void stationarymonster_start(edict_t *self);
void monster_done_dodge(edict_t *self);
/* g_misc.c */ /* g_misc.c */
void ThrowHead(edict_t *self, char *gibname, int damage, int type); void ThrowHead(edict_t *self, char *gibname, int damage, int type);
void ThrowClientHead(edict_t *self, int damage); void ThrowClientHead(edict_t *self, int damage);
void ThrowGib(edict_t *self, char *gibname, int damage, int type); void ThrowGib(edict_t *self, char *gibname, int damage, int type);
void BecomeExplosion1(edict_t *self); void BecomeExplosion1(edict_t *self);
void ThrowHeadACID(edict_t *self, char *gibname, int damage, int type);
void ThrowGibACID(edict_t *self, char *gibname, int damage, int type);
/* g_ai.c */ /* g_ai.c */
void AI_SetSightClient(void); void AI_SetSightClient(void);
@ -749,10 +897,19 @@ void fire_grenade(edict_t *self, vec3_t start, vec3_t aimdir, int damage,
void fire_grenade2(edict_t *self, vec3_t start, vec3_t aimdir, int damage, void fire_grenade2(edict_t *self, vec3_t start, vec3_t aimdir, int damage,
int speed, float timer, float damage_radius, qboolean held); int speed, float timer, float damage_radius, qboolean held);
void fire_rocket(edict_t *self, vec3_t start, vec3_t dir, int damage, void fire_rocket(edict_t *self, vec3_t start, vec3_t dir, int damage,
int speed, float damage_radius, int radius_damage); int speed, float damage_radius,
int radius_damage);
void fire_rail(edict_t *self, vec3_t start, vec3_t aimdir, int damage, int kick); void fire_rail(edict_t *self, vec3_t start, vec3_t aimdir, int damage, int kick);
void fire_bfg(edict_t *self, vec3_t start, vec3_t dir, int damage, void fire_bfg(edict_t *self, vec3_t start, vec3_t dir, int damage,
int speed, float damage_radius); int speed, float damage_radius);
void fire_ionripper(edict_t *self, vec3_t start, vec3_t aimdir, int damage,
int speed, int effect);
void fire_blueblaster(edict_t *self, vec3_t start, vec3_t aimdir, int damage,
int speed, int effect);
void fire_plasma(edict_t *self, vec3_t start, vec3_t dir, int damage, int speed,
float damage_radius, int radius_damage);
void fire_trap(edict_t *self, vec3_t start, vec3_t aimdir, int damage,
int speed, float timer, float damage_radius, qboolean held);
/* g_ptrail.c */ /* g_ptrail.c */
void PlayerTrail_Init(void); void PlayerTrail_Init(void);
@ -823,6 +980,87 @@ void ReadGame(const char *filename);
void WriteGame(const char *filename, qboolean autosave); void WriteGame(const char *filename, qboolean autosave);
void SpawnEntities(const char *mapname, char *entities, const char *spawnpoint); void SpawnEntities(const char *mapname, char *entities, const char *spawnpoint);
void fire_flechette(edict_t *self, vec3_t start, vec3_t dir, int damage,
int speed, int kick);
void fire_prox(edict_t *self, vec3_t start, vec3_t aimdir, int damage,
int speed);
void fire_nuke(edict_t *self, vec3_t start, vec3_t aimdir, int speed);
void fire_flame(edict_t *self, vec3_t start, vec3_t aimdir, int damage,
int speed);
void fire_burst(edict_t *self, vec3_t start, vec3_t aimdir, int damage,
int speed);
void fire_maintain(edict_t *, edict_t *, vec3_t start, vec3_t aimdir,
int damage, int speed);
void fire_incendiary_grenade(edict_t *self, vec3_t start, vec3_t aimdir,
int damage, int speed, float timer, float damage_radius);
void fire_player_melee(edict_t *self, vec3_t start, vec3_t aim, int reach,
int damage, int kick, int quiet, int mod);
void fire_tesla(edict_t *self, vec3_t start, vec3_t aimdir, int damage,
int speed);
void fire_blaster2(edict_t *self, vec3_t start, vec3_t aimdir, int damage,
int speed, int effect, qboolean hyper);
void fire_tracker(edict_t *self, vec3_t start, vec3_t dir, int damage,
int speed, edict_t *enemy);
/* g_newai.c */
qboolean blocked_checkplat(edict_t *self, float dist);
qboolean blocked_checkjump(edict_t *self, float dist, float maxDown, float maxUp);
qboolean blocked_checknewenemy(edict_t *self);
qboolean monsterlost_checkhint(edict_t *self);
qboolean inback(edict_t *self, edict_t *other);
float realrange(edict_t *self, edict_t *other);
edict_t *SpawnBadArea(vec3_t mins, vec3_t maxs, float lifespan, edict_t *owner);
edict_t *CheckForBadArea(edict_t *ent);
qboolean MarkTeslaArea(edict_t *self, edict_t *tesla);
void InitHintPaths(void);
void PredictAim(edict_t *target, vec3_t start, float bolt_speed, qboolean eye_height,
float offset, vec3_t aimdir, vec3_t aimpoint);
qboolean below(edict_t *self, edict_t *other);
void drawbbox(edict_t *self);
void M_MonsterDodge(edict_t *self, edict_t *attacker, float eta, trace_t *tr);
void monster_duck_down(edict_t *self);
void monster_duck_hold(edict_t *self);
void monster_duck_up(edict_t *self);
qboolean has_valid_enemy(edict_t *self);
void TargetTesla(edict_t *self, edict_t *tesla);
void hintpath_stop(edict_t *self);
edict_t *PickCoopTarget(edict_t *self);
int CountPlayers(void);
void monster_jump_start(edict_t *self);
qboolean monster_jump_finished(edict_t *self);
/* g_sphere.c */
void Defender_Launch(edict_t *self);
void Vengeance_Launch(edict_t *self);
void Hunter_Launch(edict_t *self);
/* g_newdm.c */
void InitGameRules(void);
edict_t *DoRandomRespawn(edict_t *ent);
void PrecacheForRandomRespawn(void);
qboolean Tag_PickupToken(edict_t *ent, edict_t *other);
void Tag_DropToken(edict_t *ent, gitem_t *item);
void Tag_PlayerDeath(edict_t *targ, edict_t *inflictor, edict_t *attacker);
void fire_doppleganger(edict_t *ent, vec3_t start, vec3_t aimdir);
/* g_spawn.c */
edict_t *CreateMonster(vec3_t origin, vec3_t angles, char *classname);
edict_t *CreateFlyMonster(vec3_t origin, vec3_t angles, vec3_t mins,
vec3_t maxs, char *classname);
edict_t *CreateGroundMonster(vec3_t origin, vec3_t angles, vec3_t mins,
vec3_t maxs, char *classname, int height);
qboolean FindSpawnPoint(vec3_t startpoint, vec3_t mins, vec3_t maxs,
vec3_t spawnpoint, float maxMoveUp);
qboolean CheckSpawnPoint(vec3_t origin, vec3_t mins, vec3_t maxs);
qboolean CheckGroundSpawnPoint(vec3_t origin, vec3_t entMins, vec3_t entMaxs,
float height, float gravity);
void DetermineBBox(char *classname, vec3_t mins, vec3_t maxs);
void SpawnGrow_Spawn(vec3_t startpos, int size);
void Widowlegs_Spawn(vec3_t startpos, vec3_t angles);
/* p_client.c */
void RemoveAttackingPainDaemons(edict_t *self);
/* ============================================================================ */ /* ============================================================================ */
/* client_t->anim_priority */ /* client_t->anim_priority */
@ -844,8 +1082,8 @@ typedef struct
qboolean connected; /* a loadgame will leave valid entities that qboolean connected; /* a loadgame will leave valid entities that
just don't have a connection yet */ just don't have a connection yet */
/* values saved and restored /* values saved and restored from
from edicts when changing levels */ edicts when changing levels */
int health; int health;
int max_health; int max_health;
int savedFlags; int savedFlags;
@ -860,6 +1098,8 @@ typedef struct
int max_grenades; int max_grenades;
int max_cells; int max_cells;
int max_slugs; int max_slugs;
int max_magslug;
int max_trap;
gitem_t *weapon; gitem_t *weapon;
gitem_t *lastweapon; gitem_t *lastweapon;
@ -871,6 +1111,12 @@ typedef struct
int helpchanged; int helpchanged;
qboolean spectator; /* client is a spectator */ qboolean spectator; /* client is a spectator */
int max_tesla;
int max_prox;
int max_mines;
int max_flechettes;
int max_rounds;
} client_persistant_t; } client_persistant_t;
/* client data that stays across deathmatch respawns */ /* client data that stays across deathmatch respawns */
@ -884,8 +1130,8 @@ typedef struct
qboolean spectator; /* client is a spectator */ qboolean spectator; /* client is a spectator */
} client_respawn_t; } client_respawn_t;
/* this structure is cleared on each PutClientInServer(), /* this structure is cleared on each
except for 'client->pers' */ PutClientInServer(), except for 'client->pers' */
struct gclient_s struct gclient_s
{ {
/* known to server */ /* known to server */
@ -955,6 +1201,10 @@ struct gclient_s
qboolean grenade_blew_up; qboolean grenade_blew_up;
float grenade_time; float grenade_time;
float quadfire_framenum;
qboolean trap_blew_up;
float trap_time;
int silencer_shots; int silencer_shots;
int weapon_sound; int weapon_sound;
@ -968,15 +1218,21 @@ struct gclient_s
edict_t *chase_target; /* player we are chasing */ edict_t *chase_target; /* player we are chasing */
qboolean update_chase; /* need to update chase info? */ qboolean update_chase; /* need to update chase info? */
float double_framenum;
float ir_framenum;
float nuke_framenum;
float tracker_pain_framenum;
edict_t *owned_sphere; /* this points to the player's sphere */
}; };
struct edict_s struct edict_s
{ {
entity_state_t s; entity_state_t s;
struct gclient_s *client; /* NULL if not a player struct gclient_s *client; /* NULL if not a player the server expects the first part
the server expects the first part of gclient_s to be a player_state_t but the rest of it is
of gclient_s to be a player_state_t opaque */
but the rest of it is opaque */
qboolean inuse; qboolean inuse;
int linkcount; int linkcount;
@ -1001,6 +1257,7 @@ struct edict_s
/* EXPECTS THE FIELDS IN THAT ORDER! */ /* EXPECTS THE FIELDS IN THAT ORDER! */
/* ================================ */ /* ================================ */
int movetype; int movetype;
int flags; int flags;
@ -1032,8 +1289,8 @@ struct edict_s
vec3_t avelocity; vec3_t avelocity;
int mass; int mass;
float air_finished; float air_finished;
float gravity; /* per entity gravity multiplier (1.0 is normal) float gravity; /* per entity gravity multiplier (1.0 is normal) */
use for lowgrav artifact, flares */ /* use for lowgrav artifact, flares */
edict_t *goalentity; edict_t *goalentity;
edict_t *movetarget; edict_t *movetarget;
@ -1043,7 +1300,7 @@ struct edict_s
float nextthink; float nextthink;
void (*prethink)(edict_t *ent); void (*prethink)(edict_t *ent);
void (*think)(edict_t *self); void (*think)(edict_t *self);
void (*blocked)(edict_t *self, edict_t *other); void (*blocked)(edict_t *self, edict_t *other); /* move to moveinfo? */
void (*touch)(edict_t *self, edict_t *other, cplane_t *plane, void (*touch)(edict_t *self, edict_t *other, cplane_t *plane,
csurface_t *surf); csurface_t *surf);
void (*use)(edict_t *self, edict_t *other, edict_t *activator); void (*use)(edict_t *self, edict_t *other, edict_t *activator);
@ -1051,10 +1308,11 @@ struct edict_s
void (*die)(edict_t *self, edict_t *inflictor, edict_t *attacker, void (*die)(edict_t *self, edict_t *inflictor, edict_t *attacker,
int damage, vec3_t point); int damage, vec3_t point);
float touch_debounce_time; float touch_debounce_time; /* now also used by fixbots for timeouts when getting stuck */
float pain_debounce_time; float pain_debounce_time;
float damage_debounce_time; float damage_debounce_time;
float fly_sound_debounce_time; /* now also used by insane marines to store pain sound timeout */ float fly_sound_debounce_time; /* now also used by insane marines to store pain sound timeout */
/* and by fixbots for storing object_repair timeout when getting stuck */
float last_move_time; float last_move_time;
int health; int health;
@ -1107,7 +1365,6 @@ struct edict_s
/* move this to clientinfo? */ /* move this to clientinfo? */
int light_level; int light_level;
int style; /* also used as areaportal number */ int style; /* also used as areaportal number */
gitem_t *item; /* for bonus items */ gitem_t *item; /* for bonus items */
@ -1115,8 +1372,67 @@ struct edict_s
/* common data blocks */ /* common data blocks */
moveinfo_t moveinfo; moveinfo_t moveinfo;
monsterinfo_t monsterinfo; monsterinfo_t monsterinfo;
int orders;
int plat2flags;
vec3_t offset;
vec3_t gravityVector;
edict_t *bad_area;
edict_t *hint_chain;
edict_t *monster_hint_chain;
edict_t *target_hint_chain;
int hint_chain_id;
float lastMoveTime;
}; };
#define SPHERE_DEFENDER 0x0001
#define SPHERE_HUNTER 0x0002
#define SPHERE_VENGEANCE 0x0004
#define SPHERE_DOPPLEGANGER 0x0100
#define SPHERE_TYPE 0x00FF
#define SPHERE_FLAGS 0xFF00
/* deathmatch games */
#define RDM_TAG 2
#define RDM_DEATHBALL 3
typedef struct dm_game_rs
{
void (*GameInit)(void);
void (*PostInitSetup)(void);
void (*ClientBegin)(edict_t *ent);
void (*SelectSpawnPoint)(edict_t *ent, vec3_t origin, vec3_t angles);
void (*PlayerDeath)(edict_t *targ, edict_t *inflictor, edict_t *attacker);
void (*Score)(edict_t *attacker, edict_t *victim, int scoreChange);
void (*PlayerEffects)(edict_t *ent);
void (*DogTag)(edict_t *ent, edict_t *killer, char **pic);
void (*PlayerDisconnect)(edict_t *ent);
int (*ChangeDamage)(edict_t *targ, edict_t *attacker, int damage, int mod);
int (*ChangeKnockback)(edict_t *targ, edict_t *attacker, int knockback, int mod);
int (*CheckDMRules)(void);
} dm_game_rt;
extern dm_game_rt DMGame;
void Tag_GameInit(void);
void Tag_PostInitSetup(void);
void Tag_PlayerDeath(edict_t *targ, edict_t *inflictor, edict_t *attacker);
void Tag_Score(edict_t *attacker, edict_t *victim, int scoreChange);
void Tag_PlayerEffects(edict_t *ent);
void Tag_DogTag(edict_t *ent, edict_t *killer, char **pic);
void Tag_PlayerDisconnect(edict_t *ent);
int Tag_ChangeDamage(edict_t *targ, edict_t *attacker, int damage, int mod);
void DBall_GameInit(void);
void DBall_ClientBegin(edict_t *ent);
void DBall_SelectSpawnPoint(edict_t *ent, vec3_t origin, vec3_t angles);
int DBall_ChangeKnockback(edict_t *targ, edict_t *attacker, int knockback, int mod);
int DBall_ChangeDamage(edict_t *targ, edict_t *attacker, int damage, int mod);
void DBall_PostInitSetup(void);
int DBall_CheckDMRules(void);
/* /*
* Uncomment for check that exported functions declarations are same as in * Uncomment for check that exported functions declarations are same as in
* implementation. (-Wmissing-prototypes ) * implementation. (-Wmissing-prototypes )

View file

@ -521,7 +521,7 @@ berserk_die(edict_t *self, edict_t *inflictor /* unused */, edict_t *attacker /*
if (self->health <= self->gib_health) if (self->health <= self->gib_health)
{ {
gi.sound(self, CHAN_VOICE, gi.soundindex( "misc/udeath.wav"), 1, ATTN_NORM, 0); gi.sound(self, CHAN_VOICE, gi.soundindex("misc/udeath.wav"), 1, ATTN_NORM, 0);
for (n = 0; n < 2; n++) for (n = 0; n < 2; n++)
{ {

View file

@ -873,7 +873,7 @@ makron_torso_die(edict_t *self, edict_t *inflictor /* unused */, edict_t *attack
return; return;
} }
gi.sound(self, CHAN_VOICE, gi.soundindex( "misc/udeath.wav"), 1, ATTN_NORM, 0); gi.sound(self, CHAN_VOICE, gi.soundindex("misc/udeath.wav"), 1, ATTN_NORM, 0);
ThrowGib(self, "models/objects/gibs/sm_meat/tris.md2", ThrowGib(self, "models/objects/gibs/sm_meat/tris.md2",
damage, GIB_ORGANIC); damage, GIB_ORGANIC);
@ -960,7 +960,7 @@ makron_die(edict_t *self, edict_t *inflictor /* unused */, edict_t *attacker /*
/* check for gib */ /* check for gib */
if (self->health <= self->gib_health) if (self->health <= self->gib_health)
{ {
gi.sound(self, CHAN_VOICE, gi.soundindex( "misc/udeath.wav"), 1, ATTN_NORM, 0); gi.sound(self, CHAN_VOICE, gi.soundindex("misc/udeath.wav"), 1, ATTN_NORM, 0);
ThrowGib(self, "models/objects/gibs/sm_meat/tris.md2", ThrowGib(self, "models/objects/gibs/sm_meat/tris.md2",
damage, GIB_ORGANIC); damage, GIB_ORGANIC);

View file

@ -767,7 +767,7 @@ brain_die(edict_t *self, edict_t *inflictor /* unused */, edict_t *attacker /* u
/* check for gib */ /* check for gib */
if (self->health <= self->gib_health) if (self->health <= self->gib_health)
{ {
gi.sound(self, CHAN_VOICE, gi.soundindex( "misc/udeath.wav"), 1, ATTN_NORM, 0); gi.sound(self, CHAN_VOICE, gi.soundindex("misc/udeath.wav"), 1, ATTN_NORM, 0);
for (n = 0; n < 2; n++) for (n = 0; n < 2; n++)
{ {

View file

@ -517,7 +517,7 @@ chick_die(edict_t *self, edict_t *inflictor /* unused */,
/* check for gib */ /* check for gib */
if (self->health <= self->gib_health) if (self->health <= self->gib_health)
{ {
gi.sound(self, CHAN_VOICE, gi.soundindex( "misc/udeath.wav"), 1, ATTN_NORM, 0); gi.sound(self, CHAN_VOICE, gi.soundindex("misc/udeath.wav"), 1, ATTN_NORM, 0);
for (n = 0; n < 2; n++) for (n = 0; n < 2; n++)
{ {

View file

@ -477,7 +477,7 @@ flipper_die(edict_t *self, edict_t *inflictor /* unused */, edict_t *attacker /*
/* check for gib */ /* check for gib */
if (self->health <= self->gib_health) if (self->health <= self->gib_health)
{ {
gi.sound(self, CHAN_VOICE, gi.soundindex( "misc/udeath.wav"), 1, ATTN_NORM, 0); gi.sound(self, CHAN_VOICE, gi.soundindex("misc/udeath.wav"), 1, ATTN_NORM, 0);
for (n = 0; n < 2; n++) for (n = 0; n < 2; n++)
{ {

View file

@ -497,7 +497,7 @@ gladiator_die(edict_t *self, edict_t *inflictor /* unused */,
/* check for gib */ /* check for gib */
if (self->health <= self->gib_health) if (self->health <= self->gib_health)
{ {
gi.sound(self, CHAN_VOICE, gi.soundindex( "misc/udeath.wav"), 1, ATTN_NORM, 0); gi.sound(self, CHAN_VOICE, gi.soundindex("misc/udeath.wav"), 1, ATTN_NORM, 0);
for (n = 0; n < 2; n++) for (n = 0; n < 2; n++)
{ {

View file

@ -513,7 +513,7 @@ gunner_die(edict_t *self, edict_t *inflictor /* unused */,
/* check for gib */ /* check for gib */
if (self->health <= self->gib_health) if (self->health <= self->gib_health)
{ {
gi.sound(self, CHAN_VOICE, gi.soundindex( "misc/udeath.wav"), 1, ATTN_NORM, 0); gi.sound(self, CHAN_VOICE, gi.soundindex("misc/udeath.wav"), 1, ATTN_NORM, 0);
for (n = 0; n < 2; n++) for (n = 0; n < 2; n++)
{ {

View file

@ -527,7 +527,7 @@ infantry_die(edict_t *self, edict_t *inflictor /* unused */,
/* check for gib */ /* check for gib */
if (self->health <= self->gib_health) if (self->health <= self->gib_health)
{ {
gi.sound(self, CHAN_VOICE, gi.soundindex( "misc/udeath.wav"), 1, ATTN_NORM, 0); gi.sound(self, CHAN_VOICE, gi.soundindex("misc/udeath.wav"), 1, ATTN_NORM, 0);
for (n = 0; n < 2; n++) for (n = 0; n < 2; n++)
{ {

View file

@ -888,7 +888,7 @@ insane_die(edict_t *self, edict_t *inflictor /* unused */,
if (self->health <= self->gib_health) if (self->health <= self->gib_health)
{ {
gi.sound(self, CHAN_VOICE, gi.soundindex( "misc/udeath.wav"), 1, ATTN_IDLE, 0); gi.sound(self, CHAN_VOICE, gi.soundindex("misc/udeath.wav"), 1, ATTN_IDLE, 0);
for (n = 0; n < 2; n++) for (n = 0; n < 2; n++)
{ {

View file

@ -593,7 +593,7 @@ medic_die(edict_t *self, edict_t *inflictor /* unused */,
/* check for gib */ /* check for gib */
if (self->health <= self->gib_health) if (self->health <= self->gib_health)
{ {
gi.sound(self, CHAN_VOICE, gi.soundindex( "misc/udeath.wav"), 1, ATTN_NORM, 0); gi.sound(self, CHAN_VOICE, gi.soundindex("misc/udeath.wav"), 1, ATTN_NORM, 0);
for (n = 0; n < 2; n++) for (n = 0; n < 2; n++)
{ {

View file

@ -790,7 +790,7 @@ mutant_die(edict_t *self, edict_t *inflictor /* unused */,
if (self->health <= self->gib_health) if (self->health <= self->gib_health)
{ {
gi.sound(self, CHAN_VOICE, gi.soundindex( "misc/udeath.wav"), 1, ATTN_NORM, 0); gi.sound(self, CHAN_VOICE, gi.soundindex("misc/udeath.wav"), 1, ATTN_NORM, 0);
for (n = 0; n < 2; n++) for (n = 0; n < 2; n++)
{ {