vkQuake2 doxygen  1.0 dev
g_utils.c
Go to the documentation of this file.
1 /*
2 Copyright (C) 1997-2001 Id Software, Inc.
3 
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either version 2
7 of the License, or (at your option) any later version.
8 
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12 
13 See the GNU General Public License for more details.
14 
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18 
19 */
20 // g_utils.c -- misc utility functions for game module
21 
22 #include "g_local.h"
23 
24 
25 void G_ProjectSource (vec3_t point, vec3_t distance, vec3_t forward, vec3_t right, vec3_t result)
26 {
27  result[0] = point[0] + forward[0] * distance[0] + right[0] * distance[1];
28  result[1] = point[1] + forward[1] * distance[0] + right[1] * distance[1];
29  result[2] = point[2] + forward[2] * distance[0] + right[2] * distance[1] + distance[2];
30 }
31 
32 
33 /*
34 =============
35 G_Find
36 
37 Searches all active entities for the next one that holds
38 the matching string at fieldofs (use the FOFS() macro) in the structure.
39 
40 Searches beginning at the edict after from, or the beginning if NULL
41 NULL will be returned if the end of the list is reached.
42 
43 =============
44 */
45 edict_t *G_Find (edict_t *from, int fieldofs, char *match)
46 {
47  char *s;
48 
49  if (!from)
50  from = g_edicts;
51  else
52  from++;
53 
54  for ( ; from < &g_edicts[globals.num_edicts] ; from++)
55  {
56  if (!from->inuse)
57  continue;
58  s = *(char **) ((byte *)from + fieldofs);
59  if (!s)
60  continue;
61  if (!Q_stricmp (s, match))
62  return from;
63  }
64 
65  return NULL;
66 }
67 
68 
69 /*
70 =================
71 findradius
72 
73 Returns entities that have origins within a spherical area
74 
75 findradius (origin, radius)
76 =================
77 */
78 edict_t *findradius (edict_t *from, vec3_t org, float rad)
79 {
80  vec3_t eorg;
81  int j;
82 
83  if (!from)
84  from = g_edicts;
85  else
86  from++;
87  for ( ; from < &g_edicts[globals.num_edicts]; from++)
88  {
89  if (!from->inuse)
90  continue;
91  if (from->solid == SOLID_NOT)
92  continue;
93  for (j=0 ; j<3 ; j++)
94  eorg[j] = org[j] - (from->s.origin[j] + (from->mins[j] + from->maxs[j])*0.5);
95  if (VectorLength(eorg) > rad)
96  continue;
97  return from;
98  }
99 
100  return NULL;
101 }
102 
103 
104 /*
105 =============
106 G_PickTarget
107 
108 Searches all active entities for the next one that holds
109 the matching string at fieldofs (use the FOFS() macro) in the structure.
110 
111 Searches beginning at the edict after from, or the beginning if NULL
112 NULL will be returned if the end of the list is reached.
113 
114 =============
115 */
116 #define MAXCHOICES 8
117 
118 edict_t *G_PickTarget (char *targetname)
119 {
120  edict_t *ent = NULL;
121  int num_choices = 0;
122  edict_t *choice[MAXCHOICES];
123 
124  if (!targetname)
125  {
126  gi.dprintf("G_PickTarget called with NULL targetname\n");
127  return NULL;
128  }
129 
130  while(1)
131  {
132  ent = G_Find (ent, FOFS(targetname), targetname);
133  if (!ent)
134  break;
135  choice[num_choices++] = ent;
136  if (num_choices == MAXCHOICES)
137  break;
138  }
139 
140  if (!num_choices)
141  {
142  gi.dprintf("G_PickTarget: target %s not found\n", targetname);
143  return NULL;
144  }
145 
146  return choice[rand() % num_choices];
147 }
148 
149 
150 
151 void Think_Delay (edict_t *ent)
152 {
153  G_UseTargets (ent, ent->activator);
154  G_FreeEdict (ent);
155 }
156 
157 /*
158 ==============================
159 G_UseTargets
160 
161 the global "activator" should be set to the entity that initiated the firing.
162 
163 If self.delay is set, a DelayedUse entity will be created that will actually
164 do the SUB_UseTargets after that many seconds have passed.
165 
166 Centerprints any self.message to the activator.
167 
168 Search for (string)targetname in all entities that
169 match (string)self.target and call their .use function
170 
171 ==============================
172 */
173 void G_UseTargets (edict_t *ent, edict_t *activator)
174 {
175  edict_t *t;
176 
177 //
178 // check for a delay
179 //
180  if (ent->delay)
181  {
182  // create a temp object to fire at a later time
183  t = G_Spawn();
184  t->classname = "DelayedUse";
185  t->nextthink = level.time + ent->delay;
186  t->think = Think_Delay;
187  t->activator = activator;
188  if (!activator)
189  gi.dprintf ("Think_Delay with no activator\n");
190  t->message = ent->message;
191  t->target = ent->target;
192  t->killtarget = ent->killtarget;
193  return;
194  }
195 
196 
197 //
198 // print the message
199 //
200  if ((ent->message) && !(activator->svflags & SVF_MONSTER))
201  {
202  gi.centerprintf (activator, "%s", ent->message);
203  if (ent->noise_index)
204  gi.sound (activator, CHAN_AUTO, ent->noise_index, 1, ATTN_NORM, 0);
205  else
206  gi.sound (activator, CHAN_AUTO, gi.soundindex ("misc/talk1.wav"), 1, ATTN_NORM, 0);
207  }
208 
209 //
210 // kill killtargets
211 //
212  if (ent->killtarget)
213  {
214  t = NULL;
215  while ((t = G_Find (t, FOFS(targetname), ent->killtarget)))
216  {
217  G_FreeEdict (t);
218  if (!ent->inuse)
219  {
220  gi.dprintf("entity was removed while using killtargets\n");
221  return;
222  }
223  }
224  }
225 
226 //
227 // fire targets
228 //
229  if (ent->target)
230  {
231  t = NULL;
232  while ((t = G_Find (t, FOFS(targetname), ent->target)))
233  {
234  // doors fire area portals in a specific way
235  if (!Q_stricmp(t->classname, "func_areaportal") &&
236  (!Q_stricmp(ent->classname, "func_door") || !Q_stricmp(ent->classname, "func_door_rotating")))
237  continue;
238 
239  if (t == ent)
240  {
241  gi.dprintf ("WARNING: Entity used itself.\n");
242  }
243  else
244  {
245  if (t->use)
246  t->use (t, ent, activator);
247  }
248  if (!ent->inuse)
249  {
250  gi.dprintf("entity was removed while using targets\n");
251  return;
252  }
253  }
254  }
255 }
256 
257 
258 /*
259 =============
260 TempVector
261 
262 This is just a convenience function
263 for making temporary vectors for function calls
264 =============
265 */
266 float *tv (float x, float y, float z)
267 {
268  static int index;
269  static vec3_t vecs[8];
270  float *v;
271 
272  // use an array so that multiple tempvectors won't collide
273  // for a while
274  v = vecs[index];
275  index = (index + 1)&7;
276 
277  v[0] = x;
278  v[1] = y;
279  v[2] = z;
280 
281  return v;
282 }
283 
284 
285 /*
286 =============
287 VectorToString
288 
289 This is just a convenience function
290 for printing vectors
291 =============
292 */
293 char *vtos (vec3_t v)
294 {
295  static int index;
296  static char str[8][32];
297  char *s;
298 
299  // use an array so that multiple vtos won't collide
300  s = str[index];
301  index = (index + 1)&7;
302 
303  Com_sprintf (s, 32, "(%i %i %i)", (int)v[0], (int)v[1], (int)v[2]);
304 
305  return s;
306 }
307 
308 
309 vec3_t VEC_UP = {0, -1, 0};
310 vec3_t MOVEDIR_UP = {0, 0, 1};
311 vec3_t VEC_DOWN = {0, -2, 0};
312 vec3_t MOVEDIR_DOWN = {0, 0, -1};
313 
314 void G_SetMovedir (vec3_t angles, vec3_t movedir)
315 {
316  if (VectorCompare (angles, VEC_UP))
317  {
318  VectorCopy (MOVEDIR_UP, movedir);
319  }
320  else if (VectorCompare (angles, VEC_DOWN))
321  {
322  VectorCopy (MOVEDIR_DOWN, movedir);
323  }
324  else
325  {
326  AngleVectors (angles, movedir, NULL, NULL);
327  }
328 
329  VectorClear (angles);
330 }
331 
332 
333 float vectoyaw (vec3_t vec)
334 {
335  float yaw;
336 
337  if (/*vec[YAW] == 0 &&*/ vec[PITCH] == 0)
338  {
339  yaw = 0;
340  if (vec[YAW] > 0)
341  yaw = 90;
342  else if (vec[YAW] < 0)
343  yaw = -90;
344  }
345  else
346  {
347  yaw = (int) (atan2(vec[YAW], vec[PITCH]) * 180 / M_PI);
348  if (yaw < 0)
349  yaw += 360;
350  }
351 
352  return yaw;
353 }
354 
355 
356 void vectoangles (vec3_t value1, vec3_t angles)
357 {
358  float forward;
359  float yaw, pitch;
360 
361  if (value1[1] == 0 && value1[0] == 0)
362  {
363  yaw = 0;
364  if (value1[2] > 0)
365  pitch = 90;
366  else
367  pitch = 270;
368  }
369  else
370  {
371  if (value1[0])
372  yaw = (int) (atan2(value1[1], value1[0]) * 180 / M_PI);
373  else if (value1[1] > 0)
374  yaw = 90;
375  else
376  yaw = -90;
377  if (yaw < 0)
378  yaw += 360;
379 
380  forward = sqrt (value1[0]*value1[0] + value1[1]*value1[1]);
381  pitch = (int) (atan2(value1[2], forward) * 180 / M_PI);
382  if (pitch < 0)
383  pitch += 360;
384  }
385 
386  angles[PITCH] = -pitch;
387  angles[YAW] = yaw;
388  angles[ROLL] = 0;
389 }
390 
391 char *G_CopyString (char *in)
392 {
393  char *out;
394 
395  out = gi.TagMalloc ((int)strlen(in)+1, TAG_LEVEL);
396  strcpy (out, in);
397  return out;
398 }
399 
400 
402 {
403  e->inuse = true;
404  e->classname = "noclass";
405  e->gravity = 1.0;
406  e->s.number = e - g_edicts;
407 }
408 
409 /*
410 =================
411 G_Spawn
412 
413 Either finds a free edict, or allocates a new one.
414 Try to avoid reusing an entity that was recently freed, because it
415 can cause the client to think the entity morphed into something else
416 instead of being removed and recreated, which can cause interpolated
417 angles and bad trails.
418 =================
419 */
421 {
422  int i;
423  edict_t *e;
424 
425  e = &g_edicts[(int)maxclients->value+1];
426  for ( i=maxclients->value+1 ; i<globals.num_edicts ; i++, e++)
427  {
428  // the first couple seconds of server time can involve a lot of
429  // freeing and allocating, so relax the replacement policy
430  if (!e->inuse && ( e->freetime < 2 || level.time - e->freetime > 0.5 ) )
431  {
432  G_InitEdict (e);
433  return e;
434  }
435  }
436 
437  if (i == game.maxentities)
438  gi.error ("ED_Alloc: no free edicts");
439 
441  G_InitEdict (e);
442  return e;
443 }
444 
445 /*
446 =================
447 G_FreeEdict
448 
449 Marks the edict as free
450 =================
451 */
453 {
454  gi.unlinkentity (ed); // unlink from world
455 
456  if ((ed - g_edicts) <= (maxclients->value + BODY_QUEUE_SIZE))
457  {
458 // gi.dprintf("tried to free special edict\n");
459  return;
460  }
461 
462  memset (ed, 0, sizeof(*ed));
463  ed->classname = "freed";
464  ed->freetime = level.time;
465  ed->inuse = false;
466 }
467 
468 
469 /*
470 ============
471 G_TouchTriggers
472 
473 ============
474 */
476 {
477  int i, num;
478  edict_t *touch[MAX_EDICTS], *hit;
479 
480  // dead things don't activate triggers!
481  if ((ent->client || (ent->svflags & SVF_MONSTER)) && (ent->health <= 0))
482  return;
483 
484  num = gi.BoxEdicts (ent->absmin, ent->absmax, touch
486 
487  // be careful, it is possible to have an entity in this
488  // list removed before we get to it (killtriggered)
489  for (i=0 ; i<num ; i++)
490  {
491  hit = touch[i];
492  if (!hit->inuse)
493  continue;
494  if (!hit->touch)
495  continue;
496  hit->touch (hit, ent, NULL, NULL);
497  }
498 }
499 
500 /*
501 ============
502 G_TouchSolids
503 
504 Call after linking a new trigger in during gameplay
505 to force all entities it covers to immediately touch it
506 ============
507 */
509 {
510  int i, num;
511  edict_t *touch[MAX_EDICTS], *hit;
512 
513  num = gi.BoxEdicts (ent->absmin, ent->absmax, touch
515 
516  // be careful, it is possible to have an entity in this
517  // list removed before we get to it (killtriggered)
518  for (i=0 ; i<num ; i++)
519  {
520  hit = touch[i];
521  if (!hit->inuse)
522  continue;
523  if (ent->touch)
524  ent->touch (hit, ent, NULL, NULL);
525  if (!ent->inuse)
526  break;
527  }
528 }
529 
530 
531 
532 
533 /*
534 ==============================================================================
535 
536 Kill box
537 
538 ==============================================================================
539 */
540 
541 /*
542 =================
543 KillBox
544 
545 Kills all entities that would touch the proposed new positioning
546 of ent. Ent should be unlinked before calling this!
547 =================
548 */
550 {
551  trace_t tr;
552 
553  while (1)
554  {
555  tr = gi.trace (ent->s.origin, ent->mins, ent->maxs, ent->s.origin, NULL, MASK_PLAYERSOLID);
556  if (!tr.ent)
557  break;
558 
559  // nail it
560  T_Damage (tr.ent, ent, ent, vec3_origin, ent->s.origin, vec3_origin, 100000, 0, DAMAGE_NO_PROTECTION, MOD_TELEFRAG);
561 
562  // if we didn't kill it, fail
563  if (tr.ent->solid)
564  return false;
565  }
566 
567  return true; // all clear
568 }
gi
game_import_t gi
Definition: g_main.c:25
game_import_t::dprintf
void(* dprintf)(char *fmt,...)
Definition: game.h:106
edict_s::s
entity_state_t s
Definition: g_local.h:970
YAW
#define YAW
Definition: q_shared.h:73
game_import_t::trace
trace_t(* trace)(vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end, edict_t *passent, int contentmask)
Definition: game.h:128
G_Find
edict_t * G_Find(edict_t *from, int fieldofs, char *match)
Definition: g_utils.c:45
int
CONST PIXELFORMATDESCRIPTOR int
Definition: qgl_win.c:35
edict_s::activator
edict_t * activator
Definition: g_local.h:1078
edict_s::absmax
vec3_t absmax
Definition: g_local.h:991
Think_Delay
void Think_Delay(edict_t *ent)
Definition: g_utils.c:151
maxclients
cvar_t * maxclients
Definition: g_main.c:44
BODY_QUEUE_SIZE
#define BODY_QUEUE_SIZE
Definition: g_local.h:84
v
GLdouble v
Definition: qgl_win.c:143
MOVEDIR_UP
vec3_t MOVEDIR_UP
Definition: g_utils.c:310
entity_state_s::origin
vec3_t origin
Definition: q_shared.h:1149
vectoyaw
float vectoyaw(vec3_t vec)
Definition: g_utils.c:333
qboolean
qboolean
Definition: q_shared.h:63
x
GLint GLenum GLint x
Definition: qgl_win.c:116
edict_s::inuse
qboolean inuse
Definition: g_local.h:976
trace_t
Definition: q_shared.h:453
z
GLdouble GLdouble z
Definition: qgl_win.c:283
VectorClear
#define VectorClear(a)
Definition: q_shared.h:166
i
int i
Definition: q_shared.c:305
MOD_TELEFRAG
#define MOD_TELEFRAG
Definition: g_local.h:490
edict_s::client
struct gclient_s * client
Definition: g_local.h:971
game_import_t::sound
void(* sound)(edict_t *ent, int channel, int soundindex, float volume, float attenuation, float timeofs)
Definition: game.h:109
PITCH
#define PITCH
Definition: q_shared.h:72
FOFS
#define FOFS(x)
Definition: g_local.h:510
vtos
char * vtos(vec3_t v)
Definition: g_utils.c:293
KillBox
qboolean KillBox(edict_t *ent)
Definition: g_utils.c:549
TAG_LEVEL
#define TAG_LEVEL
Definition: g_local.h:79
edict_s::mins
vec3_t mins
Definition: g_local.h:990
M_PI
#define M_PI
Definition: q_shared.h:142
g_edicts
edict_t * g_edicts
Definition: g_main.c:33
ATTN_NORM
#define ATTN_NORM
Definition: q_shared.h:995
T_Damage
void T_Damage(edict_t *targ, edict_t *inflictor, edict_t *attacker, vec3_t dir, vec3_t point, vec3_t normal, int damage, int knockback, int dflags, int mod)
Definition: g_combat.c:377
tv
float * tv(float x, float y, float z)
Definition: g_utils.c:266
G_UseTargets
void G_UseTargets(edict_t *ent, edict_t *activator)
Definition: g_utils.c:173
j
GLint j
Definition: qgl_win.c:150
edict_s::message
char * message
Definition: g_local.h:1010
AngleVectors
void AngleVectors(vec3_t angles, vec3_t forward, vec3_t right, vec3_t up)
Definition: q_shared.c:93
CHAN_AUTO
#define CHAN_AUTO
Definition: q_shared.h:983
edict_s::svflags
int svflags
Definition: g_local.h:989
DAMAGE_NO_PROTECTION
#define DAMAGE_NO_PROTECTION
Definition: g_local.h:668
edict_s::classname
char * classname
Definition: g_local.h:1011
edict_s
Definition: g_local.h:968
VEC_DOWN
vec3_t VEC_DOWN
Definition: g_utils.c:311
ROLL
#define ROLL
Definition: q_shared.h:74
game_import_t::soundindex
int(* soundindex)(char *name)
Definition: game.h:122
forward
static vec3_t forward
Definition: p_view.c:29
VectorLength
vec_t VectorLength(vec3_t v)
Definition: q_shared.c:762
G_TouchSolids
void G_TouchSolids(edict_t *ent)
Definition: g_utils.c:508
MOVEDIR_DOWN
vec3_t MOVEDIR_DOWN
Definition: g_utils.c:312
t
GLdouble t
Definition: qgl_win.c:328
AREA_TRIGGERS
#define AREA_TRIGGERS
Definition: q_shared.h:408
G_SetMovedir
void G_SetMovedir(vec3_t angles, vec3_t movedir)
Definition: g_utils.c:314
G_ProjectSource
void G_ProjectSource(vec3_t point, vec3_t distance, vec3_t forward, vec3_t right, vec3_t result)
Definition: g_utils.c:25
cvar_s::value
float value
Definition: q_shared.h:331
game
game_locals_t game
Definition: g_main.c:23
G_InitEdict
void G_InitEdict(edict_t *e)
Definition: g_utils.c:401
edict_s::noise_index
int noise_index
Definition: g_local.h:1087
entity_state_s::number
int number
Definition: q_shared.h:1147
NULL
#define NULL
Definition: q_shared.h:67
globals
game_export_t globals
Definition: g_main.c:26
edict_s::solid
solid_t solid
Definition: g_local.h:992
G_FreeEdict
void G_FreeEdict(edict_t *ed)
Definition: g_utils.c:452
game_import_t::TagMalloc
void *(* TagMalloc)(int size, int tag)
Definition: game.h:157
G_PickTarget
edict_t * G_PickTarget(char *targetname)
Definition: g_utils.c:118
Q_stricmp
int Q_stricmp(char *s1, char *s2)
Definition: q_shared.c:1180
game_import_t::centerprintf
void(* centerprintf)(edict_t *ent, char *fmt,...)
Definition: game.h:108
SOLID_NOT
@ SOLID_NOT
Definition: game.h:35
vectoangles
void vectoangles(vec3_t value1, vec3_t angles)
Definition: g_utils.c:356
MAX_EDICTS
#define MAX_EDICTS
Definition: q_shared.h:87
game_import_t::unlinkentity
void(* unlinkentity)(edict_t *ent)
Definition: game.h:139
s
static fixed16_t s
Definition: r_scan.c:30
y
GLint y
Definition: qgl_win.c:115
game_import_t::error
void(* error)(char *fmt,...)
Definition: game.h:118
VEC_UP
vec3_t VEC_UP
Definition: g_utils.c:309
VectorCopy
#define VectorCopy(a, b)
Definition: q_shared.h:165
G_CopyString
char * G_CopyString(char *in)
Definition: g_utils.c:391
vec3_origin
vec3_t vec3_origin
Definition: q_shared.c:24
G_Spawn
edict_t * G_Spawn(void)
Definition: g_utils.c:420
AREA_SOLID
#define AREA_SOLID
Definition: q_shared.h:407
level
GLint level
Definition: qgl_win.c:116
MAXCHOICES
#define MAXCHOICES
Definition: g_utils.c:116
sqrt
double sqrt(double x)
edict_s::maxs
vec3_t maxs
Definition: g_local.h:990
findradius
edict_t * findradius(edict_t *from, vec3_t org, float rad)
Definition: g_utils.c:78
edict_s::gravity
float gravity
Definition: g_local.h:1034
trace_t::ent
struct edict_s * ent
Definition: q_shared.h:462
SVF_MONSTER
#define SVF_MONSTER
Definition: game.h:29
edict_s::touch
void(* touch)(edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf)
Definition: g_local.h:1046
G_TouchTriggers
void G_TouchTriggers(edict_t *ent)
Definition: g_utils.c:475
right
GLdouble right
Definition: qgl_win.c:159
edict_s::killtarget
char * killtarget
Definition: g_local.h:1019
edict_s::delay
float delay
Definition: g_local.h:1094
VectorCompare
int VectorCompare(vec3_t v1, vec3_t v2)
Definition: q_shared.c:672
game_locals_t::maxentities
int maxentities
Definition: g_local.h:287
MASK_PLAYERSOLID
#define MASK_PLAYERSOLID
Definition: q_shared.h:396
game_import_t::BoxEdicts
int(* BoxEdicts)(vec3_t mins, vec3_t maxs, edict_t **list, int maxcount, int areatype)
Definition: game.h:140
vec3_t
vec_t vec3_t[3]
Definition: q_shared.h:134
Com_sprintf
void Com_sprintf(char *dest, int size, char *fmt,...)
Definition: q_shared.c:1223
edict_s::absmin
vec3_t absmin
Definition: g_local.h:991
edict_s::target
char * target
Definition: g_local.h:1017
game_export_t::num_edicts
int num_edicts
Definition: game.h:231
edict_s::freetime
float freetime
Definition: g_local.h:1005
g_local.h
edict_s::health
int health
Definition: g_local.h:1057