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