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