|
|
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:
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:
401: /*QUAKED trigger_push (.5 .5 .5) ? PUSH_ONCE
402: Pushes the player
403: "speed" defaults to 1000
404: */
405: void SP_trigger_push (edict_t *self)
406: {
407: InitTrigger (self);
408: windsound = gi.soundindex ("misc/windfly.wav");
409: self->touch = trigger_push_touch;
410: if (!self->speed)
411: self->speed = 1000;
412: gi.linkentity (self);
413: }
414:
415:
416: /*
417: ==============================================================================
418:
419: trigger_hurt
420:
421: ==============================================================================
422: */
423:
424: /*QUAKED trigger_hurt (.5 .5 .5) ? START_OFF TOGGLE SILENT NO_PROTECTION SLOW
425: Any entity that touches this will be hurt.
426:
427: It does dmg points of damage each server frame
428:
429: SILENT supresses playing the sound
430: SLOW changes the damage rate to once per second
431: NO_PROTECTION *nothing* stops the damage
432:
433: "dmg" default 5 (whole numbers only)
434:
435: */
436: void hurt_use (edict_t *self, edict_t *other, edict_t *activator)
437: {
438: if (self->solid == SOLID_NOT)
439: self->solid = SOLID_TRIGGER;
440: else
441: self->solid = SOLID_NOT;
442: gi.linkentity (self);
443:
444: if (!(self->spawnflags & 2))
445: self->use = NULL;
446: }
447:
448:
449: void hurt_touch (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf)
450: {
451: int dflags;
452:
453: if (!other->takedamage)
454: return;
455:
456: if (self->timestamp > level.time)
457: return;
458:
459: if (self->spawnflags & 16)
460: self->timestamp = level.time + 1;
461: else
462: self->timestamp = level.time + FRAMETIME;
463:
464: if (!(self->spawnflags & 4))
465: {
466: if ((level.framenum % 10) == 0)
467: gi.sound (other, CHAN_AUTO, self->noise_index, 1, ATTN_NORM, 0);
468: }
469:
470: if (self->spawnflags & 8)
471: dflags = DAMAGE_NO_PROTECTION;
472: else
473: dflags = 0;
474: T_Damage (other, self, self, vec3_origin, other->s.origin, vec3_origin, self->dmg, self->dmg, dflags, MOD_TRIGGER_HURT);
475: }
476:
477: void SP_trigger_hurt (edict_t *self)
478: {
479: InitTrigger (self);
480:
481: self->noise_index = gi.soundindex ("world/electro.wav");
482: self->touch = hurt_touch;
483:
484: if (!self->dmg)
485: self->dmg = 5;
486:
487: if (self->spawnflags & 1)
488: self->solid = SOLID_NOT;
489: else
490: self->solid = SOLID_TRIGGER;
491:
492: if (self->spawnflags & 2)
493: self->use = hurt_use;
494:
495: gi.linkentity (self);
496: }
497:
498:
499: /*
500: ==============================================================================
501:
502: trigger_gravity
503:
504: ==============================================================================
505: */
506:
507: /*QUAKED trigger_gravity (.5 .5 .5) ?
508: Changes the touching entites gravity to
509: the value of "gravity". 1.0 is standard
510: gravity for the level.
511: */
512:
513: void trigger_gravity_touch (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf)
514: {
515: other->gravity = self->gravity;
516: }
517:
518: void SP_trigger_gravity (edict_t *self)
519: {
520: if (st.gravity == 0)
521: {
522: gi.dprintf("trigger_gravity without gravity set at %s\n", vtos(self->s.origin));
523: G_FreeEdict (self);
524: return;
525: }
526:
527: InitTrigger (self);
528: self->gravity = atoi(st.gravity);
529: self->touch = trigger_gravity_touch;
530: }
531:
532:
533: /*
534: ==============================================================================
535:
536: trigger_monsterjump
537:
538: ==============================================================================
539: */
540:
541: /*QUAKED trigger_monsterjump (.5 .5 .5) ?
542: Walking monsters that touch this will jump in the direction of the trigger's angle
543: "speed" default to 200, the speed thrown forward
544: "height" default to 200, the speed thrown upwards
545: */
546:
547: void trigger_monsterjump_touch (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf)
548: {
549: if (other->flags & (FL_FLY | FL_SWIM) )
550: return;
551: if (other->svflags & SVF_DEADMONSTER)
552: return;
553: if ( !(other->svflags & SVF_MONSTER))
554: return;
555:
556: // set XY even if not on ground, so the jump will clear lips
557: other->velocity[0] = self->movedir[0] * self->speed;
558: other->velocity[1] = self->movedir[1] * self->speed;
559:
560: if (!other->groundentity)
561: return;
562:
563: other->groundentity = NULL;
564: other->velocity[2] = self->movedir[2];
565: }
566:
567: void SP_trigger_monsterjump (edict_t *self)
568: {
569: if (!self->speed)
570: self->speed = 200;
571: if (!st.height)
572: st.height = 200;
573: if (self->s.angles[YAW] == 0)
574: self->s.angles[YAW] = 360;
575: InitTrigger (self);
576: self->touch = trigger_monsterjump_touch;
577: self->movedir[2] = st.height;
578: }
579:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.