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 ==============================
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 if(clienttype(activator) == CLIENTTYPE_REAL)
59 centerprint (activator, self.message);
61 play2(activator, "misc/talk.wav");
66 // kill the killtagets
73 t = find (t, targetname, self.killtarget);
89 t = find (t, targetname, self.target);
110 //=============================================================================
112 float SPAWNFLAG_NOMESSAGE = 1;
113 float SPAWNFLAG_NOTOUCH = 1;
115 // the wait time has passed, so set back up for another activation
120 self.health = self.max_health;
121 self.takedamage = DAMAGE_YES;
122 self.solid = SOLID_BBOX;
127 // the trigger was just touched/killed/used
128 // self.enemy should be set to the activator so it can be held through a delay
129 // so wait for the delay time before firing
132 if (self.nextthink > time)
134 return; // allready been triggered
137 if (self.classname == "trigger_secret")
139 if (self.enemy.classname != "player")
141 found_secrets = found_secrets + 1;
142 WriteByte (MSG_ALL, SVC_FOUNDSECRET);
146 sound (self.enemy, CHAN_AUTO, self.noise, VOL_BASE, ATTN_NORM);
148 // don't trigger again until reset
149 self.takedamage = DAMAGE_NO;
151 activator = self.enemy;
157 self.think = multi_wait;
158 self.nextthink = time + self.wait;
161 { // we can't just remove (self) here, because this is a touch function
162 // called wheil C code is looping through area links...
163 self.touch = SUB_Null;
165 self.nextthink = time + 0.1;
166 self.think = SUB_Remove;
172 self.enemy = activator;
178 if not(self.spawnflags & 2)
180 if not(other.iscreature)
184 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
202 void multi_eventdamage (vector hitloc, float damage, entity inflictor, entity attacker, float deathtype)
204 if (!self.takedamage)
206 self.health = self.health - damage;
207 if (self.health <= 0)
209 self.enemy = attacker;
214 /*QUAKED spawnfunc_trigger_multiple (.5 .5 .5) ? notouch
215 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.
216 If "delay" is set, the trigger waits some time after activating before firing.
217 "wait" : Seconds between triggerings. (.2 default)
218 If notouch is set, the trigger is only fired by other entities, not by touching.
219 NOTOUCH has been obsoleted by spawnfunc_trigger_relay!
225 set "message" to text string
227 void spawnfunc_trigger_multiple()
229 if (self.sounds == 1)
231 precache_sound ("misc/secret.wav");
232 self.noise = "misc/secret.wav";
234 else if (self.sounds == 2)
236 precache_sound ("misc/talk.wav");
237 self.noise = "misc/talk.wav";
239 else if (self.sounds == 3)
241 precache_sound ("misc/trigger1.wav");
242 self.noise = "misc/trigger1.wav";
247 self.use = multi_use;
253 if (self.spawnflags & SPAWNFLAG_NOTOUCH)
254 objerror ("health and notouch don't make sense\n");
255 self.max_health = self.health;
256 self.event_damage = multi_eventdamage;
257 self.takedamage = DAMAGE_YES;
258 self.solid = SOLID_BBOX;
259 setorigin (self, self.origin); // make sure it links into the world
263 if ( !(self.spawnflags & SPAWNFLAG_NOTOUCH) )
265 self.touch = multi_touch;
266 setorigin (self, self.origin); // make sure it links into the world
272 /*QUAKED spawnfunc_trigger_once (.5 .5 .5) ? notouch
273 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
274 "targetname". If "health" is set, the trigger must be killed to activate.
275 If notouch is set, the trigger is only fired by other entities, not by touching.
276 if "killtarget" is set, any objects that have a matching "target" will be removed when the trigger is fired.
277 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.
283 set "message" to text string
285 void spawnfunc_trigger_once()
288 spawnfunc_trigger_multiple();
291 //=============================================================================
293 /*QUAKED spawnfunc_trigger_relay (.5 .5 .5) (-8 -8 -8) (8 8 8)
294 This fixed size trigger cannot be touched, it can only be fired by other events. It can contain killtargets, targets, delays, and messages.
296 void spawnfunc_trigger_relay()
298 self.use = SUB_UseTargets;
303 self.think = SUB_UseTargets;
304 self.nextthink = self.wait;
307 void spawnfunc_trigger_delay()
312 self.use = delay_use;
315 //=============================================================================
320 self.count = self.count - 1;
326 if (activator.classname == "player"
327 && (self.spawnflags & SPAWNFLAG_NOMESSAGE) == 0)
330 centerprint (activator, "There are more to go...");
331 else if (self.count == 3)
332 centerprint (activator, "Only 3 more to go...");
333 else if (self.count == 2)
334 centerprint (activator, "Only 2 more to go...");
336 centerprint (activator, "Only 1 more to go...");
341 if (activator.classname == "player"
342 && (self.spawnflags & SPAWNFLAG_NOMESSAGE) == 0)
343 centerprint(activator, "Sequence completed!");
344 self.enemy = activator;
348 /*QUAKED spawnfunc_trigger_counter (.5 .5 .5) ? nomessage
349 Acts as an intermediary for an action that takes multiple inputs.
351 If nomessage is not set, t will print "1 more.. " etc when triggered and "sequence complete" when finished.
353 After the counter has been triggered "count" times (default 2), it will fire all of it's targets and remove itself.
355 void spawnfunc_trigger_counter()
361 self.use = counter_use;
364 .float triggerhurttime;
365 void trigger_hurt_touch()
367 // only do the EXACTTRIGGER_TOUCH checks when really needed (saves some cpu)
368 if (other.iscreature)
370 if (other.takedamage)
371 if (other.triggerhurttime < time)
374 other.triggerhurttime = time + 1;
375 Damage (other, self, self, self.dmg, DEATH_HURTTRIGGER, other.origin, '0 0 0');
382 if (other.items & IT_KEY1 || other.items & IT_KEY2) // reset flag
385 other.pain_finished = min(other.pain_finished, time + 2);
387 else if (other.classname == "rune") // reset runes
390 other.nextthink = min(other.nextthink, time + 1);
398 /*QUAKED spawnfunc_trigger_hurt (.5 .5 .5) ?
399 Any object touching this will be hurt
400 set dmg to damage amount
403 .entity trigger_hurt_next;
404 entity trigger_hurt_last;
405 entity trigger_hurt_first;
406 void spawnfunc_trigger_hurt()
409 self.touch = trigger_hurt_touch;
413 self.message = "was in the wrong place";
415 self.message2 = "was thrown into a world of hurt by";
417 if(!trigger_hurt_first)
418 trigger_hurt_first = self;
419 if(trigger_hurt_last)
420 trigger_hurt_last.trigger_hurt_next = self;
421 trigger_hurt_last = self;
424 float tracebox_hits_trigger_hurt(vector start, vector mi, vector ma, vector end)
428 for(th = trigger_hurt_first; th; th = th.trigger_hurt_next)
429 if(tracebox_hits_box(start, mi, ma, end, th.absmin, th.absmax))
436 // TODO add a way to do looped sounds with sound(); then complete this entity
437 .float volume, atten;
438 void target_speaker_use() {sound(self, CHAN_TRIGGER, self.noise, VOL_BASE * self.volume, self.atten);}
440 void spawnfunc_target_speaker()
443 precache_sound (self.noise);
447 self.atten = ATTN_NORM;
448 else if(self.atten < 0)
452 self.use = target_speaker_use;
457 self.atten = ATTN_STATIC;
458 else if(self.atten < 0)
462 ambientsound (self.origin, self.noise, VOL_BASE * self.volume, self.atten);
467 void spawnfunc_func_stardust() {
468 self.effects = EF_STARDUST;
471 float pointparticles_SendEntity(entity to, float fl)
473 WriteByte(MSG_ENTITY, ENT_CLIENT_POINTPARTICLES);
474 WriteByte(MSG_ENTITY, fl);
478 WriteCoord(MSG_ENTITY, self.impulse);
480 WriteCoord(MSG_ENTITY, 0); // off
484 WriteCoord(MSG_ENTITY, self.origin_x);
485 WriteCoord(MSG_ENTITY, self.origin_y);
486 WriteCoord(MSG_ENTITY, self.origin_z);
490 if(self.modelindex != 4.2)
492 WriteShort(MSG_ENTITY, self.modelindex);
493 WriteCoord(MSG_ENTITY, self.mins_x);
494 WriteCoord(MSG_ENTITY, self.mins_y);
495 WriteCoord(MSG_ENTITY, self.mins_z);
496 WriteCoord(MSG_ENTITY, self.maxs_x);
497 WriteCoord(MSG_ENTITY, self.maxs_y);
498 WriteCoord(MSG_ENTITY, self.maxs_z);
502 WriteShort(MSG_ENTITY, 0);
503 WriteCoord(MSG_ENTITY, self.maxs_x);
504 WriteCoord(MSG_ENTITY, self.maxs_y);
505 WriteCoord(MSG_ENTITY, self.maxs_z);
507 WriteShort(MSG_ENTITY, self.cnt);
508 WriteShort(MSG_ENTITY, compressShortVector(self.velocity));
509 WriteShort(MSG_ENTITY, compressShortVector(self.movedir));
510 WriteCoord(MSG_ENTITY, self.waterlevel);
511 WriteCoord(MSG_ENTITY, self.count);
512 WriteByte(MSG_ENTITY, self.glow_color);
513 WriteString(MSG_ENTITY, self.noise);
518 void pointparticles_use()
520 self.state = !self.state;
524 void pointparticles_think()
526 if(self.origin != self.oldorigin)
529 self.oldorigin = self.origin;
531 self.nextthink = time;
534 void spawnfunc_func_pointparticles()
537 setmodel(self, self.model);
539 precache_sound (self.noise);
541 self.effects = EF_NODEPTHTEST;
542 self.SendEntity = pointparticles_SendEntity;
546 self.modelindex = 4.2;
547 self.origin += self.mins;
548 self.maxs = self.maxs - self.mins;
550 self.model = "net_entity";
552 self.cnt = particleeffectnum(self.mdl);
555 self.use = pointparticles_use;
556 if(self.spawnflags & 1)
563 self.think = pointparticles_think;
564 self.nextthink = time;
567 void spawnfunc_func_sparks()
569 // self.cnt is the amount of sparks that one burst will spawn
571 self.cnt = 25.0; // nice default value
574 // self.wait is the probability that a sparkthink will spawn a spark shower
575 // range: 0 - 1, but 0 makes little sense, so...
576 if(self.wait < 0.05) {
577 self.wait = 0.25; // nice default value
580 self.count = self.cnt;
583 self.velocity = '0 0 -1';
584 self.mdl = "TE_SPARK";
585 self.impulse = 10 * self.wait; // by default 2.5/sec
587 self.cnt = 0; // use mdl
589 spawnfunc_func_pointparticles();
592 float rainsnow_SendEntity(float to)
594 WriteByte(MSG_ENTITY, ENT_CLIENT_RAINSNOW);
595 WriteByte(MSG_ENTITY, self.state);
596 WriteCoord(MSG_ENTITY, self.origin_x + self.mins_x);
597 WriteCoord(MSG_ENTITY, self.origin_y + self.mins_y);
598 WriteCoord(MSG_ENTITY, self.origin_z + self.mins_z);
599 WriteCoord(MSG_ENTITY, self.maxs_x - self.mins_x);
600 WriteCoord(MSG_ENTITY, self.maxs_y - self.mins_y);
601 WriteCoord(MSG_ENTITY, self.maxs_z - self.mins_z);
602 WriteShort(MSG_ENTITY, compressShortVector(self.dest));
603 WriteShort(MSG_ENTITY, self.count);
604 WriteByte(MSG_ENTITY, self.cnt);
608 /*QUAKED spawnfunc_func_rain (0 .5 .8) ?
609 This is an invisible area like a trigger, which rain falls inside of.
613 falling direction (should be something like '0 0 -700', use the X and Y velocity for wind)
615 sets color of rain (default 12 - white)
617 adjusts density, this many particles fall every second for a 1024x1024 area, default is 2000
619 void spawnfunc_func_rain()
621 self.dest = self.velocity;
622 self.velocity = '0 0 0';
624 self.dest = '0 0 -700';
625 self.angles = '0 0 0';
626 self.movetype = MOVETYPE_NONE;
627 self.solid = SOLID_NOT;
628 SetBrushEntityModel();
634 self.count = 0.01 * self.count * (self.size_x / 1024) * (self.size_y / 1024);
637 if(self.count > 65535)
640 self.state = 1; // 1 is rain, 0 is snow
641 self.effects = EF_NODEPTHTEST;
642 self.SendEntity = rainsnow_SendEntity;
645 self.model = "net_entity";
649 /*QUAKED spawnfunc_func_snow (0 .5 .8) ?
650 This is an invisible area like a trigger, which snow falls inside of.
654 falling direction (should be something like '0 0 -300', use the X and Y velocity for wind)
656 sets color of rain (default 12 - white)
658 adjusts density, this many particles fall every second for a 1024x1024 area, default is 2000
660 void spawnfunc_func_snow()
662 self.dest = self.velocity;
663 self.velocity = '0 0 0';
665 self.dest = '0 0 -300';
666 self.angles = '0 0 0';
667 self.movetype = MOVETYPE_NONE;
668 self.solid = SOLID_NOT;
669 SetBrushEntityModel();
675 self.count = 0.01 * self.count * (self.size_x / 1024) * (self.size_y / 1024);
678 if(self.count > 65535)
681 self.state = 0; // 1 is rain, 0 is snow
682 self.effects = EF_NODEPTHTEST;
683 self.SendEntity = rainsnow_SendEntity;
686 self.model = "net_entity";
690 void FireRailgunBullet (vector start, vector end, float bdamage, float bforce, float deathtype);
692 void misc_laser_aim()
697 if(self.spawnflags & 2)
699 if(self.enemy.origin != self.mangle)
701 self.mangle = self.enemy.origin;
707 a = vectoangles(self.enemy.origin - self.origin);
718 if(self.angles != self.mangle)
720 self.mangle = self.angles;
724 if(self.origin != self.oldorigin)
727 self.oldorigin = self.origin;
731 void misc_laser_init()
733 if(self.target != "")
734 self.enemy = find(world, targetname, self.target);
738 void misc_laser_think()
743 self.nextthink = time;
752 o = self.enemy.origin;
753 if not(self.spawnflags & 2)
754 o = self.origin + normalize(o - self.origin) * 32768;
758 makevectors(self.mangle);
759 o = self.origin + v_forward * 32768;
765 FireRailgunBullet(self.origin, o, 100000, 0, DEATH_HURTTRIGGER);
767 FireRailgunBullet(self.origin, o, self.dmg * frametime, 0, DEATH_HURTTRIGGER);
770 if(self.enemy.target != "") // DETECTOR laser
772 traceline(self.origin, o, MOVE_NORMAL, self);
773 if(trace_ent.iscreature)
775 self.pusher = trace_ent;
782 activator = self.pusher;
795 activator = self.pusher;
803 float laser_SendEntity(entity to, float fl)
805 WriteByte(MSG_ENTITY, ENT_CLIENT_LASER);
806 fl = fl - (fl & 0xC0); // use that bit to indicate finite length laser
807 if(self.spawnflags & 2)
811 WriteByte(MSG_ENTITY, fl);
814 WriteCoord(MSG_ENTITY, self.origin_x);
815 WriteCoord(MSG_ENTITY, self.origin_y);
816 WriteCoord(MSG_ENTITY, self.origin_z);
820 WriteByte(MSG_ENTITY, self.colormod_x * 255.0);
821 WriteByte(MSG_ENTITY, self.colormod_y * 255.0);
822 WriteByte(MSG_ENTITY, self.colormod_z * 255.0);
824 WriteByte(MSG_ENTITY, self.alpha * 255.0);
825 WriteShort(MSG_ENTITY, self.cnt + 1);
831 WriteCoord(MSG_ENTITY, self.enemy.origin_x);
832 WriteCoord(MSG_ENTITY, self.enemy.origin_y);
833 WriteCoord(MSG_ENTITY, self.enemy.origin_z);
837 WriteCoord(MSG_ENTITY, self.mangle_x);
838 WriteCoord(MSG_ENTITY, self.mangle_y);
842 WriteByte(MSG_ENTITY, self.state);
846 /*QUAKED spawnfunc_misc_laser (.5 .5 .5) ? START_ON DEST_IS_FIXED
847 Any object touching the beam will be hurt
850 spawnfunc_target_position where the laser ends
852 name of beam end effect to use
854 color of the beam (default: red)
856 damage per second (-1 for a laser that kills immediately)
860 self.state = !self.state;
865 void spawnfunc_misc_laser()
869 if(self.mdl == "none")
872 self.cnt = particleeffectnum(self.mdl);
877 self.cnt = particleeffectnum("laser_deadly");
882 if(self.colormod == '0 0 0')
884 self.colormod = '1 0 0';
886 self.message = "saw the light";
888 self.message2 = "was pushed into a laser by";
889 self.think = misc_laser_think;
890 self.nextthink = time;
891 InitializeEntity(self, misc_laser_init, INITPRIO_FINDTARGET);
893 self.effects = EF_NODEPTHTEST;
894 self.SendEntity = laser_SendEntity;
897 self.model = "net_entity";
898 self.mangle = self.angles;
902 self.use = laser_use;
903 if(self.spawnflags & 1)
912 // tZorks trigger impulse / gravity
918 // targeted (directional) mode
919 void trigger_impulse_touch1()
925 // FIXME: Better checking for what to push and not.
926 if not(other.iscreature)
927 if (other.classname != "corpse")
928 if (other.classname != "body")
929 if (other.classname != "gib")
930 if (other.classname != "missile")
931 if (other.classname != "rocket")
932 if (other.classname != "casing")
933 if (other.classname != "grenade")
934 if (other.classname != "plasma")
935 if (other.classname != "plasma_prim")
936 if (other.classname != "plasma_chain")
937 if (other.classname != "droppedweapon")
940 if (other.deadflag && other.iscreature)
945 targ = find(world, targetname, self.target);
948 objerror("trigger_force without a (valid) .target!\n");
953 if(self.falloff == 1)
954 str = (str / self.radius) * self.strength;
955 else if(self.falloff == 2)
956 str = (1 - (str / self.radius)) * self.strength;
960 pushdeltatime = time - other.lastpushtime;
961 if (pushdeltatime > 0.15) pushdeltatime = 0;
962 other.lastpushtime = time;
963 if(!pushdeltatime) return;
965 other.velocity = other.velocity + normalize(targ.origin - self.origin) * self.strength * pushdeltatime;
968 // Directionless (accelerator/decelerator) mode
969 void trigger_impulse_touch2()
973 // FIXME: Better checking for what to push and not.
974 if not(other.iscreature)
975 if (other.classname != "corpse")
976 if (other.classname != "body")
977 if (other.classname != "gib")
978 if (other.classname != "missile")
979 if (other.classname != "rocket")
980 if (other.classname != "casing")
981 if (other.classname != "grenade")
982 if (other.classname != "plasma")
983 if (other.classname != "plasma_prim")
984 if (other.classname != "plasma_chain")
985 if (other.classname != "droppedweapon")
988 if (other.deadflag && other.iscreature)
993 pushdeltatime = time - other.lastpushtime;
994 if (pushdeltatime > 0.15) pushdeltatime = 0;
995 other.lastpushtime = time;
996 if(!pushdeltatime) return;
998 //if(self.strength > 1)
999 other.velocity = other.velocity * (self.strength * pushdeltatime);
1001 // other.velocity = other.velocity - (other.velocity * self.strength * pushdeltatime);
1004 // Spherical (gravity/repulsor) mode
1005 void trigger_impulse_touch3()
1007 float pushdeltatime;
1010 // FIXME: Better checking for what to push and not.
1011 if not(other.iscreature)
1012 if (other.classname != "corpse")
1013 if (other.classname != "body")
1014 if (other.classname != "gib")
1015 if (other.classname != "missile")
1016 if (other.classname != "rocket")
1017 if (other.classname != "casing")
1018 if (other.classname != "grenade")
1019 if (other.classname != "plasma")
1020 if (other.classname != "plasma_prim")
1021 if (other.classname != "plasma_chain")
1022 if (other.classname != "droppedweapon")
1025 if (other.deadflag && other.iscreature)
1030 pushdeltatime = time - other.lastpushtime;
1031 if (pushdeltatime > 0.15) pushdeltatime = 0;
1032 other.lastpushtime = time;
1033 if(!pushdeltatime) return;
1035 setsize(self, '-1 -1 -1' * self.radius,'1 1 1' * self.radius);
1037 str = min(self.radius, vlen(self.origin - other.origin));
1039 if(self.falloff == 1)
1040 str = (1 - str / self.radius) * self.strength; // 1 in the inside
1041 else if(self.falloff == 2)
1042 str = (str / self.radius) * self.strength; // 0 in the inside
1044 str = self.strength;
1046 other.velocity = other.velocity + normalize(other.origin - self.origin) * str * pushdeltatime;
1049 /*QUAKED spawnfunc_trigger_impulse (.5 .5 .5) ?
1050 -------- KEYS --------
1051 target : If this is set, this points to the spawnfunc_target_position to which the player will get pushed.
1052 If not, this trigger acts like a damper/accelerator field.
1054 strength : This is how mutch force to add in the direction of .target each second
1055 when .target is set. If not, this is hoe mutch to slow down/accelerate
1056 someting cought inside this trigger. (1=no change, 0,5 half speed rougthly each tic, 2 = doubble)
1058 radius : If set, act as a spherical device rather then a liniar one.
1060 falloff : 0 = none, 1 = liniar, 2 = inverted liniar
1062 -------- NOTES --------
1063 Use a brush textured with common/origin in the trigger entity to determine the origin of the force
1064 in directional and sperical mode. For damper/accelerator mode this is not nessesary (and has no effect).
1067 void spawnfunc_trigger_impulse()
1072 if(!self.strength) self.strength = 2000;
1073 setorigin(self, self.origin);
1074 setsize(self, '-1 -1 -1' * self.radius,'1 1 1' * self.radius);
1075 self.touch = trigger_impulse_touch3;
1081 if(!self.strength) self.strength = 950;
1082 self.touch = trigger_impulse_touch1;
1086 if(!self.strength) self.strength = 0.9;
1087 self.touch = trigger_impulse_touch2;
1092 /*QUAKED spawnfunc_trigger_flipflop (.5 .5 .5) (-8 -8 -8) (8 8 8) START_ENABLED
1093 "Flip-flop" trigger gate... lets only every second trigger event through
1097 self.state = !self.state;
1102 void spawnfunc_trigger_flipflop()
1104 if(self.spawnflags & 1)
1106 self.use = flipflop_use;
1109 /*QUAKED spawnfunc_trigger_monoflop (.5 .5 .5) (-8 -8 -8) (8 8 8)
1110 "Mono-flop" trigger gate... turns one trigger event into one "on" and one "off" event, separated by a delay of "wait"
1114 self.nextthink = time + self.wait;
1115 self.enemy = activator;
1121 void monoflop_fixed_use()
1125 self.nextthink = time + self.wait;
1127 self.enemy = activator;
1131 void monoflop_think()
1134 activator = self.enemy;
1138 void spawnfunc_trigger_monoflop()
1142 if(self.spawnflags & 1)
1143 self.use = monoflop_fixed_use;
1145 self.use = monoflop_use;
1146 self.think = monoflop_think;
1150 void multivibrator_send()
1155 cyclestart = floor((time + self.phase) / (self.wait + self.respawntime)) * (self.wait + self.respawntime) - self.phase;
1157 newstate = (time < cyclestart + self.wait);
1160 if(self.state != newstate)
1162 self.state = newstate;
1165 self.nextthink = cyclestart + self.wait + 0.01;
1167 self.nextthink = cyclestart + self.wait + self.respawntime + 0.01;
1170 void multivibrator_toggle()
1172 if(self.nextthink == 0)
1174 multivibrator_send();
1187 /*QUAKED trigger_multivibrator (.5 .5 .5) (-8 -8 -8) (8 8 8) START_ON
1188 "Multivibrator" trigger gate... repeatedly sends trigger events. When triggered, turns on or off.
1189 -------- KEYS --------
1190 target: trigger all entities with this targetname when it goes off
1191 targetname: name that identifies this entity so it can be triggered; when off, it always uses the OFF state
1192 phase: offset of the timing
1193 wait: "on" cycle time (default: 1)
1194 respawntime: "off" cycle time (default: same as wait)
1195 -------- SPAWNFLAGS --------
1196 START_ON: assume it is already turned on (when targeted)
1198 void spawnfunc_trigger_multivibrator()
1202 if(!self.respawntime)
1203 self.respawntime = self.wait;
1206 self.use = multivibrator_toggle;
1207 self.think = multivibrator_send;
1208 self.nextthink = time;
1212 if(!(self.spawnflags & 1))
1213 self.nextthink = 0; // wait for a trigger event
1216 self.nextthink = time;
1223 src = find(world, targetname, self.killtarget);
1224 dst = find(world, targetname, self.target);
1228 objerror("follow: could not find target/killtarget");
1232 dst.movetype = MOVETYPE_FOLLOW;
1234 dst.punchangle = src.angles;
1235 dst.view_ofs = dst.origin - src.origin;
1236 dst.v_angle = dst.angles - src.angles;
1241 void spawnfunc_misc_follow()
1243 InitializeEntity(self, follow_init, INITPRIO_FINDTARGET);