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);
108 void() trigger_reactivate =
110 self.solid = SOLID_TRIGGER;
113 //=============================================================================
115 float SPAWNFLAG_NOMESSAGE = 1;
116 float SPAWNFLAG_NOTOUCH = 1;
118 // the wait time has passed, so set back up for another activation
123 self.health = self.max_health;
124 self.takedamage = DAMAGE_YES;
125 self.solid = SOLID_BBOX;
130 // the trigger was just touched/killed/used
131 // self.enemy should be set to the activator so it can be held through a delay
132 // so wait for the delay time before firing
133 void() multi_trigger =
135 if (self.nextthink > time)
137 return; // allready been triggered
140 if (self.classname == "trigger_secret")
142 if (self.enemy.classname != "player")
144 found_secrets = found_secrets + 1;
145 WriteByte (MSG_ALL, SVC_FOUNDSECRET);
149 sound (self, CHAN_VOICE, self.noise, 1, ATTN_NORM);
151 // don't trigger again until reset
152 self.takedamage = DAMAGE_NO;
154 activator = self.enemy;
160 self.think = multi_wait;
161 self.nextthink = time + self.wait;
164 { // we can't just remove (self) here, because this is a touch function
165 // called wheil C code is looping through area links...
166 self.touch = nullfunction;
168 self.nextthink = time + 0.1;
169 self.think = SUB_Remove;
175 self.enemy = activator;
181 if (other.classname != "player")
184 // if the trigger has an angles field, check player's facing direction
185 if (self.movedir != '0 0 0')
187 makevectors (other.angles);
188 if (v_forward * self.movedir < 0)
189 return; // not facing the right way
196 void multi_eventdamage (vector hitloc, float damage, entity inflictor, entity attacker, float deathtype)
198 if (!self.takedamage)
200 self.health = self.health - damage;
201 if (self.health <= 0)
203 self.enemy = attacker;
208 /*QUAKED trigger_multiple (.5 .5 .5) ? notouch
209 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.
210 If "delay" is set, the trigger waits some time after activating before firing.
211 "wait" : Seconds between triggerings. (.2 default)
212 If notouch is set, the trigger is only fired by other entities, not by touching.
213 NOTOUCH has been obsoleted by trigger_relay!
219 set "message" to text string
221 void() trigger_multiple =
223 if (self.sounds == 1)
225 precache_sound ("misc/secret.wav");
226 self.noise = "misc/secret.wav";
228 else if (self.sounds == 2)
230 precache_sound ("misc/talk.wav");
231 self.noise = "misc/talk.wav";
233 else if (self.sounds == 3)
235 precache_sound ("misc/trigger1.wav");
236 self.noise = "misc/trigger1.wav";
241 self.use = multi_use;
247 if (self.spawnflags & SPAWNFLAG_NOTOUCH)
248 objerror ("health and notouch don't make sense\n");
249 self.max_health = self.health;
250 self.event_damage = multi_eventdamage;
251 self.takedamage = DAMAGE_YES;
252 self.solid = SOLID_BBOX;
253 setorigin (self, self.origin); // make sure it links into the world
257 if ( !(self.spawnflags & SPAWNFLAG_NOTOUCH) )
259 self.touch = multi_touch;
265 /*QUAKED trigger_once (.5 .5 .5) ? notouch
266 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
267 "targetname". If "health" is set, the trigger must be killed to activate.
268 If notouch is set, the trigger is only fired by other entities, not by touching.
269 if "killtarget" is set, any objects that have a matching "target" will be removed when the trigger is fired.
270 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.
276 set "message" to text string
278 void() trigger_once =
284 //=============================================================================
286 /*QUAKED trigger_relay (.5 .5 .5) (-8 -8 -8) (8 8 8)
287 This fixed size trigger cannot be touched, it can only be fired by other events. It can contain killtargets, targets, delays, and messages.
289 void() trigger_relay =
291 self.use = SUB_UseTargets;
295 //=============================================================================
300 self.count = self.count - 1;
306 if (activator.classname == "player"
307 && (self.spawnflags & SPAWNFLAG_NOMESSAGE) == 0)
310 centerprint (activator, "There are more to go...");
311 else if (self.count == 3)
312 centerprint (activator, "Only 3 more to go...");
313 else if (self.count == 2)
314 centerprint (activator, "Only 2 more to go...");
316 centerprint (activator, "Only 1 more to go...");
321 if (activator.classname == "player"
322 && (self.spawnflags & SPAWNFLAG_NOMESSAGE) == 0)
323 centerprint(activator, "Sequence completed!");
324 self.enemy = activator;
328 /*QUAKED trigger_counter (.5 .5 .5) ? nomessage
329 Acts as an intermediary for an action that takes multiple inputs.
331 If nomessage is not set, t will print "1 more.. " etc when triggered and "sequence complete" when finished.
333 After the counter has been triggered "count" times (default 2), it will fire all of it's targets and remove itself.
335 void() trigger_counter =
341 self.use = counter_use;
344 .float triggerhurttime;
347 if (other.takedamage)
348 if (other.triggerhurttime < time)
350 other.triggerhurttime = time + 1;
351 Damage (other, self, self, self.dmg, DEATH_HURTTRIGGER, other.origin, '0 0 0');
357 /*QUAKED trigger_hurt (.5 .5 .5) ?
358 Any object touching this will be hurt
359 set dmg to damage amount
362 void() trigger_hurt =
365 self.touch = hurt_touch;
369 self.message = "was in the wrong place.";
372 //void() target_speaker_use = {sound(self, CHAN_VOICE, self.noise, 1, 1);}
373 //void() target_speaker = {self.use = target_speaker_use;}
375 void() target_speaker =
378 precache_sound (self.noise);
379 ambientsound (self.origin, self.noise, 1, ATTN_STATIC);
388 self.nextthink = time + 0.1;
390 if(random() < self.wait) {
391 te_spark(self.origin,'0 0 -1',self.cnt);
398 self.think = sparksthink;
399 self.nextthink = time + 0.2;
401 // self.cnt is the amount of sparks that one burst will spawn
403 self.cnt = 25.0; // nice default value
406 // self.wait is the probability that a sparkthink will spawn a spark shower
407 // range: 0 - 1, but 0 makes little sense, so...
408 if(self.wait < 0.05) {
409 self.wait = 0.25; // nice default value
414 precache_sound (self.noise);
415 ambientsound (self.origin, self.noise, 1, ATTN_STATIC);
422 =============================================================================
426 =============================================================================
429 void() fd_secret_move1;
430 void() fd_secret_move2;
431 void() fd_secret_move3;
432 void() fd_secret_move4;
433 void() fd_secret_move5;
434 void() fd_secret_move6;
435 void() fd_secret_done;
437 float SECRET_OPEN_ONCE = 1; // stays open
438 float SECRET_1ST_LEFT = 2; // 1st move is left of arrow
439 float SECRET_1ST_DOWN = 4; // 1st move is down from arrow
440 float SECRET_NO_SHOOT = 8; // only opened by trigger
441 float SECRET_YES_SHOOT = 16; // shootable even if targeted
444 void () fd_secret_use =
449 //self.havocattack = TRUE;
451 // exit if still moving around...
452 if (self.origin != self.oldorigin)
455 self.message = ""; // no more message
457 SUB_UseTargets(); // fire all targets / killtargets
459 self.velocity = '0 0 0';
461 // Make a sound, wait a little...
463 if (self.noise1 != "")
464 sound(self, CHAN_VOICE, self.noise1, 1, ATTN_NORM);
465 self.nextthink = self.ltime + 0.1;
467 temp = 1 - (self.spawnflags & SECRET_1ST_LEFT); // 1 or -1
468 makevectors(self.mangle);
472 if (self.spawnflags & SECRET_1ST_DOWN)
473 self.t_width = fabs(v_up * self.size);
475 self.t_width = fabs(v_right * self.size);
479 self.t_length = fabs(v_forward * self.size);
481 if (self.spawnflags & SECRET_1ST_DOWN)
482 self.dest1 = self.origin - v_up * self.t_width;
484 self.dest1 = self.origin + v_right * (self.t_width * temp);
486 self.dest2 = self.dest1 + v_forward * self.t_length;
487 SUB_CalcMove(self.dest1, self.speed, fd_secret_move1);
488 if (self.noise2 != "")
489 sound(self, CHAN_VOICE, self.noise2, 1, ATTN_NORM);
492 // Wait after first movement...
493 void () fd_secret_move1 =
495 self.nextthink = self.ltime + 1.0;
496 self.think = fd_secret_move2;
497 if (self.noise3 != "")
498 sound(self, CHAN_VOICE, self.noise3, 1, ATTN_NORM);
501 // Start moving sideways w/sound...
502 void () fd_secret_move2 =
504 if (self.noise2 != "")
505 sound(self, CHAN_VOICE, self.noise2, 1, ATTN_NORM);
506 SUB_CalcMove(self.dest2, self.speed, fd_secret_move3);
509 // Wait here until time to go back...
510 void () fd_secret_move3 =
512 if (self.noise3 != "")
513 sound(self, CHAN_VOICE, self.noise3, 1, ATTN_NORM);
514 if (!(self.spawnflags & SECRET_OPEN_ONCE))
516 self.nextthink = self.ltime + self.wait;
517 self.think = fd_secret_move4;
522 void () fd_secret_move4 =
524 if (self.noise2 != "")
525 sound(self, CHAN_VOICE, self.noise2, 1, ATTN_NORM);
526 SUB_CalcMove(self.dest1, self.speed, fd_secret_move5);
530 void () fd_secret_move5 =
532 self.nextthink = self.ltime + 1.0;
533 self.think = fd_secret_move6;
534 if (self.noise3 != "")
535 sound(self, CHAN_VOICE, self.noise3, 1, ATTN_NORM);
538 void () fd_secret_move6 =
540 if (self.noise2 != "")
541 sound(self, CHAN_VOICE, self.noise2, 1, ATTN_NORM);
542 SUB_CalcMove(self.oldorigin, self.speed, fd_secret_done);
545 void () fd_secret_done =
547 if (!self.targetname || self.spawnflags&SECRET_YES_SHOOT)
550 self.takedamage = DAMAGE_YES;
551 //self.th_pain = fd_secret_use;
553 if (self.noise3 != "")
554 sound(self, CHAN_VOICE, self.noise3, 1, ATTN_NORM);
557 void () secret_blocked =
559 if (time < self.attack_finished)
561 self.attack_finished = time + 0.5;
562 //T_Damage (other, self, self, self.dmg, self.dmg, self.deathtype, DT_IMPACT, (self.absmin + self.absmax) * 0.5, '0 0 0', Obituary_Generic);
572 void() secret_touch =
574 if (activator.classname != "player")
576 if (self.attack_finished > time)
579 self.attack_finished = time + 2;
583 if (other.flags & FL_CLIENT)
584 centerprint (other, self.message);
585 sound (other, CHAN_BODY, "misc/talk.wav", 1, ATTN_NORM);
590 /*QUAKED func_door_secret (0 .5 .8) ? open_once 1st_left 1st_down no_shoot always_shoot
591 Basic secret door. Slides back, then to the side. Angle determines direction.
592 wait = # of seconds before coming back
593 1st_left = 1st move is left of arrow
594 1st_down = 1st move is down from arrow
595 always_shoot = even if targeted, keep shootable
596 t_width = override WIDTH to move back (or height if going down)
597 t_length = override LENGTH to move sideways
598 "dmg" damage to inflict when blocked (2 default)
600 If a secret door has a targetname, it will only be opened by it's botton or trigger, not by damage.
607 void () func_door_secret =
609 /*if (!self.deathtype) // map makers can override this
610 self.deathtype = " got in the way";*/
616 self.mangle = self.angles;
617 self.angles = '0 0 0';
618 self.solid = SOLID_BSP;
619 self.movetype = MOVETYPE_PUSH;
620 self.classname = "door";
621 setmodel (self, self.model);
622 setorigin (self, self.origin);
624 self.touch = secret_touch;
625 self.blocked = secret_blocked;
627 self.use = fd_secret_use;
628 if ( !self.targetname || self.spawnflags&SECRET_YES_SHOOT)
631 self.takedamage = DAMAGE_YES;
632 self.event_damage = fd_secret_use;
634 self.oldorigin = self.origin;
636 self.wait = 5; // 5 seconds before closing