|
|
1.1 root 1: #include "g_local.h"
2:
3:
4: void InitTrigger (edict_t *self)
5: {
6: if (!VectorCompare (self->s.angles, vec3_origin))
7: G_SetMovedir (self->s.angles, self->movedir);
8:
9: self->solid = SOLID_TRIGGER;
10: self->movetype = MOVETYPE_NONE;
11: gi.setmodel (self, self->model);
12: self->svflags = SVF_NOCLIENT;
13: }
14:
15:
16: // the wait time has passed, so set back up for another activation
17: void multi_wait (edict_t *ent)
18: {
19: ent->nextthink = 0;
20: }
21:
22:
23: // the trigger was just activated
24: // ent->activator should be set to the activator so it can be held through a delay
25: // so wait for the delay time before firing
26: void multi_trigger (edict_t *ent)
27: {
28: if (ent->nextthink)
29: return; // already been triggered
30:
31: G_UseTargets (ent, ent->activator);
32:
33: if (ent->wait > 0)
34: {
35: ent->think = multi_wait;
36: ent->nextthink = level.time + ent->wait;
37: }
38: else
39: { // we can't just remove (self) here, because this is a touch function
40: // called while looping through area links...
41: ent->touch = NULL;
42: ent->nextthink = level.time + FRAMETIME;
43: ent->think = G_FreeEdict;
44: }
45: }
46:
47: void Use_Multi (edict_t *ent, edict_t *other, edict_t *activator)
48: {
49: ent->activator = activator;
50: multi_trigger (ent);
51: }
52:
53: void Touch_Multi (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf)
54: {
55: if(other->client)
56: {
57: if (self->spawnflags & 2)
58: return;
59: }
60: else if (other->svflags & SVF_MONSTER)
61: {
62: if (!(self->spawnflags & 1))
63: return;
64: }
65: else
66: return;
67:
68: if (!VectorCompare(self->movedir, vec3_origin))
69: {
70: vec3_t forward;
71:
72: AngleVectors(other->s.angles, forward, NULL, NULL);
73: if (_DotProduct(forward, self->movedir) < 0)
74: return;
75: }
76:
77: self->activator = other;
78: multi_trigger (self);
79: }
80:
81: /*QUAKED trigger_multiple (.5 .5 .5) ? MONSTER NOT_PLAYER TRIGGERED
82: Variable sized repeatable trigger. Must be targeted at one or more entities.
83: If "delay" is set, the trigger waits some time after activating before firing.
84: "wait" : Seconds between triggerings. (.2 default)
85: sounds
86: 1) secret
87: 2) beep beep
88: 3) large switch
89: 4)
90: set "message" to text string
91: */
92: void trigger_enable (edict_t *self, edict_t *other, edict_t *activator)
93: {
94: self->solid = SOLID_TRIGGER;
95: self->use = Use_Multi;
96: gi.linkentity (self);
97: }
98:
99: void SP_trigger_multiple (edict_t *ent)
100: {
101: if (ent->sounds == 1)
102: ent->noise_index = gi.soundindex ("misc/secret.wav");
103: else if (ent->sounds == 2)
104: ent->noise_index = gi.soundindex ("misc/talk.wav");
105: else if (ent->sounds == 3)
106: ent->noise_index = gi.soundindex ("misc/trigger1.wav");
107:
108: if (!ent->wait)
109: ent->wait = 0.2;
110: ent->touch = Touch_Multi;
111: ent->movetype = MOVETYPE_NONE;
112: ent->svflags |= SVF_NOCLIENT;
113:
114:
115: if (ent->spawnflags & 4)
116: {
117: ent->solid = SOLID_NOT;
118: ent->use = trigger_enable;
119: }
120: else
121: {
122: ent->solid = SOLID_TRIGGER;
123: ent->use = Use_Multi;
124: }
125:
126: if (!VectorCompare(ent->s.angles, vec3_origin))
127: G_SetMovedir (ent->s.angles, ent->movedir);
128:
129: gi.setmodel (ent, ent->model);
130: gi.linkentity (ent);
131: }
132:
133:
134: /*QUAKED trigger_once (.5 .5 .5) ? x x TRIGGERED
135: Triggers once, then removes itself.
136: You must set the key "target" to the name of another object in the level that has a matching "targetname".
137:
138: If TRIGGERED, this trigger must be triggered before it is live.
139:
140: sounds
141: 1) secret
142: 2) beep beep
143: 3) large switch
144: 4)
145:
146: "message" string to be displayed when triggered
147: */
148:
149: void SP_trigger_once(edict_t *ent)
150: {
151: // make old maps work because I messed up on flag assignments here
152: // triggered was on bit 1 when it should have been on bit 4
153: if (ent->spawnflags & 1)
154: {
155: vec3_t v;
156:
157: VectorMA (ent->mins, 0.5, ent->size, v);
158: ent->spawnflags &= ~1;
159: ent->spawnflags |= 4;
160: gi.dprintf("fixed TRIGGERED flag on %s at %s\n", ent->classname, vtos(v));
161: }
162:
163: ent->wait = -1;
164: SP_trigger_multiple (ent);
165: }
166:
167: /*QUAKED trigger_relay (.5 .5 .5) (-8 -8 -8) (8 8 8)
168: This fixed size trigger cannot be touched, it can only be fired by other events.
169: */
170: void trigger_relay_use (edict_t *self, edict_t *other, edict_t *activator)
171: {
172: G_UseTargets (self, activator);
173: }
174:
175: void SP_trigger_relay (edict_t *self)
176: {
177: self->use = trigger_relay_use;
178: }
179:
180:
181: /*
182: ==============================================================================
183:
184: trigger_key
185:
186: ==============================================================================
187: */
188:
189: /*QUAKED trigger_key (.5 .5 .5) (-8 -8 -8) (8 8 8)
190: A relay trigger that only fires it's targets if player has the proper key.
191: Use "item" to specify the required key, for example "key_data_cd"
192: */
193: void trigger_key_use (edict_t *self, edict_t *other, edict_t *activator)
194: {
195: int index;
196:
197: if (!self->item)
198: return;
199: if (!activator->client)
200: return;
201:
202: index = ITEM_INDEX(self->item);
203: if (!activator->client->pers.inventory[index])
204: {
205: if (level.time < self->touch_debounce_time)
206: return;
207: self->touch_debounce_time = level.time + 5.0;
208: gi.centerprintf (activator, "You need the %s", self->item->pickup_name);
209: gi.sound (activator, CHAN_AUTO, gi.soundindex ("misc/keytry.wav"), 1, ATTN_NORM, 0);
210: return;
211: }
212:
213: gi.sound (activator, CHAN_AUTO, gi.soundindex ("misc/keyuse.wav"), 1, ATTN_NORM, 0);
214: if (coop->value)
215: {
216: int player;
217: edict_t *ent;
218:
219: if (strcmp(self->item->classname, "key_power_cube") == 0)
220: {
221: int cube;
222:
223: for (cube = 0; cube < 8; cube++)
224: if (activator->client->pers.power_cubes & (1 << cube))
225: break;
226: for (player = 1; player <= game.maxclients; player++)
227: {
228: ent = &g_edicts[player];
229: if (!ent->inuse)
230: continue;
231: if (!ent->client)
232: continue;
233: if (ent->client->pers.power_cubes & (1 << cube))
234: {
235: ent->client->pers.inventory[index]--;
236: ent->client->pers.power_cubes &= ~(1 << cube);
237: }
238: }
239: }
240: else
241: {
242: for (player = 1; player <= game.maxclients; player++)
243: {
244: ent = &g_edicts[player];
245: if (!ent->inuse)
246: continue;
247: if (!ent->client)
248: continue;
249: ent->client->pers.inventory[index] = 0;
250: }
251: }
252: }
253: else
254: {
255: activator->client->pers.inventory[index]--;
256: }
257:
258: G_UseTargets (self, activator);
259:
260: self->use = NULL;
261: }
262:
263: void SP_trigger_key (edict_t *self)
264: {
265: if (!st.item)
266: {
267: gi.dprintf("no key item for trigger_key at %s\n", vtos(self->s.origin));
268: return;
269: }
270: self->item = FindItemByClassname (st.item);
271:
272: if (!self->item)
273: {
274: gi.dprintf("item %s not found for trigger_key at %s\n", st.item, vtos(self->s.origin));
275: return;
276: }
277:
278: if (!self->target)
279: {
280: gi.dprintf("%s at %s has no target\n", self->classname, vtos(self->s.origin));
281: return;
282: }
283:
284: gi.soundindex ("misc/keytry.wav");
285: gi.soundindex ("misc/keyuse.wav");
286:
287: self->use = trigger_key_use;
288: }
289:
290:
291: /*
292: ==============================================================================
293:
294: trigger_counter
295:
296: ==============================================================================
297: */
298:
299: /*QUAKED trigger_counter (.5 .5 .5) ? nomessage
300: Acts as an intermediary for an action that takes multiple inputs.
301:
302: If nomessage is not set, t will print "1 more.. " etc when triggered and "sequence complete" when finished.
303:
304: After the counter has been triggered "count" times (default 2), it will fire all of it's targets and remove itself.
305: */
306:
307: void trigger_counter_use(edict_t *self, edict_t *other, edict_t *activator)
308: {
309: if (self->count == 0)
310: return;
311:
312: self->count--;
313:
314: if (self->count)
315: {
316: if (! (self->spawnflags & 1))
317: {
318: gi.centerprintf(activator, "%i more to go...", self->count);
319: gi.sound (activator, CHAN_AUTO, gi.soundindex ("misc/talk1.wav"), 1, ATTN_NORM, 0);
320: }
321: return;
322: }
323:
324: if (! (self->spawnflags & 1))
325: {
326: gi.centerprintf(activator, "Sequence completed!");
327: gi.sound (activator, CHAN_AUTO, gi.soundindex ("misc/talk1.wav"), 1, ATTN_NORM, 0);
328: }
329: self->activator = activator;
330: multi_trigger (self);
331: }
332:
333: void SP_trigger_counter (edict_t *self)
334: {
335: self->wait = -1;
336: if (!self->count)
337: self->count = 2;
338:
339: self->use = trigger_counter_use;
340: }
341:
342:
343: /*
344: ==============================================================================
345:
346: trigger_always
347:
348: ==============================================================================
349: */
350:
351: /*QUAKED trigger_always (.5 .5 .5) (-8 -8 -8) (8 8 8)
352: This trigger will always fire. It is activated by the world.
353: */
354: void SP_trigger_always (edict_t *ent)
355: {
356: // we must have some delay to make sure our use targets are present
357: if (ent->delay < 0.2)
358: ent->delay = 0.2;
359: G_UseTargets(ent, ent);
360: }
361:
362:
363: /*
364: ==============================================================================
365:
366: trigger_push
367:
368: ==============================================================================
369: */
370: #if 0
371: #define PUSH_ONCE 1
372:
373: static int windsound;
374:
375: void trigger_push_touch (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf)
376: {
377: if (strcmp(other->classname, "grenade") == 0)
378: {
379: VectorScale (self->movedir, self->speed * 10, other->velocity);
380: }
381: else if (other->health > 0)
382: {
383: VectorScale (self->movedir, self->speed * 10, other->velocity);
384:
385: if (other->client)
386: {
387: // don't take falling damage immediately from this
388: VectorCopy (other->velocity, other->client->oldvelocity);
389: if (other->fly_sound_debounce_time < level.time)
390: {
391: other->fly_sound_debounce_time = level.time + 1.5;
392: gi.sound (other, CHAN_AUTO, windsound, 1, ATTN_NORM, 0);
393: }
394: }
395: }
396: if (self->spawnflags & PUSH_ONCE)
397: G_FreeEdict (self);
398: }
399:
400: void SP_trigger_push (edict_t *self)
401: {
402: InitTrigger (self);
403: windsound = gi.soundindex ("misc/windfly.wav");
404: self->touch = trigger_push_touch;
405: if (!self->speed)
406: self->speed = 1000;
407: gi.linkentity (self);
408: }
409: #endif
410:
411: // RAFAEL
412: #define PUSH_ONCE 1
413:
414: static int windsound;
415:
416: void trigger_push_touch (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf)
417: {
418: if (strcmp(other->classname, "grenade") == 0)
419: {
420: VectorScale (self->movedir, self->speed * 10, other->velocity);
421: }
422: else if (other->health > 0)
423: {
424: VectorScale (self->movedir, self->speed * 10, other->velocity);
425:
426: if (other->client)
427: {
428: // don't take falling damage immediately from this
429: VectorCopy (other->velocity, other->client->oldvelocity);
430: if (other->fly_sound_debounce_time < level.time)
431: {
432: other->fly_sound_debounce_time = level.time + 1.5;
433: gi.sound (other, CHAN_AUTO, windsound, 1, ATTN_NORM, 0);
434: }
435: }
436: }
437: if (self->spawnflags & PUSH_ONCE)
438: G_FreeEdict (self);
439: }
440:
441:
442: /*QUAKED trigger_push (.5 .5 .5) ? PUSH_ONCE PUSH_PLUS PUSH_RAMP
443: Pushes the player
444: "speed" defaults to 1000
445: "wait" defaults to 10 must use PUSH_PLUS used for on
446: */
447:
448: void trigger_push_active (edict_t *self);
449:
450: void trigger_effect (edict_t *self)
451: {
452: vec3_t origin;
453: vec3_t size;
454: int i;
455:
456: VectorScale (self->size, 0.5, size);
457: VectorAdd (self->absmin, size, origin);
458:
459: for (i=0; i<10; i++)
460: {
461: origin[2] += (self->speed * 0.01) * (i + random());
462: gi.WriteByte (svc_temp_entity);
463: gi.WriteByte (TE_TUNNEL_SPARKS);
464: gi.WriteByte (1);
465: gi.WritePosition (origin);
466: gi.WriteDir (vec3_origin);
467: gi.WriteByte (0x74 + (rand()&7));
468: gi.multicast (self->s.origin, MULTICAST_PVS);
469: }
470:
471: }
472:
473: void trigger_push_inactive (edict_t *self)
474: {
475: if (self->delay > level.time)
476: {
477: self->nextthink = level.time + 0.1;
478: }
479: else
480: {
481: self->touch = trigger_push_touch;
482: self->think = trigger_push_active;
483: self->nextthink = level.time + 0.1;
484: self->delay = self->nextthink + self->wait;
485: }
486: }
487:
488: void trigger_push_active (edict_t *self)
489: {
490: if (self->delay > level.time)
491: {
492: self->nextthink = level.time + 0.1;
493: trigger_effect (self);
494: }
495: else
496: {
497: self->touch = NULL;
498: self->think = trigger_push_inactive;
499: self->nextthink = level.time + 0.1;
500: self->delay = self->nextthink + self->wait;
501: }
502: }
503:
504: void SP_trigger_push (edict_t *self)
505: {
506: InitTrigger (self);
507: windsound = gi.soundindex ("misc/windfly.wav");
508: self->touch = trigger_push_touch;
509:
510: if (self->spawnflags & 2)
511: {
512: if (!self->wait)
513: self->wait = 10;
514:
515: self->think = trigger_push_active;
516: self->nextthink = level.time + 0.1;
517: self->delay = self->nextthink + self->wait;
518: }
519:
520: if (!self->speed)
521: self->speed = 1000;
522:
523: gi.linkentity (self);
524:
525: }
526:
527: /*
528: ==============================================================================
529:
530: trigger_hurt
531:
532: ==============================================================================
533: */
534:
535: /*QUAKED trigger_hurt (.5 .5 .5) ? START_OFF TOGGLE SILENT NO_PROTECTION SLOW
536: Any entity that touches this will be hurt.
537:
538: It does dmg points of damage each server frame
539:
540: SILENT supresses playing the sound
541: SLOW changes the damage rate to once per second
542: NO_PROTECTION *nothing* stops the damage
543:
544: "dmg" default 5 (whole numbers only)
545:
546: */
547: void hurt_use (edict_t *self, edict_t *other, edict_t *activator)
548: {
549: if (self->solid == SOLID_NOT)
550: self->solid = SOLID_TRIGGER;
551: else
552: self->solid = SOLID_NOT;
553: gi.linkentity (self);
554:
555: if (!(self->spawnflags & 2))
556: self->use = NULL;
557: }
558:
559:
560: void hurt_touch (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf)
561: {
562: int dflags;
563:
564: if (!other->takedamage)
565: return;
566:
567: if (self->timestamp > level.time)
568: return;
569:
570: if (self->spawnflags & 16)
571: self->timestamp = level.time + 1;
572: else
573: self->timestamp = level.time + FRAMETIME;
574:
575: if (!(self->spawnflags & 4))
576: {
577: if ((level.framenum % 10) == 0)
578: gi.sound (other, CHAN_AUTO, self->noise_index, 1, ATTN_NORM, 0);
579: }
580:
581: if (self->spawnflags & 8)
582: dflags = DAMAGE_NO_PROTECTION;
583: else
584: dflags = 0;
585: T_Damage (other, self, self, vec3_origin, other->s.origin, vec3_origin, self->dmg, self->dmg, dflags, MOD_TRIGGER_HURT);
586: }
587:
588: void SP_trigger_hurt (edict_t *self)
589: {
590: InitTrigger (self);
591:
592: self->noise_index = gi.soundindex ("world/electro.wav");
593: self->touch = hurt_touch;
594:
595: if (!self->dmg)
596: self->dmg = 5;
597:
598: if (self->spawnflags & 1)
599: self->solid = SOLID_NOT;
600: else
601: self->solid = SOLID_TRIGGER;
602:
603: if (self->spawnflags & 2)
604: self->use = hurt_use;
605:
606: gi.linkentity (self);
607: }
608:
609:
610: /*
611: ==============================================================================
612:
613: trigger_gravity
614:
615: ==============================================================================
616: */
617:
618: /*QUAKED trigger_gravity (.5 .5 .5) ?
619: Changes the touching entites gravity to
620: the value of "gravity". 1.0 is standard
621: gravity for the level.
622: */
623:
624: void trigger_gravity_touch (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf)
625: {
626: other->gravity = self->gravity;
627: }
628:
629: void SP_trigger_gravity (edict_t *self)
630: {
631: if (st.gravity == 0)
632: {
633: gi.dprintf("trigger_gravity without gravity set at %s\n", vtos(self->s.origin));
634: G_FreeEdict (self);
635: return;
636: }
637:
638: InitTrigger (self);
639: self->gravity = atoi(st.gravity);
640: self->touch = trigger_gravity_touch;
641: }
642:
643:
644: /*
645: ==============================================================================
646:
647: trigger_monsterjump
648:
649: ==============================================================================
650: */
651:
652: /*QUAKED trigger_monsterjump (.5 .5 .5) ?
653: Walking monsters that touch this will jump in the direction of the trigger's angle
654: "speed" default to 200, the speed thrown forward
655: "height" default to 200, the speed thrown upwards
656: */
657:
658: void trigger_monsterjump_touch (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf)
659: {
660: if (other->flags & (FL_FLY | FL_SWIM) )
661: return;
662: if (other->svflags & SVF_DEADMONSTER)
663: return;
664: if ( !(other->svflags & SVF_MONSTER))
665: return;
666:
667: // set XY even if not on ground, so the jump will clear lips
668: other->velocity[0] = self->movedir[0] * self->speed;
669: other->velocity[1] = self->movedir[1] * self->speed;
670:
671: if (!other->groundentity)
672: return;
673:
674: other->groundentity = NULL;
675: other->velocity[2] = self->movedir[2];
676: }
677:
678: void SP_trigger_monsterjump (edict_t *self)
679: {
680: if (!self->speed)
681: self->speed = 200;
682: if (!st.height)
683: st.height = 200;
684: if (self->s.angles[YAW] == 0)
685: self->s.angles[YAW] = 360;
686: InitTrigger (self);
687: self->touch = trigger_monsterjump_touch;
688: self->movedir[2] = st.height;
689: }
690:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.