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 = SUB_Null;
168 self.nextthink = time + 0.1;
169 self.think = SUB_Remove;
175 self.enemy = activator;
181 if (other.classname != "player")
185 if(self.team == other.team)
188 // if the trigger has an angles field, check player's facing direction
189 if (self.movedir != '0 0 0')
191 makevectors (other.angles);
192 if (v_forward * self.movedir < 0)
193 return; // not facing the right way
200 void multi_eventdamage (vector hitloc, float damage, entity inflictor, entity attacker, float deathtype)
202 if (!self.takedamage)
204 self.health = self.health - damage;
205 if (self.health <= 0)
207 self.enemy = attacker;
212 /*QUAKED trigger_multiple (.5 .5 .5) ? notouch
213 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.
214 If "delay" is set, the trigger waits some time after activating before firing.
215 "wait" : Seconds between triggerings. (.2 default)
216 If notouch is set, the trigger is only fired by other entities, not by touching.
217 NOTOUCH has been obsoleted by trigger_relay!
223 set "message" to text string
225 void() trigger_multiple =
227 if (self.sounds == 1)
229 precache_sound ("misc/secret.wav");
230 self.noise = "misc/secret.wav";
232 else if (self.sounds == 2)
234 precache_sound ("misc/talk.wav");
235 self.noise = "misc/talk.wav";
237 else if (self.sounds == 3)
239 precache_sound ("misc/trigger1.wav");
240 self.noise = "misc/trigger1.wav";
245 self.use = multi_use;
251 if (self.spawnflags & SPAWNFLAG_NOTOUCH)
252 objerror ("health and notouch don't make sense\n");
253 self.max_health = self.health;
254 self.event_damage = multi_eventdamage;
255 self.takedamage = DAMAGE_YES;
256 self.solid = SOLID_BBOX;
257 setorigin (self, self.origin); // make sure it links into the world
261 if ( !(self.spawnflags & SPAWNFLAG_NOTOUCH) )
263 self.touch = multi_touch;
269 /*QUAKED trigger_once (.5 .5 .5) ? notouch
270 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
271 "targetname". If "health" is set, the trigger must be killed to activate.
272 If notouch is set, the trigger is only fired by other entities, not by touching.
273 if "killtarget" is set, any objects that have a matching "target" will be removed when the trigger is fired.
274 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.
280 set "message" to text string
282 void() trigger_once =
288 //=============================================================================
290 /*QUAKED trigger_relay (.5 .5 .5) (-8 -8 -8) (8 8 8)
291 This fixed size trigger cannot be touched, it can only be fired by other events. It can contain killtargets, targets, delays, and messages.
293 void() trigger_relay =
295 self.use = SUB_UseTargets;
300 self.think = SUB_UseTargets;
301 self.nextthink = self.wait;
309 self.use = delay_use;
312 //=============================================================================
317 self.count = self.count - 1;
323 if (activator.classname == "player"
324 && (self.spawnflags & SPAWNFLAG_NOMESSAGE) == 0)
327 centerprint (activator, "There are more to go...");
328 else if (self.count == 3)
329 centerprint (activator, "Only 3 more to go...");
330 else if (self.count == 2)
331 centerprint (activator, "Only 2 more to go...");
333 centerprint (activator, "Only 1 more to go...");
338 if (activator.classname == "player"
339 && (self.spawnflags & SPAWNFLAG_NOMESSAGE) == 0)
340 centerprint(activator, "Sequence completed!");
341 self.enemy = activator;
345 /*QUAKED trigger_counter (.5 .5 .5) ? nomessage
346 Acts as an intermediary for an action that takes multiple inputs.
348 If nomessage is not set, t will print "1 more.. " etc when triggered and "sequence complete" when finished.
350 After the counter has been triggered "count" times (default 2), it will fire all of it's targets and remove itself.
352 void() trigger_counter =
358 self.use = counter_use;
361 .float triggerhurttime;
366 if (other.items & IT_KEY1 || other.items & IT_KEY2) // reset flag
367 other.pain_finished = min(other.pain_finished, time + 2);
368 else if (other.classname == "rune") // reset runes
369 other.nextthink = min(other.nextthink, time + 1);
372 if (other.takedamage)
373 if (other.triggerhurttime < time)
375 other.triggerhurttime = time + 1;
376 Damage (other, self, self, self.dmg, DEATH_HURTTRIGGER, other.origin, '0 0 0');
382 /*QUAKED trigger_hurt (.5 .5 .5) ?
383 Any object touching this will be hurt
384 set dmg to damage amount
387 void() trigger_hurt =
390 self.touch = hurt_touch;
394 self.message = "was in the wrong place.";
397 //void() target_speaker_use = {sound(self, CHAN_VOICE, self.noise, 1, 1);}
398 //void() target_speaker = {self.use = target_speaker_use;}
400 void() target_speaker =
403 precache_sound (self.noise);
404 ambientsound (self.origin, self.noise, 1, ATTN_STATIC);
410 void() func_stardust {
411 self.effects = EF_STARDUST;
418 self.nextthink = time + 0.1;
420 if(random() < self.wait) {
421 te_spark(self.origin,'0 0 -1',self.cnt);
428 self.think = sparksthink;
429 self.nextthink = time + 0.2;
431 // self.cnt is the amount of sparks that one burst will spawn
433 self.cnt = 25.0; // nice default value
436 // self.wait is the probability that a sparkthink will spawn a spark shower
437 // range: 0 - 1, but 0 makes little sense, so...
438 if(self.wait < 0.05) {
439 self.wait = 0.25; // nice default value
444 precache_sound (self.noise);
445 ambientsound (self.origin, self.noise, 1, ATTN_STATIC);
451 self.nextthink = time + 0.1;
452 te_particlerain(self.absmin, self.absmax, self.dest, self.count, self.cnt);
453 // te_particlesnow(self.absmin, self.absmax, self.dest * 0.25, self.count, self.cnt);
454 // WriteByte (MSG_BROADCAST, SVC_TEMPENTITY);
455 // WriteByte (MSG_BROADCAST, TE_PARTICLERAIN);
456 // WriteVec (MSG_BROADCAST, self.absmin);
457 // WriteVec (MSG_BROADCAST, self.absmax);
458 // WriteVec (MSG_BROADCAST, self.dest);
459 // WriteShort (MSG_BROADCAST, self.count);
460 // WriteByte (MSG_BROADCAST, self.cnt);
463 /*QUAKED func_rain (0 .5 .8) ?
464 This is an invisible area like a trigger, which rain falls inside of.
468 falling direction (should be something like '0 0 -700', use the X and Y velocity for wind)
470 sets color of rain (default 12 - white)
472 adjusts density, this many particles fall every second for a 1024x1024 area, default is 2000
476 self.dest = self.velocity;
477 self.velocity = '0 0 0';
479 self.dest = '0 0 -700';
480 self.angles = '0 0 0';
481 self.movetype = MOVETYPE_NONE;
482 self.solid = SOLID_NOT;
483 setmodel(self, self.model); // no precision needed
484 setorigin(self, self.origin);
485 setsize(self, self.mins, self.maxs);
491 self.count = 0.1 * self.count * (self.size_x / 1024) * (self.size_y / 1024);
497 // convert from per second to per 0.1 sec,
498 self.count = ceil(self.count * 0.1);
499 self.think = rain_think;
500 self.nextthink = time + 0.5;
506 self.nextthink = time + 0.1 + random() * 0.05;
507 te_particlesnow(self.absmin, self.absmax, self.dest, self.count, self.cnt);
508 // WriteByte (MSG_BROADCAST, SVC_TEMPENTITY);
509 // WriteByte (MSG_BROADCAST, TE_PARTICLESNOW);
510 // WriteVec (MSG_BROADCAST, self.absmin);
511 // WriteVec (MSG_BROADCAST, self.absmax);
512 // WriteVec (MSG_BROADCAST, self.dest);
513 // WriteShort (MSG_BROADCAST, self.count);
514 // WriteByte (MSG_BROADCAST, self.cnt);
517 /*QUAKED func_snow (0 .5 .8) ?
518 This is an invisible area like a trigger, which snow falls inside of.
522 falling direction (should be something like '0 0 -300', use the X and Y velocity for wind)
524 sets color of rain (default 12 - white)
526 adjusts density, this many particles fall every second for a 1024x1024 area, default is 2000
530 self.dest = self.velocity;
531 self.velocity = '0 0 0';
533 self.dest = '0 0 -300';
534 self.angles = '0 0 0';
535 self.movetype = MOVETYPE_NONE;
536 self.solid = SOLID_NOT;
537 setmodel(self, self.model); // no precision needed
538 setorigin(self, self.origin);
539 setsize(self, self.mins, self.maxs);
545 self.count = 0.1 * self.count * (self.size_x / 1024) * (self.size_y / 1024);
551 // convert from per second to per 0.1 sec,
552 self.count = ceil(self.count * 0.1);
553 self.think = snow_think;
554 self.nextthink = time + 0.5;
558 void FireRailgunBullet (vector start, vector end, float bdamage, float bforce, float deathtype);
559 void() misc_laser_think =
564 self.enemy = find(world, targetname, self.target);
569 o = self.enemy.origin;
573 makevectors(self.angles);
574 o = self.origin + v_forward * MAX_SHOT_DISTANCE;
580 FireRailgunBullet(self.origin, o, 100000, 0, DEATH_HURTTRIGGER);
582 FireRailgunBullet(self.origin, o, self.dmg * frametime, 0, DEATH_HURTTRIGGER);
584 if(time > self.ltime)
586 trailparticles(self, self.cnt, self.origin, trace_endpos);
587 pointparticles(self.lip, trace_endpos, trace_plane_normal, 256 * frametime);
588 self.ltime = time + self.wait;
590 self.nextthink = time;
592 /*QUAKED misc_laser (.5 .5 .5) ?
593 Any object touching the beam will be hurt
596 target_position where the laser ends
598 name of beam effect to use
600 damage per second (-1 for a laser that kills immediately)
602 delay between sending the particle effect
608 self.cnt = particleeffectnum(self.mdl);
609 self.lip = particleeffectnum(strcat(self.mdl, "_end"));
613 self.cnt = particleeffectnum("misc_laser_beam");
614 self.lip = particleeffectnum("misc_laser_beam_end");
619 self.message = "saw the light";
620 self.think = misc_laser_think;
621 self.nextthink = time;