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