Merge the uncommented rest of the CTF code and fix the Makefile

This commit is contained in:
Yamagi Burmeister 2011-10-05 18:46:23 +00:00
parent 293e360333
commit c958563b2b
20 changed files with 8750 additions and 5407 deletions

View file

@ -11,7 +11,6 @@
# # # #
# Dependencies: # # Dependencies: #
# - SDL 1.2 # # - SDL 1.2 #
# - libX11 #
# - libGL # # - libGL #
# - libvorbis # # - libvorbis #
# - libogg # # - libogg #
@ -398,7 +397,7 @@ SDL_OPENGL_OBJS = $(patsubst %,build/refresher/%,$(SDL_OPENGL_OBJS_))
BASEQ2_OBJS = $(patsubst %,build/baseq2/%,$(BASEQ2_OBJS_)) BASEQ2_OBJS = $(patsubst %,build/baseq2/%,$(BASEQ2_OBJS_))
CTF_OBJS = $(patsubst %,build/baseq2/%,$(CTF_OBJS_)) CTF_OBJS = $(patsubst %,build/ctf/%,$(CTF_OBJS_))
# ---------- # ----------

View file

@ -288,7 +288,12 @@ CheckPowerArmor(edict_t *ent, vec3_t point, vec3_t normal, int damage,
} }
else else
{ {
#ifdef CTF
damagePerCell = 1;
#else
damagePerCell = 2; damagePerCell = 2;
#endif
pa_te_type = TE_SHIELD_SPARKS; pa_te_type = TE_SHIELD_SPARKS;
damage = (2 * damage) / 3; damage = (2 * damage) / 3;
} }
@ -461,6 +466,15 @@ M_ReactToDamage(edict_t *targ, edict_t *attacker)
(strcmp(attacker->classname, "monster_makron") != 0) && (strcmp(attacker->classname, "monster_makron") != 0) &&
(strcmp(attacker->classname, "monster_jorg") != 0)) (strcmp(attacker->classname, "monster_jorg") != 0))
{ {
#ifdef CTF
if (targ->enemy)
{
if (targ->enemy->client)
{
targ->oldenemy = targ->enemy;
}
}
#else
if (targ->enemy && targ->enemy->client) if (targ->enemy && targ->enemy->client)
{ {
targ->oldenemy = targ->enemy; targ->oldenemy = targ->enemy;
@ -480,6 +494,7 @@ M_ReactToDamage(edict_t *targ, edict_t *attacker)
{ {
targ->oldenemy = targ->enemy; targ->oldenemy = targ->enemy;
} }
#endif
targ->enemy = attacker; targ->enemy = attacker;
@ -729,7 +744,14 @@ T_Damage(edict_t *targ, edict_t *inflictor, edict_t *attacker,
SpawnDamage(te_sparks, point, normal); SpawnDamage(te_sparks, point, normal);
} }
#ifdef CTF
if (!CTFMatchSetup())
{
targ->health = targ->health - take; targ->health = targ->health - take;
}
#else
targ->health = targ->health - take;
#endif
if (targ->health <= 0) if (targ->health <= 0)
{ {
@ -760,7 +782,11 @@ T_Damage(edict_t *targ, edict_t *inflictor, edict_t *attacker,
} }
else if (client) else if (client)
{ {
if (!(targ->flags & FL_GODMODE) && (take)) if (!(targ->flags & FL_GODMODE) && (take)
#ifdef CTF
&& !CTFMatchSetup()
#endif
)
{ {
targ->pain(targ, attacker, knockback, take); targ->pain(targ, attacker, knockback, take);
} }

View file

@ -822,6 +822,7 @@ Drop_Ammo(edict_t *ent, gitem_t *item)
dropped->count = ent->client->pers.inventory[index]; dropped->count = ent->client->pers.inventory[index];
} }
#ifndef CTF
if (ent->client->pers.weapon && if (ent->client->pers.weapon &&
(ent->client->pers.weapon->tag == AMMO_GRENADES) && (ent->client->pers.weapon->tag == AMMO_GRENADES) &&
(item->tag == AMMO_GRENADES) && (item->tag == AMMO_GRENADES) &&
@ -831,6 +832,7 @@ Drop_Ammo(edict_t *ent, gitem_t *item)
G_FreeEdict(dropped); G_FreeEdict(dropped);
return; return;
} }
#endif
ent->client->pers.inventory[index] -= dropped->count; ent->client->pers.inventory[index] -= dropped->count;
ValidateSelectedItem(ent); ValidateSelectedItem(ent);
@ -1855,6 +1857,33 @@ gitem_t itemlist[] = {
"misc/power2.wav misc/power1.wav" "misc/power2.wav misc/power1.wav"
}, },
#ifdef CTF
/*
* weapon_grapple (.3 .3 1) (-16 -16 -16) (16 16 16)
* always owned, never in the world
*/
{
"weapon_grapple",
NULL,
Use_Weapon,
NULL,
CTFWeapon_Grapple,
"misc/w_pkup.wav",
NULL, 0,
"models/weapons/grapple/tris.md2",
"w_grapple",
"Grapple",
0,
0,
NULL,
IT_WEAPON,
WEAP_GRAPPLE,
NULL,
0,
"weapons/grapple/grfire.wav weapons/grapple/grpull.wav weapons/grapple/grhang.wav weapons/grapple/grreset.wav weapons/grapple/grhit.wav"
},
#endif
/* weapon_blaster (.3 .3 1) (-16 -16 -16) (16 16 16) /* weapon_blaster (.3 .3 1) (-16 -16 -16) (16 16 16)
always owned, never in the world */ always owned, never in the world */
{ {

View file

@ -234,6 +234,14 @@ EndDMLevel(void)
return; return;
} }
#ifdef CTF
if (*level.forcemap)
{
BeginIntermission(CreateTargetChangeLevel(level.forcemap));
return;
}
#endif
/* see if it's in the map list */ /* see if it's in the map list */
if (*sv_maplist->string) if (*sv_maplist->string)
{ {
@ -393,13 +401,31 @@ ExitLevel(void)
edict_t *ent; edict_t *ent;
char command[256]; char command[256];
#ifndef CTF
Com_sprintf(command, sizeof(command), "gamemap \"%s\"\n", level.changemap); Com_sprintf(command, sizeof(command), "gamemap \"%s\"\n", level.changemap);
gi.AddCommandString(command); gi.AddCommandString(command);
level.changemap = NULL; level.changemap = NULL;
#endif
level.exitintermission = 0; level.exitintermission = 0;
level.intermissiontime = 0; level.intermissiontime = 0;
#ifdef CTF
if (CTFNextMap())
{
return;
}
Com_sprintf(command, sizeof(command), "gamemap \"%s\"\n", level.changemap);
gi.AddCommandString(command);
#endif
ClientEndServerFrames(); ClientEndServerFrames();
#ifdef CTF
level.changemap = NULL;
#endif
/* clear some things before going to next level */ /* clear some things before going to next level */
for (i = 0; i < maxclients->value; i++) for (i = 0; i < maxclients->value; i++)
{ {

View file

@ -526,7 +526,9 @@ path_corner_touch(edict_t *self, edict_t *other, cplane_t *plane /* unused */,
v[2] -= other->mins[2]; v[2] -= other->mins[2];
VectorCopy(v, other->s.origin); VectorCopy(v, other->s.origin);
next = G_PickTarget(next->target); next = G_PickTarget(next->target);
#ifndef CTF
other->s.event = EV_OTHER_TELEPORT; other->s.event = EV_OTHER_TELEPORT;
#endif
} }
other->goalentity = other->movetarget = next; other->goalentity = other->movetarget = next;
@ -697,6 +699,19 @@ TH_viewthing(edict_t *ent)
ent->s.frame = (ent->s.frame + 1) % 7; ent->s.frame = (ent->s.frame + 1) % 7;
ent->nextthink = level.time + FRAMETIME; ent->nextthink = level.time + FRAMETIME;
#ifdef CTF
static int robotron[4];
if (ent->spawnflags)
{
if (ent->s.frame == 0)
{
ent->spawnflags = (ent->spawnflags + 1) % 4 + 1;
ent->s.modelindex = robotron[ent->spawnflags - 1];
}
}
#endif
} }
void void
@ -2500,8 +2515,10 @@ func_clock_think(edict_t *self)
if (!(self->spawnflags & 8)) if (!(self->spawnflags & 8))
{ {
#ifndef CTF
self->think = G_FreeEdict; self->think = G_FreeEdict;
self->nextthink = level.time + 1; self->nextthink = level.time + 1;
#endif
return; return;
} }

View file

@ -76,10 +76,12 @@ SV_TestEntityPosition(edict_t *ent)
if (trace.startsolid) if (trace.startsolid)
{ {
#ifndef CTF
if ((ent->svflags & SVF_DEADMONSTER) && (trace.ent->client || (trace.ent->svflags & SVF_MONSTER))) if ((ent->svflags & SVF_DEADMONSTER) && (trace.ent->client || (trace.ent->svflags & SVF_MONSTER)))
{ {
return NULL; return NULL;
} }
#endif
return g_edicts; return g_edicts;
} }
@ -526,11 +528,13 @@ retry:
trace = gi.trace(start, ent->mins, ent->maxs, end, ent, mask); trace = gi.trace(start, ent->mins, ent->maxs, end, ent, mask);
#ifndef CTF
if (trace.startsolid || trace.allsolid) if (trace.startsolid || trace.allsolid)
{ {
mask ^= CONTENTS_DEADMONSTER; mask ^= CONTENTS_DEADMONSTER;
trace = gi.trace (start, ent->mins, ent->maxs, end, ent, mask); trace = gi.trace (start, ent->mins, ent->maxs, end, ent, mask);
} }
#endif
VectorCopy(trace.endpos, ent->s.origin); VectorCopy(trace.endpos, ent->s.origin);
gi.linkentity(ent); gi.linkentity(ent);

View file

@ -1026,6 +1026,7 @@ SP_worldspawn(edict_t *ent)
gi.modelindex("#w_hyperblaster.md2"); gi.modelindex("#w_hyperblaster.md2");
gi.modelindex("#w_railgun.md2"); gi.modelindex("#w_railgun.md2");
gi.modelindex("#w_bfg.md2"); gi.modelindex("#w_bfg.md2");
gi.modelindex("#w_grapple.md2");
/* ------------------- */ /* ------------------- */

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -1,22 +1,22 @@
/* /*
Copyright (C) 1997-2001 Id Software, Inc. * Copyright (C) 1997-2001 Id Software, Inc.
*
This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2 * as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version. * of the License, or (at your option) any later version.
*
This program is distributed in the hope that it will be useful, * This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*
See the GNU General Public License for more details. * See the GNU General Public License for more details.
*
You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software * along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
*/ */
#include "g_local.h" #include "g_local.h"
@ -38,10 +38,10 @@ cvar_t *dmflags;
cvar_t *skill; cvar_t *skill;
cvar_t *fraglimit; cvar_t *fraglimit;
cvar_t *timelimit; cvar_t *timelimit;
//ZOID /* ZOID */
cvar_t *capturelimit; cvar_t *capturelimit;
cvar_t *instantweap; cvar_t *instantweap;
//ZOID /* ZOID */
cvar_t *password; cvar_t *password;
cvar_t *maxclients; cvar_t *maxclients;
cvar_t *maxentities; cvar_t *maxentities;
@ -73,43 +73,42 @@ cvar_t *flood_waitdelay;
cvar_t *sv_maplist; cvar_t *sv_maplist;
void SpawnEntities (char *mapname, char *entities, char *spawnpoint); void SpawnEntities(char *mapname, char *entities, char *spawnpoint);
void ClientThink (edict_t *ent, usercmd_t *cmd); void ClientThink(edict_t *ent, usercmd_t *cmd);
qboolean ClientConnect (edict_t *ent, char *userinfo); qboolean ClientConnect(edict_t *ent, char *userinfo);
void ClientUserinfoChanged (edict_t *ent, char *userinfo); void ClientUserinfoChanged(edict_t *ent, char *userinfo);
void ClientDisconnect (edict_t *ent); void ClientDisconnect(edict_t *ent);
void ClientBegin (edict_t *ent); void ClientBegin(edict_t *ent);
void ClientCommand (edict_t *ent); void ClientCommand(edict_t *ent);
void RunEntity (edict_t *ent); void RunEntity(edict_t *ent);
void WriteGame (char *filename, qboolean autosave); void WriteGame(char *filename, qboolean autosave);
void ReadGame (char *filename); void ReadGame(char *filename);
void WriteLevel (char *filename); void WriteLevel(char *filename);
void ReadLevel (char *filename); void ReadLevel(char *filename);
void InitGame (void); void InitGame(void);
void G_RunFrame (void); void G_RunFrame(void);
/* =================================================================== */
//=================================================================== void
ShutdownGame(void)
void ShutdownGame (void)
{ {
gi.dprintf ("==== ShutdownGame ====\n"); gi.dprintf("==== ShutdownGame ====\n");
gi.FreeTags (TAG_LEVEL); gi.FreeTags(TAG_LEVEL);
gi.FreeTags (TAG_GAME); gi.FreeTags(TAG_GAME);
} }
/* /*
================= * =================
GetGameAPI * GetGameAPI
*
Returns a pointer to the structure with all entry points * Returns a pointer to the structure with all entry points
and global variables * and global variables
================= * =================
*/ */
game_export_t *GetGameAPI (game_import_t *import) game_export_t *
GetGameAPI(game_import_t *import)
{ {
gi = *import; gi = *import;
@ -140,70 +139,76 @@ game_export_t *GetGameAPI (game_import_t *import)
} }
#ifndef GAME_HARD_LINKED #ifndef GAME_HARD_LINKED
// this is only here so the functions in q_shared.c and q_shwin.c can link /* this is only here so the functions in q_shared.c and q_shwin.c can link */
void Sys_Error (char *error, ...) void
Sys_Error(char *error, ...)
{ {
va_list argptr; va_list argptr;
char text[1024]; char text[1024];
va_start (argptr, error); va_start(argptr, error);
vsprintf (text, error, argptr); vsprintf(text, error, argptr);
va_end (argptr); va_end(argptr);
gi.error (ERR_FATAL, "%s", text); gi.error(ERR_FATAL, "%s", text);
} }
void Com_Printf (char *msg, ...) void
Com_Printf(char *msg, ...)
{ {
va_list argptr; va_list argptr;
char text[1024]; char text[1024];
va_start (argptr, msg); va_start(argptr, msg);
vsprintf (text, msg, argptr); vsprintf(text, msg, argptr);
va_end (argptr); va_end(argptr);
gi.dprintf ("%s", text); gi.dprintf("%s", text);
} }
#endif #endif
//====================================================================== /* ====================================================================== */
/* /*
================= * =================
ClientEndServerFrames * ClientEndServerFrames
================= * =================
*/ */
void ClientEndServerFrames (void) void
ClientEndServerFrames(void)
{ {
int i; int i;
edict_t *ent; edict_t *ent;
// calc the player views now that all pushing /* calc the player views now that all pushing */
// and damage has been added /* and damage has been added */
for (i=0 ; i<maxclients->value ; i++) for (i = 0; i < maxclients->value; i++)
{ {
ent = g_edicts + 1 + i; ent = g_edicts + 1 + i;
if (!ent->inuse || !ent->client) if (!ent->inuse || !ent->client)
{
continue; continue;
ClientEndServerFrame (ent);
} }
ClientEndServerFrame(ent);
}
} }
/* /*
================= * =================
CreateTargetChangeLevel * CreateTargetChangeLevel
*
Returns the created target changelevel * Returns the created target changelevel
================= * =================
*/ */
edict_t *CreateTargetChangeLevel(char *map) edict_t *
CreateTargetChangeLevel(char *map)
{ {
edict_t *ent; edict_t *ent;
ent = G_Spawn (); ent = G_Spawn();
ent->classname = "target_changelevel"; ent->classname = "target_changelevel";
Com_sprintf(level.nextmap, sizeof(level.nextmap), "%s", map); Com_sprintf(level.nextmap, sizeof(level.nextmap), "%s", map);
ent->map = level.nextmap; ent->map = level.nextmap;
@ -211,219 +216,275 @@ edict_t *CreateTargetChangeLevel(char *map)
} }
/* /*
================= * =================
EndDMLevel * EndDMLevel
*
The timelimit or fraglimit has been exceeded * The timelimit or fraglimit has been exceeded
================= * =================
*/ */
void EndDMLevel (void) void
EndDMLevel(void)
{ {
edict_t *ent; edict_t *ent;
char *s, *t, *f; char *s, *t, *f;
static const char *seps = " ,\n\r"; static const char *seps = " ,\n\r";
// stay on same level flag /* stay on same level flag */
if ((int)dmflags->value & DF_SAME_LEVEL) if ((int)dmflags->value & DF_SAME_LEVEL)
{ {
BeginIntermission (CreateTargetChangeLevel (level.mapname) ); BeginIntermission(CreateTargetChangeLevel(level.mapname));
return; return;
} }
if (*level.forcemap) { if (*level.forcemap)
BeginIntermission (CreateTargetChangeLevel (level.forcemap) ); {
BeginIntermission(CreateTargetChangeLevel(level.forcemap));
return; return;
} }
// see if it's in the map list /* see if it's in the map list */
if (*sv_maplist->string) { if (*sv_maplist->string)
{
s = strdup(sv_maplist->string); s = strdup(sv_maplist->string);
f = NULL; f = NULL;
t = strtok(s, seps); t = strtok(s, seps);
while (t != NULL) {
if (Q_stricmp(t, level.mapname) == 0) { while (t != NULL)
// it's in the list, go to the next one {
if (Q_stricmp(t, level.mapname) == 0)
{
/* it's in the list, go to the next one */
t = strtok(NULL, seps); t = strtok(NULL, seps);
if (t == NULL) { // end of list, go to first one
if (f == NULL) // there isn't a first one, same level if (t == NULL) /* end of list, go to first one */
BeginIntermission (CreateTargetChangeLevel (level.mapname) ); {
if (f == NULL) /* there isn't a first one, same level */
{
BeginIntermission(CreateTargetChangeLevel(level.mapname));
}
else else
BeginIntermission (CreateTargetChangeLevel (f) ); {
} else BeginIntermission(CreateTargetChangeLevel(f));
BeginIntermission (CreateTargetChangeLevel (t) ); }
}
else
{
BeginIntermission(CreateTargetChangeLevel(t));
}
free(s); free(s);
return; return;
} }
if (!f) if (!f)
{
f = t; f = t;
}
t = strtok(NULL, seps); t = strtok(NULL, seps);
} }
free(s); free(s);
} }
if (level.nextmap[0]) // go to a specific map if (level.nextmap[0]) /* go to a specific map */
BeginIntermission (CreateTargetChangeLevel (level.nextmap) ); {
else { // search for a changelevel BeginIntermission(CreateTargetChangeLevel(level.nextmap));
ent = G_Find (NULL, FOFS(classname), "target_changelevel"); }
else /* search for a changelevel */
{
ent = G_Find(NULL, FOFS(classname), "target_changelevel");
if (!ent) if (!ent)
{ // the map designer didn't include a changelevel, { /* the map designer didn't include a changelevel, */
// so create a fake ent that goes back to the same level /* so create a fake ent that goes back to the same level */
BeginIntermission (CreateTargetChangeLevel (level.mapname) ); BeginIntermission(CreateTargetChangeLevel(level.mapname));
return; return;
} }
BeginIntermission (ent);
BeginIntermission(ent);
} }
} }
/* /*
================= * =================
CheckDMRules * CheckDMRules
================= * =================
*/ */
void CheckDMRules (void) void
CheckDMRules(void)
{ {
int i; int i;
gclient_t *cl; gclient_t *cl;
if (level.intermissiontime) if (level.intermissiontime)
return; {
if (!deathmatch->value)
return;
//ZOID
if (ctf->value && CTFCheckRules()) {
EndDMLevel ();
return; return;
} }
if (!deathmatch->value)
{
return;
}
/* ZOID */
if (ctf->value && CTFCheckRules())
{
EndDMLevel();
return;
}
if (CTFInMatch()) if (CTFInMatch())
return; // no checking in match mode {
//ZOID return; /* no checking in match mode */
}
/* ZOID */
if (timelimit->value) if (timelimit->value)
{ {
if (level.time >= timelimit->value*60) if (level.time >= timelimit->value * 60)
{ {
gi.bprintf (PRINT_HIGH, "Timelimit hit.\n"); gi.bprintf(PRINT_HIGH, "Timelimit hit.\n");
EndDMLevel (); EndDMLevel();
return; return;
} }
} }
if (fraglimit->value) if (fraglimit->value)
for (i=0 ; i<maxclients->value ; i++) {
for (i = 0; i < maxclients->value; i++)
{ {
cl = game.clients + i; cl = game.clients + i;
if (!g_edicts[i+1].inuse)
if (!g_edicts[i + 1].inuse)
{
continue; continue;
}
if (cl->resp.score >= fraglimit->value) if (cl->resp.score >= fraglimit->value)
{ {
gi.bprintf (PRINT_HIGH, "Fraglimit hit.\n"); gi.bprintf(PRINT_HIGH, "Fraglimit hit.\n");
EndDMLevel (); EndDMLevel();
return; return;
} }
} }
}
} }
/* /*
============= * =============
ExitLevel * ExitLevel
============= * =============
*/ */
void ExitLevel (void) void
ExitLevel(void)
{ {
int i; int i;
edict_t *ent; edict_t *ent;
char command [256]; char command[256];
level.exitintermission = 0; level.exitintermission = 0;
level.intermissiontime = 0; level.intermissiontime = 0;
if (CTFNextMap()) if (CTFNextMap())
{
return; return;
}
Com_sprintf (command, sizeof(command), "gamemap \"%s\"\n", level.changemap); Com_sprintf(command, sizeof(command), "gamemap \"%s\"\n", level.changemap);
gi.AddCommandString (command); gi.AddCommandString(command);
ClientEndServerFrames (); ClientEndServerFrames();
level.changemap = NULL; level.changemap = NULL;
// clear some things before going to next level /* clear some things before going to next level */
for (i=0 ; i<maxclients->value ; i++) for (i = 0; i < maxclients->value; i++)
{ {
ent = g_edicts + 1 + i; ent = g_edicts + 1 + i;
if (!ent->inuse) if (!ent->inuse)
{
continue; continue;
}
if (ent->health > ent->client->pers.max_health) if (ent->health > ent->client->pers.max_health)
{
ent->health = ent->client->pers.max_health; ent->health = ent->client->pers.max_health;
} }
}
} }
/* /*
================ * ================
G_RunFrame * G_RunFrame
*
Advances the world by 0.1 seconds * Advances the world by 0.1 seconds
================ * ================
*/ */
void G_RunFrame (void) void
G_RunFrame(void)
{ {
int i; int i;
edict_t *ent; edict_t *ent;
level.framenum++; level.framenum++;
level.time = level.framenum*FRAMETIME; level.time = level.framenum * FRAMETIME;
// choose a client for monsters to target this frame /* choose a client for monsters to target this frame */
AI_SetSightClient (); AI_SetSightClient();
// exit intermissions /* exit intermissions */
if (level.exitintermission) if (level.exitintermission)
{ {
ExitLevel (); ExitLevel();
return; return;
} }
// /* */
// treat each object in turn /* treat each object in turn */
// even the world gets a chance to think /* even the world gets a chance to think */
// /* */
ent = &g_edicts[0]; ent = &g_edicts[0];
for (i=0 ; i<globals.num_edicts ; i++, ent++)
for (i = 0; i < globals.num_edicts; i++, ent++)
{ {
if (!ent->inuse) if (!ent->inuse)
{
continue; continue;
}
level.current_entity = ent; level.current_entity = ent;
VectorCopy (ent->s.origin, ent->s.old_origin); VectorCopy(ent->s.origin, ent->s.old_origin);
// if the ground entity moved, make sure we are still on it /* if the ground entity moved, make sure we are still on it */
if ((ent->groundentity) && (ent->groundentity->linkcount != ent->groundentity_linkcount)) if ((ent->groundentity) &&
(ent->groundentity->linkcount != ent->groundentity_linkcount))
{ {
ent->groundentity = NULL; ent->groundentity = NULL;
if ( !(ent->flags & (FL_SWIM|FL_FLY)) && (ent->svflags & SVF_MONSTER) )
if (!(ent->flags & (FL_SWIM | FL_FLY)) &&
(ent->svflags & SVF_MONSTER))
{ {
M_CheckGround (ent); M_CheckGround(ent);
} }
} }
if (i > 0 && i <= maxclients->value) if ((i > 0) && (i <= maxclients->value))
{ {
ClientBeginServerFrame (ent); ClientBeginServerFrame(ent);
continue; continue;
} }
G_RunEntity (ent); G_RunEntity(ent);
} }
// see if it is time to end a deathmatch /* see if it is time to end a deathmatch */
CheckDMRules (); CheckDMRules();
// build the playerstate_t structures for all players /* build the playerstate_t structures for all players */
ClientEndServerFrames (); ClientEndServerFrames();
} }

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -1,61 +1,61 @@
/* /*
Copyright (C) 1997-2001 Id Software, Inc. * Copyright (C) 1997-2001 Id Software, Inc.
*
This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2 * as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version. * of the License, or (at your option) any later version.
*
This program is distributed in the hope that it will be useful, * This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*
See the GNU General Public License for more details. * See the GNU General Public License for more details.
*
You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software * along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
*/ */
#include "g_local.h" #include "g_local.h"
void
void Svcmd_Test_f (void) Svcmd_Test_f(void)
{ {
gi.cprintf (NULL, PRINT_HIGH, "Svcmd_Test_f()\n"); gi.cprintf(NULL, PRINT_HIGH, "Svcmd_Test_f()\n");
} }
/* /*
============================================================================== * ==============================================================================
*
PACKET FILTERING * PACKET FILTERING
*
*
You can add or remove addresses from the filter list with: * You can add or remove addresses from the filter list with:
*
addip <ip> * addip <ip>
removeip <ip> * removeip <ip>
*
The ip address is specified in dot format, and any unspecified digits will match any value, so you can specify an entire class C network with "addip 192.246.40". * The ip address is specified in dot format, and any unspecified digits will match any value, so you can specify an entire class C network with "addip 192.246.40".
*
Removeip will only remove an address specified exactly the same way. You cannot addip a subnet, then removeip a single host. * Removeip will only remove an address specified exactly the same way. You cannot addip a subnet, then removeip a single host.
*
listip * listip
Prints the current list of filters. * Prints the current list of filters.
*
writeip * writeip
Dumps "addip <ip>" commands to listip.cfg so it can be execed at a later date. The filter lists are not saved and restored by default, because I beleive it would cause too much confusion. * Dumps "addip <ip>" commands to listip.cfg so it can be execed at a later date. The filter lists are not saved and restored by default, because I beleive it would cause too much confusion.
*
filterban <0 or 1> * filterban <0 or 1>
*
If 1 (the default), then ip addresses matching the current list will be prohibited from entering the game. This is the default setting. * If 1 (the default), then ip addresses matching the current list will be prohibited from entering the game. This is the default setting.
*
If 0, then only addresses matching the list will be allowed. This lets you easily set up a private game, or a game that only allows players from your local network. * If 0, then only addresses matching the list will be allowed. This lets you easily set up a private game, or a game that only allows players from your local network.
*
*
============================================================================== * ==============================================================================
*/ */
typedef struct typedef struct
{ {
@ -69,43 +69,52 @@ ipfilter_t ipfilters[MAX_IPFILTERS];
int numipfilters; int numipfilters;
/* /*
================= * =================
StringToFilter * StringToFilter
================= * =================
*/ */
static qboolean StringToFilter (char *s, ipfilter_t *f) static qboolean
StringToFilter(char *s, ipfilter_t *f)
{ {
char num[128]; char num[128];
int i, j; int i, j;
byte b[4]; byte b[4];
byte m[4]; byte m[4];
for (i=0 ; i<4 ; i++) for (i = 0; i < 4; i++)
{ {
b[i] = 0; b[i] = 0;
m[i] = 0; m[i] = 0;
} }
for (i=0 ; i<4 ; i++) for (i = 0; i < 4; i++)
{ {
if (*s < '0' || *s > '9') if ((*s < '0') || (*s > '9'))
{ {
gi.cprintf(NULL, PRINT_HIGH, "Bad filter address: %s\n", s); gi.cprintf(NULL, PRINT_HIGH, "Bad filter address: %s\n", s);
return false; return false;
} }
j = 0; j = 0;
while (*s >= '0' && *s <= '9') while (*s >= '0' && *s <= '9')
{ {
num[j++] = *s++; num[j++] = *s++;
} }
num[j] = 0; num[j] = 0;
b[i] = atoi(num); b[i] = atoi(num);
if (b[i] != 0) if (b[i] != 0)
{
m[i] = 255; m[i] = 255;
}
if (!*s) if (!*s)
{
break; break;
}
s++; s++;
} }
@ -116,11 +125,12 @@ static qboolean StringToFilter (char *s, ipfilter_t *f)
} }
/* /*
================= * =================
SV_FilterPacket * SV_FilterPacket
================= * =================
*/ */
qboolean SV_FilterPacket (char *from) qboolean
SV_FilterPacket(char *from)
{ {
int i; int i;
unsigned in; unsigned in;
@ -129,113 +139,153 @@ qboolean SV_FilterPacket (char *from)
i = 0; i = 0;
p = from; p = from;
while (*p && i < 4) {
while (*p && i < 4)
{
m[i] = 0; m[i] = 0;
while (*p >= '0' && *p <= '9') {
m[i] = m[i]*10 + (*p - '0'); while (*p >= '0' && *p <= '9')
{
m[i] = m[i] * 10 + (*p - '0');
p++; p++;
} }
if (!*p || *p == ':')
if (!*p || (*p == ':'))
{
break; break;
}
i++, p++; i++, p++;
} }
in = *(unsigned *)m; in = *(unsigned *)m;
for (i=0 ; i<numipfilters ; i++) for (i = 0; i < numipfilters; i++)
if ( (in & ipfilters[i].mask) == ipfilters[i].compare) {
if ((in & ipfilters[i].mask) == ipfilters[i].compare)
{
return (int)filterban->value; return (int)filterban->value;
}
}
return (int)!filterban->value; return (int)!filterban->value;
} }
/* /*
================= * =================
SV_AddIP_f * SV_AddIP_f
================= * =================
*/ */
void SVCmd_AddIP_f (void) void
SVCmd_AddIP_f(void)
{ {
int i; int i;
if (gi.argc() < 3) { if (gi.argc() < 3)
{
gi.cprintf(NULL, PRINT_HIGH, "Usage: addip <ip-mask>\n"); gi.cprintf(NULL, PRINT_HIGH, "Usage: addip <ip-mask>\n");
return; return;
} }
for (i=0 ; i<numipfilters ; i++) for (i = 0; i < numipfilters; i++)
{
if (ipfilters[i].compare == 0xffffffff) if (ipfilters[i].compare == 0xffffffff)
break; // free spot {
break; /* free spot */
}
}
if (i == numipfilters) if (i == numipfilters)
{ {
if (numipfilters == MAX_IPFILTERS) if (numipfilters == MAX_IPFILTERS)
{ {
gi.cprintf (NULL, PRINT_HIGH, "IP filter list is full\n"); gi.cprintf(NULL, PRINT_HIGH, "IP filter list is full\n");
return; return;
} }
numipfilters++; numipfilters++;
} }
if (!StringToFilter (gi.argv(2), &ipfilters[i])) if (!StringToFilter(gi.argv(2), &ipfilters[i]))
{
ipfilters[i].compare = 0xffffffff; ipfilters[i].compare = 0xffffffff;
}
} }
/* /*
================= * =================
SV_RemoveIP_f * SV_RemoveIP_f
================= * =================
*/ */
void SVCmd_RemoveIP_f (void) void
SVCmd_RemoveIP_f(void)
{ {
ipfilter_t f; ipfilter_t f;
int i, j; int i, j;
if (gi.argc() < 3) { if (gi.argc() < 3)
{
gi.cprintf(NULL, PRINT_HIGH, "Usage: sv removeip <ip-mask>\n"); gi.cprintf(NULL, PRINT_HIGH, "Usage: sv removeip <ip-mask>\n");
return; return;
} }
if (!StringToFilter (gi.argv(2), &f)) if (!StringToFilter(gi.argv(2), &f))
return;
for (i=0 ; i<numipfilters ; i++)
if (ipfilters[i].mask == f.mask
&& ipfilters[i].compare == f.compare)
{ {
for (j=i+1 ; j<numipfilters ; j++)
ipfilters[j-1] = ipfilters[j];
numipfilters--;
gi.cprintf (NULL, PRINT_HIGH, "Removed.\n");
return; return;
} }
gi.cprintf (NULL, PRINT_HIGH, "Didn't find %s.\n", gi.argv(2));
for (i = 0; i < numipfilters; i++)
{
if ((ipfilters[i].mask == f.mask) &&
(ipfilters[i].compare == f.compare))
{
for (j = i + 1; j < numipfilters; j++)
{
ipfilters[j - 1] = ipfilters[j];
}
numipfilters--;
gi.cprintf(NULL, PRINT_HIGH, "Removed.\n");
return;
}
}
gi.cprintf(NULL, PRINT_HIGH, "Didn't find %s.\n", gi.argv(2));
} }
/* /*
================= * =================
SV_ListIP_f * SV_ListIP_f
================= * =================
*/ */
void SVCmd_ListIP_f (void) void
SVCmd_ListIP_f(void)
{ {
int i; int i;
byte b[4]; byte b[4];
gi.cprintf (NULL, PRINT_HIGH, "Filter list:\n"); gi.cprintf(NULL, PRINT_HIGH, "Filter list:\n");
for (i=0 ; i<numipfilters ; i++)
for (i = 0; i < numipfilters; i++)
{ {
*(unsigned *)b = ipfilters[i].compare; *(unsigned *)b = ipfilters[i].compare;
gi.cprintf (NULL, PRINT_HIGH, "%3i.%3i.%3i.%3i\n", b[0], b[1], b[2], b[3]); gi.cprintf(NULL,
PRINT_HIGH,
"%3i.%3i.%3i.%3i\n",
b[0],
b[1],
b[2],
b[3]);
} }
} }
/* /*
================= * =================
SV_WriteIP_f * SV_WriteIP_f
================= * =================
*/ */
void SVCmd_WriteIP_f (void) void
SVCmd_WriteIP_f(void)
{ {
FILE *f; FILE *f;
char name[MAX_OSPATH]; char name[MAX_OSPATH];
@ -246,55 +296,74 @@ void SVCmd_WriteIP_f (void)
game = gi.cvar("game", "", 0); game = gi.cvar("game", "", 0);
if (!*game->string) if (!*game->string)
sprintf (name, "%s/listip.cfg", GAMEVERSION); {
sprintf(name, "%s/listip.cfg", GAMEVERSION);
}
else else
sprintf (name, "%s/listip.cfg", game->string); {
sprintf(name, "%s/listip.cfg", game->string);
}
gi.cprintf (NULL, PRINT_HIGH, "Writing %s.\n", name); gi.cprintf(NULL, PRINT_HIGH, "Writing %s.\n", name);
f = fopen(name, "wb");
f = fopen (name, "wb");
if (!f) if (!f)
{ {
gi.cprintf (NULL, PRINT_HIGH, "Couldn't open %s\n", name); gi.cprintf(NULL, PRINT_HIGH, "Couldn't open %s\n", name);
return; return;
} }
fprintf(f, "set filterban %d\n", (int)filterban->value); fprintf(f, "set filterban %d\n", (int)filterban->value);
for (i=0 ; i<numipfilters ; i++) for (i = 0; i < numipfilters; i++)
{ {
*(unsigned *)b = ipfilters[i].compare; *(unsigned *)b = ipfilters[i].compare;
fprintf (f, "sv addip %i.%i.%i.%i\n", b[0], b[1], b[2], b[3]); fprintf(f, "sv addip %i.%i.%i.%i\n", b[0], b[1], b[2], b[3]);
} }
fclose (f); fclose(f);
} }
/* /*
================= * =================
ServerCommand * ServerCommand
*
ServerCommand will be called when an "sv" command is issued. * ServerCommand will be called when an "sv" command is issued.
The game can issue gi.argc() / gi.argv() commands to get the rest * The game can issue gi.argc() / gi.argv() commands to get the rest
of the parameters * of the parameters
================= * =================
*/ */
void ServerCommand (void) void
ServerCommand(void)
{ {
char *cmd; char *cmd;
cmd = gi.argv(1); cmd = gi.argv(1);
if (Q_stricmp (cmd, "test") == 0)
Svcmd_Test_f (); if (Q_stricmp(cmd, "test") == 0)
else if (Q_stricmp (cmd, "addip") == 0) {
SVCmd_AddIP_f (); Svcmd_Test_f();
else if (Q_stricmp (cmd, "removeip") == 0) }
SVCmd_RemoveIP_f (); else if (Q_stricmp(cmd, "addip") == 0)
else if (Q_stricmp (cmd, "listip") == 0) {
SVCmd_ListIP_f (); SVCmd_AddIP_f();
else if (Q_stricmp (cmd, "writeip") == 0) }
SVCmd_WriteIP_f (); else if (Q_stricmp(cmd, "removeip") == 0)
{
SVCmd_RemoveIP_f();
}
else if (Q_stricmp(cmd, "listip") == 0)
{
SVCmd_ListIP_f();
}
else if (Q_stricmp(cmd, "writeip") == 0)
{
SVCmd_WriteIP_f();
}
else else
gi.cprintf (NULL, PRINT_HIGH, "Unknown server command \"%s\"\n", cmd); {
gi.cprintf(NULL, PRINT_HIGH, "Unknown server command \"%s\"\n", cmd);
}
} }

File diff suppressed because it is too large Load diff

View file

@ -1,53 +1,57 @@
/* /*
Copyright (C) 1997-2001 Id Software, Inc. * Copyright (C) 1997-2001 Id Software, Inc.
*
This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2 * as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version. * of the License, or (at your option) any later version.
*
This program is distributed in the hope that it will be useful, * This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*
See the GNU General Public License for more details. * See the GNU General Public License for more details.
*
You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software * along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
*/ */
#include "g_local.h" #include "g_local.h"
void
void InitTrigger (edict_t *self) InitTrigger(edict_t *self)
{ {
if (!VectorCompare (self->s.angles, vec3_origin)) if (!VectorCompare(self->s.angles, vec3_origin))
G_SetMovedir (self->s.angles, self->movedir); {
G_SetMovedir(self->s.angles, self->movedir);
}
self->solid = SOLID_TRIGGER; self->solid = SOLID_TRIGGER;
self->movetype = MOVETYPE_NONE; self->movetype = MOVETYPE_NONE;
gi.setmodel (self, self->model); gi.setmodel(self, self->model);
self->svflags = SVF_NOCLIENT; self->svflags = SVF_NOCLIENT;
} }
/* the wait time has passed, so set back up for another activation */
// the wait time has passed, so set back up for another activation void
void multi_wait (edict_t *ent) multi_wait(edict_t *ent)
{ {
ent->nextthink = 0; ent->nextthink = 0;
} }
/* the trigger was just activated */
// the trigger was just activated /* ent->activator should be set to the activator so it can be held through a delay */
// ent->activator should be set to the activator so it can be held through a delay /* so wait for the delay time before firing */
// so wait for the delay time before firing void
void multi_trigger (edict_t *ent) multi_trigger(edict_t *ent)
{ {
if (ent->nextthink) if (ent->nextthink)
return; // already been triggered {
return; /* already been triggered */
}
G_UseTargets (ent, ent->activator); G_UseTargets(ent, ent->activator);
if (ent->wait > 0) if (ent->wait > 0)
{ {
@ -55,82 +59,104 @@ void multi_trigger (edict_t *ent)
ent->nextthink = level.time + ent->wait; ent->nextthink = level.time + ent->wait;
} }
else else
{ // we can't just remove (self) here, because this is a touch function {
// called while looping through area links... /* we can't just remove (self) here, because this is a touch function */
/* called while looping through area links... */
ent->touch = NULL; ent->touch = NULL;
ent->nextthink = level.time + FRAMETIME; ent->nextthink = level.time + FRAMETIME;
ent->think = G_FreeEdict; ent->think = G_FreeEdict;
} }
} }
void Use_Multi (edict_t *ent, edict_t *other, edict_t *activator) void
Use_Multi(edict_t *ent, edict_t *other, edict_t *activator)
{ {
ent->activator = activator; ent->activator = activator;
multi_trigger (ent); multi_trigger(ent);
} }
void Touch_Multi (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf) void
Touch_Multi(edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf)
{ {
if(other->client) if (other->client)
{ {
if (self->spawnflags & 2) if (self->spawnflags & 2)
{
return; return;
} }
}
else if (other->svflags & SVF_MONSTER) else if (other->svflags & SVF_MONSTER)
{ {
if (!(self->spawnflags & 1)) if (!(self->spawnflags & 1))
{
return; return;
} }
}
else else
{
return; return;
}
if (!VectorCompare(self->movedir, vec3_origin)) if (!VectorCompare(self->movedir, vec3_origin))
{ {
vec3_t forward; vec3_t forward;
AngleVectors(other->s.angles, forward, NULL, NULL); AngleVectors(other->s.angles, forward, NULL, NULL);
if (_DotProduct(forward, self->movedir) < 0) if (_DotProduct(forward, self->movedir) < 0)
{
return; return;
} }
}
self->activator = other; self->activator = other;
multi_trigger (self); multi_trigger(self);
} }
/*QUAKED trigger_multiple (.5 .5 .5) ? MONSTER NOT_PLAYER TRIGGERED /*QUAKED trigger_multiple (.5 .5 .5) ? MONSTER NOT_PLAYER TRIGGERED
Variable sized repeatable trigger. Must be targeted at one or more entities. * Variable sized repeatable trigger. Must be targeted at one or more entities.
If "delay" is set, the trigger waits some time after activating before firing. * If "delay" is set, the trigger waits some time after activating before firing.
"wait" : Seconds between triggerings. (.2 default) * "wait" : Seconds between triggerings. (.2 default)
sounds * sounds
1) secret * 1) secret
2) beep beep * 2) beep beep
3) large switch * 3) large switch
4) * 4)
set "message" to text string * set "message" to text string
*/ */
void trigger_enable (edict_t *self, edict_t *other, edict_t *activator) void
trigger_enable(edict_t *self, edict_t *other, edict_t *activator)
{ {
self->solid = SOLID_TRIGGER; self->solid = SOLID_TRIGGER;
self->use = Use_Multi; self->use = Use_Multi;
gi.linkentity (self); gi.linkentity(self);
} }
void SP_trigger_multiple (edict_t *ent) void
SP_trigger_multiple(edict_t *ent)
{ {
if (ent->sounds == 1) if (ent->sounds == 1)
ent->noise_index = gi.soundindex ("misc/secret.wav"); {
ent->noise_index = gi.soundindex("misc/secret.wav");
}
else if (ent->sounds == 2) else if (ent->sounds == 2)
ent->noise_index = gi.soundindex ("misc/talk.wav"); {
ent->noise_index = gi.soundindex("misc/talk.wav");
}
else if (ent->sounds == 3) else if (ent->sounds == 3)
ent->noise_index = gi.soundindex ("misc/trigger1.wav"); {
ent->noise_index = gi.soundindex("misc/trigger1.wav");
}
if (!ent->wait) if (!ent->wait)
{
ent->wait = 0.2; ent->wait = 0.2;
}
ent->touch = Touch_Multi; ent->touch = Touch_Multi;
ent->movetype = MOVETYPE_NONE; ent->movetype = MOVETYPE_NONE;
ent->svflags |= SVF_NOCLIENT; ent->svflags |= SVF_NOCLIENT;
if (ent->spawnflags & 4) if (ent->spawnflags & 4)
{ {
ent->solid = SOLID_NOT; ent->solid = SOLID_NOT;
@ -143,93 +169,109 @@ void SP_trigger_multiple (edict_t *ent)
} }
if (!VectorCompare(ent->s.angles, vec3_origin)) if (!VectorCompare(ent->s.angles, vec3_origin))
G_SetMovedir (ent->s.angles, ent->movedir); {
G_SetMovedir(ent->s.angles, ent->movedir);
}
gi.setmodel (ent, ent->model); gi.setmodel(ent, ent->model);
gi.linkentity (ent); gi.linkentity(ent);
} }
/*QUAKED trigger_once (.5 .5 .5) ? x x TRIGGERED /*QUAKED trigger_once (.5 .5 .5) ? x x TRIGGERED
Triggers once, then removes itself. * Triggers once, then removes itself.
You must set the key "target" to the name of another object in the level that has a matching "targetname". * You must set the key "target" to the name of another object in the level that has a matching "targetname".
*
* If TRIGGERED, this trigger must be triggered before it is live.
*
* sounds
* 1) secret
* 2) beep beep
* 3) large switch
* 4)
*
* "message" string to be displayed when triggered
*/
If TRIGGERED, this trigger must be triggered before it is live. void
SP_trigger_once(edict_t *ent)
sounds
1) secret
2) beep beep
3) large switch
4)
"message" string to be displayed when triggered
*/
void SP_trigger_once(edict_t *ent)
{ {
// make old maps work because I messed up on flag assignments here /* make old maps work because I messed up on flag assignments here */
// triggered was on bit 1 when it should have been on bit 4 /* triggered was on bit 1 when it should have been on bit 4 */
if (ent->spawnflags & 1) if (ent->spawnflags & 1)
{ {
vec3_t v; vec3_t v;
VectorMA (ent->mins, 0.5, ent->size, v); VectorMA(ent->mins, 0.5, ent->size, v);
ent->spawnflags &= ~1; ent->spawnflags &= ~1;
ent->spawnflags |= 4; ent->spawnflags |= 4;
gi.dprintf("fixed TRIGGERED flag on %s at %s\n", ent->classname, vtos(v)); gi.dprintf("fixed TRIGGERED flag on %s at %s\n", ent->classname, vtos(v));
} }
ent->wait = -1; ent->wait = -1;
SP_trigger_multiple (ent); SP_trigger_multiple(ent);
} }
/*QUAKED trigger_relay (.5 .5 .5) (-8 -8 -8) (8 8 8) /*QUAKED trigger_relay (.5 .5 .5) (-8 -8 -8) (8 8 8)
This fixed size trigger cannot be touched, it can only be fired by other events. * This fixed size trigger cannot be touched, it can only be fired by other events.
*/ */
void trigger_relay_use (edict_t *self, edict_t *other, edict_t *activator) void
trigger_relay_use(edict_t *self, edict_t *other, edict_t *activator)
{ {
G_UseTargets (self, activator); G_UseTargets(self, activator);
} }
void SP_trigger_relay (edict_t *self) void
SP_trigger_relay(edict_t *self)
{ {
self->use = trigger_relay_use; self->use = trigger_relay_use;
} }
/* /*
============================================================================== * ==============================================================================
*
trigger_key * trigger_key
*
============================================================================== * ==============================================================================
*/ */
/*QUAKED trigger_key (.5 .5 .5) (-8 -8 -8) (8 8 8) /*QUAKED trigger_key (.5 .5 .5) (-8 -8 -8) (8 8 8)
A relay trigger that only fires it's targets if player has the proper key. * A relay trigger that only fires it's targets if player has the proper key.
Use "item" to specify the required key, for example "key_data_cd" * Use "item" to specify the required key, for example "key_data_cd"
*/ */
void trigger_key_use (edict_t *self, edict_t *other, edict_t *activator) void
trigger_key_use(edict_t *self, edict_t *other, edict_t *activator)
{ {
int index; int index;
if (!self->item) if (!self->item)
return;
if (!activator->client)
return;
index = ITEM_INDEX(self->item);
if (!activator->client->pers.inventory[index])
{ {
if (level.time < self->touch_debounce_time)
return;
self->touch_debounce_time = level.time + 5.0;
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);
return; return;
} }
gi.sound (activator, CHAN_AUTO, gi.soundindex ("misc/keyuse.wav"), 1, ATTN_NORM, 0); if (!activator->client)
{
return;
}
index = ITEM_INDEX(self->item);
if (!activator->client->pers.inventory[index])
{
if (level.time < self->touch_debounce_time)
{
return;
}
self->touch_debounce_time = level.time + 5.0;
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);
return;
}
gi.sound(activator, CHAN_AUTO, gi.soundindex(
"misc/keyuse.wav"), 1, ATTN_NORM, 0);
if (coop->value) if (coop->value)
{ {
int player; int player;
@ -240,15 +282,27 @@ void trigger_key_use (edict_t *self, edict_t *other, edict_t *activator)
int cube; int cube;
for (cube = 0; cube < 8; cube++) for (cube = 0; cube < 8; cube++)
{
if (activator->client->pers.power_cubes & (1 << cube)) if (activator->client->pers.power_cubes & (1 << cube))
{
break; break;
}
}
for (player = 1; player <= game.maxclients; player++) for (player = 1; player <= game.maxclients; player++)
{ {
ent = &g_edicts[player]; ent = &g_edicts[player];
if (!ent->inuse) if (!ent->inuse)
{
continue; continue;
}
if (!ent->client) if (!ent->client)
{
continue; continue;
}
if (ent->client->pers.power_cubes & (1 << cube)) if (ent->client->pers.power_cubes & (1 << cube))
{ {
ent->client->pers.inventory[index]--; ent->client->pers.inventory[index]--;
@ -261,10 +315,17 @@ void trigger_key_use (edict_t *self, edict_t *other, edict_t *activator)
for (player = 1; player <= game.maxclients; player++) for (player = 1; player <= game.maxclients; player++)
{ {
ent = &g_edicts[player]; ent = &g_edicts[player];
if (!ent->inuse) if (!ent->inuse)
{
continue; continue;
}
if (!ent->client) if (!ent->client)
{
continue; continue;
}
ent->client->pers.inventory[index] = 0; ent->client->pers.inventory[index] = 0;
} }
} }
@ -274,324 +335,420 @@ void trigger_key_use (edict_t *self, edict_t *other, edict_t *activator)
activator->client->pers.inventory[index]--; activator->client->pers.inventory[index]--;
} }
G_UseTargets (self, activator); G_UseTargets(self, activator);
self->use = NULL; self->use = NULL;
} }
void SP_trigger_key (edict_t *self) void
SP_trigger_key(edict_t *self)
{ {
if (!st.item) if (!st.item)
{ {
gi.dprintf("no key item for trigger_key at %s\n", vtos(self->s.origin)); gi.dprintf("no key item for trigger_key at %s\n", vtos(self->s.origin));
return; return;
} }
self->item = FindItemByClassname (st.item);
self->item = FindItemByClassname(st.item);
if (!self->item) if (!self->item)
{ {
gi.dprintf("item %s not found for trigger_key at %s\n", st.item, vtos(self->s.origin)); gi.dprintf("item %s not found for trigger_key at %s\n", st.item,
vtos(self->s.origin));
return; return;
} }
if (!self->target) if (!self->target)
{ {
gi.dprintf("%s at %s has no target\n", self->classname, vtos(self->s.origin)); gi.dprintf("%s at %s has no target\n", self->classname,
vtos(self->s.origin));
return; return;
} }
gi.soundindex ("misc/keytry.wav"); gi.soundindex("misc/keytry.wav");
gi.soundindex ("misc/keyuse.wav"); gi.soundindex("misc/keyuse.wav");
self->use = trigger_key_use; self->use = trigger_key_use;
} }
/* /*
============================================================================== * ==============================================================================
*
trigger_counter * trigger_counter
*
============================================================================== * ==============================================================================
*/ */
/*QUAKED trigger_counter (.5 .5 .5) ? nomessage /*QUAKED trigger_counter (.5 .5 .5) ? nomessage
Acts as an intermediary for an action that takes multiple inputs. * Acts as an intermediary for an action that takes multiple inputs.
*
* If nomessage is not set, t will print "1 more.. " etc when triggered and "sequence complete" when finished.
*
* After the counter has been triggered "count" times (default 2), it will fire all of it's targets and remove itself.
*/
If nomessage is not set, t will print "1 more.. " etc when triggered and "sequence complete" when finished. void
trigger_counter_use(edict_t *self, edict_t *other, edict_t *activator)
After the counter has been triggered "count" times (default 2), it will fire all of it's targets and remove itself.
*/
void trigger_counter_use(edict_t *self, edict_t *other, edict_t *activator)
{ {
if (self->count == 0) if (self->count == 0)
{
return; return;
}
self->count--; self->count--;
if (self->count) if (self->count)
{ {
if (! (self->spawnflags & 1)) if (!(self->spawnflags & 1))
{ {
gi.centerprintf(activator, "%i more to go...", self->count); gi.centerprintf(activator, "%i more to go...", self->count);
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);
} }
return; return;
} }
if (! (self->spawnflags & 1)) if (!(self->spawnflags & 1))
{ {
gi.centerprintf(activator, "Sequence completed!"); gi.centerprintf(activator, "Sequence completed!");
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);
} }
self->activator = activator; self->activator = activator;
multi_trigger (self); multi_trigger(self);
} }
void SP_trigger_counter (edict_t *self) void
SP_trigger_counter(edict_t *self)
{ {
self->wait = -1; self->wait = -1;
if (!self->count) if (!self->count)
{
self->count = 2; self->count = 2;
}
self->use = trigger_counter_use; self->use = trigger_counter_use;
} }
/* /*
============================================================================== * ==============================================================================
*
trigger_always * trigger_always
*
============================================================================== * ==============================================================================
*/ */
/*QUAKED trigger_always (.5 .5 .5) (-8 -8 -8) (8 8 8) /*QUAKED trigger_always (.5 .5 .5) (-8 -8 -8) (8 8 8)
This trigger will always fire. It is activated by the world. * This trigger will always fire. It is activated by the world.
*/ */
void SP_trigger_always (edict_t *ent) void
SP_trigger_always(edict_t *ent)
{ {
// we must have some delay to make sure our use targets are present /* we must have some delay to make sure our use targets are present */
if (ent->delay < 0.2) if (ent->delay < 0.2)
{
ent->delay = 0.2; ent->delay = 0.2;
}
G_UseTargets(ent, ent); G_UseTargets(ent, ent);
} }
/* /*
============================================================================== * ==============================================================================
*
trigger_push * trigger_push
*
============================================================================== * ==============================================================================
*/ */
#define PUSH_ONCE 1 #define PUSH_ONCE 1
static int windsound; static int windsound;
void trigger_push_touch (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf) void
trigger_push_touch(edict_t *self,
edict_t *other,
cplane_t *plane,
csurface_t *surf)
{ {
if (strcmp(other->classname, "grenade") == 0) if (strcmp(other->classname, "grenade") == 0)
{ {
VectorScale (self->movedir, self->speed * 10, other->velocity); VectorScale(self->movedir, self->speed * 10, other->velocity);
} }
else if (other->health > 0) else if (other->health > 0)
{ {
VectorScale (self->movedir, self->speed * 10, other->velocity); VectorScale(self->movedir, self->speed * 10, other->velocity);
if (other->client) if (other->client)
{ {
// don't take falling damage immediately from this /* don't take falling damage immediately from this */
VectorCopy (other->velocity, other->client->oldvelocity); VectorCopy(other->velocity, other->client->oldvelocity);
if (other->fly_sound_debounce_time < level.time) if (other->fly_sound_debounce_time < level.time)
{ {
other->fly_sound_debounce_time = level.time + 1.5; other->fly_sound_debounce_time = level.time + 1.5;
gi.sound (other, CHAN_AUTO, windsound, 1, ATTN_NORM, 0); gi.sound(other, CHAN_AUTO, windsound, 1, ATTN_NORM, 0);
} }
} }
} }
if (self->spawnflags & PUSH_ONCE)
G_FreeEdict (self);
}
if (self->spawnflags & PUSH_ONCE)
{
G_FreeEdict(self);
}
}
/*QUAKED trigger_push (.5 .5 .5) ? PUSH_ONCE /*QUAKED trigger_push (.5 .5 .5) ? PUSH_ONCE
Pushes the player * Pushes the player
"speed" defaults to 1000 * "speed" defaults to 1000
*/ */
void SP_trigger_push (edict_t *self) void
SP_trigger_push(edict_t *self)
{ {
InitTrigger (self); InitTrigger(self);
windsound = gi.soundindex ("misc/windfly.wav"); windsound = gi.soundindex("misc/windfly.wav");
self->touch = trigger_push_touch; self->touch = trigger_push_touch;
if (!self->speed)
self->speed = 1000;
gi.linkentity (self);
}
if (!self->speed)
{
self->speed = 1000;
}
gi.linkentity(self);
}
/* /*
============================================================================== * ==============================================================================
*
trigger_hurt * trigger_hurt
*
============================================================================== * ==============================================================================
*/ */
/*QUAKED trigger_hurt (.5 .5 .5) ? START_OFF TOGGLE SILENT NO_PROTECTION SLOW /*QUAKED trigger_hurt (.5 .5 .5) ? START_OFF TOGGLE SILENT NO_PROTECTION SLOW
Any entity that touches this will be hurt. * Any entity that touches this will be hurt.
*
It does dmg points of damage each server frame * It does dmg points of damage each server frame
*
SILENT supresses playing the sound * SILENT supresses playing the sound
SLOW changes the damage rate to once per second * SLOW changes the damage rate to once per second
NO_PROTECTION *nothing* stops the damage * NO_PROTECTION *nothing* stops the damage
*
"dmg" default 5 (whole numbers only) * "dmg" default 5 (whole numbers only)
*
*/ */
void hurt_use (edict_t *self, edict_t *other, edict_t *activator) void
hurt_use(edict_t *self, edict_t *other, edict_t *activator)
{ {
if (self->solid == SOLID_NOT) if (self->solid == SOLID_NOT)
{
self->solid = SOLID_TRIGGER; self->solid = SOLID_TRIGGER;
}
else else
{
self->solid = SOLID_NOT; self->solid = SOLID_NOT;
gi.linkentity (self); }
gi.linkentity(self);
if (!(self->spawnflags & 2)) if (!(self->spawnflags & 2))
{
self->use = NULL; self->use = NULL;
}
} }
void
void hurt_touch (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf) hurt_touch(edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf)
{ {
int dflags; int dflags;
if (!other->takedamage) if (!other->takedamage)
{
return; return;
}
if (self->timestamp > level.time) if (self->timestamp > level.time)
{
return; return;
}
if (self->spawnflags & 16) if (self->spawnflags & 16)
{
self->timestamp = level.time + 1; self->timestamp = level.time + 1;
}
else else
{
self->timestamp = level.time + FRAMETIME; self->timestamp = level.time + FRAMETIME;
}
if (!(self->spawnflags & 4)) if (!(self->spawnflags & 4))
{ {
if ((level.framenum % 10) == 0) if ((level.framenum % 10) == 0)
gi.sound (other, CHAN_AUTO, self->noise_index, 1, ATTN_NORM, 0); {
gi.sound(other, CHAN_AUTO, self->noise_index, 1, ATTN_NORM, 0);
}
} }
if (self->spawnflags & 8) if (self->spawnflags & 8)
{
dflags = DAMAGE_NO_PROTECTION; dflags = DAMAGE_NO_PROTECTION;
}
else else
{
dflags = 0; dflags = 0;
T_Damage (other, self, self, vec3_origin, other->s.origin, vec3_origin, self->dmg, self->dmg, dflags, MOD_TRIGGER_HURT); }
T_Damage(other,
self,
self,
vec3_origin,
other->s.origin,
vec3_origin,
self->dmg,
self->dmg,
dflags,
MOD_TRIGGER_HURT);
} }
void SP_trigger_hurt (edict_t *self) void
SP_trigger_hurt(edict_t *self)
{ {
InitTrigger (self); InitTrigger(self);
self->noise_index = gi.soundindex ("world/electro.wav"); self->noise_index = gi.soundindex("world/electro.wav");
self->touch = hurt_touch; self->touch = hurt_touch;
if (!self->dmg) if (!self->dmg)
{
self->dmg = 5; self->dmg = 5;
}
if (self->spawnflags & 1) if (self->spawnflags & 1)
{
self->solid = SOLID_NOT; self->solid = SOLID_NOT;
}
else else
{
self->solid = SOLID_TRIGGER; self->solid = SOLID_TRIGGER;
}
if (self->spawnflags & 2) if (self->spawnflags & 2)
{
self->use = hurt_use; self->use = hurt_use;
}
gi.linkentity (self); gi.linkentity(self);
} }
/* /*
============================================================================== * ==============================================================================
*
trigger_gravity * trigger_gravity
*
============================================================================== * ==============================================================================
*/ */
/*QUAKED trigger_gravity (.5 .5 .5) ? /*QUAKED trigger_gravity (.5 .5 .5) ?
Changes the touching entites gravity to * Changes the touching entites gravity to
the value of "gravity". 1.0 is standard * the value of "gravity". 1.0 is standard
gravity for the level. * gravity for the level.
*/ */
void trigger_gravity_touch (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf) void
trigger_gravity_touch(edict_t *self,
edict_t *other,
cplane_t *plane,
csurface_t *surf)
{ {
other->gravity = self->gravity; other->gravity = self->gravity;
} }
void SP_trigger_gravity (edict_t *self) void
SP_trigger_gravity(edict_t *self)
{ {
if (st.gravity == 0) if (st.gravity == 0)
{ {
gi.dprintf("trigger_gravity without gravity set at %s\n", vtos(self->s.origin)); gi.dprintf("trigger_gravity without gravity set at %s\n",
G_FreeEdict (self); vtos(self->s.origin));
G_FreeEdict(self);
return; return;
} }
InitTrigger (self); InitTrigger(self);
self->gravity = atoi(st.gravity); self->gravity = atoi(st.gravity);
self->touch = trigger_gravity_touch; self->touch = trigger_gravity_touch;
} }
/* /*
============================================================================== * ==============================================================================
*
trigger_monsterjump * trigger_monsterjump
*
============================================================================== * ==============================================================================
*/ */
/*QUAKED trigger_monsterjump (.5 .5 .5) ? /*QUAKED trigger_monsterjump (.5 .5 .5) ?
Walking monsters that touch this will jump in the direction of the trigger's angle * Walking monsters that touch this will jump in the direction of the trigger's angle
"speed" default to 200, the speed thrown forward * "speed" default to 200, the speed thrown forward
"height" default to 200, the speed thrown upwards * "height" default to 200, the speed thrown upwards
*/ */
void trigger_monsterjump_touch (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf) void
trigger_monsterjump_touch(edict_t *self,
edict_t *other,
cplane_t *plane,
csurface_t *surf)
{ {
if (other->flags & (FL_FLY | FL_SWIM) ) if (other->flags & (FL_FLY | FL_SWIM))
return; {
if (other->svflags & SVF_DEADMONSTER)
return;
if ( !(other->svflags & SVF_MONSTER))
return; return;
}
// set XY even if not on ground, so the jump will clear lips if (other->svflags & SVF_DEADMONSTER)
{
return;
}
if (!(other->svflags & SVF_MONSTER))
{
return;
}
/* set XY even if not on ground, so the jump will clear lips */
other->velocity[0] = self->movedir[0] * self->speed; other->velocity[0] = self->movedir[0] * self->speed;
other->velocity[1] = self->movedir[1] * self->speed; other->velocity[1] = self->movedir[1] * self->speed;
if (!other->groundentity) if (!other->groundentity)
{
return; return;
}
other->groundentity = NULL; other->groundentity = NULL;
other->velocity[2] = self->movedir[2]; other->velocity[2] = self->movedir[2];
} }
void SP_trigger_monsterjump (edict_t *self) void
SP_trigger_monsterjump(edict_t *self)
{ {
if (!self->speed) if (!self->speed)
{
self->speed = 200; self->speed = 200;
}
if (!st.height) if (!st.height)
{
st.height = 200; st.height = 200;
}
if (self->s.angles[YAW] == 0) if (self->s.angles[YAW] == 0)
{
self->s.angles[YAW] = 360; self->s.angles[YAW] = 360;
InitTrigger (self); }
InitTrigger(self);
self->touch = trigger_monsterjump_touch; self->touch = trigger_monsterjump_touch;
self->movedir[2] = st.height; self->movedir[2] = st.height;
} }

