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 centerprint (activator, self.message);
59 play2(activator, "misc/talk.wav");
63 // kill the killtagets
70 t = find (t, targetname, self.killtarget);
86 t = find (t, targetname, self.target);
107 //=============================================================================
109 float SPAWNFLAG_NOMESSAGE = 1;
110 float SPAWNFLAG_NOTOUCH = 1;
112 // the wait time has passed, so set back up for another activation
117 self.health = self.max_health;
118 self.takedamage = DAMAGE_YES;
119 self.solid = SOLID_BBOX;
124 // the trigger was just touched/killed/used
125 // self.enemy should be set to the activator so it can be held through a delay
126 // so wait for the delay time before firing
129 if (self.nextthink > time)
131 return; // allready been triggered
134 if (self.classname == "trigger_secret")
136 if (self.enemy.classname != "player")
138 found_secrets = found_secrets + 1;
139 WriteByte (MSG_ALL, SVC_FOUNDSECRET);
143 sound (self.enemy, CHAN_AUTO, self.noise, VOL_BASE, ATTN_NORM);
145 // don't trigger again until reset
146 self.takedamage = DAMAGE_NO;
148 activator = self.enemy;
154 self.think = multi_wait;
155 self.nextthink = time + self.wait;
158 { // we can't just remove (self) here, because this is a touch function
159 // called wheil C code is looping through area links...
160 self.touch = SUB_Null;
162 self.nextthink = time + 0.1;
163 self.think = SUB_Remove;
169 self.enemy = activator;
175 if not(self.spawnflags & 2)
177 if (other.classname != "player")
181 if(self.team == other.team)
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
199 void multi_eventdamage (vector hitloc, float damage, entity inflictor, entity attacker, float deathtype)
201 if (!self.takedamage)
203 self.health = self.health - damage;
204 if (self.health <= 0)
206 self.enemy = attacker;
211 /*QUAKED spawnfunc_trigger_multiple (.5 .5 .5) ? notouch
212 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.
213 If "delay" is set, the trigger waits some time after activating before firing.
214 "wait" : Seconds between triggerings. (.2 default)
215 If notouch is set, the trigger is only fired by other entities, not by touching.
216 NOTOUCH has been obsoleted by spawnfunc_trigger_relay!
222 set "message" to text string
224 void spawnfunc_trigger_multiple()
226 if (self.sounds == 1)
228 precache_sound ("misc/secret.wav");
229 self.noise = "misc/secret.wav";
231 else if (self.sounds == 2)
233 precache_sound ("misc/talk.wav");
234 self.noise = "misc/talk.wav";
236 else if (self.sounds == 3)
238 precache_sound ("misc/trigger1.wav");
239 self.noise = "misc/trigger1.wav";
244 self.use = multi_use;
250 if (self.spawnflags & SPAWNFLAG_NOTOUCH)
251 objerror ("health and notouch don't make sense\n");
252 self.max_health = self.health;
253 self.event_damage = multi_eventdamage;
254 self.takedamage = DAMAGE_YES;
255 self.solid = SOLID_BBOX;
256 setorigin (self, self.origin); // make sure it links into the world
260 if ( !(self.spawnflags & SPAWNFLAG_NOTOUCH) )
262 self.touch = multi_touch;
263 setorigin (self, self.origin); // make sure it links into the world
269 /*QUAKED spawnfunc_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 spawnfunc_trigger_once()
285 spawnfunc_trigger_multiple();
288 //=============================================================================
290 /*QUAKED spawnfunc_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 spawnfunc_trigger_relay()
295 self.use = SUB_UseTargets;
300 self.think = SUB_UseTargets;
301 self.nextthink = self.wait;
304 void spawnfunc_trigger_delay()
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 spawnfunc_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 spawnfunc_trigger_counter()
358 self.use = counter_use;
361 .float triggerhurttime;
362 void trigger_hurt_touch()
364 // only do the EXACTTRIGGER_TOUCH checks when really needed (saves some cpu)
367 if (other.items & IT_KEY1 || other.items & IT_KEY2) // reset flag
370 other.pain_finished = min(other.pain_finished, time + 2);
372 else if (other.classname == "rune") // reset runes
375 other.nextthink = min(other.nextthink, time + 1);
379 if (other.takedamage)
380 if (other.triggerhurttime < time)
383 other.triggerhurttime = time + 1;
384 Damage (other, self, self, self.dmg, DEATH_HURTTRIGGER, other.origin, '0 0 0');
390 /*QUAKED spawnfunc_trigger_hurt (.5 .5 .5) ?
391 Any object touching this will be hurt
392 set dmg to damage amount
395 .entity trigger_hurt_next;
396 entity trigger_hurt_last;
397 entity trigger_hurt_first;
398 void spawnfunc_trigger_hurt()
401 self.touch = trigger_hurt_touch;
405 self.message = "was in the wrong place";
407 self.message2 = "was thrown into a world of hurt by";
409 if(!trigger_hurt_first)
410 trigger_hurt_first = self;
411 if(trigger_hurt_last)
412 trigger_hurt_last.trigger_hurt_next = self;
413 trigger_hurt_last = self;
416 float tracebox_hits_trigger_hurt(vector start, vector mi, vector ma, vector end)
420 for(th = trigger_hurt_first; th; th = th.trigger_hurt_next)
421 if(tracebox_hits_box(start, mi, ma, end, th.absmin, th.absmax))
428 // TODO add a way to do looped sounds with sound(); then complete this entity
429 .float volume, atten;
430 void target_speaker_use() {sound(self, CHAN_TRIGGER, self.noise, VOL_BASE * self.volume, self.atten);}
432 void spawnfunc_target_speaker()
435 precache_sound (self.noise);
439 self.atten = ATTN_NORM;
440 else if(self.atten < 0)
444 self.use = target_speaker_use;
449 self.atten = ATTN_STATIC;
450 else if(self.atten < 0)
454 ambientsound (self.origin, self.noise, VOL_BASE * self.volume, self.atten);
459 void spawnfunc_func_stardust() {
460 self.effects = EF_STARDUST;
463 float pointparticles_SendEntity(entity to, float fl)
465 WriteByte(MSG_ENTITY, ENT_CLIENT_POINTPARTICLES);
466 WriteByte(MSG_ENTITY, fl);
470 WriteCoord(MSG_ENTITY, self.impulse);
472 WriteCoord(MSG_ENTITY, 0); // off
476 WriteCoord(MSG_ENTITY, self.origin_x);
477 WriteCoord(MSG_ENTITY, self.origin_y);
478 WriteCoord(MSG_ENTITY, self.origin_z);
482 if(self.modelindex != 4.2)
484 WriteShort(MSG_ENTITY, self.modelindex);
485 WriteCoord(MSG_ENTITY, self.mins_x);
486 WriteCoord(MSG_ENTITY, self.mins_y);
487 WriteCoord(MSG_ENTITY, self.mins_z);
488 WriteCoord(MSG_ENTITY, self.maxs_x);
489 WriteCoord(MSG_ENTITY, self.maxs_y);
490 WriteCoord(MSG_ENTITY, self.maxs_z);
494 WriteShort(MSG_ENTITY, 0);
495 WriteCoord(MSG_ENTITY, self.maxs_x);
496 WriteCoord(MSG_ENTITY, self.maxs_y);
497 WriteCoord(MSG_ENTITY, self.maxs_z);
499 WriteShort(MSG_ENTITY, self.cnt);
500 WriteShort(MSG_ENTITY, compressShortVector(self.velocity));
501 WriteShort(MSG_ENTITY, compressShortVector(self.movedir));
502 WriteCoord(MSG_ENTITY, self.waterlevel);
503 WriteCoord(MSG_ENTITY, self.count);
504 WriteByte(MSG_ENTITY, self.glow_color);
505 WriteString(MSG_ENTITY, self.noise);
510 void pointparticles_use()
512 self.state = !self.state;
516 void pointparticles_think()
518 if(self.origin != self.oldorigin)
521 self.oldorigin = self.origin;
523 self.nextthink = time;
526 void spawnfunc_func_pointparticles()
529 setmodel(self, self.model);
531 precache_sound (self.noise);
533 self.effects = EF_NODEPTHTEST;
534 self.SendEntity = pointparticles_SendEntity;
538 self.modelindex = 4.2;
539 self.origin += self.mins;
540 self.maxs -= self.mins;
542 self.model = "net_entity";
544 self.cnt = particleeffectnum(self.mdl);
547 self.use = pointparticles_use;
548 if(self.spawnflags & 1)
555 self.think = pointparticles_think;
556 self.nextthink = time;
559 void spawnfunc_func_sparks()
561 // self.cnt is the amount of sparks that one burst will spawn
563 self.cnt = 25.0; // nice default value
566 // self.wait is the probability that a sparkthink will spawn a spark shower
567 // range: 0 - 1, but 0 makes little sense, so...
568 if(self.wait < 0.05) {
569 self.wait = 0.25; // nice default value
572 self.count = self.cnt;
575 self.velocity = '0 0 -1';
576 self.mdl = "TE_SPARK";
577 self.impulse = 10 * self.wait; // by default 2.5/sec
579 self.cnt = 0; // use mdl
581 spawnfunc_func_pointparticles();
584 float rainsnow_SendEntity(float to)
586 WriteByte(MSG_ENTITY, ENT_CLIENT_RAINSNOW);
587 WriteByte(MSG_ENTITY, self.state);
588 WriteCoord(MSG_ENTITY, self.origin_x + self.mins_x);
589 WriteCoord(MSG_ENTITY, self.origin_y + self.mins_y);
590 WriteCoord(MSG_ENTITY, self.origin_z + self.mins_z);
591 WriteCoord(MSG_ENTITY, self.maxs_x - self.mins_x);
592 WriteCoord(MSG_ENTITY, self.maxs_y - self.mins_y);
593 WriteCoord(MSG_ENTITY, self.maxs_z - self.mins_z);
594 WriteShort(MSG_ENTITY, compressShortVector(self.dest));
595 WriteShort(MSG_ENTITY, self.count);
596 WriteByte(MSG_ENTITY, self.cnt);
600 /*QUAKED spawnfunc_func_rain (0 .5 .8) ?
601 This is an invisible area like a trigger, which rain falls inside of.
605 falling direction (should be something like '0 0 -700', use the X and Y velocity for wind)
607 sets color of rain (default 12 - white)
609 adjusts density, this many particles fall every second for a 1024x1024 area, default is 2000
611 void spawnfunc_func_rain()
613 self.dest = self.velocity;
614 self.velocity = '0 0 0';
616 self.dest = '0 0 -700';
617 self.angles = '0 0 0';
618 self.movetype = MOVETYPE_NONE;
619 self.solid = SOLID_NOT;
620 SetBrushEntityModel();
626 self.count = 0.01 * self.count * (self.size_x / 1024) * (self.size_y / 1024);
629 if(self.count > 65535)
632 self.state = 1; // 1 is rain, 0 is snow
633 self.effects = EF_NODEPTHTEST;
634 self.SendEntity = rainsnow_SendEntity;
637 self.model = "net_entity";
641 /*QUAKED spawnfunc_func_snow (0 .5 .8) ?
642 This is an invisible area like a trigger, which snow falls inside of.
646 falling direction (should be something like '0 0 -300', use the X and Y velocity for wind)
648 sets color of rain (default 12 - white)
650 adjusts density, this many particles fall every second for a 1024x1024 area, default is 2000
652 void spawnfunc_func_snow()
654 self.dest = self.velocity;
655 self.velocity = '0 0 0';
657 self.dest = '0 0 -300';
658 self.angles = '0 0 0';
659 self.movetype = MOVETYPE_NONE;
660 self.solid = SOLID_NOT;
661 SetBrushEntityModel();
667 self.count = 0.01 * self.count * (self.size_x / 1024) * (self.size_y / 1024);
670 if(self.count > 65535)
673 self.state = 0; // 1 is rain, 0 is snow
674 self.effects = EF_NODEPTHTEST;
675 self.SendEntity = rainsnow_SendEntity;
678 self.model = "net_entity";
682 void FireRailgunBullet (vector start, vector end, float bdamage, float bforce, float deathtype);
684 void misc_laser_aim()
689 if(self.spawnflags & 2)
691 if(self.enemy.origin != self.mangle)
693 self.mangle = self.enemy.origin;
699 a = vectoangles(self.enemy.origin - self.origin);
710 if(self.angles != self.mangle)
712 self.mangle = self.angles;
716 if(self.origin != self.oldorigin)
719 self.oldorigin = self.origin;
723 void misc_laser_init()
725 if(self.target != "")
726 self.enemy = find(world, targetname, self.target);
730 void misc_laser_think()
735 self.nextthink = time;
744 o = self.enemy.origin;
745 if not(self.spawnflags & 2)
746 o = self.origin + normalize(o - self.origin) * 32768;
750 makevectors(self.mangle);
751 o = self.origin + v_forward * 32768;
757 FireRailgunBullet(self.origin, o, 100000, 0, DEATH_HURTTRIGGER);
759 FireRailgunBullet(self.origin, o, self.dmg * frametime, 0, DEATH_HURTTRIGGER);
762 if(self.enemy.target != "") // DETECTOR laser
764 traceline(self.origin, o, MOVE_NORMAL, self);
765 if(trace_ent.classname == "player")
767 self.pusher = trace_ent;
774 activator = self.pusher;
787 activator = self.pusher;
795 float laser_SendEntity(entity to, float fl)
797 WriteByte(MSG_ENTITY, ENT_CLIENT_LASER);
798 fl = fl - (fl & 0xC0); // use that bit to indicate finite length laser
799 if(self.spawnflags & 2)
803 WriteByte(MSG_ENTITY, fl);
806 WriteCoord(MSG_ENTITY, self.origin_x);
807 WriteCoord(MSG_ENTITY, self.origin_y);
808 WriteCoord(MSG_ENTITY, self.origin_z);
812 WriteByte(MSG_ENTITY, self.colormod_x * 255.0);
813 WriteByte(MSG_ENTITY, self.colormod_y * 255.0);
814 WriteByte(MSG_ENTITY, self.colormod_z * 255.0);
816 WriteByte(MSG_ENTITY, self.alpha * 255.0);
817 WriteShort(MSG_ENTITY, self.cnt + 1);
823 WriteCoord(MSG_ENTITY, self.enemy.origin_x);
824 WriteCoord(MSG_ENTITY, self.enemy.origin_y);
825 WriteCoord(MSG_ENTITY, self.enemy.origin_z);
829 WriteCoord(MSG_ENTITY, self.mangle_x);
830 WriteCoord(MSG_ENTITY, self.mangle_y);
834 WriteByte(MSG_ENTITY, self.state);
838 /*QUAKED spawnfunc_misc_laser (.5 .5 .5) ? START_ON DEST_IS_FIXED
839 Any object touching the beam will be hurt
842 spawnfunc_target_position where the laser ends
844 name of beam end effect to use
846 color of the beam (default: red)
848 damage per second (-1 for a laser that kills immediately)
852 self.state = !self.state;
857 void spawnfunc_misc_laser()
861 if(self.mdl == "none")
864 self.cnt = particleeffectnum(self.mdl);
869 self.cnt = particleeffectnum("laser_deadly");
874 if(self.colormod == '0 0 0')
876 self.colormod = '1 0 0';
878 self.message = "saw the light";
880 self.message2 = "was pushed into a laser by";
881 self.think = misc_laser_think;
882 self.nextthink = time;
883 InitializeEntity(self, misc_laser_init, INITPRIO_FINDTARGET);
885 self.effects = EF_NODEPTHTEST;
886 self.SendEntity = laser_SendEntity;
889 self.model = "net_entity";
890 self.mangle = self.angles;
894 self.use = laser_use;
895 if(self.spawnflags & 1)
904 // tZorks trigger impulse / gravity
910 // targeted (directional) mode
911 void trigger_impulse_touch1()
917 // FIXME: Better checking for what to push and not.
918 if (other.classname != "player")
919 if (other.classname != "corpse")
920 if (other.classname != "body")
921 if (other.classname != "gib")
922 if (other.classname != "missile")
923 if (other.classname != "casing")
924 if (other.classname != "grenade")
925 if (other.classname != "plasma")
926 if (other.classname != "plasma_prim")
927 if (other.classname != "plasma_chain")
928 if (other.classname != "droppedweapon")
931 if (other.deadflag && other.classname == "player")
936 targ = find(world, targetname, self.target);
939 objerror("trigger_force without a (valid) .target!\n");
944 if(self.falloff == 1)
945 str = (str / self.radius) * self.strength;
946 else if(self.falloff == 2)
947 str = (1 - (str / self.radius)) * self.strength;
951 pushdeltatime = time - other.lastpushtime;
952 if (pushdeltatime > 0.15) pushdeltatime = 0;
953 other.lastpushtime = time;
954 if(!pushdeltatime) return;
956 other.velocity = other.velocity + normalize(targ.origin - self.origin) * self.strength * pushdeltatime;
959 // Directionless (accelerator/decelerator) mode
960 void trigger_impulse_touch2()
964 // FIXME: Better checking for what to push and not.
965 if (other.classname != "player")
966 if (other.classname != "corpse")
967 if (other.classname != "body")
968 if (other.classname != "gib")
969 if (other.classname != "missile")
970 if (other.classname != "casing")
971 if (other.classname != "grenade")
972 if (other.classname != "plasma")
973 if (other.classname != "plasma_prim")
974 if (other.classname != "plasma_chain")
975 if (other.classname != "droppedweapon")
978 if (other.deadflag && other.classname == "player")
983 pushdeltatime = time - other.lastpushtime;
984 if (pushdeltatime > 0.15) pushdeltatime = 0;
985 other.lastpushtime = time;
986 if(!pushdeltatime) return;
988 //if(self.strength > 1)
989 other.velocity = other.velocity * (self.strength * pushdeltatime);
991 // other.velocity = other.velocity - (other.velocity * self.strength * pushdeltatime);
994 // Spherical (gravity/repulsor) mode
995 void trigger_impulse_touch3()
1000 // FIXME: Better checking for what to push and not.
1001 if (other.classname != "player")
1002 if (other.classname != "corpse")
1003 if (other.classname != "body")
1004 if (other.classname != "gib")
1005 if (other.classname != "missile")
1006 if (other.classname != "casing")
1007 if (other.classname != "grenade")
1008 if (other.classname != "plasma")
1009 if (other.classname != "plasma_prim")
1010 if (other.classname != "plasma_chain")
1011 if (other.classname != "droppedweapon")
1014 if (other.deadflag && other.classname == "player")
1019 pushdeltatime = time - other.lastpushtime;
1020 if (pushdeltatime > 0.15) pushdeltatime = 0;
1021 other.lastpushtime = time;
1022 if(!pushdeltatime) return;
1024 setsize(self, '-1 -1 -1' * self.radius,'1 1 1' * self.radius);
1026 str = min(self.radius, vlen(self.origin - other.origin));
1028 if(self.falloff == 1)
1029 str = (1 - str / self.radius) * self.strength; // 1 in the inside
1030 else if(self.falloff == 2)
1031 str = (str / self.radius) * self.strength; // 0 in the inside
1033 str = self.strength;
1035 other.velocity = other.velocity + normalize(other.origin - self.origin) * str * pushdeltatime;
1038 /*QUAKED spawnfunc_trigger_impulse (.5 .5 .5) ?
1039 -------- KEYS --------
1040 target : If this is set, this points to the spawnfunc_target_position to which the player will get pushed.
1041 If not, this trigger acts like a damper/accelerator field.
1043 strength : This is how mutch force to add in the direction of .target each second
1044 when .target is set. If not, this is hoe mutch to slow down/accelerate
1045 someting cought inside this trigger. (1=no change, 0,5 half speed rougthly each tic, 2 = doubble)
1047 radius : If set, act as a spherical device rather then a liniar one.
1049 falloff : 0 = none, 1 = liniar, 2 = inverted liniar
1051 -------- NOTES --------
1052 Use a brush textured with common/origin in the trigger entity to determine the origin of the force
1053 in directional and sperical mode. For damper/accelerator mode this is not nessesary (and has no effect).
1056 void spawnfunc_trigger_impulse()
1061 if(!self.strength) self.strength = 2000;
1062 setorigin(self, self.origin);
1063 setsize(self, '-1 -1 -1' * self.radius,'1 1 1' * self.radius);
1064 self.touch = trigger_impulse_touch3;
1070 if(!self.strength) self.strength = 950;
1071 self.touch = trigger_impulse_touch1;
1075 if(!self.strength) self.strength = 0.9;
1076 self.touch = trigger_impulse_touch2;
1081 /*QUAKED spawnfunc_trigger_flipflop (.5 .5 .5) (-8 -8 -8) (8 8 8) START_ENABLED
1082 "Flip-flop" trigger gate... lets only every second trigger event through
1086 self.state = !self.state;
1091 void spawnfunc_trigger_flipflop()
1093 if(self.spawnflags & 1)
1095 self.use = flipflop_use;
1098 /*QUAKED spawnfunc_trigger_monoflop (.5 .5 .5) (-8 -8 -8) (8 8 8)
1099 "Mono-flop" trigger gate... turns one trigger event into one "on" and one "off" event, separated by a delay of "wait"
1103 self.nextthink = time + self.wait;
1109 void monoflop_fixed_use()
1113 self.nextthink = time + self.wait;
1118 void monoflop_think()
1124 void spawnfunc_trigger_monoflop()
1128 if(self.spawnflags & 1)
1129 self.use = monoflop_fixed_use;
1131 self.use = monoflop_use;
1132 self.think = monoflop_think;
1136 void multivibrator_send()
1141 cyclestart = floor((time + self.phase) / (self.wait + self.respawntime)) * (self.wait + self.respawntime) - self.phase;
1143 newstate = (time < cyclestart + self.wait);
1145 if(self.state != newstate)
1147 self.state = newstate;
1150 self.nextthink = cyclestart + self.wait + 0.01;
1152 self.nextthink = cyclestart + self.wait + self.respawntime + 0.01;
1155 void multivibrator_toggle()
1157 if(self.nextthink == 0)
1159 multivibrator_send();
1172 /*QUAKED trigger_multivibrator (.5 .5 .5) (-8 -8 -8) (8 8 8) START_ON
1173 "Multivibrator" trigger gate... repeatedly sends trigger events. When triggered, turns on or off.
1174 -------- KEYS --------
1175 target: trigger all entities with this targetname when it goes off
1176 targetname: name that identifies this entity so it can be triggered; when off, it always uses the OFF state
1177 phase: offset of the timing
1178 wait: "on" cycle time (default: 1)
1179 respawntime: "off" cycle time (default: same as wait)
1180 -------- SPAWNFLAGS --------
1181 START_ON: assume it is already turned on (when targeted)
1183 void spawnfunc_trigger_multivibrator()
1187 if(!self.respawntime)
1188 self.respawntime = self.wait;
1191 self.use = multivibrator_toggle;
1192 self.think = multivibrator_send;
1193 self.nextthink = time;
1197 if(!(self.spawnflags & 1))
1198 self.nextthink = 0; // wait for a trigger event
1201 self.nextthink = time;
1208 src = find(world, targetname, self.killtarget);
1209 dst = find(world, targetname, self.target);
1213 objerror("follow: could not find target/killtarget");
1217 dst.movetype = MOVETYPE_FOLLOW;
1219 dst.punchangle = src.angles;
1220 dst.view_ofs = dst.origin - src.origin;
1221 dst.v_angle = dst.angles - src.angles;
1226 void spawnfunc_misc_follow()
1228 InitializeEntity(self, follow_init, INITPRIO_FINDTARGET);