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