Quake II RTX doxygen  1.0 dev
g_misc.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 modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (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. See the
12 GNU General Public License for more details.
13 
14 You should have received a copy of the GNU General Public License along
15 with this program; if not, write to the Free Software Foundation, Inc.,
16 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17 */
18 // g_misc.c
19 
20 #include "g_local.h"
21 
22 
23 /*QUAKED func_group (0 0 0) ?
24 Used to group brushes together just for editor convenience.
25 */
26 
27 //=====================================================
28 
29 void Use_Areaportal(edict_t *ent, edict_t *other, edict_t *activator)
30 {
31  ent->count ^= 1; // toggle state
32 // gi.dprintf ("portalstate: %i = %i\n", ent->style, ent->count);
33  gi.SetAreaPortalState(ent->style, ent->count);
34 }
35 
36 /*QUAKED func_areaportal (0 0 0) ?
37 
38 This is a non-visible object that divides the world into
39 areas that are seperated when this portal is not activated.
40 Usually enclosed in the middle of a door.
41 */
42 void SP_func_areaportal(edict_t *ent)
43 {
44  ent->use = Use_Areaportal;
45  ent->count = 0; // always start closed;
46 }
47 
48 //=====================================================
49 
50 
51 /*
52 =================
53 Misc functions
54 =================
55 */
56 void VelocityForDamage(int damage, vec3_t v)
57 {
58  v[0] = 100.0 * crandom();
59  v[1] = 100.0 * crandom();
60  v[2] = 200.0 + 100.0 * random();
61 
62  if (damage < 50)
63  VectorScale(v, 0.7, v);
64  else
65  VectorScale(v, 1.2, v);
66 }
67 
68 void ClipGibVelocity(edict_t *ent)
69 {
70  if (ent->velocity[0] < -300)
71  ent->velocity[0] = -300;
72  else if (ent->velocity[0] > 300)
73  ent->velocity[0] = 300;
74  if (ent->velocity[1] < -300)
75  ent->velocity[1] = -300;
76  else if (ent->velocity[1] > 300)
77  ent->velocity[1] = 300;
78  if (ent->velocity[2] < 200)
79  ent->velocity[2] = 200; // always some upwards
80  else if (ent->velocity[2] > 500)
81  ent->velocity[2] = 500;
82 }
83 
84 
85 /*
86 =================
87 gibs
88 =================
89 */
90 void gib_think(edict_t *self)
91 {
92  self->s.frame++;
93  self->nextthink = level.time + FRAMETIME;
94 
95  if (self->s.frame == 10) {
96  self->think = G_FreeEdict;
97  self->nextthink = level.time + 8 + random() * 10;
98  }
99 }
100 
101 void gib_touch(edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf)
102 {
103  vec3_t normal_angles, right;
104 
105  if (!self->groundentity)
106  return;
107 
108  self->touch = NULL;
109 
110  if (plane) {
111  gi.sound(self, CHAN_VOICE, gi.soundindex("misc/fhit3.wav"), 1, ATTN_NORM, 0);
112 
113  vectoangles(plane->normal, normal_angles);
114  AngleVectors(normal_angles, NULL, right, NULL);
115  vectoangles(right, self->s.angles);
116 
117  if (self->s.modelindex == sm_meat_index) {
118  self->s.frame++;
119  self->think = gib_think;
120  self->nextthink = level.time + FRAMETIME;
121  }
122  }
123 }
124 
125 void gib_die(edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point)
126 {
127  G_FreeEdict(self);
128 }
129 
130 void ThrowGib(edict_t *self, char *gibname, int damage, int type)
131 {
132  edict_t *gib;
133  vec3_t vd;
134  vec3_t origin;
135  vec3_t size;
136  float vscale;
137 
138  gib = G_Spawn();
139 
140  VectorScale(self->size, 0.5, size);
141  VectorAdd(self->absmin, size, origin);
142  gib->s.origin[0] = origin[0] + crandom() * size[0];
143  gib->s.origin[1] = origin[1] + crandom() * size[1];
144  gib->s.origin[2] = origin[2] + crandom() * size[2];
145 
146  gi.setmodel(gib, gibname);
147  gib->solid = SOLID_NOT;
148  gib->s.effects |= EF_GIB;
149  gib->flags |= FL_NO_KNOCKBACK;
150  gib->takedamage = DAMAGE_YES;
151  gib->die = gib_die;
152 
153  if (type == GIB_ORGANIC) {
154  gib->movetype = MOVETYPE_TOSS;
155  gib->touch = gib_touch;
156  vscale = 0.5;
157  } else {
158  gib->movetype = MOVETYPE_BOUNCE;
159  vscale = 1.0;
160  }
161 
162  VelocityForDamage(damage, vd);
163  VectorMA(self->velocity, vscale, vd, gib->velocity);
164  ClipGibVelocity(gib);
165  gib->avelocity[0] = random() * 600;
166  gib->avelocity[1] = random() * 600;
167  gib->avelocity[2] = random() * 600;
168 
169  gib->think = G_FreeEdict;
170  gib->nextthink = level.time + 10 + random() * 10;
171 
172  gi.linkentity(gib);
173 }
174 
175 void ThrowHead(edict_t *self, char *gibname, int damage, int type)
176 {
177  vec3_t vd;
178  float vscale;
179 
180  self->s.skinnum = 0;
181  self->s.frame = 0;
182  VectorClear(self->mins);
183  VectorClear(self->maxs);
184 
185  self->s.modelindex2 = 0;
186  gi.setmodel(self, gibname);
187  self->solid = SOLID_NOT;
188  self->s.effects |= EF_GIB;
189  self->s.effects &= ~EF_FLIES;
190  self->s.sound = 0;
191  self->flags |= FL_NO_KNOCKBACK;
192  self->svflags &= ~SVF_MONSTER;
193  self->takedamage = DAMAGE_YES;
194  self->die = gib_die;
195 
196  if (type == GIB_ORGANIC) {
197  self->movetype = MOVETYPE_TOSS;
198  self->touch = gib_touch;
199  vscale = 0.5;
200  } else {
201  self->movetype = MOVETYPE_BOUNCE;
202  vscale = 1.0;
203  }
204 
205  VelocityForDamage(damage, vd);
206  VectorMA(self->velocity, vscale, vd, self->velocity);
207  ClipGibVelocity(self);
208 
209  self->avelocity[YAW] = crandom() * 600;
210 
211  self->think = G_FreeEdict;
212  self->nextthink = level.time + 10 + random() * 10;
213 
214  gi.linkentity(self);
215 }
216 
217 
218 void ThrowClientHead(edict_t *self, int damage)
219 {
220  vec3_t vd;
221  char *gibname;
222 
223  if (rand() & 1) {
224  gibname = "models/objects/gibs/head2/tris.md2";
225  self->s.skinnum = 1; // second skin is player
226  } else {
227  gibname = "models/objects/gibs/skull/tris.md2";
228  self->s.skinnum = 0;
229  }
230 
231  self->s.origin[2] += 32;
232  self->s.frame = 0;
233  gi.setmodel(self, gibname);
234  VectorSet(self->mins, -16, -16, 0);
235  VectorSet(self->maxs, 16, 16, 16);
236 
237  self->takedamage = DAMAGE_NO;
238  self->solid = SOLID_NOT;
239  self->s.effects = EF_GIB;
240  self->s.sound = 0;
241  self->flags |= FL_NO_KNOCKBACK;
242 
243  self->movetype = MOVETYPE_BOUNCE;
244  VelocityForDamage(damage, vd);
245  VectorAdd(self->velocity, vd, self->velocity);
246 
247  if (self->client) { // bodies in the queue don't have a client anymore
248  self->client->anim_priority = ANIM_DEATH;
249  self->client->anim_end = self->s.frame;
250  } else {
251  self->think = NULL;
252  self->nextthink = 0;
253  }
254 
255  gi.linkentity(self);
256 }
257 
258 
259 /*
260 =================
261 debris
262 =================
263 */
264 void debris_die(edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point)
265 {
266  G_FreeEdict(self);
267 }
268 
269 void ThrowDebris(edict_t *self, char *modelname, float speed, vec3_t origin)
270 {
271  edict_t *chunk;
272  vec3_t v;
273 
274  chunk = G_Spawn();
275  VectorCopy(origin, chunk->s.origin);
276  gi.setmodel(chunk, modelname);
277  v[0] = 100 * crandom();
278  v[1] = 100 * crandom();
279  v[2] = 100 + 100 * crandom();
280  VectorMA(self->velocity, speed, v, chunk->velocity);
281  chunk->movetype = MOVETYPE_BOUNCE;
282  chunk->solid = SOLID_NOT;
283  chunk->avelocity[0] = random() * 600;
284  chunk->avelocity[1] = random() * 600;
285  chunk->avelocity[2] = random() * 600;
286  chunk->think = G_FreeEdict;
287  chunk->nextthink = level.time + 5 + random() * 5;
288  chunk->s.frame = 0;
289  chunk->flags = 0;
290  chunk->classname = "debris";
291  chunk->takedamage = DAMAGE_YES;
292  chunk->die = debris_die;
293  gi.linkentity(chunk);
294 }
295 
296 
297 void BecomeExplosion1(edict_t *self)
298 {
299  gi.WriteByte(svc_temp_entity);
300  gi.WriteByte(TE_EXPLOSION1);
301  gi.WritePosition(self->s.origin);
302  gi.multicast(self->s.origin, MULTICAST_PVS);
303 
304  G_FreeEdict(self);
305 }
306 
307 
308 void BecomeExplosion2(edict_t *self)
309 {
310  gi.WriteByte(svc_temp_entity);
311  gi.WriteByte(TE_EXPLOSION2);
312  gi.WritePosition(self->s.origin);
313  gi.multicast(self->s.origin, MULTICAST_PVS);
314 
315  G_FreeEdict(self);
316 }
317 
318 
319 /*QUAKED path_corner (.5 .3 0) (-8 -8 -8) (8 8 8) TELEPORT
320 Target: next path corner
321 Pathtarget: gets used when an entity that has
322  this path_corner targeted touches it
323 */
324 
325 void path_corner_touch(edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf)
326 {
327  vec3_t v;
328  edict_t *next;
329 
330  if (other->movetarget != self)
331  return;
332 
333  if (other->enemy)
334  return;
335 
336  if (self->pathtarget) {
337  char *savetarget;
338 
339  savetarget = self->target;
340  self->target = self->pathtarget;
341  G_UseTargets(self, other);
342  self->target = savetarget;
343  }
344 
345  if (self->target)
346  next = G_PickTarget(self->target);
347  else
348  next = NULL;
349 
350  if ((next) && (next->spawnflags & 1)) {
351  VectorCopy(next->s.origin, v);
352  v[2] += next->mins[2];
353  v[2] -= other->mins[2];
354  VectorCopy(v, other->s.origin);
355  next = G_PickTarget(next->target);
356  other->s.event = EV_OTHER_TELEPORT;
357  }
358 
359  other->goalentity = other->movetarget = next;
360 
361  if (self->wait) {
362  other->monsterinfo.pausetime = level.time + self->wait;
363  other->monsterinfo.stand(other);
364  return;
365  }
366 
367  if (!other->movetarget) {
368  other->monsterinfo.pausetime = level.time + 100000000;
369  other->monsterinfo.stand(other);
370  } else {
371  VectorSubtract(other->goalentity->s.origin, other->s.origin, v);
372  other->ideal_yaw = vectoyaw(v);
373  }
374 }
375 
376 void SP_path_corner(edict_t *self)
377 {
378  if (!self->targetname) {
379  gi.dprintf("path_corner with no targetname at %s\n", vtos(self->s.origin));
380  G_FreeEdict(self);
381  return;
382  }
383 
384  self->solid = SOLID_TRIGGER;
385  self->touch = path_corner_touch;
386  VectorSet(self->mins, -8, -8, -8);
387  VectorSet(self->maxs, 8, 8, 8);
388  self->svflags |= SVF_NOCLIENT;
389  gi.linkentity(self);
390 }
391 
392 
393 /*QUAKED point_combat (0.5 0.3 0) (-8 -8 -8) (8 8 8) Hold
394 Makes this the target of a monster and it will head here
395 when first activated before going after the activator. If
396 hold is selected, it will stay here.
397 */
398 void point_combat_touch(edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf)
399 {
400  edict_t *activator;
401 
402  if (other->movetarget != self)
403  return;
404 
405  if (self->target) {
406  other->target = self->target;
407  other->goalentity = other->movetarget = G_PickTarget(other->target);
408  if (!other->goalentity) {
409  gi.dprintf("%s at %s target %s does not exist\n", self->classname, vtos(self->s.origin), self->target);
410  other->movetarget = self;
411  }
412  self->target = NULL;
413  } else if ((self->spawnflags & 1) && !(other->flags & (FL_SWIM | FL_FLY))) {
414  other->monsterinfo.pausetime = level.time + 100000000;
415  other->monsterinfo.aiflags |= AI_STAND_GROUND;
416  other->monsterinfo.stand(other);
417  }
418 
419  if (other->movetarget == self) {
420  other->target = NULL;
421  other->movetarget = NULL;
422  other->goalentity = other->enemy;
423  other->monsterinfo.aiflags &= ~AI_COMBAT_POINT;
424  }
425 
426  if (self->pathtarget) {
427  char *savetarget;
428 
429  savetarget = self->target;
430  self->target = self->pathtarget;
431  if (other->enemy && other->enemy->client)
432  activator = other->enemy;
433  else if (other->oldenemy && other->oldenemy->client)
434  activator = other->oldenemy;
435  else if (other->activator && other->activator->client)
436  activator = other->activator;
437  else
438  activator = other;
439  G_UseTargets(self, activator);
440  self->target = savetarget;
441  }
442 }
443 
444 void SP_point_combat(edict_t *self)
445 {
446  if (deathmatch->value) {
447  G_FreeEdict(self);
448  return;
449  }
450  self->solid = SOLID_TRIGGER;
451  self->touch = point_combat_touch;
452  VectorSet(self->mins, -8, -8, -16);
453  VectorSet(self->maxs, 8, 8, 16);
454  self->svflags = SVF_NOCLIENT;
455  gi.linkentity(self);
456 }
457 
458 
459 /*QUAKED viewthing (0 .5 .8) (-8 -8 -8) (8 8 8)
460 Just for the debugging level. Don't use
461 */
462 void TH_viewthing(edict_t *ent)
463 {
464  ent->s.frame = (ent->s.frame + 1) % 7;
465  ent->nextthink = level.time + FRAMETIME;
466 }
467 
468 void SP_viewthing(edict_t *ent)
469 {
470  gi.dprintf("viewthing spawned\n");
471 
472  ent->movetype = MOVETYPE_NONE;
473  ent->solid = SOLID_BBOX;
474  ent->s.renderfx = RF_FRAMELERP;
475  VectorSet(ent->mins, -16, -16, -24);
476  VectorSet(ent->maxs, 16, 16, 32);
477  ent->s.modelindex = gi.modelindex("models/objects/banner/tris.md2");
478  gi.linkentity(ent);
479  ent->nextthink = level.time + 0.5;
480  ent->think = TH_viewthing;
481  return;
482 }
483 
484 
485 /*QUAKED info_null (0 0.5 0) (-4 -4 -4) (4 4 4)
486 Used as a positional target for spotlights, etc.
487 */
488 void SP_info_null(edict_t *self)
489 {
490  G_FreeEdict(self);
491 }
492 
493 
494 /*QUAKED info_notnull (0 0.5 0) (-4 -4 -4) (4 4 4)
495 Used as a positional target for lightning.
496 */
497 void SP_info_notnull(edict_t *self)
498 {
499  VectorCopy(self->s.origin, self->absmin);
500  VectorCopy(self->s.origin, self->absmax);
501 }
502 
503 
504 /*QUAKED light (0 1 0) (-8 -8 -8) (8 8 8) START_OFF
505 Non-displayed light.
506 Default light value is 300.
507 Default style is 0.
508 If targeted, will toggle between on and off.
509 Default _cone value is 10 (used to set size of light for spotlights)
510 */
511 
512 #define START_OFF 1
513 
514 void light_use(edict_t *self, edict_t *other, edict_t *activator)
515 {
516  if (self->spawnflags & START_OFF) {
517  gi.configstring(CS_LIGHTS + self->style, "m");
518  self->spawnflags &= ~START_OFF;
519  } else {
520  gi.configstring(CS_LIGHTS + self->style, "a");
521  self->spawnflags |= START_OFF;
522  }
523 }
524 
525 void SP_light(edict_t *self)
526 {
527  // no targeted lights in deathmatch, because they cause global messages
528  if (!self->targetname || deathmatch->value) {
529  G_FreeEdict(self);
530  return;
531  }
532 
533  if (self->style >= 32) {
534  self->use = light_use;
535  if (self->spawnflags & START_OFF)
536  gi.configstring(CS_LIGHTS + self->style, "a");
537  else
538  gi.configstring(CS_LIGHTS + self->style, "m");
539  }
540 }
541 
542 
543 /*QUAKED func_wall (0 .5 .8) ? TRIGGER_SPAWN TOGGLE START_ON ANIMATED ANIMATED_FAST
544 This is just a solid wall if not inhibited
545 
546 TRIGGER_SPAWN the wall will not be present until triggered
547  it will then blink in to existance; it will
548  kill anything that was in it's way
549 
550 TOGGLE only valid for TRIGGER_SPAWN walls
551  this allows the wall to be turned on and off
552 
553 START_ON only valid for TRIGGER_SPAWN walls
554  the wall will initially be present
555 */
556 
557 void func_wall_use(edict_t *self, edict_t *other, edict_t *activator)
558 {
559  if (self->solid == SOLID_NOT) {
560  self->solid = SOLID_BSP;
561  self->svflags &= ~SVF_NOCLIENT;
562  KillBox(self);
563  } else {
564  self->solid = SOLID_NOT;
565  self->svflags |= SVF_NOCLIENT;
566  }
567  gi.linkentity(self);
568 
569  if (!(self->spawnflags & 2))
570  self->use = NULL;
571 }
572 
573 void SP_func_wall(edict_t *self)
574 {
575  self->movetype = MOVETYPE_PUSH;
576  gi.setmodel(self, self->model);
577 
578  if (self->spawnflags & 8)
579  self->s.effects |= EF_ANIM_ALL;
580  if (self->spawnflags & 16)
581  self->s.effects |= EF_ANIM_ALLFAST;
582 
583  // just a wall
584  if ((self->spawnflags & 7) == 0) {
585  self->solid = SOLID_BSP;
586  gi.linkentity(self);
587  return;
588  }
589 
590  // it must be TRIGGER_SPAWN
591  if (!(self->spawnflags & 1)) {
592 // gi.dprintf("func_wall missing TRIGGER_SPAWN\n");
593  self->spawnflags |= 1;
594  }
595 
596  // yell if the spawnflags are odd
597  if (self->spawnflags & 4) {
598  if (!(self->spawnflags & 2)) {
599  gi.dprintf("func_wall START_ON without TOGGLE\n");
600  self->spawnflags |= 2;
601  }
602  }
603 
604  self->use = func_wall_use;
605  if (self->spawnflags & 4) {
606  self->solid = SOLID_BSP;
607  } else {
608  self->solid = SOLID_NOT;
609  self->svflags |= SVF_NOCLIENT;
610  }
611  gi.linkentity(self);
612 }
613 
614 
615 /*QUAKED func_object (0 .5 .8) ? TRIGGER_SPAWN ANIMATED ANIMATED_FAST
616 This is solid bmodel that will fall if it's support it removed.
617 */
618 
619 void func_object_touch(edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf)
620 {
621  // only squash thing we fall on top of
622  if (!plane)
623  return;
624  if (plane->normal[2] < 1.0)
625  return;
626  if (other->takedamage == DAMAGE_NO)
627  return;
628  T_Damage(other, self, self, vec3_origin, self->s.origin, vec3_origin, self->dmg, 1, 0, MOD_CRUSH);
629 }
630 
631 void func_object_release(edict_t *self)
632 {
633  self->movetype = MOVETYPE_TOSS;
634  self->touch = func_object_touch;
635 }
636 
637 void func_object_use(edict_t *self, edict_t *other, edict_t *activator)
638 {
639  self->solid = SOLID_BSP;
640  self->svflags &= ~SVF_NOCLIENT;
641  self->use = NULL;
642  KillBox(self);
643  func_object_release(self);
644 }
645 
646 void SP_func_object(edict_t *self)
647 {
648  gi.setmodel(self, self->model);
649 
650  self->mins[0] += 1;
651  self->mins[1] += 1;
652  self->mins[2] += 1;
653  self->maxs[0] -= 1;
654  self->maxs[1] -= 1;
655  self->maxs[2] -= 1;
656 
657  if (!self->dmg)
658  self->dmg = 100;
659 
660  if (self->spawnflags == 0) {
661  self->solid = SOLID_BSP;
662  self->movetype = MOVETYPE_PUSH;
663  self->think = func_object_release;
664  self->nextthink = level.time + 2 * FRAMETIME;
665  } else {
666  self->solid = SOLID_NOT;
667  self->movetype = MOVETYPE_PUSH;
668  self->use = func_object_use;
669  self->svflags |= SVF_NOCLIENT;
670  }
671 
672  if (self->spawnflags & 2)
673  self->s.effects |= EF_ANIM_ALL;
674  if (self->spawnflags & 4)
675  self->s.effects |= EF_ANIM_ALLFAST;
676 
677  self->clipmask = MASK_MONSTERSOLID;
678 
679  gi.linkentity(self);
680 }
681 
682 
683 /*QUAKED func_explosive (0 .5 .8) ? Trigger_Spawn ANIMATED ANIMATED_FAST
684 Any brush that you want to explode or break apart. If you want an
685 ex0plosion, set dmg and it will do a radius explosion of that amount
686 at the center of the bursh.
687 
688 If targeted it will not be shootable.
689 
690 health defaults to 100.
691 
692 mass defaults to 75. This determines how much debris is emitted when
693 it explodes. You get one large chunk per 100 of mass (up to 8) and
694 one small chunk per 25 of mass (up to 16). So 800 gives the most.
695 */
696 void func_explosive_explode(edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point)
697 {
698  vec3_t origin;
699  vec3_t chunkorigin;
700  vec3_t size;
701  int count;
702  int mass;
703 
704  // bmodel origins are (0 0 0), we need to adjust that here
705  VectorScale(self->size, 0.5, size);
706  VectorAdd(self->absmin, size, origin);
707  VectorCopy(origin, self->s.origin);
708 
709  self->takedamage = DAMAGE_NO;
710 
711  if (self->dmg)
712  T_RadiusDamage(self, attacker, self->dmg, NULL, self->dmg + 40, MOD_EXPLOSIVE);
713 
714  VectorSubtract(self->s.origin, inflictor->s.origin, self->velocity);
715  VectorNormalize(self->velocity);
716  VectorScale(self->velocity, 150, self->velocity);
717 
718  // start chunks towards the center
719  VectorScale(size, 0.5, size);
720 
721  mass = self->mass;
722  if (!mass)
723  mass = 75;
724 
725  // big chunks
726  if (mass >= 100) {
727  count = mass / 100;
728  if (count > 8)
729  count = 8;
730  while (count--) {
731  chunkorigin[0] = origin[0] + crandom() * size[0];
732  chunkorigin[1] = origin[1] + crandom() * size[1];
733  chunkorigin[2] = origin[2] + crandom() * size[2];
734  ThrowDebris(self, "models/objects/debris1/tris.md2", 1, chunkorigin);
735  }
736  }
737 
738  // small chunks
739  count = mass / 25;
740  if (count > 16)
741  count = 16;
742  while (count--) {
743  chunkorigin[0] = origin[0] + crandom() * size[0];
744  chunkorigin[1] = origin[1] + crandom() * size[1];
745  chunkorigin[2] = origin[2] + crandom() * size[2];
746  ThrowDebris(self, "models/objects/debris2/tris.md2", 2, chunkorigin);
747  }
748 
749  G_UseTargets(self, attacker);
750 
751  if (self->dmg)
752  BecomeExplosion1(self);
753  else
754  G_FreeEdict(self);
755 }
756 
757 void func_explosive_use(edict_t *self, edict_t *other, edict_t *activator)
758 {
759  func_explosive_explode(self, other, activator, self->health, vec3_origin);
760 }
761 
762 void func_explosive_spawn(edict_t *self, edict_t *other, edict_t *activator)
763 {
764  self->solid = SOLID_BSP;
765  self->svflags &= ~SVF_NOCLIENT;
766  self->use = NULL;
767  KillBox(self);
768  gi.linkentity(self);
769 }
770 
771 void SP_func_explosive(edict_t *self)
772 {
773  if (deathmatch->value) {
774  // auto-remove for deathmatch
775  G_FreeEdict(self);
776  return;
777  }
778 
779  self->movetype = MOVETYPE_PUSH;
780 
781  gi.modelindex("models/objects/debris1/tris.md2");
782  gi.modelindex("models/objects/debris2/tris.md2");
783 
784  gi.setmodel(self, self->model);
785 
786  if (self->spawnflags & 1) {
787  self->svflags |= SVF_NOCLIENT;
788  self->solid = SOLID_NOT;
789  self->use = func_explosive_spawn;
790  } else {
791  self->solid = SOLID_BSP;
792  if (self->targetname)
793  self->use = func_explosive_use;
794  }
795 
796  if (self->spawnflags & 2)
797  self->s.effects |= EF_ANIM_ALL;
798  if (self->spawnflags & 4)
799  self->s.effects |= EF_ANIM_ALLFAST;
800 
801  if (self->use != func_explosive_use) {
802  if (!self->health)
803  self->health = 100;
804  self->die = func_explosive_explode;
805  self->takedamage = DAMAGE_YES;
806  }
807 
808  gi.linkentity(self);
809 }
810 
811 
812 /*QUAKED misc_explobox (0 .5 .8) (-16 -16 0) (16 16 40)
813 Large exploding box. You can override its mass (100),
814 health (80), and dmg (150).
815 */
816 
817 void barrel_touch(edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf)
818 
819 {
820  float ratio;
821  vec3_t v;
822 
823  if ((!other->groundentity) || (other->groundentity == self))
824  return;
825 
826  ratio = (float)other->mass / (float)self->mass;
827  VectorSubtract(self->s.origin, other->s.origin, v);
828  M_walkmove(self, vectoyaw(v), 20 * ratio * FRAMETIME);
829 }
830 
831 void barrel_explode(edict_t *self)
832 {
833  vec3_t org;
834  float spd;
835  vec3_t save;
836 
837  T_RadiusDamage(self, self->activator, self->dmg, NULL, self->dmg + 40, MOD_BARREL);
838 
839  VectorCopy(self->s.origin, save);
840  VectorMA(self->absmin, 0.5, self->size, self->s.origin);
841 
842  // a few big chunks
843  spd = 1.5 * (float)self->dmg / 200.0;
844  org[0] = self->s.origin[0] + crandom() * self->size[0];
845  org[1] = self->s.origin[1] + crandom() * self->size[1];
846  org[2] = self->s.origin[2] + crandom() * self->size[2];
847  ThrowDebris(self, "models/objects/debris1/tris.md2", spd, org);
848  org[0] = self->s.origin[0] + crandom() * self->size[0];
849  org[1] = self->s.origin[1] + crandom() * self->size[1];
850  org[2] = self->s.origin[2] + crandom() * self->size[2];
851  ThrowDebris(self, "models/objects/debris1/tris.md2", spd, org);
852 
853  // bottom corners
854  spd = 1.75 * (float)self->dmg / 200.0;
855  VectorCopy(self->absmin, org);
856  ThrowDebris(self, "models/objects/debris3/tris.md2", spd, org);
857  VectorCopy(self->absmin, org);
858  org[0] += self->size[0];
859  ThrowDebris(self, "models/objects/debris3/tris.md2", spd, org);
860  VectorCopy(self->absmin, org);
861  org[1] += self->size[1];
862  ThrowDebris(self, "models/objects/debris3/tris.md2", spd, org);
863  VectorCopy(self->absmin, org);
864  org[0] += self->size[0];
865  org[1] += self->size[1];
866  ThrowDebris(self, "models/objects/debris3/tris.md2", spd, org);
867 
868  // a bunch of little chunks
869  spd = 2 * self->dmg / 200;
870  org[0] = self->s.origin[0] + crandom() * self->size[0];
871  org[1] = self->s.origin[1] + crandom() * self->size[1];
872  org[2] = self->s.origin[2] + crandom() * self->size[2];
873  ThrowDebris(self, "models/objects/debris2/tris.md2", spd, org);
874  org[0] = self->s.origin[0] + crandom() * self->size[0];
875  org[1] = self->s.origin[1] + crandom() * self->size[1];
876  org[2] = self->s.origin[2] + crandom() * self->size[2];
877  ThrowDebris(self, "models/objects/debris2/tris.md2", spd, org);
878  org[0] = self->s.origin[0] + crandom() * self->size[0];
879  org[1] = self->s.origin[1] + crandom() * self->size[1];
880  org[2] = self->s.origin[2] + crandom() * self->size[2];
881  ThrowDebris(self, "models/objects/debris2/tris.md2", spd, org);
882  org[0] = self->s.origin[0] + crandom() * self->size[0];
883  org[1] = self->s.origin[1] + crandom() * self->size[1];
884  org[2] = self->s.origin[2] + crandom() * self->size[2];
885  ThrowDebris(self, "models/objects/debris2/tris.md2", spd, org);
886  org[0] = self->s.origin[0] + crandom() * self->size[0];
887  org[1] = self->s.origin[1] + crandom() * self->size[1];
888  org[2] = self->s.origin[2] + crandom() * self->size[2];
889  ThrowDebris(self, "models/objects/debris2/tris.md2", spd, org);
890  org[0] = self->s.origin[0] + crandom() * self->size[0];
891  org[1] = self->s.origin[1] + crandom() * self->size[1];
892  org[2] = self->s.origin[2] + crandom() * self->size[2];
893  ThrowDebris(self, "models/objects/debris2/tris.md2", spd, org);
894  org[0] = self->s.origin[0] + crandom() * self->size[0];
895  org[1] = self->s.origin[1] + crandom() * self->size[1];
896  org[2] = self->s.origin[2] + crandom() * self->size[2];
897  ThrowDebris(self, "models/objects/debris2/tris.md2", spd, org);
898  org[0] = self->s.origin[0] + crandom() * self->size[0];
899  org[1] = self->s.origin[1] + crandom() * self->size[1];
900  org[2] = self->s.origin[2] + crandom() * self->size[2];
901  ThrowDebris(self, "models/objects/debris2/tris.md2", spd, org);
902 
903  VectorCopy(save, self->s.origin);
904  if (self->groundentity)
905  BecomeExplosion2(self);
906  else
907  BecomeExplosion1(self);
908 }
909 
910 void barrel_delay(edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point)
911 {
912  self->takedamage = DAMAGE_NO;
913  self->nextthink = level.time + 2 * FRAMETIME;
914  self->think = barrel_explode;
915  self->activator = attacker;
916 }
917 
918 void SP_misc_explobox(edict_t *self)
919 {
920  if (deathmatch->value) {
921  // auto-remove for deathmatch
922  G_FreeEdict(self);
923  return;
924  }
925 
926  gi.modelindex("models/objects/debris1/tris.md2");
927  gi.modelindex("models/objects/debris2/tris.md2");
928  gi.modelindex("models/objects/debris3/tris.md2");
929 
930  self->solid = SOLID_BBOX;
931  self->movetype = MOVETYPE_STEP;
932 
933  self->model = "models/objects/barrels/tris.md2";
934  self->s.modelindex = gi.modelindex(self->model);
935  VectorSet(self->mins, -16, -16, 0);
936  VectorSet(self->maxs, 16, 16, 40);
937 
938  if (!self->mass)
939  self->mass = 400;
940  if (!self->health)
941  self->health = 10;
942  if (!self->dmg)
943  self->dmg = 150;
944 
945  self->die = barrel_delay;
946  self->takedamage = DAMAGE_YES;
947  self->monsterinfo.aiflags = AI_NOSTEP;
948 
949  self->touch = barrel_touch;
950 
951  self->think = M_droptofloor;
952  self->nextthink = level.time + 2 * FRAMETIME;
953 
954  gi.linkentity(self);
955 }
956 
957 
958 //
959 // miscellaneous specialty items
960 //
961 
962 /*QUAKED misc_blackhole (1 .5 0) (-8 -8 -8) (8 8 8)
963 */
964 
965 void misc_blackhole_use(edict_t *ent, edict_t *other, edict_t *activator)
966 {
967  /*
968  gi.WriteByte (svc_temp_entity);
969  gi.WriteByte (TE_BOSSTPORT);
970  gi.WritePosition (ent->s.origin);
971  gi.multicast (ent->s.origin, MULTICAST_PVS);
972  */
973  G_FreeEdict(ent);
974 }
975 
976 void misc_blackhole_think(edict_t *self)
977 {
978  if (++self->s.frame < 19)
979  self->nextthink = level.time + FRAMETIME;
980  else {
981  self->s.frame = 0;
982  self->nextthink = level.time + FRAMETIME;
983  }
984 }
985 
986 void SP_misc_blackhole(edict_t *ent)
987 {
988  ent->movetype = MOVETYPE_NONE;
989  ent->solid = SOLID_NOT;
990  VectorSet(ent->mins, -64, -64, 0);
991  VectorSet(ent->maxs, 64, 64, 8);
992  ent->s.modelindex = gi.modelindex("models/objects/black/tris.md2");
993  ent->s.renderfx = RF_TRANSLUCENT;
994  ent->use = misc_blackhole_use;
995  ent->think = misc_blackhole_think;
996  ent->nextthink = level.time + 2 * FRAMETIME;
997  gi.linkentity(ent);
998 }
999 
1000 /*QUAKED misc_eastertank (1 .5 0) (-32 -32 -16) (32 32 32)
1001 */
1002 
1003 void misc_eastertank_think(edict_t *self)
1004 {
1005  if (++self->s.frame < 293)
1006  self->nextthink = level.time + FRAMETIME;
1007  else {
1008  self->s.frame = 254;
1009  self->nextthink = level.time + FRAMETIME;
1010  }
1011 }
1012 
1013 void SP_misc_eastertank(edict_t *ent)
1014 {
1015  ent->movetype = MOVETYPE_NONE;
1016  ent->solid = SOLID_BBOX;
1017  VectorSet(ent->mins, -32, -32, -16);
1018  VectorSet(ent->maxs, 32, 32, 32);
1019  ent->s.modelindex = gi.modelindex("models/monsters/tank/tris.md2");
1020  ent->s.frame = 254;
1021  ent->think = misc_eastertank_think;
1022  ent->nextthink = level.time + 2 * FRAMETIME;
1023  gi.linkentity(ent);
1024 }
1025 
1026 /*QUAKED misc_easterchick (1 .5 0) (-32 -32 0) (32 32 32)
1027 */
1028 
1029 
1030 void misc_easterchick_think(edict_t *self)
1031 {
1032  if (++self->s.frame < 247)
1033  self->nextthink = level.time + FRAMETIME;
1034  else {
1035  self->s.frame = 208;
1036  self->nextthink = level.time + FRAMETIME;
1037  }
1038 }
1039 
1040 void SP_misc_easterchick(edict_t *ent)
1041 {
1042  ent->movetype = MOVETYPE_NONE;
1043  ent->solid = SOLID_BBOX;
1044  VectorSet(ent->mins, -32, -32, 0);
1045  VectorSet(ent->maxs, 32, 32, 32);
1046  ent->s.modelindex = gi.modelindex("models/monsters/bitch/tris.md2");
1047  ent->s.frame = 208;
1048  ent->think = misc_easterchick_think;
1049  ent->nextthink = level.time + 2 * FRAMETIME;
1050  gi.linkentity(ent);
1051 }
1052 
1053 /*QUAKED misc_easterchick2 (1 .5 0) (-32 -32 0) (32 32 32)
1054 */
1055 
1056 
1057 void misc_easterchick2_think(edict_t *self)
1058 {
1059  if (++self->s.frame < 287)
1060  self->nextthink = level.time + FRAMETIME;
1061  else {
1062  self->s.frame = 248;
1063  self->nextthink = level.time + FRAMETIME;
1064  }
1065 }
1066 
1067 void SP_misc_easterchick2(edict_t *ent)
1068 {
1069  ent->movetype = MOVETYPE_NONE;
1070  ent->solid = SOLID_BBOX;
1071  VectorSet(ent->mins, -32, -32, 0);
1072  VectorSet(ent->maxs, 32, 32, 32);
1073  ent->s.modelindex = gi.modelindex("models/monsters/bitch/tris.md2");
1074  ent->s.frame = 248;
1075  ent->think = misc_easterchick2_think;
1076  ent->nextthink = level.time + 2 * FRAMETIME;
1077  gi.linkentity(ent);
1078 }
1079 
1080 
1081 /*QUAKED monster_commander_body (1 .5 0) (-32 -32 0) (32 32 48)
1082 Not really a monster, this is the Tank Commander's decapitated body.
1083 There should be a item_commander_head that has this as it's target.
1084 */
1085 
1086 void commander_body_think(edict_t *self)
1087 {
1088  if (++self->s.frame < 24)
1089  self->nextthink = level.time + FRAMETIME;
1090  else
1091  self->nextthink = 0;
1092 
1093  if (self->s.frame == 22)
1094  gi.sound(self, CHAN_BODY, gi.soundindex("tank/thud.wav"), 1, ATTN_NORM, 0);
1095 }
1096 
1097 void commander_body_use(edict_t *self, edict_t *other, edict_t *activator)
1098 {
1099  self->think = commander_body_think;
1100  self->nextthink = level.time + FRAMETIME;
1101  gi.sound(self, CHAN_BODY, gi.soundindex("tank/pain.wav"), 1, ATTN_NORM, 0);
1102 }
1103 
1104 void commander_body_drop(edict_t *self)
1105 {
1106  self->movetype = MOVETYPE_TOSS;
1107  self->s.origin[2] += 2;
1108 }
1109 
1110 void SP_monster_commander_body(edict_t *self)
1111 {
1112  self->movetype = MOVETYPE_NONE;
1113  self->solid = SOLID_BBOX;
1114  self->model = "models/monsters/commandr/tris.md2";
1115  self->s.modelindex = gi.modelindex(self->model);
1116  VectorSet(self->mins, -32, -32, 0);
1117  VectorSet(self->maxs, 32, 32, 48);
1118  self->use = commander_body_use;
1119  self->takedamage = DAMAGE_YES;
1120  self->flags = FL_GODMODE;
1121  self->s.renderfx |= RF_FRAMELERP;
1122  gi.linkentity(self);
1123 
1124  gi.soundindex("tank/thud.wav");
1125  gi.soundindex("tank/pain.wav");
1126 
1127  self->think = commander_body_drop;
1128  self->nextthink = level.time + 5 * FRAMETIME;
1129 }
1130 
1131 
1132 /*QUAKED misc_banner (1 .5 0) (-4 -4 -4) (4 4 4)
1133 The origin is the bottom of the banner.
1134 The banner is 128 tall.
1135 */
1136 void misc_banner_think(edict_t *ent)
1137 {
1138  ent->s.frame = (ent->s.frame + 1) % 16;
1139  ent->nextthink = level.time + FRAMETIME;
1140 }
1141 
1142 void SP_misc_banner(edict_t *ent)
1143 {
1144  ent->movetype = MOVETYPE_NONE;
1145  ent->solid = SOLID_NOT;
1146  ent->s.modelindex = gi.modelindex("models/objects/banner/tris.md2");
1147  ent->s.frame = rand() % 16;
1148  gi.linkentity(ent);
1149 
1150  ent->think = misc_banner_think;
1151  ent->nextthink = level.time + FRAMETIME;
1152 }
1153 
1154 /*QUAKED misc_deadsoldier (1 .5 0) (-16 -16 0) (16 16 16) ON_BACK ON_STOMACH BACK_DECAP FETAL_POS SIT_DECAP IMPALED
1155 This is the dead player model. Comes in 6 exciting different poses!
1156 */
1157 void misc_deadsoldier_die(edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point)
1158 {
1159  int n;
1160 
1161  if (self->health > -80)
1162  return;
1163 
1164  gi.sound(self, CHAN_BODY, gi.soundindex("misc/udeath.wav"), 1, ATTN_NORM, 0);
1165  for (n = 0; n < 4; n++)
1166  ThrowGib(self, "models/objects/gibs/sm_meat/tris.md2", damage, GIB_ORGANIC);
1167  ThrowHead(self, "models/objects/gibs/head2/tris.md2", damage, GIB_ORGANIC);
1168 }
1169 
1170 void SP_misc_deadsoldier(edict_t *ent)
1171 {
1172  if (deathmatch->value) {
1173  // auto-remove for deathmatch
1174  G_FreeEdict(ent);
1175  return;
1176  }
1177 
1178  ent->movetype = MOVETYPE_NONE;
1179  ent->solid = SOLID_BBOX;
1180  ent->s.modelindex = gi.modelindex("models/deadbods/dude/tris.md2");
1181 
1182  // Defaults to frame 0
1183  if (ent->spawnflags & 2)
1184  ent->s.frame = 1;
1185  else if (ent->spawnflags & 4)
1186  ent->s.frame = 2;
1187  else if (ent->spawnflags & 8)
1188  ent->s.frame = 3;
1189  else if (ent->spawnflags & 16)
1190  ent->s.frame = 4;
1191  else if (ent->spawnflags & 32)
1192  ent->s.frame = 5;
1193  else
1194  ent->s.frame = 0;
1195 
1196  VectorSet(ent->mins, -16, -16, 0);
1197  VectorSet(ent->maxs, 16, 16, 16);
1198  ent->deadflag = DEAD_DEAD;
1199  ent->takedamage = DAMAGE_YES;
1200  ent->svflags |= SVF_MONSTER | SVF_DEADMONSTER;
1201  ent->die = misc_deadsoldier_die;
1202  ent->monsterinfo.aiflags |= AI_GOOD_GUY;
1203 
1204  gi.linkentity(ent);
1205 }
1206 
1207 /*QUAKED misc_viper (1 .5 0) (-16 -16 0) (16 16 32)
1208 This is the Viper for the flyby bombing.
1209 It is trigger_spawned, so you must have something use it for it to show up.
1210 There must be a path for it to follow once it is activated.
1211 
1212 "speed" How fast the Viper should fly
1213 */
1214 
1215 extern void train_use(edict_t *self, edict_t *other, edict_t *activator);
1216 extern void func_train_find(edict_t *self);
1217 
1218 void misc_viper_use(edict_t *self, edict_t *other, edict_t *activator)
1219 {
1220  self->svflags &= ~SVF_NOCLIENT;
1221  self->use = train_use;
1222  train_use(self, other, activator);
1223 }
1224 
1225 void SP_misc_viper(edict_t *ent)
1226 {
1227  if (!ent->target) {
1228  gi.dprintf("misc_viper without a target at %s\n", vtos(ent->absmin));
1229  G_FreeEdict(ent);
1230  return;
1231  }
1232 
1233  if (!ent->speed)
1234  ent->speed = 300;
1235 
1236  ent->movetype = MOVETYPE_PUSH;
1237  ent->solid = SOLID_NOT;
1238  ent->s.modelindex = gi.modelindex("models/ships/viper/tris.md2");
1239  VectorSet(ent->mins, -16, -16, 0);
1240  VectorSet(ent->maxs, 16, 16, 32);
1241 
1242  ent->think = func_train_find;
1243  ent->nextthink = level.time + FRAMETIME;
1244  ent->use = misc_viper_use;
1245  ent->svflags |= SVF_NOCLIENT;
1246  ent->moveinfo.accel = ent->moveinfo.decel = ent->moveinfo.speed = ent->speed;
1247 
1248  gi.linkentity(ent);
1249 }
1250 
1251 
1252 /*QUAKED misc_bigviper (1 .5 0) (-176 -120 -24) (176 120 72)
1253 This is a large stationary viper as seen in Paul's intro
1254 */
1255 void SP_misc_bigviper(edict_t *ent)
1256 {
1257  ent->movetype = MOVETYPE_NONE;
1258  ent->solid = SOLID_BBOX;
1259  VectorSet(ent->mins, -176, -120, -24);
1260  VectorSet(ent->maxs, 176, 120, 72);
1261  ent->s.modelindex = gi.modelindex("models/ships/bigviper/tris.md2");
1262  gi.linkentity(ent);
1263 }
1264 
1265 
1266 /*QUAKED misc_viper_bomb (1 0 0) (-8 -8 -8) (8 8 8)
1267 "dmg" how much boom should the bomb make?
1268 */
1269 void misc_viper_bomb_touch(edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf)
1270 {
1271  G_UseTargets(self, self->activator);
1272 
1273  self->s.origin[2] = self->absmin[2] + 1;
1274  T_RadiusDamage(self, self, self->dmg, NULL, self->dmg + 40, MOD_BOMB);
1275  BecomeExplosion2(self);
1276 }
1277 
1278 void misc_viper_bomb_prethink(edict_t *self)
1279 {
1280  vec3_t v;
1281  float diff;
1282 
1283  self->groundentity = NULL;
1284 
1285  diff = self->timestamp - level.time;
1286  if (diff < -1.0)
1287  diff = -1.0;
1288 
1289  VectorScale(self->moveinfo.dir, 1.0 + diff, v);
1290  v[2] = diff;
1291 
1292  diff = self->s.angles[2];
1293  vectoangles(v, self->s.angles);
1294  self->s.angles[2] = diff + 10;
1295 }
1296 
1297 void misc_viper_bomb_use(edict_t *self, edict_t *other, edict_t *activator)
1298 {
1299  edict_t *viper;
1300 
1301  self->solid = SOLID_BBOX;
1302  self->svflags &= ~SVF_NOCLIENT;
1303  self->s.effects |= EF_ROCKET;
1304  self->use = NULL;
1305  self->movetype = MOVETYPE_TOSS;
1306  self->prethink = misc_viper_bomb_prethink;
1307  self->touch = misc_viper_bomb_touch;
1308  self->activator = activator;
1309 
1310  viper = G_Find(NULL, FOFS(classname), "misc_viper");
1311  VectorScale(viper->moveinfo.dir, viper->moveinfo.speed, self->velocity);
1312 
1313  self->timestamp = level.time;
1314  VectorCopy(viper->moveinfo.dir, self->moveinfo.dir);
1315 }
1316 
1317 void SP_misc_viper_bomb(edict_t *self)
1318 {
1319  self->movetype = MOVETYPE_NONE;
1320  self->solid = SOLID_NOT;
1321  VectorSet(self->mins, -8, -8, -8);
1322  VectorSet(self->maxs, 8, 8, 8);
1323 
1324  self->s.modelindex = gi.modelindex("models/objects/bomb/tris.md2");
1325 
1326  if (!self->dmg)
1327  self->dmg = 1000;
1328 
1329  self->use = misc_viper_bomb_use;
1330  self->svflags |= SVF_NOCLIENT;
1331 
1332  gi.linkentity(self);
1333 }
1334 
1335 
1336 /*QUAKED misc_strogg_ship (1 .5 0) (-16 -16 0) (16 16 32)
1337 This is a Storgg ship for the flybys.
1338 It is trigger_spawned, so you must have something use it for it to show up.
1339 There must be a path for it to follow once it is activated.
1340 
1341 "speed" How fast it should fly
1342 */
1343 
1344 extern void train_use(edict_t *self, edict_t *other, edict_t *activator);
1345 extern void func_train_find(edict_t *self);
1346 
1347 void misc_strogg_ship_use(edict_t *self, edict_t *other, edict_t *activator)
1348 {
1349  self->svflags &= ~SVF_NOCLIENT;
1350  self->use = train_use;
1351  train_use(self, other, activator);
1352 }
1353 
1354 void SP_misc_strogg_ship(edict_t *ent)
1355 {
1356  if (!ent->target) {
1357  gi.dprintf("%s without a target at %s\n", ent->classname, vtos(ent->absmin));
1358  G_FreeEdict(ent);
1359  return;
1360  }
1361 
1362  if (!ent->speed)
1363  ent->speed = 300;
1364 
1365  ent->movetype = MOVETYPE_PUSH;
1366  ent->solid = SOLID_NOT;
1367  ent->s.modelindex = gi.modelindex("models/ships/strogg1/tris.md2");
1368  VectorSet(ent->mins, -16, -16, 0);
1369  VectorSet(ent->maxs, 16, 16, 32);
1370 
1371  ent->think = func_train_find;
1372  ent->nextthink = level.time + FRAMETIME;
1373  ent->use = misc_strogg_ship_use;
1374  ent->svflags |= SVF_NOCLIENT;
1375  ent->moveinfo.accel = ent->moveinfo.decel = ent->moveinfo.speed = ent->speed;
1376 
1377  gi.linkentity(ent);
1378 }
1379 
1380 
1381 /*QUAKED misc_satellite_dish (1 .5 0) (-64 -64 0) (64 64 128)
1382 */
1383 void misc_satellite_dish_think(edict_t *self)
1384 {
1385  self->s.frame++;
1386  if (self->s.frame < 38)
1387  self->nextthink = level.time + FRAMETIME;
1388 }
1389 
1390 void misc_satellite_dish_use(edict_t *self, edict_t *other, edict_t *activator)
1391 {
1392  self->s.frame = 0;
1393  self->think = misc_satellite_dish_think;
1394  self->nextthink = level.time + FRAMETIME;
1395 }
1396 
1397 void SP_misc_satellite_dish(edict_t *ent)
1398 {
1399  ent->movetype = MOVETYPE_NONE;
1400  ent->solid = SOLID_BBOX;
1401  VectorSet(ent->mins, -64, -64, 0);
1402  VectorSet(ent->maxs, 64, 64, 128);
1403  ent->s.modelindex = gi.modelindex("models/objects/satellite/tris.md2");
1404  ent->use = misc_satellite_dish_use;
1405  gi.linkentity(ent);
1406 }
1407 
1408 
1409 /*QUAKED light_mine1 (0 1 0) (-2 -2 -12) (2 2 12)
1410 */
1411 void SP_light_mine1(edict_t *ent)
1412 {
1413  ent->movetype = MOVETYPE_NONE;
1414  ent->solid = SOLID_BBOX;
1415  ent->s.modelindex = gi.modelindex("models/objects/minelite/light1/tris.md2");
1416  gi.linkentity(ent);
1417 }
1418 
1419 
1420 /*QUAKED light_mine2 (0 1 0) (-2 -2 -12) (2 2 12)
1421 */
1422 void SP_light_mine2(edict_t *ent)
1423 {
1424  ent->movetype = MOVETYPE_NONE;
1425  ent->solid = SOLID_BBOX;
1426  ent->s.modelindex = gi.modelindex("models/objects/minelite/light2/tris.md2");
1427  gi.linkentity(ent);
1428 }
1429 
1430 
1431 /*QUAKED misc_gib_arm (1 0 0) (-8 -8 -8) (8 8 8)
1432 Intended for use with the target_spawner
1433 */
1434 void SP_misc_gib_arm(edict_t *ent)
1435 {
1436  gi.setmodel(ent, "models/objects/gibs/arm/tris.md2");
1437  ent->solid = SOLID_NOT;
1438  ent->s.effects |= EF_GIB;
1439  ent->takedamage = DAMAGE_YES;
1440  ent->die = gib_die;
1441  ent->movetype = MOVETYPE_TOSS;
1442  ent->svflags |= SVF_MONSTER;
1443  ent->deadflag = DEAD_DEAD;
1444  ent->avelocity[0] = random() * 200;
1445  ent->avelocity[1] = random() * 200;
1446  ent->avelocity[2] = random() * 200;
1447  ent->think = G_FreeEdict;
1448  ent->nextthink = level.time + 30;
1449  gi.linkentity(ent);
1450 }
1451 
1452 /*QUAKED misc_gib_leg (1 0 0) (-8 -8 -8) (8 8 8)
1453 Intended for use with the target_spawner
1454 */
1455 void SP_misc_gib_leg(edict_t *ent)
1456 {
1457  gi.setmodel(ent, "models/objects/gibs/leg/tris.md2");
1458  ent->solid = SOLID_NOT;
1459  ent->s.effects |= EF_GIB;
1460  ent->takedamage = DAMAGE_YES;
1461  ent->die = gib_die;
1462  ent->movetype = MOVETYPE_TOSS;
1463  ent->svflags |= SVF_MONSTER;
1464  ent->deadflag = DEAD_DEAD;
1465  ent->avelocity[0] = random() * 200;
1466  ent->avelocity[1] = random() * 200;
1467  ent->avelocity[2] = random() * 200;
1468  ent->think = G_FreeEdict;
1469  ent->nextthink = level.time + 30;
1470  gi.linkentity(ent);
1471 }
1472 
1473 /*QUAKED misc_gib_head (1 0 0) (-8 -8 -8) (8 8 8)
1474 Intended for use with the target_spawner
1475 */
1476 void SP_misc_gib_head(edict_t *ent)
1477 {
1478  gi.setmodel(ent, "models/objects/gibs/head/tris.md2");
1479  ent->solid = SOLID_NOT;
1480  ent->s.effects |= EF_GIB;
1481  ent->takedamage = DAMAGE_YES;
1482  ent->die = gib_die;
1483  ent->movetype = MOVETYPE_TOSS;
1484  ent->svflags |= SVF_MONSTER;
1485  ent->deadflag = DEAD_DEAD;
1486  ent->avelocity[0] = random() * 200;
1487  ent->avelocity[1] = random() * 200;
1488  ent->avelocity[2] = random() * 200;
1489  ent->think = G_FreeEdict;
1490  ent->nextthink = level.time + 30;
1491  gi.linkentity(ent);
1492 }
1493 
1494 //=====================================================
1495 
1496 /*QUAKED target_character (0 0 1) ?
1497 used with target_string (must be on same "team")
1498 "count" is position in the string (starts at 1)
1499 */
1500 
1501 void SP_target_character(edict_t *self)
1502 {
1503  self->movetype = MOVETYPE_PUSH;
1504  gi.setmodel(self, self->model);
1505  self->solid = SOLID_BSP;
1506  self->s.frame = 12;
1507  gi.linkentity(self);
1508  return;
1509 }
1510 
1511 
1512 /*QUAKED target_string (0 0 1) (-8 -8 -8) (8 8 8)
1513 */
1514 
1515 void target_string_use(edict_t *self, edict_t *other, edict_t *activator)
1516 {
1517  edict_t *e;
1518  int n, l;
1519  char c;
1520 
1521  l = strlen(self->message);
1522  for (e = self->teammaster; e; e = e->teamchain) {
1523  if (!e->count)
1524  continue;
1525  n = e->count - 1;
1526  if (n > l) {
1527  e->s.frame = 12;
1528  continue;
1529  }
1530 
1531  c = self->message[n];
1532  if (c >= '0' && c <= '9')
1533  e->s.frame = c - '0';
1534  else if (c == '-')
1535  e->s.frame = 10;
1536  else if (c == ':')
1537  e->s.frame = 11;
1538  else
1539  e->s.frame = 12;
1540  }
1541 }
1542 
1543 void SP_target_string(edict_t *self)
1544 {
1545  if (!self->message)
1546  self->message = "";
1547  self->use = target_string_use;
1548 }
1549 
1550 
1551 /*QUAKED func_clock (0 0 1) (-8 -8 -8) (8 8 8) TIMER_UP TIMER_DOWN START_OFF MULTI_USE
1552 target a target_string with this
1553 
1554 The default is to be a time of day clock
1555 
1556 TIMER_UP and TIMER_DOWN run for "count" seconds and the fire "pathtarget"
1557 If START_OFF, this entity must be used before it starts
1558 
1559 "style" 0 "xx"
1560  1 "xx:xx"
1561  2 "xx:xx:xx"
1562 */
1563 
1564 static void func_clock_reset(edict_t *self)
1565 {
1566  self->activator = NULL;
1567  if (self->spawnflags & 1) {
1568  self->health = 0;
1569  self->wait = self->count;
1570  } else if (self->spawnflags & 2) {
1571  self->health = self->count;
1572  self->wait = 0;
1573  }
1574 }
1575 
1576 static void func_clock_format_countdown(edict_t *self)
1577 {
1578  if (self->style == 0) {
1579  Q_snprintf(self->message, CLOCK_MESSAGE_SIZE, "%2i", self->health);
1580  return;
1581  }
1582 
1583  if (self->style == 1) {
1584  Q_snprintf(self->message, CLOCK_MESSAGE_SIZE, "%2i:%2i", self->health / 60, self->health % 60);
1585  if (self->message[3] == ' ')
1586  self->message[3] = '0';
1587  return;
1588  }
1589 
1590  if (self->style == 2) {
1591  Q_snprintf(self->message, CLOCK_MESSAGE_SIZE, "%2i:%2i:%2i", self->health / 3600, (self->health - (self->health / 3600) * 3600) / 60, self->health % 60);
1592  if (self->message[3] == ' ')
1593  self->message[3] = '0';
1594  if (self->message[6] == ' ')
1595  self->message[6] = '0';
1596  return;
1597  }
1598 }
1599 
1600 void func_clock_think(edict_t *self)
1601 {
1602  if (!self->enemy) {
1603  self->enemy = G_Find(NULL, FOFS(targetname), self->target);
1604  if (!self->enemy)
1605  return;
1606  }
1607 
1608  if (self->spawnflags & 1) {
1610  self->health++;
1611  } else if (self->spawnflags & 2) {
1613  self->health--;
1614  } else {
1615  struct tm *ltime;
1616  time_t gmtime;
1617 
1618  gmtime = time(NULL);
1619  ltime = localtime(&gmtime);
1620  if (ltime)
1621  Q_snprintf(self->message, CLOCK_MESSAGE_SIZE, "%2i:%2i:%2i", ltime->tm_hour, ltime->tm_min, ltime->tm_sec);
1622  else
1623  strcpy(self->message, "00:00:00");
1624  if (self->message[3] == ' ')
1625  self->message[3] = '0';
1626  if (self->message[6] == ' ')
1627  self->message[6] = '0';
1628  }
1629 
1630  self->enemy->message = self->message;
1631  self->enemy->use(self->enemy, self, self);
1632 
1633  if (((self->spawnflags & 1) && (self->health > self->wait)) ||
1634  ((self->spawnflags & 2) && (self->health < self->wait))) {
1635  if (self->pathtarget) {
1636  char *savetarget;
1637  char *savemessage;
1638 
1639  savetarget = self->target;
1640  savemessage = self->message;
1641  self->target = self->pathtarget;
1642  self->message = NULL;
1643  G_UseTargets(self, self->activator);
1644  self->target = savetarget;
1645  self->message = savemessage;
1646  }
1647 
1648  if (!(self->spawnflags & 8))
1649  return;
1650 
1651  func_clock_reset(self);
1652 
1653  if (self->spawnflags & 4)
1654  return;
1655  }
1656 
1657  self->nextthink = level.time + 1;
1658 }
1659 
1660 void func_clock_use(edict_t *self, edict_t *other, edict_t *activator)
1661 {
1662  if (!(self->spawnflags & 8))
1663  self->use = NULL;
1664  if (self->activator)
1665  return;
1666  self->activator = activator;
1667  self->think(self);
1668 }
1669 
1670 void SP_func_clock(edict_t *self)
1671 {
1672  if (!self->target) {
1673  gi.dprintf("%s with no target at %s\n", self->classname, vtos(self->s.origin));
1674  G_FreeEdict(self);
1675  return;
1676  }
1677 
1678  if ((self->spawnflags & 2) && (!self->count)) {
1679  gi.dprintf("%s with no count at %s\n", self->classname, vtos(self->s.origin));
1680  G_FreeEdict(self);
1681  return;
1682  }
1683 
1684  if ((self->spawnflags & 1) && (!self->count))
1685  self->count = 60 * 60;;
1686 
1687  func_clock_reset(self);
1688 
1689  self->message = gi.TagMalloc(CLOCK_MESSAGE_SIZE, TAG_LEVEL);
1690 
1691  self->think = func_clock_think;
1692 
1693  if (self->spawnflags & 4)
1694  self->use = func_clock_use;
1695  else
1696  self->nextthink = level.time + 1;
1697 }
1698 
1699 //=================================================================================
1700 
1701 void teleporter_touch(edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf)
1702 {
1703  edict_t *dest;
1704  int i;
1705 
1706  if (!other->client)
1707  return;
1708  dest = G_Find(NULL, FOFS(targetname), self->target);
1709  if (!dest) {
1710  gi.dprintf("Couldn't find destination\n");
1711  return;
1712  }
1713 
1714  // unlink to make sure it can't possibly interfere with KillBox
1715  gi.unlinkentity(other);
1716 
1717  VectorCopy(dest->s.origin, other->s.origin);
1718  VectorCopy(dest->s.origin, other->s.old_origin);
1719  other->s.origin[2] += 10;
1720 
1721  // clear the velocity and hold them in place briefly
1722  VectorClear(other->velocity);
1723  other->client->ps.pmove.pm_time = 160 >> 3; // hold time
1724  other->client->ps.pmove.pm_flags |= PMF_TIME_TELEPORT;
1725 
1726  // draw the teleport splash at source and on the player
1727  self->owner->s.event = EV_PLAYER_TELEPORT;
1728  other->s.event = EV_PLAYER_TELEPORT;
1729 
1730  // set angles
1731  for (i = 0 ; i < 3 ; i++) {
1732  other->client->ps.pmove.delta_angles[i] = ANGLE2SHORT(dest->s.angles[i] - other->client->resp.cmd_angles[i]);
1733  }
1734 
1735  VectorClear(other->s.angles);
1736  VectorClear(other->client->ps.viewangles);
1737  VectorClear(other->client->v_angle);
1738 
1739  // kill anything at the destination
1740  KillBox(other);
1741 
1742  gi.linkentity(other);
1743 }
1744 
1745 /*QUAKED misc_teleporter (1 0 0) (-32 -32 -24) (32 32 -16)
1746 Stepping onto this disc will teleport players to the targeted misc_teleporter_dest object.
1747 */
1748 void SP_misc_teleporter(edict_t *ent)
1749 {
1750  edict_t *trig;
1751 
1752  if (!ent->target) {
1753  gi.dprintf("teleporter without a target.\n");
1754  G_FreeEdict(ent);
1755  return;
1756  }
1757 
1758  gi.setmodel(ent, "models/objects/dmspot/tris.md2");
1759  ent->s.skinnum = 1;
1760  ent->s.effects = EF_TELEPORTER;
1761  ent->s.sound = gi.soundindex("world/amb10.wav");
1762  ent->solid = SOLID_BBOX;
1763 
1764  VectorSet(ent->mins, -32, -32, -24);
1765  VectorSet(ent->maxs, 32, 32, -16);
1766  gi.linkentity(ent);
1767 
1768  trig = G_Spawn();
1769  trig->touch = teleporter_touch;
1770  trig->solid = SOLID_TRIGGER;
1771  trig->target = ent->target;
1772  trig->owner = ent;
1773  VectorCopy(ent->s.origin, trig->s.origin);
1774  VectorSet(trig->mins, -8, -8, 8);
1775  VectorSet(trig->maxs, 8, 8, 24);
1776  gi.linkentity(trig);
1777 
1778 }
1779 
1780 /*QUAKED misc_teleporter_dest (1 0 0) (-32 -32 -24) (32 32 -16)
1781 Point teleporters at these.
1782 */
1783 void SP_misc_teleporter_dest(edict_t *ent)
1784 {
1785  gi.setmodel(ent, "models/objects/dmspot/tris.md2");
1786  ent->s.skinnum = 0;
1787  ent->solid = SOLID_BBOX;
1788 // ent->s.effects |= EF_FLIES;
1789  VectorSet(ent->mins, -32, -32, -24);
1790  VectorSet(ent->maxs, 32, 32, -16);
1791  gi.linkentity(ent);
1792 }
1793 
gi
game_import_t gi
Definition: g_main.c:23
ThrowHead
void ThrowHead(edict_t *self, char *gibname, int damage, int type)
Definition: g_misc.c:175
misc_strogg_ship_use
void misc_strogg_ship_use(edict_t *self, edict_t *other, edict_t *activator)
Definition: g_misc.c:1347
SP_viewthing
void SP_viewthing(edict_t *ent)
Definition: g_misc.c:468
misc_deadsoldier_die
void misc_deadsoldier_die(edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point)
Definition: g_misc.c:1157
SP_light
void SP_light(edict_t *self)
Definition: g_misc.c:525
ThrowClientHead
void ThrowClientHead(edict_t *self, int damage)
Definition: g_misc.c:218
deathmatch
cvar_t * deathmatch
Definition: g_main.c:33
SP_misc_viper
void SP_misc_viper(edict_t *ent)
Definition: g_misc.c:1225
SP_misc_satellite_dish
void SP_misc_satellite_dish(edict_t *ent)
Definition: g_misc.c:1397
misc_viper_bomb_use
void misc_viper_bomb_use(edict_t *self, edict_t *other, edict_t *activator)
Definition: g_misc.c:1297
DEAD_DEAD
#define DEAD_DEAD
Definition: g_local.h:112
SP_misc_teleporter_dest
void SP_misc_teleporter_dest(edict_t *ent)
Definition: g_misc.c:1783
AI_COMBAT_POINT
#define AI_COMBAT_POINT
Definition: g_local.h:138
SP_misc_strogg_ship
void SP_misc_strogg_ship(edict_t *ent)
Definition: g_misc.c:1354
barrel_delay
void barrel_delay(edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point)
Definition: g_misc.c:910
G_Spawn
edict_t * G_Spawn(void)
Definition: g_utils.c:391
func_object_use
void func_object_use(edict_t *self, edict_t *other, edict_t *activator)
Definition: g_misc.c:637
ANIM_DEATH
#define ANIM_DEATH
Definition: g_local.h:816
AI_GOOD_GUY
#define AI_GOOD_GUY
Definition: g_local.h:134
barrel_touch
void barrel_touch(edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf)
Definition: g_misc.c:817
Q_snprintf
size_t Q_snprintf(char *dest, size_t size, const char *fmt,...)
Definition: shared.c:846
TH_viewthing
void TH_viewthing(edict_t *ent)
Definition: g_misc.c:462
misc_viper_use
void misc_viper_use(edict_t *self, edict_t *other, edict_t *activator)
Definition: g_misc.c:1218
FRAMETIME
#define FRAMETIME
Definition: g_local.h:75
MOD_BOMB
#define MOD_BOMB
Definition: g_local.h:484
SP_light_mine1
void SP_light_mine1(edict_t *ent)
Definition: g_misc.c:1411
SP_misc_deadsoldier
void SP_misc_deadsoldier(edict_t *ent)
Definition: g_misc.c:1170
path_corner_touch
void path_corner_touch(edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf)
Definition: g_misc.c:325
M_walkmove
qboolean M_walkmove(edict_t *ent, float yaw, float dist)
Definition: m_move.c:503
func_clock_think
void func_clock_think(edict_t *self)
Definition: g_misc.c:1600
SP_point_combat
void SP_point_combat(edict_t *self)
Definition: g_misc.c:444
SP_misc_bigviper
void SP_misc_bigviper(edict_t *ent)
Definition: g_misc.c:1255
SP_misc_gib_arm
void SP_misc_gib_arm(edict_t *ent)
Definition: g_misc.c:1434
misc_banner_think
void misc_banner_think(edict_t *ent)
Definition: g_misc.c:1136
target_string_use
void target_string_use(edict_t *self, edict_t *other, edict_t *activator)
Definition: g_misc.c:1515
AI_STAND_GROUND
#define AI_STAND_GROUND
Definition: g_local.h:126
SP_misc_easterchick
void SP_misc_easterchick(edict_t *ent)
Definition: g_misc.c:1040
MOVETYPE_PUSH
@ MOVETYPE_PUSH
Definition: g_local.h:188
func_train_find
void func_train_find(edict_t *self)
Definition: g_func.c:1515
SP_misc_blackhole
void SP_misc_blackhole(edict_t *ent)
Definition: g_misc.c:986
G_Find
edict_t * G_Find(edict_t *from, int fieldofs, char *match)
Definition: g_utils.c:43
DAMAGE_YES
@ DAMAGE_YES
Definition: g_local.h:88
SP_monster_commander_body
void SP_monster_commander_body(edict_t *self)
Definition: g_misc.c:1110
FOFS
#define FOFS(x)
Definition: g_local.h:498
M_droptofloor
void M_droptofloor(edict_t *ent)
Definition: g_monster.c:286
FL_NO_KNOCKBACK
#define FL_NO_KNOCKBACK
Definition: g_local.h:70
vectoyaw
float vectoyaw(vec3_t vec)
Definition: g_utils.c:310
TAG_LEVEL
#define TAG_LEVEL
Definition: g_local.h:79
commander_body_use
void commander_body_use(edict_t *self, edict_t *other, edict_t *activator)
Definition: g_misc.c:1097
misc_easterchick2_think
void misc_easterchick2_think(edict_t *self)
Definition: g_misc.c:1057
SP_target_string
void SP_target_string(edict_t *self)
Definition: g_misc.c:1543
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:358
other
@ other
Definition: ogg.c:63
BecomeExplosion2
void BecomeExplosion2(edict_t *self)
Definition: g_misc.c:308
barrel_explode
void barrel_explode(edict_t *self)
Definition: g_misc.c:831
MOVETYPE_STEP
@ MOVETYPE_STEP
Definition: g_local.h:192
commander_body_drop
void commander_body_drop(edict_t *self)
Definition: g_misc.c:1104
FL_SWIM
#define FL_SWIM
Definition: g_local.h:60
func_object_touch
void func_object_touch(edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf)
Definition: g_misc.c:619
teleporter_touch
void teleporter_touch(edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf)
Definition: g_misc.c:1701
func_wall_use
void func_wall_use(edict_t *self, edict_t *other, edict_t *activator)
Definition: g_misc.c:557
debris_die
void debris_die(edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point)
Definition: g_misc.c:264
light_use
void light_use(edict_t *self, edict_t *other, edict_t *activator)
Definition: g_misc.c:514
commander_body_think
void commander_body_think(edict_t *self)
Definition: g_misc.c:1086
vec3_origin
vec3_t vec3_origin
Definition: shared.c:21
SP_misc_banner
void SP_misc_banner(edict_t *ent)
Definition: g_misc.c:1142
vectoangles
void vectoangles(vec3_t vec, vec3_t angles)
Definition: g_utils.c:330
gib_touch
void gib_touch(edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf)
Definition: g_misc.c:101
SP_func_areaportal
void SP_func_areaportal(edict_t *ent)
Definition: g_misc.c:42
MOD_EXPLOSIVE
#define MOD_EXPLOSIVE
Definition: g_local.h:482
G_FreeEdict
void G_FreeEdict(edict_t *e)
Definition: g_utils.c:421
MOVETYPE_NONE
@ MOVETYPE_NONE
Definition: g_local.h:186
CLOCK_MESSAGE_SIZE
#define CLOCK_MESSAGE_SIZE
Definition: g_local.h:692
SP_info_notnull
void SP_info_notnull(edict_t *self)
Definition: g_misc.c:497
point_combat_touch
void point_combat_touch(edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf)
Definition: g_misc.c:398
func_object_release
void func_object_release(edict_t *self)
Definition: g_misc.c:631
svc_temp_entity
#define svc_temp_entity
Definition: g_local.h:38
crandom
#define crandom()
Definition: g_local.h:505
SP_misc_viper_bomb
void SP_misc_viper_bomb(edict_t *self)
Definition: g_misc.c:1317
FL_GODMODE
#define FL_GODMODE
Definition: g_local.h:63
misc_eastertank_think
void misc_eastertank_think(edict_t *self)
Definition: g_misc.c:1003
SP_info_null
void SP_info_null(edict_t *self)
Definition: g_misc.c:488
Use_Areaportal
void Use_Areaportal(edict_t *ent, edict_t *other, edict_t *activator)
Definition: g_misc.c:29
vtos
char * vtos(vec3_t v)
Definition: g_utils.c:275
SP_func_explosive
void SP_func_explosive(edict_t *self)
Definition: g_misc.c:771
origin
static vec3_t origin
Definition: mesh.c:27
func_clock_use
void func_clock_use(edict_t *self, edict_t *other, edict_t *activator)
Definition: g_misc.c:1660
random
#define random()
Definition: g_local.h:504
AngleVectors
void AngleVectors(vec3_t angles, vec3_t forward, vec3_t right, vec3_t up)
Definition: shared.c:23
DAMAGE_NO
@ DAMAGE_NO
Definition: g_local.h:87
SP_func_wall
void SP_func_wall(edict_t *self)
Definition: g_misc.c:573
BecomeExplosion1
void BecomeExplosion1(edict_t *self)
Definition: g_misc.c:297
SP_misc_eastertank
void SP_misc_eastertank(edict_t *ent)
Definition: g_misc.c:1013
SP_misc_easterchick2
void SP_misc_easterchick2(edict_t *ent)
Definition: g_misc.c:1067
func_clock_reset
static void func_clock_reset(edict_t *self)
Definition: g_misc.c:1564
SP_func_object
void SP_func_object(edict_t *self)
Definition: g_misc.c:646
sm_meat_index
int sm_meat_index
Definition: g_main.c:27
misc_blackhole_use
void misc_blackhole_use(edict_t *ent, edict_t *other, edict_t *activator)
Definition: g_misc.c:965
MOD_BARREL
#define MOD_BARREL
Definition: g_local.h:483
misc_blackhole_think
void misc_blackhole_think(edict_t *self)
Definition: g_misc.c:976
SP_misc_teleporter
void SP_misc_teleporter(edict_t *ent)
Definition: g_misc.c:1748
misc_viper_bomb_prethink
void misc_viper_bomb_prethink(edict_t *self)
Definition: g_misc.c:1278
MOD_CRUSH
#define MOD_CRUSH
Definition: g_local.h:477
level_locals_t::time
float time
Definition: g_local.h:299
SP_misc_explobox
void SP_misc_explobox(edict_t *self)
Definition: g_misc.c:918
ClipGibVelocity
void ClipGibVelocity(edict_t *ent)
Definition: g_misc.c:68
func_explosive_use
void func_explosive_use(edict_t *self, edict_t *other, edict_t *activator)
Definition: g_misc.c:757
ThrowGib
void ThrowGib(edict_t *self, char *gibname, int damage, int type)
Definition: g_misc.c:130
c
statCounters_t c
Definition: main.c:30
func_explosive_spawn
void func_explosive_spawn(edict_t *self, edict_t *other, edict_t *activator)
Definition: g_misc.c:762
gib_die
void gib_die(edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point)
Definition: g_misc.c:125
SP_target_character
void SP_target_character(edict_t *self)
Definition: g_misc.c:1501
SP_misc_gib_leg
void SP_misc_gib_leg(edict_t *ent)
Definition: g_misc.c:1455
misc_viper_bomb_touch
void misc_viper_bomb_touch(edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf)
Definition: g_misc.c:1269
right
static vec3_t right
Definition: p_view.c:27
G_UseTargets
void G_UseTargets(edict_t *ent, edict_t *activator)
Definition: g_utils.c:166
GIB_ORGANIC
#define GIB_ORGANIC
Definition: g_local.h:122
level
level_locals_t level
Definition: g_main.c:22
diff
static q_noinline int diff(uint32_t A_u32, uint32_t B_u32)
Definition: hq2x.c:55
SP_path_corner
void SP_path_corner(edict_t *self)
Definition: g_misc.c:376
FL_FLY
#define FL_FLY
Definition: g_local.h:59
KillBox
qboolean KillBox(edict_t *ent)
Definition: g_utils.c:515
misc_easterchick_think
void misc_easterchick_think(edict_t *self)
Definition: g_misc.c:1030
SP_misc_gib_head
void SP_misc_gib_head(edict_t *ent)
Definition: g_misc.c:1476
MOVETYPE_BOUNCE
@ MOVETYPE_BOUNCE
Definition: g_local.h:196
gib_think
void gib_think(edict_t *self)
Definition: g_misc.c:90
func_clock_format_countdown
static void func_clock_format_countdown(edict_t *self)
Definition: g_misc.c:1576
func_explosive_explode
void func_explosive_explode(edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point)
Definition: g_misc.c:696
MOVETYPE_TOSS
@ MOVETYPE_TOSS
Definition: g_local.h:194
SP_func_clock
void SP_func_clock(edict_t *self)
Definition: g_misc.c:1670
misc_satellite_dish_think
void misc_satellite_dish_think(edict_t *self)
Definition: g_misc.c:1383
SP_light_mine2
void SP_light_mine2(edict_t *ent)
Definition: g_misc.c:1422
VelocityForDamage
void VelocityForDamage(int damage, vec3_t v)
Definition: g_misc.c:56
G_PickTarget
edict_t * G_PickTarget(char *targetname)
Definition: g_utils.c:114
train_use
void train_use(edict_t *self, edict_t *other, edict_t *activator)
Definition: g_func.c:1544
misc_satellite_dish_use
void misc_satellite_dish_use(edict_t *self, edict_t *other, edict_t *activator)
Definition: g_misc.c:1390
START_OFF
#define START_OFF
Definition: g_misc.c:512
VectorNormalize
vec_t VectorNormalize(vec3_t v)
Definition: shared.c:55
ThrowDebris
void ThrowDebris(edict_t *self, char *modelname, float speed, vec3_t origin)
Definition: g_misc.c:269
g_local.h
T_RadiusDamage
void T_RadiusDamage(edict_t *inflictor, edict_t *attacker, float damage, edict_t *ignore, float radius, int mod)
Definition: g_combat.c:514
AI_NOSTEP
#define AI_NOSTEP
Definition: g_local.h:136