Cleanup g_utils.c

This commit is contained in:
Yamagi Burmeister 2011-10-15 08:22:51 +00:00
parent 725c5a94b7
commit b15f5fc407

View file

@ -1,125 +1,149 @@
/*
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.
*/
// g_utils.c -- misc utility functions for game module
* 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.
*
* =======================================================================
*
* Misc. utility functions for the game logic.
*
* =======================================================================
*/
#include "header/local.h"
void G_ProjectSource (vec3_t point, vec3_t distance, vec3_t forward, vec3_t right, vec3_t result)
void
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[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
Searches all active entities for the next one that holds
the matching string at fieldofs (use the FOFS() macro) in the structure.
Searches beginning at the edict after from, or the beginning if NULL
NULL will be returned if the end of the list is reached.
=============
*/
edict_t *G_Find (edict_t *from, int fieldofs, char *match)
* Searches all active entities for the next one
* that holds the matching string at fieldofs (use
* the FOFS() macro) in the structure.
*
* Searches beginning at the edict after from, or the
* beginning if NULL. NULL will be returned if the end
* of the list is reached.
*/
edict_t *
G_Find(edict_t *from, int fieldofs, char *match)
{
char *s;
char *s;
if (!from)
{
from = g_edicts;
}
else
{
from++;
}
for ( ; from < &g_edicts[globals.num_edicts] ; from++)
for ( ; from < &g_edicts[globals.num_edicts]; from++)
{
if (!from->inuse)
{
continue;
s = *(char **) ((byte *)from + fieldofs);
}
s = *(char **)((byte *)from + fieldofs);
if (!s)
{
continue;
if (!Q_stricmp (s, match))
}
if (!Q_stricmp(s, match))
{
return from;
}
}
return NULL;
}
/*
=================
findradius
Returns entities that have origins within a spherical area
findradius (origin, radius)
=================
*/
edict_t *findradius (edict_t *from, vec3_t org, float rad)
* Returns entities that have origins within a spherical area
*/
edict_t *
findradius(edict_t *from, vec3_t org, float rad)
{
vec3_t eorg;
int j;
vec3_t eorg;
int j;
if (!from)
{
from = g_edicts;
}
else
{
from++;
}
for ( ; from < &g_edicts[globals.num_edicts]; from++)
{
if (!from->inuse)
{
continue;
}
if (from->solid == SOLID_NOT)
{
continue;
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)
{
continue;
}
return from;
}
return NULL;
}
/*
=============
G_PickTarget
* Searches all active entities for the next one that holds
* the matching string at fieldofs (use the FOFS() macro) in the structure.
*
* Searches beginning at the edict after from, or the beginning if NULL
* NULL will be returned if the end of the list is reached.
*/
#define MAXCHOICES 8
Searches all active entities for the next one that holds
the matching string at fieldofs (use the FOFS() macro) in the structure.
Searches beginning at the edict after from, or the beginning if NULL
NULL will be returned if the end of the list is reached.
=============
*/
#define MAXCHOICES 8
edict_t *G_PickTarget (char *targetname)
edict_t *
G_PickTarget(char *targetname)
{
edict_t *ent = NULL;
int num_choices = 0;
edict_t *choice[MAXCHOICES];
edict_t *ent = NULL;
int num_choices = 0;
edict_t *choice[MAXCHOICES];
if (!targetname)
{
@ -127,14 +151,21 @@ edict_t *G_PickTarget (char *targetname)
return NULL;
}
while(1)
while (1)
{
ent = G_Find (ent, FOFS(targetname), targetname);
ent = G_Find(ent, FOFS(targetname), targetname);
if (!ent)
{
break;
}
choice[num_choices++] = ent;
if (num_choices == MAXCHOICES)
{
break;
}
}
if (!num_choices)
@ -146,75 +177,77 @@ edict_t *G_PickTarget (char *targetname)
return choice[rand() % num_choices];
}
void Think_Delay (edict_t *ent)
void
Think_Delay(edict_t *ent)
{
G_UseTargets (ent, ent->activator);
G_FreeEdict (ent);
G_UseTargets(ent, ent->activator);
G_FreeEdict(ent);
}
/*
==============================
G_UseTargets
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
do the SUB_UseTargets after that many seconds have passed.
Centerprints any self.message to the activator.
Search for (string)targetname in all entities that
match (string)self.target and call their .use function
==============================
*/
void G_UseTargets (edict_t *ent, edict_t *activator)
* 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 do the SUB_UseTargets
* after that many seconds have passed.
*
* Centerprints any self.message to the activator.
*
* Search for (string)targetname in all entities that
* match (string)self.target and call their .use function
*/
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)
{
// create a temp object to fire at a later time
/* create a temp object to fire at a later time */
t = G_Spawn();
t->classname = "DelayedUse";
t->nextthink = level.time + ent->delay;
t->think = Think_Delay;
t->activator = activator;
if (!activator)
gi.dprintf ("Think_Delay with no activator\n");
{
gi.dprintf("Think_Delay with no activator\n");
}
t->message = ent->message;
t->target = ent->target;
t->killtarget = ent->killtarget;
return;
}
//
// print the message
//
/* print the message */
if ((ent->message) && !(activator->svflags & SVF_MONSTER))
{
gi.centerprintf (activator, "%s", ent->message);
gi.centerprintf(activator, "%s", ent->message);
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
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)
{
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)
{
gi.dprintf("entity was removed while using killtargets\n");
@ -223,28 +256,33 @@ void G_UseTargets (edict_t *ent, edict_t *activator)
}
}
//
// fire targets
//
/* fire targets */
if (ent->target)
{
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") &&
(!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;
}
if (t == ent)
{
gi.dprintf ("WARNING: Entity used itself.\n");
gi.dprintf("WARNING: Entity used itself.\n");
}
else
{
if (t->use)
t->use (t, ent, activator);
{
t->use(t, ent, activator);
}
}
if (!ent->inuse)
{
gi.dprintf("entity was removed while using targets\n");
@ -254,25 +292,19 @@ void G_UseTargets (edict_t *ent, edict_t *activator)
}
}
/*
=============
TempVector
This is just a convenience function
for making temporary vectors for function calls
=============
*/
float *tv (float x, float y, float z)
* This is just a convenience function
* for making temporary vectors for function calls
*/
float *
tv(float x, float y, float z)
{
static int index;
static vec3_t vecs[8];
float *v;
static int index;
static vec3_t vecs[8];
float *v;
// use an array so that multiple tempvectors won't collide
// for a while
v = vecs[index];
index = (index + 1)&7;
index = (index + 1) & 7;
v[0] = x;
v[1] = y;
@ -281,106 +313,127 @@ float *tv (float x, float y, float z)
return v;
}
/*
=============
VectorToString
This is just a convenience function
for printing vectors
=============
*/
char *vtos (vec3_t v)
* This is just a convenience function
* for printing vectors
*/
char *
vtos(vec3_t v)
{
static int index;
static char str[8][32];
char *s;
static int index;
static char str[8][32];
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];
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;
}
vec3_t VEC_UP = {0, -1, 0};
vec3_t MOVEDIR_UP = {0, 0, 1};
vec3_t VEC_DOWN = {0, -2, 0};
vec3_t MOVEDIR_DOWN = {0, 0, -1};
vec3_t VEC_UP = {0, -1, 0};
vec3_t MOVEDIR_UP = {0, 0, 1};
vec3_t VEC_DOWN = {0, -2, 0};
vec3_t MOVEDIR_DOWN = {0, 0, -1};
void 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
{
AngleVectors (angles, movedir, NULL, NULL);
AngleVectors(angles, movedir, NULL, NULL);
}
VectorClear (angles);
VectorClear(angles);
}
float vectoyaw (vec3_t vec)
float
vectoyaw(vec3_t vec)
{
float yaw;
if (/* vec[YAW] == 0 && */ vec[PITCH] == 0)
float yaw;
if (vec[PITCH] == 0)
{
yaw = 0;
if (vec[YAW] > 0)
{
yaw = 90;
}
else if (vec[YAW] < 0)
{
yaw = -90;
}
}
else
{
yaw = (int) (atan2(vec[YAW], vec[PITCH]) * 180 / M_PI);
yaw = (int)(atan2(vec[YAW], vec[PITCH]) * 180 / M_PI);
if (yaw < 0)
{
yaw += 360;
}
}
return yaw;
}
void vectoangles (vec3_t value1, vec3_t angles)
void
vectoangles(vec3_t value1, vec3_t angles)
{
float forward;
float yaw, pitch;
if (value1[1] == 0 && value1[0] == 0)
float forward;
float yaw, pitch;
if ((value1[1] == 0) && (value1[0] == 0))
{
yaw = 0;
if (value1[2] > 0)
{
pitch = 90;
}
else
{
pitch = 270;
}
}
else
{
if (value1[0])
yaw = (int) (atan2(value1[1], value1[0]) * 180 / M_PI);
{
yaw = (int)(atan2(value1[1], value1[0]) * 180 / M_PI);
}
else if (value1[1] > 0)
{
yaw = 90;
}
else
{
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)
{
pitch += 360;
}
}
angles[PITCH] = -pitch;
@ -388,17 +441,18 @@ void vectoangles (vec3_t value1, vec3_t angles)
angles[ROLL] = 0;
}
char *G_CopyString (char *in)
char *
G_CopyString(char *in)
{
char *out;
out = gi.TagMalloc (strlen(in)+1, TAG_LEVEL);
strcpy (out, in);
char *out;
out = gi.TagMalloc(strlen(in) + 1, TAG_LEVEL);
strcpy(out, in);
return out;
}
void G_InitEdict (edict_t *e)
void
G_InitEdict(edict_t *e)
{
e->inuse = true;
e->classname = "noclass";
@ -407,162 +461,170 @@ void G_InitEdict (edict_t *e)
}
/*
=================
G_Spawn
Either finds a free edict, or allocates a new one.
Try to avoid reusing an entity that was recently freed, because it
can cause the client to think the entity morphed into something else
instead of being removed and recreated, which can cause interpolated
angles and bad trails.
=================
*/
edict_t *G_Spawn (void)
* Either finds a free edict, or allocates a new one.
* Try to avoid reusing an entity that was recently freed, because it
* can cause the client to think the entity morphed into something else
* instead of being removed and recreated, which can cause interpolated
* angles and bad trails.
*/
edict_t *
G_Spawn(void)
{
int i;
edict_t *e;
int i;
edict_t *e;
e = &g_edicts[(int)maxclients->value+1];
for ( i=maxclients->value+1 ; i<globals.num_edicts ; i++, e++)
e = &g_edicts[(int)maxclients->value + 1];
for (i = maxclients->value + 1; i < globals.num_edicts; i++, e++)
{
// the first couple seconds of server time can involve a lot of
// freeing and allocating, so relax the replacement policy
if (!e->inuse && ( e->freetime < 2 || level.time - e->freetime > 0.5 ) )
/* the first couple seconds of server time can involve a lot of
freeing and allocating, so relax the replacement policy */
if (!e->inuse && ((e->freetime < 2) || (level.time - e->freetime > 0.5)))
{
G_InitEdict (e);
G_InitEdict(e);
return e;
}
}
if (i == game.maxentities)
gi.error ("ED_Alloc: no free edicts");
{
gi.error("ED_Alloc: no free edicts");
}
globals.num_edicts++;
G_InitEdict (e);
G_InitEdict(e);
return e;
}
/*
=================
G_FreeEdict
Marks the edict as free
=================
*/
void G_FreeEdict (edict_t *ed)
* Marks the edict as free
*/
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))
{
return;
}
memset (ed, 0, sizeof(*ed));
memset(ed, 0, sizeof(*ed));
ed->classname = "freed";
ed->freetime = level.time;
ed->inuse = false;
}
/*
============
G_TouchTriggers
============
*/
void G_TouchTriggers (edict_t *ent)
void
G_TouchTriggers(edict_t *ent)
{
int i, num;
edict_t *touch[MAX_EDICTS], *hit;
int i, num;
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))
{
return;
}
num = gi.BoxEdicts (ent->absmin, ent->absmax, touch
, MAX_EDICTS, AREA_TRIGGERS);
num = gi.BoxEdicts(ent->absmin, ent->absmax, touch,
MAX_EDICTS, AREA_TRIGGERS);
// be careful, it is possible to have an entity in this
// list removed before we get to it (killtriggered)
for (i=0 ; i<num ; i++)
/* be careful, it is possible to have an entity in this
list removed before we get to it (killtriggered) */
for (i = 0; i < num; i++)
{
hit = touch[i];
if (!hit->inuse)
{
continue;
}
if (!hit->touch)
{
continue;
hit->touch (hit, ent, NULL, NULL);
}
hit->touch(hit, ent, NULL, NULL);
}
}
/*
============
G_TouchSolids
Call after linking a new trigger in during gameplay
to force all entities it covers to immediately touch it
============
*/
void G_TouchSolids (edict_t *ent)
* Call after linking a new trigger in during gameplay
* to force all entities it covers to immediately touch it
*/
void
G_TouchSolids(edict_t *ent)
{
int i, num;
edict_t *touch[MAX_EDICTS], *hit;
int i, num;
edict_t *touch[MAX_EDICTS], *hit;
num = gi.BoxEdicts (ent->absmin, ent->absmax, touch
, MAX_EDICTS, AREA_SOLID);
num = gi.BoxEdicts(ent->absmin, ent->absmax, touch,
MAX_EDICTS, AREA_SOLID);
// be careful, it is possible to have an entity in this
// list removed before we get to it (killtriggered)
for (i=0 ; i<num ; i++)
/* be careful, it is possible to have an entity in this
list removed before we get to it (killtriggered) */
for (i = 0; i < num; i++)
{
hit = touch[i];
if (!hit->inuse)
{
continue;
}
if (ent->touch)
ent->touch (hit, ent, NULL, NULL);
{
ent->touch(hit, ent, NULL, NULL);
}
if (!ent->inuse)
{
break;
}
}
}
/*
* ==============================================================================
*
* Kill box
*
* ==============================================================================
*/
/*
==============================================================================
Kill box
==============================================================================
*/
/*
=================
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)
* 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)
{
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)
{
break;
}
// nail it
T_Damage (tr.ent, ent, ent, vec3_origin, ent->s.origin, vec3_origin, 100000, 0, DAMAGE_NO_PROTECTION, MOD_TELEFRAG);
/* 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 we didn't kill it, fail */
if (tr.ent->solid)
{
return false;
}
}
return true; // all clear
return true; /* all clear */
}