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)
370 if (other.items & IT_KEY1 || other.items & IT_KEY2) // reset flag
373 other.pain_finished = min(other.pain_finished, time + 2);
375 else if (other.classname == "rune") // reset runes
378 other.nextthink = min(other.nextthink, time + 1);
382 if (other.takedamage)
383 if (other.triggerhurttime < time)
386 other.triggerhurttime = time + 1;
387 Damage (other, self, self, self.dmg, DEATH_HURTTRIGGER, other.origin, '0 0 0');
393 /*QUAKED spawnfunc_trigger_hurt (.5 .5 .5) ?
394 Any object touching this will be hurt
395 set dmg to damage amount
398 .entity trigger_hurt_next;
399 entity trigger_hurt_last;
400 entity trigger_hurt_first;
401 void spawnfunc_trigger_hurt()
404 self.touch = trigger_hurt_touch;
408 self.message = "was in the wrong place";
410 self.message2 = "was thrown into a world of hurt by";
412 if(!trigger_hurt_first)
413 trigger_hurt_first = self;
414 if(trigger_hurt_last)
415 trigger_hurt_last.trigger_hurt_next = self;
416 trigger_hurt_last = self;
419 float tracebox_hits_trigger_hurt(vector start, vector mi, vector ma, vector end)
423 for(th = trigger_hurt_first; th; th = th.trigger_hurt_next)
424 if(tracebox_hits_box(start, mi, ma, end, th.absmin, th.absmax))
431 // TODO add a way to do looped sounds with sound(); then complete this entity
432 .float volume, atten;
433 void target_speaker_use() {sound(self, CHAN_TRIGGER, self.noise, VOL_BASE * self.volume, self.atten);}
435 void spawnfunc_target_speaker()
438 precache_sound (self.noise);
442 self.atten = ATTN_NORM;
443 else if(self.atten < 0)
447 self.use = target_speaker_use;
452 self.atten = ATTN_STATIC;
453 else if(self.atten < 0)
457 ambientsound (self.origin, self.noise, VOL_BASE * self.volume, self.atten);
462 void spawnfunc_func_stardust() {
463 self.effects = EF_STARDUST;
466 float pointparticles_SendEntity(entity to, float fl)
468 WriteByte(MSG_ENTITY, ENT_CLIENT_POINTPARTICLES);
469 WriteByte(MSG_ENTITY, fl);
473 WriteCoord(MSG_ENTITY, self.impulse);
475 WriteCoord(MSG_ENTITY, 0); // off
479 WriteCoord(MSG_ENTITY, self.origin_x);
480 WriteCoord(MSG_ENTITY, self.origin_y);
481 WriteCoord(MSG_ENTITY, self.origin_z);
485 if(self.modelindex != 4.2)
487 WriteShort(MSG_ENTITY, self.modelindex);
488 WriteCoord(MSG_ENTITY, self.mins_x);
489 WriteCoord(MSG_ENTITY, self.mins_y);
490 WriteCoord(MSG_ENTITY, self.mins_z);
491 WriteCoord(MSG_ENTITY, self.maxs_x);
492 WriteCoord(MSG_ENTITY, self.maxs_y);
493 WriteCoord(MSG_ENTITY, self.maxs_z);
497 WriteShort(MSG_ENTITY, 0);
498 WriteCoord(MSG_ENTITY, self.maxs_x);
499 WriteCoord(MSG_ENTITY, self.maxs_y);
500 WriteCoord(MSG_ENTITY, self.maxs_z);
502 WriteShort(MSG_ENTITY, self.cnt);
503 WriteShort(MSG_ENTITY, compressShortVector(self.velocity));
504 WriteShort(MSG_ENTITY, compressShortVector(self.movedir));
505 WriteCoord(MSG_ENTITY, self.waterlevel);
506 WriteCoord(MSG_ENTITY, self.count);
507 WriteByte(MSG_ENTITY, self.glow_color);
508 WriteString(MSG_ENTITY, self.noise);
513 void pointparticles_use()
515 self.state = !self.state;
519 void pointparticles_think()
521 if(self.origin != self.oldorigin)
524 self.oldorigin = self.origin;
526 self.nextthink = time;
529 void spawnfunc_func_pointparticles()
532 setmodel(self, self.model);
534 precache_sound (self.noise);
536 self.effects = EF_NODEPTHTEST;
537 self.SendEntity = pointparticles_SendEntity;
541 self.modelindex = 4.2;
542 self.origin += self.mins;
543 self.maxs -= self.mins;
545 self.model = "net_entity";
547 self.cnt = particleeffectnum(self.mdl);
550 self.use = pointparticles_use;
551 if(self.spawnflags & 1)
558 self.think = pointparticles_think;
559 self.nextthink = time;
562 void spawnfunc_func_sparks()
564 // self.cnt is the amount of sparks that one burst will spawn
566 self.cnt = 25.0; // nice default value
569 // self.wait is the probability that a sparkthink will spawn a spark shower
570 // range: 0 - 1, but 0 makes little sense, so...
571 if(self.wait < 0.05) {
572 self.wait = 0.25; // nice default value
575 self.count = self.cnt;
578 self.velocity = '0 0 -1';
579 self.mdl = "TE_SPARK";
580 self.impulse = 10 * self.wait; // by default 2.5/sec
582 self.cnt = 0; // use mdl
584 spawnfunc_func_pointparticles();
587 float rainsnow_SendEntity(float to)
589 WriteByte(MSG_ENTITY, ENT_CLIENT_RAINSNOW);
590 WriteByte(MSG_ENTITY, self.state);
591 WriteCoord(MSG_ENTITY, self.origin_x + self.mins_x);
592 WriteCoord(MSG_ENTITY, self.origin_y + self.mins_y);
593 WriteCoord(MSG_ENTITY, self.origin_z + self.mins_z);
594 WriteCoord(MSG_ENTITY, self.maxs_x - self.mins_x);
595 WriteCoord(MSG_ENTITY, self.maxs_y - self.mins_y);
596 WriteCoord(MSG_ENTITY, self.maxs_z - self.mins_z);
597 WriteShort(MSG_ENTITY, compressShortVector(self.dest));
598 WriteShort(MSG_ENTITY, self.count);
599 WriteByte(MSG_ENTITY, self.cnt);
603 /*QUAKED spawnfunc_func_rain (0 .5 .8) ?
604 This is an invisible area like a trigger, which rain falls inside of.
608 falling direction (should be something like '0 0 -700', use the X and Y velocity for wind)
610 sets color of rain (default 12 - white)
612 adjusts density, this many particles fall every second for a 1024x1024 area, default is 2000
614 void spawnfunc_func_rain()
616 self.dest = self.velocity;
617 self.velocity = '0 0 0';
619 self.dest = '0 0 -700';
620 self.angles = '0 0 0';
621 self.movetype = MOVETYPE_NONE;
622 self.solid = SOLID_NOT;
623 SetBrushEntityModel();
629 self.count = 0.01 * self.count * (self.size_x / 1024) * (self.size_y / 1024);
632 if(self.count > 65535)
635 self.state = 1; // 1 is rain, 0 is snow
636 self.effects = EF_NODEPTHTEST;
637 self.SendEntity = rainsnow_SendEntity;
640 self.model = "net_entity";
644 /*QUAKED spawnfunc_func_snow (0 .5 .8) ?
645 This is an invisible area like a trigger, which snow falls inside of.
649 falling direction (should be something like '0 0 -300', use the X and Y velocity for wind)
651 sets color of rain (default 12 - white)
653 adjusts density, this many particles fall every second for a 1024x1024 area, default is 2000
655 void spawnfunc_func_snow()
657 self.dest = self.velocity;
658 self.velocity = '0 0 0';
660 self.dest = '0 0 -300';
661 self.angles = '0 0 0';
662 self.movetype = MOVETYPE_NONE;
663 self.solid = SOLID_NOT;
664 SetBrushEntityModel();
670 self.count = 0.01 * self.count * (self.size_x / 1024) * (self.size_y / 1024);
673 if(self.count > 65535)
676 self.state = 0; // 1 is rain, 0 is snow
677 self.effects = EF_NODEPTHTEST;
678 self.SendEntity = rainsnow_SendEntity;
681 self.model = "net_entity";
685 void FireRailgunBullet (vector start, vector end, float bdamage, float bforce, float deathtype);
687 void misc_laser_aim()
692 if(self.spawnflags & 2)
694 if(self.enemy.origin != self.mangle)
696 self.mangle = self.enemy.origin;
702 a = vectoangles(self.enemy.origin - self.origin);
713 if(self.angles != self.mangle)
715 self.mangle = self.angles;
719 if(self.origin != self.oldorigin)
722 self.oldorigin = self.origin;
726 void misc_laser_init()
728 if(self.target != "")
729 self.enemy = find(world, targetname, self.target);
733 void misc_laser_think()
738 self.nextthink = time;
747 o = self.enemy.origin;
748 if not(self.spawnflags & 2)
749 o = self.origin + normalize(o - self.origin) * 32768;
753 makevectors(self.mangle);
754 o = self.origin + v_forward * 32768;
760 FireRailgunBullet(self.origin, o, 100000, 0, DEATH_HURTTRIGGER);
762 FireRailgunBullet(self.origin, o, self.dmg * frametime, 0, DEATH_HURTTRIGGER);
765 if(self.enemy.target != "") // DETECTOR laser
767 traceline(self.origin, o, MOVE_NORMAL, self);
768 if(trace_ent.iscreature)
770 self.pusher = trace_ent;
777 activator = self.pusher;
790 activator = self.pusher;
798 float laser_SendEntity(entity to, float fl)
800 WriteByte(MSG_ENTITY, ENT_CLIENT_LASER);
801 fl = fl - (fl & 0xC0); // use that bit to indicate finite length laser
802 if(self.spawnflags & 2)
806 WriteByte(MSG_ENTITY, fl);
809 WriteCoord(MSG_ENTITY, self.origin_x);
810 WriteCoord(MSG_ENTITY, self.origin_y);
811 WriteCoord(MSG_ENTITY, self.origin_z);
815 WriteByte(MSG_ENTITY, self.colormod_x * 255.0);
816 WriteByte(MSG_ENTITY, self.colormod_y * 255.0);
817 WriteByte(MSG_ENTITY, self.colormod_z * 255.0);
819 WriteByte(MSG_ENTITY, self.alpha * 255.0);
820 WriteShort(MSG_ENTITY, self.cnt + 1);
826 WriteCoord(MSG_ENTITY, self.enemy.origin_x);
827 WriteCoord(MSG_ENTITY, self.enemy.origin_y);
828 WriteCoord(MSG_ENTITY, self.enemy.origin_z);
832 WriteCoord(MSG_ENTITY, self.mangle_x);
833 WriteCoord(MSG_ENTITY, self.mangle_y);
837 WriteByte(MSG_ENTITY, self.state);
841 /*QUAKED spawnfunc_misc_laser (.5 .5 .5) ? START_ON DEST_IS_FIXED
842 Any object touching the beam will be hurt
845 spawnfunc_target_position where the laser ends
847 name of beam end effect to use
849 color of the beam (default: red)
851 damage per second (-1 for a laser that kills immediately)
855 self.state = !self.state;
860 void spawnfunc_misc_laser()
864 if(self.mdl == "none")
867 self.cnt = particleeffectnum(self.mdl);
872 self.cnt = particleeffectnum("laser_deadly");
877 if(self.colormod == '0 0 0')
879 self.colormod = '1 0 0';
881 self.message = "saw the light";
883 self.message2 = "was pushed into a laser by";
884 self.think = misc_laser_think;
885 self.nextthink = time;
886 InitializeEntity(self, misc_laser_init, INITPRIO_FINDTARGET);
888 self.effects = EF_NODEPTHTEST;
889 self.SendEntity = laser_SendEntity;
892 self.model = "net_entity";
893 self.mangle = self.angles;
897 self.use = laser_use;
898 if(self.spawnflags & 1)
907 // tZorks trigger impulse / gravity
913 // targeted (directional) mode
914 void trigger_impulse_touch1()
920 // FIXME: Better checking for what to push and not.
921 if not(other.iscreature)
922 if (other.classname != "corpse")
923 if (other.classname != "body")
924 if (other.classname != "gib")
925 if (other.classname != "missile")
926 if (other.classname != "rocket")
927 if (other.classname != "casing")
928 if (other.classname != "grenade")
929 if (other.classname != "plasma")
930 if (other.classname != "plasma_prim")
931 if (other.classname != "plasma_chain")
932 if (other.classname != "droppedweapon")
935 if (other.deadflag && other.iscreature)
940 targ = find(world, targetname, self.target);
943 objerror("trigger_force without a (valid) .target!\n");
948 if(self.falloff == 1)
949 str = (str / self.radius) * self.strength;
950 else if(self.falloff == 2)
951 str = (1 - (str / self.radius)) * self.strength;
955 pushdeltatime = time - other.lastpushtime;
956 if (pushdeltatime > 0.15) pushdeltatime = 0;
957 other.lastpushtime = time;
958 if(!pushdeltatime) return;
960 other.velocity = other.velocity + normalize(targ.origin - self.origin) * self.strength * pushdeltatime;
963 // Directionless (accelerator/decelerator) mode
964 void trigger_impulse_touch2()
968 // FIXME: Better checking for what to push and not.
969 if not(other.iscreature)
970 if (other.classname != "corpse")
971 if (other.classname != "body")
972 if (other.classname != "gib")
973 if (other.classname != "missile")
974 if (other.classname != "rocket")
975 if (other.classname != "casing")
976 if (other.classname != "grenade")
977 if (other.classname != "plasma")
978 if (other.classname != "plasma_prim")
979 if (other.classname != "plasma_chain")
980 if (other.classname != "droppedweapon")
983 if (other.deadflag && other.iscreature)
988 pushdeltatime = time - other.lastpushtime;
989 if (pushdeltatime > 0.15) pushdeltatime = 0;
990 other.lastpushtime = time;
991 if(!pushdeltatime) return;
993 //if(self.strength > 1)
994 other.velocity = other.velocity * (self.strength * pushdeltatime);
996 // other.velocity = other.velocity - (other.velocity * self.strength * pushdeltatime);
999 // Spherical (gravity/repulsor) mode
1000 void trigger_impulse_touch3()
1002 float pushdeltatime;
1005 // FIXME: Better checking for what to push and not.
1006 if not(other.iscreature)
1007 if (other.classname != "corpse")
1008 if (other.classname != "body")
1009 if (other.classname != "gib")
1010 if (other.classname != "missile")
1011 if (other.classname != "rocket")
1012 if (other.classname != "casing")
1013 if (other.classname != "grenade")
1014 if (other.classname != "plasma")
1015 if (other.classname != "plasma_prim")
1016 if (other.classname != "plasma_chain")
1017 if (other.classname != "droppedweapon")
1020 if (other.deadflag && other.iscreature)
1025 pushdeltatime = time - other.lastpushtime;
1026 if (pushdeltatime > 0.15) pushdeltatime = 0;
1027 other.lastpushtime = time;
1028 if(!pushdeltatime) return;
1030 setsize(self, '-1 -1 -1' * self.radius,'1 1 1' * self.radius);
1032 str = min(self.radius, vlen(self.origin - other.origin));
1034 if(self.falloff == 1)
1035 str = (1 - str / self.radius) * self.strength; // 1 in the inside
1036 else if(self.falloff == 2)
1037 str = (str / self.radius) * self.strength; // 0 in the inside
1039 str = self.strength;
1041 other.velocity = other.velocity + normalize(other.origin - self.origin) * str * pushdeltatime;
1044 /*QUAKED spawnfunc_trigger_impulse (.5 .5 .5) ?
1045 -------- KEYS --------
1046 target : If this is set, this points to the spawnfunc_target_position to which the player will get pushed.
1047 If not, this trigger acts like a damper/accelerator field.
1049 strength : This is how mutch force to add in the direction of .target each second
1050 when .target is set. If not, this is hoe mutch to slow down/accelerate
1051 someting cought inside this trigger. (1=no change, 0,5 half speed rougthly each tic, 2 = doubble)
1053 radius : If set, act as a spherical device rather then a liniar one.
1055 falloff : 0 = none, 1 = liniar, 2 = inverted liniar
1057 -------- NOTES --------
1058 Use a brush textured with common/origin in the trigger entity to determine the origin of the force
1059 in directional and sperical mode. For damper/accelerator mode this is not nessesary (and has no effect).
1062 void spawnfunc_trigger_impulse()
1067 if(!self.strength) self.strength = 2000;
1068 setorigin(self, self.origin);
1069 setsize(self, '-1 -1 -1' * self.radius,'1 1 1' * self.radius);
1070 self.touch = trigger_impulse_touch3;
1076 if(!self.strength) self.strength = 950;
1077 self.touch = trigger_impulse_touch1;
1081 if(!self.strength) self.strength = 0.9;
1082 self.touch = trigger_impulse_touch2;
1087 /*QUAKED spawnfunc_trigger_flipflop (.5 .5 .5) (-8 -8 -8) (8 8 8) START_ENABLED
1088 "Flip-flop" trigger gate... lets only every second trigger event through
1092 self.state = !self.state;
1097 void spawnfunc_trigger_flipflop()
1099 if(self.spawnflags & 1)
1101 self.use = flipflop_use;
1104 /*QUAKED spawnfunc_trigger_monoflop (.5 .5 .5) (-8 -8 -8) (8 8 8)
1105 "Mono-flop" trigger gate... turns one trigger event into one "on" and one "off" event, separated by a delay of "wait"
1109 self.nextthink = time + self.wait;
1110 self.enemy = activator;
1116 void monoflop_fixed_use()
1120 self.nextthink = time + self.wait;
1122 self.enemy = activator;
1126 void monoflop_think()
1129 activator = self.enemy;
1133 void spawnfunc_trigger_monoflop()
1137 if(self.spawnflags & 1)
1138 self.use = monoflop_fixed_use;
1140 self.use = monoflop_use;
1141 self.think = monoflop_think;
1145 void multivibrator_send()
1150 cyclestart = floor((time + self.phase) / (self.wait + self.respawntime)) * (self.wait + self.respawntime) - self.phase;
1152 newstate = (time < cyclestart + self.wait);
1155 if(self.state != newstate)
1157 self.state = newstate;
1160 self.nextthink = cyclestart + self.wait + 0.01;
1162 self.nextthink = cyclestart + self.wait + self.respawntime + 0.01;
1165 void multivibrator_toggle()
1167 if(self.nextthink == 0)
1169 multivibrator_send();
1182 /*QUAKED trigger_multivibrator (.5 .5 .5) (-8 -8 -8) (8 8 8) START_ON
1183 "Multivibrator" trigger gate... repeatedly sends trigger events. When triggered, turns on or off.
1184 -------- KEYS --------
1185 target: trigger all entities with this targetname when it goes off
1186 targetname: name that identifies this entity so it can be triggered; when off, it always uses the OFF state
1187 phase: offset of the timing
1188 wait: "on" cycle time (default: 1)
1189 respawntime: "off" cycle time (default: same as wait)
1190 -------- SPAWNFLAGS --------
1191 START_ON: assume it is already turned on (when targeted)
1193 void spawnfunc_trigger_multivibrator()
1197 if(!self.respawntime)
1198 self.respawntime = self.wait;
1201 self.use = multivibrator_toggle;
1202 self.think = multivibrator_send;
1203 self.nextthink = time;
1207 if(!(self.spawnflags & 1))
1208 self.nextthink = 0; // wait for a trigger event
1211 self.nextthink = time;
1218 src = find(world, targetname, self.killtarget);
1219 dst = find(world, targetname, self.target);
1223 objerror("follow: could not find target/killtarget");
1227 dst.movetype = MOVETYPE_FOLLOW;
1229 dst.punchangle = src.angles;
1230 dst.view_ofs = dst.origin - src.origin;
1231 dst.v_angle = dst.angles - src.angles;
1236 void spawnfunc_misc_follow()
1238 InitializeEntity(self, follow_init, INITPRIO_FINDTARGET);