|
|
1.1 root 1:
2: entity stemp, otemp, s, old;
3:
4:
5: void() trigger_reactivate =
6: {
7: self.solid = SOLID_TRIGGER;
8: };
9:
10: //=============================================================================
11:
12: float SPAWNFLAG_NOMESSAGE = 1;
13: float SPAWNFLAG_NOTOUCH = 1;
14:
15: // the wait time has passed, so set back up for another activation
16: void() multi_wait =
17: {
18: if (self.max_health)
19: {
20: self.health = self.max_health;
21: self.takedamage = DAMAGE_YES;
22: self.solid = SOLID_BBOX;
23: }
24: };
25:
26:
27: // the trigger was just touched/killed/used
28: // self.enemy should be set to the activator so it can be held through a delay
29: // so wait for the delay time before firing
30: void() multi_trigger =
31: {
32: if (self.nextthink > time)
33: {
34: return; // allready been triggered
35: }
36:
37: if (self.classname == "trigger_secret")
38: {
39: if (self.enemy.classname != "player")
40: return;
41: found_secrets = found_secrets + 1;
42: WriteByte (MSG_ALL, SVC_FOUNDSECRET);
43: }
44:
45: if (self.noise)
46: sound (self, CHAN_VOICE, self.noise, 1, ATTN_NORM);
47:
48: // don't trigger again until reset
49: self.takedamage = DAMAGE_NO;
50:
51: activator = self.enemy;
52:
53: SUB_UseTargets();
54:
55: if (self.wait > 0)
56: {
57: self.think = multi_wait;
58: self.nextthink = time + self.wait;
59: }
60: else
61: { // we can't just remove (self) here, because this is a touch function
62: // called wheil C code is looping through area links...
63: self.touch = SUB_Null;
64: self.nextthink = time + 0.1;
65: self.think = SUB_Remove;
66: }
67: };
68:
69: void() multi_killed =
70: {
71: self.enemy = damage_attacker;
72: multi_trigger();
73: };
74:
75: void() multi_use =
76: {
77: self.enemy = activator;
78: multi_trigger();
79: };
80:
81: void() multi_touch =
82: {
83: if (other.classname != "player")
84: return;
85:
86: // if the trigger has an angles field, check player's facing direction
87: if (self.movedir != '0 0 0')
88: {
89: makevectors (other.angles);
90: if (v_forward * self.movedir < 0)
91: return; // not facing the right way
92: }
93:
94: self.enemy = other;
95: multi_trigger ();
96: };
97:
98: /*QUAKED trigger_multiple (.5 .5 .5) ? notouch
99: Variable sized repeatable trigger. Must be targeted at one or more entities. If "health" is set, the trigger must be killed to activate each time.
100: If "delay" is set, the trigger waits some time after activating before firing.
101: "wait" : Seconds between triggerings. (.2 default)
102: If notouch is set, the trigger is only fired by other entities, not by touching.
103: NOTOUCH has been obsoleted by trigger_relay!
104: sounds
105: 1) secret
106: 2) beep beep
107: 3) large switch
108: 4)
109: set "message" to text string
110: */
111: void() trigger_multiple =
112: {
113: if (self.sounds == 1)
114: {
115: precache_sound ("misc/secret.wav");
116: self.noise = "misc/secret.wav";
117: }
118: else if (self.sounds == 2)
119: {
120: precache_sound ("misc/talk.wav");
121: self.noise = "misc/talk.wav";
122: }
123: else if (self.sounds == 3)
124: {
125: precache_sound ("misc/trigger1.wav");
126: self.noise = "misc/trigger1.wav";
127: }
128:
129: if (!self.wait)
130: self.wait = 0.2;
131: self.use = multi_use;
132:
133: InitTrigger ();
134:
135: if (self.health)
136: {
137: if (self.spawnflags & SPAWNFLAG_NOTOUCH)
138: objerror ("health and notouch don't make sense\n");
139: self.max_health = self.health;
140: self.th_die = multi_killed;
141: self.takedamage = DAMAGE_YES;
142: self.solid = SOLID_BBOX;
143: setorigin (self, self.origin); // make sure it links into the world
144: }
145: else
146: {
147: if ( !(self.spawnflags & SPAWNFLAG_NOTOUCH) )
148: {
149: self.touch = multi_touch;
150: }
151: }
152: };
153:
154:
155: /*QUAKED trigger_once (.5 .5 .5) ? notouch
156: Variable sized trigger. Triggers once, then removes itself. You must set the key "target" to the name of another object in the level that has a matching
157: "targetname". If "health" is set, the trigger must be killed to activate.
158: If notouch is set, the trigger is only fired by other entities, not by touching.
159: if "killtarget" is set, any objects that have a matching "target" will be removed when the trigger is fired.
160: if "angle" is set, the trigger will only fire when someone is facing the direction of the angle. Use "360" for an angle of 0.
161: sounds
162: 1) secret
163: 2) beep beep
164: 3) large switch
165: 4)
166: set "message" to text string
167: */
168: void() trigger_once =
169: {
170: self.wait = -1;
171: trigger_multiple();
172: };
173:
174: //=============================================================================
175:
176: /*QUAKED trigger_relay (.5 .5 .5) (-8 -8 -8) (8 8 8)
177: This fixed size trigger cannot be touched, it can only be fired by other events. It can contain killtargets, targets, delays, and messages.
178: */
179: void() trigger_relay =
180: {
181: self.use = SUB_UseTargets;
182: };
183:
184:
185: //=============================================================================
186:
187: /*QUAKED trigger_secret (.5 .5 .5) ?
188: secret counter trigger
189: sounds
190: 1) secret
191: 2) beep beep
192: 3)
193: 4)
194: set "message" to text string
195: */
196: void() trigger_secret =
197: {
198: total_secrets = total_secrets + 1;
199: self.wait = -1;
200: if (!self.message)
201: self.message = "You found a secret area!";
202: if (!self.sounds)
203: self.sounds = 1;
204:
205: if (self.sounds == 1)
206: {
207: precache_sound ("misc/secret.wav");
208: self.noise = "misc/secret.wav";
209: }
210: else if (self.sounds == 2)
211: {
212: precache_sound ("misc/talk.wav");
213: self.noise = "misc/talk.wav";
214: }
215:
216: trigger_multiple ();
217: };
218:
219: //=============================================================================
220:
221:
222: void() counter_use =
223: {
224: local string junk;
225:
226: self.count = self.count - 1;
227: if (self.count < 0)
228: return;
229:
230: if (self.count != 0)
231: {
232: if (activator.classname == "player"
233: && (self.spawnflags & SPAWNFLAG_NOMESSAGE) == 0)
234: {
235: if (self.count >= 4)
236: centerprint (activator, "There are more to go...");
237: else if (self.count == 3)
238: centerprint (activator, "Only 3 more to go...");
239: else if (self.count == 2)
240: centerprint (activator, "Only 2 more to go...");
241: else
242: centerprint (activator, "Only 1 more to go...");
243: }
244: return;
245: }
246:
247: if (activator.classname == "player"
248: && (self.spawnflags & SPAWNFLAG_NOMESSAGE) == 0)
249: centerprint(activator, "Sequence completed!");
250: self.enemy = activator;
251: multi_trigger ();
252: };
253:
254: /*QUAKED trigger_counter (.5 .5 .5) ? nomessage
255: Acts as an intermediary for an action that takes multiple inputs.
256:
257: If nomessage is not set, t will print "1 more.. " etc when triggered and "sequence complete" when finished.
258:
259: After the counter has been triggered "count" times (default 2), it will fire all of it's targets and remove itself.
260: */
261: void() trigger_counter =
262: {
263: self.wait = -1;
264: if (!self.count)
265: self.count = 2;
266:
267: self.use = counter_use;
268: };
269:
270:
271: /*
272: ==============================================================================
273:
274: TELEPORT TRIGGERS
275:
276: ==============================================================================
277: */
278:
279: float PLAYER_ONLY = 1;
280: float SILENT = 2;
281:
282: void() play_teleport =
283: {
284: local float v;
285: local string tmpstr;
286:
287: v = random() * 5;
288: if (v < 1)
289: tmpstr = "misc/r_tele1.wav";
290: else if (v < 2)
291: tmpstr = "misc/r_tele2.wav";
292: else if (v < 3)
293: tmpstr = "misc/r_tele3.wav";
294: else if (v < 4)
295: tmpstr = "misc/r_tele4.wav";
296: else
297: tmpstr = "misc/r_tele5.wav";
298:
299: sound (self, CHAN_VOICE, tmpstr, 1, ATTN_NORM);
300: remove (self);
301: };
302:
303: void(vector org) spawn_tfog =
304: {
305: s = spawn ();
306: s.origin = org;
307: s.nextthink = time + 0.2;
308: s.think = play_teleport;
309:
310: WriteByte (MSG_MULTICAST, SVC_TEMPENTITY);
311: WriteByte (MSG_MULTICAST, TE_TELEPORT);
312: WriteCoord (MSG_MULTICAST, org_x);
313: WriteCoord (MSG_MULTICAST, org_y);
314: WriteCoord (MSG_MULTICAST, org_z);
315: multicast (org, MULTICAST_PHS);
316: };
317:
318:
319: void() tdeath_touch =
320: {
321: local entity other2;
322:
323: if (other == self.owner)
324: return;
325:
326: // frag anyone who teleports in on top of an invincible player
327: if (other.classname == "player")
328: {
329: if (other.invincible_finished > time &&
330: self.owner.invincible_finished > time) {
331: self.classname = "teledeath3";
332: other.invincible_finished = 0;
333: self.owner.invincible_finished = 0;
334: T_Damage (other, self, self, 50000);
335: other2 = self.owner;
336: self.owner = other;
337: T_Damage (other2, self, self, 50000);
338: }
339:
340: if (other.invincible_finished > time)
341: {
342: self.classname = "teledeath2";
343: T_Damage (self.owner, self, self, 50000);
344: return;
345: }
346:
347: }
348:
349: if (other.health)
350: {
351: T_Damage (other, self, self, 50000);
352: }
353: };
354:
355:
356: void(vector org, entity death_owner) spawn_tdeath =
357: {
358: local entity death;
359:
360: death = spawn();
361: death.classname = "teledeath";
362: death.movetype = MOVETYPE_NONE;
363: death.solid = SOLID_TRIGGER;
364: death.angles = '0 0 0';
365: setsize (death, death_owner.mins - '1 1 1', death_owner.maxs + '1 1 1');
366: setorigin (death, org);
367: death.touch = tdeath_touch;
368: death.nextthink = time + 0.2;
369: death.think = SUB_Remove;
370: death.owner = death_owner;
371:
372: force_retouch = 2; // make sure even still objects get hit
373: };
374:
375: void() teleport_touch =
376: {
377: local entity t;
378: local vector org;
379:
380: if (self.targetname)
381: {
382: if (self.nextthink < time)
383: {
384: return; // not fired yet
385: }
386: }
387:
388: if (self.spawnflags & PLAYER_ONLY)
389: {
390: if (other.classname != "player")
391: return;
392: }
393:
394: // only teleport living creatures
395: if (other.health <= 0 || other.solid != SOLID_SLIDEBOX)
396: return;
397:
398: SUB_UseTargets ();
399:
400: // put a tfog where the player was
401: spawn_tfog (other.origin);
402:
403: t = find (world, targetname, self.target);
404: if (!t)
405: objerror ("couldn't find target");
406:
407: // spawn a tfog flash in front of the destination
408: makevectors (t.mangle);
409: org = t.origin + 32 * v_forward;
410:
411: spawn_tfog (org);
412: spawn_tdeath(t.origin, other);
413:
414: // move the player and lock him down for a little while
415: if (!other.health)
416: {
417: other.origin = t.origin;
418: other.velocity = (v_forward * other.velocity_x) + (v_forward * other.velocity_y);
419: return;
420: }
421:
422: setorigin (other, t.origin);
423: other.angles = t.mangle;
424: if (other.classname == "player")
425: {
426: other.fixangle = 1; // turn this way immediately
427: other.teleport_time = time + 0.7;
428: if (other.flags & FL_ONGROUND)
429: other.flags = other.flags - FL_ONGROUND;
430: other.velocity = v_forward * 300;
431: }
432: other.flags = other.flags - other.flags & FL_ONGROUND;
433: };
434:
435: /*QUAKED info_teleport_destination (.5 .5 .5) (-8 -8 -8) (8 8 32)
436: This is the destination marker for a teleporter. It should have a "targetname" field with the same value as a teleporter's "target" field.
437: */
438: void() info_teleport_destination =
439: {
440: // this does nothing, just serves as a target spot
441: self.mangle = self.angles;
442: self.angles = '0 0 0';
443: self.model = "";
444: self.origin = self.origin + '0 0 27';
445: if (!self.targetname)
446: objerror ("no targetname");
447: };
448:
449: void() teleport_use =
450: {
451: self.nextthink = time + 0.2;
452: force_retouch = 2; // make sure even still objects get hit
453: self.think = SUB_Null;
454: };
455:
456: /*QUAKED trigger_teleport (.5 .5 .5) ? PLAYER_ONLY SILENT
457: Any object touching this will be transported to the corresponding info_teleport_destination entity. You must set the "target" field, and create an object with a "targetname" field that matches.
458:
459: If the trigger_teleport has a targetname, it will only teleport entities when it has been fired.
460: */
461: void() trigger_teleport =
462: {
463: local vector o;
464:
465: InitTrigger ();
466: self.touch = teleport_touch;
467: // find the destination
468: if (!self.target)
469: objerror ("no target");
470: self.use = teleport_use;
471:
472: if (!(self.spawnflags & SILENT))
473: {
474: precache_sound ("ambience/hum1.wav");
475: o = (self.mins + self.maxs)*0.5;
476: ambientsound (o, "ambience/hum1.wav",0.5 , ATTN_STATIC);
477: }
478: };
479:
480: /*
481: ==============================================================================
482:
483: trigger_setskill
484:
485: ==============================================================================
486: */
487:
488: /*QUAKED trigger_setskill (.5 .5 .5) ?
489: sets skill level to the value of "message".
490: Only used on start map.
491: */
492: void() trigger_setskill =
493: {
494: remove (self);
495: };
496:
497:
498: /*
499: ==============================================================================
500:
501: ONLY REGISTERED TRIGGERS
502:
503: ==============================================================================
504: */
505:
506: void() trigger_onlyregistered_touch =
507: {
508: if (other.classname != "player")
509: return;
510: if (self.attack_finished > time)
511: return;
512:
513: self.attack_finished = time + 2;
514: if (cvar("registered"))
515: {
516: self.message = "";
517: SUB_UseTargets ();
518: remove (self);
519: }
520: else
521: {
522: if (self.message != "")
523: {
524: centerprint (other, self.message);
525: sound (other, CHAN_BODY, "misc/talk.wav", 1, ATTN_NORM);
526: }
527: }
528: };
529:
530: /*QUAKED trigger_onlyregistered (.5 .5 .5) ?
531: Only fires if playing the registered version, otherwise prints the message
532: */
533: void() trigger_onlyregistered =
534: {
535: precache_sound ("misc/talk.wav");
536: InitTrigger ();
537: self.touch = trigger_onlyregistered_touch;
538: };
539:
540: //============================================================================
541:
542: void() hurt_on =
543: {
544: self.solid = SOLID_TRIGGER;
545: self.nextthink = -1;
546: };
547:
548: void() hurt_touch =
549: {
550: if (other.takedamage)
551: {
552: self.solid = SOLID_NOT;
553: T_Damage (other, self, self, self.dmg);
554: self.think = hurt_on;
555: self.nextthink = time + 1;
556: }
557:
558: return;
559: };
560:
561: /*QUAKED trigger_hurt (.5 .5 .5) ?
562: Any object touching this will be hurt
563: set dmg to damage amount
564: defalt dmg = 5
565: */
566: void() trigger_hurt =
567: {
568: InitTrigger ();
569: self.touch = hurt_touch;
570: if (!self.dmg)
571: self.dmg = 5;
572: };
573:
574: //============================================================================
575:
576: float PUSH_ONCE = 1;
577:
578: void() trigger_push_touch =
579: {
580: if (other.classname == "grenade")
581: other.velocity = self.speed * self.movedir * 10;
582: else if (other.health > 0)
583: {
584: other.velocity = self.speed * self.movedir * 10;
585: if (other.classname == "player")
586: {
587: if (other.fly_sound < time)
588: {
589: other.fly_sound = time + 1.5;
590: sound (other, CHAN_AUTO, "ambience/windfly.wav", 1, ATTN_NORM);
591: }
592: }
593: }
594: if (self.spawnflags & PUSH_ONCE)
595: remove(self);
596: };
597:
598:
599: /*QUAKED trigger_push (.5 .5 .5) ? PUSH_ONCE
600: Pushes the player
601: */
602: void() trigger_push =
603: {
604: InitTrigger ();
605: precache_sound ("ambience/windfly.wav");
606: self.touch = trigger_push_touch;
607: if (!self.speed)
608: self.speed = 1000;
609: };
610:
611: //============================================================================
612:
613: void() trigger_monsterjump_touch =
614: {
615: if ( other.flags & (FL_MONSTER | FL_FLY | FL_SWIM) != FL_MONSTER )
616: return;
617:
618: // set XY even if not on ground, so the jump will clear lips
619: other.velocity_x = self.movedir_x * self.speed;
620: other.velocity_y = self.movedir_y * self.speed;
621:
622: if ( !(other.flags & FL_ONGROUND) )
623: return;
624:
625: other.flags = other.flags - FL_ONGROUND;
626:
627: other.velocity_z = self.height;
628: };
629:
630: /*QUAKED trigger_monsterjump (.5 .5 .5) ?
631: Walking monsters that touch this will jump in the direction of the trigger's angle
632: "speed" default to 200, the speed thrown forward
633: "height" default to 200, the speed thrown upwards
634: */
635: void() trigger_monsterjump =
636: {
637: if (!self.speed)
638: self.speed = 200;
639: if (!self.height)
640: self.height = 200;
641: if (self.angles == '0 0 0')
642: self.angles = '0 360 0';
643: InitTrigger ();
644: self.touch = trigger_monsterjump_touch;
645: };
646:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.