View file

@ -1,121 +1,158 @@
/* /*
Copyright (C) 1997-2001 Id Software, Inc. * Copyright (C) 1997-2001 Id Software, Inc.
*
This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2 * as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version. * of the License, or (at your option) any later version.
*
This program is distributed in the hope that it will be useful, * This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*
See the GNU General Public License for more details. * See the GNU General Public License for more details.
*
You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software * along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
*/ */
// g_utils.c -- misc utility functions for game module /* g_utils.c -- misc utility functions for game module */
#include "g_local.h" #include "g_local.h"
void
void G_ProjectSource (vec3_t point, vec3_t distance, vec3_t forward, vec3_t right, vec3_t result) G_ProjectSource(vec3_t point,
vec3_t distance,
vec3_t forward,
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];
} }
/* /*
============= * =============
G_Find * G_Find
*
Searches all active entities for the next one that holds * Searches all active entities for the next one that holds
the matching string at fieldofs (use the FOFS() macro) in the structure. * the matching string at fieldofs (use the FOFS() macro) in the structure.
*
Searches beginning at the edict after from, or the beginning if NULL * Searches beginning at the edict after from, 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 *G_Find (edict_t *from, int fieldofs, char *match) edict_t *
G_Find(edict_t *from, int fieldofs, char *match)
{ {
char *s; char *s;
if (!from) if (!from)
{
from = g_edicts; from = g_edicts;
}
else else
{
from++; from++;
}
for ( ; from < &g_edicts[globals.num_edicts] ; from++) for ( ; from < &g_edicts[globals.num_edicts]; from++)
{ {
if (!from->inuse) if (!from->inuse)
{
continue; continue;
s = *(char **) ((byte *)from + fieldofs); }
s = *(char **)((byte *)from + fieldofs);
if (!s) if (!s)
{
continue; continue;
if (!Q_stricmp (s, match)) }
if (!Q_stricmp(s, match))
{
return from; return from;
} }
}
return NULL; return NULL;
} }
/* /*
================= * =================
findradius * findradius
*
Returns entities that have origins within a spherical area * Returns entities that have origins within a spherical area
*
findradius (origin, radius) * findradius (origin, radius)
================= * =================
*/ */
edict_t *findradius (edict_t *from, vec3_t org, float rad) edict_t *
findradius(edict_t *from, vec3_t org, float rad)
{ {
vec3_t eorg; vec3_t eorg;
int j; int j;
if (!from) if (!from)
{
from = g_edicts; from = g_edicts;
}
else else
{
from++; from++;
}
for ( ; from < &g_edicts[globals.num_edicts]; from++) for ( ; from < &g_edicts[globals.num_edicts]; from++)
{ {
if (!from->inuse) if (!from->inuse)
{
continue; continue;
}
if (from->solid == SOLID_NOT) if (from->solid == SOLID_NOT)
{
continue; continue;
for (j=0 ; j<3 ; j++) }
eorg[j] = org[j] - (from->s.origin[j] + (from->mins[j] + from->maxs[j])*0.5);
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) if (VectorLength(eorg) > rad)
{
continue; continue;
}
return from; return from;
} }
return NULL; return NULL;
} }
/* /*
============= * =============
G_PickTarget * G_PickTarget
*
Searches all active entities for the next one that holds * Searches all active entities for the next one that holds
the matching string at fieldofs (use the FOFS() macro) in the structure. * the matching string at fieldofs (use the FOFS() macro) in the structure.
*
Searches beginning at the edict after from, or the beginning if NULL * Searches beginning at the edict after from, 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.
*
============= * =============
*/ */
#define MAXCHOICES 8 #define MAXCHOICES 8
edict_t *G_PickTarget (char *targetname) edict_t *
G_PickTarget(char *targetname)
{ {
edict_t *ent = NULL; edict_t *ent = NULL;
int num_choices = 0; int num_choices = 0;
@ -127,15 +164,22 @@ edict_t *G_PickTarget (char *targetname)
return NULL; return NULL;
} }
while(1) while (1)
{ {
ent = G_Find (ent, FOFS(targetname), targetname); ent = G_Find(ent, FOFS(targetname), targetname);
if (!ent) if (!ent)
{
break; break;
}
choice[num_choices++] = ent; choice[num_choices++] = ent;
if (num_choices == MAXCHOICES) if (num_choices == MAXCHOICES)
{
break; break;
} }
}
if (!num_choices) if (!num_choices)
{ {
@ -146,75 +190,86 @@ edict_t *G_PickTarget (char *targetname)
return choice[rand() % num_choices]; return choice[rand() % num_choices];
} }
void
Think_Delay(edict_t *ent)
void Think_Delay (edict_t *ent)
{ {
G_UseTargets (ent, ent->activator); G_UseTargets(ent, ent->activator);
G_FreeEdict (ent); G_FreeEdict(ent);
} }
/* /*
============================== * ==============================
G_UseTargets * G_UseTargets
*
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 will be created that will actually
do the SUB_UseTargets after that many seconds have passed. * 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 G_UseTargets (edict_t *ent, edict_t *activator) void
G_UseTargets(edict_t *ent, edict_t *activator)
{ {
edict_t *t; edict_t *t;
// /* */
// check for a delay /* check for a delay */
// /* */
if (ent->delay) if (ent->delay)
{ {
// create a temp object to fire at a later time /* create a temp object to fire at a later time */
t = G_Spawn(); t = G_Spawn();
t->classname = "DelayedUse"; t->classname = "DelayedUse";
t->nextthink = level.time + ent->delay; t->nextthink = level.time + ent->delay;
t->think = Think_Delay; t->think = Think_Delay;
t->activator = activator; t->activator = activator;
if (!activator) if (!activator)
gi.dprintf ("Think_Delay with no activator\n"); {
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;
return; return;
} }
/* */
// /* print the message */
// print the message /* */
//
if ((ent->message) && !(activator->svflags & SVF_MONSTER)) if ((ent->message) && !(activator->svflags & SVF_MONSTER))
{ {
gi.centerprintf (activator, "%s", ent->message); gi.centerprintf(activator, "%s", ent->message);
if (ent->noise_index) if (ent->noise_index)
gi.sound (activator, CHAN_AUTO, ent->noise_index, 1, ATTN_NORM, 0); {
gi.sound(activator, CHAN_AUTO, ent->noise_index, 1, ATTN_NORM, 0);
}
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);
}
} }
// /* */
// kill killtargets /* kill killtargets */
// /* */
if (ent->killtarget) if (ent->killtarget)
{ {
t = NULL; t = NULL;
while ((t = G_Find (t, FOFS(targetname), ent->killtarget)))
while ((t = G_Find(t, FOFS(targetname), ent->killtarget)))
{ {
G_FreeEdict (t); G_FreeEdict(t);
if (!ent->inuse) if (!ent->inuse)
{ {
gi.dprintf("entity was removed while using killtargets\n"); gi.dprintf("entity was removed while using killtargets\n");
@ -223,28 +278,36 @@ void G_UseTargets (edict_t *ent, edict_t *activator)
} }
} }
// /* */
// fire targets /* fire targets */
// /* */
if (ent->target) if (ent->target)
{ {
t = NULL; t = NULL;
while ((t = G_Find (t, FOFS(targetname), ent->target)))
while ((t = G_Find(t, FOFS(targetname), ent->target)))
{ {
// doors fire area portals in a specific way /* doors fire area portals in a specific way */
if (!Q_stricmp(t->classname, "func_areaportal") && if (!Q_stricmp(t->classname, "func_areaportal") &&
(!Q_stricmp(ent->classname, "func_door") || !Q_stricmp(ent->classname, "func_door_rotating"))) (!Q_stricmp(ent->classname,
"func_door") ||
!Q_stricmp(ent->classname, "func_door_rotating")))
{
continue; continue;
}
if (t == ent) if (t == ent)
{ {
gi.dprintf ("WARNING: Entity used itself.\n"); gi.dprintf("WARNING: Entity used itself.\n");
} }
else else
{ {
if (t->use) if (t->use)
t->use (t, ent, activator); {
t->use(t, ent, activator);
} }
}
if (!ent->inuse) if (!ent->inuse)
{ {
gi.dprintf("entity was removed while using targets\n"); gi.dprintf("entity was removed while using targets\n");
@ -254,25 +317,25 @@ void G_UseTargets (edict_t *ent, edict_t *activator)
} }
} }
/* /*
============= * =============
TempVector * TempVector
*
This is just a convenience function * This is just a convenience function
for making temporary vectors for function calls * for making temporary vectors for function calls
============= * =============
*/ */
float *tv (float x, float y, float z) float *
tv(float x, float y, float z)
{ {
static int index; static int index;
static vec3_t vecs[8]; static vec3_t vecs[8];
float *v; float *v;
// use an array so that multiple tempvectors won't collide /* use an array so that multiple tempvectors won't collide */
// for a while /* for a while */
v = vecs[index]; v = vecs[index];
index = (index + 1)&7; index = (index + 1) & 7;
v[0] = x; v[0] = x;
v[1] = y; v[1] = y;
@ -281,124 +344,150 @@ float *tv (float x, float y, float z)
return v; return v;
} }
/* /*
============= * =============
VectorToString * VectorToString
*
This is just a convenience function * This is just a convenience function
for printing vectors * for printing vectors
============= * =============
*/ */
char *vtos (vec3_t v) char *
vtos(vec3_t v)
{ {
static int index; static int index;
static char str[8][32]; static char str[8][32];
char *s; char *s;
// use an array so that multiple vtos won't collide /* use an array so that multiple vtos won't collide */
s = str[index]; s = str[index];
index = (index + 1)&7; index = (index + 1) & 7;
Com_sprintf (s, 32, "(%i %i %i)", (int)v[0], (int)v[1], (int)v[2]); Com_sprintf(s, 32, "(%i %i %i)", (int)v[0], (int)v[1], (int)v[2]);
return s; return s;
} }
vec3_t VEC_UP = {0, -1, 0}; vec3_t VEC_UP = {0, -1, 0};
vec3_t MOVEDIR_UP = {0, 0, 1}; vec3_t MOVEDIR_UP = {0, 0, 1};
vec3_t VEC_DOWN = {0, -2, 0}; vec3_t VEC_DOWN = {0, -2, 0};
vec3_t MOVEDIR_DOWN = {0, 0, -1}; vec3_t MOVEDIR_DOWN = {0, 0, -1};
void G_SetMovedir (vec3_t angles, vec3_t movedir) void
G_SetMovedir(vec3_t angles, vec3_t movedir)
{ {
if (VectorCompare (angles, VEC_UP)) if (VectorCompare(angles, VEC_UP))
{ {
VectorCopy (MOVEDIR_UP, movedir); VectorCopy(MOVEDIR_UP, movedir);
} }
else if (VectorCompare (angles, VEC_DOWN)) else if (VectorCompare(angles, VEC_DOWN))
{ {
VectorCopy (MOVEDIR_DOWN, movedir); VectorCopy(MOVEDIR_DOWN, movedir);
} }
else else
{ {
AngleVectors (angles, movedir, NULL, NULL); AngleVectors(angles, movedir, NULL, NULL);
} }
VectorClear (angles); VectorClear(angles);
} }
float
float vectoyaw (vec3_t vec) vectoyaw(vec3_t vec)
{ {
float yaw; float yaw;
if (/* vec[YAW] == 0 && */ vec[PITCH] == 0) if (/* vec[YAW] == 0 && */ vec[PITCH] == 0)
{ {
yaw = 0; yaw = 0;
if (vec[YAW] > 0) if (vec[YAW] > 0)
{
yaw = 90; yaw = 90;
}
else if (vec[YAW] < 0) else if (vec[YAW] < 0)
{
yaw = -90; yaw = -90;
} }
}
else else
{ {
yaw = (int) (atan2(vec[YAW], vec[PITCH]) * 180 / M_PI); yaw = (int)(atan2(vec[YAW], vec[PITCH]) * 180 / M_PI);
if (yaw < 0) if (yaw < 0)
{
yaw += 360; yaw += 360;
} }
}
return yaw; return yaw;
} }
void
void vectoangles (vec3_t value1, vec3_t angles) vectoangles(vec3_t value1, vec3_t angles)
{ {
float forward; float forward;
float yaw, pitch; float yaw, pitch;
if (value1[1] == 0 && value1[0] == 0) if ((value1[1] == 0) && (value1[0] == 0))
{ {
yaw = 0; yaw = 0;
if (value1[2] > 0) if (value1[2] > 0)
{
pitch = 90; pitch = 90;
}
else else
{
pitch = 270; pitch = 270;
} }
}
else else
{ {
if (value1[0]) if (value1[0])
yaw = (int) (atan2(value1[1], value1[0]) * 180 / M_PI); {
yaw = (int)(atan2(value1[1], value1[0]) * 180 / M_PI);
}
else if (value1[1] > 0) else if (value1[1] > 0)
{
yaw = 90; yaw = 90;
}
else else
{
yaw = -90; yaw = -90;
if (yaw < 0) }
yaw += 360;
if (yaw < 0)
{
yaw += 360;
}
forward = sqrt(value1[0] * value1[0] + value1[1] * value1[1]);
pitch = (int)(atan2(value1[2], forward) * 180 / M_PI);
forward = sqrt (value1[0]*value1[0] + value1[1]*value1[1]);
pitch = (int) (atan2(value1[2], forward) * 180 / M_PI);
if (pitch < 0) if (pitch < 0)
{
pitch += 360; pitch += 360;
} }
}
angles[PITCH] = -pitch; angles[PITCH] = -pitch;
angles[YAW] = yaw; angles[YAW] = yaw;
angles[ROLL] = 0; angles[ROLL] = 0;
} }
char *G_CopyString (char *in) char *
G_CopyString(char *in)
{ {
char *out; char *out;
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;
} }
void
void G_InitEdict (edict_t *e) G_InitEdict(edict_t *e)
{ {
e->inuse = true; e->inuse = true;
e->classname = "noclass"; e->classname = "noclass";
@ -407,162 +496,203 @@ void G_InitEdict (edict_t *e)
} }
/* /*
================= * =================
G_Spawn * G_Spawn
*
Either finds a free edict, or allocates a new one. * Either finds a free edict, or allocates a new one.
Try to avoid reusing an entity that was recently freed, because it * Try to avoid reusing an entity that was recently freed, because it
can cause the client to think the entity morphed into something else * can cause the client to think the entity morphed into something else
instead of being removed and recreated, which can cause interpolated * instead of being removed and recreated, which can cause interpolated
angles and bad trails. * angles and bad trails.
================= * =================
*/ */
edict_t *G_Spawn (void) edict_t *
G_Spawn(void)
{ {
int i; int i;
edict_t *e; edict_t *e;
e = &g_edicts[(int)maxclients->value+1]; e = &g_edicts[(int)maxclients->value + 1];
for ( i=maxclients->value+1 ; i<globals.num_edicts ; i++, e++)
for (i = maxclients->value + 1; i < globals.num_edicts; i++, e++)
{ {
// the first couple seconds of server time can involve a lot of /* the first couple seconds of server time can involve a lot of */
// freeing and allocating, so relax the replacement policy /* freeing and allocating, so relax the replacement policy */
if (!e->inuse && ( e->freetime < 2 || level.time - e->freetime > 0.5 ) ) if (!e->inuse && ((e->freetime < 2) || (level.time - e->freetime > 0.5)))
{ {
G_InitEdict (e); G_InitEdict(e);
return e; return e;
} }
} }
if (i == game.maxentities) if (i == game.maxentities)
gi.error ("ED_Alloc: no free edicts"); {
gi.error("ED_Alloc: no free edicts");
}
globals.num_edicts++; globals.num_edicts++;
G_InitEdict (e); G_InitEdict(e);
return e; return e;
} }
/* /*
================= * =================
G_FreeEdict * G_FreeEdict
*
Marks the edict as free * Marks the edict as free
================= * =================
*/ */
void G_FreeEdict (edict_t *ed) void
G_FreeEdict(edict_t *ed)
{ {
gi.unlinkentity (ed); // unlink from world gi.unlinkentity(ed); /* unlink from world */
if ((ed - g_edicts) <= (maxclients->value + BODY_QUEUE_SIZE)) if ((ed - g_edicts) <= (maxclients->value + BODY_QUEUE_SIZE))
{ {
return; return;
} }
memset (ed, 0, sizeof(*ed)); memset(ed, 0, sizeof(*ed));
ed->classname = "freed"; ed->classname = "freed";
ed->freetime = level.time; ed->freetime = level.time;
ed->inuse = false; ed->inuse = false;
} }
/* /*
============ * ============
G_TouchTriggers * G_TouchTriggers
*
============ * ============
*/ */
void G_TouchTriggers (edict_t *ent) void
G_TouchTriggers(edict_t *ent)
{ {
int i, num; int i, num;
edict_t *touch[MAX_EDICTS], *hit; edict_t *touch[MAX_EDICTS], *hit;
// dead things don't activate triggers! /* dead things don't activate triggers! */
if ((ent->client || (ent->svflags & SVF_MONSTER)) && (ent->health <= 0)) if ((ent->client || (ent->svflags & SVF_MONSTER)) && (ent->health <= 0))
{
return; return;
}
num = gi.BoxEdicts (ent->absmin, ent->absmax, touch num = gi.BoxEdicts(ent->absmin, ent->absmax, touch,
, MAX_EDICTS, AREA_TRIGGERS); MAX_EDICTS, AREA_TRIGGERS);
// 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) */
for (i=0 ; i<num ; i++) for (i = 0; i < num; i++)
{ {
hit = touch[i]; hit = touch[i];
if (!hit->inuse) if (!hit->inuse)
{
continue; continue;
}
if (!hit->touch) if (!hit->touch)
{
continue; continue;
hit->touch (hit, ent, NULL, NULL); }
hit->touch(hit, ent, NULL, NULL);
} }
} }
/* /*
============ * ============
G_TouchSolids * G_TouchSolids
*
Call after linking a new trigger in during gameplay * Call after linking a new trigger in during gameplay
to force all entities it covers to immediately touch it * to force all entities it covers to immediately touch it
============ * ============
*/ */
void G_TouchSolids (edict_t *ent) void
G_TouchSolids(edict_t *ent)
{ {
int i, num; int i, num;
edict_t *touch[MAX_EDICTS], *hit; edict_t *touch[MAX_EDICTS], *hit;
num = gi.BoxEdicts (ent->absmin, ent->absmax, touch num = gi.BoxEdicts(ent->absmin, ent->absmax, touch,
, MAX_EDICTS, AREA_SOLID); 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) */
for (i=0 ; i<num ; i++) for (i = 0; i < num; i++)
{ {
hit = touch[i]; hit = touch[i];
if (!hit->inuse) if (!hit->inuse)
{
continue; continue;
}
if (ent->touch) if (ent->touch)
ent->touch (hit, ent, NULL, NULL); {
ent->touch(hit, ent, NULL, NULL);
}
if (!ent->inuse) if (!ent->inuse)
{
break; break;
} }
}
} }
/*
* ==============================================================================
*
* Kill box
*
* ==============================================================================
*/
/* /*
============================================================================== * =================
* KillBox
Kill box *
* Kills all entities that would touch the proposed new positioning
============================================================================== * of ent. Ent should be unlinked before calling this!
*/ * =================
*/
/* qboolean
================= KillBox(edict_t *ent)
KillBox
Kills all entities that would touch the proposed new positioning
of ent. Ent should be unlinked before calling this!
=================
*/
qboolean KillBox (edict_t *ent)
{ {
trace_t tr; trace_t tr;
while (1) while (1)
{ {
tr = gi.trace (ent->s.origin, ent->mins, ent->maxs, ent->s.origin, NULL, MASK_PLAYERSOLID); tr = gi.trace(ent->s.origin,
ent->mins,
ent->maxs,
ent->s.origin,
NULL,
MASK_PLAYERSOLID);
if (!tr.ent) if (!tr.ent)
{
break; break;
// nail it
T_Damage (tr.ent, ent, ent, vec3_origin, ent->s.origin, vec3_origin, 100000, 0, DAMAGE_NO_PROTECTION, MOD_TELEFRAG);
// if we didn't kill it, fail
if (tr.ent->solid)
return false;
} }
return true; // all clear /* nail it */
T_Damage(tr.ent,
ent,
ent,
vec3_origin,
ent->s.origin,
vec3_origin,
100000,
0,
DAMAGE_NO_PROTECTION,
MOD_TELEFRAG);
/* if we didn't kill it, fail */
if (tr.ent->solid)
{
return false;
}
}
return true; /* all clear */
} }

File diff suppressed because it is too large Load diff