6 activator = self.enemy;
12 ==============================
15 the global "activator" should be set to the entity that initiated the firing.
17 If self.delay is set, a DelayedUse entity will be created that will actually
18 do the SUB_UseTargets after that many seconds have passed.
20 Centerprints any self.message to the activator.
22 Removes all entities with a targetname that match self.killtarget,
23 and removes them, so some events can remove other triggers.
25 Search for (string)targetname in all entities that
26 match (string)self.target and call their .use function
28 ==============================
30 void() SUB_UseTargets =
32 local entity t, stemp, otemp, act;
39 // create a temp object to fire at a later time
41 t.classname = "DelayedUse";
42 t.nextthink = time + self.delay;
45 t.message = self.message;
46 t.killtarget = self.killtarget;
47 t.target = self.target;
55 if (activator.classname == "player" && self.message != "")
57 centerprint (activator, self.message);
59 sound (activator, CHAN_VOICE, "misc/talk.wav", 1, ATTN_NORM);
63 // kill the killtagets
70 t = find (t, targetname, self.killtarget);
86 t = find (t, targetname, self.target);
106 entity stemp, otemp, s, old;
109 void() trigger_reactivate =
111 self.solid = SOLID_TRIGGER;
114 //=============================================================================
116 float SPAWNFLAG_NOMESSAGE = 1;
117 float SPAWNFLAG_NOTOUCH = 1;
119 // the wait time has passed, so set back up for another activation
124 self.health = self.max_health;
125 self.takedamage = DAMAGE_YES;
126 self.solid = SOLID_BBOX;
131 // the trigger was just touched/killed/used
132 // self.enemy should be set to the activator so it can be held through a delay
133 // so wait for the delay time before firing
134 void() multi_trigger =
136 if (self.nextthink > time)
138 return; // allready been triggered
141 if (self.classname == "trigger_secret")
143 if (self.enemy.classname != "player")
145 found_secrets = found_secrets + 1;
146 WriteByte (MSG_ALL, SVC_FOUNDSECRET);
150 sound (self, CHAN_VOICE, self.noise, 1, ATTN_NORM);
152 // don't trigger again until reset
153 self.takedamage = DAMAGE_NO;
155 activator = self.enemy;
161 self.think = multi_wait;
162 self.nextthink = time + self.wait;
165 { // we can't just remove (self) here, because this is a touch function
166 // called wheil C code is looping through area links...
167 self.touch = nullfunction;
169 self.nextthink = time + 0.1;
170 self.think = SUB_Remove;
176 self.enemy = activator;
182 if (other.classname != "player")
185 // if the trigger has an angles field, check player's facing direction
186 if (self.movedir != '0 0 0')
188 makevectors (other.angles);
189 if (v_forward * self.movedir < 0)
190 return; // not facing the right way
197 void multi_eventdamage (vector hitloc, float damage, entity inflictor, entity attacker, float deathtype)
199 if (!self.takedamage)
201 self.health = self.health - damage;
202 if (self.health <= 0)
204 self.enemy = attacker;
209 /*QUAKED trigger_multiple (.5 .5 .5) ? notouch
210 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.
211 If "delay" is set, the trigger waits some time after activating before firing.
212 "wait" : Seconds between triggerings. (.2 default)
213 If notouch is set, the trigger is only fired by other entities, not by touching.
214 NOTOUCH has been obsoleted by trigger_relay!
220 set "message" to text string
222 void() trigger_multiple =
224 if (self.sounds == 1)
226 precache_sound ("misc/secret.wav");
227 self.noise = "misc/secret.wav";
229 else if (self.sounds == 2)
231 precache_sound ("misc/talk.wav");
232 self.noise = "misc/talk.wav";
234 else if (self.sounds == 3)
236 precache_sound ("misc/trigger1.wav");
237 self.noise = "misc/trigger1.wav";
242 self.use = multi_use;
248 if (self.spawnflags & SPAWNFLAG_NOTOUCH)
249 objerror ("health and notouch don't make sense\n");
250 self.max_health = self.health;
251 self.event_damage = multi_eventdamage;
252 self.takedamage = DAMAGE_YES;
253 self.solid = SOLID_BBOX;
254 setorigin (self, self.origin); // make sure it links into the world
258 if ( !(self.spawnflags & SPAWNFLAG_NOTOUCH) )
260 self.touch = multi_touch;
266 /*QUAKED trigger_once (.5 .5 .5) ? notouch
267 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
268 "targetname". If "health" is set, the trigger must be killed to activate.
269 If notouch is set, the trigger is only fired by other entities, not by touching.
270 if "killtarget" is set, any objects that have a matching "target" will be removed when the trigger is fired.
271 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.
277 set "message" to text string
279 void() trigger_once =
285 //=============================================================================
287 /*QUAKED trigger_relay (.5 .5 .5) (-8 -8 -8) (8 8 8)
288 This fixed size trigger cannot be touched, it can only be fired by other events. It can contain killtargets, targets, delays, and messages.
290 void() trigger_relay =
292 self.use = SUB_UseTargets;
296 //=============================================================================
303 self.count = self.count - 1;
309 if (activator.classname == "player"
310 && (self.spawnflags & SPAWNFLAG_NOMESSAGE) == 0)
313 centerprint (activator, "There are more to go...");
314 else if (self.count == 3)
315 centerprint (activator, "Only 3 more to go...");
316 else if (self.count == 2)
317 centerprint (activator, "Only 2 more to go...");
319 centerprint (activator, "Only 1 more to go...");
324 if (activator.classname == "player"
325 && (self.spawnflags & SPAWNFLAG_NOMESSAGE) == 0)
326 centerprint(activator, "Sequence completed!");
327 self.enemy = activator;
331 /*QUAKED trigger_counter (.5 .5 .5) ? nomessage
332 Acts as an intermediary for an action that takes multiple inputs.
334 If nomessage is not set, t will print "1 more.. " etc when triggered and "sequence complete" when finished.
336 After the counter has been triggered "count" times (default 2), it will fire all of it's targets and remove itself.
338 void() trigger_counter =
344 self.use = counter_use;
349 self.solid = SOLID_TRIGGER;
355 self.solid = SOLID_NOT;
356 self.think = hurt_on;
357 self.nextthink = time + 1;
362 if (other.takedamage)
364 self.think = hurt_off;
365 self.nextthink = time;
366 Damage (other, self, self, self.dmg, DEATH_HURTTRIGGER, '0 0 0', '0 0 0');
372 /*QUAKED trigger_hurt (.5 .5 .5) ?
373 Any object touching this will be hurt
374 set dmg to damage amount
377 void() trigger_hurt =
380 self.touch = hurt_touch;
384 self.message = "was in the wrong place.";
387 //void() target_speaker_use = {sound(self, CHAN_VOICE, self.noise, 1, 1);}
388 //void() target_speaker = {self.use = target_speaker_use;}
390 void() target_speaker =
393 precache_sound (self.noise);
394 ambientsound (self.origin, self.noise, 1, ATTN_STATIC);
403 self.nextthink = time + 0.1;
405 if(random() < self.wait) {
406 te_spark(self.origin,'0 0 -1',self.cnt);
413 self.think = sparksthink;
414 self.nextthink = time + 0.2;
416 // self.cnt is the amount of sparks that one burst will spawn
418 self.cnt = 25.0; // nice default value
421 // self.wait is the probability that a sparkthink will spawn a spark shower
422 // range: 0 - 1, but 0 makes little sense, so...
423 if(self.wait < 0.05) {
424 self.wait = 0.25; // nice default value
429 precache_sound (self.noise);
430 ambientsound (self.origin, self.noise, 1, ATTN_STATIC);
437 =============================================================================
441 =============================================================================
444 void() fd_secret_move1;
445 void() fd_secret_move2;
446 void() fd_secret_move3;
447 void() fd_secret_move4;
448 void() fd_secret_move5;
449 void() fd_secret_move6;
450 void() fd_secret_done;
452 float SECRET_OPEN_ONCE = 1; // stays open
453 float SECRET_1ST_LEFT = 2; // 1st move is left of arrow
454 float SECRET_1ST_DOWN = 4; // 1st move is down from arrow
455 float SECRET_NO_SHOOT = 8; // only opened by trigger
456 float SECRET_YES_SHOOT = 16; // shootable even if targeted
459 void () fd_secret_use =
464 //self.havocattack = TRUE;
466 // exit if still moving around...
467 if (self.origin != self.oldorigin)
470 self.message = ""; // no more message
472 SUB_UseTargets(); // fire all targets / killtargets
474 self.velocity = '0 0 0';
476 // Make a sound, wait a little...
478 if (self.noise1 != "")
479 sound(self, CHAN_VOICE, self.noise1, 1, ATTN_NORM);
480 self.nextthink = self.ltime + 0.1;
482 temp = 1 - (self.spawnflags & SECRET_1ST_LEFT); // 1 or -1
483 makevectors(self.mangle);
487 if (self.spawnflags & SECRET_1ST_DOWN)
488 self.t_width = fabs(v_up * self.size);
490 self.t_width = fabs(v_right * self.size);
494 self.t_length = fabs(v_forward * self.size);
496 if (self.spawnflags & SECRET_1ST_DOWN)
497 self.dest1 = self.origin - v_up * self.t_width;
499 self.dest1 = self.origin + v_right * (self.t_width * temp);
501 self.dest2 = self.dest1 + v_forward * self.t_length;
502 SUB_CalcMove(self.dest1, self.speed, fd_secret_move1);
503 if (self.noise2 != "")
504 sound(self, CHAN_VOICE, self.noise2, 1, ATTN_NORM);
507 // Wait after first movement...
508 void () fd_secret_move1 =
510 self.nextthink = self.ltime + 1.0;
511 self.think = fd_secret_move2;
512 if (self.noise3 != "")
513 sound(self, CHAN_VOICE, self.noise3, 1, ATTN_NORM);
516 // Start moving sideways w/sound...
517 void () fd_secret_move2 =
519 if (self.noise2 != "")
520 sound(self, CHAN_VOICE, self.noise2, 1, ATTN_NORM);
521 SUB_CalcMove(self.dest2, self.speed, fd_secret_move3);
524 // Wait here until time to go back...
525 void () fd_secret_move3 =
527 if (self.noise3 != "")
528 sound(self, CHAN_VOICE, self.noise3, 1, ATTN_NORM);
529 if (!(self.spawnflags & SECRET_OPEN_ONCE))
531 self.nextthink = self.ltime + self.wait;
532 self.think = fd_secret_move4;
537 void () fd_secret_move4 =
539 if (self.noise2 != "")
540 sound(self, CHAN_VOICE, self.noise2, 1, ATTN_NORM);
541 SUB_CalcMove(self.dest1, self.speed, fd_secret_move5);
545 void () fd_secret_move5 =
547 self.nextthink = self.ltime + 1.0;
548 self.think = fd_secret_move6;
549 if (self.noise3 != "")
550 sound(self, CHAN_VOICE, self.noise3, 1, ATTN_NORM);
553 void () fd_secret_move6 =
555 if (self.noise2 != "")
556 sound(self, CHAN_VOICE, self.noise2, 1, ATTN_NORM);
557 SUB_CalcMove(self.oldorigin, self.speed, fd_secret_done);
560 void () fd_secret_done =
562 if (!self.targetname || self.spawnflags&SECRET_YES_SHOOT)
565 self.takedamage = DAMAGE_YES;
566 //self.th_pain = fd_secret_use;
568 if (self.noise3 != "")
569 sound(self, CHAN_VOICE, self.noise3, 1, ATTN_NORM);
572 void () secret_blocked =
574 if (time < self.attack_finished)
576 self.attack_finished = time + 0.5;
577 //T_Damage (other, self, self, self.dmg, self.dmg, self.deathtype, DT_IMPACT, (self.absmin + self.absmax) * 0.5, '0 0 0', Obituary_Generic);
587 void() secret_touch =
589 if (activator.classname != "player")
591 if (self.attack_finished > time)
594 self.attack_finished = time + 2;
598 if (other.flags & FL_CLIENT)
599 centerprint (other, self.message);
600 sound (other, CHAN_BODY, "misc/talk.wav", 1, ATTN_NORM);
605 /*QUAKED func_door_secret (0 .5 .8) ? open_once 1st_left 1st_down no_shoot always_shoot
606 Basic secret door. Slides back, then to the side. Angle determines direction.
607 wait = # of seconds before coming back
608 1st_left = 1st move is left of arrow
609 1st_down = 1st move is down from arrow
610 always_shoot = even if targeted, keep shootable
611 t_width = override WIDTH to move back (or height if going down)
612 t_length = override LENGTH to move sideways
613 "dmg" damage to inflict when blocked (2 default)
615 If a secret door has a targetname, it will only be opened by it's botton or trigger, not by damage.
622 void () func_door_secret =
624 /*if (!self.deathtype) // map makers can override this
625 self.deathtype = " got in the way";*/
631 self.mangle = self.angles;
632 self.angles = '0 0 0';
633 self.solid = SOLID_BSP;
634 self.movetype = MOVETYPE_PUSH;
635 self.classname = "door";
636 setmodel (self, self.model);
637 setorigin (self, self.origin);
639 self.touch = secret_touch;
640 self.blocked = secret_blocked;
642 self.use = fd_secret_use;
643 if ( !self.targetname || self.spawnflags&SECRET_YES_SHOOT)
646 self.takedamage = DAMAGE_YES;
647 self.event_damage = fd_secret_use;
649 self.oldorigin = self.origin;
651 self.wait = 5; // 5 seconds before closing