|
|
1.1 root 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:
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: */
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: */
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:
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: */
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:
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:
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:
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:
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:
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: */
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:
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:
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:
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:
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:
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: */
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:
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: */
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:
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: */
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: */
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:
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:
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:
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:
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:
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:
663: void func_object_release (edict_t *self)
664: {
665: self->movetype = MOVETYPE_TOSS;
666: self->touch = func_object_touch;
667: }
668:
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:
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: */
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:
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
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:
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:
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:
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:
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:
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
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:
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:
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:
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:
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:
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:
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:
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:
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:
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:
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:
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:
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:
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:
1263: void commander_body_drop (edict_t *self)
1264: {
1265: self->movetype = MOVETYPE_TOSS;
1266: self->s.origin[2] += 2;
1267: }
1268:
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: */
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:
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: */
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:
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:
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:
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: */
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: */
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:
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:
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:
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:
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:
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: */
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:
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:
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: */
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: */
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: */
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: */
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: */
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:
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:
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:
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:
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:
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:
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:
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:
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:
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: */
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: */
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
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: */
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:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.