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