game: sync with ctf g_svcmds, g_target, g_trigger

This commit is contained in:
Denis Pauk 2023-11-02 00:58:27 +02:00
parent d68c31e0e4
commit c41b72125a
13 changed files with 261 additions and 2246 deletions

View file

@ -1500,9 +1500,9 @@ CTF_OBJS_ = \
src/ctf/g_save.o \
src/game/g_sphere.o \
src/ctf/g_spawn.o \
src/ctf/g_svcmds.o \
src/ctf/g_target.o \
src/ctf/g_trigger.o \
src/game/g_svcmds.o \
src/game/g_target.o \
src/game/g_trigger.o \
src/game/g_utils.o \
src/game/g_weapon.o \
src/game/menu/menu.o \

View file

@ -122,7 +122,7 @@ void
monster_fire_ionripper(edict_t *self, vec3_t start, vec3_t dir, int damage,
int speed, int flashtype, int effect)
{
if (!self)
if (!self)
{
return;
}
@ -139,7 +139,7 @@ void
monster_fire_heat(edict_t *self, vec3_t start, vec3_t dir, int damage,
int speed, int flashtype)
{
if (!self)
if (!self)
{
return;
}
@ -194,7 +194,7 @@ dabeam_hit(edict_t *self)
vec3_t end;
trace_t tr;
if (!self)
if (!self)
{
return;
}
@ -266,7 +266,7 @@ monster_dabeam(edict_t *self)
vec3_t last_movedir;
vec3_t point;
if (!self)
if (!self)
{
return;
}

View file

@ -1,5 +1,6 @@
/*
* Copyright (C) 1997-2001 Id Software, Inc.
* Copyright (c) ZeniMax Media Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -27,21 +28,20 @@
#include "header/local.h"
/*
* pushmove objects do not obey gravity, and do not interact with
* each other or trigger fields, but block normal movement and push
* normal objects when they move.
* pushmove objects do not obey gravity, and do not interact with each other or
* trigger fields, but block normal movement and push normal objects when they move.
*
* onground is set for toss objects when they come to a complete rest.
* It is set for steping or walking objects.
* onground is set for toss objects when they come to a complete rest. it is set for
* steping or walking objects
*
* doors, plats, etc are SOLID_BSP, and MOVETYPE_PUSH
* bonus items are SOLID_TRIGGER touch, and MOVETYPE_TOSS
* corpses are SOLID_NOT and MOVETYPE_TOSS
* crates are SOLID_BBOX and MOVETYPE_TOSS
* walking monsters are SOLID_SLIDEBOX and MOVETYPE_STEP
* flying/floating monsters are SOLID_SLIDEBOX and MOVETYPE_FLY
* - doors, plats, etc are SOLID_BSP, and MOVETYPE_PUSH
* - bonus items are SOLID_TRIGGER touch, and MOVETYPE_TOSS
* - corpses are SOLID_NOT and MOVETYPE_TOSS
* - crates are SOLID_BBOX and MOVETYPE_TOSS
* - walking monsters are SOLID_SLIDEBOX and MOVETYPE_STEP
* - flying/floating monsters are SOLID_SLIDEBOX and MOVETYPE_FLY
* - solid_edge items only clip against bsp models.
*
* solid_edge items only clip against bsp models.
*/
edict_t *
@ -50,7 +50,15 @@ SV_TestEntityPosition(edict_t *ent)
trace_t trace;
int mask;
if (ent->clipmask)
if (!ent)
{
return NULL;
}
/* dead bodies are supposed to not be solid so lets
ensure they only collide with BSP during pushmoves
*/
if (ent->clipmask && !(ent->svflags & SVF_DEADMONSTER))
{
mask = ent->clipmask;
}
@ -90,13 +98,19 @@ SV_CheckVelocity(edict_t *ent)
}
/*
* Runs thinking code for this frame if necessary
* Runs thinking code for
* this frame if necessary
*/
qboolean
SV_RunThink(edict_t *ent)
{
float thinktime;
if (!ent)
{
return false;
}
thinktime = ent->nextthink;
if (thinktime <= 0)
@ -122,13 +136,19 @@ SV_RunThink(edict_t *ent)
}
/*
* Two entities have touched, so run their touch functions
* Two entities have touched, so
* run their touch functions
*/
void
SV_Impact(edict_t *e1, trace_t *trace)
{
edict_t *e2;
if (!e1 || !trace)
{
return;
}
e2 = trace->ent;
if (e1->touch && (e1->solid != SOLID_NOT))

View file

@ -94,6 +94,8 @@ void SP_target_help(edict_t *ent);
void SP_target_actor(edict_t *ent);
void SP_target_lightramp(edict_t *self);
void SP_target_earthquake(edict_t *ent);
void SP_target_music(edict_t *ent);
void SP_target_sky(edict_t *ent);
void SP_target_character(edict_t *ent);
void SP_target_string(edict_t *ent);
@ -149,6 +151,7 @@ void SP_monster_mutant(edict_t *self);
void SP_monster_supertank(edict_t *self);
void SP_monster_boss2(edict_t *self);
void SP_monster_jorg(edict_t *self);
void SP_monster_makron(edict_t *self);
void SP_monster_boss3_stand(edict_t *self);
void SP_monster_commander_body(edict_t *self);
@ -157,6 +160,62 @@ void SP_turret_breach(edict_t *self);
void SP_turret_base(edict_t *self);
void SP_turret_driver(edict_t *self);
void SP_monster_soldier_hypergun(edict_t *self);
void SP_monster_soldier_lasergun(edict_t *self);
void SP_monster_soldier_ripper(edict_t *self);
void SP_monster_fixbot(edict_t *self);
void SP_monster_gekk(edict_t *self);
void SP_monster_chick_heat(edict_t *self);
void SP_monster_gladb(edict_t *self);
void SP_monster_boss5(edict_t *self);
void SP_rotating_light(edict_t *self);
void SP_object_repair(edict_t *self);
void SP_misc_crashviper(edict_t *ent);
void SP_misc_viper_missile(edict_t *self);
void SP_misc_amb4(edict_t *ent);
void SP_target_mal_laser(edict_t *ent);
void SP_misc_transport(edict_t *ent);
void SP_misc_nuke(edict_t *ent);
void SP_func_plat2(edict_t *ent);
void SP_func_door_secret2(edict_t *ent);
void SP_func_force_wall(edict_t *ent);
void SP_info_player_coop_lava(edict_t *self);
void SP_info_teleport_destination(edict_t *self);
void SP_trigger_teleport(edict_t *self);
void SP_trigger_disguise(edict_t *self);
void SP_monster_stalker(edict_t *self);
void SP_monster_turret(edict_t *self);
void SP_target_steam(edict_t *self);
void SP_target_anger(edict_t *self);
void SP_target_killplayers(edict_t *self);
void SP_target_blacklight(edict_t *self);
void SP_target_orb(edict_t *self);
void SP_hint_path(edict_t *self);
void SP_monster_carrier(edict_t *self);
void SP_monster_widow(edict_t *self);
void SP_monster_widow2(edict_t *self);
void SP_dm_tag_token(edict_t *self);
void SP_dm_dball_goal(edict_t *self);
void SP_dm_dball_ball(edict_t *self);
void SP_dm_dball_team1_start(edict_t *self);
void SP_dm_dball_team2_start(edict_t *self);
void SP_dm_dball_ball_start(edict_t *self);
void SP_dm_dball_speed_change(edict_t *self);
void SP_monster_kamikaze(edict_t *self);
void SP_turret_invisible_brain(edict_t *self);
void SP_xatrix_item(edict_t *self);
void SP_misc_nuke_core(edict_t *self);
void ThrowMoreStuff(edict_t *self, vec3_t point);
void ThrowSmallStuff(edict_t *self, vec3_t point);
void ThrowWidowGibLoc(edict_t *self, char *gibname, int damage,
int type, vec3_t startpos, qboolean fade);
void ThrowWidowGibSized(edict_t *self, char *gibname, int damage, int type,
vec3_t startpos, int hitsound, qboolean fade);
static spawn_t spawns[] = {
{"item_health", SP_item_health},
{"item_health_small", SP_item_health_small},
@ -843,128 +902,129 @@ SpawnEntities(const char *mapname, char *entities, const char *spawnpoint)
/* =================================================================== */
char *single_statusbar =
"yb -24 "
static char *single_statusbar =
"yb -24 "
/* health */
"xv 0 "
"hnum "
"xv 50 "
"pic 0 "
"xv 0 "
"hnum "
"xv 50 "
"pic 0 "
/* ammo */
"if 2 "
" xv 100 "
" anum "
" xv 150 "
" pic 2 "
"endif "
"if 2 "
" xv 100 "
" anum "
" xv 150 "
" pic 2 "
"endif "
/* armor */
"if 4 "
" xv 200 "
" rnum "
" xv 250 "
" pic 4 "
"endif "
"if 4 "
" xv 200 "
" rnum "
" xv 250 "
" pic 4 "
"endif "
/* selected item */
"if 6 "
" xv 296 "
" pic 6 "
"endif "
"if 6 "
" xv 296 "
" pic 6 "
"endif "
"yb -50 "
"yb -50 "
/* picked up item */
"if 7 "
" xv 0 "
" pic 7 "
" xv 26 "
" yb -42 "
" stat_string 8 "
" yb -50 "
"endif "
"if 7 "
" xv 0 "
" pic 7 "
" xv 26 "
" yb -42 "
" stat_string 8 "
" yb -50 "
"endif "
/* timer */
"if 9 "
" xv 262 "
" num 2 10 "
" xv 296 "
" pic 9 "
"endif "
"if 9 "
" xv 262 "
" num 2 10 "
" xv 296 "
" pic 9 "
"endif "
/* help / weapon icon */
"if 11 "
" xv 148 "
" pic 11 "
"endif "
"if 11 "
" xv 148 "
" pic 11 "
"endif "
;
char *dm_statusbar =
"yb -24 "
static char *dm_statusbar =
"yb -24 "
/* health */
"xv 0 "
"hnum "
"xv 50 "
"pic 0 "
"xv 0 "
"hnum "
"xv 50 "
"pic 0 "
/* ammo */
"if 2 "
" xv 100 "
" anum "
" xv 150 "
" pic 2 "
"endif "
"if 2 "
" xv 100 "
" anum "
" xv 150 "
" pic 2 "
"endif "
/* armor */
"if 4 "
" xv 200 "
" rnum "
" xv 250 "
" pic 4 "
"endif "
"if 4 "
" xv 200 "
" rnum "
" xv 250 "
" pic 4 "
"endif "
/* selected item */
"if 6 "
" xv 296 "
" pic 6 "
"endif "
"if 6 "
" xv 296 "
" pic 6 "
"endif "
"yb -50 "
"yb -50 "
/* picked up item */
"if 7 "
" xv 0 "
" pic 7 "
" xv 26 "
" yb -42 "
" stat_string 8 "
" yb -50 "
"endif "
"if 7 "
" xv 0 "
" pic 7 "
" xv 26 "
" yb -42 "
" stat_string 8 "
" yb -50 "
"endif "
/* timer */
"if 9 "
" xv 246 "
" num 2 10 "
" xv 296 "
" pic 9 "
"endif "
"if 9 "
" xv 246 "
" num 2 10 "
" xv 296 "
" pic 9 "
"endif "
/* help / weapon icon */
"if 11 "
" xv 148 "
" pic 11 "
"endif "
"if 11 "
" xv 148 "
" pic 11 "
"endif "
/* frags */
"xr -50 "
"yt 2 "
"num 3 14"
"xr -50 "
"yt 2 "
"num 3 14"
;
/*QUAKED worldspawn (0 0 0) ?
/*
* QUAKED worldspawn (0 0 0) ?
*
* Only used for the world.
* "sky" environment map name

View file

@ -1,344 +0,0 @@
/*
* Copyright (C) 1997-2001 Id Software, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or (at
* your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
*
* =======================================================================
*
* Game side of server CMDs. At this time only the ipfilter.
*
* =======================================================================
*/
#include "header/local.h"
void
Svcmd_Test_f(void)
{
gi.cprintf(NULL, PRINT_HIGH, "Svcmd_Test_f()\n");
}
/*
* ==============================================================================
*
* PACKET FILTERING
*
*
* You can add or remove addresses from the filter list with:
*
* addip <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".
*
* Removeip will only remove an address specified exactly the same way.
* You cannot addip a subnet, then removeip a single host.
*
* listip
* Prints the current list of filters.
*
* 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.
*
* 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 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
{
unsigned mask;
unsigned compare;
} ipfilter_t;
#define MAX_IPFILTERS 1024
ipfilter_t ipfilters[MAX_IPFILTERS];
int numipfilters;
static qboolean
StringToFilter(char *s, ipfilter_t *f)
{
char num[128];
int i, j;
byte b[4];
byte m[4];
for (i = 0; i < 4; i++)
{
b[i] = 0;
m[i] = 0;
}
for (i = 0; i < 4; i++)
{
if ((*s < '0') || (*s > '9'))
{
gi.cprintf(NULL, PRINT_HIGH, "Bad filter address: %s\n", s);
return false;
}
j = 0;
while (*s >= '0' && *s <= '9')
{
num[j++] = *s++;
}
num[j] = 0;
b[i] = atoi(num);
if (b[i] != 0)
{
m[i] = 255;
}
if (!*s)
{
break;
}
s++;
}
f->mask = *(unsigned *)m;
f->compare = *(unsigned *)b;
return true;
}
qboolean
SV_FilterPacket(char *from)
{
int i;
unsigned in;
byte m[4];
char *p;
i = 0;
p = from;
while (*p && i < 4)
{
m[i] = 0;
while (*p >= '0' && *p <= '9')
{
m[i] = m[i] * 10 + (*p - '0');
p++;
}
if (!*p || (*p == ':'))
{
break;
}
i++, p++;
}
in = *(unsigned *)m;
for (i = 0; i < numipfilters; i++)
{
if ((in & ipfilters[i].mask) == ipfilters[i].compare)
{
return (int)filterban->value;
}
}
return (int)!filterban->value;
}
void
SVCmd_AddIP_f(void)
{
int i;
if (gi.argc() < 3)
{
gi.cprintf(NULL, PRINT_HIGH, "Usage: addip <ip-mask>\n");
return;
}
for (i = 0; i < numipfilters; i++)
{
if (ipfilters[i].compare == 0xffffffff)
{
break; /* free spot */
}
}
if (i == numipfilters)
{
if (numipfilters == MAX_IPFILTERS)
{
gi.cprintf(NULL, PRINT_HIGH, "IP filter list is full\n");
return;
}
numipfilters++;
}
if (!StringToFilter(gi.argv(2), &ipfilters[i]))
{
ipfilters[i].compare = 0xffffffff;
}
}
void
SVCmd_RemoveIP_f(void)
{
ipfilter_t f;
int i, j;
if (gi.argc() < 3)
{
gi.cprintf(NULL, PRINT_HIGH, "Usage: sv removeip <ip-mask>\n");
return;
}
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;
}
}
gi.cprintf(NULL, PRINT_HIGH, "Didn't find %s.\n", gi.argv(2));
}
void
SVCmd_ListIP_f(void)
{
int i;
byte b[4];
gi.cprintf(NULL, PRINT_HIGH, "Filter list:\n");
for (i = 0; i < numipfilters; i++)
{
*(unsigned *)b = ipfilters[i].compare;
gi.cprintf(NULL, PRINT_HIGH, "%3i.%3i.%3i.%3i\n", b[0],
b[1], b[2], b[3]);
}
}
void
SVCmd_WriteIP_f(void)
{
FILE *f;
char name[MAX_OSPATH];
byte b[4];
int i;
cvar_t *game;
game = gi.cvar("game", "", 0);
if (!*game->string)
{
sprintf(name, "%s/listip.cfg", GAMEVERSION);
}
else
{
sprintf(name, "%s/listip.cfg", game->string);
}
gi.cprintf(NULL, PRINT_HIGH, "Writing %s.\n", name);
f = fopen(name, "wb");
if (!f)
{
gi.cprintf(NULL, PRINT_HIGH, "Couldn't open %s\n", name);
return;
}
fprintf(f, "set filterban %d\n", (int)filterban->value);
for (i = 0; i < numipfilters; i++)
{
*(unsigned *)b = ipfilters[i].compare;
fprintf(f, "sv addip %i.%i.%i.%i\n", b[0], b[1], b[2], b[3]);
}
fclose(f);
}
/*
* ServerCommand will be called when an "sv" command is issued.
* The game can issue gi.argc() / gi.argv() commands to get the rest
* of the parameters
*/
void
ServerCommand(void)
{
char *cmd;
cmd = gi.argv(1);
if (Q_stricmp(cmd, "test") == 0)
{
Svcmd_Test_f();
}
else if (Q_stricmp(cmd, "addip") == 0)
{
SVCmd_AddIP_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
{
gi.cprintf(NULL, PRINT_HIGH, "Unknown server command \"%s\"\n", cmd);
}
}

File diff suppressed because it is too large Load diff

View file

@ -1,756 +0,0 @@
/*
* Copyright (C) 1997-2001 Id Software, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or (at
* your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
*
* =======================================================================
*
* Trigger.
*
* =======================================================================
*/
#include "header/local.h"
void
InitTrigger(edict_t *self)
{
if (!VectorCompare(self->s.angles, vec3_origin))
{
G_SetMovedir(self->s.angles, self->movedir);
}
self->solid = SOLID_TRIGGER;
self->movetype = MOVETYPE_NONE;
gi.setmodel(self, self->model);
self->svflags = SVF_NOCLIENT;
}
/*
* The wait time has passed, so set
* back up for another activation
*/
void
multi_wait(edict_t *ent)
{
ent->nextthink = 0;
}
void
multi_trigger(edict_t *ent)
{
if (ent->nextthink)
{
return; /* already been triggered */
}
G_UseTargets(ent, ent->activator);
if (ent->wait > 0)
{
ent->think = multi_wait;
ent->nextthink = level.time + ent->wait;
}
else
{
/* we can't just remove (self) here, because this is
a touch function called while looping through area links... */
ent->touch = NULL;
ent->nextthink = level.time + FRAMETIME;
ent->think = G_FreeEdict;
}
}
void
Use_Multi(edict_t *ent, edict_t *other, edict_t *activator)
{
ent->activator = activator;
multi_trigger(ent);
}
void
Touch_Multi(edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf)
{
if (other->client)
{
if (self->spawnflags & 2)
{
return;
}
}
else if (other->svflags & SVF_MONSTER)
{
if (!(self->spawnflags & 1))
{
return;
}
}
else
{
return;
}
if (!VectorCompare(self->movedir, vec3_origin))
{
vec3_t forward;
AngleVectors(other->s.angles, forward, NULL, NULL);
if (_DotProduct(forward, self->movedir) < 0)
{
return;
}
}
self->activator = other;
multi_trigger(self);
}
/*
* QUAKED trigger_multiple (.5 .5 .5) ? MONSTER NOT_PLAYER TRIGGERED
* 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.
* "wait" : Seconds between triggerings. (.2 default)
*
* sounds
* 1) secret
* 2) beep beep
* 3) large switch
* 4)
*
* set "message" to text string
*/
void
trigger_enable(edict_t *self, edict_t *other, edict_t *activator)
{
self->solid = SOLID_TRIGGER;
self->use = Use_Multi;
gi.linkentity(self);
}
void
SP_trigger_multiple(edict_t *ent)
{
if (ent->sounds == 1)
{
ent->noise_index = gi.soundindex("misc/secret.wav");
}
else if (ent->sounds == 2)
{
ent->noise_index = gi.soundindex("misc/talk.wav");
}
else if (ent->sounds == 3)
{
ent->noise_index = gi.soundindex("misc/trigger1.wav");
}
if (!ent->wait)
{
ent->wait = 0.2;
}
ent->touch = Touch_Multi;
ent->movetype = MOVETYPE_NONE;
ent->svflags |= SVF_NOCLIENT;
if (ent->spawnflags & 4)
{
ent->solid = SOLID_NOT;
ent->use = trigger_enable;
}
else
{
ent->solid = SOLID_TRIGGER;
ent->use = Use_Multi;
}
if (!VectorCompare(ent->s.angles, vec3_origin))
{
G_SetMovedir(ent->s.angles, ent->movedir);
}
gi.setmodel(ent, ent->model);
gi.linkentity(ent);
}
/*
* QUAKED trigger_once (.5 .5 .5) ? x x TRIGGERED
* 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".
*
* 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
*/
void
SP_trigger_once(edict_t *ent)
{
/* 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 */
if (ent->spawnflags & 1)
{
vec3_t v;
VectorMA(ent->mins, 0.5, ent->size, v);
ent->spawnflags &= ~1;
ent->spawnflags |= 4;
gi.dprintf("fixed TRIGGERED flag on %s at %s\n", ent->classname, vtos(v));
}
ent->wait = -1;
SP_trigger_multiple(ent);
}
/*
* 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.
*/
void
trigger_relay_use(edict_t *self, edict_t *other, edict_t *activator)
{
G_UseTargets(self, activator);
}
void
SP_trigger_relay(edict_t *self)
{
self->use = trigger_relay_use;
}
/*
* ==============================================================================
*
* trigger_key
*
* ==============================================================================
*/
/*
* 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.
* 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)
{
int index;
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;
}
gi.sound(activator, CHAN_AUTO, gi.soundindex("misc/keyuse.wav"), 1, ATTN_NORM, 0);
if (coop->value)
{
int player;
edict_t *ent;
if (strcmp(self->item->classname, "key_power_cube") == 0)
{
int cube;
for (cube = 0; cube < 8; cube++)
{
if (activator->client->pers.power_cubes & (1 << cube))
{
break;
}
}
for (player = 1; player <= game.maxclients; player++)
{
ent = &g_edicts[player];
if (!ent->inuse)
{
continue;
}
if (!ent->client)
{
continue;
}
if (ent->client->pers.power_cubes & (1 << cube))
{
ent->client->pers.inventory[index]--;
ent->client->pers.power_cubes &= ~(1 << cube);
}
}
}
else
{
for (player = 1; player <= game.maxclients; player++)
{
ent = &g_edicts[player];
if (!ent->inuse)
{
continue;
}
if (!ent->client)
{
continue;
}
ent->client->pers.inventory[index] = 0;
}
}
}
else
{
activator->client->pers.inventory[index]--;
}
G_UseTargets(self, activator);
self->use = NULL;
}
void
SP_trigger_key(edict_t *self)
{
if (!st.item)
{
gi.dprintf("no key item for trigger_key at %s\n", vtos(self->s.origin));
return;
}
self->item = FindItemByClassname(st.item);
if (!self->item)
{
gi.dprintf("item %s not found for trigger_key at %s\n", st.item,
vtos(self->s.origin));
return;
}
if (!self->target)
{
gi.dprintf("%s at %s has no target\n", self->classname,
vtos(self->s.origin));
return;
}
gi.soundindex("misc/keytry.wav");
gi.soundindex("misc/keyuse.wav");
self->use = trigger_key_use;
}
/*
* ==============================================================================
*
* trigger_counter
*
* ==============================================================================
*/
/*
* QUAKED trigger_counter (.5 .5 .5) ? nomessage
* 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.
*/
void
trigger_counter_use(edict_t *self, edict_t *other, edict_t *activator)
{
if (self->count == 0)
{
return;
}
self->count--;
if (self->count)
{
if (!(self->spawnflags & 1))
{
gi.centerprintf(activator, "%i more to go...", self->count);
gi.sound(activator, CHAN_AUTO, gi.soundindex("misc/talk1.wav"), 1, ATTN_NORM, 0);
}
return;
}
if (!(self->spawnflags & 1))
{
gi.centerprintf(activator, "Sequence completed!");
gi.sound(activator, CHAN_AUTO, gi.soundindex("misc/talk1.wav"), 1, ATTN_NORM, 0);
}
self->activator = activator;
multi_trigger(self);
}
void
SP_trigger_counter(edict_t *self)
{
self->wait = -1;
if (!self->count)
{
self->count = 2;
}
self->use = trigger_counter_use;
}
/*
* ==============================================================================
*
* trigger_always
*
* ==============================================================================
*/
/*
* QUAKED trigger_always (.5 .5 .5) (-8 -8 -8) (8 8 8)
* This trigger will always fire. It is activated by the world.
*/
void
SP_trigger_always(edict_t *ent)
{
/* we must have some delay to make sure our use targets are present */
if (ent->delay < 0.2)
{
ent->delay = 0.2;
}
G_UseTargets(ent, ent);
}
/*
* ==============================================================================
*
* trigger_push
*
* ==============================================================================
*/
#define PUSH_ONCE 1
static int windsound;
void
trigger_push_touch(edict_t *self, edict_t *other, cplane_t *plane,
csurface_t *surf)
{
if (strcmp(other->classname, "grenade") == 0)
{
VectorScale(self->movedir, self->speed * 10, other->velocity);
}
else if (other->health > 0)
{
VectorScale(self->movedir, self->speed * 10, other->velocity);
if (other->client)
{
/* don't take falling damage immediately from this */
VectorCopy(other->velocity, other->client->oldvelocity);
if (other->fly_sound_debounce_time < level.time)
{
other->fly_sound_debounce_time = level.time + 1.5;
gi.sound(other, CHAN_AUTO, windsound, 1, ATTN_NORM, 0);
}
}
}
if (self->spawnflags & PUSH_ONCE)
{
G_FreeEdict(self);
}
}
/*
* QUAKED trigger_push (.5 .5 .5) ? PUSH_ONCE
* Pushes the player
* "speed" defaults to 1000
*/
void
SP_trigger_push(edict_t *self)
{
InitTrigger(self);
windsound = gi.soundindex("misc/windfly.wav");
self->touch = trigger_push_touch;
if (!self->speed)
{
self->speed = 1000;
}
gi.linkentity(self);
}
/*
* ==============================================================================
*
* trigger_hurt
*
* ==============================================================================
*/
/*
* QUAKED trigger_hurt (.5 .5 .5) ? START_OFF TOGGLE SILENT NO_PROTECTION SLOW
* Any entity that touches this will be hurt.
*
* It does dmg points of damage each server frame
*
* SILENT supresses playing the sound
* SLOW changes the damage rate to once per second
* NO_PROTECTION *nothing* stops the damage
*
* "dmg" default 5 (whole numbers only)
*
*/
void
hurt_use(edict_t *self, edict_t *other, edict_t *activator)
{
if (self->solid == SOLID_NOT)
{
self->solid = SOLID_TRIGGER;
}
else
{
self->solid = SOLID_NOT;
}
gi.linkentity(self);
if (!(self->spawnflags & 2))
{
self->use = NULL;
}
}
void
hurt_touch(edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf)
{
int dflags;
if (!other->takedamage)
{
return;
}
if (self->timestamp > level.time)
{
return;
}
if (self->spawnflags & 16)
{
self->timestamp = level.time + 1;
}
else
{
self->timestamp = level.time + FRAMETIME;
}
if (!(self->spawnflags & 4))
{
if ((level.framenum % 10) == 0)
{
gi.sound(other, CHAN_AUTO, self->noise_index, 1, ATTN_NORM, 0);
}
}
if (self->spawnflags & 8)
{
dflags = DAMAGE_NO_PROTECTION;
}
else
{
dflags = 0;
}
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)
{
InitTrigger(self);
self->noise_index = gi.soundindex("world/electro.wav");
self->touch = hurt_touch;
if (!self->dmg)
{
self->dmg = 5;
}
if (self->spawnflags & 1)
{
self->solid = SOLID_NOT;
}
else
{
self->solid = SOLID_TRIGGER;
}
if (self->spawnflags & 2)
{
self->use = hurt_use;
}
gi.linkentity(self);
}
/*
* ==============================================================================
*
* trigger_gravity
*
* ==============================================================================
*/
/*
* QUAKED trigger_gravity (.5 .5 .5) ?
* Changes the touching entites gravity to
* the value of "gravity". 1.0 is standard
* gravity for the level.
*/
void
trigger_gravity_touch(edict_t *self, edict_t *other, cplane_t *plane,
csurface_t *surf)
{
other->gravity = self->gravity;
}
void
SP_trigger_gravity(edict_t *self)
{
if (st.gravity == 0)
{
gi.dprintf("trigger_gravity without gravity set at %s\n", vtos(self->s.origin));
G_FreeEdict(self);
return;
}
InitTrigger(self);
self->gravity = atoi(st.gravity);
self->touch = trigger_gravity_touch;
}
/*
* ==============================================================================
*
* trigger_monsterjump
*
* ==============================================================================
*/
/*
* QUAKED trigger_monsterjump (.5 .5 .5) ?
* Walking monsters that touch this will jump in the direction of the trigger's angle
* "speed" default to 200, the speed thrown forward
* "height" default to 200, the speed thrown upwards
*/
void
trigger_monsterjump_touch(edict_t *self, edict_t *other, cplane_t *plane,
csurface_t *surf)
{
if (other->flags & (FL_FLY | FL_SWIM))
{
return;
}
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[1] = self->movedir[1] * self->speed;
if (!other->groundentity)
{
return;
}
other->groundentity = NULL;
other->velocity[2] = self->movedir[2];
}
void
SP_trigger_monsterjump(edict_t *self)
{
if (!self->speed)
{
self->speed = 200;
}
if (!st.height)
{
st.height = 200;
}
if (self->s.angles[YAW] == 0)
{
self->s.angles[YAW] = 360;
}
InitTrigger(self);
self->touch = trigger_monsterjump_touch;
self->movedir[2] = st.height;
}

View file

@ -386,7 +386,7 @@ range(edict_t *self, edict_t *other)
vec3_t v;
float len;
if (!self || !other)
if (!self || !other)
{
return 0;
}

View file

@ -1152,7 +1152,7 @@ plat2_operate(edict_t *ent, edict_t *other)
float platCenter;
edict_t *trigger;
if (!ent || !other)
if (!ent || !other)
{
return;
}

View file

@ -122,7 +122,7 @@ void
monster_fire_ionripper(edict_t *self, vec3_t start, vec3_t dir, int damage,
int speed, int flashtype, int effect)
{
if (!self)
if (!self)
{
return;
}
@ -139,7 +139,7 @@ void
monster_fire_heat(edict_t *self, vec3_t start, vec3_t dir, int damage,
int speed, int flashtype)
{
if (!self)
if (!self)
{
return;
}
@ -194,7 +194,7 @@ dabeam_hit(edict_t *self)
vec3_t end;
trace_t tr;
if (!self)
if (!self)
{
return;
}
@ -266,7 +266,7 @@ monster_dabeam(edict_t *self)
vec3_t last_movedir;
vec3_t point;
if (!self)
if (!self)
{
return;
}

View file

@ -1139,13 +1139,13 @@ static char *dm_statusbar =
" pic 9 "
"endif "
/* help / weapon icon */
/* help / weapon icon */
"if 11 "
" xv 148 "
" pic 11 "
"endif "
/* frags */
/* frags */
"xr -50 "
"yt 2 "
"num 3 14 "

View file

@ -290,7 +290,8 @@ SP_target_secret(edict_t *ent)
/* Map quirk for mine3 */
if (!Q_stricmp(level.mapname, "mine3") && (ent->s.origin[0] == 280) &&
(ent->s.origin[1] == -2048) && (ent->s.origin[2] == -624))
(ent->s.origin[1] == -2048) &&
(ent->s.origin[2] == -624))
{
ent->message = "You have found a secret area.";
}
@ -1036,7 +1037,7 @@ SP_target_laser(edict_t *self)
void
target_mal_laser_on(edict_t *self)
{
if (!self)
if (!self)
{
return;
}
@ -1054,7 +1055,7 @@ target_mal_laser_on(edict_t *self)
void
target_mal_laser_off(edict_t *self)
{
if (!self)
if (!self)
{
return;
}
@ -1087,7 +1088,7 @@ target_mal_laser_use(edict_t *self, edict_t *other /* unused */, edict_t *activa
void
mal_laser_think(edict_t *self)
{
if (!self)
if (!self)
{
return;
}
@ -1100,7 +1101,7 @@ mal_laser_think(edict_t *self)
void
SP_target_mal_laser(edict_t *self)
{
if (!self)
if (!self)
{
return;
}

View file

@ -341,6 +341,14 @@ SP_trigger_relay(edict_t *self)
self->use = trigger_relay_use;
}
/*
* ==============================================================================
*
* trigger_key
*
* ==============================================================================
*/
/*
* QUAKED trigger_key (.5 .5 .5) (-8 -8 -8) (8 8 8)
* A relay trigger that only fires it's targets if player
@ -489,6 +497,14 @@ SP_trigger_key(edict_t *self)
self->use = trigger_key_use;
}
/*
* ==============================================================================
*
* trigger_counter
*
* ==============================================================================
*/
/*
* QUAKED trigger_counter (.5 .5 .5) ? nomessage
*
@ -558,6 +574,14 @@ SP_trigger_counter(edict_t *self)
self->use = trigger_counter_use;
}
/*
* ==============================================================================
*
* trigger_always
*
* ==============================================================================
*/
/*
* QUAKED trigger_always (.5 .5 .5) (-8 -8 -8) (8 8 8)
*
@ -581,6 +605,14 @@ SP_trigger_always(edict_t *ent)
G_UseTargets(ent, ent);
}
/*
* ==============================================================================
*
* trigger_push
*
* ==============================================================================
*/
void
trigger_push_touch(edict_t *self, edict_t *other, cplane_t *plane /* unused */,
csurface_t *surf /* unused */)
@ -632,7 +664,7 @@ trigger_effect(edict_t *self)
vec3_t size;
int i;
if (!self)
if (!self)
{
return;
}
@ -656,7 +688,7 @@ trigger_effect(edict_t *self)
void
trigger_push_inactive(edict_t *self)
{
if (!self)
if (!self)
{
return;
}
@ -776,6 +808,14 @@ SP_trigger_push(edict_t *self)
gi.linkentity(self);
}
/*
* ==============================================================================
*
* trigger_hurt
*
* ==============================================================================
*/
/*
* QUAKED trigger_hurt (.5 .5 .5) ? START_OFF TOGGLE SILENT NO_PROTECTION SLOW
*
@ -805,7 +845,7 @@ hurt_use(edict_t *self, edict_t *other /* unused */,
edict_t *touch[MAX_EDICTS], *hurtme;
self->solid = SOLID_TRIGGER;
num = gi.BoxEdicts (self->absmin, self->absmax,
num = gi.BoxEdicts(self->absmin, self->absmax,
touch, MAX_EDICTS, AREA_SOLID);
/* Check for idle monsters in
@ -915,6 +955,14 @@ SP_trigger_hurt(edict_t *self)
gi.linkentity(self);
}
/*
* ==============================================================================
*
* trigger_gravity
*
* ==============================================================================
*/
void
trigger_gravity_use(edict_t *self, edict_t *other /* unused */, edict_t *activator /* unused */)
{
@ -996,6 +1044,14 @@ SP_trigger_gravity(edict_t *self)
gi.linkentity(self);
}
/*
* ==============================================================================
*
* trigger_monsterjump
*
* ==============================================================================
*/
/*
* QUAKED trigger_monsterjump (.5 .5 .5) ?
* Walking monsters that touch this will jump in the direction of the trigger's angle